@@ -109,6 +109,8 @@ static const MemoryRegionOps loongarch_virt_pm_ops = {
static struct _loaderparams {
uint64_t ram_size;
const char *kernel_filename;
+ const char *kernel_cmdline;
+ const char *initrd_filename;
} loaderparams;
static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
@@ -355,19 +357,114 @@ static void reset_load_elf(void *opaque)
}
}
+/**
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
+ * by key.
+ * @fw_cfg: The firmware config instance to store the data in.
+ * @size_key: The firmware config key to store the size of the loaded
+ * data under, with fw_cfg_add_i32().
+ * @data_key: The firmware config key to store the loaded data under,
+ * with fw_cfg_add_bytes().
+ * @image_name: The name of the image file to load. If it is NULL, the
+ * function returns without doing anything.
+ * @try_decompress: Whether the image should be decompressed (gunzipped) before
+ * adding it to fw_cfg. If decompression fails, the image is
+ * loaded as-is.
+ *
+ * In case of failure, the function prints an error message to stderr and the
+ * process exits with status 1.
+ */
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
+ uint16_t data_key, const char *image_name,
+ bool try_decompress)
+{
+ size_t size = -1;
+ uint8_t *data;
+
+ if (image_name == NULL) {
+ return;
+ }
+
+ if (try_decompress) {
+ size = load_image_gzipped_buffer(image_name,
+ LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
+ }
+
+ if (size == (size_t)-1) {
+ gchar *contents;
+ gsize length;
+
+ if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
+ error_report("failed to load \"%s\"", image_name);
+ exit(1);
+ }
+ size = length;
+ data = (uint8_t *)contents;
+ }
+
+ fw_cfg_add_i32(fw_cfg, size_key, size);
+ fw_cfg_add_bytes(fw_cfg, data_key, data, size);
+}
+
+static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
+{
+ /*
+ * Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ loaderparams.kernel_filename,
+ false);
+
+ if (loaderparams.initrd_filename) {
+ load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ loaderparams.initrd_filename, false);
+ }
+
+ if (loaderparams.kernel_cmdline) {
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+ strlen(loaderparams.kernel_cmdline) + 1);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+ loaderparams.kernel_cmdline);
+ }
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams, bool firmware_loaded)
+{
+ fw_cfg_add_kernel_info(lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(LoongArchMachineState *lams)
+{
+ MachineState *machine = MACHINE(lams);
+ int64_t kernel_addr = 0;
+ LoongArchCPU *lacpu;
+ int i;
+
+ 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);
+ }
+ }
+}
+
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;
bool firmware_loaded;
- int64_t kernel_addr = 0;
if (!cpu_model) {
cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
@@ -414,18 +511,16 @@ static void loongarch_init(MachineState *machine)
la_memmap_table,
sizeof(struct la_memmap_entry) * (la_memmap_entries));
}
-
- 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);
- }
+ loaderparams.ram_size = ram_size;
+ loaderparams.kernel_filename = machine->kernel_filename;
+ loaderparams.kernel_cmdline = machine->kernel_cmdline;
+ loaderparams.initrd_filename = machine->initrd_filename;
+ /* Load the kernel. */
+ if (loaderparams.kernel_filename) {
+ if (firmware_loaded) {
+ loongarch_firmware_boot(lams, firmware_loaded);
+ } else {
+ loongarch_direct_kernel_boot(lams);
}
}
/* Initialize the IO interrupt subsystem */
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn> --- hw/loongarch/loongson3.c | 125 ++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 15 deletions(-)