ppc/amigaone: Add kernel and initrd support

Add support for -kernel, -initrd and -append command line options.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Message-ID: <489b1be5d95d5153e924c95b0691b8b53f9ffb9e.1740673173.git.balaton@eik.bme.hu>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
This commit is contained in:
BALATON Zoltan 2025-02-27 17:39:18 +01:00 committed by Nicholas Piggin
parent c2bed9957a
commit 34f053d86b

View file

@ -25,11 +25,14 @@
#include "system/qtest.h"
#include "system/reset.h"
#include "kvm_ppc.h"
#include "elf.h"
#include <zlib.h> /* for crc32 */
#define BUS_FREQ_HZ 100000000
#define INITRD_MIN_ADDR 0x600000
/*
* Firmware binary available at
* https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28
@ -178,12 +181,68 @@ static const TypeInfo nvram_types[] = {
};
DEFINE_TYPES(nvram_types)
struct boot_info {
hwaddr entry;
hwaddr stack;
hwaddr bd_info;
hwaddr initrd_start;
hwaddr initrd_end;
hwaddr cmdline_start;
hwaddr cmdline_end;
};
/* Board info struct from U-Boot */
struct bd_info {
uint32_t bi_memstart;
uint32_t bi_memsize;
uint32_t bi_flashstart;
uint32_t bi_flashsize;
uint32_t bi_flashoffset;
uint32_t bi_sramstart;
uint32_t bi_sramsize;
uint32_t bi_bootflags;
uint32_t bi_ip_addr;
uint8_t bi_enetaddr[6];
uint16_t bi_ethspeed;
uint32_t bi_intfreq;
uint32_t bi_busfreq;
uint32_t bi_baudrate;
} QEMU_PACKED;
static void create_bd_info(hwaddr addr, ram_addr_t ram_size)
{
struct bd_info *bd = g_new0(struct bd_info, 1);
bd->bi_memsize = cpu_to_be32(ram_size);
bd->bi_flashstart = cpu_to_be32(PROM_ADDR);
bd->bi_flashsize = cpu_to_be32(1); /* match what U-Boot detects */
bd->bi_bootflags = cpu_to_be32(1);
bd->bi_intfreq = cpu_to_be32(11.5 * BUS_FREQ_HZ);
bd->bi_busfreq = cpu_to_be32(BUS_FREQ_HZ);
bd->bi_baudrate = cpu_to_be32(115200);
cpu_physical_memory_write(addr, bd, sizeof(*bd));
}
static void amigaone_cpu_reset(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
cpu_reset(CPU(cpu));
cpu_ppc_tb_reset(&cpu->env);
if (env->load_info) {
struct boot_info *bi = env->load_info;
env->gpr[1] = bi->stack;
env->gpr[2] = 1024;
env->gpr[3] = bi->bd_info;
env->gpr[4] = bi->initrd_start;
env->gpr[5] = bi->initrd_end;
env->gpr[6] = bi->cmdline_start;
env->gpr[7] = bi->cmdline_end;
env->nip = bi->entry;
}
cpu_ppc_tb_reset(env);
}
static void fix_spd_data(uint8_t *spd)
@ -205,6 +264,8 @@ static void amigaone_init(MachineState *machine)
I2CBus *i2c_bus;
uint8_t *spd_data;
DriveInfo *di;
hwaddr loadaddr;
struct boot_info *bi = NULL;
/* init CPU */
cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
@ -301,6 +362,56 @@ static void amigaone_init(MachineState *machine)
}
pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, "ide")));
pci_vga_init(pci_bus);
if (!machine->kernel_filename) {
return;
}
/* handle -kernel, -initrd, -append options and emulate U-Boot */
bi = g_new0(struct boot_info, 1);
cpu->env.load_info = bi;
loadaddr = MIN(machine->ram_size, 256 * MiB);
bi->bd_info = loadaddr - 8 * MiB;
create_bd_info(bi->bd_info, machine->ram_size);
bi->stack = bi->bd_info - 64 * KiB - 8;
if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
size_t len = strlen(machine->kernel_cmdline);
loadaddr = bi->bd_info + 1 * MiB;
cpu_physical_memory_write(loadaddr, machine->kernel_cmdline, len + 1);
bi->cmdline_start = loadaddr;
bi->cmdline_end = loadaddr + len + 1; /* including terminating '\0' */
}
sz = load_elf(machine->kernel_filename, NULL, NULL, NULL,
&bi->entry, &loadaddr, NULL, NULL,
ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
if (sz <= 0) {
sz = load_uimage(machine->kernel_filename, &bi->entry, &loadaddr,
NULL, NULL, NULL);
}
if (sz <= 0) {
error_report("Could not load kernel '%s'",
machine->kernel_filename);
exit(1);
}
loadaddr += sz;
if (machine->initrd_filename) {
loadaddr = ROUND_UP(loadaddr + 4 * MiB, 4 * KiB);
loadaddr = MAX(loadaddr, INITRD_MIN_ADDR);
sz = load_image_targphys(machine->initrd_filename, loadaddr,
bi->bd_info - loadaddr);
if (sz <= 0) {
error_report("Could not load initrd '%s'",
machine->initrd_filename);
exit(1);
}
bi->initrd_start = loadaddr;
bi->initrd_end = loadaddr + sz;
}
}
static void amigaone_machine_init(MachineClass *mc)