qemu-ppc
[Top][All Lists]
Advanced

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

Re: OpenMPIC controller emulation in qemu ?


From: BALATON Zoltan
Subject: Re: OpenMPIC controller emulation in qemu ?
Date: Sat, 18 May 2024 00:25:49 +0200 (CEST)

On Sat, 18 May 2024, Andrew Randrianasulu wrote:
On Fri, May 17, 2024 at 11:34 PM BALATON Zoltan <balaton@eik.bme.hu> wrote:

On Fri, 17 May 2024, Andrew Randrianasulu wrote:
пт, 17 мая 2024 г., 22:49 BALATON Zoltan <balaton@eik.bme.hu>:

On Fri, 17 May 2024, Andrew Randrianasulu wrote:
пт, 17 мая 2024 г., 22:02 BALATON Zoltan <balaton@eik.bme.hu>:

On Fri, 17 May 2024, Andrew Randrianasulu wrote:
On Fri, May 17, 2024 at 9:01 PM Andrew Randrianasulu <
randrianasulu@gmail.com> wrote:



On Fri, May 17, 2024 at 8:55 PM BALATON Zoltan <balaton@eik.bme.hu>
wrote:

On Fri, 17 May 2024, Andrew Randrianasulu wrote:
I also tried to add  multiple cpu support in openbios qemu ppc
arch
like it
was done for sparc, but sparc just dump cpus in / of device tree?

so same trick ofc failed because I do not really know  forth so
no
idea
where  to put for() loop start :)

No Forth needed for that. The device tree is constucred in in
openbios/arch/ppc/qemu/init.c::arch_of_init(). You can try to put a
loop
around cpu->initfn(cpu); in this function, you still have the
number
of
CPUs in temp at that point so maybe something like:

for (int i = 0; i < temp; i++)
     cpu->initfn(cpu);

might work but I did not try it.


Thanks.


Right now I am trying to modify hw/intc/openpic.c

    case OPENPIC_MODEL_KEYLARGO:
        opp->nb_irqs = KEYLARGO_MAX_EXT + KEYLARGO_MAX_IPI;
// because  I think this is total number of IRQs, not just external
ones?

        opp->vid = VID_REVISION_1_2;
        opp->vir = VIR_GENERIC;

        opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
               ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
               (opp->vid << FRR_VID_SHIFT);
// for some reason  Linux mpic probe still thinks I have only one
CPU
?
see p. 390 of CPC 945 manual

I can't help with this as I have no idea about this Apple chip but I
still
think the CPC945 is a different chip not this one. Hope somebody can
chime
in and give some insight.

        opp->vector_mask = 0xFF;
        opp->tfrr_reset = 4160000;
        opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
        opp->idr_reset = 0;
        opp->max_irq = KEYLARGO_MAX_IRQ;
        opp->irq_ipi0 = KEYLARGO_IPI_IRQ;
        opp->irq_tim0 = KEYLARGO_TMR_IRQ;
        opp->brr1 = -1;
        opp->mpic_mode_mask = GCR_MODE_MIXED;

        for (i = KEYLARGO_MAX_EXT; i < KEYLARGO_MAX_IRQ; i++) {
        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
        opp->src[i].level = false;
    }
// here i tried to init IPI sources ....

        if (opp->nb_cpus != 1) {
            //error_setg(errp, "Only UP supported today");
            //return;
        }

        map_list(opp, list_le, &list_count);
        break;
    }


===========

with this patch to openbios

ample_1280x720_surfing_with_audio.mjpeg  smp_init_openbios.patch
bash-5.1$ cat /dev/shm/smp_init_openbios.patch
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c
index 253394c..2d39289 100644
--- a/arch/ppc/qemu/init.c
+++ b/arch/ppc/qemu/init.c
@@ -1073,13 +1073,17 @@ arch_of_init(void)
    push_str("reg");
    fword("property");

+    int i;
+    for (i= 0; i<temp; i++) {
+
    cpu = id_cpu();
    cpu->initfn(cpu);
    printk("CPU type %s\n", cpu->name);
-
-    snprintf(buf, sizeof(buf), "/cpus/%s", cpu->name);
+        snprintf(buf, sizeof(buf), "/cpus/%s@%i", cpu->name, i);

That's wrong. The @0 part should come from some property of the device
node, maybe reg? This is added in cpu_g4_init() which calls
cpu_add_pir_property() that reads SPR 1023 (PIR) and uses that as reg
property. The docs say:

"2.3.17 Processor Identification Register (PIR)

The PIR register is used to differentiate between individual
processors
in
a multiprocessor environment.

Note: The PIR is an optional register in the PowerPC Architecture and
may
be implemented differently (or not at all) in the design of each
processor. The user’s manual of a specific processor will describe the
func- tionality of the PIR, if it is implemented in that processor."

And the CPU manual says read this doc for more info so it's a circular
reference. It also says this can be written and defaults to 0 so I
think
something needs to set PIR to the CPU number. Maybe QEMU when creating
or
resetting the CPU should set PIR?

+    }
    ofmem_register(find_dev("/memory"), find_dev(buf));
    node_methods_init(buf);
+

#ifdef CONFIG_RTAS
    /* OldWorld Macs don't have an /rtas node. */
bash-5.1$

finnix kernel sees more cpus in device tree!

[    2.625299] device-tree: Duplicate name in /cpus, renamed to
"PowerPC,G4@0#1"
[    2.626218] device-tree: Duplicate name in /cpus, renamed to
"PowerPC,G4@0#2"
[    2.627226] device-tree: Duplicate name in /cpus, renamed to
"PowerPC,G4@0#3"

hm, well ..

but void ppc kernel crashes  right away :

bash-5.1$ /dev/shm/qemu-9.0.0/build/qemu-system-ppc -m 512 -M mac99
-smp
4
-nographic  -kernel /mnt/tmp/boot/vmlinux -append "console=ttyPZ0"
-bios
/dev/shm/openbios-qemu.elf

Booting Linux via __start() @ 0x01000000 ...
Hello World !
[    0.000000] Total memory = 512MB; using 1024kB for hash table
[    0.000000] Activating Kernel Userspace Execution Prevention
[    0.000000] Activating Kernel Userspace Access Protection
[    0.000000] Linux version 5.13.12_1 (voidlinux@voidlinux) (gcc
(GCC)
10.2.1 20201203, GNU ld (GNU Binutils) 2.35.1) #1 SMP Thu Aug 19
14:12:26
UTC 2021
[    0.000000] ioremap() called early from
pmac_feature_init+0xd4/0xad4.
Use early_ioremap() instead
[    0.000000] Found UniNorth memory controller & host bridge @
0xf8000000
revision: 0x07
[    0.000000] Mapped at 0xf73c0000
[    0.000000] ioremap() called early from
probe_one_macio+0x17c/0x2b4.
Use
early_ioremap() instead
[    0.000000] Found a Keylargo mac-io controller, rev: 0, mapped at
0x(ptrval)
[    0.000000] PowerMac motherboard: PowerMac G4 AGP Graphics
[    0.000000] ioremap() called early from udbg_scc_init+0x1e4/0x3f8.
Use
early_ioremap() instead
[    0.000000] boot stdout isn't a display !
[    0.000000] ioremap() called early from find_via_cuda+0xb4/0x404.
Use
early_ioremap() instead

This kernel seems to have some issues. Does it work on real machine?



no idea sadly, void ppc ceased to exist as project .....

It would help if you tested with something known to work on real machine
otherwise you might hit problems with the OS instead of missing
emulation
in QEMU and OpenBIOS parts which would make it more difficult to find
what's needed. So make sure the Linux distro you boot works on a real
dual
CPU Mac. Also according to

https://en.wikipedia.org/wiki/Power_Mac_G4#Graphite_model_variations

PowerMac3,1 did not exist with two CPUs, only later version but I don't
know what else was different between them. Maybe it needs some other
hardware not emulated in QEMU?


[    0.000000] Using PowerMac machine description
[    0.000000] printk: bootconsole [udbg0] enabled
[    0.000000] CPU maps initialized for 1 thread per core
[    0.000000] -----------------------------------------------------
[    0.000000] phys_mem_size     = 0x20000000
[    0.000000] dcache_bsize      = 0x20
[    0.000000] icache_bsize      = 0x20
[    0.000000] cpu_features      = 0x000000000501a00a
[    0.000000]   possible        = 0x00000000277de14a
[    0.000000]   always          = 0x0000000001000000
[    0.000000] cpu_user_features = 0x9c000001 0x00000000
[    0.000000] mmu_features      = 0x00000001
[    0.000000] Hash_size         = 0x100000
[    0.000000] Hash_mask         = 0x3fff
[    0.000000] -----------------------------------------------------
[    0.000000] ioremap() called early from
pmac_setup_arch+0x118/0x290.
Use
early_ioremap() instead
[    0.000000] ioremap() called early from
pmac_nvram_init+0x150/0x53c.
Use
early_ioremap() instead
[    0.000000] nvram: Checking bank 0...
[    0.000000] Invalid signature
[    0.000000] Invalid checksum
[    0.000000] nvram: gen0=0, gen1=0
[    0.000000] nvram: Active bank is: 0
[    0.000000] nvram: OF partition at 0xffffffff
[    0.000000] nvram: XP partition at 0xffffffff
[    0.000000] nvram: NR partition at 0xffffffff
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000000000000-0x000000001fffffff]
[    0.000000]   Normal   empty
[    0.000000]   HighMem  empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem
0x0000000000000000-0x000000001fffffff]
[    0.000000] Initmem setup node 0 [mem
0x0000000000000000-0x000000001fffffff]
[    0.000000] percpu: Embedded 22 pages/cpu s59884 r8192 d22036
u90112
[    0.000000] ------------[ cut here ]------------
[    0.000000] kernel BUG at arch/powerpc/kernel/smp.c:1107!

I guess you could get more info by finding this source line in the
corresponding kernel source.


yeah, line moved a bit but


https://elixir.bootlin.com/linux/latest/source/arch/powerpc/kernel/smp.c

1171 BUG_ON  in smp_prepare_boot_cpu

so I guess MP system really need some way to discriminate cpus ....

I've found these docs that might contain some info. Maybe not enough to
completely understand the issue but could help to show some direction:


https://www.kernel.org/doc/html//v5.9/devicetree/booting-without-of.html


======


  3. The /cpus/* nodes

So under /cpus, you are supposed to create a node for every CPU on the
machine. There is no specific restriction on the name of the CPU, though
it’s common to call it <architecture>,<core>. For example, Apple uses
PowerPC,G5 while IBM uses PowerPC,970FX. However, the Generic Names
convention suggests that it would be better to simply use ‘cpu’ for each
cpu node and use the compatible property to identify the specific cpu
core.

Required properties:


  -

  device_type : has to be “cpu”
  -

  reg : This is the physical CPU number, it’s a single 32-bit cell and is
  also used as-is as the unit number for constructing the unit name in
the
  full path. For example, with 2 CPUs, you would have the full path:

  /cpus/PowerPC,970FX@0
  /cpus/PowerPC,970FX@1


====

so ... some more work needed in openfirmware/openbios - thanks!

I think OpenBIOS would do the right thing if you only add the loop around
the CPU init function like this:

for (int i = 0; i < temp; i++) {
     cpu->initfn(cpu);
}

and set the SPR 1023 aka PIR to the CPU number in QEMU in the
qemu/hw/ppc/mac_newworld.c::ppc_core99_reset() function after it calls
cpu_reset. But don't know how to pass CPU number to that function, it
seems to be called for all CPUs and will run OpenBIOS on all CPUs. I'm not
sure that OpenBIOS is prepared for that so QEMU may need to do here what
the Linux doc says and put CPUs >= 1 in a sleep loop or do something with
that. So maybe it's more work in QEMU than OpenBIOS.


May be

So far modding hw/ppc/mac_newworld.c init  function so it reads in cpu  part

  /* init CPUs */
   for (i = 0; i < machine->smp.cpus; i++) {
       cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
       env = &cpu->env;
       CPUState *cs;
       cs = CPU(cpu);

       /* Set time-base frequency to 100 Mhz */
       cpu_ppc_tb_init(env, TBFREQ);
       qemu_register_reset(ppc_core99_reset, cpu);
       env->spr_cb[SPR_PIR].default_value = cs->cpu_index = i;

Hmm, if OpenBIOS only runs on CPU 0 then it will only execute mfspr r0,1023 on that CPU which should have 0 there. So maybe this is not enough and you also need to modify OpenBIOS to create device nodes for additional CPUs with increasing reg property. As a test maybe instead of the pir value add a static variable in cpu_add_pir_property() and increase that with each call so it would add reg 0,1,etc.

Regards,
BALATON Zoltan

reply via email to

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