diff options
-rw-r--r-- | debian/patches/series | 1 | ||||
-rw-r--r-- | debian/patches/upstream/0001-avoid-unsupported-adm64-instructions.patch | 113 |
2 files changed, 114 insertions, 0 deletions
diff --git a/debian/patches/series b/debian/patches/series index 2ecdfd2..99a2d89 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ debian/0001-meson-nose2.patch +upstream/0001-avoid-unsupported-adm64-instructions.patch diff --git a/debian/patches/upstream/0001-avoid-unsupported-adm64-instructions.patch b/debian/patches/upstream/0001-avoid-unsupported-adm64-instructions.patch new file mode 100644 index 0000000..a53c44d --- /dev/null +++ b/debian/patches/upstream/0001-avoid-unsupported-adm64-instructions.patch @@ -0,0 +1,113 @@ +Author: Oliver Upton <oliver.upton@linux.dev> +Description: common.h: Avoid using unsupported load/store instructions in arm64 VMs + Using nvme show-regs within a VM on arm64 can sometimes lead to VM + termination. + . + To answer why this happens: one of the deficiencies of the Arm + architecture is that there exists a range of load/store instructions + that have insufficient decode information for traps taken to the + hypervisor. KVM, for example, may raise an external abort or outright + terminate the VM depending on the configuration. + . + This is a known problem on the kernel side, and is fixed by using + assembly MMIO accessors w/ 'safe' load/store instructions. So do + exactly that, providing arm64-specific accessors and falling back to + plain old volatile pointer accesses for other architectures. + +diff -Naurp nvme-cli.orig/common.h nvme-cli/common.h +--- nvme-cli.orig/common.h ++++ nvme-cli/common.h +@@ -17,43 +17,81 @@ + #define __packed __attribute__((__packed__)) + #endif /* __packed */ + +-static inline uint32_t mmio_read32(void *addr) ++/* ++ * VMs on arm64 can only use a subset of instructions for MMIO that provide ++ * the hypervisor with a complete instruction decode. Provide assembly MMIO ++ * accessors to prevent the compiler from using a possibly unsupported ++ * instruction. ++ * ++ * See kernel commit c726200dd106 ("KVM: arm/arm64: Allow reporting non-ISV ++ * data aborts to userspace") for more details. ++ */ ++#if defined(__aarch64__) ++static inline leint32_t __raw_readl(const volatile leint32_t *addr) ++{ ++ leint32_t val; ++ ++ asm volatile("ldr %w0, %1" : "=r" (val) : "Qo" (*addr)); ++ ++ return val; ++} ++ ++static inline void __raw_writel(volatile leint32_t *addr, leint32_t val) + { +- leint32_t *p = addr; ++ asm volatile("str %w0, %1" : : "r" (val), "Qo" (*addr)); ++} + +- return le32_to_cpu(*p); ++static inline void __raw_writeq(volatile leint64_t *addr, leint64_t val) ++{ ++ asm volatile("str %0, %1" : : "r" (val), "Qo" (*addr)); ++} ++#else ++static inline leint32_t __raw_readl(volatile leint32_t *addr) ++{ ++ return *addr; ++} ++ ++static inline void __raw_writel(volatile leint32_t *addr, leint32_t val) ++{ ++ *addr = val; ++} ++ ++static inline void __raw_writeq(volatile leint64_t *addr, leint64_t val) ++{ ++ *addr = val; ++} ++#endif ++ ++static inline uint32_t mmio_read32(void *addr) ++{ ++ return le32_to_cpu(__raw_readl(addr)); + } + + /* Access 64-bit registers as 2 32-bit; Some devices fail 64-bit MMIO. */ + static inline uint64_t mmio_read64(void *addr) + { +- const volatile uint32_t *p = addr; + uint32_t low, high; + +- low = le32_to_cpu(*p); +- high = le32_to_cpu(*(p + 1)); ++ low = le32_to_cpu(__raw_readl(addr)); ++ high = le32_to_cpu(__raw_readl(addr + sizeof(leint32_t))); + + return ((uint64_t)high << 32) | low; + } + + static inline void mmio_write32(void *addr, uint32_t value) + { +- leint32_t *p = addr; +- +- *p = cpu_to_le32(value); ++ __raw_writel(addr, cpu_to_le32(value)); + } + + /* Access 64-bit registers as 2 32-bit if write32 flag set; Some devices fail 64-bit MMIO. */ + static inline void mmio_write64(void *addr, uint64_t value, bool write32) + { +- uint64_t *p = addr; +- + if (write32) { + mmio_write32(addr, value); + mmio_write32((uint32_t *)addr + 1, value >> 32); + return; + } + +- *p = cpu_to_le64(value); ++ __raw_writeq(addr, cpu_to_le64(value)); + } + #endif |