| ;; @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 |