Revision 24addbc7
b/dma-helpers.c | ||
---|---|---|
14 | 14 |
|
15 | 15 |
/* #define DEBUG_IOMMU */ |
16 | 16 |
|
17 |
static void do_dma_memory_set(AddressSpace *as, |
|
18 |
dma_addr_t addr, uint8_t c, dma_addr_t len) |
|
17 |
int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) |
|
19 | 18 |
{ |
19 |
AddressSpace *as = dma->as; |
|
20 |
|
|
21 |
dma_barrier(dma, DMA_DIRECTION_FROM_DEVICE); |
|
22 |
|
|
20 | 23 |
#define FILLBUF_SIZE 512 |
21 | 24 |
uint8_t fillbuf[FILLBUF_SIZE]; |
22 | 25 |
int l; |
26 |
bool error = false; |
|
23 | 27 |
|
24 | 28 |
memset(fillbuf, c, FILLBUF_SIZE); |
25 | 29 |
while (len > 0) { |
26 | 30 |
l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; |
27 |
address_space_rw(as, addr, fillbuf, l, true); |
|
31 |
error |= address_space_rw(as, addr, fillbuf, l, true);
|
|
28 | 32 |
len -= l; |
29 | 33 |
addr += l; |
30 | 34 |
} |
31 |
} |
|
32 | 35 |
|
33 |
int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) |
|
34 |
{ |
|
35 |
dma_barrier(dma, DMA_DIRECTION_FROM_DEVICE); |
|
36 |
|
|
37 |
if (dma_has_iommu(dma)) { |
|
38 |
return iommu_dma_memory_set(dma, addr, c, len); |
|
39 |
} |
|
40 |
do_dma_memory_set(dma->as, addr, c, len); |
|
41 |
|
|
42 |
return 0; |
|
36 |
return error; |
|
43 | 37 |
} |
44 | 38 |
|
45 | 39 |
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, DMAContext *dma) |
... | ... | |
278 | 272 |
bdrv_acct_start(bs, cookie, sg->size, type); |
279 | 273 |
} |
280 | 274 |
|
281 |
bool iommu_dma_memory_valid(DMAContext *dma, dma_addr_t addr, dma_addr_t len, |
|
282 |
DMADirection dir) |
|
275 |
void dma_context_init(DMAContext *dma, AddressSpace *as) |
|
283 | 276 |
{ |
284 |
hwaddr paddr, plen; |
|
285 |
|
|
286 | 277 |
#ifdef DEBUG_IOMMU |
287 |
fprintf(stderr, "dma_memory_check context=%p addr=0x" DMA_ADDR_FMT |
|
288 |
" len=0x" DMA_ADDR_FMT " dir=%d\n", dma, addr, len, dir); |
|
289 |
#endif |
|
290 |
|
|
291 |
while (len) { |
|
292 |
if (dma->translate(dma, addr, &paddr, &plen, dir) != 0) { |
|
293 |
return false; |
|
294 |
} |
|
295 |
|
|
296 |
/* The translation might be valid for larger regions. */ |
|
297 |
if (plen > len) { |
|
298 |
plen = len; |
|
299 |
} |
|
300 |
|
|
301 |
if (!address_space_access_valid(dma->as, paddr, len, |
|
302 |
dir == DMA_DIRECTION_FROM_DEVICE)) { |
|
303 |
return false; |
|
304 |
} |
|
305 |
|
|
306 |
len -= plen; |
|
307 |
addr += plen; |
|
308 |
} |
|
309 |
|
|
310 |
return true; |
|
311 |
} |
|
312 |
|
|
313 |
int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr, |
|
314 |
void *buf, dma_addr_t len, DMADirection dir) |
|
315 |
{ |
|
316 |
hwaddr paddr, plen; |
|
317 |
int err; |
|
318 |
|
|
319 |
#ifdef DEBUG_IOMMU |
|
320 |
fprintf(stderr, "dma_memory_rw context=%p addr=0x" DMA_ADDR_FMT " len=0x" |
|
321 |
DMA_ADDR_FMT " dir=%d\n", dma, addr, len, dir); |
|
322 |
#endif |
|
323 |
|
|
324 |
while (len) { |
|
325 |
err = dma->translate(dma, addr, &paddr, &plen, dir); |
|
326 |
if (err) { |
|
327 |
/* |
|
328 |
* In case of failure on reads from the guest, we clean the |
|
329 |
* destination buffer so that a device that doesn't test |
|
330 |
* for errors will not expose qemu internal memory. |
|
331 |
*/ |
|
332 |
memset(buf, 0, len); |
|
333 |
return -1; |
|
334 |
} |
|
335 |
|
|
336 |
/* The translation might be valid for larger regions. */ |
|
337 |
if (plen > len) { |
|
338 |
plen = len; |
|
339 |
} |
|
340 |
|
|
341 |
address_space_rw(dma->as, paddr, buf, plen, dir == DMA_DIRECTION_FROM_DEVICE); |
|
342 |
|
|
343 |
len -= plen; |
|
344 |
addr += plen; |
|
345 |
buf += plen; |
|
346 |
} |
|
347 |
|
|
348 |
return 0; |
|
349 |
} |
|
350 |
|
|
351 |
int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, |
|
352 |
dma_addr_t len) |
|
353 |
{ |
|
354 |
hwaddr paddr, plen; |
|
355 |
int err; |
|
356 |
|
|
357 |
#ifdef DEBUG_IOMMU |
|
358 |
fprintf(stderr, "dma_memory_set context=%p addr=0x" DMA_ADDR_FMT |
|
359 |
" len=0x" DMA_ADDR_FMT "\n", dma, addr, len); |
|
360 |
#endif |
|
361 |
|
|
362 |
while (len) { |
|
363 |
err = dma->translate(dma, addr, &paddr, &plen, |
|
364 |
DMA_DIRECTION_FROM_DEVICE); |
|
365 |
if (err) { |
|
366 |
return err; |
|
367 |
} |
|
368 |
|
|
369 |
/* The translation might be valid for larger regions. */ |
|
370 |
if (plen > len) { |
|
371 |
plen = len; |
|
372 |
} |
|
373 |
|
|
374 |
do_dma_memory_set(dma->as, paddr, c, plen); |
|
375 |
|
|
376 |
len -= plen; |
|
377 |
addr += plen; |
|
378 |
} |
|
379 |
|
|
380 |
return 0; |
|
381 |
} |
|
382 |
|
|
383 |
void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, |
|
384 |
DMAMapFunc map, DMAUnmapFunc unmap) |
|
385 |
{ |
|
386 |
#ifdef DEBUG_IOMMU |
|
387 |
fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n", |
|
388 |
dma, translate, map, unmap); |
|
278 |
fprintf(stderr, "dma_context_init(%p -> %p)\n", dma, as); |
|
389 | 279 |
#endif |
390 | 280 |
dma->as = as; |
391 |
dma->translate = translate; |
|
392 |
dma->map = map; |
|
393 |
dma->unmap = unmap; |
|
394 |
} |
|
395 |
|
|
396 |
void *iommu_dma_memory_map(DMAContext *dma, dma_addr_t addr, dma_addr_t *len, |
|
397 |
DMADirection dir) |
|
398 |
{ |
|
399 |
int err; |
|
400 |
hwaddr paddr, plen; |
|
401 |
void *buf; |
|
402 |
|
|
403 |
if (dma->map) { |
|
404 |
return dma->map(dma, addr, len, dir); |
|
405 |
} |
|
406 |
|
|
407 |
plen = *len; |
|
408 |
err = dma->translate(dma, addr, &paddr, &plen, dir); |
|
409 |
if (err) { |
|
410 |
return NULL; |
|
411 |
} |
|
412 |
|
|
413 |
/* |
|
414 |
* If this is true, the virtual region is contiguous, |
|
415 |
* but the translated physical region isn't. We just |
|
416 |
* clamp *len, much like address_space_map() does. |
|
417 |
*/ |
|
418 |
if (plen < *len) { |
|
419 |
*len = plen; |
|
420 |
} |
|
421 |
|
|
422 |
buf = address_space_map(dma->as, paddr, &plen, dir == DMA_DIRECTION_FROM_DEVICE); |
|
423 |
*len = plen; |
|
424 |
|
|
425 |
return buf; |
|
426 |
} |
|
427 |
|
|
428 |
void iommu_dma_memory_unmap(DMAContext *dma, void *buffer, dma_addr_t len, |
|
429 |
DMADirection dir, dma_addr_t access_len) |
|
430 |
{ |
|
431 |
if (dma->unmap) { |
|
432 |
dma->unmap(dma, buffer, len, dir, access_len); |
|
433 |
return; |
|
434 |
} |
|
435 |
|
|
436 |
address_space_unmap(dma->as, buffer, len, dir == DMA_DIRECTION_FROM_DEVICE, |
|
437 |
access_len); |
|
438 |
|
|
439 | 281 |
} |
b/exec.c | ||
---|---|---|
1840 | 1840 |
memory_listener_register(&io_memory_listener, &address_space_io); |
1841 | 1841 |
memory_listener_register(&tcg_memory_listener, &address_space_memory); |
1842 | 1842 |
|
1843 |
dma_context_init(&dma_context_memory, &address_space_memory, |
|
1844 |
NULL, NULL, NULL); |
|
1843 |
dma_context_init(&dma_context_memory, &address_space_memory); |
|
1845 | 1844 |
} |
1846 | 1845 |
|
1847 | 1846 |
MemoryRegion *get_system_memory(void) |
b/hw/pci/pci.c | ||
---|---|---|
814 | 814 |
memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); |
815 | 815 |
address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); |
816 | 816 |
pci_dev->dma = g_new(DMAContext, 1); |
817 |
dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL);
|
|
817 |
dma_context_init(pci_dev->dma, &pci_dev->bus_master_as); |
|
818 | 818 |
} |
819 |
|
|
819 | 820 |
pci_dev->devfn = devfn; |
820 | 821 |
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); |
821 | 822 |
pci_dev->irq_state = 0; |
b/hw/ppc/spapr_iommu.c | ||
---|---|---|
158 | 158 |
memory_region_init_iommu(&tcet->iommu, &spapr_iommu_ops, |
159 | 159 |
"iommu-spapr", UINT64_MAX); |
160 | 160 |
address_space_init(&tcet->as, &tcet->iommu); |
161 |
dma_context_init(&tcet->dma, &tcet->as, NULL, NULL, NULL);
|
|
161 |
dma_context_init(&tcet->dma, &tcet->as); |
|
162 | 162 |
|
163 | 163 |
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); |
164 | 164 |
|
b/include/sysemu/dma.h | ||
---|---|---|
46 | 46 |
#define DMA_ADDR_BITS 64 |
47 | 47 |
#define DMA_ADDR_FMT "%" PRIx64 |
48 | 48 |
|
49 |
typedef int DMATranslateFunc(DMAContext *dma, |
|
50 |
dma_addr_t addr, |
|
51 |
hwaddr *paddr, |
|
52 |
hwaddr *len, |
|
53 |
DMADirection dir); |
|
54 |
typedef void* DMAMapFunc(DMAContext *dma, |
|
55 |
dma_addr_t addr, |
|
56 |
dma_addr_t *len, |
|
57 |
DMADirection dir); |
|
58 |
typedef void DMAUnmapFunc(DMAContext *dma, |
|
59 |
void *buffer, |
|
60 |
dma_addr_t len, |
|
61 |
DMADirection dir, |
|
62 |
dma_addr_t access_len); |
|
63 |
|
|
64 | 49 |
struct DMAContext { |
65 | 50 |
AddressSpace *as; |
66 |
DMATranslateFunc *translate; |
|
67 |
DMAMapFunc *map; |
|
68 |
DMAUnmapFunc *unmap; |
|
69 | 51 |
}; |
70 | 52 |
|
71 | 53 |
/* A global DMA context corresponding to the address_space_memory |
... | ... | |
98 | 80 |
} |
99 | 81 |
} |
100 | 82 |
|
101 |
static inline bool dma_has_iommu(DMAContext *dma) |
|
102 |
{ |
|
103 |
return dma && dma->translate; |
|
104 |
} |
|
105 |
|
|
106 | 83 |
/* Checks that the given range of addresses is valid for DMA. This is |
107 | 84 |
* useful for certain cases, but usually you should just use |
108 | 85 |
* dma_memory_{read,write}() and check for errors */ |
109 |
bool iommu_dma_memory_valid(DMAContext *dma, dma_addr_t addr, dma_addr_t len, |
|
110 |
DMADirection dir); |
|
111 | 86 |
static inline bool dma_memory_valid(DMAContext *dma, |
112 | 87 |
dma_addr_t addr, dma_addr_t len, |
113 | 88 |
DMADirection dir) |
114 | 89 |
{ |
115 |
if (!dma_has_iommu(dma)) { |
|
116 |
return address_space_access_valid(dma->as, addr, len, |
|
117 |
dir == DMA_DIRECTION_FROM_DEVICE); |
|
118 |
} else { |
|
119 |
return iommu_dma_memory_valid(dma, addr, len, dir); |
|
120 |
} |
|
90 |
return address_space_access_valid(dma->as, addr, len, |
|
91 |
dir == DMA_DIRECTION_FROM_DEVICE); |
|
121 | 92 |
} |
122 | 93 |
|
123 |
int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr, |
|
124 |
void *buf, dma_addr_t len, DMADirection dir); |
|
125 | 94 |
static inline int dma_memory_rw_relaxed(DMAContext *dma, dma_addr_t addr, |
126 | 95 |
void *buf, dma_addr_t len, |
127 | 96 |
DMADirection dir) |
128 | 97 |
{ |
129 |
if (!dma_has_iommu(dma)) { |
|
130 |
/* Fast-path for no IOMMU */ |
|
131 |
address_space_rw(dma->as, addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE); |
|
132 |
return 0; |
|
133 |
} else { |
|
134 |
return iommu_dma_memory_rw(dma, addr, buf, len, dir); |
|
135 |
} |
|
98 |
return address_space_rw(dma->as, addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE); |
|
136 | 99 |
} |
137 | 100 |
|
138 | 101 |
static inline int dma_memory_read_relaxed(DMAContext *dma, dma_addr_t addr, |
... | ... | |
170 | 133 |
DMA_DIRECTION_FROM_DEVICE); |
171 | 134 |
} |
172 | 135 |
|
173 |
int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, |
|
174 |
dma_addr_t len); |
|
175 |
|
|
176 | 136 |
int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len); |
177 | 137 |
|
178 |
void *iommu_dma_memory_map(DMAContext *dma, |
|
179 |
dma_addr_t addr, dma_addr_t *len, |
|
180 |
DMADirection dir); |
|
181 | 138 |
static inline void *dma_memory_map(DMAContext *dma, |
182 | 139 |
dma_addr_t addr, dma_addr_t *len, |
183 | 140 |
DMADirection dir) |
184 | 141 |
{ |
185 |
if (!dma_has_iommu(dma)) { |
|
186 |
hwaddr xlen = *len; |
|
187 |
void *p; |
|
188 |
|
|
189 |
p = address_space_map(dma->as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE); |
|
190 |
*len = xlen; |
|
191 |
return p; |
|
192 |
} else { |
|
193 |
return iommu_dma_memory_map(dma, addr, len, dir); |
|
194 |
} |
|
142 |
hwaddr xlen = *len; |
|
143 |
void *p; |
|
144 |
|
|
145 |
p = address_space_map(dma->as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE); |
|
146 |
*len = xlen; |
|
147 |
return p; |
|
195 | 148 |
} |
196 | 149 |
|
197 |
void iommu_dma_memory_unmap(DMAContext *dma, |
|
198 |
void *buffer, dma_addr_t len, |
|
199 |
DMADirection dir, dma_addr_t access_len); |
|
200 | 150 |
static inline void dma_memory_unmap(DMAContext *dma, |
201 | 151 |
void *buffer, dma_addr_t len, |
202 | 152 |
DMADirection dir, dma_addr_t access_len) |
203 | 153 |
{ |
204 |
if (!dma_has_iommu(dma)) { |
|
205 |
address_space_unmap(dma->as, buffer, (hwaddr)len, |
|
206 |
dir == DMA_DIRECTION_FROM_DEVICE, access_len); |
|
207 |
} else { |
|
208 |
iommu_dma_memory_unmap(dma, buffer, len, dir, access_len); |
|
209 |
} |
|
154 |
address_space_unmap(dma->as, buffer, (hwaddr)len, |
|
155 |
dir == DMA_DIRECTION_FROM_DEVICE, access_len); |
|
210 | 156 |
} |
211 | 157 |
|
212 | 158 |
#define DEFINE_LDST_DMA(_lname, _sname, _bits, _end) \ |
... | ... | |
247 | 193 |
|
248 | 194 |
#undef DEFINE_LDST_DMA |
249 | 195 |
|
250 |
void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, |
|
251 |
DMAMapFunc map, DMAUnmapFunc unmap); |
|
196 |
void dma_context_init(DMAContext *dma, AddressSpace *as); |
|
252 | 197 |
|
253 | 198 |
struct ScatterGatherEntry { |
254 | 199 |
dma_addr_t base; |
Also available in: Unified diff