// vim: et:sw=12:ts=12:sts=12 .global _start .text .code16 .set SS_CODE16, 0x08 .set SS_DATA16, 0x10 .set SS_CODE32, 0x18 .set SS_DATA32, 0x20 // _start: entry point _start: cli cld mov %sp, %bp xor %ax, %ax mov %ax, %ds mov %ax, %es push $msg_start call dbgmsg add $2, %sp // initialize our own BSS section mov $_bss_start, %di mov $_bss_end, %cx sub %di, %cx xor %al, %al rep stosb // a20_enable: Allow use of 'high' (>1Mb) memory a20_enable: // Of all the ways to toggle A20, we only try the Fast A20 Gate. // This is known to cause problems on some ancient systems, // but as our bootloader exclusively runs on 64-bit machines, // we should not run into any of those systems. // Modern machines apparently don't even have the A20 line anymore. push $msg_a20 call dbgmsg add $2, %sp inb $0x92, %al or $2, %al outb %al, $0x92 // prot_enter: Set up GDT, switch into 32-bit protected mode. prot_enter: push $msg_prot call dbgmsg add $2, %sp lgdt GDT_PTR // Set Protection Enable (PE) bit mov %cr0, %eax or $1, %al mov %eax, %cr0 ljmp $SS_CODE32, $prot_trampo .code32 prot_trampo: mov $SS_DATA32, %eax mov %eax, %ds mov %eax, %es mov %eax, %fs mov %eax, %gs mov %eax, %ss mov 'Y', %al outb %al, $0xE9 // TODO load proper stack pointer mov $0x90000, %ebp mov %ebp, %esp jmp main .code16 dbgmsg: push %bp mov %sp, %bp push %ax push %si mov 4(%bp), %si 1: lodsb test %al, %al jz 2f outb %al, $0xE9 jmp 1b 2: pop %si pop %ax pop %bp ret .data .global GDT GDT: // entry 0: null descriptor .space 8, 0 // entry 1: 16-bit code segment .byte 0xFF, 0xFF, 0, 0, 0, 0b10011010, 0x8F, 0 // entry 2: 16-bit data segment .byte 0xFF, 0xFF, 0, 0, 0, 0b10010010, 0x8F, 0 // entry 3: 32-bit code segment .byte 0xFF, 0xFF, 0, 0, 0, 0b10011010, 0xCF, 0 // entry 4: 32-bit data segment .byte 0xFF, 0xFF, 0, 0, 0, 0b10010010, 0xCF, 0 // TODO: 32-bit TSS .set GDT_SIZE, . - GDT GDT_PTR: .word GDT_SIZE - 1 .quad GDT msg_start: .asciz "Netboot via fernlader v2 ...\r\n" msg_a20: .asciz " * Enabling A20 Gate\r\n" msg_prot: .asciz " * Protected Mode\r\n"