1 #------------------------------------------------------------------------------
3 # Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
8 # Provide FSP API entry points.
10 #------------------------------------------------------------------------------
13 .equ MSR_IA32_PLATFORM_ID, 0x00000017
14 .equ MSR_IA32_BIOS_UPDT_TRIG, 0x00000079
15 .equ MSR_IA32_BIOS_SIGN_ID, 0x0000008b
19 .equ MicrocodeHdrVersion, 0x0000
20 .equ MicrocodeHdrRevision, 0x0004
21 .equ MicrocodeHdrDate, 0x0008
22 .equ MicrocodeHdrProcessor, 0x000c
23 .equ MicrocodeHdrChecksum, 0x0010
24 .equ MicrocodeHdrLoader, 0x0014
25 .equ MicrocodeHdrFlags, 0x0018
26 .equ MicrocodeHdrDataSize, 0x001C
27 .equ MicrocodeHdrTotalSize, 0x0020
28 .equ MicrocodeHdrRsvd, 0x0024
30 .equ MicrocodeHdrLength, 0x0030 # MicrocodeHdrLength = MicrocodeHdrEnd - MicrocodeHdr
34 .equ ExtSigHdrCount, 0x0000
35 .equ ExtSigHdrChecksum, 0x0004
36 .equ ExtSigHdrRsvd, 0x0008
38 .equ ExtSigHdrLength, 0x0014 #ExtSigHdrLength = ExtSigHdrEnd - ExtSigHdr
41 .equ ExtSigProcessor, 0x0000
42 .equ ExtSigFlags, 0x0004
43 .equ ExtSigChecksum, 0x0008
45 .equ ExtSigLength, 0x000C #ExtSigLength = ExtSigEnd - ExtSig
48 .equ MicrocodeCodeAddr, 0x0000
49 .equ MicrocodeCodeSize, 0x0004
50 LoadMicrocodeParamsEnd:
55 pinsrw $0x00, %ebp, %xmm7
57 pinsrw $0x01, %ebp, %xmm7
60 pinsrw $0x02, %ebx, %xmm7
62 pinsrw $0x03, %ebx, %xmm7
65 pinsrw $0x04, %esi, %xmm7
67 pinsrw $0x05, %esi, %xmm7
70 pinsrw $0x06, %edi, %xmm7
72 pinsrw $0x07, %edi, %xmm7
75 pinsrw $0x00, %esp, %xmm6
77 pinsrw $0x01, %esp, %xmm6
82 pshufd $0xe4, %xmm7, %xmm7
84 pshufd $0xe4, %xmm7, %xmm7
86 pshufd $0x39, %xmm7, %xmm7
88 pshufd $0x93, %xmm7, %xmm7
90 pshufd $0x4e, %xmm7, %xmm7
92 pshufd $0x4e, %xmm7, %xmm7
94 pshufd $0x93, %xmm7, %xmm7
96 pshufd $0x39, %xmm7, %xmm7
102 pshufd $0x39, %xmm6, %xmm6
104 pshufd $0x93, %xmm6, %xmm6
108 pshufd $0xe4, %xmm6, %xmm6
110 pshufd $0xe4, %xmm6, %xmm6
114 pinsrw $0x02, %eax, %xmm6
116 pinsrw $0x03, %eax, %xmm6
121 pinsrw $0x04, %edx, %xmm6
123 pinsrw $0x05, %edx, %xmm6
135 # Float control word initial value:
136 # all exceptions masked, double-precision, round-to-nearest
138 ASM_PFX(mFpuControlWord): .word 0x027F
140 # Multimedia-extensions control word:
141 # all exceptions masked, round-to-nearest, flush to zero for masked underflow
143 ASM_PFX(mMmxControlWord): .long 0x01F80
146 # Processor has to support SSE
151 # Initialize floating point units
154 fldcw ASM_PFX(mFpuControlWord)
157 # Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test
158 # whether the processor supports SSE instruction.
166 # Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
173 # The processor should support SSE instruction and we can use
174 # ldmxcsr instruction
176 ldmxcsr ASM_PFX(mMmxControlWord)
179 #Save in ECX-SLOT 3 in xmm6.
180 .macro SAVE_EAX_MICROCODE_RET_STATUS
181 pinsrw $0x6, %eax, %xmm6
183 pinsrw $0x7, %eax, %xmm6
187 #Restore from ECX-SLOT 3 in xmm6.
188 .macro LOAD_EAX_MICROCODE_RET_STATUS
189 pshufd $0x93, %xmm6, %xmm6
191 pshufd $0x39, %xmm6, %xmm6
197 # Following are fixed PCDs
199 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase)
200 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize)
201 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize)
204 # Following functions will be provided in C
206 ASM_GLOBAL ASM_PFX(SecStartup)
207 ASM_GLOBAL ASM_PFX(FspApiCallingCheck)
210 # Following functions will be provided in PlatformSecLib
212 ASM_GLOBAL ASM_PFX(AsmGetFspBaseAddress)
213 ASM_GLOBAL ASM_PFX(AsmGetFspInfoHeader)
214 ASM_GLOBAL ASM_PFX(GetBootFirmwareVolumeOffset)
215 ASM_GLOBAL ASM_PFX(Loader2PeiSwitchStack)
219 # Define the data length that we saved on the stack top
221 .equ DATA_LEN_OF_PER0, 0x018
222 .equ DATA_LEN_OF_MCUD, 0x018
223 .equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
225 #------------------------------------------------------------------------------
226 # SecPlatformInitDefault
228 # mm7 -> Return address
230 # eax -> 0 - Successful, Non-zero - Failed.
232 # eax is cleared and ebp is used for return address.
233 # All others reserved.
234 #------------------------------------------------------------------------------
235 ASM_GLOBAL ASM_PFX(SecPlatformInitDefault)
236 ASM_PFX(SecPlatformInitDefault):
238 # Save return address to EBP
243 SecPlatformInitDefaultExit:
247 #------------------------------------------------------------------------------
248 # LoadMicrocodeDefault
251 # esp -> LoadMicrocodeParams pointer
254 # All others destroyed
256 # No memory available, stack is hard-coded and used for return address
257 # Executed by SBSP and NBSP
258 # Beginning of microcode update region starts on paragraph boundary
259 #------------------------------------------------------------------------------
260 ASM_GLOBAL ASM_PFX(LoadMicrocodeDefault)
261 ASM_PFX(LoadMicrocodeDefault):
263 # Save return address to EBP
269 movl 4(%esp), %eax #dword ptr [] Parameter pointer
273 movl MicrocodeCodeAddr(%esp), %esi
278 movl $0x080000002, %eax
279 jmp LoadMicrocodeExit
283 # Get processor signature and platform ID from the installed processor
284 # and save into registers for later use
285 # ebx = processor signature
291 movl $MSR_IA32_PLATFORM_ID, %ecx
294 shrl $0x12, %ecx # shift (50d-32d=18d=0x12) bits
295 andl $0x07, %ecx # platform id at bit[52..50]
300 # Current register usage
301 # esp -> stack with paramters
302 # esi -> microcode update to check
303 # ebx = processor signature
308 # Check for valid microcode header
309 # Minimal test checking for header version and loader version as 1
312 cmpl %eax, MicrocodeHdrVersion(%esi)
314 cmpl %eax, MicrocodeHdrLoader(%esi)
318 # Check if signature and plaform ID match
320 cmpl MicrocodeHdrProcessor(%esi), %ebx
322 testl MicrocodeHdrFlags(%esi), %edx
323 jnz LoadCheck #Jif signature and platform ID match
327 # Check if extended header exists
328 # First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
331 cmpl %eax, MicrocodeHdrTotalSize(%esi)
333 cmpl %eax, MicrocodeHdrDataSize(%esi)
337 # Then verify total size - sizeof header > data size
339 movl MicrocodeHdrTotalSize(%esi), %ecx
340 subl $MicrocodeHdrLength, %ecx
341 cmpl MicrocodeHdrDataSize(%esi), %ecx
345 # Set edi -> extended header
348 addl $MicrocodeHdrLength, %edi
349 addl MicrocodeHdrDataSize(%esi), %edi
352 # Get count of extended structures
354 movl ExtSigHdrCount(%edi), %ecx
357 # Move pointer to first signature structure
359 addl ExtSigHdrLength, %edi
363 # Check if extended signature and platform ID match
365 cmpl %ebx, ExtSigProcessor(%edi)
367 test %edx, ExtSigFlags(%edi)
368 jnz LoadCheck # Jif signature and platform ID match
371 # Check if any more extended signatures exist
373 addl $ExtSigLength, %edi
378 # Advance just after end of this microcode
381 cmpl %eax, MicrocodeHdrTotalSize(%esi)
383 addl MicrocodeHdrTotalSize(%esi), %esi
386 addl $0x800, %esi #add esi, dword ptr 2048
391 # Advance by 4X dwords
393 addl $0x400, %esi #add esi, dword ptr 1024
397 # Is valid Microcode start point ?
399 cmpl $0x0ffffffff, MicrocodeHdrVersion(%esi)
402 # Is automatic size detection ?
404 movl MicrocodeCodeSize(%esp), %eax
405 cmpl $0x0ffffffff, %eax
408 # Address >= microcode region address + microcode region size?
410 addl MicrocodeCodeAddr(%esp), %eax
413 jae Done #Jif address is outside of microcode region
419 # Get the revision of the current microcode update loaded
421 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
422 xorl %eax, %eax # Clear EAX
423 xorl %edx, %edx # Clear EDX
424 wrmsr # Load 0 to MSR at 8Bh
428 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
429 rdmsr # Get current microcode signature
432 # Verify this microcode update is not already loaded
434 cmpl %edx, MicrocodeHdrRevision(%esi)
439 # EAX contains the linear address of the start of the Update Data
441 # ECX contains 79h (IA32_BIOS_UPDT_TRIG)
442 # Start microcode load with wrmsr
445 addl $MicrocodeHdrLength, %eax
447 movl $MSR_IA32_BIOS_UPDT_TRIG, %ecx
458 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
459 rdmsr # Get current microcode signature
462 jnz LoadMicrocodeExit
463 movl $0x08000000E, %eax
469 #----------------------------------------------------------------------------
472 #----------------------------------------------------------------------------
473 ASM_GLOBAL ASM_PFX(EstablishStackFsp)
474 ASM_PFX(EstablishStackFsp):
476 # Save parameter pointer in edx
483 movl PcdGet32(PcdTemporaryRamBase), %esp
484 addl PcdGet32(PcdTemporaryRamSize), %esp
486 pushl $DATA_LEN_OF_MCUD # Size of the data region
487 pushl $0x4455434D # Signature of the data region 'MCUD'
488 pushl 12(%edx) # Code size
489 pushl 8(%edx) # Code base
490 pushl 4(%edx) # Microcode size
491 pushl (%edx) # Microcode base
494 # Save API entry/exit timestamp into stack
496 pushl $DATA_LEN_OF_PER0 # Size of the data region
497 pushl $0x30524550 # Signature of the data region 'PER0'
507 # Terminator for the data on stack
512 # Set ECX/EDX to the BootLoader temporary memory range
514 movl PcdGet32 (PcdTemporaryRamBase), %ecx
516 addl PcdGet32 (PcdTemporaryRamSize), %edx
517 subl PcdGet32 (PcdFspTemporaryRamSize), %edx
521 movd %mm7, %esi #RET_ESI
524 #----------------------------------------------------------------------------
527 # This FSP API will load the microcode update, enable code caching for the
528 # region specified by the boot loader and also setup a temporary stack to be
529 # used till main memory is initialized.
531 #----------------------------------------------------------------------------
532 ASM_GLOBAL ASM_PFX(TempRamInitApi)
533 ASM_PFX(TempRamInitApi):
535 # Ensure SSE is enabled
540 # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
545 # Save timestamp into XMM6
556 movl $0x80000002, %eax
562 movl $TempRamInitApiL1, %esi #CALL_MMX SecPlatformInit
564 .weak ASM_PFX(SecPlatformInit)
565 .set ASM_PFX(SecPlatformInit), ASM_PFX(SecPlatformInitDefault)
566 jmp ASM_PFX(SecPlatformInit)
575 movl $TempRamInitApiL2, %esi #CALL_MMX LoadMicrocode
577 .weak ASM_PFX(LoadMicrocode)
578 .set ASM_PFX(LoadMicrocode), ASM_PFX(LoadMicrocodeDefault)
579 jmp ASM_PFX(LoadMicrocode)
581 SAVE_EAX_MICROCODE_RET_STATUS #Save microcode return status in ECX-SLOT 3 in xmm6.
582 #@note If return value eax is not 0, microcode did not load, but continue and attempt to boot from ECX-SLOT 3 in xmm6.
588 movl $TempRamInitApiL3, %esi #CALL_MMX SecCarInit
590 jmp ASM_PFX(SecCarInit)
599 movl $TempRamInitApiL4, %esi #CALL_MMX EstablishStackFsp
601 jmp ASM_PFX(EstablishStackFsp)
604 LOAD_EAX_MICROCODE_RET_STATUS #Restore microcode status if no CAR init error.
608 # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
614 #----------------------------------------------------------------------------
617 # This FSP API will perform the processor and chipset initialization.
618 # This API will not return. Instead, it transfers the control to the
619 # ContinuationFunc provided in the parameter.
621 #----------------------------------------------------------------------------
622 ASM_GLOBAL ASM_PFX(FspInitApi)
627 #----------------------------------------------------------------------------
630 # This FSP API will notify the FSP about the different phases in the boot
633 #----------------------------------------------------------------------------
634 ASM_GLOBAL ASM_PFX(NotifyPhaseApi)
635 ASM_PFX(NotifyPhaseApi):
639 #----------------------------------------------------------------------------
642 # This FSP API is called after TempRamInit and initializes the memory.
644 #----------------------------------------------------------------------------
645 ASM_GLOBAL ASM_PFX(FspMemoryInitApi)
646 ASM_PFX(FspMemoryInitApi):
650 #----------------------------------------------------------------------------
653 # This API tears down temporary RAM
655 #----------------------------------------------------------------------------
656 ASM_GLOBAL ASM_PFX(TempRamExitApi)
657 ASM_PFX(TempRamExitApi):
661 #----------------------------------------------------------------------------
664 # This FSP API initializes the CPU and the chipset including the IO
665 # controllers in the chipset to enable normal operation of these devices.
667 #----------------------------------------------------------------------------
668 ASM_GLOBAL ASM_PFX(FspSiliconInitApi)
669 ASM_PFX(FspSiliconInitApi):
673 #----------------------------------------------------------------------------
676 # This is the FSP API common entry point to resume the FSP execution
678 #----------------------------------------------------------------------------
679 ASM_GLOBAL ASM_PFX(FspApiCommon)
680 ASM_PFX(FspApiCommon):
682 # EAX holds the API index
686 # Stack must be ready
692 movl $0x080000003, %eax
697 # Verify the calling condition
700 pushl 36(%esp) #push ApiParam [esp + 4 * 8 + 4]
701 pushl %eax #push ApiIdx
702 call ASM_PFX(FspApiCallingCheck)
706 movl %eax, 0x1C(%esp) # mov dword ptr [esp + 4 * 7], eax
712 cmpl $0x01, %eax # FspInit API
714 cmpl $0x03, %eax # FspMemoryInit API
716 call ASM_PFX(AsmGetFspInfoHeader)
717 jmp Loader2PeiSwitchStack
721 # FspInit and FspMemoryInit APIs, setup the initial stack frame
725 # Place holder to store the FspInfoHeader pointer
730 # Update the FspInfoHeader pointer
733 call ASM_PFX(AsmGetFspInfoHeader)
738 # Create a Task Frame in the stack for the Boot Loader
740 pushfl # 2 pushf for 4 byte alignment
745 # Reserve 8 bytes for IDT save/restore
751 # Setup new FSP stack
754 movl PcdGet32(PcdTemporaryRamBase), %esp
755 addl PcdGet32(PcdTemporaryRamSize), %esp
756 subl $(DATA_LEN_AT_STACK_TOP + 0x40), %esp
759 # Pass the API Idx to SecStartup
764 # Pass the BootLoader stack to SecStartup
769 # Pass entry point of the PEI core
771 call ASM_PFX(AsmGetFspBaseAddress)
773 addl PcdGet32(PcdFspAreaSize), %edi
775 addl %ds:(%edi), %eax
779 # Pass BFV into the PEI Core
780 # It uses relative address to calucate the actual boot FV base
781 # For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and
782 # PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
783 # they are different. The code below can handle both cases.
785 call ASM_PFX(AsmGetFspBaseAddress)
787 call ASM_PFX(GetBootFirmwareVolumeOffset)
792 # Pass stack base and size into the PEI Core
794 movl PcdGet32(PcdTemporaryRamBase), %eax
795 addl PcdGet32(PcdTemporaryRamSize), %eax
796 subl PcdGet32(PcdFspTemporaryRamSize), %eax
798 pushl PcdGet32(PcdFspTemporaryRamSize)
801 # Pass Control into the PEI Core
803 call ASM_PFX(SecStartup)