blob: 9cc9ab0f8bdc8ecee655456cd1ba3b3b3add75ce [file] [log] [blame]
/*
* 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: