[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Bug: physmem: address_space_read_cached_slow() accesses wrong MemoryRegi
From: |
Jonathan Cameron |
Subject: |
Bug: physmem: address_space_read_cached_slow() accesses wrong MemoryRegion on latter part of large reads. |
Date: |
Mon, 12 Feb 2024 16:31:43 +0000 |
Hi All,
The continuing saga of a getting CXL emulation to play well with using the
memory as normal RAM ran into (hopefully) a last issue.
When running my boot image via virtio-blk-pci and having deliberately forced
some
buffers to end up in the CXL memory via
$ numactl --membind=1 ls
then on shut down I was getting a failure to allocate a large enough DMA buffer
even with Mattias' set to increase the size and an extra patch to apply that to
the main system memory (as virtio ignores iommu and PCI address space).
gdb/bt pointed at virtqueue_split_pop() bt pointed later than the actual problem
as descriptors were loaded but corrupt here:
https://elixir.bootlin.com/qemu/latest/source/hw/virtio/virtio.c#L1573
https://elixir.bootlin.com/qemu/latest/source/hw/virtio/virtio.c#L306
After a chase (via a highly suspicious read size of 0xffffffff it turns
out it was issuing a 16 byte read via address_space_read_cached_slow() and
getting a very odd answer.
The first 8 bytes was the correct virtio descriptor content the second 8
were coming from the flash region at physical address 0 onwards on arm-virt.
With those breadcrumbs the problem was (I think) easy to find.
https://elixir.bootlin.com/qemu/latest/source/include/exec/memory.h#L3029
address_space_read_cached_slow() operates on a MemoryRegionCache with the
hwaddr being relative to the start of that cached region.
However it calls flatview_read_continue() That's fine as long as we can
do the read in one go.
For normal memory flatview_read_continue() will deal with splitting a read up
but on each iteration it loads the mr via
mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
to cope with reads that cross MemoryRegions.
https://elixir.bootlin.com/qemu/latest/source/system/physmem.c#L2737
Unfortunately the addr passed in here is the one addressing into the
MemoryRegionCache offset by whatever we already read.
Which for this bug example that was 0x8 (in the flash memory).
Assuming I have correctly identified the problem.
One potential fix is to define a new
MemtxResult address_space_read_cached_continue(MemoryRegionCache *cache,
hwaddr addr, MemTxAttr attrs,
void *ptr, hwaddr len,
hwaddr addr1, hwaddr l,
MemoryRegion *mr)
That is nearly identical to flatview_read_continue() but with the
mr = flatview_translate() replaced with
mr = address_space_translate_cached(cache, addr, &addr1, &l, false, attrs)
That's a bit ugly though given the duplicated code but any other change
is going to involve some more invasive splitting out of utility functions
to share all but the outer loop.
I don't currently have a test hitting it but assume
flatview_write_continue() in address_space_write_cached_slow() has the
same problem.
Jonathan
p.s. Will tidy this and the rest of my house of cards up then post it.
I suspect we'll carry on hitting QEMU limitations with the CXL emulation
but for now I have x86 and ARM setups that work with TCG.
Hmm. Need to spend some time getting regressions tests in place :(
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Bug: physmem: address_space_read_cached_slow() accesses wrong MemoryRegion on latter part of large reads.,
Jonathan Cameron <=