.section .multiboot /* * Define constants for the multiboot header. See Multiboot 2 Specifications for details. */ .set align, 1<<0 .set meminfo, 1<<1 .set magic, 0xE85250D6 .set arch, 0 .set headerLength, _multibootHeaderEnd - _multibootHeaderStart .set checksum, -(magic + arch + headerLength) .set tagNotOptional, 0 .set tagInfoRequestType, 1 .set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart .set requestBootCommand, 1 .set requestBootLoaderName, 2 .set requestBootModules, 3 .set requestMemoryInfo, 4 .set requestBootDevice, 5 .set requestMemoryMap, 6 .set tagAddressType, 2 .set tagAddressSize, 24 .set tagAddressHeaderLocation, LOAD_START .set tagAddressLoadStart, LOAD_START .set tagAddressLoadEnd, LOAD_END .set tagAddressBSSEnd, BSS_END .set tagEntryType, 3 .set tagEntrySize, 12 .set tagEntryAddress, _start - (0xFF900000 - 0x100000) .set tagModuleAlignType, 6 .set tagModuleAlignSize, 8 /* * Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header. */ .align 8 _multibootHeaderStart: .long magic .long arch .long headerLength .long checksum .align 8 _multibootInfoTagStart: .short tagInfoRequestType .short tagNotOptional .long tagInfoRequestSize .long requestBootCommand .long requestBootLoaderName .long requestBootModules .long requestMemoryInfo .long requestBootDevice .long requestMemoryMap _multibootInfoTagEnd: .align 8 .short tagAddressType .short tagNotOptional .long tagAddressSize .long tagAddressHeaderLocation .long tagAddressLoadStart .long tagAddressLoadEnd .long tagAddressBSSEnd .align 8 .short tagEntryType .short tagNotOptional .long tagEntrySize .long tagEntryAddress .align 8 .short tagModuleAlignType .short tagNotOptional .long tagModuleAlignSize .align 8 /* * Terminate list of multiboot header tags. * Ending tag has type = 0, flags = 0, size = 8 */ .long 0 .long 8 _multibootHeaderEnd: .section .rodata gdt: .long 0, 0 .short 0xFFFF .short 0x0000 .short 0x9A00 .short 0x00CF .short 0xFFFF .short 0x0000 .short 0x9200 .short 0x00CF gdt_info: .short 23 .long gdt .section .bss .align 16 stackBottom: .skip 8192 stackTop: .align 4096 _tempPgDir: .skip 4096 _tempIdentityMap: .skip 4096 _tempPgTable: .skip 8192 _bootCmdLine: .skip 64 .align 64 .global system_info system_info: .skip 16 .align 64 .global memory_map memory_map: .skip 16 * 16 .section .text .global _start .type _start, @function _start: cmp $0x36d76289, %eax jne _err movb $64, 0xB8000 mov $system_info, %edi sub $BASE_DIFF, %edi add $8, %ebx switch: mov (%ebx), %eax cmp $0, %eax je s_end cmp $1, %eax je tag_1 cmp $3, %eax je tag_3 cmp $4, %eax je tag_4 cmp $6, %eax je tag_6 cmp $21, %eax je tag_21 jmp def # Boot command line tag_1: mov 4(%ebx), %ecx sub $8, %ecx mov %ebx, %esi add $8, %esi mov $_bootCmdLine, %edi sub $BASE_DIFF, %edi rep movsb mov $system_info, %edi sub $BASE_DIFF, %edi jmp def tag_3: mov 8(%ebx), %esi mov (%esi), %eax mov %al, (0xB8004) mov %ah, (0xB8006) shr $16, %eax mov %al, (0xB8008) mov %ah, (0xB800a) jmp def # Basic memory info tag_4: mov 8(%ebx), %eax mov %eax, (%edi) mov 12(%ebx), %eax mov %eax, 4(%edi) jmp def # Memory map tag_6: mov $memory_map, %esi sub $BASE_DIFF, %esi # set esi to point to the table in the kernel image mov 4(%ebx), %ecx sub $16, %ecx # set ecx to store the size of the table provided by the bootloader mov 8(%ebx), %edx # set edx to store the size of each table entry add $16, %ebx # move ebx up to the first entry 1: mov (%ebx), %eax mov %eax, (%esi) # save the address of that region in memory mov 8(%ebx), %eax mov %eax, 4(%esi) # save the size of that region in memory mov 16(%ebx), %eax mov %eax, 8(%esi) # save the type of memory in that region add $12, %esi # move esi to the next entry in the kernel's array add %edx, %ebx # move ebx to the next entry in the bootloader's array sub %edx, %ecx # subtract the size of an entry from ecx. jnz 1b # loop if there are entries left mov $0, %eax mov %eax, (%esi) mov %eax, 4(%esi) mov %eax, 8(%esi) jmp switch # Program image location tag_21: mov 8(%ebx), %eax mov %eax, 8(%edi) jmp def def: mov 4(%ebx), %eax add $7, %eax and $0xFFFFFFF8, %eax add %eax, %ebx jmp switch s_end: movb $64, 0xB8002 mov $0, %ecx 1: # Generate a page table entry pointing to a page in the kernel binary mov %ecx, %eax mov $4096, %edx mul %edx or $3, %eax # Load the address of the temporary page table and translate it to a physical address mov $_tempPgTable, %edi sub $BASE_DIFF, %edi # Save the PTE into an entry in the temporary page table mov %eax, (%edi, %ecx, 4) # Load the address of the identity map and translate it to a physical address mov $_tempIdentityMap, %edi sub $BASE_DIFF, %edi # Save the PTE into an entry in the identity map mov %eax, (%edi, %ecx, 4) # Increment count and loop inc %ecx mov $IMAGE_SIZE, %edx add $256, %edx cmp %edx, %ecx jne 1b # Load the physical address of the identity map, and generate a PDE mov $_tempIdentityMap, %eax sub $BASE_DIFF, %eax or $3, %eax # Load the physical address of the page directory mov $_tempPgDir, %edi sub $BASE_DIFF, %edi # Save the PDE to the first element in the page directory mov %eax, (%edi) # Load the physical address of the temporary page table, and generate a PDE mov $_tempPgTable, %eax sub $BASE_DIFF, %eax or $3, %eax # Save the PDE to the entry corresponding to 0xC0000000 mov %eax, 4088(%edi) # Set the last entry in the page directory to point to the page directory itself mov %edi, %eax or $3, %eax mov %eax, 4092(%edi) # Load the physical address of the page directory into CR3 mov $_tempPgDir, %edi sub $BASE_DIFF, %edi mov %edi, %cr3 # Enable paging mov %cr0, %eax or $0x80010000, %eax mov %eax, %cr0 # Jump into mapped kernel binary lea 2f, %eax jmp *%eax 2: # Delete PDE corresponding to identity map. We shouldn't need it anymore. movl $0, (_tempIdentityMap) # Reload page tables mov %cr3, %eax mov %eax, %cr3 # Initialize stack mov $stackTop, %esp lgdt gdt_info jmp $8, $.ldcs .ldcs: mov $16, %ax mov %ax, %ds mov %ax, %es mov %ax, %gs mov %ax, %fs mov %ax, %ss mov $_bootCmdLine, %eax push %eax # Call main function call main _err: cli 3: hlt jmp 3b .size _start, . - _start