/* Copyright 2009-2013 Charles Lohr under the MIT/X11 License. This code is a bootloader and switches to flat 4G code, 4G data protected mode. It then calls C code. */ //Useful article: http://thiscouldbebetter.wordpress.com/2011/03/17/entering-protected-mode-from-assembly .code16 .global loader .section .bootsector //Code runs from 0x7c00 .align 4 .org 0x00 bootstart: //Configure the stack mov $0xc00, %sp //Configure the segments xor %ax, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss //First, preserve drive letter. mov %dl, DiskDrive mov $0x4100, %ax mov $0x00, %dl //Same response with 0x80, or the original dl (which is 0) mov $0x55AA, %bx int $0x13 //cli //Just in case we have a dumb bios that set our code segment. ljmp $0x00, $continuestart continuestart: //Setup our real big GDT lgdt (GDT_ptr) cli //XXX Consider disabling the NMI //Enter protected mode mov %cr0, %eax or $0x01, %al mov %eax, %cr0 //Jump to correct data selector, and enter 32-bit mode jmpl $0x08, $later2 later2: .code32 //Setup data selectors mov $0x10, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss //Start reading the disk xor %ebx, %ebx //read count //inc %ebx mov $0x00ff, %ax //start reading sectors. //Read a number of sectors from the hard disk we are booting off of. xor %edx, %edx readloop: push %ax push %ebx //ebx = sector # // xor %ax,%ax // inc %bx mov %bx, DAP_sector xor %ax,%ax mov %ax, ci32ds mov $0x42, %ah mov %ax, ci32ax xor %ah, %ah mov DiskDrive, %al // mov $0x80, %al mov %ax, ci32dx mov $DAP, %ax mov %ax, ci32si mov $0x13, %ax mov %ax, ci32int call CallInterruptFrom32 // mov ci32ax, %al // add $48, %al // out %al, $0xe9 /* //Copy data to correct location. mov $0x7e00, %esi mov $0x1000000, %eax mov */ mov $0x7e00, %esi mov $0x1000000, %eax add %edx, %eax add $0x200, %edx // pop %ebx // push %ebx // shl $9, %ebx // add %ebx, %eax mov %eax, %edi cld mov $0x200, %ecx rep movsb pop %ebx pop %ax inc %ebx dec %ax jnz readloop //This writes some text or something mov $0x3131, %ax mov $0xb8004, %edx movw %ax, (%edx) mov $0x15000000, %esp //Enable the FPU mov %cr0, %eax and $0xfffffff3,%eax mov %eax, %cr0 fninit // mov $48, %al // out %al, $0xe9 cli jmpl $0x08, $dmain // mov $48, %al // out %al, $0xe9 rrrr: jmp rrrr //.ascii "J2MAIN" //.ascii "TEST TEST TEST TEST " //------------------------------------------------------------------------ //Transfer to real mode: //Based roughly off of http://www.rohitab.com/discuss/topic/35103-switch-between-real-mode-and-protected-mode/ //.align 4 .global CallInterruptFrom32 CallInterruptFrom32: .code32: cli pusha /* mov $0x20, %eax //Real mode, 16-bit, data selector (Selector #4) mov %eax, %ds mov %eax, %es mov %eax, %fs mov %eax, %gs mov %eax, %ss */ jmpl $0x18, $IntTCToRM IntTCToRM: .code16 //Now in 16-bit mov %cr0, %eax mov %eax, (savecr0) and $0x7FFFFFFE, %eax mov %eax, %cr0 jmpl $0x00, $enter_realmode16 enter_realmode16: lidt idt_real //Now in real mode land. pusha mov $0x0000, %ax mov %ax, %ss mov %ax, %ds mov ci32bx, %bx mov ci32cx, %cx mov ci32dx, %dx mov ci32bp, %bp mov ci32di, %di mov ci32si, %si mov ci32gs, %gs mov ci32fs, %fs mov ci32es, %es mov ci32ds, %ds mov ci32ax, %ax sti .byte 0xcd .global ci32int ci32int: .byte 0x00 nop cli mov %ax, ci32ax mov %bx, ci32bx mov %cx, ci32cx mov %dx, ci32dx mov %bp, ci32bp mov %di, ci32di mov %si, ci32si mov %gs, ci32gs mov %fs, ci32fs mov %es, ci32es mov %ds, ci32ds popa //Now, how do we get out of this mess? mov %cr0, %eax or $1, %eax mov %eax, %cr0 jmpl $0x08, $enter_protmode32 .code32 enter_protmode32: /* //Setup data selectors mov $0x10, %ax mov %ax, %ds mov %ax, %es mov %ax, %fs mov %ax, %gs mov %ax, %ss */ popa cli ret //Disk DAP for reading from floppy. .global DAP, DAP_nr_read, DAP_seg, DAP_ofs, DAP_sector .align 4 DAP: .byte 0x10 //dap size .byte 0x00 //unused DAP_nr_read: .word 0x0001 DAP_ofs: .word 0x7e00 DAP_seg: .word 0x0000 DAP_sector: .long 0x00000001 .long 0x00000000 //GDT, Flat 4GiB //http://wiki.osdev.org/GDT_Tutorial GDT: .long 0x00000000 .long 0x00000000 //Descriptor (0x9a, RW, Execute) (Code32) .long 0x0000ffff .long 0x00CF9800 //Descriptor (0x92, RW) (Data32) .long 0x0000ffff .long 0x00cf9200 //Code16 .long 0x0000ffff .long 0x000f9a00 //Data16 .long 0x0000ffff .long 0x000f9200 GDT_end: .align 8 GDT_ptr: .word GDT_end - GDT - 1// For limit storage .long GDT // For base storage //Disk Signature .org 0x1b8 .long 0xefcdab89 .short 0x0000 //Disk entry 1. .byte 0x80 //Active partition 1 (and bootable) .byte 0x00 .byte 0x02 //CHS address .byte 0x00 .byte 0x56 //Partition type .byte 0x03 .byte 0x0b //CHS adderss of last sector .byte 0x00 .long 0x02 .long 1438 //Number of sectors in partition. //Area for setting variables to call the interrupt //We are putting this here since the values must be all zeroes anyway. //In fact, we can put anything that's all zeroes on boot here. .global CI32Params, ci32ax, ci32bx, ci32cx, ci32dx, ci32ss .global ci32sp, ci32bp, ci32di, ci32si, ci32gs, ci32fs, ci32es, ci32ds .global DiskDriveAndHead CI32Params: ci32ax: .word 0x0000 ci32bx: .word 0x0000 ci32cx: .word 0x0000 ci32dx: .word 0x0000 ci32bp: .word 0x0000 ci32di: .word 0x0000 ci32si: .word 0x0000 ci32gs: .word 0x0000 ci32fs: .word 0x0000 ci32es: .word 0x0000 ci32ds: .word 0x0000 DiskDrive: .byte 0x00 //Re-written at boot to be correct value. .align 4 idt_real: .word 0x3ff .long 0x00000000 idt_prot: .word 0x0000 .long 0x00000000 savecr0: .long 0x00000000 //Still around 14 bytes left here. //MBR Signature .org 0x1fe .byte 0x55 .byte 0xaa /* .section ".endprog", "ax" .extern end_of_kernel end_of_kernel: // leave // ret */ /* //Enable a20 // mov $0x2401, %ax // int $0x15 inb $0x92, %al or $2, %al outb %al, $0x92 in $0x92, %al test $2, %al jnz after or $2, %al and $0xFE, %al out %al, $0x92 after: //Verify a20 was set. // mov %ah, %al mov $0x0e, %ah add $0x30, %al mov $0x00, %ebx int $0x10 */