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 .long offset gdt /* Base Address */ 124 125 126CheckFor64BitSupport: 127 /* Check whether the CPU supports CPUID */ 128 pushad 129 pushfd 130 pop eax 131 mov ebx, eax 132 xor eax, HEX(00200000) 133 push eax 134 popfd 135 pushfd 136 pop eax 137 cmp eax, ebx 138 jnz .CheckForPAE 139 140 mov si, offset .Msg_NoCpuidSupport 141 call writestr 142 popad 143 xor al, al 144 ret 145 146.Msg_NoCpuidSupport: 147 .ascii "The system doesn't support CPUID.", CR, LF, NUL 148 149.CheckForPAE: 150 /* CPUID support detected - getting the PAE/PGE */ 151 mov eax, 1 // Fn0000_0001 - PAE in EDX[6] 152 cpuid 153 and edx, HEX(00A0) 154 cmp edx, HEX(00A0) 155 je .CheckForLongMode 156 157 mov si, offset .Msg_NoPAE 158 call writestr 159 popad 160 xor al, al 161 ret 162 163.Msg_NoPAE: 164 .ascii "PAE or PGE not set.", CR, LF, NUL 165 166.CheckForLongMode: 167 /* Check whether extended functions are supported */ 168 mov eax, HEX(80000000) 169 cpuid 170 cmp eax, HEX(80000000) // Any function > 0x80000000 ? 171 jbe .NoLongMode // If not, no long mode. 172 /* Check whether the CPU supports Long Mode */ 173 xor edx, edx 174 mov eax, HEX(80000001) 175 cpuid 176 and edx, HEX(20000000) 177 test edx, edx 178 jnz .Success 179 180.NoLongMode: 181 mov si, offset .Msg_NoLongMode 182 call writestr 183 popad 184 xor al, al 185 ret 186 187.Msg_NoLongMode: 188 .ascii "Long mode is not supported.", CR, LF, NUL 189 190.Success: 191 popad 192 xor al, al 193 inc al 194 ret 195 196 197BuildPageTables: 198 pusha 199 push es 200 201 /* Get segment of the PML4 */ 202 mov eax, PML4_ADDRESS / 16 203 mov es, ax 204 cld 205 xor di, di 206 207 /* One entry in the PML4 pointing to PDP */ 208 mov eax, PDP_ADDRESS 209 or eax, HEX(0F) 210 stosd 211 212 /* clear rest */ 213 xor eax, eax 214 mov cx, 1023 215 rep stosd 216 217 /* One entry in the PDP pointing to PD */ 218 mov eax, PD_ADDRESS 219 or eax, HEX(0F) 220 stosd 221 222 /* clear rest */ 223 xor eax, eax 224 mov ecx, 1023 225 rep stosd 226 227 /* 512 entries in the PD, each defining a 2MB page each */ 228 mov ecx, 512 229 mov eax, HEX(008f) 230 231.Bpt2: 232 mov es:[di], eax 233 mov dword ptr es:[di + 4], 0 234 add eax, 512 * 4096 // add 512 4k pages 235 add di, 8 236 237 /* Loop all PDEs */ 238 dec cx 239 jnz .Bpt2 240 241 /* Return */ 242 pop es 243 popa 244 ret 245 246 247/******************************************************************************/ 248 249#define MSR_EFER HEX(C0000080) 250#define LMODE_CS HEX(10) 251 252/* This is the entry point from long mode */ 253RealModeEntryPoint: 254 255 /* Disable long mode */ 256 mov ecx, MSR_EFER 257 rdmsr 258 and eax, HEX(0FFFFFEFF) // ~0100 259 wrmsr 260 261 /* Mask PAE and PGE out */ 262 mov eax, cr4 263 and eax, HEX(0FFFFFF5F) // ~00A0 264 mov cr4, eax 265 266 /* Disable Protected Mode */ 267 mov eax, cr0 268 and eax, HEX(0FFFFFFFE) // ~0x00000001 269 mov cr0, eax 270 271 /* Clear prefetch queue & correct CS */ 272 ljmp16 0, InRealMode 273 274InRealMode: 275 276// mov ax, HEX(0b800) 277// mov es, ax 278// mov word ptr es:[12], HEX(0e00) + '6' 279 280 /* Set real mode segments */ 281 xor ax, ax 282 mov ds, ax 283 mov es, ax 284 mov fs, ax 285 mov gs, ax 286 mov ss, ax 287 288 /* Clear out the high 16-bits of ESP */ 289 /* This is needed because I have one */ 290 /* machine that hangs when booted to dos if */ 291 /* anything other than 0x0000 is in the high */ 292 /* 16-bits of ESP. Even though real-mode */ 293 /* code should only use SP and not ESP. */ 294 xor esp, esp 295 296 /* Restore real mode stack */ 297 mov sp, word ptr ds:[stack16] 298 299 // sti /* These are ok now */ 300 301 /* Do the callback, specified by bx */ 302 shl bx, 1 303 call word ptr ds:CallbackTable[bx] 304 305ExitToLongMode: 306 /* Disable interrupts */ 307 cli 308 309 /* Set correct segment registers */ 310 xor ax,ax 311 mov ds,ax 312 mov es,ax 313 mov fs,ax 314 mov gs,ax 315 mov ss,ax 316 317 /* Save current stack pointer */ 318 mov word ptr ds:[stack16], sp 319 320 /* Set PAE and PGE: 10100000b */ 321 // mov eax, cr4 322 // or eax, HEX(00A0) 323 mov eax, HEX(00A0) 324 mov cr4, eax 325 326 /* Point cr3 at the PML4 */ 327 mov eax, PML4_ADDRESS 328 mov cr3, eax 329 330 /* Enable long mode */ 331 mov ecx, MSR_EFER 332 rdmsr 333 or eax, HEX(00000100) 334 wrmsr 335 336 /* Activate long mode by enabling paging and protection simultaneously, 337 skipping protected mode entirely */ 338 mov eax, cr0 339 or eax, HEX(80000001) 340 mov cr0, eax 341 342 /* Clear prefetch queue & correct CS */ 343 ljmp16 LMODE_CS, InLongMode 344InLongMode: 345 //DB 66h, 0B8h, 18h, 00h // mov ax, LMODE_DS 346 //DB 66h, 8Eh, 0D8h // mov ds, ax 347 //DB 66h, 66h, 0C7h, 04h, 25h, 00h, 80h, 0Bh, 00h, 31h, 0Eh 348 //mov word ptr [HEX(b8000)], HEX(0e00) + '1' 349 350 .byte HEX(0FF), HEX(25) // opcode of 64bit indirect jump 351 .long 1 // relative address of LongModeEntryPoint 352 nop 353LongModeEntryPoint: 354 .long 0, 0 355 356 int HEX(16) 357 jmp Reboot 358 359CallbackTable: 360 .word Int386 361 .word Reboot 362 .word Relocator16Boot 363 .word PxeCallApi 364 .word PnpBiosGetDeviceNodeCount 365 .word PnpBiosGetDeviceNode 366 367 /* 16-bit stack pointer */ 368stack16: 369 .word STACK16ADDR 370 371 372#include "int386.inc" 373#include "helpers.inc" 374#include "pxe.inc" 375#include "pnp.inc" 376 377.org (FREELDR_PE_BASE - FREELDR_BASE - 1) 378.byte 0 379.endcode16 380 381END 382