#------------------------------------------------------------------------------ | |
# | |
# 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. | |
# | |
# Abstract: | |
# | |
# Provide FSP API entry points. | |
# | |
#------------------------------------------------------------------------------ | |
.equ MSR_IA32_PLATFORM_ID, 0x00000017 | |
.equ MSR_IA32_BIOS_UPDT_TRIG, 0x00000079 | |
.equ MSR_IA32_BIOS_SIGN_ID, 0x0000008b | |
MicrocodeHdr: | |
.equ MicrocodeHdrVersion, 0x0000 | |
.equ MicrocodeHdrRevision, 0x0004 | |
.equ MicrocodeHdrDate, 0x0008 | |
.equ MicrocodeHdrProcessor, 0x000c | |
.equ MicrocodeHdrChecksum, 0x0010 | |
.equ MicrocodeHdrLoader, 0x0014 | |
.equ MicrocodeHdrFlags, 0x0018 | |
.equ MicrocodeHdrDataSize, 0x001C | |
.equ MicrocodeHdrTotalSize, 0x0020 | |
.equ MicrocodeHdrRsvd, 0x0024 | |
MicrocodeHdrEnd: | |
.equ MicrocodeHdrLength, 0x0030 # MicrocodeHdrLength = MicrocodeHdrEnd - MicrocodeHdr | |
ExtSigHdr: | |
.equ ExtSigHdrCount, 0x0000 | |
.equ ExtSigHdrChecksum, 0x0004 | |
.equ ExtSigHdrRsvd, 0x0008 | |
ExtSigHdrEnd: | |
.equ ExtSigHdrLength, 0x0014 #ExtSigHdrLength = ExtSigHdrEnd - ExtSigHdr | |
ExtSig: | |
.equ ExtSigProcessor, 0x0000 | |
.equ ExtSigFlags, 0x0004 | |
.equ ExtSigChecksum, 0x0008 | |
ExtSigEnd: | |
.equ ExtSigLength, 0x000C #ExtSigLength = ExtSigEnd - ExtSig | |
LoadMicrocodeParams: | |
.equ MicrocodeCodeAddr, 0x0000 | |
.equ MicrocodeCodeSize, 0x0004 | |
LoadMicrocodeParamsEnd: | |
.macro SAVE_REGS | |
pinsrw $0x00, %ebp, %xmm7 | |
ror $0x10, %ebp | |
pinsrw $0x01, %ebp, %xmm7 | |
ror $0x10, %ebp | |
# | |
pinsrw $0x02, %ebx, %xmm7 | |
ror $0x10, %ebx | |
pinsrw $0x03, %ebx, %xmm7 | |
ror $0x10, %ebx | |
# | |
pinsrw $0x04, %esi, %xmm7 | |
ror $0x10, %esi | |
pinsrw $0x05, %esi, %xmm7 | |
ror $0x10, %esi | |
# | |
pinsrw $0x06, %edi, %xmm7 | |
ror $0x10, %edi | |
pinsrw $0x07, %edi, %xmm7 | |
ror $0x10, %edi | |
# | |
pinsrw $0x00, %esp, %xmm6 | |
ror $0x10, %esp | |
pinsrw $0x01, %esp, %xmm6 | |
ror $0x10, %esp | |
.endm | |
.macro LOAD_REGS | |
pshufd $0xe4, %xmm7, %xmm7 | |
movd %xmm7, %ebp | |
pshufd $0xe4, %xmm7, %xmm7 | |
# | |
pshufd $0x39, %xmm7, %xmm7 | |
movd %xmm7, %ebx | |
pshufd $0x93, %xmm7, %xmm7 | |
# | |
pshufd $0x4e, %xmm7, %xmm7 | |
movd %xmm7, %esi | |
pshufd $0x4e, %xmm7, %xmm7 | |
# | |
pshufd $0x93, %xmm7, %xmm7 | |
movd %xmm7, %edi | |
pshufd $0x39, %xmm7, %xmm7 | |
# | |
movd %xmm6, %esp | |
.endm | |
.macro LOAD_EAX | |
pshufd $0x39, %xmm6, %xmm6 | |
movd %xmm6, %eax | |
pshufd $0x93, %xmm6, %xmm6 | |
.endm | |
.macro LOAD_EDX | |
pshufd $0xe4, %xmm6, %xmm6 | |
movd %xmm6, %edx | |
pshufd $0xe4, %xmm6, %xmm6 | |
.endm | |
.macro SAVE_EAX | |
pinsrw $0x02, %eax, %xmm6 | |
ror $0x10, %eax | |
pinsrw $0x03, %eax, %xmm6 | |
ror $0x10, %eax | |
.endm | |
.macro SAVE_EDX | |
pinsrw $0x04, %edx, %xmm6 | |
ror $0x10, %edx | |
pinsrw $0x05, %edx, %xmm6 | |
ror $0x10, %edx | |
.endm | |
.macro LOAD_ESP | |
movd %xmm6, %esp | |
.endm | |
.macro ENABLE_SSE | |
jmp NextAddress | |
.align 4 | |
# | |
# Float control word initial value: | |
# all exceptions masked, double-precision, round-to-nearest | |
# | |
ASM_PFX(mFpuControlWord): .word 0x027F | |
# | |
# Multimedia-extensions control word: | |
# all exceptions masked, round-to-nearest, flush to zero for masked underflow | |
# | |
ASM_PFX(mMmxControlWord): .long 0x01F80 | |
SseError: | |
# | |
# Processor has to support SSE | |
# | |
jmp SseError | |
NextAddress: | |
# | |
# Initialize floating point units | |
# | |
finit | |
fldcw ASM_PFX(mFpuControlWord) | |
# | |
# Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test | |
# whether the processor supports SSE instruction. | |
# | |
movl $1, %eax | |
cpuid | |
btl $25, %edx | |
jnc SseError | |
# | |
# Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10) | |
# | |
movl %cr4, %eax | |
orl $BIT9, %eax | |
movl %eax, %cr4 | |
# | |
# The processor should support SSE instruction and we can use | |
# ldmxcsr instruction | |
# | |
ldmxcsr ASM_PFX(mMmxControlWord) | |
.endm | |
#Save in ECX-SLOT 3 in xmm6. | |
.macro SAVE_EAX_MICROCODE_RET_STATUS | |
pinsrw $0x6, %eax, %xmm6 | |
ror $0x10, %eax | |
pinsrw $0x7, %eax, %xmm6 | |
rol $0x10, %eax | |
.endm | |
#Restore from ECX-SLOT 3 in xmm6. | |
.macro LOAD_EAX_MICROCODE_RET_STATUS | |
pshufd $0x93, %xmm6, %xmm6 | |
movd %xmm6, %eax | |
pshufd $0x39, %xmm6, %xmm6 | |
.endm | |
# | |
# Following are fixed PCDs | |
# | |
ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase) | |
ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize) | |
ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize) | |
# | |
# Following functions will be provided in C | |
# | |
ASM_GLOBAL ASM_PFX(SecStartup) | |
ASM_GLOBAL ASM_PFX(FspApiCallingCheck) | |
# | |
# Following functions will be provided in PlatformSecLib | |
# | |
ASM_GLOBAL ASM_PFX(AsmGetFspBaseAddress) | |
ASM_GLOBAL ASM_PFX(AsmGetFspInfoHeader) | |
ASM_GLOBAL ASM_PFX(GetBootFirmwareVolumeOffset) | |
ASM_GLOBAL ASM_PFX(Loader2PeiSwitchStack) | |
# | |
# Define the data length that we saved on the stack top | |
# | |
.equ DATA_LEN_OF_PER0, 0x018 | |
.equ DATA_LEN_OF_MCUD, 0x018 | |
.equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4) | |
#------------------------------------------------------------------------------ | |
# 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. | |
#------------------------------------------------------------------------------ | |
ASM_GLOBAL ASM_PFX(SecPlatformInitDefault) | |
ASM_PFX(SecPlatformInitDefault): | |
# | |
# Save return address to EBP | |
# | |
movd %mm7, %ebp | |
xorl %eax, %eax | |
SecPlatformInitDefaultExit: | |
jmp *%ebp | |
#------------------------------------------------------------------------------ | |
# 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 | |
#------------------------------------------------------------------------------ | |
ASM_GLOBAL ASM_PFX(LoadMicrocodeDefault) | |
ASM_PFX(LoadMicrocodeDefault): | |
# | |
# Save return address to EBP | |
# | |
movd %mm7, %ebp | |
cmpl $0x00, %esp | |
jz ParamError | |
movl 4(%esp), %eax #dword ptr [] Parameter pointer | |
cmpl $0x00, %eax | |
jz ParamError | |
movl %eax, %esp | |
movl MicrocodeCodeAddr(%esp), %esi | |
cmpl $0x00, %esi | |
jnz CheckMainHeader | |
ParamError: | |
movl $0x080000002, %eax | |
jmp LoadMicrocodeExit | |
CheckMainHeader: | |
# | |
# Get processor signature and platform ID from the installed processor | |
# and save into registers for later use | |
# ebx = processor signature | |
# edx = platform ID | |
# | |
movl $0x01, %eax | |
cpuid | |
movl %eax, %ebx | |
movl $MSR_IA32_PLATFORM_ID, %ecx | |
rdmsr | |
movl %edx, %ecx | |
shrl $0x12, %ecx # shift (50d-32d=18d=0x12) bits | |
andl $0x07, %ecx # platform id at bit[52..50] | |
movl $0x01, %edx | |
shll %cl,%edx | |
# | |
# 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 | |
# | |
movl $0x01, %eax | |
cmpl %eax, MicrocodeHdrVersion(%esi) | |
jne AdvanceFixedSize | |
cmpl %eax, MicrocodeHdrLoader(%esi) | |
jne AdvanceFixedSize | |
# | |
# Check if signature and plaform ID match | |
# | |
cmpl MicrocodeHdrProcessor(%esi), %ebx | |
jne LoadMicrocodeL0 | |
testl MicrocodeHdrFlags(%esi), %edx | |
jnz LoadCheck #Jif signature and platform ID match | |
LoadMicrocodeL0: | |
# | |
# Check if extended header exists | |
# First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid | |
# | |
xorl %eax, %eax | |
cmpl %eax, MicrocodeHdrTotalSize(%esi) | |
je NextMicrocode | |
cmpl %eax, MicrocodeHdrDataSize(%esi) | |
je NextMicrocode | |
# | |
# Then verify total size - sizeof header > data size | |
# | |
movl MicrocodeHdrTotalSize(%esi), %ecx | |
subl $MicrocodeHdrLength, %ecx | |
cmpl MicrocodeHdrDataSize(%esi), %ecx | |
jle NextMicrocode | |
# | |
# Set edi -> extended header | |
# | |
movl %esi, %edi | |
addl $MicrocodeHdrLength, %edi | |
addl MicrocodeHdrDataSize(%esi), %edi | |
# | |
# Get count of extended structures | |
# | |
movl ExtSigHdrCount(%edi), %ecx | |
# | |
# Move pointer to first signature structure | |
# | |
addl ExtSigHdrLength, %edi | |
CheckExtSig: | |
# | |
# Check if extended signature and platform ID match | |
# | |
cmpl %ebx, ExtSigProcessor(%edi) | |
jne LoadMicrocodeL1 | |
test %edx, ExtSigFlags(%edi) | |
jnz LoadCheck # Jif signature and platform ID match | |
LoadMicrocodeL1: | |
# | |
# Check if any more extended signatures exist | |
# | |
addl $ExtSigLength, %edi | |
loop CheckExtSig | |
NextMicrocode: | |
# | |
# Advance just after end of this microcode | |
# | |
xorl %eax, %eax | |
cmpl %eax, MicrocodeHdrTotalSize(%esi) | |
je LoadMicrocodeL2 | |
addl MicrocodeHdrTotalSize(%esi), %esi | |
jmp CheckAddress | |
LoadMicrocodeL2: | |
addl $0x800, %esi #add esi, dword ptr 2048 | |
jmp CheckAddress | |
AdvanceFixedSize: | |
# | |
# Advance by 4X dwords | |
# | |
addl $0x400, %esi #add esi, dword ptr 1024 | |
CheckAddress: | |
# | |
# Is valid Microcode start point ? | |
# | |
cmpl $0x0ffffffff, MicrocodeHdrVersion(%esi) | |
# | |
# Is automatic size detection ? | |
# | |
movl MicrocodeCodeSize(%esp), %eax | |
cmpl $0x0ffffffff, %eax | |
jz LoadMicrocodeL3 | |
# | |
# Address >= microcode region address + microcode region size? | |
# | |
addl MicrocodeCodeAddr(%esp), %eax | |
cmpl %eax, %esi | |
jae Done #Jif address is outside of microcode region | |
jmp CheckMainHeader | |
LoadMicrocodeL3: | |
LoadCheck: | |
# | |
# Get the revision of the current microcode update loaded | |
# | |
movl $MSR_IA32_BIOS_SIGN_ID, %ecx | |
xorl %eax, %eax # Clear EAX | |
xorl %edx, %edx # Clear EDX | |
wrmsr # Load 0 to MSR at 8Bh | |
movl $0x01, %eax | |
cpuid | |
movl $MSR_IA32_BIOS_SIGN_ID, %ecx | |
rdmsr # Get current microcode signature | |
# | |
# Verify this microcode update is not already loaded | |
# | |
cmpl %edx, MicrocodeHdrRevision(%esi) | |
je Continue | |
LoadMicrocode0: | |
# | |
# 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 | |
# | |
movl %esi, %eax | |
addl $MicrocodeHdrLength, %eax | |
xorl %edx, %edx | |
movl $MSR_IA32_BIOS_UPDT_TRIG, %ecx | |
wrmsr | |
movl $0x01, %eax | |
cpuid | |
Continue: | |
jmp NextMicrocode | |
Done: | |
movl $0x01, %eax | |
cpuid | |
movl $MSR_IA32_BIOS_SIGN_ID, %ecx | |
rdmsr # Get current microcode signature | |
xorl %eax, %eax | |
cmpl $0x00, %edx | |
jnz LoadMicrocodeExit | |
movl $0x08000000E, %eax | |
LoadMicrocodeExit: | |
jmp *%ebp | |
#---------------------------------------------------------------------------- | |
# EstablishStackFsp | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(EstablishStackFsp) | |
ASM_PFX(EstablishStackFsp): | |
# | |
# Save parameter pointer in edx | |
# | |
movl 4(%esp), %edx | |
# | |
# Enable FSP STACK | |
# | |
movl PcdGet32(PcdTemporaryRamBase), %esp | |
addl PcdGet32(PcdTemporaryRamSize), %esp | |
pushl $DATA_LEN_OF_MCUD # Size of the data region | |
pushl $0x4455434D # Signature of the data region 'MCUD' | |
pushl 12(%edx) # Code size | |
pushl 8(%edx) # Code base | |
pushl 4(%edx) # Microcode size | |
pushl (%edx) # Microcode base | |
# | |
# Save API entry/exit timestamp into stack | |
# | |
pushl $DATA_LEN_OF_PER0 # Size of the data region | |
pushl $0x30524550 # Signature of the data region 'PER0' | |
LOAD_EDX | |
pushl %edx | |
LOAD_EAX | |
pushl %eax | |
rdtsc | |
pushl %edx | |
pushl %eax | |
# | |
# Terminator for the data on stack | |
# | |
push $0x00 | |
# | |
# Set ECX/EDX to the BootLoader temporary memory range | |
# | |
movl PcdGet32 (PcdTemporaryRamBase), %ecx | |
movl %ecx, %edx | |
addl PcdGet32 (PcdTemporaryRamSize), %edx | |
subl PcdGet32 (PcdFspTemporaryRamSize), %edx | |
xorl %eax, %eax | |
movd %mm7, %esi #RET_ESI | |
jmp *%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. | |
# | |
#---------------------------------------------------------------------------- | |
ASM_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 | |
# | |
movl 4(%esp), %eax | |
cmpl $0x00, %eax | |
movl $0x80000002, %eax | |
jz NemInitExit | |
# | |
# Sec Platform Init | |
# | |
movl $TempRamInitApiL1, %esi #CALL_MMX SecPlatformInit | |
movd %esi, %mm7 | |
.weak ASM_PFX(SecPlatformInit) | |
.set ASM_PFX(SecPlatformInit), ASM_PFX(SecPlatformInitDefault) | |
jmp ASM_PFX(SecPlatformInit) | |
TempRamInitApiL1: | |
cmpl $0x00, %eax | |
jnz NemInitExit | |
# | |
# Load microcode | |
# | |
LOAD_ESP | |
movl $TempRamInitApiL2, %esi #CALL_MMX LoadMicrocode | |
movd %esi, %mm7 | |
.weak ASM_PFX(LoadMicrocode) | |
.set ASM_PFX(LoadMicrocode), ASM_PFX(LoadMicrocodeDefault) | |
jmp ASM_PFX(LoadMicrocode) | |
TempRamInitApiL2: | |
SAVE_EAX_MICROCODE_RET_STATUS #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 from ECX-SLOT 3 in xmm6. | |
# | |
# Call Sec CAR Init | |
# | |
LOAD_ESP | |
movl $TempRamInitApiL3, %esi #CALL_MMX SecCarInit | |
movd %esi, %mm7 | |
jmp ASM_PFX(SecCarInit) | |
TempRamInitApiL3: | |
cmpl $0x00, %eax | |
jnz NemInitExit | |
# | |
# EstablishStackFsp | |
# | |
LOAD_ESP | |
movl $TempRamInitApiL4, %esi #CALL_MMX EstablishStackFsp | |
movd %esi, %mm7 | |
jmp ASM_PFX(EstablishStackFsp) | |
TempRamInitApiL4: | |
LOAD_EAX_MICROCODE_RET_STATUS #Restore microcode status if no CAR init error. | |
NemInitExit: | |
# | |
# Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6 | |
# | |
LOAD_REGS | |
ret | |
#---------------------------------------------------------------------------- | |
# 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. | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(FspInitApi) | |
ASM_PFX(FspInitApi): | |
movl $0x01, %eax | |
jmp FspApiCommon | |
#---------------------------------------------------------------------------- | |
# NotifyPhase API | |
# | |
# This FSP API will notify the FSP about the different phases in the boot | |
# process | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(NotifyPhaseApi) | |
ASM_PFX(NotifyPhaseApi): | |
movl $0x02, %eax | |
jmp FspApiCommon | |
#---------------------------------------------------------------------------- | |
# FspMemoryInit API | |
# | |
# This FSP API is called after TempRamInit and initializes the memory. | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(FspMemoryInitApi) | |
ASM_PFX(FspMemoryInitApi): | |
movl $0x03, %eax | |
jmp FspApiCommon | |
#---------------------------------------------------------------------------- | |
# TempRamExitApi API | |
# | |
# This API tears down temporary RAM | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(TempRamExitApi) | |
ASM_PFX(TempRamExitApi): | |
movl $0x04, %eax | |
jmp FspApiCommon | |
#---------------------------------------------------------------------------- | |
# 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. | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(FspSiliconInitApi) | |
ASM_PFX(FspSiliconInitApi): | |
movl $0x05, %eax | |
jmp FspApiCommon | |
#---------------------------------------------------------------------------- | |
# FspApiCommon API | |
# | |
# This is the FSP API common entry point to resume the FSP execution | |
# | |
#---------------------------------------------------------------------------- | |
ASM_GLOBAL ASM_PFX(FspApiCommon) | |
ASM_PFX(FspApiCommon): | |
# | |
# EAX holds the API index | |
# | |
# | |
# Stack must be ready | |
# | |
pushl %eax | |
addl $0x04, %esp | |
cmpl -4(%esp), %eax | |
jz FspApiCommonL0 | |
movl $0x080000003, %eax | |
jmp FspApiCommonExit | |
FspApiCommonL0: | |
# | |
# Verify the calling condition | |
# | |
pushal | |
pushl 36(%esp) #push ApiParam [esp + 4 * 8 + 4] | |
pushl %eax #push ApiIdx | |
call ASM_PFX(FspApiCallingCheck) | |
addl $0x08, %esp | |
cmpl $0x00, %eax | |
jz FspApiCommonL1 | |
movl %eax, 0x1C(%esp) # mov dword ptr [esp + 4 * 7], eax | |
popal | |
ret | |
FspApiCommonL1: | |
popal | |
cmpl $0x01, %eax # FspInit API | |
jz FspApiCommonL2 | |
cmpl $0x03, %eax # FspMemoryInit API | |
jz FspApiCommonL2 | |
call ASM_PFX(AsmGetFspInfoHeader) | |
jmp Loader2PeiSwitchStack | |
FspApiCommonL2: | |
# | |
# FspInit and FspMemoryInit APIs, setup the initial stack frame | |
# | |
# | |
# Place holder to store the FspInfoHeader pointer | |
# | |
pushl %eax | |
# | |
# Update the FspInfoHeader pointer | |
# | |
pushl %eax | |
call ASM_PFX(AsmGetFspInfoHeader) | |
movl %eax, 4(%esp) | |
popl %eax | |
# | |
# Create a Task Frame in the stack for the Boot Loader | |
# | |
pushfl # 2 pushf for 4 byte alignment | |
cli | |
pushal | |
# | |
# Reserve 8 bytes for IDT save/restore | |
# | |
subl $0x08, %esp | |
sidt (%esp) | |
# | |
# Setup new FSP stack | |
# | |
movl %esp, %edi | |
movl PcdGet32(PcdTemporaryRamBase), %esp | |
addl PcdGet32(PcdTemporaryRamSize), %esp | |
subl $(DATA_LEN_AT_STACK_TOP + 0x40), %esp | |
# | |
# Pass the API Idx to SecStartup | |
# | |
pushl %eax | |
# | |
# Pass the BootLoader stack to SecStartup | |
# | |
pushl %edi | |
# | |
# Pass entry point of the PEI core | |
# | |
call ASM_PFX(AsmGetFspBaseAddress) | |
movl %eax, %edi | |
addl PcdGet32(PcdFspAreaSize), %edi | |
subl $0x20, %edi | |
addl %ds:(%edi), %eax | |
pushl %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 ASM_PFX(AsmGetFspBaseAddress) | |
movl %eax, %edi | |
call ASM_PFX(GetBootFirmwareVolumeOffset) | |
addl %edi, %eax | |
pushl %eax | |
# | |
# Pass stack base and size into the PEI Core | |
# | |
movl PcdGet32(PcdTemporaryRamBase), %eax | |
addl PcdGet32(PcdTemporaryRamSize), %eax | |
subl PcdGet32(PcdFspTemporaryRamSize), %eax | |
pushl %eax | |
pushl PcdGet32(PcdFspTemporaryRamSize) | |
# | |
# Pass Control into the PEI Core | |
# | |
call ASM_PFX(SecStartup) | |
addl $4, %esp | |
FspApiCommonExit: | |
ret | |