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