• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#------------------------------------------------------------------------------
2#
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.
8#
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.
11#
12# Abstract:
13#
14#   Provide FSP API entry points.
15#
16#------------------------------------------------------------------------------
17
18
19.equ MSR_IA32_PLATFORM_ID,                   0x00000017
20.equ MSR_IA32_BIOS_UPDT_TRIG,                0x00000079
21.equ MSR_IA32_BIOS_SIGN_ID,                  0x0000008b
22
23
24MicrocodeHdr:
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
35MicrocodeHdrEnd:
36.equ        MicrocodeHdrLength,                  0x0030  # MicrocodeHdrLength = MicrocodeHdrEnd - MicrocodeHdr
37
38
39ExtSigHdr:
40.equ        ExtSigHdrCount,                  0x0000
41.equ        ExtSigHdrChecksum,               0x0004
42.equ        ExtSigHdrRsvd,                   0x0008
43ExtSigHdrEnd:
44.equ        ExtSigHdrLength,                 0x0014  #ExtSigHdrLength = ExtSigHdrEnd - ExtSigHdr
45
46ExtSig:
47.equ        ExtSigProcessor,                 0x0000
48.equ        ExtSigFlags,                     0x0004
49.equ        ExtSigChecksum,                  0x0008
50ExtSigEnd:
51.equ        ExtSigLength,                    0x000C  #ExtSigLength = ExtSigEnd - ExtSig
52
53LoadMicrocodeParams:
54.equ        MicrocodeCodeAddr,               0x0000
55.equ        MicrocodeCodeSize,               0x0004
56LoadMicrocodeParamsEnd:
57
58
59
60.macro SAVE_REGS
61  pinsrw     $0x00, %ebp, %xmm7
62  ror        $0x10, %ebp
63  pinsrw     $0x01, %ebp, %xmm7
64  ror        $0x10, %ebp
65#
66  pinsrw     $0x02, %ebx, %xmm7
67  ror        $0x10, %ebx
68  pinsrw     $0x03, %ebx, %xmm7
69  ror        $0x10, %ebx
70#
71  pinsrw     $0x04, %esi, %xmm7
72  ror        $0x10, %esi
73  pinsrw     $0x05, %esi, %xmm7
74  ror        $0x10, %esi
75#
76  pinsrw     $0x06, %edi, %xmm7
77  ror        $0x10, %edi
78  pinsrw     $0x07, %edi, %xmm7
79  ror        $0x10, %edi
80#
81  pinsrw     $0x00, %esp, %xmm6
82  ror        $0x10, %esp
83  pinsrw     $0x01, %esp, %xmm6
84  ror        $0x10, %esp
85.endm
86
87.macro LOAD_REGS
88  pshufd     $0xe4, %xmm7, %xmm7
89  movd       %xmm7, %ebp
90  pshufd     $0xe4, %xmm7, %xmm7
91#
92  pshufd     $0x39, %xmm7, %xmm7
93  movd       %xmm7, %ebx
94  pshufd     $0x93, %xmm7, %xmm7
95#
96  pshufd     $0x4e, %xmm7, %xmm7
97  movd       %xmm7, %esi
98  pshufd     $0x4e, %xmm7, %xmm7
99#
100  pshufd     $0x93, %xmm7, %xmm7
101  movd       %xmm7, %edi
102  pshufd     $0x39, %xmm7, %xmm7
103#
104  movd       %xmm6, %esp
105.endm
106
107.macro LOAD_EAX
108  pshufd     $0x39, %xmm6, %xmm6
109  movd       %xmm6, %eax
110  pshufd     $0x93, %xmm6, %xmm6
111.endm
112
113.macro LOAD_EDX
114  pshufd     $0xe4, %xmm6, %xmm6
115  movd       %xmm6, %edx
116  pshufd     $0xe4, %xmm6, %xmm6
117.endm
118
119.macro SAVE_EAX
120  pinsrw     $0x02, %eax, %xmm6
121  ror        $0x10, %eax
122  pinsrw     $0x03, %eax, %xmm6
123  ror        $0x10, %eax
124.endm
125
126.macro SAVE_EDX
127  pinsrw     $0x04, %edx, %xmm6
128  ror        $0x10, %edx
129  pinsrw     $0x05, %edx, %xmm6
130  ror        $0x10, %edx
131.endm
132
133.macro LOAD_ESP
134  movd       %xmm6, %esp
135.endm
136
137.macro ENABLE_SSE
138    jmp     NextAddress
139.align 4
140    #
141    # Float control word initial value:
142    # all exceptions masked, double-precision, round-to-nearest
143    #
144ASM_PFX(mFpuControlWord): .word     0x027F
145    #
146    # Multimedia-extensions control word:
147    # all exceptions masked, round-to-nearest, flush to zero for masked underflow
148    #
149ASM_PFX(mMmxControlWord): .long     0x01F80
150SseError:
151    #
152    # Processor has to support SSE
153    #
154    jmp     SseError
155NextAddress:
156    #
157    # Initialize floating point units
158    #
159    finit
160    fldcw   ASM_PFX(mFpuControlWord)
161
162    #
163    # Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test
164    # whether the processor supports SSE instruction.
165    #
166    movl    $1,  %eax
167    cpuid
168    btl     $25, %edx
169    jnc     SseError
170
171    #
172    # Set OSFXSR bit (bit #9) & OSXMMEXCPT bit (bit #10)
173    #
174    movl    %cr4, %eax
175    orl     $BIT9, %eax
176    movl    %eax, %cr4
177
178    #
179    # The processor should support SSE instruction and we can use
180    # ldmxcsr instruction
181    #
182    ldmxcsr ASM_PFX(mMmxControlWord)
183.endm
184
185#Save in ECX-SLOT 3 in xmm6.
186.macro SAVE_EAX_MICROCODE_RET_STATUS
187  pinsrw     $0x6, %eax, %xmm6
188  ror        $0x10, %eax
189  pinsrw     $0x7, %eax, %xmm6
190  rol        $0x10, %eax
191.endm
192
193#Restore from ECX-SLOT 3 in xmm6.
194.macro LOAD_EAX_MICROCODE_RET_STATUS
195  pshufd     $0x93, %xmm6, %xmm6
196  movd       %xmm6, %eax
197  pshufd     $0x39, %xmm6, %xmm6
198.endm
199
200
201
202#
203# Following are fixed PCDs
204#
205ASM_GLOBAL    ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamBase)
206ASM_GLOBAL    ASM_PFX(_gPcd_FixedAtBuild_PcdTemporaryRamSize)
207ASM_GLOBAL    ASM_PFX(_gPcd_FixedAtBuild_PcdFspTemporaryRamSize)
208
209#
210# Following functions will be provided in C
211#
212ASM_GLOBAL    ASM_PFX(SecStartup)
213ASM_GLOBAL    ASM_PFX(FspApiCallingCheck)
214
215#
216# Following functions will be provided in PlatformSecLib
217#
218ASM_GLOBAL    ASM_PFX(AsmGetFspBaseAddress)
219ASM_GLOBAL    ASM_PFX(AsmGetFspInfoHeader)
220ASM_GLOBAL    ASM_PFX(GetBootFirmwareVolumeOffset)
221ASM_GLOBAL    ASM_PFX(Loader2PeiSwitchStack)
222
223
224#
225# Define the data length that we saved on the stack top
226#
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)
230
231#------------------------------------------------------------------------------
232# SecPlatformInitDefault
233# Inputs:
234#   mm7 -> Return address
235# Outputs:
236#   eax -> 0 - Successful, Non-zero - Failed.
237# Register Usage:
238#   eax is cleared and ebp is used for return address.
239#   All others reserved.
240#------------------------------------------------------------------------------
241ASM_GLOBAL ASM_PFX(SecPlatformInitDefault)
242ASM_PFX(SecPlatformInitDefault):
243   #
244   # Save return address to EBP
245   #
246   movd   %mm7, %ebp
247   xorl   %eax, %eax
248
249SecPlatformInitDefaultExit:
250   jmp   *%ebp
251
252
253#------------------------------------------------------------------------------
254# LoadMicrocodeDefault
255#
256# Inputs:
257#   esp -> LoadMicrocodeParams pointer
258# Register Usage:
259#   esp  Preserved
260#   All others destroyed
261# Assumptions:
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#------------------------------------------------------------------------------
266ASM_GLOBAL ASM_PFX(LoadMicrocodeDefault)
267ASM_PFX(LoadMicrocodeDefault):
268   #
269   # Save return address to EBP
270   #
271   movd   %mm7, %ebp
272
273   cmpl   $0x00, %esp
274   jz     ParamError
275   movl   4(%esp), %eax                       #dword ptr []     Parameter pointer
276   cmpl   $0x00, %eax
277   jz     ParamError
278   movl   %eax, %esp
279   movl   MicrocodeCodeAddr(%esp), %esi
280   cmpl   $0x00, %esi
281   jnz    CheckMainHeader
282
283ParamError:
284   movl   $0x080000002, %eax
285   jmp    LoadMicrocodeExit
286
287CheckMainHeader:
288   #
289   # Get processor signature and platform ID from the installed processor
290   # and save into registers for later use
291   # ebx = processor signature
292   # edx = platform ID
293   #
294   movl   $0x01, %eax
295   cpuid
296   movl   %eax, %ebx
297   movl   $MSR_IA32_PLATFORM_ID, %ecx
298   rdmsr
299   movl   %edx, %ecx
300   shrl   $0x12, %ecx                        # shift (50d-32d=18d=0x12) bits
301   andl   $0x07, %ecx                        # platform id at bit[52..50]
302   movl   $0x01, %edx
303   shll   %cl,%edx
304
305   #
306   # Current register usage
307   # esp -> stack with paramters
308   # esi -> microcode update to check
309   # ebx = processor signature
310   # edx = platform ID
311   #
312
313   #
314   # Check for valid microcode header
315   # Minimal test checking for header version and loader version as 1
316   #
317   movl   $0x01, %eax
318   cmpl   %eax, MicrocodeHdrVersion(%esi)
319   jne    AdvanceFixedSize
320   cmpl   %eax, MicrocodeHdrLoader(%esi)
321   jne    AdvanceFixedSize
322
323   #
324   # Check if signature and plaform ID match
325   #
326   cmpl   MicrocodeHdrProcessor(%esi), %ebx
327   jne    LoadMicrocodeL0
328   testl  MicrocodeHdrFlags(%esi), %edx
329   jnz    LoadCheck                          #Jif signature and platform ID match
330
331LoadMicrocodeL0:
332   #
333   # Check if extended header exists
334   # First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
335   #
336   xorl   %eax, %eax
337   cmpl   %eax, MicrocodeHdrTotalSize(%esi)
338   je     NextMicrocode
339   cmpl   %eax, MicrocodeHdrDataSize(%esi)
340   je     NextMicrocode
341
342   #
343   # Then verify total size - sizeof header > data size
344   #
345   movl   MicrocodeHdrTotalSize(%esi), %ecx
346   subl   $MicrocodeHdrLength, %ecx
347   cmpl   MicrocodeHdrDataSize(%esi), %ecx
348   jle NextMicrocode
349
350   #
351   # Set edi -> extended header
352   #
353   movl   %esi, %edi
354   addl   $MicrocodeHdrLength, %edi
355   addl   MicrocodeHdrDataSize(%esi), %edi
356
357   #
358   # Get count of extended structures
359   #
360   movl   ExtSigHdrCount(%edi), %ecx
361
362   #
363   # Move pointer to first signature structure
364   #
365   addl   ExtSigHdrLength, %edi
366
367CheckExtSig:
368   #
369   # Check if extended signature and platform ID match
370   #
371   cmpl   %ebx, ExtSigProcessor(%edi)
372   jne    LoadMicrocodeL1
373   test   %edx, ExtSigFlags(%edi)
374   jnz    LoadCheck                          # Jif signature and platform ID match
375LoadMicrocodeL1:
376   #
377   # Check if any more extended signatures exist
378   #
379   addl   $ExtSigLength, %edi
380   loop   CheckExtSig
381
382NextMicrocode:
383   #
384   # Advance just after end of this microcode
385   #
386   xorl   %eax, %eax
387   cmpl   %eax, MicrocodeHdrTotalSize(%esi)
388   je     LoadMicrocodeL2
389   addl   MicrocodeHdrTotalSize(%esi), %esi
390   jmp    CheckAddress
391LoadMicrocodeL2:
392   addl   $0x800, %esi                       #add   esi, dword ptr 2048
393   jmp    CheckAddress
394
395AdvanceFixedSize:
396   #
397   # Advance by 4X dwords
398   #
399   addl   $0x400, %esi                       #add   esi, dword ptr 1024
400
401CheckAddress:
402   #
403   # Is valid Microcode start point ?
404   #
405   cmpl   $0x0ffffffff, MicrocodeHdrVersion(%esi)
406
407   #
408   # Is automatic size detection ?
409   #
410   movl   MicrocodeCodeSize(%esp), %eax
411   cmpl   $0x0ffffffff, %eax
412   jz     LoadMicrocodeL3
413   #
414   # Address >= microcode region address + microcode region size?
415   #
416   addl   MicrocodeCodeAddr(%esp), %eax
417
418   cmpl   %eax, %esi
419   jae    Done                               #Jif address is outside of microcode region
420   jmp    CheckMainHeader
421
422LoadMicrocodeL3:
423LoadCheck:
424   #
425   # Get the revision of the current microcode update loaded
426   #
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
431
432   movl   $0x01, %eax
433   cpuid
434   movl   $MSR_IA32_BIOS_SIGN_ID, %ecx
435   rdmsr                                     # Get current microcode signature
436
437   #
438   # Verify this microcode update is not already loaded
439   #
440   cmpl   %edx, MicrocodeHdrRevision(%esi)
441   je     Continue
442
443LoadMicrocode0:
444   #
445   # EAX contains the linear address of the start of the Update Data
446   # EDX contains zero
447   # ECX contains 79h (IA32_BIOS_UPDT_TRIG)
448   # Start microcode load with wrmsr
449   #
450   movl   %esi, %eax
451   addl   $MicrocodeHdrLength, %eax
452   xorl   %edx, %edx
453   movl   $MSR_IA32_BIOS_UPDT_TRIG, %ecx
454   wrmsr
455   movl   $0x01, %eax
456   cpuid
457
458Continue:
459   jmp    NextMicrocode
460
461Done:
462   movl   $0x01, %eax
463   cpuid
464   movl   $MSR_IA32_BIOS_SIGN_ID, %ecx
465   rdmsr                                     # Get current microcode signature
466   xorl   %eax, %eax
467   cmpl   $0x00, %edx
468   jnz    LoadMicrocodeExit
469   movl   $0x08000000E, %eax
470
471LoadMicrocodeExit:
472   jmp   *%ebp
473
474
475#----------------------------------------------------------------------------
476# EstablishStackFsp
477#
478#----------------------------------------------------------------------------
479ASM_GLOBAL ASM_PFX(EstablishStackFsp)
480ASM_PFX(EstablishStackFsp):
481  #
482  # Save parameter pointer in edx
483  #
484  movl    4(%esp), %edx
485
486  #
487  # Enable FSP STACK
488  #
489  movl    PcdGet32(PcdTemporaryRamBase), %esp
490  addl    PcdGet32(PcdTemporaryRamSize), %esp
491
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
498
499  #
500  # Save API entry/exit timestamp into stack
501  #
502  pushl   $DATA_LEN_OF_PER0                  # Size of the data region
503  pushl   $0x30524550                        # Signature of the  data region 'PER0'
504  LOAD_EDX
505  pushl   %edx
506  LOAD_EAX
507  pushl   %eax
508  rdtsc
509  pushl   %edx
510  pushl   %eax
511
512  #
513  # Terminator for the data on stack
514  #
515  push    $0x00
516
517  #
518  # Set ECX/EDX to the BootLoader temporary memory range
519  #
520  movl       PcdGet32 (PcdTemporaryRamBase), %ecx
521  movl       %ecx, %edx
522  addl       PcdGet32 (PcdTemporaryRamSize), %edx
523  subl       PcdGet32 (PcdFspTemporaryRamSize), %edx
524
525  xorl       %eax, %eax
526
527  movd       %mm7, %esi                      #RET_ESI
528  jmp        *%esi
529
530#----------------------------------------------------------------------------
531# TempRamInit API
532#
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.
536#
537#----------------------------------------------------------------------------
538ASM_GLOBAL ASM_PFX(TempRamInitApi)
539ASM_PFX(TempRamInitApi):
540  #
541  # Ensure SSE is enabled
542  #
543  ENABLE_SSE
544
545  #
546  # Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
547  #
548  SAVE_REGS
549
550  #
551  # Save timestamp into XMM6
552  #
553  rdtsc
554  SAVE_EAX
555  SAVE_EDX
556
557  #
558  # Check Parameter
559  #
560  movl    4(%esp), %eax
561  cmpl    $0x00, %eax
562  movl    $0x80000002, %eax
563  jz      NemInitExit
564
565  #
566  # Sec Platform Init
567  #
568  movl    $TempRamInitApiL1, %esi            #CALL_MMX  SecPlatformInit
569  movd    %esi, %mm7
570  .weak   ASM_PFX(SecPlatformInit)
571  .set    ASM_PFX(SecPlatformInit), ASM_PFX(SecPlatformInitDefault)
572  jmp     ASM_PFX(SecPlatformInit)
573TempRamInitApiL1:
574  cmpl    $0x00, %eax
575  jnz     NemInitExit
576
577  #
578  # Load microcode
579  #
580  LOAD_ESP
581  movl    $TempRamInitApiL2, %esi            #CALL_MMX  LoadMicrocode
582  movd    %esi, %mm7
583  .weak   ASM_PFX(LoadMicrocode)
584  .set    ASM_PFX(LoadMicrocode), ASM_PFX(LoadMicrocodeDefault)
585  jmp     ASM_PFX(LoadMicrocode)
586TempRamInitApiL2:
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.
589
590  #
591  # Call Sec CAR Init
592  #
593  LOAD_ESP
594  movl    $TempRamInitApiL3, %esi            #CALL_MMX  SecCarInit
595  movd    %esi, %mm7
596  jmp     ASM_PFX(SecCarInit)
597TempRamInitApiL3:
598  cmpl    $0x00, %eax
599  jnz     NemInitExit
600
601  #
602  # EstablishStackFsp
603  #
604  LOAD_ESP
605  movl    $TempRamInitApiL4, %esi            #CALL_MMX  EstablishStackFsp
606  movd    %esi, %mm7
607  jmp     ASM_PFX(EstablishStackFsp)
608TempRamInitApiL4:
609
610  LOAD_EAX_MICROCODE_RET_STATUS              #Restore microcode status if no CAR init error.
611
612NemInitExit:
613  #
614  # Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
615  #
616  LOAD_REGS
617  ret
618
619
620#----------------------------------------------------------------------------
621# FspInit API
622#
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.
626#
627#----------------------------------------------------------------------------
628ASM_GLOBAL ASM_PFX(FspInitApi)
629ASM_PFX(FspInitApi):
630  movl   $0x01, %eax
631  jmp    FspApiCommon
632
633#----------------------------------------------------------------------------
634# NotifyPhase API
635#
636# This FSP API will notify the FSP about the different phases in the boot
637# process
638#
639#----------------------------------------------------------------------------
640ASM_GLOBAL ASM_PFX(NotifyPhaseApi)
641ASM_PFX(NotifyPhaseApi):
642  movl   $0x02, %eax
643  jmp    FspApiCommon
644
645#----------------------------------------------------------------------------
646# FspMemoryInit API
647#
648# This FSP API is called after TempRamInit and initializes the memory.
649#
650#----------------------------------------------------------------------------
651ASM_GLOBAL ASM_PFX(FspMemoryInitApi)
652ASM_PFX(FspMemoryInitApi):
653  movl   $0x03, %eax
654  jmp    FspApiCommon
655
656#----------------------------------------------------------------------------
657# TempRamExitApi API
658#
659# This API tears down temporary RAM
660#
661#----------------------------------------------------------------------------
662ASM_GLOBAL ASM_PFX(TempRamExitApi)
663ASM_PFX(TempRamExitApi):
664  movl   $0x04, %eax
665  jmp    FspApiCommon
666
667#----------------------------------------------------------------------------
668# FspSiliconInit API
669#
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.
672#
673#----------------------------------------------------------------------------
674ASM_GLOBAL ASM_PFX(FspSiliconInitApi)
675ASM_PFX(FspSiliconInitApi):
676  movl   $0x05, %eax
677  jmp    FspApiCommon
678
679#----------------------------------------------------------------------------
680# FspApiCommon API
681#
682# This is the FSP API common entry point to resume the FSP execution
683#
684#----------------------------------------------------------------------------
685ASM_GLOBAL ASM_PFX(FspApiCommon)
686ASM_PFX(FspApiCommon):
687  #
688  # EAX holds the API index
689  #
690
691  #
692  # Stack must be ready
693  #
694  pushl   %eax
695  addl    $0x04, %esp
696  cmpl    -4(%esp), %eax
697  jz      FspApiCommonL0
698  movl    $0x080000003, %eax
699  jmp     FspApiCommonExit
700
701FspApiCommonL0:
702  #
703  # Verify the calling condition
704  #
705  pushal
706  pushl   36(%esp)  #push ApiParam  [esp + 4 * 8 + 4]
707  pushl   %eax      #push ApiIdx
708  call    ASM_PFX(FspApiCallingCheck)
709  addl    $0x08, %esp
710  cmpl    $0x00, %eax
711  jz      FspApiCommonL1
712  movl    %eax, 0x1C(%esp)                   # mov    dword ptr [esp + 4 * 7], eax
713  popal
714  ret
715
716FspApiCommonL1:
717  popal
718  cmpl    $0x01, %eax                        # FspInit API
719  jz      FspApiCommonL2
720  cmpl    $0x03, %eax                        # FspMemoryInit API
721  jz      FspApiCommonL2
722  call    ASM_PFX(AsmGetFspInfoHeader)
723  jmp     Loader2PeiSwitchStack
724
725FspApiCommonL2:
726  #
727  # FspInit and FspMemoryInit APIs, setup the initial stack frame
728  #
729
730  #
731  # Place holder to store the FspInfoHeader pointer
732  #
733  pushl  %eax
734
735  #
736  # Update the FspInfoHeader pointer
737  #
738  pushl  %eax
739  call   ASM_PFX(AsmGetFspInfoHeader)
740  movl   %eax, 4(%esp)
741  popl   %eax
742
743  #
744  # Create a Task Frame in the stack for the Boot Loader
745  #
746  pushfl                                     # 2 pushf for 4 byte alignment
747  cli
748  pushal
749
750  #
751  # Reserve 8 bytes for IDT save/restore
752  #
753  subl    $0x08, %esp
754  sidt    (%esp)
755
756  #
757  # Setup new FSP stack
758  #
759  movl    %esp, %edi
760  movl    PcdGet32(PcdTemporaryRamBase), %esp
761  addl    PcdGet32(PcdTemporaryRamSize), %esp
762  subl    $(DATA_LEN_AT_STACK_TOP + 0x40), %esp
763
764  #
765  # Pass the API Idx to SecStartup
766  #
767  pushl   %eax
768
769  #
770  # Pass the BootLoader stack to SecStartup
771  #
772  pushl   %edi
773
774  #
775  # Pass entry point of the PEI core
776  #
777  call    ASM_PFX(AsmGetFspBaseAddress)
778  movl    %eax, %edi
779  addl    PcdGet32(PcdFspAreaSize), %edi
780  subl    $0x20, %edi
781  addl    %ds:(%edi), %eax
782  pushl   %eax
783
784  #
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.
790  #
791  call    ASM_PFX(AsmGetFspBaseAddress)
792  movl    %eax, %edi
793  call    ASM_PFX(GetBootFirmwareVolumeOffset)
794  addl    %edi, %eax
795  pushl   %eax
796
797  #
798  # Pass stack base and size into the PEI Core
799  #
800  movl    PcdGet32(PcdTemporaryRamBase), %eax
801  addl    PcdGet32(PcdTemporaryRamSize), %eax
802  subl    PcdGet32(PcdFspTemporaryRamSize), %eax
803  pushl   %eax
804  pushl   PcdGet32(PcdFspTemporaryRamSize)
805
806  #
807  # Pass Control into the PEI Core
808  #
809  call    ASM_PFX(SecStartup)
810  addl    $4, %esp
811FspApiCommonExit:
812  ret
813
814