2 * QEMU sun4u IOMMU emulation
4 * Copyright (c) 2006 Fabrice Bellard
5 * Copyright (c) 2012,2013 Artyom Tarasenko
6 * Copyright (c) 2017 Mark Cave-Ayland
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "qemu/osdep.h"
28 #include "hw/sysbus.h"
29 #include "hw/sparc/sun4u_iommu.h"
30 #include "exec/address-spaces.h"
35 #define IOMMU_PAGE_SIZE_8K (1ULL << 13)
36 #define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
37 #define IOMMU_PAGE_SIZE_64K (1ULL << 16)
38 #define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
40 #define IOMMU_CTRL 0x0
41 #define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
42 #define IOMMU_CTRL_MMU_EN (1ULL)
44 #define IOMMU_CTRL_TSB_SHIFT 16
46 #define IOMMU_BASE 0x8
47 #define IOMMU_FLUSH 0x10
49 #define IOMMU_TTE_DATA_V (1ULL << 63)
50 #define IOMMU_TTE_DATA_SIZE (1ULL << 61)
51 #define IOMMU_TTE_DATA_W (1ULL << 1)
53 #define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
54 #define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
56 #define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
57 #define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
58 #define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
59 #define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
60 #define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
61 #define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
62 #define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
63 #define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
65 #define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
66 #define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
67 #define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
68 #define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
69 #define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
70 #define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
73 /* Called from RCU critical section */
74 static IOMMUTLBEntry
sun4u_translate_iommu(IOMMUMemoryRegion
*iommu
,
76 IOMMUAccessFlags flag
, int iommu_idx
)
78 IOMMUState
*is
= container_of(iommu
, IOMMUState
, iommu
);
79 hwaddr baseaddr
, offset
;
83 .target_as
= &address_space_memory
,
86 .addr_mask
= ~(hwaddr
)0,
90 if (!(is
->regs
[IOMMU_CTRL
>> 3] & IOMMU_CTRL_MMU_EN
)) {
91 /* IOMMU disabled, passthrough using standard 8K page */
92 ret
.iova
= addr
& IOMMU_PAGE_MASK_8K
;
93 ret
.translated_addr
= addr
;
94 ret
.addr_mask
= IOMMU_PAGE_MASK_8K
;
100 baseaddr
= is
->regs
[IOMMU_BASE
>> 3];
101 tsbsize
= (is
->regs
[IOMMU_CTRL
>> 3] >> IOMMU_CTRL_TSB_SHIFT
) & 0x7;
103 if (is
->regs
[IOMMU_CTRL
>> 3] & IOMMU_CTRL_TBW_SIZE
) {
107 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_64M
) >> 13;
110 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_128M
) >> 13;
113 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_256M
) >> 13;
116 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_512M
) >> 13;
119 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_1G
) >> 13;
122 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_2G
) >> 13;
125 /* Not implemented, error */
132 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_8M
) >> 10;
135 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_16M
) >> 10;
138 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_32M
) >> 10;
141 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_64M
) >> 10;
144 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_128M
) >> 10;
147 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_256M
) >> 10;
150 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_512M
) >> 10;
153 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_1G
) >> 10;
158 tte
= address_space_ldq_be(&address_space_memory
, baseaddr
+ offset
,
159 MEMTXATTRS_UNSPECIFIED
, NULL
);
161 if (!(tte
& IOMMU_TTE_DATA_V
)) {
162 /* Invalid mapping */
166 if (tte
& IOMMU_TTE_DATA_W
) {
174 if (tte
& IOMMU_TTE_DATA_SIZE
) {
176 ret
.iova
= addr
& IOMMU_PAGE_MASK_64K
;
177 ret
.translated_addr
= tte
& IOMMU_TTE_PHYS_MASK_64K
;
178 ret
.addr_mask
= (IOMMU_PAGE_SIZE_64K
- 1);
181 ret
.iova
= addr
& IOMMU_PAGE_MASK_8K
;
182 ret
.translated_addr
= tte
& IOMMU_TTE_PHYS_MASK_8K
;
183 ret
.addr_mask
= (IOMMU_PAGE_SIZE_8K
- 1);
186 trace_sun4u_iommu_translate(ret
.iova
, ret
.translated_addr
, tte
);
191 static void iommu_mem_write(void *opaque
, hwaddr addr
,
192 uint64_t val
, unsigned size
)
194 IOMMUState
*is
= opaque
;
196 trace_sun4u_iommu_mem_write(addr
, val
, size
);
201 is
->regs
[IOMMU_CTRL
>> 3] &= 0xffffffffULL
;
202 is
->regs
[IOMMU_CTRL
>> 3] |= val
<< 32;
204 is
->regs
[IOMMU_CTRL
>> 3] = val
;
207 case IOMMU_CTRL
+ 0x4:
208 is
->regs
[IOMMU_CTRL
>> 3] &= 0xffffffff00000000ULL
;
209 is
->regs
[IOMMU_CTRL
>> 3] |= val
& 0xffffffffULL
;
213 is
->regs
[IOMMU_BASE
>> 3] &= 0xffffffffULL
;
214 is
->regs
[IOMMU_BASE
>> 3] |= val
<< 32;
216 is
->regs
[IOMMU_BASE
>> 3] = val
;
219 case IOMMU_BASE
+ 0x4:
220 is
->regs
[IOMMU_BASE
>> 3] &= 0xffffffff00000000ULL
;
221 is
->regs
[IOMMU_BASE
>> 3] |= val
& 0xffffffffULL
;
224 case IOMMU_FLUSH
+ 0x4:
227 qemu_log_mask(LOG_UNIMP
,
228 "sun4u-iommu: Unimplemented register write "
229 "reg 0x%" HWADDR_PRIx
" size 0x%x value 0x%" PRIx64
"\n",
235 static uint64_t iommu_mem_read(void *opaque
, hwaddr addr
, unsigned size
)
237 IOMMUState
*is
= opaque
;
243 val
= is
->regs
[IOMMU_CTRL
>> 3] >> 32;
245 val
= is
->regs
[IOMMU_CTRL
>> 3];
248 case IOMMU_CTRL
+ 0x4:
249 val
= is
->regs
[IOMMU_CTRL
>> 3] & 0xffffffffULL
;
253 val
= is
->regs
[IOMMU_BASE
>> 3] >> 32;
255 val
= is
->regs
[IOMMU_BASE
>> 3];
258 case IOMMU_BASE
+ 0x4:
259 val
= is
->regs
[IOMMU_BASE
>> 3] & 0xffffffffULL
;
262 case IOMMU_FLUSH
+ 0x4:
266 qemu_log_mask(LOG_UNIMP
,
267 "sun4u-iommu: Unimplemented register read "
268 "reg 0x%" HWADDR_PRIx
" size 0x%x\n",
274 trace_sun4u_iommu_mem_read(addr
, val
, size
);
279 static const MemoryRegionOps iommu_mem_ops
= {
280 .read
= iommu_mem_read
,
281 .write
= iommu_mem_write
,
282 .endianness
= DEVICE_BIG_ENDIAN
,
285 static void iommu_reset(DeviceState
*d
)
287 IOMMUState
*s
= SUN4U_IOMMU(d
);
289 memset(s
->regs
, 0, IOMMU_NREGS
* sizeof(uint64_t));
292 static void iommu_init(Object
*obj
)
294 IOMMUState
*s
= SUN4U_IOMMU(obj
);
295 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
297 memory_region_init_iommu(&s
->iommu
, sizeof(s
->iommu
),
298 TYPE_SUN4U_IOMMU_MEMORY_REGION
, OBJECT(s
),
299 "iommu-sun4u", UINT64_MAX
);
300 address_space_init(&s
->iommu_as
, MEMORY_REGION(&s
->iommu
), "iommu-as");
302 memory_region_init_io(&s
->iomem
, obj
, &iommu_mem_ops
, s
, "iommu",
303 IOMMU_NREGS
* sizeof(uint64_t));
304 sysbus_init_mmio(sbd
, &s
->iomem
);
307 static void iommu_class_init(ObjectClass
*klass
, void *data
)
309 DeviceClass
*dc
= DEVICE_CLASS(klass
);
311 dc
->reset
= iommu_reset
;
314 static const TypeInfo iommu_info
= {
315 .name
= TYPE_SUN4U_IOMMU
,
316 .parent
= TYPE_SYS_BUS_DEVICE
,
317 .instance_size
= sizeof(IOMMUState
),
318 .instance_init
= iommu_init
,
319 .class_init
= iommu_class_init
,
322 static void sun4u_iommu_memory_region_class_init(ObjectClass
*klass
, void *data
)
324 IOMMUMemoryRegionClass
*imrc
= IOMMU_MEMORY_REGION_CLASS(klass
);
326 imrc
->translate
= sun4u_translate_iommu
;
329 static const TypeInfo sun4u_iommu_memory_region_info
= {
330 .parent
= TYPE_IOMMU_MEMORY_REGION
,
331 .name
= TYPE_SUN4U_IOMMU_MEMORY_REGION
,
332 .class_init
= sun4u_iommu_memory_region_class_init
,
335 static void iommu_register_types(void)
337 type_register_static(&iommu_info
);
338 type_register_static(&sun4u_iommu_memory_region_info
);
341 type_init(iommu_register_types
)