mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-21 10:19:04 +00:00
acpidump: dump AMD IVRS table describing IOMMU layout
Reviewed by: markj Sponsored by: Advanced Micro Devices (AMD) Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D44634
This commit is contained in:
parent
969a4b8be5
commit
6d789b6126
|
@ -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)
|
||||
{
|
||||
|
@ -2084,6 +2454,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))
|
||||
|
|
Loading…
Reference in a new issue