diff mbox

ppc/spapr: implement H_SIGNAL_SYS_RESET

Message ID 20161205035647.17406-1-npiggin@gmail.com
State New
Headers show

Commit Message

Nicholas Piggin Dec. 5, 2016, 3:56 a.m. UTC
The H_SIGNAL_SYS_RESET hcall allows a guest CPU to raise a system reset
exception on CPUs within the same guest -- all CPUs, all-but-self, or a
specific CPU (including self).

This has not made its way to a PAPR release yet, but we have an hcall
number assigned.

  H_SIGNAL_SYS_RESET = 0x380

  Syntax:
    hcall(uint64 H_SIGNAL_SYS_RESET, int64 target);

  Generate a system reset NMI on the threads indicated by target.

  Values for target:
    -1 = target all online threads including the caller
    -2 = target all online threads except for the caller
    All other negative values: reserved
    Positive values: The thread to be targeted, obtained from the value
    of the "ibm,ppc-interrupt-server#s" property of the CPU in the OF
    device tree.

  Semantics:
    - Invalid target: return H_Parameter.
    - Otherwise: Generate a system reset NMI on target thread(s),
      return H_Success.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
Hi,

I have taken into account feedback since last posting, the comments
were appreciated.

  http://lists.nongnu.org/archive/html/qemu-devel/2016-10/msg04881.html

- Improved changelog description.
- Shared code with QEMU NMI injection.
- Move hcall-specific parameter definitions out of header.
- Added an "unofficial" PAPR specification to changelog.

There is interest to improve the community process with PAPR
development, but I can't say if/when/how, so this is the best I can do.

* Some additional background information follows *

The Linux powerpc branch has a corresponding change to add this hcall
definition:

  https://git.kernel.org/cgit/linux/kernel/git/powerpc/linux.git/commit/?h=next&id=53ce299615e587e900548eb6b384c3081b71bbfa

The motivation is to allow a crash or debug event to pull stuck
(interrupts disabled) CPUs into the crash/debug handlers. This is in
response to a problem encountered in the wild on a customer machine.
Linux guest patches to that end were posted for review:

  https://lists.ozlabs.org/pipermail/linuxppc-dev/2016-November/150684.html

Additionally, there is ongoing firmware effort to provide a similar
service for non-virtualized environments:

  https://lists.ozlabs.org/pipermail/skiboot/2016-November/005481.html

Thanks,
Nick

 hw/ppc/spapr.c         |  4 ++--
 hw/ppc/spapr_hcall.c   | 41 +++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/spapr.h |  5 ++++-
 3 files changed, 47 insertions(+), 3 deletions(-)

Comments

David Gibson Dec. 5, 2016, 5:12 a.m. UTC | #1
On Mon, Dec 05, 2016 at 02:56:47PM +1100, Nicholas Piggin wrote:
> The H_SIGNAL_SYS_RESET hcall allows a guest CPU to raise a system reset
> exception on CPUs within the same guest -- all CPUs, all-but-self, or a
> specific CPU (including self).
> 
> This has not made its way to a PAPR release yet, but we have an hcall
> number assigned.
> 
>   H_SIGNAL_SYS_RESET = 0x380
> 
>   Syntax:
>     hcall(uint64 H_SIGNAL_SYS_RESET, int64 target);
> 
>   Generate a system reset NMI on the threads indicated by target.
> 
>   Values for target:
>     -1 = target all online threads including the caller
>     -2 = target all online threads except for the caller
>     All other negative values: reserved
>     Positive values: The thread to be targeted, obtained from the value
>     of the "ibm,ppc-interrupt-server#s" property of the CPU in the OF
>     device tree.
> 
>   Semantics:
>     - Invalid target: return H_Parameter.
>     - Otherwise: Generate a system reset NMI on target thread(s),
>       return H_Success.
> 
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>

This is much too late for qemu-2.8, so can you please rebase this onto
my ppc-for-2.9 branch - it doesn't apply clean there.

> ---
> Hi,
> 
> I have taken into account feedback since last posting, the comments
> were appreciated.
> 
>   http://lists.nongnu.org/archive/html/qemu-devel/2016-10/msg04881.html
> 
> - Improved changelog description.
> - Shared code with QEMU NMI injection.
> - Move hcall-specific parameter definitions out of header.
> - Added an "unofficial" PAPR specification to changelog.
> 
> There is interest to improve the community process with PAPR
> development, but I can't say if/when/how, so this is the best I can do.
> 
> * Some additional background information follows *
> 
> The Linux powerpc branch has a corresponding change to add this hcall
> definition:
> 
>   https://git.kernel.org/cgit/linux/kernel/git/powerpc/linux.git/commit/?h=next&id=53ce299615e587e900548eb6b384c3081b71bbfa
> 
> The motivation is to allow a crash or debug event to pull stuck
> (interrupts disabled) CPUs into the crash/debug handlers. This is in
> response to a problem encountered in the wild on a customer machine.
> Linux guest patches to that end were posted for review:
> 
>   https://lists.ozlabs.org/pipermail/linuxppc-dev/2016-November/150684.html
> 
> Additionally, there is ongoing firmware effort to provide a similar
> service for non-virtualized environments:
> 
>   https://lists.ozlabs.org/pipermail/skiboot/2016-November/005481.html
> 
> Thanks,
> Nick
> 
>  hw/ppc/spapr.c         |  4 ++--
>  hw/ppc/spapr_hcall.c   | 41 +++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/spapr.h |  5 ++++-
>  3 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 208ef7b..5d2adf8 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -2252,7 +2252,7 @@ static void spapr_machine_finalizefn(Object *obj)
>      g_free(spapr->kvm_type);
>  }
>  
> -static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
> +void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
>  {
>      cpu_synchronize_state(cs);
>      ppc_cpu_do_system_reset(cs);
> @@ -2263,7 +2263,7 @@ static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
>      CPUState *cs;
>  
>      CPU_FOREACH(cs) {
> -        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
> +        async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
>      }
>  }
>  
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 9a9bedf..b61ac9d 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -881,6 +881,46 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      return ret;
>  }
>  
> +#define H_SIGNAL_SYS_RESET_ALL         -1
> +#define H_SIGNAL_SYS_RESET_ALLBUTSELF  -2
> +
> +static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
> +                                       sPAPRMachineState *spapr,
> +                                       target_ulong opcode, target_ulong *args)
> +{
> +    target_long target = args[0];
> +    CPUState *cs;
> +
> +    if (target < 0) {
> +        /* Broadcast */
> +        if (target < H_SIGNAL_SYS_RESET_ALLBUTSELF) {
> +            return H_PARAMETER;
> +        }
> +
> +        CPU_FOREACH(cs) {
> +            PowerPCCPU *c = POWERPC_CPU(cs);
> +
> +            if (target == H_SIGNAL_SYS_RESET_ALLBUTSELF) {
> +                if (c == cpu) {
> +                    continue;
> +                }
> +            }
> +            run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
> +        }
> +        return H_SUCCESS;
> +
> +    } else {
> +        /* Unicast */
> +        CPU_FOREACH(cs) {
> +            if (cpu->cpu_dt_id == target) {
> +                run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
> +                return H_SUCCESS;
> +            }
> +        }
> +        return H_PARAMETER;
> +    }
> +}
> +
>  typedef struct {
>      uint32_t cpu_version;
>      Error *err;
> @@ -1101,6 +1141,7 @@ static void hypercall_register_types(void)
>      /* hcall-splpar */
>      spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
>      spapr_register_hypercall(H_CEDE, h_cede);
> +    spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
>  
>      /* processor register resource access h-calls */
>      spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0);
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index bd5bcf7..443c425 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -347,7 +347,8 @@ struct sPAPRMachineState {
>  #define H_XIRR_X                0x2FC
>  #define H_RANDOM                0x300
>  #define H_SET_MODE              0x31C
> -#define MAX_HCALL_OPCODE        H_SET_MODE
> +#define H_SIGNAL_SYS_RESET      0x380
> +#define MAX_HCALL_OPCODE        H_SIGNAL_SYS_RESET
>  
>  /* The hcalls above are standardized in PAPR and implemented by pHyp
>   * as well.
> @@ -662,4 +663,6 @@ int spapr_rng_populate_dt(void *fdt);
>  #define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020
>  #define SPAPR_LMB_FLAGS_RESERVED 0x00000080
>  
> +void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
> +
>  #endif /* HW_SPAPR_H */
diff mbox

Patch

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 208ef7b..5d2adf8 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2252,7 +2252,7 @@  static void spapr_machine_finalizefn(Object *obj)
     g_free(spapr->kvm_type);
 }
 
-static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
+void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg)
 {
     cpu_synchronize_state(cs);
     ppc_cpu_do_system_reset(cs);
@@ -2263,7 +2263,7 @@  static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
     CPUState *cs;
 
     CPU_FOREACH(cs) {
-        async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+        async_run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
     }
 }
 
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 9a9bedf..b61ac9d 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -881,6 +881,46 @@  static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     return ret;
 }
 
+#define H_SIGNAL_SYS_RESET_ALL         -1
+#define H_SIGNAL_SYS_RESET_ALLBUTSELF  -2
+
+static target_ulong h_signal_sys_reset(PowerPCCPU *cpu,
+                                       sPAPRMachineState *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_long target = args[0];
+    CPUState *cs;
+
+    if (target < 0) {
+        /* Broadcast */
+        if (target < H_SIGNAL_SYS_RESET_ALLBUTSELF) {
+            return H_PARAMETER;
+        }
+
+        CPU_FOREACH(cs) {
+            PowerPCCPU *c = POWERPC_CPU(cs);
+
+            if (target == H_SIGNAL_SYS_RESET_ALLBUTSELF) {
+                if (c == cpu) {
+                    continue;
+                }
+            }
+            run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
+        }
+        return H_SUCCESS;
+
+    } else {
+        /* Unicast */
+        CPU_FOREACH(cs) {
+            if (cpu->cpu_dt_id == target) {
+                run_on_cpu(cs, spapr_do_system_reset_on_cpu, RUN_ON_CPU_NULL);
+                return H_SUCCESS;
+            }
+        }
+        return H_PARAMETER;
+    }
+}
+
 typedef struct {
     uint32_t cpu_version;
     Error *err;
@@ -1101,6 +1141,7 @@  static void hypercall_register_types(void)
     /* hcall-splpar */
     spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
     spapr_register_hypercall(H_CEDE, h_cede);
+    spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
 
     /* processor register resource access h-calls */
     spapr_register_hypercall(H_SET_SPRG0, h_set_sprg0);
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index bd5bcf7..443c425 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -347,7 +347,8 @@  struct sPAPRMachineState {
 #define H_XIRR_X                0x2FC
 #define H_RANDOM                0x300
 #define H_SET_MODE              0x31C
-#define MAX_HCALL_OPCODE        H_SET_MODE
+#define H_SIGNAL_SYS_RESET      0x380
+#define MAX_HCALL_OPCODE        H_SIGNAL_SYS_RESET
 
 /* The hcalls above are standardized in PAPR and implemented by pHyp
  * as well.
@@ -662,4 +663,6 @@  int spapr_rng_populate_dt(void *fdt);
 #define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020
 #define SPAPR_LMB_FLAGS_RESERVED 0x00000080
 
+void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg);
+
 #endif /* HW_SPAPR_H */