diff mbox series

[v2,03/12] target/ppc: Implement attn instruction on BookS 64-bit processors

Message ID 20240521013029.30082-4-npiggin@gmail.com
State Not Applicable
Headers show
Series target/ppc: Various TCG emulation patches | expand

Commit Message

Nicholas Piggin May 21, 2024, 1:30 a.m. UTC
attn is an implementation-specific instruction that on POWER (and G5/
970) can be enabled with a HID bit (disabled = illegal), and executing
it causes the host processor to stop and the service processor to be
notified. Generally used for debugging.

Implement attn and make it checkstop the system, which should be good
enough for QEMU debugging.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 target/ppc/cpu.h                     | 12 +++++
 target/ppc/helper.h                  |  1 +
 target/ppc/insn32.decode             |  4 ++
 target/ppc/cpu_init.c                | 69 ++++++++++++++++++++++++++++
 target/ppc/excp_helper.c             | 43 +++++++++++++----
 target/ppc/translate/misc-impl.c.inc | 10 ++++
 6 files changed, 130 insertions(+), 9 deletions(-)

Comments

Miles Glenn May 21, 2024, 3:41 p.m. UTC | #1
Looks like this patch is failing to apply to the current master head?

Thanks,

Glenn

On Tue, 2024-05-21 at 11:30 +1000, Nicholas Piggin wrote:
> attn is an implementation-specific instruction that on POWER (and G5/
> 970) can be enabled with a HID bit (disabled = illegal), and
> executing
> it causes the host processor to stop and the service processor to be
> notified. Generally used for debugging.
> 
> Implement attn and make it checkstop the system, which should be good
> enough for QEMU debugging.
> 
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
>  target/ppc/cpu.h                     | 12 +++++
>  target/ppc/helper.h                  |  1 +
>  target/ppc/insn32.decode             |  4 ++
>  target/ppc/cpu_init.c                | 69
> ++++++++++++++++++++++++++++
>  target/ppc/excp_helper.c             | 43 +++++++++++++----
>  target/ppc/translate/misc-impl.c.inc | 10 ++++
>  6 files changed, 130 insertions(+), 9 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index c358927211..2532408be0 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1375,6 +1375,9 @@ struct CPUArchState {
>      /* Power management */
>      int (*check_pow)(CPUPPCState *env);
>  
> +    /* attn instruction enable */
> +    int (*check_attn)(CPUPPCState *env);
> +
>  #if !defined(CONFIG_USER_ONLY)
>      void *load_info;  /* holds boot loading state */
>  #endif
> @@ -1523,6 +1526,7 @@ struct PowerPCCPUClass {
>      int n_host_threads;
>      void (*init_proc)(CPUPPCState *env);
>      int  (*check_pow)(CPUPPCState *env);
> +    int  (*check_attn)(CPUPPCState *env);
>  };
>  
>  ObjectClass *ppc_cpu_class_by_name(const char *name);
> @@ -2320,6 +2324,8 @@ void ppc_compat_add_property(Object *obj, const
> char *name,
>  #define HID0_NAP            (1 << 22)           /* pre-2.06 */
>  #define HID0_HILE           PPC_BIT(19) /* POWER8 */
>  #define HID0_POWER9_HILE    PPC_BIT(4)
> +#define HID0_ENABLE_ATTN    PPC_BIT(31) /* POWER8 */
> +#define HID0_POWER9_ENABLE_ATTN PPC_BIT(3)
>  
>  /*******************************************************************
> **********/
>  /* PowerPC Instructions types
> definitions                                    */
> @@ -3025,6 +3031,12 @@ static inline int
> check_pow_nocheck(CPUPPCState *env)
>      return 1;
>  }
>  
> +/* attn enable
> check                                                         */
> +static inline int check_attn_none(CPUPPCState *env)
> +{
> +    return 0;
> +}
> +
>  /*******************************************************************
> **********/
>  /* PowerPC implementations
> definitions                                       */
>  
> diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> index 55293e20a9..09d50f9b76 100644
> --- a/target/ppc/helper.h
> +++ b/target/ppc/helper.h
> @@ -825,5 +825,6 @@ DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG,
> void, env)
>  #if defined(TARGET_PPC64)
>  DEF_HELPER_1(clrbhrb, void, env)
>  DEF_HELPER_FLAGS_2(mfbhrbe, TCG_CALL_NO_WG, i64, env, i32)
> +DEF_HELPER_1(attn, noreturn, env)
>  #endif
>  #endif
> diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
> index d4dd022df4..ee33141476 100644
> --- a/target/ppc/insn32.decode
> +++ b/target/ppc/insn32.decode
> @@ -1198,3 +1198,7 @@ EIEIO           011111 ----- ----- -----
> 1101010110 -
>  
>  MFBHRBE         011111 ..... ..... ..... 0100101110 -   @XFX_bhrbe
>  CLRBHRB         011111 ----- ----- ----- 0110101110 -
> +
> +## Misc POWER instructions
> +
> +ATTN            000000 00000 00000 00000 0100000000 0
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index 1ec84b5ddc..ee01415c32 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -2107,6 +2107,26 @@ static int check_pow_hid0_74xx(CPUPPCState
> *env)
>      return 0;
>  }
>  
> +#if defined(TARGET_PPC64)
> +static int check_attn_hid0(CPUPPCState *env)
> +{
> +    if (env->spr[SPR_HID0] & HID0_ENABLE_ATTN) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int check_attn_hid0_power9(CPUPPCState *env)
> +{
> +    if (env->spr[SPR_HID0] & HID0_POWER9_ENABLE_ATTN) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +#endif
> +
>  static void init_proc_405(CPUPPCState *env)
>  {
>      register_40x_sprs(env);
> @@ -2138,6 +2158,7 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 405";
>      pcc->init_proc = init_proc_405;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_DCR | PPC_WRTEE |
>                         PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |
> @@ -2210,6 +2231,7 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 440 EP";
>      pcc->init_proc = init_proc_440EP;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
>                         PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -2248,6 +2270,7 @@ POWERPC_FAMILY(460EX)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 460 EX";
>      pcc->init_proc = init_proc_440EP;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
>                         PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -2308,6 +2331,7 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 440 GP";
>      pcc->init_proc = init_proc_440GP;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
>                         PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI
> |
>                         PPC_CACHE | PPC_CACHE_ICBI |
> @@ -2382,6 +2406,7 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 440x5";
>      pcc->init_proc = init_proc_440x5;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
>                         PPC_DCR | PPC_WRTEE | PPC_RFMCI |
>                         PPC_CACHE | PPC_CACHE_ICBI |
> @@ -2417,6 +2442,7 @@ POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc,
> void *data)
>      dc->desc = "PowerPC 440x5 with double precision FPU";
>      pcc->init_proc = init_proc_440x5;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
>                         PPC_FLOAT | PPC_FLOAT_FSQRT |
>                         PPC_FLOAT_STFIWX |
> @@ -2465,6 +2491,7 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void
> *data)
>      dc->desc = "Freescale 5xx cores (aka RCPU)";
>      pcc->init_proc = init_proc_MPC5xx;
>      pcc->check_pow = check_pow_none;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
>                         PPC_MEM_EIEIO | PPC_MEM_SYNC |
>                         PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX
> |
> @@ -2507,6 +2534,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void
> *data)
>      dc->desc = "Freescale 8xx cores (aka PowerQUICC)";
>      pcc->init_proc = init_proc_MPC8xx;
>      pcc->check_pow = check_pow_none;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING  |
>                         PPC_MEM_EIEIO | PPC_MEM_SYNC |
>                         PPC_CACHE_ICBI | PPC_MFTB;
> @@ -2557,6 +2585,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
>      dc->desc = "PowerPC G2";
>      pcc->init_proc = init_proc_G2;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_STFIWX |
> @@ -2595,6 +2624,7 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC G2LE";
>      pcc->init_proc = init_proc_G2;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_STFIWX |
> @@ -2741,6 +2771,7 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void
> *data)
>      dc->desc = "e200 core";
>      pcc->init_proc = init_proc_e200;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      /*
>       * XXX: unimplemented instructions:
>       * dcblc
> @@ -3029,6 +3060,7 @@ POWERPC_FAMILY(e500v1)(ObjectClass *oc, void
> *data)
>      dc->desc = "e500v1 core";
>      pcc->init_proc = init_proc_e500v1;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
>                         PPC_SPE | PPC_SPE_SINGLE |
>                         PPC_WRTEE | PPC_RFDI |
> @@ -3072,6 +3104,7 @@ POWERPC_FAMILY(e500v2)(ObjectClass *oc, void
> *data)
>      dc->desc = "e500v2 core";
>      pcc->init_proc = init_proc_e500v2;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
>                         PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE |
>                         PPC_WRTEE | PPC_RFDI |
> @@ -3115,6 +3148,7 @@ POWERPC_FAMILY(e500mc)(ObjectClass *oc, void
> *data)
>      dc->desc = "e500mc core";
>      pcc->init_proc = init_proc_e500mc;
>      pcc->check_pow = check_pow_none;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
>                         PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
>                         PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
> @@ -3161,6 +3195,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void
> *data)
>      dc->desc = "e5500 core";
>      pcc->init_proc = init_proc_e5500;
>      pcc->check_pow = check_pow_none;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
>                         PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
>                         PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
> @@ -3209,6 +3244,7 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void
> *data)
>      dc->desc = "e6500 core";
>      pcc->init_proc = init_proc_e6500;
>      pcc->check_pow = check_pow_none;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
>                         PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
>                         PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
> @@ -3271,6 +3307,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 603";
>      pcc->init_proc = init_proc_603;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3310,6 +3347,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 603e";
>      pcc->init_proc = init_proc_603;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3355,6 +3393,7 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void
> *data)
>      dc->desc = "e300 core";
>      pcc->init_proc = init_proc_e300;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_STFIWX |
> @@ -3410,6 +3449,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 604";
>      pcc->init_proc = init_proc_604;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3455,6 +3495,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 604E";
>      pcc->init_proc = init_proc_604E;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3511,6 +3552,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 740";
>      pcc->init_proc = init_proc_740;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3576,6 +3618,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 750";
>      pcc->init_proc = init_proc_750;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3722,6 +3765,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 750 CL";
>      pcc->init_proc = init_proc_750cl;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      /*
>       * XXX: not implemented:
>       * cache lock instructions:
> @@ -3829,6 +3873,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 750CX";
>      pcc->init_proc = init_proc_750cx;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3901,6 +3946,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 750FX";
>      pcc->init_proc = init_proc_750fx;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -3973,6 +4019,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 750GX";
>      pcc->init_proc = init_proc_750gx;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -4032,6 +4079,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 745";
>      pcc->init_proc = init_proc_745;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -4077,6 +4125,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 755";
>      pcc->init_proc = init_proc_755;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> @@ -4143,6 +4192,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7400 (aka G4)";
>      pcc->init_proc = init_proc_7400;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4222,6 +4272,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7410 (aka G4)";
>      pcc->init_proc = init_proc_7410;
>      pcc->check_pow = check_pow_hid0;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4322,6 +4373,7 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7440 (aka G4)";
>      pcc->init_proc = init_proc_7440;
>      pcc->check_pow = check_pow_hid0_74xx;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4444,6 +4496,7 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7450 (aka G4)";
>      pcc->init_proc = init_proc_7450;
>      pcc->check_pow = check_pow_hid0_74xx;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4573,6 +4626,7 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7445 (aka G4)";
>      pcc->init_proc = init_proc_7445;
>      pcc->check_pow = check_pow_hid0_74xx;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4704,6 +4758,7 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7455 (aka G4)";
>      pcc->init_proc = init_proc_7455;
>      pcc->check_pow = check_pow_hid0_74xx;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4855,6 +4910,7 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 7457 (aka G4)";
>      pcc->init_proc = init_proc_7457;
>      pcc->check_pow = check_pow_hid0_74xx;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -4989,6 +5045,7 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC e600";
>      pcc->init_proc = init_proc_e600;
>      pcc->check_pow = check_pow_hid0_74xx;
> +    pcc->check_attn = check_attn_none;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -5904,6 +5961,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void
> *data)
>      dc->desc = "PowerPC 970";
>      pcc->init_proc = init_proc_970;
>      pcc->check_pow = check_pow_970;
> +    pcc->check_attn = check_attn_hid0;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -5979,6 +6037,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void
> *data)
>      dc->desc = "POWER5+";
>      pcc->init_proc = init_proc_power5plus;
>      pcc->check_pow = check_pow_970;
> +    pcc->check_attn = check_attn_hid0;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6086,6 +6145,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void
> *data)
>      pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER7;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_hid0;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6247,6 +6307,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void
> *data)
>      pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
> PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER8;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_hid0;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6439,6 +6500,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void
> *data)
>                           PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER9;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_hid0_power9;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6618,6 +6680,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void
> *data)
>                           PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
>      pcc->init_proc = init_proc_POWER10;
>      pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_hid0_power9;
>      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> PPC_MFTB |
>                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
>                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> @@ -6856,6 +6919,11 @@ static void init_ppc_proc(PowerPCCPU *cpu)
>          warn_report("no power management check handler registered."
>                      " Attempt QEMU to crash very soon !");
>      }
> +
> +    if (env->check_attn == NULL) {
> +        warn_report("no attn check handler registered."
> +                    " Attempt QEMU to crash very soon !");
> +    }
>  }
>  
>  
> @@ -7317,6 +7385,7 @@ static void ppc_cpu_instance_init(Object *obj)
>      env->flags = pcc->flags;
>      env->bfd_mach = pcc->bfd_mach;
>      env->check_pow = pcc->check_pow;
> +    env->check_attn = pcc->check_attn;
>  
>      /*
>       * Mark HV mode as supported if the CPU has an MSR_HV bit in the
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 17bf8df9d7..e786a9044b 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -154,6 +154,7 @@ static uint32_t ppc_ldl_code(CPUArchState *env,
> target_ulong addr)
>  
>      return insn;
>  }
> +
>  #endif
>  
>  static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
> @@ -425,21 +426,20 @@ static void powerpc_set_excp_state(PowerPCCPU
> *cpu, target_ulong vector,
>      env->reserve_addr = -1;
>  }
>  
> -static void powerpc_mcheck_checkstop(CPUPPCState *env)
> -{
> -    /* KVM guests always have MSR[ME] enabled */
>  #ifdef CONFIG_TCG
> +/*
> + * This stops the machine and logs CPU state without killing QEMU
> (like
> + * cpu_abort()) because it is often a guest error as opposed to a
> QEMU error,
> + * so the machine can still be debugged.
> + */
> +static G_NORETURN void powerpc_checkstop(CPUPPCState *env, const
> char *reason)
> +{
>      CPUState *cs = env_cpu(env);
>      FILE *f;
>  
> -    if (FIELD_EX64(env->msr, MSR, ME)) {
> -        return;
> -    }
> -
>      f = qemu_log_trylock();
>      if (f) {
> -        fprintf(f, "Entering checkstop state: "
> -                   "machine check with MSR[ME]=0\n");
> +        fprintf(f, "Entering checkstop state: %s\n", reason);
>          cpu_dump_state(cs, f, CPU_DUMP_FPU | CPU_DUMP_CCOP);
>          qemu_log_unlock(f);
>      }
> @@ -451,6 +451,31 @@ static void powerpc_mcheck_checkstop(CPUPPCState
> *env)
>       */
>      qemu_system_guest_panicked(NULL);
>      cpu_loop_exit_noexc(cs);
> +}
> +
> +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
> +void helper_attn(CPUPPCState *env)
> +{
> +    /* POWER attn is unprivileged when enabled by HID, otherwise
> illegal */
> +    if ((*env->check_attn)(env)) {
> +        powerpc_checkstop(env, "host executed attn");
> +    } else {
> +        raise_exception_err(env, POWERPC_EXCP_HV_EMU,
> +                            POWERPC_EXCP_INVAL |
> POWERPC_EXCP_INVAL_INVAL);
> +    }
> +}
> +#endif
> +#endif /* CONFIG_TCG */
> +
> +static void powerpc_mcheck_checkstop(CPUPPCState *env)
> +{
> +    /* KVM guests always have MSR[ME] enabled */
> +#ifdef CONFIG_TCG
> +    if (FIELD_EX64(env->msr, MSR, ME)) {
> +        return;
> +    }
> +
> +    powerpc_checkstop(env, "machine check with MSR[ME]=0");
>  #endif
>  }
>  
> diff --git a/target/ppc/translate/misc-impl.c.inc
> b/target/ppc/translate/misc-impl.c.inc
> index c1661d2f43..cbf82b1ea0 100644
> --- a/target/ppc/translate/misc-impl.c.inc
> +++ b/target/ppc/translate/misc-impl.c.inc
> @@ -145,3 +145,13 @@ static bool trans_EIEIO(DisasContext *ctx,
> arg_EIEIO *a)
>  
>      return true;
>  }
> +
> +static bool trans_ATTN(DisasContext *ctx, arg_ATTN *a)
> +{
> +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
> +    gen_helper_attn(tcg_env);
> +    return true;
> +#else
> +    return false;
> +#endif
> +}
Richard Henderson May 21, 2024, 5:34 p.m. UTC | #2
On 5/20/24 18:30, Nicholas Piggin wrote:
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index c358927211..2532408be0 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -3025,6 +3031,12 @@ static inline int check_pow_nocheck(CPUPPCState *env)
>       return 1;
>   }
>   
> +/* attn enable check                                                         */
> +static inline int check_attn_none(CPUPPCState *env)
> +{
> +    return 0;
> +}

No point in putting this here, as a static inline...

> @@ -2138,6 +2158,7 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
>       dc->desc = "PowerPC 405";
>       pcc->init_proc = init_proc_405;
>       pcc->check_pow = check_pow_nocheck;
> +    pcc->check_attn = check_attn_none;

... when the only uses force an out-of-line instance.

Alternately,

> +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
> +void helper_attn(CPUPPCState *env)
> +{
> +    /* POWER attn is unprivileged when enabled by HID, otherwise illegal */
> +    if ((*env->check_attn)(env)) {
> +        powerpc_checkstop(env, "host executed attn");

... allow the hook to be null to indicate no attn.

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~
Nicholas Piggin May 22, 2024, 1:30 a.m. UTC | #3
Ah sorry, it's on top of some of Chinmay's decodetree series which is
causing a couple of minor rejects.

Thanks,
Nick

On Wed May 22, 2024 at 1:41 AM AEST, Miles Glenn wrote:
> Looks like this patch is failing to apply to the current master head?
>
> Thanks,
>
> Glenn
>
> On Tue, 2024-05-21 at 11:30 +1000, Nicholas Piggin wrote:
> > attn is an implementation-specific instruction that on POWER (and G5/
> > 970) can be enabled with a HID bit (disabled = illegal), and
> > executing
> > it causes the host processor to stop and the service processor to be
> > notified. Generally used for debugging.
> > 
> > Implement attn and make it checkstop the system, which should be good
> > enough for QEMU debugging.
> > 
> > Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> > ---
> >  target/ppc/cpu.h                     | 12 +++++
> >  target/ppc/helper.h                  |  1 +
> >  target/ppc/insn32.decode             |  4 ++
> >  target/ppc/cpu_init.c                | 69
> > ++++++++++++++++++++++++++++
> >  target/ppc/excp_helper.c             | 43 +++++++++++++----
> >  target/ppc/translate/misc-impl.c.inc | 10 ++++
> >  6 files changed, 130 insertions(+), 9 deletions(-)
> > 
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index c358927211..2532408be0 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -1375,6 +1375,9 @@ struct CPUArchState {
> >      /* Power management */
> >      int (*check_pow)(CPUPPCState *env);
> >  
> > +    /* attn instruction enable */
> > +    int (*check_attn)(CPUPPCState *env);
> > +
> >  #if !defined(CONFIG_USER_ONLY)
> >      void *load_info;  /* holds boot loading state */
> >  #endif
> > @@ -1523,6 +1526,7 @@ struct PowerPCCPUClass {
> >      int n_host_threads;
> >      void (*init_proc)(CPUPPCState *env);
> >      int  (*check_pow)(CPUPPCState *env);
> > +    int  (*check_attn)(CPUPPCState *env);
> >  };
> >  
> >  ObjectClass *ppc_cpu_class_by_name(const char *name);
> > @@ -2320,6 +2324,8 @@ void ppc_compat_add_property(Object *obj, const
> > char *name,
> >  #define HID0_NAP            (1 << 22)           /* pre-2.06 */
> >  #define HID0_HILE           PPC_BIT(19) /* POWER8 */
> >  #define HID0_POWER9_HILE    PPC_BIT(4)
> > +#define HID0_ENABLE_ATTN    PPC_BIT(31) /* POWER8 */
> > +#define HID0_POWER9_ENABLE_ATTN PPC_BIT(3)
> >  
> >  /*******************************************************************
> > **********/
> >  /* PowerPC Instructions types
> > definitions                                    */
> > @@ -3025,6 +3031,12 @@ static inline int
> > check_pow_nocheck(CPUPPCState *env)
> >      return 1;
> >  }
> >  
> > +/* attn enable
> > check                                                         */
> > +static inline int check_attn_none(CPUPPCState *env)
> > +{
> > +    return 0;
> > +}
> > +
> >  /*******************************************************************
> > **********/
> >  /* PowerPC implementations
> > definitions                                       */
> >  
> > diff --git a/target/ppc/helper.h b/target/ppc/helper.h
> > index 55293e20a9..09d50f9b76 100644
> > --- a/target/ppc/helper.h
> > +++ b/target/ppc/helper.h
> > @@ -825,5 +825,6 @@ DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG,
> > void, env)
> >  #if defined(TARGET_PPC64)
> >  DEF_HELPER_1(clrbhrb, void, env)
> >  DEF_HELPER_FLAGS_2(mfbhrbe, TCG_CALL_NO_WG, i64, env, i32)
> > +DEF_HELPER_1(attn, noreturn, env)
> >  #endif
> >  #endif
> > diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
> > index d4dd022df4..ee33141476 100644
> > --- a/target/ppc/insn32.decode
> > +++ b/target/ppc/insn32.decode
> > @@ -1198,3 +1198,7 @@ EIEIO           011111 ----- ----- -----
> > 1101010110 -
> >  
> >  MFBHRBE         011111 ..... ..... ..... 0100101110 -   @XFX_bhrbe
> >  CLRBHRB         011111 ----- ----- ----- 0110101110 -
> > +
> > +## Misc POWER instructions
> > +
> > +ATTN            000000 00000 00000 00000 0100000000 0
> > diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> > index 1ec84b5ddc..ee01415c32 100644
> > --- a/target/ppc/cpu_init.c
> > +++ b/target/ppc/cpu_init.c
> > @@ -2107,6 +2107,26 @@ static int check_pow_hid0_74xx(CPUPPCState
> > *env)
> >      return 0;
> >  }
> >  
> > +#if defined(TARGET_PPC64)
> > +static int check_attn_hid0(CPUPPCState *env)
> > +{
> > +    if (env->spr[SPR_HID0] & HID0_ENABLE_ATTN) {
> > +        return 1;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int check_attn_hid0_power9(CPUPPCState *env)
> > +{
> > +    if (env->spr[SPR_HID0] & HID0_POWER9_ENABLE_ATTN) {
> > +        return 1;
> > +    }
> > +
> > +    return 0;
> > +}
> > +#endif
> > +
> >  static void init_proc_405(CPUPPCState *env)
> >  {
> >      register_40x_sprs(env);
> > @@ -2138,6 +2158,7 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 405";
> >      pcc->init_proc = init_proc_405;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_DCR | PPC_WRTEE |
> >                         PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |
> > @@ -2210,6 +2231,7 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 440 EP";
> >      pcc->init_proc = init_proc_440EP;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
> >                         PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -2248,6 +2270,7 @@ POWERPC_FAMILY(460EX)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 460 EX";
> >      pcc->init_proc = init_proc_440EP;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
> >                         PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -2308,6 +2331,7 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 440 GP";
> >      pcc->init_proc = init_proc_440GP;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
> >                         PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI
> > |
> >                         PPC_CACHE | PPC_CACHE_ICBI |
> > @@ -2382,6 +2406,7 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 440x5";
> >      pcc->init_proc = init_proc_440x5;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
> >                         PPC_DCR | PPC_WRTEE | PPC_RFMCI |
> >                         PPC_CACHE | PPC_CACHE_ICBI |
> > @@ -2417,6 +2442,7 @@ POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc,
> > void *data)
> >      dc->desc = "PowerPC 440x5 with double precision FPU";
> >      pcc->init_proc = init_proc_440x5;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
> >                         PPC_FLOAT | PPC_FLOAT_FSQRT |
> >                         PPC_FLOAT_STFIWX |
> > @@ -2465,6 +2491,7 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "Freescale 5xx cores (aka RCPU)";
> >      pcc->init_proc = init_proc_MPC5xx;
> >      pcc->check_pow = check_pow_none;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
> >                         PPC_MEM_EIEIO | PPC_MEM_SYNC |
> >                         PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX
> > |
> > @@ -2507,6 +2534,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "Freescale 8xx cores (aka PowerQUICC)";
> >      pcc->init_proc = init_proc_MPC8xx;
> >      pcc->check_pow = check_pow_none;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING  |
> >                         PPC_MEM_EIEIO | PPC_MEM_SYNC |
> >                         PPC_CACHE_ICBI | PPC_MFTB;
> > @@ -2557,6 +2585,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
> >      dc->desc = "PowerPC G2";
> >      pcc->init_proc = init_proc_G2;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_STFIWX |
> > @@ -2595,6 +2624,7 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC G2LE";
> >      pcc->init_proc = init_proc_G2;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_STFIWX |
> > @@ -2741,6 +2771,7 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e200 core";
> >      pcc->init_proc = init_proc_e200;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      /*
> >       * XXX: unimplemented instructions:
> >       * dcblc
> > @@ -3029,6 +3060,7 @@ POWERPC_FAMILY(e500v1)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e500v1 core";
> >      pcc->init_proc = init_proc_e500v1;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
> >                         PPC_SPE | PPC_SPE_SINGLE |
> >                         PPC_WRTEE | PPC_RFDI |
> > @@ -3072,6 +3104,7 @@ POWERPC_FAMILY(e500v2)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e500v2 core";
> >      pcc->init_proc = init_proc_e500v2;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
> >                         PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE |
> >                         PPC_WRTEE | PPC_RFDI |
> > @@ -3115,6 +3148,7 @@ POWERPC_FAMILY(e500mc)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e500mc core";
> >      pcc->init_proc = init_proc_e500mc;
> >      pcc->check_pow = check_pow_none;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
> >                         PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
> >                         PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
> > @@ -3161,6 +3195,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e5500 core";
> >      pcc->init_proc = init_proc_e5500;
> >      pcc->check_pow = check_pow_none;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
> >                         PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
> >                         PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
> > @@ -3209,6 +3244,7 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e6500 core";
> >      pcc->init_proc = init_proc_e6500;
> >      pcc->check_pow = check_pow_none;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
> >                         PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
> >                         PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
> > @@ -3271,6 +3307,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 603";
> >      pcc->init_proc = init_proc_603;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3310,6 +3347,7 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 603e";
> >      pcc->init_proc = init_proc_603;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3355,6 +3393,7 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "e300 core";
> >      pcc->init_proc = init_proc_e300;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_STFIWX |
> > @@ -3410,6 +3449,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 604";
> >      pcc->init_proc = init_proc_604;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3455,6 +3495,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 604E";
> >      pcc->init_proc = init_proc_604E;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3511,6 +3552,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 740";
> >      pcc->init_proc = init_proc_740;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3576,6 +3618,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 750";
> >      pcc->init_proc = init_proc_750;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3722,6 +3765,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 750 CL";
> >      pcc->init_proc = init_proc_750cl;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      /*
> >       * XXX: not implemented:
> >       * cache lock instructions:
> > @@ -3829,6 +3873,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 750CX";
> >      pcc->init_proc = init_proc_750cx;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3901,6 +3946,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 750FX";
> >      pcc->init_proc = init_proc_750fx;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -3973,6 +4019,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 750GX";
> >      pcc->init_proc = init_proc_750gx;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -4032,6 +4079,7 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 745";
> >      pcc->init_proc = init_proc_745;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -4077,6 +4125,7 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 755";
> >      pcc->init_proc = init_proc_755;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
> > @@ -4143,6 +4192,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7400 (aka G4)";
> >      pcc->init_proc = init_proc_7400;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4222,6 +4272,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7410 (aka G4)";
> >      pcc->init_proc = init_proc_7410;
> >      pcc->check_pow = check_pow_hid0;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4322,6 +4373,7 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7440 (aka G4)";
> >      pcc->init_proc = init_proc_7440;
> >      pcc->check_pow = check_pow_hid0_74xx;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4444,6 +4496,7 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7450 (aka G4)";
> >      pcc->init_proc = init_proc_7450;
> >      pcc->check_pow = check_pow_hid0_74xx;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4573,6 +4626,7 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7445 (aka G4)";
> >      pcc->init_proc = init_proc_7445;
> >      pcc->check_pow = check_pow_hid0_74xx;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4704,6 +4758,7 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7455 (aka G4)";
> >      pcc->init_proc = init_proc_7455;
> >      pcc->check_pow = check_pow_hid0_74xx;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4855,6 +4910,7 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 7457 (aka G4)";
> >      pcc->init_proc = init_proc_7457;
> >      pcc->check_pow = check_pow_hid0_74xx;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -4989,6 +5045,7 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC e600";
> >      pcc->init_proc = init_proc_e600;
> >      pcc->check_pow = check_pow_hid0_74xx;
> > +    pcc->check_attn = check_attn_none;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -5904,6 +5961,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "PowerPC 970";
> >      pcc->init_proc = init_proc_970;
> >      pcc->check_pow = check_pow_970;
> > +    pcc->check_attn = check_attn_hid0;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -5979,6 +6037,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void
> > *data)
> >      dc->desc = "POWER5+";
> >      pcc->init_proc = init_proc_power5plus;
> >      pcc->check_pow = check_pow_970;
> > +    pcc->check_attn = check_attn_hid0;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -6086,6 +6145,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void
> > *data)
> >      pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> >      pcc->init_proc = init_proc_POWER7;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_hid0;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> > PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -6247,6 +6307,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void
> > *data)
> >      pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
> > PCR_COMPAT_2_05;
> >      pcc->init_proc = init_proc_POWER8;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_hid0;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> > PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -6439,6 +6500,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void
> > *data)
> >                           PCR_COMPAT_2_05;
> >      pcc->init_proc = init_proc_POWER9;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_hid0_power9;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> > PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -6618,6 +6680,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void
> > *data)
> >                           PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> >      pcc->init_proc = init_proc_POWER10;
> >      pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_hid0_power9;
> >      pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING |
> > PPC_MFTB |
> >                         PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
> >                         PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
> > @@ -6856,6 +6919,11 @@ static void init_ppc_proc(PowerPCCPU *cpu)
> >          warn_report("no power management check handler registered."
> >                      " Attempt QEMU to crash very soon !");
> >      }
> > +
> > +    if (env->check_attn == NULL) {
> > +        warn_report("no attn check handler registered."
> > +                    " Attempt QEMU to crash very soon !");
> > +    }
> >  }
> >  
> >  
> > @@ -7317,6 +7385,7 @@ static void ppc_cpu_instance_init(Object *obj)
> >      env->flags = pcc->flags;
> >      env->bfd_mach = pcc->bfd_mach;
> >      env->check_pow = pcc->check_pow;
> > +    env->check_attn = pcc->check_attn;
> >  
> >      /*
> >       * Mark HV mode as supported if the CPU has an MSR_HV bit in the
> > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> > index 17bf8df9d7..e786a9044b 100644
> > --- a/target/ppc/excp_helper.c
> > +++ b/target/ppc/excp_helper.c
> > @@ -154,6 +154,7 @@ static uint32_t ppc_ldl_code(CPUArchState *env,
> > target_ulong addr)
> >  
> >      return insn;
> >  }
> > +
> >  #endif
> >  
> >  static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
> > @@ -425,21 +426,20 @@ static void powerpc_set_excp_state(PowerPCCPU
> > *cpu, target_ulong vector,
> >      env->reserve_addr = -1;
> >  }
> >  
> > -static void powerpc_mcheck_checkstop(CPUPPCState *env)
> > -{
> > -    /* KVM guests always have MSR[ME] enabled */
> >  #ifdef CONFIG_TCG
> > +/*
> > + * This stops the machine and logs CPU state without killing QEMU
> > (like
> > + * cpu_abort()) because it is often a guest error as opposed to a
> > QEMU error,
> > + * so the machine can still be debugged.
> > + */
> > +static G_NORETURN void powerpc_checkstop(CPUPPCState *env, const
> > char *reason)
> > +{
> >      CPUState *cs = env_cpu(env);
> >      FILE *f;
> >  
> > -    if (FIELD_EX64(env->msr, MSR, ME)) {
> > -        return;
> > -    }
> > -
> >      f = qemu_log_trylock();
> >      if (f) {
> > -        fprintf(f, "Entering checkstop state: "
> > -                   "machine check with MSR[ME]=0\n");
> > +        fprintf(f, "Entering checkstop state: %s\n", reason);
> >          cpu_dump_state(cs, f, CPU_DUMP_FPU | CPU_DUMP_CCOP);
> >          qemu_log_unlock(f);
> >      }
> > @@ -451,6 +451,31 @@ static void powerpc_mcheck_checkstop(CPUPPCState
> > *env)
> >       */
> >      qemu_system_guest_panicked(NULL);
> >      cpu_loop_exit_noexc(cs);
> > +}
> > +
> > +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
> > +void helper_attn(CPUPPCState *env)
> > +{
> > +    /* POWER attn is unprivileged when enabled by HID, otherwise
> > illegal */
> > +    if ((*env->check_attn)(env)) {
> > +        powerpc_checkstop(env, "host executed attn");
> > +    } else {
> > +        raise_exception_err(env, POWERPC_EXCP_HV_EMU,
> > +                            POWERPC_EXCP_INVAL |
> > POWERPC_EXCP_INVAL_INVAL);
> > +    }
> > +}
> > +#endif
> > +#endif /* CONFIG_TCG */
> > +
> > +static void powerpc_mcheck_checkstop(CPUPPCState *env)
> > +{
> > +    /* KVM guests always have MSR[ME] enabled */
> > +#ifdef CONFIG_TCG
> > +    if (FIELD_EX64(env->msr, MSR, ME)) {
> > +        return;
> > +    }
> > +
> > +    powerpc_checkstop(env, "machine check with MSR[ME]=0");
> >  #endif
> >  }
> >  
> > diff --git a/target/ppc/translate/misc-impl.c.inc
> > b/target/ppc/translate/misc-impl.c.inc
> > index c1661d2f43..cbf82b1ea0 100644
> > --- a/target/ppc/translate/misc-impl.c.inc
> > +++ b/target/ppc/translate/misc-impl.c.inc
> > @@ -145,3 +145,13 @@ static bool trans_EIEIO(DisasContext *ctx,
> > arg_EIEIO *a)
> >  
> >      return true;
> >  }
> > +
> > +static bool trans_ATTN(DisasContext *ctx, arg_ATTN *a)
> > +{
> > +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
> > +    gen_helper_attn(tcg_env);
> > +    return true;
> > +#else
> > +    return false;
> > +#endif
> > +}
Nicholas Piggin May 22, 2024, 1:32 a.m. UTC | #4
On Wed May 22, 2024 at 3:34 AM AEST, Richard Henderson wrote:
> On 5/20/24 18:30, Nicholas Piggin wrote:
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index c358927211..2532408be0 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -3025,6 +3031,12 @@ static inline int check_pow_nocheck(CPUPPCState *env)
> >       return 1;
> >   }
> >   
> > +/* attn enable check                                                         */
> > +static inline int check_attn_none(CPUPPCState *env)
> > +{
> > +    return 0;
> > +}
>
> No point in putting this here, as a static inline...
>
> > @@ -2138,6 +2158,7 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
> >       dc->desc = "PowerPC 405";
> >       pcc->init_proc = init_proc_405;
> >       pcc->check_pow = check_pow_nocheck;
> > +    pcc->check_attn = check_attn_none;
>
> ... when the only uses force an out-of-line instance.

Yeah... I was following existing convention (although apparently not
naming convention :/).

>
> Alternately,
>
> > +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
> > +void helper_attn(CPUPPCState *env)
> > +{
> > +    /* POWER attn is unprivileged when enabled by HID, otherwise illegal */
> > +    if ((*env->check_attn)(env)) {
> > +        powerpc_checkstop(env, "host executed attn");
>
> ... allow the hook to be null to indicate no attn.

I'll add a todo list to change this and check_pow to follow this
suggestion.

>
> Otherwise,
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

Thanks,
Nick
diff mbox series

Patch

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index c358927211..2532408be0 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1375,6 +1375,9 @@  struct CPUArchState {
     /* Power management */
     int (*check_pow)(CPUPPCState *env);
 
+    /* attn instruction enable */
+    int (*check_attn)(CPUPPCState *env);
+
 #if !defined(CONFIG_USER_ONLY)
     void *load_info;  /* holds boot loading state */
 #endif
@@ -1523,6 +1526,7 @@  struct PowerPCCPUClass {
     int n_host_threads;
     void (*init_proc)(CPUPPCState *env);
     int  (*check_pow)(CPUPPCState *env);
+    int  (*check_attn)(CPUPPCState *env);
 };
 
 ObjectClass *ppc_cpu_class_by_name(const char *name);
@@ -2320,6 +2324,8 @@  void ppc_compat_add_property(Object *obj, const char *name,
 #define HID0_NAP            (1 << 22)           /* pre-2.06 */
 #define HID0_HILE           PPC_BIT(19) /* POWER8 */
 #define HID0_POWER9_HILE    PPC_BIT(4)
+#define HID0_ENABLE_ATTN    PPC_BIT(31) /* POWER8 */
+#define HID0_POWER9_ENABLE_ATTN PPC_BIT(3)
 
 /*****************************************************************************/
 /* PowerPC Instructions types definitions                                    */
@@ -3025,6 +3031,12 @@  static inline int check_pow_nocheck(CPUPPCState *env)
     return 1;
 }
 
+/* attn enable check                                                         */
+static inline int check_attn_none(CPUPPCState *env)
+{
+    return 0;
+}
+
 /*****************************************************************************/
 /* PowerPC implementations definitions                                       */
 
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 55293e20a9..09d50f9b76 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -825,5 +825,6 @@  DEF_HELPER_FLAGS_1(fixup_thrm, TCG_CALL_NO_RWG, void, env)
 #if defined(TARGET_PPC64)
 DEF_HELPER_1(clrbhrb, void, env)
 DEF_HELPER_FLAGS_2(mfbhrbe, TCG_CALL_NO_WG, i64, env, i32)
+DEF_HELPER_1(attn, noreturn, env)
 #endif
 #endif
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index d4dd022df4..ee33141476 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -1198,3 +1198,7 @@  EIEIO           011111 ----- ----- ----- 1101010110 -
 
 MFBHRBE         011111 ..... ..... ..... 0100101110 -   @XFX_bhrbe
 CLRBHRB         011111 ----- ----- ----- 0110101110 -
+
+## Misc POWER instructions
+
+ATTN            000000 00000 00000 00000 0100000000 0
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 1ec84b5ddc..ee01415c32 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -2107,6 +2107,26 @@  static int check_pow_hid0_74xx(CPUPPCState *env)
     return 0;
 }
 
+#if defined(TARGET_PPC64)
+static int check_attn_hid0(CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & HID0_ENABLE_ATTN) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int check_attn_hid0_power9(CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & HID0_POWER9_ENABLE_ATTN) {
+        return 1;
+    }
+
+    return 0;
+}
+#endif
+
 static void init_proc_405(CPUPPCState *env)
 {
     register_40x_sprs(env);
@@ -2138,6 +2158,7 @@  POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 405";
     pcc->init_proc = init_proc_405;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_DCR | PPC_WRTEE |
                        PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT |
@@ -2210,6 +2231,7 @@  POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 440 EP";
     pcc->init_proc = init_proc_440EP;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
                        PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -2248,6 +2270,7 @@  POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 460 EX";
     pcc->init_proc = init_proc_440EP;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
                        PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -2308,6 +2331,7 @@  POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 440 GP";
     pcc->init_proc = init_proc_440GP;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
                        PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI |
                        PPC_CACHE | PPC_CACHE_ICBI |
@@ -2382,6 +2406,7 @@  POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 440x5";
     pcc->init_proc = init_proc_440x5;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
                        PPC_DCR | PPC_WRTEE | PPC_RFMCI |
                        PPC_CACHE | PPC_CACHE_ICBI |
@@ -2417,6 +2442,7 @@  POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 440x5 with double precision FPU";
     pcc->init_proc = init_proc_440x5;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
                        PPC_FLOAT | PPC_FLOAT_FSQRT |
                        PPC_FLOAT_STFIWX |
@@ -2465,6 +2491,7 @@  POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data)
     dc->desc = "Freescale 5xx cores (aka RCPU)";
     pcc->init_proc = init_proc_MPC5xx;
     pcc->check_pow = check_pow_none;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
                        PPC_MEM_EIEIO | PPC_MEM_SYNC |
                        PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX |
@@ -2507,6 +2534,7 @@  POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
     dc->desc = "Freescale 8xx cores (aka PowerQUICC)";
     pcc->init_proc = init_proc_MPC8xx;
     pcc->check_pow = check_pow_none;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING  |
                        PPC_MEM_EIEIO | PPC_MEM_SYNC |
                        PPC_CACHE_ICBI | PPC_MFTB;
@@ -2557,6 +2585,7 @@  POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC G2";
     pcc->init_proc = init_proc_G2;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_STFIWX |
@@ -2595,6 +2624,7 @@  POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC G2LE";
     pcc->init_proc = init_proc_G2;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_STFIWX |
@@ -2741,6 +2771,7 @@  POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
     dc->desc = "e200 core";
     pcc->init_proc = init_proc_e200;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     /*
      * XXX: unimplemented instructions:
      * dcblc
@@ -3029,6 +3060,7 @@  POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data)
     dc->desc = "e500v1 core";
     pcc->init_proc = init_proc_e500v1;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
                        PPC_SPE | PPC_SPE_SINGLE |
                        PPC_WRTEE | PPC_RFDI |
@@ -3072,6 +3104,7 @@  POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data)
     dc->desc = "e500v2 core";
     pcc->init_proc = init_proc_e500v2;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL |
                        PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE |
                        PPC_WRTEE | PPC_RFDI |
@@ -3115,6 +3148,7 @@  POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data)
     dc->desc = "e500mc core";
     pcc->init_proc = init_proc_e500mc;
     pcc->check_pow = check_pow_none;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
                        PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
                        PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
@@ -3161,6 +3195,7 @@  POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
     dc->desc = "e5500 core";
     pcc->init_proc = init_proc_e5500;
     pcc->check_pow = check_pow_none;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
                        PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
                        PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
@@ -3209,6 +3244,7 @@  POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data)
     dc->desc = "e6500 core";
     pcc->init_proc = init_proc_e6500;
     pcc->check_pow = check_pow_none;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_MFTB |
                        PPC_WRTEE | PPC_RFDI | PPC_RFMCI |
                        PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI |
@@ -3271,6 +3307,7 @@  POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 603";
     pcc->init_proc = init_proc_603;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3310,6 +3347,7 @@  POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 603e";
     pcc->init_proc = init_proc_603;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3355,6 +3393,7 @@  POWERPC_FAMILY(e300)(ObjectClass *oc, void *data)
     dc->desc = "e300 core";
     pcc->init_proc = init_proc_e300;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_STFIWX |
@@ -3410,6 +3449,7 @@  POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 604";
     pcc->init_proc = init_proc_604;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3455,6 +3495,7 @@  POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 604E";
     pcc->init_proc = init_proc_604E;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3511,6 +3552,7 @@  POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 740";
     pcc->init_proc = init_proc_740;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3576,6 +3618,7 @@  POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 750";
     pcc->init_proc = init_proc_750;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3722,6 +3765,7 @@  POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 750 CL";
     pcc->init_proc = init_proc_750cl;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     /*
      * XXX: not implemented:
      * cache lock instructions:
@@ -3829,6 +3873,7 @@  POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 750CX";
     pcc->init_proc = init_proc_750cx;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3901,6 +3946,7 @@  POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 750FX";
     pcc->init_proc = init_proc_750fx;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -3973,6 +4019,7 @@  POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 750GX";
     pcc->init_proc = init_proc_750gx;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -4032,6 +4079,7 @@  POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 745";
     pcc->init_proc = init_proc_745;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -4077,6 +4125,7 @@  POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 755";
     pcc->init_proc = init_proc_755;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |
@@ -4143,6 +4192,7 @@  POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7400 (aka G4)";
     pcc->init_proc = init_proc_7400;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4222,6 +4272,7 @@  POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7410 (aka G4)";
     pcc->init_proc = init_proc_7410;
     pcc->check_pow = check_pow_hid0;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4322,6 +4373,7 @@  POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7440 (aka G4)";
     pcc->init_proc = init_proc_7440;
     pcc->check_pow = check_pow_hid0_74xx;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4444,6 +4496,7 @@  POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7450 (aka G4)";
     pcc->init_proc = init_proc_7450;
     pcc->check_pow = check_pow_hid0_74xx;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4573,6 +4626,7 @@  POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7445 (aka G4)";
     pcc->init_proc = init_proc_7445;
     pcc->check_pow = check_pow_hid0_74xx;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4704,6 +4758,7 @@  POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7455 (aka G4)";
     pcc->init_proc = init_proc_7455;
     pcc->check_pow = check_pow_hid0_74xx;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4855,6 +4910,7 @@  POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 7457 (aka G4)";
     pcc->init_proc = init_proc_7457;
     pcc->check_pow = check_pow_hid0_74xx;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -4989,6 +5045,7 @@  POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC e600";
     pcc->init_proc = init_proc_e600;
     pcc->check_pow = check_pow_hid0_74xx;
+    pcc->check_attn = check_attn_none;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -5904,6 +5961,7 @@  POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
     dc->desc = "PowerPC 970";
     pcc->init_proc = init_proc_970;
     pcc->check_pow = check_pow_970;
+    pcc->check_attn = check_attn_hid0;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -5979,6 +6037,7 @@  POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
     dc->desc = "POWER5+";
     pcc->init_proc = init_proc_power5plus;
     pcc->check_pow = check_pow_970;
+    pcc->check_attn = check_attn_hid0;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6086,6 +6145,7 @@  POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
     pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER7;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_hid0;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6247,6 +6307,7 @@  POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
     pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER8;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_hid0;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6439,6 +6500,7 @@  POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
                          PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER9;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_hid0_power9;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6618,6 +6680,7 @@  POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
                          PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->init_proc = init_proc_POWER10;
     pcc->check_pow = check_pow_nocheck;
+    pcc->check_attn = check_attn_hid0_power9;
     pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
                        PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
                        PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
@@ -6856,6 +6919,11 @@  static void init_ppc_proc(PowerPCCPU *cpu)
         warn_report("no power management check handler registered."
                     " Attempt QEMU to crash very soon !");
     }
+
+    if (env->check_attn == NULL) {
+        warn_report("no attn check handler registered."
+                    " Attempt QEMU to crash very soon !");
+    }
 }
 
 
@@ -7317,6 +7385,7 @@  static void ppc_cpu_instance_init(Object *obj)
     env->flags = pcc->flags;
     env->bfd_mach = pcc->bfd_mach;
     env->check_pow = pcc->check_pow;
+    env->check_attn = pcc->check_attn;
 
     /*
      * Mark HV mode as supported if the CPU has an MSR_HV bit in the
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 17bf8df9d7..e786a9044b 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -154,6 +154,7 @@  static uint32_t ppc_ldl_code(CPUArchState *env, target_ulong addr)
 
     return insn;
 }
+
 #endif
 
 static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp)
@@ -425,21 +426,20 @@  static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector,
     env->reserve_addr = -1;
 }
 
-static void powerpc_mcheck_checkstop(CPUPPCState *env)
-{
-    /* KVM guests always have MSR[ME] enabled */
 #ifdef CONFIG_TCG
+/*
+ * This stops the machine and logs CPU state without killing QEMU (like
+ * cpu_abort()) because it is often a guest error as opposed to a QEMU error,
+ * so the machine can still be debugged.
+ */
+static G_NORETURN void powerpc_checkstop(CPUPPCState *env, const char *reason)
+{
     CPUState *cs = env_cpu(env);
     FILE *f;
 
-    if (FIELD_EX64(env->msr, MSR, ME)) {
-        return;
-    }
-
     f = qemu_log_trylock();
     if (f) {
-        fprintf(f, "Entering checkstop state: "
-                   "machine check with MSR[ME]=0\n");
+        fprintf(f, "Entering checkstop state: %s\n", reason);
         cpu_dump_state(cs, f, CPU_DUMP_FPU | CPU_DUMP_CCOP);
         qemu_log_unlock(f);
     }
@@ -451,6 +451,31 @@  static void powerpc_mcheck_checkstop(CPUPPCState *env)
      */
     qemu_system_guest_panicked(NULL);
     cpu_loop_exit_noexc(cs);
+}
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+void helper_attn(CPUPPCState *env)
+{
+    /* POWER attn is unprivileged when enabled by HID, otherwise illegal */
+    if ((*env->check_attn)(env)) {
+        powerpc_checkstop(env, "host executed attn");
+    } else {
+        raise_exception_err(env, POWERPC_EXCP_HV_EMU,
+                            POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
+    }
+}
+#endif
+#endif /* CONFIG_TCG */
+
+static void powerpc_mcheck_checkstop(CPUPPCState *env)
+{
+    /* KVM guests always have MSR[ME] enabled */
+#ifdef CONFIG_TCG
+    if (FIELD_EX64(env->msr, MSR, ME)) {
+        return;
+    }
+
+    powerpc_checkstop(env, "machine check with MSR[ME]=0");
 #endif
 }
 
diff --git a/target/ppc/translate/misc-impl.c.inc b/target/ppc/translate/misc-impl.c.inc
index c1661d2f43..cbf82b1ea0 100644
--- a/target/ppc/translate/misc-impl.c.inc
+++ b/target/ppc/translate/misc-impl.c.inc
@@ -145,3 +145,13 @@  static bool trans_EIEIO(DisasContext *ctx, arg_EIEIO *a)
 
     return true;
 }
+
+static bool trans_ATTN(DisasContext *ctx, arg_ATTN *a)
+{
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+    gen_helper_attn(tcg_env);
+    return true;
+#else
+    return false;
+#endif
+}