audk/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.asm

602 lines
15 KiB
NASM

;; @file
; Provide FSP API entry points.
;
; Copyright (c) 2014 - 2015, 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.
;;
.586p
.model flat,C
.code
.xmm
INCLUDE SaveRestoreSse.inc
INCLUDE MicrocodeLoad.inc
;
; Following are fixed PCDs
;
EXTERN PcdGet32(PcdTemporaryRamBase):DWORD
EXTERN PcdGet32(PcdTemporaryRamSize):DWORD
EXTERN PcdGet32(PcdFspTemporaryRamSize):DWORD
EXTERN PcdGet32(PcdFspAreaSize):DWORD
;
; Following functions will be provided in C
;
EXTERN SecStartup:PROC
EXTERN FspApiCallingCheck:PROC
;
; Following functions will be provided in PlatformSecLib
;
EXTERN AsmGetFspBaseAddress:PROC
EXTERN AsmGetFspInfoHeader:PROC
EXTERN GetBootFirmwareVolumeOffset:PROC
EXTERN Loader2PeiSwitchStack:PROC
EXTERN LoadMicrocode(LoadMicrocodeDefault):PROC
EXTERN SecPlatformInit(SecPlatformInitDefault):PROC
EXTERN SecCarInit:PROC
;
; 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)
;
; Define SSE macros
;
LOAD_MMX_EXT MACRO ReturnAddress, MmxRegister
mov esi, ReturnAddress
movd MmxRegister, esi ; save ReturnAddress into MMX
ENDM
CALL_MMX_EXT MACRO RoutineLabel, MmxRegister
local ReturnAddress
mov esi, offset ReturnAddress
movd MmxRegister, esi ; save ReturnAddress into MMX
jmp RoutineLabel
ReturnAddress:
ENDM
RET_ESI_EXT MACRO MmxRegister
movd esi, MmxRegister ; move ReturnAddress from MMX to ESI
jmp esi
ENDM
CALL_MMX MACRO RoutineLabel
CALL_MMX_EXT RoutineLabel, mm7
ENDM
RET_ESI MACRO
RET_ESI_EXT mm7
ENDM
;------------------------------------------------------------------------------
SecPlatformInitDefault PROC NEAR PUBLIC
; 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
exit:
jmp ebp
SecPlatformInitDefault ENDP
;------------------------------------------------------------------------------
LoadMicrocodeDefault PROC NEAR PUBLIC
; 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 ptr [esp + 4] ; Parameter pointer
cmp eax, 0
jz paramerror
mov esp, eax
mov esi, [esp].LoadMicrocodeParams.MicrocodeCodeAddr
cmp esi, 0
jnz check_main_header
paramerror:
mov eax, 080000002h
jmp exit
mov esi, [esp].LoadMicrocodeParams.MicrocodeCodeAddr
check_main_header:
; 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 paramters
; 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 ptr 1
cmp [esi].MicrocodeHdr.MicrocodeHdrVersion, eax
jne advance_fixed_size
cmp [esi].MicrocodeHdr.MicrocodeHdrLoader, eax
jne advance_fixed_size
; Check if signature and plaform ID match
cmp ebx, [esi].MicrocodeHdr.MicrocodeHdrProcessor
jne @f
test edx, [esi].MicrocodeHdr.MicrocodeHdrFlags
jnz load_check ; Jif signature and platform ID match
@@:
; Check if extended header exists
; First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
xor eax, eax
cmp [esi].MicrocodeHdr.MicrocodeHdrTotalSize, eax
je next_microcode
cmp [esi].MicrocodeHdr.MicrocodeHdrDataSize, eax
je next_microcode
; Then verify total size - sizeof header > data size
mov ecx, [esi].MicrocodeHdr.MicrocodeHdrTotalSize
sub ecx, sizeof MicrocodeHdr
cmp ecx, [esi].MicrocodeHdr.MicrocodeHdrDataSize
jng next_microcode ; Jif extended header does not exist
; Set edi -> extended header
mov edi, esi
add edi, sizeof MicrocodeHdr
add edi, [esi].MicrocodeHdr.MicrocodeHdrDataSize
; Get count of extended structures
mov ecx, [edi].ExtSigHdr.ExtSigHdrCount
; Move pointer to first signature structure
add edi, sizeof ExtSigHdr
check_ext_sig:
; Check if extended signature and platform ID match
cmp [edi].ExtSig.ExtSigProcessor, ebx
jne @f
test [edi].ExtSig.ExtSigFlags, edx
jnz load_check ; Jif signature and platform ID match
@@:
; Check if any more extended signatures exist
add edi, sizeof ExtSig
loop check_ext_sig
next_microcode:
; Advance just after end of this microcode
xor eax, eax
cmp [esi].MicrocodeHdr.MicrocodeHdrTotalSize, eax
je @f
add esi, [esi].MicrocodeHdr.MicrocodeHdrTotalSize
jmp check_address
@@:
add esi, dword ptr 2048
jmp check_address
advance_fixed_size:
; Advance by 4X dwords
add esi, dword ptr 1024
check_address:
; Is valid Microcode start point ?
cmp dword ptr [esi].MicrocodeHdr.MicrocodeHdrVersion, 0ffffffffh
jz done
; Is automatic size detection ?
mov eax, [esp].LoadMicrocodeParams.MicrocodeCodeSize
cmp eax, 0ffffffffh
jz @f
; Address >= microcode region address + microcode region size?
add eax, [esp].LoadMicrocodeParams.MicrocodeCodeAddr
cmp esi, eax
jae done ;Jif address is outside of microcode region
jmp check_main_header
@@:
load_check:
; 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 [esi].MicrocodeHdr.MicrocodeHdrRevision, edx
je continue
load_microcode:
; 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, sizeof MicrocodeHdr
xor edx, edx
mov ecx, MSR_IA32_BIOS_UPDT_TRIG
wrmsr
mov eax, 1
cpuid
continue:
jmp next_microcode
done:
mov eax, 1
cpuid
mov ecx, MSR_IA32_BIOS_SIGN_ID
rdmsr ; Get current microcode signature
xor eax, eax
cmp edx, 0
jnz exit
mov eax, 08000000Eh
exit:
jmp ebp
LoadMicrocodeDefault ENDP
EstablishStackFsp PROC NEAR PRIVATE
;
; Save parameter pointer in edx
;
mov edx, dword ptr [esp + 4]
;
; Enable FSP STACK
;
mov esp, PcdGet32 (PcdTemporaryRamBase)
add esp, PcdGet32 (PcdTemporaryRamSize)
push DATA_LEN_OF_MCUD ; Size of the data region
push 4455434Dh ; Signature of the data region 'MCUD'
push dword ptr [edx + 12] ; Code size
push dword ptr [edx + 8] ; Code base
push dword ptr [edx + 4] ; Microcode size
push dword ptr [edx] ; Microcode base
;
; 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'
LOAD_EDX
push edx
LOAD_EAX
push eax
rdtsc
push edx
push eax
;
; Terminator for the data on stack
;
push 0
;
; Set ECX/EDX to the BootLoader temporary memory range
;
mov ecx, PcdGet32 (PcdTemporaryRamBase)
mov edx, ecx
add edx, PcdGet32 (PcdTemporaryRamSize)
sub edx, PcdGet32 (PcdFspTemporaryRamSize)
xor eax, eax
RET_ESI
EstablishStackFsp ENDP
;----------------------------------------------------------------------------
; 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.
;
;----------------------------------------------------------------------------
TempRamInitApi PROC NEAR PUBLIC
;
; 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 ptr [esp + 4]
cmp eax, 0
mov eax, 80000002h
jz TempRamInitExit
;
; Sec Platform Init
;
CALL_MMX SecPlatformInit
cmp eax, 0
jnz TempRamInitExit
; Load microcode
LOAD_ESP
CALL_MMX LoadMicrocode
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 SecCarInit
cmp eax, 0
jnz TempRamInitExit
LOAD_ESP
CALL_MMX EstablishStackFsp
LXMMN xmm6, eax, 3 ;Restore microcode status if no CAR init error from ECX-SLOT 3 in xmm6.
TempRamInitExit:
;
; Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
;
LOAD_REGS
ret
TempRamInitApi ENDP
;----------------------------------------------------------------------------
; FspInit API
;
; This FSP API will perform the processor and chipset initialization.
; This API will not return. Instead, it transfers the control to the
; ContinuationFunc provided in the parameter.
;
;----------------------------------------------------------------------------
FspInitApi PROC NEAR PUBLIC
mov eax, 1
jmp FspApiCommon
FspInitApi ENDP
;----------------------------------------------------------------------------
; NotifyPhase API
;
; This FSP API will notify the FSP about the different phases in the boot
; process
;
;----------------------------------------------------------------------------
NotifyPhaseApi PROC C PUBLIC
mov eax, 2
jmp FspApiCommon
NotifyPhaseApi ENDP
;----------------------------------------------------------------------------
; FspMemoryInit API
;
; This FSP API is called after TempRamInit and initializes the memory.
;
;----------------------------------------------------------------------------
FspMemoryInitApi PROC NEAR PUBLIC
mov eax, 3
jmp FspApiCommon
FspMemoryInitApi ENDP
;----------------------------------------------------------------------------
; TempRamExitApi API
;
; This API tears down temporary RAM
;
;----------------------------------------------------------------------------
TempRamExitApi PROC C PUBLIC
mov eax, 4
jmp FspApiCommon
TempRamExitApi ENDP
;----------------------------------------------------------------------------
; FspSiliconInit API
;
; This FSP API initializes the CPU and the chipset including the IO
; controllers in the chipset to enable normal operation of these devices.
;
;----------------------------------------------------------------------------
FspSiliconInitApi PROC C PUBLIC
mov eax, 5
jmp FspApiCommon
FspSiliconInitApi ENDP
;----------------------------------------------------------------------------
; FspApiCommon API
;
; This is the FSP API common entry point to resume the FSP execution
;
;----------------------------------------------------------------------------
FspApiCommon PROC C PUBLIC
;
; EAX holds the API index
;
;
; Stack must be ready
;
push eax
add esp, 4
cmp eax, dword ptr [esp - 4]
jz @F
mov eax, 080000003h
jmp exit
@@:
;
; Verify the calling condition
;
pushad
push [esp + 4 * 8 + 4] ; push ApiParam
push eax ; push ApiIdx
call FspApiCallingCheck
add esp, 8
cmp eax, 0
jz @F
mov dword ptr [esp + 4 * 7], eax
popad
ret
@@:
popad
cmp eax, 1 ; FspInit API
jz @F
cmp eax, 3 ; FspMemoryInit API
jz @F
call AsmGetFspInfoHeader
jmp Loader2PeiSwitchStack
@@:
;
; FspInit and FspMemoryInit APIs, setup the initial stack frame
;
;
; Place holder to store the FspInfoHeader pointer
;
push eax
;
; Update the FspInfoHeader pointer
;
push eax
call AsmGetFspInfoHeader
mov [esp + 4], eax
pop eax
;
; Create a Task Frame in the stack for the Boot Loader
;
pushfd ; 2 pushf for 4 byte alignment
cli
pushad
; Reserve 8 bytes for IDT save/restore
sub esp, 8
sidt fword ptr [esp]
;
; Setup new FSP stack
;
mov edi, esp
mov esp, PcdGet32(PcdTemporaryRamBase)
add esp, PcdGet32(PcdTemporaryRamSize)
sub esp, (DATA_LEN_AT_STACK_TOP + 40h)
;
; Pass the API Idx to SecStartup
;
push eax
;
; Pass the BootLoader stack to SecStartup
;
push edi
;
; Pass entry point of the PEI core
;
call AsmGetFspBaseAddress
mov edi, eax
add edi, PcdGet32 (PcdFspAreaSize)
sub edi, 20h
add eax, DWORD PTR ds:[edi]
push eax
;
; Pass BFV into the PEI Core
; It uses relative address to calucate the actual boot FV base
; For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and
; PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
; they are different. The code below can handle both cases.
;
call AsmGetFspBaseAddress
mov edi, eax
call GetBootFirmwareVolumeOffset
add eax, edi
push eax
;
; Pass stack base and size into the PEI Core
;
mov eax, PcdGet32(PcdTemporaryRamBase)
add eax, PcdGet32(PcdTemporaryRamSize)
sub eax, PcdGet32(PcdFspTemporaryRamSize)
push eax
push PcdGet32(PcdFspTemporaryRamSize)
;
; Pass Control into the PEI Core
;
call SecStartup
add esp, 4
exit:
ret
FspApiCommon ENDP
END