@@ -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)"
@@ -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
@@ -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);
@@ -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 = {
@@ -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
@@ -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')
@@ -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
new file mode 160000
@@ -0,0 +1 @@
+Subproject commit 5590654699e4926bee834ae99f90c8062bc418eb
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 <laurent@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