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