mirror of https://github.com/acidanthera/audk.git
512 lines
15 KiB
NASM
512 lines
15 KiB
NASM
;; @file
|
|
; Provide FSP API entry points.
|
|
;
|
|
; Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
|
|
; SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
;;
|
|
|
|
SECTION .text
|
|
|
|
%include "SaveRestoreSseAvxNasm.inc"
|
|
%include "MicrocodeLoadNasm.inc"
|
|
|
|
;
|
|
; Following are fixed PCDs
|
|
;
|
|
extern ASM_PFX(PcdGet32 (PcdTemporaryRamBase))
|
|
extern ASM_PFX(PcdGet32 (PcdTemporaryRamSize))
|
|
extern ASM_PFX(PcdGet32 (PcdFspReservedBufferSize))
|
|
|
|
;
|
|
; Following functions will be provided in PlatformSecLib
|
|
;
|
|
extern ASM_PFX(AsmGetFspBaseAddress)
|
|
extern ASM_PFX(AsmGetFspInfoHeaderNoStack)
|
|
;extern ASM_PFX(LoadMicrocode) ; @todo: needs a weak implementation
|
|
extern ASM_PFX(SecPlatformInit) ; @todo: needs a weak implementation
|
|
extern ASM_PFX(SecCarInit)
|
|
|
|
;
|
|
; Define the data length that we saved on the stack top
|
|
;
|
|
DATA_LEN_OF_PER0 EQU 18h
|
|
DATA_LEN_OF_MCUD EQU 18h
|
|
DATA_LEN_AT_STACK_TOP EQU (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
|
|
|
|
;
|
|
; @todo: These structures are moved from MicrocodeLoadNasm.inc to avoid
|
|
; build error. This needs to be fixed later on.
|
|
;
|
|
struc MicrocodeHdr
|
|
.MicrocodeHdrVersion: resd 1
|
|
.MicrocodeHdrRevision: resd 1
|
|
.MicrocodeHdrDate: resd 1
|
|
.MicrocodeHdrProcessor: resd 1
|
|
.MicrocodeHdrChecksum: resd 1
|
|
.MicrocodeHdrLoader: resd 1
|
|
.MicrocodeHdrFlags: resd 1
|
|
.MicrocodeHdrDataSize: resd 1
|
|
.MicrocodeHdrTotalSize: resd 1
|
|
.MicrocodeHdrRsvd: resd 3
|
|
.size:
|
|
endstruc
|
|
|
|
struc ExtSigHdr
|
|
.ExtSigHdrCount: resd 1
|
|
.ExtSigHdrChecksum: resd 1
|
|
.ExtSigHdrRsvd: resd 3
|
|
.size:
|
|
endstruc
|
|
|
|
struc ExtSig
|
|
.ExtSigProcessor: resd 1
|
|
.ExtSigFlags: resd 1
|
|
.ExtSigChecksum: resd 1
|
|
.size:
|
|
endstruc
|
|
|
|
struc LoadMicrocodeParamsFsp24
|
|
; FSP_UPD_HEADER {
|
|
.FspUpdHeaderSignature: resd 2
|
|
.FspUpdHeaderRevision: resb 1
|
|
.FspUpdHeaderReserved: resb 23
|
|
; }
|
|
; FSPT_ARCH2_UPD {
|
|
.FsptArchRevision: resb 1
|
|
.FsptArchReserved: resb 3
|
|
.FsptArchLength: resd 1
|
|
.FspDebugHandler resq 1
|
|
.FsptArchUpd: resd 4
|
|
; }
|
|
; FSPT_CORE_UPD {
|
|
.MicrocodeCodeAddr: resq 1
|
|
.MicrocodeCodeSize: resq 1
|
|
.CodeRegionBase: resq 1
|
|
.CodeRegionSize: resq 1
|
|
; }
|
|
.size:
|
|
endstruc
|
|
|
|
%macro CALL_RDI 1
|
|
|
|
mov rdi, %%ReturnAddress
|
|
jmp %1
|
|
%%ReturnAddress:
|
|
|
|
%endmacro
|
|
|
|
;
|
|
; @todo: The strong/weak implementation does not work.
|
|
; This needs to be reviewed later.
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
;;global ASM_PFX(SecPlatformInitDefault)
|
|
;ASM_PFX(SecPlatformInitDefault):
|
|
; ; Inputs:
|
|
; ; ymm7 -> Return address
|
|
; ; Outputs:
|
|
; ; rax -> 0 - Successful, Non-zero - Failed.
|
|
; ; Register Usage:
|
|
; ; rax is cleared and rbp is used for return address.
|
|
; ; All others reserved.
|
|
;
|
|
; ; Save return address to RBP
|
|
; LOAD_RBP
|
|
;
|
|
; xor rax, rax
|
|
;Exit1:
|
|
; jmp rbp
|
|
|
|
;------------------------------------------------------------------------------
|
|
global ASM_PFX(LoadMicrocodeDefault)
|
|
ASM_PFX(LoadMicrocodeDefault):
|
|
; Inputs:
|
|
; rcx -> LoadMicrocodeParams pointer
|
|
; Register Usage:
|
|
; All are destroyed
|
|
; Assumptions:
|
|
; No memory available, stack is hard-coded and used for return address
|
|
; Executed by SBSP and NBSP
|
|
; Beginning of microcode update region starts on paragraph boundary
|
|
|
|
;
|
|
; Save return address to RBP
|
|
;
|
|
LOAD_RBP
|
|
|
|
test rsp, rsp
|
|
jz ParamError
|
|
test rcx, rcx
|
|
jz ParamError
|
|
mov rsp, rcx
|
|
|
|
;
|
|
; If microcode already loaded before this function, exit this function with SUCCESS.
|
|
;
|
|
mov ecx, MSR_IA32_BIOS_SIGN_ID
|
|
xor eax, eax ; Clear EAX
|
|
xor edx, edx ; Clear EDX
|
|
wrmsr ; Load 0 to MSR at 8Bh
|
|
|
|
mov eax, 1
|
|
cpuid
|
|
mov ecx, MSR_IA32_BIOS_SIGN_ID
|
|
rdmsr ; Get current microcode signature
|
|
xor rax, rax
|
|
test edx, edx
|
|
jnz Exit2
|
|
|
|
; skip loading Microcode if the MicrocodeCodeSize is zero
|
|
; and report error if size is less than 2k
|
|
; first check UPD header revision
|
|
cmp byte [rsp + LoadMicrocodeParamsFsp24.FspUpdHeaderRevision], 2
|
|
jb ParamError
|
|
cmp byte [rsp + LoadMicrocodeParamsFsp24.FsptArchRevision], 2
|
|
jne ParamError
|
|
|
|
; UPD structure is compliant with FSP spec 2.4
|
|
mov rax, qword [rsp + LoadMicrocodeParamsFsp24.MicrocodeCodeSize]
|
|
test rax, rax
|
|
jz Exit2
|
|
cmp rax, 0800h
|
|
jl ParamError
|
|
|
|
mov rsi, qword [rsp + LoadMicrocodeParamsFsp24.MicrocodeCodeAddr]
|
|
test rsi, rsi
|
|
jnz CheckMainHeader
|
|
|
|
ParamError:
|
|
mov rax, 08000000000000002h
|
|
jmp Exit2
|
|
|
|
CheckMainHeader:
|
|
; Get processor signature and platform ID from the installed processor
|
|
; and save into registers for later use
|
|
; ebx = processor signature
|
|
; edx = platform ID
|
|
mov eax, 1
|
|
cpuid
|
|
mov ebx, eax
|
|
mov ecx, MSR_IA32_PLATFORM_ID
|
|
rdmsr
|
|
mov ecx, edx
|
|
shr ecx, 50-32 ; shift (50d-32d=18d=0x12) bits
|
|
and ecx, 7h ; platform id at bit[52..50]
|
|
mov edx, 1
|
|
shl edx, cl
|
|
|
|
; Current register usage
|
|
; esp -> stack with parameters
|
|
; esi -> microcode update to check
|
|
; ebx = processor signature
|
|
; edx = platform ID
|
|
|
|
; Check for valid microcode header
|
|
; Minimal test checking for header version and loader version as 1
|
|
mov eax, dword 1
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrVersion], eax
|
|
jne AdvanceFixedSize
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrLoader], eax
|
|
jne AdvanceFixedSize
|
|
|
|
; Check if signature and plaform ID match
|
|
cmp ebx, dword [esi + MicrocodeHdr.MicrocodeHdrProcessor]
|
|
jne LoadMicrocodeDefault1
|
|
test edx, dword [esi + MicrocodeHdr.MicrocodeHdrFlags ]
|
|
jnz LoadMicrocode ; Jif signature and platform ID match
|
|
|
|
LoadMicrocodeDefault1:
|
|
; Check if extended header exists
|
|
; First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
|
|
xor rax, rax
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrTotalSize], eax
|
|
je NextMicrocode
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrDataSize], eax
|
|
je NextMicrocode
|
|
|
|
; Then verify total size - sizeof header > data size
|
|
mov ecx, dword [esi + MicrocodeHdr.MicrocodeHdrTotalSize]
|
|
sub ecx, MicrocodeHdr.size
|
|
cmp ecx, dword [esi + MicrocodeHdr.MicrocodeHdrDataSize]
|
|
jng NextMicrocode ; Jif extended header does not exist
|
|
|
|
; Set edi -> extended header
|
|
mov edi, esi
|
|
add edi, MicrocodeHdr.size
|
|
add edi, dword [esi + MicrocodeHdr.MicrocodeHdrDataSize]
|
|
|
|
; Get count of extended structures
|
|
mov ecx, dword [edi + ExtSigHdr.ExtSigHdrCount]
|
|
|
|
; Move pointer to first signature structure
|
|
add edi, ExtSigHdr.size
|
|
|
|
CheckExtSig:
|
|
; Check if extended signature and platform ID match
|
|
cmp dword [edi + ExtSig.ExtSigProcessor], ebx
|
|
jne LoadMicrocodeDefault2
|
|
test dword [edi + ExtSig.ExtSigFlags], edx
|
|
jnz LoadMicrocode ; Jif signature and platform ID match
|
|
LoadMicrocodeDefault2:
|
|
; Check if any more extended signatures exist
|
|
add edi, ExtSig.size
|
|
loop CheckExtSig
|
|
|
|
NextMicrocode:
|
|
; Advance just after end of this microcode
|
|
xor rax, rax
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrTotalSize], eax
|
|
je LoadMicrocodeDefault3
|
|
add esi, dword [esi + MicrocodeHdr.MicrocodeHdrTotalSize]
|
|
jmp CheckAddress
|
|
LoadMicrocodeDefault3:
|
|
add esi, dword 2048
|
|
jmp CheckAddress
|
|
|
|
AdvanceFixedSize:
|
|
; Advance by 4X dwords
|
|
add esi, dword 1024
|
|
|
|
CheckAddress:
|
|
; Check UPD header revision
|
|
cmp byte [rsp + LoadMicrocodeParamsFsp24.FspUpdHeaderRevision], 2
|
|
jb ParamError
|
|
cmp byte [rsp + LoadMicrocodeParamsFsp24.FsptArchRevision], 2
|
|
jne ParamError
|
|
|
|
; UPD structure is compliant with FSP spec 2.4
|
|
; Is automatic size detection ?
|
|
mov rax, qword [rsp + LoadMicrocodeParamsFsp24.MicrocodeCodeSize]
|
|
mov rcx, 0ffffffffffffffffh
|
|
cmp rax, rcx
|
|
jz LoadMicrocodeDefault4
|
|
|
|
; Address >= microcode region address + microcode region size?
|
|
add rax, qword [rsp + LoadMicrocodeParamsFsp24.MicrocodeCodeAddr]
|
|
cmp rsi, rax
|
|
jae Done ;Jif address is outside of microcode region
|
|
jmp CheckMainHeader
|
|
|
|
LoadMicrocodeDefault4:
|
|
; Is valid Microcode start point ?
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrVersion], 0ffffffffh
|
|
jz Done
|
|
jmp CheckMainHeader
|
|
|
|
LoadMicrocode:
|
|
; EAX contains the linear address of the start of the Update Data
|
|
; EDX contains zero
|
|
; ECX contains 79h (IA32_BIOS_UPDT_TRIG)
|
|
; Start microcode load with wrmsr
|
|
mov eax, esi
|
|
add eax, MicrocodeHdr.size
|
|
xor edx, edx
|
|
mov ecx, MSR_IA32_BIOS_UPDT_TRIG
|
|
wrmsr
|
|
mov eax, 1
|
|
cpuid
|
|
|
|
Done:
|
|
mov ecx, MSR_IA32_BIOS_SIGN_ID
|
|
xor eax, eax ; Clear EAX
|
|
xor edx, edx ; Clear EDX
|
|
wrmsr ; Load 0 to MSR at 8Bh
|
|
|
|
mov eax, 1
|
|
cpuid
|
|
mov ecx, MSR_IA32_BIOS_SIGN_ID
|
|
rdmsr ; Get current microcode signature
|
|
xor eax, eax
|
|
test edx, edx
|
|
jnz Exit2
|
|
mov rax, 0800000000000000Eh
|
|
|
|
Exit2:
|
|
jmp rbp
|
|
|
|
|
|
global ASM_PFX(EstablishStackFsp)
|
|
ASM_PFX(EstablishStackFsp):
|
|
;
|
|
; Save parameter pointer in rdx
|
|
;
|
|
mov rdx, rcx
|
|
;
|
|
; Enable FSP STACK
|
|
;
|
|
mov rax, ASM_PFX(PcdGet32 (PcdTemporaryRamBase))
|
|
mov esp, DWORD[rax]
|
|
mov rax, ASM_PFX(PcdGet32 (PcdTemporaryRamSize))
|
|
add esp, DWORD[rax]
|
|
|
|
sub esp, 4
|
|
mov dword[esp], DATA_LEN_OF_MCUD ; Size of the data region
|
|
sub esp, 4
|
|
mov dword[esp], 4455434Dh ; Signature of the data region 'MCUD'
|
|
|
|
; check UPD structure revision (rdx + 8)
|
|
cmp byte [rdx + LoadMicrocodeParamsFsp24.FspUpdHeaderRevision], 2
|
|
jb ParamError1
|
|
cmp byte [rdx + LoadMicrocodeParamsFsp24.FsptArchRevision], 2
|
|
je Fsp24UpdHeader
|
|
|
|
ParamError1:
|
|
mov rax, 08000000000000002h
|
|
jmp EstablishStackFspExit
|
|
|
|
Fsp24UpdHeader:
|
|
; UPD structure is compliant with FSP spec 2.4
|
|
xor rax, rax
|
|
mov rax, qword [rdx + LoadMicrocodeParamsFsp24.CodeRegionSize] ; Code size sizeof(FSPT_UPD_COMMON) + 18h
|
|
sub rsp, 8
|
|
mov qword[rsp], rax
|
|
mov rax, qword [rdx + LoadMicrocodeParamsFsp24.CodeRegionBase] ; Code base sizeof(FSPT_UPD_COMMON) + 10h
|
|
sub rsp, 8
|
|
mov qword[rsp], rax
|
|
mov rax, qword [rdx + LoadMicrocodeParamsFsp24.MicrocodeCodeSize] ; Microcode size sizeof(FSPT_UPD_COMMON) + 8h
|
|
sub rsp, 8
|
|
mov qword[rsp], rax
|
|
mov rax, qword [rdx + LoadMicrocodeParamsFsp24.MicrocodeCodeAddr] ; Microcode base sizeof(FSPT_UPD_COMMON) + 0h
|
|
sub rsp, 8
|
|
mov qword[rsp], rax
|
|
|
|
ContinueAfterUpdPush:
|
|
;
|
|
; Save API entry/exit timestamp into stack
|
|
;
|
|
sub esp, 4
|
|
mov dword[esp], DATA_LEN_OF_PER0 ; Size of the data region
|
|
sub esp, 4
|
|
mov dword[esp], 30524550h ; Signature of the data region 'PER0'
|
|
rdtsc
|
|
sub esp, 4
|
|
mov dword[esp], edx
|
|
sub esp, 4
|
|
mov dword[esp], eax
|
|
LOAD_TS rax
|
|
push rax
|
|
|
|
;
|
|
; Terminator for the data on stack
|
|
;
|
|
push 0
|
|
|
|
;
|
|
; Set ECX/EDX to the BootLoader temporary memory range
|
|
;
|
|
mov rcx, ASM_PFX(PcdGet32 (PcdTemporaryRamBase))
|
|
mov edx, [ecx]
|
|
mov rcx, ASM_PFX(PcdGet32 (PcdTemporaryRamSize))
|
|
add edx, [ecx]
|
|
mov rcx, ASM_PFX(PcdGet32 (PcdFspReservedBufferSize))
|
|
sub edx, [ecx]
|
|
mov rcx, ASM_PFX(PcdGet32 (PcdTemporaryRamBase))
|
|
mov ecx, [ecx]
|
|
|
|
cmp ecx, edx ; If PcdFspReservedBufferSize >= PcdTemporaryRamSize, then error.
|
|
jb EstablishStackFspSuccess
|
|
mov rax, 08000000000000003h ; EFI_UNSUPPORTED
|
|
jmp EstablishStackFspExit
|
|
EstablishStackFspSuccess:
|
|
xor rax, rax
|
|
|
|
EstablishStackFspExit:
|
|
RET_YMM
|
|
|
|
;----------------------------------------------------------------------------
|
|
; TempRamInit API
|
|
;
|
|
; This FSP API will load the microcode update, enable code caching for the
|
|
; region specified by the boot loader and also setup a temporary stack to be
|
|
; used till main memory is initialized.
|
|
;
|
|
;----------------------------------------------------------------------------
|
|
global ASM_PFX(TempRamInitApi)
|
|
ASM_PFX(TempRamInitApi):
|
|
;
|
|
; Ensure both SSE and AVX are enabled
|
|
;
|
|
ENABLE_SSE
|
|
ENABLE_AVX
|
|
;
|
|
; Save RBP, RBX, RSI, RDI and RSP in YMM7, YMM8 and YMM6
|
|
;
|
|
SAVE_REGS
|
|
|
|
;
|
|
; Save BFV address in YMM9
|
|
;
|
|
SAVE_BFV rbp
|
|
|
|
;
|
|
; Save Input Parameter in YMM10
|
|
;
|
|
cmp rcx, 0
|
|
jnz ParamValid
|
|
|
|
;
|
|
; Fall back to default UPD
|
|
;
|
|
CALL_RDI ASM_PFX(AsmGetFspInfoHeaderNoStack)
|
|
xor rcx, rcx
|
|
mov ecx, DWORD [rax + 01Ch] ; Read FsptImageBaseAddress
|
|
add ecx, DWORD [rax + 024h] ; Get Cfg Region base address = FsptImageBaseAddress + CfgRegionOffset
|
|
ParamValid:
|
|
SAVE_RCX
|
|
|
|
;
|
|
; Save timestamp into YMM6
|
|
;
|
|
rdtsc
|
|
shl rdx, 32
|
|
or rax, rdx
|
|
SAVE_TS rax
|
|
|
|
;
|
|
; Sec Platform Init
|
|
;
|
|
CALL_YMM ASM_PFX(SecPlatformInit)
|
|
test rax, rax
|
|
jnz TempRamInitExit
|
|
|
|
; Load microcode
|
|
LOAD_RCX
|
|
CALL_YMM ASM_PFX(LoadMicrocodeDefault)
|
|
SAVE_UCODE_STATUS rax ; Save microcode return status in SLOT 0 in YMM9 (upper 128bits).
|
|
; @note If return value rax is not 0, microcode did not load, but continue and attempt to boot.
|
|
|
|
; Call Sec CAR Init
|
|
LOAD_RCX
|
|
CALL_YMM ASM_PFX(SecCarInit)
|
|
test rax, rax
|
|
jnz TempRamInitExit
|
|
|
|
LOAD_RCX
|
|
CALL_YMM ASM_PFX(EstablishStackFsp)
|
|
test rax, rax
|
|
jnz TempRamInitExit
|
|
|
|
LOAD_UCODE_STATUS rax ; Restore microcode status if no CAR init error from SLOT 0 in YMM9 (upper 128bits).
|
|
|
|
TempRamInitExit:
|
|
mov bl, al ; save al data in bl
|
|
mov al, 07Fh ; API exit postcode 7f
|
|
out 080h, al
|
|
mov al, bl ; restore al data from bl
|
|
|
|
;
|
|
; Load RBP, RBX, RSI, RDI and RSP from YMM7, YMM8 and YMM6
|
|
;
|
|
LOAD_REGS
|
|
LOAD_BFV rbp
|
|
ret
|
|
|
|
;----------------------------------------------------------------------------
|
|
; Module Entrypoint API
|
|
;----------------------------------------------------------------------------
|
|
global ASM_PFX(_ModuleEntryPoint)
|
|
ASM_PFX(_ModuleEntryPoint):
|
|
jmp $
|
|
|