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