mirror of https://github.com/acidanthera/audk.git
602 lines
15 KiB
NASM
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
|