Introduce the nested PAPR hcall H_GUEST_CREATE_VCPU which is used to create and initialize the specified VCPU resource for the previously created guest. Each guest can have multiple VCPUs upto max 2048. All VCPUs for a guest gets deallocated on guest delete.
Signed-off-by: Michael Neuling <[email protected]> Signed-off-by: Harsh Prateek Bora <[email protected]> --- hw/ppc/spapr_nested.c | 100 ++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 2 + include/hw/ppc/spapr_nested.h | 8 +++ 3 files changed, 110 insertions(+) diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c index e95e70e20c..b38116b7c3 100644 --- a/hw/ppc/spapr_nested.c +++ b/hw/ppc/spapr_nested.c @@ -411,6 +411,41 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) address_space_unmap(CPU(cpu)->as, regs, len, len, true); } +static +SpaprMachineStateNestedGuest *spapr_get_nested_guest(SpaprMachineState *spapr, + target_ulong guestid) +{ + SpaprMachineStateNestedGuest *guest; + + guest = g_hash_table_lookup(spapr->nested.guests, GINT_TO_POINTER(guestid)); + return guest; +} + +static bool spapr_nested_vcpu_check(SpaprMachineStateNestedGuest *guest, + target_ulong vcpuid) +{ + struct SpaprMachineStateNestedGuestVcpu *vcpu; + /* + * Perform sanity checks for the provided vcpuid of a guest. + * For now, ensure its valid, allocated and enabled for use. + */ + + if (vcpuid >= PAPR_NESTED_GUEST_VCPU_MAX) { + return false; + } + + if (!(vcpuid < guest->vcpus)) { + return false; + } + + vcpu = &guest->vcpu[vcpuid]; + if (!vcpu->enabled) { + return false; + } + + return true; +} + static target_ulong h_guest_get_capabilities(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, @@ -481,6 +516,11 @@ static void destroy_guest_helper(gpointer value) { struct SpaprMachineStateNestedGuest *guest = value; + + for (int i = 0; i < guest->vcpus; i++) { + cpu_ppc_tb_free(&guest->vcpu[i].env); + } + g_free(guest->vcpu); g_free(guest); } @@ -576,6 +616,65 @@ static target_ulong h_guest_delete(PowerPCCPU *cpu, return H_SUCCESS; } +static target_ulong h_guest_create_vcpu(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + CPUPPCState *env = &cpu->env, *l2env; + target_ulong flags = args[0]; + target_ulong guestid = args[1]; + target_ulong vcpuid = args[2]; + SpaprMachineStateNestedGuest *guest; + + if (flags) { /* don't handle any flags for now */ + return H_UNSUPPORTED_FLAG; + } + + guest = spapr_get_nested_guest(spapr, guestid); + if (!guest) { + return H_P2; + } + + if (vcpuid < guest->vcpus) { + return H_IN_USE; + } + + if (guest->vcpus >= PAPR_NESTED_GUEST_VCPU_MAX) { + return H_P3; + } + + if (guest->vcpus) { + SpaprMachineStateNestedGuestVcpu *vcpus; + vcpus = g_try_renew(struct SpaprMachineStateNestedGuestVcpu, + guest->vcpu, + guest->vcpus + 1); + if (!vcpus) { + return H_NO_MEM; + } + memset(&vcpus[guest->vcpus], 0, + sizeof(SpaprMachineStateNestedGuestVcpu)); + guest->vcpu = vcpus; + } else { + guest->vcpu = g_try_new0(SpaprMachineStateNestedGuestVcpu, 1); + if (guest->vcpu == NULL) { + return H_NO_MEM; + } + } + l2env = &guest->vcpu[guest->vcpus].env; + guest->vcpus++; + assert(vcpuid < guest->vcpus); /* linear vcpuid allocation only */ + /* Copy L1 PVR to L2 */ + l2env->spr[SPR_PVR] = env->spr[SPR_PVR]; + cpu_ppc_tb_init(l2env, SPAPR_TIMEBASE_FREQ); + guest->vcpu[vcpuid].enabled = true; + + if (!spapr_nested_vcpu_check(guest, vcpuid)) { + return H_PARAMETER; + } + return H_SUCCESS; +} + void spapr_register_nested(void) { spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); @@ -591,6 +690,7 @@ void spapr_register_nested_papr(void) spapr_register_hypercall(H_GUEST_SET_CAPABILITIES, h_guest_set_capabilities); spapr_register_hypercall(H_GUEST_CREATE , h_guest_create); spapr_register_hypercall(H_GUEST_DELETE , h_guest_delete); + spapr_register_hypercall(H_GUEST_CREATE_VCPU , h_guest_create_vcpu); } #else void spapr_exit_nested(PowerPCCPU *cpu, int excp) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index fcc6f0a3d9..25aa8c5ffe 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -367,6 +367,7 @@ struct SpaprMachineState { #define H_UNSUPPORTED -67 #define H_OVERLAP -68 #define H_STATE -75 +#define H_IN_USE -77 #define H_UNSUPPORTED_FLAG -256 #define H_MULTI_THREADS_ACTIVE -9005 @@ -589,6 +590,7 @@ struct SpaprMachineState { #define H_GUEST_GET_CAPABILITIES 0x460 #define H_GUEST_SET_CAPABILITIES 0x464 #define H_GUEST_CREATE 0x470 +#define H_GUEST_CREATE_VCPU 0x474 #define H_GUEST_DELETE 0x488 #define MAX_HCALL_OPCODE H_GUEST_DELETE diff --git a/include/hw/ppc/spapr_nested.h b/include/hw/ppc/spapr_nested.h index f186005f00..91cb744a5b 100644 --- a/include/hw/ppc/spapr_nested.h +++ b/include/hw/ppc/spapr_nested.h @@ -16,8 +16,15 @@ typedef struct SpaprMachineStateNested { typedef struct SpaprMachineStateNestedGuest { uint32_t pvr_logical; + unsigned long vcpus; + struct SpaprMachineStateNestedGuestVcpu *vcpu; } SpaprMachineStateNestedGuest; +typedef struct SpaprMachineStateNestedGuestVcpu { + bool enabled; + CPUPPCState env; +} SpaprMachineStateNestedGuestVcpu; + /* Nested PAPR API related macros */ #define H_GUEST_CAPABILITIES_COPY_MEM 0x8000000000000000 #define H_GUEST_CAPABILITIES_P9_MODE 0x4000000000000000 @@ -27,6 +34,7 @@ typedef struct SpaprMachineStateNestedGuest { #define H_GUEST_CAP_P10_MODE_BMAP 2 #define PAPR_NESTED_GUEST_MAX 4096 #define H_GUEST_DELETE_ALL_FLAG 0x8000000000000000ULL +#define PAPR_NESTED_GUEST_VCPU_MAX 2048 /* * Register state for entering a nested guest with H_ENTER_NESTED. -- 2.39.3
