[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / arch / amd64 / arch.S
1 .intel_syntax noprefix
2 .text
3 .code16
4
5 #define ASM
6 #include <arch.h>
7
8 //.org 0x8000
9
10 .global RealEntryPoint
11 RealEntryPoint:
12
13 cli
14
15 /* Setup real mode segment registers */
16 xor ax, ax
17 mov ds, ax
18 mov es, ax
19 mov fs, ax
20 mov gs, ax
21 mov ss, ax
22
23 /* checkPoint Charlie - where it all began... */
24 mov si, offset CheckPoint0
25 call writestr
26
27 /* Setup a real mode stack */
28 mov sp, stack16
29
30 /* Zero BootDrive and BootPartition */
31 xor eax, eax
32 mov BootDrive, eax
33 mov BootPartition, eax
34
35 /* Store the boot drive */
36 mov BootDrive, dl
37
38 /* Store the boot partition */
39 mov BootPartition, dh
40
41 /* Load the GDT */
42 lgdt gdtptr
43 /* Load the IDT */
44 // lidt idtptr
45
46 call x86_16_EnableA20
47
48 /* checkPoint Charlie - where it all began... */
49 mov si, offset CheckPoint1
50 call writestr
51
52 call x86_16_BuildPageTables
53
54 /* checkPoint Charlie - where it all began... */
55 mov si, offset CheckPoint2
56 call writestr
57
58 /* Check if CPU supports CPUID */
59
60 pushfd
61 pop eax
62 mov ebx, eax
63 xor eax, 0x00200000
64 push eax
65 popfd
66 pushfd
67 pop eax
68 cmp eax,ebx
69 jz NO_CPUID_SUPPORT_DETECTED
70
71 /* CPUID support detected - getting the PAE/PGE */
72
73 mov eax,1 // Fn0000_0001 - PAE in EDX[6]
74 cpuid
75 xor eax,eax
76 and edx,0x00a0
77 test edx,edx // are PAE and PGE bits set?
78 jz NO_X64_SUPPORT_DETECTED
79
80 /* PAE and PGE are here */
81
82 xor edx, edx
83 mov eax, 0x80000001
84 cpuid
85 and edx, 0x20000000
86 test edx,edx
87 jz NO_X64_SUPPORT_DETECTED
88
89 /* X64 Processor */
90
91 /* checkPoint Charlie - where it all began... */
92 mov si, offset CheckPoint3
93 call writestr
94
95 jmp switch64
96
97 NO_X64_SUPPORT_DETECTED:
98 mov si, offset NotAnX64Processor // Loading message
99 call writestr
100 jmp fail
101
102 NO_CPUID_SUPPORT_DETECTED:
103 mov si, offset NoCPUIDSupport // Loading message
104 call writestr
105
106 fail:
107 jmp fail
108 nop
109 nop
110
111 switch64:
112 call x86_16_SwitchToLong
113
114 .code64
115
116 // mov ax, LMODE_DS
117 // mov ds, ax
118 // mov word ptr ds:[0xb8000], 0x0e00 + '1'
119
120 /* GO! */
121 xor rcx, rcx
122 call BootMain
123
124 /* Checkpoint */
125 // mov ax, LMODE_DS
126 // mov ds, ax
127 // mov word ptr ds:[0xb8002], 0x0e02 + '2'
128
129
130 /* Return into real mode */
131 call x86_64_SwitchToReal
132 .code16
133
134 // int 0x19
135
136 /* We should never get here */
137 stop:
138 jmp stop
139 nop
140 nop
141
142
143 /** 16 Bit helper functions ***************************************************/
144 .code16
145
146 x86_16_Empty8042:
147 .word 0x00eb,0x00eb // jmp $+2, jmp $+2
148 in al, 0x64
149 cmp al, 0xff // legacy-free machine without keyboard
150 jz empty_8042_ret // controllers on Intel Macs read back 0xFF
151 test al, 0x02
152 jnz x86_16_Empty8042
153 empty_8042_ret:
154 ret
155
156 x86_16_EnableA20:
157 pusha
158 call x86_16_Empty8042
159 mov al, 0xD1 // command write
160 out 0x64, al
161 call x86_16_Empty8042
162 mov al, 0xDF // A20 on
163 out 0x60, al
164 call x86_16_Empty8042
165 popa
166 ret
167
168 /*
169 * We define 512 2MB pages at the start of memory, so we can access the first
170 * 1 GB as if paging was disabled
171 */
172 x86_16_BuildPageTables:
173 pusha
174 push es
175
176 /* Get segment of pml4 */
177 mov eax, offset pml4_startup
178 shr eax, 4
179 mov es, ax
180 cld
181 xor di, di
182
183 /* One entry in the PML4 pointing to PDP */
184 mov eax, offset pdp_startup
185 or eax, 0x00f
186 stosd
187 /* clear rest */
188 xor eax, eax
189 mov cx, 0x03ff
190 rep stosd
191
192 /* One entry in the PDP pointing to PD */
193 mov eax, offset pd_startup
194 or eax, 0x00f
195 stosd
196 /* clear rest */
197 xor eax, eax
198 mov ecx, 0x03ff
199 rep stosd
200
201 /* 512 entries in the PD defining a 2MB page each */
202 mov ecx, 512
203 mov eax, 0x008f
204
205 Bpt2:
206 mov es: [di], eax
207 mov dword ptr es: [di + 4], 0
208 add eax, 512 << 12 // add 512 4k pages
209 add di, 8
210
211 /* Loop it */
212 dec cx
213 jnz Bpt2
214
215 /* Return */
216 pop es
217 popa
218 ret
219
220 /*
221 * writechr,writestr
222 *
223 *
224 */
225 writestr:
226 pushfd
227 pushad
228 .top:
229 lodsb
230 and al, al
231 jz .end
232 call writechr
233 jmp short .top
234 .end:
235 popad
236 popfd
237 ret
238
239
240 writechr:
241 pushf
242 pusha
243 mov ah, 0x0E
244 xor bx, bx
245 int 0x10
246 popa
247 popf
248 ret
249
250 //.global x86_16_SwitchToLong
251 x86_16_SwitchToLong:
252
253 cli
254
255 xor ax,ax
256 mov ds,ax
257 mov es,ax
258 mov fs,ax
259 mov gs,ax
260 mov ss,ax
261
262 /* Get the return address off the stack */
263 pop word ptr code64ret
264
265 /* Save 16-bit stack pointer */
266 mov stack16, sp
267
268 mov eax, 0x00a0 // Set PAE and PGE: 10100000b
269 mov cr4, eax
270
271 mov edx, offset pml4_startup // Point cr3 at PML4
272 mov cr3, edx
273
274 mov ecx, 0xC0000080 // Specify EFER MSR
275
276 rdmsr // Enable long mode
277 or eax, 0x00000100
278 wrmsr
279
280 mov ebx, cr0 // Activate long mode
281 or ebx, 0x80000001 // by enabling paging and protection simultaneously
282 mov cr0, ebx // skipping protected mode entirely
283
284 jmp LMODE_CS:offset LongCat //Load CS with 64 bit segment and flush the instruction cache
285
286 .code64
287 LongCat:
288 /* Set up 64 bit stack */
289 mov rsp, stack64
290
291 /* Put the return address back onto the stack */
292 push qword ptr code64ret
293
294 /* Now return in long mode! */
295 ret
296
297 /** 64 Bit functions **********************************************************/
298 .code64
299
300 .global x86_64_SwitchToReal
301 x86_64_SwitchToReal:
302
303 /* Get the return address off the stack */
304 pop qword ptr code64ret
305
306 /* Save 64-bit stack pointer */
307 mov stack64, rsp
308
309 // mov ax, LMODE_DS
310 // mov ds, ax
311 // mov word ptr ds:[0xb8004], 0x0e00 + '3'
312
313 /* Step 1 - jump to compatibility segment */
314 ljmp jumpvector
315
316 jumpvector:
317 .long SwitchToReal1
318 .word CMODE_CS
319
320 SwitchToReal1:
321 .code32
322
323 // mov word ptr ds:[0xb8006], 0x0e00 + '4'
324
325 /* Step 2 - deactivate long mode, by disabling paging */
326 mov eax, cr0
327 and eax, 0x000000007fffffff //~0x80000000
328 mov cr0, eax
329
330 /* Step 2 - disable long mode in EFER MSR */
331 // mov ecx, 0xC0000080 // Specify EFER MSR
332 // rdmsr
333 // and eax, ~0x00000100 // Disable EFER.LME
334 // wrmsr
335
336 /* Step 3 - jump to 16-bit segment to set the limit correctly */
337 jmp RMODE_CS: offset SwitchToReal2
338
339 SwitchToReal2:
340 .code16
341
342 /* Step 4 - Disable Protected Mode */
343 mov eax, cr0
344 and eax, ~0x00000001
345 mov cr0, eax
346
347 /* Clear prefetch queue & correct CS */
348 jmp 0:offset BeReal
349
350 BeReal:
351 /* Checkpoint */
352 // mov ax, 0xb800
353 // mov fs, ax
354 // mov word ptr fs:[0x0C], 0x0e00 + '7'
355
356 /* Restore segment registers */
357 mov ax, 0
358 mov ds, ax
359 mov es, ax
360 mov fs, ax
361 mov gs, ax
362 mov ss, ax
363
364 /* Restore 16 bit stack */
365 mov sp, stack16
366
367 // lidt rmode_idtptr /* Load IDTR with real mode value */
368
369 // sti /* These are ok now */
370
371 /* Put the return address back onto the stack */
372 push word ptr code64ret
373
374 /* Now return in real mode! */
375 ret
376
377
378
379 /** Some data *****************************************************************/
380
381 .code64
382
383 stack16:
384 .quad STACK16ADDR
385
386 stack64:
387 .quad STACK64ADDR
388
389 code64ret:
390 .quad 0
391
392 .p2align 2
393 gdt:
394 .quad 0x0000000000000000 /* 00: NULL descriptor */
395 .quad 0x0000000000000000 /* 08: */
396 .quad 0x0020980000000000 /* 10: long mode cs */
397 .quad 0x00cff3000000ffff /* 18: long mode ds */
398 .word 0xFFFF, 0x0000, 0x9E00, 0x0000 /* 16-bit real mode CS */
399 .word 0xFFFF, 0x0000, 0x9200, 0x0000 /* 16-bit real mode DS */
400 .quad 0x00CF9B000000FFFF /* 30: compat mode cs */
401
402 /* GDT table pointer */
403 gdtptr:
404 .word 0x37 /* Limit */
405 .long gdt /* Base Address */
406
407
408 .global BootDrive
409 BootDrive:
410 .long 0
411
412 .global BootPartition
413 BootPartition:
414 .long 0
415
416 .global NotAnX64Processor
417 NotAnX64Processor:
418 .ascii "FreeLoader: No x64-compatible CPU detected! Exiting..."
419 .byte 0x0d, 0x0a, 0
420
421 .global NoCPUIDSupport
422 NoCPUIDSupport:
423 .ascii "FreeLoader: No CPUID instruction support detected! Exiting..."
424 .byte 0x0d, 0x0a, 0
425
426 /////////////////////////// Checkpoint messages ///////////////////////////////
427 .global CheckPoint0
428 CheckPoint0:
429 .ascii "Starting FreeLoader..."
430 .byte 0x0d, 0x0a, 0
431
432 .global CheckPoint1
433 CheckPoint1:
434 .ascii "FreeLoader[16-bit]: building page tables..."
435 .byte 0x0d, 0x0a, 0
436
437 .global CheckPoint2
438 CheckPoint2:
439 .ascii "FreeLoader[16-bit]: checking CPU for x64 long mode..."
440 .byte 0x0d, 0x0a, 0
441
442 .global CheckPoint3
443 CheckPoint3:
444 .ascii "FreeLoader: Switching to x64 long mode..."
445 .byte 0x0d, 0x0a, 0
446
447 ///////////////////////////////////////////////////////////////////////////////
448
449 /* Need to include them here, because of linking issues between 64 / 16 bit */
450 //#include "debug16.S"
451 #include "int386.S"
452 #include "boot.S"
453 #include "i386pnp.S"
454