1;; @file
2;  Provide FSP API entry points.
3;
4; Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
5; This program and the accompanying materials
6; are licensed and made available under the terms and conditions of the BSD License
7; which accompanies this distribution.  The full text of the license may be found at
8; http://opensource.org/licenses/bsd-license.php.
9;
10; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12;;
13
14    .586p
15    .model  flat,C
16    .code
17    .xmm
18
19INCLUDE    SaveRestoreSse.inc
20INCLUDE    MicrocodeLoad.inc
21
22;
23; Following are fixed PCDs
24;
25EXTERN   PcdGet32(PcdTemporaryRamBase):DWORD
26EXTERN   PcdGet32(PcdTemporaryRamSize):DWORD
27EXTERN   PcdGet32(PcdFspTemporaryRamSize):DWORD
28EXTERN   PcdGet32(PcdFspAreaSize):DWORD
29
30;
31; Following functions will be provided in C
32;
33
34EXTERN   SecStartup:PROC
35EXTERN   FspApiCallingCheck:PROC
36
37;
38; Following functions will be provided in PlatformSecLib
39;
40EXTERN   AsmGetFspBaseAddress:PROC
41EXTERN   AsmGetFspInfoHeader:PROC
42EXTERN   GetBootFirmwareVolumeOffset:PROC
43EXTERN   Loader2PeiSwitchStack:PROC
44EXTERN   LoadMicrocode(LoadMicrocodeDefault):PROC
45EXTERN   SecPlatformInit(SecPlatformInitDefault):PROC
46EXTERN   SecCarInit:PROC
47
48;
49; Define the data length that we saved on the stack top
50;
51DATA_LEN_OF_PER0         EQU   18h
52DATA_LEN_OF_MCUD         EQU   18h
53DATA_LEN_AT_STACK_TOP    EQU   (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
54
55;
56; Define SSE macros
57;
58LOAD_MMX_EXT MACRO   ReturnAddress, MmxRegister
59  mov     esi, ReturnAddress
60  movd    MmxRegister, esi              ; save ReturnAddress into MMX
61ENDM
62
63CALL_MMX_EXT MACRO   RoutineLabel, MmxRegister
64  local   ReturnAddress
65  mov     esi, offset ReturnAddress
66  movd    MmxRegister, esi              ; save ReturnAddress into MMX
67  jmp     RoutineLabel
68ReturnAddress:
69ENDM
70
71RET_ESI_EXT  MACRO   MmxRegister
72  movd    esi, MmxRegister              ; move ReturnAddress from MMX to ESI
73  jmp     esi
74ENDM
75
76CALL_MMX MACRO   RoutineLabel
77         CALL_MMX_EXT  RoutineLabel, mm7
78ENDM
79
80RET_ESI  MACRO
81         RET_ESI_EXT   mm7
82ENDM
83
84;------------------------------------------------------------------------------
85SecPlatformInitDefault PROC NEAR PUBLIC
86   ; Inputs:
87   ;   mm7 -> Return address
88   ; Outputs:
89   ;   eax -> 0 - Successful, Non-zero - Failed.
90   ; Register Usage:
91   ;   eax is cleared and ebp is used for return address.
92   ;   All others reserved.
93   
94   ; Save return address to EBP
95   movd  ebp, mm7
96
97   xor   eax, eax
98exit:
99   jmp   ebp
100SecPlatformInitDefault   ENDP
101
102;------------------------------------------------------------------------------
103LoadMicrocodeDefault   PROC  NEAR PUBLIC
104   ; Inputs:
105   ;   esp -> LoadMicrocodeParams pointer
106   ; Register Usage:
107   ;   esp  Preserved
108   ;   All others destroyed
109   ; Assumptions:
110   ;   No memory available, stack is hard-coded and used for return address
111   ;   Executed by SBSP and NBSP
112   ;   Beginning of microcode update region starts on paragraph boundary
113
114   ;
115   ;
116   ; Save return address to EBP
117   movd   ebp, mm7
118
119   cmp    esp, 0
120   jz     paramerror
121   mov    eax, dword ptr [esp + 4]    ; Parameter pointer
122   cmp    eax, 0
123   jz     paramerror
124   mov    esp, eax
125   mov    esi, [esp].LoadMicrocodeParams.MicrocodeCodeAddr
126   cmp    esi, 0
127   jnz    check_main_header
128
129paramerror:
130   mov    eax, 080000002h
131   jmp    exit
132
133   mov    esi, [esp].LoadMicrocodeParams.MicrocodeCodeAddr
134
135check_main_header:
136   ; Get processor signature and platform ID from the installed processor
137   ; and save into registers for later use
138   ; ebx = processor signature
139   ; edx = platform ID
140   mov   eax, 1
141   cpuid
142   mov   ebx, eax
143   mov   ecx, MSR_IA32_PLATFORM_ID
144   rdmsr
145   mov   ecx, edx
146   shr   ecx, 50-32                          ; shift (50d-32d=18d=0x12) bits
147   and   ecx, 7h                             ; platform id at bit[52..50]
148   mov   edx, 1
149   shl   edx, cl
150
151   ; Current register usage
152   ; esp -> stack with paramters
153   ; esi -> microcode update to check
154   ; ebx = processor signature
155   ; edx = platform ID
156
157   ; Check for valid microcode header
158   ; Minimal test checking for header version and loader version as 1
159   mov   eax, dword ptr 1
160   cmp   [esi].MicrocodeHdr.MicrocodeHdrVersion, eax
161   jne   advance_fixed_size
162   cmp   [esi].MicrocodeHdr.MicrocodeHdrLoader, eax
163   jne   advance_fixed_size
164
165   ; Check if signature and plaform ID match
166   cmp   ebx, [esi].MicrocodeHdr.MicrocodeHdrProcessor
167   jne   @f
168   test  edx, [esi].MicrocodeHdr.MicrocodeHdrFlags
169   jnz   load_check  ; Jif signature and platform ID match
170
171@@:
172   ; Check if extended header exists
173   ; First check if MicrocodeHdrTotalSize and MicrocodeHdrDataSize are valid
174   xor   eax, eax
175   cmp   [esi].MicrocodeHdr.MicrocodeHdrTotalSize, eax
176   je    next_microcode
177   cmp   [esi].MicrocodeHdr.MicrocodeHdrDataSize, eax
178   je    next_microcode
179
180   ; Then verify total size - sizeof header > data size
181   mov   ecx, [esi].MicrocodeHdr.MicrocodeHdrTotalSize
182   sub   ecx, sizeof MicrocodeHdr
183   cmp   ecx, [esi].MicrocodeHdr.MicrocodeHdrDataSize
184   jng   next_microcode    ; Jif extended header does not exist
185
186   ; Set edi -> extended header
187   mov   edi, esi
188   add   edi, sizeof MicrocodeHdr
189   add   edi, [esi].MicrocodeHdr.MicrocodeHdrDataSize
190
191   ; Get count of extended structures
192   mov   ecx, [edi].ExtSigHdr.ExtSigHdrCount
193
194   ; Move pointer to first signature structure
195   add   edi, sizeof ExtSigHdr
196
197check_ext_sig:
198   ; Check if extended signature and platform ID match
199   cmp   [edi].ExtSig.ExtSigProcessor, ebx
200   jne   @f
201   test  [edi].ExtSig.ExtSigFlags, edx
202   jnz   load_check     ; Jif signature and platform ID match
203@@:
204   ; Check if any more extended signatures exist
205   add   edi, sizeof ExtSig
206   loop  check_ext_sig
207
208next_microcode:
209   ; Advance just after end of this microcode
210   xor   eax, eax
211   cmp   [esi].MicrocodeHdr.MicrocodeHdrTotalSize, eax
212   je    @f
213   add   esi, [esi].MicrocodeHdr.MicrocodeHdrTotalSize
214   jmp   check_address
215@@:
216   add   esi, dword ptr 2048
217   jmp   check_address
218
219advance_fixed_size:
220   ; Advance by 4X dwords
221   add   esi, dword ptr 1024
222
223check_address:
224   ; Is valid Microcode start point ?
225   cmp   dword ptr [esi].MicrocodeHdr.MicrocodeHdrVersion, 0ffffffffh
226   jz    done
227
228   ; Is automatic size detection ?
229   mov   eax, [esp].LoadMicrocodeParams.MicrocodeCodeSize
230   cmp   eax, 0ffffffffh
231   jz    @f
232
233   ; Address >= microcode region address + microcode region size?
234   add   eax, [esp].LoadMicrocodeParams.MicrocodeCodeAddr
235   cmp   esi, eax
236   jae   done        ;Jif address is outside of microcode region
237   jmp   check_main_header
238
239@@:
240load_check:
241   ; Get the revision of the current microcode update loaded
242   mov   ecx, MSR_IA32_BIOS_SIGN_ID
243   xor   eax, eax               ; Clear EAX
244   xor   edx, edx               ; Clear EDX
245   wrmsr                        ; Load 0 to MSR at 8Bh
246
247   mov   eax, 1
248   cpuid
249   mov   ecx, MSR_IA32_BIOS_SIGN_ID
250   rdmsr                         ; Get current microcode signature
251
252   ; Verify this microcode update is not already loaded
253   cmp   [esi].MicrocodeHdr.MicrocodeHdrRevision, edx
254   je    continue
255
256load_microcode:
257   ; EAX contains the linear address of the start of the Update Data
258   ; EDX contains zero
259   ; ECX contains 79h (IA32_BIOS_UPDT_TRIG)
260   ; Start microcode load with wrmsr
261   mov   eax, esi
262   add   eax, sizeof MicrocodeHdr
263   xor   edx, edx
264   mov   ecx, MSR_IA32_BIOS_UPDT_TRIG
265   wrmsr
266   mov   eax, 1
267   cpuid
268
269continue:
270   jmp   next_microcode
271
272done:
273   mov   eax, 1
274   cpuid
275   mov   ecx, MSR_IA32_BIOS_SIGN_ID
276   rdmsr                         ; Get current microcode signature
277   xor   eax, eax
278   cmp   edx, 0
279   jnz   exit
280   mov   eax, 08000000Eh
281
282exit:
283   jmp   ebp
284
285LoadMicrocodeDefault   ENDP
286
287EstablishStackFsp    PROC    NEAR    PRIVATE
288  ;
289  ; Save parameter pointer in edx
290  ;
291  mov       edx, dword ptr [esp + 4]
292
293  ;
294  ; Enable FSP STACK
295  ;
296  mov       esp, PcdGet32 (PcdTemporaryRamBase)
297  add       esp, PcdGet32 (PcdTemporaryRamSize)
298
299  push      DATA_LEN_OF_MCUD     ; Size of the data region
300  push      4455434Dh            ; Signature of the  data region 'MCUD'
301  push      dword ptr [edx + 12] ; Code size
302  push      dword ptr [edx + 8]  ; Code base
303  push      dword ptr [edx + 4]  ; Microcode size
304  push      dword ptr [edx]      ; Microcode base
305
306  ;
307  ; Save API entry/exit timestamp into stack
308  ;
309  push      DATA_LEN_OF_PER0     ; Size of the data region 
310  push      30524550h            ; Signature of the  data region 'PER0'
311  LOAD_EDX
312  push      edx
313  LOAD_EAX
314  push      eax
315  rdtsc
316  push      edx
317  push      eax
318
319  ;
320  ; Terminator for the data on stack
321  ; 
322  push      0
323
324  ;
325  ; Set ECX/EDX to the BootLoader temporary memory range
326  ;
327  mov       ecx, PcdGet32 (PcdTemporaryRamBase)
328  mov       edx, ecx
329  add       edx, PcdGet32 (PcdTemporaryRamSize)
330  sub       edx, PcdGet32 (PcdFspTemporaryRamSize)
331
332  xor       eax, eax
333
334  RET_ESI
335
336EstablishStackFsp    ENDP
337
338
339;----------------------------------------------------------------------------
340; TempRamInit API
341;
342; This FSP API will load the microcode update, enable code caching for the
343; region specified by the boot loader and also setup a temporary stack to be
344; used till main memory is initialized.
345;
346;----------------------------------------------------------------------------
347TempRamInitApi   PROC    NEAR    PUBLIC
348  ;
349  ; Ensure SSE is enabled
350  ;
351  ENABLE_SSE
352
353  ;
354  ; Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
355  ;
356  SAVE_REGS
357
358  ;
359  ; Save timestamp into XMM6
360  ;
361  rdtsc
362  SAVE_EAX
363  SAVE_EDX
364
365  ;
366  ; Check Parameter
367  ;
368  mov       eax, dword ptr [esp + 4]
369  cmp       eax, 0
370  mov       eax, 80000002h
371  jz        TempRamInitExit
372
373  ;
374  ; Sec Platform Init
375  ;
376  CALL_MMX  SecPlatformInit
377  cmp       eax, 0
378  jnz       TempRamInitExit
379
380  ; Load microcode
381  LOAD_ESP
382  CALL_MMX  LoadMicrocode
383  SXMMN     xmm6, 3, eax            ;Save microcode return status in ECX-SLOT 3 in xmm6.
384  ;@note If return value eax is not 0, microcode did not load, but continue and attempt to boot.
385
386  ; Call Sec CAR Init
387  LOAD_ESP
388  CALL_MMX  SecCarInit
389  cmp       eax, 0
390  jnz       TempRamInitExit
391
392  LOAD_ESP
393  CALL_MMX  EstablishStackFsp
394
395  LXMMN      xmm6, eax, 3  ;Restore microcode status if no CAR init error from ECX-SLOT 3 in xmm6.
396
397TempRamInitExit:
398  ;
399  ; Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
400  ;
401  LOAD_REGS
402  ret
403TempRamInitApi   ENDP
404
405;----------------------------------------------------------------------------
406; FspInit API
407;
408; This FSP API will perform the processor and chipset initialization.
409; This API will not return.  Instead, it transfers the control to the
410; ContinuationFunc provided in the parameter.
411;
412;----------------------------------------------------------------------------
413FspInitApi   PROC    NEAR    PUBLIC
414  mov    eax,  1
415  jmp    FspApiCommon
416  FspInitApi   ENDP
417
418;----------------------------------------------------------------------------
419; NotifyPhase API
420;
421; This FSP API will notify the FSP about the different phases in the boot
422; process
423;
424;----------------------------------------------------------------------------
425NotifyPhaseApi   PROC C PUBLIC
426  mov    eax,  2
427  jmp    FspApiCommon
428NotifyPhaseApi   ENDP
429
430;----------------------------------------------------------------------------
431; FspMemoryInit API
432;
433; This FSP API is called after TempRamInit and initializes the memory.
434;
435;----------------------------------------------------------------------------
436FspMemoryInitApi   PROC    NEAR    PUBLIC
437  mov    eax,  3
438  jmp    FspApiCommon
439FspMemoryInitApi   ENDP
440
441
442;----------------------------------------------------------------------------
443; TempRamExitApi API
444;
445; This API tears down temporary RAM
446;
447;----------------------------------------------------------------------------
448TempRamExitApi   PROC C PUBLIC
449  mov    eax,  4
450  jmp    FspApiCommon
451TempRamExitApi   ENDP
452
453
454;----------------------------------------------------------------------------
455; FspSiliconInit API
456;
457; This FSP API initializes the CPU and the chipset including the IO
458; controllers in the chipset to enable normal operation of these devices.
459;
460;----------------------------------------------------------------------------
461FspSiliconInitApi   PROC C PUBLIC
462  mov    eax,  5
463  jmp    FspApiCommon
464FspSiliconInitApi   ENDP
465
466;----------------------------------------------------------------------------
467; FspApiCommon API
468;
469; This is the FSP API common entry point to resume the FSP execution
470;
471;----------------------------------------------------------------------------
472FspApiCommon   PROC C PUBLIC
473  ;
474  ; EAX holds the API index
475  ;
476
477  ;
478  ; Stack must be ready
479  ;  
480  push   eax
481  add    esp, 4
482  cmp    eax, dword ptr [esp - 4]
483  jz     @F
484  mov    eax, 080000003h
485  jmp    exit
486
487@@:
488  ;
489  ; Verify the calling condition
490  ;
491  pushad
492  push   [esp + 4 * 8 + 4]  ; push ApiParam
493  push   eax                ; push ApiIdx
494  call   FspApiCallingCheck
495  add    esp, 8
496  cmp    eax, 0
497  jz     @F
498  mov    dword ptr [esp + 4 * 7], eax
499  popad
500  ret
501
502@@:
503  popad
504  cmp    eax, 1   ; FspInit API
505  jz     @F
506  cmp    eax, 3   ; FspMemoryInit API
507  jz     @F
508
509  call   AsmGetFspInfoHeader
510  jmp    Loader2PeiSwitchStack
511
512@@:
513  ;
514  ; FspInit and FspMemoryInit APIs, setup the initial stack frame
515  ;
516  
517  ;
518  ; Place holder to store the FspInfoHeader pointer
519  ;
520  push   eax
521
522  ;
523  ; Update the FspInfoHeader pointer
524  ;
525  push   eax
526  call   AsmGetFspInfoHeader
527  mov    [esp + 4], eax
528  pop    eax
529
530  ;
531  ; Create a Task Frame in the stack for the Boot Loader
532  ;
533  pushfd     ; 2 pushf for 4 byte alignment
534  cli
535  pushad
536
537  ; Reserve 8 bytes for IDT save/restore
538  sub     esp, 8
539  sidt    fword ptr [esp]
540
541  ;
542  ; Setup new FSP stack
543  ;
544  mov     edi, esp
545  mov     esp, PcdGet32(PcdTemporaryRamBase)
546  add     esp, PcdGet32(PcdTemporaryRamSize)
547  sub     esp, (DATA_LEN_AT_STACK_TOP + 40h)
548
549  ;
550  ; Pass the API Idx to SecStartup
551  ;
552  push    eax
553  
554  ;
555  ; Pass the BootLoader stack to SecStartup
556  ;
557  push    edi
558
559  ;
560  ; Pass entry point of the PEI core
561  ;
562  call    AsmGetFspBaseAddress
563  mov     edi, eax
564  add     edi, PcdGet32 (PcdFspAreaSize) 
565  sub     edi, 20h
566  add     eax, DWORD PTR ds:[edi]
567  push    eax
568
569  ;
570  ; Pass BFV into the PEI Core
571  ; It uses relative address to calucate the actual boot FV base
572  ; For FSP implementation with single FV, PcdFspBootFirmwareVolumeBase and
573  ; PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
574  ; they are different. The code below can handle both cases.
575  ;
576  call    AsmGetFspBaseAddress
577  mov     edi, eax
578  call    GetBootFirmwareVolumeOffset
579  add     eax, edi
580  push    eax
581
582  ;
583  ; Pass stack base and size into the PEI Core
584  ;
585  mov     eax,  PcdGet32(PcdTemporaryRamBase)
586  add     eax,  PcdGet32(PcdTemporaryRamSize)
587  sub     eax,  PcdGet32(PcdFspTemporaryRamSize)
588  push    eax
589  push    PcdGet32(PcdFspTemporaryRamSize)
590
591  ;
592  ; Pass Control into the PEI Core
593  ;
594  call    SecStartup
595  add     esp, 4
596exit:
597  ret
598
599FspApiCommon   ENDP
600
601END
602