Hi Huacai, On 10/30/20 11:25 AM, Huacai Chen wrote: > Add Loongson-3 based machine support, it use liointc as the interrupt > controler and use GPEX as the pci controller. Currently it can work with > both TCG and KVM. > > As the machine model is not based on any exiting physical hardware, the > name of the machine is "loongson3-virt". It may be superseded in future > by a real machine model. If this happens, then a regular deprecation > procedure shall occur for "loongson3-virt" machine. > > We now already have a full functional Linux kernel (based on Linux-5.4.x > LTS, the kvm host side and guest side have both been upstream for Linux- > 5.9, but Linux-5.9 has not been released yet) here: > > https://github.com/chenhuacai/linux > > Of course the upstream kernel is also usable (though it is "unstable" > now): > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git > > How to use QEMU/Loongson-3? > 1, Download kernel source from the above URL; > 2, Build a kernel with arch/mips/configs/loongson3_defconfig; > 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode); > 4, Build QEMU-master with this patchset; > 5, modprobe kvm (only necessary for KVM mode); > 6, Use QEMU with TCG: > qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 > -kernel <path_to_kernel> -append ... > Use QEMU with KVM: > qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 > -kernel <path_to_kernel> -append ... > > The "-cpu" parameter is optional here and QEMU will use the correct type > for TCG/KVM automatically. > > Signed-off-by: Huacai Chen <che...@lemote.com> > Co-developed-by: Jiaxun Yang <jiaxun.y...@flygoat.com> > Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> > --- > default-configs/devices/mips64el-softmmu.mak | 1 + > hw/mips/Kconfig | 12 + > hw/mips/loongson3_virt.c | 620 > +++++++++++++++++++++++++++ > hw/mips/meson.build | 2 +- > 4 files changed, 634 insertions(+), 1 deletion(-) > create mode 100644 hw/mips/loongson3_virt.c ... > +static inline void loongson3_virt_devices_init(MachineState *machine, > DeviceState *pic) > +{ > + int i; > + qemu_irq irq; > + PCIBus *pci_bus; > + DeviceState *dev; > + MemoryRegion *pio_alias; > + MemoryRegion *mmio_alias, *mmio_reg; > + MemoryRegion *ecam_alias, *ecam_reg; > + > + dev = qdev_new(TYPE_GPEX_HOST); > + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); > + pci_bus = PCI_HOST_BRIDGE(dev)->bus; > + > + ecam_alias = g_new0(MemoryRegion, 1); > + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); > + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", > + ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size); > + memory_region_add_subregion(get_system_memory(), > + virt_memmap[VIRT_PCIE_ECAM].base, > ecam_alias); > + > + mmio_alias = g_new0(MemoryRegion, 1); > + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); > + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", > + mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base, > + virt_memmap[VIRT_PCIE_MMIO].size); > + memory_region_add_subregion(get_system_memory(), > + virt_memmap[VIRT_PCIE_MMIO].base, > mmio_alias); > + > + pio_alias = g_new0(MemoryRegion, 1); > + memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio", > + get_system_io(), 0, > virt_memmap[VIRT_PCIE_PIO].size); > + memory_region_add_subregion(get_system_memory(), > + virt_memmap[VIRT_PCIE_PIO].base, pio_alias); > + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base); > + > + for (i = 0; i < GPEX_NUM_IRQS; i++) { > + irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i); > + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); > + gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i); > + } > + > + pci_vga_init(pci_bus); > + > + if (defaults_enabled()) { > + pci_create_simple(pci_bus, -1, "pci-ohci"); > + usb_create_simple(usb_bus_find(-1), "usb-kbd"); > + usb_create_simple(usb_bus_find(-1), "usb-tablet"); > + } > + > + for (i = 0; i < nb_nics; i++) { > + NICInfo *nd = &nd_table[i]; > + > + if (!nd->model) { > + nd->model = g_strdup("virtio"); > + } > + > + pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); > + } > +} > + > +static void mips_loongson3_virt_init(MachineState *machine) > +{ > + int i; > + long bios_size; > + MIPSCPU *cpu; > + Clock *cpuclk; > + CPUMIPSState *env; > + DeviceState *liointc; > + char *filename; > + const char *kernel_cmdline = machine->kernel_cmdline; > + const char *kernel_filename = machine->kernel_filename; > + const char *initrd_filename = machine->initrd_filename; > + ram_addr_t ram_size = machine->ram_size; > + MemoryRegion *address_space_mem = get_system_memory(); > + MemoryRegion *ram = g_new(MemoryRegion, 1); > + MemoryRegion *bios = g_new(MemoryRegion, 1); > + MemoryRegion *iomem = g_new(MemoryRegion, 1); > + > + /* TODO: TCG will support all CPU types */ > + if (!kvm_enabled()) { > + if (!machine->cpu_type) { > + machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000"); > + } > + if (!strstr(machine->cpu_type, "Loongson-3A1000")) { > + error_report("Loongson-3/TCG needs cpu type Loongson-3A1000"); > + exit(1); > + } > + } else { > + if (!machine->cpu_type) { > + machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000"); > + } > + if (!strstr(machine->cpu_type, "Loongson-3A4000")) { > + error_report("Loongson-3/KVM needs cpu type Loongson-3A4000"); > + exit(1); > + } > + } > + > + if (ram_size < 512 * MiB) { > + error_report("Loongson-3 machine needs at least 512MB memory"); > + exit(1); > + } > + > + /* > + * The whole MMIO range among configure registers doesn't generate > + * exception when accessing invalid memory. Create some unimplememted > + * devices to emulate this feature. > + */ > + create_unimplemented_device("mmio fallback 0", 0x10000000, 256 * MiB); > + create_unimplemented_device("mmio fallback 1", 0x30000000, 256 * MiB); > + > + liointc = qdev_new("loongson.liointc");
Please use TYPE_name when creating QOM (here TYPE_LOONGSON_LIOINTC). Similarly loongson3_virt_devices_init(). (no need to respin yet). > + sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal); > + > + sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, > virt_memmap[VIRT_LIOINTC].base); > + > + serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0, > + qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0), > + DEVICE_NATIVE_ENDIAN); > + > + sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base, > + qdev_get_gpio_in(liointc, RTC_IRQ)); > + > + cpuclk = clock_new(OBJECT(machine), "cpu-refclk"); > + clock_set_hz(cpuclk, DEF_LOONGSON3_FREQ); > + > + for (i = 0; i < machine->smp.cpus; i++) { > + int ip; > + > + /* init CPUs */ > + cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk); > + > + /* Init internal devices */ > + cpu_mips_irq_init_cpu(cpu); > + cpu_mips_clock_init(cpu); > + qemu_register_reset(main_cpu_reset, cpu); > + > + if (i >= 4) { > + continue; /* Only node-0 can be connected to LIOINTC */ > + } > + > + for (ip = 0; ip < 4 ; ip++) { > + int pin = i * 4 + ip; > + sysbus_connect_irq(SYS_BUS_DEVICE(liointc), > + pin, cpu->env.irq[ip + 2]); > + } > + } > + env = &MIPS_CPU(first_cpu)->env; ...