Commit 0115768b authored by niuyongwen's avatar niuyongwen Committed by xiongmengbiao
Browse files

arch/x86/kvm: Support psp virtualization

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9C3AM


CVE: NA

---------------------------

Support the PSP virtualization basic framework.

The guest uses the vmmcall instruction to
interact with KVM, which then forwards
the data to the PSP device driver and sends
it to the PSP hardware.

Signed-off-by: default avatarniuyongwen <niuyongwen@hygon.cn>
parent 9632f791
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2170,6 +2170,8 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
		    unsigned long ipi_bitmap_high, u32 min,
		    unsigned long icr, int op_64_bit);
int kvm_pv_psp_op(struct kvm *kvm, int cmd, gpa_t data_gpa,
		gpa_t psp_ret_gpa, gpa_t table_gpa);

int kvm_add_user_return_msr(u32 msr);
int kvm_find_user_return_msr(u32 msr);
+1 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ include $(srctree)/virt/kvm/Makefile.kvm
kvm-y			+= x86.o emulate.o i8259.o irq.o lapic.o \
			   i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
			   hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
			   mmu/spte.o
			   mmu/spte.o psp.o

ifdef CONFIG_HYPERV
kvm-y			+= kvm_onhyperv.o

arch/x86/kvm/psp.c

0 → 100644
+84 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * PSP virtualization
 *
 * Copyright (c) 2023, HYGON CORPORATION. All rights reserved.
 *     Author: Ge Yang <yangge@hygon.cn>
 *
 */

#include <linux/kvm_types.h>
#include <linux/slab.h>
#include <linux/kvm_host.h>
#include <linux/psp-sev.h>

struct psp_cmdresp_head {
	uint32_t buf_size;
	uint32_t cmdresp_size;
	uint32_t cmdresp_code;
} __packed;

int guest_addr_map_table_op(void *data_hva, gpa_t data_gpa, gpa_t table_gpa,
		int op)
{
	return 0;
}

int kvm_pv_psp_op(struct kvm *kvm, int cmd, gpa_t data_gpa, gpa_t psp_ret_gpa,
		gpa_t table_gpa)
{
	void *data;
	struct psp_cmdresp_head psp_head;
	uint32_t data_size;
	int psp_ret = 0;
	int ret = 0;

	if (unlikely(kvm_read_guest(kvm, data_gpa, &psp_head,
					sizeof(struct psp_cmdresp_head))))
		return -EFAULT;

	data_size = psp_head.buf_size;
	data = kzalloc(data_size, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	if (unlikely(kvm_read_guest(kvm, data_gpa, data, data_size))) {
		ret = -EFAULT;
		goto e_free;
	}

	if (guest_addr_map_table_op(data, data_gpa, table_gpa, 0)) {
		ret = -EFAULT;
		goto e_free;
	}

	ret = psp_do_cmd(cmd, data, &psp_ret);
	if (ret) {
		pr_err("%s: psp do cmd error, %d\n", __func__, psp_ret);
		ret = -EIO;
		goto e_free;
	}

	if (guest_addr_map_table_op(data, data_gpa, table_gpa, 1)) {
		ret = -EFAULT;
		goto e_free;
	}

	if (unlikely(kvm_write_guest(kvm, data_gpa, data, data_size))) {
		ret = -EFAULT;
		goto e_free;
	}

	if (unlikely(kvm_write_guest(kvm, psp_ret_gpa, &psp_ret,
				sizeof(psp_ret)))) {
		ret = -EFAULT;
		goto e_free;
	}

	return ret;

e_free:
	kfree(data);
	return ret;
}
+4 −1
Original line number Diff line number Diff line
@@ -9970,7 +9970,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
	}

	if (static_call(kvm_x86_get_cpl)(vcpu) != 0 &&
	    !(is_x86_vendor_hygon() && nr == KVM_HC_VM_ATTESTATION)) {
	    !(is_x86_vendor_hygon() && (nr == KVM_HC_VM_ATTESTATION || nr == KVM_HC_PSP_OP))) {
		ret = -KVM_EPERM;
		goto out;
	}
@@ -10007,6 +10007,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
		kvm_sched_yield(vcpu, a0);
		ret = 0;
		break;
	case KVM_HC_PSP_OP:
		ret = kvm_pv_psp_op(vcpu->kvm, a0, a1, a2, a3);
		break;
	case KVM_HC_MAP_GPA_RANGE: {
		u64 gpa = a0, npages = a1, attrs = a2;

+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#define KVM_HC_SCHED_YIELD		11
#define KVM_HC_MAP_GPA_RANGE		12
#define KVM_HC_VM_ATTESTATION		100	/* Specific to Hygon CPU */
#define KVM_HC_PSP_OP			101	/* Specific to Hygon platform */

/*
 * hypercalls use architecture specific