diff mbox series

[v3,39/43] hw/loongarch: Add LoongArch load elf function.

Message ID 20220429100729.1572481-40-yangxiaojuan@loongson.cn (mailing list archive)
State New, archived
Headers show
Series Add LoongArch softmmu support | expand

Commit Message

Xiaojuan Yang April 29, 2022, 10:07 a.m. UTC
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
 hw/loongarch/loongson3.c    | 66 +++++++++++++++++++++++++++++++++++--
 include/hw/loongarch/virt.h |  9 +++++
 target/loongarch/cpu.h      |  2 ++
 3 files changed, 75 insertions(+), 2 deletions(-)

Comments

Richard Henderson May 7, 2022, 10:08 p.m. UTC | #1
On 4/29/22 05:07, Xiaojuan Yang wrote:
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   hw/loongarch/loongson3.c    | 66 +++++++++++++++++++++++++++++++++++--
>   include/hw/loongarch/virt.h |  9 +++++
>   target/loongarch/cpu.h      |  2 ++
>   3 files changed, 75 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index 7029d8c8b8..f9ee024f63 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -19,6 +19,8 @@
>   #include "exec/address-spaces.h"
>   #include "hw/irq.h"
>   #include "net/net.h"
> +#include "hw/loader.h"
> +#include "elf.h"
>   #include "hw/intc/loongarch_ipi.h"
>   #include "hw/intc/loongarch_extioi.h"
>   #include "hw/intc/loongarch_pch_pic.h"
> @@ -29,6 +31,36 @@
>   
>   #include "target/loongarch/cpu.h"
>   
> +static struct _loaderparams {
> +    unsigned long ram_size;
> +    const char *kernel_filename;
> +} loaderparams;

Never use "unsigned long", only "uint{32,64}_t" or "size_t".
Otherwise you don't know what the host is going to give you.

> +static int64_t load_kernel_info(void)
> +{
> +    int64_t kernel_entry, kernel_low, kernel_high;

Why are you using signed values here,

> +    long kernel_size;
> +
> +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
> +                           cpu_loongarch_virt_to_phys, NULL,
> +                           (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
> +                           (uint64_t *)&kernel_high, NULL, 0,

and casting them?  Oh, and kernel_size must be ssize_t.

> @@ -237,22 +283,38 @@ static void loongarch_init(MachineState *machine)
>           cpu_create(machine->cpu_type);
>       }
>   
> +    if (ram_size < 1 * GiB) {
> +        error_report("ram_size must be greater than 1G.");
> +        exit(1);
> +    }

Why is this here?  It's certainly not related to load_elf.


r~
diff mbox series

Patch

diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 7029d8c8b8..f9ee024f63 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -19,6 +19,8 @@ 
 #include "exec/address-spaces.h"
 #include "hw/irq.h"
 #include "net/net.h"
+#include "hw/loader.h"
+#include "elf.h"
 #include "hw/intc/loongarch_ipi.h"
 #include "hw/intc/loongarch_extioi.h"
 #include "hw/intc/loongarch_pch_pic.h"
@@ -29,6 +31,36 @@ 
 
 #include "target/loongarch/cpu.h"
 
+static struct _loaderparams {
+    unsigned long ram_size;
+    const char *kernel_filename;
+} loaderparams;
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+    return addr & 0x1fffffffll;
+}
+
+static int64_t load_kernel_info(void)
+{
+    int64_t kernel_entry, kernel_low, kernel_high;
+    long kernel_size;
+
+    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
+                           cpu_loongarch_virt_to_phys, NULL,
+                           (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
+                           (uint64_t *)&kernel_high, NULL, 0,
+                           EM_LOONGARCH, 1, 0);
+
+    if (kernel_size < 0) {
+        error_report("could not load kernel '%s': %s",
+                     loaderparams.kernel_filename,
+                     load_elf_strerror(kernel_size));
+        exit(1);
+    }
+    return kernel_entry;
+}
+
 static void loongarch_devices_init(DeviceState *pch_pic)
 {
     DeviceState *gpex_dev;
@@ -213,15 +245,29 @@  static void loongarch_irq_init(LoongArchMachineState *lams)
     loongarch_devices_init(pch_pic);
 }
 
+static void reset_load_elf(void *opaque)
+{
+    LoongArchCPU *cpu = opaque;
+    CPULoongArchState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+    if (env->load_elf) {
+        cpu_set_pc(CPU(cpu), env->elf_address);
+    }
+}
+
 static void loongarch_init(MachineState *machine)
 {
     const char *cpu_model = machine->cpu_type;
+    const char *kernel_filename = machine->kernel_filename;
     ram_addr_t offset = 0;
     ram_addr_t ram_size = machine->ram_size;
     uint64_t highram_size = 0;
     MemoryRegion *address_space_mem = get_system_memory();
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    LoongArchCPU *lacpu;
     int i;
+    int64_t kernel_addr = 0;
 
     if (!cpu_model) {
         cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
@@ -237,22 +283,38 @@  static void loongarch_init(MachineState *machine)
         cpu_create(machine->cpu_type);
     }
 
+    if (ram_size < 1 * GiB) {
+        error_report("ram_size must be greater than 1G.");
+        exit(1);
+    }
+
     /* Add memory region */
     memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
                              machine->ram, 0, 256 * MiB);
     memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
     offset += 256 * MiB;
-
     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);
-
     /* 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);
+    if (kernel_filename) {
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        kernel_addr = load_kernel_info();
+        if (!machine->firmware) {
+            for (i = 0; i < machine->smp.cpus; i++) {
+                lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
+                lacpu->env.load_elf = true;
+                lacpu->env.elf_address = kernel_addr;
+                qemu_register_reset(reset_load_elf, lacpu);
+            }
+        }
+    }
     /* Initialize the IO interrupt subsystem */
     loongarch_irq_init(lams);
 }
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 09a816191c..35e6bc5055 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -12,12 +12,17 @@ 
 #include "hw/boards.h"
 #include "qemu/queue.h"
 #include "hw/intc/loongarch_ipi.h"
+#include "qemu/units.h"
 
 #define LOONGARCH_MAX_VCPUS     4
 
 #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 >*/
     MachineState parent_obj;
@@ -26,6 +31,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")
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 03cc96ee9b..71a5036c3c 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -308,6 +308,8 @@  typedef struct CPUArchState {
     AddressSpace address_space_iocsr;
     MemoryRegion system_iocsr;
     MemoryRegion iocsr_mem;
+    bool load_elf;
+    uint64_t elf_address;
 } CPULoongArchState;
 
 /**