--- /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
+#.INCLUDE "UcodeLoad.inc"\r
+\r
+#\r
+# Following are fixed PCDs\r
+#\r
+\r
+.equ MSR_IA32_PLATFORM_ID, 0x000000017\r
+.equ MSR_IA32_BIOS_UPDT_TRIG, 0x000000079\r
+.equ MSR_IA32_BIOS_SIGN_ID, 0x00000008b\r
+\r
+ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase)\r
+ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize)\r
+ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize)\r
+ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspAreaSize)\r
+\r
+\r
+#\r
+# Following functions will be provided in C\r
+#\r
+#EXTERNDEF SecStartup:PROC\r
+#EXTERNDEF FspApiCallingCheck:PROC\r
+\r
+#\r
+# Following functions will be provided in PlatformSecLib\r
+#\r
+#EXTERNDEF GetFspBaseAddress:PROC\r
+#EXTERNDEF GetBootFirmwareVolumeOffset:PROC\r
+#EXTERNDEF PlatformTempRamInit:PROC\r
+#EXTERNDEF Pei2LoaderSwitchStack:PROC\r
+#EXTERN FspSelfCheck(FspSelfCheckDflt):PROC\r
+#EXTERN PlatformBasicInit(PlatformBasicInitDflt):PROC\r
+\r
+#\r
+# Define the data length that we saved on the stack top\r
+#\r
+.equ DATA_LEN_OF_PER0, 0x018\r
+.equ DATA_LEN_OF_MCUD, 0x018\r
+.equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)\r
+\r
+#\r
+# Define SSE macros\r
+#\r
+.macro ENABLE_SSE\r
+ movl %cr4, %eax\r
+ orl $0x00000600,%eax # Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)\r
+ movl %eax,%cr4\r
+.endm\r
+\r
+.macro SAVE_REGS\r
+ movd %ebp, %xmm7\r
+ pshufd $0x93, %xmm7, %xmm7\r
+ movd %ebx, %xmm6\r
+ por %xmm6, %xmm7\r
+ pshufd $0x93, %xmm7, %xmm7\r
+ movd %esi,%xmm6\r
+ por %xmm6, %xmm7\r
+ pshufd $0x93, %xmm7, %xmm7\r
+ movd %edi, %xmm6\r
+ por %xmm6, %xmm7\r
+ movd %esp, %xmm6\r
+.endm\r
+\r
+.macro LOAD_REGS\r
+ movd %xmm6, %esp\r
+ movd %xmm7, %edi\r
+ pshufd $0x39,%xmm7, %xmm7\r
+ movd %xmm7, %esi\r
+ pshufd $0x39,%xmm7, %xmm7\r
+ movd %xmm7, %ebx\r
+ pshufd $0x39, %xmm7, %xmm7\r
+ movd %xmm7, %ebp\r
+.endm\r
+\r
+.macro LOAD_ESP\r
+ movd %xmm6, %esp\r
+.endm\r
+\r
+#------------------------------------------------------------------------------\r
+ASM_GLOBAL ASM_PFX(FspSelfCheckDflt)\r
+ASM_PFX(FspSelfCheckDflt):\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
+ movl %eax, %ebp\r
+ xorl %eax, %eax\r
+exit:\r
+ jmp *%ebp\r
+#FspSelfCheckDflt ENDP\r
+\r
+#------------------------------------------------------------------------------\r
+ASM_GLOBAL ASM_PFX(PlatformBasicInitDflt)\r
+ASM_PFX(PlatformBasicInitDflt):\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
+ movl %eax, %ebp\r
+ xorl %eax, %eax\r
+exit2:\r
+ jmp *%ebp\r
+#PlatformBasicInitDflt ENDP\r
+\r
+#------------------------------------------------------------------------------\r
+ASM_GLOBAL ASM_PFX(LoadUcode)\r
+ASM_PFX(LoadUcode):\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
+ movl %eax, %ebp\r
+ cmpl $0, %esp\r
+ jz paramerror\r
+ movl (%esp), %eax #dword ptr [] Parameter pointer\r
+ cmpl $0, %eax\r
+ jz paramerror\r
+ movl %eax, %esp\r
+ movl (%esp), %esi #LOAD_UCODE_PARAMS.ucode_code_addr\r
+ cmpl $0, %esi\r
+ jnz L0\r
+\r
+paramerror:\r
+ movl $0x080000002, %eax\r
+ jmp exit4\r
+\r
+ movl (%esp), %esi #.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
+ movl $1, %eax\r
+ cpuid\r
+ movl %eax, %ebx\r
+ movl MSR_IA32_PLATFORM_ID, %ecx\r
+ rdmsr\r
+ movl %edx, %ecx\r
+ #--------------------------------------------------------------------------------------------------------------------\r
+ shrl $18, %ecx #($50-$32)\r
+ andl $0x7, %ecx\r
+ movl $1, %edx\r
+ shll %cl,%edx\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
+ movl $1, %eax\r
+ cmpl %eax, (%esi) #.ucode_hdr.version\r
+ jne advance_fixed_size\r
+ cmpl %eax, 0x18(%esi) #.ucode_hdr.loader\r
+ jne advance_fixed_size\r
+\r
+ # Check if signature and plaform ID match\r
+ #--------------------------------------------------------------------------------------------------------------------------\r
+ cmpl 0x10(%esi), %ebx #(%esi).ucode_hdr.processor\r
+ jne L0\r
+ testl 0x1c(%esi) , %edx #(%esi).ucode_hdr.flags\r
+ jnz load_check # Jif signature and platform ID match\r
+\r
+L0:\r
+ # Check if extended header exists\r
+ # First check if total_size and data_size are valid\r
+ xorl %eax, %eax\r
+ cmpl %eax,0x24(%esi) #(%esi).ucode_hdr.total_size\r
+ je next_microcode\r
+ cmpl %eax,0x20(%esi) #(%esi) .ucode_hdr.data_size\r
+ je next_microcode\r
+\r
+ # Then verify total size - sizeof header > data size\r
+ movl 0x24(%esi), %ecx #(%esi).ucode_hdr.total_size\r
+ subl $0x30, %ecx #sizeof ucode_hdr = 48\r
+ cmpl 0x20(%esi), %ecx #(%esi).ucode_hdr.data_size\r
+ jz load_check\r
+ jb next_microcode # Jif extended header does not exist\r
+\r
+ # Check if total size fits in microcode region\r
+ movl %esi , %edi\r
+ addl 0x24(%esi), %edi # (%esi).ucode_hdr.total_size\r
+ movl (%esp), %ecx # (%esp).LOAD_UCODE_PARAMS.ucode_code_addr\r
+ addl 4(%esp), %ecx #.LOAD_UCODE_PARAMS.ucode_code_size\r
+ cmpl %ecx , %edi\r
+ xorl %eax, %eax\r
+ ja exit4 # Jif address is outside of ucode region\r
+\r
+ # Set edi -> extended header\r
+ movl %esi , %edi\r
+ addl $0x30 , %edi #sizeof ucode_hdr = 48\r
+ addl 0x20(%esi), %edi #%esi.ucode_hdr.data_size\r
+\r
+ # Get count of extended structures\r
+ movl (%edi), %ecx #(%edi).ext_sig_hdr.count\r
+\r
+ # Move pointer to first signature structure\r
+ addl $0x20, %edi # sizeof ext_sig_hdr = 20\r
+\r
+check_ext_sig:\r
+ # Check if extended signature and platform ID match\r
+ cmpl %ebx, (%edi) #[edi].ext_sig.processor\r
+ jne L1\r
+ test %edx, 4(%edi) #[edi].ext_sig.flags\r
+ jnz load_check # Jif signature and platform ID match\r
+L9:\r
+ # Check if any more extended signatures exist\r
+ addl $0xc, %edi #sizeof ext_sig = 12\r
+ loop check_ext_sig\r
+\r
+next_microcode:\r
+ # Advance just after end of this microcode\r
+ xorl %eax, %eax\r
+ cmpl %eax, 0x24(%esi) #(%esi).ucode_hdr.total_size\r
+ je L2\r
+ add 0x24(%esi) , %esi #(%esi).ucode_hdr.total_size\r
+ jmp check_address\r
+L10:\r
+ addl $0x800, %esi\r
+ jmp check_address\r
+\r
+advance_fixed_size:\r
+ # Advance by 4X dwords\r
+ addl $0x400, %esi\r
+\r
+check_address:\r
+ # Is valid Microcode start point ?\r
+ cmp $0x0ffffffff , %esi\r
+ jz done\r
+\r
+ # Address >= microcode region address + microcode region size?\r
+ movl (%esp), %eax #(%esp).LOAD_UCODE_PARAMS.ucode_code_addr\r
+ addl 4(%esp), %eax #(%esp).LOAD_UCODE_PARAMS.ucode_code_size\r
+ cmpl %eax, %esi\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
+ movl MSR_IA32_BIOS_SIGN_ID, %ecx\r
+ xorl %eax, %eax # Clear EAX\r
+ xorl %edx, %edx # Clear EDX\r
+ wrmsr # Load 0 to MSR at 8Bh\r
+\r
+ movl $1, %eax\r
+ cpuid\r
+ movl MSR_IA32_BIOS_SIGN_ID, %ecx\r
+ rdmsr # Get current microcode signature\r
+\r
+ # Verify this microcode update is not already loaded\r
+ cmpl %edx, 4(%esi) #(%esi).ucode_hdr.revision\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 %esi, %eax\r
+ add $0x30, %eax #sizeof ucode_hdr = 48\r
+ xorl %edx, %edx\r
+ mov MSR_IA32_BIOS_UPDT_TRIG,%ecx\r
+ wrmsr\r
+ mov $1, %eax\r
+ cpuid\r
+\r
+continue:\r
+ jmp next_microcode\r
+\r
+done:\r
+ mov $1, %eax\r
+ cpuid\r
+ mov MSR_IA32_BIOS_SIGN_ID, %ecx\r
+ rdmsr # Get current microcode signature\r
+ xorl %eax, %eax\r
+ cmp $0 , %edx\r
+ jnz exit4\r
+ mov $0x08000000E, %eax\r
+\r
+exit4:\r
+ jmp *%ebp\r
+\r
+#LoadUcode 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
+ASM_GLOBAL ASM_PFX(TempRamInitApi)\r
+ASM_PFX(TempRamInitApi):\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
+ movd %edx, %xmm4\r
+ movd %eax, %xmm5\r
+\r
+ #\r
+ # CPUID/DeviceID check\r
+ #\r
+ movl L11, %eax\r
+ jmp ASM_PFX(FspSelfCheck) # Note: ESP can not be changed.\r
+L11:\r
+ cmpl $0, %eax\r
+ jnz NemInitExit\r
+\r
+ #\r
+ # Platform Basic Init.\r
+ #\r
+ movl L1, %eax\r
+ jmp ASM_PFX(PlatformBasicInitDflt)\r
+L1:\r
+ cmp $0, %eax\r
+ jnz NemInitExit\r
+\r
+ #\r
+ # Load microcode\r
+ #\r
+ movl L2, %eax\r
+ addl $4, %esp\r
+ jmp LoadUcode\r
+L2:\r
+ LOAD_ESP\r
+ cmpl $0, %eax\r
+ jnz NemInitExit\r
+\r
+ #\r
+ # Call platform NEM init\r
+ #-------------------------------------------------------------------------------------------------------------------------\r
+ movl L3, %eax\r
+ addl $4, %esp\r
+ jmp ASM_PFX(PlatformTempRamInit)\r
+L3:\r
+ subl $4, %esp\r
+ cmpl $0, %eax\r
+ jnz NemInitExit\r
+\r
+ #\r
+ # Save parameter pointer in edx\r
+ #\r
+ movl 4(%esp), %edx\r
+\r
+ #\r
+ # Enable FSP STACK\r
+ #\r
+ movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %esp\r
+ addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize), %esp\r
+\r
+ pushl $DATA_LEN_OF_MCUD # Size of the data region\r
+ pushl 0x4455434D # Signature of the data region 'MCUD'\r
+ pushl 12(%edx) # Code size\r
+ pushl 8(%edx) # Code base\r
+ cmpl $0, %edx # Is parameter pointer valid ?\r
+ jz InvalidMicrocodeRegion\r
+ pushl 4(%edx) # Microcode size\r
+ pushl (%edx) # Microcode base\r
+ jmp L4\r
+\r
+InvalidMicrocodeRegion:\r
+ pushl $0 # Microcode size\r
+ pushl $0 # Microcode base\r
+\r
+L4:\r
+ #\r
+ # Save API entry/exit timestamp into stack\r
+ #\r
+ pushl DATA_LEN_OF_PER0 # Size of the data region\r
+ pushl 0x30524550 # Signature of the data region 'PER0'\r
+ movd %xmm4, %eax\r
+ pushl %eax\r
+ movd %xmm5, %eax\r
+ pushl %eax\r
+ rdtsc\r
+ pushl %edx\r
+ pushl %eax\r
+\r
+ #\r
+ # Terminator for the data on stack\r
+ #\r
+ pushl $0\r
+\r
+ #\r
+ # Set ECX/EDX to the bootloader temporary memory range\r
+ #\r
+ movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %ecx\r
+ movl %ecx, %edx\r
+ addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize), %edx\r
+ subl ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize), %edx\r
+\r
+ xorl %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
+ASM_GLOBAL ASM_PFX(FspInitApi)\r
+ASM_PFX(FspInitApi):\r
+ #\r
+ # Stack must be ready\r
+ #\r
+ pushl $0x087654321\r
+ pop %eax\r
+ cmpl $0x087654321, %eax\r
+ jz L5\r
+ movl $0x080000003, %eax\r
+ jmp exit3\r
+\r
+L5:\r
+ #\r
+ # Additional check\r
+ #\r
+ pusha\r
+ pushl $1\r
+ call ASM_PFX(FspApiCallingCheck)\r
+ addl $4, %esp\r
+ movl %eax, 28(%esp)\r
+ popa\r
+ cmpl $0 , %eax\r
+ jz L6\r
+ jmp exit3\r
+\r
+L6:\r
+ #\r
+ # Save the Platform Data Pointer in EDI\r
+ #\r
+ movl 4(%esp), %edi\r
+\r
+ #\r
+ # Store the address in FSP which will return control to the BL\r
+ #\r
+ pushl $exit3\r
+\r
+ #\r
+ # Create a Task Frame in the stack for the Boot Loader\r
+ #\r
+ pushfl\r
+ pushfl # 2 pushf for 4 byte alignment\r
+ cli\r
+ pushal\r
+\r
+ # Reserve 8 bytes for IDT save/restore\r
+ pushl $0\r
+ pushl $0\r
+ sidt (%esp)\r
+\r
+ #\r
+ # Setup new FSP stack\r
+ #\r
+ movl %esp, %eax\r
+ movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %esp\r
+ addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize) , %esp\r
+ subl DATA_LEN_AT_STACK_TOP, %esp\r
+ addl $0x0FFFFFFC0, %esp\r
+\r
+ #\r
+ # Save the bootloader's stack pointer\r
+ #\r
+ pushl %eax\r
+\r
+ #\r
+ # Pass entry point of the PEI core\r
+ #\r
+ call ASM_PFX(GetFspBaseAddress)\r
+ movl %eax, %edi\r
+ addl ASM_PFX(_gPcd_FixedAtBuild_PcdFspAreaSize), %edi\r
+ subl $0x20, %edi\r
+ addl %ds:(%edi), %eax\r
+ pushl %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 ASM_PFX(GetFspBaseAddress)\r
+ movl %eax , %edi\r
+ call ASM_PFX(GetBootFirmwareVolumeOffset)\r
+ addl %edi ,%eax\r
+ pushl %eax\r
+\r
+ #\r
+ # Pass stack base and size into the PEI Core\r
+ #\r
+ movl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase), %eax\r
+ addl ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize), %eax\r
+ subl ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize), %eax\r
+ pushl %eax\r
+ pushl ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize)\r
+\r
+ #\r
+ # Pass Control into the PEI Core\r
+ #\r
+ call ASM_PFX(SecStartup)\r
+\r
+exit3:\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
+ASM_GLOBAL ASM_PFX(NotifyPhaseApi)\r
+ASM_PFX(NotifyPhaseApi):\r
+ #\r
+ # Stack must be ready\r
+ #\r
+ pushl $0x0087654321\r
+ pop %eax\r
+ cmpl $0x087654321, %eax\r
+ jz L7\r
+ movl $0x080000003, %eax\r
+ jmp err_exit\r
+\r
+L7:\r
+ #\r
+ # Verify the calling condition\r
+ #\r
+ pusha\r
+ pushl $2\r
+ call ASM_PFX(FspApiCallingCheck)\r
+ add $4, %esp\r
+ mov %eax, 28(%esp)\r
+ popa\r
+\r
+ cmpl $0, %eax\r
+ jz L8\r
+\r
+ #\r
+ # Error return\r
+ #\r
+err_exit:\r
+ ret\r
+\r
+L8:\r
+ jmp ASM_PFX(Pei2LoaderSwitchStack)\r
+\r
+#NotifyPhaseApi ENDP\r
+\r
+\r
+#END\r