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"
32 #include "qemu/module.h"
36 #define IOMMU_PAGE_SIZE_8K (1ULL << 13)
37 #define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
38 #define IOMMU_PAGE_SIZE_64K (1ULL << 16)
39 #define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
41 #define IOMMU_CTRL 0x0
42 #define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
43 #define IOMMU_CTRL_MMU_EN (1ULL)
45 #define IOMMU_CTRL_TSB_SHIFT 16
47 #define IOMMU_BASE 0x8
48 #define IOMMU_FLUSH 0x10
50 #define IOMMU_TTE_DATA_V (1ULL << 63)
51 #define IOMMU_TTE_DATA_SIZE (1ULL << 61)
52 #define IOMMU_TTE_DATA_W (1ULL << 1)
54 #define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
55 #define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
57 #define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
58 #define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
59 #define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
60 #define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
61 #define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
62 #define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
63 #define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
64 #define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
66 #define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
67 #define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
68 #define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
69 #define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
70 #define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
71 #define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
74 /* Called from RCU critical section */
75 static IOMMUTLBEntry
sun4u_translate_iommu(IOMMUMemoryRegion
*iommu
,
77 IOMMUAccessFlags flag
, int iommu_idx
)
79 IOMMUState
*is
= container_of(iommu
, IOMMUState
, iommu
);
80 hwaddr baseaddr
, offset
;
84 .target_as
= &address_space_memory
,
87 .addr_mask
= ~(hwaddr
)0,
91 if (!(is
->regs
[IOMMU_CTRL
>> 3] & IOMMU_CTRL_MMU_EN
)) {
92 /* IOMMU disabled, passthrough using standard 8K page */
93 ret
.iova
= addr
& IOMMU_PAGE_MASK_8K
;
94 ret
.translated_addr
= addr
;
95 ret
.addr_mask
= IOMMU_PAGE_MASK_8K
;
101 baseaddr
= is
->regs
[IOMMU_BASE
>> 3];
102 tsbsize
= (is
->regs
[IOMMU_CTRL
>> 3] >> IOMMU_CTRL_TSB_SHIFT
) & 0x7;
104 if (is
->regs
[IOMMU_CTRL
>> 3] & IOMMU_CTRL_TBW_SIZE
) {
108 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_64M
) >> 13;
111 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_128M
) >> 13;
114 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_256M
) >> 13;
117 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_512M
) >> 13;
120 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_1G
) >> 13;
123 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_2G
) >> 13;
126 /* Not implemented, error */
133 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_8M
) >> 10;
136 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_16M
) >> 10;
139 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_32M
) >> 10;
142 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_64M
) >> 10;
145 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_128M
) >> 10;
148 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_256M
) >> 10;
151 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_512M
) >> 10;
154 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_1G
) >> 10;
159 tte
= address_space_ldq_be(&address_space_memory
, baseaddr
+ offset
,
160 MEMTXATTRS_UNSPECIFIED
, NULL
);
162 if (!(tte
& IOMMU_TTE_DATA_V
)) {
163 /* Invalid mapping */
167 if (tte
& IOMMU_TTE_DATA_W
) {
175 if (tte
& IOMMU_TTE_DATA_SIZE
) {
177 ret
.iova
= addr
& IOMMU_PAGE_MASK_64K
;
178 ret
.translated_addr
= tte
& IOMMU_TTE_PHYS_MASK_64K
;
179 ret
.addr_mask
= (IOMMU_PAGE_SIZE_64K
- 1);
182 ret
.iova
= addr
& IOMMU_PAGE_MASK_8K
;
183 ret
.translated_addr
= tte
& IOMMU_TTE_PHYS_MASK_8K
;
184 ret
.addr_mask
= (IOMMU_PAGE_SIZE_8K
- 1);
187 trace_sun4u_iommu_translate(ret
.iova
, ret
.translated_addr
, tte
);
192 static void iommu_mem_write(void *opaque
, hwaddr addr
,
193 uint64_t val
, unsigned size
)
195 IOMMUState
*is
= opaque
;
197 trace_sun4u_iommu_mem_write(addr
, val
, size
);
202 is
->regs
[IOMMU_CTRL
>> 3] &= 0xffffffffULL
;
203 is
->regs
[IOMMU_CTRL
>> 3] |= val
<< 32;
205 is
->regs
[IOMMU_CTRL
>> 3] = val
;
208 case IOMMU_CTRL
+ 0x4:
209 is
->regs
[IOMMU_CTRL
>> 3] &= 0xffffffff00000000ULL
;
210 is
->regs
[IOMMU_CTRL
>> 3] |= val
& 0xffffffffULL
;
214 is
->regs
[IOMMU_BASE
>> 3] &= 0xffffffffULL
;
215 is
->regs
[IOMMU_BASE
>> 3] |= val
<< 32;
217 is
->regs
[IOMMU_BASE
>> 3] = val
;
220 case IOMMU_BASE
+ 0x4:
221 is
->regs
[IOMMU_BASE
>> 3] &= 0xffffffff00000000ULL
;
222 is
->regs
[IOMMU_BASE
>> 3] |= val
& 0xffffffffULL
;
225 case IOMMU_FLUSH
+ 0x4:
228 qemu_log_mask(LOG_UNIMP
,
229 "sun4u-iommu: Unimplemented register write "
230 "reg 0x%" HWADDR_PRIx
" size 0x%x value 0x%" PRIx64
"\n",
236 static uint64_t iommu_mem_read(void *opaque
, hwaddr addr
, unsigned size
)
238 IOMMUState
*is
= opaque
;
244 val
= is
->regs
[IOMMU_CTRL
>> 3] >> 32;
246 val
= is
->regs
[IOMMU_CTRL
>> 3];
249 case IOMMU_CTRL
+ 0x4:
250 val
= is
->regs
[IOMMU_CTRL
>> 3] & 0xffffffffULL
;
254 val
= is
->regs
[IOMMU_BASE
>> 3] >> 32;
256 val
= is
->regs
[IOMMU_BASE
>> 3];
259 case IOMMU_BASE
+ 0x4:
260 val
= is
->regs
[IOMMU_BASE
>> 3] & 0xffffffffULL
;
263 case IOMMU_FLUSH
+ 0x4:
267 qemu_log_mask(LOG_UNIMP
,
268 "sun4u-iommu: Unimplemented register read "
269 "reg 0x%" HWADDR_PRIx
" size 0x%x\n",
275 trace_sun4u_iommu_mem_read(addr
, val
, size
);
280 static const MemoryRegionOps iommu_mem_ops
= {
281 .read
= iommu_mem_read
,
282 .write
= iommu_mem_write
,
283 .endianness
= DEVICE_BIG_ENDIAN
,
286 static void iommu_reset(DeviceState
*d
)
288 IOMMUState
*s
= SUN4U_IOMMU(d
);
290 memset(s
->regs
, 0, IOMMU_NREGS
* sizeof(uint64_t));
293 static void iommu_init(Object
*obj
)
295 IOMMUState
*s
= SUN4U_IOMMU(obj
);
296 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
298 memory_region_init_iommu(&s
->iommu
, sizeof(s
->iommu
),
299 TYPE_SUN4U_IOMMU_MEMORY_REGION
, OBJECT(s
),
300 "iommu-sun4u", UINT64_MAX
);
301 address_space_init(&s
->iommu_as
, MEMORY_REGION(&s
->iommu
), "iommu-as");
303 memory_region_init_io(&s
->iomem
, obj
, &iommu_mem_ops
, s
, "iommu",
304 IOMMU_NREGS
* sizeof(uint64_t));
305 sysbus_init_mmio(sbd
, &s
->iomem
);
308 static void iommu_class_init(ObjectClass
*klass
, void *data
)
310 DeviceClass
*dc
= DEVICE_CLASS(klass
);
312 device_class_set_legacy_reset(dc
, iommu_reset
);
315 static const TypeInfo iommu_info
= {
316 .name
= TYPE_SUN4U_IOMMU
,
317 .parent
= TYPE_SYS_BUS_DEVICE
,
318 .instance_size
= sizeof(IOMMUState
),
319 .instance_init
= iommu_init
,
320 .class_init
= iommu_class_init
,
323 static void sun4u_iommu_memory_region_class_init(ObjectClass
*klass
, void *data
)
325 IOMMUMemoryRegionClass
*imrc
= IOMMU_MEMORY_REGION_CLASS(klass
);
327 imrc
->translate
= sun4u_translate_iommu
;
330 static const TypeInfo sun4u_iommu_memory_region_info
= {
331 .parent
= TYPE_IOMMU_MEMORY_REGION
,
332 .name
= TYPE_SUN4U_IOMMU_MEMORY_REGION
,
333 .class_init
= sun4u_iommu_memory_region_class_init
,
336 static void iommu_register_types(void)
338 type_register_static(&iommu_info
);
339 type_register_static(&sun4u_iommu_memory_region_info
);
342 type_init(iommu_register_types
)