diff options
Diffstat (limited to 'hw/riscv/virt.c')
| -rw-r--r-- | hw/riscv/virt.c | 129 |
1 files changed, 120 insertions, 9 deletions
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index d36f5625ec..cc8f311e6b 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -26,6 +26,7 @@ #include "hw/boards.h" #include "hw/loader.h" #include "hw/sysbus.h" +#include "hw/qdev-properties.h" #include "hw/char/serial.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" @@ -61,12 +62,77 @@ static const struct MemmapEntry { [VIRT_PLIC] = { 0xc000000, 0x4000000 }, [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, + [VIRT_FLASH] = { 0x20000000, 0x2000000 }, [VIRT_DRAM] = { 0x80000000, 0x0 }, [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, [VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 }, [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, }; +#define VIRT_FLASH_SECTOR_SIZE (256 * KiB) + +static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, + const char *name, + const char *alias_prop_name) +{ + /* + * Create a single flash device. We use the same parameters as + * the flash devices on the ARM virt board. + */ + DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); + + qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); + qdev_prop_set_uint8(dev, "width", 4); + qdev_prop_set_uint8(dev, "device-width", 2); + qdev_prop_set_bit(dev, "big-endian", false); + qdev_prop_set_uint16(dev, "id0", 0x89); + qdev_prop_set_uint16(dev, "id1", 0x18); + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_string(dev, "name", name); + + object_property_add_child(OBJECT(s), name, OBJECT(dev), + &error_abort); + object_property_add_alias(OBJECT(s), alias_prop_name, + OBJECT(dev), "drive", &error_abort); + + return PFLASH_CFI01(dev); +} + +static void virt_flash_create(RISCVVirtState *s) +{ + s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0"); + s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1"); +} + +static void virt_flash_map1(PFlashCFI01 *flash, + hwaddr base, hwaddr size, + MemoryRegion *sysmem) +{ + DeviceState *dev = DEVICE(flash); + + assert(size % VIRT_FLASH_SECTOR_SIZE == 0); + assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); + qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); + qdev_init_nofail(dev); + + memory_region_add_subregion(sysmem, base, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), + 0)); +} + +static void virt_flash_map(RISCVVirtState *s, + MemoryRegion *sysmem) +{ + hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = virt_memmap[VIRT_FLASH].base; + + virt_flash_map1(s->flash[0], flashbase, flashsize, + sysmem); + virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize, + sysmem); +} + static void create_pcie_irq_map(void *fdt, char *nodename, uint32_t plic_phandle) { @@ -121,6 +187,8 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, char *nodename; uint32_t plic_phandle, phandle = 1; int i; + hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = virt_memmap[VIRT_FLASH].base; fdt = s->fdt = create_device_tree(&s->fdt_size); if (!fdt) { @@ -161,8 +229,6 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); char *isa = riscv_isa_string(&s->soc.harts[cpu]); qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", - VIRT_CLOCK_FREQ); qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv"); @@ -316,6 +382,15 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } g_free(nodename); + + nodename = g_strdup_printf("/flash@%" PRIx64, flashbase); + qemu_fdt_add_subnode(s->fdt, nodename); + qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(s->fdt, nodename, "reg", + 2, flashbase, 2, flashsize, + 2, flashbase + flashsize, 2, flashsize); + qemu_fdt_setprop_cell(s->fdt, nodename, "bank-width", 4); + g_free(nodename); } @@ -362,13 +437,13 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, static void riscv_virt_board_init(MachineState *machine) { const struct MemmapEntry *memmap = virt_memmap; - - RISCVVirtState *s = g_new0(RISCVVirtState, 1); + RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); char *plic_hart_config; size_t plic_hart_config_len; + target_ulong start_addr = memmap[VIRT_DRAM].base; int i; unsigned int smp_cpus = machine->smp.cpus; @@ -415,6 +490,14 @@ static void riscv_virt_board_init(MachineState *machine) } } + if (drive_get(IF_PFLASH, 0, 0)) { + /* + * Pflash was supplied, let's overwrite the address we jump to after + * reset to the base of the flash. + */ + start_addr = virt_memmap[VIRT_FLASH].base; + } + /* reset vector */ uint32_t reset_vec[8] = { 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ @@ -427,7 +510,7 @@ static void riscv_virt_board_init(MachineState *machine) #endif 0x00028067, /* jr t0 */ 0x00000000, - memmap[VIRT_DRAM].base, /* start: .dword memmap[VIRT_DRAM].base */ + start_addr, /* start: .dword */ 0x00000000, /* dtb: */ }; @@ -496,15 +579,43 @@ static void riscv_virt_board_init(MachineState *machine) 0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); + virt_flash_create(s); + + for (i = 0; i < ARRAY_SIZE(s->flash); i++) { + /* Map legacy -drive if=pflash to machine properties */ + pflash_cfi01_legacy_drive(s->flash[i], + drive_get(IF_PFLASH, 0, i)); + } + virt_flash_map(s, system_memory); + g_free(plic_hart_config); } -static void riscv_virt_board_machine_init(MachineClass *mc) +static void riscv_virt_machine_instance_init(Object *obj) { - mc->desc = "RISC-V VirtIO Board (Privileged ISA v1.10)"; +} + +static void riscv_virt_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->desc = "RISC-V VirtIO board"; mc->init = riscv_virt_board_init; - mc->max_cpus = 8; /* hardcoded limit in BBL */ + mc->max_cpus = 8; mc->default_cpu_type = VIRT_CPU; } -DEFINE_MACHINE("virt", riscv_virt_board_machine_init) +static const TypeInfo riscv_virt_machine_typeinfo = { + .name = MACHINE_TYPE_NAME("virt"), + .parent = TYPE_MACHINE, + .class_init = riscv_virt_machine_class_init, + .instance_init = riscv_virt_machine_instance_init, + .instance_size = sizeof(RISCVVirtState), +}; + +static void riscv_virt_machine_init_register_types(void) +{ + type_register_static(&riscv_virt_machine_typeinfo); +} + +type_init(riscv_virt_machine_init_register_types) |