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
This commit is contained in:
Eric Auger 2018-07-03 01:11:04 -04:00 committed by Lioncash
parent e8b92838fe
commit 7ecf09a13d
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
2 changed files with 20 additions and 23 deletions

View file

@ -2325,8 +2325,6 @@ void cpu_physical_memory_unmap(AddressSpace *as, void *buffer, hwaddr len,
#define ARG1 as #define ARG1 as
#define SUFFIX #define SUFFIX
#define TRANSLATE(...) address_space_translate(as, __VA_ARGS__) #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 INVALIDATE(mr, ofs, len)
#define RCU_READ_LOCK(...) rcu_read_lock() #define RCU_READ_LOCK(...) rcu_read_lock()
#define RCU_READ_UNLOCK(...) rcu_read_unlock() #define RCU_READ_UNLOCK(...) rcu_read_unlock()

View file

@ -15,7 +15,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * 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 <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
@ -36,7 +37,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //release_lock |= prepare_mmio_access(mr);
@ -53,7 +54,7 @@ static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
#endif #endif
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
switch (endian) { switch (endian) {
case DEVICE_LITTLE_ENDIAN: case DEVICE_LITTLE_ENDIAN:
val = ldl_le_p(ptr); val = ldl_le_p(ptr);
@ -136,7 +137,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //release_lock |= prepare_mmio_access(mr);
@ -153,7 +154,7 @@ static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
#endif #endif
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
switch (endian) { switch (endian) {
case DEVICE_LITTLE_ENDIAN: case DEVICE_LITTLE_ENDIAN:
val = ldq_le_p(ptr); val = ldq_le_p(ptr);
@ -234,7 +235,7 @@ uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false); mr = TRANSLATE(addr, &addr1, &l, false);
if (!IS_DIRECT(mr, false)) { if (!memory_access_is_direct(mr, false)) {
// Unicorn: commented out // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //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); r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs);
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
val = ldub_p(ptr); val = ldub_p(ptr);
r = MEMTX_OK; r = MEMTX_OK;
} }
@ -282,7 +283,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, false); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //release_lock |= prepare_mmio_access(mr);
@ -299,7 +300,7 @@ static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
#endif #endif
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
switch (endian) { switch (endian) {
case DEVICE_LITTLE_ENDIAN: case DEVICE_LITTLE_ENDIAN:
val = lduw_le_p(ptr); val = lduw_le_p(ptr);
@ -382,13 +383,13 @@ void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs); r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
} else { } else {
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
stl_p(ptr, val); stl_p(ptr, val);
r = MEMTX_OK; r = MEMTX_OK;
} }
@ -426,7 +427,7 @@ static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //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); r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
switch (endian) { switch (endian) {
case DEVICE_LITTLE_ENDIAN: case DEVICE_LITTLE_ENDIAN:
stl_le_p(ptr, val); stl_le_p(ptr, val);
@ -522,13 +523,13 @@ void glue(address_space_stb, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true); mr = TRANSLATE(addr, &addr1, &l, true);
if (!IS_DIRECT(mr, true)) { if (!memory_access_is_direct(mr, true)) {
// Unicorn: commented out // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //release_lock |= prepare_mmio_access(mr);
r = memory_region_dispatch_write(mr, addr1, val, 1, attrs); r = memory_region_dispatch_write(mr, addr1, val, 1, attrs);
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
stb_p(ptr, val); stb_p(ptr, val);
INVALIDATE(mr, addr1, 1); INVALIDATE(mr, addr1, 1);
r = MEMTX_OK; r = MEMTX_OK;
@ -567,7 +568,7 @@ static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //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); r = memory_region_dispatch_write(mr, addr1, val, 2, attrs);
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
switch (endian) { switch (endian) {
case DEVICE_LITTLE_ENDIAN: case DEVICE_LITTLE_ENDIAN:
stw_le_p(ptr, val); stw_le_p(ptr, val);
@ -664,7 +665,7 @@ static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
// Unicorn: commented out // Unicorn: commented out
//RCU_READ_LOCK(); //RCU_READ_LOCK();
mr = TRANSLATE(addr, &addr1, &l, true); 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 // Unicorn: commented out
//release_lock |= prepare_mmio_access(mr); //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); r = memory_region_dispatch_write(mr, addr1, val, 8, attrs);
} else { } else {
/* RAM case */ /* RAM case */
ptr = MAP_RAM(mr, addr1); ptr = qemu_map_ram_ptr(mr->uc, mr->ram_block, addr1);
switch (endian) { switch (endian) {
case DEVICE_LITTLE_ENDIAN: case DEVICE_LITTLE_ENDIAN:
stq_le_p(ptr, val); 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 ARG1
#undef SUFFIX #undef SUFFIX
#undef TRANSLATE #undef TRANSLATE
#undef IS_DIRECT
#undef MAP_RAM
#undef INVALIDATE #undef INVALIDATE
#undef RCU_READ_LOCK #undef RCU_READ_LOCK
#undef RCU_READ_UNLOCK #undef RCU_READ_UNLOCK