/** Get Protected mode code segment from current GDT table. @return Protected mode code segment value. **/ UINT16 GetProtectedModeCS ( VOID ) { IA32_DESCRIPTOR GdtrDesc; IA32_SEGMENT_DESCRIPTOR *GdtEntry; UINTN GdtEntryCount; UINT16 Index; Index = (UINT16) -1; AsmReadGdtr (&GdtrDesc); GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR); GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base; for (Index = 0; Index < GdtEntryCount; Index++) { if (GdtEntry->Bits.L == 0) { if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) { break; } } GdtEntry++; } ASSERT (Index != -1); return Index * 8; }
/** 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; } }
/** 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); }
/** 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 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; }