boot.s (4064B)
1 /* Multiboot1 header for 32-bit kernel */ 2 .section .multiboot 3 .align 4 4 .long 0x1BADB002 /* magic */ 5 .long 0x00000007 /* flags: PAGE_ALIGN | MEMORY_INFO | VIDEO_MODE */ 6 .long -(0x1BADB002 + 0x00000007) /* checksum */ 7 8 /* Video mode fields (for flag bit 2) */ 9 .long 0 /* header_addr (unused) */ 10 .long 0 /* load_addr (unused) */ 11 .long 0 /* load_end_addr (unused) */ 12 .long 0 /* bss_end_addr (unused) */ 13 .long 0 /* entry_addr (unused) */ 14 15 /* Video mode preference */ 16 .long 0 /* mode_type: 0 = linear graphics mode */ 17 .long 1024 /* width: 1024 pixels */ 18 .long 768 /* height: 768 pixels */ 19 .long 32 /* depth: 32 bits per pixel */ 20 21 /* Allocate the initial stack */ 22 .section .bss 23 .align 16 24 kernel_stack_bottom: 25 .skip 16384 # 16 KiB kernel stack 26 kernel_stack_top: 27 28 .align 16 29 user_stack_bottom: 30 .skip 524288 # 512 KiB user stack (LuaJIT needs more stack space) 31 user_stack_top: 32 33 /* TSS (Task State Segment) */ 34 .section .bss 35 .align 16 36 .global tss 37 .global kernel_stack_top 38 tss: 39 .skip 104 /* TSS structure (104 bytes) */ 40 41 /* GDT */ 42 .section .data 43 .align 16 44 .global gdt_start 45 gdt_start: 46 .quad 0x0000000000000000 /* 0x00: Null descriptor */ 47 .quad 0x00CF9A000000FFFF /* 0x08: Kernel code (ring 0) */ 48 .quad 0x00CF92000000FFFF /* 0x10: Kernel data (ring 0) */ 49 .quad 0x00CFFA000000FFFF /* 0x18: User code (ring 3) */ 50 .quad 0x00CFF3000000FFFF /* 0x20: User data (ring 3) - readable+writable, expand-up */ 51 .quad 0x0000000000000000 /* 0x28: TSS descriptor (filled at runtime) */ 52 .quad 0x00CFF3000000FFFF /* 0x30: User TLS data segment (FS) - ring 3 */ 53 .quad 0x00CFF3000000FFFF /* 0x38: User TLS data segment (GS) - ring 3 */ 54 gdt_end: 55 56 gdt_descriptor: 57 .word gdt_end - gdt_start - 1 58 .long gdt_start 59 60 /* Store multiboot info pointer */ 61 .section .bss 62 .global multiboot_info_ptr 63 multiboot_info_ptr: 64 .long 0 65 66 /* Entry point */ 67 .section .text 68 .global _start 69 .type _start, @function 70 _start: 71 /* Save multiboot info pointer (EBX contains it) */ 72 movl %ebx, multiboot_info_ptr 73 74 /* Set up the kernel stack */ 75 mov $kernel_stack_top, %esp 76 77 /* Load our GDT */ 78 lgdt gdt_descriptor 79 80 /* Reload segment registers */ 81 mov $0x10, %ax /* Kernel data segment */ 82 mov %ax, %ds 83 mov %ax, %es 84 mov %ax, %fs 85 mov %ax, %gs 86 mov %ax, %ss 87 88 /* Far jump to reload CS */ 89 ljmp $0x08, $gdt_loaded 90 91 gdt_loaded: 92 /* Call the kernel main function */ 93 call kernel_main 94 95 /* Hang if kernel_main returns */ 96 cli 97 1: hlt 98 jmp 1b 99 100 .size _start, . - _start 101 102 /* Function to transition to user mode */ 103 .global enter_usermode 104 .type enter_usermode, @function 105 enter_usermode: 106 /* Get the entry point from parameter (before we push things) */ 107 mov 4(%esp), %eax /* entry_point parameter */ 108 109 /* Disable interrupts during transition */ 110 cli 111 112 /* Build stack frame for iret (iret expects: EIP, CS, EFLAGS, ESP, SS) */ 113 /* Push SS (user data segment) */ 114 pushl $0x23 /* User data segment (0x20 | 3 for RPL=3) */ 115 116 /* Push ESP (user stack pointer) - ensure 16-byte alignment */ 117 movl $user_stack_top, %edx 118 andl $-16, %edx /* Align to 16 bytes */ 119 pushl %edx 120 121 /* Push EFLAGS with IOPL=3 and IF=1 to allow usermode I/O and interrupts */ 122 pushf 123 popl %edx 124 orl $0x3200, %edx /* Set IOPL=3 (bits 12-13) and IF=1 (bit 9) */ 125 pushl %edx 126 127 /* Push CS (user code segment) */ 128 pushl $0x1B /* User code segment (0x18 | 3 for RPL=3) */ 129 130 /* Push EIP (entry point) */ 131 pushl %eax 132 133 /* DON'T set user segments here - we're still in kernel mode! 134 * The iret will set CS and SS. We'll set DS/ES/FS/GS in user code. */ 135 136 /* Execute iret to jump to user mode */ 137 iret 138 139 .size enter_usermode, . - enter_usermode