;; @file | |
; Provide FSP API entry points. | |
; | |
; Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR> | |
; SPDX-License-Identifier: BSD-2-Clause-Patent | |
;; | |
SECTION .text | |
%include "SaveRestoreSseNasm.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(AsmGetFspInfoHeader) | |
;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 LoadMicrocodeParams | |
; FSP_UPD_HEADER { | |
.FspUpdHeader: resd 8 | |
; } | |
; FSPT_CORE_UPD { | |
.MicrocodeCodeAddr: resd 1 | |
.MicrocodeCodeSize: resd 1 | |
.CodeRegionBase: resd 1 | |
.CodeRegionSize: resd 1 | |
; } | |
.size: | |
endstruc | |
struc LoadMicrocodeParamsFsp22 | |
; FSP_UPD_HEADER { | |
.FspUpdHeaderSignature: resd 2 | |
.FspUpdHeaderRevision: resb 1 | |
.FspUpdHeaderReserved: resb 23 | |
; } | |
; FSPT_ARCH_UPD{ | |
.FsptArchUpd: resd 8 | |
; } | |
; FSPT_CORE_UPD { | |
.MicrocodeCodeAddr: resd 1 | |
.MicrocodeCodeSize: resd 1 | |
.CodeRegionBase: resd 1 | |
.CodeRegionSize: resd 1 | |
; } | |
.size: | |
endstruc | |
; | |
; Define SSE macros | |
; | |
; | |
;args 1: ReturnAddress 2:MmxRegister | |
; | |
%macro LOAD_MMX_EXT 2 | |
mov esi, %1 | |
movd %2, esi ; save ReturnAddress into MMX | |
%endmacro | |
; | |
;args 1: RoutineLabel 2:MmxRegister | |
; | |
%macro CALL_MMX_EXT 2 | |
mov esi, %%ReturnAddress | |
movd %2, esi ; save ReturnAddress into MMX | |
jmp %1 | |
%%ReturnAddress: | |
%endmacro | |
; | |
;arg 1:MmxRegister | |
; | |
%macro RET_ESI_EXT 1 | |
movd esi, %1 ; move ReturnAddress from MMX to ESI | |
jmp esi | |
%endmacro | |
; | |
;arg 1:RoutineLabel | |
; | |
%macro CALL_MMX 1 | |
CALL_MMX_EXT %1, mm7 | |
%endmacro | |
%macro RET_ESI 0 | |
RET_ESI_EXT mm7 | |
%endmacro | |
; | |
; @todo: The strong/weak implementation does not work. | |
; This needs to be reviewed later. | |
; | |
;------------------------------------------------------------------------------ | |
; | |
;;global ASM_PFX(SecPlatformInitDefault) | |
;ASM_PFX(SecPlatformInitDefault): | |
; ; Inputs: | |
; ; mm7 -> Return address | |
; ; Outputs: | |
; ; eax -> 0 - Successful, Non-zero - Failed. | |
; ; Register Usage: | |
; ; eax is cleared and ebp is used for return address. | |
; ; All others reserved. | |
; | |
; ; Save return address to EBP | |
; movd ebp, mm7 | |
; | |
; xor eax, eax | |
;Exit1: | |
; jmp ebp | |
;------------------------------------------------------------------------------ | |
global ASM_PFX(LoadMicrocodeDefault) | |
ASM_PFX(LoadMicrocodeDefault): | |
; Inputs: | |
; esp -> LoadMicrocodeParams pointer | |
; Register Usage: | |
; esp Preserved | |
; All others 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 EBP | |
movd ebp, mm7 | |
cmp esp, 0 | |
jz ParamError | |
mov eax, dword [esp + 4] ; Parameter pointer | |
cmp eax, 0 | |
jz ParamError | |
mov esp, eax | |
; skip loading Microcode if the MicrocodeCodeSize is zero | |
; and report error if size is less than 2k | |
; first check UPD header revision | |
cmp byte [esp + LoadMicrocodeParamsFsp22.FspUpdHeaderRevision], 2 | |
jae Fsp22UpdHeader | |
; UPD structure is compliant with FSP spec 2.0/2.1 | |
mov eax, dword [esp + LoadMicrocodeParams.MicrocodeCodeSize] | |
cmp eax, 0 | |
jz Exit2 | |
cmp eax, 0800h | |
jl ParamError | |
mov esi, dword [esp + LoadMicrocodeParams.MicrocodeCodeAddr] | |
cmp esi, 0 | |
jnz CheckMainHeader | |
jmp ParamError | |
Fsp22UpdHeader: | |
; UPD structure is compliant with FSP spec 2.2 | |
mov eax, dword [esp + LoadMicrocodeParamsFsp22.MicrocodeCodeSize] | |
cmp eax, 0 | |
jz Exit2 | |
cmp eax, 0800h | |
jl ParamError | |
mov esi, dword [esp + LoadMicrocodeParamsFsp22.MicrocodeCodeAddr] | |
cmp esi, 0 | |
jnz CheckMainHeader | |
ParamError: | |
mov eax, 080000002h | |
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 LoadCheck ; Jif signature and platform ID match | |
LoadMicrocodeDefault1: | |
; Check if extended header exists | |
; First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid | |
xor eax, eax | |
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 LoadCheck ; 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 eax, eax | |
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 [esp + LoadMicrocodeParamsFsp22.FspUpdHeaderRevision], 2 | |
jae Fsp22UpdHeader1 | |
; UPD structure is compliant with FSP spec 2.0/2.1 | |
; Is automatic size detection ? | |
mov eax, dword [esp + LoadMicrocodeParams.MicrocodeCodeSize] | |
cmp eax, 0ffffffffh | |
jz LoadMicrocodeDefault4 | |
; Address >= microcode region address + microcode region size? | |
add eax, dword [esp + LoadMicrocodeParams.MicrocodeCodeAddr] | |
cmp esi, eax | |
jae Done ;Jif address is outside of microcode region | |
jmp CheckMainHeader | |
Fsp22UpdHeader1: | |
; UPD structure is compliant with FSP spec 2.2 | |
; Is automatic size detection ? | |
mov eax, dword [esp + LoadMicrocodeParamsFsp22.MicrocodeCodeSize] | |
cmp eax, 0ffffffffh | |
jz LoadMicrocodeDefault4 | |
; Address >= microcode region address + microcode region size? | |
add eax, dword [esp + LoadMicrocodeParamsFsp22.MicrocodeCodeAddr] | |
cmp esi, eax | |
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 | |
LoadCheck: | |
; Get the revision of the current microcode update loaded | |
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 | |
; Verify this microcode update is not already loaded | |
cmp dword [esi + MicrocodeHdr.MicrocodeHdrRevision], edx | |
je Continue | |
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 | |
Continue: | |
jmp NextMicrocode | |
Done: | |
mov eax, 1 | |
cpuid | |
mov ecx, MSR_IA32_BIOS_SIGN_ID | |
rdmsr ; Get current microcode signature | |
xor eax, eax | |
cmp edx, 0 | |
jnz Exit2 | |
mov eax, 08000000Eh | |
Exit2: | |
jmp ebp | |
global ASM_PFX(EstablishStackFsp) | |
ASM_PFX(EstablishStackFsp): | |
; | |
; Save parameter pointer in edx | |
; | |
mov edx, dword [esp + 4] | |
; | |
; Enable FSP STACK | |
; | |
mov esp, DWORD [ASM_PFX(PcdGet32 (PcdTemporaryRamBase))] | |
add esp, DWORD [ASM_PFX(PcdGet32 (PcdTemporaryRamSize))] | |
push DATA_LEN_OF_MCUD ; Size of the data region | |
push 4455434Dh ; Signature of the data region 'MCUD' | |
; check UPD structure revision (edx + 8) | |
cmp byte [edx + LoadMicrocodeParamsFsp22.FspUpdHeaderRevision], 2 | |
jae Fsp22UpdHeader2 | |
; UPD structure is compliant with FSP spec 2.0/2.1 | |
push dword [edx + LoadMicrocodeParams.CodeRegionSize] ; Code size sizeof(FSPT_UPD_COMMON) + 12 | |
push dword [edx + LoadMicrocodeParams.CodeRegionBase] ; Code base sizeof(FSPT_UPD_COMMON) + 8 | |
push dword [edx + LoadMicrocodeParams.MicrocodeCodeSize] ; Microcode size sizeof(FSPT_UPD_COMMON) + 4 | |
push dword [edx + LoadMicrocodeParams.MicrocodeCodeAddr] ; Microcode base sizeof(FSPT_UPD_COMMON) + 0 | |
jmp ContinueAfterUpdPush | |
Fsp22UpdHeader2: | |
; UPD structure is compliant with FSP spec 2.2 | |
push dword [edx + LoadMicrocodeParamsFsp22.CodeRegionSize] ; Code size sizeof(FSPT_UPD_COMMON) + 12 | |
push dword [edx + LoadMicrocodeParamsFsp22.CodeRegionBase] ; Code base sizeof(FSPT_UPD_COMMON) + 8 | |
push dword [edx + LoadMicrocodeParamsFsp22.MicrocodeCodeSize] ; Microcode size sizeof(FSPT_UPD_COMMON) + 4 | |
push dword [edx + LoadMicrocodeParamsFsp22.MicrocodeCodeAddr] ; Microcode base sizeof(FSPT_UPD_COMMON) + 0 | |
ContinueAfterUpdPush: | |
; | |
; Save API entry/exit timestamp into stack | |
; | |
push DATA_LEN_OF_PER0 ; Size of the data region | |
push 30524550h ; Signature of the data region 'PER0' | |
rdtsc | |
push edx | |
push eax | |
LOAD_EDX | |
push edx | |
LOAD_EAX | |
push eax | |
; | |
; Terminator for the data on stack | |
; | |
push 0 | |
; | |
; Set ECX/EDX to the BootLoader temporary memory range | |
; | |
mov ecx, [ASM_PFX(PcdGet32 (PcdTemporaryRamBase))] | |
mov edx, ecx | |
add edx, [ASM_PFX(PcdGet32 (PcdTemporaryRamSize))] | |
sub edx, [ASM_PFX(PcdGet32 (PcdFspReservedBufferSize))] | |
cmp ecx, edx ;If PcdFspReservedBufferSize >= PcdTemporaryRamSize, then error. | |
jb EstablishStackFspSuccess | |
mov eax, 80000003h ;EFI_UNSUPPORTED | |
jmp EstablishStackFspExit | |
EstablishStackFspSuccess: | |
xor eax, eax | |
EstablishStackFspExit: | |
RET_ESI | |
;---------------------------------------------------------------------------- | |
; 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 SSE is enabled | |
; | |
ENABLE_SSE | |
; | |
; Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6 | |
; | |
SAVE_REGS | |
; | |
; Save timestamp into XMM6 | |
; | |
rdtsc | |
SAVE_EAX | |
SAVE_EDX | |
; | |
; Check Parameter | |
; | |
mov eax, dword [esp + 4] | |
cmp eax, 0 | |
mov eax, 80000002h | |
jz TempRamInitExit | |
; | |
; Sec Platform Init | |
; | |
CALL_MMX ASM_PFX(SecPlatformInit) | |
cmp eax, 0 | |
jnz TempRamInitExit | |
; Load microcode | |
LOAD_ESP | |
CALL_MMX ASM_PFX(LoadMicrocodeDefault) | |
SXMMN xmm6, 3, eax ;Save microcode return status in ECX-SLOT 3 in xmm6. | |
;@note If return value eax is not 0, microcode did not load, but continue and attempt to boot. | |
; Call Sec CAR Init | |
LOAD_ESP | |
CALL_MMX ASM_PFX(SecCarInit) | |
cmp eax, 0 | |
jnz TempRamInitExit | |
LOAD_ESP | |
CALL_MMX ASM_PFX(EstablishStackFsp) | |
cmp eax, 0 | |
jnz TempRamInitExit | |
LXMMN xmm6, eax, 3 ;Restore microcode status if no CAR init error from ECX-SLOT 3 in xmm6. | |
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 EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6 | |
; | |
LOAD_REGS | |
ret | |
;---------------------------------------------------------------------------- | |
; Module Entrypoint API | |
;---------------------------------------------------------------------------- | |
global ASM_PFX(_ModuleEntryPoint) | |
ASM_PFX(_ModuleEntryPoint): | |
jmp $ |