From nobody Sat Sep 6 00:47:36 2025 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 17514960158420.4457408958517135; Wed, 2 Jul 2025 15:40:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uX65y-0008Mk-5T; Wed, 02 Jul 2025 18:38:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uX65t-0008Id-R4; Wed, 02 Jul 2025 18:38:21 -0400 Received: from zero.eik.bme.hu ([152.66.115.2]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uX65r-0005Gj-6X; Wed, 02 Jul 2025 18:38:21 -0400 Received: from zero.eik.bme.hu (localhost [127.0.0.1]) by zero.eik.bme.hu (Postfix) with ESMTP id 2E18155CCAB; Thu, 03 Jul 2025 00:38:17 +0200 (CEST) Received: from zero.eik.bme.hu ([127.0.0.1]) by zero.eik.bme.hu (zero.eik.bme.hu [127.0.0.1]) (amavisd-new, port 10028) with ESMTP id cUd9eMHA3ehj; Thu, 3 Jul 2025 00:38:15 +0200 (CEST) Received: by zero.eik.bme.hu (Postfix, from userid 432) id 2F68855CCA8; Thu, 03 Jul 2025 00:38:15 +0200 (CEST) X-Virus-Scanned: amavisd-new at eik.bme.hu Message-ID: <58b460095a54cfc69c6a4cc6d88b0b93932deb54.1751494995.git.balaton@eik.bme.hu> In-Reply-To: References: From: BALATON Zoltan Subject: [PATCH v2 12/13] hw/ppc/pegasos2: Add Pegasos I emulation MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org Cc: Nicholas Piggin Date: Thu, 03 Jul 2025 00:38:15 +0200 (CEST) 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: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.237, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1751496017711116600 Content-Type: text/plain; charset="utf-8" The Pegasos II is a redesign of the original Pegasos (later marked I) that replaces the north bridge and has updated firmware but otherwise these are very similar. The Pegasos uses the same north bridge that AmigaOne used which we already emulate so we can also easily emulate Pegasos I. Signed-off-by: BALATON Zoltan --- hw/ppc/pegasos2.c | 170 +++++++++++++++++++++++++++++++++------------- 1 file changed, 124 insertions(+), 46 deletions(-) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index ae3f01231d..a88d93ae04 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -1,5 +1,5 @@ /* - * QEMU PowerPC CHRP (Genesi/bPlan Pegasos II) hardware System Emulator + * QEMU PowerPC CHRP (Genesi/bPlan Pegasos I/II) hardware System Emulator * * Copyright (c) 2018-2021 BALATON Zoltan * @@ -15,6 +15,7 @@ #include "hw/pci/pci_host.h" #include "hw/irq.h" #include "hw/or-irq.h" +#include "hw/pci-host/articia.h" #include "hw/pci-host/mv64361.h" #include "hw/isa/vt82c686.h" #include "hw/ide/pci.h" @@ -55,12 +56,18 @@ #define H_PRIVILEGE -3 /* Caller not privileged */ #define H_PARAMETER -4 /* Parameter invalid, out-of-range or conflicting= */ =20 +typedef enum { + PEGASOS1 =3D 1, + PEGASOS2 =3D 2, +} PegasosMachineType; + #define TYPE_PEGASOS_MACHINE MACHINE_TYPE_NAME("pegasos") OBJECT_DECLARE_SIMPLE_TYPE(PegasosMachineState, PEGASOS_MACHINE) =20 struct PegasosMachineState { MachineState parent_obj; =20 + PegasosMachineType type; PowerPCCPU *cpu; DeviceState *nb; /* north bridge */ DeviceState *sb; /* south bridge */ @@ -79,7 +86,7 @@ struct PegasosMachineState { =20 static void *pegasos2_build_fdt(PegasosMachineState *pm, int *fdt_size); =20 -static void pegasos2_cpu_reset(void *opaque) +static void pegasos_cpu_reset(void *opaque) { PowerPCCPU *cpu =3D opaque; PegasosMachineState *pm =3D PEGASOS_MACHINE(current_machine); @@ -89,6 +96,8 @@ static void pegasos2_cpu_reset(void *opaque) if (pm->vof) { cpu->env.gpr[1] =3D 2 * VOF_STACK_SIZE - 0x20; cpu->env.nip =3D 0x100; + } else if (pm->type =3D=3D PEGASOS1) { + cpu->env.nip =3D 0xfffc0100; } cpu_ppc_tb_reset(&cpu->env); } @@ -139,13 +148,15 @@ static void pegasos_init(MachineState *machine) PegasosMachineState *pm =3D PEGASOS_MACHINE(machine); CPUPPCState *env; MemoryRegion *rom =3D g_new(MemoryRegion, 1); - PCIBus *pci_bus; + PCIBus *pci_bus =3D NULL; Object *via; PCIDevice *dev; I2CBus *i2c_bus; const char *fwname =3D machine->firmware ?: PROM_FILENAME; char *filename; + hwaddr prom_addr; ssize_t sz; + int devfn; uint8_t *spd_data; =20 /* init CPU */ @@ -158,7 +169,7 @@ static void pegasos_init(MachineState *machine) =20 /* Set time-base frequency */ cpu_ppc_tb_init(env, pm->bus_freq_hz / 4); - qemu_register_reset(pegasos2_cpu_reset, pm->cpu); + qemu_register_reset(pegasos_cpu_reset, pm->cpu); =20 /* RAM */ if (machine->ram_size > 2 * GiB) { @@ -176,12 +187,16 @@ static void pegasos_init(MachineState *machine) 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); + prom_addr =3D PROM_ADDR; + if (pm->type =3D=3D PEGASOS1) { + prom_addr +=3D PROM_SIZE; + } + memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal); + memory_region_add_subregion(get_system_memory(), prom_addr, rom); sz =3D load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0); if (sz <=3D 0) { - sz =3D load_image_targphys(filename, pm->vof ? 0 : 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); @@ -192,13 +207,37 @@ static void pegasos_init(MachineState *machine) pm->vof->fw_size =3D sz; } =20 - /* Marvell Discovery II system controller */ - pm->nb =3D DEVICE(sysbus_create_simple(TYPE_MV64361, -1, - qdev_get_gpio_in(DEVICE(pm->cpu), PPC6xx_INPUT_I= NT))); - pci_bus =3D mv64361_get_pci_bus(pm->nb, 1); + /* north bridge */ + switch (pm->type) { + case PEGASOS1: + { + MemoryRegion *pci_mem, *mr; + + /* Articia S */ + pm->nb =3D DEVICE(sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, N= ULL)); + pci_mem =3D sysbus_mmio_get_region(SYS_BUS_DEVICE(pm->nb), 1); + mr =3D g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(pm->nb), "pci-mem-low", pci_me= m, + 0, 0x1000000); + memory_region_add_subregion(get_system_memory(), 0xfd000000, mr); + mr =3D g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(pm->nb), "pci-mem-high", pci_m= em, + 0x80000000, 0x7d000000); + memory_region_add_subregion(get_system_memory(), 0x80000000, mr); + pci_bus =3D PCI_BUS(qdev_get_child_bus(pm->nb, "pci.0")); + break; + } + case PEGASOS2: + /* Marvell Discovery II system controller */ + pm->nb =3D DEVICE(sysbus_create_simple(TYPE_MV64361, -1, + qdev_get_gpio_in(DEVICE(pm->cpu), PPC6xx_INPUT_INT= ))); + pci_bus =3D mv64361_get_pci_bus(pm->nb, 1); + break; + } =20 /* VIA VT8231 South Bridge (multifunction PCI device) */ - pm->sb =3D DEVICE(pci_new_multifunction(PCI_DEVFN(12, 0), TYPE_VT8231_= ISA)); + devfn =3D PCI_DEVFN(pm->type =3D=3D PEGASOS1 ? 7 : 12, 0); + pm->sb =3D DEVICE(pci_new_multifunction(devfn, TYPE_VT8231_ISA)); via =3D OBJECT(pm->sb); =20 /* Set properties on individual devices before realizing the south bri= dge */ @@ -223,7 +262,21 @@ static void pegasos_init(MachineState *machine) /* other PC hardware */ pci_vga_init(pci_bus); =20 - pegasos2_setup_pci_irq(pm); + /* pci interrupt routing */ + switch (pm->type) { + case PEGASOS1: + qdev_connect_gpio_out_named(pm->sb, "intr", 0, + qdev_get_gpio_in(DEVICE(pm->cpu), + PPC6xx_INPUT_INT)); + for (int i =3D 0; i < PCI_NUM_PINS; i++) { + qdev_connect_gpio_out(pm->nb, i, + qdev_get_gpio_in_named(pm->sb, "pirq", i= )); + } + break; + case PEGASOS2: + pegasos2_setup_pci_irq(pm); + break; + } =20 if (machine->kernel_filename) { sz =3D load_elf(machine->kernel_filename, NULL, NULL, NULL, @@ -376,7 +429,7 @@ static void pegasos2_chipset_reset(PegasosMachineState = *pm) PCI_INTERRUPT_LINE, 2, 0x309); } =20 -static void pegasos2_machine_reset(MachineState *machine, ResetType type) +static void pegasos_machine_reset(MachineState *machine, ResetType type) { PegasosMachineState *pm =3D PEGASOS_MACHINE(machine); void *fdt; @@ -387,6 +440,9 @@ static void pegasos2_machine_reset(MachineState *machin= e, ResetType type) qemu_devices_reset(type); if (!pm->vof) { return; /* Firmware should set up machine so nothing to do */ + } else if (pm->type =3D=3D PEGASOS1) { + error_report("VOF is not supported by this machine"); + exit(1); } =20 /* Otherwise, set up devices that board firmware would normally do */ @@ -558,12 +614,12 @@ static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pe= gasosMachineState *pm, } } =20 -static bool pegasos2_cpu_in_nested(PowerPCCPU *cpu) +static bool pegasos_cpu_in_nested(PowerPCCPU *cpu) { return false; } =20 -static void pegasos2_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) +static void pegasos_hypercall(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) { PegasosMachineState *pm =3D PEGASOS_MACHINE(vhyp); CPUPPCState *env =3D &cpu->env; @@ -574,7 +630,7 @@ static void pegasos2_hypercall(PPCVirtualHypervisor *vh= yp, PowerPCCPU *cpu) if (FIELD_EX64(env->msr, 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) { + } else if (env->gpr[3] =3D=3D KVMPPC_H_RTAS && pm->type =3D=3D PEGASOS= 2) { 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, MACHINE(pm)->fdt, @@ -596,62 +652,84 @@ static target_ulong vhyp_encode_hpt_for_kvm_pr(PPCVir= tualHypervisor *vhyp) return POWERPC_CPU(current_cpu)->env.spr[SPR_SDR1]; } =20 -static bool pegasos2_setprop(MachineState *ms, const char *path, - const char *propname, void *val, int vallen) +static bool pegasos_setprop(MachineState *ms, const char *path, + const char *propname, void *val, int vallen) { return true; } =20 -static void pegasos2_init(Object *obj) -{ - PegasosMachineState *pm =3D PEGASOS_MACHINE(obj); - - pm->bus_freq_hz =3D 133333333; -} - -static void pegasos2_machine_class_init(ObjectClass *oc, const void *data) +static void pegasos_machine_init(MachineClass *mc) { - MachineClass *mc =3D MACHINE_CLASS(oc); - PPCVirtualHypervisorClass *vhc =3D PPC_VIRTUAL_HYPERVISOR_CLASS(oc); - VofMachineIfClass *vmc =3D VOF_MACHINE_CLASS(oc); + PPCVirtualHypervisorClass *vhc =3D PPC_VIRTUAL_HYPERVISOR_CLASS(mc); + VofMachineIfClass *vmc =3D VOF_MACHINE_CLASS(mc); =20 - mc->desc =3D "Genesi/bPlan Pegasos II"; mc->init =3D pegasos_init; - mc->reset =3D pegasos2_machine_reset; + mc->reset =3D pegasos_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("7457_v1.2"); - mc->default_ram_id =3D "pegasos2.ram"; + mc->default_ram_id =3D "ram"; mc->default_ram_size =3D 512 * MiB; machine_add_audiodev_property(mc); =20 - vhc->cpu_in_nested =3D pegasos2_cpu_in_nested; - vhc->hypercall =3D pegasos2_hypercall; + vhc->cpu_in_nested =3D pegasos_cpu_in_nested; + vhc->hypercall =3D pegasos_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 - vmc->setprop =3D pegasos2_setprop; + vmc->setprop =3D pegasos_setprop; +} + +static void pegasos1_init(Object *obj) +{ + PegasosMachineState *pm =3D PEGASOS_MACHINE(obj); + + pm->type =3D PEGASOS1; + pm->bus_freq_hz =3D 33000000; +} + +static void pegasos1_machine_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "Genesi/bPlan Pegasos I"; + mc->default_cpu_type =3D POWERPC_CPU_TYPE_NAME("750cxe_v3.1b"); +} + +static void pegasos2_init(Object *obj) +{ + PegasosMachineState *pm =3D PEGASOS_MACHINE(obj); + + pm->type =3D PEGASOS2; + pm->bus_freq_hz =3D 133333333; +} + +static void pegasos2_machine_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "Genesi/bPlan Pegasos II"; + mc->default_cpu_type =3D POWERPC_CPU_TYPE_NAME("7457_v1.2"); } =20 +DEFINE_MACHINE_EXTENDED("pegasos", MACHINE, PegasosMachineState, + pegasos_machine_init, true, + { TYPE_PPC_VIRTUAL_HYPERVISOR }, + { TYPE_VOF_MACHINE_IF }, { }) + static const TypeInfo pegasos_machine_types[] =3D { { - .name =3D TYPE_PEGASOS_MACHINE, - .parent =3D TYPE_MACHINE, - .instance_size =3D sizeof(PegasosMachineState), - .abstract =3D true, + .name =3D MACHINE_TYPE_NAME("pegasos1"), + .parent =3D TYPE_PEGASOS_MACHINE, + .class_init =3D pegasos1_machine_class_init, + .instance_init =3D pegasos1_init, }, { .name =3D MACHINE_TYPE_NAME("pegasos2"), .parent =3D TYPE_PEGASOS_MACHINE, .class_init =3D pegasos2_machine_class_init, .instance_init =3D pegasos2_init, - .interfaces =3D (const InterfaceInfo[]) { - { TYPE_PPC_VIRTUAL_HYPERVISOR }, - { TYPE_VOF_MACHINE_IF }, - { } - }, }, }; =20 --=20 2.41.3