mirror of https://github.com/acidanthera/audk.git
478 lines
13 KiB
NASM
478 lines
13 KiB
NASM
;; @file
|
|
; Provide FSP API entry points.
|
|
;
|
|
; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
|
; This program and the accompanying materials
|
|
; are licensed and made available under the terms and conditions of the BSD License
|
|
; which accompanies this distribution. The full text of the license may be found at
|
|
; http://opensource.org/licenses/bsd-license.php.
|
|
;
|
|
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
;;
|
|
|
|
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
|
|
|
|
|
|
;
|
|
; 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
|
|
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
|
|
|
|
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:
|
|
; Is valid Microcode start point ?
|
|
cmp dword [esi + MicrocodeHdr.MicrocodeHdrVersion], 0ffffffffh
|
|
jz Done
|
|
|
|
; 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
|
|
|
|
LoadMicrocodeDefault4:
|
|
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'
|
|
push dword [edx + 2Ch] ; Code size sizeof(FSPT_UPD_COMMON) + 12
|
|
push dword [edx + 28h] ; Code base sizeof(FSPT_UPD_COMMON) + 8
|
|
push dword [edx + 24h] ; Microcode size sizeof(FSPT_UPD_COMMON) + 4
|
|
push dword [edx + 20h] ; Microcode base sizeof(FSPT_UPD_COMMON) + 0
|
|
|
|
;
|
|
; 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 $
|