From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: "Luo, Heng" <heng.luo@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Chaganty, Rangasai V" <rangasai.v.chaganty@intel.com>
Subject: Re: [PATCH 30/40] TigerlakeSiliconPkg/IpBlock: Add Vtd component
Date: Thu, 4 Feb 2021 03:56:29 +0000 [thread overview]
Message-ID: <BN6PR1101MB2147FDCAC1D42F81C11268A7CDB39@BN6PR1101MB2147.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20210201013657.1833-30-heng.luo@intel.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
> -----Original Message-----
> From: Luo, Heng <heng.luo@intel.com>
> Sent: Sunday, January 31, 2021 5:37 PM
> To: devel@edk2.groups.io
> Cc: Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone,
> Nathaniel L <nathaniel.l.desimone@intel.com>
> Subject: [PATCH 30/40] TigerlakeSiliconPkg/IpBlock: Add Vtd component
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3171
>
> Adds the following files:
> * IpBlock/Vtd/IncludePrivate
> * IpBlock/Vtd/Library
> * IpBlock/Vtd/LibraryPrivate
>
> Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Signed-off-by: Heng Luo <heng.luo@intel.com>
> ---
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVtdI
> nitLib.h | 62
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVtd
> PolicyLib.h | 67
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/VtdDataHob.h
> | 32 ++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLib/
> PeiDxeSmmVtdInfoLib.inf | 45
> +++++++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLib/
> VtdInfoLib.c | 86
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/D
> xeVtdInitLib.c | 684
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/D
> xeVtdInitLib.inf | 71
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyLib
> /DxeVtdPolicyLib.c | 90
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyLib
> /DxeVtdPolicyLib.inf | 35 +++++++++++++++++++++++++++++++++++
> 9 files changed, 1172 insertions(+)
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVt
> dInitLib.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVt
> dInitLib.h
> new file mode 100644
> index 0000000000..e439cfbac2
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVt
> dInitLib.h
> @@ -0,0 +1,62 @@
> +/** @file
>
> + Header file for DXE VTD Init Lib.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _DXE_VTD_INIT_LIB_H_
>
> +#define _DXE_VTD_INIT_LIB_H_
>
> +
>
> +#include <Uefi.h>
>
> +#include <Uefi/UefiBaseType.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/MemoryAllocationLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/HobLib.h>
>
> +#include <Library/UefiLib.h>
>
> +#include <Library/ConfigBlockLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <Library/PchCycleDecodingLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/VtdInfoLib.h>
>
> +#include <Library/SaPlatformLib.h>
>
> +#include <IndustryStandard/Acpi.h>
>
> +#include <IndustryStandard/Pci.h>
>
> +#include <VtdDataHob.h>
>
> +#include <PchConfigHob.h>
>
> +#include <PchInfoHob.h>
>
> +#include <Register/P2sbRegs.h>
>
> +#include <Register/IpuRegs.h>
>
> +#include <Register/IgdRegs.h>
>
> +#include <Register/VtdRegs.h>
>
> +#include <DmaRemappingTable.h>
>
> +#include <Protocol/AcpiSystemDescriptionTable.h>
>
> +#include <Protocol/AcpiTable.h>
>
> +#include <Protocol/SaPolicy.h>
>
> +#include <Protocol/SaNvsArea.h>
>
> +#include <Protocol/FirmwareVolume2.h>
>
> +
>
> +/**
>
> + Locate the VT-d ACPI tables data file and read ACPI SSDT tables.
>
> + Publish the appropriate SSDT based on current configuration and
> capabilities.
>
> +
>
> + @param[in] SaPolicy SA DXE Policy protocol
>
> +
>
> + @retval EFI_SUCCESS - Vtd initialization complete
>
> + @retval Other - No Vtd function initiated
>
> +**/
>
> +EFI_STATUS
>
> +VtdInit (
>
> + IN SA_POLICY_PROTOCOL *SaPolicy
>
> + );
>
> +
>
> +/**
>
> + EndOfPcieEnum routine for update DMAR
>
> +**/
>
> +VOID
>
> +UpdateDmarEndOfPcieEnum (
>
> + VOID
>
> + );
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVt
> dPolicyLib.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVt
> dPolicyLib.h
> new file mode 100644
> index 0000000000..d55cf6bc34
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/Library/DxeVt
> dPolicyLib.h
> @@ -0,0 +1,67 @@
> +/** @file
>
> + Prototype of the DXE VTD Policy Init library.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _DXE_VTD_POLICY_INIT_LIB_H_
>
> +#define _DXE_VTD_POLICY_INIT_LIB_H_
>
> +
>
> +#include <Uefi.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/UefiLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/MemoryAllocationLib.h>
>
> +#include <Protocol/SaPolicy.h>
>
> +#include <ConfigBlock.h>
>
> +#include <VtdConfig.h>
>
> +#include <Library/SiConfigBlockLib.h>
>
> +
>
> +extern EFI_GUID gVtdDxeConfigGuid;
>
> +
>
> +/**
>
> + This function Load default Vtd DXE policy.
>
> +
>
> + @param[in] ConfigBlockPointer The pointer to add VTD config block
>
> +**/
>
> +VOID
>
> +VtdLoadDefaultDxe (
>
> + IN VOID *ConfigBlockPointer
>
> + );
>
> +
>
> +/**
>
> + This function prints the DXE phase VTD policy.
>
> +
>
> + @param[in] SaPolicy - Instance of SA_POLICY_PROTOCOL
>
> +**/
>
> +VOID
>
> +VtdPrintPolicyDxe (
>
> + IN SA_POLICY_PROTOCOL *SaPolicy
>
> + );
>
> +
>
> +/**
>
> + This function is used to add VTD Config Block.
>
> +
>
> + @param[in] ConfigBlockTableAddress The pointer to add VTD config
> blocks
>
> +
>
> + @retval EFI_SUCCESS The policy default is initialized.
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create
> buffer
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +VtdAddConfigBlocksDxe (
>
> + IN VOID *ConfigBlockTableAddress
>
> + );
>
> +
>
> +/**
>
> + Get VTD DXE config block table total size.
>
> +
>
> + @retval Size of VTD DXE config block table
>
> +**/
>
> +UINT16
>
> +EFIAPI
>
> +VtdGetConfigBlockTotalSizeDxe (
>
> + VOID
>
> + );
>
> +#endif // _DXE_VTD_POLICY_INIT_LIB_H_
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/VtdDataHob.
> h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/VtdDataHob.
> h
> new file mode 100644
> index 0000000000..0f9d500af9
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/IncludePrivate/VtdDataHob.
> h
> @@ -0,0 +1,32 @@
> +/** @file
>
> + The GUID definition for Vtd Data Hob
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _VTD_DATA_HOB_H_
>
> +#define _VTD_DATA_HOB_H_
>
> +
>
> +#include <Library/VtdInfoLib.h>
>
> +#include <Base.h>
>
> +
>
> +extern EFI_GUID gVtdDataHobGuid;
>
> +
>
> +#pragma pack (push,1)
>
> +
>
> +///
>
> +/// The data elements should be initialized by a Platform Module.
>
> +/// The data structure is for VT-d driver initialization
>
> +///
>
> +typedef struct {
>
> + EFI_HOB_GUID_TYPE EfiHobGuidType; ///< GUID Hob type
> structure for gVtdDataHobGuid
>
> + BOOLEAN VtdDisable; ///< 1 = Avoids programming Vtd
> bars, Vtd overrides and DMAR table
>
> + UINT32 BaseAddress[VTD_ENGINE_NUMBER]; ///< This field is
> used to describe the base addresses for VT-d function
>
> + BOOLEAN X2ApicOptOut; ///< This field is used to enable
> the X2APIC_OPT_OUT bit in the DMAR table. <b>1=Enable/Set</b> and
> 0=Disable/Clear
>
> + BOOLEAN DmaControlGuarantee; ///< This field is used to
> enable the DMA_CONTROL_GUARANTEE bit in the DMAR table.
> <b>1=Enable/Set</b> and 0=Disable/Clear
>
> + BOOLEAN InterruptRemappingSupport; ///< This field is used to
> indicate Interrupt Remapping supported or not
>
> + UINT32 DmaBufferBase; ///< Iommu PEI DMA buffer
> base in low memory region, in Mbytes units
>
> +} VTD_DATA_HOB;
>
> +
>
> +#pragma pack (pop)
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLi
> b/PeiDxeSmmVtdInfoLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLi
> b/PeiDxeSmmVtdInfoLib.inf
> new file mode 100644
> index 0000000000..c7c5e56b84
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLi
> b/PeiDxeSmmVtdInfoLib.inf
> @@ -0,0 +1,45 @@
> +## @file
>
> +# VTD Common Library.
>
> +#
>
> +# All function in this library is available for PEI, DXE, and SMM,
>
> +# But do not support UEFI RUNTIME environment call.
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = PeiDxeSmmVtdInfoLib
>
> +FILE_GUID = A1480873-3FDA-4E90-B450-743D8031F9DE
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = BASE
>
> +LIBRARY_CLASS = VtdInfoLib
>
> +
>
> +[LibraryClasses]
>
> +BaseLib
>
> +IoLib
>
> +DebugLib
>
> +PciSegmentLib
>
> +HobLib
>
> +VtdInfoLib
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +[Sources]
>
> +VtdInfoLib.c
>
> +
>
> +[Pcd]
>
> +gSiPkgTokenSpaceGuid.VtdEngine1BaseAddeess
>
> +gSiPkgTokenSpaceGuid.VtdEngine2BaseAddeess
>
> +gSiPkgTokenSpaceGuid.VtdEngine3BaseAddeess
>
> +gSiPkgTokenSpaceGuid.VtdEngine4BaseAddeess
>
> +gSiPkgTokenSpaceGuid.VtdEngine5BaseAddeess
>
> +gSiPkgTokenSpaceGuid.VtdEngine6BaseAddeess
>
> +gSiPkgTokenSpaceGuid.VtdEngine7BaseAddeess
>
> +
>
> +[FixedPcd]
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLi
> b/VtdInfoLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLi
> b/VtdInfoLib.c
> new file mode 100644
> index 0000000000..e4f08592cc
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/Library/PeiDxeSmmVtdInfoLi
> b/VtdInfoLib.c
> @@ -0,0 +1,86 @@
> +/** @file
>
> + VTD Info library.
>
> + All function in this library is available for PEI, DXE, and SMM,
>
> + But do not support UEFI RUNTIME environment call.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include <Ppi/SiPolicy.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/BaseLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/VtdInfoLib.h>
>
> +#include <Register/VtdRegs.h>
>
> +
>
> +/**
>
> + Get VTD Engine Base Address from PCD value
>
> +
>
> + @param[in] VtdEngineNumber - Engine number for which VTD Base
> Adderess is required.
>
> +
>
> + @retval VTD Engine Base Address
>
> +**/
>
> +UINT32
>
> +GetVtdBaseAddress (
>
> + IN UINT8 VtdEngineNumber
>
> + )
>
> +{
>
> + switch (VtdEngineNumber) {
>
> + case 0:
>
> + return PcdGet32(VtdEngine1BaseAddeess);
>
> + break;
>
> + case 2:
>
> + return PcdGet32(VtdEngine3BaseAddeess);
>
> + break;
>
> + default:
>
> + return 0x0;
>
> + break;
>
> + }
>
> +}
>
> +
>
> +
>
> +/**
>
> + Read VTD Engine Base Address from VTD BAR Offsets.
>
> +
>
> + @param[in] VtdEngineNumber - Engine number for which VTD Base
> Adderess is required.
>
> +
>
> + @retval VTD Engine Base Address
>
> +**/
>
> +UINT32
>
> +ReadVtdBaseAddress (
>
> + IN UINT8 VtdEngineNumber
>
> + )
>
> +{
>
> + UINT64 McD0BaseAddress;
>
> + UINTN MchBar;
>
> +
>
> + McD0BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM,
> SA_MC_BUS, 0, 0, 0);
>
> + MchBar = PciSegmentRead32 (McD0BaseAddress + R_SA_MCHBAR) &
> (~BIT0);
>
> +
>
> + switch (VtdEngineNumber) {
>
> + case 0:
>
> + return (MmioRead32 (MchBar + R_MCHBAR_VTD1_OFFSET) & (~BIT0));
>
> + break;
>
> + case 2:
>
> + return (MmioRead32 (MchBar + R_MCHBAR_VTD3_OFFSET) & (~BIT0));
>
> + break;
>
> + default:
>
> + return 0x0;
>
> + break;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + GetMaxVtdEngineNumber: Get Maximum Vtd Engine Number
>
> +
>
> + @retval Vtd Engine Number
>
> +**/
>
> +UINT8
>
> +GetMaxVtdEngineNumber(
>
> + VOID
>
> +)
>
> +{
>
> + return (UINT8)VTD_ENGINE_NUMBER;
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/
> DxeVtdInitLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/
> DxeVtdInitLib.c
> new file mode 100644
> index 0000000000..faac07c45d
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/
> DxeVtdInitLib.c
> @@ -0,0 +1,684 @@
> +/** @file
>
> + DXE Library for VTD ACPI table initialization.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <Library/DxeVtdInitLib.h>
>
> +#include <Library/DxeVtdPolicyLib.h>
>
> +#include <Library/VtdInitFruLib.h>
>
> +#include <Register/SaRegsHostBridge.h>
>
> +
>
> +///
>
> +/// Global Variables
>
> +///
>
> +GLOBAL_REMOVE_IF_UNREFERENCED VTD_DATA_HOB *mVtdDataHob;
>
> +
>
> +BOOLEAN mInterruptRemappingSupport;
>
> +
>
> +/**
>
> + Get the corresponding device Enable/Disable bit according DevNum and
> FunNum
>
> +
>
> + @param[in] DevNum - Device Number
>
> + @param[in] FunNum - Function Number
>
> +
>
> + @retval If the device is found, return disable/Enable bit in FD/Deven
> reigster
>
> + @retval If not found return 0xFF
>
> +**/
>
> +UINT16
>
> +GetFunDisableBit (
>
> + UINT8 DevNum,
>
> + UINT8 FunNum
>
> + )
>
> +{
>
> + UINTN Index;
>
> +
>
> + for (Index = 0; Index < mDevEnMapSize; Index++) {
>
> + if (mDevEnMap[Index][0] == ((DevNum << 0x08) | FunNum)) {
>
> + return mDevEnMap[Index][1];
>
> + }
>
> + }
>
> +
>
> + return 0xFF;
>
> +}
>
> +
>
> +/**
>
> + Update the DRHD structure
>
> +
>
> + @param[in, out] DrhdEnginePtr - A pointer to DRHD structure
>
> +**/
>
> +VOID
>
> +UpdateDrhd (
>
> + IN OUT VOID *DrhdEnginePtr
>
> + )
>
> +{
>
> + UINT16 Length;
>
> + UINT16 DisableBit;
>
> + BOOLEAN NeedRemove;
>
> + EFI_ACPI_DRHD_ENGINE1_STRUCT *DrhdEngine;
>
> +
>
> + //
>
> + // Convert DrhdEnginePtr to EFI_ACPI_DRHD_ENGINE1_STRUCT Pointer
>
> + //
>
> + DrhdEngine = (EFI_ACPI_DRHD_ENGINE1_STRUCT *) DrhdEnginePtr;
>
> + Length = DrhdEngine->DrhdHeader.Header.Length;
>
> + DisableBit = GetFunDisableBit (
>
> + DrhdEngine->DeviceScope[0].PciPath.Device,
>
> + DrhdEngine->DeviceScope[0].PciPath.Function
>
> + );
>
> + NeedRemove = FALSE;
>
> +
>
> + if ((DisableBit == 0xFF) ||
>
> + (DrhdEngine->DrhdHeader.RegisterBaseAddress == 0) ||
>
> + ((DisableBit == 0x80) &&
>
> + (PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, 0,
> DrhdEngine->DeviceScope[0].PciPath.Device, DrhdEngine-
> >DeviceScope[0].PciPath.Function, 0x00)) == 0xFFFFFFFF))
>
> + ) {
>
> + NeedRemove = TRUE;
>
> + }
>
> + if ((DrhdEngine->DeviceScope[0].PciPath.Device == IGD_DEV_NUM) &&
> (DrhdEngine->DeviceScope[0].PciPath.Function == IGD_FUN_NUM) &&
>
> + (PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, 0,
> DrhdEngine->DeviceScope[0].PciPath.Device, DrhdEngine-
> >DeviceScope[0].PciPath.Function, 0x00)) != 0xFFFFFFFF)) {
>
> + NeedRemove = FALSE;
>
> + }
>
> + if (NeedRemove) {
>
> + Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
>
> + }
>
> + ///
>
> + /// If no devicescope is left, we set the structure length as 0x00
>
> + ///
>
> + if ((Length > EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) || (DrhdEngine-
> >DrhdHeader.Flags == 0x01)) {
>
> + DrhdEngine->DrhdHeader.Header.Length = Length;
>
> + } else {
>
> + DrhdEngine->DrhdHeader.Header.Length = 0;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Get IOAPIC ID from LPC
>
> +
>
> + @retval APIC ID
>
> +**/
>
> +UINT8
>
> +GetIoApicId (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 IoApicAddress;
>
> + UINT32 IoApicId;
>
> +
>
> + IoApicAddress = PcdGet32 (PcdSiIoApicBaseAddress);
>
> + ///
>
> + /// Get current IO APIC ID
>
> + ///
>
> + MmioWrite8 ((UINTN) (IoApicAddress +
> R_IO_APIC_MEM_INDEX_OFFSET), 0);
>
> + IoApicId = MmioRead32 ((UINTN) (IoApicAddress +
> R_IO_APIC_MEM_DATA_OFFSET)) >> 24;
>
> +
>
> + return (UINT8) IoApicId;
>
> +}
>
> +
>
> +/**
>
> + Update the second DRHD structure
>
> +
>
> + @param[in, out] DrhdEnginePtr - A pointer to DRHD structure
>
> +**/
>
> +VOID
>
> +UpdateDrhd2 (
>
> + IN OUT VOID *DrhdEnginePtr
>
> + )
>
> +{
>
> + UINT16 Length;
>
> + UINTN DeviceScopeNum;
>
> + UINTN ValidDeviceScopeNum;
>
> + UINT16 Index;
>
> + UINT8 Bus;
>
> + UINT8 Path[2];
>
> + BOOLEAN NeedRemove;
>
> + EFI_ACPI_DRHD_ENGINE3_STRUCT *DrhdEngine;
>
> + VOID *HobPtr;
>
> + PCH_INFO_HOB *PchInfoHob;
>
> +
>
> + ///
>
> + /// Convert DrhdEnginePtr to EFI_ACPI_DRHD_ENGINE3_STRUCT Pointer
>
> + ///
>
> + DrhdEngine = (EFI_ACPI_DRHD_ENGINE3_STRUCT *) DrhdEnginePtr;
>
> +
>
> + Length = DrhdEngine->DrhdHeader.Header.Length;
>
> + DeviceScopeNum = (DrhdEngine->DrhdHeader.Header.Length -
> EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) / sizeof
> (EFI_ACPI_DEV_SCOPE_STRUCTURE);
>
> + Bus = 0;
>
> + ValidDeviceScopeNum = 0;
>
> + Path[0] = 0;
>
> + Path[1] = 0;
>
> +
>
> + HobPtr = GetFirstGuidHob (&gPchInfoHobGuid);
>
> + ASSERT (HobPtr != NULL);
>
> + if (HobPtr == NULL) {
>
> + return;
>
> + }
>
> + PchInfoHob = (PCH_INFO_HOB *) GET_GUID_HOB_DATA (HobPtr);
>
> + ASSERT (PchInfoHob != NULL);
>
> + if (PchInfoHob == NULL) {
>
> + return;
>
> + }
>
> +
>
> + for (Index = 0; Index < DeviceScopeNum; Index++) {
>
> + NeedRemove = FALSE;
>
> + /**
>
> + For HPET and APIC, update device scope if Interrupt remapping is
> supported. remove device scope
>
> + if interrupt remapping is not supported.
>
> + - Index = 0 - IOAPIC
>
> + - Index = 1 - HPET
>
> + **/
>
> + if (mInterruptRemappingSupport) {
>
> + if (Index == 0) {
>
> + ///
>
> + /// Update source id for IoApic's device scope entry
>
> + ///
>
> + Bus = (UINT8) PchInfoHob->IoApicBusNum;
>
> + Path[0] = (UINT8) PchInfoHob->IoApicDevNum;
>
> + Path[1] = (UINT8) PchInfoHob->IoApicFuncNum;
>
> + DrhdEngine-
> >DeviceScope[Index].DeviceScopeStructureHeader.StartBusNumber = Bus;
>
> + DrhdEngine->DeviceScope[Index].PciPath.Device = Path[0];
>
> + DrhdEngine->DeviceScope[Index].PciPath.Function = Path[1];
>
> + //
>
> + // Update APIC ID
>
> + //
>
> + DrhdEngine-
> >DeviceScope[Index].DeviceScopeStructureHeader.EnumerationId =
> GetIoApicId ();
>
> + }
>
> + if (Index == 1) {
>
> + ///
>
> + /// Update source id for HPET's device scope entry
>
> + ///
>
> + Bus = (UINT8) PchInfoHob->HpetBusNum;
>
> + Path[0] = (UINT8) PchInfoHob->HpetDevNum;
>
> + Path[1] = (UINT8) PchInfoHob->HpetFuncNum;
>
> + DrhdEngine-
> >DeviceScope[Index].DeviceScopeStructureHeader.StartBusNumber = Bus;
>
> + DrhdEngine->DeviceScope[Index].PciPath.Device = Path[0];
>
> + DrhdEngine->DeviceScope[Index].PciPath.Function = Path[1];
>
> + }
>
> + } else {
>
> + if ((Index == 0) || (Index == 1)) {
>
> + NeedRemove = TRUE;
>
> + }
>
> + }
>
> +
>
> + CopyMem (
>
> + &DrhdEngine->DeviceScope[ValidDeviceScopeNum],
>
> + &DrhdEngine->DeviceScope[Index],
>
> + sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE)
>
> + );
>
> + if (NeedRemove) {
>
> + Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
>
> + } else {
>
> + ValidDeviceScopeNum++;
>
> + }
>
> + }
>
> + ///
>
> + /// If no devicescope is left, we set the structure length as 0x00
>
> + ///
>
> + if ((Length > EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) || (DrhdEngine-
> >DrhdHeader.Flags == 0x01)) {
>
> + DrhdEngine->DrhdHeader.Header.Length = Length;
>
> + } else {
>
> + DrhdEngine->DrhdHeader.Header.Length = 0;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Update the RMRR structure
>
> +
>
> + @param[in, out] RmrrPtr - A pointer to RMRR structure
>
> +**/
>
> +VOID
>
> +UpdateRmrr (
>
> + IN OUT VOID *RmrrPtr
>
> + )
>
> +{
>
> + UINT16 Length;
>
> + UINT16 DisableBit;
>
> + UINTN DeviceScopeNum;
>
> + UINTN ValidDeviceScopeNum;
>
> + UINTN Index;
>
> + BOOLEAN NeedRemove;
>
> + EFI_ACPI_RMRR_USB_STRUC *Rmrr;
>
> +
>
> + ///
>
> + /// To make sure all devicescope can be checked,
>
> + /// we convert the RmrrPtr to EFI_ACPI_RMRR_USB_STRUC pointer
>
> + ///
>
> + Rmrr = (EFI_ACPI_RMRR_USB_STRUC *) RmrrPtr;
>
> +
>
> + Length = Rmrr->RmrrHeader.Header.Length;
>
> + ValidDeviceScopeNum = 0;
>
> + DeviceScopeNum = (Rmrr->RmrrHeader.Header.Length -
> EFI_ACPI_RMRR_HEADER_LENGTH) / sizeof
> (EFI_ACPI_DEV_SCOPE_STRUCTURE);
>
> + for (Index = 0; Index < DeviceScopeNum; Index++) {
>
> + DisableBit = GetFunDisableBit (
>
> + Rmrr->DeviceScope[Index].PciPath.Device,
>
> + Rmrr->DeviceScope[Index].PciPath.Function
>
> + );
>
> + NeedRemove = FALSE;
>
> + if ((DisableBit == 0xFF) ||
>
> + ((DisableBit == 0x80) &&
>
> + (PciSegmentRead32 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, 0,
> Rmrr->DeviceScope[Index].PciPath.Device, Rmrr-
> >DeviceScope[Index].PciPath.Function, 0x00)) == 0xFFFFFFFF))
>
> + ) {
>
> + NeedRemove = TRUE;
>
> + } else if (DisableBit == 0x8F) {
>
> + DEBUG ((DEBUG_ERROR, "Rmrr-
> >RmrrHeader.ReservedMemoryRegionBaseAddress %x\n", Rmrr-
> >RmrrHeader.ReservedMemoryRegionBaseAddress));
>
> +
>
> + if (Rmrr->RmrrHeader.ReservedMemoryRegionBaseAddress != 0) {
>
> + DEBUG ((DEBUG_ERROR, "NeedRemove = FALSE\n"));
>
> + NeedRemove = FALSE;
>
> + } else {
>
> + DEBUG ((DEBUG_ERROR, "NeedRemove = TRUE\n"));
>
> + NeedRemove = TRUE;
>
> + }
>
> + }
>
> + CopyMem (
>
> + &Rmrr->DeviceScope[ValidDeviceScopeNum],
>
> + &Rmrr->DeviceScope[Index],
>
> + sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE)
>
> + );
>
> +
>
> + if (Rmrr->RmrrHeader.ReservedMemoryRegionLimitAddress == 0x0) {
>
> + NeedRemove = TRUE;
>
> + }
>
> +
>
> + if (NeedRemove) {
>
> + Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE);
>
> + } else {
>
> + ValidDeviceScopeNum++;
>
> + }
>
> + }
>
> + ///
>
> + /// If No deviceScope is left, set length as 0x00
>
> + ///
>
> + if (Length > EFI_ACPI_RMRR_HEADER_LENGTH) {
>
> + Rmrr->RmrrHeader.Header.Length = Length;
>
> + } else {
>
> + Rmrr->RmrrHeader.Header.Length = 0;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Update the DMAR table
>
> +
>
> + @param[in, out] TableHeader - The table to be set
>
> + @param[in, out] Version - Version to publish
>
> +**/
>
> +VOID
>
> +DmarTableUpdate (
>
> + IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader,
>
> + IN OUT EFI_ACPI_TABLE_VERSION *Version
>
> + )
>
> +{
>
> + EFI_ACPI_DMAR_TABLE *DmarTable;
>
> + EFI_ACPI_DMAR_TABLE TempDmarTable;
>
> + UINTN Offset;
>
> + UINTN StructureLen;
>
> + UINT64 McD0BaseAddress;
>
> + UINT32 GttMmAdr;
>
> + UINT64 McD2BaseAddress;
>
> + UINT16 IgdMode;
>
> + UINT16 GttMode;
>
> + UINT32 IgdMemSize;
>
> + UINT32 GttMemSize;
>
> + EFI_STATUS Status;
>
> + VTD_DXE_CONFIG *VtdDxeConfig;
>
> + SA_POLICY_PROTOCOL *SaPolicy;
>
> +
>
> +
>
> + IgdMemSize = 0;
>
> + GttMemSize = 0;
>
> + DmarTable = (EFI_ACPI_DMAR_TABLE *) TableHeader;
>
> +
>
> + Status = gBS->LocateProtocol (&gSaPolicyProtocolGuid, NULL, (VOID **)
> &SaPolicy);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = GetConfigBlock ((VOID *) SaPolicy, &gVtdDxeConfigGuid, (VOID
> *)&VtdDxeConfig);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// Set INTR_REMAP bit (BIT 0) if interrupt remapping is supported
>
> + ///
>
> + if (mInterruptRemappingSupport) {
>
> + DmarTable->DmarHeader.Flags |= BIT0;
>
> + }
>
> +
>
> + if (mVtdDataHob->X2ApicOptOut == 1) {
>
> + DmarTable->DmarHeader.Flags |= BIT1;
>
> + } else {
>
> + DmarTable->DmarHeader.Flags &= 0xFD;
>
> + }
>
> +
>
> + ///
>
> + /// Set DMA_CONTROL_GUARANTEE bit (BIT 2) if Dma Control Guarantee
> is supported
>
> + ///
>
> + if (mVtdDataHob->DmaControlGuarantee == 1) {
>
> + DmarTable->DmarHeader.Flags |= BIT2;
>
> + }
>
> + ///
>
> + /// Get OemId
>
> + ///
>
> + CopyMem (DmarTable->DmarHeader.Header.OemId, PcdGetPtr
> (PcdAcpiDefaultOemId), sizeof (DmarTable->DmarHeader.Header.OemId));
>
> + DmarTable->DmarHeader.Header.OemTableId = PcdGet64
> (PcdAcpiDefaultOemTableId);
>
> + DmarTable->DmarHeader.Header.OemRevision = PcdGet32
> (PcdAcpiDefaultOemRevision);
>
> + DmarTable->DmarHeader.Header.CreatorId = PcdGet32
> (PcdAcpiDefaultCreatorId);
>
> + DmarTable->DmarHeader.Header.CreatorRevision = PcdGet32
> (PcdAcpiDefaultCreatorRevision);
>
> +
>
> + ///
>
> + /// Calculate IGD memsize
>
> + ///
>
> + McD0BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM,
> SA_MC_BUS, 0, 0, 0);
>
> + IgdMode = ((PciSegmentRead16 (McD0BaseAddress + R_SA_GGC) &
> B_SA_GGC_GMS_MASK) >> N_SA_GGC_GMS_OFFSET) & 0xFF;
>
> + if (IgdMode < 0xF0) {
>
> + IgdMemSize = IgdMode * 32 * (1024) * (1024);
>
> + } else {
>
> + IgdMemSize = 4 * (IgdMode - 0xF0 + 1) * (1024) * (1024);
>
> + }
>
> + ///
>
> + /// Calculate GTT mem size
>
> + ///
>
> + GttMemSize = 0;
>
> + GttMode = (PciSegmentRead16 (McD0BaseAddress + R_SA_GGC) &
> B_SA_GGC_GGMS_MASK) >> N_SA_GGC_GGMS_OFFSET;
>
> + if (GttMode <= V_SA_GGC_GGMS_8MB) {
>
> + GttMemSize = (1 << GttMode) * (1024) * (1024);
>
> + }
>
> +
>
> + McD2BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM,
> IGD_BUS_NUM, IGD_DEV_NUM, IGD_FUN_NUM, 0);
>
> + GttMmAdr = (PciSegmentRead32 (McD2BaseAddress +
> R_SA_IGD_GTTMMADR)) & 0xFFFFFFF0;
>
> +
>
> + DmarTable->RmrrIgd.RmrrHeader.ReservedMemoryRegionBaseAddress
> = (PciSegmentRead32 (McD0BaseAddress + R_SA_BGSM) & ~(0x01));
>
> + DmarTable->RmrrIgd.RmrrHeader.ReservedMemoryRegionLimitAddress
> = DmarTable->RmrrIgd.RmrrHeader.ReservedMemoryRegionBaseAddress +
> IgdMemSize + GttMemSize - 1;
>
> + DEBUG ((DEBUG_INFO, "RMRR Base address IGD %016lX\n", DmarTable-
> >RmrrIgd.RmrrHeader.ReservedMemoryRegionBaseAddress));
>
> + DEBUG ((DEBUG_INFO, "RMRR Limit address IGD %016lX\n", DmarTable-
> >RmrrIgd.RmrrHeader.ReservedMemoryRegionLimitAddress));
>
> +
>
> + ///
>
> + /// Update DRHD structures of DmarTable
>
> + ///
>
> + DmarTable->DrhdEngine1.DrhdHeader.RegisterBaseAddress =
> ReadVtdBaseAddress(0);
>
> + DmarTable->DrhdEngine3.DrhdHeader.RegisterBaseAddress =
> ReadVtdBaseAddress (2);
>
> +
>
> + DEBUG ((DEBUG_INFO, "VTD base address 1 = %x\n", DmarTable-
> >DrhdEngine1.DrhdHeader.RegisterBaseAddress));
>
> + DEBUG ((DEBUG_INFO, "VTD base address 3 = %x\n", DmarTable-
> >DrhdEngine3.DrhdHeader.RegisterBaseAddress));
>
> + ///
>
> + /// copy DmarTable to TempDmarTable to be processed
>
> + ///
>
> + CopyMem (&TempDmarTable, DmarTable, sizeof
> (EFI_ACPI_DMAR_TABLE));
>
> +
>
> + ///
>
> + /// Update DRHD structures of temp DMAR table
>
> + ///
>
> + UpdateDrhd (&TempDmarTable.DrhdEngine1);
>
> + UpdateDrhd2 (&TempDmarTable.DrhdEngine3);
>
> +
>
> + ///
>
> + /// Remove unused device scope or entire DRHD structures
>
> + ///
>
> + Offset = (UINTN) (&TempDmarTable.DrhdEngine1);
>
> + if (TempDmarTable.DrhdEngine1.DrhdHeader.Header.Length != 0) {
>
> + Offset += TempDmarTable.DrhdEngine1.DrhdHeader.Header.Length;
>
> + }
>
> + if (TempDmarTable.DrhdEngine3.DrhdHeader.Header.Length != 0) {
>
> + StructureLen =
> TempDmarTable.DrhdEngine3.DrhdHeader.Header.Length;
>
> + CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.DrhdEngine3,
> TempDmarTable.DrhdEngine3.DrhdHeader.Header.Length);
>
> + Offset += StructureLen;
>
> + }
>
> + ///
>
> + /// Remove unused device scope or entire RMRR structures
>
> + ///
>
> + if (TempDmarTable.RmrrIgd.RmrrHeader.Header.Length != 0) {
>
> + StructureLen = TempDmarTable.RmrrIgd.RmrrHeader.Header.Length;
>
> + CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.RmrrIgd,
> TempDmarTable.RmrrIgd.RmrrHeader.Header.Length);
>
> + Offset += StructureLen;
>
> + }
>
> + Offset = Offset - (UINTN) &TempDmarTable;
>
> + ///
>
> + /// Re-calculate DMAR table check sum
>
> + ///
>
> + TempDmarTable.DmarHeader.Header.Checksum = (UINT8)
> (TempDmarTable.DmarHeader.Header.Checksum +
> TempDmarTable.DmarHeader.Header.Length - Offset);
>
> + ///
>
> + /// Set DMAR table length
>
> + ///
>
> + TempDmarTable.DmarHeader.Header.Length = (UINT32) Offset;
>
> + ///
>
> + /// Replace DMAR table with rebuilt table TempDmarTable
>
> + ///
>
> + CopyMem ((VOID *) DmarTable, (VOID *) &TempDmarTable,
> TempDmarTable.DmarHeader.Header.Length);
>
> +}
>
> +
>
> +/**
>
> + EndOfPcieEnumration routine for update DMAR
>
> +**/
>
> +VOID
>
> +UpdateDmarEndOfPcieEnum (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_HANDLE *HandleBuffer;
>
> + UINTN NumberOfHandles;
>
> + EFI_FV_FILETYPE FileType;
>
> + UINT32 FvStatus;
>
> + EFI_FV_FILE_ATTRIBUTES Attributes;
>
> + UINTN Size;
>
> + UINTN i;
>
> + INTN Instance;
>
> + EFI_ACPI_TABLE_VERSION Version;
>
> + EFI_ACPI_COMMON_HEADER *CurrentTable;
>
> + UINTN AcpiTableHandle;
>
> + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
>
> + EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
>
> + EFI_ACPI_DESCRIPTION_HEADER *VtdAcpiTable;
>
> + STATIC BOOLEAN Triggered = FALSE;
>
> +
>
> +
>
> + if (Triggered) {
>
> + return;
>
> + }
>
> +
>
> + Triggered = TRUE;
>
> +
>
> + FwVol = NULL;
>
> + AcpiTable = NULL;
>
> + VtdAcpiTable = NULL;
>
> +
>
> + DEBUG ((DEBUG_INFO, "UpdateDmarEndOfPcieEnum \n"));
>
> +
>
> +
>
> + ///
>
> + /// Fix DMAR Table always created, skip install when disabled
>
> + ///
>
> + if ((mVtdDataHob->VtdDisable == TRUE) || (PciSegmentRead32
> (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, 0, 0,
> R_SA_MC_CAPID0_A_OFFSET)) & BIT23)) {
>
> + DEBUG ((DEBUG_INFO, "Vtd Disabled, skip DMAR Table install\n"));
>
> + return;
>
> + }
>
> +
>
> +
>
> + ///
>
> + /// Locate ACPI support protocol
>
> + ///
>
> + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID
> **) &AcpiTable);
>
> +
>
> + ///
>
> + /// Locate protocol.
>
> + /// There is little chance we can't find an FV protocol
>
> + ///
>
> + Status = gBS->LocateHandleBuffer (
>
> + ByProtocol,
>
> + &gEfiFirmwareVolume2ProtocolGuid,
>
> + NULL,
>
> + &NumberOfHandles,
>
> + &HandleBuffer
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// Looking for FV with ACPI storage file
>
> + ///
>
> + for (i = 0; i < NumberOfHandles; i++) {
>
> + ///
>
> + /// Get the protocol on this handle
>
> + /// This should not fail because of LocateHandleBuffer
>
> + ///
>
> + Status = gBS->HandleProtocol (
>
> + HandleBuffer[i],
>
> + &gEfiFirmwareVolume2ProtocolGuid,
>
> + (VOID **) &FwVol
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// See if it has the ACPI storage file
>
> + ///
>
> + Size = 0;
>
> + FvStatus = 0;
>
> + Status = FwVol->ReadFile (
>
> + FwVol,
>
> + &gSaAcpiTableStorageGuid,
>
> + NULL,
>
> + &Size,
>
> + &FileType,
>
> + &Attributes,
>
> + &FvStatus
>
> + );
>
> +
>
> + ///
>
> + /// If we found it, then we are done
>
> + ///
>
> + if (Status == EFI_SUCCESS) {
>
> + break;
>
> + }
>
> + }
>
> + ///
>
> + /// Our exit status is determined by the success of the previous operations
>
> + /// If the protocol was found, Instance already points to it.
>
> + ///
>
> + ///
>
> + /// Free any allocated buffers
>
> + ///
>
> + FreePool (HandleBuffer);
>
> +
>
> + ///
>
> + /// Sanity check that we found our data file
>
> + ///
>
> + ASSERT (FwVol);
>
> + if (FwVol == NULL) {
>
> + return;
>
> + }
>
> + ///
>
> + /// By default, a table belongs in all ACPI table versions published.
>
> + ///
>
> + Version = EFI_ACPI_TABLE_VERSION_1_0B |
> EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
>
> +
>
> + ///
>
> + /// Read tables from the storage file.
>
> + ///
>
> + Instance = 0;
>
> + CurrentTable = NULL;
>
> +
>
> + while (Status == EFI_SUCCESS) {
>
> + Status = FwVol->ReadSection (
>
> + FwVol,
>
> + &gSaAcpiTableStorageGuid,
>
> + EFI_SECTION_RAW,
>
> + Instance,
>
> + (VOID **) &CurrentTable,
>
> + &Size,
>
> + &FvStatus
>
> + );
>
> +
>
> + if (!EFI_ERROR (Status)) {
>
> + ///
>
> + /// Check the Signature ID to modify the table
>
> + ///
>
> + if ((CurrentTable != NULL) && ((EFI_ACPI_DESCRIPTION_HEADER *)
> CurrentTable)->Signature == EFI_ACPI_VTD_DMAR_TABLE_SIGNATURE) {
>
> + VtdAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable;
>
> + DmarTableUpdate (VtdAcpiTable, &Version);
>
> + break;
>
> + }
>
> + ///
>
> + /// Increment the instance
>
> + ///
>
> + Instance++;
>
> + if (CurrentTable != NULL) {
>
> + gBS->FreePool (CurrentTable);
>
> + CurrentTable = NULL;
>
> + }
>
> + }
>
> + }
>
> + ///
>
> + /// Update the VTD table in the ACPI tables.
>
> + ///
>
> + AcpiTableHandle = 0;
>
> + if (VtdAcpiTable != NULL) {
>
> + Status = AcpiTable->InstallAcpiTable (
>
> + AcpiTable,
>
> + VtdAcpiTable,
>
> + VtdAcpiTable->Length,
>
> + &AcpiTableHandle
>
> + );
>
> + FreePool (VtdAcpiTable);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Locate the VT-d ACPI tables data file and read ACPI SSDT tables.
>
> + Publish the appropriate SSDT based on current configuration and
> capabilities.
>
> +
>
> + @param[in] SaPolicy - SA DXE Policy protocol
>
> +
>
> + @retval EFI_SUCCESS - Vtd initialization complete
>
> + @exception EFI_UNSUPPORTED - Vtd is not enabled by policy
>
> +**/
>
> +EFI_STATUS
>
> +VtdInit (
>
> + IN SA_POLICY_PROTOCOL *SaPolicy
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT64 McD0BaseAddress;
>
> + UINT64 McD2BaseAddress;
>
> + SYSTEM_AGENT_NVS_AREA_PROTOCOL *SaNvsAreaProtocol;
>
> + UINT8 Index;
>
> +
>
> + mInterruptRemappingSupport = FALSE;
>
> + mVtdDataHob = NULL;
>
> + mVtdDataHob = GetFirstGuidHob(&gVtdDataHobGuid);
>
> + if (mVtdDataHob != NULL) {
>
> + mInterruptRemappingSupport = mVtdDataHob-
> >InterruptRemappingSupport;
>
> + }
>
> +
>
> + ///
>
> + /// Locate the SA Global NVS Protocol.
>
> + ///
>
> + Status = gBS->LocateProtocol (
>
> + &gSaNvsAreaProtocolGuid,
>
> + NULL,
>
> + (VOID **) &SaNvsAreaProtocol
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> +
>
> + McD0BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM,
> SA_MC_BUS, 0, 0, 0);
>
> + McD2BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM,
> IGD_BUS_NUM, IGD_DEV_NUM, IGD_FUN_NUM, 0);
>
> +
>
> + if (mVtdDataHob != NULL) {
>
> + SaNvsAreaProtocol->Area->VtdDisable = mVtdDataHob->VtdDisable;
>
> + }
>
> +
>
> + for (Index = 0; Index < VTD_ENGINE_NUMBER; Index++) {
>
> + SaNvsAreaProtocol->Area->VtdBaseAddress[Index] =
> ReadVtdBaseAddress (Index);
>
> + }
>
> + SaNvsAreaProtocol->Area->VtdEngine1Vid =
> PciSegmentRead16(McD2BaseAddress + PCI_VENDOR_ID_OFFSET);
>
> +
>
> + if (mVtdDataHob != NULL) {
>
> + if ((mVtdDataHob->VtdDisable) || (PciSegmentRead32
> (McD0BaseAddress + R_SA_MC_CAPID0_A_OFFSET) & BIT23)) {
>
> + DEBUG ((DEBUG_WARN, "VTd disabled or no capability!\n"));
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> + }
>
> + ///
>
> + /// Check SA supports VTD and VTD is enabled in setup menu
>
> + ///
>
> + DEBUG ((DEBUG_INFO, "VTd enabled\n"));
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/
> DxeVtdInitLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/
> DxeVtdInitLib.inf
> new file mode 100644
> index 0000000000..9797c31cc6
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdInitLib/
> DxeVtdInitLib.inf
> @@ -0,0 +1,71 @@
> +## @file
>
> +# Component description file for the Dxe VTD Init library.
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = DxeVtdInitLib
>
> +FILE_GUID = 9BD11E68-923C-424C-A278-716084B4C931
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = DXE_DRIVER
>
> +LIBRARY_CLASS = DxeVtdInitLib
>
> +
>
> +[LibraryClasses]
>
> +UefiLib
>
> +UefiRuntimeServicesTableLib
>
> +UefiBootServicesTableLib
>
> +DebugLib
>
> +PostCodeLib
>
> +ConfigBlockLib
>
> +HobLib
>
> +IoLib
>
> +PciSegmentLib
>
> +BaseMemoryLib
>
> +MemoryAllocationLib
>
> +MmPciLib
>
> +VtdInfoLib
>
> +PchInfoLib
>
> +PchCycleDecodingLib
>
> +SaPlatformLib
>
> +DxeVtdInitFruLib
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +[Sources]
>
> +DxeVtdInitLib.c
>
> +
>
> +[Pcd]
>
> +gSiPkgTokenSpaceGuid.PcdSiIoApicBaseAddress
>
> +gSiPkgTokenSpaceGuid.PcdAcpiDefaultOemId
>
> +gSiPkgTokenSpaceGuid.PcdAcpiDefaultOemTableId
>
> +gSiPkgTokenSpaceGuid.PcdAcpiDefaultOemRevision
>
> +gSiPkgTokenSpaceGuid.PcdAcpiDefaultCreatorId
>
> +gSiPkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision
>
> +
>
> +[FixedPcd]
>
> +
>
> +[Guids]
>
> +gPchInfoHobGuid ## CONSUMES
>
> +gSaAcpiTableStorageGuid
>
> +gVtdDataHobGuid
>
> +gVtdDxeConfigGuid
>
> +
>
> +[Protocols]
>
> +gSaPolicyProtocolGuid ## CONSUMES
>
> +gSaNvsAreaProtocolGuid ## CONSUMES
>
> +gEfiFirmwareVolume2ProtocolGuid
>
> +gEfiAcpiTableProtocolGuid
>
> +
>
> +[Depex]
>
> +gEfiAcpiTableProtocolGuid AND
>
> +gEfiFirmwareVolume2ProtocolGuid AND
>
> +gSaPolicyProtocolGuid AND
>
> +gEfiPciRootBridgeIoProtocolGuid AND
>
> +gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure
> that PCI MMIO resource has been prepared and available for this driver to
> allocate.
>
> +gEfiHiiDatabaseProtocolGuid
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyLi
> b/DxeVtdPolicyLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyL
> ib/DxeVtdPolicyLib.c
> new file mode 100644
> index 0000000000..168de0c0a9
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyL
> ib/DxeVtdPolicyLib.c
> @@ -0,0 +1,90 @@
> +/** @file
>
> + This file provides services for DXE VTD policy default initialization
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include <Library/DxeVtdPolicyLib.h>
>
> +
>
> +/**
>
> + This function prints the DXE phase VTD policy.
>
> +
>
> + @param[in] SaPolicy - Instance of SA_POLICY_PROTOCOL
>
> +**/
>
> +VOID
>
> +VtdPrintPolicyDxe (
>
> + IN SA_POLICY_PROTOCOL *SaPolicy
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + VTD_DXE_CONFIG *VtdDxeConfig;
>
> +
>
> + //
>
> + // Get requisite IP Config Blocks which needs to be used here
>
> + //
>
> + Status = GetConfigBlock ((VOID *) SaPolicy, &gVtdDxeConfigGuid, (VOID
> *)&VtdDxeConfig);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + DEBUG_CODE_BEGIN ();
>
> + DEBUG ((DEBUG_INFO, "\n------------------------ Vtd Policy (DXE) print
> BEGIN -----------------\n"));
>
> + DEBUG ((DEBUG_INFO, " Revision : %d\n", VtdDxeConfig-
> >Header.Revision));
>
> + ASSERT (VtdDxeConfig->Header.Revision ==
> VTD_DXE_CONFIG_REVISION);
>
> + DEBUG ((DEBUG_INFO, "\n------------------------ Vtd Policy (DXE) print END -
> ----------------\n"));
>
> + DEBUG_CODE_END ();
>
> + return;
>
> +}
>
> +
>
> +/**
>
> + This function Load default Vtd DXE policy.
>
> +
>
> + @param[in] ConfigBlockPointer The pointer to add VTD config block
>
> +**/
>
> +VOID
>
> +VtdLoadDefaultDxe (
>
> + IN VOID *ConfigBlockPointer
>
> + )
>
> +{
>
> + VTD_DXE_CONFIG *VtdDxeConfig;
>
> +
>
> + VtdDxeConfig = ConfigBlockPointer;
>
> + DEBUG ((DEBUG_INFO, "VtdDxeConfig->Header.GuidHob.Name = %g\n",
> &VtdDxeConfig->Header.GuidHob.Name));
>
> + DEBUG ((DEBUG_INFO, "VtdDxeConfig-
> >Header.GuidHob.Header.HobLength = 0x%x\n", VtdDxeConfig-
> >Header.GuidHob.Header.HobLength));
>
> +}
>
> +
>
> +static COMPONENT_BLOCK_ENTRY mVtdDxeIpBlock = {
>
> + &gVtdDxeConfigGuid, sizeof (VTD_DXE_CONFIG),
> VTD_DXE_CONFIG_REVISION, VtdLoadDefaultDxe
>
> +};
>
> +
>
> +/**
>
> + Get VTD DXE config block table total size.
>
> +
>
> + @retval Size of VTD DXE config block table
>
> +**/
>
> +UINT16
>
> +EFIAPI
>
> +VtdGetConfigBlockTotalSizeDxe (
>
> + VOID
>
> + )
>
> +{
>
> + return mVtdDxeIpBlock.Size;
>
> +}
>
> +
>
> +/**
>
> + VtdAddConfigBlocks add VTD DXE config block.
>
> +
>
> + @param[in] ConfigBlockTableAddress The pointer to add VTD config
> blocks
>
> +
>
> + @retval EFI_SUCCESS The policy default is initialized.
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create
> buffer
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +VtdAddConfigBlocksDxe (
>
> + IN VOID *ConfigBlockTableAddress
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + Status = AddComponentConfigBlocks (ConfigBlockTableAddress,
> &mVtdDxeIpBlock, 1);
>
> + return Status;
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyLi
> b/DxeVtdPolicyLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyL
> ib/DxeVtdPolicyLib.inf
> new file mode 100644
> index 0000000000..1fe288416a
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/Vtd/LibraryPrivate/DxeVtdPolicyL
> ib/DxeVtdPolicyLib.inf
> @@ -0,0 +1,35 @@
> +## @file
>
> +# Component description file for the DxeVtdPolicy library.
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = DxeVtdPolicyLib
>
> +FILE_GUID = 54754C6D-4883-4B67-BBBA-49D241539BE7
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = BASE
>
> +LIBRARY_CLASS = DxeVtdPolicyLib
>
> +
>
> +[LibraryClasses]
>
> +BaseMemoryLib
>
> +UefiRuntimeServicesTableLib
>
> +UefiBootServicesTableLib
>
> +DebugLib
>
> +PostCodeLib
>
> +ConfigBlockLib
>
> +HobLib
>
> +SiConfigBlockLib
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +[Sources]
>
> +DxeVtdPolicyLib.c
>
> +
>
> +[Guids]
>
> +gVtdDxeConfigGuid
>
> --
> 2.24.0.windows.2
next prev parent reply other threads:[~2021-02-04 3:56 UTC|newest]
Thread overview: 81+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-01 1:36 [PATCH 01/40] TigerlakeSiliconPkg: Add package and Include/ConfigBlock headers Heng Luo
2021-02-01 1:36 ` [PATCH 02/40] TigerlakeSiliconPkg/Include: Add Library, PPI and Protocol include headers Heng Luo
2021-02-04 3:51 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 03/40] TigerlakeSiliconPkg/Include: Add Pins, Register and other " Heng Luo
2021-02-04 3:52 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 04/40] TigerlakeSiliconPkg/Cpu: Add Include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 05/40] TigerlakeSiliconPkg/Pch: Add include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 06/40] TigerlakeSiliconPkg/Pch: Add IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 07/40] TigerlakeSiliconPkg/SystemAgent: Add include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 08/40] TigerlakeSiliconPkg/SystemAgent: Add IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 09/40] TigerlakeSiliconPkg/Fru: Add TglCpu/Include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 10/40] TigerlakeSiliconPkg/Fru: Add TglCpu/IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 11/40] TigerlakeSiliconPkg/Fru: Add TglPch/Include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 12/40] TigerlakeSiliconPkg/Fru: Add TglPch/IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 13/40] TigerlakeSiliconPkg/IpBlock: Add Cnvi component Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 14/40] TigerlakeSiliconPkg/IpBlock: Add CpuPcieRp component Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 15/40] TigerlakeSiliconPkg/IpBlock: Add Espi component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 16/40] TigerlakeSiliconPkg/IpBlock: Add Gbe component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 17/40] TigerlakeSiliconPkg/IpBlock: Add Gpio component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 18/40] TigerlakeSiliconPkg/IpBlock: Add Graphics component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 19/40] TigerlakeSiliconPkg/IpBlock: Add Hda component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 20/40] TigerlakeSiliconPkg/IpBlock: Add HostBridge component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 21/40] TigerlakeSiliconPkg/IpBlock: Add P2sb component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 22/40] TigerlakeSiliconPkg/IpBlock: Add PchDmi component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 23/40] TigerlakeSiliconPkg/IpBlock: Add PcieRp component Heng Luo
2021-02-04 3:55 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 24/40] TigerlakeSiliconPkg/IpBlock: Add Pmc component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 25/40] TigerlakeSiliconPkg/IpBlock: Add Psf component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 26/40] TigerlakeSiliconPkg/IpBlock: Add Sata component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 27/40] TigerlakeSiliconPkg/IpBlock: Add SerialIo component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 28/40] TigerlakeSiliconPkg/IpBlock: Add Smbus component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 29/40] TigerlakeSiliconPkg/IpBlock: Add Spi component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 30/40] TigerlakeSiliconPkg/IpBlock: Add Vtd component Heng Luo
2021-02-04 3:56 ` Nate DeSimone [this message]
2021-02-01 1:36 ` [PATCH 31/40] TigerlakeSiliconPkg/Library: Add package common library instances Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 32/40] TigerlakeSiliconPkg/Pch: Add Pch " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 33/40] TigerlakeSiliconPkg/Pch: Add Pch private " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 34/40] TigerlakeSiliconPkg/SystemAgent: Add Acpi Tables and " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 35/40] TigerlakeSiliconPkg/Fru/TglCpu: Add CpuPcieRp and Vtd " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 37/40] TigerlakeSiliconPkg/SystemAgent: Add SystemAgent modules Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 38/40] TigerlakeSiliconPkg/Fru: Add Fru DSC files Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 39/40] TigerlakeSiliconPkg: Add package " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 40/40] Maintainers.txt: Add TigerlakeSiliconPkg maintainers Heng Luo
2021-02-04 3:51 ` Nate DeSimone
2021-02-04 8:24 ` Heng Luo
2021-02-04 3:51 ` [PATCH 01/40] TigerlakeSiliconPkg: Add package and Include/ConfigBlock headers Nate DeSimone
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=BN6PR1101MB2147FDCAC1D42F81C11268A7CDB39@BN6PR1101MB2147.namprd11.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox