/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { VOID *BaseOfStack; VOID *TopOfStack; EFI_STATUS Status; UINTN PageTables; // // Allocate 128KB for the Stack // BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE)); ASSERT (BaseOfStack != NULL); // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); PageTables = 0; if (FeaturePcdGet (PcdDxeIplBuildPageTables)) { // // Create page table and save PageMapLevel4 to CR3 // PageTables = CreateIdentityMappingPageTables (); } // // End of PEI phase signal // Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); ASSERT_EFI_ERROR (Status); if (FeaturePcdGet (PcdDxeIplBuildPageTables)) { AsmWriteCr3 (PageTables); } // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE); // // Transfer the control to the entry point of DxeCore. // SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, TopOfStack ); }
VOID EnterDxeMain ( IN VOID *StackTop, IN VOID *DxeCoreEntryPoint, IN VOID *Hob, IN VOID *PageTable ) { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, Hob, NULL, StackTop ); }
/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { VOID *BaseOfStack; VOID *TopOfStack; EFI_STATUS Status; // // Allocate 128KB for the Stack // BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE)); ASSERT (BaseOfStack != NULL); if (PcdGetBool (PcdSetNxForStack)) { Status = ArmSetMemoryRegionNoExec ((UINTN)BaseOfStack, STACK_SIZE); ASSERT_EFI_ERROR (Status); } // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); // // End of PEI phase singal // Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); ASSERT_EFI_ERROR (Status); // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE); SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, TopOfStack ); }
/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { VOID *BaseOfStack; VOID *TopOfStack; EFI_STATUS Status; // // // Allocate 128KB for the Stack // BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE)); ASSERT (BaseOfStack != NULL); // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); // // End of PEI phase signal // Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); ASSERT_EFI_ERROR (Status); // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, STACK_SIZE); DEBUG ((EFI_D_INFO, "DXE Core new stack at %x, stack pointer at %x\n", BaseOfStack, TopOfStack)); // // Transfer the control to the entry point of DxeCore. // SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, TopOfStack ); }
/** Entry function of Boot script exector. This function will be executed in S3 boot path. This function should not return, because it is invoked by switch stack. @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE @retval EFI_INVALID_PARAMETER - OS waking vector not found @retval EFI_UNSUPPORTED - something wrong when we resume to OS **/ EFI_STATUS EFIAPI S3BootScriptExecutorEntryFunction ( IN ACPI_S3_CONTEXT *AcpiS3Context, IN PEI_S3_RESUME_STATE *PeiS3ResumeState ) { EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; EFI_STATUS Status; UINTN TempStackTop; UINTN TempStack[0x10]; UINTN AsmTransferControl16Address; IA32_DESCRIPTOR IdtDescriptor; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmReadIdtr (&IdtDescriptor); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); // // If invalid script table or opcode in S3 boot script table. // ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { CpuDeadLoop (); return Status; } AsmWbinvd (); // // Get ACPI Table Address // Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); // // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. // if (PeiS3ResumeState != 0) { // // Need report status back to S3ResumePeim. // If boot script execution is failed, S3ResumePeim wil report the error status code. // PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status; if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { // // X64 S3 Resume // DEBUG ((EFI_D_ERROR, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32; if ((Facs != NULL) && (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) && (Facs->FirmwareWakingVector != 0) ) { // // more step needed - because relative address is handled differently between X64 and IA32. // AsmTransferControl16Address = (UINTN)AsmTransferControl16; AsmFixAddress16 = (UINT32)AsmTransferControl16Address; AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12)); } AsmDisablePaging64 ( PeiS3ResumeState->ReturnCs, (UINT32)PeiS3ResumeState->ReturnEntryPoint, (UINT32)(UINTN)AcpiS3Context, (UINT32)(UINTN)PeiS3ResumeState, (UINT32)PeiS3ResumeState->ReturnStackPointer ); } else { // // IA32 S3 Resume // DEBUG ((EFI_D_ERROR, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl; SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)AcpiS3Context, (VOID *)(UINTN)PeiS3ResumeState, (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer ); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; } // // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly // if (Facs->XFirmwareWakingVector != 0) { // // Switch to native waking vector // TempStackTop = (UINTN)&TempStack + sizeof(TempStack); if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) && ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) { // // X64 long mode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } else { // Unsupported for 32bit DXE, 64bit OS vector DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n")); ASSERT (FALSE); } } else { // // IA32 protected mode waking vector (Page disabled) // DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { AsmDisablePaging64 ( 0x10, (UINT32)Facs->XFirmwareWakingVector, 0, 0, (UINT32)TempStackTop ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } } } else { // // 16bit Realmode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector)); AsmTransferControl (Facs->FirmwareWakingVector, 0x0); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
EFI_STATUS EFIAPI LoadDxeCoreFromFfsFile ( IN EFI_PEI_FILE_HANDLE FileHandle, IN UINTN StackSize ) { EFI_STATUS Status; VOID *PeCoffImage; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; EFI_PHYSICAL_ADDRESS EntryPoint; VOID *BaseOfStack; VOID *TopOfStack; VOID *Hob; EFI_FV_FILE_INFO FvFileInfo; Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage); if (EFI_ERROR (Status)) { return Status; } Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); // For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); ASSERT_EFI_ERROR (Status); // // Extract the DxeCore GUID file name. // Status = FfsGetFileInfo (FileHandle, &FvFileInfo); ASSERT_EFI_ERROR (Status); BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint); DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint)); Hob = GetHobList (); if (StackSize == 0) { // User the current stack ((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob); } else { // // Allocate 128KB for the Stack // BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize)); ASSERT (BaseOfStack != NULL); // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize); SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint, Hob, NULL, TopOfStack ); } // Should never get here as DXE Core does not return DEBUG ((EFI_D_ERROR, "DxeCore returned\n")); ASSERT (FALSE); return EFI_DEVICE_ERROR; }
/** Perform SMM initialization for all processors in the S3 boot path. For a native platform, MP initialization in the S3 boot path is also performed in this function. **/ VOID EFIAPI SmmRestoreCpu ( VOID ) { SMM_S3_RESUME_STATE *SmmS3ResumeState; IA32_DESCRIPTOR Ia32Idtr; IA32_DESCRIPTOR X64Idtr; IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; EFI_STATUS Status; DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n")); mSmmS3Flag = TRUE; InitializeSpinLock (mMemoryMappedLock); // // See if there is enough context to resume PEI Phase // if (mSmmS3ResumeState == NULL) { DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); CpuDeadLoop (); } SmmS3ResumeState = mSmmS3ResumeState; ASSERT (SmmS3ResumeState != NULL); if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { // // Save the IA32 IDT Descriptor // AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Setup X64 IDT table // ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32); X64Idtr.Base = (UINTN) IdtEntryTable; X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); // // Setup the default exception handler // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Initialize Debug Agent to support source level debug // InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL); } // // Skip initialization if mAcpiCpuData is not valid // if (mAcpiCpuData.NumberOfCpus > 0) { // // First time microcode load and restore MTRRs // InitializeCpuBeforeRebase (); } // // Restore SMBASE for BSP and all APs // SmmRelocateBases (); // // Skip initialization if mAcpiCpuData is not valid // if (mAcpiCpuData.NumberOfCpus > 0) { // // Restore MSRs for BSP and all APs // InitializeCpuAfterRebase (); } // // Set a flag to restore SMM configuration in S3 path. // mRestoreSmmConfigurationInS3 = TRUE; DEBUG (( EFI_D_INFO, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs)); DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint)); DEBUG (( EFI_D_INFO, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1)); DEBUG (( EFI_D_INFO, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2)); DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer)); // // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase // if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) { DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1, (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2, (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer ); } // // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase // if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) { DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); // // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IA32 IDT table // AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); AsmDisablePaging64 ( SmmS3ResumeState->ReturnCs, (UINT32)SmmS3ResumeState->ReturnEntryPoint, (UINT32)SmmS3ResumeState->ReturnContext1, (UINT32)SmmS3ResumeState->ReturnContext2, (UINT32)SmmS3ResumeState->ReturnStackPointer ); } // // Can not resume PEI Phase // DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n")); CpuDeadLoop (); }
/** Transfers control to DxeCore. This function performs a CPU architecture specific operations to execute the entry point of DxeCore with the parameters of HobList. It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase. @param DxeCoreEntryPoint The entry point of DxeCore. @param HobList The start of HobList passed to DxeCore. **/ VOID HandOffToDxeCore ( IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS BaseOfStack; EFI_PHYSICAL_ADDRESS TopOfStack; UINTN PageTables; X64_IDT_GATE_DESCRIPTOR *IdtTable; UINTN SizeOfTemplate; VOID *TemplateBase; EFI_PHYSICAL_ADDRESS VectorAddress; UINT32 Index; X64_IDT_TABLE *IdtTableForX64; EFI_VECTOR_HANDOFF_INFO *VectorInfo; EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi; BOOLEAN BuildPageTablesIa32Pae; if (IsNullDetectionEnabled ()) { ClearFirst4KPage (HobList.Raw); } Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack); ASSERT_EFI_ERROR (Status); if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) { // // Compute the top of the stack we were allocated, which is used to load X64 dxe core. // Pre-allocate a 32 bytes which confroms to x64 calling convention. // // The first four parameters to a function are passed in rcx, rdx, r8 and r9. // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the // register parameters is reserved on the stack, in case the called function // wants to spill them; this is important if the function is variadic. // TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32; // // x64 Calling Conventions requires that the stack must be aligned to 16 bytes // TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16); // // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA // memory, it may be corrupted when copying FV to high-end memory // AsmWriteGdtr (&gGdt); // // Create page table and save PageMapLevel4 to CR3 // PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE); // // End of PEI phase signal // PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); // // Paging might be already enabled. To avoid conflict configuration, // disable paging first anyway. // AsmWriteCr0 (AsmReadCr0 () & (~BIT31)); AsmWriteCr3 (PageTables); // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase); Status = PeiServicesAllocatePages ( EfiBootServicesData, EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT), &VectorAddress ); ASSERT_EFI_ERROR (Status); // // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that // it may not be gotten correctly after IDT register is re-written. // IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress; IdtTableForX64->PeiService = GetPeiServicesTablePointer (); VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1); IdtTable = IdtTableForX64->IdtTable; for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) { IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e; IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0; IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL; IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress; IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16)); IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32)); IdtTable[Index].Reserved = 0; CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate); AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index); VectorAddress += SizeOfTemplate; } gLidtDescriptor.Base = (UINTN) IdtTable; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmWriteIdtr (&gLidtDescriptor); DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", __FUNCTION__, BaseOfStack, STACK_SIZE )); // // Go to Long Mode and transfer control to DxeCore. // Interrupts will not get turned on until the CPU AP is loaded. // Call x64 drivers passing in single argument, a pointer to the HOBs. // AsmEnablePaging64 ( SYS_CODE64_SEL, DxeCoreEntryPoint, (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), 0, TopOfStack ); } else { // // Get Vector Hand-off Info PPI and build Guided HOB // Status = PeiServicesLocatePpi ( &gEfiVectorHandoffInfoPpiGuid, 0, NULL, (VOID **)&VectorHandoffInfoPpi ); if (Status == EFI_SUCCESS) { DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n")); VectorInfo = VectorHandoffInfoPpi->Info; Index = 1; while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) { VectorInfo ++; Index ++; } BuildGuidDataHob ( &gEfiVectorHandoffInfoPpiGuid, VectorHandoffInfoPpi->Info, sizeof (EFI_VECTOR_HANDOFF_INFO) * Index ); } // // Compute the top of the stack we were allocated. Pre-allocate a UINTN // for safety. // TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT; TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); PageTables = 0; BuildPageTablesIa32Pae = ToBuildPageTable (); if (BuildPageTablesIa32Pae) { PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE); if (IsEnableNonExecNeeded ()) { EnableExecuteDisableBit(); } } // // End of PEI phase signal // PERF_EVENT_SIGNAL_BEGIN (gEndOfPeiSignalPpi.Guid); Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi); PERF_EVENT_SIGNAL_END (gEndOfPeiSignalPpi.Guid); ASSERT_EFI_ERROR (Status); if (BuildPageTablesIa32Pae) { // // Paging might be already enabled. To avoid conflict configuration, // disable paging first anyway. // AsmWriteCr0 (AsmReadCr0 () & (~BIT31)); AsmWriteCr3 (PageTables); // // Set Physical Address Extension (bit 5 of CR4). // AsmWriteCr4 (AsmReadCr4 () | BIT5); } // // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. // UpdateStackHob (BaseOfStack, STACK_SIZE); DEBUG (( DEBUG_INFO, "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n", __FUNCTION__, BaseOfStack, STACK_SIZE )); // // Transfer the control to the entry point of DxeCore. // if (BuildPageTablesIa32Pae) { AsmEnablePaging32 ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, (VOID *) (UINTN) TopOfStack ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint, HobList.Raw, NULL, (VOID *) (UINTN) TopOfStack ); } } }
/** Entry function of Boot script exector. This function will be executed in S3 boot path. This function should not return, because it is invoked by switch stack. @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE @retval EFI_INVALID_PARAMETER - OS waking vector not found @retval EFI_UNSUPPORTED - something wrong when we resume to OS **/ EFI_STATUS EFIAPI S3BootScriptExecutorEntryFunction ( IN ACPI_S3_CONTEXT *AcpiS3Context, IN PEI_S3_RESUME_STATE *PeiS3ResumeState ) { EFI_STATUS Status; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, NULL, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); AsmWbinvd (); // // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume. // if (PeiS3ResumeState != 0) { // // Need report status back to S3ResumePeim. // If boot script execution is failed, S3ResumePeim wil report the error status code. // PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status; // // IA32 S3 Resume // DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformTransferControl16; SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint, (VOID *)(UINTN)AcpiS3Context, (VOID *)(UINTN)PeiS3ResumeState, (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer ); // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
VOID SecLoadSecCore ( IN UINTN TemporaryRam, IN UINTN TemporaryRamSize, IN VOID *BootFirmwareVolumeBase, IN UINTN BootFirmwareVolumeSize, IN VOID *SecCorePe32File ) /*++ Routine Description: This is the service to load the SEC Core from the Firmware Volume Arguments: TemporaryRam - Memory to use for SEC. TemporaryRamSize - Size of Memory to use for SEC BootFirmwareVolumeBase - Start of the Boot FV SecCorePe32File - SEC Core PE32 Returns: Success means control is transfered and thus we should never return --*/ { EFI_STATUS Status; VOID *TopOfStack; VOID *SecCoreEntryPoint; EFI_SEC_PEI_HAND_OFF *SecCoreData; UINTN SecStackSize; // // Compute Top Of Memory for Stack and PEI Core Allocations // SecStackSize = TemporaryRamSize >> 1; // // |-----------| <---- TemporaryRamBase + TemporaryRamSize // | Heap | // | | // |-----------| <---- StackBase / PeiTemporaryMemoryBase // | | // | Stack | // |-----------| <---- TemporaryRamBase // TopOfStack = (VOID *)(TemporaryRam + SecStackSize); // // Reservet space for storing PeiCore's parament in stack. // TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); // // Bind this information into the SEC hand-off state // SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack; SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF); SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase; SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize; SecCoreData->TemporaryRamBase = (VOID*)TemporaryRam; SecCoreData->TemporaryRamSize = TemporaryRamSize; SecCoreData->StackBase = SecCoreData->TemporaryRamBase; SecCoreData->StackSize = SecStackSize; SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize); SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize; // // Load the PEI Core from a Firmware Volume // Status = SecPeCoffGetEntryPoint ( SecCorePe32File, &SecCoreEntryPoint ); if (EFI_ERROR (Status)) { return ; } // // Transfer control to the SEC Core // SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)SecCoreEntryPoint, SecCoreData, GetThunkPpiList (), TopOfStack ); // // If we get here, then the SEC Core returned. This is an error // return ; }