Mercurial > lcfOS
view cos/kernel/goto64.asm @ 219:1fa3e0050b49
Expanded ad hoc code generator
author | Windel Bouwman |
---|---|
date | Sat, 06 Jul 2013 12:38:09 +0200 |
parents | bcb3b68c8147 |
children |
line wrap: on
line source
;#!/usr/bin/nasm ; ; See http://wiki.osdev.org/User:Stephanvanschaik/Setting_Up_Long_Mode ; Loader assembly to load the 64 bits kernel just after this file. ; Assume that we are loaded at 1M (0x100000) ; This file sets up long mode and creates paging tables. ; Use 2 mbyte pages. Is this more efficient? ; Intended memory map (copied from pure64), at the end of this file: ; MOVED TO 0x5000!! 0x0 : IDT, 256 entries ; 0x1000 - 0x2000 : PML4 (Page map level 4) ; 0x2000 - 0x3000 : PDPT (page directory pointer table) ; 0x3000 - 0x4000 : PDT (page directory table) ; 0x4000 - 0x5000 : PT (page table) ; 0x5000 - 0x6000 : IDT entries ; 0x6000 - 0xA000 : Stack bits 32 ; Start in 32 bits mode, as loaded by GRUB ; Multiboot header: ; Settings for multiboot header PAGE_ALIGN equ 1 << 0 MEM_INFO equ 1 << 1 KLUDGE equ 1 << 16 MAGIC equ 0x1BADB002 FLAGS equ PAGE_ALIGN | MEM_INFO | KLUDGE ; align and provide memory map CHECKSUM equ -(MAGIC+FLAGS) ; actual multiboot header: align 4 MultiBootHeader: dd MAGIC dd FLAGS dd CHECKSUM ; item below are present if bit 16 is set in flags extern load_end_address ; Import load end address from linker script extern bss_end_address ; Import bss end address to make sure data is zero initialized. dd MultiBootHeader ; physical address in file of header (will be 0x100000 if put at start) dd 0x100000 ; load_addr: load address, the address to start loading dd load_end_address ; load_end_addr: zero indicates to load whole file dd bss_end_address ; bss_end_addr: zero indicates no bss segment present dd loader ; entry_addr: jump to here ; 32 bits temporary GDT: align 16 gdt32: dw 0x0000, 0x0000, 0x0000, 0x0000 ; Null desciptor dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 32-bit code desciptor dw 0xFFFF, 0x0000, 0x9200, 0x008F ; 32-bit data desciptor gdt32_end: ; 32 bits gdt pointer: align 16 gdt32pointer: ; Global Descriptors Table Register dw gdt32_end - gdt32 - 1 ; limit of GDT (size minus one) dq gdt32 ; linear address of GDT ; GDT, three entries: one for code, one for data align 16 gdt64: .Null: equ $ - gdt64 dq 0 .Code: equ $ - gdt64 dw 0 ; Segment limit 15-0 dw 0 ; Base 15 - 0 db 0 ; Base 23 - 16 db 10011000b ; access 0x98 (P=1 => Present) db 00100000b ; granularity 0x20 (L=1 => long mode) db 0 .Data: equ $ - gdt64 dw 0 dw 0 db 0 db 10010000b ; access ; 0x90 db 00000000b ; granularity 0x00 db 0 gdt64end: ;SYS64_NULL_SEL equ $-gdt64 ; Null Segment ; dq 0x0000000000000000 ; SYS64_CODE_SEL equ $-gdt64 ; Code segment, read/execute, nonconforming ; dq 0x0020980000000000 ; 0x00209A0000000000 ; SYS64_DATA_SEL equ $-gdt64 ; Data segment, read/write, expand down ; dq 0x0000900000000000 ; 0x0020920000000000 ; gdt64_end: gdt64pointer: ; GDT pointer dw gdt64end - gdt64 - 1 ; Limit (size) dq gdt64 ; Base hltmessage: db "Long mode not supported", 0x0 ; Start of loader code: loader: ; here ebx contains the pointer to the multiboot header, store is for later use. ; Make sure that multiboot_info is located in the BSS section and that this section ; is proper zeroed. extern multiboot_info mov [multiboot_info], ebx ; Check that the CPU supports long mode: mov eax, 80000000h cpuid cmp eax, 80000000h jbe no_long_mode mov eax, 80000001h cpuid bt edx, 29 jnc no_long_mode jmp cpu_has_long_mode no_long_mode: ; Print long mode not supported mov edi, 0xb8000 mov esi, hltmessage xor eax, eax loop1: lodsb mov dl, al stosb mov al, 0x1f stosb cmp dl, 0 jne loop1 hlt cpu_has_long_mode: lgdt [gdt32pointer] ; Reload a valid temporary 32 bits GDT, overload GRUB gdt. mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax jmp 8:start32 ; make sure CS is loaded. start32: cld ; clear direction? ; Clear the paging tables 0x1000, 0x2000, 0x3000 and 0x4000: mov edi, 0x1000 xor eax, eax mov ecx, 0x1000 rep stosd ; Create PML4 table: mov edi, 0x1000 mov eax, 0x2003 stosd ; Create PDP (page directory pointer) table: mov edi, 0x2000 mov eax, 0x3003 ; PDPT entry, present and read/write stosd ; Create PD (page directory) table mov edi, 0x3000 ; First entry: mov eax, 0x8F ; PD entry, present (bit 0), read write (bit 1) and bit 7, page size=2MB stosd xor eax, eax stosd ; Second entry: mov eax, 0x20008f stosd xor eax, eax stosd ; Third entry: mov eax, 0x40008f stosd xor eax, eax stosd ; 6 MB mapped in total now. mov edi, 0x1000 ; Set load address mov cr3, edi ; CR3 is the PML4 base address! ; Enable address extension: mov eax, cr4 or eax, 1 << 5 ; PAE-bit is bit 5 mov cr4, eax lgdt [gdt64pointer] ; Load the GDT ; Set LM-bit (Long Mode bit): mov ecx, 0xC0000080 rdmsr or eax, 0x100 ; Set bit 8 (LM-bit) wrmsr ; Enable paging: mov eax, cr0 or eax, 0x80000000 ; Set bit 31 (PG-bit) mov cr0, eax ; Jump to 64 bits kernel: jmp gdt64.Code:Realm64 bits 64 align 16 Realm64: ; Clear segment registers: xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax lgdt [gdt64pointer] ; Reload GDT in 64 bits mode ; Test: mov ax, 0x10 mov ds, ax ; End of test ; TODO: determine a good place for the kernel stack. mov rsp, 0xA000 ; Setup stack pointer. extern kmain call kmain ; Call kernel in C-code