git: f95a254aa722 - stable/13 - acpidump: dump AMD IVRS table describing IOMMU layout

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 17 Apr 2024 08:13:44 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=f95a254aa7226160d41768112fd714a5c16bae61

commit f95a254aa7226160d41768112fd714a5c16bae61
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-03-31 23:30:37 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-04-17 08:13:18 +0000

    acpidump: dump AMD IVRS table describing IOMMU layout
    
    (cherry picked from commit 6d789b6126afe1c23b65eef2c5cf4c6bd258c26f)
---
 usr.sbin/acpi/acpidump/acpi.c | 372 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 372 insertions(+)

diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c
index ec7bd65b14c9..d4ab70c9ca86 100644
--- a/usr.sbin/acpi/acpidump/acpi.c
+++ b/usr.sbin/acpi/acpidump/acpi.c
@@ -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))