1 #------------------------------------------------------------------------------
3 # Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4 # This program and the accompanying materials
5 # are licensed and made available under the terms and conditions of the BSD License
6 # which accompanies this distribution. The full text of the license may be found at
7 # http://opensource.org/licenses/bsd-license.php.
9 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 # Provide FSP API entry points.
16 #------------------------------------------------------------------------------
18 #.INCLUDE "UcodeLoadGcc.inc" - begin
20 .equ MSR_IA32_PLATFORM_ID, 0x00000017
21 .equ MSR_IA32_BIOS_UPDT_TRIG, 0x00000079
22 .equ MSR_IA32_BIOS_SIGN_ID, 0x0000008b
25 .equ UcodeVersion, 0x0000
26 .equ UcodeRevision, 0x0004
27 .equ UcodeDate, 0x0008
28 .equ UcodeProcessor, 0x000C
29 .equ UcodeChecksum, 0x0010
30 .equ UcodeLoader, 0x0014
31 .equ UcodeRsvd, 0x0018
35 .equ UcodeHdrVersion, 0x0000
36 .equ UcodeHdrRevision, 0x0004
37 .equ UcodeHdrDate, 0x0008
38 .equ UcodeHdrProcessor, 0x000c
39 .equ UcodeHdrChecksum, 0x0010
40 .equ UcodeHdrLoader, 0x0014
41 .equ UcodeHdrFlags, 0x0018
42 .equ UcodeHdrDataSize, 0x001C
43 .equ UcodeHdrTotalSize, 0x0020
44 .equ UcodeHdrRsvd, 0x0024
46 .equ UcodeHdrLength, 0x0030 # UcodeHdrLength = UcodeHdrEnd - UcodeHdr
50 .equ ExtSigHdrCount, 0x0000
51 .equ ExtSigHdrChecksum, 0x0004
54 .equ ExtSigHdrLength, 0x0014 #ExtSigHdrLength = ExtSigHdrEnd - ExtSigHdr
57 .equ ExtSigProcessor, 0x0000
58 .equ ExtSigFlags, 0x0004
59 .equ ExtSigChecksum, 0x0008
61 .equ ExtSigLength, 0x000C #ExtSigLength = ExtSigEnd - ExtSig
64 .equ LoadUcodeParamsUcodeCodeAddr, 0x0000
65 .equ LoadUcodeParamsUcodeCodeSize, 0x0004
68 #.INCLUDE "UcodeLoadGcc.inc" - end
70 #.INCLUDE "SaveRestoreSseGcc.inc" - begin
73 pinsrw $0x00, %ebp, %xmm7
75 pinsrw $0x01, %ebp, %xmm7
78 pinsrw $0x02, %ebx, %xmm7
80 pinsrw $0x03, %ebx, %xmm7
83 pinsrw $0x04, %esi, %xmm7
85 pinsrw $0x05, %esi, %xmm7
88 pinsrw $0x06, %edi, %xmm7
90 pinsrw $0x07, %edi, %xmm7
93 pinsrw $0x00, %esp, %xmm6
95 pinsrw $0x01, %esp, %xmm6
100 pshufd $0xe4, %xmm7, %xmm7
102 pshufd $0xe4, %xmm7, %xmm7
104 pshufd $0x39, %xmm7, %xmm7
106 pshufd $0x93, %xmm7, %xmm7
108 pshufd $0x4e, %xmm7, %xmm7
110 pshufd $0x4e, %xmm7, %xmm7
112 pshufd $0x93, %xmm7, %xmm7
114 pshufd $0x39, %xmm7, %xmm7
120 pshufd $0x39, %xmm6, %xmm6
122 pshufd $0x93, %xmm6, %xmm6
126 pshufd $0xe4, %xmm6, %xmm6
128 pshufd $0xe4, %xmm6, %xmm6
132 pinsrw $0x02, %eax, %xmm6
134 pinsrw $0x03, %eax, %xmm6
139 pinsrw $0x04, %edx, %xmm6
141 pinsrw $0x05, %edx, %xmm6
151 orl $0x00000600, %eax # Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
155 #.INCLUDE "SaveRestoreSseGcc.inc" - end
159 # Following are fixed PCDs
161 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase)
162 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize)
163 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize)
166 # Following functions will be provided in C
168 ASM_GLOBAL ASM_PFX(SecStartup)
169 ASM_GLOBAL ASM_PFX(FspApiCallingCheck)
172 # Following functions will be provided in PlatformSecLib
174 ASM_GLOBAL ASM_PFX(GetBootFirmwareVolumeOffset)
175 ASM_GLOBAL ASM_PFX(Pei2LoaderSwitchStack)
179 # Define the data length that we saved on the stack top
181 .equ DATA_LEN_OF_PER0, 0x018
182 .equ DATA_LEN_OF_MCUD, 0x018
183 .equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
185 #------------------------------------------------------------------------------
188 # eax -> Return address
190 # eax -> 0 - Successful, Non-zero - Failed.
192 # eax is cleared and ebp is used for return address.
193 # All others reserved.
194 #------------------------------------------------------------------------------
195 ASM_GLOBAL ASM_PFX(FspSelfCheckDflt)
196 ASM_PFX(FspSelfCheckDflt):
198 # Save return address to EBP
203 FspSelfCheckDfltExit:
207 #------------------------------------------------------------------------------
208 # SecPlatformInitDflt
210 # eax -> Return address
212 # eax -> 0 - Successful, Non-zero - Failed.
214 # eax is cleared and ebp is used for return address.
215 # All others reserved.
216 #------------------------------------------------------------------------------
217 ASM_GLOBAL ASM_PFX(SecPlatformInitDflt)
218 ASM_PFX(SecPlatformInitDflt):
220 # Save return address to EBP
225 SecPlatformInitDfltExit:
229 #------------------------------------------------------------------------------
233 # esp -> LOAD_UCODE_PARAMS pointer
236 # All others destroyed
238 # No memory available, stack is hard-coded and used for return address
239 # Executed by SBSP and NBSP
240 # Beginning of microcode update region starts on paragraph boundary
241 #------------------------------------------------------------------------------
242 ASM_GLOBAL ASM_PFX(LoadUcode)
245 # Save return address to EBP
251 movl (%esp), %eax #dword ptr [] Parameter pointer
255 movl LoadUcodeParamsUcodeCodeAddr(%esp), %esi #mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
260 movl $0x080000002, %eax
265 # Get processor signature and platform ID from the installed processor
266 # and save into registers for later use
267 # ebx = processor signature
273 movl $MSR_IA32_PLATFORM_ID, %ecx
276 shrl $0x12, %ecx #($50-$32)
282 # Current register usage
283 # esp -> stack with paramters
284 # esi -> microcode update to check
285 # ebx = processor signature
290 # Check for valid microcode header
291 # Minimal test checking for header version and loader version as 1
294 cmpl %eax, UcodeHdrVersion(%esi) #cmp [esi].ucode_hdr.version, eax
296 cmpl %eax, UcodeHdrLoader(%esi) #cmp [esi].ucode_hdr.loader, eax
300 # Check if signature and plaform ID match
302 cmpl UcodeHdrProcessor(%esi), %ebx #cmp ebx, [esi].ucode_hdr.processor
304 testl UcodeHdrFlags(%esi), %edx #test edx, [esi].ucode_hdr.flags
305 jnz LoadCheck #Jif signature and platform ID match
309 # Check if extended header exists
310 # First check if total_size and data_size are valid
313 cmpl %eax, UcodeHdrTotalSize(%esi) #cmp [esi].ucode_hdr.total_size, eax
315 cmpl %eax, UcodeHdrDataSize(%esi) #cmp [esi].ucode_hdr.data_size, eax
319 # Then verify total size - sizeof header > data size
321 movl UcodeHdrTotalSize(%esi), %ecx #mov ecx, [esi].ucode_hdr.total_size
322 subl $UcodeHdrLength, %ecx #sub ecx, sizeof ucode_hdr
323 cmpl UcodeHdrDataSize(%esi), %ecx #cmp ecx, [esi].ucode_hdr.data_size
327 # Set edi -> extended header
330 addl $UcodeHdrLength, %edi #add edi, sizeof ucode_hdr
331 addl UcodeHdrDataSize(%esi), %edi #add edi, [esi].ucode_hdr.data_size
334 # Get count of extended structures
336 movl ExtSigHdrCount(%edi), %ecx #mov ecx, [edi].ext_sig_hdr.count
339 # Move pointer to first signature structure
341 addl ExtSigHdrLength, %edi #add edi, sizeof ext_sig_hdr
345 # Check if extended signature and platform ID match
347 cmpl %ebx, ExtSigProcessor(%edi) #cmp [edi].ext_sig.processor, ebx
349 test %edx, ExtSigFlags(%edi) #test [edi].ext_sig.flags, edx
350 jnz LoadCheck # Jif signature and platform ID match
353 # Check if any more extended signatures exist
355 addl $ExtSigLength, %edi #add edi, sizeof ext_sig
360 # Advance just after end of this microcode
363 cmpl %eax, UcodeHdrTotalSize(%esi) #cmp [esi].ucode_hdr.total_size, eax
365 addl UcodeHdrTotalSize(%esi), %esi #add esi, [esi].ucode_hdr.total_size
368 addl $0x800, %esi #add esi, dword ptr 2048
373 # Advance by 4X dwords
375 addl $0x400, %esi #add esi, dword ptr 1024
379 # Is valid Microcode start point ?
381 cmpl $0x0ffffffff, UcodeHdrVersion(%esi)
384 # Is automatic size detection ?
386 movl LoadUcodeParamsUcodeCodeSize(%esp), %eax
387 cmpl $0x0ffffffff, %eax
390 # Address >= microcode region address + microcode region size?
392 addl LoadUcodeParamsUcodeCodeAddr(%esp), %eax #mov eax, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
395 jae Done #Jif address is outside of ucode region
401 # Get the revision of the current microcode update loaded
403 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
404 xorl %eax, %eax # Clear EAX
405 xorl %edx, %edx # Clear EDX
406 wrmsr # Load 0 to MSR at 8Bh
410 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
411 rdmsr # Get current microcode signature
414 # Verify this microcode update is not already loaded
416 cmpl %edx, UcodeHdrRevision(%esi) #cmp [esi].ucode_hdr.revision, edx
421 # EAX contains the linear address of the start of the Update Data
423 # ECX contains 79h (IA32_BIOS_UPDT_TRIG)
424 # Start microcode load with wrmsr
427 addl $UcodeHdrLength, %eax #add eax, sizeof ucode_hdr
429 movl $MSR_IA32_BIOS_UPDT_TRIG, %ecx
440 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
441 rdmsr # Get current microcode signature
445 movl $0x08000000E, %eax
451 #----------------------------------------------------------------------------
454 #----------------------------------------------------------------------------
455 ASM_GLOBAL ASM_PFX(EstablishStackFsp)
456 ASM_PFX(EstablishStackFsp):
458 # Save parameter pointer in edx
465 movl PcdGet32(PcdTemporaryRamBase), %esp
466 addl PcdGet32(PcdTemporaryRamSize), %esp
468 pushl $DATA_LEN_OF_MCUD # Size of the data region
469 pushl $0x4455434D # Signature of the data region 'MCUD'
470 pushl 12(%edx) # Code size
471 pushl 8(%edx) # Code base
472 cmpl $0, %edx # Is parameter pointer valid ?
473 jz InvalidMicrocodeRegion
474 pushl 4(%edx) # Microcode size
475 pushl (%edx) # Microcode base
476 jmp EstablishStackFspExit
478 InvalidMicrocodeRegion:
479 push $0 # Microcode size
480 push $0 # Microcode base
482 EstablishStackFspExit:
484 # Save API entry/exit timestamp into stack
486 pushl $DATA_LEN_OF_PER0 # Size of the data region
487 pushl $0x30524550 # Signature of the data region 'PER0'
497 # Terminator for the data on stack
502 # Set ECX/EDX to the bootloader temporary memory range
504 movl PcdGet32 (PcdTemporaryRamBase), %ecx
506 addl PcdGet32 (PcdTemporaryRamSize), %edx
507 subl PcdGet32 (PcdFspTemporaryRamSize), %edx
511 movd %mm7, %esi #RET_ESI
514 #----------------------------------------------------------------------------
517 # This FSP API will load the microcode update, enable code caching for the
518 # region specified by the boot loader and also setup a temporary stack to be
519 # used till main memory is initialized.
521 #----------------------------------------------------------------------------
522 ASM_GLOBAL ASM_PFX(TempRamInitApi)
523 ASM_PFX(TempRamInitApi):
525 # Ensure SSE is enabled
530 # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
535 # Save timestamp into XMM4 & XMM5
546 movl $0x80000002, %eax
550 # CPUID/DeviceID check
552 movl $TempRamInitApiL0, %eax
553 jmp ASM_PFX(FspSelfCheckDflt) # @note: ESP can not be changed.
561 movl $TempRamInitApiL1, %esi #CALL_MMX SecPlatformInit
563 jmp ASM_PFX(SecPlatformInit)
572 movl $TempRamInitApiL2, %esi #CALL_MMX LoadUcode
574 jmp ASM_PFX(LoadUcode)
583 movl $TempRamInitApiL3, %esi #CALL_MMX SecCarInit
585 jmp ASM_PFX(SecCarInit)
594 movl $TempRamInitApiL4, %esi #CALL_MMX EstablishStackFsp
596 jmp ASM_PFX(EstablishStackFsp)
601 # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
606 #----------------------------------------------------------------------------
609 # This FSP API will perform the processor and chipset initialization.
610 # This API will not return. Instead, it transfers the control to the
611 # ContinuationFunc provided in the parameter.
613 #----------------------------------------------------------------------------
614 ASM_GLOBAL ASM_PFX(FspInitApi)
619 #----------------------------------------------------------------------------
622 # This FSP API will notify the FSP about the different phases in the boot
625 #----------------------------------------------------------------------------
626 ASM_GLOBAL ASM_PFX(NotifyPhaseApi)
627 ASM_PFX(NotifyPhaseApi):
631 #----------------------------------------------------------------------------
634 # This FSP API is called after TempRamInit and initializes the memory.
636 #----------------------------------------------------------------------------
637 ASM_GLOBAL ASM_PFX(FspMemoryInitApi)
638 ASM_PFX(FspMemoryInitApi):
642 #----------------------------------------------------------------------------
645 # This API tears down temporary RAM
647 #----------------------------------------------------------------------------
648 ASM_GLOBAL ASM_PFX(TempRamExitApi)
649 ASM_PFX(TempRamExitApi):
653 #----------------------------------------------------------------------------
656 # This FSP API initializes the CPU and the chipset including the IO
657 # controllers in the chipset to enable normal operation of these devices.
659 #----------------------------------------------------------------------------
660 ASM_GLOBAL ASM_PFX(FspSiliconInitApi)
661 ASM_PFX(FspSiliconInitApi):
665 #----------------------------------------------------------------------------
668 # This is the FSP API common entry point to resume the FSP execution
670 #----------------------------------------------------------------------------
671 ASM_GLOBAL ASM_PFX(FspApiCommon)
672 ASM_PFX(FspApiCommon):
674 # EAX holds the API index
678 # Stack must be ready
684 movl $0x080000003, %eax
689 # Verify the calling condition
693 call ASM_PFX(FspApiCallingCheck)
697 movl %eax, 0x1C(%esp) # mov dword ptr [esp + 4 * 7], eax
703 cmpl $0x01, %eax # FspInit API
705 cmpl $0x03, %eax # FspMemoryInit API
707 jmp Pei2LoaderSwitchStack
711 # FspInit and FspMemoryInit APIs, setup the initial stack frame
715 # Store the address in FSP which will return control to the BL
717 pushl $FspApiCommonExit
720 # Create a Task Frame in the stack for the Boot Loader
722 pushfl # 2 pushf for 4 byte alignment
727 # Reserve 8 bytes for IDT save/restore
733 # Setup new FSP stack
736 movl PcdGet32(PcdTemporaryRamBase), %esp
737 addl PcdGet32(PcdTemporaryRamSize), %esp
738 subl $(DATA_LEN_AT_STACK_TOP + 0x40), %esp
741 # Pass the API Idx to SecStartup
746 # Pass the bootloader stack to SecStartup
751 # Pass entry point of the PEI core
753 call ASM_PFX(GetFspBaseAddress)
755 addl PcdGet32(PcdFspAreaSize), %edi
757 addl %ds:(%edi), %eax
761 # Pass BFV into the PEI Core
762 # It uses relative address to calucate the actual boot FV base
763 # For FSP impleantion with single FV, PcdFlashFvRecoveryBase and
764 # PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
765 # they are different. The code below can handle both cases.
767 call ASM_PFX(GetFspBaseAddress)
769 call ASM_PFX(GetBootFirmwareVolumeOffset)
774 # Pass stack base and size into the PEI Core
776 movl PcdGet32(PcdTemporaryRamBase), %eax
777 addl PcdGet32(PcdTemporaryRamSize), %eax
778 subl PcdGet32(PcdFspTemporaryRamSize), %eax
780 pushl PcdGet32(PcdFspTemporaryRamSize)
783 # Pass Control into the PEI Core
785 call ASM_PFX(SecStartup)