[TASKMGR] Process page: Allow using "Open File Location" functionality without runnin...
[reactos.git] / boot / freeldr / freeldr / arch / realmode / amd64.S
1
2 #include <asm.inc>
3 #include "../../include/arch/pc/x86common.h"
4
5 #define IMAGE_DOS_HEADER_e_lfanew 60
6 #define IMAGE_FILE_HEADER_SIZE 20
7 #define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16
8
9 .code16
10
11 /* FAT helper code */
12 #include "fathelp.inc"
13
14 .org 512
15 Startup:
16
17 cli
18
19 /* Setup real mode segment registers */
20 xor ax, ax
21 mov ds, ax
22 mov es, ax
23 mov fs, ax
24 mov gs, ax
25 mov ss, ax
26
27 /* Save the boot drive and partition */
28 mov byte ptr ds:[BSS_BootDrive], dl
29 mov byte ptr ds:[BSS_BootPartition], dh
30
31 /* Setup a real mode stack */
32 mov sp, word ptr ds:[stack16]
33
34 /* Output first status */
35 mov si, offset Msg_Starting
36 call writestr
37
38 /* Enable A20 address line */
39 call EnableA20
40
41 /* Check the CPU */
42 call CheckFor64BitSupport
43 test al, al
44 jnz .LongModeSupported
45
46 /* Output failure message */
47 mov si, offset Msg_Unsupported
48 call writestr
49
50 /* Wait for a keypress */
51 int HEX(16)
52 jmp Reboot
53
54 Msg_Unsupported:
55 .ascii "This CPU is not supported.", CR, LF
56 .ascii "Press any key to reboot...", NUL
57
58 Msg_Starting:
59 .ascii "Starting FreeLoader...", CR, LF, NUL
60
61 Msg_LongModeSupported:
62 .ascii "Long mode support detected.", CR, LF, NUL
63
64 .LongModeSupported:
65 /* Output status */
66 mov si, offset Msg_LongModeSupported
67 call writestr
68
69 /* Load the GDT */
70 #ifdef _USE_ML
71 lgdt fword ptr [gdtptr]
72 #else
73 lgdt cs:[gdtptr]
74 #endif
75
76 /* Build the startup page tables */
77 call BuildPageTables
78
79 /* Store real mode entry point in shared memory */
80 mov dword ptr ds:[BSS_RealModeEntry], offset RealModeEntryPoint
81
82 /* Address the image with es segment */
83 mov ax, FREELDR_PE_BASE / 16
84 mov es, ax
85
86 /* Get address of optional header */
87 mov eax, dword ptr es:[IMAGE_DOS_HEADER_e_lfanew]
88 add eax, 4 + IMAGE_FILE_HEADER_SIZE
89
90 /* Get address of entry point */
91 mov eax, dword ptr es:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint]
92 add eax, FREELDR_PE_BASE
93
94 /* Save entry point */
95 mov dword ptr ds:[LongModeEntryPoint], eax
96
97 /* Restore es */
98 xor ax, ax
99 mov es, ax
100
101 /* Output status */
102 mov si, offset Msg_SwitchToLongMode
103 call writestr
104
105 jmp ExitToLongMode
106
107 Msg_SwitchToLongMode:
108 .ascii "Switching to long mode....", CR, LF, NUL
109
110 .align 8
111 gdt:
112 .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 00: NULL descriptor */
113 .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 08: */
114 .word HEX(0000), HEX(0000), HEX(9800), HEX(0020) /* 10: long mode CS */
115 .word HEX(FFFF), HEX(0000), HEX(F300), HEX(00CF) /* 18: long mode DS */
116 .word HEX(FFFF), HEX(0000), HEX(9E00), HEX(0000) /* 20: 16-bit real mode CS */
117 .word HEX(FFFF), HEX(0000), HEX(9200), HEX(0000) /* 28: 16-bit real mode DS */
118 .word HEX(FFFF), HEX(0000), HEX(9B00), HEX(00CF) /* 30: compat mode CS */
119
120 /* GDT table pointer */
121 gdtptr:
122 .word HEX(37) /* Limit */
123 #ifdef _USE_ML
124 .long offset gdt /* Base Address */
125 #else
126 .long gdt /* Base Address */
127 #endif
128
129
130 CheckFor64BitSupport:
131 /* Check whether the CPU supports CPUID */
132 pushad
133 pushfd
134 pop eax
135 mov ebx, eax
136 xor eax, HEX(00200000)
137 push eax
138 popfd
139 pushfd
140 pop eax
141 cmp eax, ebx
142 jnz .CheckForPAE
143
144 mov si, offset .Msg_NoCpuidSupport
145 call writestr
146 popad
147 xor al, al
148 ret
149
150 .Msg_NoCpuidSupport:
151 .ascii "The system doesn't support CPUID.", CR, LF, NUL
152
153 .CheckForPAE:
154 /* CPUID support detected - getting the PAE/PGE */
155 mov eax, 1 // Fn0000_0001 - PAE in EDX[6]
156 cpuid
157 and edx, HEX(00A0)
158 cmp edx, HEX(00A0)
159 je .CheckForLongMode
160
161 mov si, offset .Msg_NoPAE
162 call writestr
163 popad
164 xor al, al
165 ret
166
167 .Msg_NoPAE:
168 .ascii "PAE or PGE not set.", CR, LF, NUL
169
170 .CheckForLongMode:
171 /* Check whether extended functions are supported */
172 mov eax, HEX(80000000)
173 cpuid
174 cmp eax, HEX(80000000) // Any function > 0x80000000 ?
175 jbe .NoLongMode // If not, no long mode.
176 /* Check whether the CPU supports Long Mode */
177 xor edx, edx
178 mov eax, HEX(80000001)
179 cpuid
180 and edx, HEX(20000000)
181 test edx, edx
182 jnz .Success
183
184 .NoLongMode:
185 mov si, offset .Msg_NoLongMode
186 call writestr
187 popad
188 xor al, al
189 ret
190
191 .Msg_NoLongMode:
192 .ascii "Long mode is not supported.", CR, LF, NUL
193
194 .Success:
195 popad
196 xor al, al
197 inc al
198 ret
199
200
201 BuildPageTables:
202 pusha
203 push es
204
205 /* Get segment of the PML4 */
206 mov eax, PML4_ADDRESS / 16
207 mov es, ax
208 cld
209 xor di, di
210
211 /* One entry in the PML4 pointing to PDP */
212 mov eax, PDP_ADDRESS
213 or eax, HEX(0F)
214 stosd
215
216 /* clear rest */
217 xor eax, eax
218 mov cx, 1023
219 rep stosd
220
221 /* One entry in the PDP pointing to PD */
222 mov eax, PD_ADDRESS
223 or eax, HEX(0F)
224 stosd
225
226 /* clear rest */
227 xor eax, eax
228 mov ecx, 1023
229 rep stosd
230
231 /* 512 entries in the PD, each defining a 2MB page each */
232 mov ecx, 512
233 mov eax, HEX(008f)
234
235 .Bpt2:
236 mov es:[di], eax
237 mov dword ptr es:[di + 4], 0
238 add eax, 512 * 4096 // add 512 4k pages
239 add di, 8
240
241 /* Loop all PDEs */
242 dec cx
243 jnz .Bpt2
244
245 /* Return */
246 pop es
247 popa
248 ret
249
250
251 /******************************************************************************/
252
253 #define MSR_EFER HEX(C0000080)
254 #define LMODE_CS HEX(10)
255
256 /* This is the entry point from long mode */
257 RealModeEntryPoint:
258
259 /* Disable long mode */
260 mov ecx, MSR_EFER
261 rdmsr
262 and eax, HEX(0FFFFFEFF) // ~0100
263 wrmsr
264
265 /* Mask PAE and PGE out */
266 mov eax, cr4
267 and eax, HEX(0FFFFFF5F) // ~00A0
268 mov cr4, eax
269
270 /* Disable Protected Mode */
271 mov eax, cr0
272 and eax, HEX(0FFFFFFFE) // ~0x00000001
273 mov cr0, eax
274
275 /* Clear prefetch queue & correct CS */
276 ljmp16 0, InRealMode
277
278 InRealMode:
279
280 // mov ax, HEX(0b800)
281 // mov es, ax
282 // mov word ptr es:[12], HEX(0e00) + '6'
283
284 /* Set real mode segments */
285 xor ax, ax
286 mov ds, ax
287 mov es, ax
288 mov fs, ax
289 mov gs, ax
290 mov ss, ax
291
292 /* Clear out the high 16-bits of ESP */
293 /* This is needed because I have one */
294 /* machine that hangs when booted to dos if */
295 /* anything other than 0x0000 is in the high */
296 /* 16-bits of ESP. Even though real-mode */
297 /* code should only use SP and not ESP. */
298 xor esp, esp
299
300 /* Restore real mode stack */
301 mov sp, word ptr ds:[stack16]
302
303 // sti /* These are ok now */
304
305 /* Do the callback, specified by bx */
306 shl bx, 1
307 call word ptr ds:CallbackTable[bx]
308
309 ExitToLongMode:
310 /* Disable interrupts */
311 cli
312
313 /* Set correct segment registers */
314 xor ax,ax
315 mov ds,ax
316 mov es,ax
317 mov fs,ax
318 mov gs,ax
319 mov ss,ax
320
321 /* Save current stack pointer */
322 mov word ptr ds:[stack16], sp
323
324 /* Set PAE and PGE: 10100000b */
325 mov eax, cr4
326 or eax, HEX(00A0)
327 mov cr4, eax
328
329 /* Point cr3 at the PML4 */
330 mov eax, PML4_ADDRESS
331 mov cr3, eax
332
333 /* Enable long mode */
334 mov ecx, MSR_EFER
335 rdmsr
336 or eax, HEX(00000100)
337 wrmsr
338
339 /* Activate long mode by enabling paging and protection simultaneously,
340 skipping protected mode entirely */
341 mov eax, cr0
342 or eax, HEX(80000001)
343 mov cr0, eax
344
345 /* Clear prefetch queue & correct CS */
346 ljmp16 LMODE_CS, InLongMode
347 InLongMode:
348 //DB 66h, 0B8h, 18h, 00h // mov ax, LMODE_DS
349 //DB 66h, 8Eh, 0D8h // mov ds, ax
350 //DB 66h, 66h, 0C7h, 04h, 25h, 00h, 80h, 0Bh, 00h, 31h, 0Eh
351 //mov word ptr [HEX(b8000)], HEX(0e00) + '1'
352
353 .byte HEX(0FF), HEX(25) // opcode of 64bit indirect jump
354 .long 1 // relative address of LongModeEntryPoint
355 nop
356 LongModeEntryPoint:
357 .long 0, 0
358
359 int HEX(16)
360 jmp Reboot
361
362 /* FNID_* functions */
363 CallbackTable:
364 .word Int386
365 .word Reboot
366 .word Relocator16Boot
367 .word PxeCallApi
368 .word PnpBiosGetDeviceNodeCount
369 .word PnpBiosGetDeviceNode
370 .word PnpBiosGetDockStationInformation
371
372 /* 16-bit stack pointer */
373 stack16:
374 .word STACK16ADDR
375
376
377 #include "int386.inc"
378 #include "helpers.inc"
379 #include "pxe.inc"
380 #include "pnp.inc"
381
382 .org (FREELDR_PE_BASE - FREELDR_BASE - 1)
383 .byte 0
384 .endcode16
385
386 END