+++ /dev/null
-;; @file\r
-; Provide FSP API entry points.\r
-;\r
-; Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
-; SPDX-License-Identifier: BSD-2-Clause-Patent\r
-;;\r
-\r
- .586p\r
- .model flat,C\r
- .code\r
- .xmm\r
-\r
-INCLUDE SaveRestoreSse.inc\r
-INCLUDE MicrocodeLoad.inc\r
-\r
-;\r
-; Following are fixed PCDs\r
-;\r
-EXTERN PcdGet32(PcdTemporaryRamBase):DWORD\r
-EXTERN PcdGet32(PcdTemporaryRamSize):DWORD\r
-EXTERN PcdGet32(PcdFspTemporaryRamSize):DWORD\r
-EXTERN PcdGet32(PcdFspAreaSize):DWORD\r
-\r
-;\r
-; Following functions will be provided in C\r
-;\r
-\r
-EXTERN SecStartup:PROC\r
-EXTERN FspApiCallingCheck:PROC\r
-\r
-;\r
-; Following functions will be provided in PlatformSecLib\r
-;\r
-EXTERN AsmGetFspBaseAddress:PROC\r
-EXTERN AsmGetFspInfoHeader:PROC\r
-EXTERN GetBootFirmwareVolumeOffset:PROC\r
-EXTERN Loader2PeiSwitchStack:PROC\r
-EXTERN LoadMicrocode(LoadMicrocodeDefault):PROC\r
-EXTERN SecPlatformInit(SecPlatformInitDefault):PROC\r
-EXTERN SecCarInit:PROC\r
-\r
-;\r
-; Define the data length that we saved on the stack top\r
-;\r
-DATA_LEN_OF_PER0 EQU 18h\r
-DATA_LEN_OF_MCUD EQU 18h\r
-DATA_LEN_AT_STACK_TOP EQU (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)\r
-\r
-;\r
-; Define SSE macros\r
-;\r
-LOAD_MMX_EXT MACRO ReturnAddress, MmxRegister\r
- mov esi, ReturnAddress\r
- movd MmxRegister, esi ; save ReturnAddress into MMX\r
-ENDM\r
-\r
-CALL_MMX_EXT MACRO RoutineLabel, MmxRegister\r
- local ReturnAddress\r
- mov esi, offset ReturnAddress\r
- movd MmxRegister, esi ; save ReturnAddress into MMX\r
- jmp RoutineLabel\r
-ReturnAddress:\r
-ENDM\r
-\r
-RET_ESI_EXT MACRO MmxRegister\r
- movd esi, MmxRegister ; move ReturnAddress from MMX to ESI\r
- jmp esi\r
-ENDM\r
-\r
-CALL_MMX MACRO RoutineLabel\r
- CALL_MMX_EXT RoutineLabel, mm7\r
-ENDM\r
-\r
-RET_ESI MACRO\r
- RET_ESI_EXT mm7\r
-ENDM\r
-\r
-;------------------------------------------------------------------------------\r
-SecPlatformInitDefault PROC NEAR PUBLIC\r
- ; Inputs:\r
- ; mm7 -> Return address\r
- ; Outputs:\r
- ; eax -> 0 - Successful, Non-zero - Failed.\r
- ; Register Usage:\r
- ; eax is cleared and ebp is used for return address.\r
- ; All others reserved.\r
- \r
- ; Save return address to EBP\r
- movd ebp, mm7\r
-\r
- xor eax, eax\r
-exit:\r
- jmp ebp\r
-SecPlatformInitDefault ENDP\r
-\r
-;------------------------------------------------------------------------------\r
-LoadMicrocodeDefault PROC NEAR PUBLIC\r
- ; Inputs:\r
- ; esp -> LoadMicrocodeParams pointer\r
- ; Register Usage:\r
- ; esp Preserved\r
- ; All others destroyed\r
- ; Assumptions:\r
- ; No memory available, stack is hard-coded and used for return address\r
- ; Executed by SBSP and NBSP\r
- ; Beginning of microcode update region starts on paragraph boundary\r
-\r
- ;\r
- ;\r
- ; Save return address to EBP\r
- movd ebp, mm7\r
-\r
- cmp esp, 0\r
- jz paramerror\r
- mov eax, dword ptr [esp + 4] ; Parameter pointer\r
- cmp eax, 0\r
- jz paramerror\r
- mov esp, eax\r
- mov esi, [esp].LoadMicrocodeParams.MicrocodeCodeAddr\r
- cmp esi, 0\r
- jnz check_main_header\r
-\r
-paramerror:\r
- mov eax, 080000002h\r
- jmp exit\r
-\r
- mov esi, [esp].LoadMicrocodeParams.MicrocodeCodeAddr\r
-\r
-check_main_header:\r
- ; Get processor signature and platform ID from the installed processor\r
- ; and save into registers for later use\r
- ; ebx = processor signature\r
- ; edx = platform ID\r
- mov eax, 1\r
- cpuid\r
- mov ebx, eax\r
- mov ecx, MSR_IA32_PLATFORM_ID\r
- rdmsr\r
- mov ecx, edx\r
- shr ecx, 50-32 ; shift (50d-32d=18d=0x12) bits\r
- and ecx, 7h ; platform id at bit[52..50]\r
- mov edx, 1\r
- shl edx, cl\r
-\r
- ; Current register usage\r
- ; esp -> stack with paramters\r
- ; esi -> microcode update to check\r
- ; ebx = processor signature\r
- ; edx = platform ID\r
-\r
- ; Check for valid microcode header\r
- ; Minimal test checking for header version and loader version as 1\r
- mov eax, dword ptr 1\r
- cmp [esi].MicrocodeHdr.MicrocodeHdrVersion, eax\r
- jne advance_fixed_size\r
- cmp [esi].MicrocodeHdr.MicrocodeHdrLoader, eax\r
- jne advance_fixed_size\r
-\r
- ; Check if signature and plaform ID match\r
- cmp ebx, [esi].MicrocodeHdr.MicrocodeHdrProcessor\r
- jne @f\r
- test edx, [esi].MicrocodeHdr.MicrocodeHdrFlags\r
- jnz load_check ; Jif signature and platform ID match\r
-\r
-@@:\r
- ; Check if extended header exists\r
- ; First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid\r
- xor eax, eax\r
- cmp [esi].MicrocodeHdr.MicrocodeHdrTotalSize, eax\r
- je next_microcode\r
- cmp [esi].MicrocodeHdr.MicrocodeHdrDataSize, eax\r
- je next_microcode\r
-\r
- ; Then verify total size - sizeof header > data size\r
- mov ecx, [esi].MicrocodeHdr.MicrocodeHdrTotalSize\r
- sub ecx, sizeof MicrocodeHdr\r
- cmp ecx, [esi].MicrocodeHdr.MicrocodeHdrDataSize\r
- jng next_microcode ; Jif extended header does not exist\r
-\r
- ; Set edi -> extended header\r
- mov edi, esi\r
- add edi, sizeof MicrocodeHdr\r
- add edi, [esi].MicrocodeHdr.MicrocodeHdrDataSize\r
-\r
- ; Get count of extended structures\r
- mov ecx, [edi].ExtSigHdr.ExtSigHdrCount\r
-\r
- ; Move pointer to first signature structure\r
- add edi, sizeof ExtSigHdr\r
-\r
-check_ext_sig:\r
- ; Check if extended signature and platform ID match\r
- cmp [edi].ExtSig.ExtSigProcessor, ebx\r
- jne @f\r
- test [edi].ExtSig.ExtSigFlags, edx\r
- jnz load_check ; Jif signature and platform ID match\r
-@@:\r
- ; Check if any more extended signatures exist\r
- add edi, sizeof ExtSig\r
- loop check_ext_sig\r
-\r
-next_microcode:\r
- ; Advance just after end of this microcode\r
- xor eax, eax\r
- cmp [esi].MicrocodeHdr.MicrocodeHdrTotalSize, eax\r
- je @f\r
- add esi, [esi].MicrocodeHdr.MicrocodeHdrTotalSize\r
- jmp check_address\r
-@@:\r
- add esi, dword ptr 2048\r
- jmp check_address\r
-\r
-advance_fixed_size:\r
- ; Advance by 4X dwords\r
- add esi, dword ptr 1024\r
-\r
-check_address:\r
- ; Is valid Microcode start point ?\r
- cmp dword ptr [esi].MicrocodeHdr.MicrocodeHdrVersion, 0ffffffffh\r
- jz done\r
-\r
- ; Is automatic size detection ?\r
- mov eax, [esp].LoadMicrocodeParams.MicrocodeCodeSize\r
- cmp eax, 0ffffffffh\r
- jz @f\r
-\r
- ; Address >= microcode region address + microcode region size?\r
- add eax, [esp].LoadMicrocodeParams.MicrocodeCodeAddr\r
- cmp esi, eax\r
- jae done ;Jif address is outside of microcode region\r
- jmp check_main_header\r
-\r
-@@:\r
-load_check:\r
- ; Get the revision of the current microcode update loaded\r
- mov ecx, MSR_IA32_BIOS_SIGN_ID\r
- xor eax, eax ; Clear EAX\r
- xor edx, edx ; Clear EDX\r
- wrmsr ; Load 0 to MSR at 8Bh\r
-\r
- mov eax, 1\r
- cpuid\r
- mov ecx, MSR_IA32_BIOS_SIGN_ID\r
- rdmsr ; Get current microcode signature\r
-\r
- ; Verify this microcode update is not already loaded\r
- cmp [esi].MicrocodeHdr.MicrocodeHdrRevision, edx\r
- je continue\r
-\r
-load_microcode:\r
- ; EAX contains the linear address of the start of the Update Data\r
- ; EDX contains zero\r
- ; ECX contains 79h (IA32_BIOS_UPDT_TRIG)\r
- ; Start microcode load with wrmsr\r
- mov eax, esi\r
- add eax, sizeof MicrocodeHdr\r
- xor edx, edx\r
- mov ecx, MSR_IA32_BIOS_UPDT_TRIG\r
- wrmsr\r
- mov eax, 1\r
- cpuid\r
-\r
-continue:\r
- jmp next_microcode\r
-\r
-done:\r
- mov eax, 1\r
- cpuid\r
- mov ecx, MSR_IA32_BIOS_SIGN_ID\r
- rdmsr ; Get current microcode signature\r
- xor eax, eax\r
- cmp edx, 0\r
- jnz exit\r
- mov eax, 08000000Eh\r
-\r
-exit:\r
- jmp ebp\r
-\r
-LoadMicrocodeDefault ENDP\r
-\r
-EstablishStackFsp PROC NEAR PRIVATE\r
- ;\r
- ; Save parameter pointer in edx\r
- ;\r
- mov edx, dword ptr [esp + 4]\r
-\r
- ;\r
- ; Enable FSP STACK\r
- ;\r
- mov esp, PcdGet32 (PcdTemporaryRamBase)\r
- add esp, PcdGet32 (PcdTemporaryRamSize)\r
-\r
- push DATA_LEN_OF_MCUD ; Size of the data region\r
- push 4455434Dh ; Signature of the data region 'MCUD'\r
- push dword ptr [edx + 12] ; Code size\r
- push dword ptr [edx + 8] ; Code base\r
- push dword ptr [edx + 4] ; Microcode size\r
- push dword ptr [edx] ; Microcode base\r
-\r
- ;\r
- ; Save API entry/exit timestamp into stack\r
- ;\r
- push DATA_LEN_OF_PER0 ; Size of the data region \r
- push 30524550h ; Signature of the data region 'PER0'\r
- LOAD_EDX\r
- push edx\r
- LOAD_EAX\r
- push eax\r
- rdtsc\r
- push edx\r
- push eax\r
-\r
- ;\r
- ; Terminator for the data on stack\r
- ; \r
- push 0\r
-\r
- ;\r
- ; Set ECX/EDX to the BootLoader temporary memory range\r
- ;\r
- mov ecx, PcdGet32 (PcdTemporaryRamBase)\r
- mov edx, ecx\r
- add edx, PcdGet32 (PcdTemporaryRamSize)\r
- sub edx, PcdGet32 (PcdFspTemporaryRamSize)\r
-\r
- xor eax, eax\r
-\r
- RET_ESI\r
-\r
-EstablishStackFsp ENDP\r
-\r
-\r
-;----------------------------------------------------------------------------\r
-; TempRamInit API\r
-;\r
-; This FSP API will load the microcode update, enable code caching for the\r
-; region specified by the boot loader and also setup a temporary stack to be\r
-; used till main memory is initialized.\r
-;\r
-;----------------------------------------------------------------------------\r
-TempRamInitApi PROC NEAR PUBLIC\r
- ;\r
- ; Ensure SSE is enabled\r
- ;\r
- ENABLE_SSE\r
-\r
- ;\r
- ; Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6\r
- ;\r
- SAVE_REGS\r
-\r
- ;\r
- ; Save timestamp into XMM6\r
- ;\r
- rdtsc\r
- SAVE_EAX\r
- SAVE_EDX\r
-\r
- ;\r
- ; Check Parameter\r
- ;\r
- mov eax, dword ptr [esp + 4]\r
- cmp eax, 0\r
- mov eax, 80000002h\r
- jz TempRamInitExit\r
-\r
- ;\r
- ; Sec Platform Init\r
- ;\r
- CALL_MMX SecPlatformInit\r
- cmp eax, 0\r
- jnz TempRamInitExit\r
-\r
- ; Load microcode\r
- LOAD_ESP\r
- CALL_MMX LoadMicrocode\r
- SXMMN xmm6, 3, eax ;Save microcode return status in ECX-SLOT 3 in xmm6.\r
- ;@note If return value eax is not 0, microcode did not load, but continue and attempt to boot.\r
-\r
- ; Call Sec CAR Init\r
- LOAD_ESP\r
- CALL_MMX SecCarInit\r
- cmp eax, 0\r
- jnz TempRamInitExit\r
-\r
- LOAD_ESP\r
- CALL_MMX EstablishStackFsp\r
-\r
- LXMMN xmm6, eax, 3 ;Restore microcode status if no CAR init error from ECX-SLOT 3 in xmm6.\r
-\r
-TempRamInitExit:\r
- ;\r
- ; Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6\r
- ;\r
- LOAD_REGS\r
- ret\r
-TempRamInitApi ENDP\r
-\r
-;----------------------------------------------------------------------------\r
-; FspInit API\r
-;\r
-; This FSP API will perform the processor and chipset initialization.\r
-; This API will not return. Instead, it transfers the control to the\r
-; ContinuationFunc provided in the parameter.\r
-;\r
-;----------------------------------------------------------------------------\r
-FspInitApi PROC NEAR PUBLIC\r
- mov eax, 1\r
- jmp FspApiCommon\r
- FspInitApi ENDP\r
-\r
-;----------------------------------------------------------------------------\r
-; NotifyPhase API\r
-;\r
-; This FSP API will notify the FSP about the different phases in the boot\r
-; process\r
-;\r
-;----------------------------------------------------------------------------\r
-NotifyPhaseApi PROC C PUBLIC\r
- mov eax, 2\r
- jmp FspApiCommon\r
-NotifyPhaseApi ENDP\r
-\r
-;----------------------------------------------------------------------------\r
-; FspMemoryInit API\r
-;\r
-; This FSP API is called after TempRamInit and initializes the memory.\r
-;\r
-;----------------------------------------------------------------------------\r
-FspMemoryInitApi PROC NEAR PUBLIC\r
- mov eax, 3\r
- jmp FspApiCommon\r
-FspMemoryInitApi ENDP\r
-\r
-\r
-;----------------------------------------------------------------------------\r
-; TempRamExitApi API\r
-;\r
-; This API tears down temporary RAM\r
-;\r
-;----------------------------------------------------------------------------\r
-TempRamExitApi PROC C PUBLIC\r
- mov eax, 4\r
- jmp FspApiCommon\r
-TempRamExitApi ENDP\r
-\r
-\r
-;----------------------------------------------------------------------------\r
-; FspSiliconInit API\r
-;\r
-; This FSP API initializes the CPU and the chipset including the IO\r
-; controllers in the chipset to enable normal operation of these devices.\r
-;\r
-;----------------------------------------------------------------------------\r
-FspSiliconInitApi PROC C PUBLIC\r
- mov eax, 5\r
- jmp FspApiCommon\r
-FspSiliconInitApi ENDP\r
-\r
-;----------------------------------------------------------------------------\r
-; FspApiCommon API\r
-;\r
-; This is the FSP API common entry point to resume the FSP execution\r
-;\r
-;----------------------------------------------------------------------------\r
-FspApiCommon PROC C PUBLIC\r
- ;\r
- ; EAX holds the API index\r
- ;\r
-\r
- ;\r
- ; Stack must be ready\r
- ; \r
- push eax\r
- add esp, 4\r
- cmp eax, dword ptr [esp - 4]\r
- jz @F\r
- mov eax, 080000003h\r
- jmp exit\r
-\r
-@@:\r
- ;\r
- ; Verify the calling condition\r
- ;\r
- pushad\r
- push [esp + 4 * 8 + 4] ; push ApiParam\r
- push eax ; push ApiIdx\r
- call FspApiCallingCheck\r
- add esp, 8\r
- cmp eax, 0\r
- jz @F\r
- mov dword ptr [esp + 4 * 7], eax\r
- popad\r
- ret\r
-\r
-@@:\r
- popad\r
- cmp eax, 1 ; FspInit API\r
- jz @F\r
- cmp eax, 3 ; FspMemoryInit API\r
- jz @F\r
-\r
- call AsmGetFspInfoHeader\r
- jmp Loader2PeiSwitchStack\r
-\r
-@@:\r
- ;\r
- ; FspInit and FspMemoryInit APIs, setup the initial stack frame\r
- ;\r
- \r
- ;\r
- ; Place holder to store the FspInfoHeader pointer\r
- ;\r
- push eax\r
-\r
- ;\r
- ; Update the FspInfoHeader pointer\r
- ;\r
- push eax\r
- call AsmGetFspInfoHeader\r
- mov [esp + 4], eax\r
- pop eax\r
-\r
- ;\r
- ; Create a Task Frame in the stack for the Boot Loader\r
- ;\r
- pushfd ; 2 pushf for 4 byte alignment\r
- cli\r
- pushad\r
-\r
- ; Reserve 8 bytes for IDT save/restore\r
- sub esp, 8\r
- sidt fword ptr [esp]\r
-\r
- ;\r
- ; Setup new FSP stack\r
- ;\r
- mov edi, esp\r
- mov esp, PcdGet32(PcdTemporaryRamBase)\r
- add esp, PcdGet32(PcdTemporaryRamSize)\r
- sub esp, (DATA_LEN_AT_STACK_TOP + 40h)\r
-\r
- ;\r
- ; Pass the API Idx to SecStartup\r
- ;\r
- push eax\r
- \r
- ;\r
- ; Pass the BootLoader stack to SecStartup\r
- ;\r
- push edi\r
-\r
- ;\r
- ; Pass entry point of the PEI core\r
- ;\r
- call AsmGetFspBaseAddress\r
- mov edi, eax\r
- add edi, PcdGet32 (PcdFspAreaSize) \r
- sub edi, 20h\r
- add eax, DWORD PTR ds:[edi]\r
- push eax\r
-\r
- ;\r
- ; Pass BFV into the PEI Core\r
- ; It uses relative address to calucate the actual boot FV base\r
- ; For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and\r
- ; PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,\r
- ; they are different. The code below can handle both cases.\r
- ;\r
- call AsmGetFspBaseAddress\r
- mov edi, eax\r
- call GetBootFirmwareVolumeOffset\r
- add eax, edi\r
- push eax\r
-\r
- ;\r
- ; Pass stack base and size into the PEI Core\r
- ;\r
- mov eax, PcdGet32(PcdTemporaryRamBase)\r
- add eax, PcdGet32(PcdTemporaryRamSize)\r
- sub eax, PcdGet32(PcdFspTemporaryRamSize)\r
- push eax\r
- push PcdGet32(PcdFspTemporaryRamSize)\r
-\r
- ;\r
- ; Pass Control into the PEI Core\r
- ;\r
- call SecStartup\r
- add esp, 4\r
-exit:\r
- ret\r
-\r
-FspApiCommon ENDP\r
-\r
-END\r