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 #------------------------------------------------------------------------------
19 .equ MSR_IA32_PLATFORM_ID, 0x00000017
20 .equ MSR_IA32_BIOS_UPDT_TRIG, 0x00000079
21 .equ MSR_IA32_BIOS_SIGN_ID, 0x0000008b
25 .equ MicrocodeHdrVersion, 0x0000
26 .equ MicrocodeHdrRevision, 0x0004
27 .equ MicrocodeHdrDate, 0x0008
28 .equ MicrocodeHdrProcessor, 0x000c
29 .equ MicrocodeHdrChecksum, 0x0010
30 .equ MicrocodeHdrLoader, 0x0014
31 .equ MicrocodeHdrFlags, 0x0018
32 .equ MicrocodeHdrDataSize, 0x001C
33 .equ MicrocodeHdrTotalSize, 0x0020
34 .equ MicrocodeHdrRsvd, 0x0024
36 .equ MicrocodeHdrLength, 0x0030 # MicrocodeHdrLength = MicrocodeHdrEnd - MicrocodeHdr
40 .equ ExtSigHdrCount, 0x0000
41 .equ ExtSigHdrChecksum, 0x0004
42 .equ ExtSigHdrRsvd, 0x0008
44 .equ ExtSigHdrLength, 0x0014 #ExtSigHdrLength = ExtSigHdrEnd - ExtSigHdr
47 .equ ExtSigProcessor, 0x0000
48 .equ ExtSigFlags, 0x0004
49 .equ ExtSigChecksum, 0x0008
51 .equ ExtSigLength, 0x000C #ExtSigLength = ExtSigEnd - ExtSig
54 .equ MicrocodeCodeAddr, 0x0000
55 .equ MicrocodeCodeSize, 0x0004
56 LoadMicrocodeParamsEnd:
61 pinsrw $0x00, %ebp, %xmm7
63 pinsrw $0x01, %ebp, %xmm7
66 pinsrw $0x02, %ebx, %xmm7
68 pinsrw $0x03, %ebx, %xmm7
71 pinsrw $0x04, %esi, %xmm7
73 pinsrw $0x05, %esi, %xmm7
76 pinsrw $0x06, %edi, %xmm7
78 pinsrw $0x07, %edi, %xmm7
81 pinsrw $0x00, %esp, %xmm6
83 pinsrw $0x01, %esp, %xmm6
88 pshufd $0xe4, %xmm7, %xmm7
90 pshufd $0xe4, %xmm7, %xmm7
92 pshufd $0x39, %xmm7, %xmm7
94 pshufd $0x93, %xmm7, %xmm7
96 pshufd $0x4e, %xmm7, %xmm7
98 pshufd $0x4e, %xmm7, %xmm7
100 pshufd $0x93, %xmm7, %xmm7
102 pshufd $0x39, %xmm7, %xmm7
108 pshufd $0x39, %xmm6, %xmm6
110 pshufd $0x93, %xmm6, %xmm6
114 pshufd $0xe4, %xmm6, %xmm6
116 pshufd $0xe4, %xmm6, %xmm6
120 pinsrw $0x02, %eax, %xmm6
122 pinsrw $0x03, %eax, %xmm6
127 pinsrw $0x04, %edx, %xmm6
129 pinsrw $0x05, %edx, %xmm6
141 # Float control word initial value:
142 # all exceptions masked, double-precision, round-to-nearest
144 ASM_PFX(mFpuControlWord): .word 0x027F
146 # Multimedia-extensions control word:
147 # all exceptions masked, round-to-nearest, flush to zero for masked underflow
149 ASM_PFX(mMmxControlWord): .long 0x01F80
152 # Processor has to support SSE
157 # Initialize floating point units
160 fldcw ASM_PFX(mFpuControlWord)
163 # Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test
164 # whether the processor supports SSE instruction.
172 # Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
179 # The processor should support SSE instruction and we can use
180 # ldmxcsr instruction
182 ldmxcsr ASM_PFX(mMmxControlWord)
185 #Save in ECX-SLOT 3 in xmm6.
186 .macro SAVE_EAX_MICROCODE_RET_STATUS
187 pinsrw $0x6, %eax, %xmm6
189 pinsrw $0x7, %eax, %xmm6
193 #Restore from ECX-SLOT 3 in xmm6.
194 .macro LOAD_EAX_MICROCODE_RET_STATUS
195 pshufd $0x93, %xmm6, %xmm6
197 pshufd $0x39, %xmm6, %xmm6
203 # Following are fixed PCDs
205 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase)
206 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize)
207 ASM_GLOBAL ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize)
210 # Following functions will be provided in C
212 ASM_GLOBAL ASM_PFX(SecStartup)
213 ASM_GLOBAL ASM_PFX(FspApiCallingCheck)
216 # Following functions will be provided in PlatformSecLib
218 ASM_GLOBAL ASM_PFX(GetBootFirmwareVolumeOffset)
219 ASM_GLOBAL ASM_PFX(Pei2LoaderSwitchStack)
223 # Define the data length that we saved on the stack top
225 .equ DATA_LEN_OF_PER0, 0x018
226 .equ DATA_LEN_OF_MCUD, 0x018
227 .equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
229 #------------------------------------------------------------------------------
230 # SecPlatformInitDefault
232 # mm7 -> Return address
234 # eax -> 0 - Successful, Non-zero - Failed.
236 # eax is cleared and ebp is used for return address.
237 # All others reserved.
238 #------------------------------------------------------------------------------
239 ASM_GLOBAL ASM_PFX(SecPlatformInitDefault)
240 ASM_PFX(SecPlatformInitDefault):
242 # Save return address to EBP
247 SecPlatformInitDefaultExit:
251 #------------------------------------------------------------------------------
252 # LoadMicrocodeDefault
255 # esp -> LoadMicrocodeParams pointer
258 # All others destroyed
260 # No memory available, stack is hard-coded and used for return address
261 # Executed by SBSP and NBSP
262 # Beginning of microcode update region starts on paragraph boundary
263 #------------------------------------------------------------------------------
264 ASM_GLOBAL ASM_PFX(LoadMicrocodeDefault)
265 ASM_PFX(LoadMicrocodeDefault):
267 # Save return address to EBP
273 movl 4(%esp), %eax #dword ptr [] Parameter pointer
277 movl MicrocodeCodeAddr(%esp), %esi
282 movl $0x080000002, %eax
283 jmp LoadMicrocodeExit
287 # Get processor signature and platform ID from the installed processor
288 # and save into registers for later use
289 # ebx = processor signature
295 movl $MSR_IA32_PLATFORM_ID, %ecx
298 shrl $0x12, %ecx #($50-$32)
304 # Current register usage
305 # esp -> stack with paramters
306 # esi -> microcode update to check
307 # ebx = processor signature
312 # Check for valid microcode header
313 # Minimal test checking for header version and loader version as 1
316 cmpl %eax, MicrocodeHdrVersion(%esi)
318 cmpl %eax, MicrocodeHdrLoader(%esi)
322 # Check if signature and plaform ID match
324 cmpl MicrocodeHdrProcessor(%esi), %ebx
326 testl MicrocodeHdrFlags(%esi), %edx
327 jnz LoadCheck #Jif signature and platform ID match
331 # Check if extended header exists
332 # First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
335 cmpl %eax, MicrocodeHdrTotalSize(%esi)
337 cmpl %eax, MicrocodeHdrDataSize(%esi)
341 # Then verify total size - sizeof header > data size
343 movl MicrocodeHdrTotalSize(%esi), %ecx
344 subl $MicrocodeHdrLength, %ecx
345 cmpl MicrocodeHdrDataSize(%esi), %ecx
349 # Set edi -> extended header
352 addl $MicrocodeHdrLength, %edi
353 addl MicrocodeHdrDataSize(%esi), %edi
356 # Get count of extended structures
358 movl ExtSigHdrCount(%edi), %ecx
361 # Move pointer to first signature structure
363 addl ExtSigHdrLength, %edi
367 # Check if extended signature and platform ID match
369 cmpl %ebx, ExtSigProcessor(%edi)
371 test %edx, ExtSigFlags(%edi)
372 jnz LoadCheck # Jif signature and platform ID match
375 # Check if any more extended signatures exist
377 addl $ExtSigLength, %edi
382 # Advance just after end of this microcode
385 cmpl %eax, MicrocodeHdrTotalSize(%esi)
387 addl MicrocodeHdrTotalSize(%esi), %esi
390 addl $0x800, %esi #add esi, dword ptr 2048
395 # Advance by 4X dwords
397 addl $0x400, %esi #add esi, dword ptr 1024
401 # Is valid Microcode start point ?
403 cmpl $0x0ffffffff, MicrocodeHdrVersion(%esi)
406 # Is automatic size detection ?
408 movl MicrocodeCodeSize(%esp), %eax
409 cmpl $0x0ffffffff, %eax
412 # Address >= microcode region address + microcode region size?
414 addl MicrocodeCodeAddr(%esp), %eax
417 jae Done #Jif address is outside of microcode region
423 # Get the revision of the current microcode update loaded
425 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
426 xorl %eax, %eax # Clear EAX
427 xorl %edx, %edx # Clear EDX
428 wrmsr # Load 0 to MSR at 8Bh
432 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
433 rdmsr # Get current microcode signature
436 # Verify this microcode update is not already loaded
438 cmpl %edx, MicrocodeHdrRevision(%esi)
443 # EAX contains the linear address of the start of the Update Data
445 # ECX contains 79h (IA32_BIOS_UPDT_TRIG)
446 # Start microcode load with wrmsr
449 addl $MicrocodeHdrLength, %eax
451 movl $MSR_IA32_BIOS_UPDT_TRIG, %ecx
462 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
463 rdmsr # Get current microcode signature
466 jnz LoadMicrocodeExit
467 movl $0x08000000E, %eax
473 #----------------------------------------------------------------------------
476 #----------------------------------------------------------------------------
477 ASM_GLOBAL ASM_PFX(EstablishStackFsp)
478 ASM_PFX(EstablishStackFsp):
480 # Save parameter pointer in edx
487 movl PcdGet32(PcdTemporaryRamBase), %esp
488 addl PcdGet32(PcdTemporaryRamSize), %esp
490 pushl $DATA_LEN_OF_MCUD # Size of the data region
491 pushl $0x4455434D # Signature of the data region 'MCUD'
492 pushl 12(%edx) # Code size
493 pushl 8(%edx) # Code base
494 pushl 4(%edx) # Microcode size
495 pushl (%edx) # Microcode base
498 # Save API entry/exit timestamp into stack
500 pushl $DATA_LEN_OF_PER0 # Size of the data region
501 pushl $0x30524550 # Signature of the data region 'PER0'
511 # Terminator for the data on stack
516 # Set ECX/EDX to the BootLoader temporary memory range
518 movl PcdGet32 (PcdTemporaryRamBase), %ecx
520 addl PcdGet32 (PcdTemporaryRamSize), %edx
521 subl PcdGet32 (PcdFspTemporaryRamSize), %edx
525 movd %mm7, %esi #RET_ESI
528 #----------------------------------------------------------------------------
531 # This FSP API will load the microcode update, enable code caching for the
532 # region specified by the boot loader and also setup a temporary stack to be
533 # used till main memory is initialized.
535 #----------------------------------------------------------------------------
536 ASM_GLOBAL ASM_PFX(TempRamInitApi)
537 ASM_PFX(TempRamInitApi):
539 # Ensure SSE is enabled
544 # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
549 # Save timestamp into XMM6
560 movl $0x80000002, %eax
564 # CPUID/DeviceID check
565 # and Sec Platform Init
567 movl $TempRamInitApiL1, %esi #CALL_MMX SecPlatformInit
569 .weak ASM_PFX(SecPlatformInit)
570 .set ASM_PFX(SecPlatformInit), ASM_PFX(SecPlatformInitDefault)
571 jmp ASM_PFX(SecPlatformInit)
580 movl $TempRamInitApiL2, %esi #CALL_MMX LoadMicrocode
582 .weak ASM_PFX(LoadMicrocode)
583 .set ASM_PFX(LoadMicrocode), ASM_PFX(LoadMicrocodeDefault)
584 jmp ASM_PFX(LoadMicrocode)
586 SAVE_EAX_MICROCODE_RET_STATUS #Save microcode return status in ECX-SLOT 3 in xmm6.
587 #@note If return value eax is not 0, microcode did not load, but continue and attempt to boot from ECX-SLOT 3 in xmm6.
593 movl $TempRamInitApiL3, %esi #CALL_MMX SecCarInit
595 jmp ASM_PFX(SecCarInit)
604 movl $TempRamInitApiL4, %esi #CALL_MMX EstablishStackFsp
606 jmp ASM_PFX(EstablishStackFsp)
609 LOAD_EAX_MICROCODE_RET_STATUS #Restore microcode status if no CAR init error.
613 # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
619 #----------------------------------------------------------------------------
622 # This FSP API will perform the processor and chipset initialization.
623 # This API will not return. Instead, it transfers the control to the
624 # ContinuationFunc provided in the parameter.
626 #----------------------------------------------------------------------------
627 ASM_GLOBAL ASM_PFX(FspInitApi)
632 #----------------------------------------------------------------------------
635 # This FSP API will notify the FSP about the different phases in the boot
638 #----------------------------------------------------------------------------
639 ASM_GLOBAL ASM_PFX(NotifyPhaseApi)
640 ASM_PFX(NotifyPhaseApi):
644 #----------------------------------------------------------------------------
647 # This FSP API is called after TempRamInit and initializes the memory.
649 #----------------------------------------------------------------------------
650 ASM_GLOBAL ASM_PFX(FspMemoryInitApi)
651 ASM_PFX(FspMemoryInitApi):
655 #----------------------------------------------------------------------------
658 # This API tears down temporary RAM
660 #----------------------------------------------------------------------------
661 ASM_GLOBAL ASM_PFX(TempRamExitApi)
662 ASM_PFX(TempRamExitApi):
666 #----------------------------------------------------------------------------
669 # This FSP API initializes the CPU and the chipset including the IO
670 # controllers in the chipset to enable normal operation of these devices.
672 #----------------------------------------------------------------------------
673 ASM_GLOBAL ASM_PFX(FspSiliconInitApi)
674 ASM_PFX(FspSiliconInitApi):
678 #----------------------------------------------------------------------------
681 # This is the FSP API common entry point to resume the FSP execution
683 #----------------------------------------------------------------------------
684 ASM_GLOBAL ASM_PFX(FspApiCommon)
685 ASM_PFX(FspApiCommon):
687 # EAX holds the API index
691 # Stack must be ready
697 movl $0x080000003, %eax
702 # Verify the calling condition
706 call ASM_PFX(FspApiCallingCheck)
710 movl %eax, 0x1C(%esp) # mov dword ptr [esp + 4 * 7], eax
716 cmpl $0x01, %eax # FspInit API
718 cmpl $0x03, %eax # FspMemoryInit API
720 jmp Pei2LoaderSwitchStack
724 # FspInit and FspMemoryInit APIs, setup the initial stack frame
728 # Store the address in FSP which will return control to the BL
730 pushl $FspApiCommonExit
733 # Create a Task Frame in the stack for the Boot Loader
735 pushfl # 2 pushf for 4 byte alignment
740 # Reserve 8 bytes for IDT save/restore
746 # Setup new FSP stack
749 movl PcdGet32(PcdTemporaryRamBase), %esp
750 addl PcdGet32(PcdTemporaryRamSize), %esp
751 subl $(DATA_LEN_AT_STACK_TOP + 0x40), %esp
754 # Pass the API Idx to SecStartup
759 # Pass the BootLoader stack to SecStartup
764 # Pass entry point of the PEI core
766 call ASM_PFX(GetFspBaseAddress)
768 addl PcdGet32(PcdFspAreaSize), %edi
770 addl %ds:(%edi), %eax
774 # Pass BFV into the PEI Core
775 # It uses relative address to calucate the actual boot FV base
776 # For FSP impleantion with single FV, PcdFlashFvRecoveryBase and
777 # PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
778 # they are different. The code below can handle both cases.
780 call ASM_PFX(GetFspBaseAddress)
782 call ASM_PFX(GetBootFirmwareVolumeOffset)
787 # Pass stack base and size into the PEI Core
789 movl PcdGet32(PcdTemporaryRamBase), %eax
790 addl PcdGet32(PcdTemporaryRamSize), %eax
791 subl PcdGet32(PcdFspTemporaryRamSize), %eax
793 pushl PcdGet32(PcdFspTemporaryRamSize)
796 # Pass Control into the PEI Core
798 call ASM_PFX(SecStartup)