From 95b84938573fe876ae99ed27b2680a7604ddae9a Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 20 Sep 2023 10:27:42 +0200 Subject: [PATCH] drivers/nvme: Return an error in case of non dword-aligned data buffer This is a specific case for NVMe where given data buffer pointers must be dword (4 bytes) aligned. There is no virtual memory management between the user thread and NVMe driver (which one could detect such wrong alignement on physical memory and thus reallocate the memory properly, so it would be fully transparent for the user thread), thus the need to push that check to the user. This has been going under the radar so far as Qemu does not seem to follow NVMe specifications where PRP1 (in DPTR) must always be dword-aligned. It really does not follow the rule: specifications details that if bits 1:0 of PRP1 are set, the controller may generate an error or treat the address as if these bits were unset. Seems like a bug in Qemu, I did not check the code there however. Signed-off-by: Tomasz Bursztyka --- drivers/disk/nvme/nvme_disk.c | 10 ++++++++++ drivers/disk/nvme/nvme_helpers.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/disk/nvme/nvme_disk.c b/drivers/disk/nvme/nvme_disk.c index 3308e04db5b..834a6e2e6c7 100644 --- a/drivers/disk/nvme/nvme_disk.c +++ b/drivers/disk/nvme/nvme_disk.c @@ -34,6 +34,11 @@ static int nvme_disk_read(struct disk_info *disk, uint32_t payload_size; int ret = 0; + if (!NVME_IS_BUFFER_DWORD_ALIGNED(data_buf)) { + LOG_WRN("Data buffer pointer needs to be 4-bytes aligned"); + return -EINVAL; + } + nvme_lock(disk->dev); payload_size = num_sector * nvme_namespace_get_sector_size(ns); @@ -78,6 +83,11 @@ static int nvme_disk_write(struct disk_info *disk, uint32_t payload_size; int ret = 0; + if (!NVME_IS_BUFFER_DWORD_ALIGNED(data_buf)) { + LOG_WRN("Data buffer pointer needs to be 4-bytes aligned"); + return -EINVAL; + } + nvme_lock(disk->dev); payload_size = num_sector * nvme_namespace_get_sector_size(ns); diff --git a/drivers/disk/nvme/nvme_helpers.h b/drivers/disk/nvme/nvme_helpers.h index fb8165be519..325c6e9b842 100644 --- a/drivers/disk/nvme/nvme_helpers.h +++ b/drivers/disk/nvme/nvme_helpers.h @@ -514,4 +514,6 @@ enum shst_value { (mm_reg_t)b_a + nvme_mmio_offsetof(reg) + 4); \ } while (0) +#define NVME_IS_BUFFER_DWORD_ALIGNED(_buf_addr) (!((uintptr_t)_buf_addr & 0x3)) + #endif /* ZEPHYR_DRIVERS_DISK_NVME_NHME_HELPERS_H_ */