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"
31 #include "qapi/error.h"
38 #define IOMMU_DPRINTF(fmt, ...) \
39 do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
41 #define IOMMU_DPRINTF(fmt, ...)
45 #define IOMMU_PAGE_SIZE_8K (1ULL << 13)
46 #define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1))
47 #define IOMMU_PAGE_SIZE_64K (1ULL << 16)
48 #define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1))
50 #define IOMMU_CTRL 0x0
51 #define IOMMU_CTRL_TBW_SIZE (1ULL << 2)
52 #define IOMMU_CTRL_MMU_EN (1ULL)
54 #define IOMMU_CTRL_TSB_SHIFT 16
56 #define IOMMU_BASE 0x8
57 #define IOMMU_FLUSH 0x10
59 #define IOMMU_TTE_DATA_V (1ULL << 63)
60 #define IOMMU_TTE_DATA_SIZE (1ULL << 61)
61 #define IOMMU_TTE_DATA_W (1ULL << 1)
63 #define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL
64 #define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
66 #define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL
67 #define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL
68 #define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL
69 #define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL
70 #define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL
71 #define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL
72 #define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL
73 #define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL
75 #define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL
76 #define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
77 #define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
78 #define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
79 #define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL
80 #define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL
83 /* Called from RCU critical section */
84 static IOMMUTLBEntry
pbm_translate_iommu(IOMMUMemoryRegion
*iommu
, hwaddr addr
,
85 IOMMUAccessFlags flag
)
87 IOMMUState
*is
= container_of(iommu
, IOMMUState
, iommu
);
88 hwaddr baseaddr
, offset
;
92 .target_as
= &address_space_memory
,
95 .addr_mask
= ~(hwaddr
)0,
99 if (!(is
->regs
[IOMMU_CTRL
>> 3] & IOMMU_CTRL_MMU_EN
)) {
100 /* IOMMU disabled, passthrough using standard 8K page */
101 ret
.iova
= addr
& IOMMU_PAGE_MASK_8K
;
102 ret
.translated_addr
= addr
;
103 ret
.addr_mask
= IOMMU_PAGE_MASK_8K
;
109 baseaddr
= is
->regs
[IOMMU_BASE
>> 3];
110 tsbsize
= (is
->regs
[IOMMU_CTRL
>> 3] >> IOMMU_CTRL_TSB_SHIFT
) & 0x7;
112 if (is
->regs
[IOMMU_CTRL
>> 3] & IOMMU_CTRL_TBW_SIZE
) {
116 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_64M
) >> 13;
119 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_128M
) >> 13;
122 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_256M
) >> 13;
125 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_512M
) >> 13;
128 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_1G
) >> 13;
131 offset
= (addr
& IOMMU_TSB_64K_OFFSET_MASK_2G
) >> 13;
134 /* Not implemented, error */
141 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_8M
) >> 10;
144 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_16M
) >> 10;
147 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_32M
) >> 10;
150 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_64M
) >> 10;
153 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_128M
) >> 10;
156 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_256M
) >> 10;
159 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_512M
) >> 10;
162 offset
= (addr
& IOMMU_TSB_8K_OFFSET_MASK_1G
) >> 10;
167 tte
= address_space_ldq_be(&address_space_memory
, baseaddr
+ offset
,
168 MEMTXATTRS_UNSPECIFIED
, NULL
);
170 if (!(tte
& IOMMU_TTE_DATA_V
)) {
171 /* Invalid mapping */
175 if (tte
& IOMMU_TTE_DATA_W
) {
183 if (tte
& IOMMU_TTE_DATA_SIZE
) {
185 ret
.iova
= addr
& IOMMU_PAGE_MASK_64K
;
186 ret
.translated_addr
= tte
& IOMMU_TTE_PHYS_MASK_64K
;
187 ret
.addr_mask
= (IOMMU_PAGE_SIZE_64K
- 1);
190 ret
.iova
= addr
& IOMMU_PAGE_MASK_8K
;
191 ret
.translated_addr
= tte
& IOMMU_TTE_PHYS_MASK_8K
;
192 ret
.addr_mask
= (IOMMU_PAGE_SIZE_8K
- 1);
198 static void iommu_mem_write(void *opaque
, hwaddr addr
,
199 uint64_t val
, unsigned size
)
201 IOMMUState
*is
= opaque
;
203 IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx
" val: %" PRIx64
204 " size: %d\n", addr
, val
, size
);
209 is
->regs
[IOMMU_CTRL
>> 3] &= 0xffffffffULL
;
210 is
->regs
[IOMMU_CTRL
>> 3] |= val
<< 32;
212 is
->regs
[IOMMU_CTRL
>> 3] = val
;
215 case IOMMU_CTRL
+ 0x4:
216 is
->regs
[IOMMU_CTRL
>> 3] &= 0xffffffff00000000ULL
;
217 is
->regs
[IOMMU_CTRL
>> 3] |= val
& 0xffffffffULL
;
221 is
->regs
[IOMMU_BASE
>> 3] &= 0xffffffffULL
;
222 is
->regs
[IOMMU_BASE
>> 3] |= val
<< 32;
224 is
->regs
[IOMMU_BASE
>> 3] = val
;
227 case IOMMU_BASE
+ 0x4:
228 is
->regs
[IOMMU_BASE
>> 3] &= 0xffffffff00000000ULL
;
229 is
->regs
[IOMMU_BASE
>> 3] |= val
& 0xffffffffULL
;
232 case IOMMU_FLUSH
+ 0x4:
235 qemu_log_mask(LOG_UNIMP
,
236 "apb iommu: Unimplemented register write "
237 "reg 0x%" HWADDR_PRIx
" size 0x%x value 0x%" PRIx64
"\n",
243 static uint64_t iommu_mem_read(void *opaque
, hwaddr addr
, unsigned size
)
245 IOMMUState
*is
= opaque
;
251 val
= is
->regs
[IOMMU_CTRL
>> 3] >> 32;
253 val
= is
->regs
[IOMMU_CTRL
>> 3];
256 case IOMMU_CTRL
+ 0x4:
257 val
= is
->regs
[IOMMU_CTRL
>> 3] & 0xffffffffULL
;
261 val
= is
->regs
[IOMMU_BASE
>> 3] >> 32;
263 val
= is
->regs
[IOMMU_BASE
>> 3];
266 case IOMMU_BASE
+ 0x4:
267 val
= is
->regs
[IOMMU_BASE
>> 3] & 0xffffffffULL
;
270 case IOMMU_FLUSH
+ 0x4:
274 qemu_log_mask(LOG_UNIMP
,
275 "apb iommu: Unimplemented register read "
276 "reg 0x%" HWADDR_PRIx
" size 0x%x\n",
282 IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx
" val: %" PRIx64
283 " size: %d\n", addr
, val
, size
);
288 static const MemoryRegionOps iommu_mem_ops
= {
289 .read
= iommu_mem_read
,
290 .write
= iommu_mem_write
,
291 .endianness
= DEVICE_BIG_ENDIAN
,
294 static void iommu_reset(DeviceState
*d
)
296 IOMMUState
*s
= SUN4U_IOMMU(d
);
298 memset(s
->regs
, 0, IOMMU_NREGS
* sizeof(uint64_t));
301 static void iommu_init(Object
*obj
)
303 IOMMUState
*s
= SUN4U_IOMMU(obj
);
304 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
306 memory_region_init_iommu(&s
->iommu
, sizeof(s
->iommu
),
307 TYPE_APB_IOMMU_MEMORY_REGION
, OBJECT(s
),
308 "iommu-apb", UINT64_MAX
);
309 address_space_init(&s
->iommu_as
, MEMORY_REGION(&s
->iommu
), "pbm-as");
311 memory_region_init_io(&s
->iomem
, obj
, &iommu_mem_ops
, s
, "iommu",
312 IOMMU_NREGS
* sizeof(uint64_t));
313 sysbus_init_mmio(sbd
, &s
->iomem
);
316 static void iommu_class_init(ObjectClass
*klass
, void *data
)
318 DeviceClass
*dc
= DEVICE_CLASS(klass
);
320 dc
->reset
= iommu_reset
;
323 static const TypeInfo pbm_iommu_info
= {
324 .name
= TYPE_SUN4U_IOMMU
,
325 .parent
= TYPE_SYS_BUS_DEVICE
,
326 .instance_size
= sizeof(IOMMUState
),
327 .instance_init
= iommu_init
,
328 .class_init
= iommu_class_init
,
331 static void pbm_iommu_memory_region_class_init(ObjectClass
*klass
, void *data
)
333 IOMMUMemoryRegionClass
*imrc
= IOMMU_MEMORY_REGION_CLASS(klass
);
335 imrc
->translate
= pbm_translate_iommu
;
338 static const TypeInfo pbm_iommu_memory_region_info
= {
339 .parent
= TYPE_IOMMU_MEMORY_REGION
,
340 .name
= TYPE_APB_IOMMU_MEMORY_REGION
,
341 .class_init
= pbm_iommu_memory_region_class_init
,
344 static void pbm_register_types(void)
346 type_register_static(&pbm_iommu_info
);
347 type_register_static(&pbm_iommu_memory_region_info
);
350 type_init(pbm_register_types
)