[PATCH v3] powernv: boot OpenBSD on POWER9

Kirill A. Korinsky posted 1 patch 3 weeks, 2 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260702130152.89334-2-kirill@korins.ky
Maintainers: Nicholas Piggin <npiggin@gmail.com>, Aditya Gupta <adityag@linux.ibm.com>, Glenn Miles <milesg@linux.ibm.com>, Harsh Prateek Bora <harshpb@linux.ibm.com>, Chinmay Rath <rathc@linux.ibm.com>, Brad Smith <brad@comstyle.com>
There is a newer version of this series
hw/ppc/pnv_psi.c                       | 11 ++++--
target/ppc/mmu-book3s-v3.c             | 38 ++++++++++++++++---
tests/functional/ppc64/meson.build     |  2 +
tests/functional/ppc64/test_openbsd.py | 52 ++++++++++++++++++++++++++
4 files changed, 94 insertions(+), 9 deletions(-)
create mode 100755 tests/functional/ppc64/test_openbsd.py
[PATCH v3] powernv: boot OpenBSD on POWER9
Posted by Kirill A. Korinsky 3 weeks, 2 days ago
OpenBSD/powernv programs PTCR for LPID 0 with a partition
table size exponent one smaller than QEMU's existing ISA v3.0
interpretation. Try QEMU's existing PATS interpretation first,
then fall back to the OpenBSD LPID 0 form; nonzero LPIDs keep
the old behaviour.

The PSI model now exposes POWER9 IRQ level and pending status
registers, and keeps both updated while delivering through the
existing XIVE LSI source. This lets guests that select the
POWER9 PSI LSI IRQ method continue to receive LPC interrupts.

The blast radius is probably minimal: the partition table
fallback is limited to bare metal LPID 0 after the original
lookup fails, while the PSI change only touches POWER9 PSI
state and reuses the existing delivery path.

Signed-off-by: Kirill A. Korinsky <kirill@korins.ky>
---
 hw/ppc/pnv_psi.c                       | 11 ++++--
 target/ppc/mmu-book3s-v3.c             | 38 ++++++++++++++++---
 tests/functional/ppc64/meson.build     |  2 +
 tests/functional/ppc64/test_openbsd.py | 52 ++++++++++++++++++++++++++
 4 files changed, 94 insertions(+), 9 deletions(-)
 create mode 100755 tests/functional/ppc64/test_openbsd.py

diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index e8701c6100..39ec448f3c 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -688,6 +688,8 @@ static uint64_t pnv_psi_p9_mmio_read(void *opaque, hwaddr addr, unsigned size)
     case PSIHB9_ESB_CI_BASE:
     case PSIHB9_ESB_NOTIF_ADDR:
     case PSIHB9_IVT_OFFSET:
+    case PSIHB9_IRQ_LEVEL:
+    case PSIHB9_IRQ_STAT:
         val = psi->regs[reg];
         break;
     default:
@@ -818,17 +820,20 @@ static void pnv_psi_power9_set_irq(void *opaque, int irq, int state)
 {
     PnvPsi *psi = opaque;
     uint64_t irq_method = psi->regs[PSIHB_REG(PSIHB9_INTERRUPT_CONTROL)];
+    uint64_t irq_bit = PPC_BIT(irq);
 
     if (irq_method & PSIHB9_IRQ_METHOD) {
         qemu_log_mask(LOG_GUEST_ERROR, "PSI: LSI IRQ method no supported\n");
         return;
     }
 
-    /* Update LSI levels */
+    /* Update LSI levels and pending status */
     if (state) {
-        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= PPC_BIT(irq);
+        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] |= irq_bit;
+        psi->regs[PSIHB_REG(PSIHB9_IRQ_STAT)] |= irq_bit;
     } else {
-        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~PPC_BIT(irq);
+        psi->regs[PSIHB_REG(PSIHB9_IRQ_LEVEL)] &= ~irq_bit;
+        psi->regs[PSIHB_REG(PSIHB9_IRQ_STAT)] &= ~irq_bit;
     }
 
     qemu_set_irq(psi->qirqs[irq], state);
diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c
index 3865556310..36b0733b6a 100644
--- a/target/ppc/mmu-book3s-v3.c
+++ b/target/ppc/mmu-book3s-v3.c
@@ -23,25 +23,51 @@
 #include "mmu-hash64.h"
 #include "mmu-book3s-v3.h"
 
-bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
+#define PPC64_V3_PATE_SIZE 16 /* two 64-bit words */
+
+static bool ppc64_v3_get_pate_from_size(PowerPCCPU *cpu, target_ulong lpid,
+                                        ppc_v3_pate_t *entry,
+                                        uint64_t table_size)
 {
     uint64_t patb = cpu->env.spr[SPR_PTCR] & PTCR_PATB;
-    uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS;
+    uint64_t entries;
 
     /* Check if partition table is properly aligned */
-    if (patb & MAKE_64BIT_MASK(0, pats + 12)) {
+    if (patb & (table_size - 1)) {
         return false;
     }
 
     /* Calculate number of entries */
-    pats = 1ull << (pats + 12 - 4);
-    if (pats <= lpid) {
+    entries = table_size / PPC64_V3_PATE_SIZE;
+    if (entries <= lpid) {
         return false;
     }
 
     /* Grab entry */
-    patb += 16 * lpid;
+    patb += PPC64_V3_PATE_SIZE * lpid;
     entry->dw0 = ldq_phys(CPU(cpu)->as, patb);
     entry->dw1 = ldq_phys(CPU(cpu)->as, patb + 8);
     return true;
 }
+
+bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
+{
+    uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS;
+
+    /*
+     * Keep the existing ISA v3.0 PATS interpretation first.  OpenBSD/powernv
+     * computes the value written to PTCR as ffs(PATMEMSZ) - 12, which writes 5
+     * for its 64KiB LPID 0 partition table. If the existing interpretation
+     * fails, accept that form only for the bare metal LPID 0 table.
+     */
+    if (ppc64_v3_get_pate_from_size(cpu, lpid, entry, 1ull << (pats + 12))) {
+        return true;
+    }
+
+    if (lpid == 0) {
+        return ppc64_v3_get_pate_from_size(cpu, lpid, entry,
+                                           1ull << (pats + 11));
+    }
+
+    return false;
+}
diff --git a/tests/functional/ppc64/meson.build b/tests/functional/ppc64/meson.build
index f0f8ab8f61..cb3c745624 100644
--- a/tests/functional/ppc64/meson.build
+++ b/tests/functional/ppc64/meson.build
@@ -4,6 +4,7 @@ test_ppc64_timeouts = {
   'fadump' : 480,
   'hv' : 1000,
   'mac99' : 120,
+  'openbsd' : 240,
   'powernv' : 480,
   'pseries' : 480,
   'replay' : 210,
@@ -20,6 +21,7 @@ tests_ppc64_system_thorough = [
   'fadump',
   'hv',
   'mac99',
+  'openbsd',
   'powernv',
   'pseries',
   'replay',
diff --git a/tests/functional/ppc64/test_openbsd.py b/tests/functional/ppc64/test_openbsd.py
new file mode 100755
index 0000000000..bdbef6bf82
--- /dev/null
+++ b/tests/functional/ppc64/test_openbsd.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+#
+# Test that OpenBSD boots on a ppc powernv machine and reaches the installer.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+
+
+class OpenBSDPowerNV(QemuSystemTest):
+
+    ASSET_MINIROOT = Asset(
+        'https://kirill.korins.ky/pub/qemu-powerpc64-openbsd/miniroot79.img',
+        '7829e42b75d81cafd732038b9d63228b79c1f5828d8375872a4bb655e1d6b13c')
+
+    ASSET_BOOTKERNEL = Asset(
+        'https://kirill.korins.ky/pub/qemu-powerpc64-openbsd/pnor.BOOTKERNEL',
+        '397ce43ce61910e1a2c4f13d301f957e61513a9ec5371bc3e87d3095411fae7b')
+
+    def test_powernv9_openbsd_installer(self):
+        self.set_machine('powernv9')
+        self.require_accelerator('tcg')
+
+        miniroot_path = self.ASSET_MINIROOT.fetch()
+        bootkernel_path = self.ASSET_BOOTKERNEL.fetch()
+
+        self.vm.set_console()
+        self.vm.add_args('-cpu', 'power9',
+                         '-accel', 'tcg,thread=single',
+                         '-smp', '1,cores=1,threads=1',
+                         '-m', '2g',
+                         '-kernel', bootkernel_path,
+                         '-device',
+                         'ich9-ahci,id=sata0,bus=pcie.0,addr=0x0',
+                         '-drive',
+                         f'file={miniroot_path},format=raw,if=none,'
+                         'id=bootdisk,snapshot=on',
+                         '-device',
+                         'ide-hd,bus=sata0.0,unit=0,drive=bootdisk,'
+                         'bootindex=1')
+        self.vm.launch()
+
+        wait_for_console_pattern(self, 'OpenBSD 7.9 (RAMDISK)', 'panic:')
+        wait_for_console_pattern(
+            self,
+            '(I)nstall, (U)pgrade, (A)utoinstall or (S)hell?',
+            'panic:')
+
+
+if __name__ == '__main__':
+    QemuSystemTest.main()
-- 
2.54.0
Re: [PATCH v3] powernv: boot OpenBSD on POWER9
Posted by Aditya Gupta 3 weeks, 1 day ago
On 02/07/26 18:31, Kirill A. Korinsky wrote:

> <...snip...>
>
> +
> +bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
> +{
> +    uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS;
> +
> +    /*
> +     * Keep the existing ISA v3.0 PATS interpretation first.  OpenBSD/powernv
> +     * computes the value written to PTCR as ffs(PATMEMSZ) - 12, which writes 5
> +     * for its 64KiB LPID 0 partition table. If the existing interpretation
> +     * fails, accept that form only for the bare metal LPID 0 table.
> +     */
> +    if (ppc64_v3_get_pate_from_size(cpu, lpid, entry, 1ull << (pats + 12))) {
> +        return true;
> +    }
Thanks for the patch, though I still have a doubt here about PATS.
PowerISA says Partition Table Size=2^(12+PATS). But seems OpenBSD on PowerNV
populates PATS in such way that Partition Table Size=2^11 + PATS. Why does
OpenBSD populate PATS this way, or am I missing some document where 
Partition
Table Size was 2^(11+PATS) ?

Rest of the code looks good to me.


Thanks,
- Aditya G
Re: [PATCH v3] powernv: boot OpenBSD on POWER9
Posted by Kirill A. Korinsky 3 weeks, 1 day ago
On Fri, 03 Jul 2026 14:49:23 +0200,
Aditya Gupta <adityag@linux.ibm.com> wrote:
> 
> On 02/07/26 18:31, Kirill A. Korinsky wrote:
> 
> > <...snip...>
> > 
> > +
> > +bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
> > +{
> > +    uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS;
> > +
> > +    /*
> > +     * Keep the existing ISA v3.0 PATS interpretation first.  OpenBSD/powernv
> > +     * computes the value written to PTCR as ffs(PATMEMSZ) - 12, which writes 5
> > +     * for its 64KiB LPID 0 partition table. If the existing interpretation
> > +     * fails, accept that form only for the bare metal LPID 0 table.
> > +     */
> > +    if (ppc64_v3_get_pate_from_size(cpu, lpid, entry, 1ull << (pats + 12))) {
> > +        return true;
> > +    }
> Thanks for the patch, though I still have a doubt here about PATS.
> PowerISA says Partition Table Size=2^(12+PATS). But seems OpenBSD on PowerNV
> populates PATS in such way that Partition Table Size=2^11 + PATS. Why does
> OpenBSD populate PATS this way, or am I missing some document where
> Partition
> Table Size was 2^(11+PATS) ?
> 

I have no idea why OpenBSD does it but I see in powerpc64's pmap.c:

#define PATMEMSZ	(64 * 1024)
#define PATSIZE		(ffs(PATMEMSZ) - 12)

which was introduced by this commit:
https://github.com/openbsd/src/commit/dfe2a24332fd6769a7f9bb5806753189dae4d9c9

-- 
wbr, Kirill
Re: [PATCH v3] powernv: boot OpenBSD on POWER9
Posted by Shivang Upadhyay 2 weeks, 5 days ago
On Fri, 2026-07-03 at 15:06 +0200, Kirill A.Korinsky wrote:
> I have no idea why OpenBSD does it but I see in powerpc64's pmap.c:
> 
> #define PATMEMSZ	(64 * 1024)
> #define PATSIZE		(ffs(PATMEMSZ) - 12)
Hi,

This seems like a bug in openbsd to me.
PowerISAv3.1 under PTCR says,
	

	4:51 PATB  | Partition Table Base
	59:63 PATS | Partition Table Size=2^12+PATS , PATS≤24

I think the developer was perhaps wanted a LOG2 functions instead of
ffs (which is just LOG2, but 1-indexed). IMO, this should better
handled on OS side.

Thanks.

> 
> which was introduced by this commit:
> https://github.com/openbsd/src/commit/dfe2a24332fd6769a7f9bb5806753189dae4d9c9
> 
> --
Re: [PATCH v3] powernv: boot OpenBSD on POWER9
Posted by Kirill A. Korinsky 6 days, 14 hours ago
On Mon, 06 Jul 2026 10:36:57 +0200,
Shivang Upadhyay <shivangu@linux.ibm.com> wrote:
> 
> On Fri, 2026-07-03 at 15:06 +0200, Kirill A.Korinsky wrote:
> > I have no idea why OpenBSD does it but I see in powerpc64's pmap.c:
> > 
> > #define PATMEMSZ	(64 * 1024)
> > #define PATSIZE		(ffs(PATMEMSZ) - 12)
> Hi,
> 
> This seems like a bug in openbsd to me.
> PowerISAv3.1 under PTCR says,
> 	
> 
> 	4:51 PATB  | Partition Table Base
> 	59:63 PATS | Partition Table Size=2^12+PATS , PATS≤24
> 
> I think the developer was perhaps wanted a LOG2 functions instead of
> ffs (which is just LOG2, but 1-indexed). IMO, this should better
> handled on OS side.
> 

Thanks, OpenBSD was fixed:

https://marc.info/?l=openbsd-cvs&m=178436960888757&w=2

I'll send new version of original diff shortly.

-- 
wbr, Kirill

Re: [PATCH v3] powernv: boot OpenBSD on POWER9
Posted by Kirill A. Korinsky 2 weeks, 5 days ago
On Mon, 06 Jul 2026 10:36:57 +0200,
Shivang Upadhyay <shivangu@linux.ibm.com> wrote:
> 
> On Fri, 2026-07-03 at 15:06 +0200, Kirill A.Korinsky wrote:
> > I have no idea why OpenBSD does it but I see in powerpc64's pmap.c:
> > 
> > #define PATMEMSZ	(64 * 1024)
> > #define PATSIZE		(ffs(PATMEMSZ) - 12)
> Hi,
> 
> This seems like a bug in openbsd to me.
> PowerISAv3.1 under PTCR says,
> 	
> 
> 	4:51 PATB  | Partition Table Base
> 	59:63 PATS | Partition Table Size=2^12+PATS , PATS≤24
> 
> I think the developer was perhaps wanted a LOG2 functions instead of
> ffs (which is just LOG2, but 1-indexed). IMO, this should better
> handled on OS side.
> 
> Thanks.
>

I'd like to add Mark to the loop who is the author of that code.

> > 
> > which was introduced by this commit:
> > https://github.com/openbsd/src/commit/dfe2a24332fd6769a7f9bb5806753189dae4d9c9
> > 
> > --
> 

-- 
wbr, Kirill