block/nvme: Fix use of write-only doorbells page on Aarch64 arch

qemu_vfio_pci_map_bar() calls mmap(), and mmap(2) states:

  'offset' must be a multiple of the page size as returned
   by sysconf(_SC_PAGE_SIZE).

In commit f68453237b we started to use an offset of 4K which
broke this contract on Aarch64 arch.

Fix by mapping at offset 0, and and accessing doorbells at offset=4K.

Fixes: f68453237b ("block/nvme: Map doorbells pages write-only")
Reported-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20201029093306.1063879-24-philmd@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
This commit is contained in:
Philippe Mathieu-Daudé 2020-10-29 10:33:04 +01:00 committed by Stefan Hajnoczi
parent 9e13d59884
commit 4b19e9b815

View File

@ -94,6 +94,7 @@ typedef struct {
struct BDRVNVMeState { struct BDRVNVMeState {
AioContext *aio_context; AioContext *aio_context;
QEMUVFIOState *vfio; QEMUVFIOState *vfio;
void *bar0_wo_map;
/* Memory mapped registers */ /* Memory mapped registers */
volatile struct { volatile struct {
uint32_t sq_tail; uint32_t sq_tail;
@ -777,8 +778,10 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace,
} }
} }
s->doorbells = qemu_vfio_pci_map_bar(s->vfio, 0, sizeof(NvmeBar), s->bar0_wo_map = qemu_vfio_pci_map_bar(s->vfio, 0, 0,
NVME_DOORBELL_SIZE, PROT_WRITE, errp); sizeof(NvmeBar) + NVME_DOORBELL_SIZE,
PROT_WRITE, errp);
s->doorbells = (void *)((uintptr_t)s->bar0_wo_map + sizeof(NvmeBar));
if (!s->doorbells) { if (!s->doorbells) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
@ -910,8 +913,8 @@ static void nvme_close(BlockDriverState *bs)
&s->irq_notifier[MSIX_SHARED_IRQ_IDX], &s->irq_notifier[MSIX_SHARED_IRQ_IDX],
false, NULL, NULL); false, NULL, NULL);
event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]); event_notifier_cleanup(&s->irq_notifier[MSIX_SHARED_IRQ_IDX]);
qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->doorbells, qemu_vfio_pci_unmap_bar(s->vfio, 0, s->bar0_wo_map,
sizeof(NvmeBar), NVME_DOORBELL_SIZE); 0, sizeof(NvmeBar) + NVME_DOORBELL_SIZE);
qemu_vfio_close(s->vfio); qemu_vfio_close(s->vfio);
g_free(s->device); g_free(s->device);