diff cos/kernel/goto64.asm @ 20:b1fed2171e1a

Now working with 2 MB pages
author windel
date Mon, 28 Nov 2011 20:54:40 +0100
parents 6129643f5c34
children 5dd47d6eebac
line wrap: on
line diff
--- a/cos/kernel/goto64.asm	Sun Nov 27 21:38:38 2011 +0100
+++ b/cos/kernel/goto64.asm	Mon Nov 28 20:54:40 2011 +0100
@@ -5,9 +5,20 @@
 ; Loader assembly to load the 64 bits kernel just after this file.
 
 ; Assume that we are loaded at 1M (0x100000)
-;org 0x100000 ; this only works with flat bin output, not with elf64 output.
+
+; This file sets up long mode and creates paging tables.
+; Use 2 mbyte pages. Is this more efficient?
 
-bits 32 ; Start in 32 bits mode.
+; Intended memory map (copied from pure64), at the end of this file:
+; 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 - 0xA000 : Stack
+
+bits 32 ; Start in 32 bits mode, as loaded by GRUB
+
 ; Multiboot header:
 ; Settings for multiboot header
 PAGE_ALIGN equ 1 << 0
@@ -30,30 +41,54 @@
 dd 0x0             ; 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
-GDT64:
-.Null: equ $ - GDT64
+align 16
+gdt64:
+.Null: equ $ - gdt64
 dq 0
-.Code: equ $ - GDT64
+.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
+.Data: equ $ - gdt64
 dw 0
 dw 0
 db 0
 db 10010000b ; access ; 0x90
 db 00000000b ; granularity 0x00
 db 0
-.Pointer: ; GDT pointer
-dw $ - GDT64 - 1 ; Limit
-dq GDT64 ; Base
+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
 
 ; Start of loader code:
-global loader
 loader:
 
 ; Check that the CPU supports long mode:
@@ -65,51 +100,72 @@
 cpuid
 bt edx, 29
 jnc no_long_mode
-jmp long_mode
+jmp cpu_has_long_mode
 
 no_long_mode:
 hlt
 
-long_mode:
+cpu_has_long_mode:
 
-; Prepare paging:
-; PML4T - 0x1000
-; PDPT - 0x2000
-; PDT - 0x3000
-; PT - 0x4000
+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:
 
-; Clear the tables:
+cld   ; clear direction?
+
+; Clear the paging tables 0x1000, 0x2000, 0x3000 and 0x4000:
 mov edi, 0x1000
-mov cr3, edi ; CR3 is the page table address!
 xor eax, eax
 mov ecx, 4096
 rep stosd
-mov edi, cr3 ; restore edi
 
-mov DWORD [edi], 0x2003 ; present and readwrite, points to first PDPT
-add edi, 0x1000
-mov DWORD [edi], 0x3003 ; present and readwrite, points to first PDT
-add edi, 0x1000
-mov DWORD [edi], 0x4003 ; present and readwrite, points to first PT
-add edi, 0x1000
+; 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
 
-; identity map the first two megabytes:
-mov ebx, 0x00000003
-mov ecx, 512
-; Fill all PT entries at 0x4000
-SetEntry:
-mov DWORD [edi], ebx
-add ebx, 0x1000
-add edi, 8
-loop SetEntry
+; 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
 
-; Enable paging:
+; 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
 
 ; Load the GDT:
-lgdt [GDT64.Pointer]
+lgdt [gdt64pointer]
 
 ; Set LM-bit (Long Mode bit):
 mov ecx, 0xC0000080
@@ -122,13 +178,12 @@
 or eax, 0x80000000 ; Set bit 31 (PG-bit)
 mov cr0, eax
 
-
 ; Jump to 64 bits kernel:
-jmp GDT64.Code:Realm64
+jmp gdt64.Code:Realm64
 
 bits 64
+align 16
 
-; realm64
 Realm64:
 
 ; Clear segment registers:
@@ -139,33 +194,15 @@
 mov fs, ax
 mov gs, ax
 
-; Reoad the GDT:
-lgdt [GDT64.Pointer]
-
-; Done!
-
-; Setup stack pointer:
-mov rsp, stackEnd
-; Put a B upper left corner
-mov al, 66 ; 'B'
-mov [0xb8000], al
+lgdt [gdt64pointer]    ; Reload GDT in 64 bits mode
 
-; Jump to code that is glued after this file
-jmp einde
+mov rsp, 0xA000      ; Setup stack pointer.
 
-align 16
-dataEnd:
-; reserve bytes for stack:
-stackBegin:
-resb 1024
-stackEnd:
-
-einde:
 # XCHG BX, BX ; bochs breakpoint
 
-# Call kernel:
 extern kmain
-call kmain
+call kmain              ; Call kernel in C-code
+
 # Should we ever return, remain in endless loop:
 cli
 hang: