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