acpidump: dump AMD IVRS table describing IOMMU layout

(cherry picked from commit 6d789b6126)
This commit is contained in:
Konstantin Belousov 2024-04-01 02:30:37 +03:00
parent f7fd7f8b88
commit f95a254aa7

View file

@ -36,6 +36,7 @@
#include <err.h>
#include <fcntl.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@ -1496,6 +1497,375 @@ acpi_handle_dmar(ACPI_TABLE_HEADER *sdp)
printf(END_COMMENT);
}
static void
acpi_handle_ivrs_ivhd_header(ACPI_IVRS_HEADER *addr)
{
printf("\n\tIVHD Type=%#x IOMMUId=%x\n\tFlags=",
addr->Type, addr->DeviceId);
#define PRINTFLAG(flag, name) printflag(addr->Flags, flag, #name)
PRINTFLAG(ACPI_IVHD_TT_ENABLE, HtTunEn);
PRINTFLAG(ACPI_IVHD_ISOC, PassPW);
PRINTFLAG(ACPI_IVHD_RES_PASS_PW, ResPassPW);
PRINTFLAG(ACPI_IVHD_ISOC, Isoc);
PRINTFLAG(ACPI_IVHD_TT_ENABLE, IotlbSup);
PRINTFLAG((1 << 5), Coherent);
PRINTFLAG((1 << 6), PreFSup);
PRINTFLAG((1 << 7), PPRSup);
#undef PRINTFLAG
PRINTFLAG_END();
}
static void
acpi_handle_ivrs_ivhd_dte(UINT8 dte)
{
if (dte == 0) {
printf("\n");
return;
}
printf(" DTE=");
#define PRINTFLAG(flag, name) printflag(dte, flag, #name)
PRINTFLAG(ACPI_IVHD_INIT_PASS, INITPass);
PRINTFLAG(ACPI_IVHD_EINT_PASS, EIntPass);
PRINTFLAG(ACPI_IVHD_NMI_PASS, NMIPass);
PRINTFLAG(ACPI_IVHD_SYSTEM_MGMT, SysMgtPass);
PRINTFLAG(ACPI_IVHD_LINT0_PASS, Lint0Pass);
PRINTFLAG(ACPI_IVHD_LINT1_PASS, Lint1Pass);
#undef PRINTFLAG
PRINTFLAG_END();
}
static void
acpi_handle_ivrs_ivhd_edte(UINT32 edte)
{
if (edte == 0)
return;
printf("\t\t ExtDTE=");
#define PRINTFLAG(flag, name) printflag(edte, flag, #name)
PRINTFLAG(ACPI_IVHD_ATS_DISABLED, AtsDisabled);
#undef PRINTFLAG
PRINTFLAG_END();
}
static const char *
acpi_handle_ivrs_ivhd_variety(UINT8 v)
{
switch (v) {
case ACPI_IVHD_IOAPIC:
return ("IOAPIC");
case ACPI_IVHD_HPET:
return ("HPET");
default:
return ("UNKNOWN");
}
}
static void
acpi_handle_ivrs_ivhd_devs(ACPI_IVRS_DE_HEADER *d, char *de)
{
char *db;
ACPI_IVRS_DEVICE4 *d4;
ACPI_IVRS_DEVICE8A *d8a;
ACPI_IVRS_DEVICE8B *d8b;
ACPI_IVRS_DEVICE8C *d8c;
ACPI_IVRS_DEVICE_HID *dh;
size_t len;
UINT32 x32;
for (; (char *)d < de; d = (ACPI_IVRS_DE_HEADER *)(db + len)) {
db = (char *)d;
if (d->Type == ACPI_IVRS_TYPE_PAD4) {
len = sizeof(*d4);
} else if (d->Type == ACPI_IVRS_TYPE_ALL) {
d4 = (ACPI_IVRS_DEVICE4 *)db;
len = sizeof(*d4);
printf("\t\tDev Type=%#x Id=ALL", d4->Header.Type);
acpi_handle_ivrs_ivhd_dte(d4->Header.DataSetting);
} else if (d->Type == ACPI_IVRS_TYPE_SELECT) {
d4 = (ACPI_IVRS_DEVICE4 *)db;
len = sizeof(*d4);
printf("\t\tDev Type=%#x Id=%#06x", d4->Header.Type,
d4->Header.Id);
acpi_handle_ivrs_ivhd_dte(d4->Header.DataSetting);
} else if (d->Type == ACPI_IVRS_TYPE_START) {
d4 = (ACPI_IVRS_DEVICE4 *)db;
len = 2 * sizeof(*d4);
printf("\t\tDev Type=%#x Id=%#06x-%#06x",
d4->Header.Type,
d4->Header.Id, (d4 + 1)->Header.Id);
acpi_handle_ivrs_ivhd_dte(d4->Header.DataSetting);
} else if (d->Type == ACPI_IVRS_TYPE_END) {
d4 = (ACPI_IVRS_DEVICE4 *)db;
len = 2 * sizeof(*d4);
printf("\t\tDev Type=%#x Id=%#06x BIOS BUG\n",
d4->Header.Type, d4->Header.Id);
} else if (d->Type == ACPI_IVRS_TYPE_PAD8) {
len = sizeof(*d8a);
} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_SELECT) {
d8a = (ACPI_IVRS_DEVICE8A *)db;
len = sizeof(*d8a);
printf("\t\tDev Type=%#x Id=%#06x AliasId=%#06x",
d8a->Header.Type, d8a->Header.Id, d8a->UsedId);
acpi_handle_ivrs_ivhd_dte(d8a->Header.DataSetting);
} else if (d->Type == ACPI_IVRS_TYPE_ALIAS_START) {
d8a = (ACPI_IVRS_DEVICE8A *)db;
d4 = (ACPI_IVRS_DEVICE4 *)(db + sizeof(*d8a));
len = sizeof(*d8a) + sizeof(*d4);
printf("\t\tDev Type=%#x Id=%#06x-%#06x AliasId=%#06x",
d8a->Header.Type, d8a->Header.Id, d4->Header.Id,
d8a->UsedId);
acpi_handle_ivrs_ivhd_dte(d8a->Header.DataSetting);
} else if (d->Type == ACPI_IVRS_TYPE_EXT_SELECT) {
d8b = (ACPI_IVRS_DEVICE8B *)db;
len = sizeof(*d8b);
printf("\t\tDev Type=%#x Id=%#06x",
d8a->Header.Type, d8a->Header.Id);
acpi_handle_ivrs_ivhd_dte(d8b->Header.DataSetting);
printf("\t\t");
acpi_handle_ivrs_ivhd_edte(d8b->ExtendedData);
} else if (d->Type == ACPI_IVRS_TYPE_EXT_START) {
d8b = (ACPI_IVRS_DEVICE8B *)db;
len = sizeof(*d8b);
d4 = (ACPI_IVRS_DEVICE4 *)(db + sizeof(*d8a));
len = sizeof(*d8a) + sizeof(*d4);
printf("\t\tDev Type=%#x Id=%#06x-%#06x",
d8a->Header.Type, d8a->Header.Id, d4->Header.Id);
acpi_handle_ivrs_ivhd_dte(d8b->Header.DataSetting);
acpi_handle_ivrs_ivhd_edte(d8b->ExtendedData);
} else if (d->Type == ACPI_IVRS_TYPE_SPECIAL) {
d8c = (ACPI_IVRS_DEVICE8C *)db;
len = sizeof(*d8c);
printf("\t\tDev Type=%#x Id=%#06x Handle=%#x "
"Variety=%d(%s)",
d8c->Header.Type, d8c->UsedId, d8c->Handle,
d8c->Variety,
acpi_handle_ivrs_ivhd_variety(d8c->Variety));
acpi_handle_ivrs_ivhd_dte(d8c->Header.DataSetting);
} else if (d->Type == ACPI_IVRS_TYPE_HID) {
dh = (ACPI_IVRS_DEVICE_HID *)db;
len = sizeof(*dh) + dh->UidLength;
printf("\t\tDev Type=%#x Id=%#06x HID=",
dh->Header.Type, dh->Header.Id);
acpi_print_string((char *)&dh->AcpiHid,
sizeof(dh->AcpiHid));
printf(" CID=");
acpi_print_string((char *)&dh->AcpiCid,
sizeof(dh->AcpiCid));
printf(" UID=");
switch (dh->UidType) {
case ACPI_IVRS_UID_NOT_PRESENT:
default:
printf("none");
break;
case ACPI_IVRS_UID_IS_INTEGER:
memcpy(&x32, dh + 1, sizeof(x32));
printf("%#x", x32);
break;
case ACPI_IVRS_UID_IS_STRING:
acpi_print_string((char *)(dh + 1),
dh->UidLength);
break;
}
acpi_handle_ivrs_ivhd_dte(dh->Header.DataSetting);
} else {
printf("\t\tDev Type=%#x Unknown\n", d->Type);
if (d->Type <= 63)
len = sizeof(*d4);
else if (d->Type <= 127)
len = sizeof(*d8a);
else {
printf("Abort, cannot advance iterator.\n");
return;
}
}
}
}
static void
acpi_handle_ivrs_ivhd_10(ACPI_IVRS_HARDWARE1 *addr, bool efrsup)
{
acpi_handle_ivrs_ivhd_header(&addr->Header);
printf("\tCapOffset=%#x Base=%#jx PCISeg=%#x Unit=%#x MSIlog=%d\n",
addr->CapabilityOffset, (uintmax_t)addr->BaseAddress,
addr->PciSegmentGroup, (addr->Info & ACPI_IVHD_UNIT_ID_MASK) >> 8,
addr->Info & ACPI_IVHD_MSI_NUMBER_MASK);
if (efrsup) {
#define PRINTFLAG(flag, name) printflag(addr->FeatureReporting, flag, #name)
#define PRINTFIELD(lbit, hbit, name) \
printfield(addr->FeatureReporting, lbit, hbit, #name)
PRINTFIELD(30, 31, HATS);
PRINTFIELD(28, 29, GATS);
PRINTFIELD(23, 27, MsiNumPPR);
PRINTFIELD(17, 22, PNBanks);
PRINTFIELD(13, 16, PNCounters);
PRINTFIELD(8, 12, PASmax);
PRINTFLAG(1 << 7, HESup);
PRINTFLAG(1 << 6, GASup);
PRINTFLAG(1 << 5, UASup);
PRINTFIELD(3, 2, GLXSup);
PRINTFLAG(1 << 1, NXSup);
PRINTFLAG(1 << 0, XTSup);
#undef PRINTFLAG
#undef PRINTFIELD
PRINTFLAG_END();
}
acpi_handle_ivrs_ivhd_devs((ACPI_IVRS_DE_HEADER *)(addr + 1),
(char *)addr + addr->Header.Length);
}
static void
acpi_handle_ivrs_ivhd_info_11(ACPI_IVRS_HARDWARE2 *addr)
{
acpi_handle_ivrs_ivhd_header(&addr->Header);
printf("\tCapOffset=%#x Base=%#jx PCISeg=%#x Unit=%#x MSIlog=%d\n",
addr->CapabilityOffset, (uintmax_t)addr->BaseAddress,
addr->PciSegmentGroup, (addr->Info >> 8) & 0x1f,
addr->Info & 0x5);
printf("\tAttr=");
#define PRINTFIELD(lbit, hbit, name) \
printfield(addr->Attributes, lbit, hbit, #name)
PRINTFIELD(23, 27, MsiNumPPR);
PRINTFIELD(17, 22, PNBanks);
PRINTFIELD(13, 16, PNCounters);
#undef PRINTFIELD
PRINTFLAG_END();
}
static void
acpi_handle_ivrs_ivhd_11(ACPI_IVRS_HARDWARE2 *addr)
{
acpi_handle_ivrs_ivhd_info_11(addr);
printf("\tEFRreg=%#018jx\n", (uintmax_t)addr->EfrRegisterImage);
acpi_handle_ivrs_ivhd_devs((ACPI_IVRS_DE_HEADER *)(addr + 1),
(char *)addr + addr->Header.Length);
}
static void
acpi_handle_ivrs_ivhd_40(ACPI_IVRS_HARDWARE2 *addr)
{
acpi_handle_ivrs_ivhd_info_11(addr);
printf("\tEFRreg=%#018jx EFR2reg=%#018jx\n",
(uintmax_t)addr->EfrRegisterImage, (uintmax_t)addr->Reserved);
acpi_handle_ivrs_ivhd_devs((ACPI_IVRS_DE_HEADER *)(addr + 1),
(char *)addr + addr->Header.Length);
}
static const char *
acpi_handle_ivrs_ivmd_type(ACPI_IVRS_MEMORY *addr)
{
switch (addr->Header.Type) {
case ACPI_IVRS_TYPE_MEMORY1:
return ("ALL");
case ACPI_IVRS_TYPE_MEMORY2:
return ("specified");
case ACPI_IVRS_TYPE_MEMORY3:
return ("range");
default:
return ("unknown");
}
}
static void
acpi_handle_ivrs_ivmd(ACPI_IVRS_MEMORY *addr)
{
printf("\tMem Type=%#x(%s) ",
addr->Header.Type, acpi_handle_ivrs_ivmd_type(addr));
switch (addr->Header.Type) {
case ACPI_IVRS_TYPE_MEMORY2:
printf("Id=%#06x PCISeg=%#x ", addr->Header.DeviceId,
*(UINT16 *)&addr->Reserved);
break;
case ACPI_IVRS_TYPE_MEMORY3:
printf("Id=%#06x-%#06x PCISeg=%#x", addr->Header.DeviceId,
addr->AuxData, *(UINT16 *)&addr->Reserved);
break;
}
printf("Start=%#18jx Length=%#jx Flags=",
(uintmax_t)addr->StartAddress, (uintmax_t)addr->MemoryLength);
#define PRINTFLAG(flag, name) printflag(addr->Header.Flags, flag, #name)
PRINTFLAG(ACPI_IVMD_EXCLUSION_RANGE, ExclusionRange);
PRINTFLAG(ACPI_IVMD_WRITE, IW);
PRINTFLAG(ACPI_IVMD_READ, IR);
PRINTFLAG(ACPI_IVMD_UNITY, Unity);
#undef PRINTFLAG
PRINTFLAG_END();
}
static int
acpi_handle_ivrs_blocks(void *addr, int remaining, bool efrsup)
{
ACPI_IVRS_HEADER *hdr = addr;
if (remaining < (int)sizeof(ACPI_IVRS_HEADER))
return (-1);
if (remaining < hdr->Length)
return (-1);
switch (hdr->Type) {
case ACPI_IVRS_TYPE_HARDWARE1:
acpi_handle_ivrs_ivhd_10(addr, efrsup);
break;
case ACPI_IVRS_TYPE_HARDWARE2:
if (!efrsup)
printf("\t!! Found IVHD block 0x11 but !EFRsup\n");
acpi_handle_ivrs_ivhd_11(addr);
break;
case ACPI_IVRS_TYPE_HARDWARE3:
if (!efrsup)
printf("\t!! Found IVHD block 0x40 but !EFRsup\n");
acpi_handle_ivrs_ivhd_40(addr);
break;
case ACPI_IVRS_TYPE_MEMORY1:
case ACPI_IVRS_TYPE_MEMORY2:
case ACPI_IVRS_TYPE_MEMORY3:
acpi_handle_ivrs_ivmd(addr);
break;
default:
printf("\n");
printf("\tType=%d\n", hdr->Type);
printf("\tLength=%d\n", hdr->Length);
break;
}
return (hdr->Length);
}
#define ACPI_IVRS_DMAREMAP 0x00000002
#define ACPI_IVRS_EFRSUP 0x00000001
#define ACPI_IVRS_GVA_SIZE 0x000000e0
static void
acpi_handle_ivrs(ACPI_TABLE_HEADER *sdp)
{
ACPI_TABLE_IVRS *ivrs;
char *cp;
int remaining, consumed;
bool efrsup;
printf(BEGIN_COMMENT);
acpi_print_sdt(sdp);
ivrs = (ACPI_TABLE_IVRS *)sdp;
efrsup = (ivrs->Info & ACPI_IVRS_EFRSUP) != 0;
printf("\tVAsize=%d PAsize=%d GVAsize=%d\n",
(ivrs->Info & ACPI_IVRS_VIRTUAL_SIZE) >> 15,
(ivrs->Info & ACPI_IVRS_PHYSICAL_SIZE) >> 8,
(ivrs->Info & ACPI_IVRS_GVA_SIZE) >> 5);
printf("\tATS_resp_res=%d DMA_preboot_remap=%d EFRsup=%d\n",
(ivrs->Info & ACPI_IVRS_ATS_RESERVED) != 0,
(ivrs->Info & ACPI_IVRS_DMAREMAP) != 0, efrsup);
remaining = sdp->Length - sizeof(ACPI_TABLE_IVRS);
while (remaining > 0) {
cp = (char *)sdp + sdp->Length - remaining;
consumed = acpi_handle_ivrs_blocks(cp, remaining, efrsup);
if (consumed <= 0)
break;
else
remaining -= consumed;
}
printf(END_COMMENT);
}
static void
acpi_print_srat_memory(ACPI_SRAT_MEM_AFFINITY *mp)
{
@ -2086,6 +2456,8 @@ acpi_handle_rsdt(ACPI_TABLE_HEADER *rsdp)
acpi_handle_tcpa(sdp);
else if (!memcmp(sdp->Signature, ACPI_SIG_DMAR, 4))
acpi_handle_dmar(sdp);
else if (!memcmp(sdp->Signature, ACPI_SIG_IVRS, 4))
acpi_handle_ivrs(sdp);
else if (!memcmp(sdp->Signature, ACPI_SIG_NFIT, 4))
acpi_handle_nfit(sdp);
else if (!memcmp(sdp->Signature, ACPI_SIG_WDDT, 4))