Skip to content

Commit

Permalink
KVM: PPC: Add support for nestedv2 guests
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Vaibhav Jain <[email protected]>
Signed-off-by: Gautam Menghani <[email protected]>
Signed-off-by: Kautuk Consul <[email protected]>
Signed-off-by: Amit Machhiwal <[email protected]>
Signed-off-by: Jordan Niethe <[email protected]>
Signed-off-by: Michael Ellerman <[email protected]>
Link: https://msgid.link/[email protected]
  • Loading branch information
iamjpn authored and mpe committed Sep 14, 2023
1 parent dfcaacc commit 19d31c5
Show file tree
Hide file tree
Showing 14 changed files with 1,843 additions and 97 deletions.
91 changes: 91 additions & 0 deletions arch/powerpc/include/asm/guest-state-buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef _ASM_POWERPC_GUEST_STATE_BUFFER_H
#define _ASM_POWERPC_GUEST_STATE_BUFFER_H

#include "asm/hvcall.h"
#include <linux/gfp.h>
#include <linux/bitmap.h>
#include <asm/plpar_wrappers.h>
Expand Down Expand Up @@ -313,6 +314,8 @@ struct kvmppc_gs_buff *kvmppc_gsb_new(size_t size, unsigned long guest_id,
unsigned long vcpu_id, gfp_t flags);
void kvmppc_gsb_free(struct kvmppc_gs_buff *gsb);
void *kvmppc_gsb_put(struct kvmppc_gs_buff *gsb, size_t size);
int kvmppc_gsb_send(struct kvmppc_gs_buff *gsb, unsigned long flags);
int kvmppc_gsb_recv(struct kvmppc_gs_buff *gsb, unsigned long flags);

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

/**
* kvmppc_gsb_receive_data - flexibly update values from a guest state buffer
* @gsb: guest state buffer
* @gsm: guest state message
*
* Requests updated values for the guest state values included in the guest
* state message. The guest state message will then deserialize the guest state
* buffer.
*/
static inline int kvmppc_gsb_receive_data(struct kvmppc_gs_buff *gsb,
struct kvmppc_gs_msg *gsm)
{
int rc;

kvmppc_gsb_reset(gsb);
rc = kvmppc_gsm_fill_info(gsm, gsb);
if (rc < 0)
return rc;

rc = kvmppc_gsb_recv(gsb, gsm->flags);
if (rc < 0)
return rc;

rc = kvmppc_gsm_refresh_info(gsm, gsb);
if (rc < 0)
return rc;
return 0;
}

/**
* kvmppc_gsb_recv - receive a single guest state ID
* @gsb: guest state buffer
* @gsm: guest state message
* @iden: guest state identity
*/
static inline int kvmppc_gsb_receive_datum(struct kvmppc_gs_buff *gsb,
struct kvmppc_gs_msg *gsm, u16 iden)
{
int rc;

kvmppc_gsm_include(gsm, iden);
rc = kvmppc_gsb_receive_data(gsb, gsm);
if (rc < 0)
return rc;
kvmppc_gsm_reset(gsm);
return 0;
}

/**
* kvmppc_gsb_send_data - flexibly send values from a guest state buffer
* @gsb: guest state buffer
* @gsm: guest state message
*
* Sends the guest state values included in the guest state message.
*/
static inline int kvmppc_gsb_send_data(struct kvmppc_gs_buff *gsb,
struct kvmppc_gs_msg *gsm)
{
int rc;

kvmppc_gsb_reset(gsb);
rc = kvmppc_gsm_fill_info(gsm, gsb);
if (rc < 0)
return rc;
rc = kvmppc_gsb_send(gsb, gsm->flags);

return rc;
}

/**
* kvmppc_gsb_recv - send a single guest state ID
* @gsb: guest state buffer
* @gsm: guest state message
* @iden: guest state identity
*/
static inline int kvmppc_gsb_send_datum(struct kvmppc_gs_buff *gsb,
struct kvmppc_gs_msg *gsm, u16 iden)
{
int rc;

kvmppc_gsm_include(gsm, iden);
rc = kvmppc_gsb_send_data(gsb, gsm);
if (rc < 0)
return rc;
kvmppc_gsm_reset(gsm);
return 0;
}

#endif /* _ASM_POWERPC_GUEST_STATE_BUFFER_H */
30 changes: 30 additions & 0 deletions arch/powerpc/include/asm/hvcall.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@
#define H_COP_HW -74
#define H_STATE -75
#define H_IN_USE -77

#define H_INVALID_ELEMENT_ID -79
#define H_INVALID_ELEMENT_SIZE -80
#define H_INVALID_ELEMENT_VALUE -81
#define H_INPUT_BUFFER_NOT_DEFINED -82
#define H_INPUT_BUFFER_TOO_SMALL -83
#define H_OUTPUT_BUFFER_NOT_DEFINED -84
#define H_OUTPUT_BUFFER_TOO_SMALL -85
#define H_PARTITION_PAGE_TABLE_NOT_DEFINED -86
#define H_GUEST_VCPU_STATE_NOT_HV_OWNED -87


#define H_UNSUPPORTED_FLAG_START -256
#define H_UNSUPPORTED_FLAG_END -511
#define H_MULTI_THREADS_ACTIVE -9005
Expand Down Expand Up @@ -381,6 +393,15 @@
#define H_ENTER_NESTED 0xF804
#define H_TLB_INVALIDATE 0xF808
#define H_COPY_TOFROM_GUEST 0xF80C
#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_GET_STATE 0x478
#define H_GUEST_SET_STATE 0x47C
#define H_GUEST_RUN_VCPU 0x480
#define H_GUEST_COPY_MEMORY 0x484
#define H_GUEST_DELETE 0x488

/* Flags for H_SVM_PAGE_IN */
#define H_PAGE_IN_SHARED 0x1
Expand Down Expand Up @@ -467,6 +488,15 @@
#define H_RPTI_PAGE_1G 0x08
#define H_RPTI_PAGE_ALL (-1UL)

/* Flags for H_GUEST_{S,G}_STATE */
#define H_GUEST_FLAGS_WIDE (1UL<<(63-0))

/* Flag values used for H_{S,G}SET_GUEST_CAPABILITIES */
#define H_GUEST_CAP_COPY_MEM (1UL<<(63-0))
#define H_GUEST_CAP_POWER9 (1UL<<(63-1))
#define H_GUEST_CAP_POWER10 (1UL<<(63-2))
#define H_GUEST_CAP_BITMAP2 (1UL<<(63-63))

#ifndef __ASSEMBLY__
#include <linux/types.h>

Expand Down
Loading

0 comments on commit 19d31c5

Please sign in to comment.