/* * Copyright (c) 2009 Corey Tabaka * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* The magic number for the Multiboot header. */ #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 /* The flags for the Multiboot header. */ #if defined(__ELF__) && 0 #define MULTIBOOT_HEADER_FLAGS 0x00000002 #else #define MULTIBOOT_HEADER_FLAGS 0x00010002 #endif /* The magic number passed by a Multiboot-compliant boot loader. */ #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 #define NUM_INT 0x31 #define NUM_EXC 0x14 .text .global _start _start: jmp real_start .align 4 multiboot_header: /* magic */ .int MULTIBOOT_HEADER_MAGIC /* flags */ .int MULTIBOOT_HEADER_FLAGS /* checksum */ .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) #if !defined(__ELF__) || 1 /* header_addr */ .int multiboot_header /* load_addr */ .int _start /* load_end_addr */ .int __bss_start /* bss_end_addr */ .int __bss_end /* entry_addr */ .int real_start #endif real_start: cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax jne 0f movl %ebx, (_multiboot_info) 0: /* setup isr stub descriptors in the idt */ movl $_isr, %esi movl $_idt, %edi movl $NUM_INT, %ecx .Lloop: movl %esi, %ebx movw %bx, (%edi) /* low word in IDT(n).low */ shrl $16, %ebx movw %bx, 6(%edi) /* high word in IDT(n).high */ addl $isr_stub_len, %esi/* index the next ISR stub */ addl $8, %edi /* index the next IDT entry */ loop .Lloop lidt _idtr xorl %eax, %eax movl %eax, %cr3 lgdt _gdtr movw $datasel, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %ss movw %ax, %gs movw %ax, %ss movl $_kstack, %esp /* zero the bss section */ movl $__bss_start, %edi /* starting address of the bss */ movl $__bss_end, %ecx /* find the length of the bss in bytes */ subl %edi, %ecx shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */ 2: movl $0, (%edi) addl $4, %edi loop 2b /* call the main module */ call kmain 0: /* just sit around waiting for interrupts */ hlt /* interrupts will unhalt the processor */ pause jmp 0b /* so jump back to halt to conserve power */ /* interrupt service routine stubs */ _isr: .set i, 0 .rept NUM_INT .set isr_stub_start, . .if i == 8 || (i >= 10 && i <= 14) || i == 17 nop /* error code pushed by exception */ nop /* 2 nops are the same length as push byte */ pushl $i /* interrupt number */ jmp interrupt_common .else pushl $0 /* fill in error code in iframe */ pushl $i /* interrupt number */ jmp interrupt_common .endif /* figure out the length of a single isr stub (usually 6 or 9 bytes) */ .set isr_stub_len, . - isr_stub_start .set i, i + 1 .endr /* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */ .fill 256 interrupt_common: pushl %gs /* save segment registers */ pushl %fs pushl %es pushl %ds pusha /* save general purpose registers */ movl $datasel, %eax /* put known good value in segment registers */ movl %eax, %gs movl %eax, %fs movl %eax, %es movl %eax, %ds movl %esp, %eax /* store stack switch pivot. push esp has errata on some cpus, so use mov/push */ pushl %eax movl %esp, %eax /* store pointer to iframe, using same method */ pushl %eax incl critical_section_count call platform_irq cmpl $0,%eax je 0f call thread_preempt 0: decl critical_section_count popl %eax /* drop pointer to iframe */ popl %eax /* restore task_esp, stack switch can occur here if task_esp is modified */ movl %eax, %esp popa /* restore general purpose registers */ popl %ds /* restore segment registers */ popl %es popl %fs popl %gs addl $8, %esp /* drop exception number and error code */ iret .data .align 4 /* define the heap end as read-write data containing the default end of the * heap. dynamic memory length discovery can update this value during init. * other archs can define this statically based on the memory layout of the * platform. */ .global _heap_end _heap_end: .int 4096*1024 /* default to 4MB total */ .global _multiboot_info _multiboot_info: .int 0 .global _gdtr _gdtr: .short _gdt_end - _gdt - 1 .int _gdt .global _gdt _gdt: .int 0 .int 0 /* ring 0 descriptors */ .set codesel, . - _gdt _code_gde: .short 0xffff /* limit 15:00 */ .short 0x0000 /* base 15:00 */ .byte 0x00 /* base 23:16 */ .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */ .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */ .byte 0x0 /* base 31:24 */ .set datasel, . - _gdt _data_gde: .short 0xffff /* limit 15:00 */ .short 0x0000 /* base 15:00 */ .byte 0x00 /* base 23:16 */ .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */ .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */ .byte 0x0 /* base 31:24 */ .set videosel, . - _gdt _video_gde: .short 0xffff /* limit 15:00 */ .short 0x8000 /* base 15:00 */ .byte 0x0b /* base 23:16 */ .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */ .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */ .byte 0x0 /* base 31:24 */ .if 1 /* ring 3 descriptors */ .set user_codesel, . - _gdt _user_code_gde: .short 0xffff /* limit 15:00 */ .short 0x0000 /* base 15:00 */ .byte 0x00 /* base 23:16 */ .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */ .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */ .byte 0x0 /* base 31:24 */ .set user_datasel, . - _gdt _user_data_gde: .short 0xffff /* limit 15:00 */ .short 0x0000 /* base 15:00 */ .byte 0x00 /* base 23:16 */ .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */ .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */ .byte 0x0 /* base 31:24 */ .endif /* TSS descriptor */ .if 1 .set tsssel, . - _gdt _tss_gde: .short 0 /* limit 15:00 */ .short 0 /* base 15:00 */ .byte 0 /* base 23:16 */ .byte 0xe9 /* P(1) DPL(11) 0 10 B(0) 1 */ .byte 0x00 /* G(0) 0 0 AVL(0) limit 19:16 */ .short 0 /* base 31:24 */ .endif .global _gdt_end _gdt_end: .global _idtr _idtr: .short _idt_end - _idt - 1 /* IDT limit */ .int _idt /* interrupt descriptor table (IDT) */ .global _idt _idt: .set i, 0 .rept NUM_INT-1 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ .short codesel /* selector */ .byte 0 .byte 0x8e /* present, ring 0, 32-bit interrupt gate */ .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ .set i, i + 1 .endr /* syscall int (ring 3) */ _idt30: .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ .short codesel /* selector */ .byte 0 .byte 0xee /* present, ring 3, 32-bit interrupt gate */ .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ .global _idt_end _idt_end: .bss .align 4096 .global _kstack .fill 4096 _kstack: