qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: mac99 SMP


From: BALATON Zoltan
Subject: Re: mac99 SMP
Date: Sun, 30 Mar 2025 13:47:43 +0200 (CEST)

On Sun, 30 Mar 2025, Jd Lyons wrote:
I did my best to implement your suggestions, tho GPIO 15 and 16 seem to be outside the rage of the GPIO array so I rerouted them to GPIO 5 and 6.

According to linux/arch/powerpc/include/asm/keylargo.h
#define KEYLARGO_GPIO_EXTINT_CNT        18
so you probably have to increase the array in QEMU. Using other random GPIO lines instead may not work if the guest expects that to be something else and use them which may result in randomly resetting CPUs when not expected. So better put these where they are on real machine (or what Linux thinks it should be as that maybe was taken from some real hardware).

Sadly it didn’t make any difference what so ever that I can tell, the

I told before that adding more CPUs is not likely to fix anything, it's more likely to break things. What might fix something is implementing TB sync so maybe to solve that instead.

system boots fine and kbd works in Openbios but as soon as the Tiger Kernel loads I lose kbd/m even in single user mode no kbd.

Seems to not work even with only one CPU.

The system does run as I can put apps in the Startup Items and they run. Altivec Fractional Carbon runs and is x4 as fast as single CPU, I just have zero input.

Best I can figure it’s the code changes to mac_newworld.c are breaking input via USB, but not other PCI devices. I just can’t figure out how to trace usb events to see if I can find the issue??

There's -trace enable="usb*" but not sure it would give you much useful info.

I haven't looked at the patch.

Regards,
BALATON Zoltan

diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 78a82d0d30..eca8866b95 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -50,7 +50,7 @@
#ifdef DEBUG_OPENPIC
static const int debug_openpic = 1;
#else
-static const int debug_openpic = 0;
+static const int debug_openpic = 1;
#endif

static int get_current_cpu(void);
@@ -1580,12 +1580,12 @@ static void openpic_realize(DeviceState *dev, Error 
**errp)
        opp->irq_tim0 = KEYLARGO_TMR_IRQ;
        opp->brr1 = -1;
        opp->mpic_mode_mask = GCR_MODE_MIXED;
-
+#if 0
        if (opp->nb_cpus != 1) {
            error_setg(errp, "Only UP supported today");
            return;
        }
-
+#endif
        map_list(opp, list_le, &list_count);
        break;
    }
diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c
index e87bfca1f5..410257ad61 100644
--- a/hw/misc/macio/gpio.c
+++ b/hw/misc/macio/gpio.c
@@ -33,6 +33,11 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
+#define KEYLARGO_GPIO_EXTINT_0        0x58
+#define KL_GPIO_RESET_CPU1            (KEYLARGO_GPIO_EXTINT_0 + 0x04)
+#define KL_GPIO_RESET_CPU2            (KEYLARGO_GPIO_EXTINT_0 + 0x0f)
+#define KL_GPIO_RESET_CPU3            (KEYLARGO_GPIO_EXTINT_0 + 0x10)
+

enum MacioGPIORegisterBits {
    OUT_DATA   = 1,
@@ -56,18 +61,13 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool 
state)
        new_reg |= IN_DATA;
    }

-    if (new_reg == s->gpio_regs[gpio]) {
+    /* For GPIOs 4, 5, and 6 (reset lines), always update so we can 
assert/deassert */
+    if ((gpio != 4) && (gpio != 5) && (gpio != 6) && (new_reg == 
s->gpio_regs[gpio])) {
        return;
    }

-    s->gpio_regs[gpio] = new_reg;

-    /*
-     * Note that we probably need to get access to the MPIC config to
-     * decode polarity since qemu always use "raise" regardless.
-     *
-     * For now, we hard wire known GPIOs
-     */
+    s->gpio_regs[gpio] = new_reg;

    switch (gpio) {
    case 1:
@@ -81,6 +81,39 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool 
state)
        }
        break;

+    case 4:
+        /* Active low, CPU1 reset */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
+    case 5:
+        /* Active low, CPU2 reset */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
+    case 6:
+        /* Active low, CPU3 reset */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
    case 9:
        /* Edge, triggered by NMI below */
        if (state) {
@@ -97,6 +130,8 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool 
state)
    }
}

+
+
static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
                             unsigned size)
{
@@ -105,11 +140,12 @@ static void macio_gpio_write(void *opaque, hwaddr addr, 
uint64_t value,

    trace_macio_gpio_write(addr, value);

-    /* Levels regs are read-only */
+    /* Level registers are read-only */
    if (addr < 8) {
        return;
    }

+    /* Adjust for the first 8 bytes being level registers */
    addr -= 8;
    if (addr < 36) {
        value &= ~IN_DATA;
@@ -120,7 +156,21 @@ static void macio_gpio_write(void *opaque, hwaddr addr, 
uint64_t value,
            ibit = s->gpio_regs[addr] & IN_DATA;
        }

-        s->gpio_regs[addr] = value | ibit;
+        if (addr == (KL_GPIO_RESET_CPU1 - KEYLARGO_GPIO_EXTINT_0)) {
+            /* For CPU1 reset: (0x58+0x04) - 0x58 = 0x04 */
+            if (!(value & OUT_ENABLE)) {
+                ibit = 1; /* Ensure pulled high unless driven low */
+            }
+            macio_set_gpio(s, 4, ibit);
+        } else if (addr == (KL_GPIO_RESET_CPU2 - KEYLARGO_GPIO_EXTINT_0)) {
+            /* For CPU2 reset: (0x58+0x0f) - 0x58 = 0x0F */
+            macio_set_gpio(s, 5, ibit);
+        } else if (addr == (KL_GPIO_RESET_CPU3 - KEYLARGO_GPIO_EXTINT_0)) {
+            /* For CPU3 reset: (0x58+0x10) - 0x58 = 0x10 */
+            macio_set_gpio(s, 6, ibit);
+        } else {
+            s->gpio_regs[addr] = value | ibit;
+        }
    }
}

@@ -186,6 +236,9 @@ static void macio_gpio_reset(DeviceState *dev)

    /* GPIO 1 is up by default */
    macio_set_gpio(s, 1, true);
+    macio_set_gpio(s, 4, true);
+    macio_set_gpio(s, 5, true);
+    macio_set_gpio(s, 6, true);
}

static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index 0d82e5a128..3ef53d26ca 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -46,7 +46,7 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr,
    MacIONVRAMState *s = opaque;

    addr = (addr >> s->it_shift) & (s->size - 1);
-    trace_macio_nvram_write(addr, value);
+//    trace_macio_nvram_write(addr, value);
    s->data[addr] = value;
    if (s->blk) {
        if (blk_pwrite(s->blk, addr, 1, &s->data[addr], 0) < 0) {
@@ -64,7 +64,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,

    addr = (addr >> s->it_shift) & (s->size - 1);
    value = s->data[addr];
-    trace_macio_nvram_read(addr, value);
+//    trace_macio_nvram_read(addr, value);

    return value;
}
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index cb3dc3ab48..a67a72ae83 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -73,6 +73,7 @@
#include "kvm_ppc.h"
#include "hw/usb.h"
#include "hw/sysbus.h"
+#include "hw/irq.h"
#include "trace.h"

#define MAX_IDE_BUS 2
@@ -128,12 +129,26 @@ static void ppc_core99_reset(void *opaque)
    cpu->env.nip = PROM_BASE + 0x100;
}

+static void cpu_kick(void *opaque, int n, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+
+
+    if (level) {
+        cpu->env.excp_prefix = 0;
+        cpu_reset(cs);
+        ppc_cpu_do_system_reset(cs);
+    }
+}
+
/* PowerPC Mac99 hardware initialisation */
static void ppc_core99_init(MachineState *machine)
{
    Core99MachineState *core99_machine = CORE99_MACHINE(machine);
    MachineClass *mc = MACHINE_GET_CLASS(machine);
-    PowerPCCPU *cpu = NULL;
+    qemu_irq kick;
+    PowerPCCPU **cpus = NULL;
    CPUPPCState *env = NULL;
    char *filename;
    IrqLines *openpic_irqs;
@@ -157,14 +172,18 @@ static void ppc_core99_init(MachineState *machine)
    uint64_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TBFREQ;

    /* init CPUs */
+    cpus = g_new0(PowerPCCPU *, machine->smp.cpus);
    for (i = 0; i < machine->smp.cpus; i++) {
-        cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
-        env = &cpu->env;
-
+        cpus[i] = POWERPC_CPU(cpu_create(machine->cpu_type));
+        fprintf(stderr, "cpus[%d] = %p %p\n", i, (void *)cpus[i], (void 
*)&cpus[i]->env);
+        /* Secondary CPUs start halted */
+        object_property_set_bool(OBJECT(cpus[i]), "start-powered-off", i != 0,
+                                 &error_abort);
        /* Set time-base frequency to 100 Mhz */
-        cpu_ppc_tb_init(env, TBFREQ);
-        qemu_register_reset(ppc_core99_reset, cpu);
+        cpu_ppc_tb_init(&cpus[i]->env, TBFREQ);
+        qemu_register_reset(ppc_core99_reset, cpus[i]);
    }
+    env = &cpus[0]->env;

    /* allocate RAM */
    if (machine->ram_size > 2 * GiB) {
@@ -184,7 +203,6 @@ static void ppc_core99_init(MachineState *machine)
        bios_size = load_elf(filename, NULL, NULL, NULL, NULL,
                             NULL, NULL, NULL,
                             ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
-
        if (bios_size <= 0) {
            /* or load binary ROM image */
            bios_size = load_image_targphys(filename, PROM_BASE, PROM_SIZE);
@@ -198,7 +216,6 @@ static void ppc_core99_init(MachineState *machine)

    if (machine->kernel_filename) {
        int bswap_needed = 0;
-
#ifdef BSWAP_NEEDED
        bswap_needed = 1;
#endif
@@ -239,9 +256,6 @@ static void ppc_core99_init(MachineState *machine)
        ppc_boot_device = 'm';
    } else {
        ppc_boot_device = '\0';
-        /* We consider that NewWorld PowerMac never have any floppy drive
-         * For now, OHW cannot boot from the network.
-         */
        for (i = 0; machine->boot_config.order[i] != '\0'; i++) {
            if (machine->boot_config.order[i] >= 'c' &&
                machine->boot_config.order[i] <= 'f') {
@@ -256,22 +270,18 @@ static void ppc_core99_init(MachineState *machine)
    }

    openpic_irqs = g_new0(IrqLines, machine->smp.cpus);
-    dev = DEVICE(cpu);
    for (i = 0; i < machine->smp.cpus; i++) {
-        /* Mac99 IRQ connection between OpenPIC outputs pins
-         * and PowerPC input pins
-         */
+        dev = DEVICE(cpus[i]);
+        /* Mac99 IRQ connection between OpenPIC outputs pins and PowerPC input 
pins */
        switch (PPC_INPUT(env)) {
        case PPC_FLAGS_INPUT_6xx:
            openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
                qdev_get_gpio_in(dev, PPC6xx_INPUT_INT);
            openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
-                 qdev_get_gpio_in(dev, PPC6xx_INPUT_INT);
+                qdev_get_gpio_in(dev, PPC6xx_INPUT_INT);
            openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
                qdev_get_gpio_in(dev, PPC6xx_INPUT_MCP);
-            /* Not connected ? */
            openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
-            /* Check this */
            openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
                qdev_get_gpio_in(dev, PPC6xx_INPUT_HRESET);
            break;
@@ -283,13 +293,11 @@ static void ppc_core99_init(MachineState *machine)
                qdev_get_gpio_in(dev, PPC970_INPUT_INT);
            openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
                qdev_get_gpio_in(dev, PPC970_INPUT_MCP);
-            /* Not connected ? */
            openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
-            /* Check this */
            openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
                qdev_get_gpio_in(dev, PPC970_INPUT_HRESET);
            break;
-#endif /* defined(TARGET_PPC64) */
+#endif
        default:
            error_report("Bus model not supported on mac99 machine");
            exit(1);
@@ -305,47 +313,37 @@ static void ppc_core99_init(MachineState *machine)
    if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
        machine_arch = ARCH_MAC99_U3;
        /* 970 gets a U3 bus */
-        /* Uninorth AGP bus */
        uninorth_pci_dev = qdev_new(TYPE_U3_AGP_HOST_BRIDGE);
        s = SYS_BUS_DEVICE(uninorth_pci_dev);
        sysbus_realize_and_unref(s, &error_fatal);
        sysbus_mmio_map(s, 0, 0xf0800000);
        sysbus_mmio_map(s, 1, 0xf0c00000);
-        /* PCI hole */
        memory_region_add_subregion(get_system_memory(), 0x80000000,
                                    sysbus_mmio_get_region(s, 2));
-        /* Register 8 MB of ISA IO space */
        memory_region_add_subregion(get_system_memory(), 0xf2000000,
                                    sysbus_mmio_get_region(s, 3));
    } else {
        machine_arch = ARCH_MAC99;
-        /* Use values found on a real PowerMac */
-        /* Uninorth AGP bus */
        uninorth_agp_dev = qdev_new(TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
        s = SYS_BUS_DEVICE(uninorth_agp_dev);
        sysbus_realize_and_unref(s, &error_fatal);
        sysbus_mmio_map(s, 0, 0xf0800000);
        sysbus_mmio_map(s, 1, 0xf0c00000);

-        /* Uninorth internal bus */
-        uninorth_internal_dev = qdev_new(
-                                TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
+        uninorth_internal_dev = 
qdev_new(TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
        s = SYS_BUS_DEVICE(uninorth_internal_dev);
        sysbus_realize_and_unref(s, &error_fatal);
        sysbus_mmio_map(s, 0, 0xf4800000);
        sysbus_mmio_map(s, 1, 0xf4c00000);

-        /* Uninorth main bus - this must be last to make it the default */
        uninorth_pci_dev = qdev_new(TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
        qdev_prop_set_uint32(uninorth_pci_dev, "ofw-addr", 0xf2000000);
        s = SYS_BUS_DEVICE(uninorth_pci_dev);
        sysbus_realize_and_unref(s, &error_fatal);
        sysbus_mmio_map(s, 0, 0xf2800000);
        sysbus_mmio_map(s, 1, 0xf2c00000);
-        /* PCI hole */
        memory_region_add_subregion(get_system_memory(), 0x80000000,
                                    sysbus_mmio_get_region(s, 2));
-        /* Register 8 MB of ISA IO space */
        memory_region_add_subregion(get_system_memory(), 0xf2000000,
                                    sysbus_mmio_get_region(s, 3));
    }
@@ -355,7 +353,6 @@ static void ppc_core99_init(MachineState *machine)
    has_adb = (core99_machine->via_config == CORE99_VIA_CONFIG_CUDA ||
               core99_machine->via_config == CORE99_VIA_CONFIG_PMU_ADB);

-    /* init basic PC hardware */
    pci_bus = PCI_HOST_BRIDGE(uninorth_pci_dev)->bus;

    /* MacIO */
@@ -369,13 +366,30 @@ static void ppc_core99_init(MachineState *machine)
    qdev_prop_set_chr(dev, "chrA", serial_hd(0));
    qdev_prop_set_chr(dev, "chrB", serial_hd(1));

+    pic_dev = DEVICE(object_resolve_path_component(macio, "pic"));
+    qdev_prop_set_uint32(pic_dev, "nb_cpus", machine->smp.cpus);
+
    pci_realize_and_unref(PCI_DEVICE(macio), pci_bus, &error_fatal);

-    pic_dev = DEVICE(object_resolve_path_component(macio, "pic"));
-    for (i = 0; i < 4; i++) {
-        qdev_connect_gpio_out(uninorth_pci_dev, i,
-                              qdev_get_gpio_in(pic_dev, 0x1b + i));
+    /* --- Connect GPIO reset IRQs for secondary CPUs --- */
+    s = SYS_BUS_DEVICE(object_resolve_path_component(macio, "gpio"));
+    if (machine->smp.cpus > 1) {
+        /* CPU1 reset: use GPIO 4 */
+        kick = qemu_allocate_irq(cpu_kick, cpus[1], 1);
+        sysbus_connect_irq(s, 4, kick);
+    }
+    if (machine->smp.cpus > 2) {
+        /* CPU2 reset: use GPIO 5 */
+        kick = qemu_allocate_irq(cpu_kick, cpus[2], 2);
+        sysbus_connect_irq(s, 5, kick);
    }
+    if (machine->smp.cpus > 3) {
+        /* CPU3 reset: use GPIO 6 */
+        kick = qemu_allocate_irq(cpu_kick, cpus[3], 3);
+        sysbus_connect_irq(s, 6, kick);
+    }
+
+

    /* TODO: additional PCI buses only wired up for 32-bit machines */
    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_970) {
@@ -384,7 +398,6 @@ static void ppc_core99_init(MachineState *machine)
            qdev_connect_gpio_out(uninorth_agp_dev, i,
                                  qdev_get_gpio_in(pic_dev, 0x1b + i));
        }
-
        /* Uninorth internal bus */
        for (i = 0; i < 4; i++) {
            qdev_connect_gpio_out(uninorth_internal_dev, i,
@@ -402,12 +415,10 @@ static void ppc_core99_init(MachineState *machine)
    }
    g_free(openpic_irqs);

-    /* We only emulate 2 out of 3 IDE controllers for now */
+    /* IDE controllers */
    ide_drive_get(hd, ARRAY_SIZE(hd));
-
    macio_ide = MACIO_IDE(object_resolve_path_component(macio, "ide[0]"));
    macio_ide_init_drives(macio_ide, hd);
-
    macio_ide = MACIO_IDE(object_resolve_path_component(macio, "ide[1]"));
    macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]);

@@ -417,23 +428,18 @@ static void ppc_core99_init(MachineState *machine)
        } else {
            dev = DEVICE(object_resolve_path_component(macio, "cuda"));
        }
-
        adb_bus = qdev_get_child_bus(dev, "adb.0");
        dev = qdev_new(TYPE_ADB_KEYBOARD);
        qdev_realize_and_unref(dev, adb_bus, &error_fatal);
-
        dev = qdev_new(TYPE_ADB_MOUSE);
        qdev_realize_and_unref(dev, adb_bus, &error_fatal);
    }

    if (machine->usb) {
        pci_create_simple(pci_bus, -1, "pci-ohci");
-
-        /* U3 needs to use USB for input because Linux doesn't support via-cuda
-        on PPC64 */
+        /* U3 needs to use USB for input because Linux doesn't support 
via-cuda on PPC64 */
        if (!has_adb || machine_arch == ARCH_MAC99_U3) {
            USBBus *usb_bus;
-
            usb_bus = USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS,
                                                              &error_abort));
            usb_create_simple(usb_bus, "usb-kbd");
@@ -451,8 +457,6 @@ static void ppc_core99_init(MachineState *machine)

    /* The NewWorld NVRAM is not located in the MacIO device */
    if (kvm_enabled() && qemu_real_host_page_size() > 4096) {
-        /* We can't combine read-write and read-only in a single page, so
-           move the NVRAM out of ROM again for KVM */
        nvram_addr = 0xFFE00000;
    }
    dev = qdev_new(TYPE_MACIO_NVRAM);
@@ -462,7 +466,6 @@ static void ppc_core99_init(MachineState *machine)
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, nvram_addr);
    nvr = MACIO_NVRAM(dev);
    pmac_format_nvram_partition(nvr, MACIO_NVRAM_SIZE);
-    /* No PCI init: the BIOS will do it */

    dev = qdev_new(TYPE_FW_CFG_MEM);
    fw_cfg = FW_CFG(dev);
@@ -500,24 +503,20 @@ static void ppc_core99_init(MachineState *machine)
    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
    if (kvm_enabled()) {
        uint8_t *hypercall;
-
        hypercall = g_malloc(16);
        kvmppc_get_hypercall(env, hypercall, 16);
        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
    }
    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, tbfreq);
-    /* Mac OS X requires a "known good" clock-frequency value; pass it one. */
    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, CLOCKFREQ);
    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_BUSFREQ, BUSFREQ);
    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_NVRAM_ADDR, nvram_addr);

-    /* MacOS NDRV VGA driver */
    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME);
    if (filename) {
        gchar *ndrv_file;
        gsize ndrv_size;
-
        if (g_file_get_contents(filename, &ndrv_file, &ndrv_size, NULL)) {
            fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size);
        }
@@ -576,7 +575,7 @@ static void core99_machine_class_init(ObjectClass *oc, void 
*data)
    mc->init = ppc_core99_init;
    mc->block_default_type = IF_IDE;
    /* SMP is not supported currently */
-    mc->max_cpus = 1;
+    mc->max_cpus = 4;
    mc->default_boot_order = "cd";
    mc->default_display = "std";
    mc->default_nic = "sungem";
diff --git a/include/hw/misc/macio/gpio.h b/include/hw/misc/macio/gpio.h
index 7d2aa886c2..139d505617 100644
--- a/include/hw/misc/macio/gpio.h
+++ b/include/hw/misc/macio/gpio.h
@@ -30,6 +30,19 @@
#include "hw/sysbus.h"
#include "qom/object.h"

+/* Linux/KeyLargo definitions for GPIO reset and extint lines */
+#define KEYLARGO_GPIO_EXTINT_0        0x58
+#define KEYLARGO_GPIO_0               0x50   /* if needed for extint 
calculations */
+
+#define KL_GPIO_EXTINT_CPU1           (KEYLARGO_GPIO_0 + 0x0a)
+#define KL_GPIO_EXTINT_CPU1_ASSERT    0x04
+#define KL_GPIO_EXTINT_CPU1_RELEASE   0x38
+
+#define KL_GPIO_RESET_CPU0            (KEYLARGO_GPIO_EXTINT_0 + 0x03)
+#define KL_GPIO_RESET_CPU1            (KEYLARGO_GPIO_EXTINT_0 + 0x04)
+#define KL_GPIO_RESET_CPU2            (KEYLARGO_GPIO_EXTINT_0 + 0x0f)
+#define KL_GPIO_RESET_CPU3            (KEYLARGO_GPIO_EXTINT_0 + 0x10)
+
#define TYPE_MACIO_GPIO "macio-gpio"
OBJECT_DECLARE_SIMPLE_TYPE(MacIOGPIOState, MACIO_GPIO)



On Mar 29, 2025, at 6:41 PM, BALATON Zoltan <balaton@eik.bme.hu> wrote:

On Sat, 29 Mar 2025, Jd Lyons wrote:
I made some patches and got all four cores working in Mac OS X Triger, but I 
broke KB/Mouse input???

diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 78a82d0d30..eca8866b95 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -50,7 +50,7 @@
#ifdef DEBUG_OPENPIC
static const int debug_openpic = 1;
#else
-static const int debug_openpic = 0;
+static const int debug_openpic = 1;
#endif

static int get_current_cpu(void);
@@ -1580,12 +1580,12 @@ static void openpic_realize(DeviceState *dev, Error 
**errp)
       opp->irq_tim0 = KEYLARGO_TMR_IRQ;
       opp->brr1 = -1;
       opp->mpic_mode_mask = GCR_MODE_MIXED;
-
+#if 0
       if (opp->nb_cpus != 1) {
           error_setg(errp, "Only UP supported today");
           return;
       }
-
+#endif
       map_list(opp, list_le, &list_count);
       break;
   }
diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c
index e87bfca1f5..b0df44bced 100644
--- a/hw/misc/macio/gpio.c
+++ b/hw/misc/macio/gpio.c
@@ -56,18 +56,13 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool 
state)
       new_reg |= IN_DATA;
   }

-    if (new_reg == s->gpio_regs[gpio]) {
+    /* For GPIOs 4, 5, and 6 (reset lines), always update so we can 
assert/deassert */
+    if ((gpio != 4) && (gpio != 5) && (gpio != 6) && (new_reg == 
s->gpio_regs[gpio])) {

I don't think any of these changes to this function are needed. Revert them.

       return;
   }

-    s->gpio_regs[gpio] = new_reg;

-    /*
-     * Note that we probably need to get access to the MPIC config to
-     * decode polarity since qemu always use "raise" regardless.
-     *
-     * For now, we hard wire known GPIOs
-     */
+    s->gpio_regs[gpio] = new_reg;

   switch (gpio) {
   case 1:
@@ -81,6 +76,39 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool 
state)
       }
       break;

+    case 4:
+        /* Active low, CPU1 reset */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
+    case 5:
+        /* Active low, CPU2 reset */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;
+
+    case 6:
+        /* Active low, CPU3 reset */
+        if (!state) {
+            trace_macio_gpio_irq_assert(gpio);
+            qemu_irq_raise(s->gpio_extirqs[gpio]);
+        } else {
+            trace_macio_gpio_irq_deassert(gpio);
+            qemu_irq_lower(s->gpio_extirqs[gpio]);
+        }
+        break;

Are case 4 and case 6 correct? Aren't these at some higher GPIO numbers or did 
you add corresponding soft-reset properties to point to these GPIOs? I think 
the defaults in Linux don't match these so maybe we should match the defaults 
in Linux.

+
   case 9:
       /* Edge, triggered by NMI below */
       if (state) {
@@ -97,6 +125,8 @@ void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool 
state)
   }
}

+
+
static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
                            unsigned size)
{
@@ -105,12 +135,12 @@ static void macio_gpio_write(void *opaque, hwaddr addr, 
uint64_t value,

   trace_macio_gpio_write(addr, value);

-    /* Levels regs are read-only */
+    /* Level registers are read-only */
   if (addr < 8) {
       return;
   }

-    addr -= 8;
+    addr -= 8;  /* Adjust: first 8 bytes are level regs */
   if (addr < 36) {
       value &= ~IN_DATA;

@@ -120,7 +150,21 @@ static void macio_gpio_write(void *opaque, hwaddr addr, 
uint64_t value,
           ibit = s->gpio_regs[addr] & IN_DATA;
       }

-        s->gpio_regs[addr] = value | ibit;
+        if (addr == 4) {
+            /* MMIO offset 0x0C (0xC - 8 = 4): route to GPIO 4 */
+            if (!(value & OUT_ENABLE)) {
+                ibit = 1; /* high unless driven low */
+            }
+            macio_set_gpio(s, 4, ibit);
+        } else if (addr == 0x0F) {
+            /* MMIO offset 0x17 (0x17 - 8 = 0x0F): route to GPIO 5 */
+            macio_set_gpio(s, 5, ibit);
+        } else if (addr == 0x10) {

And the addresses here also don't match, these should not be setting 5 and 6 
but the corresponding GPIO lines which I think would be 15 and 16 according 
these addresses. You also need the pull up to 1 value if not set to output for 
those lines too. You could do this in the single if without separate else if 
branches, just use addr as parameter to mmio_set_gpio and add those addresses 
to the if condition with ||. E.g.
addr == 4 || addr == 15...

+            /* MMIO offset 0x18 (0x18 - 8 = 0x10): route to GPIO 6 */
+            macio_set_gpio(s, 6, ibit);
+        } else {
+            s->gpio_regs[addr] = value | ibit;
+        }
   }
}

@@ -186,6 +230,7 @@ static void macio_gpio_reset(DeviceState *dev)

   /* GPIO 1 is up by default */
   macio_set_gpio(s, 1, true);
+    macio_set_gpio(s, 4, true);

You'd also need to set default to high for the other two reset lines here, 
otherwise it would reset the CPU on start up.

}

static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index 0d82e5a128..3ef53d26ca 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -46,7 +46,7 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr,
   MacIONVRAMState *s = opaque;

   addr = (addr >> s->it_shift) & (s->size - 1);
-    trace_macio_nvram_write(addr, value);
+//    trace_macio_nvram_write(addr, value);
   s->data[addr] = value;
   if (s->blk) {
       if (blk_pwrite(s->blk, addr, 1, &s->data[addr], 0) < 0) {
@@ -64,7 +64,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,

   addr = (addr >> s->it_shift) & (s->size - 1);
   value = s->data[addr];
-    trace_macio_nvram_read(addr, value);
+//    trace_macio_nvram_read(addr, value);

   return value;
}
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index cb3dc3ab48..6bcbd392f5 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -73,6 +73,7 @@
#include "kvm_ppc.h"
#include "hw/usb.h"
#include "hw/sysbus.h"
+#include "hw/irq.h"
#include "trace.h"

#define MAX_IDE_BUS 2
@@ -128,12 +129,26 @@ static void ppc_core99_reset(void *opaque)
   cpu->env.nip = PROM_BASE + 0x100;
}

+static void cpu_kick(void *opaque, int n, int level)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+
+
+    if (level) {
+        cpu->env.excp_prefix = 0;
+        cpu_reset(cs);
+        ppc_cpu_do_system_reset(cs);
+    }
+}
+
/* PowerPC Mac99 hardware initialisation */
static void ppc_core99_init(MachineState *machine)
{
   Core99MachineState *core99_machine = CORE99_MACHINE(machine);
   MachineClass *mc = MACHINE_GET_CLASS(machine);
-    PowerPCCPU *cpu = NULL;
+    qemu_irq kick;
+    PowerPCCPU **cpus = NULL;
   CPUPPCState *env = NULL;
   char *filename;
   IrqLines *openpic_irqs;
@@ -157,14 +172,18 @@ static void ppc_core99_init(MachineState *machine)
   uint64_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TBFREQ;

   /* init CPUs */
+    cpus = g_new0(PowerPCCPU *, machine->smp.cpus);
   for (i = 0; i < machine->smp.cpus; i++) {
-        cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
-        env = &cpu->env;
-
+        cpus[i] = POWERPC_CPU(cpu_create(machine->cpu_type));
+fprintf(stderr, "cpus[%d] = %p %p\n", i, (void *)cpus[i], (void 
*)&cpus[i]->env);
+        /* Secondary CPUs start halted */
+        object_property_set_bool(OBJECT(cpus[i]), "start-powered-off", i != 0,
+                                 &error_abort);
       /* Set time-base frequency to 100 Mhz */
-        cpu_ppc_tb_init(env, TBFREQ);
-        qemu_register_reset(ppc_core99_reset, cpu);
+        cpu_ppc_tb_init(&cpus[i]->env, TBFREQ);
+        qemu_register_reset(ppc_core99_reset, cpus[i]);
   }
+    env = &cpus[0]->env;

   /* allocate RAM */
   if (machine->ram_size > 2 * GiB) {
@@ -256,8 +275,8 @@ static void ppc_core99_init(MachineState *machine)
   }

   openpic_irqs = g_new0(IrqLines, machine->smp.cpus);
-    dev = DEVICE(cpu);
   for (i = 0; i < machine->smp.cpus; i++) {
+        dev = DEVICE(cpus[i]);
       /* Mac99 IRQ connection between OpenPIC outputs pins
        * and PowerPC input pins
        */
@@ -369,13 +388,29 @@ static void ppc_core99_init(MachineState *machine)
   qdev_prop_set_chr(dev, "chrA", serial_hd(0));
   qdev_prop_set_chr(dev, "chrB", serial_hd(1));

+    pic_dev = DEVICE(object_resolve_path_component(macio, "pic"));
+    qdev_prop_set_uint32(pic_dev, "nb_cpus", machine->smp.cpus);
+
   pci_realize_and_unref(PCI_DEVICE(macio), pci_bus, &error_fatal);

-    pic_dev = DEVICE(object_resolve_path_component(macio, "pic"));
-    for (i = 0; i < 4; i++) {
-        qdev_connect_gpio_out(uninorth_pci_dev, i,
-                              qdev_get_gpio_in(pic_dev, 0x1b + i));
+    s = SYS_BUS_DEVICE(object_resolve_path_component(macio, "gpio"));
+    if (machine->smp.cpus > 1) {
+        /* CPU1 reset: use GPIO 4 */
+        kick = qemu_allocate_irq(cpu_kick, cpus[1], 1);
+        sysbus_connect_irq(s, 4, kick);
+    }
+    if (machine->smp.cpus > 2) {
+        /* CPU2 reset: use GPIO 5 */
+        kick = qemu_allocate_irq(cpu_kick, cpus[2], 2);
+        sysbus_connect_irq(s, 5, kick);
   }
+    if (machine->smp.cpus > 3) {
+        /* CPU3 reset: use GPIO 6 */
+        kick = qemu_allocate_irq(cpu_kick, cpus[3], 3);
+        sysbus_connect_irq(s, 6, kick);

There must be a better way to do this. Maybe put the lines in an array such as 
int reset_lines[] = {3, 4, 15, 16}; then connect to those gpio lines in the 
loop without these ifs.

+    }
+
+

   /* TODO: additional PCI buses only wired up for 32-bit machines */
   if (PPC_INPUT(env) != PPC_FLAGS_INPUT_970) {
@@ -576,7 +611,7 @@ static void core99_machine_class_init(ObjectClass *oc, void 
*data)
   mc->init = ppc_core99_init;
   mc->block_default_type = IF_IDE;
   /* SMP is not supported currently */
-    mc->max_cpus = 1;
+    mc->max_cpus = 8;

This cannot be more than 4.

Regards,
BALATON Zoltan


reply via email to

[Prev in Thread] Current Thread [Next in Thread]