singrdk/base/boot/SingLdrPc/blentry16.asm

1899 lines
35 KiB
NASM
Raw Normal View History

2008-11-17 18:29:00 -05:00
;++
;
; 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