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