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