219b0ee9c18a80c549a4d3f24f3ec5e52f3ab7d6
[mirror_edk2.git] / IntelFspPkg / FspSecCore / Ia32 / FspApiEntry.asm
1 ;------------------------------------------------------------------------------
2 ;
3 ; Copyright (c) 2014, 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 .586p
19 .model flat,C
20 .code
21 .xmm
22
23 INCLUDE SaveRestoreSse.inc
24 INCLUDE UcodeLoad.inc
25
26 ;
27 ; Following are fixed PCDs
28 ;
29 EXTERN PcdGet32(PcdTemporaryRamBase):DWORD
30 EXTERN PcdGet32(PcdTemporaryRamSize):DWORD
31 EXTERN PcdGet32(PcdFspTemporaryRamSize):DWORD
32
33 ;
34 ; Following functions will be provided in C
35 ;
36 EXTERN FspImageSizeOffset:DWORD
37 EXTERN SecStartup:PROC
38 EXTERN FspApiCallingCheck:PROC
39
40 ;
41 ; Following functions will be provided in PlatformSecLib
42 ;
43 EXTERN GetFspBaseAddress:PROC
44 EXTERN GetBootFirmwareVolumeOffset:PROC
45 EXTERN PlatformTempRamInit:PROC
46 EXTERN Pei2LoaderSwitchStack:PROC
47 EXTERN FspSelfCheck(FspSelfCheckDflt):PROC
48 EXTERN PlatformBasicInit(PlatformBasicInitDflt):PROC
49 EXTERN LoadUcode(LoadUcodeDflt):PROC
50
51 ;
52 ; Define the data length that we saved on the stack top
53 ;
54 DATA_LEN_OF_PER0 EQU 18h
55 DATA_LEN_OF_MCUD EQU 18h
56 DATA_LEN_AT_STACK_TOP EQU (DATA_LEN_OF_PER0 + DATA_LEN_OF_MCUD + 4)
57
58 ;------------------------------------------------------------------------------
59 FspSelfCheckDflt PROC NEAR PUBLIC
60 ; Inputs:
61 ; eax -> Return address
62 ; Outputs:
63 ; eax -> 0 - Successful, Non-zero - Failed.
64 ; Register Usage:
65 ; eax is cleared and ebp is used for return address.
66 ; All others reserved.
67
68 ; Save return address to EBP
69 mov ebp, eax
70
71 xor eax, eax
72 exit:
73 jmp ebp
74 FspSelfCheckDflt ENDP
75
76 ;------------------------------------------------------------------------------
77 PlatformBasicInitDflt PROC NEAR PUBLIC
78 ; Inputs:
79 ; eax -> Return address
80 ; Outputs:
81 ; eax -> 0 - Successful, Non-zero - Failed.
82 ; Register Usage:
83 ; eax is cleared and ebp is used for return address.
84 ; All others reserved.
85
86 ; Save return address to EBP
87 mov ebp, eax
88
89 xor eax, eax
90 exit:
91 jmp ebp
92 PlatformBasicInitDflt ENDP
93
94 ;------------------------------------------------------------------------------
95 LoadUcodeDflt PROC NEAR PUBLIC
96 ; Inputs:
97 ; esp -> LOAD_UCODE_PARAMS pointer
98 ; Register Usage:
99 ; esp Preserved
100 ; All others destroyed
101 ; Assumptions:
102 ; No memory available, stack is hard-coded and used for return address
103 ; Executed by SBSP and NBSP
104 ; Beginning of microcode update region starts on paragraph boundary
105
106 ;
107 ;
108 ; Save return address to EBP
109 mov ebp, eax
110
111 cmp esp, 0
112 jz paramerror
113 mov eax, dword ptr [esp] ; Parameter pointer
114 cmp eax, 0
115 jz paramerror
116 mov esp, eax
117 mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
118 cmp esi, 0
119 jnz check_main_header
120
121 paramerror:
122 mov eax, 080000002h
123 jmp exit
124
125 mov esi, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
126
127 check_main_header:
128 ; Get processor signature and platform ID from the installed processor
129 ; and save into registers for later use
130 ; ebx = processor signature
131 ; edx = platform ID
132 mov eax, 1
133 cpuid
134 mov ebx, eax
135 mov ecx, MSR_IA32_PLATFORM_ID
136 rdmsr
137 mov ecx, edx
138 shr ecx, 50-32
139 and ecx, 7h
140 mov edx, 1
141 shl edx, cl
142
143 ; Current register usage
144 ; esp -> stack with paramters
145 ; esi -> microcode update to check
146 ; ebx = processor signature
147 ; edx = platform ID
148
149 ; Check for valid microcode header
150 ; Minimal test checking for header version and loader version as 1
151 mov eax, dword ptr 1
152 cmp [esi].ucode_hdr.version, eax
153 jne advance_fixed_size
154 cmp [esi].ucode_hdr.loader, eax
155 jne advance_fixed_size
156
157 ; Check if signature and plaform ID match
158 cmp ebx, [esi].ucode_hdr.processor
159 jne @f
160 test edx, [esi].ucode_hdr.flags
161 jnz load_check ; Jif signature and platform ID match
162
163 @@:
164 ; Check if extended header exists
165 ; First check if total_size and data_size are valid
166 xor eax, eax
167 cmp [esi].ucode_hdr.total_size, eax
168 je next_microcode
169 cmp [esi].ucode_hdr.data_size, eax
170 je next_microcode
171
172 ; Then verify total size - sizeof header > data size
173 mov ecx, [esi].ucode_hdr.total_size
174 sub ecx, sizeof ucode_hdr
175 cmp ecx, [esi].ucode_hdr.data_size
176 jng next_microcode ; Jif extended header does not exist
177
178 ; Set edi -> extended header
179 mov edi, esi
180 add edi, sizeof ucode_hdr
181 add edi, [esi].ucode_hdr.data_size
182
183 ; Get count of extended structures
184 mov ecx, [edi].ext_sig_hdr.count
185
186 ; Move pointer to first signature structure
187 add edi, sizeof ext_sig_hdr
188
189 check_ext_sig:
190 ; Check if extended signature and platform ID match
191 cmp [edi].ext_sig.processor, ebx
192 jne @f
193 test [edi].ext_sig.flags, edx
194 jnz load_check ; Jif signature and platform ID match
195 @@:
196 ; Check if any more extended signatures exist
197 add edi, sizeof ext_sig
198 loop check_ext_sig
199
200 next_microcode:
201 ; Advance just after end of this microcode
202 xor eax, eax
203 cmp [esi].ucode_hdr.total_size, eax
204 je @f
205 add esi, [esi].ucode_hdr.total_size
206 jmp check_address
207 @@:
208 add esi, dword ptr 2048
209 jmp check_address
210
211 advance_fixed_size:
212 ; Advance by 4X dwords
213 add esi, dword ptr 1024
214
215 check_address:
216 ; Is valid Microcode start point ?
217 cmp dword ptr [esi].ucode_hdr.version, 0ffffffffh
218 jz done
219
220 ; Is automatic size detection ?
221 mov eax, [esp].LOAD_UCODE_PARAMS.ucode_code_size
222 cmp eax, 0ffffffffh
223 jz @f
224
225 ; Address >= microcode region address + microcode region size?
226 add eax, [esp].LOAD_UCODE_PARAMS.ucode_code_addr
227 cmp esi, eax
228 jae done ;Jif address is outside of ucode region
229 jmp check_main_header
230
231 @@:
232 load_check:
233 ; Get the revision of the current microcode update loaded
234 mov ecx, MSR_IA32_BIOS_SIGN_ID
235 xor eax, eax ; Clear EAX
236 xor edx, edx ; Clear EDX
237 wrmsr ; Load 0 to MSR at 8Bh
238
239 mov eax, 1
240 cpuid
241 mov ecx, MSR_IA32_BIOS_SIGN_ID
242 rdmsr ; Get current microcode signature
243
244 ; Verify this microcode update is not already loaded
245 cmp [esi].ucode_hdr.revision, edx
246 je continue
247
248 load_microcode:
249 ; EAX contains the linear address of the start of the Update Data
250 ; EDX contains zero
251 ; ECX contains 79h (IA32_BIOS_UPDT_TRIG)
252 ; Start microcode load with wrmsr
253 mov eax, esi
254 add eax, sizeof ucode_hdr
255 xor edx, edx
256 mov ecx, MSR_IA32_BIOS_UPDT_TRIG
257 wrmsr
258 mov eax, 1
259 cpuid
260
261 continue:
262 jmp next_microcode
263
264 done:
265 mov eax, 1
266 cpuid
267 mov ecx, MSR_IA32_BIOS_SIGN_ID
268 rdmsr ; Get current microcode signature
269 xor eax, eax
270 cmp edx, 0
271 jnz exit
272 mov eax, 08000000Eh
273
274 exit:
275 jmp ebp
276
277 LoadUcodeDflt ENDP
278
279 ;----------------------------------------------------------------------------
280 ; TempRamInit API
281 ;
282 ; This FSP API will load the microcode update, enable code caching for the
283 ; region specified by the boot loader and also setup a temporary stack to be
284 ; used till main memory is initialized.
285 ;
286 ;----------------------------------------------------------------------------
287 TempRamInitApi PROC NEAR PUBLIC
288 ;
289 ; Ensure SSE is enabled
290 ;
291 ENABLE_SSE
292
293 ;
294 ; Save EBP, EBX, ESI, EDI & ESP in XMM7 & XMM6
295 ;
296 SAVE_REGS
297
298 ;
299 ; Save timestamp into XMM4 & XMM5
300 ;
301 rdtsc
302 SAVE_EAX
303 SAVE_EDX
304
305 ;
306 ; Check Parameter
307 ;
308 mov eax, dword ptr [esp + 4]
309 cmp eax, 0
310 mov eax, 80000002h
311 jz NemInitExit
312
313 ;
314 ; CPUID/DeviceID check
315 ;
316 mov eax, @F
317 jmp FspSelfCheck ; Note: ESP can not be changed.
318 @@:
319 cmp eax, 0
320 jnz NemInitExit
321
322 ;
323 ; Platform Basic Init.
324 ;
325 mov eax, @F
326 jmp PlatformBasicInit
327 @@:
328 cmp eax, 0
329 jnz NemInitExit
330
331 ;
332 ; Load microcode
333 ;
334 mov eax, @F
335 add esp, 4
336 jmp LoadUcode
337 @@:
338 LOAD_ESP
339 cmp eax, 0
340 jnz NemInitExit
341
342 ;
343 ; Call platform NEM init
344 ;
345 mov eax, @F
346 add esp, 4
347 jmp PlatformTempRamInit
348 @@:
349 LOAD_ESP
350 cmp eax, 0
351 jnz NemInitExit
352
353 ;
354 ; Save parameter pointer in edx
355 ;
356 mov edx, dword ptr [esp + 4]
357
358 ;
359 ; Enable FSP STACK
360 ;
361 mov esp, PcdGet32(PcdTemporaryRamBase)
362 add esp, PcdGet32(PcdTemporaryRamSize)
363
364 push DATA_LEN_OF_MCUD ; Size of the data region
365 push 4455434Dh ; Signature of the data region 'MCUD'
366 push dword ptr [edx + 4] ; Microcode size
367 push dword ptr [edx + 0] ; Microcode base
368 push dword ptr [edx + 12] ; Code size
369 push dword ptr [edx + 8] ; Code base
370
371 ;
372 ; Save API entry/exit timestamp into stack
373 ;
374 push DATA_LEN_OF_PER0 ; Size of the data region
375 push 30524550h ; Signature of the data region 'PER0'
376 rdtsc
377 push edx
378 push eax
379 LOAD_EAX
380 LOAD_EDX
381 push edx
382 push eax
383
384 ;
385 ; Terminator for the data on stack
386 ;
387 push 0
388
389 ;
390 ; Set ECX/EDX to the bootloader temporary memory range
391 ;
392 mov ecx, PcdGet32(PcdTemporaryRamBase)
393 mov edx, ecx
394 add edx, PcdGet32(PcdTemporaryRamSize)
395 sub edx, PcdGet32(PcdFspTemporaryRamSize)
396
397 xor eax, eax
398
399 NemInitExit:
400 ;
401 ; Load EBP, EBX, ESI, EDI & ESP from XMM7 & XMM6
402 ;
403 LOAD_REGS
404 ret
405 TempRamInitApi ENDP
406
407 ;----------------------------------------------------------------------------
408 ; FspInit API
409 ;
410 ; This FSP API will perform the processor and chipset initialization.
411 ; This API will not return. Instead, it transfers the control to the
412 ; ContinuationFunc provided in the parameter.
413 ;
414 ;----------------------------------------------------------------------------
415 FspInitApi PROC NEAR PUBLIC
416 ;
417 ; Stack must be ready
418 ;
419 push 087654321h
420 pop eax
421 cmp eax, 087654321h
422 jz @F
423 mov eax, 080000003h
424 jmp exit
425
426 @@:
427 ;
428 ; Additional check
429 ;
430 pushad
431 push 1
432 call FspApiCallingCheck
433 add esp, 4
434 mov dword ptr [esp + 4 * 7], eax
435 popad
436 cmp eax, 0
437 jz @F
438 jmp exit
439
440 @@:
441 ;
442 ; Store the address in FSP which will return control to the BL
443 ;
444 push offset exit
445
446 ;
447 ; Create a Task Frame in the stack for the Boot Loader
448 ;
449 pushfd ; 2 pushf for 4 byte alignment
450 cli
451 pushad
452
453 ; Reserve 8 bytes for IDT save/restore
454 sub esp, 8
455 sidt fword ptr [esp]
456
457 ;
458 ; Setup new FSP stack
459 ;
460 mov eax, esp
461 mov esp, PcdGet32(PcdTemporaryRamBase)
462 add esp, PcdGet32(PcdTemporaryRamSize)
463 sub esp, (DATA_LEN_AT_STACK_TOP + 40h)
464
465 ;
466 ; Save the bootloader's stack pointer
467 ;
468 push eax
469
470 ;
471 ; Pass entry point of the PEI core
472 ;
473 call GetFspBaseAddress
474 mov edi, FspImageSizeOffset
475 mov edi, DWORD PTR [eax + edi]
476 add edi, eax
477 sub edi, 20h
478 add eax, DWORD PTR [edi]
479 push eax
480
481 ;
482 ; Pass BFV into the PEI Core
483 ; It uses relative address to calucate the actual boot FV base
484 ; For FSP impleantion with single FV, PcdFlashFvRecoveryBase and
485 ; PcdFspAreaBaseAddress are the same. For FSP with mulitple FVs,
486 ; they are different. The code below can handle both cases.
487 ;
488 call GetFspBaseAddress
489 mov edi, eax
490 call GetBootFirmwareVolumeOffset
491 add eax, edi
492 push eax
493
494 ;
495 ; Pass stack base and size into the PEI Core
496 ;
497 mov eax, PcdGet32(PcdTemporaryRamBase)
498 add eax, PcdGet32(PcdTemporaryRamSize)
499 sub eax, PcdGet32(PcdFspTemporaryRamSize)
500 push eax
501 push PcdGet32(PcdFspTemporaryRamSize)
502
503 ;
504 ; Pass Control into the PEI Core
505 ;
506 call SecStartup
507
508 exit:
509 ret
510
511 FspInitApi ENDP
512
513 ;----------------------------------------------------------------------------
514 ; NotifyPhase API
515 ;
516 ; This FSP API will notify the FSP about the different phases in the boot
517 ; process
518 ;
519 ;----------------------------------------------------------------------------
520 NotifyPhaseApi PROC C PUBLIC
521 ;
522 ; Stack must be ready
523 ;
524 push 087654321h
525 pop eax
526 cmp eax, 087654321h
527 jz @F
528 mov eax, 080000003h
529 jmp err_exit
530
531 @@:
532 ;
533 ; Verify the calling condition
534 ;
535 pushad
536 push 2
537 call FspApiCallingCheck
538 add esp, 4
539 mov dword ptr [esp + 4 * 7], eax
540 popad
541
542 cmp eax, 0
543 jz @F
544
545 ;
546 ; Error return
547 ;
548 err_exit:
549 ret
550
551 @@:
552 jmp Pei2LoaderSwitchStack
553
554 NotifyPhaseApi ENDP
555
556
557 END