/** Initialize IDT to setup exception handlers for SMM. **/ VOID InitializeSmmIdt ( VOID ) { EFI_STATUS Status; BOOLEAN InterruptState; IA32_DESCRIPTOR DxeIdtr; // // Disable Interrupt and save DXE IDT table // InterruptState = SaveAndDisableInterrupts (); AsmReadIdtr (&DxeIdtr); // // Load SMM temporary IDT table // AsmWriteIdtr (&gcSmiIdtr); // // Setup SMM default exception handlers, SMM IDT table // will be updated and saved in gcSmiIdtr // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Restore DXE IDT table and CPU interrupt // AsmWriteIdtr ((IA32_DESCRIPTOR *) &DxeIdtr); SetInterruptState (InterruptState); }
/** A stub to convert framework boot script dispatch to PI boot script dispatch. @param ImageHandle It should be is NULL. @param Context The first parameter to pass to 32bit code @return dispatch value. **/ EFI_STATUS EFIAPI FrameworkBootScriptDispatchStub ( IN EFI_HANDLE ImageHandle, IN VOID *Context ) { EFI_STATUS Status; DISPATCH_ENTRYPOINT_FUNC EntryFunc; VOID *PeiServices; IA32_DESCRIPTOR Idtr; DEBUG ((EFI_D_ERROR, "FrameworkBootScriptDispatchStub - 0x%08x\n", (UINTN)Context)); EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (Context); AsmReadIdtr (&Idtr); PeiServices = (VOID *)(UINTN)(*(UINT32 *)(Idtr.Base - sizeof (UINT32))); // // ECP assumes first parameter is NULL, and second parameter is PeiServices. // Status = Execute32BitCode ((UINT64)(UINTN)EntryFunc, 0, (UINT64)(UINTN)PeiServices); return Status; }
/** This function initialize basic context for FRM. **/ VOID InitBasicContext ( VOID ) { UINT32 RegEax; mHostContextCommon.CpuNum = GetCpuNumFromAcpi (); GetPciExpressInfoFromAcpi (&mHostContextCommon.PciExpressBaseAddress, &mHostContextCommon.PciExpressLength); PcdSet64 (PcdPciExpressBaseAddress, mHostContextCommon.PciExpressBaseAddress); if (mHostContextCommon.PciExpressBaseAddress == 0) { CpuDeadLoop (); } mHostContextCommon.AcpiTimerIoPortBaseAddress = GetAcpiTimerPort (&mHostContextCommon.AcpiTimerWidth); PcdSet16 (PcdAcpiTimerIoPortBaseAddress, mHostContextCommon.AcpiTimerIoPortBaseAddress); PcdSet8 (PcdAcpiTimerWidth, mHostContextCommon.AcpiTimerWidth); if (mHostContextCommon.AcpiTimerIoPortBaseAddress == 0) { CpuDeadLoop (); } mHostContextCommon.ResetIoPortBaseAddress = GetAcpiResetPort (); mHostContextCommon.AcpiPmControlIoPortBaseAddress = GetAcpiPmControlPort (); if (mHostContextCommon.AcpiPmControlIoPortBaseAddress == 0) { CpuDeadLoop (); } mHostContextCommon.HostContextPerCpu = AllocatePages (FRM_SIZE_TO_PAGES(sizeof(FRM_HOST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum); mGuestContextCommon.GuestContextPerCpu = AllocatePages (FRM_SIZE_TO_PAGES(sizeof(FRM_GUEST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum); mHostContextCommon.LowMemoryBase = mCommunicationData.LowMemoryBase; mHostContextCommon.LowMemorySize = mCommunicationData.LowMemorySize; mHostContextCommon.LowMemoryBackupBase = (UINT64)(UINTN)AllocatePages (FRM_SIZE_TO_PAGES ((UINTN)mCommunicationData.LowMemorySize)); // // Save current context // mBspIndex = ApicToIndex (ReadLocalApicId ()); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0 = AsmReadCr0 (); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3 = AsmReadCr3 (); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4 = AsmReadCr4 (); AsmReadGdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr); AsmReadIdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr); AsmCpuid (CPUID_EXTENDED_INFORMATION, &RegEax, NULL, NULL, NULL); if (RegEax >= CPUID_EXTENDED_ADDRESS_SIZE) { AsmCpuid (CPUID_EXTENDED_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL); mHostContextCommon.PhysicalAddressBits = (UINT8)RegEax; } else { mHostContextCommon.PhysicalAddressBits = 36; } }
/** Caches a pointer PEI Services Table. Caches the pointer to the PEI Services Table specified by PeiServicesTablePointer in a CPU specific manner as specified in the CPU binding section of the Platform Initialization Pre-EFI Initialization Core Interface Specification. The function set the pointer of PEI services immediately preceding the IDT table according to PI specification. If PeiServicesTablePointer is NULL, then ASSERT(). @param PeiServicesTablePointer The address of PeiServices pointer. **/ VOID EFIAPI SetPeiServicesTablePointer ( IN CONST EFI_PEI_SERVICES ** PeiServicesTablePointer ) { IA32_DESCRIPTOR Idtr; ASSERT (PeiServicesTablePointer != NULL); AsmReadIdtr (&Idtr); (*(UINTN*)(Idtr.Base - sizeof (UINTN))) = (UINTN)PeiServicesTablePointer; }
EFIAPI GetPeiServicesTablePointer ( VOID ) { CONST EFI_PEI_SERVICES **PeiServices; IA32_DESCRIPTOR Idtr; AsmReadIdtr (&Idtr); PeiServices = (CONST EFI_PEI_SERVICES **) (*(UINTN*)(Idtr.Base - sizeof (UINTN))); ASSERT (PeiServices != NULL); return PeiServices; }
/** Initialize IDT entries to support source level debug. **/ VOID InitializeDebugIdt ( VOID ) { IA32_IDT_GATE_DESCRIPTOR *IdtEntry; UINTN InterruptHandler; IA32_DESCRIPTOR IdtDescriptor; UINTN Index; UINT16 CodeSegment; UINT32 RegEdx; AsmReadIdtr (&IdtDescriptor); // // Use current CS as the segment selector of interrupt gate in IDT // CodeSegment = AsmReadCs (); IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; for (Index = 0; Index < 20; Index ++) { if (((PcdGet32 (PcdExceptionsIgnoredByDebugger) & ~(BIT1 | BIT3)) & (1 << Index)) != 0) { // // If the exception is masked to be reserved except for INT1 and INT3, skip it // continue; } InterruptHandler = (UINTN)&Exception0Handle + Index * ExceptionStubHeaderSize; IdtEntry[Index].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; IdtEntry[Index].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); IdtEntry[Index].Bits.Selector = CodeSegment; IdtEntry[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; } InterruptHandler = (UINTN) &TimerInterruptHandle; IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; IdtEntry[DEBUG_TIMER_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); IdtEntry[DEBUG_TIMER_VECTOR].Bits.Selector = CodeSegment; IdtEntry[DEBUG_TIMER_VECTOR].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; // // If the CPU supports Debug Extensions(CPUID:01 EDX:BIT2), then // Set DE flag in CR4 to enable IO breakpoint // AsmCpuid (1, NULL, NULL, NULL, &RegEdx); if ((RegEdx & BIT2) != 0) { AsmWriteCr4 (AsmReadCr4 () | BIT3); } }
/** Retrieve exception handler from IDT table by ExceptionNum. @param[in] ExceptionNum Exception number @return Exception handler **/ VOID * GetExceptionHandlerInIdtEntry ( IN UINTN ExceptionNum ) { IA32_IDT_GATE_DESCRIPTOR *IdtEntry; IA32_DESCRIPTOR IdtDescriptor; AsmReadIdtr (&IdtDescriptor); IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; return (VOID *) (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetLow) | (((UINTN)IdtEntry[ExceptionNum].Bits.OffsetHigh) << 16)); }
/** Set the pointer of Mailbox into IDT entry before memory is ready. @param[in] Mailbox The pointer of Mailbox. **/ VOID SetMailboxPointerInIdtEntry ( IN VOID *Mailbox ) { IA32_IDT_GATE_DESCRIPTOR *IdtEntry; IA32_DESCRIPTOR IdtDescriptor; AsmReadIdtr (&IdtDescriptor); IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow = (UINT16)(UINTN)Mailbox; IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh = (UINT16)((UINTN)Mailbox >> 16); }
/** Write IDT Gate Descriptor into IDT Table. @param Vector Specifies vector number. @param IdtGateDescriptor Pointer to IDT Gate Descriptor written into IDT Table. **/ VOID WriteIdtGateDescriptor ( EFI_EXCEPTION_TYPE Vector, IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor ) { IA32_DESCRIPTOR IdtrValue; IA32_IDT_GATE_DESCRIPTOR *IdtTable; AsmReadIdtr (&IdtrValue); IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtrValue.Base; CopyMem ((VOID *) &(IdtTable)[Vector], (VOID *) IdtGateDescriptor, sizeof (IA32_IDT_GATE_DESCRIPTOR)); }
/** Set exception handler in IDT table by ExceptionNum. @param[in] ExceptionNum Exception number @param[in] ExceptionHandler Exception Handler to be set **/ VOID SetExceptionHandlerInIdtEntry ( IN UINTN ExceptionNum, IN VOID *ExceptionHandler ) { IA32_IDT_GATE_DESCRIPTOR *IdtEntry; IA32_DESCRIPTOR IdtDescriptor; AsmReadIdtr (&IdtDescriptor); IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; IdtEntry[ExceptionNum].Bits.OffsetLow = (UINT16)(UINTN)ExceptionHandler; IdtEntry[ExceptionNum].Bits.OffsetHigh = (UINT16)((UINTN)ExceptionHandler >> 16); }
/** Get pointer to Mailbox from IDT entry before memory is ready. **/ VOID * GetMailboxPointerInIdtEntry ( VOID ) { IA32_IDT_GATE_DESCRIPTOR *IdtEntry; IA32_DESCRIPTOR IdtDescriptor; UINTN Mailbox; AsmReadIdtr (&IdtDescriptor); IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base; Mailbox = IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16); return (VOID *) Mailbox; }
/** Hook IDT with our page fault handler so that the on-demand paging works on page fault. The function hooks the IDT with PageFaultHandlerHook to get on-demand paging work for PI<->Framework CpuSaveStates marshalling. It also saves original handler for pass-through purpose. **/ VOID HookPageFaultHandler ( VOID ) { IA32_DESCRIPTOR Idtr; IA32_IDT_GATE_DESCRIPTOR *IdtGateDesc; UINT32 OffsetUpper; InitializeSpinLock (&mPFLock); AsmReadIdtr (&Idtr); IdtGateDesc = (IA32_IDT_GATE_DESCRIPTOR *) Idtr.Base; OffsetUpper = *(UINT32*)((UINT64*)IdtGateDesc + 1); mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (OffsetUpper, 32) + IdtGateDesc[14].Bits.OffsetLow + (IdtGateDesc[14].Bits.OffsetHigh << 16)); IdtGateDesc[14].Bits.OffsetLow = (UINT32)((UINTN)PageFaultHandlerHook & ((1 << 16) - 1)); IdtGateDesc[14].Bits.OffsetHigh = (UINT32)(((UINTN)PageFaultHandlerHook >> 16) & ((1 << 16) - 1)); }
EFIAPI GetPeiServicesTablePointer ( VOID ) { IA32_DESCRIPTOR Idtr; EFI_PEI_SERVICES **PeiServices; AsmReadIdtr (&Idtr); PeiServices = (EFI_PEI_SERVICES **)(UINTN)(*(UINTN*)(Idtr.Base - sizeof (UINTN))); if ((*PeiServices)->Hdr.Signature == PEI_SERVICES_SIGNATURE) { return PeiServices; } else { PeiServices = (EFI_PEI_SERVICES **)(UINTN)AsmReadMm7 (); ASSERT (PeiServices != NULL); return PeiServices; } }
/** Initialize IDT to setup exception handlers for SMM. **/ VOID InitializeSmmIdt ( VOID ) { EFI_STATUS Status; BOOLEAN InterruptState; IA32_DESCRIPTOR DxeIdtr; // // There are 32 (not 255) entries in it since only processor // generated exceptions will be handled. // gcSmiIdtr.Limit = (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 32) - 1; // // Allocate page aligned IDT, because it might be set as read only. // gcSmiIdtr.Base = (UINTN)AllocateCodePages (EFI_SIZE_TO_PAGES(gcSmiIdtr.Limit + 1)); ASSERT (gcSmiIdtr.Base != 0); ZeroMem ((VOID *)gcSmiIdtr.Base, gcSmiIdtr.Limit + 1); // // Disable Interrupt and save DXE IDT table // InterruptState = SaveAndDisableInterrupts (); AsmReadIdtr (&DxeIdtr); // // Load SMM temporary IDT table // AsmWriteIdtr (&gcSmiIdtr); // // Setup SMM default exception handlers, SMM IDT table // will be updated and saved in gcSmiIdtr // Status = InitializeCpuExceptionHandlers (NULL); ASSERT_EFI_ERROR (Status); // // Restore DXE IDT table and CPU interrupt // AsmWriteIdtr ((IA32_DESCRIPTOR *) &DxeIdtr); SetInterruptState (InterruptState); }
/** Wrapper for a thunk to transition from long mode to compatibility mode to execute 32-bit code and then transit back to long mode. @param[in] Function The 32bit code entry to be executed. @param[in] Param1 The first parameter to pass to 32bit code. @return EFI_STATUS. **/ EFI_STATUS Execute32BitCode ( IN UINT64 Function, IN UINT64 Param1 ) { EFI_STATUS Status; IA32_DESCRIPTOR Idtr; // // Idtr might be changed inside of FSP. 32bit FSP only knows the <4G address. // If IDTR.Base is >4G, FSP can not handle. So we need save/restore IDTR here for X64 only. // Interrupt is already disabled here, so it is safety to update IDTR. // AsmReadIdtr (&Idtr); Status = AsmExecute32BitCode (Function, Param1, 0, &mGdt); AsmWriteIdtr (&Idtr); return Status; }
/** This function initialize guest BSP in S3. **/ VOID BspS3Init ( VOID ) { UINT32 Index; mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0 = AsmReadCr0 (); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3 = AsmReadCr3 (); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4 = AsmReadCr4 (); AsmReadGdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr); AsmReadIdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr); InitHostContextPerCpu (mBspIndex); for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) { mGuestContextCommon.GuestContextPerCpu[Index].Cr0 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0; mGuestContextCommon.GuestContextPerCpu[Index].Cr3 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3; mGuestContextCommon.GuestContextPerCpu[Index].Cr4 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4; CopyMem (&mGuestContextCommon.GuestContextPerCpu[Index].Gdtr, &mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr, sizeof(IA32_DESCRIPTOR)); } InitGuestContextPerCpu (mBspIndex); }
/** Perform CPU specific actions required to migrate the PEI Services Table pointer from temporary RAM to permanent RAM. For IA32 CPUs, the PEI Services Table pointer is stored in the 4 bytes immediately preceding the Interrupt Descriptor Table (IDT) in memory. For X64 CPUs, the PEI Services Table pointer is stored in the 8 bytes immediately preceding the Interrupt Descriptor Table (IDT) in memory. For Itanium and ARM CPUs, a the PEI Services Table Pointer is stored in a dedicated CPU register. This means that there is no memory storage associated with storing the PEI Services Table pointer, so no additional migration actions are required for Itanium or ARM CPUs. If The cached PEI Services Table pointer is NULL, then ASSERT(). If the permanent memory is allocated failed, then ASSERT(). **/ VOID EFIAPI MigratePeiServicesTablePointer ( VOID ) { EFI_STATUS Status; IA32_DESCRIPTOR Idtr; EFI_PHYSICAL_ADDRESS IdtBase; CONST EFI_PEI_SERVICES **PeiServices; // // Get PEI Services Table pointer // AsmReadIdtr (&Idtr); PeiServices = (CONST EFI_PEI_SERVICES **) (*(UINTN*)(Idtr.Base - sizeof (UINTN))); ASSERT (PeiServices != NULL); // // Allocate the permanent memory. // Status = (*PeiServices)->AllocatePages ( PeiServices, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Idtr.Limit + 1 + sizeof (UINTN)), &IdtBase ); ASSERT_EFI_ERROR (Status); // // Idt table needs to be migrated into memory. // CopyMem ((VOID *) (UINTN) IdtBase, (VOID *) (Idtr.Base - sizeof (UINTN)), Idtr.Limit + 1 + sizeof (UINTN)); Idtr.Base = (UINTN) IdtBase + sizeof (UINTN); AsmWriteIdtr (&Idtr); return; }
/** Initialize debug agent. This function is used to set up debug enviroment for DXE phase. If this function is called by DXE Core, Context must be the pointer to HOB list which will be used to get GUIDed HOB. It will enable interrupt to support break-in feature. If this function is called by DXE module, Context must be NULL. It will enable interrupt to support break-in feature. @param[in] InitFlag Init flag is used to decide initialize process. @param[in] Context Context needed according to InitFlag. @param[in] Function Continue function called by debug agent library; it was optional. **/ VOID EFIAPI InitializeDebugAgent ( IN UINT32 InitFlag, IN VOID *Context, OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL ) { DEBUG_AGENT_MAILBOX *Mailbox; IA32_DESCRIPTOR Idtr; UINT16 IdtEntryCount; BOOLEAN InterruptStatus; if (InitFlag != DEBUG_AGENT_INIT_DXE_CORE && InitFlag != DEBUG_AGENT_INIT_S3 && InitFlag != DEBUG_AGENT_INIT_DXE_AP) { return; } // // Save and disable original interrupt status // InterruptStatus = SaveAndDisableInterrupts (); if (InitFlag == DEBUG_AGENT_INIT_DXE_CORE) { // // Try to get Mailbox from GUIDed HOB. // mDxeCoreFlag = TRUE; Mailbox = GetMailboxFromHob (Context); // // Clear Break CPU index value // mDebugMpContext.BreakAtCpuIndex = (UINT32) -1; } else if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { EnableInterrupts (); return; } else { // // If it is in S3 path, needn't to install configuration table. // Mailbox = NULL; } if (Mailbox != NULL) { // // If Mailbox exists, copy it into one global variable. // CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); } else { // // If Mailbox not exists, used the local Mailbox. // ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX)); } mMailboxPointer = &mMailbox; // // Get original IDT address and size. // AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); if (IdtEntryCount < 33) { Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); Idtr.Base = (UINTN) &mIdtEntryTable; ZeroMem (&mIdtEntryTable, Idtr.Limit + 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); } // // Initialize the IDT table entries to support source level debug. // InitializeDebugIdt (); // // Initialize debug communication port // mMailboxPointer->DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailbox.DebugPortHandle, NULL); InitializeSpinLock (&mDebugMpContext.MpContextSpinLock); InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock); if (InitFlag == DEBUG_AGENT_INIT_DXE_CORE) { // // Initialize Debug Timer hardware and enable interrupt. // InitializeDebugTimer (); EnableInterrupts (); return; } else { // // Disable Debug Timer interrupt in S3 path. // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore interrupt state. // SetInterruptState (InterruptStatus); } }
/** The entry function of the CpuS3Data driver. Allocate and initialize all fields of the ACPI_CPU_DATA structure except the MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set to the address that ACPI_CPU_DATA is allocated at. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval EFI_UNSUPPORTED Do not support ACPI S3. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI CpuS3DataInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; ACPI_CPU_DATA_EX *AcpiCpuDataEx; ACPI_CPU_DATA *AcpiCpuData; EFI_MP_SERVICES_PROTOCOL *MpServices; UINTN NumberOfCpus; UINTN NumberOfEnabledProcessors; VOID *Stack; UINTN TableSize; CPU_REGISTER_TABLE *RegisterTable; UINTN Index; EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; UINTN GdtSize; UINTN IdtSize; VOID *Gdt; VOID *Idt; EFI_EVENT Event; ACPI_CPU_DATA *OldAcpiCpuData; if (!PcdGetBool (PcdAcpiS3Enable)) { return EFI_UNSUPPORTED; } // // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure // OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress); AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX)); ASSERT (AcpiCpuDataEx != NULL); AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData; // // Get MP Services Protocol // Status = gBS->LocateProtocol ( &gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices ); ASSERT_EFI_ERROR (Status); // // Get the number of CPUs // Status = MpServices->GetNumberOfProcessors ( MpServices, &NumberOfCpus, &NumberOfEnabledProcessors ); ASSERT_EFI_ERROR (Status); AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus; // // Initialize ACPI_CPU_DATA fields // AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize); AcpiCpuData->ApMachineCheckHandlerBase = 0; AcpiCpuData->ApMachineCheckHandlerSize = 0; AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile; AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile; AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable; // // Allocate stack space for all CPUs. // Use ACPI NVS memory type because this data will be directly used by APs // in S3 resume phase in long mode. Also during S3 resume, the stack buffer // will only be used as scratch space. i.e. we won't read anything from it // before we write to it, in PiSmmCpuDxeSmm. // Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize); ASSERT (Stack != NULL); AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack; // // Get the boot processor's GDT and IDT // AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile); AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile); // // Allocate GDT and IDT and copy current GDT and IDT contents // GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; Gdt = AllocateZeroPages (GdtSize + IdtSize); ASSERT (Gdt != NULL); Idt = (VOID *)((UINTN)Gdt + GdtSize); CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize); CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize); AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt; AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt; if (OldAcpiCpuData != NULL) { AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable; AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable; AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation; CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION)); } else { // // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs // TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE); RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize); ASSERT (RegisterTable != NULL); for (Index = 0; Index < NumberOfCpus; Index++) { Status = MpServices->GetProcessorInfo ( MpServices, Index, &ProcessorInfoBuffer ); ASSERT_EFI_ERROR (Status); RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; RegisterTable[Index].TableLength = 0; RegisterTable[Index].AllocatedSize = 0; RegisterTable[Index].RegisterTableEntry = 0; RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; RegisterTable[NumberOfCpus + Index].TableLength = 0; RegisterTable[NumberOfCpus + Index].AllocatedSize = 0; RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0; } AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus); } // // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure // Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); ASSERT_EFI_ERROR (Status); // // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuS3DataOnEndOfDxe, AcpiCpuData, &gEfiEndOfDxeEventGroupGuid, &Event ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
/** 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 (); }
/** This function set TXT HEAP. @param MleLoadAddress MLE address @param MleLoadSize MLE size @param PageTableBase page table base **/ VOID TxtSetupHeap ( IN UINT64 MleLoadAddress, IN UINT64 MleLoadSize, IN UINT64 PageTableBase ) { VOID *TxtOsMleData; MLE_PRIVATE_DATA *MlePrivateData; DCE_PRIVATE_DATA *DcePrivateData; TXT_OS_TO_SINIT_DATA *OsSinitData; TXT_SINIT_TO_MLE_DATA *SinitMleData; TXT_ACM_FORMAT *SinitAcm; TXT_CHIPSET_ACM_INFORMATION_TABLE *ChipsetAcmInformationTable; UINTN TxtHeapSize; UINTN TxtHeapOccupiedSize; // // MlePrivateData // TxtOsMleData = GetTxtOsToMleData(); DEBUG((EFI_D_INFO, "(TXT) TxtOsMleData - 0x%x\n", TxtOsMleData)); *((UINT64 *)TxtOsMleData - 1) = sizeof(UINT64) + sizeof(TXT_OS_TO_MLE_DATA_STRUCT); MlePrivateData = GetMlePrivateData (); DcePrivateData = &MlePrivateData->DcePrivateData; AsmReadGdtr (&MlePrivateData->Gdtr); AsmReadIdtr (&MlePrivateData->Idtr); MlePrivateData->Ds = AsmReadDs (); MlePrivateData->TempEsp = (UINT32)(UINT32)((UINTN)GetTxtHeap () + GetTxtHeapSize () - MLE_TEMP_STACK_SIZE_RLP - 0x20); // // Patch CS/Offset in stack // // +---------+ // | Offset | // +---------+ // | CS | // +---------+ // | Dummy | // +---------+ // | Dummy | // +---------+ // | Dummy | // +---------+ // | Dummy | // +---------+ <- TempEsp if (PostInitAddr != 0) { MlePrivateData->PostSinitOffset = (UINT32)((UINTN)AsmMleEntryPoint + PostInitAddr); MlePrivateData->PostSinitSegment = (UINT32)AsmReadCs(); } MlePrivateData->Lock = 0; MlePrivateData->RlpInitializedNumber = 0; // // OsSinitData // OsSinitData = GetTxtOsToSinitData (); DEBUG((EFI_D_INFO, "(TXT) OsSinitData - 0x%x\n", OsSinitData)); *((UINT64 *)OsSinitData - 1) = sizeof(UINT64) + sizeof(*OsSinitData); OsSinitData->Version = TXT_OS_TO_SINIT_DATA_VERSION; OsSinitData->Flags = 0; OsSinitData->MLEPageTableBase = PageTableBase; // // We copy MleHeader to DPR // { TXT_MLE_HEADER *MleHeader; MleHeader = (TXT_MLE_HEADER *)(UINTN)MleLoadAddress; CopyMem (&MleHeader->Uuid, &gMleHeaderUuid, sizeof(gMleHeaderUuid)); MleHeader->HeaderLen = sizeof(*MleHeader); MleHeader->Version = TXT_MLE_HEADER_VERSION; MleHeader->EntryPoint = (UINT32)(UINTN)MleHeader + sizeof(*MleHeader); if (MleHeader->Version < TXT_MLE_HEADER_VERSION_2_1) { MleHeader->EntryPoint -= (sizeof(MleHeader->CmdlineStart) + sizeof(MleHeader->CmdlineEnd)); } // // Patch the instruction for ILP // *(UINT8 *)(UINTN)MleHeader->EntryPoint = 0x90; // nop *(UINT8 *)((UINTN)MleHeader->EntryPoint + 1) = 0xE9; // near jmp *(UINT32 *)((UINTN)MleHeader->EntryPoint + 2) = (UINT32)((UINTN)AsmMleEntryPoint - ((UINTN)MleHeader->EntryPoint + 6)); // minus next instruction // // Patch the instrution for RLPs: cli, hlt, and jmp $-2 // *(UINT32 *)((UINTN)MleHeader->EntryPoint + 6) = 0xFCEBF4FA; MleHeader->EntryPoint -= (UINT32)PageTableBase; if (MleHeader->Version >= TXT_MLE_HEADER_VERSION_1_1) { MleHeader->FirstValidPage = (UINT32)MleLoadAddress; MleHeader->FirstValidPage -= (UINT32)PageTableBase; MleHeader->MleStart = MleHeader->FirstValidPage; //MleHeader->MleEnd = MleHeader->MleStart + sizeof(*MleHeader) + 10; // Offset (1 nop + 5 jmp + 4 deadloop) MleHeader->MleEnd = MleHeader->MleStart + (UINT32)MleLoadSize; } if (MleHeader->Version >= TXT_MLE_HEADER_VERSION_2) { MleHeader->Capabilities = TXT_MLE_SINIT_CAPABILITY_GETSET_WAKEUP | TXT_MLE_SINIT_CAPABILITY_MONITOR_ADDRESS_RLP_WAKEUP; MleHeader->Capabilities |= TXT_MLE_SINIT_CAPABILITY_ECX_HAS_PAGE_TABLE; #ifdef STM_SUPPORT MleHeader->Capabilities |= TXT_MLE_SINIT_CAPABILITY_STM; #endif } if (MleHeader->Version >= TXT_MLE_HEADER_VERSION_2_1) { MleHeader->CmdlineStart = 0; // Not use MleHeader->CmdlineEnd = 0; // Not use } // // Done // OsSinitData->MLEHeaderBase = (UINT64)(UINTN)MleHeader; OsSinitData->MLEHeaderBase -= PageTableBase; OsSinitData->MLESize = (UINT64)(MleHeader->MleEnd - MleHeader->MleStart); } OsSinitData->PMRLowBase = MlePrivateData->DcePrivateData.PmrLowBase; OsSinitData->PMRLowSize = MlePrivateData->DcePrivateData.PmrLowSize; OsSinitData->PMRHighBase = MlePrivateData->DcePrivateData.PmrHighBase; OsSinitData->PMRHighSize = MlePrivateData->DcePrivateData.PmrHighSize; OsSinitData->LCPPOBase = MlePrivateData->DcePrivateData.LcpPoBase; OsSinitData->LCPPOSize = MlePrivateData->DcePrivateData.LcpPoSize; SinitAcm = (TXT_ACM_FORMAT *)(UINTN)TxtPubRead32 (TXT_SINIT_BASE); ChipsetAcmInformationTable = (TXT_CHIPSET_ACM_INFORMATION_TABLE *) \ ((UINTN)(SinitAcm + 1) + SinitAcm->KeySize * 4 + sizeof(UINT32) + ACM_PKCS_1_5_RSA_SIGNATURE_SIZE + SinitAcm->ScratchSize * 4 ); if ((ChipsetAcmInformationTable->Capabilities & TXT_MLE_SINIT_CAPABILITY_MONITOR_ADDRESS_RLP_WAKEUP) != 0) { OsSinitData->Capabilities = TXT_MLE_SINIT_CAPABILITY_MONITOR_ADDRESS_RLP_WAKEUP; } else { OsSinitData->Capabilities = TXT_MLE_SINIT_CAPABILITY_GETSET_WAKEUP; } OsSinitData->Version = ChipsetAcmInformationTable->OsSinitTableVer; if (ChipsetAcmInformationTable->OsSinitTableVer >= TXT_OS_TO_SINIT_DATA_VERSION_5) { OsSinitData->RsdpPtr = (UINT64)(UINTN)FindAcpiRsdPtr (); if (OsSinitData->RsdpPtr == 0) { OsSinitData->RsdpPtr = (UINT64)(UINTN)&MlePrivateData->UefiRsdp; } if (ChipsetAcmInformationTable->OsSinitTableVer >= TXT_OS_TO_SINIT_DATA_VERSION_6) { if (ChipsetAcmInformationTable->OsSinitTableVer >= TXT_OS_TO_SINIT_DATA_VERSION_7) { OsSinitData->Flags = TXT_OS_TO_SINIT_DATA_FLAGS_MAX_AGILE_POLICY; } // // Fill Event Log data there // TXT_HEAP_EXT_DATA_ELEMENT *Element; TXT_HEAP_EVENTLOG_EXT_ELEMENT *EventLogElement; TXT_EVENT_LOG_CONTAINER *EventLog; TXT_HEAP_EVENT_LOG_POINTER_ELEMENT2 *EventLogPointerElement2; TXT_HEAP_EVENT_LOG_POINTER_ELEMENT2_1 *EventLogPointerElement2_1; TXT_HEAP_EVENT_LOG_DESCR *EventLogDesc; UINTN Index; TCG_LOG_DESCRIPTOR *TcgLogDesc; TCG_PCR_EVENT_HDR *PcrEvent; *((UINT64 *)OsSinitData - 1) = sizeof(UINT64) + sizeof(*OsSinitData); Element = (TXT_HEAP_EXT_DATA_ELEMENT *)(OsSinitData + 1); if (DcePrivateData->TpmType == FRM_TPM_TYPE_TPM12) { // TPM1.2 Element->Type = TXT_HEAP_EXTDATA_TYPE_EVENTLOG_PTR; Element->Size = sizeof(TXT_HEAP_EXT_DATA_ELEMENT) + sizeof(TXT_HEAP_EVENTLOG_EXT_ELEMENT); EventLogElement = (TXT_HEAP_EVENTLOG_EXT_ELEMENT *)(Element + 1); DcePrivateData->EventLogElement = EventLogElement; // // Init EventLogContainer // EventLog = (TXT_EVENT_LOG_CONTAINER *)(UINTN)(MlePrivateData->DcePrivateData.EventLogBase); ZeroMem(EventLog, MAX_EVENT_LOG_BUFFER_SIZE); CopyMem(EventLog->Signature, TXT_EVENTLOG_SIGNATURE, sizeof(TXT_EVENTLOG_SIGNATURE)); EventLog->ContainerVersionMajor = TXT_EVENTLOG_CONTAINER_MAJOR_VERSION; EventLog->ContainerVersionMinor = TXT_EVENTLOG_CONTAINER_MINOR_VERSION; EventLog->PcrEventVersionMajor = TXT_EVENTLOG_EVENT_MAJOR_VERSION; EventLog->PcrEventVersionMinor = TXT_EVENTLOG_EVENT_MINOR_VERSION; EventLog->Size = MAX_EVENT_LOG_BUFFER_SIZE; EventLog->PcrEventsOffset = sizeof(*EventLog); EventLog->NextEventOffset = sizeof(*EventLog); EventLogElement->EventLogAddress = (UINT64)(UINTN)EventLog; *((UINT64 *)OsSinitData - 1) += Element->Size; Element = (TXT_HEAP_EXT_DATA_ELEMENT *)((UINTN)Element + Element->Size); } if (DcePrivateData->TpmType == FRM_TPM_TYPE_TPM2) { // TPM2.0 UINT16 TpmHashAlgo[] = { TPM_ALG_SHA1, TPM_ALG_SHA256, TPM_ALG_SHA384, TPM_ALG_SHA512, TPM_ALG_SM3_256 }; UINTN SubIndex; DcePrivateData->EventHashAlgoIDCount = 0; for (Index = 0; Index < sizeof(TpmHashAlgo) / sizeof(TpmHashAlgo[0]); Index++) { if ((DcePrivateData->ActivePcrBanks & (1 << Index)) != 0) { for (SubIndex = 0; SubIndex < DcePrivateData->AcmTpmHashAlgoIDCount; SubIndex++) { if (DcePrivateData->AcmTpmHashAlgoID[SubIndex] == TpmHashAlgo[Index]) { // Both TPM and ACM support this hash algo. DcePrivateData->EventHashAlgoID[DcePrivateData->EventHashAlgoIDCount] = TpmHashAlgo[Index]; DcePrivateData->EventHashAlgoIDCount++; } } } } if ((DcePrivateData->AcmCapabilities & TXT_MLE_SINIT_CAPABILITY_TCG2_COMPATIBILE_EVENTLOG) == 0) { Element->Type = TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2; EventLogPointerElement2 = (TXT_HEAP_EVENT_LOG_POINTER_ELEMENT2 *)(Element + 1); DcePrivateData->EventLogPointerElement2 = EventLogPointerElement2; EventLogPointerElement2->Count = DcePrivateData->EventHashAlgoIDCount; EventLogDesc = (TXT_HEAP_EVENT_LOG_DESCR *)(EventLogPointerElement2 + 1); Element->Size = sizeof(TXT_HEAP_EXT_DATA_ELEMENT) + sizeof(TXT_HEAP_EVENT_LOG_POINTER_ELEMENT2) + EventLogPointerElement2->Count * sizeof(TXT_HEAP_EVENT_LOG_DESCR); for (Index = 0; Index < EventLogPointerElement2->Count; Index++, EventLogDesc++) { EventLogDesc->HashAlgID = DcePrivateData->EventHashAlgoID[Index]; EventLogDesc->Reserved = 0; EventLogDesc->PhysicalAddress = (UINT64)(UINTN)(MlePrivateData->DcePrivateData.EventLogBase + MAX_EVENT_LOG_BUFFER_SIZE * (Index + 1)); ZeroMem((VOID *)(UINTN)EventLogDesc->PhysicalAddress, MAX_EVENT_LOG_BUFFER_SIZE); EventLogDesc->AllocatedEventContainerSize = MAX_EVENT_LOG_BUFFER_SIZE; if (EventLogDesc->HashAlgID == TPM_ALG_SHA) { PcrEvent = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogDesc->PhysicalAddress; TcgLogDesc = (TCG_LOG_DESCRIPTOR *)(PcrEvent + 1); PcrEvent->PCRIndex = 0; PcrEvent->EventType = EV_NO_ACTION; ZeroMem(&PcrEvent->Digest, sizeof(PcrEvent->Digest)); PcrEvent->EventSize = sizeof(TCG_LOG_DESCRIPTOR); CopyMem(TcgLogDesc->Signature, TCG_LOG_DESCRIPTOR_SIGNATURE, sizeof(TCG_LOG_DESCRIPTOR_SIGNATURE)); TcgLogDesc->Revision = TCG_LOG_DESCRIPTOR_REVISION; TcgLogDesc->DigestAlgID = DIGEST_ALG_ID_SHA_1; TcgLogDesc->DigestSize = SHA1_DIGEST_SIZE; EventLogDesc->FirstRecordOffset = sizeof(TCG_PCR_EVENT_HDR) + PcrEvent->EventSize; EventLogDesc->NextRecordOffset = sizeof(TCG_PCR_EVENT_HDR) + PcrEvent->EventSize; } else { EventLogDesc->FirstRecordOffset = 0; EventLogDesc->NextRecordOffset = 0; } } } else { Element->Type = TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1; EventLogPointerElement2_1 = (TXT_HEAP_EVENT_LOG_POINTER_ELEMENT2_1 *)(Element + 1); DcePrivateData->EventLogPointerElement2_1 = EventLogPointerElement2_1; EventLogPointerElement2_1->PhysicalAddress = (UINT64)(UINTN)(MlePrivateData->DcePrivateData.EventLogBase + MAX_EVENT_LOG_BUFFER_SIZE); ZeroMem((VOID *)(UINTN)EventLogPointerElement2_1->PhysicalAddress, MAX_EVENT_LOG_BUFFER_SIZE); EventLogPointerElement2_1->AllocatedEventContainerSize = MAX_EVENT_LOG_BUFFER_SIZE * 5; EventLogPointerElement2_1->FirstRecordOffset = 0; EventLogPointerElement2_1->NextRecordOffset = 0; } *((UINT64 *)OsSinitData - 1) += Element->Size; Element = (TXT_HEAP_EXT_DATA_ELEMENT *)((UINTN)Element + Element->Size); } Element->Type = TXT_HEAP_EXTDATA_TYPE_END; Element->Size = sizeof(TXT_HEAP_END_ELEMENT); *((UINT64 *)OsSinitData - 1) += sizeof(TXT_HEAP_END_ELEMENT); } } else { // Version 4 *((UINT64 *)OsSinitData - 1) = sizeof(UINT64) + sizeof(*OsSinitData) - sizeof(UINT64); } // // SinitMleData // SinitMleData = GetTxtSinitToMleData (); DEBUG((EFI_D_INFO, "(TXT) SinitMleData - 0x%x\n", SinitMleData)); *((UINT64 *)SinitMleData - 1) = 0; ZeroMem (SinitMleData, sizeof(*SinitMleData)); TxtHeapSize = GetTxtHeapSize (); TxtHeapOccupiedSize = GetTxtHeapOccupiedSize (); DEBUG ((EFI_D_INFO, "(TXT) TXT Heap base - %08x\n", GetTxtHeap ())); DEBUG ((EFI_D_INFO, "(TXT) TXT Heap size - %08x\n", TxtHeapSize)); DEBUG ((EFI_D_INFO, "(TXT) TXT BiosOsData - %08x\n", GetTxtBiosToOsData())); DEBUG ((EFI_D_INFO, "(TXT) TXT OsMleData - %08x\n", (UINTN)TxtOsMleData)); DEBUG ((EFI_D_INFO, "(TXT) TXT OsSinitData - %08x\n", (UINTN)OsSinitData)); DEBUG ((EFI_D_INFO, "(TXT) TXT SinitMleData - %08x\n", (UINTN)SinitMleData)); DEBUG ((EFI_D_INFO, "(TXT) TXT OccupiedSize - %08x\n", TxtHeapOccupiedSize)); // // Check heap // if (TxtHeapOccupiedSize >= TxtHeapSize) { DEBUG ((EFI_D_ERROR, "(TXT) ERROR: TXT Heap overflow - Occupied (%08x), Allocated (%08x)\n", TxtHeapOccupiedSize, TxtHeapSize)); ASSERT(FALSE); } if (OsSinitData->RsdpPtr != 0) { EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; EFI_ACPI_DESCRIPTION_HEADER *Rsdt; EFI_ACPI_DESCRIPTION_HEADER *Xsdt; // validate ACPI RSDP/RSDT/XSDT Rsdp = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)OsSinitData->RsdpPtr; DEBUG ((EFI_D_INFO, "(TXT) RSDP Address - %08x\n", Rsdp)); DEBUG ((EFI_D_INFO, "(TXT) RSDP Checksum - %02x\n", CalculateCheckSum8((UINT8 *)Rsdp, sizeof(EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER)))); if (Rsdp->Revision >= 2) { DEBUG ((EFI_D_INFO, "(TXT) RSDP Length - %08x\n", Rsdp->Length)); DEBUG ((EFI_D_INFO, "(TXT) RSDP ExtendedChecksum - %02x\n", CalculateCheckSum8((UINT8 *)Rsdp, Rsdp->Length))); } Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress; DEBUG ((EFI_D_INFO, "(TXT) RSDT Address - %08x\n", Rsdt)); DEBUG ((EFI_D_INFO, "(TXT) RSDT Length - %08x\n", Rsdt->Length)); DEBUG ((EFI_D_INFO, "(TXT) RSDT Checksum - %02x\n", CalculateCheckSum8((UINT8 *)Rsdt, Rsdt->Length))); if (Rsdp->Revision >= 2) { Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress; DEBUG ((EFI_D_INFO, "(TXT) XSDT Address - %016lx\n", Xsdt)); DEBUG ((EFI_D_INFO, "(TXT) XSDT Length - %08x\n", Xsdt->Length)); DEBUG ((EFI_D_INFO, "(TXT) XSDT Checksum - %02x\n", CalculateCheckSum8((UINT8 *)Xsdt, Xsdt->Length))); } } return ; }
/** The X64 entrypoint is used to process capsule in long mode then return to 32-bit protected mode. @param EntrypointContext Pointer to the context of long mode. @param ReturnContext Pointer to the context of 32-bit protected mode. @retval This function should never return actually. **/ EFI_STATUS EFIAPI _ModuleEntryPoint ( SWITCH_32_TO_64_CONTEXT *EntrypointContext, SWITCH_64_TO_32_CONTEXT *ReturnContext ) { EFI_STATUS Status; IA32_DESCRIPTOR Ia32Idtr; IA32_DESCRIPTOR X64Idtr; IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER]; // // Save the IA32 IDT Descriptor // AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Setup X64 IDT table // ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER); X64Idtr.Base = (UINTN) IdtEntryTable; X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER - 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr); // // Setup the default CPU exception handlers // 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); // // Call CapsuleDataCoalesce to process capsule. // Status = CapsuleDataCoalesce ( NULL, (EFI_PHYSICAL_ADDRESS *) (UINTN) EntrypointContext->BlockListAddr, (VOID **) (UINTN) EntrypointContext->MemoryBase64Ptr, (UINTN *) (UINTN) EntrypointContext->MemorySize64Ptr ); ReturnContext->ReturnStatus = Status; // // Disable interrupt of Debug timer, since the new IDT table cannot work in long mode // SaveAndSetDebugTimerInterrupt (FALSE); // // Restore IA32 IDT table // AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr); // // Finish to coalesce capsule, and return to 32-bit mode. // AsmDisablePaging64 ( ReturnContext->ReturnCs, (UINT32) ReturnContext->ReturnEntryPoint, (UINT32) (UINTN) EntrypointContext, (UINT32) (UINTN) ReturnContext, (UINT32) (EntrypointContext->StackBufferBase + EntrypointContext->StackBufferLength) ); // // Should never be here. // ASSERT (FALSE); return EFI_SUCCESS; }
/** Entry point to the C language phase of SEC. After the SEC assembly code has initialized some temporary memory and set up the stack, the control is transferred to this function. @param[in] SizeOfRam Size of the temporary memory available for use. @param[in] TempRamBase Base address of temporary ram @param[in] BootFirmwareVolume Base address of the Boot Firmware Volume. @param[in] PeiCore PeiCore entry point. @param[in] BootLoaderStack BootLoader stack. @param[in] ApiIdx the index of API. @return This function never returns. **/ VOID EFIAPI SecStartup ( IN UINT32 SizeOfRam, IN UINT32 TempRamBase, IN VOID *BootFirmwareVolume, IN PEI_CORE_ENTRY PeiCore, IN UINT32 BootLoaderStack, IN UINT32 ApiIdx ) { EFI_SEC_PEI_HAND_OFF SecCoreData; IA32_DESCRIPTOR IdtDescriptor; SEC_IDT_TABLE IdtTableInStack; UINT32 Index; FSP_GLOBAL_DATA PeiFspData; UINT64 ExceptionHandler; UINTN IdtSize; // // Process all libraries constructor function linked to SecCore. // ProcessLibraryConstructorList (); // // Initialize floating point operating environment // to be compliant with UEFI spec. // InitializeFloatingPointUnits (); // |-------------------|----> // |Idt Table | // |-------------------| // |PeiService Pointer | PeiStackSize // |-------------------| // | | // | Stack | // |-------------------|----> // | | // | | // | Heap | PeiTemporayRamSize // | | // | | // |-------------------|----> TempRamBase IdtTableInStack.PeiService = NULL; AsmReadIdtr (&IdtDescriptor); if (IdtDescriptor.Base == 0) { ExceptionHandler = FspGetExceptionHandler(mIdtEntryTemplate); for (Index = 0; Index < FixedPcdGet8(PcdFspMaxInterruptSupported); Index ++) { CopyMem ((VOID*)&IdtTableInStack.IdtTable[Index], (VOID*)&ExceptionHandler, sizeof (UINT64)); } IdtSize = sizeof (IdtTableInStack.IdtTable); } else { IdtSize = IdtDescriptor.Limit + 1; if (IdtSize > sizeof (IdtTableInStack.IdtTable)) { // // ERROR: IDT table size from boot loader is larger than FSP can support, DeadLoop here! // CpuDeadLoop(); } else { CopyMem ((VOID *) (UINTN) &IdtTableInStack.IdtTable, (VOID *) IdtDescriptor.Base, IdtSize); } } IdtDescriptor.Base = (UINTN) &IdtTableInStack.IdtTable; IdtDescriptor.Limit = (UINT16)(IdtSize - 1); AsmWriteIdtr (&IdtDescriptor); // // Initialize the global FSP data region // FspGlobalDataInit (&PeiFspData, BootLoaderStack, (UINT8)ApiIdx); // // Update the base address and length of Pei temporary memory // SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF); SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume; SecCoreData.BootFirmwareVolumeSize = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)BootFirmwareVolume)->FvLength; SecCoreData.TemporaryRamBase = (VOID*)(UINTN) TempRamBase; SecCoreData.TemporaryRamSize = SizeOfRam; SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase; SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize * PcdGet8 (PcdFspHeapSizePercentage) / 100; SecCoreData.StackBase = (VOID*)(UINTN)((UINTN)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize); SecCoreData.StackSize = SecCoreData.TemporaryRamSize - SecCoreData.PeiTemporaryRamSize; DEBUG ((DEBUG_INFO, "Fsp BootFirmwareVolumeBase - 0x%x\n", SecCoreData.BootFirmwareVolumeBase)); DEBUG ((DEBUG_INFO, "Fsp BootFirmwareVolumeSize - 0x%x\n", SecCoreData.BootFirmwareVolumeSize)); DEBUG ((DEBUG_INFO, "Fsp TemporaryRamBase - 0x%x\n", SecCoreData.TemporaryRamBase)); DEBUG ((DEBUG_INFO, "Fsp TemporaryRamSize - 0x%x\n", SecCoreData.TemporaryRamSize)); DEBUG ((DEBUG_INFO, "Fsp PeiTemporaryRamBase - 0x%x\n", SecCoreData.PeiTemporaryRamBase)); DEBUG ((DEBUG_INFO, "Fsp PeiTemporaryRamSize - 0x%x\n", SecCoreData.PeiTemporaryRamSize)); DEBUG ((DEBUG_INFO, "Fsp StackBase - 0x%x\n", SecCoreData.StackBase)); DEBUG ((DEBUG_INFO, "Fsp StackSize - 0x%x\n", SecCoreData.StackSize)); // // Call PeiCore Entry // PeiCore (&SecCoreData, mPeiSecPlatformInformationPpi); // // Should never be here // CpuDeadLoop (); }
/** Worker function to setup IDT table and initialize the IDT entries. @param[in] Mailbox Pointer to Mailbox. **/ VOID SetupDebugAgentEnviroment ( IN DEBUG_AGENT_MAILBOX *Mailbox ) { IA32_DESCRIPTOR Idtr; UINT16 IdtEntryCount; UINT64 DebugPortHandle; if (mMultiProcessorDebugSupport) { InitializeSpinLock (&mDebugMpContext.MpContextSpinLock); InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock); InitializeSpinLock (&mDebugMpContext.MailboxSpinLock); // // Clear Break CPU index value // mDebugMpContext.BreakAtCpuIndex = (UINT32) -1; } // // Get original IDT address and size. // AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); if (IdtEntryCount < 33) { ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33); // // Copy original IDT table into new one // CopyMem (&mIdtEntryTable, (VOID *) Idtr.Base, Idtr.Limit + 1); // // Load new IDT table // Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); Idtr.Base = (UINTN) &mIdtEntryTable; AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); } // // Initialize the IDT table entries to support source level debug. // InitializeDebugIdt (); // // If mMailboxPointer is not set before, set it // if (mMailboxPointer == NULL) { if (Mailbox != NULL) { // // If Mailbox exists, copy it into one global variable // CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); } else { ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX)); } mMailboxPointer = &mMailbox; } // // Initialize debug communication port // DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL); UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); if (Mailbox == NULL) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE); SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); // // Memory has been ready // if (IsHostAttached ()) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } } }
/** Initialize debug agent. This function is used to set up debug enviroment for DXE phase. If this function is called by DXE Core, Context must be the pointer to HOB list which will be used to get GUIDed HOB. It will enable interrupt to support break-in feature. If this function is called by DXE module, Context must be NULL. It will enable interrupt to support break-in feature. @param[in] InitFlag Init flag is used to decide initialize process. @param[in] Context Context needed according to InitFlag. @param[in] Function Continue function called by debug agent library; it was optional. **/ VOID EFIAPI InitializeDebugAgent ( IN UINT32 InitFlag, IN VOID *Context, OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL ) { UINT64 *MailboxLocation; DEBUG_AGENT_MAILBOX *Mailbox; BOOLEAN InterruptStatus; VOID *HobList; IA32_DESCRIPTOR IdtDescriptor; IA32_DESCRIPTOR *Ia32Idtr; IA32_IDT_ENTRY *Ia32IdtEntry; if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { // // Invoked by AP, enable interrupt to let AP could receive IPI from other processors // EnableInterrupts (); return ; } // // Disable Debug Timer interrupt // SaveAndSetDebugTimerInterrupt (FALSE); // // Save and disable original interrupt status // InterruptStatus = SaveAndDisableInterrupts (); // // Try to get mailbox firstly // HobList = NULL; Mailbox = NULL; MailboxLocation = NULL; switch (InitFlag) { case DEBUG_AGENT_INIT_DXE_LOAD: // // Check if Debug Agent has been initialized before // if (IsDebugAgentInitialzed ()) { DEBUG ((EFI_D_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n")); } mMultiProcessorDebugSupport = TRUE; // // Save original IDT table // AsmReadIdtr (&IdtDescriptor); mSaveIdtTableSize = IdtDescriptor.Limit + 1; mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *) IdtDescriptor.Base); // // Initialize Debug Timer hardware and save its initial count // mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (); // // Check if Debug Agent initialized in DXE phase // Mailbox = GetMailboxFromConfigurationTable (); if (Mailbox == NULL) { // // Try to get mailbox from GUIDed HOB build in PEI // HobList = GetHobList (); Mailbox = GetMailboxFromHob (HobList); } // // Set up IDT table and prepare for IDT entries // SetupDebugAgentEnviroment (Mailbox); // // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor() // InternalConstructorWorker (); // // Enable interrupt to receive Debug Timer interrupt // EnableInterrupts (); mDebugAgentInitialized = TRUE; FindAndReportModuleImageInfo (SIZE_4KB); *(EFI_STATUS *)Context = EFI_SUCCESS; if (gST->ConOut != NULL) { Print (L"Debug Agent: Initialized successfully!\r\n"); Print (L"If the Debug Port is serial port, please make sure this serial port isn't connected by ISA Serial driver\r\n"); Print (L"You could do the following steps to disconnect the serial port:\r\n"); Print (L"1: Shell> drivers\r\n"); Print (L" ...\r\n"); Print (L" V VERSION E G G #D #C DRIVER NAME IMAGE NAME\r\n"); Print (L" == ======== = = = == == =================================== ===================\r\n"); Print (L" 8F 0000000A B - - 1 14 PCI Bus Driver PciBusDxe\r\n"); Print (L" 91 00000010 ? - - - - ATA Bus Driver AtaBusDxe\r\n"); Print (L" ...\r\n"); Print (L" A7 0000000A B - - 1 1 ISA Serial Driver IsaSerialDxe\r\n"); Print (L" ...\r\n"); Print (L"2: Shell> dh -d A7\r\n"); Print (L" A7: Image(IsaSerialDxe) ImageDevPath (..9FB3-11D4-9A3A-0090273FC14D))DriverBinding ComponentName ComponentName2\r\n"); Print (L" Driver Name : ISA Serial Driver\r\n"); Print (L" Image Name : FvFile(93B80003-9FB3-11D4-9A3A-0090273FC14D)\r\n"); Print (L" Driver Version : 0000000A\r\n"); Print (L" Driver Type : BUS\r\n"); Print (L" Configuration : NO\r\n"); Print (L" Diagnostics : NO\r\n"); Print (L" Managing :\r\n"); Print (L" Ctrl[EA] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)\r\n"); Print (L" Child[EB] : PciRoot(0x0)/Pci(0x1F,0x0)/Serial(0x0)/Uart(115200,8,N,1)\r\n"); Print (L"3: Shell> disconnect EA\r\n"); Print (L"4: Shell> load -nc DebugAgentDxe.efi\r\n\r\n"); } break; case DEBUG_AGENT_INIT_DXE_UNLOAD: if (mDebugAgentInitialized) { if (IsHostAttached ()) { Print (L"Debug Agent: Host is still connected, please de-attach TARGET firstly!\r\n"); *(EFI_STATUS *)Context = EFI_ACCESS_DENIED; // // Enable Debug Timer interrupt again // SaveAndSetDebugTimerInterrupt (TRUE); } else { // // Restore original IDT table // AsmReadIdtr (&IdtDescriptor); IdtDescriptor.Limit = (UINT16) (mSaveIdtTableSize - 1); CopyMem ((VOID *) IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize); AsmWriteIdtr (&IdtDescriptor); FreePool (mSavedIdtTable); mDebugAgentInitialized = FALSE; *(EFI_STATUS *)Context = EFI_SUCCESS; } } else { Print (L"Debug Agent: It hasn't been initialized, cannot unload it!\r\n"); *(EFI_STATUS *)Context = EFI_NOT_STARTED; } // // Restore interrupt state. // SetInterruptState (InterruptStatus); break; case DEBUG_AGENT_INIT_DXE_CORE: mDxeCoreFlag = TRUE; mMultiProcessorDebugSupport = TRUE; // // Initialize Debug Timer hardware and its initial count // mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (); // // Try to get mailbox from GUIDed HOB build in PEI // HobList = Context; Mailbox = GetMailboxFromHob (HobList); // // Set up IDT table and prepare for IDT entries // SetupDebugAgentEnviroment (Mailbox); // // Enable interrupt to receive Debug Timer interrupt // EnableInterrupts (); break; case DEBUG_AGENT_INIT_S3: if (Context != NULL) { Ia32Idtr = (IA32_DESCRIPTOR *) Context; Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); VerifyMailboxChecksum (Mailbox); } // // Save Mailbox pointer in global variable // mMailboxPointer = Mailbox; // // Set up IDT table and prepare for IDT entries // SetupDebugAgentEnviroment (Mailbox); // // Disable interrupt // DisableInterrupts (); FindAndReportModuleImageInfo (SIZE_4KB); if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) { // // If Boot Script entry break is set, code will be break at here. // CpuBreakpoint (); } break; default: // // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this // Debug Agent library instance. // DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); CpuDeadLoop (); break; } }
/** This service of the TEMPORARY_RAM_SUPPORT_PPI that migrates temporary RAM into permanent memory. @param[in] PeiServices Pointer to the PEI Services Table. @param[in] TemporaryMemoryBase Source Address in temporary memory from which the SEC or PEIM will copy the Temporary RAM contents. @param[in] PermanentMemoryBase Destination Address in permanent memory into which the SEC or PEIM will copy the Temporary RAM contents. @param[in] CopySize Amount of memory to migrate from temporary to permanent memory. @retval EFI_SUCCESS The data was successfully returned. @retval EFI_INVALID_PARAMETER PermanentMemoryBase + CopySize > TemporaryMemoryBase when TemporaryMemoryBase > PermanentMemoryBase. **/ EFI_STATUS EFIAPI SecTemporaryRamSupport ( IN CONST EFI_PEI_SERVICES **PeiServices, IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase, IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase, IN UINTN CopySize ) { IA32_DESCRIPTOR IdtDescriptor; VOID* OldHeap; VOID* NewHeap; VOID* OldStack; VOID* NewStack; UINTN HeapSize; UINTN StackSize; HeapSize = CopySize * PcdGet8 (PcdFspHeapSizePercentage) / 100 ; StackSize = CopySize - HeapSize; OldHeap = (VOID*)(UINTN)TemporaryMemoryBase; NewHeap = (VOID*)((UINTN)PermanentMemoryBase + StackSize); OldStack = (VOID*)((UINTN)TemporaryMemoryBase + HeapSize); NewStack = (VOID*)(UINTN)PermanentMemoryBase; // // Migrate Heap // CopyMem (NewHeap, OldHeap, HeapSize); // // Migrate Stack // CopyMem (NewStack, OldStack, StackSize); // // We need *not* fix the return address because currently, // The PeiCore is executed in flash. // // // Rebase IDT table in permanent memory // AsmReadIdtr (&IdtDescriptor); IdtDescriptor.Base = IdtDescriptor.Base - (UINTN)OldStack + (UINTN)NewStack; AsmWriteIdtr (&IdtDescriptor); // // Fixed the FSP data pointer // FspDataPointerFixUp ((UINTN)NewStack - (UINTN)OldStack); // // SecSwitchStack function must be invoked after the memory migration // immediatly, also we need fixup the stack change caused by new call into // permenent memory. // SecSwitchStack ( (UINT32) (UINTN) OldStack, (UINT32) (UINTN) NewStack ); return EFI_SUCCESS; }
/** Initialize debug agent. This function is used to set up debug enviroment for source level debug in SMM code. If InitFlag is DEBUG_AGENT_INIT_SMM, it will overirde IDT table entries and initialize debug port. It will get debug agent Mailbox from GUIDed HOB, it it exists, debug agent wiil copied it into the local Mailbox in SMM space. it will overirde IDT table entries and initialize debug port. Context will be NULL. If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug Registers and get local Mailbox in SMM space. Context will be NULL. If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug Registers. Context will be NULL. @param[in] InitFlag Init flag is used to decide initialize process. @param[in] Context Context needed according to InitFlag. @param[in] Function Continue function called by debug agent library; it was optional. **/ VOID EFIAPI InitializeDebugAgent ( IN UINT32 InitFlag, IN VOID *Context, OPTIONAL IN DEBUG_AGENT_CONTINUE Function OPTIONAL ) { EFI_STATUS Status; UINT64 DebugPortHandle; IA32_IDT_GATE_DESCRIPTOR IdtEntry[33]; IA32_DESCRIPTOR IdtDescriptor; IA32_DESCRIPTOR *Ia32Idtr; IA32_IDT_ENTRY *Ia32IdtEntry; IA32_DESCRIPTOR Idtr; UINT16 IdtEntryCount; DEBUG_AGENT_MAILBOX *Mailbox; UINT64 *MailboxLocation; UINT32 DebugTimerFrequency; BOOLEAN PeriodicMode; UINTN TimerCycle; switch (InitFlag) { case DEBUG_AGENT_INIT_SMM: // // Install configuration table for persisted vector handoff info // Status = gSmst->SmmInstallConfigurationTable ( gSmst, &gEfiVectorHandoffTableGuid, (VOID *) &mVectorHandoffInfoDebugAgent[0], sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n")); CpuDeadLoop (); } // // Check if Debug Agent initialized in DXE phase // Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox); if (Status == EFI_SUCCESS && Mailbox != NULL) { VerifyMailboxChecksum (Mailbox); mMailboxPointer = Mailbox; break; } // // Check if Debug Agent initialized in SEC/PEI phase // Mailbox = GetMailboxFromHob (); if (Mailbox != NULL) { mMailboxPointer = Mailbox; break; } // // Debug Agent was not initialized before, use the local mailbox. // ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX)); Mailbox = &mLocalMailbox; // // Save original IDT entries // AsmReadIdtr (&IdtDescriptor); CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); // // Initialized Debug Agent // InitializeDebugIdt (); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL); UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle); mMailboxPointer = Mailbox; // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE); SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1); // // Memory has been ready // if (IsHostAttached ()) { // // Trigger one software interrupt to inform HOST // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } // // Find and report PE/COFF image info to HOST // FindAndReportModuleImageInfo (SIZE_4KB); // // Restore saved IDT entries // CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR)); break; case DEBUG_AGENT_INIT_ENTER_SMI: SaveDebugRegister (); if (!mSmmDebugIdtInitFlag) { // // We only need to initialize Debug IDT table at first SMI entry // after SMM relocation. // InitializeDebugIdt (); mSmmDebugIdtInitFlag = TRUE; } // // Check if CPU APIC Timer is working, otherwise initialize it. // InitializeLocalApicSoftwareEnable (TRUE); GetApicTimerState (NULL, &PeriodicMode, NULL); TimerCycle = GetApicTimerInitCount (); if (!PeriodicMode || TimerCycle == 0) { InitializeDebugTimer (NULL, FALSE); } Mailbox = GetMailboxPointer (); if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) { // // If Debug Agent has been communicaton state with HOST, we need skip // any break points set in SMM, set Skip Breakpoint flag // mSkipBreakpoint = TRUE; } if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) { if (mSkipBreakpoint) { // // Print warning message if ignore smm entry break // DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, (UINT8 *)mWarningMsgIgnoreSmmEntryBreak, AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak) ); } else { // // If SMM entry break is set, SMM code will be break at here. // CpuBreakpoint (); } } break; case DEBUG_AGENT_INIT_EXIT_SMI: Mailbox = GetMailboxPointer (); // // Clear Skip Breakpoint flag // mSkipBreakpoint = FALSE; RestoreDebugRegister (); break; case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: if (Context == NULL) { DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n")); CpuDeadLoop (); } else { Ia32Idtr = (IA32_DESCRIPTOR *) Context; Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base); MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow + (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16)); mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation); VerifyMailboxChecksum (mMailboxPointer); // // Get original IDT address and size. // AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); if (IdtEntryCount < 33) { Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); Idtr.Base = (UINTN) &mIdtEntryTable; ZeroMem (&mIdtEntryTable, Idtr.Limit + 1); AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); } InitializeDebugIdt (); // // Initialize Debug Timer hardware and save its frequency // InitializeDebugTimer (&DebugTimerFrequency, TRUE); UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency); // // Enable Debug Timer interrupt and CPU interrupt // SaveAndSetDebugTimerInterrupt (TRUE); EnableInterrupts (); FindAndReportModuleImageInfo (SIZE_4KB); } break; default: // // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this // Debug Agent library instance. // DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n")); CpuDeadLoop (); break; } }
/** 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; }