qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/2] system/memory.c: support unaligned access


From: Tomoyuki HIROSE
Subject: [PATCH 1/2] system/memory.c: support unaligned access
Date: Mon, 11 Dec 2023 16:12:03 +0900

The previous code ignored 'impl.unaligned' and handled unaligned accesses
as is. But this implementation cannot emulate specific registers of some
devices that allow unaligned access such as xHCI Host Controller Capability
Registers.
This commit checks 'impl.unaligned' and if it is false, QEMU emulates
unaligned access with multiple aligned access.

Signed-off-by: Tomoyuki HIROSE <tomoyuki.hirose@igel.co.jp>
---
 system/memory.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/system/memory.c b/system/memory.c
index 798b6c0a17..b0caa90fef 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -539,6 +539,9 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
     unsigned i;
     MemTxResult r = MEMTX_OK;
     bool reentrancy_guard_applied = false;
+    hwaddr aligned_addr;
+    unsigned corrected_size = size;
+    signed align_diff = 0;
 
     if (!access_size_min) {
         access_size_min = 1;
@@ -560,18 +563,25 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
         reentrancy_guard_applied = true;
     }
 
-    /* FIXME: support unaligned access? */
     access_size = MAX(MIN(size, access_size_max), access_size_min);
     access_mask = MAKE_64BIT_MASK(0, access_size * 8);
+    if (!mr->ops->impl.unaligned) {
+        aligned_addr = addr & ~(access_size - 1);
+        align_diff = addr - aligned_addr;
+        corrected_size = size < access_size ? access_size :
+                            size + (align_diff > 0 ? access_size : 0);
+        addr = aligned_addr;
+    }
     if (memory_region_big_endian(mr)) {
-        for (i = 0; i < size; i += access_size) {
+        for (i = 0; i < corrected_size; i += access_size) {
             r |= access_fn(mr, addr + i, value, access_size,
-                        (size - access_size - i) * 8, access_mask, attrs);
+                        (size - access_size - i + align_diff) * 8,
+                        access_mask, attrs);
         }
     } else {
-        for (i = 0; i < size; i += access_size) {
-            r |= access_fn(mr, addr + i, value, access_size, i * 8,
-                        access_mask, attrs);
+        for (i = 0; i < corrected_size; i += access_size) {
+            r |= access_fn(mr, addr + i, value, access_size,
+                        ((signed)i - align_diff) * 8, access_mask, attrs);
         }
     }
     if (mr->dev && reentrancy_guard_applied) {
-- 
2.39.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]