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 15Startup: 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 54Msg_Unsupported: 55 .ascii "This CPU is not supported.", CR, LF 56 .ascii "Press any key to reboot...", NUL 57 58Msg_Starting: 59 .ascii "Starting FreeLoader...", CR, LF, NUL 60 61Msg_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 107Msg_SwitchToLongMode: 108 .ascii "Switching to long mode....", CR, LF, NUL 109 110.align 8 111gdt: 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 */ 121gdtptr: 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 130CheckFor64BitSupport: 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 201BuildPageTables: 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 */ 257RealModeEntryPoint: 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 278InRealMode: 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 309ExitToLongMode: 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 eax, HEX(00A0) 328 mov cr4, eax 329 330 /* Point cr3 at the PML4 */ 331 mov eax, PML4_ADDRESS 332 mov cr3, eax 333 334 /* Enable long mode */ 335 mov ecx, MSR_EFER 336 rdmsr 337 or eax, HEX(00000100) 338 wrmsr 339 340 /* Activate long mode by enabling paging and protection simultaneously, 341 skipping protected mode entirely */ 342 mov eax, cr0 343 or eax, HEX(80000001) 344 mov cr0, eax 345 346 /* Clear prefetch queue & correct CS */ 347 ljmp16 LMODE_CS, InLongMode 348InLongMode: 349 //DB 66h, 0B8h, 18h, 00h // mov ax, LMODE_DS 350 //DB 66h, 8Eh, 0D8h // mov ds, ax 351 //DB 66h, 66h, 0C7h, 04h, 25h, 00h, 80h, 0Bh, 00h, 31h, 0Eh 352 //mov word ptr [HEX(b8000)], HEX(0e00) + '1' 353 354 .byte HEX(0FF), HEX(25) // opcode of 64bit indirect jump 355 .long 1 // relative address of LongModeEntryPoint 356 nop 357LongModeEntryPoint: 358 .long 0, 0 359 360 int HEX(16) 361 jmp Reboot 362 363/* FNID_* functions */ 364CallbackTable: 365 .word Int386 366 .word Reboot 367 .word Relocator16Boot 368 .word PxeCallApi 369 .word PnpBiosGetDeviceNodeCount 370 .word PnpBiosGetDeviceNode 371 .word PnpBiosGetDockStationInformation 372 373 /* 16-bit stack pointer */ 374stack16: 375 .word STACK16ADDR 376 377 378#include "int386.inc" 379#include "helpers.inc" 380#include "pxe.inc" 381#include "pnp.inc" 382 383.org (FREELDR_PE_BASE - FREELDR_BASE - 1) 384.byte 0 385.endcode16 386 387END 388