Add riscv_is_big_endian() helper that checks the hart's big-endian CPU
property and use it throughout the boot code:

- ELF loading: pass ELFDATA2MSB or ELFDATA2LSB based on endianness
- Firmware dynamic info: use cpu_to_be* or cpu_to_le* based on endianness
- Reset vector: instructions (entries 0-5) remain always little-endian,
  data words (entries 6-9) use target data endianness. For RV64 BE, the
  hi/lo word pairs within each dword are swapped since LD reads as BE.

This is part of the runtime big-endian support series which avoids
separate BE binaries by handling endianness as a CPU property.
---
 hw/riscv/boot.c         | 68 +++++++++++++++++++++++++++++++++--------
 include/hw/riscv/boot.h |  2 ++
 2 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index e5490beda0..e9a049d2ba 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -40,6 +40,11 @@ bool riscv_is_32bit(RISCVHartArrayState *harts)
     return mcc->def->misa_mxl_max == MXL_RV32;
 }
 
+bool riscv_is_big_endian(RISCVHartArrayState *harts)
+{
+    return harts->harts[0].cfg.big_endian;
+}
+
 /*
  * Return the per-socket PLIC hart topology configuration string
  * (caller must free with g_free())
@@ -72,6 +77,7 @@ void riscv_boot_info_init(RISCVBootInfo *info, 
RISCVHartArrayState *harts)
     info->kernel_size = 0;
     info->initrd_size = 0;
     info->is_32bit = riscv_is_32bit(harts);
+    info->is_big_endian = riscv_is_big_endian(harts);
 }
 
 vaddr riscv_calc_kernel_start_addr(RISCVBootInfo *info,
@@ -247,8 +253,10 @@ void riscv_load_kernel(MachineState *machine,
      */
     kernel_size = load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, NULL,
                                    &info->image_low_addr, 
&info->image_high_addr,
-                                   NULL, ELFDATA2LSB, EM_RISCV,
-                                   1, 0, NULL, true, sym_cb);
+                                   NULL,
+                                   info->is_big_endian ? ELFDATA2MSB
+                                                       : ELFDATA2LSB,
+                                   EM_RISCV, 1, 0, NULL, true, sym_cb);
     if (kernel_size > 0) {
         info->kernel_size = kernel_size;
         goto out;
@@ -391,21 +399,32 @@ void riscv_rom_copy_firmware_info(MachineState *machine,
     struct fw_dynamic_info64 dinfo64;
     void *dinfo_ptr = NULL;
     size_t dinfo_len;
+    bool big_endian = riscv_is_big_endian(harts);
 
     if (riscv_is_32bit(harts)) {
-        dinfo32.magic = cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
-        dinfo32.version = cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
-        dinfo32.next_mode = cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
-        dinfo32.next_addr = cpu_to_le32(kernel_entry);
+        dinfo32.magic = big_endian ? cpu_to_be32(FW_DYNAMIC_INFO_MAGIC_VALUE)
+                                   : cpu_to_le32(FW_DYNAMIC_INFO_MAGIC_VALUE);
+        dinfo32.version = big_endian ? cpu_to_be32(FW_DYNAMIC_INFO_VERSION)
+                                     : cpu_to_le32(FW_DYNAMIC_INFO_VERSION);
+        dinfo32.next_mode = big_endian
+                          ? cpu_to_be32(FW_DYNAMIC_INFO_NEXT_MODE_S)
+                          : cpu_to_le32(FW_DYNAMIC_INFO_NEXT_MODE_S);
+        dinfo32.next_addr = big_endian ? cpu_to_be32(kernel_entry)
+                                       : cpu_to_le32(kernel_entry);
         dinfo32.options = 0;
         dinfo32.boot_hart = 0;
         dinfo_ptr = &dinfo32;
         dinfo_len = sizeof(dinfo32);
     } else {
-        dinfo64.magic = cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE);
-        dinfo64.version = cpu_to_le64(FW_DYNAMIC_INFO_VERSION);
-        dinfo64.next_mode = cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S);
-        dinfo64.next_addr = cpu_to_le64(kernel_entry);
+        dinfo64.magic = big_endian ? cpu_to_be64(FW_DYNAMIC_INFO_MAGIC_VALUE)
+                                   : cpu_to_le64(FW_DYNAMIC_INFO_MAGIC_VALUE);
+        dinfo64.version = big_endian ? cpu_to_be64(FW_DYNAMIC_INFO_VERSION)
+                                     : cpu_to_le64(FW_DYNAMIC_INFO_VERSION);
+        dinfo64.next_mode = big_endian
+                          ? cpu_to_be64(FW_DYNAMIC_INFO_NEXT_MODE_S)
+                          : cpu_to_le64(FW_DYNAMIC_INFO_NEXT_MODE_S);
+        dinfo64.next_addr = big_endian ? cpu_to_be64(kernel_entry)
+                                       : cpu_to_le64(kernel_entry);
         dinfo64.options = 0;
         dinfo64.boot_hart = 0;
         dinfo_ptr = &dinfo64;
@@ -474,10 +493,35 @@ void riscv_setup_rom_reset_vec(MachineState *machine, 
RISCVHartArrayState *harts
         reset_vec[2] = 0x00000013;   /*     addi   x0, x0, 0 */
     }
 
-    /* copy in the reset vector in little_endian byte order */
-    for (i = 0; i < ARRAY_SIZE(reset_vec); i++) {
+    /* RISC-V instructions are always little-endian */
+    for (i = 0; i < 6; i++) {
         reset_vec[i] = cpu_to_le32(reset_vec[i]);
     }
+
+    /*
+     * Data words (addresses at entries 6-9) must match the firmware's data
+     * endianness. For 64-bit big-endian, the high/low word order within
+     * each dword must also be swapped since LD interprets bytes as BE.
+     */
+    if (riscv_is_big_endian(harts)) {
+        if (!riscv_is_32bit(harts)) {
+            uint32_t tmp;
+            tmp = reset_vec[6];
+            reset_vec[6] = cpu_to_be32(reset_vec[7]);
+            reset_vec[7] = cpu_to_be32(tmp);
+            tmp = reset_vec[8];
+            reset_vec[8] = cpu_to_be32(reset_vec[9]);
+            reset_vec[9] = cpu_to_be32(tmp);
+        } else {
+            for (i = 6; i < ARRAY_SIZE(reset_vec); i++) {
+                reset_vec[i] = cpu_to_be32(reset_vec[i]);
+            }
+        }
+    } else {
+        for (i = 6; i < ARRAY_SIZE(reset_vec); i++) {
+            reset_vec[i] = cpu_to_le32(reset_vec[i]);
+        }
+    }
     rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
                           rom_base, &address_space_memory);
     riscv_rom_copy_firmware_info(machine, harts,
diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index f00b3ca122..a54c2b397d 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -36,9 +36,11 @@ typedef struct RISCVBootInfo {
     ssize_t initrd_size;
 
     bool is_32bit;
+    bool is_big_endian;
 } RISCVBootInfo;
 
 bool riscv_is_32bit(RISCVHartArrayState *harts);
+bool riscv_is_big_endian(RISCVHartArrayState *harts);
 
 char *riscv_plic_hart_config_string(int hart_count);
 
-- 
2.34.1

Reply via email to