From 7ecf09a13de7f3146c01abd4cbde2be9641e45ea Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 3 Jul 2018 01:11:04 -0400 Subject: [PATCH] exec: Fix MAP_RAM for cached access When an IOMMUMemoryRegion is in front of a virtio device, address_space_cache_init does not set cache->ptr as the memory region is not RAM. However when the device performs an access, we end up in glue() which performs the translation and then uses MAP_RAM. This latter uses the unset ptr and returns a wrong value which leads to a SIGSEV in address_space_lduw_internal_cached_slow, for instance. In slow path cache->ptr is NULL and MAP_RAM must redirect to qemu_map_ram_ptr((mr)->ram_block, ofs). As MAP_RAM, IS_DIRECT and INVALIDATE are the same in _cached_slow and non cached mode, let's remove those macros. This fixes the use cases featuring vIOMMU (Intel and ARM SMMU) which lead to a SIGSEV. Fixes: 48564041a73a (exec: reintroduce MemoryRegion caching) Backports part of commit a99761d3c85679da380c0f597468acd3dc1b53b3 from qemu --- qemu/exec.c | 2 -- qemu/memory_ldst.inc.c | 41 ++++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/qemu/exec.c b/qemu/exec.c index 15580a3b..987a2dc1 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -2325,8 +2325,6 @@ void cpu_physical_memory_unmap(AddressSpace *as, void *buffer, hwaddr len, #define ARG1 as #define SUFFIX #define TRANSLATE(...) address_space_translate(as, __VA_ARGS__) -#define IS_DIRECT(mr, is_write) memory_access_is_direct(mr, is_write) -#define MAP_RAM(mr, ofs) qemu_map_ram_ptr((mr)->uc, (mr)->ram_block, ofs) #define INVALIDATE(mr, ofs, len) #define RCU_READ_LOCK(...) rcu_read_lock() #define RCU_READ_UNLOCK(...) rcu_read_unlock() diff --git a/qemu/memory_ldst.inc.c b/qemu/memory_ldst.inc.c index 4e505cf4..8f625b31 100644 --- a/qemu/memory_ldst.inc.c +++ b/qemu/memory_ldst.inc.c @@ -15,7 +15,8 @@ * 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 + * You should have received a copy of t ptr = MAP_RAM(mr, addr1); +he GNU Lesser General Public * License along with this library; if not, see . */ @@ -36,7 +37,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, false); - if (l < 4 || !IS_DIRECT(mr, false)) { + if (l < 4 || !memory_access_is_direct(mr, false)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -53,7 +54,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL, #endif } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = ldl_le_p(ptr); @@ -136,7 +137,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, false); - if (l < 8 || !IS_DIRECT(mr, false)) { + if (l < 8 || !memory_access_is_direct(mr, false)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -153,7 +154,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, #endif } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = ldq_le_p(ptr); @@ -234,7 +235,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, false); - if (!IS_DIRECT(mr, false)) { + if (!memory_access_is_direct(mr, false)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -242,7 +243,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs); } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); val = ldub_p(ptr); r = MEMTX_OK; } @@ -282,7 +283,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, false); - if (l < 2 || !IS_DIRECT(mr, false)) { + if (l < 2 || !memory_access_is_direct(mr, false)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -299,7 +300,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, #endif } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: val = lduw_le_p(ptr); @@ -382,13 +383,13 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, true); - if (l < 4 || !IS_DIRECT(mr, true)) { + if (l < 4 || !memory_access_is_direct(mr, true)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); } else { - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); stl_p(ptr, val); r = MEMTX_OK; } @@ -426,7 +427,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, true); - if (l < 4 || !IS_DIRECT(mr, true)) { + if (l < 4 || !memory_access_is_direct(mr, true)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -442,7 +443,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: stl_le_p(ptr, val); @@ -522,13 +523,13 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, true); - if (!IS_DIRECT(mr, true)) { + if (!memory_access_is_direct(mr, true)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); r = memory_region_dispatch_write(mr, addr1, val, 1, attrs); } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); stb_p(ptr, val); INVALIDATE(mr, addr1, 1); r = MEMTX_OK; @@ -567,7 +568,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, true); - if (l < 2 || !IS_DIRECT(mr, true)) { + if (l < 2 || !memory_access_is_direct(mr, true)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -583,7 +584,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, r = memory_region_dispatch_write(mr, addr1, val, 2, attrs); } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: stw_le_p(ptr, val); @@ -664,7 +665,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, // Unicorn: commented out //RCU_READ_LOCK(); mr = TRANSLATE(addr, &addr1, &l, true); - if (l < 8 || !IS_DIRECT(mr, true)) { + if (l < 8 || !memory_access_is_direct(mr, true)) { // Unicorn: commented out //release_lock |= prepare_mmio_access(mr); @@ -680,7 +681,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, r = memory_region_dispatch_write(mr, addr1, val, 8, attrs); } else { /* RAM case */ - ptr = MAP_RAM(mr, addr1); + ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1); switch (endian) { case DEVICE_LITTLE_ENDIAN: stq_le_p(ptr, val); @@ -750,8 +751,6 @@ void glue(stq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) #undef ARG1 #undef SUFFIX #undef TRANSLATE -#undef IS_DIRECT -#undef MAP_RAM #undef INVALIDATE #undef RCU_READ_LOCK #undef RCU_READ_UNLOCK