@@ -30,6 +30,76 @@
#define LOONGSON3_BIOSNAME "loongarch_bios.bin"
+static struct _loaderparams {
+ unsigned long 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)
+{
+ return addr & 0x1fffffffll;
+}
+
+static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
+{
+ int64_t kernel_entry, kernel_low, kernel_high, initrd_size = 0;
+ long kernel_size;
+ ram_addr_t initrd_offset = 0;
+ void *cmdline_buf;
+ int ret = 0;
+
+ 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);
+ }
+
+ fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ENTRY, kernel_entry);
+
+ if (loaderparams.initrd_filename) {
+ initrd_size = get_image_size(loaderparams.initrd_filename);
+
+ if (initrd_size > 0) {
+ initrd_offset = MAX(INITRD_BASE,
+ ROUND_UP(kernel_high, INITRD_PAGE_SIZE));
+ if (initrd_offset + initrd_size > 0x10000000) {
+ error_report("ramdisk '%s' is too big",
+ loaderparams.initrd_filename);
+ exit(1);
+ }
+ initrd_size = load_image_targphys(loaderparams.initrd_filename,
+ initrd_offset,
+ loaderparams.ram_size - initrd_offset);
+ }
+ if (initrd_size == (target_ulong) -1) {
+ error_report("could not load initial ram disk '%s'",
+ loaderparams.initrd_filename);
+ exit(1);
+ }
+ }
+
+ cmdline_buf = g_malloc0(COMMAND_LINE_SIZE);
+ if (initrd_size > 0)
+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE,
+ "initrd=0x%lx,%li %s", initrd_offset,
+ initrd_size, loaderparams.kernel_cmdline));
+ else
+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, "%s",
+ loaderparams.kernel_cmdline));
+
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ret);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf);
+}
+
static void loongarch_cpu_reset(void *opaque)
{
LoongArchCPU *cpu = opaque;
@@ -257,6 +327,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
static void loongarch_init(MachineState *machine)
{
const char *cpu_model = machine->cpu_type;
+ const char *kernel_filename = machine->kernel_filename;
+ const char *kernel_cmdline = machine->kernel_cmdline;
+ const char *initrd_filename = machine->initrd_filename;
LoongArchCPU *la_cpu;
CPULoongArchState *env;
ram_addr_t offset = 0;
@@ -331,6 +404,14 @@ static void loongarch_init(MachineState *machine)
exit(1);
}
+ if (kernel_filename) {
+ loaderparams.ram_size = ram_size;
+ loaderparams.kernel_filename = kernel_filename;
+ loaderparams.kernel_cmdline = kernel_cmdline;
+ loaderparams.initrd_filename = initrd_filename;
+ fw_cfg_add_kernel_info(lams->fw_cfg);
+ }
+
memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
LA_BIOS_SIZE, &error_fatal);
memory_region_set_readonly(&lams->bios, true);
@@ -39,6 +39,11 @@
#define LA_BIOS_BASE 0x1c000000
#define LA_BIOS_SIZE (4 * 1024 * 1024)
+/* Kernels can be configured with 64KB pages */
+#define INITRD_PAGE_SIZE (64 * KiB)
+#define INITRD_BASE 0x04000000
+#define COMMAND_LINE_SIZE 4096
+
typedef struct LoongArchMachineState {
/*< private >*/
MachineState parent_obj;