]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s
Add IntelFspPkg to support create FSP bin based on EDKII.
[mirror_edk2.git] / IntelFspPkg / FspSecCore / Ia32 / FspApiEntry.s
diff --git a/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s b/IntelFspPkg/FspSecCore/Ia32/FspApiEntry.s
new file mode 100644 (file)
index 0000000..433ef92
--- /dev/null
@@ -0,0 +1,611 @@
+#------------------------------------------------------------------------------\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