Skip to content

Commit

Permalink
hw/loongarch: Add linux kernel booting support
Browse files Browse the repository at this point in the history
There are two situations to start system by kernel file. If exists bios
option, system will boot from loaded bios file, else system will boot
from hardcoded auxcode, and jump to kernel elf entry.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Message-Id: <20220712083206.4187715-4-yangxiaojuan@loongson.cn>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
yangxiaojuan-loongson authored and rth7680 committed Jul 19, 2022
1 parent 98afb0d commit fb1cd3a
Showing 1 changed file with 99 additions and 15 deletions.
114 changes: 99 additions & 15 deletions hw/loongarch/loongson3.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit fb1cd3a

Please sign in to comment.