physmem: Fix wrong address in large address_space_read/write_cached_slow()
If the access is bigger than the MemoryRegion supports, flatview_read/write_continue() will attempt to update the Memory Region. but the address passed to flatview_translate() is relative to the cache, not to the FlatView. On arm/virt with interleaved CXL memory emulation and virtio-blk-pci this lead to the first part of descriptor being read from the CXL memory and the second part from PA 0x8 which happens to be a blank region of a flash chip and all ffs on this particular configuration. Note this test requires the out of tree ARM support for CXL, but the problem is more general. Avoid this by adding new address_space_read_continue_cached() and address_space_write_continue_cached() which share all the logic with the flatview versions except for the MemoryRegion lookup which is unnecessary as the MemoryRegionCache only covers one MemoryRegion. Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Link: https://lore.kernel.org/r/20240307153710.30907-5-Jonathan.Cameron@huawei.com Signed-off-by: Peter Xu <peterx@redhat.com>
This commit is contained in:
parent
e7927d33cf
commit
47293c922c
@ -3370,6 +3370,59 @@ static inline MemoryRegion *address_space_translate_cached(
|
||||
return section.mr;
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
static MemTxResult address_space_write_continue_cached(MemTxAttrs attrs,
|
||||
const void *ptr,
|
||||
hwaddr len,
|
||||
hwaddr mr_addr,
|
||||
hwaddr l,
|
||||
MemoryRegion *mr)
|
||||
{
|
||||
MemTxResult result = MEMTX_OK;
|
||||
const uint8_t *buf = ptr;
|
||||
|
||||
for (;;) {
|
||||
result |= flatview_write_continue_step(attrs, buf, len, mr_addr, &l,
|
||||
mr);
|
||||
|
||||
len -= l;
|
||||
buf += l;
|
||||
mr_addr += l;
|
||||
|
||||
if (!len) {
|
||||
break;
|
||||
}
|
||||
|
||||
l = len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
static MemTxResult address_space_read_continue_cached(MemTxAttrs attrs,
|
||||
void *ptr, hwaddr len,
|
||||
hwaddr mr_addr, hwaddr l,
|
||||
MemoryRegion *mr)
|
||||
{
|
||||
MemTxResult result = MEMTX_OK;
|
||||
uint8_t *buf = ptr;
|
||||
|
||||
for (;;) {
|
||||
result |= flatview_read_continue_step(attrs, buf, len, mr_addr, &l, mr);
|
||||
len -= l;
|
||||
buf += l;
|
||||
mr_addr += l;
|
||||
|
||||
if (!len) {
|
||||
break;
|
||||
}
|
||||
l = len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section. address_space_read_cached uses this
|
||||
* out of line function when the target is an MMIO or IOMMU region.
|
||||
*/
|
||||
@ -3383,9 +3436,8 @@ address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr,
|
||||
l = len;
|
||||
mr = address_space_translate_cached(cache, addr, &mr_addr, &l, false,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
return flatview_read_continue(cache->fv,
|
||||
addr, MEMTXATTRS_UNSPECIFIED, buf, len,
|
||||
mr_addr, l, mr);
|
||||
return address_space_read_continue_cached(MEMTXATTRS_UNSPECIFIED,
|
||||
buf, len, mr_addr, l, mr);
|
||||
}
|
||||
|
||||
/* Called from RCU critical section. address_space_write_cached uses this
|
||||
@ -3401,9 +3453,8 @@ address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr,
|
||||
l = len;
|
||||
mr = address_space_translate_cached(cache, addr, &mr_addr, &l, true,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
return flatview_write_continue(cache->fv,
|
||||
addr, MEMTXATTRS_UNSPECIFIED, buf, len,
|
||||
mr_addr, l, mr);
|
||||
return address_space_write_continue_cached(MEMTXATTRS_UNSPECIFIED,
|
||||
buf, len, mr_addr, l, mr);
|
||||
}
|
||||
|
||||
#define ARG1_DECL MemoryRegionCache *cache
|
||||
|
Loading…
Reference in New Issue
Block a user