| /* | |
| * Physical memory access templates | |
| * | |
| * Copyright (c) 2003 Fabrice Bellard | |
| * Copyright (c) 2015 Linaro, Inc. | |
| * Copyright (c) 2016 Red Hat, Inc. | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| /* warning: addr must be aligned */ | |
| static inline | |
| uint64_t glue(address_space_ldm_internal, SUFFIX)(ARG1_DECL, MemOp mop, | |
| hwaddr addr, | |
| MemTxAttrs attrs, | |
| MemTxResult *result) | |
| { | |
| const unsigned size = memop_size(mop); | |
| uint64_t val; | |
| MemoryRegion *mr; | |
| hwaddr l = size; | |
| hwaddr addr1; | |
| MemTxResult r; | |
| bool release_lock = false; | |
| RCU_READ_LOCK(); | |
| mr = TRANSLATE(addr, &addr1, &l, false, attrs); | |
| if (l < size || !memory_access_is_direct(mr, false, attrs)) { | |
| release_lock |= prepare_mmio_access(mr); | |
| /* I/O case */ | |
| r = memory_region_dispatch_read(mr, addr1, &val, mop, attrs); | |
| } else { | |
| /* RAM case */ | |
| fuzz_dma_read_cb(addr, size, mr); | |
| val = ldm_p(qemu_map_ram_ptr(mr->ram_block, addr1), mop); | |
| r = MEMTX_OK; | |
| } | |
| if (result) { | |
| *result = r; | |
| } | |
| if (release_lock) { | |
| bql_unlock(); | |
| } | |
| RCU_READ_UNLOCK(); | |
| return val; | |
| } | |
| uint8_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, hwaddr addr, | |
| MemTxAttrs attrs, MemTxResult *result) | |
| { | |
| return glue(address_space_ldm_internal, SUFFIX)(ARG1, MO_8, addr, | |
| attrs, result); | |
| } | |
| /* warning: addr must be aligned */ | |
| static inline | |
| void glue(address_space_stm_internal, SUFFIX)(ARG1_DECL, MemOp mop, | |
| hwaddr addr, uint64_t val, | |
| MemTxAttrs attrs, | |
| MemTxResult *result) | |
| { | |
| const unsigned size = memop_size(mop); | |
| MemoryRegion *mr; | |
| hwaddr l = size; | |
| hwaddr addr1; | |
| MemTxResult r; | |
| bool release_lock = false; | |
| RCU_READ_LOCK(); | |
| mr = TRANSLATE(addr, &addr1, &l, true, attrs); | |
| if (l < size || !memory_access_is_direct(mr, true, attrs)) { | |
| release_lock |= prepare_mmio_access(mr); | |
| r = memory_region_dispatch_write(mr, addr1, val, mop, attrs); | |
| } else { | |
| /* RAM case */ | |
| stm_p(qemu_map_ram_ptr(mr->ram_block, addr1), mop, val); | |
| invalidate_and_set_dirty(mr, addr1, size); | |
| r = MEMTX_OK; | |
| } | |
| if (result) { | |
| *result = r; | |
| } | |
| if (release_lock) { | |
| bql_unlock(); | |
| } | |
| RCU_READ_UNLOCK(); | |
| } | |
| void glue(address_space_stb, SUFFIX)(ARG1_DECL, hwaddr addr, uint8_t val, | |
| MemTxAttrs attrs, MemTxResult *result) | |
| { | |
| glue(address_space_stm_internal, SUFFIX)(ARG1, MO_8, addr, val, | |
| attrs, result); | |
| } | |
| #ifndef TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API | |
| #define ENDIANNESS | |
| #define MO_ENDIAN (target_big_endian() ? MO_BE : MO_LE) | |
| #include "memory_ldst_endian.c.inc" | |
| #endif /* TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API */ | |
| #define ENDIANNESS _le | |
| #define MO_ENDIAN MO_LE | |
| #include "memory_ldst_endian.c.inc" | |
| #define ENDIANNESS _be | |
| #define MO_ENDIAN MO_BE | |
| #include "memory_ldst_endian.c.inc" | |
| #undef ARG1_DECL | |
| #undef ARG1 | |
| #undef SUFFIX | |
| #undef TRANSLATE | |
| #undef RCU_READ_LOCK | |
| #undef RCU_READ_UNLOCK |