--- /dev/null
+;------------------------------------------------------------------------------\r
+;\r
+; Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+; This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution. The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php.\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+; Abstract:\r
+;\r
+; Provide FSP API entry points.\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+ .586p\r
+ .model flat,C\r
+ .code\r
+ .xmm\r
+\r
+INCLUDE SaveRestoreSse.inc\r
+INCLUDE UcodeLoad.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
+\r
+;\r
+; Following functions will be provided in C\r
+;\r
+EXTERN FspImageSizeOffset:DWORD\r
+EXTERN SecStartup:PROC\r
+EXTERN FspApiCallingCheck:PROC\r
+\r
+;\r
+; Following functions will be provided in PlatformSecLib\r
+;\r
+EXTERN GetFspBaseAddress:PROC\r
+EXTERN GetBootFirmwareVolumeOffset:PROC\r
+EXTERN PlatformTempRamInit:PROC\r
+EXTERN Pei2LoaderSwitchStack:PROC\r
+EXTERN FspSelfCheck(FspSelfCheckDflt):PROC\r
+EXTERN PlatformBasicInit(PlatformBasicInitDflt):PROC\r
+EXTERN LoadUcode(LoadUcodeDflt):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
+FspSelfCheckDflt PROC NEAR PUBLIC\r
+ ; Inputs:\r
+ ; eax -> 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
+ mov ebp, eax\r
+\r
+ xor eax, eax\r
+exit:\r
+ jmp ebp\r
+FspSelfCheckDflt ENDP\r
+\r
+;------------------------------------------------------------------------------\r
+PlatformBasicInitDflt PROC NEAR PUBLIC\r
+ ; Inputs:\r
+ ; eax -> 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
+ mov ebp, eax\r
+\r
+ xor eax, eax\r
+exit:\r
+ jmp ebp\r
+PlatformBasicInitDflt ENDP\r
+\r
+;------------------------------------------------------------------------------\r
+LoadUcodeDflt PROC NEAR PUBLIC\r
+ ; Inputs:\r
+ ; esp -> LOAD_UCODE_PARAMS 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
+ mov ebp, eax\r
+\r
+ cmp esp, 0\r
+ jz paramerror\r
+ mov eax, dword ptr [esp] ; Parameter pointer\r
+ cmp eax, 0\r
+ jz paramerror\r
+ mov esp, eax\r
+ mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr\r
+ cmp esi, 0\r
+ jnz check_main_header\r
+\r
+paramerror:\r
+ mov eax, 080000002h\r
+ jmp exit\r
+\r
+ mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr\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\r
+ and ecx, 7h\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].ucode_hdr.version, eax\r
+ jne advance_fixed_size\r
+ cmp [esi].ucode_hdr.loader, eax\r
+ jne advance_fixed_size\r
+\r
+ ; Check if signature and plaform ID match\r
+ cmp ebx, [esi].ucode_hdr.processor\r
+ jne @f\r
+ test edx, [esi].ucode_hdr.flags\r
+ jnz load_check ; Jif signature and platform ID match\r
+\r
+@@:\r
+ ; Check if extended header exists\r
+ ; First check if total_size and data_size are valid\r
+ xor eax, eax\r
+ cmp [esi].ucode_hdr.total_size, eax\r
+ je next_microcode\r
+ cmp [esi].ucode_hdr.data_size, eax\r
+ je next_microcode\r
+\r
+ ; Then verify total size - sizeof header > data size\r
+ mov ecx, [esi].ucode_hdr.total_size\r
+ sub ecx, sizeof ucode_hdr\r
+ cmp ecx, [esi].ucode_hdr.data_size\r
+ jng next_microcode ; Jif extended header does not exist\r
+\r
+ ; Set edi -> extended header\r
+ mov edi, esi\r
+ add edi, sizeof ucode_hdr\r
+ add edi, [esi].ucode_hdr.data_size\r
+\r
+ ; Get count of extended structures\r
+ mov ecx, [edi].ext_sig_hdr.count\r
+\r
+ ; Move pointer to first signature structure\r
+ add edi, sizeof ext_sig_hdr\r
+\r
+check_ext_sig:\r
+ ; Check if extended signature and platform ID match\r
+ cmp [edi].ext_sig.processor, ebx\r
+ jne @f\r
+ test [edi].ext_sig.flags, edx\r
+ jnz load_check ; Jif signature and platform ID match\r
+@@:\r
+ ; Check if any more extended signatures exist\r
+ add edi, sizeof ext_sig\r
+ loop check_ext_sig\r
+\r
+next_microcode:\r
+ ; Advance just after end of this microcode\r
+ xor eax, eax\r
+ cmp [esi].ucode_hdr.total_size, eax\r
+ je @f\r
+ add esi, [esi].ucode_hdr.total_size\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], 0ffffffffh\r
+ jz done\r
+\r
+ ; Address >= microcode region address + microcode region size?\r
+ mov eax, [esp].LOAD_UCODE_PARAMS.ucode_code_addr\r
+ add eax, [esp].LOAD_UCODE_PARAMS.ucode_code_size\r
+ cmp esi, eax\r
+ jae done ;Jif address is outside of ucode region\r
+ jmp check_main_header\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].ucode_hdr.revision, 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 ucode_hdr\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
+LoadUcodeDflt ENDP\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 XMM4 & XMM5\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 NemInitExit\r
+\r
+ ;\r
+ ; CPUID/DeviceID check\r
+ ;\r
+ mov eax, @F\r
+ jmp FspSelfCheck ; Note: ESP can not be changed.\r
+@@:\r
+ cmp eax, 0\r
+ jnz NemInitExit\r
+\r
+ ;\r
+ ; Platform Basic Init.\r
+ ;\r
+ mov eax, @F\r
+ jmp PlatformBasicInit\r
+@@:\r
+ cmp eax, 0\r
+ jnz NemInitExit\r
+\r
+ ;\r
+ ; Load microcode\r
+ ;\r
+ mov eax, @F\r
+ add esp, 4\r
+ jmp LoadUcode\r
+@@:\r
+ LOAD_ESP\r
+ cmp eax, 0\r
+ jnz NemInitExit\r
+\r
+ ;\r
+ ; Call platform NEM init\r
+ ;\r
+ mov eax, @F\r
+ add esp, 4\r
+ jmp PlatformTempRamInit\r
+@@:\r
+ LOAD_ESP\r
+ cmp eax, 0\r
+ jnz NemInitExit\r
+\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 + 4] ; Microcode size\r
+ push dword ptr [edx + 0] ; Microcode base\r
+ push dword ptr [edx + 12] ; Code size\r
+ push dword ptr [edx + 8] ; Code 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
+ rdtsc\r
+ push edx\r
+ push eax\r
+ LOAD_EAX\r
+ LOAD_EDX\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
+NemInitExit:\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
+ ;\r
+ ; Stack must be ready\r
+ ;\r
+ push 087654321h\r
+ pop eax\r
+ cmp eax, 087654321h\r
+ jz @F\r
+ mov eax, 080000003h\r
+ jmp exit\r
+\r
+@@:\r
+ ;\r
+ ; Additional check\r
+ ;\r
+ pushad\r
+ push 1\r
+ call FspApiCallingCheck\r
+ add esp, 4\r
+ mov dword ptr [esp + 4 * 7], eax\r
+ popad\r
+ cmp eax, 0\r
+ jz @F\r
+ jmp exit\r
+\r
+@@:\r
+ ;\r
+ ; Store the address in FSP which will return control to the BL\r
+ ;\r
+ push offset exit\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 eax, esp\r
+ mov esp, PcdGet32(PcdTemporaryRamBase)\r
+ add esp, PcdGet32(PcdTemporaryRamSize)\r
+ sub esp, (DATA_LEN_AT_STACK_TOP + 40h)\r
+\r
+ ;\r
+ ; Save the bootloader's stack pointer\r
+ ;\r
+ push eax\r
+\r
+ ;\r
+ ; Pass entry point of the PEI core\r
+ ;\r
+ call GetFspBaseAddress\r
+ mov edi, FspImageSizeOffset\r
+ mov edi, DWORD PTR [eax + edi]\r
+ add edi, eax\r
+ sub edi, 20h\r
+ add eax, DWORD PTR [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 impleantion with single FV, PcdFlashFvRecoveryBase 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 GetFspBaseAddress\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
+\r
+exit:\r
+ ret\r
+\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
+ ;\r
+ ; Stack must be ready\r
+ ;\r
+ push 087654321h\r
+ pop eax\r
+ cmp eax, 087654321h\r
+ jz @F\r
+ mov eax, 080000003h\r
+ jmp err_exit\r
+\r
+@@:\r
+ ;\r
+ ; Verify the calling condition\r
+ ;\r
+ pushad\r
+ push 2\r
+ call FspApiCallingCheck\r
+ add esp, 4\r
+ mov dword ptr [esp + 4 * 7], eax\r
+ popad\r
+\r
+ cmp eax, 0\r
+ jz @F\r
+\r
+ ;\r
+ ; Error return\r
+ ;\r
+err_exit:\r
+ ret\r
+\r
+@@:\r
+ jmp Pei2LoaderSwitchStack\r
+\r
+NotifyPhaseApi ENDP\r
+\r
+\r
+END\r