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