@samitouri / QOSamiQemu / commits / a2f775037e

ppc/mpipl: Implement S0 SBE interrupt

During MPIPL (aka fadump), after a kernel crash, the kernel does opal_cec_reboot2 opal call, signifying an abnormal termination. When OPAL receives this opal call, it further triggers SBE S0 interrupt, to trigger a MPIPL boot. Currently S0 interrupt is unimplemented in QEMU. Implement S0 interrupt as 'pause_vcpus' + 'guest_reset' in QEMU, as the SBE's implementation of S0 seems to be basically "stop all clocks" and then "host reset". pause_vcpus is done in a later patch when register preserving support is added See 'stopClocksS0' in SBE source code for more information. Also log both S0 and S1 interrupts. Reviewed-by: Hari Bathini <hbathini@linux.ibm.com> Reviewed-by: Sourabh Jain <sourabhjain@linux.ibm.com> Signed-off-by: Aditya Gupta <adityag@linux.ibm.com> Tested-by: Shivang Upadhyay <shivangu@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20260424083837.214947-3-adityag@linux.ibm.com Signed-off-by: Harsh Prateek Bora <harshpb@linux.ibm.com>

Aditya Gupta committed Apr 24, 2026 at 14:08 UTC a2f775037e5c59a93212127b255aae28f3d9196e
5 files changed +80
hw/ppc/meson.build
+1
@@ -56,6 +56,7 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
56 'pnv_pnor.c',
57 'pnv_nest_pervasive.c',
58 'pnv_n1_chiplet.c',
59 + 'pnv_mpipl.c',
60 ))
61 # PowerPC 4xx boards
62 ppc_ss.add(when: 'CONFIG_PPC405', if_true: files(
hw/ppc/pnv_mpipl.c new
+26
@@ -0,0 +1,26 @@
1 +/*
2 + * Emulation of MPIPL (Memory Preserving Initial Program Load), aka fadump
3 + *
4 + * SPDX-License-Identifier: GPL-2.0-or-later
5 + */
6 +
7 +#include "qemu/osdep.h"
8 +#include "system/runstate.h"
9 +#include "hw/ppc/pnv.h"
10 +#include "hw/ppc/pnv_mpipl.h"
11 +
12 +void do_mpipl_preserve(PnvMachineState *pnv)
13 +{
14 + /* Mark next boot as Memory-preserving boot */
15 + pnv->mpipl_state.is_next_boot_mpipl = true;
16 +
17 + /*
18 + * Do a guest reset.
19 + * Next reset will see 'is_next_boot_mpipl' as true, and trigger MPIPL
20 + *
21 + * Requirement:
22 + * GUEST_RESET is expected to NOT clear the memory, as is the case when
23 + * this is merged
24 + */
25 + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
26 +}
hw/ppc/pnv_sbe.c
+29
@@ -26,6 +26,9 @@
26 #include "hw/ppc/pnv.h"
27 #include "hw/ppc/pnv_xscom.h"
28 #include "hw/ppc/pnv_sbe.h"
29 +#include "hw/ppc/pnv_mpipl.h"
30 +#include "system/cpus.h"
31 +#include "system/runstate.h"
32 #include "trace.h"
33
34 /*
@@ -113,11 +116,37 @@ static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr,
116 static void pnv_sbe_power9_xscom_ctrl_write(void *opaque, hwaddr addr,
117 uint64_t val, unsigned size)
118 {
119 + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
120 + PnvSBE *sbe = opaque;
121 uint32_t offset = addr >> 3;
122
123 trace_pnv_sbe_xscom_ctrl_write(addr, val);
124
125 switch (offset) {
126 + case SBE_CONTROL_REG_RW:
127 + switch (val) {
128 + case SBE_CONTROL_REG_S0:
129 + qemu_log_mask(LOG_UNIMP, "SBE: S0 Interrupt triggered\n");
130 +
131 + pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_RESPONSE_MASK);
132 +
133 + /* Preserve memory regions and CPU state, if MPIPL is registered */
134 + do_mpipl_preserve(pnv);
135 +
136 + /*
137 + * Control may not come back here as 'do_mpipl_preserve' triggers
138 + * a guest reboot
139 + */
140 + break;
141 + case SBE_CONTROL_REG_S1:
142 + qemu_log_mask(LOG_UNIMP, "SBE: S1 Interrupt triggered\n");
143 + break;
144 + default:
145 + qemu_log_mask(LOG_UNIMP,
146 + "SBE: CONTROL_REG_RW: Unknown value: Ox%."
147 + HWADDR_PRIx "\n", val);
148 + }
149 + break;
150 default:
151 qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
152 HWADDR_PRIx "\n", addr >> 3);
include/hw/ppc/pnv.h
+5
@@ -25,6 +25,7 @@
25 #include "hw/core/sysbus.h"
26 #include "hw/ipmi/ipmi.h"
27 #include "hw/ppc/pnv_pnor.h"
28 +#include "hw/ppc/pnv_mpipl.h"
29
30 #define TYPE_PNV_CHIP "pnv-chip"
31
@@ -113,6 +114,7 @@ struct PnvMachineState {
114 bool lpar_per_core;
115
116 Notifier machine_init_done;
117 + MpiplPreservedState mpipl_state;
118 };
119
120 PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
@@ -292,4 +294,7 @@ void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor);
294
295 #define PNV11_OCC_SENSOR_BASE(chip) PNV10_OCC_SENSOR_BASE(chip)
296
297 +/* MPIPL helpers */
298 +void do_mpipl_preserve(PnvMachineState *pnv);
299 +
300 #endif /* PPC_PNV_H */
include/hw/ppc/pnv_mpipl.h new
+19
@@ -0,0 +1,19 @@
1 +/*
2 + * Emulation of MPIPL (Memory Preserving Initial Program Load), aka fadump
3 + *
4 + * SPDX-License-Identifier: GPL-2.0-or-later
5 + */
6 +
7 +#ifndef PNV_MPIPL_H
8 +#define PNV_MPIPL_H
9 +
10 +#include <stdbool.h>
11 +
12 +typedef struct MpiplPreservedState MpiplPreservedState;
13 +
14 +/* Preserved state to be saved in PnvMachineState */
15 +struct MpiplPreservedState {
16 + bool is_next_boot_mpipl;
17 +};
18 +
19 +#endif