2 * Copyright (C) 2014-2016 Broadcom Corporation
3 * Copyright (c) 2017 Red Hat, Inc.
4 * Written by Prem Mallappa, Eric Auger
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
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.
15 * Author: Prem Mallappa <pmallapp@broadcom.com>
19 #include "qemu/osdep.h"
20 #include "sysemu/sysemu.h"
21 #include "exec/address-spaces.h"
23 #include "exec/target_page.h"
25 #include "hw/qdev-properties.h"
26 #include "qapi/error.h"
28 #include "qemu/error-report.h"
29 #include "hw/arm/smmu-common.h"
30 #include "smmu-internal.h"
32 /* VMSAv8-64 Translation */
35 * get_pte - Get the content of a page table entry located at
38 static int get_pte(dma_addr_t baseaddr
, uint32_t index
, uint64_t *pte
,
39 SMMUPTWEventInfo
*info
)
42 dma_addr_t addr
= baseaddr
+ index
* sizeof(*pte
);
44 /* TODO: guarantee 64-bit single-copy atomicity */
45 ret
= dma_memory_read(&address_space_memory
, addr
,
46 (uint8_t *)pte
, sizeof(*pte
));
48 if (ret
!= MEMTX_OK
) {
49 info
->type
= SMMU_PTW_ERR_WALK_EABT
;
53 trace_smmu_get_pte(baseaddr
, index
, addr
, *pte
);
57 /* VMSAv8-64 Translation Table Format Descriptor Decoding */
60 * get_page_pte_address - returns the L3 descriptor output address,
62 * ARM ARM spec: Figure D4-17 VMSAv8-64 level 3 descriptor format
64 static inline hwaddr
get_page_pte_address(uint64_t pte
, int granule_sz
)
66 return PTE_ADDRESS(pte
, granule_sz
);
70 * get_table_pte_address - return table descriptor output address,
71 * ie. address of next level table
72 * ARM ARM Figure D4-16 VMSAv8-64 level0, level1, and level 2 descriptor formats
74 static inline hwaddr
get_table_pte_address(uint64_t pte
, int granule_sz
)
76 return PTE_ADDRESS(pte
, granule_sz
);
80 * get_block_pte_address - return block descriptor output address and block size
81 * ARM ARM Figure D4-16 VMSAv8-64 level0, level1, and level 2 descriptor formats
83 static inline hwaddr
get_block_pte_address(uint64_t pte
, int level
,
84 int granule_sz
, uint64_t *bsz
)
86 int n
= (granule_sz
- 3) * (4 - level
) + 3;
89 return PTE_ADDRESS(pte
, n
);
92 SMMUTransTableInfo
*select_tt(SMMUTransCfg
*cfg
, dma_addr_t iova
)
94 bool tbi
= extract64(iova
, 55, 1) ? TBI1(cfg
->tbi
) : TBI0(cfg
->tbi
);
95 uint8_t tbi_byte
= tbi
* 8;
98 !extract64(iova
, 64 - cfg
->tt
[0].tsz
, cfg
->tt
[0].tsz
- tbi_byte
)) {
99 /* there is a ttbr0 region and we are in it (high bits all zero) */
101 } else if (cfg
->tt
[1].tsz
&&
102 !extract64(iova
, 64 - cfg
->tt
[1].tsz
, cfg
->tt
[1].tsz
- tbi_byte
)) {
103 /* there is a ttbr1 region and we are in it (high bits all one) */
105 } else if (!cfg
->tt
[0].tsz
) {
106 /* ttbr0 region is "everything not in the ttbr1 region" */
108 } else if (!cfg
->tt
[1].tsz
) {
109 /* ttbr1 region is "everything not in the ttbr0 region" */
112 /* in the gap between the two regions, this is a Translation fault */
117 * smmu_ptw_64 - VMSAv8-64 Walk of the page tables for a given IOVA
118 * @cfg: translation config
119 * @iova: iova to translate
121 * @tlbe: IOMMUTLBEntry (out)
122 * @info: handle to an error info
124 * Return 0 on success, < 0 on error. In case of error, @info is filled
125 * and tlbe->perm is set to IOMMU_NONE.
126 * Upon success, @tlbe is filled with translated_addr and entry
129 static int smmu_ptw_64(SMMUTransCfg
*cfg
,
130 dma_addr_t iova
, IOMMUAccessFlags perm
,
131 IOMMUTLBEntry
*tlbe
, SMMUPTWEventInfo
*info
)
133 dma_addr_t baseaddr
, indexmask
;
134 int stage
= cfg
->stage
;
135 SMMUTransTableInfo
*tt
= select_tt(cfg
, iova
);
136 uint8_t level
, granule_sz
, inputsize
, stride
;
138 if (!tt
|| tt
->disabled
) {
139 info
->type
= SMMU_PTW_ERR_TRANSLATION
;
143 granule_sz
= tt
->granule_sz
;
144 stride
= granule_sz
- 3;
145 inputsize
= 64 - tt
->tsz
;
146 level
= 4 - (inputsize
- 4) / stride
;
147 indexmask
= (1ULL << (inputsize
- (stride
* (4 - level
)))) - 1;
148 baseaddr
= extract64(tt
->ttb
, 0, 48);
149 baseaddr
&= ~indexmask
;
152 tlbe
->addr_mask
= (1 << granule_sz
) - 1;
155 uint64_t subpage_size
= 1ULL << level_shift(level
, granule_sz
);
156 uint64_t mask
= subpage_size
- 1;
157 uint32_t offset
= iova_level_offset(iova
, inputsize
, level
, granule_sz
);
159 dma_addr_t pte_addr
= baseaddr
+ offset
* sizeof(pte
);
162 if (get_pte(baseaddr
, offset
, &pte
, info
)) {
165 trace_smmu_ptw_level(level
, iova
, subpage_size
,
166 baseaddr
, offset
, pte
);
168 if (is_invalid_pte(pte
) || is_reserved_pte(pte
, level
)) {
169 trace_smmu_ptw_invalid_pte(stage
, level
, baseaddr
,
170 pte_addr
, offset
, pte
);
171 info
->type
= SMMU_PTW_ERR_TRANSLATION
;
175 if (is_page_pte(pte
, level
)) {
176 uint64_t gpa
= get_page_pte_address(pte
, granule_sz
);
179 if (is_permission_fault(ap
, perm
)) {
180 info
->type
= SMMU_PTW_ERR_PERMISSION
;
184 tlbe
->translated_addr
= gpa
+ (iova
& mask
);
185 tlbe
->perm
= PTE_AP_TO_PERM(ap
);
186 trace_smmu_ptw_page_pte(stage
, level
, iova
,
187 baseaddr
, pte_addr
, pte
, gpa
);
190 if (is_block_pte(pte
, level
)) {
192 hwaddr gpa
= get_block_pte_address(pte
, level
, granule_sz
,
196 if (is_permission_fault(ap
, perm
)) {
197 info
->type
= SMMU_PTW_ERR_PERMISSION
;
201 trace_smmu_ptw_block_pte(stage
, level
, baseaddr
,
202 pte_addr
, pte
, iova
, gpa
,
205 tlbe
->translated_addr
= gpa
+ (iova
& mask
);
206 tlbe
->perm
= PTE_AP_TO_PERM(ap
);
211 ap
= PTE_APTABLE(pte
);
213 if (is_permission_fault(ap
, perm
)) {
214 info
->type
= SMMU_PTW_ERR_PERMISSION
;
217 baseaddr
= get_table_pte_address(pte
, granule_sz
);
221 info
->type
= SMMU_PTW_ERR_TRANSLATION
;
224 tlbe
->perm
= IOMMU_NONE
;
229 * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
231 * @cfg: translation configuration
232 * @iova: iova to translate
233 * @perm: tentative access type
234 * @tlbe: returned entry
235 * @info: ptw event handle
237 * return 0 on success
239 inline int smmu_ptw(SMMUTransCfg
*cfg
, dma_addr_t iova
, IOMMUAccessFlags perm
,
240 IOMMUTLBEntry
*tlbe
, SMMUPTWEventInfo
*info
)
244 * This code path is not entered as we check this while decoding
245 * the configuration data in the derived SMMU model.
247 g_assert_not_reached();
250 return smmu_ptw_64(cfg
, iova
, perm
, tlbe
, info
);
254 * The bus number is used for lookup when SID based invalidation occurs.
255 * In that case we lazily populate the SMMUPciBus array from the bus hash
256 * table. At the time the SMMUPciBus is created (smmu_find_add_as), the bus
257 * numbers may not be always initialized yet.
259 SMMUPciBus
*smmu_find_smmu_pcibus(SMMUState
*s
, uint8_t bus_num
)
261 SMMUPciBus
*smmu_pci_bus
= s
->smmu_pcibus_by_bus_num
[bus_num
];
266 g_hash_table_iter_init(&iter
, s
->smmu_pcibus_by_busptr
);
267 while (g_hash_table_iter_next(&iter
, NULL
, (void **)&smmu_pci_bus
)) {
268 if (pci_bus_num(smmu_pci_bus
->bus
) == bus_num
) {
269 s
->smmu_pcibus_by_bus_num
[bus_num
] = smmu_pci_bus
;
277 static AddressSpace
*smmu_find_add_as(PCIBus
*bus
, void *opaque
, int devfn
)
279 SMMUState
*s
= opaque
;
280 SMMUPciBus
*sbus
= g_hash_table_lookup(s
->smmu_pcibus_by_busptr
, bus
);
284 sbus
= g_malloc0(sizeof(SMMUPciBus
) +
285 sizeof(SMMUDevice
*) * SMMU_PCI_DEVFN_MAX
);
287 g_hash_table_insert(s
->smmu_pcibus_by_busptr
, bus
, sbus
);
290 sdev
= sbus
->pbdev
[devfn
];
292 char *name
= g_strdup_printf("%s-%d-%d",
294 pci_bus_num(bus
), devfn
);
295 sdev
= sbus
->pbdev
[devfn
] = g_new0(SMMUDevice
, 1);
301 memory_region_init_iommu(&sdev
->iommu
, sizeof(sdev
->iommu
),
303 OBJECT(s
), name
, 1ULL << SMMU_MAX_VA_BITS
);
304 address_space_init(&sdev
->as
,
305 MEMORY_REGION(&sdev
->iommu
), name
);
306 trace_smmu_add_mr(name
);
313 static void smmu_base_realize(DeviceState
*dev
, Error
**errp
)
315 SMMUState
*s
= ARM_SMMU(dev
);
316 SMMUBaseClass
*sbc
= ARM_SMMU_GET_CLASS(dev
);
317 Error
*local_err
= NULL
;
319 sbc
->parent_realize(dev
, &local_err
);
321 error_propagate(errp
, local_err
);
325 s
->smmu_pcibus_by_busptr
= g_hash_table_new(NULL
, NULL
);
327 if (s
->primary_bus
) {
328 pci_setup_iommu(s
->primary_bus
, smmu_find_add_as
, s
);
330 error_setg(errp
, "SMMU is not attached to any PCI bus!");
334 static void smmu_base_reset(DeviceState
*dev
)
336 /* will be filled later on */
339 static Property smmu_dev_properties
[] = {
340 DEFINE_PROP_UINT8("bus_num", SMMUState
, bus_num
, 0),
341 DEFINE_PROP_LINK("primary-bus", SMMUState
, primary_bus
, "PCI", PCIBus
*),
342 DEFINE_PROP_END_OF_LIST(),
345 static void smmu_base_class_init(ObjectClass
*klass
, void *data
)
347 DeviceClass
*dc
= DEVICE_CLASS(klass
);
348 SMMUBaseClass
*sbc
= ARM_SMMU_CLASS(klass
);
350 dc
->props
= smmu_dev_properties
;
351 device_class_set_parent_realize(dc
, smmu_base_realize
,
352 &sbc
->parent_realize
);
353 dc
->reset
= smmu_base_reset
;
356 static const TypeInfo smmu_base_info
= {
357 .name
= TYPE_ARM_SMMU
,
358 .parent
= TYPE_SYS_BUS_DEVICE
,
359 .instance_size
= sizeof(SMMUState
),
361 .class_size
= sizeof(SMMUBaseClass
),
362 .class_init
= smmu_base_class_init
,
366 static void smmu_base_register_types(void)
368 type_register_static(&smmu_base_info
);
371 type_init(smmu_base_register_types
)