9
|
1 ;#!/usr/bin/nasm
|
|
2
|
|
3 ;
|
|
4 ; See http://wiki.osdev.org/User:Stephanvanschaik/Setting_Up_Long_Mode
|
|
5 ; Loader assembly to load the 64 bits kernel just after this file.
|
|
6
|
|
7 ; Assume that we are loaded at 1M (0x100000)
|
|
8 ;org 0x100000 ; this only works with flat bin output, not with elf64 output.
|
|
9
|
|
10 bits 32 ; Start in 32 bits mode.
|
|
11 ; Multiboot header:
|
|
12 ; Settings for multiboot header
|
|
13 PAGE_ALIGN equ 1 << 0
|
|
14 MEM_INFO equ 1 << 1
|
|
15 KLUDGE equ 1 << 16
|
|
16 MAGIC equ 0x1BADB002
|
|
17 FLAGS equ PAGE_ALIGN | MEM_INFO | KLUDGE ; align and provide memory map
|
|
18 CHECKSUM equ -(MAGIC+FLAGS)
|
|
19
|
|
20 ; actual multiboot header:
|
|
21 align 4
|
|
22 MultiBootHeader:
|
|
23 dd MAGIC
|
|
24 dd FLAGS
|
|
25 dd CHECKSUM
|
|
26 ; item below are present if bit 16 is set in flags
|
|
27 dd MultiBootHeader ; physical address in file of header (will be 0x100000 if put at start)
|
|
28 dd 0x100000 ; load_addr: load address, the address to start loading
|
|
29 dd 0x0 ; load_end_addr: zero indicates to load whole file
|
|
30 dd 0x0 ; bss_end_addr: zero indicates no bss segment present
|
|
31 dd loader ; entry_addr: jump to here
|
|
32
|
|
33 ; GDT, three entries: one for code, one for data
|
|
34 GDT64:
|
|
35 .Null: equ $ - GDT64
|
|
36 dw 0
|
|
37 dw 0
|
|
38 db 0
|
|
39 db 0
|
|
40 db 0
|
|
41 db 0
|
|
42 .Code: equ $ - GDT64
|
|
43 dw 0
|
|
44 dw 0
|
|
45 db 0
|
|
46 db 10011000b ; access
|
|
47 db 00100000b ; granularity
|
|
48 db 0
|
|
49 .Data: equ $ - GDT64
|
|
50 dw 0
|
|
51 dw 0
|
|
52 db 0
|
|
53 db 10010000b ; access
|
|
54 db 00000000b ; granularity
|
|
55 db 0
|
|
56 .Pointer: ; GDT pointer
|
|
57 dw $ - GDT64 - 1 ; Limit
|
|
58 dq GDT64 ; Base
|
|
59
|
|
60 ; Start of loader code:
|
|
61 global loader
|
|
62 loader:
|
|
63
|
|
64 ; Prepare paging:
|
|
65 ; PML4T - 0x1000
|
|
66 ; PDPT - 0x2000
|
|
67 ; PDT - 0x3000
|
|
68 ; PT - 0x4000
|
|
69
|
|
70 ; Clear the tables:
|
|
71 mov edi, 0x1000
|
|
72 mov cr3, edi ; CR3 is the page table address!
|
|
73 xor eax, eax
|
|
74 mov ecx, 4096
|
|
75 rep stosd
|
|
76 mov edi, cr3 ; restore edi
|
|
77
|
|
78 mov DWORD [edi], 0x2003 ; present and readwrite, points to first PDPT
|
|
79 add edi, 0x1000
|
|
80 mov DWORD [edi], 0x3003 ; present and readwrite, points to first PDT
|
|
81 add edi, 0x1000
|
|
82 mov DWORD [edi], 0x4003 ; present and readwrite, points to first PT
|
|
83 add edi, 0x1000
|
|
84
|
|
85 ; identity map the first two megabytes:
|
|
86 mov ebx, 0x00000003
|
|
87 mov ecx, 512
|
|
88 ; Fill all PT entries at 0x4000
|
|
89 SetEntry:
|
|
90 mov DWORD [edi], ebx
|
|
91 add ebx, 0x1000
|
|
92 add edi, 8
|
|
93 loop SetEntry
|
|
94
|
|
95 ; Enable paging:
|
|
96 mov eax, cr4
|
|
97 or eax, 1 << 5 ; PAE-bit is bit 5
|
|
98 mov cr4, eax
|
|
99
|
|
100 ; Set LM-bit (Long Mode bit):
|
|
101 mov ecx, 0xC0000080
|
|
102 rdmsr
|
|
103 or eax, 0x100 ; Set bit 8 (LM-bit)
|
|
104 wrmsr
|
|
105
|
|
106 ; Enable paging:
|
|
107 mov eax, cr0
|
|
108 or eax, 0x80000000 ; Set bit 31 (PG-bit)
|
|
109 mov cr0, eax
|
|
110
|
|
111 ; Load the GDT:
|
|
112 lgdt [GDT64.Pointer]
|
|
113
|
|
114 ; Jump to 64 bits kernel:
|
|
115 jmp GDT64.Code:Realm64
|
|
116
|
|
117 bits 64
|
|
118
|
|
119 ; realm64
|
|
120 Realm64:
|
|
121
|
|
122 cli
|
|
123 mov ax, GDT64.Data
|
|
124 mov ds, ax
|
|
125 mov es, ax
|
|
126 mov fs, ax
|
|
127 mov gs, ax
|
|
128
|
|
129 ; Done!
|
|
130
|
|
131 ; Setup stack pointer:
|
|
132 mov rsp, stackEnd
|
|
133 ; Put a B upper left corner
|
|
134 mov al, 66 ; 'B'
|
|
135 mov [0xb8000], al
|
|
136
|
|
137 ; Jump to code that is glued after this file
|
|
138 jmp einde
|
|
139
|
|
140 align 16
|
|
141 dataEnd:
|
|
142 ; reserve bytes for stack:
|
|
143 stackBegin:
|
|
144 resb 1024
|
|
145 stackEnd:
|
|
146
|
|
147 einde:
|
|
148 XCHG BX, BX ; bochs breakpoint
|
|
149
|
|
150 # Call kernel:
|
|
151 extern kmain
|
|
152 call kmain
|
|
153 # Should we ever return, remain in endless loop:
|
|
154 cli
|
|
155 hang:
|
|
156 hlt
|
|
157 jmp hang
|
|
158
|