Update ApiEntry.asm to use MACRO instead of direct XMM access. Add sanity parameter check for FSP API. Add sanity return code check for internal API. Call LoadUcode before CarInit to meet silicon requirement. Remove unnecessary VpdBase for PatchTable. Add ASSERT for NULL check FSP1.1 entrypoint. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Yao, Jiewen" <jiewen.yao@intel.com> Reviewed-by: "Rangarajan, Ravi P" <ravi.p.rangarajan@intel.com> Reviewed-by: "Ma, Maurice" <maurice.ma@intel.com> Reviewed-by: "Mudusuru, Giri P" <giri.p.mudusuru@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16834 6f19259b-4bc3-4df7-8a09-765794883524
621 lines
15 KiB
NASM
621 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 UcodeLoad.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 GetFspBaseAddress:PROC
|
|
EXTERN GetBootFirmwareVolumeOffset:PROC
|
|
EXTERN Pei2LoaderSwitchStack:PROC
|
|
EXTERN FspSelfCheck(FspSelfCheckDflt):PROC
|
|
EXTERN LoadUcode(LoadUcodeDflt):PROC
|
|
EXTERN SecPlatformInit(SecPlatformInitDflt):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 MM7
|
|
ENDM
|
|
|
|
CALL_MMX_EXT MACRO RoutineLabel, MmxRegister
|
|
local ReturnAddress
|
|
mov esi, offset ReturnAddress
|
|
movd MmxRegister, esi ; save ReturnAddress into MM7
|
|
jmp RoutineLabel
|
|
ReturnAddress:
|
|
ENDM
|
|
|
|
RET_ESI_EXT MACRO MmxRegister
|
|
movd esi, MmxRegister ; restore ESP from MM7
|
|
jmp esi
|
|
ENDM
|
|
|
|
CALL_MMX MACRO RoutineLabel
|
|
CALL_MMX_EXT RoutineLabel, mm7
|
|
ENDM
|
|
|
|
RET_ESI MACRO
|
|
RET_ESI_EXT mm7
|
|
ENDM
|
|
|
|
;------------------------------------------------------------------------------
|
|
FspSelfCheckDflt PROC NEAR PUBLIC
|
|
; Inputs:
|
|
; eax -> 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
|
|
mov ebp, eax
|
|
|
|
xor eax, eax
|
|
exit:
|
|
jmp ebp
|
|
FspSelfCheckDflt ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
SecPlatformInitDflt PROC NEAR PUBLIC
|
|
; Inputs:
|
|
; eax -> 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
|
|
mov ebp, eax
|
|
|
|
xor eax, eax
|
|
exit:
|
|
jmp ebp
|
|
SecPlatformInitDflt ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
LoadUcodeDflt PROC NEAR PUBLIC
|
|
; Inputs:
|
|
; esp -> LOAD_UCODE_PARAMS 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] ; Parameter pointer
|
|
cmp eax, 0
|
|
jz paramerror
|
|
mov esp, eax
|
|
mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
|
|
cmp esi, 0
|
|
jnz check_main_header
|
|
|
|
paramerror:
|
|
mov eax, 080000002h
|
|
jmp exit
|
|
|
|
mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
|
|
|
|
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
|
|
and ecx, 7h
|
|
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].ucode_hdr.version, eax
|
|
jne advance_fixed_size
|
|
cmp [esi].ucode_hdr.loader, eax
|
|
jne advance_fixed_size
|
|
|
|
; Check if signature and plaform ID match
|
|
cmp ebx, [esi].ucode_hdr.processor
|
|
jne @f
|
|
test edx, [esi].ucode_hdr.flags
|
|
jnz load_check ; Jif signature and platform ID match
|
|
|
|
@@:
|
|
; Check if extended header exists
|
|
; First check if total_size and data_size are valid
|
|
xor eax, eax
|
|
cmp [esi].ucode_hdr.total_size, eax
|
|
je next_microcode
|
|
cmp [esi].ucode_hdr.data_size, eax
|
|
je next_microcode
|
|
|
|
; Then verify total size - sizeof header > data size
|
|
mov ecx, [esi].ucode_hdr.total_size
|
|
sub ecx, sizeof ucode_hdr
|
|
cmp ecx, [esi].ucode_hdr.data_size
|
|
jng next_microcode ; Jif extended header does not exist
|
|
|
|
; Set edi -> extended header
|
|
mov edi, esi
|
|
add edi, sizeof ucode_hdr
|
|
add edi, [esi].ucode_hdr.data_size
|
|
|
|
; Get count of extended structures
|
|
mov ecx, [edi].ext_sig_hdr.count
|
|
|
|
; Move pointer to first signature structure
|
|
add edi, sizeof ext_sig_hdr
|
|
|
|
check_ext_sig:
|
|
; Check if extended signature and platform ID match
|
|
cmp [edi].ext_sig.processor, ebx
|
|
jne @f
|
|
test [edi].ext_sig.flags, edx
|
|
jnz load_check ; Jif signature and platform ID match
|
|
@@:
|
|
; Check if any more extended signatures exist
|
|
add edi, sizeof ext_sig
|
|
loop check_ext_sig
|
|
|
|
next_microcode:
|
|
; Advance just after end of this microcode
|
|
xor eax, eax
|
|
cmp [esi].ucode_hdr.total_size, eax
|
|
je @f
|
|
add esi, [esi].ucode_hdr.total_size
|
|
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].ucode_hdr.version, 0ffffffffh
|
|
jz done
|
|
|
|
; Is automatic size detection ?
|
|
mov eax, [esp].LOAD_UCODE_PARAMS.ucode_code_size
|
|
cmp eax, 0ffffffffh
|
|
jz @f
|
|
|
|
; Address >= microcode region address + microcode region size?
|
|
add eax, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
|
|
cmp esi, eax
|
|
jae done ;Jif address is outside of ucode 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].ucode_hdr.revision, 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 ucode_hdr
|
|
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
|
|
|
|
LoadUcodeDflt 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
|
|
cmp edx, 0 ; Is parameter pointer valid ?
|
|
jz InvalidMicrocodeRegion
|
|
push dword ptr [edx + 4] ; Microcode size
|
|
push dword ptr [edx] ; Microcode base
|
|
jmp @F
|
|
|
|
InvalidMicrocodeRegion:
|
|
push 0 ; Microcode size
|
|
push 0 ; 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 XMM4 & XMM5
|
|
;
|
|
rdtsc
|
|
SAVE_EAX
|
|
SAVE_EDX
|
|
|
|
;
|
|
; Check Parameter
|
|
;
|
|
mov eax, dword ptr [esp + 4]
|
|
cmp eax, 0
|
|
mov eax, 80000002h
|
|
jz NemInitExit
|
|
|
|
;
|
|
; CPUID/DeviceID check
|
|
;
|
|
mov eax, @F
|
|
jmp FspSelfCheck ; Note: ESP can not be changed.
|
|
@@:
|
|
cmp eax, 0
|
|
jnz NemInitExit
|
|
|
|
CALL_MMX SecPlatformInit
|
|
cmp eax, 0
|
|
jnz NemInitExit
|
|
|
|
; Load microcode
|
|
LOAD_ESP
|
|
CALL_MMX LoadUcode
|
|
cmp eax, 0
|
|
jnz NemInitExit
|
|
|
|
; Call Sec CAR Init
|
|
LOAD_ESP
|
|
CALL_MMX SecCarInit
|
|
cmp eax, 0
|
|
jnz NemInitExit
|
|
|
|
LOAD_ESP
|
|
CALL_MMX EstablishStackFsp
|
|
|
|
NemInitExit:
|
|
;
|
|
; 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 eax
|
|
call FspApiCallingCheck
|
|
add esp, 4
|
|
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
|
|
jmp Pei2LoaderSwitchStack
|
|
|
|
@@:
|
|
;
|
|
; FspInit and FspMemoryInit APIs, setup the initial stack frame
|
|
;
|
|
|
|
;
|
|
; Store the address in FSP which will return control to the BL
|
|
;
|
|
push offset exit
|
|
|
|
;
|
|
; 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 GetFspBaseAddress
|
|
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 impleantion with single FV, PcdFlashFvRecoveryBase and
|
|
; PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
|
|
; they are different. The code below can handle both cases.
|
|
;
|
|
call GetFspBaseAddress
|
|
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
|
|
|
|
exit:
|
|
ret
|
|
|
|
FspApiCommon ENDP
|
|
|
|
END
|