Message ID | 20240308111940.1617660-7-harshpb@linux.ibm.com |
---|---|
State | New |
Headers | show |
Series | Nested PAPR API (KVM on PowerVM) | expand |
On Fri Mar 8, 2024 at 9:19 PM AEST, Harsh Prateek Bora wrote: > Introduce the nested PAPR hcalls: > - H_GUEST_GET_CAPABILITIES which is used to query the capabilities > of the API and the L2 guests it provides. > - H_GUEST_SET_CAPABILITIES which is used to set the Guest API > capabilities that the Host Partition supports and may use. > > [amachhiw: support for p9 compat mode and return register bug fixes] > > Signed-off-by: Michael Neuling <mikey@neuling.org> > Signed-off-by: Amit Machhiwal <amachhiw@linux.vnet.ibm.com> > Signed-off-by: Harsh Prateek Bora <harshpb@linux.ibm.com> Reviewed-by: Nicholas Piggin <npiggin@gmail.com> > --- > include/hw/ppc/spapr.h | 7 ++- > include/hw/ppc/spapr_nested.h | 12 ++++ > hw/ppc/spapr_nested.c | 112 ++++++++++++++++++++++++++++++++++ > 3 files changed, 130 insertions(+), 1 deletion(-) > > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h > index 0eb01ea6fd..2906d59137 100644 > --- a/include/hw/ppc/spapr.h > +++ b/include/hw/ppc/spapr.h > @@ -364,6 +364,7 @@ struct SpaprMachineState { > #define H_NOOP -63 > #define H_UNSUPPORTED -67 > #define H_OVERLAP -68 > +#define H_STATE -75 > #define H_UNSUPPORTED_FLAG -256 > #define H_MULTI_THREADS_ACTIVE -9005 > > @@ -583,8 +584,10 @@ struct SpaprMachineState { > #define H_RPT_INVALIDATE 0x448 > #define H_SCM_FLUSH 0x44C > #define H_WATCHDOG 0x45C > +#define H_GUEST_GET_CAPABILITIES 0x460 > +#define H_GUEST_SET_CAPABILITIES 0x464 > > -#define MAX_HCALL_OPCODE H_WATCHDOG > +#define MAX_HCALL_OPCODE H_GUEST_SET_CAPABILITIES > > /* The hcalls above are standardized in PAPR and implemented by pHyp > * as well. > @@ -1033,5 +1036,7 @@ void spapr_watchdog_init(SpaprMachineState *spapr); > void spapr_register_nested_hv(void); > void spapr_unregister_nested_hv(void); > void spapr_nested_reset(SpaprMachineState *spapr); > +void spapr_register_nested_papr(void); > +void spapr_unregister_nested_papr(void); > > #endif /* HW_SPAPR_H */ > diff --git a/include/hw/ppc/spapr_nested.h b/include/hw/ppc/spapr_nested.h > index bf3a7b8d89..73687e03e4 100644 > --- a/include/hw/ppc/spapr_nested.h > +++ b/include/hw/ppc/spapr_nested.h > @@ -7,8 +7,20 @@ typedef struct SpaprMachineStateNested { > uint64_t ptcr; > uint8_t api; > #define NESTED_API_KVM_HV 1 > + bool capabilities_set; > + uint32_t pvr_base; > } SpaprMachineStateNested; > > +/* Nested PAPR API related macros */ > +#define H_GUEST_CAPABILITIES_COPY_MEM 0x8000000000000000 > +#define H_GUEST_CAPABILITIES_P9_MODE 0x4000000000000000 > +#define H_GUEST_CAPABILITIES_P10_MODE 0x2000000000000000 > +#define H_GUEST_CAP_VALID_MASK (H_GUEST_CAPABILITIES_P10_MODE | \ > + H_GUEST_CAPABILITIES_P9_MODE) > +#define H_GUEST_CAP_COPY_MEM_BMAP 0 > +#define H_GUEST_CAP_P9_MODE_BMAP 1 > +#define H_GUEST_CAP_P10_MODE_BMAP 2 > + > /* > * Register state for entering a nested guest with H_ENTER_NESTED. > * New member must be added at the end. > diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c > index 12fdbe2aba..601f669060 100644 > --- a/hw/ppc/spapr_nested.c > +++ b/hw/ppc/spapr_nested.c > @@ -7,6 +7,7 @@ > #include "hw/ppc/spapr_cpu_core.h" > #include "hw/ppc/spapr_nested.h" > #include "mmu-book3s-v3.h" > +#include "cpu-models.h" > > void spapr_nested_reset(SpaprMachineState *spapr) > { > @@ -16,6 +17,7 @@ void spapr_nested_reset(SpaprMachineState *spapr) > spapr_register_nested_hv(); > } else { > spapr->nested.api = 0; > + spapr->nested.capabilities_set = false; > } > } > > @@ -432,6 +434,92 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) > } > } > > +static target_ulong h_guest_get_capabilities(PowerPCCPU *cpu, > + SpaprMachineState *spapr, > + target_ulong opcode, > + target_ulong *args) > +{ > + CPUPPCState *env = &cpu->env; > + target_ulong flags = args[0]; > + > + if (flags) { /* don't handle any flags capabilities for now */ > + return H_PARAMETER; > + } > + > + /* P10 capabilities */ > + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, > + spapr->max_compat_pvr)) { > + env->gpr[4] |= H_GUEST_CAPABILITIES_P10_MODE; > + } > + > + /* P9 capabilities */ > + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, > + spapr->max_compat_pvr)) { > + env->gpr[4] |= H_GUEST_CAPABILITIES_P9_MODE; > + } > + > + return H_SUCCESS; > +} > + > +static target_ulong h_guest_set_capabilities(PowerPCCPU *cpu, > + SpaprMachineState *spapr, > + target_ulong opcode, > + target_ulong *args) > +{ > + CPUPPCState *env = &cpu->env; > + target_ulong flags = args[0]; > + target_ulong capabilities = args[1]; > + env->gpr[4] = 0; > + > + if (flags) { /* don't handle any flags capabilities for now */ > + return H_PARAMETER; > + } > + > + if (capabilities & H_GUEST_CAPABILITIES_COPY_MEM) { > + env->gpr[4] = 1; > + return H_P2; /* isn't supported */ > + } > + > + /* If there are no capabilities configured, set the R5 to the index of > + * the first supported Power Processor Mode > + */ > + if (!capabilities) { > + env->gpr[4] = 1; > + > + /* set R5 to the first supported Power Processor Mode */ > + if(ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, > + spapr->max_compat_pvr)) { > + env->gpr[5] = H_GUEST_CAP_P10_MODE_BMAP; > + } > + else if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, > + spapr->max_compat_pvr)) { > + env->gpr[5] = H_GUEST_CAP_P9_MODE_BMAP; > + } > + > + return H_P2; > + } > + > + /* If an invalid capability is set, R5 should contain the index of the > + * invalid capability bit > + */ > + if (capabilities & ~H_GUEST_CAP_VALID_MASK) { > + env->gpr[4] = 1; > + > + /* Set R5 to the index of the invalid capability */ > + env->gpr[5] = 63 - ctz64(capabilities); > + > + return H_P2; > + } > + > + if (!spapr->nested.capabilities_set) { > + spapr->nested.capabilities_set = true; > + spapr->nested.pvr_base = env->spr[SPR_PVR]; > + return H_SUCCESS; > + } else { > + return H_STATE; > + } > +} > + > void spapr_register_nested_hv(void) > { > spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); > @@ -447,6 +535,19 @@ void spapr_unregister_nested_hv(void) > spapr_unregister_hypercall(KVMPPC_H_TLB_INVALIDATE); > spapr_unregister_hypercall(KVMPPC_H_COPY_TOFROM_GUEST); > } > + > +void spapr_register_nested_papr(void) > +{ > + spapr_register_hypercall(H_GUEST_GET_CAPABILITIES, h_guest_get_capabilities); > + spapr_register_hypercall(H_GUEST_SET_CAPABILITIES, h_guest_set_capabilities); > +} > + > +void spapr_unregister_nested_papr(void) > +{ > + spapr_unregister_hypercall(H_GUEST_GET_CAPABILITIES); > + spapr_unregister_hypercall(H_GUEST_SET_CAPABILITIES); > +} > + > #else > void spapr_exit_nested(PowerPCCPU *cpu, int excp) > { > @@ -468,4 +569,15 @@ bool spapr_get_pate_nested_hv(SpaprMachineState *spapr, PowerPCCPU *cpu, > { > return false; > } > + > +void spapr_register_nested_papr(void) > +{ > + /* DO NOTHING */ > +} > + > +void spapr_unregister_nested_papr(void) > +{ > + /* DO NOTHING */ > +} > + > #endif
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 0eb01ea6fd..2906d59137 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -364,6 +364,7 @@ struct SpaprMachineState { #define H_NOOP -63 #define H_UNSUPPORTED -67 #define H_OVERLAP -68 +#define H_STATE -75 #define H_UNSUPPORTED_FLAG -256 #define H_MULTI_THREADS_ACTIVE -9005 @@ -583,8 +584,10 @@ struct SpaprMachineState { #define H_RPT_INVALIDATE 0x448 #define H_SCM_FLUSH 0x44C #define H_WATCHDOG 0x45C +#define H_GUEST_GET_CAPABILITIES 0x460 +#define H_GUEST_SET_CAPABILITIES 0x464 -#define MAX_HCALL_OPCODE H_WATCHDOG +#define MAX_HCALL_OPCODE H_GUEST_SET_CAPABILITIES /* The hcalls above are standardized in PAPR and implemented by pHyp * as well. @@ -1033,5 +1036,7 @@ void spapr_watchdog_init(SpaprMachineState *spapr); void spapr_register_nested_hv(void); void spapr_unregister_nested_hv(void); void spapr_nested_reset(SpaprMachineState *spapr); +void spapr_register_nested_papr(void); +void spapr_unregister_nested_papr(void); #endif /* HW_SPAPR_H */ diff --git a/include/hw/ppc/spapr_nested.h b/include/hw/ppc/spapr_nested.h index bf3a7b8d89..73687e03e4 100644 --- a/include/hw/ppc/spapr_nested.h +++ b/include/hw/ppc/spapr_nested.h @@ -7,8 +7,20 @@ typedef struct SpaprMachineStateNested { uint64_t ptcr; uint8_t api; #define NESTED_API_KVM_HV 1 + bool capabilities_set; + uint32_t pvr_base; } SpaprMachineStateNested; +/* Nested PAPR API related macros */ +#define H_GUEST_CAPABILITIES_COPY_MEM 0x8000000000000000 +#define H_GUEST_CAPABILITIES_P9_MODE 0x4000000000000000 +#define H_GUEST_CAPABILITIES_P10_MODE 0x2000000000000000 +#define H_GUEST_CAP_VALID_MASK (H_GUEST_CAPABILITIES_P10_MODE | \ + H_GUEST_CAPABILITIES_P9_MODE) +#define H_GUEST_CAP_COPY_MEM_BMAP 0 +#define H_GUEST_CAP_P9_MODE_BMAP 1 +#define H_GUEST_CAP_P10_MODE_BMAP 2 + /* * Register state for entering a nested guest with H_ENTER_NESTED. * New member must be added at the end. diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c index 12fdbe2aba..601f669060 100644 --- a/hw/ppc/spapr_nested.c +++ b/hw/ppc/spapr_nested.c @@ -7,6 +7,7 @@ #include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/spapr_nested.h" #include "mmu-book3s-v3.h" +#include "cpu-models.h" void spapr_nested_reset(SpaprMachineState *spapr) { @@ -16,6 +17,7 @@ void spapr_nested_reset(SpaprMachineState *spapr) spapr_register_nested_hv(); } else { spapr->nested.api = 0; + spapr->nested.capabilities_set = false; } } @@ -432,6 +434,92 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) } } +static target_ulong h_guest_get_capabilities(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + + if (flags) { /* don't handle any flags capabilities for now */ + return H_PARAMETER; + } + + /* P10 capabilities */ + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, + spapr->max_compat_pvr)) { + env->gpr[4] |= H_GUEST_CAPABILITIES_P10_MODE; + } + + /* P9 capabilities */ + if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { + env->gpr[4] |= H_GUEST_CAPABILITIES_P9_MODE; + } + + return H_SUCCESS; +} + +static target_ulong h_guest_set_capabilities(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong capabilities = args[1]; + env->gpr[4] = 0; + + if (flags) { /* don't handle any flags capabilities for now */ + return H_PARAMETER; + } + + if (capabilities & H_GUEST_CAPABILITIES_COPY_MEM) { + env->gpr[4] = 1; + return H_P2; /* isn't supported */ + } + + /* If there are no capabilities configured, set the R5 to the index of + * the first supported Power Processor Mode + */ + if (!capabilities) { + env->gpr[4] = 1; + + /* set R5 to the first supported Power Processor Mode */ + if(ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_10, 0, + spapr->max_compat_pvr)) { + env->gpr[5] = H_GUEST_CAP_P10_MODE_BMAP; + } + else if (ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { + env->gpr[5] = H_GUEST_CAP_P9_MODE_BMAP; + } + + return H_P2; + } + + /* If an invalid capability is set, R5 should contain the index of the + * invalid capability bit + */ + if (capabilities & ~H_GUEST_CAP_VALID_MASK) { + env->gpr[4] = 1; + + /* Set R5 to the index of the invalid capability */ + env->gpr[5] = 63 - ctz64(capabilities); + + return H_P2; + } + + if (!spapr->nested.capabilities_set) { + spapr->nested.capabilities_set = true; + spapr->nested.pvr_base = env->spr[SPR_PVR]; + return H_SUCCESS; + } else { + return H_STATE; + } +} + void spapr_register_nested_hv(void) { spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); @@ -447,6 +535,19 @@ void spapr_unregister_nested_hv(void) spapr_unregister_hypercall(KVMPPC_H_TLB_INVALIDATE); spapr_unregister_hypercall(KVMPPC_H_COPY_TOFROM_GUEST); } + +void spapr_register_nested_papr(void) +{ + spapr_register_hypercall(H_GUEST_GET_CAPABILITIES, h_guest_get_capabilities); + spapr_register_hypercall(H_GUEST_SET_CAPABILITIES, h_guest_set_capabilities); +} + +void spapr_unregister_nested_papr(void) +{ + spapr_unregister_hypercall(H_GUEST_GET_CAPABILITIES); + spapr_unregister_hypercall(H_GUEST_SET_CAPABILITIES); +} + #else void spapr_exit_nested(PowerPCCPU *cpu, int excp) { @@ -468,4 +569,15 @@ bool spapr_get_pate_nested_hv(SpaprMachineState *spapr, PowerPCCPU *cpu, { return false; } + +void spapr_register_nested_papr(void) +{ + /* DO NOTHING */ +} + +void spapr_unregister_nested_papr(void) +{ + /* DO NOTHING */ +} + #endif