Skip to content

Commit 19d31c5

Browse files
iamjpnmpe
authored andcommitted
KVM: PPC: Add support for nestedv2 guests
A series of hcalls have been added to the PAPR which allow a regular guest partition to create and manage guest partitions of its own. KVM already had an interface that allowed this on powernv platforms. This existing interface will now be called "nestedv1". The newly added PAPR interface will be called "nestedv2". PHYP will support the nestedv2 interface. At this time the host side of the nestedv2 interface has not been implemented on powernv but there is no technical reason why it could not be added. The nestedv1 interface is still supported. Add support to KVM to utilize these hcalls to enable running nested guests as a pseries guest on PHYP. Overview of the new hcall usage: - L1 and L0 negotiate capabilities with H_GUEST_{G,S}ET_CAPABILITIES() - L1 requests the L0 create a L2 with H_GUEST_CREATE() and receives a handle to use in future hcalls - L1 requests the L0 create a L2 vCPU with H_GUEST_CREATE_VCPU() - L1 sets up the L2 using H_GUEST_SET and the H_GUEST_VCPU_RUN input buffer - L1 requests the L0 runs the L2 vCPU using H_GUEST_VCPU_RUN() - L2 returns to L1 with an exit reason and L1 reads the H_GUEST_VCPU_RUN output buffer populated by the L0 - L1 handles the exit using H_GET_STATE if necessary - L1 reruns L2 vCPU with H_GUEST_VCPU_RUN - L1 frees the L2 in the L0 with H_GUEST_DELETE() Support for the new API is determined by trying H_GUEST_GET_CAPABILITIES. On a successful return, use the nestedv2 interface. Use the vcpu register state setters for tracking modified guest state elements and copy the thread wide values into the H_GUEST_VCPU_RUN input buffer immediately before running a L2. The guest wide elements can not be added to the input buffer so send them with a separate H_GUEST_SET call if necessary. Make the vcpu register getter load the corresponding value from the real host with H_GUEST_GET. To avoid unnecessarily calling H_GUEST_GET, track which values have already been loaded between H_GUEST_VCPU_RUN calls. If an element is present in the H_GUEST_VCPU_RUN output buffer it also does not need to be loaded again. Tested-by: Sachin Sant <sachinp@linux.ibm.com> Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com> Signed-off-by: Gautam Menghani <gautam@linux.ibm.com> Signed-off-by: Kautuk Consul <kconsul@linux.vnet.ibm.com> Signed-off-by: Amit Machhiwal <amachhiw@linux.vnet.ibm.com> Signed-off-by: Jordan Niethe <jniethe5@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20230914030600.16993-11-jniethe5@gmail.com
1 parent dfcaacc commit 19d31c5

14 files changed

+1843
-97
lines changed

arch/powerpc/include/asm/guest-state-buffer.h

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef _ASM_POWERPC_GUEST_STATE_BUFFER_H
66
#define _ASM_POWERPC_GUEST_STATE_BUFFER_H
77

8+
#include "asm/hvcall.h"
89
#include <linux/gfp.h>
910
#include <linux/bitmap.h>
1011
#include <asm/plpar_wrappers.h>
@@ -313,6 +314,8 @@ struct kvmppc_gs_buff *kvmppc_gsb_new(size_t size, unsigned long guest_id,
313314
unsigned long vcpu_id, gfp_t flags);
314315
void kvmppc_gsb_free(struct kvmppc_gs_buff *gsb);
315316
void *kvmppc_gsb_put(struct kvmppc_gs_buff *gsb, size_t size);
317+
int kvmppc_gsb_send(struct kvmppc_gs_buff *gsb, unsigned long flags);
318+
int kvmppc_gsb_recv(struct kvmppc_gs_buff *gsb, unsigned long flags);
316319

317320
/**
318321
* kvmppc_gsb_header() - the header of a guest state buffer
@@ -901,4 +904,92 @@ static inline void kvmppc_gsm_reset(struct kvmppc_gs_msg *gsm)
901904
kvmppc_gsbm_zero(&gsm->bitmap);
902905
}
903906

907+
/**
908+
* kvmppc_gsb_receive_data - flexibly update values from a guest state buffer
909+
* @gsb: guest state buffer
910+
* @gsm: guest state message
911+
*
912+
* Requests updated values for the guest state values included in the guest
913+
* state message. The guest state message will then deserialize the guest state
914+
* buffer.
915+
*/
916+
static inline int kvmppc_gsb_receive_data(struct kvmppc_gs_buff *gsb,
917+
struct kvmppc_gs_msg *gsm)
918+
{
919+
int rc;
920+
921+
kvmppc_gsb_reset(gsb);
922+
rc = kvmppc_gsm_fill_info(gsm, gsb);
923+
if (rc < 0)
924+
return rc;
925+
926+
rc = kvmppc_gsb_recv(gsb, gsm->flags);
927+
if (rc < 0)
928+
return rc;
929+
930+
rc = kvmppc_gsm_refresh_info(gsm, gsb);
931+
if (rc < 0)
932+
return rc;
933+
return 0;
934+
}
935+
936+
/**
937+
* kvmppc_gsb_recv - receive a single guest state ID
938+
* @gsb: guest state buffer
939+
* @gsm: guest state message
940+
* @iden: guest state identity
941+
*/
942+
static inline int kvmppc_gsb_receive_datum(struct kvmppc_gs_buff *gsb,
943+
struct kvmppc_gs_msg *gsm, u16 iden)
944+
{
945+
int rc;
946+
947+
kvmppc_gsm_include(gsm, iden);
948+
rc = kvmppc_gsb_receive_data(gsb, gsm);
949+
if (rc < 0)
950+
return rc;
951+
kvmppc_gsm_reset(gsm);
952+
return 0;
953+
}
954+
955+
/**
956+
* kvmppc_gsb_send_data - flexibly send values from a guest state buffer
957+
* @gsb: guest state buffer
958+
* @gsm: guest state message
959+
*
960+
* Sends the guest state values included in the guest state message.
961+
*/
962+
static inline int kvmppc_gsb_send_data(struct kvmppc_gs_buff *gsb,
963+
struct kvmppc_gs_msg *gsm)
964+
{
965+
int rc;
966+
967+
kvmppc_gsb_reset(gsb);
968+
rc = kvmppc_gsm_fill_info(gsm, gsb);
969+
if (rc < 0)
970+
return rc;
971+
rc = kvmppc_gsb_send(gsb, gsm->flags);
972+
973+
return rc;
974+
}
975+
976+
/**
977+
* kvmppc_gsb_recv - send a single guest state ID
978+
* @gsb: guest state buffer
979+
* @gsm: guest state message
980+
* @iden: guest state identity
981+
*/
982+
static inline int kvmppc_gsb_send_datum(struct kvmppc_gs_buff *gsb,
983+
struct kvmppc_gs_msg *gsm, u16 iden)
984+
{
985+
int rc;
986+
987+
kvmppc_gsm_include(gsm, iden);
988+
rc = kvmppc_gsb_send_data(gsb, gsm);
989+
if (rc < 0)
990+
return rc;
991+
kvmppc_gsm_reset(gsm);
992+
return 0;
993+
}
994+
904995
#endif /* _ASM_POWERPC_GUEST_STATE_BUFFER_H */

arch/powerpc/include/asm/hvcall.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@
100100
#define H_COP_HW -74
101101
#define H_STATE -75
102102
#define H_IN_USE -77
103+
104+
#define H_INVALID_ELEMENT_ID -79
105+
#define H_INVALID_ELEMENT_SIZE -80
106+
#define H_INVALID_ELEMENT_VALUE -81
107+
#define H_INPUT_BUFFER_NOT_DEFINED -82
108+
#define H_INPUT_BUFFER_TOO_SMALL -83
109+
#define H_OUTPUT_BUFFER_NOT_DEFINED -84
110+
#define H_OUTPUT_BUFFER_TOO_SMALL -85
111+
#define H_PARTITION_PAGE_TABLE_NOT_DEFINED -86
112+
#define H_GUEST_VCPU_STATE_NOT_HV_OWNED -87
113+
114+
103115
#define H_UNSUPPORTED_FLAG_START -256
104116
#define H_UNSUPPORTED_FLAG_END -511
105117
#define H_MULTI_THREADS_ACTIVE -9005
@@ -381,6 +393,15 @@
381393
#define H_ENTER_NESTED 0xF804
382394
#define H_TLB_INVALIDATE 0xF808
383395
#define H_COPY_TOFROM_GUEST 0xF80C
396+
#define H_GUEST_GET_CAPABILITIES 0x460
397+
#define H_GUEST_SET_CAPABILITIES 0x464
398+
#define H_GUEST_CREATE 0x470
399+
#define H_GUEST_CREATE_VCPU 0x474
400+
#define H_GUEST_GET_STATE 0x478
401+
#define H_GUEST_SET_STATE 0x47C
402+
#define H_GUEST_RUN_VCPU 0x480
403+
#define H_GUEST_COPY_MEMORY 0x484
404+
#define H_GUEST_DELETE 0x488
384405

385406
/* Flags for H_SVM_PAGE_IN */
386407
#define H_PAGE_IN_SHARED 0x1
@@ -467,6 +488,15 @@
467488
#define H_RPTI_PAGE_1G 0x08
468489
#define H_RPTI_PAGE_ALL (-1UL)
469490

491+
/* Flags for H_GUEST_{S,G}_STATE */
492+
#define H_GUEST_FLAGS_WIDE (1UL<<(63-0))
493+
494+
/* Flag values used for H_{S,G}SET_GUEST_CAPABILITIES */
495+
#define H_GUEST_CAP_COPY_MEM (1UL<<(63-0))
496+
#define H_GUEST_CAP_POWER9 (1UL<<(63-1))
497+
#define H_GUEST_CAP_POWER10 (1UL<<(63-2))
498+
#define H_GUEST_CAP_BITMAP2 (1UL<<(63-63))
499+
470500
#ifndef __ASSEMBLY__
471501
#include <linux/types.h>
472502

0 commit comments

Comments
 (0)