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
13 #include "fathelp.inc"
20 /* Setup real mode segment registers */
28 /* Save the boot drive and partition */
29 mov byte ptr ds:[BSS_BootDrive], dl
30 mov byte ptr ds:[BSS_BootPartition], dh
32 /* Setup a real mode stack */
33 mov sp, word ptr ds:[stack16]
35 /* Output first status */
36 mov si, offset Msg_Starting
39 /* Enable A20 address line */
43 call CheckFor64BitSupport
45 jnz .LongModeSupported
47 /* Output failure message */
48 mov si, offset Msg_Unsupported
51 /* Wait for a keypress */
56 .ascii "This CPU is not supported.", CR, LF
57 .ascii "Press any key to reboot...", NUL
60 .ascii "Starting FreeLoader...", CR, LF, NUL
62 Msg_LongModeSupported:
63 .ascii "Long mode support detected.", CR, LF, NUL
67 mov si, offset Msg_LongModeSupported
71 lgdt fword ptr [gdtptr]
73 /* Build the startup page tables */
76 /* Store real mode entry point in shared memory */
77 mov dword ptr ds:[BSS_RealModeEntry], offset RealModeEntryPoint
79 /* Address the image with es segment */
80 mov ax, FREELDR_PE_BASE / 16
83 /* Get address of optional header */
84 mov eax, dword ptr es:[IMAGE_DOS_HEADER_e_lfanew]
85 add eax, 4 + IMAGE_FILE_HEADER_SIZE
87 /* Get address of entry point */
88 mov eax, dword ptr es:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint]
89 add eax, FREELDR_PE_BASE
91 /* Save entry point */
92 mov dword ptr ds:[LongModeEntryPoint], eax
99 mov si, offset Msg_SwitchToLongMode
104 Msg_SwitchToLongMode:
105 .ascii "Switching to long mode....", CR, LF, NUL
109 .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 00: NULL descriptor */
110 .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 08: */
111 .word HEX(0000), HEX(0000), HEX(9800), HEX(0020) /* 10: long mode cs */
112 .word HEX(ffff), HEX(0000), HEX(f300), HEX(00cf) /* 18: long mode ds */
113 .word HEX(FFFF), HEX(0000), HEX(9E00), HEX(0000) /* 20: 16-bit real mode CS */
114 .word HEX(FFFF), HEX(0000), HEX(9200), HEX(0000) /* 28: 16-bit real mode DS */
115 .word HEX(FFFF), HEX(0000), HEX(9B00), HEX(00CF) /* 30: compat mode cs */
117 /* GDT table pointer */
119 .word HEX(37) /* Limit */
120 .long offset gdt /* Base Address */
123 CheckFor64BitSupport:
124 /* Check if CPU supports CPUID */
129 xor eax, HEX(00200000)
137 mov si, offset .Msg_NoCpuidSupport
144 .ascii "The system doesn't support CPUID.", CR, LF, NUL
147 /* CPUID support detected - getting the PAE/PGE */
148 mov eax,1 // Fn0000_0001 - PAE in EDX[6]
154 mov si, offset .Msg_NoPAE
161 .ascii "PAE or PGE not set.", CR, LF, NUL
165 mov eax, HEX(80000001)
167 and edx, HEX(20000000)
171 mov si, offset .Msg_NoLongMode
178 .ascii "Long mode is not supported.", CR, LF, NUL
191 /* Get segment of the PML4 */
192 mov eax, PML4_ADDRESS / 16
197 /* One entry in the PML4 pointing to PDP */
207 /* One entry in the PDP pointing to PD */
217 /* 512 entries in the PD, each defining a 2MB page each */
223 mov dword ptr es: [di + 4], 0
224 add eax, 512 * 4096 // add 512 4k pages
237 /******************************************************************************/
239 #define MSR_EFER HEX(C0000080)
240 #define LMODE_CS HEX(10)
242 /* This is the entry point from long mode */
244 /* Disable Protected Mode */
246 and eax, HEX(0fffffffe) // ~0x00000001
249 /* Clear prefetch queue & correct CS */
250 ljmp16 0, offset InRealMode
254 // mov ax, HEX(0b800)
256 // mov word ptr es:[12], HEX(0e00) + '6'
258 /* Set real mode segments */
266 /* Clear out the high 16-bits of ESP */
267 /* This is needed because I have one */
268 /* machine that hangs when booted to dos if */
269 /* anything other than 0x0000 is in the high */
270 /* 16-bits of ESP. Even though real-mode */
271 /* code should only use SP and not ESP. */
274 /* Restore real mode stack */
275 mov sp, word ptr ds:[stack16]
277 // sti /* These are ok now */
279 /* Do the callback, specified by bx */
281 call word ptr ds:CallbackTable[bx]
284 /* Disable interrupts */
287 /* Set correct segment registers */
295 /* Safe current stack pointer */
296 mov word ptr ds:[stack16], sp
298 /* Set PAE and PGE: 10100000b */
302 /* Point cr3 at the PML4 */
303 mov eax, PML4_ADDRESS
306 /* Enable long mode */
309 or eax, HEX(00000100)
312 /* Activate long mode by enabling paging and protection simultaneously,
313 skipping protected mode entirely */
315 or eax, HEX(80000001)
318 /* Clear prefetch queue & correct CS */
319 ljmp16 LMODE_CS, InLongMode
321 //DB 66h, 0B8h, 18h, 00h // mov ax, LMODE_DS
322 //DB 66h, 8Eh, 0D8h // mov ds, ax
323 //DB 66h, 66h, 0C7h, 04h, 25h, 00h, 80h, 0Bh, 00h, 31h, 0Eh
324 //mov word ptr [HEX(b8000)], HEX(0e00) + '1'
326 .byte HEX(0ff), HEX(25) // opcode of 64bit indirect jump
327 .long 1 // relative address of LongModeEntryPoint
338 .word ChainLoadBiosBootSectorCode
340 .word PnpBiosGetDeviceNodeCount
341 .word PnpBiosGetDeviceNode
342 .word 0 // BootLinuxKernel
344 /* 16-bit stack pointer */
349 #include "int386.inc"
352 #include "helpers.inc"
354 .org (FREELDR_PE_BASE - FREELDR_BASE - 1)