;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; blentry16.asm (x64) ; ; Abstract: ; ; This module implements the 16-bit entry point for the boot loader. ; ; Environment: ; ; Boot loader. ; ;-- .model tiny, c OPTION SCOPED include bl.inc REAL_MODE_BASE equ 07b00h VIDEO_BASE equ 0b8000h BLUE equ 01f00h RED equ 02f00h GREEN equ 04f00h .code .686p JMPF16 MACRO SEG:REQ,OFF:REQ db 0eah dw OFF dw SEG ENDM JMPF32 MACRO SEG:REQ,OFF:REQ db 0eah dd OFF dw SEG ENDM _TEXT16 segment page public use16 'CODE' org 100h ;++ ; ; VOID ; BlEntry16( ; VOID ; ) ; ; Routine Description: ; ; This function is the 16-bit entry point for the boot loader and it detects ; the type of boot to perform and calls the appropriate function. ; ;-- BlEntry16 proc ; ; Disable interrupts. ; cli mov bp, sp ;; Write a character to the screen. ;; Configure GS to point to the text-mode video console. mov ax, 0b800h mov gs, ax mov ax, GREEN + 'A' mov gs:[0], ax mov ax, GREEN + '-' mov gs:[2], ax ; ; If CS is 0x5000, then it indicates a CD or HD boot. ; mov bx, PXE_BOOT mov dx, 0 mov ax, cs cmp ax, 05000h jne boot_ready ; ; Check for CD signature on the stack. ; mov dx, word ptr [bp + 8] mov bx, CD_BOOT cmp word ptr [bp + 4], 04344h je boot_needs_fixup ; ; Check for FAT16 signature on the stack. ; mov bx, FAT16_BOOT cmp word ptr [bp + 4], 04806h je boot_needs_fixup ; ; Check for FAT32 signature on the stack. ; mov bx, FAT32_BOOT cmp word ptr [bp + 4], 04803h je boot_needs_fixup ; ; Unknown boot device ; mov ax, GREEN + 'B' mov gs:[2], ax @@: jmp @b ; ; Copy 64K from 57C0:0000 to 07C0:0000. ; boot_needs_fixup: mov ax, GREEN + 'C' mov gs:[4], ax mov ax, 057C0h mov ds, ax mov si, 0 mov ax, 007C0h mov es, ax mov di, 0 mov cx, 04000h rep movsd ; ; Continue execution at the relocated block with known segment selector. ; boot_ready: mov ax, GREEN + 'D' mov gs:[6], ax ; ; Jump to relocated code. ; JMPF16 07b0h, @f @@: ; bx = BootType ; dx = BootDriveNumber ; ; Initialize DS, ES, SS, and SP for real mode. ; mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP mov ax, GREEN + 'E' mov gs:[8], ax ; ; Initialize boot environment block (pass bx & dx). ; call BlInitializeBeb ; ; Initialize video. ; call BlInitializeVideo ; ; Load GDT. ; mov ax, GREEN + 'F' mov gs:[10], ax mov di, OFFSET BlGDTS_Limit lgdt fword ptr ds:[di] mov ax, RM_VIDEO_SELECTOR mov gs, ax mov ax, GREEN + 'G' mov gs:[12], ax ; ; Clear the real-mode segment registers. ; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Enable protected mode. ; mov eax, cr0 or eax, CR0_PE OR CR0_NE mov cr0, eax ; ; Jump far to 32-bit protected-mode code. ; JMPF16 PM_CODE_SELECTOR, LOWWORD ( REAL_MODE_BASE + OFFSET BlEntry32 ) BlEntry16 endp ;++ ; ; VOID ; BlInitializeVideo( ; VOID ; ) ; ; Routine Description: ; ; This function initializes video support for the boot loader. ; ;-- BlInitializeVideo proc mov ax, 1202h ; LINES_400_CONFIGURATION mov bx, 0301h ; SELECT_SCAN_LINE int 10h mov ax, 3h ; SET_80X25_16_COLOR_MODE mov bx, 0h ; PAGE0 int 10h mov ax, 1112h ; LOAD_8X8_CHARACTER_SET mov bx, 0h int 10h mov ax, 1003h ; Disable BLINK mode, enable background intensity. mov bx, 0h int 10h mov ax, 0200h ; Set Cursor position to 0, 0 mov bx, 0h mov dx, 0h int 10h ret BlInitializeVideo endp ;++ ; ; VOID ; BlInitializeBeb( ; bx = BootType ; dx = BootDriveNumber ; ) ; ; Routine Description: ; ; This function initializes the boot environment block. ; ;-- BlInitializeBeb proc push es push di mov di, BEB_SEG16 mov es, di mov di, BEB_OFF16 xor al, al mov cx, 4096 rep stosb mov di, BEB_OFF16 ;; See if we are booting from Flash mov si, BlFlashImage mov eax, [si] cmp eax, 0 je @f mov dword ptr es:[di].BEB.FlashImage, eax mov si, BlSmapAddr mov eax, [si] mov dword ptr es:[di].BEB.SmapAddr, eax mov si, BlSmapSize mov eax, [si] mov dword ptr es:[di].BEB.SmapSize, eax mov bx, FLASH_BOOT @@: mov word ptr es:[di].BEB.BootType, bx mov word ptr es:[di].BEB.BootDriveNumber, dx ifdef BOOT_X64 mov dword ptr es:[di].BEB.LegacyReturnCr3, LM_PML4T_ADDRESS else mov dword ptr es:[di].BEB.LegacyReturnCr3, PM_PDPT_ADDRESS endif lea ax, BlApEntry16 mov word ptr es:[di].BEB.ApEntry16, ax mov ax, cs mov word ptr es:[di].BEB.ApEntry16 + 2, ax lea ax, BlApStartupLock mov word ptr es:[di].BEB.ApStartupLock, ax mov ax, cs mov word ptr es:[di].BEB.ApStartupLock + 2, ax pop di pop es ret BlInitializeBeb endp ;++ ; ; Hardware Protection Configuration Data ; ;-- ; ; TSS. ; ALIGN 16 BlTSS: db 066h dup (0) dw 068h ; ; Global Descriptor Table (GDT). ; ALIGN 16 BlGDTStart: dq 00000000000000000h ; 00: NULL segment [NULL_SELECTOR]. dq 00000930B8000FFFFh ; 08: 000B8000[0000FFFF] Data [PM_VIDEO_SELECTOR]. dq 000009B007B00FFFFh ; 10: 00007800[0000FFFF] COde [RM_CODE_SELECTOR]. dq 0000093007B00FFFFh ; 18: 00007B00[0000FFFF] Data [RM_DATA_SELECTOR]. dq 000CF9B000000FFFFh ; 20: PM code segment [PM_CODE_SELECTOR]. dq 000CF93000000FFFFh ; 28: PM data segment [PM_DATA_SELECTOR]. dq 000209B0000000000h ; 30: LM code segment [LM_CODE_SELECTOR]. dq 00000930000000000h ; 38: LM data segment [LM_DATA_SELECTOR]. dq 00000000000000000h ; 40: PM user code segment [UM_CODE_SELECTOR]. dq 00000000000000000h ; 48: PM user data segment [UM_DATA_SELECTOR]. dq 00000000000000000h ; 50: FS/GS segment [PROCESSOR_SELECTOR]. dq 00000000000000000h ; 58: [UNUSED_SELECTOR] ; ; TSS segment. ; dw 00067h dw REAL_MODE_BASE + OFFSET BlTSS db 000h db 089h dw 00000h ifdef BOOT_X64 dq 00000000000000000h endif BlGDTLimit: ; ; Global Descriptor Table Selector (GDTS). ; ALIGN 16 ;; Padding to align address (and limit to -2) dw 00000h dw 00000h dw 00000h BlGDTS_Limit: dw offset BlGDTLimit - offset BlGDTStart BlGDTS_Address: dw REAL_MODE_BASE + OFFSET BlGDTStart dw 0 dd 0 ;++ ; ; VOID ; BlReturnToRealMode( ; VOID ; ) ; ; Routine Description: ; ; This function switches the processor back to real mode to execute a real ; mode request. ; ;-- ALIGN 16 BlReturnToRealMode proc ; ; Zero all registers. ; xor ebx, ebx xor ecx, ecx xor edx, edx xor esi, esi xor edi, edi xor esp, esp xor ebp, ebp ; ; Disable protected mode. ; mov eax, cr0 and eax, NOT (CR0_PE OR CR0_NE) mov cr0, eax ; ; Return to real mode. ; JMPF16 07b0h, OFFSET BlProcessRealModeRequest BlReturnToRealMode endp ;++ ; ; VOID ; BlLeaveLrbPmToBoot( ; VOID ; ) ; ; Routine Description: ; ; This function switches the processor back to real mode for boot. ; ;-- ALIGN 16 BlLeaveLrbPmToBoot PROC mov ax, RM_VIDEO_SELECTOR mov gs, ax ;; Write to position 0. mov ax, RED + 'T' mov gs:[12], ax ; Zero all registers. ; xor ebx, ebx xor ecx, ecx xor edx, edx xor esi, esi xor edi, edi xor esp, esp xor ebp, ebp ; ; Disable paging. ; mov eax, cr0 and eax, NOT (CR0_PG) mov cr0, eax xor eax, eax mov cr3, eax mov cr4, eax ; ; Disable long mode and return to legacy protected-mode. ; mov ecx, EFER_MSR_INDEX rdmsr and eax, NOT (EFER_LME OR EFER_NXE) wrmsr ; ; Disable protected mode. ; mov eax, cr0 and eax, NOT (CR0_PE OR CR0_NE) mov cr0, eax ; ; Return to real mode. ; JMPF16 07b0h, OFFSET @f @@: mov ax, 0b800h mov gs, ax ;; Write to position 0. mov ax, RED + 'U' mov gs:[14], ax mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP ;; Write to position 0. mov ax, RED + 'V' mov gs:[16], ax ; ; Return to real mode boot entry. ; JMPF16 07b0h, OFFSET BlEntry16 BlLeaveLrbPmToBoot endp ;++ ; ; VOID ; BlProcessRealModeRequest( ; VOID ; ) ; ; Routine Description: ; ; This function performs the requested real mode operation and returns back to ; protected mode as necessary. ; ;-- ; ; Real-mode IDTR. ; BlRealModeIdtr: dw 01000h dq 0 ; ; Protected-mode IDTR. ; BlProtModeIdtr: dw 01000h dq 0 BlProcessRealModeRequest proc ; ; Set DS, ES, SS, SP, and SI for real-mode legacy call. ; xor eax,eax mov ax, cs mov ds, ax mov ax, BEB_SEG16 mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP mov si, BEB_OFF16 ; ; Switch back to real-mode IDT. ; lea eax, BlRealModeIdtr lidt fword ptr ds:[eax] cmp word ptr es:[si].BEB.LegacyCall_OpCode, LC_INTXX jne @f mov cl, byte ptr es:[si].BEB.LegacyCall_Vector call BlProcessIntXx jmp BlProcessRealModeRequest_Exit @@: cmp word ptr es:[si].BEB.LegacyCall_OpCode, LC_FARCALL jne @f call BlProcessFarCall jmp BlProcessRealModeRequest_Exit @@: BlProcessRealModeRequest_Exit: ; ; Restore DS, ES, SS, and SP to their initial real-mode values. ; mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP ; ; Load GDT. ; mov di, OFFSET BlGDTS_Limit lgdt fword ptr ds:[di] ; ; Clear the real-mode segment registers. ; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Enable protected mode. ; mov eax, cr0 or eax, CR0_PE OR CR0_NE mov cr0, eax ; ; Jump far to 32-bit protected-mode code. ; JMPF16 PM_CODE_SELECTOR, LOWWORD ( REAL_MODE_BASE + OFFSET BlEnter32AfterRealModeRequest ) BlProcessRealModeRequest endp ;++ ; ; Lock to protect shared access to real-mode boot stack. ; ;-- BlApStartupLock: dd 0 Bl16End db 0deh, 0adh, 0beh, 0efh org 500h ;++ ; ; VOID ; BlApEntry16( ; VOID ; ) ; ; Routine Description: ; ; This function implements the entry point for application processors ; on a multi-processor system. ; ;-- BlApEntry16 proc ; ; Disable interrupts. ; cli ; ; Set DS to access AP startup lock. ; mov ax, 07b0h mov ds, ax ; ; Acquire AP startup lock before touching any other memory or stack. ; @@: cmp word ptr ds:[BlApStartupLock], 0 jne @b mov ax, 1 xchg word ptr ds:[BlApStartupLock], ax cmp ax, 0 jne @b ; ; Set SS & SP and switch to 16-bit entry CS. ; mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP JMPF16 07b0h, OFFSET @f @@: ; ; Initialize DS, ES, SS, and SP for real mode. ; mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP ; ; Load GDT. ; mov di, OFFSET BlGDTS_Limit lgdt fword ptr ds:[di] ; ; Clear the real-mode segment registers. ; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Enable protected mode. ; mov eax, cr0 or eax, CR0_PE OR CR0_NE mov cr0, eax ; ; Jump far to 32-bit protected-mode code. ; JMPF16 PM_CODE_SELECTOR, LOWWORD ( REAL_MODE_BASE + OFFSET BlApEntry32 ) BlApEntry16 endp ; ; ; SAVE_CONTEXT_TO_STACK macro push eax push ebx push ecx push edx push esi push edi push ds push es pushfd endm RESTORE_CONTEXT_FROM_STACK macro popfd pop es pop ds pop edi pop esi pop edx pop ecx pop ebx pop eax endm SAVE_CALL_CONTEXT_TO_STACK macro mov ax, BEB_SEG16 mov es, ax mov si, BEB_OFF16 push dword ptr es:[si].BEB.LegacyCall_eax push dword ptr es:[si].BEB.LegacyCall_ebx push dword ptr es:[si].BEB.LegacyCall_ecx push dword ptr es:[si].BEB.LegacyCall_edx push dword ptr es:[si].BEB.LegacyCall_esi push dword ptr es:[si].BEB.LegacyCall_edi push word ptr es:[si].BEB.LegacyCall_ds push word ptr es:[si].BEB.LegacyCall_es pushfd endm RESTORE_CALL_CONTEXT_FROM_STACK macro mov ax, BEB_SEG16 mov es, ax mov si, BEB_OFF16 pop dword ptr es:[si].BEB.LegacyCall_eflags pop word ptr es:[si].BEB.LegacyCall_es pop word ptr es:[si].BEB.LegacyCall_ds pop dword ptr es:[si].BEB.LegacyCall_edi pop dword ptr es:[si].BEB.LegacyCall_esi pop dword ptr es:[si].BEB.LegacyCall_edx pop dword ptr es:[si].BEB.LegacyCall_ecx pop dword ptr es:[si].BEB.LegacyCall_ebx pop dword ptr es:[si].BEB.LegacyCall_eax endm ;++ ; ; VOID ; BlProcessIntXx( ; UCHAR InterruptVector ; ) ; ; Routine Description: ; ; This function processes INT XX requests. ; ; Arguments: ; ; InterruptVector (cl) - Supplies the interrupt vector to invoke. ; ;-- BlProcessIntXx proc mov byte ptr @f, cl SAVE_CONTEXT_TO_STACK SAVE_CALL_CONTEXT_TO_STACK RESTORE_CONTEXT_FROM_STACK ; ; INT XX instruction. ; db 0CDh @@: db 000h SAVE_CONTEXT_TO_STACK RESTORE_CALL_CONTEXT_FROM_STACK RESTORE_CONTEXT_FROM_STACK ret BlProcessIntXx endp ;++ ; ; VOID ; BlProcessFarCall( ; UCHAR InterruptVector ; ) ; ; Routine Description: ; ; This function processes far call requests. ; ;-- BlProcessFarCall proc SAVE_CONTEXT_TO_STACK push bp mov bp, sp ; ; Copy the call frame to the stack. ; mov ax, BEB_SEG16 mov es, ax mov si, BEB_OFF16 mov ax, word ptr es:[si].BEB.LegacyCall_FramePtr + 2 mov ds, ax mov bx, word ptr es:[si].BEB.LegacyCall_FramePtr mov cx, word ptr es:[si].BEB.LegacyCall_FrameSize add bx, cx mov ax, cx @@: cmp ax, 0 je @f sub bx, 2 push word ptr ds:[bx] sub ax, 2 jmp @b @@: ; ; Set return address. ; push cs push @f ; ; Set call address. ; push dword ptr es:[si].BEB.LegacyCall_FuncPtr ; ; Set caller provided context. ; SAVE_CALL_CONTEXT_TO_STACK RESTORE_CONTEXT_FROM_STACK ; ; Call the specified function with a far return. ; retf @@: ; ; Copy the output context to BEB. ; SAVE_CONTEXT_TO_STACK RESTORE_CALL_CONTEXT_FROM_STACK mov sp, bp pop bp RESTORE_CONTEXT_FROM_STACK ret BlProcessFarCall endp _TEXT16 ends _TEXT32 segment page public use32 'CODE' ;++ ; ; VOID ; BlEntry32( ; VOID ; ) ; ; Routine Description: ; ; This function implements the 32-bit entry point for the boot loader. ; ;-- BlEntry32 proc ; ; Load the protected-mode segment registers. ; mov ax, PM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov esp, PM_INITIAL_ESP mov ax, NULL_SELECTOR mov fs, ax mov gs, ax mov esi, VIDEO_BASE + 14 mov [esi], ax ifdef BOOT_X64 ; ; Check for long mode. ; call BlCheckLongMode cmp eax, 0 jne @f ; ; Long mode is not supported -- halt execution. ; call BlHalt @@: endif ; ; Initialize boot environment block. ; call BlRegisterExitAddress ; ; Prepare page tables. ; call BlPreparePageTables mov ax, GREEN + 'I' mov esi, VIDEO_BASE + 14 mov [esi], ax ; ; Enable PSE, PAE, performance counters, and floating point support. ; mov eax, cr4 or eax, CR4_PSE OR CR4_PAE OR CR4_PCE OR CR4_OSFXSR mov cr4, eax ; ; Set root page table. ; ifdef BOOT_X64 mov eax, LM_PML4T_ADDRESS else mov eax, PM_PDPT_ADDRESS endif mov cr3, eax ifdef BOOT_X64 ; ; Enable long-mode and no-execute. ; mov ecx, EFER_MSR_INDEX rdmsr or eax, EFER_LME OR EFER_NXE wrmsr endif ; ; Enable paging. ; mov eax, cr0 or eax, CR0_PG mov cr0, eax ; ; Load PE image. ; call BlLoadImage mov bx, GREEN + 'J' mov esi, VIDEO_BASE + 16 mov [esi], bx ifdef BOOT_X64 ; ; Enter long mode. ; JMPF32 LM_CODE_SELECTOR, REAL_MODE_BASE + OFFSET @f @@: mov dx, LM_DATA_SELECTOR mov ds, dx mov es, dx mov ss, dx mov bx, GREEN + 'K' mov esi, VIDEO_BASE + 18 mov [esi], bx endif ; ; Switch to entry stack and call entry point. ; mov esp, BL_ENTRY_SP call eax BlEntry32 endp ;++ ; ; VOID ; BlEnter32AfterRealModeRequest( ; VOID ; ) ; ; Routine Description: ; ; This function returns to normal mode after a legacy mode request was handled. ; ;-- BlEnter32AfterRealModeRequest proc ; ; Load the protected-mode segment registers. ; mov ax, PM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov esp, PM_INITIAL_ESP mov ax, NULL_SELECTOR mov fs, ax mov gs, ax ; ; Enable PSE, PAE, performance counters, and floating point support. ; mov eax, cr4 or eax, CR4_PSE OR CR4_PAE OR CR4_PCE OR CR4_OSFXSR mov cr4, eax ; ; Set root page table. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.LegacyReturnCr3 mov cr3, eax ifdef BOOT_X64 ; ; Enable long-mode and no-execute. ; mov ecx, EFER_MSR_INDEX rdmsr or eax, EFER_LME OR EFER_NXE wrmsr endif ; ; Restore the IDT ; mov eax, OFFSET BlProtModeIdtr add eax, REAL_MODE_BASE lidt fword ptr ds:[eax] ; ; Enable paging. ; mov eax, cr0 or eax, CR0_PG mov cr0, eax ; ; Get return address from BEB. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.LegacyReturnAddress ifdef BOOT_X64 ; ; Enter long mode. ; JMPF32 LM_CODE_SELECTOR, REAL_MODE_BASE + OFFSET @f @@: mov edx, LM_DATA_SELECTOR mov ds, edx mov es, edx mov ss, edx endif ; ; Return to normal code. ; call eax BlEnter32AfterRealModeRequest endp ;++ ; ; VOID ; BlPreparePageTables( ; VOID ; ) ; ; Routine Description: ; ; This function prepares page tables for long mode execution. ; ;-- BlPreparePageTables proc ifdef BOOT_X64 ; ; Clear all entries for 4th level table. ; xor eax, eax mov edi, LM_PML4T_ADDRESS mov ecx, 0400h rep stosd ; ; Create a single 4th level entry. ; mov eax, LM_PML4T_ADDRESS mov dword ptr [eax], PM_PDPT_ADDRESS OR PTE_PRESENT OR PTE_WRITEABLE OR PTE_ACCESSED endif ; ; Clear all entries for 2nd and 3rd level tables. ; xor eax, eax mov edi, PM_PDPT_ADDRESS mov ecx, 0400h rep stosd xor eax, eax mov edi, PM_PDT_ADDRESS mov ecx, 0400h rep stosd ; ; Create a single 3rd level entry. ; mov eax, PM_PDPT_ADDRESS ifdef BOOT_X64 mov dword ptr [eax], PM_PDT_ADDRESS OR PTE_PRESENT OR PTE_WRITEABLE OR PTE_ACCESSED else ;;; See if these can't be the same. mov dword ptr [eax], PM_PDT_ADDRESS OR PTE_PRESENT endif ; ; Create a single 2nd level entry to identity-map the first 2MB of memory. ; mov eax, PM_PDT_ADDRESS mov dword ptr [eax], 0 OR PTE_PRESENT OR PTE_WRITEABLE OR PTE_ACCESSED OR PTE_2MB ret BlPreparePageTables endp ifdef BOOT_X64 ;++ ; ; VOID ; BlCheckLongMode( ; VOID ; ) ; ; Routine Description: ; ; This function checks if the processor supports long mode execution. ; ; Return Value: ; ; TRUE, if long mode execution is supported. ; FALSE, otherwise. ; ;-- BlCheckLongMode proc ; ; Get the largest extended function supported. ; mov eax, 080000000h cpuid ; ; If 0x80000000 is the limit, then long mode is not supported. ; cmp eax, 080000000h jbe NoLongMode ; ; Execute extended function 1 and check for long mode bit. ; mov eax, 080000001h cpuid bt edx, 29 jnc NoLongMode ; ; Return 1 to indicate presence of long mode. ; mov eax, 1 ret NoLongMode: ; ; Return 0 to indicate absense of long mode. ; mov eax, 0 ret BlCheckLongMode endp endif ;++ ; ; VOID ; BlHalt( ; VOID ; ) ; ; Routine Description: ; ; This function halts execution. ; ;-- BlHalt proc @@: jmp @b BlHalt endp ;++ ; ; VOID ; BlLeaveProtectedMode( ; VOID ; ) ; ; Routine Description: ; ; This function leaves protected mode to perform a real mode operation. ; ;-- ALIGN 16 BlLeaveProtectedMode proc ; ; Disable paging, reset root page table, and flush TLB. ; mov eax, cr0 and eax, NOT CR0_PG mov cr0, eax xor eax, eax mov cr3, eax mov cr4, eax jmp @f ALIGN 16 @@: ; ; Save the IDT. ; mov eax, OFFSET BlProtModeIdtr add eax, REAL_MODE_BASE sidt fword ptr ds:[eax] ifdef BOOT_X64 ; ; Disable long mode and return to legacy protected-mode. ; mov ecx, EFER_MSR_INDEX rdmsr and eax, NOT (EFER_LME OR EFER_NXE) wrmsr endif ; ; Return to real-mode code. ; JMPF32 RM_CODE_SELECTOR, OFFSET BlReturnToRealMode BlLeaveProtectedMode endp ;++ ; ; PVOID ; BlLoadImage( ; VOID ; ) ; ; Routine Description: ; ; This function loads the higher-level boot loader image. ; ; Return Value: ; ; Entry point address for the loaded image. ; ;-- BlLoadImage proc lea ebp, OFFSET BlImageStart add ebp, REAL_MODE_BASE ; ; Check DOS signature. ; cmp word ptr [ebp], IMAGE_DOS_SIGNATURE jne BlInvalidImage ; ; Calculate NT header address. ; mov ebx, dword ptr [ebp + IDH_NT_HEADER_OFFSET] add ebx, ebp ; ; Check NT signature. ; cmp dword ptr [ebx + INH_SIGNATURE], IMAGE_NT_SIGNATURE jne BlInvalidImage ; ; Check image base. ; ifdef BOOT_X64 cmp dword ptr [ebx + INH_OPTIONAL_HEADER + IOH64_IMAGE_BASE + 4], 0 jne BlInvalidImage cmp dword ptr [ebx + INH_OPTIONAL_HEADER + IOH64_IMAGE_BASE], IMAGE_ADDRESS else cmp dword ptr [ebx + INH_OPTIONAL_HEADER + IOH32_IMAGE_BASE], IMAGE_ADDRESS endif jne BlInvalidImage ; ; Copy headers. ; mov esi, ebp mov edi, IMAGE_ADDRESS mov ecx, dword ptr [ebx + INH_OPTIONAL_HEADER + IOH_SIZE_OF_HEADERS] rep movsb ; ; Calculate the address of first section header. ; ; SectionHeader = (PIMAGE_SECTION_HEADER) (((ULONG_PTR) &NtHeaders->OptionalHeader) + NtHeaders->FileHeader.SizeOfOptionalHeader) ; xor esi, esi mov si, word ptr [ebx + INH_FILE_HEADER + IFH_SIZE_OF_OPTIONAL_HEADER] add esi, INH_OPTIONAL_HEADER add esi, ebx xor ecx, ecx mov cx, word ptr [ebx + INH_FILE_HEADER + IFH_NUMBER_OF_SECTIONS] cmp cx, 0 jne @f call BlInvalidImage ; ; for (Index = 0; Index < NtHeaders->FileHeader.NumberOfSections; Index += 1) { ; ; BlCopySection(DosHeader, &SectionHeader[Index]); ; } ; @@: push ecx mov ecx, ebp mov edx, esi call BlCopySection pop ecx add esi, IMAGE_SECTION_HEADER_SIZE dec ecx jnz @b mov eax, dword ptr [ebx + INH_OPTIONAL_HEADER + IOH_ADDRESS_OF_ENTRY_POINT] add eax, IMAGE_ADDRESS ret BlLoadImage endp ;++ ; ; VOID ; FASTCALL ; BlCopySection( ; PIMAGE_DOS_HEADER DosHeader, ; PIMAGE_SECTION_HEADER SectionHeader ; ) ; ; Routine Description: ; ; This function copies the specified image section. ; ; Arguments: ; ; DosHeader (ecx) - Supplies a pointer to the source image to copy from. ; ; SectionHeader (edx) - Supplies a pointer to the section header describing ; the section to copy. ; ;-- BlCopySection proc ; ; Create call frame and save non-volatile registers that will be used. ; push ebp mov ebp, esp push esi push edi ; ; Calculate source and destination address for the copy operation. ; mov esi, dword ptr [edx + ISH_POINTER_TO_RAW_DATA] add esi, ecx mov edi, dword ptr [edx + ISH_VIRTUAL_ADDRESS] add edi, IMAGE_ADDRESS ; ; Save source and destination addresses -- rep stosb below will use them. ; push esi push edi ; ; Zero the entire target virtual range. ; mov eax, 0 mov ecx, dword ptr [edx + ISH_VIRTUAL_SIZE] rep stosb ; ; Restore source and destination addresses. ; pop edi pop esi ; ; BytesToCopy = min(SectionHeader->VirtualSize, SectionHeader->SizeOfRawData) ; mov ecx, dword ptr [edx + ISH_VIRTUAL_SIZE] cmp ecx, dword ptr [edx + ISH_SIZE_OF_RAW_DATA] jl @f mov ecx, dword ptr [edx + ISH_SIZE_OF_RAW_DATA] @@: ; ; Perform copy. ; rep movsb ; ; Restore used non-volatile registers, base pointer, and return. ; pop edi pop esi mov esp, ebp pop ebp ret BlCopySection endp ;++ ; ; VOID ; BlInvalidImage( ; VOID ; ) ; ; Routine Description: ; ; This function is called to halt execution if the embedded image is corrupted. ; ;-- BlInvalidImage proc call BlHalt BlInvalidImage endp ;++ ; ; VOID ; BlRegisterExitAddress( ; VOID ; ) ; ; Routine Description: ; ; This function registers the exit address in the boot environment block. ; ;-- BlRegisterExitAddress proc mov ecx, BEB_BASE lea eax, BlLeaveProtectedMode add eax, REAL_MODE_BASE mov dword ptr [ecx].BEB.LegacyCallAddress, eax ret BlRegisterExitAddress endp ;++ ; ; VOID ; BlApEntry32( ; VOID ; ) ; ; Routine Description: ; ; This function implements 32-bit entry point for application processors. ; ;-- BlApEntry32 proc ; ; Load the protected-mode segment registers. ; mov ax, PM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov esp, PM_INITIAL_ESP mov ax, NULL_SELECTOR mov fs, ax mov gs, ax ; ; Enable PSE, PAE, performance counters, and floating point support. ; mov eax, cr4 or eax, CR4_PSE OR CR4_PAE OR CR4_PCE OR CR4_OSFXSR mov cr4, eax ; ; Set root page table. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.LegacyReturnCr3 mov cr3, eax ifdef BOOT_X64 ; ; Enable long-mode and no-execute. ; mov ecx, EFER_MSR_INDEX rdmsr or eax, EFER_LME OR EFER_NXE wrmsr endif ; ; Enable paging. ; mov eax, cr0 or eax, CR0_PG mov cr0, eax ; ; Get entry address from BEB. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.ApEntry ifdef BOOT_X64 ; ; Enter long mode. ; JMPF32 LM_CODE_SELECTOR, REAL_MODE_BASE + OFFSET @f @@: mov edx, LM_DATA_SELECTOR mov ds, edx mov es, edx mov ss, edx endif ; ; Switch to entry stack and call entry point. ; mov esp, BL_ENTRY_SP call eax BlApEntry32 endp ;++ ; ; VOID ; BlLeaveLrb64ToBoot( ; VOID ; ) ; ; Routine Description: ; ; This function leaves paging and protected mode to boot. ; ;-- ALIGN 16 db 'S','I','N','G' db 'L','R','B',0 db 0f8h, 0f9h, 0fah, 0fbh db 0fch, 0fdh, 0feh, 0ffh BlFlashImage: dd 0 BlSmapAddr: dd 0 BlSmapSize: dd 0 dd 0 BlLeaveLrb64ToBoot proc mov eax, BLUE + 'P' mov esi, VIDEO_BASE + 0 mov [esi], ax mov eax, BLUE + 'O' mov esi, VIDEO_BASE + 2 mov [esi], ax mov eax, BLUE + 'N' mov esi, VIDEO_BASE + 4 mov [esi], ax mov eax, BLUE + 'M' mov esi, VIDEO_BASE + 6 mov [esi], ax mov eax, BLUE + 'L' mov esi, VIDEO_BASE + 8 mov [esi], ax ; ; Prepare a known GDT. ; mov eax, BLUE + 'K' mov esi, VIDEO_BASE + 10 mov [esi], ax mov eax, BLUE + 'J' mov esi, VIDEO_BASE + 12 mov [esi], ax ; ; Load the known GDT. ; mov edi, BlGDTS_Limit add edi, REAL_MODE_BASE lgdt fword ptr ds:[edi] mov eax, RED + 'R' mov esi, VIDEO_BASE + 8 mov [esi], ax mov eax, RED + 'S' mov esi, VIDEO_BASE + 10 mov [esi], ax mov edi, REAL_MODE_BASE + offset target jmp fword ptr [edi] target: dd OFFSET BlLeaveLrbPmToBoot dw RM_CODE_SELECTOR BlLeaveLrb64ToBoot endp ; ; Align to 16-bytes before PE image is concatenated. ; ALIGN 16 BlImageStart: _TEXT32 ends end BlEntry16