Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ff887b8 authored by Suraj Jitindar Singh's avatar Suraj Jitindar Singh Committed by Paul Mackerras
Browse files

KVM: PPC: Book3S: Introduce new hcall H_COPY_TOFROM_GUEST to access quadrants 1 & 2



A guest cannot access quadrants 1 or 2 as this would result in an
exception. Thus introduce the hcall H_COPY_TOFROM_GUEST to be used by a
guest when it wants to perform an access to quadrants 1 or 2, for
example when it wants to access memory for one of its nested guests.

Also provide an implementation for the kvm-hv module.

Signed-off-by: default avatarSuraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent 873db2cd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -335,6 +335,7 @@
#define H_SET_PARTITION_TABLE	0xF800
#define H_ENTER_NESTED		0xF804
#define H_TLB_INVALIDATE	0xF808
#define H_COPY_TOFROM_GUEST	0xF80C

/* Values for 2nd argument to H_SET_MODE */
#define H_SET_MODE_RESOURCE_SET_CIABR		1
+4 −0
Original line number Diff line number Diff line
@@ -188,6 +188,9 @@ extern int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hc);
extern int kvmppc_book3s_radix_page_fault(struct kvm_run *run,
			struct kvm_vcpu *vcpu,
			unsigned long ea, unsigned long dsisr);
extern unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid,
					gva_t eaddr, void *to, void *from,
					unsigned long n);
extern long kvmhv_copy_from_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr,
					void *to, unsigned long n);
extern long kvmhv_copy_to_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr,
@@ -301,6 +304,7 @@ long kvmhv_nested_init(void);
void kvmhv_nested_exit(void);
void kvmhv_vm_nested_init(struct kvm *kvm);
long kvmhv_set_partition_table(struct kvm_vcpu *vcpu);
long kvmhv_copy_tofrom_guest_nested(struct kvm_vcpu *vcpu);
void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1);
void kvmhv_release_all_nested(struct kvm *kvm);
long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu);
+4 −3
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@
 */
static int p9_supported_radix_bits[4] = { 5, 9, 9, 13 };

static unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid,
unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid,
					      gva_t eaddr, void *to, void *from,
					      unsigned long n)
{
@@ -82,6 +82,7 @@ static unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid,

	return ret;
}
EXPORT_SYMBOL_GPL(__kvmhv_copy_tofrom_guest_radix);

static long kvmhv_copy_tofrom_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr,
					  void *to, void *from, unsigned long n)
+5 −1
Original line number Diff line number Diff line
@@ -996,7 +996,11 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
		if (nesting_enabled(vcpu->kvm))
			ret = kvmhv_do_nested_tlbie(vcpu);
		break;

	case H_COPY_TOFROM_GUEST:
		ret = H_FUNCTION;
		if (nesting_enabled(vcpu->kvm))
			ret = kvmhv_copy_tofrom_guest_nested(vcpu);
		break;
	default:
		return RESUME_HOST;
	}
+75 −0
Original line number Diff line number Diff line
@@ -461,6 +461,81 @@ long kvmhv_set_partition_table(struct kvm_vcpu *vcpu)
	return ret;
}

/*
 * Handle the H_COPY_TOFROM_GUEST hcall.
 * r4 = L1 lpid of nested guest
 * r5 = pid
 * r6 = eaddr to access
 * r7 = to buffer (L1 gpa)
 * r8 = from buffer (L1 gpa)
 * r9 = n bytes to copy
 */
long kvmhv_copy_tofrom_guest_nested(struct kvm_vcpu *vcpu)
{
	struct kvm_nested_guest *gp;
	int l1_lpid = kvmppc_get_gpr(vcpu, 4);
	int pid = kvmppc_get_gpr(vcpu, 5);
	gva_t eaddr = kvmppc_get_gpr(vcpu, 6);
	gpa_t gp_to = (gpa_t) kvmppc_get_gpr(vcpu, 7);
	gpa_t gp_from = (gpa_t) kvmppc_get_gpr(vcpu, 8);
	void *buf;
	unsigned long n = kvmppc_get_gpr(vcpu, 9);
	bool is_load = !!gp_to;
	long rc;

	if (gp_to && gp_from) /* One must be NULL to determine the direction */
		return H_PARAMETER;

	if (eaddr & (0xFFFUL << 52))
		return H_PARAMETER;

	buf = kzalloc(n, GFP_KERNEL);
	if (!buf)
		return H_NO_MEM;

	gp = kvmhv_get_nested(vcpu->kvm, l1_lpid, false);
	if (!gp) {
		rc = H_PARAMETER;
		goto out_free;
	}

	mutex_lock(&gp->tlb_lock);

	if (is_load) {
		/* Load from the nested guest into our buffer */
		rc = __kvmhv_copy_tofrom_guest_radix(gp->shadow_lpid, pid,
						     eaddr, buf, NULL, n);
		if (rc)
			goto not_found;

		/* Write what was loaded into our buffer back to the L1 guest */
		rc = kvm_vcpu_write_guest(vcpu, gp_to, buf, n);
		if (rc)
			goto not_found;
	} else {
		/* Load the data to be stored from the L1 guest into our buf */
		rc = kvm_vcpu_read_guest(vcpu, gp_from, buf, n);
		if (rc)
			goto not_found;

		/* Store from our buffer into the nested guest */
		rc = __kvmhv_copy_tofrom_guest_radix(gp->shadow_lpid, pid,
						     eaddr, NULL, buf, n);
		if (rc)
			goto not_found;
	}

out_unlock:
	mutex_unlock(&gp->tlb_lock);
	kvmhv_put_nested(gp);
out_free:
	kfree(buf);
	return rc;
not_found:
	rc = H_NOT_FOUND;
	goto out_unlock;
}

/*
 * Reload the partition table entry for a guest.
 * Caller must hold gp->tlb_lock.