From nobody Sat May 18 18:02:03 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=eik.bme.hu Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1624812189907451.5607571306973; Sun, 27 Jun 2021 09:43:09 -0700 (PDT) Received: from localhost ([::1]:40714 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxXsC-00017Q-T2 for importer@patchew.org; Sun, 27 Jun 2021 12:43:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35946) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoa-0002Km-4Y; Sun, 27 Jun 2021 12:39:24 -0400 Received: from zero.eik.bme.hu ([152.66.115.2]:54240) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoM-0007mv-Jt; Sun, 27 Jun 2021 12:39:23 -0400 Received: from zero.eik.bme.hu (blah.eik.bme.hu [152.66.115.182]) by localhost (Postfix) with SMTP id BECEB746344; Sun, 27 Jun 2021 18:39:07 +0200 (CEST) Received: by zero.eik.bme.hu (Postfix, from userid 432) id 494097457F0; Sun, 27 Jun 2021 18:39:07 +0200 (CEST) Message-Id: <7f6d5fbf4f70c64dba001483174a2921dd616ecd.1624811233.git.balaton@eik.bme.hu> In-Reply-To: References: From: BALATON Zoltan Subject: [PATCH 1/4] ppc/pegasos2: Introduce Pegasos2MachineState structure Date: Sun, 27 Jun 2021 18:27:13 +0200 MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org X-Spam-Probability: 8% Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=152.66.115.2; envelope-from=balaton@eik.bme.hu; helo=zero.eik.bme.hu X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Alexey Kardashevskiy , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Add own machine state structure which will be used to store state needed for firmware emulation. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/ppc/pegasos2.c | 50 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 0bfd0928aa..07971175c9 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -1,7 +1,7 @@ /* * QEMU PowerPC CHRP (Genesi/bPlan Pegasos II) hardware System Emulator * - * Copyright (c) 2018-2020 BALATON Zoltan + * Copyright (c) 2018-2021 BALATON Zoltan * * This work is licensed under the GNU GPL license version 2 or later. * @@ -41,6 +41,15 @@ =20 #define BUS_FREQ_HZ 133333333 =20 +#define TYPE_PEGASOS2_MACHINE MACHINE_TYPE_NAME("pegasos2") +OBJECT_DECLARE_TYPE(Pegasos2MachineState, MachineClass, PEGASOS2_MACHINE) + +struct Pegasos2MachineState { + MachineState parent_obj; + PowerPCCPU *cpu; + DeviceState *mv; +}; + static void pegasos2_cpu_reset(void *opaque) { PowerPCCPU *cpu =3D opaque; @@ -51,9 +60,9 @@ static void pegasos2_cpu_reset(void *opaque) =20 static void pegasos2_init(MachineState *machine) { - PowerPCCPU *cpu =3D NULL; + Pegasos2MachineState *pm =3D PEGASOS2_MACHINE(machine); + CPUPPCState *env; MemoryRegion *rom =3D g_new(MemoryRegion, 1); - DeviceState *mv; PCIBus *pci_bus; PCIDevice *dev; I2CBus *i2c_bus; @@ -63,15 +72,16 @@ static void pegasos2_init(MachineState *machine) uint8_t *spd_data; =20 /* init CPU */ - cpu =3D POWERPC_CPU(cpu_create(machine->cpu_type)); - if (PPC_INPUT(&cpu->env) !=3D PPC_FLAGS_INPUT_6xx) { + pm->cpu =3D POWERPC_CPU(cpu_create(machine->cpu_type)); + env =3D &pm->cpu->env; + if (PPC_INPUT(env) !=3D PPC_FLAGS_INPUT_6xx) { error_report("Incompatible CPU, only 6xx bus supported"); exit(1); } =20 /* Set time-base frequency */ - cpu_ppc_tb_init(&cpu->env, BUS_FREQ_HZ / 4); - qemu_register_reset(pegasos2_cpu_reset, cpu); + cpu_ppc_tb_init(env, BUS_FREQ_HZ / 4); + qemu_register_reset(pegasos2_cpu_reset, pm->cpu); =20 /* RAM */ memory_region_add_subregion(get_system_memory(), 0, machine->ram); @@ -96,16 +106,16 @@ static void pegasos2_init(MachineState *machine) g_free(filename); =20 /* Marvell Discovery II system controller */ - mv =3D DEVICE(sysbus_create_simple(TYPE_MV64361, -1, - ((qemu_irq *)cpu->env.irq_inputs)[PPC6xx_INPUT_INT= ])); - pci_bus =3D mv64361_get_pci_bus(mv, 1); + pm->mv =3D DEVICE(sysbus_create_simple(TYPE_MV64361, -1, + ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_IN= T])); + pci_bus =3D mv64361_get_pci_bus(pm->mv, 1); =20 /* VIA VT8231 South Bridge (multifunction PCI device) */ /* VT8231 function 0: PCI-to-ISA Bridge */ dev =3D pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), tru= e, TYPE_VT8231_ISA); qdev_connect_gpio_out(DEVICE(dev), 0, - qdev_get_gpio_in_named(mv, "gpp", 31)); + qdev_get_gpio_in_named(pm->mv, "gpp", 31)); =20 /* VT8231 function 1: IDE Controller */ dev =3D pci_create_simple(pci_bus, PCI_DEVFN(12, 1), "via-ide"); @@ -129,8 +139,10 @@ static void pegasos2_init(MachineState *machine) pci_vga_init(pci_bus); } =20 -static void pegasos2_machine(MachineClass *mc) +static void pegasos2_machine_class_init(ObjectClass *oc, void *data) { + MachineClass *mc =3D MACHINE_CLASS(oc); + mc->desc =3D "Genesi/bPlan Pegasos II"; mc->init =3D pegasos2_init; mc->block_default_type =3D IF_IDE; @@ -141,4 +153,16 @@ static void pegasos2_machine(MachineClass *mc) mc->default_ram_size =3D 512 * MiB; } =20 -DEFINE_MACHINE("pegasos2", pegasos2_machine) +static const TypeInfo pegasos2_machine_info =3D { + .name =3D TYPE_PEGASOS2_MACHINE, + .parent =3D TYPE_MACHINE, + .class_init =3D pegasos2_machine_class_init, + .instance_size =3D sizeof(Pegasos2MachineState), +}; + +static void pegasos2_machine_register_types(void) +{ + type_register_static(&pegasos2_machine_info); +} + +type_init(pegasos2_machine_register_types) --=20 2.21.4 From nobody Sat May 18 18:02:03 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=eik.bme.hu Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1624812048245434.4785102695133; Sun, 27 Jun 2021 09:40:48 -0700 (PDT) Received: from localhost ([::1]:33952 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxXpv-00050E-6J for importer@patchew.org; Sun, 27 Jun 2021 12:40:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35932) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoZ-0002Hv-1C; Sun, 27 Jun 2021 12:39:23 -0400 Received: from zero.eik.bme.hu ([152.66.115.2]:54249) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoS-0007pE-8p; Sun, 27 Jun 2021 12:39:22 -0400 Received: from zero.eik.bme.hu (blah.eik.bme.hu [152.66.115.182]) by localhost (Postfix) with SMTP id 16FBA7456E3; Sun, 27 Jun 2021 18:39:14 +0200 (CEST) Received: by zero.eik.bme.hu (Postfix, from userid 432) id 4EE0574634B; Sun, 27 Jun 2021 18:39:07 +0200 (CEST) Message-Id: <21c7745aabbb68fcc50bb2ffaf16b939ba21261c.1624811233.git.balaton@eik.bme.hu> In-Reply-To: References: From: BALATON Zoltan Subject: [PATCH 2/4] target/ppc: Allow virtual hypervisor on CPU without HV Date: Sun, 27 Jun 2021 18:27:13 +0200 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org X-Spam-Probability: 8% Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=152.66.115.2; envelope-from=balaton@eik.bme.hu; helo=zero.eik.bme.hu X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Alexey Kardashevskiy , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Change the assert in ppc_store_sdr1() to allow vhyp to be set on CPUs without HV bit. This allows using the vhyp interface for firmware emulation on pegasos2. Signed-off-by: BALATON Zoltan --- target/ppc/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index 19d67b5b07..a29299882a 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -72,7 +72,7 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value) { PowerPCCPU *cpu =3D env_archcpu(env); qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value); - assert(!cpu->vhyp); + assert(!cpu->env.has_hv_mode || !cpu->vhyp); #if defined(TARGET_PPC64) if (mmu_is_64bit(env->mmu_model)) { target_ulong sdr_mask =3D SDR_64_HTABORG | SDR_64_HTABSIZE; --=20 2.21.4 From nobody Sat May 18 18:02:03 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=eik.bme.hu Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1624812051643809.3135407141094; Sun, 27 Jun 2021 09:40:51 -0700 (PDT) Received: from localhost ([::1]:34142 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxXpy-00057w-Ed for importer@patchew.org; Sun, 27 Jun 2021 12:40:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35918) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoY-0002Gc-D1; Sun, 27 Jun 2021 12:39:22 -0400 Received: from zero.eik.bme.hu ([152.66.115.2]:54246) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoS-0007pC-8U; Sun, 27 Jun 2021 12:39:22 -0400 Received: from zero.eik.bme.hu (blah.eik.bme.hu [152.66.115.182]) by localhost (Postfix) with SMTP id 107847456B4; Sun, 27 Jun 2021 18:39:14 +0200 (CEST) Received: by zero.eik.bme.hu (Postfix, from userid 432) id 531357457EE; Sun, 27 Jun 2021 18:39:07 +0200 (CEST) Message-Id: <1d6ed6f290c5c1f0b5a1e1c51cf1151452d70d9a.1624811233.git.balaton@eik.bme.hu> In-Reply-To: References: From: BALATON Zoltan Subject: [PATCH 3/4] ppc/pegasos2: Use Virtual Open Firmware as firmware replacement Date: Sun, 27 Jun 2021 18:27:13 +0200 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org X-Spam-Probability: 10% Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=152.66.115.2; envelope-from=balaton@eik.bme.hu; helo=zero.eik.bme.hu X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Alexey Kardashevskiy , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" The pegasos2 board comes with an Open Firmware compliant ROM based on SmartFirmware but it has some changes that are not open source therefore the ROM binary cannot be included in QEMU. Guests running on the board however depend on services provided by the firmware. The Virtual Open Firmware recently added to QEMU implements a minimal set of these services to allow some guests to boot without the original firmware. This patch adds VOF as the default firmware for pegasos2 which allows booting Linux and MorphOS via -kernel option while a ROM image can still be used with -bios for guests that don't run with VOF. Signed-off-by: BALATON Zoltan --- hw/ppc/Kconfig | 1 + hw/ppc/pegasos2.c | 602 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 601 insertions(+), 2 deletions(-) diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 67630f80e1..7fcafec60a 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -76,6 +76,7 @@ config PEGASOS2 select VT82C686 select IDE_VIA select SMBUS_EEPROM + select VOF # This should come with VT82C686 select ACPI_X86 =20 diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 07971175c9..f1741a4512 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -34,13 +34,33 @@ #include "trace.h" #include "qemu/datadir.h" #include "sysemu/device_tree.h" +#include "hw/ppc/vof.h" =20 -#define PROM_FILENAME "pegasos2.rom" +#include + +#define PROM_FILENAME "vof.bin" #define PROM_ADDR 0xfff00000 #define PROM_SIZE 0x80000 =20 +#define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_VOF_CLIENT (KVMPPC_HCALL_BASE + 0x5) + +#define H_SUCCESS 0 +#define H_PRIVILEGE -3 /* Caller not privileged */ +#define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting= */ + #define BUS_FREQ_HZ 133333333 =20 +#define PCI0_MEM_BASE 0xc0000000 +#define PCI0_MEM_SIZE 0x20000000 +#define PCI0_IO_BASE 0xf8000000 +#define PCI0_IO_SIZE 0x10000 + +#define PCI1_MEM_BASE 0x80000000 +#define PCI1_MEM_SIZE 0x40000000 +#define PCI1_IO_BASE 0xfe000000 +#define PCI1_IO_SIZE 0x10000 + #define TYPE_PEGASOS2_MACHINE MACHINE_TYPE_NAME("pegasos2") OBJECT_DECLARE_TYPE(Pegasos2MachineState, MachineClass, PEGASOS2_MACHINE) =20 @@ -48,14 +68,26 @@ struct Pegasos2MachineState { MachineState parent_obj; PowerPCCPU *cpu; DeviceState *mv; + Vof *vof; + void *fdt_blob; + uint64_t kernel_addr; + uint64_t kernel_entry; + uint64_t kernel_size; }; =20 +static void *build_fdt(MachineState *machine, int *fdt_size); + static void pegasos2_cpu_reset(void *opaque) { PowerPCCPU *cpu =3D opaque; + Pegasos2MachineState *pm =3D PEGASOS2_MACHINE(current_machine); =20 cpu_reset(CPU(cpu)); cpu->env.spr[SPR_HID1] =3D 7ULL << 28; + if (pm->vof) { + cpu->env.gpr[1] =3D 2 * VOF_STACK_SIZE - 0x20; + cpu->env.nip =3D 0x100; + } } =20 static void pegasos2_init(MachineState *machine) @@ -92,18 +124,24 @@ static void pegasos2_init(MachineState *machine) error_report("Could not find firmware '%s'", fwname); exit(1); } + if (!machine->firmware && !pm->vof) { + pm->vof =3D g_malloc0(sizeof(*pm->vof)); + } memory_region_init_rom(rom, NULL, "pegasos2.rom", PROM_SIZE, &error_fa= tal); memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom); sz =3D load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0); if (sz <=3D 0) { - sz =3D load_image_targphys(filename, PROM_ADDR, PROM_SIZE); + sz =3D load_image_targphys(filename, pm->vof ? 0 : PROM_ADDR, PROM= _SIZE); } if (sz <=3D 0 || sz > PROM_SIZE) { error_report("Could not load firmware '%s'", filename); exit(1); } g_free(filename); + if (pm->vof) { + pm->vof->fw_size =3D sz; + } =20 /* Marvell Discovery II system controller */ pm->mv =3D DEVICE(sysbus_create_simple(TYPE_MV64361, -1, @@ -137,20 +175,185 @@ static void pegasos2_init(MachineState *machine) =20 /* other PC hardware */ pci_vga_init(pci_bus); + + if (machine->kernel_filename) { + sz =3D load_elf(machine->kernel_filename, NULL, NULL, NULL, + &pm->kernel_entry, &pm->kernel_addr, NULL, NULL, 1, + PPC_ELF_MACHINE, 0, 0); + if (sz <=3D 0) { + error_report("Could not load kernel '%s'", + machine->kernel_filename); + exit(1); + } + pm->kernel_size =3D sz; + if (!pm->vof) { + warn_report("Option -kernel may be ineffective with -bios."); + } + } + if (machine->kernel_cmdline && !pm->vof) { + warn_report("Option -append may be ineffective with -bios."); + } +} + +static void pegasos2_pci_config_write(AddressSpace *as, int bus, uint32_t = addr, + uint32_t len, uint32_t val) +{ + hwaddr pcicfg =3D (bus ? 0xf1000c78 : 0xf1000cf8); + + stl_le_phys(as, pcicfg, addr | BIT(31)); + switch (len) { + case 4: + stl_le_phys(as, pcicfg + 4, val); + break; + case 2: + stw_le_phys(as, pcicfg + 4, val); + break; + case 1: + stb_phys(as, pcicfg + 4, val); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid length\n", __func__); + break; + } +} + +static void pegasos2_machine_reset(MachineState *machine) +{ + Pegasos2MachineState *pm =3D PEGASOS2_MACHINE(machine); + AddressSpace *as =3D CPU(pm->cpu)->as; + void *fdt; + uint64_t d[2]; + int sz; + + qemu_devices_reset(); + if (!pm->vof) { + return; /* Firmware should set up machine so nothing to do */ + } + + /* Otherwise, set up devices that board firmware would normally do */ + stl_le_phys(as, 0xf1000000, 0x28020ff); + stl_le_phys(as, 0xf1000278, 0xa31fc); + stl_le_phys(as, 0xf100f300, 0x11ff0400); + stl_le_phys(as, 0xf100f10c, 0x80000000); + stl_le_phys(as, 0xf100001c, 0x8000000); + pegasos2_pci_config_write(as, 0, PCI_COMMAND, 2, PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pegasos2_pci_config_write(as, 1, PCI_COMMAND, 2, PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 0) << 8) | + PCI_INTERRUPT_LINE, 2, 0x9); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 0) << 8) | + 0x50, 1, 0x2); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) | + PCI_INTERRUPT_LINE, 2, 0x109); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) | + PCI_CLASS_PROG, 1, 0xf); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) | + 0x40, 1, 0xb); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) | + 0x50, 4, 0x17171717); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) | + PCI_COMMAND, 2, 0x87); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 2) << 8) | + PCI_INTERRUPT_LINE, 2, 0x409); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 3) << 8) | + PCI_INTERRUPT_LINE, 2, 0x409); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) | + PCI_INTERRUPT_LINE, 2, 0x9); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) | + 0x48, 4, 0xf00); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) | + 0x40, 4, 0x558020); + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) | + 0x90, 4, 0xd00); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 5) << 8) | + PCI_INTERRUPT_LINE, 2, 0x309); + + pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 6) << 8) | + PCI_INTERRUPT_LINE, 2, 0x309); + + /* Device tree and VOF set up */ + vof_init(pm->vof, machine->ram_size, &error_fatal); + if (vof_claim(pm->vof, 0, VOF_STACK_SIZE, VOF_STACK_SIZE) =3D=3D -1) { + error_report("Memory allocation for stack failed"); + exit(1); + } + if (pm->kernel_size && + vof_claim(pm->vof, pm->kernel_addr, pm->kernel_size, 0) =3D=3D -1)= { + error_report("Memory for kernel is in use"); + exit(1); + } + fdt =3D build_fdt(machine, &sz); + /* FIXME: VOF assumes entry is same as load address */ + d[0] =3D cpu_to_be64(pm->kernel_entry); + d[1] =3D cpu_to_be64(pm->kernel_size - (pm->kernel_entry - pm->kernel_= addr)); + qemu_fdt_setprop(fdt, "/chosen", "qemu,boot-kernel", d, sizeof(d)); + + qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); + g_free(pm->fdt_blob); + pm->fdt_blob =3D fdt; + + vof_build_dt(fdt, pm->vof); + vof_client_open_store(fdt, pm->vof, "/chosen", "stdout", "/failsafe"); + pm->cpu->vhyp =3D PPC_VIRTUAL_HYPERVISOR(machine); +} + +static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +{ + Pegasos2MachineState *pm =3D PEGASOS2_MACHINE(vhyp); + CPUPPCState *env =3D &cpu->env; + + /* The TCG path should also be holding the BQL at this point */ + g_assert(qemu_mutex_iothread_locked()); + + if (msr_pr) { + qemu_log_mask(LOG_GUEST_ERROR, "Hypercall made with MSR[PR]=3D1\n"= ); + env->gpr[3] =3D H_PRIVILEGE; + } else if (env->gpr[3] =3D=3D KVMPPC_H_VOF_CLIENT) { + int ret =3D vof_client_call(MACHINE(pm), pm->vof, pm->fdt_blob, + env->gpr[4]); + env->gpr[3] =3D (ret ? H_PARAMETER : H_SUCCESS); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "Unsupported hypercall " TARGET_FMT= _lx + "\n", env->gpr[3]); + env->gpr[3] =3D -1; + } +} + +static void vhyp_nop(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +{ +} + +static target_ulong vhyp_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp) +{ + return POWERPC_CPU(current_cpu)->env.spr[SPR_SDR1]; } =20 static void pegasos2_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc =3D MACHINE_CLASS(oc); + PPCVirtualHypervisorClass *vhc =3D PPC_VIRTUAL_HYPERVISOR_CLASS(oc); =20 mc->desc =3D "Genesi/bPlan Pegasos II"; mc->init =3D pegasos2_init; + mc->reset =3D pegasos2_machine_reset; mc->block_default_type =3D IF_IDE; mc->default_boot_order =3D "cd"; mc->default_display =3D "std"; mc->default_cpu_type =3D POWERPC_CPU_TYPE_NAME("7400_v2.9"); mc->default_ram_id =3D "pegasos2.ram"; mc->default_ram_size =3D 512 * MiB; + + vhc->hypercall =3D pegasos2_hypercall; + vhc->cpu_exec_enter =3D vhyp_nop; + vhc->cpu_exec_exit =3D vhyp_nop; + vhc->encode_hpt_for_kvm_pr =3D vhyp_encode_hpt_for_kvm_pr; } =20 static const TypeInfo pegasos2_machine_info =3D { @@ -158,6 +361,10 @@ static const TypeInfo pegasos2_machine_info =3D { .parent =3D TYPE_MACHINE, .class_init =3D pegasos2_machine_class_init, .instance_size =3D sizeof(Pegasos2MachineState), + .interfaces =3D (InterfaceInfo[]) { + { TYPE_PPC_VIRTUAL_HYPERVISOR }, + { } + }, }; =20 static void pegasos2_machine_register_types(void) @@ -166,3 +373,394 @@ static void pegasos2_machine_register_types(void) } =20 type_init(pegasos2_machine_register_types) + +/* FDT creation for passing to firmware */ + +typedef struct { + void *fdt; + const char *path; +} FDTInfo; + +/* We do everything in reverse order so it comes out right in the tree */ + +static void dt_ide(PCIBus *bus, PCIDevice *d, FDTInfo *fi) +{ + qemu_fdt_setprop_string(fi->fdt, fi->path, "device_type", "spi"); +} + +static void dt_usb(PCIBus *bus, PCIDevice *d, FDTInfo *fi) +{ + qemu_fdt_setprop_cell(fi->fdt, fi->path, "#size-cells", 0); + qemu_fdt_setprop_cell(fi->fdt, fi->path, "#address-cells", 1); + qemu_fdt_setprop_string(fi->fdt, fi->path, "device_type", "usb"); +} + +static void dt_isa(PCIBus *bus, PCIDevice *d, FDTInfo *fi) +{ + GString *name =3D g_string_sized_new(64); + uint32_t cells[3]; + + qemu_fdt_setprop_cell(fi->fdt, fi->path, "#size-cells", 1); + qemu_fdt_setprop_cell(fi->fdt, fi->path, "#address-cells", 2); + qemu_fdt_setprop_string(fi->fdt, fi->path, "device_type", "isa"); + qemu_fdt_setprop_string(fi->fdt, fi->path, "name", "isa"); + + /* addional devices */ + g_string_printf(name, "%s/lpt@i3bc", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); + cells[0] =3D cpu_to_be32(7); + cells[1] =3D 0; + qemu_fdt_setprop(fi->fdt, name->str, "interrupts", + cells, 2 * sizeof(cells[0])); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x3bc); + cells[2] =3D cpu_to_be32(8); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", "lpt"); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "lpt"); + + g_string_printf(name, "%s/fdc@i3f0", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); + cells[0] =3D cpu_to_be32(6); + cells[1] =3D 0; + qemu_fdt_setprop(fi->fdt, name->str, "interrupts", + cells, 2 * sizeof(cells[0])); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x3f0); + cells[2] =3D cpu_to_be32(8); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", "fdc"); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "fdc"); + + g_string_printf(name, "%s/timer@i40", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x40); + cells[2] =3D cpu_to_be32(8); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", "timer"); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "timer"); + + g_string_printf(name, "%s/rtc@i70", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + qemu_fdt_setprop_string(fi->fdt, name->str, "compatible", "ds1385-rtc"= ); + qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); + cells[0] =3D cpu_to_be32(8); + cells[1] =3D 0; + qemu_fdt_setprop(fi->fdt, name->str, "interrupts", + cells, 2 * sizeof(cells[0])); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x70); + cells[2] =3D cpu_to_be32(2); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", "rtc"); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "rtc"); + + g_string_printf(name, "%s/keyboard@i60", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D 0; + qemu_fdt_setprop(fi->fdt, name->str, "interrupts", + cells, 2 * sizeof(cells[0])); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x60); + cells[2] =3D cpu_to_be32(5); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", "keyboard"); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "keyboard"); + + g_string_printf(name, "%s/8042@i60", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + qemu_fdt_setprop_cell(fi->fdt, name->str, "#interrupt-cells", 2); + qemu_fdt_setprop_cell(fi->fdt, name->str, "#size-cells", 0); + qemu_fdt_setprop_cell(fi->fdt, name->str, "#address-cells", 1); + qemu_fdt_setprop_string(fi->fdt, name->str, "interrupt-controller", ""= ); + qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x60); + cells[2] =3D cpu_to_be32(5); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", ""); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "8042"); + + g_string_printf(name, "%s/serial@i2f8", fi->path); + qemu_fdt_add_subnode(fi->fdt, name->str); + qemu_fdt_setprop_cell(fi->fdt, name->str, "clock-frequency", 0); + cells[0] =3D cpu_to_be32(3); + cells[1] =3D 0; + qemu_fdt_setprop(fi->fdt, name->str, "interrupts", + cells, 2 * sizeof(cells[0])); + cells[0] =3D cpu_to_be32(1); + cells[1] =3D cpu_to_be32(0x2f8); + cells[2] =3D cpu_to_be32(8); + qemu_fdt_setprop(fi->fdt, name->str, "reg", cells, 3 * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, name->str, "device_type", "serial"); + qemu_fdt_setprop_string(fi->fdt, name->str, "name", "serial"); + + g_string_free(name, TRUE); +} + +static struct { + const char *id; + const char *name; + void (*dtf)(PCIBus *bus, PCIDevice *d, FDTInfo *fi); +} device_map[] =3D { + { "pci11ab,6460", "host", NULL }, + { "pci1106,8231", "isa", dt_isa }, + { "pci1106,571", "ide", dt_ide }, + { "pci1106,3044", "firewire", NULL }, + { "pci1106,3038", "usb", dt_usb }, + { "pci1106,8235", "other", NULL }, + { "pci1106,3058", "sound", NULL }, + { NULL, NULL } +}; + +static void add_pci_device(PCIBus *bus, PCIDevice *d, void *opaque) +{ + FDTInfo *fi =3D opaque; + GString *node =3D g_string_new(NULL); + uint32_t cells[(PCI_NUM_REGIONS + 1) * 5]; + int i, j; + const char *name =3D NULL; + g_autofree const gchar *pn =3D g_strdup_printf("pci%x,%x", + pci_get_word(&d->config[PCI_VENDOR_ID= ]), + pci_get_word(&d->config[PCI_DEVICE_ID= ])); + + for (i =3D 0; device_map[i].id; i++) { + if (!strcmp(pn, device_map[i].id)) { + name =3D device_map[i].name; + break; + } + } + g_string_printf(node, "%s/%s@%x", fi->path, (name ?: pn), + PCI_SLOT(d->devfn)); + if (PCI_FUNC(d->devfn)) { + g_string_append_printf(node, ",%x", PCI_FUNC(d->devfn)); + } + + qemu_fdt_add_subnode(fi->fdt, node->str); + if (device_map[i].dtf) { + FDTInfo cfi =3D { fi->fdt, node->str }; + device_map[i].dtf(bus, d, &cfi); + } + cells[0] =3D cpu_to_be32(d->devfn << 8); + cells[1] =3D 0; + cells[2] =3D 0; + cells[3] =3D 0; + cells[4] =3D 0; + j =3D 5; + for (i =3D 0; i < PCI_NUM_REGIONS; i++) { + if (!d->io_regions[i].size) { + continue; + } + cells[j] =3D cpu_to_be32(d->devfn << 8 | (PCI_BASE_ADDRESS_0 + i *= 4)); + if (d->io_regions[i].type & PCI_BASE_ADDRESS_SPACE_IO) { + cells[j] |=3D cpu_to_be32(1 << 24); + } else { + cells[j] |=3D cpu_to_be32(2 << 24); + if (d->io_regions[i].type & PCI_BASE_ADDRESS_MEM_PREFETCH) { + cells[j] |=3D cpu_to_be32(4 << 28); + } + } + cells[j + 1] =3D 0; + cells[j + 2] =3D 0; + cells[j + 3] =3D cpu_to_be32(d->io_regions[i].size >> 32); + cells[j + 4] =3D cpu_to_be32(d->io_regions[i].size); + j +=3D 5; + } + qemu_fdt_setprop(fi->fdt, node->str, "reg", cells, j * sizeof(cells[0]= )); + qemu_fdt_setprop_string(fi->fdt, node->str, "name", name ?: pn); + if (pci_get_byte(&d->config[PCI_INTERRUPT_PIN])) { + qemu_fdt_setprop_cell(fi->fdt, node->str, "interrupts", + pci_get_byte(&d->config[PCI_INTERRUPT_PIN])); + } + /* Pegasos2 firmware has subsystem-id amd subsystem-vendor-id swapped = */ + qemu_fdt_setprop_cell(fi->fdt, node->str, "subsystem-vendor-id", + pci_get_word(&d->config[PCI_SUBSYSTEM_ID])); + qemu_fdt_setprop_cell(fi->fdt, node->str, "subsystem-id", + pci_get_word(&d->config[PCI_SUBSYSTEM_VENDOR_ID]= )); + cells[0] =3D pci_get_long(&d->config[PCI_CLASS_REVISION]); + qemu_fdt_setprop_cell(fi->fdt, node->str, "class-code", cells[0] >> 8); + qemu_fdt_setprop_cell(fi->fdt, node->str, "revision-id", cells[0] && 0= xff); + qemu_fdt_setprop_cell(fi->fdt, node->str, "device-id", + pci_get_word(&d->config[PCI_DEVICE_ID])); + qemu_fdt_setprop_cell(fi->fdt, node->str, "vendor-id", + pci_get_word(&d->config[PCI_VENDOR_ID])); + + g_string_free(node, TRUE); +} + +static void *build_fdt(MachineState *machine, int *fdt_size) +{ + Pegasos2MachineState *pm =3D PEGASOS2_MACHINE(machine); + PowerPCCPU *cpu =3D pm->cpu; + PCIBus *pci_bus; + FDTInfo fi; + uint32_t cells[16]; + void *fdt =3D create_device_tree(fdt_size); + + fi.fdt =3D fdt; + + /* root node */ + qemu_fdt_setprop_string(fdt, "/", "CODEGEN,description", + "Pegasos CHRP PowerPC System"); + qemu_fdt_setprop_string(fdt, "/", "CODEGEN,board", "Pegasos2"); + qemu_fdt_setprop_string(fdt, "/", "CODEGEN,vendor", "bplan GmbH"); + qemu_fdt_setprop_string(fdt, "/", "revision", "2B"); + qemu_fdt_setprop_string(fdt, "/", "model", "Pegasos2"); + qemu_fdt_setprop_string(fdt, "/", "device_type", "chrp"); + qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 1); + qemu_fdt_setprop_string(fdt, "/", "name", "bplan,Pegasos2"); + + /* pci@c0000000 */ + qemu_fdt_add_subnode(fdt, "/pci@c0000000"); + cells[0] =3D 0; + cells[1] =3D 0; + qemu_fdt_setprop(fdt, "/pci@c0000000", "bus-range", + cells, 2 * sizeof(cells[0])); + qemu_fdt_setprop_cell(fdt, "/pci@c0000000", "pci-bridge-number", 1); + cells[0] =3D cpu_to_be32(PCI0_MEM_BASE); + cells[1] =3D cpu_to_be32(PCI0_MEM_SIZE); + qemu_fdt_setprop(fdt, "/pci@c0000000", "reg", cells, 2 * sizeof(cells[= 0])); + cells[0] =3D cpu_to_be32(0x01000000); + cells[1] =3D 0; + cells[2] =3D 0; + cells[3] =3D cpu_to_be32(PCI0_IO_BASE); + cells[4] =3D 0; + cells[5] =3D cpu_to_be32(PCI0_IO_SIZE); + cells[6] =3D cpu_to_be32(0x02000000); + cells[7] =3D 0; + cells[8] =3D cpu_to_be32(PCI0_MEM_BASE); + cells[9] =3D cpu_to_be32(PCI0_MEM_BASE); + cells[10] =3D 0; + cells[11] =3D cpu_to_be32(PCI0_MEM_SIZE); + qemu_fdt_setprop(fdt, "/pci@c0000000", "ranges", + cells, 12 * sizeof(cells[0])); + qemu_fdt_setprop_cell(fdt, "/pci@c0000000", "#size-cells", 2); + qemu_fdt_setprop_cell(fdt, "/pci@c0000000", "#address-cells", 3); + qemu_fdt_setprop_string(fdt, "/pci@c0000000", "device_type", "pci"); + qemu_fdt_setprop_string(fdt, "/pci@c0000000", "name", "pci"); + + fi.path =3D "/pci@c0000000"; + pci_bus =3D mv64361_get_pci_bus(pm->mv, 0); + pci_for_each_device_reverse(pci_bus, 0, add_pci_device, &fi); + + /* pci@80000000 */ + qemu_fdt_add_subnode(fdt, "/pci@80000000"); + cells[0] =3D 0; + cells[1] =3D 0; + qemu_fdt_setprop(fdt, "/pci@80000000", "bus-range", + cells, 2 * sizeof(cells[0])); + qemu_fdt_setprop_cell(fdt, "/pci@80000000", "pci-bridge-number", 0); + cells[0] =3D cpu_to_be32(PCI1_MEM_BASE); + cells[1] =3D cpu_to_be32(PCI1_MEM_SIZE); + qemu_fdt_setprop(fdt, "/pci@80000000", "reg", cells, 2 * sizeof(cells[= 0])); + qemu_fdt_setprop_cell(fdt, "/pci@80000000", "8259-interrupt-acknowledg= e", + 0xf1000cb4); + cells[0] =3D cpu_to_be32(0x01000000); + cells[1] =3D 0; + cells[2] =3D 0; + cells[3] =3D cpu_to_be32(PCI1_IO_BASE); + cells[4] =3D 0; + cells[5] =3D cpu_to_be32(PCI1_IO_SIZE); + cells[6] =3D cpu_to_be32(0x02000000); + cells[7] =3D 0; + cells[8] =3D cpu_to_be32(PCI1_MEM_BASE); + cells[9] =3D cpu_to_be32(PCI1_MEM_BASE); + cells[10] =3D 0; + cells[11] =3D cpu_to_be32(PCI1_MEM_SIZE); + qemu_fdt_setprop(fdt, "/pci@80000000", "ranges", + cells, 12 * sizeof(cells[0])); + qemu_fdt_setprop_cell(fdt, "/pci@80000000", "#size-cells", 2); + qemu_fdt_setprop_cell(fdt, "/pci@80000000", "#address-cells", 3); + qemu_fdt_setprop_string(fdt, "/pci@80000000", "device_type", "pci"); + qemu_fdt_setprop_string(fdt, "/pci@80000000", "name", "pci"); + + fi.path =3D "/pci@80000000"; + pci_bus =3D mv64361_get_pci_bus(pm->mv, 1); + pci_for_each_device_reverse(pci_bus, 0, add_pci_device, &fi); + + qemu_fdt_add_subnode(fdt, "/failsafe"); + qemu_fdt_setprop_string(fdt, "/failsafe", "device_type", "serial"); + qemu_fdt_setprop_string(fdt, "/failsafe", "name", "failsafe"); + + /* cpus */ + qemu_fdt_add_subnode(fdt, "/cpus"); + qemu_fdt_setprop_cell(fdt, "/cpus", "#cpus", 1); + qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); + qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); + qemu_fdt_setprop_string(fdt, "/cpus", "name", "cpus"); + + /* FIXME Get CPU name from CPU object */ + const char *cp =3D "/cpus/PowerPC,G4"; + qemu_fdt_add_subnode(fdt, cp); + qemu_fdt_setprop_cell(fdt, cp, "l2cr", 0); + qemu_fdt_setprop_cell(fdt, cp, "d-cache-size", 0x8000); + qemu_fdt_setprop_cell(fdt, cp, "d-cache-block-size", + cpu->env.dcache_line_size); + qemu_fdt_setprop_cell(fdt, cp, "d-cache-line-size", + cpu->env.dcache_line_size); + qemu_fdt_setprop_cell(fdt, cp, "i-cache-size", 0x8000); + qemu_fdt_setprop_cell(fdt, cp, "i-cache-block-size", + cpu->env.icache_line_size); + qemu_fdt_setprop_cell(fdt, cp, "i-cache-line-size", + cpu->env.icache_line_size); + if (cpu->env.id_tlbs) { + qemu_fdt_setprop_cell(fdt, cp, "i-tlb-sets", cpu->env.nb_ways); + qemu_fdt_setprop_cell(fdt, cp, "i-tlb-size", cpu->env.tlb_per_way); + qemu_fdt_setprop_cell(fdt, cp, "d-tlb-sets", cpu->env.nb_ways); + qemu_fdt_setprop_cell(fdt, cp, "d-tlb-size", cpu->env.tlb_per_way); + qemu_fdt_setprop_string(fdt, cp, "tlb-split", ""); + } + qemu_fdt_setprop_cell(fdt, cp, "tlb-sets", cpu->env.nb_ways); + qemu_fdt_setprop_cell(fdt, cp, "tlb-size", cpu->env.nb_tlb); + qemu_fdt_setprop_string(fdt, cp, "state", "running"); + if (cpu->env.insns_flags & PPC_ALTIVEC) { + qemu_fdt_setprop_string(fdt, cp, "altivec", ""); + qemu_fdt_setprop_string(fdt, cp, "data-streams", ""); + } + /* + * FIXME What flags do data-streams, external-control and + * performance-monitor depend on? + */ + qemu_fdt_setprop_string(fdt, cp, "external-control", ""); + if (cpu->env.insns_flags & PPC_FLOAT_FSQRT) { + qemu_fdt_setprop_string(fdt, cp, "general-purpose", ""); + } + qemu_fdt_setprop_string(fdt, cp, "performance-monitor", ""); + if (cpu->env.insns_flags & PPC_FLOAT_FRES) { + qemu_fdt_setprop_string(fdt, cp, "graphics", ""); + } + qemu_fdt_setprop_cell(fdt, cp, "reservation-granule-size", 4); + qemu_fdt_setprop_cell(fdt, cp, "timebase-frequency", + cpu->env.tb_env->tb_freq); + qemu_fdt_setprop_cell(fdt, cp, "bus-frequency", BUS_FREQ_HZ); + qemu_fdt_setprop_cell(fdt, cp, "clock-frequency", BUS_FREQ_HZ * 7.5); + qemu_fdt_setprop_cell(fdt, cp, "cpu-version", cpu->env.spr[SPR_PVR]); + cells[0] =3D 0; + cells[1] =3D 0; + qemu_fdt_setprop(fdt, cp, "reg", cells, 2 * sizeof(cells[0])); + qemu_fdt_setprop_string(fdt, cp, "device_type", "cpu"); + qemu_fdt_setprop_string(fdt, cp, "name", strrchr(cp, '/') + 1); + + /* memory */ + qemu_fdt_add_subnode(fdt, "/memory@0"); + cells[0] =3D 0; + cells[1] =3D cpu_to_be32(machine->ram_size); + qemu_fdt_setprop(fdt, "/memory@0", "reg", cells, 2 * sizeof(cells[0])); + qemu_fdt_setprop_string(fdt, "/memory@0", "device_type", "memory"); + qemu_fdt_setprop_string(fdt, "/memory@0", "name", "memory"); + + qemu_fdt_add_subnode(fdt, "/chosen"); + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + machine->kernel_cmdline ?: ""); + qemu_fdt_setprop_string(fdt, "/chosen", "name", "chosen"); + + qemu_fdt_add_subnode(fdt, "/openprom"); + qemu_fdt_setprop_string(fdt, "/openprom", "model", "Pegasos2,1.1"); + + return fdt; +} --=20 2.21.4 From nobody Sat May 18 18:02:03 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=eik.bme.hu Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1624812186696624.9439210485345; Sun, 27 Jun 2021 09:43:06 -0700 (PDT) Received: from localhost ([::1]:40460 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxXs9-0000vX-Lt for importer@patchew.org; Sun, 27 Jun 2021 12:43:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35894) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoV-0002Ev-Ue; Sun, 27 Jun 2021 12:39:21 -0400 Received: from zero.eik.bme.hu ([2001:738:2001:2001::2001]:54243) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxXoM-0007mw-E8; Sun, 27 Jun 2021 12:39:19 -0400 Received: from zero.eik.bme.hu (blah.eik.bme.hu [152.66.115.182]) by localhost (Postfix) with SMTP id 01643746396; Sun, 27 Jun 2021 18:39:08 +0200 (CEST) Received: by zero.eik.bme.hu (Postfix, from userid 432) id 57F637457EF; Sun, 27 Jun 2021 18:39:07 +0200 (CEST) Message-Id: In-Reply-To: References: From: BALATON Zoltan Subject: [PATCH 4/4] ppc/pegasos2: Implement some RTAS functions with VOF Date: Sun, 27 Jun 2021 18:27:13 +0200 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org X-Spam-Probability: 10% Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:738:2001:2001::2001; envelope-from=balaton@eik.bme.hu; helo=zero.eik.bme.hu X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Alexey Kardashevskiy , David Gibson Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Linux uses RTAS functions to access PCI devices so we need to provide these with VOF. Implement some of the most important functions to allow booting Linux with VOF. With this the board is now usable without a binary ROM image and we can enable it by default as other boards. Signed-off-by: BALATON Zoltan --- default-configs/devices/ppc-softmmu.mak | 2 +- hw/ppc/pegasos2.c | 131 ++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/default-configs/devices/ppc-softmmu.mak b/default-configs/devi= ces/ppc-softmmu.mak index c2d41198cd..4535993d8d 100644 --- a/default-configs/devices/ppc-softmmu.mak +++ b/default-configs/devices/ppc-softmmu.mak @@ -14,7 +14,7 @@ CONFIG_SAM460EX=3Dy CONFIG_MAC_OLDWORLD=3Dy CONFIG_MAC_NEWWORLD=3Dy =20 -CONFIG_PEGASOS2=3Dn +CONFIG_PEGASOS2=3Dy =20 # For PReP CONFIG_PREP=3Dy diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index f1741a4512..d482806edd 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -43,6 +43,7 @@ #define PROM_SIZE 0x80000 =20 #define KVMPPC_HCALL_BASE 0xf000 +#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) #define KVMPPC_H_VOF_CLIENT (KVMPPC_HCALL_BASE + 0x5) =20 #define H_SUCCESS 0 @@ -195,6 +196,30 @@ static void pegasos2_init(MachineState *machine) } } =20 +static uint32_t pegasos2_pci_config_read(AddressSpace *as, int bus, + uint32_t addr, uint32_t len) +{ + hwaddr pcicfg =3D (bus ? 0xf1000c78 : 0xf1000cf8); + uint32_t val =3D 0xffffffff; + + stl_le_phys(as, pcicfg, addr | BIT(31)); + switch (len) { + case 4: + val =3D ldl_le_phys(as, pcicfg + 4); + break; + case 2: + val =3D lduw_le_phys(as, pcicfg + 4); + break; + case 1: + val =3D ldub_phys(as, pcicfg + 4); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid length\n", __func__); + break; + } + return val; +} + static void pegasos2_pci_config_write(AddressSpace *as, int bus, uint32_t = addr, uint32_t len, uint32_t val) { @@ -304,6 +329,87 @@ static void pegasos2_machine_reset(MachineState *machi= ne) pm->cpu->vhyp =3D PPC_VIRTUAL_HYPERVISOR(machine); } =20 +enum pegasos2_rtas_tokens { + RTAS_RESTART_RTAS =3D 0, + RTAS_NVRAM_FETCH =3D 1, + RTAS_NVRAM_STORE =3D 2, + RTAS_GET_TIME_OF_DAY =3D 3, + RTAS_SET_TIME_OF_DAY =3D 4, + RTAS_EVENT_SCAN =3D 6, + RTAS_CHECK_EXCEPTION =3D 7, + RTAS_READ_PCI_CONFIG =3D 8, + RTAS_WRITE_PCI_CONFIG =3D 9, + RTAS_DISPLAY_CHARACTER =3D 10, + RTAS_SET_INDICATOR =3D 11, + RTAS_POWER_OFF =3D 17, + RTAS_SUSPEND =3D 18, + RTAS_HIBERNATE =3D 19, + RTAS_SYSTEM_REBOOT =3D 20, +}; + +static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *p= m, + target_ulong args_real) +{ + AddressSpace *as =3D CPU(cpu)->as; + uint32_t token =3D ldl_be_phys(as, args_real); + uint32_t nargs =3D ldl_be_phys(as, args_real + 4); + uint32_t nrets =3D ldl_be_phys(as, args_real + 8); + uint32_t args =3D args_real + 12; + uint32_t rets =3D args_real + 12 + nargs * 4; + + if (nrets < 1) { + qemu_log_mask(LOG_GUEST_ERROR, "Too few return values in RTAS call= \n"); + return H_PARAMETER; + } + switch (token) { + case RTAS_READ_PCI_CONFIG: + { + uint32_t addr, len, val; + + if (nargs !=3D 2 || nrets !=3D 2) { + stl_be_phys(as, rets, -1); + return H_PARAMETER; + } + addr =3D ldl_be_phys(as, args); + len =3D ldl_be_phys(as, args + 4); + val =3D pegasos2_pci_config_read(as, !(addr >> 24), + addr & 0x0fffffff, len); + stl_be_phys(as, rets, 0); + stl_be_phys(as, rets + 4, val); + return H_SUCCESS; + } + case RTAS_WRITE_PCI_CONFIG: + { + uint32_t addr, len, val; + + if (nargs !=3D 3 || nrets !=3D 1) { + stl_be_phys(as, rets, -1); + return H_PARAMETER; + } + addr =3D ldl_be_phys(as, args); + len =3D ldl_be_phys(as, args + 4); + val =3D ldl_be_phys(as, args + 8); + pegasos2_pci_config_write(as, !(addr >> 24), + addr & 0x0fffffff, len, val); + stl_be_phys(as, rets, 0); + return H_SUCCESS; + } + case RTAS_DISPLAY_CHARACTER: + if (nargs !=3D 1 || nrets !=3D 1) { + stl_be_phys(as, rets, -1); + return H_PARAMETER; + } + qemu_log_mask(LOG_UNIMP, "%c", ldl_be_phys(as, args)); + stl_be_phys(as, rets, 0); + return H_SUCCESS; + default: + qemu_log_mask(LOG_UNIMP, "Unknown RTAS token %u (args=3D%u, rets= =3D%u)\n", + token, nargs, nrets); + stl_be_phys(as, rets, 0); + return H_SUCCESS; + } +} + static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) { Pegasos2MachineState *pm =3D PEGASOS2_MACHINE(vhyp); @@ -315,6 +421,8 @@ static void pegasos2_hypercall(PPCVirtualHypervisor *vh= yp, PowerPCCPU *cpu) if (msr_pr) { qemu_log_mask(LOG_GUEST_ERROR, "Hypercall made with MSR[PR]=3D1\n"= ); env->gpr[3] =3D H_PRIVILEGE; + } else if (env->gpr[3] =3D=3D KVMPPC_H_RTAS) { + env->gpr[3] =3D pegasos2_rtas(cpu, pm, env->gpr[4]); } else if (env->gpr[3] =3D=3D KVMPPC_H_VOF_CLIENT) { int ret =3D vof_client_call(MACHINE(pm), pm->vof, pm->fdt_blob, env->gpr[4]); @@ -687,6 +795,29 @@ static void *build_fdt(MachineState *machine, int *fdt= _size) qemu_fdt_setprop_string(fdt, "/failsafe", "device_type", "serial"); qemu_fdt_setprop_string(fdt, "/failsafe", "name", "failsafe"); =20 + qemu_fdt_add_subnode(fdt, "/rtas"); + qemu_fdt_setprop_cell(fdt, "/rtas", "system-reboot", 20); + qemu_fdt_setprop_cell(fdt, "/rtas", "hibernate", 19); + qemu_fdt_setprop_cell(fdt, "/rtas", "suspend", 18); + qemu_fdt_setprop_cell(fdt, "/rtas", "power-off", 17); + qemu_fdt_setprop_cell(fdt, "/rtas", "set-indicator", 11); + qemu_fdt_setprop_cell(fdt, "/rtas", "display-character", 10); + qemu_fdt_setprop_cell(fdt, "/rtas", "write-pci-config", 9); + qemu_fdt_setprop_cell(fdt, "/rtas", "read-pci-config", 8); + /* Pegasos2 firmware misspells check-exception and guests use that */ + qemu_fdt_setprop_cell(fdt, "/rtas", "check-execption", 7); + qemu_fdt_setprop_cell(fdt, "/rtas", "event-scan", 6); + qemu_fdt_setprop_cell(fdt, "/rtas", "set-time-of-day", 4); + qemu_fdt_setprop_cell(fdt, "/rtas", "get-time-of-day", 3); + qemu_fdt_setprop_cell(fdt, "/rtas", "nvram-store", 2); + qemu_fdt_setprop_cell(fdt, "/rtas", "nvram-fetch", 1); + qemu_fdt_setprop_cell(fdt, "/rtas", "restart-rtas", 0); + qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-error-log-max", 0); + qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-event-scan-rate", 0); + qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-display-device", 0); + qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size", 20); + qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-version", 1); + /* cpus */ qemu_fdt_add_subnode(fdt, "/cpus"); qemu_fdt_setprop_cell(fdt, "/cpus", "#cpus", 1); --=20 2.21.4