@@ -1654,6 +1654,81 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
return H_SUCCESS;
}
+/* H_GET_CPU_CHARACTERISTICS return values */
+#define H_CPU_CHAR_SPEC_BAR_ORI31 PPC_BIT(0)
+#define H_CPU_CHAR_BCCTRL_SERIALISED PPC_BIT(1)
+#define H_CPU_CHAR_L1D_FLUSH_ORI30 PPC_BIT(2)
+#define H_CPU_CHAR_L1D_FLUSH_TRIG2 PPC_BIT(3)
+#define H_CPU_CHAR_L1D_THREAD_PRIV PPC_BIT(4)
+#define H_CPU_CHAR_HON_BRANCH_HINTS PPC_BIT(5)
+#define H_CPU_CHAR_THR_RECONF_TRIG PPC_BIT(6)
+#define H_CPU_BEHAV_FAVOUR_SECURITY PPC_BIT(0)
+#define H_CPU_BEHAV_L1D_FLUSH_PR PPC_BIT(1)
+#define H_CPU_BEHAV_BNDS_CHK_SPEC_BAR PPC_BIT(2)
+
+static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ uint64_t characteristics = H_CPU_CHAR_HON_BRANCH_HINTS &
+ ~H_CPU_CHAR_THR_RECONF_TRIG;
+ uint64_t behaviour = H_CPU_BEHAV_FAVOUR_SECURITY;
+ uint8_t safe_cache = spapr_get_cap(spapr, SPAPR_CAP_CFPC);
+ uint8_t safe_bounds_check = spapr_get_cap(spapr, SPAPR_CAP_SBBC);
+ uint8_t safe_indirect_branch = spapr_get_cap(spapr, SPAPR_CAP_IBS);
+
+ switch (safe_cache) {
+ case SPAPR_CAP_WORKAROUND:
+ characteristics |= H_CPU_CHAR_L1D_FLUSH_ORI30;
+ characteristics |= H_CPU_CHAR_L1D_FLUSH_TRIG2;
+ characteristics |= H_CPU_CHAR_L1D_THREAD_PRIV;
+ behaviour |= H_CPU_BEHAV_L1D_FLUSH_PR;
+ break;
+ case SPAPR_CAP_FIXED:
+ break;
+ default: /* broken */
+ if (safe_cache != SPAPR_CAP_BROKEN) {
+ error_report("Invalid value for cap-cfpc (%d), assuming broken",
+ safe_cache);
+ }
+ behaviour |= H_CPU_BEHAV_L1D_FLUSH_PR;
+ break;
+ }
+
+ switch (safe_bounds_check) {
+ case SPAPR_CAP_WORKAROUND:
+ characteristics |= H_CPU_CHAR_SPEC_BAR_ORI31;
+ behaviour |= H_CPU_BEHAV_BNDS_CHK_SPEC_BAR;
+ break;
+ case SPAPR_CAP_FIXED:
+ break;
+ default: /* broken */
+ if (safe_bounds_check != SPAPR_CAP_BROKEN) {
+ error_report("Invalid value for cap-sbbc (%d), assuming broken",
+ safe_bounds_check);
+ }
+ behaviour |= H_CPU_BEHAV_BNDS_CHK_SPEC_BAR;
+ break;
+ }
+
+ switch (safe_indirect_branch) {
+ case SPAPR_CAP_FIXED:
+ characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
+ default: /* broken */
+ if (safe_indirect_branch != SPAPR_CAP_BROKEN) {
+ error_report("Invalid value for cap-ibs (%d), assuming broken",
+ safe_indirect_branch);
+ }
+ break;
+ }
+
+ args[0] = characteristics;
+ args[1] = behaviour;
+
+ return H_SUCCESS;
+}
+
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
@@ -1733,6 +1808,9 @@ static void hypercall_register_types(void)
spapr_register_hypercall(H_INVALIDATE_PID, h_invalidate_pid);
spapr_register_hypercall(H_REGISTER_PROC_TBL, h_register_process_table);
+ /* hcall-get-cpu-characteristics */
+ spapr_register_hypercall(H_GET_CPU_CHARACTERISTICS, h_get_cpu_characteristics);
+
/* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
* here between the "CI" and the "CACHE" variants, they will use whatever
* mapping attributes qemu is using. When using KVM, the kernel will
@@ -392,6 +392,7 @@ struct sPAPRMachineState {
#define H_GET_HCA_INFO 0x1B8
#define H_GET_PERF_COUNT 0x1BC
#define H_MANAGE_TRACE 0x1C0
+#define H_GET_CPU_CHARACTERISTICS 0x1C8
#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
#define H_QUERY_INT_STATE 0x1E4
#define H_POLL_PENDING 0x1D8