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 # PlatformBasicInitDflt
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(PlatformBasicInitDflt)
218 ASM_PFX(PlatformBasicInitDflt):
220 # Save return address to EBP
225 PlatformBasicInitDfltExit:
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 # Following is the code copied from BYTFSP, need to figure out what it is doing..
456 #----------------------------------------------------------------------------
457 ASM_GLOBAL ASM_PFX(EstablishStackFsp)
458 ASM_PFX(EstablishStackFsp):
460 # Save parameter pointer in edx
467 movl PcdGet32(PcdTemporaryRamBase), %esp
468 addl PcdGet32(PcdTemporaryRamSize), %esp
470 pushl $DATA_LEN_OF_MCUD # Size of the data region
471 pushl $0x4455434D # Signature of the data region 'MCUD'
472 pushl 12(%edx) # Code size
473 pushl 8(%edx) # Code base
474 cmpl $0, %edx # Is parameter pointer valid ?
475 jz InvalidMicrocodeRegion
476 pushl 4(%edx) # Microcode size
477 pushl (%edx) # Microcode base
478 jmp EstablishStackFspExit
480 InvalidMicrocodeRegion:
481 push $0 # Microcode size
482 push $0 # Microcode base
484 EstablishStackFspExit:
486 # Save API entry/exit timestamp into stack
488 pushl $DATA_LEN_OF_PER0 # Size of the data region
489 pushl $0x30524550 # Signature of the data region 'PER0'
499 # Terminator for the data on stack
504 # Set ECX/EDX to the bootloader temporary memory range
506 movl PcdGet32 (PcdTemporaryRamBase), %ecx
508 addl PcdGet32 (PcdTemporaryRamSize), %edx
509 subl PcdGet32 (PcdFspTemporaryRamSize), %edx
513 movd %mm7, %esi #RET_ESI
516 #----------------------------------------------------------------------------
519 # This FSP API will load the microcode update, enable code caching for the
520 # region specified by the boot loader and also setup a temporary stack to be
521 # used till main memory is initialized.
523 #----------------------------------------------------------------------------
524 ASM_GLOBAL ASM_PFX(TempRamInitApi)
525 ASM_PFX(TempRamInitApi):
527 # Ensure SSE is enabled
532 # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
537 # Save timestamp into XMM4 & XMM5
544 # CPUID/DeviceID check
546 movl $TempRamInitApiL0, %eax
547 jmp ASM_PFX(FspSelfCheckDflt) # @note: ESP can not be changed.
555 movl $TempRamInitApiL1, %esi #CALL_MMX SecPlatformInit
557 jmp ASM_PFX(SecPlatformInit)
563 movl $TempRamInitApiL2, %esi #CALL_MMX SecCarInit
565 jmp ASM_PFX(SecCarInit)
568 # @todo: ESP has been modified, we need to restore here.
576 movl $TempRamInitApiL3, %esi #CALL_MMX LoadUcode
578 jmp ASM_PFX(LoadUcode)
584 movl $TempRamInitApiL4, %esi #CALL_MMX EstablishStackFsp
586 jmp ASM_PFX(EstablishStackFsp)
591 # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
596 #----------------------------------------------------------------------------
599 # This FSP API will perform the processor and chipset initialization.
600 # This API will not return. Instead, it transfers the control to the
601 # ContinuationFunc provided in the parameter.
603 #----------------------------------------------------------------------------
604 ASM_GLOBAL ASM_PFX(FspInitApi)
609 #----------------------------------------------------------------------------
612 # This FSP API will notify the FSP about the different phases in the boot
615 #----------------------------------------------------------------------------
616 ASM_GLOBAL ASM_PFX(NotifyPhaseApi)
617 ASM_PFX(NotifyPhaseApi):
621 #----------------------------------------------------------------------------
624 # This FSP API is called after TempRamInit and initializes the memory.
626 #----------------------------------------------------------------------------
627 ASM_GLOBAL ASM_PFX(FspMemoryInitApi)
628 ASM_PFX(FspMemoryInitApi):
632 #----------------------------------------------------------------------------
635 # This API tears down temporary RAM
637 #----------------------------------------------------------------------------
638 ASM_GLOBAL ASM_PFX(TempRamExitApi)
639 ASM_PFX(TempRamExitApi):
643 #----------------------------------------------------------------------------
646 # This FSP API initializes the CPU and the chipset including the IO
647 # controllers in the chipset to enable normal operation of these devices.
649 #----------------------------------------------------------------------------
650 ASM_GLOBAL ASM_PFX(FspSiliconInitApi)
651 ASM_PFX(FspSiliconInitApi):
655 #----------------------------------------------------------------------------
658 # This is the FSP API common entry point to resume the FSP execution
660 #----------------------------------------------------------------------------
661 ASM_GLOBAL ASM_PFX(FspApiCommon)
662 ASM_PFX(FspApiCommon):
664 # EAX holds the API index
668 # Stack must be ready
674 movl $0x080000003, %eax
679 # Verify the calling condition
683 call ASM_PFX(FspApiCallingCheck)
687 movl %eax, 0x1C(%esp) # mov dword ptr [esp + 4 * 7], eax
693 cmpl $0x01, %eax # FspInit API
695 cmpl $0x03, %eax # FspMemoryInit API
697 jmp Pei2LoaderSwitchStack
701 # FspInit and FspMemoryInit APIs, setup the initial stack frame
705 # Store the address in FSP which will return control to the BL
707 pushl $FspApiCommonExit
710 # Create a Task Frame in the stack for the Boot Loader
712 pushfl # 2 pushf for 4 byte alignment
717 # Reserve 8 bytes for IDT save/restore
723 # Setup new FSP stack
726 movl PcdGet32(PcdTemporaryRamBase), %esp
727 addl PcdGet32(PcdTemporaryRamSize), %esp
728 subl $(DATA_LEN_AT_STACK_TOP + 0x40), %esp
731 # Pass the API Idx to SecStartup
736 # Pass the bootloader stack to SecStartup
741 # Pass entry point of the PEI core
743 call ASM_PFX(GetFspBaseAddress)
745 addl PcdGet32(PcdFspAreaSize), %edi
747 addl %ds:(%edi), %eax
751 # Pass BFV into the PEI Core
752 # It uses relative address to calucate the actual boot FV base
753 # For FSP impleantion with single FV, PcdFlashFvRecoveryBase and
754 # PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
755 # they are different. The code below can handle both cases.
757 call ASM_PFX(GetFspBaseAddress)
759 call ASM_PFX(GetBootFirmwareVolumeOffset)
764 # Pass stack base and size into the PEI Core
766 movl PcdGet32(PcdTemporaryRamBase), %eax
767 addl PcdGet32(PcdTemporaryRamSize), %eax
768 subl PcdGet32(PcdFspTemporaryRamSize), %eax
770 pushl PcdGet32(PcdFspTemporaryRamSize)
773 # Pass Control into the PEI Core
775 call ASM_PFX(SecStartup)