@@ -103,6 +103,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)
@@ -352,18 +354,97 @@ static void reset_load_elf(void *opaque)
}
}
+/* Load an image file into an fw_cfg entry identified by key. */
+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)
+{
+ 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;
+ }
+ }
+}
+
static void loongarch_init(MachineState *machine)
{
+ LoongArchCPU *lacpu;
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("la464");
@@ -412,20 +493,23 @@ static void loongarch_init(MachineState *machine)
memmap_table,
sizeof(struct memmap_entry) * (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 (lams->bios_loaded) {
+ loongarch_firmware_boot(lams);
+ } else {
+ loongarch_direct_kernel_boot(lams);
}
}
+ /* register reset function */
+ for (i = 0; i < machine->smp.cpus; i++) {
+ lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
+ qemu_register_reset(reset_load_elf, lacpu);
+ }
/* Initialize the IO interrupt subsystem */
loongarch_irq_init(lams);
}