xref: /qemu/hw/riscv/riscv-iommu.h (revision 9ee727802012ddb32e193d84052a44e382088277)
1 /*
2  * QEMU emulation of an RISC-V IOMMU
3  *
4  * Copyright (C) 2022-2023 Rivos Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2 or later, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef HW_RISCV_IOMMU_STATE_H
20 #define HW_RISCV_IOMMU_STATE_H
21 
22 #include "qom/object.h"
23 #include "hw/qdev-properties.h"
24 #include "system/dma.h"
25 #include "hw/riscv/iommu.h"
26 #include "hw/riscv/riscv-iommu-bits.h"
27 
28 typedef enum riscv_iommu_igs_modes riscv_iommu_igs_mode;
29 
30 struct RISCVIOMMUState {
31     /*< private >*/
32     DeviceState parent_obj;
33 
34     /*< public >*/
35     uint32_t version;     /* Reported interface version number */
36     uint32_t pid_bits;    /* process identifier width */
37     uint32_t bus;         /* PCI bus mapping for non-root endpoints */
38 
39     uint64_t cap;         /* IOMMU supported capabilities */
40     uint64_t fctl;        /* IOMMU enabled features */
41     uint64_t icvec_avail_vectors;  /* Available interrupt vectors in ICVEC */
42 
43     bool enable_off;      /* Enable out-of-reset OFF mode (DMA disabled) */
44     bool enable_msi;      /* Enable MSI remapping */
45     bool enable_ats;      /* Enable ATS support */
46     bool enable_s_stage;  /* Enable S/VS-Stage translation */
47     bool enable_g_stage;  /* Enable G-Stage translation */
48 
49     /* IOMMU Internal State */
50     uint64_t ddtp;        /* Validated Device Directory Tree Root Pointer */
51 
52     dma_addr_t cq_addr;   /* Command queue base physical address */
53     dma_addr_t fq_addr;   /* Fault/event queue base physical address */
54     dma_addr_t pq_addr;   /* Page request queue base physical address */
55 
56     uint32_t cq_mask;     /* Command queue index bit mask */
57     uint32_t fq_mask;     /* Fault/event queue index bit mask */
58     uint32_t pq_mask;     /* Page request queue index bit mask */
59 
60     /* interrupt notifier */
61     void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
62 
63     /* IOMMU target address space */
64     AddressSpace *target_as;
65     MemoryRegion *target_mr;
66 
67     /* MSI / MRIF access trap */
68     AddressSpace trap_as;
69     MemoryRegion trap_mr;
70 
71     GHashTable *ctx_cache;          /* Device translation Context Cache */
72 
73     GHashTable *iot_cache;          /* IO Translated Address Cache */
74     unsigned iot_limit;             /* IO Translation Cache size limit */
75 
76     /* MMIO Hardware Interface */
77     MemoryRegion regs_mr;
78     uint8_t *regs_rw;  /* register state (user write) */
79     uint8_t *regs_wc;  /* write-1-to-clear mask */
80     uint8_t *regs_ro;  /* read-only mask */
81 
82     QLIST_ENTRY(RISCVIOMMUState) iommus;
83     QLIST_HEAD(, RISCVIOMMUSpace) spaces;
84 
85     /* HPM cycle counter */
86     QEMUTimer *hpm_timer;
87     uint64_t hpmcycle_val;      /* Current value of cycle register */
88     uint64_t hpmcycle_prev;     /* Saved value of QEMU_CLOCK_VIRTUAL clock */
89     uint64_t irq_overflow_left; /* Value beyond INT64_MAX after overflow */
90 
91     /* HPM event counters */
92     GHashTable *hpm_event_ctr_map; /* Mapping of events to counters */
93     uint8_t hpm_cntrs;
94 };
95 
96 void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
97          Error **errp);
98 void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
99 void riscv_iommu_reset(RISCVIOMMUState *s);
100 void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
101 
102 typedef struct RISCVIOMMUContext RISCVIOMMUContext;
103 /* Device translation context state. */
104 struct RISCVIOMMUContext {
105     uint64_t devid:24;          /* Requester Id, AKA device_id */
106     uint64_t process_id:20;     /* Process ID. PASID for PCIe */
107     uint64_t tc;                /* Translation Control */
108     uint64_t ta;                /* Translation Attributes */
109     uint64_t satp;              /* S-Stage address translation and protection */
110     uint64_t gatp;              /* G-Stage address translation and protection */
111     uint64_t msi_addr_mask;     /* MSI filtering - address mask */
112     uint64_t msi_addr_pattern;  /* MSI filtering - address pattern */
113     uint64_t msiptp;            /* MSI redirection page table pointer */
114 };
115 
116 /* private helpers */
117 
118 /* Register helper functions */
riscv_iommu_reg_mod32(RISCVIOMMUState * s,unsigned idx,uint32_t set,uint32_t clr)119 static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
120     unsigned idx, uint32_t set, uint32_t clr)
121 {
122     uint32_t val = ldl_le_p(s->regs_rw + idx);
123     stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
124     return val;
125 }
126 
riscv_iommu_reg_set32(RISCVIOMMUState * s,unsigned idx,uint32_t set)127 static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
128                                          uint32_t set)
129 {
130     stl_le_p(s->regs_rw + idx, set);
131 }
132 
riscv_iommu_reg_get32(RISCVIOMMUState * s,unsigned idx)133 static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
134 {
135     return ldl_le_p(s->regs_rw + idx);
136 }
137 
riscv_iommu_reg_mod64(RISCVIOMMUState * s,unsigned idx,uint64_t set,uint64_t clr)138 static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
139                                              uint64_t set, uint64_t clr)
140 {
141     uint64_t val = ldq_le_p(s->regs_rw + idx);
142     stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
143     return val;
144 }
145 
riscv_iommu_reg_set64(RISCVIOMMUState * s,unsigned idx,uint64_t set)146 static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
147                                          uint64_t set)
148 {
149     stq_le_p(s->regs_rw + idx, set);
150 }
151 
riscv_iommu_reg_get64(RISCVIOMMUState * s,unsigned idx)152 static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
153     unsigned idx)
154 {
155     return ldq_le_p(s->regs_rw + idx);
156 }
157 #endif
158