diff --git a/sys/x86/iommu/amd_reg.h b/sys/x86/iommu/amd_reg.h new file mode 100644 --- /dev/null +++ b/sys/x86/iommu/amd_reg.h @@ -0,0 +1,746 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __X86_IOMMU_AMD_REG_H +#define __X86_IOMMU_AMD_REG_H + +/* + * MMIO Registers. Offsets and bits definitions. + */ + +#define AMDIOMMU_DEVTAB_BASE 0x0000 +#define AMDIOMMU_CMDBUF_BASE 0x0008 +#define AMDIOMMU_EVNTLOG_BASE 0x0010 +#define AMDIOMMU_CTRL 0x0018 +#define AMDIOMMU_EXCL_BASE 0x0020 +#define AMDIOMMU_EXCL_RANGE 0x0028 +#define AMDIOMMU_EFR 0x0030 +#define AMDIOMMU_PPRLOG_BASE 0x0038 +#define AMDIOMMU_HWEV_UPPER 0x0040 +#define AMDIOMMU_HWEV_LOWER 0x0048 +#define AMDIOMMU_HWEV_STATUS 0x0050 + +#define AMDIOMMU_SMIF_0 0x0060 +#define AMDIOMMU_SMIF_1 0x0068 +#define AMDIOMMU_SMIF_2 0x0070 +#define AMDIOMMU_SMIF_3 0x0078 +#define AMDIOMMU_SMIF_4 0x0080 +#define AMDIOMMU_SMIF_5 0x0088 +#define AMDIOMMU_SMIF_6 0x0090 +#define AMDIOMMU_SMIF_7 0x0098 +#define AMDIOMMU_SMIF_8 0x00a0 +#define AMDIOMMU_SMIF_9 0x00a8 +#define AMDIOMMU_SMIF_10 0x00b0 +#define AMDIOMMU_SMIF_11 0x00b8 +#define AMDIOMMU_SMIF_12 0x00c0 +#define AMDIOMMU_SMIF_13 0x00c8 +#define AMDIOMMU_SMIF_14 0x00d0 +#define AMDIOMMU_SMIF_15 0x00d8 + +#define AMDIOMMU_VAPIC_LOG_BASE 0x00e0 +#define AMDIOMMU_VAPIC_LOG_TAIL 0x00e8 +#define AMDIOMMU_PPRLOGB_BASE 0x00f0 +#define AMDIOMMU_EVNTLOGB_BASE 0x00f0 + +#define AMDIOMMU_DEVTAB_S1_BASE 0x0100 +#define AMDIOMMU_DEVTAB_S2_BASE 0x0108 +#define AMDIOMMU_DEVTAB_S3_BASE 0x0110 +#define AMDIOMMU_DEVTAB_S4_BASE 0x0118 +#define AMDIOMMU_DEVTAB_S5_BASE 0x0120 +#define AMDIOMMU_DEVTAB_S6_BASE 0x0128 +#define AMDIOMMU_DEVTAB_S7_BASE 0x0130 + +#define AMDIOMMU_DSFX 0x0138 +#define AMDIOMMU_DSCX 0x0140 +#define AMDIOMMU_DSSX 0x0148 + +#define AMDIOMMU_MSI_VEC0 0x0150 +#define AMDIOMMU_MSI_VEC1 0x0154 +#define AMDIOMMU_MSI_CAP_H 0x0158 +#define AMDIOMMU_MSI_ADDR_LOW 0x015c +#define AMDIOMMU_MSI_ADDR_HIGH 0x0160 +#define AMDIOMMU_MSI_DATA 0x0164 +#define AMDIOMMU_MSI_MAPCAP 0x0168 + +#define AMDIOMMU_PERFOPT 0x016c + +#define AMDIOMMU_x2APIC_CTRL 0x0170 +#define AMDIOMMU_PPRI_CTRL 0x0178 +#define AMDIOMMU_GALOGI_CTRL 0x0180 + +#define AMDIOMMU_vIOMMU_STATUS 0x0190 + +#define AMDIOMMU_MARC0_BASE 0x0200 +#define AMDIOMMU_MARC0_RELOC 0x0208 +#define AMDIOMMU_MARC0_LEN 0x0210 +#define AMDIOMMU_MARC1_BASE 0x0218 +#define AMDIOMMU_MARC1_RELOC 0x0220 +#define AMDIOMMU_MARC1_LEN 0x0228 +#define AMDIOMMU_MARC2_BASE 0x0230 +#define AMDIOMMU_MARC2_RELOC 0x0238 +#define AMDIOMMU_MARC2_LEN 0x0240 +#define AMDIOMMU_MARC3_BASE 0x0248 +#define AMDIOMMU_MARC3_RELOC 0x0250 +#define AMDIOMMU_MARC3_LEN 0x0258 + +#define AMDIOMMU_EFR2 0x01a0 + +#define AMDIOMMU_CMDBUF_HEAD 0x2000 +#define AMDIOMMU_CMDBUF_TAIL 0x2008 +#define AMDIOMMU_EVNTLOG_HEAD 0x2010 +#define AMDIOMMU_EVNTLOG_TAIL 0x2018 +#define AMDIOMMU_CMDEV_STATUS 0x2020 +#define AMDIOMMU_PPRLOG_HEAD 0x2030 +#define AMDIOMMU_PPRLOG_TAIL 0x2038 +#define AMDIOMMU_vAPICLOG_HEAD 0x2040 +#define AMDIOMMU_vAPICLOG_TAIL 0x2048 +#define AMDIOMMU_PPRLOGB_HEAD 0x2050 +#define AMDIOMMU_PPRLOGB_TAIL 0x2058 +#define AMDIOMMU_EVNTLOGB_HEAD 0x2070 +#define AMDIOMMU_EVNTLOGB_TAIL 0x2078 +#define AMDIOMMU_PPRLOG_AUR 0x2080 +#define AMDIOMMU_PPRLOG_EAI 0x2088 +#define AMDIOMMU_PPRLOGB_AUR 0x2090 + +/* + * IOMMU Control Register AMDIOMMU_CTRL fields + */ +#define AMDIOMMU_CTRL_EN 0x0000000000000001ull /* IOMMU En */ +#define AMDIOMMU_CTRL_HTTUN_EN 0x0000000000000002ull /* HT Tun Trans En */ +#define AMDIOMMU_CTRL_EVNTLOG_EN 0x0000000000000004ull /* Event Log En */ +#define AMDIOMMU_CTRL_EVENTINT_EN 0x0000000000000008ull /* Event Log Intr En */ +#define AMDIOMMU_CTRL_COMWINT_EN 0x0000000000000010ull /* Compl Wait Intr En */ +#define AMDIOMMU_CTRL_INVTOUT_MASK 0x00000000000000e0ull /* IOTLB Inv Timeout*/ +#define AMDIOMMU_CTRL_INVTOUT_NO 0x0000000000000000ull +#define AMDIOMMU_CTRL_INVTOUT_1MS 0x0000000000000020ull +#define AMDIOMMU_CTRL_INVTOUT_10MS 0x0000000000000040ull +#define AMDIOMMU_CTRL_INVTOUT_100MS 0x0000000000000060ull +#define AMDIOMMU_CTRL_INVTOUT_1S 0x0000000000000080ull +#define AMDIOMMU_CTRL_INVTOUT_10S 0x00000000000000a0ull +#define AMDIOMMU_CTRL_INVTOUT_100S 0x00000000000000b0ull +#define AMDIOMMU_CTRL_INVTOUT_RSRV 0x00000000000000e0ull +#define AMDIOMMU_CTRL_PASSPW 0x0000000000000100ull /* HT Pass Posted Wr */ +#define AMDIOMMU_CTRL_REPASSPW 0x0000000000000200ull /* HT Resp Pass Posted Wr */ +#define AMDIOMMU_CTRL_COHERENT 0x0000000000000400ull /* HT Coherent Reads */ +#define AMDIOMMU_CTRL_ISOC 0x0000000000000800ull /* HT Isoc Reads */ +#define AMDIOMMU_CTRL_CMDBUF_EN 0x0000000000001000ull /* Start CMD proc En */ +#define AMDIOMMU_CTRL_PPRLOG_EN 0x0000000000002000ull /* Periph Page Req Log En */ +#define AMDIOMMU_CTRL_PPRINT_EN 0x0000000000004000ull /* Periph Page Req Intr En */ +#define AMDIOMMU_CTRL_PPR_EN 0x0000000000008000ull /* Periph Page Req En */ +#define AMDIOMMU_CTRL_GT_EN 0x0000000000010000ull /* Guest En */ +#define AMDIOMMU_CTRL_GA_EN 0x0000000000020000ull /* Guest vAPIC En */ +#define AMDIOMMU_CTRL_SMIF_EN 0x0000000000400000ull /* SMI Filter En */ +#define AMDIOMMU_CTRL_SLFWB_DIS 0x0000000000800000ull /* Self WriteBack Dis */ +#define AMDIOMMU_CTRL_SMIFLOG_EN 0x0000000001000000ull /* SMI Filter Log En */ +#define AMDIOMMU_CTRL_GAM_EN_MASK 0x000000000e000000ull /* Guest vAPIC Mode En */ +#define AMDIOMMU_CTRL_GAM_EN_vAPIC_GM0 0x0000000000000000ull /* IRTE.GM = 0 */ +#define AMDIOMMU_CTRL_GAM_EN_vAPIC_GM1 0x0000000002000000ull /* IRTE.GM = 1 */ +#define AMDIOMMU_CTRL_GALOG_EN 0x0000000010000000ull /* Guest vAPIC GA Log En */ +#define AMDIOMMU_CTRL_GAINT_EN 0x0000000020000000ull /* Guest vAPIC GA Intr En */ +#define AMDIOMMU_CTRL_DUALPPRLOG_MASK 0x00000000c0000000ull /* Dual Periph Page Req Log En */ +#define AMDIOMMU_CTRL_DUALPPRLOG_A 0x0000000000000000ull /* Use Log A */ +#define AMDIOMMU_CTRL_DUALPPRLOG_B 0x0000000040000000ull /* Use Log B */ +#define AMDIOMMU_CTRL_DUALPPRLOG_SWAP 0x0000000080000000ull /* Auto-swap on full */ +#define AMDIOMMU_CTRL_DUALPPRLOG_RSRV 0x00000000c0000000ull +#define AMDIOMMU_CTRL_DUALEVNTLOG_MASK 0x0000000300000000ull /* Dual Event Log En */ +#define AMDIOMMU_CTRL_DUALEVNTLOG_A 0x0000000000000000ull /* Use Log A Buf */ +#define AMDIOMMU_CTRL_DUALEVNTLOG_B 0x0000000100000000ull /* Use Log B Buf */ +#define AMDIOMMU_CTRL_DUALEVNTLOG_SWAP 0x0000000200000000ull /* Auto-swap on full */ +#define AMDIOMMU_CTRL_DUALEVNTLOG_RSRV 0x0000000300000000ull +#define AMDIOMMU_CTRL_DEVTABSEG_MASK 0x0000001c00000000ull /* Dev Table Segm */ +#define AMDIOMMU_CTRL_DEVTABSEG_1 0x0000000000000000ull /* 1 Segment */ +#define AMDIOMMU_CTRL_DEVTABSEG_2 0x0000000400000000ull /* 2 Segments */ +#define AMDIOMMU_CTRL_DEVTABSEG_4 0x0000000800000000ull /* 4 Segments */ +#define AMDIOMMU_CTRL_DEVTABSEG_8 0x0000000c00000000ull /* 8 Segments */ +#define AMDIOMMU_CTRL_PRIVABRT_MASK 0x0000006000000000ull /* Privilege Abort En */ +#define AMDIOMMU_CTRL_PRIVABRT_USR 0x0000000000000000ull /* Privilege Abort User */ +#define AMDIOMMU_CTRL_PRIVABRT_ALL 0x0000002000000000ull /* Privilege Abort Always */ +#define AMDIOMMU_CTRL_PPRAUTORSP_EN 0x0000008000000000ull /* PPR Auto Resp En */ +#define AMDIOMMU_CTRL_MARC_EN 0x0000010000000000ull /* Memory Addr Routing En */ +#define AMDIOMMU_CTRL_BLKSTOPMRK_EN 0x0000020000000000ull /* Block StopMark En */ +#define AMDIOMMU_CTRL_PPRAUTORESPA_EN 0x0000040000000000ull /* PPR Auto Resp Always En */ +#define AMDIOMMU_CTRL_EPH_EN 0x0000200000000000ull /* Enh PPR Handling En */ +#define AMDIOMMU_CTRL_HADUP_MASK 0x0000c00000000000ull /* Access and Dirty in host PT */ +#define AMDIOMMU_CTRL_GDUP_DIS 0x0001000000000000ull /* Dis Dirty in guest PT */ +#define AMDIOMMU_CTRL_XT_EN 0x0004000000000000ull /* x2APIC mode */ +#define AMDIOMMU_CTRL_INTCAPXT_EN 0x0008000000000000ull /* x2APIC mode for IOMMU intrs */ +#define AMDIOMMU_CTRL_vCMD_EN 0x0010000000000000ull /* vCMD buffer proc En */ +#define AMDIOMMU_CTRL_vIOMMU_EN 0x0020000000000000ull /* vIOMMU En */ +#define AMDIOMMU_CTRL_GAUP_DIS 0x0040000000000000ull /* Dis Access in guest PT */ +#define AMDIOMMU_CTRL_GAPPI_EN 0x0080000000000000ull /* Guest APIC phys proc intr En */ +#define AMDIOMMU_CTRL_TMPM_EN 0x0100000000000000ull /* Tiered Mem Page Migration En */ +#define AMDIOMMU_CTRL_GGCR3TRP_PHYS 0x0400000000000000ull /* GCR3 is GPA (otherwise SPA) */ +#define AMDIOMMU_CTRL_IRTCACHE_DIS 0x0800000000000000ull /* IRT Caching Dis */ +#define AMDIOMMU_CTRL_GSTBUFTRP_MODE 0x1000000000000000ull /* See spec */ +#define AMDIOMMU_CTRL_SNPAVIC_MASK 0xe000000000000000ull /* MBZ */ + +/* + * IOMMU Extended Feature Register AMDIOMMU_EFR fields + */ +#define AMDIOMMU_EFR_XT_SUP 0x0000000000000004ull /* x2APIC */ +#define AMDIOMMU_EFR_HWEV_SUP 0x0000000000000100ull /* HW Event regs */ +#define AMDIOMMU_EFR_PC_SUP 0x0000000000000200ull /* Perf counters */ +#define AMDIOMMU_EFR_HATS_MASK 0x0000000000000c00ull /* Host Addr Trans Size */ +#define AMDIOMMU_EFR_HATS_4LVL 0x0000000000000000ull +#define AMDIOMMU_EFR_HATS_5LVL 0x0000000000000400ull +#define AMDIOMMU_EFR_HATS_6LVL 0x0000000000000800ull +#define AMDIOMMU_EFR_DEVTBLSEG_MASK 0x000000c000000000ull /* DevTbl segmentation */ +#define AMDIOMMU_EFR_DEVTBLSEG_SHIFT 38 + +/* IOMMU Command Pointers (Head/Tail) registers fields */ +#define AMDIOMMU_CMDPTR_MASK 0x000000000007fff0ull + +/* IOMMU Command Buffer Base fields */ +#define AMDIOMMU_CMDBUF_BASE_SZSHIFT 56 /* Shift for size */ +#define AMDIOMMU_CMDBUF_MAX (512 * 1024) + +/* IOMMU Event Log Base register fields */ +#define AMDIOMMU_EVNTLOG_BASE_SZSHIFT 56 /* Shift for size */ +#define AMDIOMMU_EVNTLOG_MIN 256 +#define AMDIOMMU_EVNTLOG_MAX 32768 + +/* IOMMU Hardware Event Status register fields */ +#define AMDIOMMU_HWEVS_HEV 0x00000001 /* HW Ev Valid */ +#define AMDIOMMU_HWEVS_HEO 0x00000002 /* HW Ev Overfl */ + +/* + * IOMMU Command and Event Status register fields. + * From the spec, all defined bits are either RO or RW1C. As a consequence, + * single bit can be safely written to the register to clean a specific + * condition. + */ +#define AMDIOMMU_CMDEVS_EVOVRFLW 0x00000001 +#define AMDIOMMU_CMDEVS_EVLOGINT 0x00000002 +#define AMDIOMMU_CMDEVS_COMWAITINT 0x00000004 +#define AMDIOMMU_CMDEVS_EVLOGRUN 0x00000008 +#define AMDIOMMU_CMDEVS_CMDBUFRUN 0x00000010 +#define AMDIOMMU_CMDEVS_PPROVRFLW 0x00000020 +#define AMDIOMMU_CMDEVS_PPRINT 0x00000040 +#define AMDIOMMU_CMDEVS_PPRLOGRUN 0x00000080 +#define AMDIOMMU_CMDEVS_GALOGRUN 0x00000100 +#define AMDIOMMU_CMDEVS_GALOVRFLW 0x00000200 +#define AMDIOMMU_CMDEVS_GAINT 0x00000400 +#define AMDIOMMU_CMDEVS_PPROVRFLWB 0x00000800 +#define AMDIOMMU_CMDEVS_PPRLOGACTIVE 0x00001000 +#define AMDIOMMU_CMDEVS_RESV1 0x00002000 +#define AMDIOMMU_CMDEVS_RESV2 0x00004000 +#define AMDIOMMU_CMDEVS_EVOVRFLWB 0x00008000 +#define AMDIOMMU_CMDEVS_EVLOGACTIVE 0x00010000 +#define AMDIOMMU_CMDEVS_PPROVRFLWEB 0x00020000 +#define AMDIOMMU_CMDEVS_PPROVRFLWE 0x00040000 + +/* + * Device Table Entry (DTE) + */ +struct amdiommu_dte { + u_int v:1; /* Valid */ + u_int tv:1; /* Translation Valid */ + u_int rsrv0:5; + u_int had:2; /* Host Access Dirty */ + u_int pgmode:3; /* Paging Mode */ + uint64_t ptroot:40; /* Page Table Root */ + u_int ppr:1; /* PPR En */ + u_int gprp:1; /* Guest PPR Resp with PASID */ + u_int giov:1; /* Guest IO Prot Valid */ + u_int gv:1; /* Guest Translation Valid */ + u_int glx:2; /* Guest Levels Translated */ + u_int gcr3root0:3; /* GCR3 root pointer part */ + u_int ir:1; /* Read Perm */ + u_int iw:1; /* Write Perm */ + u_int rsrv1:1; + u_int domainid:16; /* domain tag */ + u_int gcr3root1:16; /* GCR3 root pointer part */ + u_int i:1; /* IOTLB En */ + u_int se:1; /* Suppress IO Fault Events */ + u_int sa:1; /* Suppress All IO Fault Events */ + u_int pioctl:2; /* Port IO Control */ + u_int cache:1; /* IOTLB Cache Hint */ + u_int sd:1; /* Snoop Disable */ + u_int ex:1; /* Allow Exclusion */ + u_int sysmgt:2; /* System Management Msg Handling */ + u_int sats:1; /* Secure/Non-secure ATS */ + u_int gcr3root2:21; /* GCR3 root pointer part */ + u_int iv:1; /* Intr Map Valid */ + u_int inttablen:4; /* log2 Intr Table Len */ + u_int ig:1; /* Ignore Unmapped Interrupts */ + uint64_t intrroot:46; /* Interrupt Table Root (-low 6bits) */ + u_int rsrv2:2; + u_int gpm:2; /* Guest Paging Mode */ + u_int initpass:1; /* INIT pass-through */ + u_int eintpass:1; /* ExtInt pass-through */ + u_int nmipass:1; /* NMI pass-through */ + u_int hptmode:1; /* Host Page Table Mode Hint */ + u_int intctl:2; /* Interrupt Control */ + u_int lint0pass:1; /* LINT0 pass-through */ + u_int lint1pass:1; /* LINT1 pass-through */ + u_int rsrv3:15; + u_int vimu:1; /* Virtualize IOMMU En */ + u_int gdevid:16; /* Guest Dev Id */ + u_int gid:16; /* Guest Id */ + u_int rsrv4:5; + u_int rsrv5:1; /* Not Checked, sw avail */ + u_int attrv:1; /* Attr Override Valid */ + u_int mode0fc:1; /* Replace for PTE.FC */ + u_int snoopattr:8; /* GuestPTE.PAT -> ATS.N xlat */ +} __packed; +_Static_assert(sizeof(struct amdiommu_dte) == 8 * sizeof(uint32_t), "DTE"); + +#define AMDIOMMU_DTE_HAD_NAND 0x0 /* No Access, No Dirty */ +#define AMDIOMMU_DTE_HAD_AND 0x1 /* Access, No Dirty */ +#define AMDIOMMU_DTE_HAD_RSRV 0x2 +#define AMDIOMMU_DTE_HAD_AD 0x3 /* Access, Dirty */ + +#define AMDIOMMU_DTE_PGMODE_1T1 0x0 /* SPA = GPA */ +#define AMDIOMMU_DTE_PGMODE_1LV 0x1 /* 1 Level PT */ +#define AMDIOMMU_DTE_PGMODE_2LV 0x2 /* 2 Level PT */ +#define AMDIOMMU_DTE_PGMODE_3LV 0x3 /* 3 Level PT */ +#define AMDIOMMU_DTE_PGMODE_4LV 0x4 /* 4 Level PT */ +#define AMDIOMMU_DTE_PGMODE_5LV 0x5 /* 5 Level PT */ +#define AMDIOMMU_DTE_PGMODE_6LV 0x6 /* 6 Level PT */ +#define AMDIOMMU_DTE_PGMODE_RSRV 0x7 + +#define AMDIOMMU_DTE_GLX_1LV 0x0 /* 1 Level GCR3 */ +#define AMDIOMMU_DTE_GLX_2LV 0x1 /* 2 Level GCR3 */ +#define AMDIOMMU_DTE_GLX_3LV 0x2 /* 3 Level GCR3 */ +#define AMDIOMMU_DTE_GLX_RSRV 0x3 + +#define AMDIOMMU_DTE_PIOCTL_DIS 0x0 +#define AMDIOMMU_DTE_PIOCTL_EN 0x1 +#define AMDIOMMU_DTE_PIOCTL_MAP 0x2 +#define AMDIOMMU_DTE_PIOCTL_RSRV 0x3 + +#define AMDIOMMU_DTE_SYSMGT_DIS 0x0 /* Target Abort */ +#define AMDIOMMU_DTE_SYSMGT_FW 0x0 /* Forwarded All */ +#define AMDIOMMU_DTE_SYSMGT_FWI 0x0 /* Forwarded INT */ +#define AMDIOMMU_DTE_SYSMGT_T 0x0 /* Translated */ + +#define AMDIOMMU_DTE_GPM_4LV 0x0 /* 4 Level */ +#define AMDIOMMU_DTE_GPM_5LV 0x1 /* 4 Level */ +#define AMDIOMMU_DTE_GPM_RSRV1 0x2 +#define AMDIOMMU_DTE_GPM_RSRV2 0x3 + +#define AMDIOMMU_DTE_INTCTL_DIS 0x0 /* Target Abort */ +#define AMDIOMMU_DTE_INTCTL_FW 0x1 /* Forward Unmapped */ +#define AMDIOMMU_DTE_INTCTL_MAP 0x2 /* Forward Remapped */ +#define AMDIOMMU_DTE_INTCTL_RSRV 0x3 + +#define AMDIOMMU_PGTBL_MAXLVL 6 + +/* + * Page Table Entry (PTE/PDE) + */ +#define AMDIOMMU_PTE_PR 0x0001 /* Present, AKA V */ +#define AMDIOMMU_IGN1 0x0002 +#define AMDIOMMU_IGN2 0x0004 +#define AMDIOMMU_IGN3 0x0008 +#define AMDIOMMU_IGN4 0x0010 +#define AMDIOMMU_PTE_A 0x0020 /* Accessed */ +#define AMDIOMMU_PTE_D 0x0040 /* Dirty */ +#define AMDIOMMU_IGN5 0x0080 +#define AMDIOMMU_IGN6 0x0100 +#define AMDIOMMU_PTE_NLVL_MASK 0x0e00 /* Next Level */ +#define AMDIOMMU_PTE_NLVL_SHIFT 9 +#define AMDIOMMU_PTE_NLVL_7h 0x0e00 /* Magic Next Level */ +#define AMDIOMMU_PTE_PA_MASK 0x000ffffffffff000ull +#define AMDIOMMU_PTE_PA_SHIFT 12 +#define AMDIOMMU_PTE_PMC_MASK 0x0600000000000000ull /* Page Migr */ +#define AMDIOMMU_PTE_U 0x0800000000000000ull /* ATS.U */ +#define AMDIOMMU_PTE_FC 0x1000000000000000ull /* Force Coh */ +#define AMDIOMMU_PTE_IR 0x2000000000000000ull /* Read Perm */ +#define AMDIOMMU_PTE_IW 0x4000000000000000ull /* Write Perm */ +#define AMDIOMMU_PTE_IGN7 0x8000000000000000ull + +/* + * IRTEs + */ + +/* vAPIC is not enabled, guestmode = 0 */ +struct amdiommu_irte_basic_novapic { + u_int remapen:1; /* 0 - Target Abort */ + u_int supiopf:1; /* Supress IO_PAGE_FAULT events */ + u_int inttype:3; + u_int rqeoi:1; /* Request EOI */ + u_int dm:1; /* Dest Mode */ + u_int guestmode:1; /* MBZ */ + u_int dest:8; /* Destination APIC */ + u_int vector:8; + u_int rsrv:8; +} __packed; +_Static_assert(sizeof(struct amdiommu_irte_basic_novapic) == + 1 * sizeof(uint32_t), "IRTE 1"); + +/* vAPIC is enabled, guestmode = 0 */ +struct amdiommu_irte_basic_vapic { + u_int remapen:1; /* 0 - Target Abort */ + u_int supiopf:1; /* Supress IO_PAGE_FAULT events */ + u_int inttype:3; + u_int rqeoi:1; /* Request EOI */ + u_int dm:1; /* Dest Mode */ + u_int guestmode:1; /* MBZ */ + u_int dest:8; /* Destination APIC */ + u_int rsrv0:16; + u_int rsrv1:32; + u_int vector:8; + u_int rsrv2:24; + u_int rsrv3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_irte_basic_vapic) == + 4 * sizeof(uint32_t), "IRTE 2"); + +/* vAPIC is enabled, guestmode = 1 */ +struct amdiommu_irte_guest_vapic { + u_int remapen:1; /* 0 - Target Abort */ + u_int supiopf:1; /* Supress IO_PAGE_FAULT events */ + u_int galogintr:1; + u_int rsrv0:2; + u_int gappidis:1; /* supress GAPPI */ + u_int isrun:1; /* Guest Running hint */ + u_int guestmode:1; /* MB1 */ + u_int dest:8; /* Destination APIC for dorbell */ + u_int rsrv1:16; + u_int gatag:32; + u_int vector:8; + u_int rsrv2:4; + uint64_t vapicrp:40; /* 51:12 bits of SPA for APIC backing page */ + u_int rsrv3:12; +} __packed; +_Static_assert(sizeof(struct amdiommu_irte_guest_vapic) == + 4 * sizeof(uint32_t), "IRTE 3"); + +/* vAPIC is enabled, guestmode = 0, x2APIC */ +struct amdiommu_irte_basic_vapic_x2 { + u_int remapen:1; /* 0 - Target Abort */ + u_int supiopf:1; /* Supress IO_PAGE_FAULT events */ + u_int inttype:3; + u_int rqeoi:1; /* Request EOI */ + u_int dm:1; /* Dest Mode */ + u_int guestmode:1; /* MBZ */ + u_int dest0:24; /* Destination APIC 23:0 */ + u_int rsrv0:32; + u_int vector:8; + u_int rsrv1:24; + u_int rsrv2:24; + u_int dest1:8; /* Destination APIC 31:24 */ +} __packed; +_Static_assert(sizeof(struct amdiommu_irte_basic_vapic_x2) == + 4 * sizeof(uint32_t), "IRTE 4"); + +/* vAPIC is enabled, guestmode = 1, x2APIC */ +struct amdiommu_irte_guest_vapic_x2 { + u_int remapen:1; /* 0 - Target Abort */ + u_int supiopf:1; /* Supress IO_PAGE_FAULT events */ + u_int galogintr:1; + u_int rsrv0:2; + u_int gappidis:1; /* supress GAPPI */ + u_int isrun:1; /* Guest Running hint */ + u_int guestmode:1; /* MB1 */ + u_int dest0:24; /* Destination APIC for dorbell 23:0 */ + u_int gatag:32; + u_int vector:8; + u_int rsrv2:4; + uint64_t vapicrp:40; /* 51:12 bits of SPA for APIC backing page */ + u_int rsrv3:4; + u_int dest1:8; /* Destination APIC 31:24 */ +} __packed; +_Static_assert(sizeof(struct amdiommu_irte_guest_vapic_x2) == + 4 * sizeof(uint32_t), "IRTE 5"); + +#define AMDIOMMU_IRTE_INTTYPE_FIXED 0 +#define AMDIOMMU_IRTE_INTTYPE_ARBITR 1 + +#define AMDIOMMU_IRTE_DM_LOGICAL 1 +#define AMDIOMMU_IRTE_DM_PHYSICAL 1 + +/* + * Commands + */ + +struct amdiommu_cmd_generic { + u_int w0:32; + union { + u_int ww1:32; + struct { + u_int w1:28; + u_int op:4; + }; + }; + u_int w2:32; + u_int w3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_generic) == + 4 * sizeof(uint32_t), "CMD_GENERIC"); + +#define AMDIOMMU_CMD_SZ_SHIFT 4 /* Shift for cmd count + to ring offset */ +#define AMDIOMMU_CMD_SZ sizeof(struct amdiommu_cmd_generic) + /* Command size */ +_Static_assert((1 << AMDIOMMU_CMD_SZ_SHIFT) == AMDIOMMU_CMD_SZ, + "CMD size shift"); + +struct amdiommu_cmd_completion_wait { + u_int s:1; + u_int i:1; + u_int f:1; + u_int address0:29; /* Store Address 31:3 */ + u_int address1:20; /* Store Address 51:32 */ + u_int rsrv:8; + u_int op:4; + u_int data0:32; + u_int data1:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_completion_wait) == + 4 * sizeof(uint32_t), "CMD_COMPLETION_WAIT"); + +struct amdiommu_cmd_invalidate_devtab_entry { + u_int devid:16; + u_int rsrv0:16; + u_int rsrv1:28; + u_int op:4; + u_int rsrv2:32; + u_int rsrv3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_invalidate_devtab_entry) == + 4 * sizeof(uint32_t), "CMD_INVALIDATE_DEVTAB_ENTRY"); + +struct amdiommu_cmd_invalidate_iommu_pages { + u_int pasid:20; + u_int rsrv0:12; + u_int domainid:16; + u_int rsrv1:12; + u_int op:4; + u_int s:1; + u_int pde:1; + u_int gn:1; + u_int rsrv2:9; + uint64_t address:52; /* Address 63:12 */ +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_invalidate_iommu_pages) == + 4 * sizeof(uint32_t), "CMD_INVALIDATE_IOMMU_PAGES"); + +struct amdiommu_cmd_invalidate_iotlb_pages { + u_int devid:16; + u_int pasid1:8; + u_int maxpend0:8; + u_int queueid:16; + u_int pasid0:8; + u_int pasid2:4; + u_int op:4; + u_int s:1; + u_int rsrv0:1; + u_int gn:1; + u_int rsrv1:1; + u_int type:2; + u_int rsrv2:6; + uint64_t address:52; /* Address 63:12 */ +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_invalidate_iotlb_pages) == + 4 * sizeof(uint32_t), "CMD_INVALIDATE_IOTLB_PAGES"); + +struct amdiommu_cmd_invalidate_interrupt_table { + u_int devid:16; + u_int rsrv0:16; + u_int rsrv1:28; + u_int op:4; + u_int rsrv2:32; + u_int rsrv3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_invalidate_interrupt_table) == + 4 * sizeof(uint32_t), "CMD_INVALIDATE_INTERRUPT_TABLE"); + +struct amdiommu_cmd_prefetch_iommu_pages { + u_int devid:16; + u_int rsrv0:8; + u_int pfcount:8; + u_int pasid:20; + u_int rsrv1:8; + u_int op:4; + u_int s:1; + u_int rsrv2:1; + u_int gn:1; + u_int rsrv3:1; + u_int inval:1; /* Invalidate First */ + u_int rsrv4:7; + uint64_t address:52; /* Address 63:12 */ +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_prefetch_iommu_pages) == + 4 * sizeof(uint32_t), "CMD_PREFETCH_IOMMU_PAGES"); + +struct amdiommu_cmd_complete_ppr_request { + u_int devid:16; + u_int rsrv0:16; + u_int pasid:20; + u_int rsrv1:8; + u_int op:4; + u_int rsrv2:2; + u_int gn:1; + u_int rsrv3:29; + u_int compltag:16; + u_int rsrv4:16; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_complete_ppr_request) == + 4 * sizeof(uint32_t), "CMD_COMPLETE_PPR_REQUEST"); + +struct amdiommu_cmd_invalidate_iommu_all { + u_int rsrv0:32; + u_int op:4; + u_int rsrv1:28; + u_int rsrv2:32; + u_int rsrv3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_invalidate_iommu_all) == + 4 * sizeof(uint32_t), "CMD_INVALIDATE_IOMMU_ALL"); + +struct amdiommu_cmd_insert_guest_event { + u_int rsrv0:32; + u_int guestid:16; + u_int rsrv1:12; + u_int op:4; + u_int rsrv2:32; + u_int rsrv3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_insert_guest_event) == + 4 * sizeof(uint32_t), "CMD_INSERT_GUEST_EVENT"); + +struct amdiommu_cmd_reset_vmmio { + u_int guestid:16; + u_int rsrv0:11; + u_int all:1; + u_int rsrv1:3; + u_int vcmd:1; + u_int rsrv2:27; + u_int op:4; + u_int rsrv3:32; + u_int rsrv4:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_cmd_reset_vmmio) == + 4 * sizeof(uint32_t), "CMD_RESET_VMMIO"); + +#define AMDIOMMU_CMD_COMPLETION_WAIT 0x1 +#define AMDIOMMU_CMD_INVALIDATE_DEVTAB_ENTRY 0x2 +#define AMDIOMMU_CMD_INVALIDATE_IOMMU_PAGES 0x3 +#define AMDIOMMU_CMD_INVALIDATE_IOTLB_PAGES 0x4 +#define AMDIOMMU_CMD_INVALIDATE_INTERRUPT_TABLE 0x5 +#define AMDIOMMU_CMD_PREFETCH_IOMMU_PAGES 0x6 +#define AMDIOMMU_CMD_COMPLETE_PPR_REQUEST 0x7 +#define AMDIOMMU_CMD_INVALIDATE_IOMMU_ALL 0x8 +#define AMDIOMMU_CMD_INSERT_GUEST_EVENT 0x9 +#define AMDIOMMU_CMD_RESET_VMMIO 0xa + +/* + * Logging + */ +struct amdiommu_event_generic { + u_int w0:32; + union { + u_int ww1:32; + struct { + u_int w1:28; + u_int code:4; + }; + }; + u_int w2:32; + u_int w3:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_event_generic) == + 4 * sizeof(uint32_t), "EVENT_GENERIC"); + +#define AMDIOMMU_EV_SZ_SHIFT 4 /* Shift for event count + to ring offset */ +#define AMDIOMMU_EV_SZ sizeof(struct amdiommu_event_generic) + /* Event size */ +_Static_assert((1 << AMDIOMMU_EV_SZ_SHIFT) == AMDIOMMU_EV_SZ, + "Event size shift"); + +struct amdiommu_event_ill_dev_table_entry { + u_int devid:16; + u_int pasid1:4; + u_int rsrv0:7; + u_int vnr:1; + u_int rsrv1:1; + u_int vevent:1; + u_int vptr:1; + u_int vcmd:1; + u_int pasid:16; + u_int gn:1; + u_int rsrv2:2; + u_int i:1; + u_int rsrv3:1; + u_int rw:1; + u_int rsrv4:1; + u_int rz:1; + u_int tr:1; + u_int rsrv5:3; + u_int code:4; + u_int rsrv6:2; + u_int addr1:30; + u_int addr2:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_event_ill_dev_table_entry) == + 4 * sizeof(uint32_t), "EVENT_ILLEGAL_DEV_TABLE_ENTRY"); + +struct amdiommu_event_io_page_fault_entry { + u_int devid:16; + u_int pasid1:4; + u_int rsrv0:7; + u_int vnr:1; + u_int rsrv1:1; + u_int vevent:1; + u_int vptr:1; + u_int vcmd:1; + u_int pasid:16; /* also domain id */ + u_int gn:1; + u_int nx:1; + u_int us:1; + u_int i:1; + u_int pr:1; + u_int rw:1; + u_int pe:1; + u_int rz:1; + u_int tr:1; + u_int rsrv2:3; + u_int code:4; + u_int addr1:32; + u_int addr2:32; +} __packed; +_Static_assert(sizeof(struct amdiommu_event_io_page_fault_entry) == + 4 * sizeof(uint32_t), "EVENT_IO_PAGE_FAULT_ENTRY"); + +#define AMDIOMMU_EV_ILL_DEV_TABLE_ENTRY 0x1 +#define AMDIOMMU_EV_IO_PAGE_FAULT 0x2 +#define AMDIOMMU_EV_DEV_TAB_HW_ERROR 0x3 +#define AMDIOMMU_EV_PAGE_TAB_HW_ERROR 0x4 +#define AMDIOMMU_EV_ILL_CMD_ERROR 0x5 +#define AMDIOMMU_EV_CMD_HW_ERROR 0x6 +#define AMDIOMMU_EV_IOTLB_INV_TIMEOUT 0x7 +#define AMDIOMMU_EV_INVALID_DEV_REQ 0x8 +#define AMDIOMMU_EV_INVALID_PPR_REQ 0x9 +#define AMDIOMMU_EV_COUNTER_ZERO 0xa /* Typo in table 42? */ + +#endif /* __X86_IOMMU_AMD_REG_H */