diff mbox series

[5/5] ppc/pnv: Implement mce injection

Message ID 20200325144147.221875-6-npiggin@gmail.com
State New
Headers show
Series ppc: sreset and machine check injection | expand

Commit Message

Nicholas Piggin March 25, 2020, 2:41 p.m. UTC
This implements mce injection for pnv.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 hw/ppc/pnv.c             | 55 ++++++++++++++++++++++++++++++++++++++++
 target/ppc/cpu.h         |  1 +
 target/ppc/excp_helper.c | 12 +++++++++
 3 files changed, 68 insertions(+)

Comments

Cédric Le Goater March 25, 2020, 4:39 p.m. UTC | #1
On 3/25/20 3:41 PM, Nicholas Piggin wrote:
> This implements mce injection for pnv.

This would be the command to use ? 

(qemu) mce 0 0x100000 0x80 0xdeadbeef 1

> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
>  hw/ppc/pnv.c             | 55 ++++++++++++++++++++++++++++++++++++++++
>  target/ppc/cpu.h         |  1 +
>  target/ppc/excp_helper.c | 12 +++++++++
>  3 files changed, 68 insertions(+)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 671535ebe6..9c515bfeed 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -38,6 +38,7 @@
>  #include "hw/nmi.h"
>  #include "exec/address-spaces.h"
>  #include "qapi/visitor.h"
> +#include "qapi/qmp/qdict.h"
>  #include "monitor/monitor.h"
>  #include "hw/intc/intc.h"
>  #include "hw/ipmi/ipmi.h"
> @@ -1981,11 +1982,63 @@ static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
>      }
>  }
> 
> +typedef struct MCEInjectionParams {
> +    uint64_t srr1_mask;
> +    uint32_t dsisr;
> +    uint64_t dar;
> +    bool recovered;
> +} MCEInjectionParams;
> +
> +static void pnv_do_mce_on_cpu(CPUState *cs, run_on_cpu_data data)
> +{
> +    MCEInjectionParams *params = data.host_ptr;
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    CPUPPCState *env = &cpu->env;
> +    uint64_t srr1_mce_bits = PPC_BITMASK(42, 45) | PPC_BIT(36);
> +
> +    cpu_synchronize_state(cs);

I think this call is superfluous as we don't support any accelerators 
on this machine (but we might one day).
 
> +    ppc_cpu_do_machine_check(cs);
> +
> +    env->spr[SPR_SRR1] |= (params->srr1_mask & srr1_mce_bits);

Don't  we need to clear the previous settings like on spapr ? 

> +    if (params->dsisr) {
> +        env->spr[SPR_DSISR] = params->dsisr;
> +        env->spr[SPR_DAR] = params->dar;
> +    }
> +
> +    if (!params->recovered) {
> +        env->msr &= ~MSR_RI;
> +    }
> +}
> +
> +static void pnv_mce(MCEState *m, const QDict *qdict, Error **errp)
> +{
> +    int cpu_index = qdict_get_int(qdict, "cpu_index");
> +    uint64_t srr1_mask = qdict_get_int(qdict, "srr1_mask");
> +    uint32_t dsisr = qdict_get_int(qdict, "dsisr");
> +    uint64_t dar = qdict_get_int(qdict, "dar");
> +    bool recovered = qdict_get_int(qdict, "recovered");
> +    CPUState *cs;
> +
> +    cs = qemu_get_cpu(cpu_index);
> +
> +    if (cs != NULL) {
> +        MCEInjectionParams params = {
> +            .srr1_mask = srr1_mask,
> +            .dsisr = dsisr,
> +            .dar = dar,
> +            .recovered = recovered,
> +        };
> +
> +        run_on_cpu(cs, pnv_do_mce_on_cpu, RUN_ON_CPU_HOST_PTR(&params));
> +    }
> +}
> +
>  static void pnv_machine_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
>      InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
>      NMIClass *nc = NMI_CLASS(oc);
> +    MCEClass *mcec = MCE_CLASS(oc);
> 
>      mc->desc = "IBM PowerNV (Non-Virtualized)";
>      mc->init = pnv_init;
> @@ -2003,6 +2056,7 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
>      mc->default_ram_id = "pnv.ram";
>      ispc->print_info = pnv_pic_print_info;
>      nc->nmi_monitor_handler = pnv_nmi;
> +    mcec->mce_monitor_handler = pnv_mce;
> 
>      object_class_property_add_bool(oc, "hb-mode",
>                                     pnv_machine_get_hb, pnv_machine_set_hb,
> @@ -2067,6 +2121,7 @@ static const TypeInfo types[] = {
>          .interfaces = (InterfaceInfo[]) {
>              { TYPE_INTERRUPT_STATS_PROVIDER },
>              { TYPE_NMI },
> +            { TYPE_MCE },
>          },
>      },
>      {
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index f4a5304d43..9be27f59c5 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1221,6 +1221,7 @@ int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
>                                 int cpuid, void *opaque);
>  #ifndef CONFIG_USER_ONLY
>  void ppc_cpu_do_system_reset(CPUState *cs);
> +void ppc_cpu_do_machine_check(CPUState *cs);
>  void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
>  extern const VMStateDescription vmstate_ppc_cpu;
>  #endif
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 7f2b5899d3..81dd8b6f8e 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -279,6 +279,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              cs->halted = 1;
>              cpu_interrupt_exittb(cs);
>          }
> +        if (msr_pow) {
> +            /* indicate that we resumed from power save mode */
> +            msr |= 0x10000;

#define ? 

> +        }
>          if (env->msr_mask & MSR_HVB) {
>              /*
>               * ISA specifies HV, but can be delivered to guest with HV
> @@ -969,6 +973,14 @@ void ppc_cpu_do_system_reset(CPUState *cs)
>      powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
>  }
> 
> +void ppc_cpu_do_machine_check(CPUState *cs)
> +{
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    CPUPPCState *env = &cpu->env;
> +
> +    powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
> +}
> +
>  void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
>  {
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
>
Nicholas Piggin April 3, 2020, 8:07 a.m. UTC | #2
Cédric Le Goater's on March 26, 2020 2:39 am:
> On 3/25/20 3:41 PM, Nicholas Piggin wrote:
>> This implements mce injection for pnv.
> 
> This would be the command to use ? 
> 
> (qemu) mce 0 0x100000 0x80 0xdeadbeef 1
> 
>> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
>> ---
>>  hw/ppc/pnv.c             | 55 ++++++++++++++++++++++++++++++++++++++++
>>  target/ppc/cpu.h         |  1 +
>>  target/ppc/excp_helper.c | 12 +++++++++
>>  3 files changed, 68 insertions(+)
>> 
>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>> index 671535ebe6..9c515bfeed 100644
>> --- a/hw/ppc/pnv.c
>> +++ b/hw/ppc/pnv.c
>> @@ -38,6 +38,7 @@
>>  #include "hw/nmi.h"
>>  #include "exec/address-spaces.h"
>>  #include "qapi/visitor.h"
>> +#include "qapi/qmp/qdict.h"
>>  #include "monitor/monitor.h"
>>  #include "hw/intc/intc.h"
>>  #include "hw/ipmi/ipmi.h"
>> @@ -1981,11 +1982,63 @@ static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
>>      }
>>  }
>> 
>> +typedef struct MCEInjectionParams {
>> +    uint64_t srr1_mask;
>> +    uint32_t dsisr;
>> +    uint64_t dar;
>> +    bool recovered;
>> +} MCEInjectionParams;
>> +
>> +static void pnv_do_mce_on_cpu(CPUState *cs, run_on_cpu_data data)
>> +{
>> +    MCEInjectionParams *params = data.host_ptr;
>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
>> +    CPUPPCState *env = &cpu->env;
>> +    uint64_t srr1_mce_bits = PPC_BITMASK(42, 45) | PPC_BIT(36);
>> +
>> +    cpu_synchronize_state(cs);
> 
> I think this call is superfluous as we don't support any accelerators 
> on this machine (but we might one day).

Okay. I can remove it, or do you think it's fine to stay?

>> +    ppc_cpu_do_machine_check(cs);
>> +
>> +    env->spr[SPR_SRR1] |= (params->srr1_mask & srr1_mce_bits);
> 
> Don't  we need to clear the previous settings like on spapr ? 

Yes, good catch.

>> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
>> index 7f2b5899d3..81dd8b6f8e 100644
>> --- a/target/ppc/excp_helper.c
>> +++ b/target/ppc/excp_helper.c
>> @@ -279,6 +279,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>>              cs->halted = 1;
>>              cpu_interrupt_exittb(cs);
>>          }
>> +        if (msr_pow) {
>> +            /* indicate that we resumed from power save mode */
>> +            msr |= 0x10000;
> 
> #define ? 

It matches system reset, but yes it should be put in a define (or
PPC_BIT should be okay I guess because it's architecture). As
discussed in the nmi patch, we have to make some adjustments for
pnv so I'll tidy that up too.

Thanks,
Nick
diff mbox series

Patch

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 671535ebe6..9c515bfeed 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -38,6 +38,7 @@ 
 #include "hw/nmi.h"
 #include "exec/address-spaces.h"
 #include "qapi/visitor.h"
+#include "qapi/qmp/qdict.h"
 #include "monitor/monitor.h"
 #include "hw/intc/intc.h"
 #include "hw/ipmi/ipmi.h"
@@ -1981,11 +1982,63 @@  static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
     }
 }
 
+typedef struct MCEInjectionParams {
+    uint64_t srr1_mask;
+    uint32_t dsisr;
+    uint64_t dar;
+    bool recovered;
+} MCEInjectionParams;
+
+static void pnv_do_mce_on_cpu(CPUState *cs, run_on_cpu_data data)
+{
+    MCEInjectionParams *params = data.host_ptr;
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+    uint64_t srr1_mce_bits = PPC_BITMASK(42, 45) | PPC_BIT(36);
+
+    cpu_synchronize_state(cs);
+    ppc_cpu_do_machine_check(cs);
+
+    env->spr[SPR_SRR1] |= (params->srr1_mask & srr1_mce_bits);
+    if (params->dsisr) {
+        env->spr[SPR_DSISR] = params->dsisr;
+        env->spr[SPR_DAR] = params->dar;
+    }
+
+    if (!params->recovered) {
+        env->msr &= ~MSR_RI;
+    }
+}
+
+static void pnv_mce(MCEState *m, const QDict *qdict, Error **errp)
+{
+    int cpu_index = qdict_get_int(qdict, "cpu_index");
+    uint64_t srr1_mask = qdict_get_int(qdict, "srr1_mask");
+    uint32_t dsisr = qdict_get_int(qdict, "dsisr");
+    uint64_t dar = qdict_get_int(qdict, "dar");
+    bool recovered = qdict_get_int(qdict, "recovered");
+    CPUState *cs;
+
+    cs = qemu_get_cpu(cpu_index);
+
+    if (cs != NULL) {
+        MCEInjectionParams params = {
+            .srr1_mask = srr1_mask,
+            .dsisr = dsisr,
+            .dar = dar,
+            .recovered = recovered,
+        };
+
+        run_on_cpu(cs, pnv_do_mce_on_cpu, RUN_ON_CPU_HOST_PTR(&params));
+    }
+}
+
 static void pnv_machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
     InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc);
     NMIClass *nc = NMI_CLASS(oc);
+    MCEClass *mcec = MCE_CLASS(oc);
 
     mc->desc = "IBM PowerNV (Non-Virtualized)";
     mc->init = pnv_init;
@@ -2003,6 +2056,7 @@  static void pnv_machine_class_init(ObjectClass *oc, void *data)
     mc->default_ram_id = "pnv.ram";
     ispc->print_info = pnv_pic_print_info;
     nc->nmi_monitor_handler = pnv_nmi;
+    mcec->mce_monitor_handler = pnv_mce;
 
     object_class_property_add_bool(oc, "hb-mode",
                                    pnv_machine_get_hb, pnv_machine_set_hb,
@@ -2067,6 +2121,7 @@  static const TypeInfo types[] = {
         .interfaces = (InterfaceInfo[]) {
             { TYPE_INTERRUPT_STATS_PROVIDER },
             { TYPE_NMI },
+            { TYPE_MCE },
         },
     },
     {
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index f4a5304d43..9be27f59c5 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1221,6 +1221,7 @@  int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
                                int cpuid, void *opaque);
 #ifndef CONFIG_USER_ONLY
 void ppc_cpu_do_system_reset(CPUState *cs);
+void ppc_cpu_do_machine_check(CPUState *cs);
 void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
 extern const VMStateDescription vmstate_ppc_cpu;
 #endif
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 7f2b5899d3..81dd8b6f8e 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -279,6 +279,10 @@  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             cs->halted = 1;
             cpu_interrupt_exittb(cs);
         }
+        if (msr_pow) {
+            /* indicate that we resumed from power save mode */
+            msr |= 0x10000;
+        }
         if (env->msr_mask & MSR_HVB) {
             /*
              * ISA specifies HV, but can be delivered to guest with HV
@@ -969,6 +973,14 @@  void ppc_cpu_do_system_reset(CPUState *cs)
     powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
 }
 
+void ppc_cpu_do_machine_check(CPUState *cs)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    CPUPPCState *env = &cpu->env;
+
+    powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
+}
+
 void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);