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 if 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 xor edx, edx 164 mov eax, HEX(80000001) 165 cpuid 166 and edx, HEX(20000000) 167 test edx,edx 168 jnz .Success 169 170 mov si, offset .Msg_NoLongMode 171 call writestr 172 popad 173 xor al, al 174 ret 175 176.Msg_NoLongMode: 177 .ascii "Long mode is not supported.", CR, LF, NUL 178 179.Success: 180 popad 181 xor al, al 182 inc al 183 ret 184 185 186BuildPageTables: 187 pusha 188 push es 189 190 /* Get segment of the PML4 */ 191 mov eax, PML4_ADDRESS / 16 192 mov es, ax 193 cld 194 xor di, di 195 196 /* One entry in the PML4 pointing to PDP */ 197 mov eax, PDP_ADDRESS 198 or eax, HEX(0f) 199 stosd 200 201 /* clear rest */ 202 xor eax, eax 203 mov cx, 1023 204 rep stosd 205 206 /* One entry in the PDP pointing to PD */ 207 mov eax, PD_ADDRESS 208 or eax, HEX(0f) 209 stosd 210 211 /* clear rest */ 212 xor eax, eax 213 mov ecx, 1023 214 rep stosd 215 216 /* 512 entries in the PD, each defining a 2MB page each */ 217 mov ecx, 512 218 mov eax, HEX(008f) 219 220.Bpt2: 221 mov es: [di], eax 222 mov dword ptr es: [di + 4], 0 223 add eax, 512 * 4096 // add 512 4k pages 224 add di, 8 225 226 /* Loop all PDEs */ 227 dec cx 228 jnz .Bpt2 229 230 /* Return */ 231 pop es 232 popa 233 ret 234 235 236/******************************************************************************/ 237 238#define MSR_EFER HEX(C0000080) 239#define LMODE_CS HEX(10) 240 241/* This is the entry point from long mode */ 242RealModeEntryPoint: 243 /* Disable Protected Mode */ 244 mov eax, cr0 245 and eax, HEX(0fffffffe) // ~0x00000001 246 mov cr0, eax 247 248 /* Clear prefetch queue & correct CS */ 249 ljmp16 0, offset InRealMode 250 251InRealMode: 252 253// mov ax, HEX(0b800) 254// mov es, ax 255// mov word ptr es:[12], HEX(0e00) + '6' 256 257 /* Set real mode segments */ 258 xor ax, ax 259 mov ds, ax 260 mov es, ax 261 mov fs, ax 262 mov gs, ax 263 mov ss, ax 264 265 /* Clear out the high 16-bits of ESP */ 266 /* This is needed because I have one */ 267 /* machine that hangs when booted to dos if */ 268 /* anything other than 0x0000 is in the high */ 269 /* 16-bits of ESP. Even though real-mode */ 270 /* code should only use SP and not ESP. */ 271 xor esp, esp 272 273 /* Restore real mode stack */ 274 mov sp, word ptr ds:[stack16] 275 276 // sti /* These are ok now */ 277 278 /* Do the callback, specified by bx */ 279 shl bx, 1 280 call word ptr ds:CallbackTable[bx] 281 282ExitToLongMode: 283 /* Disable interrupts */ 284 cli 285 286 /* Set correct segment registers */ 287 xor ax,ax 288 mov ds,ax 289 mov es,ax 290 mov fs,ax 291 mov gs,ax 292 mov ss,ax 293 294 /* Save current stack pointer */ 295 mov word ptr ds:[stack16], sp 296 297 /* Set PAE and PGE: 10100000b */ 298 mov eax, HEX(00a0) 299 mov cr4, eax 300 301 /* Point cr3 at the PML4 */ 302 mov eax, PML4_ADDRESS 303 mov cr3, eax 304 305 /* Enable long mode */ 306 mov ecx, MSR_EFER 307 rdmsr 308 or eax, HEX(00000100) 309 wrmsr 310 311 /* Activate long mode by enabling paging and protection simultaneously, 312 skipping protected mode entirely */ 313 mov eax, cr0 314 or eax, HEX(80000001) 315 mov cr0, eax 316 317 /* Clear prefetch queue & correct CS */ 318 ljmp16 LMODE_CS, InLongMode 319InLongMode: 320 //DB 66h, 0B8h, 18h, 00h // mov ax, LMODE_DS 321 //DB 66h, 8Eh, 0D8h // mov ds, ax 322 //DB 66h, 66h, 0C7h, 04h, 25h, 00h, 80h, 0Bh, 00h, 31h, 0Eh 323 //mov word ptr [HEX(b8000)], HEX(0e00) + '1' 324 325 .byte HEX(0ff), HEX(25) // opcode of 64bit indirect jump 326 .long 1 // relative address of LongModeEntryPoint 327 nop 328LongModeEntryPoint: 329 .long 0, 0 330 331 int HEX(16) 332 jmp Reboot 333 334CallbackTable: 335 .word Int386 336 .word Reboot 337 .word ChainLoadBiosBootSectorCode 338 .word PxeCallApi 339 .word PnpBiosGetDeviceNodeCount 340 .word PnpBiosGetDeviceNode 341 .word 0 // BootLinuxKernel 342 343 /* 16-bit stack pointer */ 344stack16: 345 .word STACK16ADDR 346 347 348#include "int386.inc" 349#include "pxe.inc" 350#include "pnp.inc" 351#include "helpers.inc" 352 353.org (FREELDR_PE_BASE - FREELDR_BASE - 1) 354.byte 0 355.endcode16 356 357END 358