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