diff mbox

[QEMU-PPC,RFC,2/3] hw/spapr/spapr_caps: Add new caps safe_[cache/bounds_check/indirect_branch]

Message ID 20180109092103.18458-3-sjitindarsingh@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Suraj Jitindar Singh Jan. 9, 2018, 9:21 a.m. UTC
This patch adds three new capabilities:
cap-cfpc -> safe_cache
cap-sbbc -> safe_bounds_check
cap-ibs  -> safe_indirect_branch

Each capability is tristate with the possible values "broken",
"workaround" or "fixed". Add generic getter and setter functions for
this new capability type. Add these new capabilities to the capabilities
list. The maximum value for the capabilities is queried from kvm through
new kvm capabilities. The requested values are considered to be
compatible if kvm can support an equal or higher value for each
capability.

Discussion:
Currently these new capabilities default to broken to allow for
backwards compatibility, is this the best option?
---
 hw/ppc/spapr.c            |   6 ++
 hw/ppc/spapr_caps.c       | 224 ++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/ppc/spapr.h    |  15 +++-
 linux-headers/linux/kvm.h |   3 +
 target/ppc/kvm.c          |  28 ++++++
 target/ppc/kvm_ppc.h      |  18 ++++
 6 files changed, 293 insertions(+), 1 deletion(-)

Comments

Murilo Opsfelder Araújo Jan. 9, 2018, 11:15 a.m. UTC | #1
On 01/09/2018 07:21 AM, Suraj Jitindar Singh wrote:
> This patch adds three new capabilities:
> cap-cfpc -> safe_cache
> cap-sbbc -> safe_bounds_check
> cap-ibs  -> safe_indirect_branch

Hi, Suraj.

What about splitting this into smaller patches, one per capability?

> Each capability is tristate with the possible values "broken",
> "workaround" or "fixed". Add generic getter and setter functions for
> this new capability type. Add these new capabilities to the capabilities
> list. The maximum value for the capabilities is queried from kvm through
> new kvm capabilities. The requested values are considered to be
> compatible if kvm can support an equal or higher value for each
> capability.
> 
> Discussion:
> Currently these new capabilities default to broken to allow for
> backwards compatibility, is this the best option?

This could be placed in the cover letter, not in the commit message.

Cheers
Murilo
Jose Ricardo Ziviani Jan. 9, 2018, 12:02 p.m. UTC | #2
On Tue, Jan 09, 2018 at 08:21:02PM +1100, Suraj Jitindar Singh wrote:
> This patch adds three new capabilities:
> cap-cfpc -> safe_cache
> cap-sbbc -> safe_bounds_check
> cap-ibs  -> safe_indirect_branch
> 
> Each capability is tristate with the possible values "broken",
> "workaround" or "fixed". Add generic getter and setter functions for
> this new capability type. Add these new capabilities to the capabilities
> list. The maximum value for the capabilities is queried from kvm through
> new kvm capabilities. The requested values are considered to be
> compatible if kvm can support an equal or higher value for each
> capability.
> 
> Discussion:
> Currently these new capabilities default to broken to allow for
> backwards compatibility, is this the best option?
> ---
>  hw/ppc/spapr.c            |   6 ++
>  hw/ppc/spapr_caps.c       | 224 ++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/spapr.h    |  15 +++-
>  linux-headers/linux/kvm.h |   3 +
>  target/ppc/kvm.c          |  28 ++++++
>  target/ppc/kvm_ppc.h      |  18 ++++
>  6 files changed, 293 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 7fa45729ba..d9700b0254 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1765,6 +1765,9 @@ static const VMStateDescription vmstate_spapr = {
>          &vmstate_spapr_cap_htm,
>          &vmstate_spapr_cap_vsx,
>          &vmstate_spapr_cap_dfp,
> +        &vmstate_spapr_cap_cfpc,
> +        &vmstate_spapr_cap_sbbc,
> +        &vmstate_spapr_cap_ibs,
>          NULL
>      }
>  };
> @@ -3837,6 +3840,9 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
>      smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
>      smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
>      smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
> +    smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
> +    smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
> +    smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
>      spapr_caps_add_properties(smc, &error_abort);
>  }
> 
> diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> index af40f2e469..e6910aa191 100644
> --- a/hw/ppc/spapr_caps.c
> +++ b/hw/ppc/spapr_caps.c
> @@ -75,6 +75,64 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
>                                               SPAPR_CAP_CMD_LINE;
>  }
> 
> +static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
> +{
> +    sPAPRCapabilityInfo *cap = opaque;
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> +    char *val = NULL;
> +    uint8_t value = spapr_get_cap(spapr, cap->index);
> +
> +    switch (value) {
> +    case SPAPR_CAP_BROKEN:
> +        val = g_strdup("broken");
> +        break;
> +    case SPAPR_CAP_WORKAROUND:
> +        val = g_strdup("workaround");
> +        break;
> +    case SPAPR_CAP_FIXED:
> +        val = g_strdup("fixed");
> +        break;
> +    default:
> +        break;

Hello Suraj

Is default a possible case? If so, will val be handled correctly by
visit_type_str and g_free?

if not, maybe a throwing an error like you did in
spapr_cap_set_tristate could be better.

> +    }
> +
> +    visit_type_str(v, name, &val, errp);
> +    g_free(val);
> +}
> +
> +static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
> +{
> +    sPAPRCapabilityInfo *cap = opaque;
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> +    char *val;
> +    Error *local_err = NULL;
> +    uint8_t value;
> +
> +    visit_type_str(v, name, &val, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    if (!strcasecmp(val, "broken")) {
> +        value = SPAPR_CAP_BROKEN;
> +    } else if (!strcasecmp(val, "workaround")) {
> +        value = SPAPR_CAP_WORKAROUND;
> +    } else if (!strcasecmp(val, "fixed")) {
> +        value = SPAPR_CAP_FIXED;
> +    } else {
> +        error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
> +                   cap->name);
> +        goto out;
> +    }
> +
> +    spapr->cmd_line_caps.caps[cap->index] = value | SPAPR_CAP_CMD_LINE;
> +out:
> +    g_free(val);
> +}
> +
>  static void cap_htm_allow(sPAPRMachineState *spapr, uint8_t val, Error **errp)
>  {
>      if (!val) {
> @@ -122,6 +180,31 @@ static void cap_dfp_allow(sPAPRMachineState *spapr, uint8_t val, Error **errp)
>      }
>  }
> 
> +static void cap_safe_cache_allow(sPAPRMachineState *spapr, uint8_t val,
> +                                 Error **errp)
> +{
> +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
> +        error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
> +    }
> +}
> +
> +static void cap_safe_bounds_check_allow(sPAPRMachineState *spapr, uint8_t val,
> +                                        Error **errp)
> +{
> +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
> +        error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
> +    }
> +}
> +
> +static void cap_safe_indirect_branch_allow(sPAPRMachineState *spapr,
> +                                           uint8_t val, Error **errp)
> +{
> +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
> +        error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
> +    }
> +}
> +
> +#define VALUE_DESC_TRISTATE     " (broken, workaround, fixed)"
> 
>  sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
>      [SPAPR_CAP_HTM] = {
> @@ -154,6 +237,36 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
>          .type = "bool",
>          .allow = cap_dfp_allow,
>      },
> +    [SPAPR_CAP_CFPC] = {
> +        .name = "cfpc",
> +        .description = "Cache Flush on Privilege Change",
> +        .options = VALUE_DESC_TRISTATE,
> +        .index = SPAPR_CAP_CFPC,
> +        .get = spapr_cap_get_tristate,
> +        .set = spapr_cap_set_tristate,
> +        .type = "string",
> +        .allow = cap_safe_cache_allow,
> +    },
> +    [SPAPR_CAP_SBBC] = {
> +        .name = "sbbc",
> +        .description = "Speculation Barrier Bounds Checking",
> +        .options = VALUE_DESC_TRISTATE,
> +        .index = SPAPR_CAP_SBBC,
> +        .get = spapr_cap_get_tristate,
> +        .set = spapr_cap_set_tristate,
> +        .type = "string",
> +        .allow = cap_safe_bounds_check_allow,
> +    },
> +    [SPAPR_CAP_IBS] = {
> +        .name = "ibs",
> +        .description = "Indirect Branch Serialisation",
> +        .options = VALUE_DESC_TRISTATE,
> +        .index = SPAPR_CAP_IBS,
> +        .get = spapr_cap_get_tristate,
> +        .set = spapr_cap_set_tristate,
> +        .type = "string",
> +        .allow = cap_safe_indirect_branch_allow,
> +    },
>  };
> 
>  static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
> @@ -326,6 +439,117 @@ const VMStateDescription vmstate_spapr_cap_dfp = {
>      },
>  };
> 
> +static bool spapr_cap_safe_cache_needed(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC] & SPAPR_CAP_CMD_LINE);
> +}
> +
> +static int spapr_cap_safe_cache_pre_save(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_CFPC] =
> +        spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC];
> +    return 0;
> +}
> +
> +static int spapr_cap_safe_cache_pre_load(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_CFPC] = 0;
> +    return 0;
> +}
> +
> +const VMStateDescription vmstate_spapr_cap_cfpc = {
> +    .name = "spapr/cap_cfpc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = spapr_cap_safe_cache_needed,
> +    .pre_save = spapr_cap_safe_cache_pre_save,
> +    .pre_load = spapr_cap_safe_cache_pre_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_CFPC], sPAPRMachineState),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static bool spapr_cap_safe_bounds_check_needed(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC] & SPAPR_CAP_CMD_LINE);
> +}
> +
> +static int spapr_cap_safe_bounds_check_pre_save(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_SBBC] =
> +        spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC];
> +    return 0;
> +}
> +
> +static int spapr_cap_safe_bounds_check_pre_load(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_SBBC] = 0;
> +    return 0;
> +}
> +
> +const VMStateDescription vmstate_spapr_cap_sbbc = {
> +    .name = "spapr/cap_sbbc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = spapr_cap_safe_bounds_check_needed,
> +    .pre_save = spapr_cap_safe_bounds_check_pre_save,
> +    .pre_load = spapr_cap_safe_bounds_check_pre_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_SBBC], sPAPRMachineState),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static bool spapr_cap_safe_indirect_branch_needed(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_IBS] & SPAPR_CAP_CMD_LINE);
> +}
> +
> +static int spapr_cap_safe_indirect_branch_pre_save(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_IBS] =
> +        spapr->cmd_line_caps.caps[SPAPR_CAP_IBS];
> +    return 0;
> +}
> +
> +static int spapr_cap_safe_indirect_branch_pre_load(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_IBS] = 0;
> +    return 0;
> +}
> +
> +const VMStateDescription vmstate_spapr_cap_ibs = {
> +    .name = "spapr/cap_ibs",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = spapr_cap_safe_indirect_branch_needed,
> +    .pre_save = spapr_cap_safe_indirect_branch_pre_save,
> +    .pre_load = spapr_cap_safe_indirect_branch_pre_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_IBS], sPAPRMachineState),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
>  void spapr_caps_reset(sPAPRMachineState *spapr)
>  {
>      sPAPRCapabilities caps;
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index 2804fbbf12..2db2f3e2e2 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -62,8 +62,14 @@ typedef enum {
>  #define SPAPR_CAP_VSX                   0x01
>  /* Decimal Floating Point */
>  #define SPAPR_CAP_DFP                   0x02
> +/* Cache Flush on Privilege Change */
> +#define SPAPR_CAP_CFPC                  0x03
> +/* Speculation Barrier Bounds Checking */
> +#define SPAPR_CAP_SBBC                  0x04
> +/* Indirect Branch Serialisation */
> +#define SPAPR_CAP_IBS                   0x05
>  /* Num Caps */
> -#define SPAPR_CAP_NUM                   (SPAPR_CAP_DFP + 1)
> +#define SPAPR_CAP_NUM                   (SPAPR_CAP_IBS + 1)
> 
>  /*
>   * Capability Values
> @@ -73,6 +79,10 @@ typedef enum {
>  /* Bool Caps */
>  #define SPAPR_CAP_OFF                   0x00
>  #define SPAPR_CAP_ON                    0x01
> +/* Broken | Workaround | Fixed Caps */
> +#define SPAPR_CAP_BROKEN                0x00
> +#define SPAPR_CAP_WORKAROUND            0x01
> +#define SPAPR_CAP_FIXED                 0x02
> 
>  typedef struct sPAPRCapabilities sPAPRCapabilities;
>  struct sPAPRCapabilities {
> @@ -763,6 +773,9 @@ qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
>  extern const VMStateDescription vmstate_spapr_cap_htm;
>  extern const VMStateDescription vmstate_spapr_cap_vsx;
>  extern const VMStateDescription vmstate_spapr_cap_dfp;
> +extern const VMStateDescription vmstate_spapr_cap_cfpc;
> +extern const VMStateDescription vmstate_spapr_cap_sbbc;
> +extern const VMStateDescription vmstate_spapr_cap_ibs;
> 
>  static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap)
>  {
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index ce6c2f11f4..0abe0a0abb 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -932,6 +932,9 @@ struct kvm_ppc_resize_hpt {
>  #define KVM_CAP_HYPERV_SYNIC2 148
>  #define KVM_CAP_HYPERV_VP_INDEX 149
>  #define KVM_CAP_S390_AIS_MIGRATION 150
> +#define KVM_CAP_PPC_SAFE_CACHE 151
> +#define KVM_CAP_PPC_SAFE_BOUNDS_CHECK 152
> +#define KVM_CAP_PPC_SAFE_INDIRECT_BRANCH 153
> 
>  #ifdef KVM_CAP_IRQ_ROUTING
> 
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 518dd06e98..818499237c 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -89,6 +89,9 @@ static int cap_mmu_radix;
>  static int cap_mmu_hash_v3;
>  static int cap_resize_hpt;
>  static int cap_ppc_pvr_compat;
> +static int cap_ppc_safe_cache;
> +static int cap_ppc_safe_bounds_check;
> +static int cap_ppc_safe_indirect_branch;
> 
>  static uint32_t debug_inst_opcode;
> 
> @@ -147,6 +150,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>      cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
>      cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
>      cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
> +    cap_ppc_safe_cache = kvm_vm_check_extension(s, KVM_CAP_PPC_SAFE_CACHE);
> +    cap_ppc_safe_cache = cap_ppc_safe_cache > 0 ? cap_ppc_safe_cache : 0;
> +    cap_ppc_safe_bounds_check = kvm_vm_check_extension(s,
> +                                KVM_CAP_PPC_SAFE_BOUNDS_CHECK);
> +    cap_ppc_safe_bounds_check = cap_ppc_safe_bounds_check > 0 ?
> +                                cap_ppc_safe_bounds_check : 0;
> +    cap_ppc_safe_indirect_branch = kvm_vm_check_extension(s,
> +                                   KVM_CAP_PPC_SAFE_INDIRECT_BRANCH);
> +    cap_ppc_safe_indirect_branch = cap_ppc_safe_indirect_branch > 0 ?
> +                                   cap_ppc_safe_indirect_branch : 0;
>      /*
>       * Note: setting it to false because there is not such capability
>       * in KVM at this moment.
> @@ -2456,6 +2469,21 @@ bool kvmppc_has_cap_mmu_hash_v3(void)
>      return cap_mmu_hash_v3;
>  }
> 
> +int kvmppc_get_cap_safe_cache(void)
> +{
> +    return cap_ppc_safe_cache;
> +}
> +
> +int kvmppc_get_cap_safe_bounds_check(void)
> +{
> +    return cap_ppc_safe_bounds_check;
> +}
> +
> +int kvmppc_get_cap_safe_indirect_branch(void)
> +{
> +    return cap_ppc_safe_indirect_branch;
> +}
> +
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
>  {
>      uint32_t host_pvr = mfpvr();
> diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> index ecb55493cc..39830baa77 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -59,6 +59,9 @@ bool kvmppc_has_cap_fixup_hcalls(void);
>  bool kvmppc_has_cap_htm(void);
>  bool kvmppc_has_cap_mmu_radix(void);
>  bool kvmppc_has_cap_mmu_hash_v3(void);
> +int kvmppc_get_cap_safe_cache(void);
> +int kvmppc_get_cap_safe_bounds_check(void);
> +int kvmppc_get_cap_safe_indirect_branch(void);
>  int kvmppc_enable_hwrng(void);
>  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
> @@ -290,6 +293,21 @@ static inline bool kvmppc_has_cap_mmu_hash_v3(void)
>      return false;
>  }
> 
> +static inline int kvmppc_get_cap_safe_cache(void)
> +{
> +    return 0;
> +}
> +
> +static inline int kvmppc_get_cap_safe_bounds_check(void)
> +{
> +    return 0;
> +}
> +
> +static inline int kvmppc_get_cap_safe_indirect_branch(void)
> +{
> +    return 0;
> +}
> +
>  static inline int kvmppc_enable_hwrng(void)
>  {
>      return -1;
> -- 
> 2.13.6
> 
>
Suraj Jitindar Singh Jan. 10, 2018, 12:23 a.m. UTC | #3
On Tue, 2018-01-09 at 10:02 -0200, joserz@linux.vnet.ibm.com wrote:
> On Tue, Jan 09, 2018 at 08:21:02PM +1100, Suraj Jitindar Singh wrote:
> > This patch adds three new capabilities:
> > cap-cfpc -> safe_cache
> > cap-sbbc -> safe_bounds_check
> > cap-ibs  -> safe_indirect_branch
> > 
> > Each capability is tristate with the possible values "broken",
> > "workaround" or "fixed". Add generic getter and setter functions
> > for
> > this new capability type. Add these new capabilities to the
> > capabilities
> > list. The maximum value for the capabilities is queried from kvm
> > through
> > new kvm capabilities. The requested values are considered to be
> > compatible if kvm can support an equal or higher value for each
> > capability.
> > 
> > Discussion:
> > Currently these new capabilities default to broken to allow for
> > backwards compatibility, is this the best option?
> > ---
> >  hw/ppc/spapr.c            |   6 ++
> >  hw/ppc/spapr_caps.c       | 224
> > ++++++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/ppc/spapr.h    |  15 +++-
> >  linux-headers/linux/kvm.h |   3 +
> >  target/ppc/kvm.c          |  28 ++++++
> >  target/ppc/kvm_ppc.h      |  18 ++++
> >  6 files changed, 293 insertions(+), 1 deletion(-)
> > 
> > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > index 7fa45729ba..d9700b0254 100644
> > --- a/hw/ppc/spapr.c
> > +++ b/hw/ppc/spapr.c
> > @@ -1765,6 +1765,9 @@ static const VMStateDescription vmstate_spapr
> > = {
> >          &vmstate_spapr_cap_htm,
> >          &vmstate_spapr_cap_vsx,
> >          &vmstate_spapr_cap_dfp,
> > +        &vmstate_spapr_cap_cfpc,
> > +        &vmstate_spapr_cap_sbbc,
> > +        &vmstate_spapr_cap_ibs,
> >          NULL
> >      }
> >  };
> > @@ -3837,6 +3840,9 @@ static void
> > spapr_machine_class_init(ObjectClass *oc, void *data)
> >      smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
> >      smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
> >      smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
> > +    smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
> > +    smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
> > +    smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
> >      spapr_caps_add_properties(smc, &error_abort);
> >  }
> > 
> > diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> > index af40f2e469..e6910aa191 100644
> > --- a/hw/ppc/spapr_caps.c
> > +++ b/hw/ppc/spapr_caps.c
> > @@ -75,6 +75,64 @@ static void spapr_cap_set_bool(Object *obj,
> > Visitor *v, const char *name,
> >                                               SPAPR_CAP_CMD_LINE;
> >  }
> > 
> > +static void spapr_cap_get_tristate(Object *obj, Visitor *v, const
> > char *name,
> > +                                   void *opaque, Error **errp)
> > +{
> > +    sPAPRCapabilityInfo *cap = opaque;
> > +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> > +    char *val = NULL;
> > +    uint8_t value = spapr_get_cap(spapr, cap->index);
> > +
> > +    switch (value) {
> > +    case SPAPR_CAP_BROKEN:
> > +        val = g_strdup("broken");
> > +        break;
> > +    case SPAPR_CAP_WORKAROUND:
> > +        val = g_strdup("workaround");
> > +        break;
> > +    case SPAPR_CAP_FIXED:
> > +        val = g_strdup("fixed");
> > +        break;
> > +    default:
> > +        break;
> 
> Hello Suraj
> 
> Is default a possible case? If so, will val be handled correctly by
> visit_type_str and g_free?

The default case would represent an internal error somehow and should
throw an error. Will change that.

Thanks :)

> 
> if not, maybe a throwing an error like you did in
> spapr_cap_set_tristate could be better.
> 
> > +    }
> > +
> > +    visit_type_str(v, name, &val, errp);
> > +    g_free(val);
> > +}
> > +
> > +static void spapr_cap_set_tristate(Object *obj, Visitor *v, const
> > char *name,
> > +                                   void *opaque, Error **errp)
> > +{
> > +    sPAPRCapabilityInfo *cap = opaque;
> > +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> > +    char *val;
> > +    Error *local_err = NULL;
> > +    uint8_t value;
> > +
> > +    visit_type_str(v, name, &val, &local_err);
> > +    if (local_err) {
> > +        error_propagate(errp, local_err);
> > +        return;
> > +    }
> > +
> > +    if (!strcasecmp(val, "broken")) {
> > +        value = SPAPR_CAP_BROKEN;
> > +    } else if (!strcasecmp(val, "workaround")) {
> > +        value = SPAPR_CAP_WORKAROUND;
> > +    } else if (!strcasecmp(val, "fixed")) {
> > +        value = SPAPR_CAP_FIXED;
> > +    } else {
> > +        error_setg(errp, "Invalid capability mode \"%s\" for cap-
> > %s", val,
> > +                   cap->name);
> > +        goto out;
> > +    }
> > +
> > +    spapr->cmd_line_caps.caps[cap->index] = value |
> > SPAPR_CAP_CMD_LINE;
> > +out:
> > +    g_free(val);
> > +}
> > +
> >  static void cap_htm_allow(sPAPRMachineState *spapr, uint8_t val,
> > Error **errp)
> >  {
> >      if (!val) {
> > @@ -122,6 +180,31 @@ static void cap_dfp_allow(sPAPRMachineState
> > *spapr, uint8_t val, Error **errp)
> >      }
> >  }
> > 
> > +static void cap_safe_cache_allow(sPAPRMachineState *spapr, uint8_t
> > val,
> > +                                 Error **errp)
> > +{
> > +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
> > +        error_setg(errp, "Requested safe cache capability level
> > not supported by kvm, try a different value for cap-cfpc");
> > +    }
> > +}
> > +
> > +static void cap_safe_bounds_check_allow(sPAPRMachineState *spapr,
> > uint8_t val,
> > +                                        Error **errp)
> > +{
> > +    if (kvm_enabled() && (val >
> > kvmppc_get_cap_safe_bounds_check())) {
> > +        error_setg(errp, "Requested safe bounds check capability
> > level not supported by kvm, try a different value for cap-sbbc");
> > +    }
> > +}
> > +
> > +static void cap_safe_indirect_branch_allow(sPAPRMachineState
> > *spapr,
> > +                                           uint8_t val, Error
> > **errp)
> > +{
> > +    if (kvm_enabled() && (val >
> > kvmppc_get_cap_safe_indirect_branch())) {
> > +        error_setg(errp, "Requested safe indirect branch
> > capability level not supported by kvm, try a different value for
> > cap-ibs");
> > +    }
> > +}
> > +
> > +#define VALUE_DESC_TRISTATE     " (broken, workaround, fixed)"
> > 
> >  sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
> >      [SPAPR_CAP_HTM] = {
> > @@ -154,6 +237,36 @@ sPAPRCapabilityInfo
> > capability_table[SPAPR_CAP_NUM] = {
> >          .type = "bool",
> >          .allow = cap_dfp_allow,
> >      },
> > +    [SPAPR_CAP_CFPC] = {
> > +        .name = "cfpc",
> > +        .description = "Cache Flush on Privilege Change",
> > +        .options = VALUE_DESC_TRISTATE,
> > +        .index = SPAPR_CAP_CFPC,
> > +        .get = spapr_cap_get_tristate,
> > +        .set = spapr_cap_set_tristate,
> > +        .type = "string",
> > +        .allow = cap_safe_cache_allow,
> > +    },
> > +    [SPAPR_CAP_SBBC] = {
> > +        .name = "sbbc",
> > +        .description = "Speculation Barrier Bounds Checking",
> > +        .options = VALUE_DESC_TRISTATE,
> > +        .index = SPAPR_CAP_SBBC,
> > +        .get = spapr_cap_get_tristate,
> > +        .set = spapr_cap_set_tristate,
> > +        .type = "string",
> > +        .allow = cap_safe_bounds_check_allow,
> > +    },
> > +    [SPAPR_CAP_IBS] = {
> > +        .name = "ibs",
> > +        .description = "Indirect Branch Serialisation",
> > +        .options = VALUE_DESC_TRISTATE,
> > +        .index = SPAPR_CAP_IBS,
> > +        .get = spapr_cap_get_tristate,
> > +        .set = spapr_cap_set_tristate,
> > +        .type = "string",
> > +        .allow = cap_safe_indirect_branch_allow,
> > +    },
> >  };
> > 
> >  static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState
> > *spapr,
> > @@ -326,6 +439,117 @@ const VMStateDescription
> > vmstate_spapr_cap_dfp = {
> >      },
> >  };
> > 
> > +static bool spapr_cap_safe_cache_needed(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC] &
> > SPAPR_CAP_CMD_LINE);
> > +}
> > +
> > +static int spapr_cap_safe_cache_pre_save(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_CFPC] =
> > +        spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC];
> > +    return 0;
> > +}
> > +
> > +static int spapr_cap_safe_cache_pre_load(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_CFPC] = 0;
> > +    return 0;
> > +}
> > +
> > +const VMStateDescription vmstate_spapr_cap_cfpc = {
> > +    .name = "spapr/cap_cfpc",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = spapr_cap_safe_cache_needed,
> > +    .pre_save = spapr_cap_safe_cache_pre_save,
> > +    .pre_load = spapr_cap_safe_cache_pre_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_CFPC],
> > sPAPRMachineState),
> > +        VMSTATE_END_OF_LIST()
> > +    },
> > +};
> > +
> > +static bool spapr_cap_safe_bounds_check_needed(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC] &
> > SPAPR_CAP_CMD_LINE);
> > +}
> > +
> > +static int spapr_cap_safe_bounds_check_pre_save(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_SBBC] =
> > +        spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC];
> > +    return 0;
> > +}
> > +
> > +static int spapr_cap_safe_bounds_check_pre_load(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_SBBC] = 0;
> > +    return 0;
> > +}
> > +
> > +const VMStateDescription vmstate_spapr_cap_sbbc = {
> > +    .name = "spapr/cap_sbbc",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = spapr_cap_safe_bounds_check_needed,
> > +    .pre_save = spapr_cap_safe_bounds_check_pre_save,
> > +    .pre_load = spapr_cap_safe_bounds_check_pre_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_SBBC],
> > sPAPRMachineState),
> > +        VMSTATE_END_OF_LIST()
> > +    },
> > +};
> > +
> > +static bool spapr_cap_safe_indirect_branch_needed(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_IBS] &
> > SPAPR_CAP_CMD_LINE);
> > +}
> > +
> > +static int spapr_cap_safe_indirect_branch_pre_save(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_IBS] =
> > +        spapr->cmd_line_caps.caps[SPAPR_CAP_IBS];
> > +    return 0;
> > +}
> > +
> > +static int spapr_cap_safe_indirect_branch_pre_load(void *opaque)
> > +{
> > +    sPAPRMachineState *spapr = opaque;
> > +
> > +    spapr->mig_caps.caps[SPAPR_CAP_IBS] = 0;
> > +    return 0;
> > +}
> > +
> > +const VMStateDescription vmstate_spapr_cap_ibs = {
> > +    .name = "spapr/cap_ibs",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = spapr_cap_safe_indirect_branch_needed,
> > +    .pre_save = spapr_cap_safe_indirect_branch_pre_save,
> > +    .pre_load = spapr_cap_safe_indirect_branch_pre_load,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_IBS],
> > sPAPRMachineState),
> > +        VMSTATE_END_OF_LIST()
> > +    },
> > +};
> > +
> >  void spapr_caps_reset(sPAPRMachineState *spapr)
> >  {
> >      sPAPRCapabilities caps;
> > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> > index 2804fbbf12..2db2f3e2e2 100644
> > --- a/include/hw/ppc/spapr.h
> > +++ b/include/hw/ppc/spapr.h
> > @@ -62,8 +62,14 @@ typedef enum {
> >  #define SPAPR_CAP_VSX                   0x01
> >  /* Decimal Floating Point */
> >  #define SPAPR_CAP_DFP                   0x02
> > +/* Cache Flush on Privilege Change */
> > +#define SPAPR_CAP_CFPC                  0x03
> > +/* Speculation Barrier Bounds Checking */
> > +#define SPAPR_CAP_SBBC                  0x04
> > +/* Indirect Branch Serialisation */
> > +#define SPAPR_CAP_IBS                   0x05
> >  /* Num Caps */
> > -#define SPAPR_CAP_NUM                   (SPAPR_CAP_DFP + 1)
> > +#define SPAPR_CAP_NUM                   (SPAPR_CAP_IBS + 1)
> > 
> >  /*
> >   * Capability Values
> > @@ -73,6 +79,10 @@ typedef enum {
> >  /* Bool Caps */
> >  #define SPAPR_CAP_OFF                   0x00
> >  #define SPAPR_CAP_ON                    0x01
> > +/* Broken | Workaround | Fixed Caps */
> > +#define SPAPR_CAP_BROKEN                0x00
> > +#define SPAPR_CAP_WORKAROUND            0x01
> > +#define SPAPR_CAP_FIXED                 0x02
> > 
> >  typedef struct sPAPRCapabilities sPAPRCapabilities;
> >  struct sPAPRCapabilities {
> > @@ -763,6 +773,9 @@ qemu_irq spapr_qirq(sPAPRMachineState *spapr,
> > int irq);
> >  extern const VMStateDescription vmstate_spapr_cap_htm;
> >  extern const VMStateDescription vmstate_spapr_cap_vsx;
> >  extern const VMStateDescription vmstate_spapr_cap_dfp;
> > +extern const VMStateDescription vmstate_spapr_cap_cfpc;
> > +extern const VMStateDescription vmstate_spapr_cap_sbbc;
> > +extern const VMStateDescription vmstate_spapr_cap_ibs;
> > 
> >  static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int
> > cap)
> >  {
> > diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> > index ce6c2f11f4..0abe0a0abb 100644
> > --- a/linux-headers/linux/kvm.h
> > +++ b/linux-headers/linux/kvm.h
> > @@ -932,6 +932,9 @@ struct kvm_ppc_resize_hpt {
> >  #define KVM_CAP_HYPERV_SYNIC2 148
> >  #define KVM_CAP_HYPERV_VP_INDEX 149
> >  #define KVM_CAP_S390_AIS_MIGRATION 150
> > +#define KVM_CAP_PPC_SAFE_CACHE 151
> > +#define KVM_CAP_PPC_SAFE_BOUNDS_CHECK 152
> > +#define KVM_CAP_PPC_SAFE_INDIRECT_BRANCH 153
> > 
> >  #ifdef KVM_CAP_IRQ_ROUTING
> > 
> > diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> > index 518dd06e98..818499237c 100644
> > --- a/target/ppc/kvm.c
> > +++ b/target/ppc/kvm.c
> > @@ -89,6 +89,9 @@ static int cap_mmu_radix;
> >  static int cap_mmu_hash_v3;
> >  static int cap_resize_hpt;
> >  static int cap_ppc_pvr_compat;
> > +static int cap_ppc_safe_cache;
> > +static int cap_ppc_safe_bounds_check;
> > +static int cap_ppc_safe_indirect_branch;
> > 
> >  static uint32_t debug_inst_opcode;
> > 
> > @@ -147,6 +150,16 @@ int kvm_arch_init(MachineState *ms, KVMState
> > *s)
> >      cap_mmu_radix = kvm_vm_check_extension(s,
> > KVM_CAP_PPC_MMU_RADIX);
> >      cap_mmu_hash_v3 = kvm_vm_check_extension(s,
> > KVM_CAP_PPC_MMU_HASH_V3);
> >      cap_resize_hpt = kvm_vm_check_extension(s,
> > KVM_CAP_SPAPR_RESIZE_HPT);
> > +    cap_ppc_safe_cache = kvm_vm_check_extension(s,
> > KVM_CAP_PPC_SAFE_CACHE);
> > +    cap_ppc_safe_cache = cap_ppc_safe_cache > 0 ?
> > cap_ppc_safe_cache : 0;
> > +    cap_ppc_safe_bounds_check = kvm_vm_check_extension(s,
> > +                                KVM_CAP_PPC_SAFE_BOUNDS_CHECK);
> > +    cap_ppc_safe_bounds_check = cap_ppc_safe_bounds_check > 0 ?
> > +                                cap_ppc_safe_bounds_check : 0;
> > +    cap_ppc_safe_indirect_branch = kvm_vm_check_extension(s,
> > +                                   KVM_CAP_PPC_SAFE_INDIRECT_BRANC
> > H);
> > +    cap_ppc_safe_indirect_branch = cap_ppc_safe_indirect_branch >
> > 0 ?
> > +                                   cap_ppc_safe_indirect_branch :
> > 0;
> >      /*
> >       * Note: setting it to false because there is not such
> > capability
> >       * in KVM at this moment.
> > @@ -2456,6 +2469,21 @@ bool kvmppc_has_cap_mmu_hash_v3(void)
> >      return cap_mmu_hash_v3;
> >  }
> > 
> > +int kvmppc_get_cap_safe_cache(void)
> > +{
> > +    return cap_ppc_safe_cache;
> > +}
> > +
> > +int kvmppc_get_cap_safe_bounds_check(void)
> > +{
> > +    return cap_ppc_safe_bounds_check;
> > +}
> > +
> > +int kvmppc_get_cap_safe_indirect_branch(void)
> > +{
> > +    return cap_ppc_safe_indirect_branch;
> > +}
> > +
> >  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
> >  {
> >      uint32_t host_pvr = mfpvr();
> > diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> > index ecb55493cc..39830baa77 100644
> > --- a/target/ppc/kvm_ppc.h
> > +++ b/target/ppc/kvm_ppc.h
> > @@ -59,6 +59,9 @@ bool kvmppc_has_cap_fixup_hcalls(void);
> >  bool kvmppc_has_cap_htm(void);
> >  bool kvmppc_has_cap_mmu_radix(void);
> >  bool kvmppc_has_cap_mmu_hash_v3(void);
> > +int kvmppc_get_cap_safe_cache(void);
> > +int kvmppc_get_cap_safe_bounds_check(void);
> > +int kvmppc_get_cap_safe_indirect_branch(void);
> >  int kvmppc_enable_hwrng(void);
> >  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
> >  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
> > @@ -290,6 +293,21 @@ static inline bool
> > kvmppc_has_cap_mmu_hash_v3(void)
> >      return false;
> >  }
> > 
> > +static inline int kvmppc_get_cap_safe_cache(void)
> > +{
> > +    return 0;
> > +}
> > +
> > +static inline int kvmppc_get_cap_safe_bounds_check(void)
> > +{
> > +    return 0;
> > +}
> > +
> > +static inline int kvmppc_get_cap_safe_indirect_branch(void)
> > +{
> > +    return 0;
> > +}
> > +
> >  static inline int kvmppc_enable_hwrng(void)
> >  {
> >      return -1;
> > -- 
> > 2.13.6
> > 
> > 
> 
>
Suraj Jitindar Singh Jan. 10, 2018, 12:25 a.m. UTC | #4
On Tue, 2018-01-09 at 09:15 -0200, Murilo Opsfelder Araújo wrote:
> On 01/09/2018 07:21 AM, Suraj Jitindar Singh wrote:
> > This patch adds three new capabilities:
> > cap-cfpc -> safe_cache
> > cap-sbbc -> safe_bounds_check
> > cap-ibs  -> safe_indirect_branch
> 
> Hi, Suraj.
> 
> What about splitting this into smaller patches, one per capability?

Yep

> 
> > Each capability is tristate with the possible values "broken",
> > "workaround" or "fixed". Add generic getter and setter functions
> > for
> > this new capability type. Add these new capabilities to the
> > capabilities
> > list. The maximum value for the capabilities is queried from kvm
> > through
> > new kvm capabilities. The requested values are considered to be
> > compatible if kvm can support an equal or higher value for each
> > capability.
> > 
> > Discussion:
> > Currently these new capabilities default to broken to allow for
> > backwards compatibility, is this the best option?
> 
> This could be placed in the cover letter, not in the commit 

Only here because this is an RFC

> 
> Cheers
> Murilo
>
David Gibson Jan. 10, 2018, 4:54 a.m. UTC | #5
On Tue, Jan 09, 2018 at 08:21:02PM +1100, Suraj Jitindar Singh wrote:
> This patch adds three new capabilities:
> cap-cfpc -> safe_cache
> cap-sbbc -> safe_bounds_check
> cap-ibs  -> safe_indirect_branch
> 
> Each capability is tristate with the possible values "broken",
> "workaround" or "fixed". Add generic getter and setter functions for
> this new capability type. Add these new capabilities to the capabilities
> list. The maximum value for the capabilities is queried from kvm through
> new kvm capabilities. The requested values are considered to be
> compatible if kvm can support an equal or higher value for each
> capability.
> 
> Discussion:
> Currently these new capabilities default to broken to allow for
> backwards compatibility, is this the best option?
> ---
>  hw/ppc/spapr.c            |   6 ++
>  hw/ppc/spapr_caps.c       | 224 ++++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/ppc/spapr.h    |  15 +++-
>  linux-headers/linux/kvm.h |   3 +
>  target/ppc/kvm.c          |  28 ++++++
>  target/ppc/kvm_ppc.h      |  18 ++++
>  6 files changed, 293 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 7fa45729ba..d9700b0254 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1765,6 +1765,9 @@ static const VMStateDescription vmstate_spapr = {
>          &vmstate_spapr_cap_htm,
>          &vmstate_spapr_cap_vsx,
>          &vmstate_spapr_cap_dfp,
> +        &vmstate_spapr_cap_cfpc,
> +        &vmstate_spapr_cap_sbbc,
> +        &vmstate_spapr_cap_ibs,
>          NULL
>      }
>  };
> @@ -3837,6 +3840,9 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
>      smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
>      smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
>      smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
> +    smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
> +    smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
> +    smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
>      spapr_caps_add_properties(smc, &error_abort);
>  }
>  
> diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
> index af40f2e469..e6910aa191 100644
> --- a/hw/ppc/spapr_caps.c
> +++ b/hw/ppc/spapr_caps.c
> @@ -75,6 +75,64 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
>                                               SPAPR_CAP_CMD_LINE;
>  }
>  
> +static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
> +{
> +    sPAPRCapabilityInfo *cap = opaque;
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> +    char *val = NULL;
> +    uint8_t value = spapr_get_cap(spapr, cap->index);
> +
> +    switch (value) {
> +    case SPAPR_CAP_BROKEN:
> +        val = g_strdup("broken");
> +        break;
> +    case SPAPR_CAP_WORKAROUND:
> +        val = g_strdup("workaround");
> +        break;
> +    case SPAPR_CAP_FIXED:
> +        val = g_strdup("fixed");
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    visit_type_str(v, name, &val, errp);
> +    g_free(val);
> +}
> +
> +static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
> +{
> +    sPAPRCapabilityInfo *cap = opaque;
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
> +    char *val;
> +    Error *local_err = NULL;
> +    uint8_t value;
> +
> +    visit_type_str(v, name, &val, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    if (!strcasecmp(val, "broken")) {
> +        value = SPAPR_CAP_BROKEN;
> +    } else if (!strcasecmp(val, "workaround")) {
> +        value = SPAPR_CAP_WORKAROUND;
> +    } else if (!strcasecmp(val, "fixed")) {
> +        value = SPAPR_CAP_FIXED;
> +    } else {
> +        error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
> +                   cap->name);
> +        goto out;
> +    }
> +
> +    spapr->cmd_line_caps.caps[cap->index] = value | SPAPR_CAP_CMD_LINE;
> +out:
> +    g_free(val);
> +}
> +
>  static void cap_htm_allow(sPAPRMachineState *spapr, uint8_t val, Error **errp)
>  {
>      if (!val) {
> @@ -122,6 +180,31 @@ static void cap_dfp_allow(sPAPRMachineState *spapr, uint8_t val, Error **errp)
>      }
>  }
>  
> +static void cap_safe_cache_allow(sPAPRMachineState *spapr, uint8_t val,
> +                                 Error **errp)
> +{
> +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
> +        error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
> +    }

Maybe throw in a FIXME comment for TCG.  Given the bugs can be
triggered via Javascript, there's a good chance they can be triggered
via TCG as well - but obviously we don't want to delay the KVM fixes
to work out what the TCG situation is.

> +}
> +
> +static void cap_safe_bounds_check_allow(sPAPRMachineState *spapr, uint8_t val,
> +                                        Error **errp)
> +{
> +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
> +        error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
> +    }
> +}
> +
> +static void cap_safe_indirect_branch_allow(sPAPRMachineState *spapr,
> +                                           uint8_t val, Error **errp)
> +{
> +    if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
> +        error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
> +    }
> +}
> +
> +#define VALUE_DESC_TRISTATE     " (broken, workaround, fixed)"
>  
>  sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
>      [SPAPR_CAP_HTM] = {
> @@ -154,6 +237,36 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
>          .type = "bool",
>          .allow = cap_dfp_allow,
>      },
> +    [SPAPR_CAP_CFPC] = {
> +        .name = "cfpc",
> +        .description = "Cache Flush on Privilege Change",
> +        .options = VALUE_DESC_TRISTATE,
> +        .index = SPAPR_CAP_CFPC,
> +        .get = spapr_cap_get_tristate,
> +        .set = spapr_cap_set_tristate,
> +        .type = "string",
> +        .allow = cap_safe_cache_allow,
> +    },
> +    [SPAPR_CAP_SBBC] = {
> +        .name = "sbbc",
> +        .description = "Speculation Barrier Bounds Checking",
> +        .options = VALUE_DESC_TRISTATE,
> +        .index = SPAPR_CAP_SBBC,
> +        .get = spapr_cap_get_tristate,
> +        .set = spapr_cap_set_tristate,
> +        .type = "string",
> +        .allow = cap_safe_bounds_check_allow,
> +    },
> +    [SPAPR_CAP_IBS] = {
> +        .name = "ibs",
> +        .description = "Indirect Branch Serialisation",
> +        .options = VALUE_DESC_TRISTATE,
> +        .index = SPAPR_CAP_IBS,
> +        .get = spapr_cap_get_tristate,
> +        .set = spapr_cap_set_tristate,
> +        .type = "string",
> +        .allow = cap_safe_indirect_branch_allow,
> +    },
>  };
>  
>  static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
> @@ -326,6 +439,117 @@ const VMStateDescription vmstate_spapr_cap_dfp = {
>      },
>  };
>  
> +static bool spapr_cap_safe_cache_needed(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC] & SPAPR_CAP_CMD_LINE);
> +}
> +
> +static int spapr_cap_safe_cache_pre_save(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_CFPC] =
> +        spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC];
> +    return 0;
> +}
> +
> +static int spapr_cap_safe_cache_pre_load(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_CFPC] = 0;
> +    return 0;
> +}
> +
> +const VMStateDescription vmstate_spapr_cap_cfpc = {
> +    .name = "spapr/cap_cfpc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = spapr_cap_safe_cache_needed,
> +    .pre_save = spapr_cap_safe_cache_pre_save,
> +    .pre_load = spapr_cap_safe_cache_pre_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_CFPC], sPAPRMachineState),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static bool spapr_cap_safe_bounds_check_needed(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC] & SPAPR_CAP_CMD_LINE);
> +}
> +
> +static int spapr_cap_safe_bounds_check_pre_save(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_SBBC] =
> +        spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC];
> +    return 0;
> +}
> +
> +static int spapr_cap_safe_bounds_check_pre_load(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_SBBC] = 0;
> +    return 0;
> +}
> +
> +const VMStateDescription vmstate_spapr_cap_sbbc = {
> +    .name = "spapr/cap_sbbc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = spapr_cap_safe_bounds_check_needed,
> +    .pre_save = spapr_cap_safe_bounds_check_pre_save,
> +    .pre_load = spapr_cap_safe_bounds_check_pre_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_SBBC], sPAPRMachineState),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static bool spapr_cap_safe_indirect_branch_needed(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_IBS] & SPAPR_CAP_CMD_LINE);
> +}
> +
> +static int spapr_cap_safe_indirect_branch_pre_save(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_IBS] =
> +        spapr->cmd_line_caps.caps[SPAPR_CAP_IBS];
> +    return 0;
> +}
> +
> +static int spapr_cap_safe_indirect_branch_pre_load(void *opaque)
> +{
> +    sPAPRMachineState *spapr = opaque;
> +
> +    spapr->mig_caps.caps[SPAPR_CAP_IBS] = 0;
> +    return 0;
> +}
> +
> +const VMStateDescription vmstate_spapr_cap_ibs = {
> +    .name = "spapr/cap_ibs",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = spapr_cap_safe_indirect_branch_needed,
> +    .pre_save = spapr_cap_safe_indirect_branch_pre_save,
> +    .pre_load = spapr_cap_safe_indirect_branch_pre_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_IBS], sPAPRMachineState),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
>  void spapr_caps_reset(sPAPRMachineState *spapr)
>  {
>      sPAPRCapabilities caps;
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index 2804fbbf12..2db2f3e2e2 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -62,8 +62,14 @@ typedef enum {
>  #define SPAPR_CAP_VSX                   0x01
>  /* Decimal Floating Point */
>  #define SPAPR_CAP_DFP                   0x02
> +/* Cache Flush on Privilege Change */
> +#define SPAPR_CAP_CFPC                  0x03
> +/* Speculation Barrier Bounds Checking */
> +#define SPAPR_CAP_SBBC                  0x04
> +/* Indirect Branch Serialisation */
> +#define SPAPR_CAP_IBS                   0x05
>  /* Num Caps */
> -#define SPAPR_CAP_NUM                   (SPAPR_CAP_DFP + 1)
> +#define SPAPR_CAP_NUM                   (SPAPR_CAP_IBS + 1)
>  
>  /*
>   * Capability Values
> @@ -73,6 +79,10 @@ typedef enum {
>  /* Bool Caps */
>  #define SPAPR_CAP_OFF                   0x00
>  #define SPAPR_CAP_ON                    0x01
> +/* Broken | Workaround | Fixed Caps */
> +#define SPAPR_CAP_BROKEN                0x00
> +#define SPAPR_CAP_WORKAROUND            0x01
> +#define SPAPR_CAP_FIXED                 0x02
>  
>  typedef struct sPAPRCapabilities sPAPRCapabilities;
>  struct sPAPRCapabilities {
> @@ -763,6 +773,9 @@ qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
>  extern const VMStateDescription vmstate_spapr_cap_htm;
>  extern const VMStateDescription vmstate_spapr_cap_vsx;
>  extern const VMStateDescription vmstate_spapr_cap_dfp;
> +extern const VMStateDescription vmstate_spapr_cap_cfpc;
> +extern const VMStateDescription vmstate_spapr_cap_sbbc;
> +extern const VMStateDescription vmstate_spapr_cap_ibs;
>  
>  static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap)
>  {
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index ce6c2f11f4..0abe0a0abb 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -932,6 +932,9 @@ struct kvm_ppc_resize_hpt {
>  #define KVM_CAP_HYPERV_SYNIC2 148
>  #define KVM_CAP_HYPERV_VP_INDEX 149
>  #define KVM_CAP_S390_AIS_MIGRATION 150
> +#define KVM_CAP_PPC_SAFE_CACHE 151
> +#define KVM_CAP_PPC_SAFE_BOUNDS_CHECK 152
> +#define KVM_CAP_PPC_SAFE_INDIRECT_BRANCH 153
>  
>  #ifdef KVM_CAP_IRQ_ROUTING
>  
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 518dd06e98..818499237c 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -89,6 +89,9 @@ static int cap_mmu_radix;
>  static int cap_mmu_hash_v3;
>  static int cap_resize_hpt;
>  static int cap_ppc_pvr_compat;
> +static int cap_ppc_safe_cache;
> +static int cap_ppc_safe_bounds_check;
> +static int cap_ppc_safe_indirect_branch;
>  
>  static uint32_t debug_inst_opcode;
>  
> @@ -147,6 +150,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
>      cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
>      cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
>      cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
> +    cap_ppc_safe_cache = kvm_vm_check_extension(s, KVM_CAP_PPC_SAFE_CACHE);
> +    cap_ppc_safe_cache = cap_ppc_safe_cache > 0 ? cap_ppc_safe_cache : 0;
> +    cap_ppc_safe_bounds_check = kvm_vm_check_extension(s,
> +                                KVM_CAP_PPC_SAFE_BOUNDS_CHECK);
> +    cap_ppc_safe_bounds_check = cap_ppc_safe_bounds_check > 0 ?
> +                                cap_ppc_safe_bounds_check : 0;
> +    cap_ppc_safe_indirect_branch = kvm_vm_check_extension(s,
> +                                   KVM_CAP_PPC_SAFE_INDIRECT_BRANCH);
> +    cap_ppc_safe_indirect_branch = cap_ppc_safe_indirect_branch > 0 ?
> +                                   cap_ppc_safe_indirect_branch : 0;
>      /*
>       * Note: setting it to false because there is not such capability
>       * in KVM at this moment.
> @@ -2456,6 +2469,21 @@ bool kvmppc_has_cap_mmu_hash_v3(void)
>      return cap_mmu_hash_v3;
>  }
>  
> +int kvmppc_get_cap_safe_cache(void)
> +{
> +    return cap_ppc_safe_cache;
> +}
> +
> +int kvmppc_get_cap_safe_bounds_check(void)
> +{
> +    return cap_ppc_safe_bounds_check;
> +}
> +
> +int kvmppc_get_cap_safe_indirect_branch(void)
> +{
> +    return cap_ppc_safe_indirect_branch;
> +}
> +
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
>  {
>      uint32_t host_pvr = mfpvr();
> diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> index ecb55493cc..39830baa77 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -59,6 +59,9 @@ bool kvmppc_has_cap_fixup_hcalls(void);
>  bool kvmppc_has_cap_htm(void);
>  bool kvmppc_has_cap_mmu_radix(void);
>  bool kvmppc_has_cap_mmu_hash_v3(void);
> +int kvmppc_get_cap_safe_cache(void);
> +int kvmppc_get_cap_safe_bounds_check(void);
> +int kvmppc_get_cap_safe_indirect_branch(void);
>  int kvmppc_enable_hwrng(void);
>  int kvmppc_put_books_sregs(PowerPCCPU *cpu);
>  PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
> @@ -290,6 +293,21 @@ static inline bool kvmppc_has_cap_mmu_hash_v3(void)
>      return false;
>  }
>  
> +static inline int kvmppc_get_cap_safe_cache(void)
> +{
> +    return 0;
> +}
> +
> +static inline int kvmppc_get_cap_safe_bounds_check(void)
> +{
> +    return 0;
> +}
> +
> +static inline int kvmppc_get_cap_safe_indirect_branch(void)
> +{
> +    return 0;
> +}
> +
>  static inline int kvmppc_enable_hwrng(void)
>  {
>      return -1;
diff mbox

Patch

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 7fa45729ba..d9700b0254 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1765,6 +1765,9 @@  static const VMStateDescription vmstate_spapr = {
         &vmstate_spapr_cap_htm,
         &vmstate_spapr_cap_vsx,
         &vmstate_spapr_cap_dfp,
+        &vmstate_spapr_cap_cfpc,
+        &vmstate_spapr_cap_sbbc,
+        &vmstate_spapr_cap_ibs,
         NULL
     }
 };
@@ -3837,6 +3840,9 @@  static void spapr_machine_class_init(ObjectClass *oc, void *data)
     smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
     smc->default_caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_ON;
     smc->default_caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_ON;
+    smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
+    smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
+    smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
     spapr_caps_add_properties(smc, &error_abort);
 }
 
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index af40f2e469..e6910aa191 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -75,6 +75,64 @@  static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
                                              SPAPR_CAP_CMD_LINE;
 }
 
+static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
+                                   void *opaque, Error **errp)
+{
+    sPAPRCapabilityInfo *cap = opaque;
+    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+    char *val = NULL;
+    uint8_t value = spapr_get_cap(spapr, cap->index);
+
+    switch (value) {
+    case SPAPR_CAP_BROKEN:
+        val = g_strdup("broken");
+        break;
+    case SPAPR_CAP_WORKAROUND:
+        val = g_strdup("workaround");
+        break;
+    case SPAPR_CAP_FIXED:
+        val = g_strdup("fixed");
+        break;
+    default:
+        break;
+    }
+
+    visit_type_str(v, name, &val, errp);
+    g_free(val);
+}
+
+static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
+                                   void *opaque, Error **errp)
+{
+    sPAPRCapabilityInfo *cap = opaque;
+    sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+    char *val;
+    Error *local_err = NULL;
+    uint8_t value;
+
+    visit_type_str(v, name, &val, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    if (!strcasecmp(val, "broken")) {
+        value = SPAPR_CAP_BROKEN;
+    } else if (!strcasecmp(val, "workaround")) {
+        value = SPAPR_CAP_WORKAROUND;
+    } else if (!strcasecmp(val, "fixed")) {
+        value = SPAPR_CAP_FIXED;
+    } else {
+        error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
+                   cap->name);
+        goto out;
+    }
+
+    spapr->cmd_line_caps.caps[cap->index] = value | SPAPR_CAP_CMD_LINE;
+out:
+    g_free(val);
+}
+
 static void cap_htm_allow(sPAPRMachineState *spapr, uint8_t val, Error **errp)
 {
     if (!val) {
@@ -122,6 +180,31 @@  static void cap_dfp_allow(sPAPRMachineState *spapr, uint8_t val, Error **errp)
     }
 }
 
+static void cap_safe_cache_allow(sPAPRMachineState *spapr, uint8_t val,
+                                 Error **errp)
+{
+    if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
+        error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
+    }
+}
+
+static void cap_safe_bounds_check_allow(sPAPRMachineState *spapr, uint8_t val,
+                                        Error **errp)
+{
+    if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
+        error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
+    }
+}
+
+static void cap_safe_indirect_branch_allow(sPAPRMachineState *spapr,
+                                           uint8_t val, Error **errp)
+{
+    if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
+        error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
+    }
+}
+
+#define VALUE_DESC_TRISTATE     " (broken, workaround, fixed)"
 
 sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
     [SPAPR_CAP_HTM] = {
@@ -154,6 +237,36 @@  sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
         .type = "bool",
         .allow = cap_dfp_allow,
     },
+    [SPAPR_CAP_CFPC] = {
+        .name = "cfpc",
+        .description = "Cache Flush on Privilege Change",
+        .options = VALUE_DESC_TRISTATE,
+        .index = SPAPR_CAP_CFPC,
+        .get = spapr_cap_get_tristate,
+        .set = spapr_cap_set_tristate,
+        .type = "string",
+        .allow = cap_safe_cache_allow,
+    },
+    [SPAPR_CAP_SBBC] = {
+        .name = "sbbc",
+        .description = "Speculation Barrier Bounds Checking",
+        .options = VALUE_DESC_TRISTATE,
+        .index = SPAPR_CAP_SBBC,
+        .get = spapr_cap_get_tristate,
+        .set = spapr_cap_set_tristate,
+        .type = "string",
+        .allow = cap_safe_bounds_check_allow,
+    },
+    [SPAPR_CAP_IBS] = {
+        .name = "ibs",
+        .description = "Indirect Branch Serialisation",
+        .options = VALUE_DESC_TRISTATE,
+        .index = SPAPR_CAP_IBS,
+        .get = spapr_cap_get_tristate,
+        .set = spapr_cap_set_tristate,
+        .type = "string",
+        .allow = cap_safe_indirect_branch_allow,
+    },
 };
 
 static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
@@ -326,6 +439,117 @@  const VMStateDescription vmstate_spapr_cap_dfp = {
     },
 };
 
+static bool spapr_cap_safe_cache_needed(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC] & SPAPR_CAP_CMD_LINE);
+}
+
+static int spapr_cap_safe_cache_pre_save(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    spapr->mig_caps.caps[SPAPR_CAP_CFPC] =
+        spapr->cmd_line_caps.caps[SPAPR_CAP_CFPC];
+    return 0;
+}
+
+static int spapr_cap_safe_cache_pre_load(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    spapr->mig_caps.caps[SPAPR_CAP_CFPC] = 0;
+    return 0;
+}
+
+const VMStateDescription vmstate_spapr_cap_cfpc = {
+    .name = "spapr/cap_cfpc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = spapr_cap_safe_cache_needed,
+    .pre_save = spapr_cap_safe_cache_pre_save,
+    .pre_load = spapr_cap_safe_cache_pre_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_CFPC], sPAPRMachineState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static bool spapr_cap_safe_bounds_check_needed(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC] & SPAPR_CAP_CMD_LINE);
+}
+
+static int spapr_cap_safe_bounds_check_pre_save(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    spapr->mig_caps.caps[SPAPR_CAP_SBBC] =
+        spapr->cmd_line_caps.caps[SPAPR_CAP_SBBC];
+    return 0;
+}
+
+static int spapr_cap_safe_bounds_check_pre_load(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    spapr->mig_caps.caps[SPAPR_CAP_SBBC] = 0;
+    return 0;
+}
+
+const VMStateDescription vmstate_spapr_cap_sbbc = {
+    .name = "spapr/cap_sbbc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = spapr_cap_safe_bounds_check_needed,
+    .pre_save = spapr_cap_safe_bounds_check_pre_save,
+    .pre_load = spapr_cap_safe_bounds_check_pre_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_SBBC], sPAPRMachineState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static bool spapr_cap_safe_indirect_branch_needed(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    return !!(spapr->cmd_line_caps.caps[SPAPR_CAP_IBS] & SPAPR_CAP_CMD_LINE);
+}
+
+static int spapr_cap_safe_indirect_branch_pre_save(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    spapr->mig_caps.caps[SPAPR_CAP_IBS] =
+        spapr->cmd_line_caps.caps[SPAPR_CAP_IBS];
+    return 0;
+}
+
+static int spapr_cap_safe_indirect_branch_pre_load(void *opaque)
+{
+    sPAPRMachineState *spapr = opaque;
+
+    spapr->mig_caps.caps[SPAPR_CAP_IBS] = 0;
+    return 0;
+}
+
+const VMStateDescription vmstate_spapr_cap_ibs = {
+    .name = "spapr/cap_ibs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = spapr_cap_safe_indirect_branch_needed,
+    .pre_save = spapr_cap_safe_indirect_branch_pre_save,
+    .pre_load = spapr_cap_safe_indirect_branch_pre_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(mig_caps.caps[SPAPR_CAP_IBS], sPAPRMachineState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 void spapr_caps_reset(sPAPRMachineState *spapr)
 {
     sPAPRCapabilities caps;
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 2804fbbf12..2db2f3e2e2 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -62,8 +62,14 @@  typedef enum {
 #define SPAPR_CAP_VSX                   0x01
 /* Decimal Floating Point */
 #define SPAPR_CAP_DFP                   0x02
+/* Cache Flush on Privilege Change */
+#define SPAPR_CAP_CFPC                  0x03
+/* Speculation Barrier Bounds Checking */
+#define SPAPR_CAP_SBBC                  0x04
+/* Indirect Branch Serialisation */
+#define SPAPR_CAP_IBS                   0x05
 /* Num Caps */
-#define SPAPR_CAP_NUM                   (SPAPR_CAP_DFP + 1)
+#define SPAPR_CAP_NUM                   (SPAPR_CAP_IBS + 1)
 
 /*
  * Capability Values
@@ -73,6 +79,10 @@  typedef enum {
 /* Bool Caps */
 #define SPAPR_CAP_OFF                   0x00
 #define SPAPR_CAP_ON                    0x01
+/* Broken | Workaround | Fixed Caps */
+#define SPAPR_CAP_BROKEN                0x00
+#define SPAPR_CAP_WORKAROUND            0x01
+#define SPAPR_CAP_FIXED                 0x02
 
 typedef struct sPAPRCapabilities sPAPRCapabilities;
 struct sPAPRCapabilities {
@@ -763,6 +773,9 @@  qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
 extern const VMStateDescription vmstate_spapr_cap_htm;
 extern const VMStateDescription vmstate_spapr_cap_vsx;
 extern const VMStateDescription vmstate_spapr_cap_dfp;
+extern const VMStateDescription vmstate_spapr_cap_cfpc;
+extern const VMStateDescription vmstate_spapr_cap_sbbc;
+extern const VMStateDescription vmstate_spapr_cap_ibs;
 
 static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap)
 {
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index ce6c2f11f4..0abe0a0abb 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -932,6 +932,9 @@  struct kvm_ppc_resize_hpt {
 #define KVM_CAP_HYPERV_SYNIC2 148
 #define KVM_CAP_HYPERV_VP_INDEX 149
 #define KVM_CAP_S390_AIS_MIGRATION 150
+#define KVM_CAP_PPC_SAFE_CACHE 151
+#define KVM_CAP_PPC_SAFE_BOUNDS_CHECK 152
+#define KVM_CAP_PPC_SAFE_INDIRECT_BRANCH 153
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 518dd06e98..818499237c 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -89,6 +89,9 @@  static int cap_mmu_radix;
 static int cap_mmu_hash_v3;
 static int cap_resize_hpt;
 static int cap_ppc_pvr_compat;
+static int cap_ppc_safe_cache;
+static int cap_ppc_safe_bounds_check;
+static int cap_ppc_safe_indirect_branch;
 
 static uint32_t debug_inst_opcode;
 
@@ -147,6 +150,16 @@  int kvm_arch_init(MachineState *ms, KVMState *s)
     cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
     cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
     cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
+    cap_ppc_safe_cache = kvm_vm_check_extension(s, KVM_CAP_PPC_SAFE_CACHE);
+    cap_ppc_safe_cache = cap_ppc_safe_cache > 0 ? cap_ppc_safe_cache : 0;
+    cap_ppc_safe_bounds_check = kvm_vm_check_extension(s,
+                                KVM_CAP_PPC_SAFE_BOUNDS_CHECK);
+    cap_ppc_safe_bounds_check = cap_ppc_safe_bounds_check > 0 ?
+                                cap_ppc_safe_bounds_check : 0;
+    cap_ppc_safe_indirect_branch = kvm_vm_check_extension(s,
+                                   KVM_CAP_PPC_SAFE_INDIRECT_BRANCH);
+    cap_ppc_safe_indirect_branch = cap_ppc_safe_indirect_branch > 0 ?
+                                   cap_ppc_safe_indirect_branch : 0;
     /*
      * Note: setting it to false because there is not such capability
      * in KVM at this moment.
@@ -2456,6 +2469,21 @@  bool kvmppc_has_cap_mmu_hash_v3(void)
     return cap_mmu_hash_v3;
 }
 
+int kvmppc_get_cap_safe_cache(void)
+{
+    return cap_ppc_safe_cache;
+}
+
+int kvmppc_get_cap_safe_bounds_check(void)
+{
+    return cap_ppc_safe_bounds_check;
+}
+
+int kvmppc_get_cap_safe_indirect_branch(void)
+{
+    return cap_ppc_safe_indirect_branch;
+}
+
 PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
 {
     uint32_t host_pvr = mfpvr();
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index ecb55493cc..39830baa77 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -59,6 +59,9 @@  bool kvmppc_has_cap_fixup_hcalls(void);
 bool kvmppc_has_cap_htm(void);
 bool kvmppc_has_cap_mmu_radix(void);
 bool kvmppc_has_cap_mmu_hash_v3(void);
+int kvmppc_get_cap_safe_cache(void);
+int kvmppc_get_cap_safe_bounds_check(void);
+int kvmppc_get_cap_safe_indirect_branch(void);
 int kvmppc_enable_hwrng(void);
 int kvmppc_put_books_sregs(PowerPCCPU *cpu);
 PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
@@ -290,6 +293,21 @@  static inline bool kvmppc_has_cap_mmu_hash_v3(void)
     return false;
 }
 
+static inline int kvmppc_get_cap_safe_cache(void)
+{
+    return 0;
+}
+
+static inline int kvmppc_get_cap_safe_bounds_check(void)
+{
+    return 0;
+}
+
+static inline int kvmppc_get_cap_safe_indirect_branch(void)
+{
+    return 0;
+}
+
 static inline int kvmppc_enable_hwrng(void)
 {
     return -1;