diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -26,6 +26,9 @@ * */ +#ifndef __PCI_PCIREG_H +#define __PCI_PCIREG_H + /* * PCIM_xxx: mask to locate subfield in register * PCIR_xxx: config register offset @@ -1121,3 +1124,57 @@ #define PCIM_ACS_USP_MEM_TGT_ACC_CTL 0x0c00 #define PCIM_ACS_UNCLAIMED_REQ_REDIRECT_CTL 0x1000 #define PCIR_ACS_EGRESS_CONTROL_VECTOR 0x8 + +/* + * AMD IOMMU Base Capability + * From AMD I/O Virtualization Technology (IOMMU) Specification + * Publication # 48882 Revision: 3.09-PUB Date: October 2023 + */ +#define PCIR_AMDIOMMU_CAP_HEADER 0x0000 +#define PCIR_AMDIOMMU_BASE_LOW 0x0004 +#define PCIR_AMDIOMMU_BASE_HIGH 0x0008 +#define PCIR_AMDIOMMU_RANGE 0x000c +#define PCIR_AMDIOMMU_MISC0 0x0010 +#define PCIR_AMDIOMMU_MISC1 0x0014 + +#define PCIM_AMDIOMMU_CAP_CAPEXT (1 << 28) +#define PCIM_AMDIOMMU_CAP_EFR (1 << 27) +#define PCIM_AMDIOMMU_CAP_NPCACHE (1 << 26) +#define PCIM_AMDIOMMU_CAP_HTTUN (1 << 25) +#define PCIM_AMDIOMMU_CAP_IOTLB (1 << 24) +#define PCIM_AMDIOMMU_CAP_REV_MASK (0x1f << 19) +#define PCIM_AMDIOMMU_CAP_REV_VAL (0x1 << 19) +#define PCIM_AMDIOMMU_CAP_TYPE_MASK (7 << 16) +#define PCIM_AMDIOMMU_CAP_TYPE_VAL (0x3 << 16) + +#define PCIM_AMDIOMMU_BASE_LOW_EN 0x00000001 +#define PCIM_AMDIOMMU_BASE_LOW_ADDRM 0xffffc000 + +#define PCIM_AMDIOMMU_RANGE_UNITID_MASK 0x1f +#define PCIM_AMDIOMMU_RANGE_RNGVALID (1 << 7) +#define PCIM_AMDIOMMU_RANGE_BUSNUM_MASK (0xffffu << 8) +#define PCIM_AMDIOMMU_RANGE_FIRSTDEV_MASK (0xffffu << 16) +#define PCIM_AMDIOMMU_RANGE_LASTDEV_MASK (0xffffu << 24) + +#define PCIM_AMDIOMMU_MISC0_MSINUMPPR_MASK (0x1f << 27) +#define PCIM_AMDIOMMU_MISC0_HTATSRESV (1 << 22) +#define PCIM_AMDIOMMU_MISC0_VASIZE_MASK (0x7f << 15) +#define PCIM_AMDIOMMU_MISC0_PASIZE_MASK (0x7f << 8) +#define PCIM_AMDIOMMU_MISC0_GVASIZE_MASK (0x3 << 5) +#define PCIM_AMDIOMMU_MISC0_MSINUM_MASK 0x1f + +#define PCIM_AMDIOMMU_MISC0_VASIZE_32 (0x20 << 15) +#define PCIM_AMDIOMMU_MISC0_VASIZE_40 (0x28 << 15) +#define PCIM_AMDIOMMU_MISC0_VASIZE_48 (0x30 << 15) +#define PCIM_AMDIOMMU_MISC0_VASIZE_64 (0x40 << 15) + +#define PCIM_AMDIOMMU_MISC0_PASIZE_40 (0x28 << 8) +#define PCIM_AMDIOMMU_MISC0_PASIZE_48 (0x30 << 8) +#define PCIM_AMDIOMMU_MISC0_PASIZE_52 (0x34 << 8) + +#define PCIM_AMDIOMMU_MISC0_GVASIZE_48 (0x2 << 5) +#define PCIM_AMDIOMMU_MISC0_GVASIZE_57 (0x3 << 5) + +#define PCIM_AMDIOMMU_MISC1_MSINUMGA_MASK 0x1f + +#endif /* __PCI_PCIREG_H */ diff --git a/usr.sbin/pciconf/cap.c b/usr.sbin/pciconf/cap.c --- a/usr.sbin/pciconf/cap.c +++ b/usr.sbin/pciconf/cap.c @@ -376,6 +376,118 @@ printf("PCI Bridge subvendor=0x%04x subdevice=0x%04x", ssvid, ssid); } +static const char * +cap_secdev_amdiommu_decode_vasize(uint32_t misc0) +{ + switch (misc0 & PCIM_AMDIOMMU_MISC0_VASIZE_MASK) { + case PCIM_AMDIOMMU_MISC0_VASIZE_32: + return ("32bit"); + case PCIM_AMDIOMMU_MISC0_VASIZE_40: + return ("40bit"); + case PCIM_AMDIOMMU_MISC0_VASIZE_48: + return ("48bit"); + case PCIM_AMDIOMMU_MISC0_VASIZE_64: + return ("64bit"); + default: + return ("unknown"); + } +} + +static const char * +cap_secdev_amdiommu_decode_pasize(uint32_t misc0) +{ + switch (misc0 & PCIM_AMDIOMMU_MISC0_PASIZE_MASK) { + case PCIM_AMDIOMMU_MISC0_PASIZE_40: + return ("40bit"); + case PCIM_AMDIOMMU_MISC0_PASIZE_48: + return ("48bit"); + case PCIM_AMDIOMMU_MISC0_PASIZE_52: + return ("52bit"); + default: + return ("unknown"); + } +} + +static const char * +cap_secdev_amdiommu_decode_gvasize(uint32_t misc0) +{ + switch (misc0 & PCIM_AMDIOMMU_MISC0_GVASIZE_MASK) { + case PCIM_AMDIOMMU_MISC0_GVASIZE_48: + return ("48bit"); + case PCIM_AMDIOMMU_MISC0_GVASIZE_57: + return ("57bit"); + default: + return ("unknown"); + } +} + +static void +cap_secdev(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint32_t cap_h; + uint32_t cap_type, cap_rev; + uint32_t base_low, base_high; + uint32_t range; + uint32_t misc0, misc1; + const char *delim; + + cap_h = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_CAP_HEADER, 4); + cap_type = cap_h & PCIM_AMDIOMMU_CAP_TYPE_MASK; + cap_rev = cap_h & PCIM_AMDIOMMU_CAP_REV_MASK; + if (cap_type != PCIM_AMDIOMMU_CAP_TYPE_VAL || + cap_rev != PCIM_AMDIOMMU_CAP_REV_VAL) { + printf("Secure Device Type=0x%1x Rev=0x%02x\n", + cap_type >> 16, cap_rev >> 19); + return; + } + base_low = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_LOW, + 4); + base_high = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_HIGH, + 4); + printf("AMD IOMMU Base Capability Base=%#018jx/%sabled", + (uintmax_t)(base_low & PCIM_AMDIOMMU_BASE_LOW_ADDRM) + + ((uintmax_t)base_high << 32), + (base_low & PCIM_AMDIOMMU_BASE_LOW_EN) != 0 ? "En" : "Dis"); + + delim = "\n\t\t"; +#define PRINTCAP(bit, name) \ + if ((cap_h & PCIM_AMDIOMMU_CAP_ ##bit) != 0) { \ + printf("%s%s", delim, #name); \ + delim = ","; \ + } + PRINTCAP(CAPEXT, CapExt); + PRINTCAP(EFR, EFRSup); + PRINTCAP(NPCACHE, NpCache); + PRINTCAP(HTTUN, HtTunnel); + PRINTCAP(IOTLB, IotlbSup); +#undef PRINTCAP + + range = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_RANGE, 4); + printf("\n\t\tUnitId=%d", range & PCIM_AMDIOMMU_RANGE_UNITID_MASK); + if ((range & PCIM_AMDIOMMU_RANGE_RNGVALID) != 0) { + printf(" BusNum=%#06x FirstDev=%#06x LastDev=%#06x", + (range & PCIM_AMDIOMMU_RANGE_BUSNUM_MASK) >> 8, + (range & PCIM_AMDIOMMU_RANGE_FIRSTDEV_MASK) >> 16, + (range & PCIM_AMDIOMMU_RANGE_LASTDEV_MASK) >> 24); + } + + misc0 = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_MISC0, 4); + printf("\n\t\tMsiNum=%d MsiNumPPR=%d HtAtsResv=%d", + misc0 & PCIM_AMDIOMMU_MISC0_MSINUM_MASK, + (misc0 & PCIM_AMDIOMMU_MISC0_MSINUMPPR_MASK) >> 27, + (misc0 & PCIM_AMDIOMMU_MISC0_HTATSRESV) != 0); + if ((cap_h & PCIM_AMDIOMMU_CAP_CAPEXT) != 0) { + misc1 = read_config(fd, &p->pc_sel, + ptr + PCIR_AMDIOMMU_MISC1, 4); + printf(" MsiNumGA=%d", + misc1 & PCIM_AMDIOMMU_MISC1_MSINUMGA_MASK); + } + printf("\n\t\tVAsize=%s PAsize=%s GVAsize=%s", + cap_secdev_amdiommu_decode_vasize(misc0), + cap_secdev_amdiommu_decode_pasize(misc0), + cap_secdev_amdiommu_decode_gvasize(misc0)); +} + #define MAX_PAYLOAD(field) (128 << (field)) static const char * @@ -813,6 +925,9 @@ case PCIY_SUBVENDOR: cap_subvendor(fd, p, ptr); break; + case PCIY_SECDEV: + cap_secdev(fd, p, ptr); + break; case PCIY_EXPRESS: express = 1; cap_express(fd, p, ptr);