On 5/20/25 09:35, Jamin Lin wrote:
On big-endian hosts, the aspeed_ram_capacity_write() function previously passed
the address of a 64-bit "data" variable directly to address_space_write(),
assuming host and guest endianness matched.

However, the data is expected to be written in little-endian format to DRAM.
On big-endian hosts, this led to incorrect data being written into DRAM,
which caused the guest firmware to misdetect the DRAM size.

As a result, U-Boot fails to boot and hangs.

- Explicitly converting the 32-bit portion of "data" to little-endian format
   using cpu_to_le32(), storing it in a temporary "uint32_t le_data".
- Updating the MemoryRegionOps to restrict access to exactly 4 bytes
   using .valid.{min,max}_access_size = 4 and .impl.min_access_size = 4.

Signed-off-by: Jamin Lin <jamin_...@aspeedtech.com>
Fixes: 7436db1 ("aspeed/soc: fix incorrect dram size for AST2700")
---
  hw/arm/aspeed_ast27x0.c | 21 ++++++++++++++++-----
  1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 1974a25766..7ed0919b3f 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -335,24 +335,34 @@ static void aspeed_ram_capacity_write(void *opaque, 
hwaddr addr, uint64_t data,
      AspeedSoCState *s = ASPEED_SOC(opaque);
      ram_addr_t ram_size;
      MemTxResult result;
+    uint32_t le_data;
ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
                                          &error_abort);
assert(ram_size > 0); + if (size != 4) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Unsupported write size: %d (only 4-byte allowed)\n",
+                      __func__, size);
+        return;
+    }

The core memory subsystem should find such issues if the valid attributes
of MemoryRegionOps are set correctly.

+    le_data = cpu_to_le32((uint32_t)data);
+
      /*
       * Emulate ddr capacity hardware behavior.
       * If writes the data to the address which is beyond the ram size,
       * it would write the data to the "address % ram_size".
       */
      result = address_space_write(&s->dram_as, addr % ram_size,
-                                 MEMTXATTRS_UNSPECIFIED, &data, 4);
+                                 MEMTXATTRS_UNSPECIFIED, &le_data, 4);


This should be enough :

    address_space_stl_le(&s->dram_as, addr % ram_size, data,
                         MEMTXATTRS_UNSPECIFIED, &result);

Sorry for not spotting this earlier. Finding a BE host is difficult.
Thanks for the time you spent on fixing this issue.

C.


      if (result != MEMTX_OK) {
          qemu_log_mask(LOG_GUEST_ERROR,
                        "%s: DRAM write failed, addr:0x%" HWADDR_PRIx
-                      ", data :0x%" PRIx64  "\n",
-                      __func__, addr % ram_size, data);
+                      ", data :0x%x\n",
+                      __func__, addr % ram_size, le_data);
      }
  }
@@ -360,9 +370,10 @@ static const MemoryRegionOps aspeed_ram_capacity_ops = {
      .read = aspeed_ram_capacity_read,
      .write = aspeed_ram_capacity_write,
      .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl.min_access_size = 4,
      .valid = {
-        .min_access_size = 1,
-        .max_access_size = 8,
+        .min_access_size = 4,
+        .max_access_size = 4,
      },
  };


Reply via email to