diff mbox series

[1/8] hw/loongarch: Add default bios startup support

Message ID 20220620080451.3711049-2-yangxiaojuan@loongson.cn (mailing list archive)
State New, archived
Headers show
Series Add some functions for LoongArch | expand

Commit Message

Xiaojuan Yang June 20, 2022, 8:04 a.m. UTC
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/loongarch/fw_cfg.c       | 33 +++++++++++++++
 hw/loongarch/fw_cfg.h       | 15 +++++++
 hw/loongarch/loongson3.c    | 81 ++++++++++++++++++++++++++++++++++++-
 include/hw/loongarch/virt.h |  7 ++++
 4 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 hw/loongarch/fw_cfg.c
 create mode 100644 hw/loongarch/fw_cfg.h

Comments

chen huacai June 20, 2022, 10:04 a.m. UTC | #1
Hi, Xiaojuan,

On Mon, Jun 20, 2022 at 4:21 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> ---
>  hw/loongarch/fw_cfg.c       | 33 +++++++++++++++
>  hw/loongarch/fw_cfg.h       | 15 +++++++
>  hw/loongarch/loongson3.c    | 81 ++++++++++++++++++++++++++++++++++++-
>  include/hw/loongarch/virt.h |  7 ++++
>  4 files changed, 135 insertions(+), 1 deletion(-)
>  create mode 100644 hw/loongarch/fw_cfg.c
>  create mode 100644 hw/loongarch/fw_cfg.h
>
> diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
> new file mode 100644
> index 0000000000..a641f603b6
> --- /dev/null
> +++ b/hw/loongarch/fw_cfg.c
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU fw_cfg helpers (LoongArch specific)
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/loongarch/fw_cfg.h"
> +#include "hw/loongarch/virt.h"
> +#include "hw/nvram/fw_cfg.h"
> +#include "sysemu/sysemu.h"
> +
> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
> +                            Error **errp)
> +{
> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
> +}
> +
> +FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms)
> +{
> +    FWCfgState *fw_cfg;
> +    int max_cpus = ms->smp.max_cpus;
> +    int smp_cpus = ms->smp.cpus;
> +
> +    fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 8, 0, NULL);
> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
> +
> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> +    return fw_cfg;
> +}
> diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h
> new file mode 100644
> index 0000000000..7c0de4db4a
> --- /dev/null
> +++ b/hw/loongarch/fw_cfg.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU fw_cfg helpers (LoongArch specific)
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGARCH_FW_CFG_H
> +#define HW_LOONGARCH_FW_CFG_H
> +
> +#include "hw/boards.h"
> +#include "hw/nvram/fw_cfg.h"
> +
> +FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms);
> +#endif
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index bd20ebbb78..1e2c69dd8e 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -28,13 +28,46 @@
>  #include "hw/pci-host/ls7a.h"
>  #include "hw/pci-host/gpex.h"
>  #include "hw/misc/unimp.h"
> -
> +#include "hw/loongarch/fw_cfg.h"
>  #include "target/loongarch/cpu.h"
>
>  #define PM_BASE 0x10080000
>  #define PM_SIZE 0x100
>  #define PM_CTRL 0x10
>
> +struct la_memmap_entry {
> +    uint64_t address;
> +    uint64_t length;
> +    uint32_t type;
> +    uint32_t reserved;
> +};
> +
> +static struct la_memmap_entry *la_memmap_table;
> +static unsigned la_memmap_entries;
Since they are static, we can drop the la_ prefix here. And if a
prefix is really needed, I prefer loongarch_ or larch rather than la_.

Huacai

> +
> +static int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
> +{
> +    int i;
> +
> +    for (i = 0; i < la_memmap_entries; i++) {
> +        if (la_memmap_table[i].address == address) {
> +            fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n",
> +                     __func__, address, length);
> +            return 0;
> +        }
> +    }
> +
> +    la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table,
> +                                                      la_memmap_entries + 1);
> +    la_memmap_table[la_memmap_entries].address = cpu_to_le64(address);
> +    la_memmap_table[la_memmap_entries].length = cpu_to_le64(length);
> +    la_memmap_table[la_memmap_entries].type = cpu_to_le32(type);
> +    la_memmap_entries++;
> +
> +    return la_memmap_entries;
> +}
> +
> +
>  /*
>   * This is a placeholder for missing ACPI,
>   * and will eventually be replaced.
> @@ -279,6 +312,38 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
>      loongarch_devices_init(pch_pic);
>  }
>
> +static bool loongarch_firmware_init(LoongArchMachineState *lams)
> +{
> +    char *filename = MACHINE(lams)->firmware;
> +    char *bios_name = NULL;
> +    bool loaded = false;
> +    int bios_size;
> +
> +    if (filename) {
> +        bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
> +        if (!bios_name) {
> +            error_report("Could not find ROM image '%s'", filename);
> +            exit(1);
> +        }
> +
> +        bios_size = load_image_targphys(bios_name, LA_BIOS_BASE, LA_BIOS_SIZE);
> +        if (bios_size < 0) {
> +            error_report("Could not load ROM image '%s'", bios_name);
> +            exit(1);
> +        }
> +
> +        g_free(bios_name);
> +
> +        memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
> +                               LA_BIOS_SIZE, &error_fatal);
> +        memory_region_set_readonly(&lams->bios, true);
> +        memory_region_add_subregion(get_system_memory(), LA_BIOS_BASE, &lams->bios);
> +        loaded = true;
> +    }
> +
> +    return loaded;
> +}
> +
>  static void reset_load_elf(void *opaque)
>  {
>      LoongArchCPU *cpu = opaque;
> @@ -301,6 +366,7 @@ static void loongarch_init(MachineState *machine)
>      LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>      LoongArchCPU *lacpu;
>      int i;
> +    bool firmware_loaded;
>      int64_t kernel_addr = 0;
>
>      if (!cpu_model) {
> @@ -327,15 +393,28 @@ static void loongarch_init(MachineState *machine)
>                               machine->ram, 0, 256 * MiB);
>      memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
>      offset += 256 * MiB;
> +    la_memmap_add_entry(0, 256 * MiB, 1);
>      highram_size = ram_size - 256 * MiB;
>      memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
>                               machine->ram, offset, highram_size);
>      memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
> +    la_memmap_add_entry(0x90000000, highram_size, 1);
>      /* Add isa io region */
>      memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
>                               get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
>      memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
>                                  &lams->isa_io);
> +    /* load the BIOS image. */
> +    firmware_loaded = loongarch_firmware_init(lams);
> +    lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
> +    rom_set_fw(lams->fw_cfg);
> +
> +    if (lams->fw_cfg != NULL) {
> +        fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
> +                        la_memmap_table,
> +                        sizeof(struct la_memmap_entry) * (la_memmap_entries));
> +    }
> +
>      if (kernel_filename) {
>          loaderparams.ram_size = ram_size;
>          loaderparams.kernel_filename = kernel_filename;
> diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
> index 09a816191c..448f46fc6b 100644
> --- a/include/hw/loongarch/virt.h
> +++ b/include/hw/loongarch/virt.h
> @@ -17,6 +17,9 @@
>
>  #define LOONGARCH_ISA_IO_BASE   0x18000000UL
>  #define LOONGARCH_ISA_IO_SIZE   0x0004000
> +#define FW_CFG_ADDR             0x1e020000
> +#define LA_BIOS_BASE            0x1c000000
> +#define LA_BIOS_SIZE            (4 * MiB)
>
>  struct LoongArchMachineState {
>      /*< private >*/
> @@ -26,6 +29,10 @@ struct LoongArchMachineState {
>      MemoryRegion lowmem;
>      MemoryRegion highmem;
>      MemoryRegion isa_io;
> +    MemoryRegion bios;
> +
> +    /* State for other subsystems/APIs: */
> +    FWCfgState  *fw_cfg;
>  };
>
>  #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
> --
> 2.31.1
>
>
diff mbox series

Patch

diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
new file mode 100644
index 0000000000..a641f603b6
--- /dev/null
+++ b/hw/loongarch/fw_cfg.c
@@ -0,0 +1,33 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU fw_cfg helpers (LoongArch specific)
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/loongarch/fw_cfg.h"
+#include "hw/loongarch/virt.h"
+#include "hw/nvram/fw_cfg.h"
+#include "sysemu/sysemu.h"
+
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+                            Error **errp)
+{
+    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+}
+
+FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms)
+{
+    FWCfgState *fw_cfg;
+    int max_cpus = ms->smp.max_cpus;
+    int smp_cpus = ms->smp.cpus;
+
+    fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 8, 0, NULL);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+    return fw_cfg;
+}
diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h
new file mode 100644
index 0000000000..7c0de4db4a
--- /dev/null
+++ b/hw/loongarch/fw_cfg.h
@@ -0,0 +1,15 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU fw_cfg helpers (LoongArch specific)
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_FW_CFG_H
+#define HW_LOONGARCH_FW_CFG_H
+
+#include "hw/boards.h"
+#include "hw/nvram/fw_cfg.h"
+
+FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms);
+#endif
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index bd20ebbb78..1e2c69dd8e 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -28,13 +28,46 @@ 
 #include "hw/pci-host/ls7a.h"
 #include "hw/pci-host/gpex.h"
 #include "hw/misc/unimp.h"
-
+#include "hw/loongarch/fw_cfg.h"
 #include "target/loongarch/cpu.h"
 
 #define PM_BASE 0x10080000
 #define PM_SIZE 0x100
 #define PM_CTRL 0x10
 
+struct la_memmap_entry {
+    uint64_t address;
+    uint64_t length;
+    uint32_t type;
+    uint32_t reserved;
+};
+
+static struct la_memmap_entry *la_memmap_table;
+static unsigned la_memmap_entries;
+
+static int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
+{
+    int i;
+
+    for (i = 0; i < la_memmap_entries; i++) {
+        if (la_memmap_table[i].address == address) {
+            fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n",
+                     __func__, address, length);
+            return 0;
+        }
+    }
+
+    la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table,
+                                                      la_memmap_entries + 1);
+    la_memmap_table[la_memmap_entries].address = cpu_to_le64(address);
+    la_memmap_table[la_memmap_entries].length = cpu_to_le64(length);
+    la_memmap_table[la_memmap_entries].type = cpu_to_le32(type);
+    la_memmap_entries++;
+
+    return la_memmap_entries;
+}
+
+
 /*
  * This is a placeholder for missing ACPI,
  * and will eventually be replaced.
@@ -279,6 +312,38 @@  static void loongarch_irq_init(LoongArchMachineState *lams)
     loongarch_devices_init(pch_pic);
 }
 
+static bool loongarch_firmware_init(LoongArchMachineState *lams)
+{
+    char *filename = MACHINE(lams)->firmware;
+    char *bios_name = NULL;
+    bool loaded = false;
+    int bios_size;
+
+    if (filename) {
+        bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
+        if (!bios_name) {
+            error_report("Could not find ROM image '%s'", filename);
+            exit(1);
+        }
+
+        bios_size = load_image_targphys(bios_name, LA_BIOS_BASE, LA_BIOS_SIZE);
+        if (bios_size < 0) {
+            error_report("Could not load ROM image '%s'", bios_name);
+            exit(1);
+        }
+
+        g_free(bios_name);
+
+        memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
+                               LA_BIOS_SIZE, &error_fatal);
+        memory_region_set_readonly(&lams->bios, true);
+        memory_region_add_subregion(get_system_memory(), LA_BIOS_BASE, &lams->bios);
+        loaded = true;
+    }
+
+    return loaded;
+}
+
 static void reset_load_elf(void *opaque)
 {
     LoongArchCPU *cpu = opaque;
@@ -301,6 +366,7 @@  static void loongarch_init(MachineState *machine)
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
     LoongArchCPU *lacpu;
     int i;
+    bool firmware_loaded;
     int64_t kernel_addr = 0;
 
     if (!cpu_model) {
@@ -327,15 +393,28 @@  static void loongarch_init(MachineState *machine)
                              machine->ram, 0, 256 * MiB);
     memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
     offset += 256 * MiB;
+    la_memmap_add_entry(0, 256 * MiB, 1);
     highram_size = ram_size - 256 * MiB;
     memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
                              machine->ram, offset, highram_size);
     memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
+    la_memmap_add_entry(0x90000000, highram_size, 1);
     /* Add isa io region */
     memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
                              get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
     memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
                                 &lams->isa_io);
+    /* load the BIOS image. */
+    firmware_loaded = loongarch_firmware_init(lams);
+    lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
+    rom_set_fw(lams->fw_cfg);
+
+    if (lams->fw_cfg != NULL) {
+        fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
+                        la_memmap_table,
+                        sizeof(struct la_memmap_entry) * (la_memmap_entries));
+    }
+
     if (kernel_filename) {
         loaderparams.ram_size = ram_size;
         loaderparams.kernel_filename = kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 09a816191c..448f46fc6b 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -17,6 +17,9 @@ 
 
 #define LOONGARCH_ISA_IO_BASE   0x18000000UL
 #define LOONGARCH_ISA_IO_SIZE   0x0004000
+#define FW_CFG_ADDR             0x1e020000
+#define LA_BIOS_BASE            0x1c000000
+#define LA_BIOS_SIZE            (4 * MiB)
 
 struct LoongArchMachineState {
     /*< private >*/
@@ -26,6 +29,10 @@  struct LoongArchMachineState {
     MemoryRegion lowmem;
     MemoryRegion highmem;
     MemoryRegion isa_io;
+    MemoryRegion bios;
+
+    /* State for other subsystems/APIs: */
+    FWCfgState  *fw_cfg;
 };
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")