mirror of https://github.com/acidanthera/audk.git
262 lines
7.9 KiB
C
262 lines
7.9 KiB
C
|
/** @file
|
||
|
|
||
|
TDX Dxe driver. This driver is dispatched early in DXE, due to being list
|
||
|
in APRIORI.
|
||
|
|
||
|
This module is responsible for:
|
||
|
- Sets max logical cpus based on TDINFO
|
||
|
- Sets PCI PCDs based on resource hobs
|
||
|
- Alter MATD table to record address of Mailbox
|
||
|
|
||
|
Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
|
||
|
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include <Library/BaseLib.h>
|
||
|
#include <Library/BaseMemoryLib.h>
|
||
|
#include <Library/DebugLib.h>
|
||
|
#include <Library/DxeServicesTableLib.h>
|
||
|
#include <Library/MemoryAllocationLib.h>
|
||
|
#include <Library/PcdLib.h>
|
||
|
#include <Library/UefiLib.h>
|
||
|
#include <Library/HobLib.h>
|
||
|
#include <Protocol/Cpu.h>
|
||
|
#include <Library/UefiBootServicesTableLib.h>
|
||
|
#include <IndustryStandard/Tdx.h>
|
||
|
#include <Library/PlatformInitLib.h>
|
||
|
#include <Library/TdxLib.h>
|
||
|
#include <TdxAcpiTable.h>
|
||
|
#include <Library/MemEncryptTdxLib.h>
|
||
|
|
||
|
/**
|
||
|
Location of resource hob matching type and starting address
|
||
|
|
||
|
@param[in] Type The type of resource hob to locate.
|
||
|
|
||
|
@param[in] Start The resource hob must at least begin at address.
|
||
|
|
||
|
@retval pointer to resource Return pointer to a resource hob that matches or NULL.
|
||
|
**/
|
||
|
STATIC
|
||
|
EFI_HOB_RESOURCE_DESCRIPTOR *
|
||
|
GetResourceDescriptor (
|
||
|
EFI_RESOURCE_TYPE Type,
|
||
|
EFI_PHYSICAL_ADDRESS Start,
|
||
|
EFI_PHYSICAL_ADDRESS End
|
||
|
)
|
||
|
{
|
||
|
EFI_PEI_HOB_POINTERS Hob;
|
||
|
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
|
||
|
|
||
|
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
|
||
|
while (Hob.Raw != NULL) {
|
||
|
DEBUG ((
|
||
|
DEBUG_INFO,
|
||
|
"%a:%d: resource type 0x%x %llx %llx\n",
|
||
|
__func__,
|
||
|
__LINE__,
|
||
|
Hob.ResourceDescriptor->ResourceType,
|
||
|
Hob.ResourceDescriptor->PhysicalStart,
|
||
|
Hob.ResourceDescriptor->ResourceLength
|
||
|
));
|
||
|
|
||
|
if ((Hob.ResourceDescriptor->ResourceType == Type) &&
|
||
|
(Hob.ResourceDescriptor->PhysicalStart >= Start) &&
|
||
|
((Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength) < End))
|
||
|
{
|
||
|
ResourceDescriptor = Hob.ResourceDescriptor;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
||
|
Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
|
||
|
}
|
||
|
|
||
|
return ResourceDescriptor;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Location of resource hob matching type and highest address below end
|
||
|
|
||
|
@param[in] Type The type of resource hob to locate.
|
||
|
|
||
|
@param[in] End The resource hob return is the closest to the End address
|
||
|
|
||
|
@retval pointer to resource Return pointer to a resource hob that matches or NULL.
|
||
|
**/
|
||
|
STATIC
|
||
|
EFI_HOB_RESOURCE_DESCRIPTOR *
|
||
|
GetHighestResourceDescriptor (
|
||
|
EFI_RESOURCE_TYPE Type,
|
||
|
EFI_PHYSICAL_ADDRESS End
|
||
|
)
|
||
|
{
|
||
|
EFI_PEI_HOB_POINTERS Hob;
|
||
|
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceDescriptor = NULL;
|
||
|
|
||
|
Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
|
||
|
while (Hob.Raw != NULL) {
|
||
|
if ((Hob.ResourceDescriptor->ResourceType == Type) &&
|
||
|
(Hob.ResourceDescriptor->PhysicalStart < End))
|
||
|
{
|
||
|
if (!ResourceDescriptor ||
|
||
|
(ResourceDescriptor->PhysicalStart < Hob.ResourceDescriptor->PhysicalStart))
|
||
|
{
|
||
|
ResourceDescriptor = Hob.ResourceDescriptor;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
||
|
Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
|
||
|
}
|
||
|
|
||
|
return ResourceDescriptor;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Set the shared bit for mmio region in Tdx guest.
|
||
|
|
||
|
In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
|
||
|
For direct access, the shared bit of the PageTableEntry should be set.
|
||
|
The mmio region information is retrieved from hob list.
|
||
|
|
||
|
@retval EFI_SUCCESS The shared bit is set successfully.
|
||
|
@retval EFI_UNSUPPORTED Setting the shared bit of memory region
|
||
|
is not supported
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
SetMmioSharedBit (
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
EFI_PEI_HOB_POINTERS Hob;
|
||
|
|
||
|
Hob.Raw = (UINT8 *)GetHobList ();
|
||
|
|
||
|
//
|
||
|
// Parse the HOB list until end of list or matching type is found.
|
||
|
//
|
||
|
while (!END_OF_HOB_LIST (Hob)) {
|
||
|
if ( (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)
|
||
|
&& (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO))
|
||
|
{
|
||
|
MemEncryptTdxSetPageSharedBit (
|
||
|
0,
|
||
|
Hob.ResourceDescriptor->PhysicalStart,
|
||
|
EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TdxDxeEntryPoint (
|
||
|
IN EFI_HANDLE ImageHandle,
|
||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
RETURN_STATUS PcdStatus;
|
||
|
EFI_HOB_RESOURCE_DESCRIPTOR *Res = NULL;
|
||
|
EFI_HOB_RESOURCE_DESCRIPTOR *MemRes = NULL;
|
||
|
EFI_HOB_PLATFORM_INFO *PlatformInfo = NULL;
|
||
|
EFI_HOB_GUID_TYPE *GuidHob;
|
||
|
UINT32 CpuMaxLogicalProcessorNumber;
|
||
|
TD_RETURN_DATA TdReturnData;
|
||
|
EFI_EVENT QemuAcpiTableEvent;
|
||
|
void *Registration;
|
||
|
|
||
|
GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
|
||
|
|
||
|
if (GuidHob == NULL) {
|
||
|
return EFI_UNSUPPORTED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Both Td and Non-Td guest have PlatformInfoHob which contains the HostBridgePciDevId
|
||
|
//
|
||
|
PlatformInfo = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
|
||
|
ASSERT (PlatformInfo->HostBridgeDevId != 0);
|
||
|
PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
|
||
|
ASSERT_RETURN_ERROR (PcdStatus);
|
||
|
|
||
|
if (!TdIsEnabled ()) {
|
||
|
return EFI_UNSUPPORTED;
|
||
|
}
|
||
|
|
||
|
SetMmioSharedBit ();
|
||
|
|
||
|
//
|
||
|
// Call TDINFO to get actual number of cpus in domain
|
||
|
//
|
||
|
Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
|
||
|
ASSERT (Status == EFI_SUCCESS);
|
||
|
|
||
|
CpuMaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
|
||
|
|
||
|
//
|
||
|
// Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
|
||
|
// more than number of reported cpus, update.
|
||
|
//
|
||
|
if (CpuMaxLogicalProcessorNumber > TdReturnData.TdInfo.NumVcpus) {
|
||
|
PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, TdReturnData.TdInfo.NumVcpus);
|
||
|
ASSERT_RETURN_ERROR (PcdStatus);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Register for protocol notifications to call the AlterAcpiTable(),
|
||
|
// the protocol will be installed in AcpiPlatformDxe when the ACPI
|
||
|
// table provided by Qemu is ready.
|
||
|
//
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_SIGNAL,
|
||
|
TPL_CALLBACK,
|
||
|
AlterAcpiTable,
|
||
|
NULL,
|
||
|
&QemuAcpiTableEvent
|
||
|
);
|
||
|
|
||
|
Status = gBS->RegisterProtocolNotify (
|
||
|
&gQemuAcpiTableNotifyProtocolGuid,
|
||
|
QemuAcpiTableEvent,
|
||
|
&Registration
|
||
|
);
|
||
|
|
||
|
#define INIT_PCDSET(NAME, RES) do {\
|
||
|
PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
|
||
|
ASSERT_RETURN_ERROR (PcdStatus); \
|
||
|
PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
|
||
|
ASSERT_RETURN_ERROR (PcdStatus); \
|
||
|
} while(0)
|
||
|
|
||
|
if (PlatformInfo) {
|
||
|
PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgeDevId);
|
||
|
|
||
|
if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, (EFI_PHYSICAL_ADDRESS)0x100000000, (EFI_PHYSICAL_ADDRESS)-1)) != NULL) {
|
||
|
INIT_PCDSET (PcdPciMmio64, Res);
|
||
|
}
|
||
|
|
||
|
if ((Res = GetResourceDescriptor (EFI_RESOURCE_IO, 0, 0x10001)) != NULL) {
|
||
|
INIT_PCDSET (PcdPciIo, Res);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// To find low mmio, first find top of low memory, and then search for io space.
|
||
|
//
|
||
|
if ((MemRes = GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY, 0xffc00000)) != NULL) {
|
||
|
if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, MemRes->PhysicalStart, 0x100000000)) != NULL) {
|
||
|
INIT_PCDSET (PcdPciMmio32, Res);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|