Add a firmware for the m68k virt machine The firmware is based on petit boot (also used in bare metal POWER systems)
Petit boot is embedded in a buildroot filesystem. This patch define the buildroot repository, add make targets to build and install the kernel and filesystem produced by buildroot. To build the firmware: $ git submodule init roms/buildroot $ git submodule update roms/buildroot $ make -C roms m68k-virt-firmware Signed-off-by: Laurent Vivier <laur...@vivier.eu> --- configure | 3 +- include/hw/misc/virt_ctrl.h | 6 ++ hw/m68k/virt.c | 12 +++- hw/misc/virt_ctrl.c | 111 +++++++++++++++++++++++++++++++++++- .gitmodules | 3 + pc-bios/meson.build | 2 + roms/Makefile | 8 +++ roms/buildroot | 1 + 8 files changed, 140 insertions(+), 6 deletions(-) create mode 160000 roms/buildroot diff --git a/configure b/configure index e6cfc0e4be6c..5cc3d7029455 100755 --- a/configure +++ b/configure @@ -3685,7 +3685,8 @@ for bios_file in \ $source_path/pc-bios/openbios-* \ $source_path/pc-bios/u-boot.* \ $source_path/pc-bios/palcode-* \ - $source_path/pc-bios/qemu_vga.ndrv + $source_path/pc-bios/qemu_vga.ndrv \ + $source_path/pc-bios/m68k-virt.* do LINKS="$LINKS pc-bios/$(basename $bios_file)" diff --git a/include/hw/misc/virt_ctrl.h b/include/hw/misc/virt_ctrl.h index 25a237e51874..e1a3f027ab03 100644 --- a/include/hw/misc/virt_ctrl.h +++ b/include/hw/misc/virt_ctrl.h @@ -17,6 +17,12 @@ struct VirtCtrlState { qemu_irq irq; uint32_t irq_enabled; + + MachineState *machine; + char *fw_elf; + char *fw_ramfs; + uint32_t fw_bootinfo_size; + uint8_t *fw_bootinfo; }; #endif diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 11aff6d93865..d6af84d1a3f6 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -89,9 +89,11 @@ /* * At the end of the memory address space we have a 1 MB ROM */ -#define VIRT_ROM_ADDR 0xfff00000 -#define VIRT_ROM_SIZE 0x00100000 -#define VIRT_ROM_NAME "m68k-virt.rom" +#define VIRT_ROM_ADDR 0xfff00000 +#define VIRT_ROM_SIZE 0x00100000 +#define VIRT_ROM_NAME "m68k-virt.rom" +#define VIRT_FW_ELF_NAME "m68k-virt.vmlinux" +#define VIRT_FW_RAMFS_NAME "m68k-virt.petitboot" typedef struct { M68kCPU *cpu; @@ -202,6 +204,10 @@ static void virt_init(MachineState *machine) /* virt controller */ dev = qdev_new(TYPE_VIRT_CTRL); + object_property_set_link(OBJECT(dev), "machine", OBJECT(machine), + &error_abort); + qdev_prop_set_string(dev, "fw.elf", VIRT_FW_ELF_NAME); + qdev_prop_set_string(dev, "fw.ramfs", VIRT_FW_RAMFS_NAME); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, VIRT_CTRL_MMIO_BASE); diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c index e75d1e7e17b3..2ac725f1570b 100644 --- a/hw/misc/virt_ctrl.c +++ b/hw/misc/virt_ctrl.c @@ -5,28 +5,98 @@ */ #include "qemu/osdep.h" +#include "qemu/datadir.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" +#include "hw/loader.h" +#include "hw/boards.h" #include "migration/vmstate.h" #include "qemu/log.h" #include "trace.h" +#include "elf.h" #include "sysemu/runstate.h" #include "hw/misc/virt_ctrl.h" enum { REG_FEATURES = 0x00, REG_CMD = 0x04, + REG_PARAM = 0x08, }; #define FEAT_POWER_CTRL 0x00000001 +#define FEAT_FW_CTRL 0x00000002 + +#define FEAT_SUPPORTED (FEAT_POWER_CTRL | FEAT_FW_CTRL) enum { + /* Power Control */ CMD_NOOP, CMD_RESET, CMD_HALT, CMD_PANIC, + /* Firmware Control */ + CMD_FW_MACHINE_ID, + CMD_FW_LOAD, + CMD_FW_RAMSIZE, + CMD_FW_QEMU_VERSION +}; + +enum { + FW_M68K, }; +static uint32_t param; + +#define RESULT_ERROR (-1) + +static uint32_t fw_load_m68k(VirtCtrlState *s) +{ + char *elf_filename, *ramfs_filename; + int32_t kernel_size; + uint64_t elf_entry, high; + int32_t ramfs_size; + ram_addr_t ramfs_base; + void *ram_ptr; + + elf_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->fw_elf); + if (elf_filename == NULL) { + error_report("Cannot find %s", s->fw_elf); + return RESULT_ERROR; + } + ramfs_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->fw_ramfs); + if (ramfs_filename == NULL) { + error_report("Cannot find %s", s->fw_ramfs); + return RESULT_ERROR; + } + + kernel_size = load_elf_ram(elf_filename, NULL, NULL, NULL, + &elf_entry, NULL, &high, NULL, 1, + EM_68K, 0, 0, NULL, false); + if (kernel_size < 0) { + error_report("could not load kernel '%s'", elf_filename); + return RESULT_ERROR; + } + + ramfs_size = get_image_size(ramfs_filename); + if (ramfs_size < 0) { + error_report("could not load initial ram disk '%s'", + ramfs_filename); + return RESULT_ERROR; + } + + ram_ptr = memory_region_get_ram_ptr(s->machine->ram); + + ramfs_base = (s->machine->ram_size - ramfs_size) & ~0xfff; + load_image_size(ramfs_filename, ram_ptr + ramfs_base, ramfs_size); + + high = (high + 1) & ~1; + *(uint32_t *)(ram_ptr + high) = cpu_to_be32(elf_entry); + *(uint32_t *)(ram_ptr + high + 4) = cpu_to_be32(ramfs_base); + *(uint32_t *)(ram_ptr + high + 8) = cpu_to_be32(ramfs_size); + + return high; +} + static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size) { VirtCtrlState *s = opaque; @@ -34,7 +104,10 @@ static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size) switch (addr) { case REG_FEATURES: - value = FEAT_POWER_CTRL; + value = FEAT_SUPPORTED; + break; + case REG_PARAM: + value = param; break; default: qemu_log_mask(LOG_UNIMP, @@ -43,7 +116,7 @@ static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size) break; } - trace_virt_ctrl_write(s, addr, size, value); + trace_virt_ctrl_read(s, addr, size, value); return value; } @@ -69,8 +142,32 @@ static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value, case CMD_PANIC: qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC); break; + case CMD_FW_LOAD: + switch (param) { + case FW_M68K: + param = fw_load_m68k(s); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented FW type %d\n", + __func__, param); + break; + } + break; + case CMD_FW_RAMSIZE: + param = s->machine->ram_size; + break; + case CMD_FW_QEMU_VERSION: + param = (QEMU_VERSION_MAJOR << 24) | (QEMU_VERSION_MINOR << 16) | + (QEMU_VERSION_MICRO << 8); + break; + case CMD_FW_MACHINE_ID: + param = 0; + break; } break; + case REG_PARAM: + param = value; + break; default: qemu_log_mask(LOG_UNIMP, "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n", @@ -114,6 +211,14 @@ static const VMStateDescription vmstate_virt_ctrl = { } }; +static Property virt_ctl_properties[] = { + DEFINE_PROP_LINK("machine", VirtCtrlState, machine, + TYPE_MACHINE, MachineState *), + DEFINE_PROP_STRING("fw.elf", VirtCtrlState, fw_elf), + DEFINE_PROP_STRING("fw.ramfs", VirtCtrlState, fw_ramfs), + DEFINE_PROP_END_OF_LIST(), +}; + static void virt_ctrl_instance_init(Object *obj) { SysBusDevice *dev = SYS_BUS_DEVICE(obj); @@ -132,6 +237,8 @@ static void virt_ctrl_class_init(ObjectClass *oc, void *data) dc->reset = virt_ctrl_reset; dc->realize = virt_ctrl_realize; dc->vmsd = &vmstate_virt_ctrl; + + device_class_set_props(dc, virt_ctl_properties); } static const TypeInfo virt_ctrl_info = { diff --git a/.gitmodules b/.gitmodules index 315d597d057a..b45269f896cf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -70,3 +70,6 @@ [submodule "roms/m68k-virt"] path = roms/m68k-virt url = https://github.com/vivier/m68k-virt-bootstrap.git +[submodule "roms/buildroot"] + path = roms/buildroot + url = https://github.com/vivier/buildroot.git diff --git a/pc-bios/meson.build b/pc-bios/meson.build index ffec6decdc4c..c94b63d17d7b 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -82,6 +82,8 @@ blobs = files( 'opensbi-riscv64-generic-fw_dynamic.bin', 'npcm7xx_bootrom.bin', 'm68k-virt.rom', + 'm68k-virt.vmlinux', + 'm68k-virt.petitboot', ) if get_option('install_blobs') diff --git a/roms/Makefile b/roms/Makefile index f9f84e8efb1b..8275083444ef 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -71,6 +71,7 @@ default help: @echo " opensbi64-generic -- update OpenSBI for 64-bit generic machine" @echo " qboot -- update qboot" @echo " m68k-virt-bootrom -- update m68k-virt bootrom" + @echo " m68k-virt-firmware -- update m68k-virt firmware (petitboot)" @echo " clean -- delete the files generated by the previous" \ "build targets" @@ -203,6 +204,12 @@ m68k-virt-bootrom: $(MAKE) -C m68k-virt CROSS_COMPILE=$(m68k_cross_prefix) cp m68k-virt/rom.bin ../pc-bios/m68k-virt.rom +m68k-virt-firmware: + $(MAKE) -C buildroot qemu_m68k_virt_petitboot_defconfig + $(MAKE) -C buildroot -j $$(( $$(getconf _NPROCESSORS_ONLN) * 2 + 1)) + cp buildroot/output/images/vmlinux ../pc-bios/m68k-virt.vmlinux + cp buildroot/output/images/rootfs.cpio.xz ../pc-bios/m68k-virt.petitboot + clean: rm -rf seabios/.config seabios/out seabios/builds $(MAKE) -C sgabios clean @@ -218,3 +225,4 @@ clean: $(MAKE) -C qboot clean $(MAKE) -C vbootrom clean $(MAKE) -C m68k-virt clean + $(MAKE) -C buildroot clean diff --git a/roms/buildroot b/roms/buildroot new file mode 160000 index 000000000000..5590654699e4 --- /dev/null +++ b/roms/buildroot @@ -0,0 +1 @@ +Subproject commit 5590654699e4926bee834ae99f90c8062bc418eb -- 2.34.1