qapi: allow unions to contain further unions
[qemu/armbru.git] / memory_ldst.c.inc
blob84b868f29464853b60cd070534d1d3a346692a6d
1 /*
2  *  Physical memory access templates
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *  Copyright (c) 2015 Linaro, Inc.
6  *  Copyright (c) 2016 Red Hat, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20  */
22 /* warning: addr must be aligned */
23 static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
24     hwaddr addr, MemTxAttrs attrs, MemTxResult *result,
25     enum device_endian endian)
27     uint8_t *ptr;
28     uint64_t val;
29     MemoryRegion *mr;
30     hwaddr l = 4;
31     hwaddr addr1;
32     MemTxResult r;
33     bool release_lock = false;
35     RCU_READ_LOCK();
36     mr = TRANSLATE(addr, &addr1, &l, false, attrs);
37     if (l < 4 || !memory_access_is_direct(mr, false)) {
38         release_lock |= prepare_mmio_access(mr);
40         /* I/O case */
41         r = memory_region_dispatch_read(mr, addr1, &val,
42                                         MO_32 | devend_memop(endian), attrs);
43     } else {
44         /* RAM case */
45         fuzz_dma_read_cb(addr, 4, mr);
46         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
47         switch (endian) {
48         case DEVICE_LITTLE_ENDIAN:
49             val = ldl_le_p(ptr);
50             break;
51         case DEVICE_BIG_ENDIAN:
52             val = ldl_be_p(ptr);
53             break;
54         default:
55             val = ldl_p(ptr);
56             break;
57         }
58         r = MEMTX_OK;
59     }
60     if (result) {
61         *result = r;
62     }
63     if (release_lock) {
64         qemu_mutex_unlock_iothread();
65     }
66     RCU_READ_UNLOCK();
67     return val;
70 uint32_t glue(address_space_ldl, SUFFIX)(ARG1_DECL,
71     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
73     return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result,
74                                                     DEVICE_NATIVE_ENDIAN);
77 uint32_t glue(address_space_ldl_le, SUFFIX)(ARG1_DECL,
78     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
80     return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result,
81                                                     DEVICE_LITTLE_ENDIAN);
84 uint32_t glue(address_space_ldl_be, SUFFIX)(ARG1_DECL,
85     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
87     return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result,
88                                                     DEVICE_BIG_ENDIAN);
91 /* warning: addr must be aligned */
92 static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
93     hwaddr addr, MemTxAttrs attrs, MemTxResult *result,
94     enum device_endian endian)
96     uint8_t *ptr;
97     uint64_t val;
98     MemoryRegion *mr;
99     hwaddr l = 8;
100     hwaddr addr1;
101     MemTxResult r;
102     bool release_lock = false;
104     RCU_READ_LOCK();
105     mr = TRANSLATE(addr, &addr1, &l, false, attrs);
106     if (l < 8 || !memory_access_is_direct(mr, false)) {
107         release_lock |= prepare_mmio_access(mr);
109         /* I/O case */
110         r = memory_region_dispatch_read(mr, addr1, &val,
111                                         MO_64 | devend_memop(endian), attrs);
112     } else {
113         /* RAM case */
114         fuzz_dma_read_cb(addr, 8, mr);
115         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
116         switch (endian) {
117         case DEVICE_LITTLE_ENDIAN:
118             val = ldq_le_p(ptr);
119             break;
120         case DEVICE_BIG_ENDIAN:
121             val = ldq_be_p(ptr);
122             break;
123         default:
124             val = ldq_p(ptr);
125             break;
126         }
127         r = MEMTX_OK;
128     }
129     if (result) {
130         *result = r;
131     }
132     if (release_lock) {
133         qemu_mutex_unlock_iothread();
134     }
135     RCU_READ_UNLOCK();
136     return val;
139 uint64_t glue(address_space_ldq, SUFFIX)(ARG1_DECL,
140     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
142     return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result,
143                                                     DEVICE_NATIVE_ENDIAN);
146 uint64_t glue(address_space_ldq_le, SUFFIX)(ARG1_DECL,
147     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
149     return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result,
150                                                     DEVICE_LITTLE_ENDIAN);
153 uint64_t glue(address_space_ldq_be, SUFFIX)(ARG1_DECL,
154     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
156     return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result,
157                                                     DEVICE_BIG_ENDIAN);
160 uint8_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
161     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
163     uint8_t *ptr;
164     uint64_t val;
165     MemoryRegion *mr;
166     hwaddr l = 1;
167     hwaddr addr1;
168     MemTxResult r;
169     bool release_lock = false;
171     RCU_READ_LOCK();
172     mr = TRANSLATE(addr, &addr1, &l, false, attrs);
173     if (!memory_access_is_direct(mr, false)) {
174         release_lock |= prepare_mmio_access(mr);
176         /* I/O case */
177         r = memory_region_dispatch_read(mr, addr1, &val, MO_8, attrs);
178     } else {
179         /* RAM case */
180         fuzz_dma_read_cb(addr, 1, mr);
181         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
182         val = ldub_p(ptr);
183         r = MEMTX_OK;
184     }
185     if (result) {
186         *result = r;
187     }
188     if (release_lock) {
189         qemu_mutex_unlock_iothread();
190     }
191     RCU_READ_UNLOCK();
192     return val;
195 /* warning: addr must be aligned */
196 static inline uint16_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
197     hwaddr addr, MemTxAttrs attrs, MemTxResult *result,
198     enum device_endian endian)
200     uint8_t *ptr;
201     uint64_t val;
202     MemoryRegion *mr;
203     hwaddr l = 2;
204     hwaddr addr1;
205     MemTxResult r;
206     bool release_lock = false;
208     RCU_READ_LOCK();
209     mr = TRANSLATE(addr, &addr1, &l, false, attrs);
210     if (l < 2 || !memory_access_is_direct(mr, false)) {
211         release_lock |= prepare_mmio_access(mr);
213         /* I/O case */
214         r = memory_region_dispatch_read(mr, addr1, &val,
215                                         MO_16 | devend_memop(endian), attrs);
216     } else {
217         /* RAM case */
218         fuzz_dma_read_cb(addr, 2, mr);
219         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
220         switch (endian) {
221         case DEVICE_LITTLE_ENDIAN:
222             val = lduw_le_p(ptr);
223             break;
224         case DEVICE_BIG_ENDIAN:
225             val = lduw_be_p(ptr);
226             break;
227         default:
228             val = lduw_p(ptr);
229             break;
230         }
231         r = MEMTX_OK;
232     }
233     if (result) {
234         *result = r;
235     }
236     if (release_lock) {
237         qemu_mutex_unlock_iothread();
238     }
239     RCU_READ_UNLOCK();
240     return val;
243 uint16_t glue(address_space_lduw, SUFFIX)(ARG1_DECL,
244     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
246     return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result,
247                                                      DEVICE_NATIVE_ENDIAN);
250 uint16_t glue(address_space_lduw_le, SUFFIX)(ARG1_DECL,
251     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
253     return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result,
254                                                      DEVICE_LITTLE_ENDIAN);
257 uint16_t glue(address_space_lduw_be, SUFFIX)(ARG1_DECL,
258     hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
260     return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result,
261                                        DEVICE_BIG_ENDIAN);
264 /* warning: addr must be aligned. The ram page is not masked as dirty
265    and the code inside is not invalidated. It is useful if the dirty
266    bits are used to track modified PTEs */
267 void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
268     hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
270     uint8_t *ptr;
271     MemoryRegion *mr;
272     hwaddr l = 4;
273     hwaddr addr1;
274     MemTxResult r;
275     uint8_t dirty_log_mask;
276     bool release_lock = false;
278     RCU_READ_LOCK();
279     mr = TRANSLATE(addr, &addr1, &l, true, attrs);
280     if (l < 4 || !memory_access_is_direct(mr, true)) {
281         release_lock |= prepare_mmio_access(mr);
283         r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs);
284     } else {
285         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
286         stl_p(ptr, val);
288         dirty_log_mask = memory_region_get_dirty_log_mask(mr);
289         dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
290         cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
291                                             4, dirty_log_mask);
292         r = MEMTX_OK;
293     }
294     if (result) {
295         *result = r;
296     }
297     if (release_lock) {
298         qemu_mutex_unlock_iothread();
299     }
300     RCU_READ_UNLOCK();
303 /* warning: addr must be aligned */
304 static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
305     hwaddr addr, uint32_t val, MemTxAttrs attrs,
306     MemTxResult *result, enum device_endian endian)
308     uint8_t *ptr;
309     MemoryRegion *mr;
310     hwaddr l = 4;
311     hwaddr addr1;
312     MemTxResult r;
313     bool release_lock = false;
315     RCU_READ_LOCK();
316     mr = TRANSLATE(addr, &addr1, &l, true, attrs);
317     if (l < 4 || !memory_access_is_direct(mr, true)) {
318         release_lock |= prepare_mmio_access(mr);
319         r = memory_region_dispatch_write(mr, addr1, val,
320                                          MO_32 | devend_memop(endian), attrs);
321     } else {
322         /* RAM case */
323         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
324         switch (endian) {
325         case DEVICE_LITTLE_ENDIAN:
326             stl_le_p(ptr, val);
327             break;
328         case DEVICE_BIG_ENDIAN:
329             stl_be_p(ptr, val);
330             break;
331         default:
332             stl_p(ptr, val);
333             break;
334         }
335         invalidate_and_set_dirty(mr, addr1, 4);
336         r = MEMTX_OK;
337     }
338     if (result) {
339         *result = r;
340     }
341     if (release_lock) {
342         qemu_mutex_unlock_iothread();
343     }
344     RCU_READ_UNLOCK();
347 void glue(address_space_stl, SUFFIX)(ARG1_DECL,
348     hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
350     glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs,
351                                              result, DEVICE_NATIVE_ENDIAN);
354 void glue(address_space_stl_le, SUFFIX)(ARG1_DECL,
355     hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
357     glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs,
358                                              result, DEVICE_LITTLE_ENDIAN);
361 void glue(address_space_stl_be, SUFFIX)(ARG1_DECL,
362     hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
364     glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs,
365                                              result, DEVICE_BIG_ENDIAN);
368 void glue(address_space_stb, SUFFIX)(ARG1_DECL,
369     hwaddr addr, uint8_t val, MemTxAttrs attrs, MemTxResult *result)
371     uint8_t *ptr;
372     MemoryRegion *mr;
373     hwaddr l = 1;
374     hwaddr addr1;
375     MemTxResult r;
376     bool release_lock = false;
378     RCU_READ_LOCK();
379     mr = TRANSLATE(addr, &addr1, &l, true, attrs);
380     if (!memory_access_is_direct(mr, true)) {
381         release_lock |= prepare_mmio_access(mr);
382         r = memory_region_dispatch_write(mr, addr1, val, MO_8, attrs);
383     } else {
384         /* RAM case */
385         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
386         stb_p(ptr, val);
387         invalidate_and_set_dirty(mr, addr1, 1);
388         r = MEMTX_OK;
389     }
390     if (result) {
391         *result = r;
392     }
393     if (release_lock) {
394         qemu_mutex_unlock_iothread();
395     }
396     RCU_READ_UNLOCK();
399 /* warning: addr must be aligned */
400 static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
401     hwaddr addr, uint16_t val, MemTxAttrs attrs,
402     MemTxResult *result, enum device_endian endian)
404     uint8_t *ptr;
405     MemoryRegion *mr;
406     hwaddr l = 2;
407     hwaddr addr1;
408     MemTxResult r;
409     bool release_lock = false;
411     RCU_READ_LOCK();
412     mr = TRANSLATE(addr, &addr1, &l, true, attrs);
413     if (l < 2 || !memory_access_is_direct(mr, true)) {
414         release_lock |= prepare_mmio_access(mr);
415         r = memory_region_dispatch_write(mr, addr1, val,
416                                          MO_16 | devend_memop(endian), attrs);
417     } else {
418         /* RAM case */
419         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
420         switch (endian) {
421         case DEVICE_LITTLE_ENDIAN:
422             stw_le_p(ptr, val);
423             break;
424         case DEVICE_BIG_ENDIAN:
425             stw_be_p(ptr, val);
426             break;
427         default:
428             stw_p(ptr, val);
429             break;
430         }
431         invalidate_and_set_dirty(mr, addr1, 2);
432         r = MEMTX_OK;
433     }
434     if (result) {
435         *result = r;
436     }
437     if (release_lock) {
438         qemu_mutex_unlock_iothread();
439     }
440     RCU_READ_UNLOCK();
443 void glue(address_space_stw, SUFFIX)(ARG1_DECL,
444     hwaddr addr, uint16_t val, MemTxAttrs attrs, MemTxResult *result)
446     glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result,
447                                              DEVICE_NATIVE_ENDIAN);
450 void glue(address_space_stw_le, SUFFIX)(ARG1_DECL,
451     hwaddr addr, uint16_t val, MemTxAttrs attrs, MemTxResult *result)
453     glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result,
454                                              DEVICE_LITTLE_ENDIAN);
457 void glue(address_space_stw_be, SUFFIX)(ARG1_DECL,
458     hwaddr addr, uint16_t val, MemTxAttrs attrs, MemTxResult *result)
460     glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result,
461                                DEVICE_BIG_ENDIAN);
464 static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
465     hwaddr addr, uint64_t val, MemTxAttrs attrs,
466     MemTxResult *result, enum device_endian endian)
468     uint8_t *ptr;
469     MemoryRegion *mr;
470     hwaddr l = 8;
471     hwaddr addr1;
472     MemTxResult r;
473     bool release_lock = false;
475     RCU_READ_LOCK();
476     mr = TRANSLATE(addr, &addr1, &l, true, attrs);
477     if (l < 8 || !memory_access_is_direct(mr, true)) {
478         release_lock |= prepare_mmio_access(mr);
479         r = memory_region_dispatch_write(mr, addr1, val,
480                                          MO_64 | devend_memop(endian), attrs);
481     } else {
482         /* RAM case */
483         ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
484         switch (endian) {
485         case DEVICE_LITTLE_ENDIAN:
486             stq_le_p(ptr, val);
487             break;
488         case DEVICE_BIG_ENDIAN:
489             stq_be_p(ptr, val);
490             break;
491         default:
492             stq_p(ptr, val);
493             break;
494         }
495         invalidate_and_set_dirty(mr, addr1, 8);
496         r = MEMTX_OK;
497     }
498     if (result) {
499         *result = r;
500     }
501     if (release_lock) {
502         qemu_mutex_unlock_iothread();
503     }
504     RCU_READ_UNLOCK();
507 void glue(address_space_stq, SUFFIX)(ARG1_DECL,
508     hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result)
510     glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result,
511                                              DEVICE_NATIVE_ENDIAN);
514 void glue(address_space_stq_le, SUFFIX)(ARG1_DECL,
515     hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result)
517     glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result,
518                                              DEVICE_LITTLE_ENDIAN);
521 void glue(address_space_stq_be, SUFFIX)(ARG1_DECL,
522     hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result)
524     glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result,
525                                              DEVICE_BIG_ENDIAN);
528 #undef ARG1_DECL
529 #undef ARG1
530 #undef SUFFIX
531 #undef TRANSLATE
532 #undef RCU_READ_LOCK
533 #undef RCU_READ_UNLOCK