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