1899 lines
35 KiB
NASM
1899 lines
35 KiB
NASM
|
;++
|
||
|
;
|
||
|
; 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
|