3 #include "../../include/arch/pc/x86common.h"
5 #define IMAGE_DOS_HEADER_e_lfanew 60
6 #define IMAGE_FILE_HEADER_SIZE 20
7 #define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16
12 #include "fathelp.inc"
19 /* Setup real mode segment registers */
27 /* Save the boot drive and partition */
28 mov byte ptr ds:[BSS_BootDrive], dl
29 mov byte ptr ds:[BSS_BootPartition], dh
31 /* Setup a real mode stack */
32 mov sp, word ptr ds:[stack16]
34 /* Output first status */
35 mov si, offset Msg_Starting
38 /* Enable A20 address line */
42 call CheckFor64BitSupport
44 jnz .LongModeSupported
46 /* Output failure message */
47 mov si, offset Msg_Unsupported
50 /* Wait for a keypress */
55 .ascii "This CPU is not supported.", CR, LF
56 .ascii "Press any key to reboot...", NUL
59 .ascii "Starting FreeLoader...", CR, LF, NUL
61 Msg_LongModeSupported:
62 .ascii "Long mode support detected.", CR, LF, NUL
66 mov si, offset Msg_LongModeSupported
71 lgdt fword ptr [gdtptr]
76 /* Build the startup page tables */
79 /* Store real mode entry point in shared memory */
80 mov dword ptr ds:[BSS_RealModeEntry], offset RealModeEntryPoint
82 /* Address the image with es segment */
83 mov ax, FREELDR_PE_BASE / 16
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
90 /* Get address of entry point */
91 mov eax, dword ptr es:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint]
92 add eax, FREELDR_PE_BASE
94 /* Save entry point */
95 mov dword ptr ds:[LongModeEntryPoint], eax
102 mov si, offset Msg_SwitchToLongMode
107 Msg_SwitchToLongMode:
108 .ascii "Switching to long mode....", CR, LF, NUL
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 */
120 /* GDT table pointer */
122 .word HEX(37) /* Limit */
124 .long offset gdt /* Base Address */
126 .long gdt /* Base Address */
130 CheckFor64BitSupport:
131 /* Check whether the CPU supports CPUID */
136 xor eax, HEX(00200000)
144 mov si, offset .Msg_NoCpuidSupport
151 .ascii "The system doesn't support CPUID.", CR, LF, NUL
154 /* CPUID support detected - getting the PAE/PGE */
155 mov eax, 1 // Fn0000_0001 - PAE in EDX[6]
161 mov si, offset .Msg_NoPAE
168 .ascii "PAE or PGE not set.", CR, LF, NUL
171 /* Check whether extended functions are supported */
172 mov eax, HEX(80000000)
174 cmp eax, HEX(80000000) // Any function > 0x80000000 ?
175 jbe .NoLongMode // If not, no long mode.
176 /* Check whether the CPU supports Long Mode */
178 mov eax, HEX(80000001)
180 and edx, HEX(20000000)
185 mov si, offset .Msg_NoLongMode
192 .ascii "Long mode is not supported.", CR, LF, NUL
205 /* Get segment of the PML4 */
206 mov eax, PML4_ADDRESS / 16
211 /* One entry in the PML4 pointing to PDP */
221 /* One entry in the PDP pointing to PD */
231 /* 512 entries in the PD, each defining a 2MB page each */
237 mov dword ptr es:[di + 4], 0
238 add eax, 512 * 4096 // add 512 4k pages
251 /******************************************************************************/
253 #define MSR_EFER HEX(C0000080)
254 #define LMODE_CS HEX(10)
256 /* This is the entry point from long mode */
259 /* Disable long mode */
262 and eax, HEX(0FFFFFEFF) // ~0100
265 /* Mask PAE and PGE out */
267 and eax, HEX(0FFFFFF5F) // ~00A0
270 /* Disable Protected Mode */
272 and eax, HEX(0FFFFFFFE) // ~0x00000001
275 /* Clear prefetch queue & correct CS */
280 // mov ax, HEX(0b800)
282 // mov word ptr es:[12], HEX(0e00) + '6'
284 /* Set real mode segments */
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. */
300 /* Restore real mode stack */
301 mov sp, word ptr ds:[stack16]
303 // sti /* These are ok now */
305 /* Do the callback, specified by bx */
307 call word ptr ds:CallbackTable[bx]
310 /* Disable interrupts */
313 /* Set correct segment registers */
321 /* Save current stack pointer */
322 mov word ptr ds:[stack16], sp
324 /* Set PAE and PGE: 10100000b */
329 /* Point cr3 at the PML4 */
330 mov eax, PML4_ADDRESS
333 /* Enable long mode */
336 or eax, HEX(00000100)
339 /* Activate long mode by enabling paging and protection simultaneously,
340 skipping protected mode entirely */
342 or eax, HEX(80000001)
345 /* Clear prefetch queue & correct CS */
346 ljmp16 LMODE_CS, 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'
353 .byte HEX(0FF), HEX(25) // opcode of 64bit indirect jump
354 .long 1 // relative address of LongModeEntryPoint
362 /* FNID_* functions */
366 .word Relocator16Boot
368 .word PnpBiosGetDeviceNodeCount
369 .word PnpBiosGetDeviceNode
370 .word PnpBiosGetDockStationInformation
372 /* 16-bit stack pointer */
377 #include "int386.inc"
378 #include "helpers.inc"
382 .org (FREELDR_PE_BASE - FREELDR_BASE - 1)