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(AsmGetFspBaseAddress)
219 ASM_GLOBAL ASM_PFX(AsmGetFspInfoHeader)
220 ASM_GLOBAL ASM_PFX(GetBootFirmwareVolumeOffset)
221 ASM_GLOBAL ASM_PFX(Loader2PeiSwitchStack)
225 # Define the data length that we saved on the stack top
227 .equ DATA_LEN_OF_PER0, 0x018
228 .equ DATA_LEN_OF_MCUD, 0x018
229 .equ DATA_LEN_AT_STACK_TOP, (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
231 #------------------------------------------------------------------------------
232 # SecPlatformInitDefault
234 # mm7 -> Return address
236 # eax -> 0 - Successful, Non-zero - Failed.
238 # eax is cleared and ebp is used for return address.
239 # All others reserved.
240 #------------------------------------------------------------------------------
241 ASM_GLOBAL ASM_PFX(SecPlatformInitDefault)
242 ASM_PFX(SecPlatformInitDefault):
244 # Save return address to EBP
249 SecPlatformInitDefaultExit:
253 #------------------------------------------------------------------------------
254 # LoadMicrocodeDefault
257 # esp -> LoadMicrocodeParams pointer
260 # All others destroyed
262 # No memory available, stack is hard-coded and used for return address
263 # Executed by SBSP and NBSP
264 # Beginning of microcode update region starts on paragraph boundary
265 #------------------------------------------------------------------------------
266 ASM_GLOBAL ASM_PFX(LoadMicrocodeDefault)
267 ASM_PFX(LoadMicrocodeDefault):
269 # Save return address to EBP
275 movl 4(%esp), %eax #dword ptr [] Parameter pointer
279 movl MicrocodeCodeAddr(%esp), %esi
284 movl $0x080000002, %eax
285 jmp LoadMicrocodeExit
289 # Get processor signature and platform ID from the installed processor
290 # and save into registers for later use
291 # ebx = processor signature
297 movl $MSR_IA32_PLATFORM_ID, %ecx
300 shrl $0x12, %ecx # shift (50d-32d=18d=0x12) bits
301 andl $0x07, %ecx # platform id at bit[52..50]
306 # Current register usage
307 # esp -> stack with paramters
308 # esi -> microcode update to check
309 # ebx = processor signature
314 # Check for valid microcode header
315 # Minimal test checking for header version and loader version as 1
318 cmpl %eax, MicrocodeHdrVersion(%esi)
320 cmpl %eax, MicrocodeHdrLoader(%esi)
324 # Check if signature and plaform ID match
326 cmpl MicrocodeHdrProcessor(%esi), %ebx
328 testl MicrocodeHdrFlags(%esi), %edx
329 jnz LoadCheck #Jif signature and platform ID match
333 # Check if extended header exists
334 # First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
337 cmpl %eax, MicrocodeHdrTotalSize(%esi)
339 cmpl %eax, MicrocodeHdrDataSize(%esi)
343 # Then verify total size - sizeof header > data size
345 movl MicrocodeHdrTotalSize(%esi), %ecx
346 subl $MicrocodeHdrLength, %ecx
347 cmpl MicrocodeHdrDataSize(%esi), %ecx
351 # Set edi -> extended header
354 addl $MicrocodeHdrLength, %edi
355 addl MicrocodeHdrDataSize(%esi), %edi
358 # Get count of extended structures
360 movl ExtSigHdrCount(%edi), %ecx
363 # Move pointer to first signature structure
365 addl ExtSigHdrLength, %edi
369 # Check if extended signature and platform ID match
371 cmpl %ebx, ExtSigProcessor(%edi)
373 test %edx, ExtSigFlags(%edi)
374 jnz LoadCheck # Jif signature and platform ID match
377 # Check if any more extended signatures exist
379 addl $ExtSigLength, %edi
384 # Advance just after end of this microcode
387 cmpl %eax, MicrocodeHdrTotalSize(%esi)
389 addl MicrocodeHdrTotalSize(%esi), %esi
392 addl $0x800, %esi #add esi, dword ptr 2048
397 # Advance by 4X dwords
399 addl $0x400, %esi #add esi, dword ptr 1024
403 # Is valid Microcode start point ?
405 cmpl $0x0ffffffff, MicrocodeHdrVersion(%esi)
408 # Is automatic size detection ?
410 movl MicrocodeCodeSize(%esp), %eax
411 cmpl $0x0ffffffff, %eax
414 # Address >= microcode region address + microcode region size?
416 addl MicrocodeCodeAddr(%esp), %eax
419 jae Done #Jif address is outside of microcode region
425 # Get the revision of the current microcode update loaded
427 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
428 xorl %eax, %eax # Clear EAX
429 xorl %edx, %edx # Clear EDX
430 wrmsr # Load 0 to MSR at 8Bh
434 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
435 rdmsr # Get current microcode signature
438 # Verify this microcode update is not already loaded
440 cmpl %edx, MicrocodeHdrRevision(%esi)
445 # EAX contains the linear address of the start of the Update Data
447 # ECX contains 79h (IA32_BIOS_UPDT_TRIG)
448 # Start microcode load with wrmsr
451 addl $MicrocodeHdrLength, %eax
453 movl $MSR_IA32_BIOS_UPDT_TRIG, %ecx
464 movl $MSR_IA32_BIOS_SIGN_ID, %ecx
465 rdmsr # Get current microcode signature
468 jnz LoadMicrocodeExit
469 movl $0x08000000E, %eax
475 #----------------------------------------------------------------------------
478 #----------------------------------------------------------------------------
479 ASM_GLOBAL ASM_PFX(EstablishStackFsp)
480 ASM_PFX(EstablishStackFsp):
482 # Save parameter pointer in edx
489 movl PcdGet32(PcdTemporaryRamBase), %esp
490 addl PcdGet32(PcdTemporaryRamSize), %esp
492 pushl $DATA_LEN_OF_MCUD # Size of the data region
493 pushl $0x4455434D # Signature of the data region 'MCUD'
494 pushl 12(%edx) # Code size
495 pushl 8(%edx) # Code base
496 pushl 4(%edx) # Microcode size
497 pushl (%edx) # Microcode base
500 # Save API entry/exit timestamp into stack
502 pushl $DATA_LEN_OF_PER0 # Size of the data region
503 pushl $0x30524550 # Signature of the data region 'PER0'
513 # Terminator for the data on stack
518 # Set ECX/EDX to the BootLoader temporary memory range
520 movl PcdGet32 (PcdTemporaryRamBase), %ecx
522 addl PcdGet32 (PcdTemporaryRamSize), %edx
523 subl PcdGet32 (PcdFspTemporaryRamSize), %edx
527 movd %mm7, %esi #RET_ESI
530 #----------------------------------------------------------------------------
533 # This FSP API will load the microcode update, enable code caching for the
534 # region specified by the boot loader and also setup a temporary stack to be
535 # used till main memory is initialized.
537 #----------------------------------------------------------------------------
538 ASM_GLOBAL ASM_PFX(TempRamInitApi)
539 ASM_PFX(TempRamInitApi):
541 # Ensure SSE is enabled
546 # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
551 # Save timestamp into XMM6
562 movl $0x80000002, %eax
568 movl $TempRamInitApiL1, %esi #CALL_MMX SecPlatformInit
570 .weak ASM_PFX(SecPlatformInit)
571 .set ASM_PFX(SecPlatformInit), ASM_PFX(SecPlatformInitDefault)
572 jmp ASM_PFX(SecPlatformInit)
581 movl $TempRamInitApiL2, %esi #CALL_MMX LoadMicrocode
583 .weak ASM_PFX(LoadMicrocode)
584 .set ASM_PFX(LoadMicrocode), ASM_PFX(LoadMicrocodeDefault)
585 jmp ASM_PFX(LoadMicrocode)
587 SAVE_EAX_MICROCODE_RET_STATUS #Save microcode return status in ECX-SLOT 3 in xmm6.
588 #@note If return value eax is not 0, microcode did not load, but continue and attempt to boot from ECX-SLOT 3 in xmm6.
594 movl $TempRamInitApiL3, %esi #CALL_MMX SecCarInit
596 jmp ASM_PFX(SecCarInit)
605 movl $TempRamInitApiL4, %esi #CALL_MMX EstablishStackFsp
607 jmp ASM_PFX(EstablishStackFsp)
610 LOAD_EAX_MICROCODE_RET_STATUS #Restore microcode status if no CAR init error.
614 # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
620 #----------------------------------------------------------------------------
623 # This FSP API will perform the processor and chipset initialization.
624 # This API will not return. Instead, it transfers the control to the
625 # ContinuationFunc provided in the parameter.
627 #----------------------------------------------------------------------------
628 ASM_GLOBAL ASM_PFX(FspInitApi)
633 #----------------------------------------------------------------------------
636 # This FSP API will notify the FSP about the different phases in the boot
639 #----------------------------------------------------------------------------
640 ASM_GLOBAL ASM_PFX(NotifyPhaseApi)
641 ASM_PFX(NotifyPhaseApi):
645 #----------------------------------------------------------------------------
648 # This FSP API is called after TempRamInit and initializes the memory.
650 #----------------------------------------------------------------------------
651 ASM_GLOBAL ASM_PFX(FspMemoryInitApi)
652 ASM_PFX(FspMemoryInitApi):
656 #----------------------------------------------------------------------------
659 # This API tears down temporary RAM
661 #----------------------------------------------------------------------------
662 ASM_GLOBAL ASM_PFX(TempRamExitApi)
663 ASM_PFX(TempRamExitApi):
667 #----------------------------------------------------------------------------
670 # This FSP API initializes the CPU and the chipset including the IO
671 # controllers in the chipset to enable normal operation of these devices.
673 #----------------------------------------------------------------------------
674 ASM_GLOBAL ASM_PFX(FspSiliconInitApi)
675 ASM_PFX(FspSiliconInitApi):
679 #----------------------------------------------------------------------------
682 # This is the FSP API common entry point to resume the FSP execution
684 #----------------------------------------------------------------------------
685 ASM_GLOBAL ASM_PFX(FspApiCommon)
686 ASM_PFX(FspApiCommon):
688 # EAX holds the API index
692 # Stack must be ready
698 movl $0x080000003, %eax
703 # Verify the calling condition
706 pushl 36(%esp) #push ApiParam [esp + 4 * 8 + 4]
707 pushl %eax #push ApiIdx
708 call ASM_PFX(FspApiCallingCheck)
712 movl %eax, 0x1C(%esp) # mov dword ptr [esp + 4 * 7], eax
718 cmpl $0x01, %eax # FspInit API
720 cmpl $0x03, %eax # FspMemoryInit API
722 call ASM_PFX(AsmGetFspInfoHeader)
723 jmp Loader2PeiSwitchStack
727 # FspInit and FspMemoryInit APIs, setup the initial stack frame
731 # Place holder to store the FspInfoHeader pointer
736 # Update the FspInfoHeader pointer
739 call ASM_PFX(AsmGetFspInfoHeader)
744 # Create a Task Frame in the stack for the Boot Loader
746 pushfl # 2 pushf for 4 byte alignment
751 # Reserve 8 bytes for IDT save/restore
757 # Setup new FSP stack
760 movl PcdGet32(PcdTemporaryRamBase), %esp
761 addl PcdGet32(PcdTemporaryRamSize), %esp
762 subl $(DATA_LEN_AT_STACK_TOP + 0x40), %esp
765 # Pass the API Idx to SecStartup
770 # Pass the BootLoader stack to SecStartup
775 # Pass entry point of the PEI core
777 call ASM_PFX(AsmGetFspBaseAddress)
779 addl PcdGet32(PcdFspAreaSize), %edi
781 addl %ds:(%edi), %eax
785 # Pass BFV into the PEI Core
786 # It uses relative address to calucate the actual boot FV base
787 # For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and
788 # PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
789 # they are different. The code below can handle both cases.
791 call ASM_PFX(AsmGetFspBaseAddress)
793 call ASM_PFX(GetBootFirmwareVolumeOffset)
798 # Pass stack base and size into the PEI Core
800 movl PcdGet32(PcdTemporaryRamBase), %eax
801 addl PcdGet32(PcdTemporaryRamSize), %eax
802 subl PcdGet32(PcdFspTemporaryRamSize), %eax
804 pushl PcdGet32(PcdFspTemporaryRamSize)
807 # Pass Control into the PEI Core
809 call ASM_PFX(SecStartup)