162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Kernel-based Virtual Machine driver for Linux
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * AMD SVM-SEV support
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright 2010 Red Hat, Inc. and/or its affiliates.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kvm_types.h>
1262306a36Sopenharmony_ci#include <linux/kvm_host.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/highmem.h>
1562306a36Sopenharmony_ci#include <linux/psp.h>
1662306a36Sopenharmony_ci#include <linux/psp-sev.h>
1762306a36Sopenharmony_ci#include <linux/pagemap.h>
1862306a36Sopenharmony_ci#include <linux/swap.h>
1962306a36Sopenharmony_ci#include <linux/misc_cgroup.h>
2062306a36Sopenharmony_ci#include <linux/processor.h>
2162306a36Sopenharmony_ci#include <linux/trace_events.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <asm/pkru.h>
2462306a36Sopenharmony_ci#include <asm/trapnr.h>
2562306a36Sopenharmony_ci#include <asm/fpu/xcr.h>
2662306a36Sopenharmony_ci#include <asm/debugreg.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "mmu.h"
2962306a36Sopenharmony_ci#include "x86.h"
3062306a36Sopenharmony_ci#include "svm.h"
3162306a36Sopenharmony_ci#include "svm_ops.h"
3262306a36Sopenharmony_ci#include "cpuid.h"
3362306a36Sopenharmony_ci#include "trace.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#ifndef CONFIG_KVM_AMD_SEV
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * When this config is not defined, SEV feature is not supported and APIs in
3862306a36Sopenharmony_ci * this file are not used but this file still gets compiled into the KVM AMD
3962306a36Sopenharmony_ci * module.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * We will not have MISC_CG_RES_SEV and MISC_CG_RES_SEV_ES entries in the enum
4262306a36Sopenharmony_ci * misc_res_type {} defined in linux/misc_cgroup.h.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Below macros allow compilation to succeed.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ci#define MISC_CG_RES_SEV MISC_CG_RES_TYPES
4762306a36Sopenharmony_ci#define MISC_CG_RES_SEV_ES MISC_CG_RES_TYPES
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#ifdef CONFIG_KVM_AMD_SEV
5162306a36Sopenharmony_ci/* enable/disable SEV support */
5262306a36Sopenharmony_cistatic bool sev_enabled = true;
5362306a36Sopenharmony_cimodule_param_named(sev, sev_enabled, bool, 0444);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* enable/disable SEV-ES support */
5662306a36Sopenharmony_cistatic bool sev_es_enabled = true;
5762306a36Sopenharmony_cimodule_param_named(sev_es, sev_es_enabled, bool, 0444);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* enable/disable SEV-ES DebugSwap support */
6062306a36Sopenharmony_cistatic bool sev_es_debug_swap_enabled = true;
6162306a36Sopenharmony_cimodule_param_named(debug_swap, sev_es_debug_swap_enabled, bool, 0444);
6262306a36Sopenharmony_ci#else
6362306a36Sopenharmony_ci#define sev_enabled false
6462306a36Sopenharmony_ci#define sev_es_enabled false
6562306a36Sopenharmony_ci#define sev_es_debug_swap_enabled false
6662306a36Sopenharmony_ci#endif /* CONFIG_KVM_AMD_SEV */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic u8 sev_enc_bit;
6962306a36Sopenharmony_cistatic DECLARE_RWSEM(sev_deactivate_lock);
7062306a36Sopenharmony_cistatic DEFINE_MUTEX(sev_bitmap_lock);
7162306a36Sopenharmony_ciunsigned int max_sev_asid;
7262306a36Sopenharmony_cistatic unsigned int min_sev_asid;
7362306a36Sopenharmony_cistatic unsigned long sev_me_mask;
7462306a36Sopenharmony_cistatic unsigned int nr_asids;
7562306a36Sopenharmony_cistatic unsigned long *sev_asid_bitmap;
7662306a36Sopenharmony_cistatic unsigned long *sev_reclaim_asid_bitmap;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct enc_region {
7962306a36Sopenharmony_ci	struct list_head list;
8062306a36Sopenharmony_ci	unsigned long npages;
8162306a36Sopenharmony_ci	struct page **pages;
8262306a36Sopenharmony_ci	unsigned long uaddr;
8362306a36Sopenharmony_ci	unsigned long size;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* Called with the sev_bitmap_lock held, or on shutdown  */
8762306a36Sopenharmony_cistatic int sev_flush_asids(int min_asid, int max_asid)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	int ret, asid, error = 0;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* Check if there are any ASIDs to reclaim before performing a flush */
9262306a36Sopenharmony_ci	asid = find_next_bit(sev_reclaim_asid_bitmap, nr_asids, min_asid);
9362306a36Sopenharmony_ci	if (asid > max_asid)
9462306a36Sopenharmony_ci		return -EBUSY;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * DEACTIVATE will clear the WBINVD indicator causing DF_FLUSH to fail,
9862306a36Sopenharmony_ci	 * so it must be guarded.
9962306a36Sopenharmony_ci	 */
10062306a36Sopenharmony_ci	down_write(&sev_deactivate_lock);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	wbinvd_on_all_cpus();
10362306a36Sopenharmony_ci	ret = sev_guest_df_flush(&error);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	up_write(&sev_deactivate_lock);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (ret)
10862306a36Sopenharmony_ci		pr_err("SEV: DF_FLUSH failed, ret=%d, error=%#x\n", ret, error);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return ret;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline bool is_mirroring_enc_context(struct kvm *kvm)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	return !!to_kvm_svm(kvm)->sev_info.enc_context_owner;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/* Must be called with the sev_bitmap_lock held */
11962306a36Sopenharmony_cistatic bool __sev_recycle_asids(int min_asid, int max_asid)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	if (sev_flush_asids(min_asid, max_asid))
12262306a36Sopenharmony_ci		return false;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* The flush process will flush all reclaimable SEV and SEV-ES ASIDs */
12562306a36Sopenharmony_ci	bitmap_xor(sev_asid_bitmap, sev_asid_bitmap, sev_reclaim_asid_bitmap,
12662306a36Sopenharmony_ci		   nr_asids);
12762306a36Sopenharmony_ci	bitmap_zero(sev_reclaim_asid_bitmap, nr_asids);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return true;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int sev_misc_cg_try_charge(struct kvm_sev_info *sev)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	enum misc_res_type type = sev->es_active ? MISC_CG_RES_SEV_ES : MISC_CG_RES_SEV;
13562306a36Sopenharmony_ci	return misc_cg_try_charge(type, sev->misc_cg, 1);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic void sev_misc_cg_uncharge(struct kvm_sev_info *sev)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	enum misc_res_type type = sev->es_active ? MISC_CG_RES_SEV_ES : MISC_CG_RES_SEV;
14162306a36Sopenharmony_ci	misc_cg_uncharge(type, sev->misc_cg, 1);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int sev_asid_new(struct kvm_sev_info *sev)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	int asid, min_asid, max_asid, ret;
14762306a36Sopenharmony_ci	bool retry = true;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	WARN_ON(sev->misc_cg);
15062306a36Sopenharmony_ci	sev->misc_cg = get_current_misc_cg();
15162306a36Sopenharmony_ci	ret = sev_misc_cg_try_charge(sev);
15262306a36Sopenharmony_ci	if (ret) {
15362306a36Sopenharmony_ci		put_misc_cg(sev->misc_cg);
15462306a36Sopenharmony_ci		sev->misc_cg = NULL;
15562306a36Sopenharmony_ci		return ret;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	mutex_lock(&sev_bitmap_lock);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/*
16162306a36Sopenharmony_ci	 * SEV-enabled guests must use asid from min_sev_asid to max_sev_asid.
16262306a36Sopenharmony_ci	 * SEV-ES-enabled guest can use from 1 to min_sev_asid - 1.
16362306a36Sopenharmony_ci	 */
16462306a36Sopenharmony_ci	min_asid = sev->es_active ? 1 : min_sev_asid;
16562306a36Sopenharmony_ci	max_asid = sev->es_active ? min_sev_asid - 1 : max_sev_asid;
16662306a36Sopenharmony_ciagain:
16762306a36Sopenharmony_ci	asid = find_next_zero_bit(sev_asid_bitmap, max_asid + 1, min_asid);
16862306a36Sopenharmony_ci	if (asid > max_asid) {
16962306a36Sopenharmony_ci		if (retry && __sev_recycle_asids(min_asid, max_asid)) {
17062306a36Sopenharmony_ci			retry = false;
17162306a36Sopenharmony_ci			goto again;
17262306a36Sopenharmony_ci		}
17362306a36Sopenharmony_ci		mutex_unlock(&sev_bitmap_lock);
17462306a36Sopenharmony_ci		ret = -EBUSY;
17562306a36Sopenharmony_ci		goto e_uncharge;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	__set_bit(asid, sev_asid_bitmap);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	mutex_unlock(&sev_bitmap_lock);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return asid;
18362306a36Sopenharmony_cie_uncharge:
18462306a36Sopenharmony_ci	sev_misc_cg_uncharge(sev);
18562306a36Sopenharmony_ci	put_misc_cg(sev->misc_cg);
18662306a36Sopenharmony_ci	sev->misc_cg = NULL;
18762306a36Sopenharmony_ci	return ret;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int sev_get_asid(struct kvm *kvm)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return sev->asid;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic void sev_asid_free(struct kvm_sev_info *sev)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct svm_cpu_data *sd;
20062306a36Sopenharmony_ci	int cpu;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	mutex_lock(&sev_bitmap_lock);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	__set_bit(sev->asid, sev_reclaim_asid_bitmap);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
20762306a36Sopenharmony_ci		sd = per_cpu_ptr(&svm_data, cpu);
20862306a36Sopenharmony_ci		sd->sev_vmcbs[sev->asid] = NULL;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	mutex_unlock(&sev_bitmap_lock);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	sev_misc_cg_uncharge(sev);
21462306a36Sopenharmony_ci	put_misc_cg(sev->misc_cg);
21562306a36Sopenharmony_ci	sev->misc_cg = NULL;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic void sev_decommission(unsigned int handle)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct sev_data_decommission decommission;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (!handle)
22362306a36Sopenharmony_ci		return;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	decommission.handle = handle;
22662306a36Sopenharmony_ci	sev_guest_decommission(&decommission, NULL);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic void sev_unbind_asid(struct kvm *kvm, unsigned int handle)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct sev_data_deactivate deactivate;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (!handle)
23462306a36Sopenharmony_ci		return;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	deactivate.handle = handle;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/* Guard DEACTIVATE against WBINVD/DF_FLUSH used in ASID recycling */
23962306a36Sopenharmony_ci	down_read(&sev_deactivate_lock);
24062306a36Sopenharmony_ci	sev_guest_deactivate(&deactivate, NULL);
24162306a36Sopenharmony_ci	up_read(&sev_deactivate_lock);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	sev_decommission(handle);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
24962306a36Sopenharmony_ci	int asid, ret;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (kvm->created_vcpus)
25262306a36Sopenharmony_ci		return -EINVAL;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	ret = -EBUSY;
25562306a36Sopenharmony_ci	if (unlikely(sev->active))
25662306a36Sopenharmony_ci		return ret;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	sev->active = true;
25962306a36Sopenharmony_ci	sev->es_active = argp->id == KVM_SEV_ES_INIT;
26062306a36Sopenharmony_ci	asid = sev_asid_new(sev);
26162306a36Sopenharmony_ci	if (asid < 0)
26262306a36Sopenharmony_ci		goto e_no_asid;
26362306a36Sopenharmony_ci	sev->asid = asid;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ret = sev_platform_init(&argp->error);
26662306a36Sopenharmony_ci	if (ret)
26762306a36Sopenharmony_ci		goto e_free;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	INIT_LIST_HEAD(&sev->regions_list);
27062306a36Sopenharmony_ci	INIT_LIST_HEAD(&sev->mirror_vms);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	kvm_set_apicv_inhibit(kvm, APICV_INHIBIT_REASON_SEV);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cie_free:
27762306a36Sopenharmony_ci	sev_asid_free(sev);
27862306a36Sopenharmony_ci	sev->asid = 0;
27962306a36Sopenharmony_cie_no_asid:
28062306a36Sopenharmony_ci	sev->es_active = false;
28162306a36Sopenharmony_ci	sev->active = false;
28262306a36Sopenharmony_ci	return ret;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct sev_data_activate activate;
28862306a36Sopenharmony_ci	int asid = sev_get_asid(kvm);
28962306a36Sopenharmony_ci	int ret;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* activate ASID on the given handle */
29262306a36Sopenharmony_ci	activate.handle = handle;
29362306a36Sopenharmony_ci	activate.asid   = asid;
29462306a36Sopenharmony_ci	ret = sev_guest_activate(&activate, error);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return ret;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int __sev_issue_cmd(int fd, int id, void *data, int *error)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct fd f;
30262306a36Sopenharmony_ci	int ret;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	f = fdget(fd);
30562306a36Sopenharmony_ci	if (!f.file)
30662306a36Sopenharmony_ci		return -EBADF;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ret = sev_issue_cmd_external_user(f.file, id, data, error);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	fdput(f);
31162306a36Sopenharmony_ci	return ret;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return __sev_issue_cmd(sev->fd, id, data, error);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
32462306a36Sopenharmony_ci	struct sev_data_launch_start start;
32562306a36Sopenharmony_ci	struct kvm_sev_launch_start params;
32662306a36Sopenharmony_ci	void *dh_blob, *session_blob;
32762306a36Sopenharmony_ci	int *error = &argp->error;
32862306a36Sopenharmony_ci	int ret;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (!sev_guest(kvm))
33162306a36Sopenharmony_ci		return -ENOTTY;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
33462306a36Sopenharmony_ci		return -EFAULT;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	memset(&start, 0, sizeof(start));
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	dh_blob = NULL;
33962306a36Sopenharmony_ci	if (params.dh_uaddr) {
34062306a36Sopenharmony_ci		dh_blob = psp_copy_user_blob(params.dh_uaddr, params.dh_len);
34162306a36Sopenharmony_ci		if (IS_ERR(dh_blob))
34262306a36Sopenharmony_ci			return PTR_ERR(dh_blob);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		start.dh_cert_address = __sme_set(__pa(dh_blob));
34562306a36Sopenharmony_ci		start.dh_cert_len = params.dh_len;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	session_blob = NULL;
34962306a36Sopenharmony_ci	if (params.session_uaddr) {
35062306a36Sopenharmony_ci		session_blob = psp_copy_user_blob(params.session_uaddr, params.session_len);
35162306a36Sopenharmony_ci		if (IS_ERR(session_blob)) {
35262306a36Sopenharmony_ci			ret = PTR_ERR(session_blob);
35362306a36Sopenharmony_ci			goto e_free_dh;
35462306a36Sopenharmony_ci		}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		start.session_address = __sme_set(__pa(session_blob));
35762306a36Sopenharmony_ci		start.session_len = params.session_len;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	start.handle = params.handle;
36162306a36Sopenharmony_ci	start.policy = params.policy;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* create memory encryption context */
36462306a36Sopenharmony_ci	ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, &start, error);
36562306a36Sopenharmony_ci	if (ret)
36662306a36Sopenharmony_ci		goto e_free_session;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	/* Bind ASID to this guest */
36962306a36Sopenharmony_ci	ret = sev_bind_asid(kvm, start.handle, error);
37062306a36Sopenharmony_ci	if (ret) {
37162306a36Sopenharmony_ci		sev_decommission(start.handle);
37262306a36Sopenharmony_ci		goto e_free_session;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* return handle to userspace */
37662306a36Sopenharmony_ci	params.handle = start.handle;
37762306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params))) {
37862306a36Sopenharmony_ci		sev_unbind_asid(kvm, start.handle);
37962306a36Sopenharmony_ci		ret = -EFAULT;
38062306a36Sopenharmony_ci		goto e_free_session;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	sev->handle = start.handle;
38462306a36Sopenharmony_ci	sev->fd = argp->sev_fd;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cie_free_session:
38762306a36Sopenharmony_ci	kfree(session_blob);
38862306a36Sopenharmony_cie_free_dh:
38962306a36Sopenharmony_ci	kfree(dh_blob);
39062306a36Sopenharmony_ci	return ret;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
39462306a36Sopenharmony_ci				    unsigned long ulen, unsigned long *n,
39562306a36Sopenharmony_ci				    int write)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
39862306a36Sopenharmony_ci	unsigned long npages, size;
39962306a36Sopenharmony_ci	int npinned;
40062306a36Sopenharmony_ci	unsigned long locked, lock_limit;
40162306a36Sopenharmony_ci	struct page **pages;
40262306a36Sopenharmony_ci	unsigned long first, last;
40362306a36Sopenharmony_ci	int ret;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	lockdep_assert_held(&kvm->lock);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (ulen == 0 || uaddr + ulen < uaddr)
40862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* Calculate number of pages. */
41162306a36Sopenharmony_ci	first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
41262306a36Sopenharmony_ci	last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
41362306a36Sopenharmony_ci	npages = (last - first + 1);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	locked = sev->pages_locked + npages;
41662306a36Sopenharmony_ci	lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
41762306a36Sopenharmony_ci	if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
41862306a36Sopenharmony_ci		pr_err("SEV: %lu locked pages exceed the lock limit of %lu.\n", locked, lock_limit);
41962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (WARN_ON_ONCE(npages > INT_MAX))
42362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* Avoid using vmalloc for smaller buffers. */
42662306a36Sopenharmony_ci	size = npages * sizeof(struct page *);
42762306a36Sopenharmony_ci	if (size > PAGE_SIZE)
42862306a36Sopenharmony_ci		pages = __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
42962306a36Sopenharmony_ci	else
43062306a36Sopenharmony_ci		pages = kmalloc(size, GFP_KERNEL_ACCOUNT);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (!pages)
43362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* Pin the user virtual address. */
43662306a36Sopenharmony_ci	npinned = pin_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages);
43762306a36Sopenharmony_ci	if (npinned != npages) {
43862306a36Sopenharmony_ci		pr_err("SEV: Failure locking %lu pages.\n", npages);
43962306a36Sopenharmony_ci		ret = -ENOMEM;
44062306a36Sopenharmony_ci		goto err;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	*n = npages;
44462306a36Sopenharmony_ci	sev->pages_locked = locked;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	return pages;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cierr:
44962306a36Sopenharmony_ci	if (npinned > 0)
45062306a36Sopenharmony_ci		unpin_user_pages(pages, npinned);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	kvfree(pages);
45362306a36Sopenharmony_ci	return ERR_PTR(ret);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic void sev_unpin_memory(struct kvm *kvm, struct page **pages,
45762306a36Sopenharmony_ci			     unsigned long npages)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	unpin_user_pages(pages, npages);
46262306a36Sopenharmony_ci	kvfree(pages);
46362306a36Sopenharmony_ci	sev->pages_locked -= npages;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic void sev_clflush_pages(struct page *pages[], unsigned long npages)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	uint8_t *page_virtual;
46962306a36Sopenharmony_ci	unsigned long i;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (this_cpu_has(X86_FEATURE_SME_COHERENT) || npages == 0 ||
47262306a36Sopenharmony_ci	    pages == NULL)
47362306a36Sopenharmony_ci		return;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	for (i = 0; i < npages; i++) {
47662306a36Sopenharmony_ci		page_virtual = kmap_local_page(pages[i]);
47762306a36Sopenharmony_ci		clflush_cache_range(page_virtual, PAGE_SIZE);
47862306a36Sopenharmony_ci		kunmap_local(page_virtual);
47962306a36Sopenharmony_ci		cond_resched();
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic unsigned long get_num_contig_pages(unsigned long idx,
48462306a36Sopenharmony_ci				struct page **inpages, unsigned long npages)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	unsigned long paddr, next_paddr;
48762306a36Sopenharmony_ci	unsigned long i = idx + 1, pages = 1;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* find the number of contiguous pages starting from idx */
49062306a36Sopenharmony_ci	paddr = __sme_page_pa(inpages[idx]);
49162306a36Sopenharmony_ci	while (i < npages) {
49262306a36Sopenharmony_ci		next_paddr = __sme_page_pa(inpages[i++]);
49362306a36Sopenharmony_ci		if ((paddr + PAGE_SIZE) == next_paddr) {
49462306a36Sopenharmony_ci			pages++;
49562306a36Sopenharmony_ci			paddr = next_paddr;
49662306a36Sopenharmony_ci			continue;
49762306a36Sopenharmony_ci		}
49862306a36Sopenharmony_ci		break;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return pages;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	unsigned long vaddr, vaddr_end, next_vaddr, npages, pages, size, i;
50762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
50862306a36Sopenharmony_ci	struct kvm_sev_launch_update_data params;
50962306a36Sopenharmony_ci	struct sev_data_launch_update_data data;
51062306a36Sopenharmony_ci	struct page **inpages;
51162306a36Sopenharmony_ci	int ret;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (!sev_guest(kvm))
51462306a36Sopenharmony_ci		return -ENOTTY;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
51762306a36Sopenharmony_ci		return -EFAULT;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	vaddr = params.uaddr;
52062306a36Sopenharmony_ci	size = params.len;
52162306a36Sopenharmony_ci	vaddr_end = vaddr + size;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* Lock the user memory. */
52462306a36Sopenharmony_ci	inpages = sev_pin_memory(kvm, vaddr, size, &npages, 1);
52562306a36Sopenharmony_ci	if (IS_ERR(inpages))
52662306a36Sopenharmony_ci		return PTR_ERR(inpages);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/*
52962306a36Sopenharmony_ci	 * Flush (on non-coherent CPUs) before LAUNCH_UPDATE encrypts pages in
53062306a36Sopenharmony_ci	 * place; the cache may contain the data that was written unencrypted.
53162306a36Sopenharmony_ci	 */
53262306a36Sopenharmony_ci	sev_clflush_pages(inpages, npages);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	data.reserved = 0;
53562306a36Sopenharmony_ci	data.handle = sev->handle;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	for (i = 0; vaddr < vaddr_end; vaddr = next_vaddr, i += pages) {
53862306a36Sopenharmony_ci		int offset, len;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		/*
54162306a36Sopenharmony_ci		 * If the user buffer is not page-aligned, calculate the offset
54262306a36Sopenharmony_ci		 * within the page.
54362306a36Sopenharmony_ci		 */
54462306a36Sopenharmony_ci		offset = vaddr & (PAGE_SIZE - 1);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		/* Calculate the number of pages that can be encrypted in one go. */
54762306a36Sopenharmony_ci		pages = get_num_contig_pages(i, inpages, npages);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		len = min_t(size_t, ((pages * PAGE_SIZE) - offset), size);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		data.len = len;
55262306a36Sopenharmony_ci		data.address = __sme_page_pa(inpages[i]) + offset;
55362306a36Sopenharmony_ci		ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA, &data, &argp->error);
55462306a36Sopenharmony_ci		if (ret)
55562306a36Sopenharmony_ci			goto e_unpin;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		size -= len;
55862306a36Sopenharmony_ci		next_vaddr = vaddr + len;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cie_unpin:
56262306a36Sopenharmony_ci	/* content of memory is updated, mark pages dirty */
56362306a36Sopenharmony_ci	for (i = 0; i < npages; i++) {
56462306a36Sopenharmony_ci		set_page_dirty_lock(inpages[i]);
56562306a36Sopenharmony_ci		mark_page_accessed(inpages[i]);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci	/* unlock the user pages */
56862306a36Sopenharmony_ci	sev_unpin_memory(kvm, inpages, npages);
56962306a36Sopenharmony_ci	return ret;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic int sev_es_sync_vmsa(struct vcpu_svm *svm)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	struct sev_es_save_area *save = svm->sev_es.vmsa;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* Check some debug related fields before encrypting the VMSA */
57762306a36Sopenharmony_ci	if (svm->vcpu.guest_debug || (svm->vmcb->save.dr7 & ~DR7_FIXED_1))
57862306a36Sopenharmony_ci		return -EINVAL;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/*
58162306a36Sopenharmony_ci	 * SEV-ES will use a VMSA that is pointed to by the VMCB, not
58262306a36Sopenharmony_ci	 * the traditional VMSA that is part of the VMCB. Copy the
58362306a36Sopenharmony_ci	 * traditional VMSA as it has been built so far (in prep
58462306a36Sopenharmony_ci	 * for LAUNCH_UPDATE_VMSA) to be the initial SEV-ES state.
58562306a36Sopenharmony_ci	 */
58662306a36Sopenharmony_ci	memcpy(save, &svm->vmcb->save, sizeof(svm->vmcb->save));
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* Sync registgers */
58962306a36Sopenharmony_ci	save->rax = svm->vcpu.arch.regs[VCPU_REGS_RAX];
59062306a36Sopenharmony_ci	save->rbx = svm->vcpu.arch.regs[VCPU_REGS_RBX];
59162306a36Sopenharmony_ci	save->rcx = svm->vcpu.arch.regs[VCPU_REGS_RCX];
59262306a36Sopenharmony_ci	save->rdx = svm->vcpu.arch.regs[VCPU_REGS_RDX];
59362306a36Sopenharmony_ci	save->rsp = svm->vcpu.arch.regs[VCPU_REGS_RSP];
59462306a36Sopenharmony_ci	save->rbp = svm->vcpu.arch.regs[VCPU_REGS_RBP];
59562306a36Sopenharmony_ci	save->rsi = svm->vcpu.arch.regs[VCPU_REGS_RSI];
59662306a36Sopenharmony_ci	save->rdi = svm->vcpu.arch.regs[VCPU_REGS_RDI];
59762306a36Sopenharmony_ci#ifdef CONFIG_X86_64
59862306a36Sopenharmony_ci	save->r8  = svm->vcpu.arch.regs[VCPU_REGS_R8];
59962306a36Sopenharmony_ci	save->r9  = svm->vcpu.arch.regs[VCPU_REGS_R9];
60062306a36Sopenharmony_ci	save->r10 = svm->vcpu.arch.regs[VCPU_REGS_R10];
60162306a36Sopenharmony_ci	save->r11 = svm->vcpu.arch.regs[VCPU_REGS_R11];
60262306a36Sopenharmony_ci	save->r12 = svm->vcpu.arch.regs[VCPU_REGS_R12];
60362306a36Sopenharmony_ci	save->r13 = svm->vcpu.arch.regs[VCPU_REGS_R13];
60462306a36Sopenharmony_ci	save->r14 = svm->vcpu.arch.regs[VCPU_REGS_R14];
60562306a36Sopenharmony_ci	save->r15 = svm->vcpu.arch.regs[VCPU_REGS_R15];
60662306a36Sopenharmony_ci#endif
60762306a36Sopenharmony_ci	save->rip = svm->vcpu.arch.regs[VCPU_REGS_RIP];
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Sync some non-GPR registers before encrypting */
61062306a36Sopenharmony_ci	save->xcr0 = svm->vcpu.arch.xcr0;
61162306a36Sopenharmony_ci	save->pkru = svm->vcpu.arch.pkru;
61262306a36Sopenharmony_ci	save->xss  = svm->vcpu.arch.ia32_xss;
61362306a36Sopenharmony_ci	save->dr6  = svm->vcpu.arch.dr6;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (sev_es_debug_swap_enabled)
61662306a36Sopenharmony_ci		save->sev_features |= SVM_SEV_FEAT_DEBUG_SWAP;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	pr_debug("Virtual Machine Save Area (VMSA):\n");
61962306a36Sopenharmony_ci	print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	return 0;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic int __sev_launch_update_vmsa(struct kvm *kvm, struct kvm_vcpu *vcpu,
62562306a36Sopenharmony_ci				    int *error)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct sev_data_launch_update_vmsa vmsa;
62862306a36Sopenharmony_ci	struct vcpu_svm *svm = to_svm(vcpu);
62962306a36Sopenharmony_ci	int ret;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (vcpu->guest_debug) {
63262306a36Sopenharmony_ci		pr_warn_once("KVM_SET_GUEST_DEBUG for SEV-ES guest is not supported");
63362306a36Sopenharmony_ci		return -EINVAL;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* Perform some pre-encryption checks against the VMSA */
63762306a36Sopenharmony_ci	ret = sev_es_sync_vmsa(svm);
63862306a36Sopenharmony_ci	if (ret)
63962306a36Sopenharmony_ci		return ret;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/*
64262306a36Sopenharmony_ci	 * The LAUNCH_UPDATE_VMSA command will perform in-place encryption of
64362306a36Sopenharmony_ci	 * the VMSA memory content (i.e it will write the same memory region
64462306a36Sopenharmony_ci	 * with the guest's key), so invalidate it first.
64562306a36Sopenharmony_ci	 */
64662306a36Sopenharmony_ci	clflush_cache_range(svm->sev_es.vmsa, PAGE_SIZE);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	vmsa.reserved = 0;
64962306a36Sopenharmony_ci	vmsa.handle = to_kvm_svm(kvm)->sev_info.handle;
65062306a36Sopenharmony_ci	vmsa.address = __sme_pa(svm->sev_es.vmsa);
65162306a36Sopenharmony_ci	vmsa.len = PAGE_SIZE;
65262306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_VMSA, &vmsa, error);
65362306a36Sopenharmony_ci	if (ret)
65462306a36Sopenharmony_ci	  return ret;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	vcpu->arch.guest_state_protected = true;
65762306a36Sopenharmony_ci	return 0;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
66362306a36Sopenharmony_ci	unsigned long i;
66462306a36Sopenharmony_ci	int ret;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (!sev_es_guest(kvm))
66762306a36Sopenharmony_ci		return -ENOTTY;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm) {
67062306a36Sopenharmony_ci		ret = mutex_lock_killable(&vcpu->mutex);
67162306a36Sopenharmony_ci		if (ret)
67262306a36Sopenharmony_ci			return ret;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		ret = __sev_launch_update_vmsa(kvm, vcpu, &argp->error);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		mutex_unlock(&vcpu->mutex);
67762306a36Sopenharmony_ci		if (ret)
67862306a36Sopenharmony_ci			return ret;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	return 0;
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	void __user *measure = (void __user *)(uintptr_t)argp->data;
68762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
68862306a36Sopenharmony_ci	struct sev_data_launch_measure data;
68962306a36Sopenharmony_ci	struct kvm_sev_launch_measure params;
69062306a36Sopenharmony_ci	void __user *p = NULL;
69162306a36Sopenharmony_ci	void *blob = NULL;
69262306a36Sopenharmony_ci	int ret;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (!sev_guest(kvm))
69562306a36Sopenharmony_ci		return -ENOTTY;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (copy_from_user(&params, measure, sizeof(params)))
69862306a36Sopenharmony_ci		return -EFAULT;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* User wants to query the blob length */
70362306a36Sopenharmony_ci	if (!params.len)
70462306a36Sopenharmony_ci		goto cmd;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	p = (void __user *)(uintptr_t)params.uaddr;
70762306a36Sopenharmony_ci	if (p) {
70862306a36Sopenharmony_ci		if (params.len > SEV_FW_BLOB_MAX_SIZE)
70962306a36Sopenharmony_ci			return -EINVAL;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		blob = kzalloc(params.len, GFP_KERNEL_ACCOUNT);
71262306a36Sopenharmony_ci		if (!blob)
71362306a36Sopenharmony_ci			return -ENOMEM;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		data.address = __psp_pa(blob);
71662306a36Sopenharmony_ci		data.len = params.len;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cicmd:
72062306a36Sopenharmony_ci	data.handle = sev->handle;
72162306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_MEASURE, &data, &argp->error);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/*
72462306a36Sopenharmony_ci	 * If we query the session length, FW responded with expected data.
72562306a36Sopenharmony_ci	 */
72662306a36Sopenharmony_ci	if (!params.len)
72762306a36Sopenharmony_ci		goto done;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	if (ret)
73062306a36Sopenharmony_ci		goto e_free_blob;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (blob) {
73362306a36Sopenharmony_ci		if (copy_to_user(p, blob, params.len))
73462306a36Sopenharmony_ci			ret = -EFAULT;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cidone:
73862306a36Sopenharmony_ci	params.len = data.len;
73962306a36Sopenharmony_ci	if (copy_to_user(measure, &params, sizeof(params)))
74062306a36Sopenharmony_ci		ret = -EFAULT;
74162306a36Sopenharmony_cie_free_blob:
74262306a36Sopenharmony_ci	kfree(blob);
74362306a36Sopenharmony_ci	return ret;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int sev_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
74962306a36Sopenharmony_ci	struct sev_data_launch_finish data;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (!sev_guest(kvm))
75262306a36Sopenharmony_ci		return -ENOTTY;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	data.handle = sev->handle;
75562306a36Sopenharmony_ci	return sev_issue_cmd(kvm, SEV_CMD_LAUNCH_FINISH, &data, &argp->error);
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int sev_guest_status(struct kvm *kvm, struct kvm_sev_cmd *argp)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
76162306a36Sopenharmony_ci	struct kvm_sev_guest_status params;
76262306a36Sopenharmony_ci	struct sev_data_guest_status data;
76362306a36Sopenharmony_ci	int ret;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	if (!sev_guest(kvm))
76662306a36Sopenharmony_ci		return -ENOTTY;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	data.handle = sev->handle;
77162306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_GUEST_STATUS, &data, &argp->error);
77262306a36Sopenharmony_ci	if (ret)
77362306a36Sopenharmony_ci		return ret;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	params.policy = data.policy;
77662306a36Sopenharmony_ci	params.state = data.state;
77762306a36Sopenharmony_ci	params.handle = data.handle;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params)))
78062306a36Sopenharmony_ci		ret = -EFAULT;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return ret;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic int __sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src,
78662306a36Sopenharmony_ci			       unsigned long dst, int size,
78762306a36Sopenharmony_ci			       int *error, bool enc)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
79062306a36Sopenharmony_ci	struct sev_data_dbg data;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	data.reserved = 0;
79362306a36Sopenharmony_ci	data.handle = sev->handle;
79462306a36Sopenharmony_ci	data.dst_addr = dst;
79562306a36Sopenharmony_ci	data.src_addr = src;
79662306a36Sopenharmony_ci	data.len = size;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	return sev_issue_cmd(kvm,
79962306a36Sopenharmony_ci			     enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT,
80062306a36Sopenharmony_ci			     &data, error);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr,
80462306a36Sopenharmony_ci			     unsigned long dst_paddr, int sz, int *err)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	int offset;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/*
80962306a36Sopenharmony_ci	 * Its safe to read more than we are asked, caller should ensure that
81062306a36Sopenharmony_ci	 * destination has enough space.
81162306a36Sopenharmony_ci	 */
81262306a36Sopenharmony_ci	offset = src_paddr & 15;
81362306a36Sopenharmony_ci	src_paddr = round_down(src_paddr, 16);
81462306a36Sopenharmony_ci	sz = round_up(sz + offset, 16);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	return __sev_issue_dbg_cmd(kvm, src_paddr, dst_paddr, sz, err, false);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr,
82062306a36Sopenharmony_ci				  void __user *dst_uaddr,
82162306a36Sopenharmony_ci				  unsigned long dst_paddr,
82262306a36Sopenharmony_ci				  int size, int *err)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	struct page *tpage = NULL;
82562306a36Sopenharmony_ci	int ret, offset;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* if inputs are not 16-byte then use intermediate buffer */
82862306a36Sopenharmony_ci	if (!IS_ALIGNED(dst_paddr, 16) ||
82962306a36Sopenharmony_ci	    !IS_ALIGNED(paddr,     16) ||
83062306a36Sopenharmony_ci	    !IS_ALIGNED(size,      16)) {
83162306a36Sopenharmony_ci		tpage = (void *)alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
83262306a36Sopenharmony_ci		if (!tpage)
83362306a36Sopenharmony_ci			return -ENOMEM;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		dst_paddr = __sme_page_pa(tpage);
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	ret = __sev_dbg_decrypt(kvm, paddr, dst_paddr, size, err);
83962306a36Sopenharmony_ci	if (ret)
84062306a36Sopenharmony_ci		goto e_free;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (tpage) {
84362306a36Sopenharmony_ci		offset = paddr & 15;
84462306a36Sopenharmony_ci		if (copy_to_user(dst_uaddr, page_address(tpage) + offset, size))
84562306a36Sopenharmony_ci			ret = -EFAULT;
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cie_free:
84962306a36Sopenharmony_ci	if (tpage)
85062306a36Sopenharmony_ci		__free_page(tpage);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return ret;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic int __sev_dbg_encrypt_user(struct kvm *kvm, unsigned long paddr,
85662306a36Sopenharmony_ci				  void __user *vaddr,
85762306a36Sopenharmony_ci				  unsigned long dst_paddr,
85862306a36Sopenharmony_ci				  void __user *dst_vaddr,
85962306a36Sopenharmony_ci				  int size, int *error)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	struct page *src_tpage = NULL;
86262306a36Sopenharmony_ci	struct page *dst_tpage = NULL;
86362306a36Sopenharmony_ci	int ret, len = size;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* If source buffer is not aligned then use an intermediate buffer */
86662306a36Sopenharmony_ci	if (!IS_ALIGNED((unsigned long)vaddr, 16)) {
86762306a36Sopenharmony_ci		src_tpage = alloc_page(GFP_KERNEL_ACCOUNT);
86862306a36Sopenharmony_ci		if (!src_tpage)
86962306a36Sopenharmony_ci			return -ENOMEM;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		if (copy_from_user(page_address(src_tpage), vaddr, size)) {
87262306a36Sopenharmony_ci			__free_page(src_tpage);
87362306a36Sopenharmony_ci			return -EFAULT;
87462306a36Sopenharmony_ci		}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci		paddr = __sme_page_pa(src_tpage);
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/*
88062306a36Sopenharmony_ci	 *  If destination buffer or length is not aligned then do read-modify-write:
88162306a36Sopenharmony_ci	 *   - decrypt destination in an intermediate buffer
88262306a36Sopenharmony_ci	 *   - copy the source buffer in an intermediate buffer
88362306a36Sopenharmony_ci	 *   - use the intermediate buffer as source buffer
88462306a36Sopenharmony_ci	 */
88562306a36Sopenharmony_ci	if (!IS_ALIGNED((unsigned long)dst_vaddr, 16) || !IS_ALIGNED(size, 16)) {
88662306a36Sopenharmony_ci		int dst_offset;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci		dst_tpage = alloc_page(GFP_KERNEL_ACCOUNT);
88962306a36Sopenharmony_ci		if (!dst_tpage) {
89062306a36Sopenharmony_ci			ret = -ENOMEM;
89162306a36Sopenharmony_ci			goto e_free;
89262306a36Sopenharmony_ci		}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci		ret = __sev_dbg_decrypt(kvm, dst_paddr,
89562306a36Sopenharmony_ci					__sme_page_pa(dst_tpage), size, error);
89662306a36Sopenharmony_ci		if (ret)
89762306a36Sopenharmony_ci			goto e_free;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		/*
90062306a36Sopenharmony_ci		 *  If source is kernel buffer then use memcpy() otherwise
90162306a36Sopenharmony_ci		 *  copy_from_user().
90262306a36Sopenharmony_ci		 */
90362306a36Sopenharmony_ci		dst_offset = dst_paddr & 15;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		if (src_tpage)
90662306a36Sopenharmony_ci			memcpy(page_address(dst_tpage) + dst_offset,
90762306a36Sopenharmony_ci			       page_address(src_tpage), size);
90862306a36Sopenharmony_ci		else {
90962306a36Sopenharmony_ci			if (copy_from_user(page_address(dst_tpage) + dst_offset,
91062306a36Sopenharmony_ci					   vaddr, size)) {
91162306a36Sopenharmony_ci				ret = -EFAULT;
91262306a36Sopenharmony_ci				goto e_free;
91362306a36Sopenharmony_ci			}
91462306a36Sopenharmony_ci		}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci		paddr = __sme_page_pa(dst_tpage);
91762306a36Sopenharmony_ci		dst_paddr = round_down(dst_paddr, 16);
91862306a36Sopenharmony_ci		len = round_up(size, 16);
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	ret = __sev_issue_dbg_cmd(kvm, paddr, dst_paddr, len, error, true);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cie_free:
92462306a36Sopenharmony_ci	if (src_tpage)
92562306a36Sopenharmony_ci		__free_page(src_tpage);
92662306a36Sopenharmony_ci	if (dst_tpage)
92762306a36Sopenharmony_ci		__free_page(dst_tpage);
92862306a36Sopenharmony_ci	return ret;
92962306a36Sopenharmony_ci}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	unsigned long vaddr, vaddr_end, next_vaddr;
93462306a36Sopenharmony_ci	unsigned long dst_vaddr;
93562306a36Sopenharmony_ci	struct page **src_p, **dst_p;
93662306a36Sopenharmony_ci	struct kvm_sev_dbg debug;
93762306a36Sopenharmony_ci	unsigned long n;
93862306a36Sopenharmony_ci	unsigned int size;
93962306a36Sopenharmony_ci	int ret;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (!sev_guest(kvm))
94262306a36Sopenharmony_ci		return -ENOTTY;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	if (copy_from_user(&debug, (void __user *)(uintptr_t)argp->data, sizeof(debug)))
94562306a36Sopenharmony_ci		return -EFAULT;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (!debug.len || debug.src_uaddr + debug.len < debug.src_uaddr)
94862306a36Sopenharmony_ci		return -EINVAL;
94962306a36Sopenharmony_ci	if (!debug.dst_uaddr)
95062306a36Sopenharmony_ci		return -EINVAL;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	vaddr = debug.src_uaddr;
95362306a36Sopenharmony_ci	size = debug.len;
95462306a36Sopenharmony_ci	vaddr_end = vaddr + size;
95562306a36Sopenharmony_ci	dst_vaddr = debug.dst_uaddr;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	for (; vaddr < vaddr_end; vaddr = next_vaddr) {
95862306a36Sopenharmony_ci		int len, s_off, d_off;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci		/* lock userspace source and destination page */
96162306a36Sopenharmony_ci		src_p = sev_pin_memory(kvm, vaddr & PAGE_MASK, PAGE_SIZE, &n, 0);
96262306a36Sopenharmony_ci		if (IS_ERR(src_p))
96362306a36Sopenharmony_ci			return PTR_ERR(src_p);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		dst_p = sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, 1);
96662306a36Sopenharmony_ci		if (IS_ERR(dst_p)) {
96762306a36Sopenharmony_ci			sev_unpin_memory(kvm, src_p, n);
96862306a36Sopenharmony_ci			return PTR_ERR(dst_p);
96962306a36Sopenharmony_ci		}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		/*
97262306a36Sopenharmony_ci		 * Flush (on non-coherent CPUs) before DBG_{DE,EN}CRYPT read or modify
97362306a36Sopenharmony_ci		 * the pages; flush the destination too so that future accesses do not
97462306a36Sopenharmony_ci		 * see stale data.
97562306a36Sopenharmony_ci		 */
97662306a36Sopenharmony_ci		sev_clflush_pages(src_p, 1);
97762306a36Sopenharmony_ci		sev_clflush_pages(dst_p, 1);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		/*
98062306a36Sopenharmony_ci		 * Since user buffer may not be page aligned, calculate the
98162306a36Sopenharmony_ci		 * offset within the page.
98262306a36Sopenharmony_ci		 */
98362306a36Sopenharmony_ci		s_off = vaddr & ~PAGE_MASK;
98462306a36Sopenharmony_ci		d_off = dst_vaddr & ~PAGE_MASK;
98562306a36Sopenharmony_ci		len = min_t(size_t, (PAGE_SIZE - s_off), size);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		if (dec)
98862306a36Sopenharmony_ci			ret = __sev_dbg_decrypt_user(kvm,
98962306a36Sopenharmony_ci						     __sme_page_pa(src_p[0]) + s_off,
99062306a36Sopenharmony_ci						     (void __user *)dst_vaddr,
99162306a36Sopenharmony_ci						     __sme_page_pa(dst_p[0]) + d_off,
99262306a36Sopenharmony_ci						     len, &argp->error);
99362306a36Sopenharmony_ci		else
99462306a36Sopenharmony_ci			ret = __sev_dbg_encrypt_user(kvm,
99562306a36Sopenharmony_ci						     __sme_page_pa(src_p[0]) + s_off,
99662306a36Sopenharmony_ci						     (void __user *)vaddr,
99762306a36Sopenharmony_ci						     __sme_page_pa(dst_p[0]) + d_off,
99862306a36Sopenharmony_ci						     (void __user *)dst_vaddr,
99962306a36Sopenharmony_ci						     len, &argp->error);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		sev_unpin_memory(kvm, src_p, n);
100262306a36Sopenharmony_ci		sev_unpin_memory(kvm, dst_p, n);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		if (ret)
100562306a36Sopenharmony_ci			goto err;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		next_vaddr = vaddr + len;
100862306a36Sopenharmony_ci		dst_vaddr = dst_vaddr + len;
100962306a36Sopenharmony_ci		size -= len;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_cierr:
101262306a36Sopenharmony_ci	return ret;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
101862306a36Sopenharmony_ci	struct sev_data_launch_secret data;
101962306a36Sopenharmony_ci	struct kvm_sev_launch_secret params;
102062306a36Sopenharmony_ci	struct page **pages;
102162306a36Sopenharmony_ci	void *blob, *hdr;
102262306a36Sopenharmony_ci	unsigned long n, i;
102362306a36Sopenharmony_ci	int ret, offset;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	if (!sev_guest(kvm))
102662306a36Sopenharmony_ci		return -ENOTTY;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
102962306a36Sopenharmony_ci		return -EFAULT;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	pages = sev_pin_memory(kvm, params.guest_uaddr, params.guest_len, &n, 1);
103262306a36Sopenharmony_ci	if (IS_ERR(pages))
103362306a36Sopenharmony_ci		return PTR_ERR(pages);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/*
103662306a36Sopenharmony_ci	 * Flush (on non-coherent CPUs) before LAUNCH_SECRET encrypts pages in
103762306a36Sopenharmony_ci	 * place; the cache may contain the data that was written unencrypted.
103862306a36Sopenharmony_ci	 */
103962306a36Sopenharmony_ci	sev_clflush_pages(pages, n);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/*
104262306a36Sopenharmony_ci	 * The secret must be copied into contiguous memory region, lets verify
104362306a36Sopenharmony_ci	 * that userspace memory pages are contiguous before we issue command.
104462306a36Sopenharmony_ci	 */
104562306a36Sopenharmony_ci	if (get_num_contig_pages(0, pages, n) != n) {
104662306a36Sopenharmony_ci		ret = -EINVAL;
104762306a36Sopenharmony_ci		goto e_unpin_memory;
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	offset = params.guest_uaddr & (PAGE_SIZE - 1);
105362306a36Sopenharmony_ci	data.guest_address = __sme_page_pa(pages[0]) + offset;
105462306a36Sopenharmony_ci	data.guest_len = params.guest_len;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	blob = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
105762306a36Sopenharmony_ci	if (IS_ERR(blob)) {
105862306a36Sopenharmony_ci		ret = PTR_ERR(blob);
105962306a36Sopenharmony_ci		goto e_unpin_memory;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	data.trans_address = __psp_pa(blob);
106362306a36Sopenharmony_ci	data.trans_len = params.trans_len;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
106662306a36Sopenharmony_ci	if (IS_ERR(hdr)) {
106762306a36Sopenharmony_ci		ret = PTR_ERR(hdr);
106862306a36Sopenharmony_ci		goto e_free_blob;
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci	data.hdr_address = __psp_pa(hdr);
107162306a36Sopenharmony_ci	data.hdr_len = params.hdr_len;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	data.handle = sev->handle;
107462306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, &data, &argp->error);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	kfree(hdr);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cie_free_blob:
107962306a36Sopenharmony_ci	kfree(blob);
108062306a36Sopenharmony_cie_unpin_memory:
108162306a36Sopenharmony_ci	/* content of memory is updated, mark pages dirty */
108262306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
108362306a36Sopenharmony_ci		set_page_dirty_lock(pages[i]);
108462306a36Sopenharmony_ci		mark_page_accessed(pages[i]);
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci	sev_unpin_memory(kvm, pages, n);
108762306a36Sopenharmony_ci	return ret;
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_cistatic int sev_get_attestation_report(struct kvm *kvm, struct kvm_sev_cmd *argp)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	void __user *report = (void __user *)(uintptr_t)argp->data;
109362306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
109462306a36Sopenharmony_ci	struct sev_data_attestation_report data;
109562306a36Sopenharmony_ci	struct kvm_sev_attestation_report params;
109662306a36Sopenharmony_ci	void __user *p;
109762306a36Sopenharmony_ci	void *blob = NULL;
109862306a36Sopenharmony_ci	int ret;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (!sev_guest(kvm))
110162306a36Sopenharmony_ci		return -ENOTTY;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
110462306a36Sopenharmony_ci		return -EFAULT;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/* User wants to query the blob length */
110962306a36Sopenharmony_ci	if (!params.len)
111062306a36Sopenharmony_ci		goto cmd;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	p = (void __user *)(uintptr_t)params.uaddr;
111362306a36Sopenharmony_ci	if (p) {
111462306a36Sopenharmony_ci		if (params.len > SEV_FW_BLOB_MAX_SIZE)
111562306a36Sopenharmony_ci			return -EINVAL;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci		blob = kzalloc(params.len, GFP_KERNEL_ACCOUNT);
111862306a36Sopenharmony_ci		if (!blob)
111962306a36Sopenharmony_ci			return -ENOMEM;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		data.address = __psp_pa(blob);
112262306a36Sopenharmony_ci		data.len = params.len;
112362306a36Sopenharmony_ci		memcpy(data.mnonce, params.mnonce, sizeof(params.mnonce));
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_cicmd:
112662306a36Sopenharmony_ci	data.handle = sev->handle;
112762306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_ATTESTATION_REPORT, &data, &argp->error);
112862306a36Sopenharmony_ci	/*
112962306a36Sopenharmony_ci	 * If we query the session length, FW responded with expected data.
113062306a36Sopenharmony_ci	 */
113162306a36Sopenharmony_ci	if (!params.len)
113262306a36Sopenharmony_ci		goto done;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (ret)
113562306a36Sopenharmony_ci		goto e_free_blob;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (blob) {
113862306a36Sopenharmony_ci		if (copy_to_user(p, blob, params.len))
113962306a36Sopenharmony_ci			ret = -EFAULT;
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_cidone:
114362306a36Sopenharmony_ci	params.len = data.len;
114462306a36Sopenharmony_ci	if (copy_to_user(report, &params, sizeof(params)))
114562306a36Sopenharmony_ci		ret = -EFAULT;
114662306a36Sopenharmony_cie_free_blob:
114762306a36Sopenharmony_ci	kfree(blob);
114862306a36Sopenharmony_ci	return ret;
114962306a36Sopenharmony_ci}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci/* Userspace wants to query session length. */
115262306a36Sopenharmony_cistatic int
115362306a36Sopenharmony_ci__sev_send_start_query_session_length(struct kvm *kvm, struct kvm_sev_cmd *argp,
115462306a36Sopenharmony_ci				      struct kvm_sev_send_start *params)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
115762306a36Sopenharmony_ci	struct sev_data_send_start data;
115862306a36Sopenharmony_ci	int ret;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
116162306a36Sopenharmony_ci	data.handle = sev->handle;
116262306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, &data, &argp->error);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	params->session_len = data.session_len;
116562306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)argp->data, params,
116662306a36Sopenharmony_ci				sizeof(struct kvm_sev_send_start)))
116762306a36Sopenharmony_ci		ret = -EFAULT;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	return ret;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_cistatic int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
117562306a36Sopenharmony_ci	struct sev_data_send_start data;
117662306a36Sopenharmony_ci	struct kvm_sev_send_start params;
117762306a36Sopenharmony_ci	void *amd_certs, *session_data;
117862306a36Sopenharmony_ci	void *pdh_cert, *plat_certs;
117962306a36Sopenharmony_ci	int ret;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if (!sev_guest(kvm))
118262306a36Sopenharmony_ci		return -ENOTTY;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
118562306a36Sopenharmony_ci				sizeof(struct kvm_sev_send_start)))
118662306a36Sopenharmony_ci		return -EFAULT;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	/* if session_len is zero, userspace wants to query the session length */
118962306a36Sopenharmony_ci	if (!params.session_len)
119062306a36Sopenharmony_ci		return __sev_send_start_query_session_length(kvm, argp,
119162306a36Sopenharmony_ci				&params);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	/* some sanity checks */
119462306a36Sopenharmony_ci	if (!params.pdh_cert_uaddr || !params.pdh_cert_len ||
119562306a36Sopenharmony_ci	    !params.session_uaddr || params.session_len > SEV_FW_BLOB_MAX_SIZE)
119662306a36Sopenharmony_ci		return -EINVAL;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	/* allocate the memory to hold the session data blob */
119962306a36Sopenharmony_ci	session_data = kzalloc(params.session_len, GFP_KERNEL_ACCOUNT);
120062306a36Sopenharmony_ci	if (!session_data)
120162306a36Sopenharmony_ci		return -ENOMEM;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	/* copy the certificate blobs from userspace */
120462306a36Sopenharmony_ci	pdh_cert = psp_copy_user_blob(params.pdh_cert_uaddr,
120562306a36Sopenharmony_ci				params.pdh_cert_len);
120662306a36Sopenharmony_ci	if (IS_ERR(pdh_cert)) {
120762306a36Sopenharmony_ci		ret = PTR_ERR(pdh_cert);
120862306a36Sopenharmony_ci		goto e_free_session;
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	plat_certs = psp_copy_user_blob(params.plat_certs_uaddr,
121262306a36Sopenharmony_ci				params.plat_certs_len);
121362306a36Sopenharmony_ci	if (IS_ERR(plat_certs)) {
121462306a36Sopenharmony_ci		ret = PTR_ERR(plat_certs);
121562306a36Sopenharmony_ci		goto e_free_pdh;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	amd_certs = psp_copy_user_blob(params.amd_certs_uaddr,
121962306a36Sopenharmony_ci				params.amd_certs_len);
122062306a36Sopenharmony_ci	if (IS_ERR(amd_certs)) {
122162306a36Sopenharmony_ci		ret = PTR_ERR(amd_certs);
122262306a36Sopenharmony_ci		goto e_free_plat_cert;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* populate the FW SEND_START field with system physical address */
122662306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
122762306a36Sopenharmony_ci	data.pdh_cert_address = __psp_pa(pdh_cert);
122862306a36Sopenharmony_ci	data.pdh_cert_len = params.pdh_cert_len;
122962306a36Sopenharmony_ci	data.plat_certs_address = __psp_pa(plat_certs);
123062306a36Sopenharmony_ci	data.plat_certs_len = params.plat_certs_len;
123162306a36Sopenharmony_ci	data.amd_certs_address = __psp_pa(amd_certs);
123262306a36Sopenharmony_ci	data.amd_certs_len = params.amd_certs_len;
123362306a36Sopenharmony_ci	data.session_address = __psp_pa(session_data);
123462306a36Sopenharmony_ci	data.session_len = params.session_len;
123562306a36Sopenharmony_ci	data.handle = sev->handle;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, &data, &argp->error);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (!ret && copy_to_user((void __user *)(uintptr_t)params.session_uaddr,
124062306a36Sopenharmony_ci			session_data, params.session_len)) {
124162306a36Sopenharmony_ci		ret = -EFAULT;
124262306a36Sopenharmony_ci		goto e_free_amd_cert;
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	params.policy = data.policy;
124662306a36Sopenharmony_ci	params.session_len = data.session_len;
124762306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)argp->data, &params,
124862306a36Sopenharmony_ci				sizeof(struct kvm_sev_send_start)))
124962306a36Sopenharmony_ci		ret = -EFAULT;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cie_free_amd_cert:
125262306a36Sopenharmony_ci	kfree(amd_certs);
125362306a36Sopenharmony_cie_free_plat_cert:
125462306a36Sopenharmony_ci	kfree(plat_certs);
125562306a36Sopenharmony_cie_free_pdh:
125662306a36Sopenharmony_ci	kfree(pdh_cert);
125762306a36Sopenharmony_cie_free_session:
125862306a36Sopenharmony_ci	kfree(session_data);
125962306a36Sopenharmony_ci	return ret;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci/* Userspace wants to query either header or trans length. */
126362306a36Sopenharmony_cistatic int
126462306a36Sopenharmony_ci__sev_send_update_data_query_lengths(struct kvm *kvm, struct kvm_sev_cmd *argp,
126562306a36Sopenharmony_ci				     struct kvm_sev_send_update_data *params)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
126862306a36Sopenharmony_ci	struct sev_data_send_update_data data;
126962306a36Sopenharmony_ci	int ret;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
127262306a36Sopenharmony_ci	data.handle = sev->handle;
127362306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, &data, &argp->error);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	params->hdr_len = data.hdr_len;
127662306a36Sopenharmony_ci	params->trans_len = data.trans_len;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)argp->data, params,
127962306a36Sopenharmony_ci			 sizeof(struct kvm_sev_send_update_data)))
128062306a36Sopenharmony_ci		ret = -EFAULT;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	return ret;
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_cistatic int sev_send_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
128862306a36Sopenharmony_ci	struct sev_data_send_update_data data;
128962306a36Sopenharmony_ci	struct kvm_sev_send_update_data params;
129062306a36Sopenharmony_ci	void *hdr, *trans_data;
129162306a36Sopenharmony_ci	struct page **guest_page;
129262306a36Sopenharmony_ci	unsigned long n;
129362306a36Sopenharmony_ci	int ret, offset;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	if (!sev_guest(kvm))
129662306a36Sopenharmony_ci		return -ENOTTY;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
129962306a36Sopenharmony_ci			sizeof(struct kvm_sev_send_update_data)))
130062306a36Sopenharmony_ci		return -EFAULT;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	/* userspace wants to query either header or trans length */
130362306a36Sopenharmony_ci	if (!params.trans_len || !params.hdr_len)
130462306a36Sopenharmony_ci		return __sev_send_update_data_query_lengths(kvm, argp, &params);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	if (!params.trans_uaddr || !params.guest_uaddr ||
130762306a36Sopenharmony_ci	    !params.guest_len || !params.hdr_uaddr)
130862306a36Sopenharmony_ci		return -EINVAL;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	/* Check if we are crossing the page boundary */
131162306a36Sopenharmony_ci	offset = params.guest_uaddr & (PAGE_SIZE - 1);
131262306a36Sopenharmony_ci	if (params.guest_len > PAGE_SIZE || (params.guest_len + offset) > PAGE_SIZE)
131362306a36Sopenharmony_ci		return -EINVAL;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	/* Pin guest memory */
131662306a36Sopenharmony_ci	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
131762306a36Sopenharmony_ci				    PAGE_SIZE, &n, 0);
131862306a36Sopenharmony_ci	if (IS_ERR(guest_page))
131962306a36Sopenharmony_ci		return PTR_ERR(guest_page);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* allocate memory for header and transport buffer */
132262306a36Sopenharmony_ci	ret = -ENOMEM;
132362306a36Sopenharmony_ci	hdr = kzalloc(params.hdr_len, GFP_KERNEL_ACCOUNT);
132462306a36Sopenharmony_ci	if (!hdr)
132562306a36Sopenharmony_ci		goto e_unpin;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	trans_data = kzalloc(params.trans_len, GFP_KERNEL_ACCOUNT);
132862306a36Sopenharmony_ci	if (!trans_data)
132962306a36Sopenharmony_ci		goto e_free_hdr;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
133262306a36Sopenharmony_ci	data.hdr_address = __psp_pa(hdr);
133362306a36Sopenharmony_ci	data.hdr_len = params.hdr_len;
133462306a36Sopenharmony_ci	data.trans_address = __psp_pa(trans_data);
133562306a36Sopenharmony_ci	data.trans_len = params.trans_len;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	/* The SEND_UPDATE_DATA command requires C-bit to be always set. */
133862306a36Sopenharmony_ci	data.guest_address = (page_to_pfn(guest_page[0]) << PAGE_SHIFT) + offset;
133962306a36Sopenharmony_ci	data.guest_address |= sev_me_mask;
134062306a36Sopenharmony_ci	data.guest_len = params.guest_len;
134162306a36Sopenharmony_ci	data.handle = sev->handle;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, &data, &argp->error);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (ret)
134662306a36Sopenharmony_ci		goto e_free_trans_data;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	/* copy transport buffer to user space */
134962306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)params.trans_uaddr,
135062306a36Sopenharmony_ci			 trans_data, params.trans_len)) {
135162306a36Sopenharmony_ci		ret = -EFAULT;
135262306a36Sopenharmony_ci		goto e_free_trans_data;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	/* Copy packet header to userspace. */
135662306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)params.hdr_uaddr, hdr,
135762306a36Sopenharmony_ci			 params.hdr_len))
135862306a36Sopenharmony_ci		ret = -EFAULT;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_cie_free_trans_data:
136162306a36Sopenharmony_ci	kfree(trans_data);
136262306a36Sopenharmony_cie_free_hdr:
136362306a36Sopenharmony_ci	kfree(hdr);
136462306a36Sopenharmony_cie_unpin:
136562306a36Sopenharmony_ci	sev_unpin_memory(kvm, guest_page, n);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	return ret;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cistatic int sev_send_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
137362306a36Sopenharmony_ci	struct sev_data_send_finish data;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (!sev_guest(kvm))
137662306a36Sopenharmony_ci		return -ENOTTY;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	data.handle = sev->handle;
137962306a36Sopenharmony_ci	return sev_issue_cmd(kvm, SEV_CMD_SEND_FINISH, &data, &argp->error);
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic int sev_send_cancel(struct kvm *kvm, struct kvm_sev_cmd *argp)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
138562306a36Sopenharmony_ci	struct sev_data_send_cancel data;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (!sev_guest(kvm))
138862306a36Sopenharmony_ci		return -ENOTTY;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	data.handle = sev->handle;
139162306a36Sopenharmony_ci	return sev_issue_cmd(kvm, SEV_CMD_SEND_CANCEL, &data, &argp->error);
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_cistatic int sev_receive_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
139762306a36Sopenharmony_ci	struct sev_data_receive_start start;
139862306a36Sopenharmony_ci	struct kvm_sev_receive_start params;
139962306a36Sopenharmony_ci	int *error = &argp->error;
140062306a36Sopenharmony_ci	void *session_data;
140162306a36Sopenharmony_ci	void *pdh_data;
140262306a36Sopenharmony_ci	int ret;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	if (!sev_guest(kvm))
140562306a36Sopenharmony_ci		return -ENOTTY;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	/* Get parameter from the userspace */
140862306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
140962306a36Sopenharmony_ci			sizeof(struct kvm_sev_receive_start)))
141062306a36Sopenharmony_ci		return -EFAULT;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/* some sanity checks */
141362306a36Sopenharmony_ci	if (!params.pdh_uaddr || !params.pdh_len ||
141462306a36Sopenharmony_ci	    !params.session_uaddr || !params.session_len)
141562306a36Sopenharmony_ci		return -EINVAL;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	pdh_data = psp_copy_user_blob(params.pdh_uaddr, params.pdh_len);
141862306a36Sopenharmony_ci	if (IS_ERR(pdh_data))
141962306a36Sopenharmony_ci		return PTR_ERR(pdh_data);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	session_data = psp_copy_user_blob(params.session_uaddr,
142262306a36Sopenharmony_ci			params.session_len);
142362306a36Sopenharmony_ci	if (IS_ERR(session_data)) {
142462306a36Sopenharmony_ci		ret = PTR_ERR(session_data);
142562306a36Sopenharmony_ci		goto e_free_pdh;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	memset(&start, 0, sizeof(start));
142962306a36Sopenharmony_ci	start.handle = params.handle;
143062306a36Sopenharmony_ci	start.policy = params.policy;
143162306a36Sopenharmony_ci	start.pdh_cert_address = __psp_pa(pdh_data);
143262306a36Sopenharmony_ci	start.pdh_cert_len = params.pdh_len;
143362306a36Sopenharmony_ci	start.session_address = __psp_pa(session_data);
143462306a36Sopenharmony_ci	start.session_len = params.session_len;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* create memory encryption context */
143762306a36Sopenharmony_ci	ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_RECEIVE_START, &start,
143862306a36Sopenharmony_ci				error);
143962306a36Sopenharmony_ci	if (ret)
144062306a36Sopenharmony_ci		goto e_free_session;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	/* Bind ASID to this guest */
144362306a36Sopenharmony_ci	ret = sev_bind_asid(kvm, start.handle, error);
144462306a36Sopenharmony_ci	if (ret) {
144562306a36Sopenharmony_ci		sev_decommission(start.handle);
144662306a36Sopenharmony_ci		goto e_free_session;
144762306a36Sopenharmony_ci	}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	params.handle = start.handle;
145062306a36Sopenharmony_ci	if (copy_to_user((void __user *)(uintptr_t)argp->data,
145162306a36Sopenharmony_ci			 &params, sizeof(struct kvm_sev_receive_start))) {
145262306a36Sopenharmony_ci		ret = -EFAULT;
145362306a36Sopenharmony_ci		sev_unbind_asid(kvm, start.handle);
145462306a36Sopenharmony_ci		goto e_free_session;
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci    	sev->handle = start.handle;
145862306a36Sopenharmony_ci	sev->fd = argp->sev_fd;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cie_free_session:
146162306a36Sopenharmony_ci	kfree(session_data);
146262306a36Sopenharmony_cie_free_pdh:
146362306a36Sopenharmony_ci	kfree(pdh_data);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	return ret;
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cistatic int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
147162306a36Sopenharmony_ci	struct kvm_sev_receive_update_data params;
147262306a36Sopenharmony_ci	struct sev_data_receive_update_data data;
147362306a36Sopenharmony_ci	void *hdr = NULL, *trans = NULL;
147462306a36Sopenharmony_ci	struct page **guest_page;
147562306a36Sopenharmony_ci	unsigned long n;
147662306a36Sopenharmony_ci	int ret, offset;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (!sev_guest(kvm))
147962306a36Sopenharmony_ci		return -EINVAL;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
148262306a36Sopenharmony_ci			sizeof(struct kvm_sev_receive_update_data)))
148362306a36Sopenharmony_ci		return -EFAULT;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (!params.hdr_uaddr || !params.hdr_len ||
148662306a36Sopenharmony_ci	    !params.guest_uaddr || !params.guest_len ||
148762306a36Sopenharmony_ci	    !params.trans_uaddr || !params.trans_len)
148862306a36Sopenharmony_ci		return -EINVAL;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/* Check if we are crossing the page boundary */
149162306a36Sopenharmony_ci	offset = params.guest_uaddr & (PAGE_SIZE - 1);
149262306a36Sopenharmony_ci	if (params.guest_len > PAGE_SIZE || (params.guest_len + offset) > PAGE_SIZE)
149362306a36Sopenharmony_ci		return -EINVAL;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
149662306a36Sopenharmony_ci	if (IS_ERR(hdr))
149762306a36Sopenharmony_ci		return PTR_ERR(hdr);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	trans = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
150062306a36Sopenharmony_ci	if (IS_ERR(trans)) {
150162306a36Sopenharmony_ci		ret = PTR_ERR(trans);
150262306a36Sopenharmony_ci		goto e_free_hdr;
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	memset(&data, 0, sizeof(data));
150662306a36Sopenharmony_ci	data.hdr_address = __psp_pa(hdr);
150762306a36Sopenharmony_ci	data.hdr_len = params.hdr_len;
150862306a36Sopenharmony_ci	data.trans_address = __psp_pa(trans);
150962306a36Sopenharmony_ci	data.trans_len = params.trans_len;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	/* Pin guest memory */
151262306a36Sopenharmony_ci	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
151362306a36Sopenharmony_ci				    PAGE_SIZE, &n, 1);
151462306a36Sopenharmony_ci	if (IS_ERR(guest_page)) {
151562306a36Sopenharmony_ci		ret = PTR_ERR(guest_page);
151662306a36Sopenharmony_ci		goto e_free_trans;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	/*
152062306a36Sopenharmony_ci	 * Flush (on non-coherent CPUs) before RECEIVE_UPDATE_DATA, the PSP
152162306a36Sopenharmony_ci	 * encrypts the written data with the guest's key, and the cache may
152262306a36Sopenharmony_ci	 * contain dirty, unencrypted data.
152362306a36Sopenharmony_ci	 */
152462306a36Sopenharmony_ci	sev_clflush_pages(guest_page, n);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* The RECEIVE_UPDATE_DATA command requires C-bit to be always set. */
152762306a36Sopenharmony_ci	data.guest_address = (page_to_pfn(guest_page[0]) << PAGE_SHIFT) + offset;
152862306a36Sopenharmony_ci	data.guest_address |= sev_me_mask;
152962306a36Sopenharmony_ci	data.guest_len = params.guest_len;
153062306a36Sopenharmony_ci	data.handle = sev->handle;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	ret = sev_issue_cmd(kvm, SEV_CMD_RECEIVE_UPDATE_DATA, &data,
153362306a36Sopenharmony_ci				&argp->error);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	sev_unpin_memory(kvm, guest_page, n);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_cie_free_trans:
153862306a36Sopenharmony_ci	kfree(trans);
153962306a36Sopenharmony_cie_free_hdr:
154062306a36Sopenharmony_ci	kfree(hdr);
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	return ret;
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
154862306a36Sopenharmony_ci	struct sev_data_receive_finish data;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	if (!sev_guest(kvm))
155162306a36Sopenharmony_ci		return -ENOTTY;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	data.handle = sev->handle;
155462306a36Sopenharmony_ci	return sev_issue_cmd(kvm, SEV_CMD_RECEIVE_FINISH, &data, &argp->error);
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic bool is_cmd_allowed_from_mirror(u32 cmd_id)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci	/*
156062306a36Sopenharmony_ci	 * Allow mirrors VM to call KVM_SEV_LAUNCH_UPDATE_VMSA to enable SEV-ES
156162306a36Sopenharmony_ci	 * active mirror VMs. Also allow the debugging and status commands.
156262306a36Sopenharmony_ci	 */
156362306a36Sopenharmony_ci	if (cmd_id == KVM_SEV_LAUNCH_UPDATE_VMSA ||
156462306a36Sopenharmony_ci	    cmd_id == KVM_SEV_GUEST_STATUS || cmd_id == KVM_SEV_DBG_DECRYPT ||
156562306a36Sopenharmony_ci	    cmd_id == KVM_SEV_DBG_ENCRYPT)
156662306a36Sopenharmony_ci		return true;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	return false;
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic int sev_lock_two_vms(struct kvm *dst_kvm, struct kvm *src_kvm)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	struct kvm_sev_info *dst_sev = &to_kvm_svm(dst_kvm)->sev_info;
157462306a36Sopenharmony_ci	struct kvm_sev_info *src_sev = &to_kvm_svm(src_kvm)->sev_info;
157562306a36Sopenharmony_ci	int r = -EBUSY;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	if (dst_kvm == src_kvm)
157862306a36Sopenharmony_ci		return -EINVAL;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	/*
158162306a36Sopenharmony_ci	 * Bail if these VMs are already involved in a migration to avoid
158262306a36Sopenharmony_ci	 * deadlock between two VMs trying to migrate to/from each other.
158362306a36Sopenharmony_ci	 */
158462306a36Sopenharmony_ci	if (atomic_cmpxchg_acquire(&dst_sev->migration_in_progress, 0, 1))
158562306a36Sopenharmony_ci		return -EBUSY;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (atomic_cmpxchg_acquire(&src_sev->migration_in_progress, 0, 1))
158862306a36Sopenharmony_ci		goto release_dst;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	r = -EINTR;
159162306a36Sopenharmony_ci	if (mutex_lock_killable(&dst_kvm->lock))
159262306a36Sopenharmony_ci		goto release_src;
159362306a36Sopenharmony_ci	if (mutex_lock_killable_nested(&src_kvm->lock, SINGLE_DEPTH_NESTING))
159462306a36Sopenharmony_ci		goto unlock_dst;
159562306a36Sopenharmony_ci	return 0;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ciunlock_dst:
159862306a36Sopenharmony_ci	mutex_unlock(&dst_kvm->lock);
159962306a36Sopenharmony_cirelease_src:
160062306a36Sopenharmony_ci	atomic_set_release(&src_sev->migration_in_progress, 0);
160162306a36Sopenharmony_cirelease_dst:
160262306a36Sopenharmony_ci	atomic_set_release(&dst_sev->migration_in_progress, 0);
160362306a36Sopenharmony_ci	return r;
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_cistatic void sev_unlock_two_vms(struct kvm *dst_kvm, struct kvm *src_kvm)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	struct kvm_sev_info *dst_sev = &to_kvm_svm(dst_kvm)->sev_info;
160962306a36Sopenharmony_ci	struct kvm_sev_info *src_sev = &to_kvm_svm(src_kvm)->sev_info;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	mutex_unlock(&dst_kvm->lock);
161262306a36Sopenharmony_ci	mutex_unlock(&src_kvm->lock);
161362306a36Sopenharmony_ci	atomic_set_release(&dst_sev->migration_in_progress, 0);
161462306a36Sopenharmony_ci	atomic_set_release(&src_sev->migration_in_progress, 0);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci/* vCPU mutex subclasses.  */
161862306a36Sopenharmony_cienum sev_migration_role {
161962306a36Sopenharmony_ci	SEV_MIGRATION_SOURCE = 0,
162062306a36Sopenharmony_ci	SEV_MIGRATION_TARGET,
162162306a36Sopenharmony_ci	SEV_NR_MIGRATION_ROLES,
162262306a36Sopenharmony_ci};
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_cistatic int sev_lock_vcpus_for_migration(struct kvm *kvm,
162562306a36Sopenharmony_ci					enum sev_migration_role role)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
162862306a36Sopenharmony_ci	unsigned long i, j;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm) {
163162306a36Sopenharmony_ci		if (mutex_lock_killable_nested(&vcpu->mutex, role))
163262306a36Sopenharmony_ci			goto out_unlock;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci#ifdef CONFIG_PROVE_LOCKING
163562306a36Sopenharmony_ci		if (!i)
163662306a36Sopenharmony_ci			/*
163762306a36Sopenharmony_ci			 * Reset the role to one that avoids colliding with
163862306a36Sopenharmony_ci			 * the role used for the first vcpu mutex.
163962306a36Sopenharmony_ci			 */
164062306a36Sopenharmony_ci			role = SEV_NR_MIGRATION_ROLES;
164162306a36Sopenharmony_ci		else
164262306a36Sopenharmony_ci			mutex_release(&vcpu->mutex.dep_map, _THIS_IP_);
164362306a36Sopenharmony_ci#endif
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	return 0;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ciout_unlock:
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	kvm_for_each_vcpu(j, vcpu, kvm) {
165162306a36Sopenharmony_ci		if (i == j)
165262306a36Sopenharmony_ci			break;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci#ifdef CONFIG_PROVE_LOCKING
165562306a36Sopenharmony_ci		if (j)
165662306a36Sopenharmony_ci			mutex_acquire(&vcpu->mutex.dep_map, role, 0, _THIS_IP_);
165762306a36Sopenharmony_ci#endif
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		mutex_unlock(&vcpu->mutex);
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci	return -EINTR;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic void sev_unlock_vcpus_for_migration(struct kvm *kvm)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct kvm_vcpu *vcpu;
166762306a36Sopenharmony_ci	unsigned long i;
166862306a36Sopenharmony_ci	bool first = true;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	kvm_for_each_vcpu(i, vcpu, kvm) {
167162306a36Sopenharmony_ci		if (first)
167262306a36Sopenharmony_ci			first = false;
167362306a36Sopenharmony_ci		else
167462306a36Sopenharmony_ci			mutex_acquire(&vcpu->mutex.dep_map,
167562306a36Sopenharmony_ci				      SEV_NR_MIGRATION_ROLES, 0, _THIS_IP_);
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		mutex_unlock(&vcpu->mutex);
167862306a36Sopenharmony_ci	}
167962306a36Sopenharmony_ci}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cistatic void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	struct kvm_sev_info *dst = &to_kvm_svm(dst_kvm)->sev_info;
168462306a36Sopenharmony_ci	struct kvm_sev_info *src = &to_kvm_svm(src_kvm)->sev_info;
168562306a36Sopenharmony_ci	struct kvm_vcpu *dst_vcpu, *src_vcpu;
168662306a36Sopenharmony_ci	struct vcpu_svm *dst_svm, *src_svm;
168762306a36Sopenharmony_ci	struct kvm_sev_info *mirror;
168862306a36Sopenharmony_ci	unsigned long i;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	dst->active = true;
169162306a36Sopenharmony_ci	dst->asid = src->asid;
169262306a36Sopenharmony_ci	dst->handle = src->handle;
169362306a36Sopenharmony_ci	dst->pages_locked = src->pages_locked;
169462306a36Sopenharmony_ci	dst->enc_context_owner = src->enc_context_owner;
169562306a36Sopenharmony_ci	dst->es_active = src->es_active;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	src->asid = 0;
169862306a36Sopenharmony_ci	src->active = false;
169962306a36Sopenharmony_ci	src->handle = 0;
170062306a36Sopenharmony_ci	src->pages_locked = 0;
170162306a36Sopenharmony_ci	src->enc_context_owner = NULL;
170262306a36Sopenharmony_ci	src->es_active = false;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	/*
170762306a36Sopenharmony_ci	 * If this VM has mirrors, "transfer" each mirror's refcount of the
170862306a36Sopenharmony_ci	 * source to the destination (this KVM).  The caller holds a reference
170962306a36Sopenharmony_ci	 * to the source, so there's no danger of use-after-free.
171062306a36Sopenharmony_ci	 */
171162306a36Sopenharmony_ci	list_cut_before(&dst->mirror_vms, &src->mirror_vms, &src->mirror_vms);
171262306a36Sopenharmony_ci	list_for_each_entry(mirror, &dst->mirror_vms, mirror_entry) {
171362306a36Sopenharmony_ci		kvm_get_kvm(dst_kvm);
171462306a36Sopenharmony_ci		kvm_put_kvm(src_kvm);
171562306a36Sopenharmony_ci		mirror->enc_context_owner = dst_kvm;
171662306a36Sopenharmony_ci	}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	/*
171962306a36Sopenharmony_ci	 * If this VM is a mirror, remove the old mirror from the owners list
172062306a36Sopenharmony_ci	 * and add the new mirror to the list.
172162306a36Sopenharmony_ci	 */
172262306a36Sopenharmony_ci	if (is_mirroring_enc_context(dst_kvm)) {
172362306a36Sopenharmony_ci		struct kvm_sev_info *owner_sev_info =
172462306a36Sopenharmony_ci			&to_kvm_svm(dst->enc_context_owner)->sev_info;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci		list_del(&src->mirror_entry);
172762306a36Sopenharmony_ci		list_add_tail(&dst->mirror_entry, &owner_sev_info->mirror_vms);
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	kvm_for_each_vcpu(i, dst_vcpu, dst_kvm) {
173162306a36Sopenharmony_ci		dst_svm = to_svm(dst_vcpu);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci		sev_init_vmcb(dst_svm);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci		if (!dst->es_active)
173662306a36Sopenharmony_ci			continue;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci		/*
173962306a36Sopenharmony_ci		 * Note, the source is not required to have the same number of
174062306a36Sopenharmony_ci		 * vCPUs as the destination when migrating a vanilla SEV VM.
174162306a36Sopenharmony_ci		 */
174262306a36Sopenharmony_ci		src_vcpu = kvm_get_vcpu(src_kvm, i);
174362306a36Sopenharmony_ci		src_svm = to_svm(src_vcpu);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci		/*
174662306a36Sopenharmony_ci		 * Transfer VMSA and GHCB state to the destination.  Nullify and
174762306a36Sopenharmony_ci		 * clear source fields as appropriate, the state now belongs to
174862306a36Sopenharmony_ci		 * the destination.
174962306a36Sopenharmony_ci		 */
175062306a36Sopenharmony_ci		memcpy(&dst_svm->sev_es, &src_svm->sev_es, sizeof(src_svm->sev_es));
175162306a36Sopenharmony_ci		dst_svm->vmcb->control.ghcb_gpa = src_svm->vmcb->control.ghcb_gpa;
175262306a36Sopenharmony_ci		dst_svm->vmcb->control.vmsa_pa = src_svm->vmcb->control.vmsa_pa;
175362306a36Sopenharmony_ci		dst_vcpu->arch.guest_state_protected = true;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		memset(&src_svm->sev_es, 0, sizeof(src_svm->sev_es));
175662306a36Sopenharmony_ci		src_svm->vmcb->control.ghcb_gpa = INVALID_PAGE;
175762306a36Sopenharmony_ci		src_svm->vmcb->control.vmsa_pa = INVALID_PAGE;
175862306a36Sopenharmony_ci		src_vcpu->arch.guest_state_protected = false;
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_cistatic int sev_check_source_vcpus(struct kvm *dst, struct kvm *src)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	struct kvm_vcpu *src_vcpu;
176562306a36Sopenharmony_ci	unsigned long i;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (!sev_es_guest(src))
176862306a36Sopenharmony_ci		return 0;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	if (atomic_read(&src->online_vcpus) != atomic_read(&dst->online_vcpus))
177162306a36Sopenharmony_ci		return -EINVAL;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	kvm_for_each_vcpu(i, src_vcpu, src) {
177462306a36Sopenharmony_ci		if (!src_vcpu->arch.guest_state_protected)
177562306a36Sopenharmony_ci			return -EINVAL;
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	return 0;
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ciint sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	struct kvm_sev_info *dst_sev = &to_kvm_svm(kvm)->sev_info;
178462306a36Sopenharmony_ci	struct kvm_sev_info *src_sev, *cg_cleanup_sev;
178562306a36Sopenharmony_ci	struct fd f = fdget(source_fd);
178662306a36Sopenharmony_ci	struct kvm *source_kvm;
178762306a36Sopenharmony_ci	bool charged = false;
178862306a36Sopenharmony_ci	int ret;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	if (!f.file)
179162306a36Sopenharmony_ci		return -EBADF;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (!file_is_kvm(f.file)) {
179462306a36Sopenharmony_ci		ret = -EBADF;
179562306a36Sopenharmony_ci		goto out_fput;
179662306a36Sopenharmony_ci	}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	source_kvm = f.file->private_data;
179962306a36Sopenharmony_ci	ret = sev_lock_two_vms(kvm, source_kvm);
180062306a36Sopenharmony_ci	if (ret)
180162306a36Sopenharmony_ci		goto out_fput;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (sev_guest(kvm) || !sev_guest(source_kvm)) {
180462306a36Sopenharmony_ci		ret = -EINVAL;
180562306a36Sopenharmony_ci		goto out_unlock;
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	src_sev = &to_kvm_svm(source_kvm)->sev_info;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	dst_sev->misc_cg = get_current_misc_cg();
181162306a36Sopenharmony_ci	cg_cleanup_sev = dst_sev;
181262306a36Sopenharmony_ci	if (dst_sev->misc_cg != src_sev->misc_cg) {
181362306a36Sopenharmony_ci		ret = sev_misc_cg_try_charge(dst_sev);
181462306a36Sopenharmony_ci		if (ret)
181562306a36Sopenharmony_ci			goto out_dst_cgroup;
181662306a36Sopenharmony_ci		charged = true;
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	ret = sev_lock_vcpus_for_migration(kvm, SEV_MIGRATION_SOURCE);
182062306a36Sopenharmony_ci	if (ret)
182162306a36Sopenharmony_ci		goto out_dst_cgroup;
182262306a36Sopenharmony_ci	ret = sev_lock_vcpus_for_migration(source_kvm, SEV_MIGRATION_TARGET);
182362306a36Sopenharmony_ci	if (ret)
182462306a36Sopenharmony_ci		goto out_dst_vcpu;
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	ret = sev_check_source_vcpus(kvm, source_kvm);
182762306a36Sopenharmony_ci	if (ret)
182862306a36Sopenharmony_ci		goto out_source_vcpu;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	sev_migrate_from(kvm, source_kvm);
183162306a36Sopenharmony_ci	kvm_vm_dead(source_kvm);
183262306a36Sopenharmony_ci	cg_cleanup_sev = src_sev;
183362306a36Sopenharmony_ci	ret = 0;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ciout_source_vcpu:
183662306a36Sopenharmony_ci	sev_unlock_vcpus_for_migration(source_kvm);
183762306a36Sopenharmony_ciout_dst_vcpu:
183862306a36Sopenharmony_ci	sev_unlock_vcpus_for_migration(kvm);
183962306a36Sopenharmony_ciout_dst_cgroup:
184062306a36Sopenharmony_ci	/* Operates on the source on success, on the destination on failure.  */
184162306a36Sopenharmony_ci	if (charged)
184262306a36Sopenharmony_ci		sev_misc_cg_uncharge(cg_cleanup_sev);
184362306a36Sopenharmony_ci	put_misc_cg(cg_cleanup_sev->misc_cg);
184462306a36Sopenharmony_ci	cg_cleanup_sev->misc_cg = NULL;
184562306a36Sopenharmony_ciout_unlock:
184662306a36Sopenharmony_ci	sev_unlock_two_vms(kvm, source_kvm);
184762306a36Sopenharmony_ciout_fput:
184862306a36Sopenharmony_ci	fdput(f);
184962306a36Sopenharmony_ci	return ret;
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ciint sev_mem_enc_ioctl(struct kvm *kvm, void __user *argp)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	struct kvm_sev_cmd sev_cmd;
185562306a36Sopenharmony_ci	int r;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	if (!sev_enabled)
185862306a36Sopenharmony_ci		return -ENOTTY;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	if (!argp)
186162306a36Sopenharmony_ci		return 0;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	if (copy_from_user(&sev_cmd, argp, sizeof(struct kvm_sev_cmd)))
186462306a36Sopenharmony_ci		return -EFAULT;
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	mutex_lock(&kvm->lock);
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	/* Only the enc_context_owner handles some memory enc operations. */
186962306a36Sopenharmony_ci	if (is_mirroring_enc_context(kvm) &&
187062306a36Sopenharmony_ci	    !is_cmd_allowed_from_mirror(sev_cmd.id)) {
187162306a36Sopenharmony_ci		r = -EINVAL;
187262306a36Sopenharmony_ci		goto out;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	switch (sev_cmd.id) {
187662306a36Sopenharmony_ci	case KVM_SEV_ES_INIT:
187762306a36Sopenharmony_ci		if (!sev_es_enabled) {
187862306a36Sopenharmony_ci			r = -ENOTTY;
187962306a36Sopenharmony_ci			goto out;
188062306a36Sopenharmony_ci		}
188162306a36Sopenharmony_ci		fallthrough;
188262306a36Sopenharmony_ci	case KVM_SEV_INIT:
188362306a36Sopenharmony_ci		r = sev_guest_init(kvm, &sev_cmd);
188462306a36Sopenharmony_ci		break;
188562306a36Sopenharmony_ci	case KVM_SEV_LAUNCH_START:
188662306a36Sopenharmony_ci		r = sev_launch_start(kvm, &sev_cmd);
188762306a36Sopenharmony_ci		break;
188862306a36Sopenharmony_ci	case KVM_SEV_LAUNCH_UPDATE_DATA:
188962306a36Sopenharmony_ci		r = sev_launch_update_data(kvm, &sev_cmd);
189062306a36Sopenharmony_ci		break;
189162306a36Sopenharmony_ci	case KVM_SEV_LAUNCH_UPDATE_VMSA:
189262306a36Sopenharmony_ci		r = sev_launch_update_vmsa(kvm, &sev_cmd);
189362306a36Sopenharmony_ci		break;
189462306a36Sopenharmony_ci	case KVM_SEV_LAUNCH_MEASURE:
189562306a36Sopenharmony_ci		r = sev_launch_measure(kvm, &sev_cmd);
189662306a36Sopenharmony_ci		break;
189762306a36Sopenharmony_ci	case KVM_SEV_LAUNCH_FINISH:
189862306a36Sopenharmony_ci		r = sev_launch_finish(kvm, &sev_cmd);
189962306a36Sopenharmony_ci		break;
190062306a36Sopenharmony_ci	case KVM_SEV_GUEST_STATUS:
190162306a36Sopenharmony_ci		r = sev_guest_status(kvm, &sev_cmd);
190262306a36Sopenharmony_ci		break;
190362306a36Sopenharmony_ci	case KVM_SEV_DBG_DECRYPT:
190462306a36Sopenharmony_ci		r = sev_dbg_crypt(kvm, &sev_cmd, true);
190562306a36Sopenharmony_ci		break;
190662306a36Sopenharmony_ci	case KVM_SEV_DBG_ENCRYPT:
190762306a36Sopenharmony_ci		r = sev_dbg_crypt(kvm, &sev_cmd, false);
190862306a36Sopenharmony_ci		break;
190962306a36Sopenharmony_ci	case KVM_SEV_LAUNCH_SECRET:
191062306a36Sopenharmony_ci		r = sev_launch_secret(kvm, &sev_cmd);
191162306a36Sopenharmony_ci		break;
191262306a36Sopenharmony_ci	case KVM_SEV_GET_ATTESTATION_REPORT:
191362306a36Sopenharmony_ci		r = sev_get_attestation_report(kvm, &sev_cmd);
191462306a36Sopenharmony_ci		break;
191562306a36Sopenharmony_ci	case KVM_SEV_SEND_START:
191662306a36Sopenharmony_ci		r = sev_send_start(kvm, &sev_cmd);
191762306a36Sopenharmony_ci		break;
191862306a36Sopenharmony_ci	case KVM_SEV_SEND_UPDATE_DATA:
191962306a36Sopenharmony_ci		r = sev_send_update_data(kvm, &sev_cmd);
192062306a36Sopenharmony_ci		break;
192162306a36Sopenharmony_ci	case KVM_SEV_SEND_FINISH:
192262306a36Sopenharmony_ci		r = sev_send_finish(kvm, &sev_cmd);
192362306a36Sopenharmony_ci		break;
192462306a36Sopenharmony_ci	case KVM_SEV_SEND_CANCEL:
192562306a36Sopenharmony_ci		r = sev_send_cancel(kvm, &sev_cmd);
192662306a36Sopenharmony_ci		break;
192762306a36Sopenharmony_ci	case KVM_SEV_RECEIVE_START:
192862306a36Sopenharmony_ci		r = sev_receive_start(kvm, &sev_cmd);
192962306a36Sopenharmony_ci		break;
193062306a36Sopenharmony_ci	case KVM_SEV_RECEIVE_UPDATE_DATA:
193162306a36Sopenharmony_ci		r = sev_receive_update_data(kvm, &sev_cmd);
193262306a36Sopenharmony_ci		break;
193362306a36Sopenharmony_ci	case KVM_SEV_RECEIVE_FINISH:
193462306a36Sopenharmony_ci		r = sev_receive_finish(kvm, &sev_cmd);
193562306a36Sopenharmony_ci		break;
193662306a36Sopenharmony_ci	default:
193762306a36Sopenharmony_ci		r = -EINVAL;
193862306a36Sopenharmony_ci		goto out;
193962306a36Sopenharmony_ci	}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (copy_to_user(argp, &sev_cmd, sizeof(struct kvm_sev_cmd)))
194262306a36Sopenharmony_ci		r = -EFAULT;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ciout:
194562306a36Sopenharmony_ci	mutex_unlock(&kvm->lock);
194662306a36Sopenharmony_ci	return r;
194762306a36Sopenharmony_ci}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ciint sev_mem_enc_register_region(struct kvm *kvm,
195062306a36Sopenharmony_ci				struct kvm_enc_region *range)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
195362306a36Sopenharmony_ci	struct enc_region *region;
195462306a36Sopenharmony_ci	int ret = 0;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	if (!sev_guest(kvm))
195762306a36Sopenharmony_ci		return -ENOTTY;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	/* If kvm is mirroring encryption context it isn't responsible for it */
196062306a36Sopenharmony_ci	if (is_mirroring_enc_context(kvm))
196162306a36Sopenharmony_ci		return -EINVAL;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	if (range->addr > ULONG_MAX || range->size > ULONG_MAX)
196462306a36Sopenharmony_ci		return -EINVAL;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	region = kzalloc(sizeof(*region), GFP_KERNEL_ACCOUNT);
196762306a36Sopenharmony_ci	if (!region)
196862306a36Sopenharmony_ci		return -ENOMEM;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	mutex_lock(&kvm->lock);
197162306a36Sopenharmony_ci	region->pages = sev_pin_memory(kvm, range->addr, range->size, &region->npages, 1);
197262306a36Sopenharmony_ci	if (IS_ERR(region->pages)) {
197362306a36Sopenharmony_ci		ret = PTR_ERR(region->pages);
197462306a36Sopenharmony_ci		mutex_unlock(&kvm->lock);
197562306a36Sopenharmony_ci		goto e_free;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	region->uaddr = range->addr;
197962306a36Sopenharmony_ci	region->size = range->size;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	list_add_tail(&region->list, &sev->regions_list);
198262306a36Sopenharmony_ci	mutex_unlock(&kvm->lock);
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	/*
198562306a36Sopenharmony_ci	 * The guest may change the memory encryption attribute from C=0 -> C=1
198662306a36Sopenharmony_ci	 * or vice versa for this memory range. Lets make sure caches are
198762306a36Sopenharmony_ci	 * flushed to ensure that guest data gets written into memory with
198862306a36Sopenharmony_ci	 * correct C-bit.
198962306a36Sopenharmony_ci	 */
199062306a36Sopenharmony_ci	sev_clflush_pages(region->pages, region->npages);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	return ret;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_cie_free:
199562306a36Sopenharmony_ci	kfree(region);
199662306a36Sopenharmony_ci	return ret;
199762306a36Sopenharmony_ci}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_cistatic struct enc_region *
200062306a36Sopenharmony_cifind_enc_region(struct kvm *kvm, struct kvm_enc_region *range)
200162306a36Sopenharmony_ci{
200262306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
200362306a36Sopenharmony_ci	struct list_head *head = &sev->regions_list;
200462306a36Sopenharmony_ci	struct enc_region *i;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	list_for_each_entry(i, head, list) {
200762306a36Sopenharmony_ci		if (i->uaddr == range->addr &&
200862306a36Sopenharmony_ci		    i->size == range->size)
200962306a36Sopenharmony_ci			return i;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	return NULL;
201362306a36Sopenharmony_ci}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_cistatic void __unregister_enc_region_locked(struct kvm *kvm,
201662306a36Sopenharmony_ci					   struct enc_region *region)
201762306a36Sopenharmony_ci{
201862306a36Sopenharmony_ci	sev_unpin_memory(kvm, region->pages, region->npages);
201962306a36Sopenharmony_ci	list_del(&region->list);
202062306a36Sopenharmony_ci	kfree(region);
202162306a36Sopenharmony_ci}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ciint sev_mem_enc_unregister_region(struct kvm *kvm,
202462306a36Sopenharmony_ci				  struct kvm_enc_region *range)
202562306a36Sopenharmony_ci{
202662306a36Sopenharmony_ci	struct enc_region *region;
202762306a36Sopenharmony_ci	int ret;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	/* If kvm is mirroring encryption context it isn't responsible for it */
203062306a36Sopenharmony_ci	if (is_mirroring_enc_context(kvm))
203162306a36Sopenharmony_ci		return -EINVAL;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	mutex_lock(&kvm->lock);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	if (!sev_guest(kvm)) {
203662306a36Sopenharmony_ci		ret = -ENOTTY;
203762306a36Sopenharmony_ci		goto failed;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	region = find_enc_region(kvm, range);
204162306a36Sopenharmony_ci	if (!region) {
204262306a36Sopenharmony_ci		ret = -EINVAL;
204362306a36Sopenharmony_ci		goto failed;
204462306a36Sopenharmony_ci	}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	/*
204762306a36Sopenharmony_ci	 * Ensure that all guest tagged cache entries are flushed before
204862306a36Sopenharmony_ci	 * releasing the pages back to the system for use. CLFLUSH will
204962306a36Sopenharmony_ci	 * not do this, so issue a WBINVD.
205062306a36Sopenharmony_ci	 */
205162306a36Sopenharmony_ci	wbinvd_on_all_cpus();
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	__unregister_enc_region_locked(kvm, region);
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	mutex_unlock(&kvm->lock);
205662306a36Sopenharmony_ci	return 0;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_cifailed:
205962306a36Sopenharmony_ci	mutex_unlock(&kvm->lock);
206062306a36Sopenharmony_ci	return ret;
206162306a36Sopenharmony_ci}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ciint sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd)
206462306a36Sopenharmony_ci{
206562306a36Sopenharmony_ci	struct fd f = fdget(source_fd);
206662306a36Sopenharmony_ci	struct kvm *source_kvm;
206762306a36Sopenharmony_ci	struct kvm_sev_info *source_sev, *mirror_sev;
206862306a36Sopenharmony_ci	int ret;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	if (!f.file)
207162306a36Sopenharmony_ci		return -EBADF;
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	if (!file_is_kvm(f.file)) {
207462306a36Sopenharmony_ci		ret = -EBADF;
207562306a36Sopenharmony_ci		goto e_source_fput;
207662306a36Sopenharmony_ci	}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	source_kvm = f.file->private_data;
207962306a36Sopenharmony_ci	ret = sev_lock_two_vms(kvm, source_kvm);
208062306a36Sopenharmony_ci	if (ret)
208162306a36Sopenharmony_ci		goto e_source_fput;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	/*
208462306a36Sopenharmony_ci	 * Mirrors of mirrors should work, but let's not get silly.  Also
208562306a36Sopenharmony_ci	 * disallow out-of-band SEV/SEV-ES init if the target is already an
208662306a36Sopenharmony_ci	 * SEV guest, or if vCPUs have been created.  KVM relies on vCPUs being
208762306a36Sopenharmony_ci	 * created after SEV/SEV-ES initialization, e.g. to init intercepts.
208862306a36Sopenharmony_ci	 */
208962306a36Sopenharmony_ci	if (sev_guest(kvm) || !sev_guest(source_kvm) ||
209062306a36Sopenharmony_ci	    is_mirroring_enc_context(source_kvm) || kvm->created_vcpus) {
209162306a36Sopenharmony_ci		ret = -EINVAL;
209262306a36Sopenharmony_ci		goto e_unlock;
209362306a36Sopenharmony_ci	}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	/*
209662306a36Sopenharmony_ci	 * The mirror kvm holds an enc_context_owner ref so its asid can't
209762306a36Sopenharmony_ci	 * disappear until we're done with it
209862306a36Sopenharmony_ci	 */
209962306a36Sopenharmony_ci	source_sev = &to_kvm_svm(source_kvm)->sev_info;
210062306a36Sopenharmony_ci	kvm_get_kvm(source_kvm);
210162306a36Sopenharmony_ci	mirror_sev = &to_kvm_svm(kvm)->sev_info;
210262306a36Sopenharmony_ci	list_add_tail(&mirror_sev->mirror_entry, &source_sev->mirror_vms);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	/* Set enc_context_owner and copy its encryption context over */
210562306a36Sopenharmony_ci	mirror_sev->enc_context_owner = source_kvm;
210662306a36Sopenharmony_ci	mirror_sev->active = true;
210762306a36Sopenharmony_ci	mirror_sev->asid = source_sev->asid;
210862306a36Sopenharmony_ci	mirror_sev->fd = source_sev->fd;
210962306a36Sopenharmony_ci	mirror_sev->es_active = source_sev->es_active;
211062306a36Sopenharmony_ci	mirror_sev->handle = source_sev->handle;
211162306a36Sopenharmony_ci	INIT_LIST_HEAD(&mirror_sev->regions_list);
211262306a36Sopenharmony_ci	INIT_LIST_HEAD(&mirror_sev->mirror_vms);
211362306a36Sopenharmony_ci	ret = 0;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	/*
211662306a36Sopenharmony_ci	 * Do not copy ap_jump_table. Since the mirror does not share the same
211762306a36Sopenharmony_ci	 * KVM contexts as the original, and they may have different
211862306a36Sopenharmony_ci	 * memory-views.
211962306a36Sopenharmony_ci	 */
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_cie_unlock:
212262306a36Sopenharmony_ci	sev_unlock_two_vms(kvm, source_kvm);
212362306a36Sopenharmony_cie_source_fput:
212462306a36Sopenharmony_ci	fdput(f);
212562306a36Sopenharmony_ci	return ret;
212662306a36Sopenharmony_ci}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_civoid sev_vm_destroy(struct kvm *kvm)
212962306a36Sopenharmony_ci{
213062306a36Sopenharmony_ci	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
213162306a36Sopenharmony_ci	struct list_head *head = &sev->regions_list;
213262306a36Sopenharmony_ci	struct list_head *pos, *q;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	if (!sev_guest(kvm))
213562306a36Sopenharmony_ci		return;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	WARN_ON(!list_empty(&sev->mirror_vms));
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	/* If this is a mirror_kvm release the enc_context_owner and skip sev cleanup */
214062306a36Sopenharmony_ci	if (is_mirroring_enc_context(kvm)) {
214162306a36Sopenharmony_ci		struct kvm *owner_kvm = sev->enc_context_owner;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci		mutex_lock(&owner_kvm->lock);
214462306a36Sopenharmony_ci		list_del(&sev->mirror_entry);
214562306a36Sopenharmony_ci		mutex_unlock(&owner_kvm->lock);
214662306a36Sopenharmony_ci		kvm_put_kvm(owner_kvm);
214762306a36Sopenharmony_ci		return;
214862306a36Sopenharmony_ci	}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	/*
215162306a36Sopenharmony_ci	 * Ensure that all guest tagged cache entries are flushed before
215262306a36Sopenharmony_ci	 * releasing the pages back to the system for use. CLFLUSH will
215362306a36Sopenharmony_ci	 * not do this, so issue a WBINVD.
215462306a36Sopenharmony_ci	 */
215562306a36Sopenharmony_ci	wbinvd_on_all_cpus();
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	/*
215862306a36Sopenharmony_ci	 * if userspace was terminated before unregistering the memory regions
215962306a36Sopenharmony_ci	 * then lets unpin all the registered memory.
216062306a36Sopenharmony_ci	 */
216162306a36Sopenharmony_ci	if (!list_empty(head)) {
216262306a36Sopenharmony_ci		list_for_each_safe(pos, q, head) {
216362306a36Sopenharmony_ci			__unregister_enc_region_locked(kvm,
216462306a36Sopenharmony_ci				list_entry(pos, struct enc_region, list));
216562306a36Sopenharmony_ci			cond_resched();
216662306a36Sopenharmony_ci		}
216762306a36Sopenharmony_ci	}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	sev_unbind_asid(kvm, sev->handle);
217062306a36Sopenharmony_ci	sev_asid_free(sev);
217162306a36Sopenharmony_ci}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_civoid __init sev_set_cpu_caps(void)
217462306a36Sopenharmony_ci{
217562306a36Sopenharmony_ci	if (!sev_enabled)
217662306a36Sopenharmony_ci		kvm_cpu_cap_clear(X86_FEATURE_SEV);
217762306a36Sopenharmony_ci	if (!sev_es_enabled)
217862306a36Sopenharmony_ci		kvm_cpu_cap_clear(X86_FEATURE_SEV_ES);
217962306a36Sopenharmony_ci}
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_civoid __init sev_hardware_setup(void)
218262306a36Sopenharmony_ci{
218362306a36Sopenharmony_ci#ifdef CONFIG_KVM_AMD_SEV
218462306a36Sopenharmony_ci	unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count;
218562306a36Sopenharmony_ci	bool sev_es_supported = false;
218662306a36Sopenharmony_ci	bool sev_supported = false;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	if (!sev_enabled || !npt_enabled || !nrips)
218962306a36Sopenharmony_ci		goto out;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	/*
219262306a36Sopenharmony_ci	 * SEV must obviously be supported in hardware.  Sanity check that the
219362306a36Sopenharmony_ci	 * CPU supports decode assists, which is mandatory for SEV guests to
219462306a36Sopenharmony_ci	 * support instruction emulation.
219562306a36Sopenharmony_ci	 */
219662306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_SEV) ||
219762306a36Sopenharmony_ci	    WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)))
219862306a36Sopenharmony_ci		goto out;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	/* Retrieve SEV CPUID information */
220162306a36Sopenharmony_ci	cpuid(0x8000001f, &eax, &ebx, &ecx, &edx);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	/* Set encryption bit location for SEV-ES guests */
220462306a36Sopenharmony_ci	sev_enc_bit = ebx & 0x3f;
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	/* Maximum number of encrypted guests supported simultaneously */
220762306a36Sopenharmony_ci	max_sev_asid = ecx;
220862306a36Sopenharmony_ci	if (!max_sev_asid)
220962306a36Sopenharmony_ci		goto out;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	/* Minimum ASID value that should be used for SEV guest */
221262306a36Sopenharmony_ci	min_sev_asid = edx;
221362306a36Sopenharmony_ci	sev_me_mask = 1UL << (ebx & 0x3f);
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	/*
221662306a36Sopenharmony_ci	 * Initialize SEV ASID bitmaps. Allocate space for ASID 0 in the bitmap,
221762306a36Sopenharmony_ci	 * even though it's never used, so that the bitmap is indexed by the
221862306a36Sopenharmony_ci	 * actual ASID.
221962306a36Sopenharmony_ci	 */
222062306a36Sopenharmony_ci	nr_asids = max_sev_asid + 1;
222162306a36Sopenharmony_ci	sev_asid_bitmap = bitmap_zalloc(nr_asids, GFP_KERNEL);
222262306a36Sopenharmony_ci	if (!sev_asid_bitmap)
222362306a36Sopenharmony_ci		goto out;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	sev_reclaim_asid_bitmap = bitmap_zalloc(nr_asids, GFP_KERNEL);
222662306a36Sopenharmony_ci	if (!sev_reclaim_asid_bitmap) {
222762306a36Sopenharmony_ci		bitmap_free(sev_asid_bitmap);
222862306a36Sopenharmony_ci		sev_asid_bitmap = NULL;
222962306a36Sopenharmony_ci		goto out;
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	sev_asid_count = max_sev_asid - min_sev_asid + 1;
223362306a36Sopenharmony_ci	WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV, sev_asid_count));
223462306a36Sopenharmony_ci	sev_supported = true;
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	/* SEV-ES support requested? */
223762306a36Sopenharmony_ci	if (!sev_es_enabled)
223862306a36Sopenharmony_ci		goto out;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	/*
224162306a36Sopenharmony_ci	 * SEV-ES requires MMIO caching as KVM doesn't have access to the guest
224262306a36Sopenharmony_ci	 * instruction stream, i.e. can't emulate in response to a #NPF and
224362306a36Sopenharmony_ci	 * instead relies on #NPF(RSVD) being reflected into the guest as #VC
224462306a36Sopenharmony_ci	 * (the guest can then do a #VMGEXIT to request MMIO emulation).
224562306a36Sopenharmony_ci	 */
224662306a36Sopenharmony_ci	if (!enable_mmio_caching)
224762306a36Sopenharmony_ci		goto out;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci	/* Does the CPU support SEV-ES? */
225062306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_SEV_ES))
225162306a36Sopenharmony_ci		goto out;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	/* Has the system been allocated ASIDs for SEV-ES? */
225462306a36Sopenharmony_ci	if (min_sev_asid == 1)
225562306a36Sopenharmony_ci		goto out;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci	sev_es_asid_count = min_sev_asid - 1;
225862306a36Sopenharmony_ci	WARN_ON_ONCE(misc_cg_set_capacity(MISC_CG_RES_SEV_ES, sev_es_asid_count));
225962306a36Sopenharmony_ci	sev_es_supported = true;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ciout:
226262306a36Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_SEV))
226362306a36Sopenharmony_ci		pr_info("SEV %s (ASIDs %u - %u)\n",
226462306a36Sopenharmony_ci			sev_supported ? "enabled" : "disabled",
226562306a36Sopenharmony_ci			min_sev_asid, max_sev_asid);
226662306a36Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_SEV_ES))
226762306a36Sopenharmony_ci		pr_info("SEV-ES %s (ASIDs %u - %u)\n",
226862306a36Sopenharmony_ci			sev_es_supported ? "enabled" : "disabled",
226962306a36Sopenharmony_ci			min_sev_asid > 1 ? 1 : 0, min_sev_asid - 1);
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	sev_enabled = sev_supported;
227262306a36Sopenharmony_ci	sev_es_enabled = sev_es_supported;
227362306a36Sopenharmony_ci	if (!sev_es_enabled || !cpu_feature_enabled(X86_FEATURE_DEBUG_SWAP) ||
227462306a36Sopenharmony_ci	    !cpu_feature_enabled(X86_FEATURE_NO_NESTED_DATA_BP))
227562306a36Sopenharmony_ci		sev_es_debug_swap_enabled = false;
227662306a36Sopenharmony_ci#endif
227762306a36Sopenharmony_ci}
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_civoid sev_hardware_unsetup(void)
228062306a36Sopenharmony_ci{
228162306a36Sopenharmony_ci	if (!sev_enabled)
228262306a36Sopenharmony_ci		return;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	/* No need to take sev_bitmap_lock, all VMs have been destroyed. */
228562306a36Sopenharmony_ci	sev_flush_asids(1, max_sev_asid);
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	bitmap_free(sev_asid_bitmap);
228862306a36Sopenharmony_ci	bitmap_free(sev_reclaim_asid_bitmap);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	misc_cg_set_capacity(MISC_CG_RES_SEV, 0);
229162306a36Sopenharmony_ci	misc_cg_set_capacity(MISC_CG_RES_SEV_ES, 0);
229262306a36Sopenharmony_ci}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ciint sev_cpu_init(struct svm_cpu_data *sd)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	if (!sev_enabled)
229762306a36Sopenharmony_ci		return 0;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	sd->sev_vmcbs = kcalloc(nr_asids, sizeof(void *), GFP_KERNEL);
230062306a36Sopenharmony_ci	if (!sd->sev_vmcbs)
230162306a36Sopenharmony_ci		return -ENOMEM;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	return 0;
230462306a36Sopenharmony_ci}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci/*
230762306a36Sopenharmony_ci * Pages used by hardware to hold guest encrypted state must be flushed before
230862306a36Sopenharmony_ci * returning them to the system.
230962306a36Sopenharmony_ci */
231062306a36Sopenharmony_cistatic void sev_flush_encrypted_page(struct kvm_vcpu *vcpu, void *va)
231162306a36Sopenharmony_ci{
231262306a36Sopenharmony_ci	int asid = to_kvm_svm(vcpu->kvm)->sev_info.asid;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	/*
231562306a36Sopenharmony_ci	 * Note!  The address must be a kernel address, as regular page walk
231662306a36Sopenharmony_ci	 * checks are performed by VM_PAGE_FLUSH, i.e. operating on a user
231762306a36Sopenharmony_ci	 * address is non-deterministic and unsafe.  This function deliberately
231862306a36Sopenharmony_ci	 * takes a pointer to deter passing in a user address.
231962306a36Sopenharmony_ci	 */
232062306a36Sopenharmony_ci	unsigned long addr = (unsigned long)va;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	/*
232362306a36Sopenharmony_ci	 * If CPU enforced cache coherency for encrypted mappings of the
232462306a36Sopenharmony_ci	 * same physical page is supported, use CLFLUSHOPT instead. NOTE: cache
232562306a36Sopenharmony_ci	 * flush is still needed in order to work properly with DMA devices.
232662306a36Sopenharmony_ci	 */
232762306a36Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_SME_COHERENT)) {
232862306a36Sopenharmony_ci		clflush_cache_range(va, PAGE_SIZE);
232962306a36Sopenharmony_ci		return;
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	/*
233362306a36Sopenharmony_ci	 * VM Page Flush takes a host virtual address and a guest ASID.  Fall
233462306a36Sopenharmony_ci	 * back to WBINVD if this faults so as not to make any problems worse
233562306a36Sopenharmony_ci	 * by leaving stale encrypted data in the cache.
233662306a36Sopenharmony_ci	 */
233762306a36Sopenharmony_ci	if (WARN_ON_ONCE(wrmsrl_safe(MSR_AMD64_VM_PAGE_FLUSH, addr | asid)))
233862306a36Sopenharmony_ci		goto do_wbinvd;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	return;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_cido_wbinvd:
234362306a36Sopenharmony_ci	wbinvd_on_all_cpus();
234462306a36Sopenharmony_ci}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_civoid sev_guest_memory_reclaimed(struct kvm *kvm)
234762306a36Sopenharmony_ci{
234862306a36Sopenharmony_ci	if (!sev_guest(kvm))
234962306a36Sopenharmony_ci		return;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	wbinvd_on_all_cpus();
235262306a36Sopenharmony_ci}
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_civoid sev_free_vcpu(struct kvm_vcpu *vcpu)
235562306a36Sopenharmony_ci{
235662306a36Sopenharmony_ci	struct vcpu_svm *svm;
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	if (!sev_es_guest(vcpu->kvm))
235962306a36Sopenharmony_ci		return;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	svm = to_svm(vcpu);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (vcpu->arch.guest_state_protected)
236462306a36Sopenharmony_ci		sev_flush_encrypted_page(vcpu, svm->sev_es.vmsa);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	__free_page(virt_to_page(svm->sev_es.vmsa));
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	if (svm->sev_es.ghcb_sa_free)
236962306a36Sopenharmony_ci		kvfree(svm->sev_es.ghcb_sa);
237062306a36Sopenharmony_ci}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_cistatic void dump_ghcb(struct vcpu_svm *svm)
237362306a36Sopenharmony_ci{
237462306a36Sopenharmony_ci	struct ghcb *ghcb = svm->sev_es.ghcb;
237562306a36Sopenharmony_ci	unsigned int nbits;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	/* Re-use the dump_invalid_vmcb module parameter */
237862306a36Sopenharmony_ci	if (!dump_invalid_vmcb) {
237962306a36Sopenharmony_ci		pr_warn_ratelimited("set kvm_amd.dump_invalid_vmcb=1 to dump internal KVM state.\n");
238062306a36Sopenharmony_ci		return;
238162306a36Sopenharmony_ci	}
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	nbits = sizeof(ghcb->save.valid_bitmap) * 8;
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	pr_err("GHCB (GPA=%016llx):\n", svm->vmcb->control.ghcb_gpa);
238662306a36Sopenharmony_ci	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code",
238762306a36Sopenharmony_ci	       ghcb->save.sw_exit_code, ghcb_sw_exit_code_is_valid(ghcb));
238862306a36Sopenharmony_ci	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1",
238962306a36Sopenharmony_ci	       ghcb->save.sw_exit_info_1, ghcb_sw_exit_info_1_is_valid(ghcb));
239062306a36Sopenharmony_ci	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2",
239162306a36Sopenharmony_ci	       ghcb->save.sw_exit_info_2, ghcb_sw_exit_info_2_is_valid(ghcb));
239262306a36Sopenharmony_ci	pr_err("%-20s%016llx is_valid: %u\n", "sw_scratch",
239362306a36Sopenharmony_ci	       ghcb->save.sw_scratch, ghcb_sw_scratch_is_valid(ghcb));
239462306a36Sopenharmony_ci	pr_err("%-20s%*pb\n", "valid_bitmap", nbits, ghcb->save.valid_bitmap);
239562306a36Sopenharmony_ci}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_cistatic void sev_es_sync_to_ghcb(struct vcpu_svm *svm)
239862306a36Sopenharmony_ci{
239962306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
240062306a36Sopenharmony_ci	struct ghcb *ghcb = svm->sev_es.ghcb;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	/*
240362306a36Sopenharmony_ci	 * The GHCB protocol so far allows for the following data
240462306a36Sopenharmony_ci	 * to be returned:
240562306a36Sopenharmony_ci	 *   GPRs RAX, RBX, RCX, RDX
240662306a36Sopenharmony_ci	 *
240762306a36Sopenharmony_ci	 * Copy their values, even if they may not have been written during the
240862306a36Sopenharmony_ci	 * VM-Exit.  It's the guest's responsibility to not consume random data.
240962306a36Sopenharmony_ci	 */
241062306a36Sopenharmony_ci	ghcb_set_rax(ghcb, vcpu->arch.regs[VCPU_REGS_RAX]);
241162306a36Sopenharmony_ci	ghcb_set_rbx(ghcb, vcpu->arch.regs[VCPU_REGS_RBX]);
241262306a36Sopenharmony_ci	ghcb_set_rcx(ghcb, vcpu->arch.regs[VCPU_REGS_RCX]);
241362306a36Sopenharmony_ci	ghcb_set_rdx(ghcb, vcpu->arch.regs[VCPU_REGS_RDX]);
241462306a36Sopenharmony_ci}
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_cistatic void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
241762306a36Sopenharmony_ci{
241862306a36Sopenharmony_ci	struct vmcb_control_area *control = &svm->vmcb->control;
241962306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
242062306a36Sopenharmony_ci	struct ghcb *ghcb = svm->sev_es.ghcb;
242162306a36Sopenharmony_ci	u64 exit_code;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	/*
242462306a36Sopenharmony_ci	 * The GHCB protocol so far allows for the following data
242562306a36Sopenharmony_ci	 * to be supplied:
242662306a36Sopenharmony_ci	 *   GPRs RAX, RBX, RCX, RDX
242762306a36Sopenharmony_ci	 *   XCR0
242862306a36Sopenharmony_ci	 *   CPL
242962306a36Sopenharmony_ci	 *
243062306a36Sopenharmony_ci	 * VMMCALL allows the guest to provide extra registers. KVM also
243162306a36Sopenharmony_ci	 * expects RSI for hypercalls, so include that, too.
243262306a36Sopenharmony_ci	 *
243362306a36Sopenharmony_ci	 * Copy their values to the appropriate location if supplied.
243462306a36Sopenharmony_ci	 */
243562306a36Sopenharmony_ci	memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs));
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(svm->sev_es.valid_bitmap) != sizeof(ghcb->save.valid_bitmap));
243862306a36Sopenharmony_ci	memcpy(&svm->sev_es.valid_bitmap, &ghcb->save.valid_bitmap, sizeof(ghcb->save.valid_bitmap));
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	vcpu->arch.regs[VCPU_REGS_RAX] = kvm_ghcb_get_rax_if_valid(svm, ghcb);
244162306a36Sopenharmony_ci	vcpu->arch.regs[VCPU_REGS_RBX] = kvm_ghcb_get_rbx_if_valid(svm, ghcb);
244262306a36Sopenharmony_ci	vcpu->arch.regs[VCPU_REGS_RCX] = kvm_ghcb_get_rcx_if_valid(svm, ghcb);
244362306a36Sopenharmony_ci	vcpu->arch.regs[VCPU_REGS_RDX] = kvm_ghcb_get_rdx_if_valid(svm, ghcb);
244462306a36Sopenharmony_ci	vcpu->arch.regs[VCPU_REGS_RSI] = kvm_ghcb_get_rsi_if_valid(svm, ghcb);
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	svm->vmcb->save.cpl = kvm_ghcb_get_cpl_if_valid(svm, ghcb);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	if (kvm_ghcb_xcr0_is_valid(svm)) {
244962306a36Sopenharmony_ci		vcpu->arch.xcr0 = ghcb_get_xcr0(ghcb);
245062306a36Sopenharmony_ci		kvm_update_cpuid_runtime(vcpu);
245162306a36Sopenharmony_ci	}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	/* Copy the GHCB exit information into the VMCB fields */
245462306a36Sopenharmony_ci	exit_code = ghcb_get_sw_exit_code(ghcb);
245562306a36Sopenharmony_ci	control->exit_code = lower_32_bits(exit_code);
245662306a36Sopenharmony_ci	control->exit_code_hi = upper_32_bits(exit_code);
245762306a36Sopenharmony_ci	control->exit_info_1 = ghcb_get_sw_exit_info_1(ghcb);
245862306a36Sopenharmony_ci	control->exit_info_2 = ghcb_get_sw_exit_info_2(ghcb);
245962306a36Sopenharmony_ci	svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm, ghcb);
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	/* Clear the valid entries fields */
246262306a36Sopenharmony_ci	memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
246362306a36Sopenharmony_ci}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_cistatic u64 kvm_ghcb_get_sw_exit_code(struct vmcb_control_area *control)
246662306a36Sopenharmony_ci{
246762306a36Sopenharmony_ci	return (((u64)control->exit_code_hi) << 32) | control->exit_code;
246862306a36Sopenharmony_ci}
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_cistatic int sev_es_validate_vmgexit(struct vcpu_svm *svm)
247162306a36Sopenharmony_ci{
247262306a36Sopenharmony_ci	struct vmcb_control_area *control = &svm->vmcb->control;
247362306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
247462306a36Sopenharmony_ci	u64 exit_code;
247562306a36Sopenharmony_ci	u64 reason;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	/*
247862306a36Sopenharmony_ci	 * Retrieve the exit code now even though it may not be marked valid
247962306a36Sopenharmony_ci	 * as it could help with debugging.
248062306a36Sopenharmony_ci	 */
248162306a36Sopenharmony_ci	exit_code = kvm_ghcb_get_sw_exit_code(control);
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	/* Only GHCB Usage code 0 is supported */
248462306a36Sopenharmony_ci	if (svm->sev_es.ghcb->ghcb_usage) {
248562306a36Sopenharmony_ci		reason = GHCB_ERR_INVALID_USAGE;
248662306a36Sopenharmony_ci		goto vmgexit_err;
248762306a36Sopenharmony_ci	}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	reason = GHCB_ERR_MISSING_INPUT;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	if (!kvm_ghcb_sw_exit_code_is_valid(svm) ||
249262306a36Sopenharmony_ci	    !kvm_ghcb_sw_exit_info_1_is_valid(svm) ||
249362306a36Sopenharmony_ci	    !kvm_ghcb_sw_exit_info_2_is_valid(svm))
249462306a36Sopenharmony_ci		goto vmgexit_err;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	switch (exit_code) {
249762306a36Sopenharmony_ci	case SVM_EXIT_READ_DR7:
249862306a36Sopenharmony_ci		break;
249962306a36Sopenharmony_ci	case SVM_EXIT_WRITE_DR7:
250062306a36Sopenharmony_ci		if (!kvm_ghcb_rax_is_valid(svm))
250162306a36Sopenharmony_ci			goto vmgexit_err;
250262306a36Sopenharmony_ci		break;
250362306a36Sopenharmony_ci	case SVM_EXIT_RDTSC:
250462306a36Sopenharmony_ci		break;
250562306a36Sopenharmony_ci	case SVM_EXIT_RDPMC:
250662306a36Sopenharmony_ci		if (!kvm_ghcb_rcx_is_valid(svm))
250762306a36Sopenharmony_ci			goto vmgexit_err;
250862306a36Sopenharmony_ci		break;
250962306a36Sopenharmony_ci	case SVM_EXIT_CPUID:
251062306a36Sopenharmony_ci		if (!kvm_ghcb_rax_is_valid(svm) ||
251162306a36Sopenharmony_ci		    !kvm_ghcb_rcx_is_valid(svm))
251262306a36Sopenharmony_ci			goto vmgexit_err;
251362306a36Sopenharmony_ci		if (vcpu->arch.regs[VCPU_REGS_RAX] == 0xd)
251462306a36Sopenharmony_ci			if (!kvm_ghcb_xcr0_is_valid(svm))
251562306a36Sopenharmony_ci				goto vmgexit_err;
251662306a36Sopenharmony_ci		break;
251762306a36Sopenharmony_ci	case SVM_EXIT_INVD:
251862306a36Sopenharmony_ci		break;
251962306a36Sopenharmony_ci	case SVM_EXIT_IOIO:
252062306a36Sopenharmony_ci		if (control->exit_info_1 & SVM_IOIO_STR_MASK) {
252162306a36Sopenharmony_ci			if (!kvm_ghcb_sw_scratch_is_valid(svm))
252262306a36Sopenharmony_ci				goto vmgexit_err;
252362306a36Sopenharmony_ci		} else {
252462306a36Sopenharmony_ci			if (!(control->exit_info_1 & SVM_IOIO_TYPE_MASK))
252562306a36Sopenharmony_ci				if (!kvm_ghcb_rax_is_valid(svm))
252662306a36Sopenharmony_ci					goto vmgexit_err;
252762306a36Sopenharmony_ci		}
252862306a36Sopenharmony_ci		break;
252962306a36Sopenharmony_ci	case SVM_EXIT_MSR:
253062306a36Sopenharmony_ci		if (!kvm_ghcb_rcx_is_valid(svm))
253162306a36Sopenharmony_ci			goto vmgexit_err;
253262306a36Sopenharmony_ci		if (control->exit_info_1) {
253362306a36Sopenharmony_ci			if (!kvm_ghcb_rax_is_valid(svm) ||
253462306a36Sopenharmony_ci			    !kvm_ghcb_rdx_is_valid(svm))
253562306a36Sopenharmony_ci				goto vmgexit_err;
253662306a36Sopenharmony_ci		}
253762306a36Sopenharmony_ci		break;
253862306a36Sopenharmony_ci	case SVM_EXIT_VMMCALL:
253962306a36Sopenharmony_ci		if (!kvm_ghcb_rax_is_valid(svm) ||
254062306a36Sopenharmony_ci		    !kvm_ghcb_cpl_is_valid(svm))
254162306a36Sopenharmony_ci			goto vmgexit_err;
254262306a36Sopenharmony_ci		break;
254362306a36Sopenharmony_ci	case SVM_EXIT_RDTSCP:
254462306a36Sopenharmony_ci		break;
254562306a36Sopenharmony_ci	case SVM_EXIT_WBINVD:
254662306a36Sopenharmony_ci		break;
254762306a36Sopenharmony_ci	case SVM_EXIT_MONITOR:
254862306a36Sopenharmony_ci		if (!kvm_ghcb_rax_is_valid(svm) ||
254962306a36Sopenharmony_ci		    !kvm_ghcb_rcx_is_valid(svm) ||
255062306a36Sopenharmony_ci		    !kvm_ghcb_rdx_is_valid(svm))
255162306a36Sopenharmony_ci			goto vmgexit_err;
255262306a36Sopenharmony_ci		break;
255362306a36Sopenharmony_ci	case SVM_EXIT_MWAIT:
255462306a36Sopenharmony_ci		if (!kvm_ghcb_rax_is_valid(svm) ||
255562306a36Sopenharmony_ci		    !kvm_ghcb_rcx_is_valid(svm))
255662306a36Sopenharmony_ci			goto vmgexit_err;
255762306a36Sopenharmony_ci		break;
255862306a36Sopenharmony_ci	case SVM_VMGEXIT_MMIO_READ:
255962306a36Sopenharmony_ci	case SVM_VMGEXIT_MMIO_WRITE:
256062306a36Sopenharmony_ci		if (!kvm_ghcb_sw_scratch_is_valid(svm))
256162306a36Sopenharmony_ci			goto vmgexit_err;
256262306a36Sopenharmony_ci		break;
256362306a36Sopenharmony_ci	case SVM_VMGEXIT_NMI_COMPLETE:
256462306a36Sopenharmony_ci	case SVM_VMGEXIT_AP_HLT_LOOP:
256562306a36Sopenharmony_ci	case SVM_VMGEXIT_AP_JUMP_TABLE:
256662306a36Sopenharmony_ci	case SVM_VMGEXIT_UNSUPPORTED_EVENT:
256762306a36Sopenharmony_ci		break;
256862306a36Sopenharmony_ci	default:
256962306a36Sopenharmony_ci		reason = GHCB_ERR_INVALID_EVENT;
257062306a36Sopenharmony_ci		goto vmgexit_err;
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	return 0;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_civmgexit_err:
257662306a36Sopenharmony_ci	if (reason == GHCB_ERR_INVALID_USAGE) {
257762306a36Sopenharmony_ci		vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n",
257862306a36Sopenharmony_ci			    svm->sev_es.ghcb->ghcb_usage);
257962306a36Sopenharmony_ci	} else if (reason == GHCB_ERR_INVALID_EVENT) {
258062306a36Sopenharmony_ci		vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
258162306a36Sopenharmony_ci			    exit_code);
258262306a36Sopenharmony_ci	} else {
258362306a36Sopenharmony_ci		vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
258462306a36Sopenharmony_ci			    exit_code);
258562306a36Sopenharmony_ci		dump_ghcb(svm);
258662306a36Sopenharmony_ci	}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
258962306a36Sopenharmony_ci	ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, reason);
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci	/* Resume the guest to "return" the error code. */
259262306a36Sopenharmony_ci	return 1;
259362306a36Sopenharmony_ci}
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_civoid sev_es_unmap_ghcb(struct vcpu_svm *svm)
259662306a36Sopenharmony_ci{
259762306a36Sopenharmony_ci	if (!svm->sev_es.ghcb)
259862306a36Sopenharmony_ci		return;
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	if (svm->sev_es.ghcb_sa_free) {
260162306a36Sopenharmony_ci		/*
260262306a36Sopenharmony_ci		 * The scratch area lives outside the GHCB, so there is a
260362306a36Sopenharmony_ci		 * buffer that, depending on the operation performed, may
260462306a36Sopenharmony_ci		 * need to be synced, then freed.
260562306a36Sopenharmony_ci		 */
260662306a36Sopenharmony_ci		if (svm->sev_es.ghcb_sa_sync) {
260762306a36Sopenharmony_ci			kvm_write_guest(svm->vcpu.kvm,
260862306a36Sopenharmony_ci					svm->sev_es.sw_scratch,
260962306a36Sopenharmony_ci					svm->sev_es.ghcb_sa,
261062306a36Sopenharmony_ci					svm->sev_es.ghcb_sa_len);
261162306a36Sopenharmony_ci			svm->sev_es.ghcb_sa_sync = false;
261262306a36Sopenharmony_ci		}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci		kvfree(svm->sev_es.ghcb_sa);
261562306a36Sopenharmony_ci		svm->sev_es.ghcb_sa = NULL;
261662306a36Sopenharmony_ci		svm->sev_es.ghcb_sa_free = false;
261762306a36Sopenharmony_ci	}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	trace_kvm_vmgexit_exit(svm->vcpu.vcpu_id, svm->sev_es.ghcb);
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	sev_es_sync_to_ghcb(svm);
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map, true);
262462306a36Sopenharmony_ci	svm->sev_es.ghcb = NULL;
262562306a36Sopenharmony_ci}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_civoid pre_sev_run(struct vcpu_svm *svm, int cpu)
262862306a36Sopenharmony_ci{
262962306a36Sopenharmony_ci	struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
263062306a36Sopenharmony_ci	int asid = sev_get_asid(svm->vcpu.kvm);
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	/* Assign the asid allocated with this SEV guest */
263362306a36Sopenharmony_ci	svm->asid = asid;
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci	/*
263662306a36Sopenharmony_ci	 * Flush guest TLB:
263762306a36Sopenharmony_ci	 *
263862306a36Sopenharmony_ci	 * 1) when different VMCB for the same ASID is to be run on the same host CPU.
263962306a36Sopenharmony_ci	 * 2) or this VMCB was executed on different host CPU in previous VMRUNs.
264062306a36Sopenharmony_ci	 */
264162306a36Sopenharmony_ci	if (sd->sev_vmcbs[asid] == svm->vmcb &&
264262306a36Sopenharmony_ci	    svm->vcpu.arch.last_vmentry_cpu == cpu)
264362306a36Sopenharmony_ci		return;
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	sd->sev_vmcbs[asid] = svm->vmcb;
264662306a36Sopenharmony_ci	svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
264762306a36Sopenharmony_ci	vmcb_mark_dirty(svm->vmcb, VMCB_ASID);
264862306a36Sopenharmony_ci}
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci#define GHCB_SCRATCH_AREA_LIMIT		(16ULL * PAGE_SIZE)
265162306a36Sopenharmony_cistatic int setup_vmgexit_scratch(struct vcpu_svm *svm, bool sync, u64 len)
265262306a36Sopenharmony_ci{
265362306a36Sopenharmony_ci	struct vmcb_control_area *control = &svm->vmcb->control;
265462306a36Sopenharmony_ci	u64 ghcb_scratch_beg, ghcb_scratch_end;
265562306a36Sopenharmony_ci	u64 scratch_gpa_beg, scratch_gpa_end;
265662306a36Sopenharmony_ci	void *scratch_va;
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	scratch_gpa_beg = svm->sev_es.sw_scratch;
265962306a36Sopenharmony_ci	if (!scratch_gpa_beg) {
266062306a36Sopenharmony_ci		pr_err("vmgexit: scratch gpa not provided\n");
266162306a36Sopenharmony_ci		goto e_scratch;
266262306a36Sopenharmony_ci	}
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	scratch_gpa_end = scratch_gpa_beg + len;
266562306a36Sopenharmony_ci	if (scratch_gpa_end < scratch_gpa_beg) {
266662306a36Sopenharmony_ci		pr_err("vmgexit: scratch length (%#llx) not valid for scratch address (%#llx)\n",
266762306a36Sopenharmony_ci		       len, scratch_gpa_beg);
266862306a36Sopenharmony_ci		goto e_scratch;
266962306a36Sopenharmony_ci	}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	if ((scratch_gpa_beg & PAGE_MASK) == control->ghcb_gpa) {
267262306a36Sopenharmony_ci		/* Scratch area begins within GHCB */
267362306a36Sopenharmony_ci		ghcb_scratch_beg = control->ghcb_gpa +
267462306a36Sopenharmony_ci				   offsetof(struct ghcb, shared_buffer);
267562306a36Sopenharmony_ci		ghcb_scratch_end = control->ghcb_gpa +
267662306a36Sopenharmony_ci				   offsetof(struct ghcb, reserved_0xff0);
267762306a36Sopenharmony_ci
267862306a36Sopenharmony_ci		/*
267962306a36Sopenharmony_ci		 * If the scratch area begins within the GHCB, it must be
268062306a36Sopenharmony_ci		 * completely contained in the GHCB shared buffer area.
268162306a36Sopenharmony_ci		 */
268262306a36Sopenharmony_ci		if (scratch_gpa_beg < ghcb_scratch_beg ||
268362306a36Sopenharmony_ci		    scratch_gpa_end > ghcb_scratch_end) {
268462306a36Sopenharmony_ci			pr_err("vmgexit: scratch area is outside of GHCB shared buffer area (%#llx - %#llx)\n",
268562306a36Sopenharmony_ci			       scratch_gpa_beg, scratch_gpa_end);
268662306a36Sopenharmony_ci			goto e_scratch;
268762306a36Sopenharmony_ci		}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci		scratch_va = (void *)svm->sev_es.ghcb;
269062306a36Sopenharmony_ci		scratch_va += (scratch_gpa_beg - control->ghcb_gpa);
269162306a36Sopenharmony_ci	} else {
269262306a36Sopenharmony_ci		/*
269362306a36Sopenharmony_ci		 * The guest memory must be read into a kernel buffer, so
269462306a36Sopenharmony_ci		 * limit the size
269562306a36Sopenharmony_ci		 */
269662306a36Sopenharmony_ci		if (len > GHCB_SCRATCH_AREA_LIMIT) {
269762306a36Sopenharmony_ci			pr_err("vmgexit: scratch area exceeds KVM limits (%#llx requested, %#llx limit)\n",
269862306a36Sopenharmony_ci			       len, GHCB_SCRATCH_AREA_LIMIT);
269962306a36Sopenharmony_ci			goto e_scratch;
270062306a36Sopenharmony_ci		}
270162306a36Sopenharmony_ci		scratch_va = kvzalloc(len, GFP_KERNEL_ACCOUNT);
270262306a36Sopenharmony_ci		if (!scratch_va)
270362306a36Sopenharmony_ci			return -ENOMEM;
270462306a36Sopenharmony_ci
270562306a36Sopenharmony_ci		if (kvm_read_guest(svm->vcpu.kvm, scratch_gpa_beg, scratch_va, len)) {
270662306a36Sopenharmony_ci			/* Unable to copy scratch area from guest */
270762306a36Sopenharmony_ci			pr_err("vmgexit: kvm_read_guest for scratch area failed\n");
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci			kvfree(scratch_va);
271062306a36Sopenharmony_ci			return -EFAULT;
271162306a36Sopenharmony_ci		}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci		/*
271462306a36Sopenharmony_ci		 * The scratch area is outside the GHCB. The operation will
271562306a36Sopenharmony_ci		 * dictate whether the buffer needs to be synced before running
271662306a36Sopenharmony_ci		 * the vCPU next time (i.e. a read was requested so the data
271762306a36Sopenharmony_ci		 * must be written back to the guest memory).
271862306a36Sopenharmony_ci		 */
271962306a36Sopenharmony_ci		svm->sev_es.ghcb_sa_sync = sync;
272062306a36Sopenharmony_ci		svm->sev_es.ghcb_sa_free = true;
272162306a36Sopenharmony_ci	}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	svm->sev_es.ghcb_sa = scratch_va;
272462306a36Sopenharmony_ci	svm->sev_es.ghcb_sa_len = len;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	return 0;
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_cie_scratch:
272962306a36Sopenharmony_ci	ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
273062306a36Sopenharmony_ci	ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_SCRATCH_AREA);
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	return 1;
273362306a36Sopenharmony_ci}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_cistatic void set_ghcb_msr_bits(struct vcpu_svm *svm, u64 value, u64 mask,
273662306a36Sopenharmony_ci			      unsigned int pos)
273762306a36Sopenharmony_ci{
273862306a36Sopenharmony_ci	svm->vmcb->control.ghcb_gpa &= ~(mask << pos);
273962306a36Sopenharmony_ci	svm->vmcb->control.ghcb_gpa |= (value & mask) << pos;
274062306a36Sopenharmony_ci}
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_cistatic u64 get_ghcb_msr_bits(struct vcpu_svm *svm, u64 mask, unsigned int pos)
274362306a36Sopenharmony_ci{
274462306a36Sopenharmony_ci	return (svm->vmcb->control.ghcb_gpa >> pos) & mask;
274562306a36Sopenharmony_ci}
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_cistatic void set_ghcb_msr(struct vcpu_svm *svm, u64 value)
274862306a36Sopenharmony_ci{
274962306a36Sopenharmony_ci	svm->vmcb->control.ghcb_gpa = value;
275062306a36Sopenharmony_ci}
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_cistatic int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
275362306a36Sopenharmony_ci{
275462306a36Sopenharmony_ci	struct vmcb_control_area *control = &svm->vmcb->control;
275562306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
275662306a36Sopenharmony_ci	u64 ghcb_info;
275762306a36Sopenharmony_ci	int ret = 1;
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	ghcb_info = control->ghcb_gpa & GHCB_MSR_INFO_MASK;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	trace_kvm_vmgexit_msr_protocol_enter(svm->vcpu.vcpu_id,
276262306a36Sopenharmony_ci					     control->ghcb_gpa);
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	switch (ghcb_info) {
276562306a36Sopenharmony_ci	case GHCB_MSR_SEV_INFO_REQ:
276662306a36Sopenharmony_ci		set_ghcb_msr(svm, GHCB_MSR_SEV_INFO(GHCB_VERSION_MAX,
276762306a36Sopenharmony_ci						    GHCB_VERSION_MIN,
276862306a36Sopenharmony_ci						    sev_enc_bit));
276962306a36Sopenharmony_ci		break;
277062306a36Sopenharmony_ci	case GHCB_MSR_CPUID_REQ: {
277162306a36Sopenharmony_ci		u64 cpuid_fn, cpuid_reg, cpuid_value;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci		cpuid_fn = get_ghcb_msr_bits(svm,
277462306a36Sopenharmony_ci					     GHCB_MSR_CPUID_FUNC_MASK,
277562306a36Sopenharmony_ci					     GHCB_MSR_CPUID_FUNC_POS);
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci		/* Initialize the registers needed by the CPUID intercept */
277862306a36Sopenharmony_ci		vcpu->arch.regs[VCPU_REGS_RAX] = cpuid_fn;
277962306a36Sopenharmony_ci		vcpu->arch.regs[VCPU_REGS_RCX] = 0;
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci		ret = svm_invoke_exit_handler(vcpu, SVM_EXIT_CPUID);
278262306a36Sopenharmony_ci		if (!ret) {
278362306a36Sopenharmony_ci			/* Error, keep GHCB MSR value as-is */
278462306a36Sopenharmony_ci			break;
278562306a36Sopenharmony_ci		}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		cpuid_reg = get_ghcb_msr_bits(svm,
278862306a36Sopenharmony_ci					      GHCB_MSR_CPUID_REG_MASK,
278962306a36Sopenharmony_ci					      GHCB_MSR_CPUID_REG_POS);
279062306a36Sopenharmony_ci		if (cpuid_reg == 0)
279162306a36Sopenharmony_ci			cpuid_value = vcpu->arch.regs[VCPU_REGS_RAX];
279262306a36Sopenharmony_ci		else if (cpuid_reg == 1)
279362306a36Sopenharmony_ci			cpuid_value = vcpu->arch.regs[VCPU_REGS_RBX];
279462306a36Sopenharmony_ci		else if (cpuid_reg == 2)
279562306a36Sopenharmony_ci			cpuid_value = vcpu->arch.regs[VCPU_REGS_RCX];
279662306a36Sopenharmony_ci		else
279762306a36Sopenharmony_ci			cpuid_value = vcpu->arch.regs[VCPU_REGS_RDX];
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci		set_ghcb_msr_bits(svm, cpuid_value,
280062306a36Sopenharmony_ci				  GHCB_MSR_CPUID_VALUE_MASK,
280162306a36Sopenharmony_ci				  GHCB_MSR_CPUID_VALUE_POS);
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci		set_ghcb_msr_bits(svm, GHCB_MSR_CPUID_RESP,
280462306a36Sopenharmony_ci				  GHCB_MSR_INFO_MASK,
280562306a36Sopenharmony_ci				  GHCB_MSR_INFO_POS);
280662306a36Sopenharmony_ci		break;
280762306a36Sopenharmony_ci	}
280862306a36Sopenharmony_ci	case GHCB_MSR_TERM_REQ: {
280962306a36Sopenharmony_ci		u64 reason_set, reason_code;
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci		reason_set = get_ghcb_msr_bits(svm,
281262306a36Sopenharmony_ci					       GHCB_MSR_TERM_REASON_SET_MASK,
281362306a36Sopenharmony_ci					       GHCB_MSR_TERM_REASON_SET_POS);
281462306a36Sopenharmony_ci		reason_code = get_ghcb_msr_bits(svm,
281562306a36Sopenharmony_ci						GHCB_MSR_TERM_REASON_MASK,
281662306a36Sopenharmony_ci						GHCB_MSR_TERM_REASON_POS);
281762306a36Sopenharmony_ci		pr_info("SEV-ES guest requested termination: %#llx:%#llx\n",
281862306a36Sopenharmony_ci			reason_set, reason_code);
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci		vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
282162306a36Sopenharmony_ci		vcpu->run->system_event.type = KVM_SYSTEM_EVENT_SEV_TERM;
282262306a36Sopenharmony_ci		vcpu->run->system_event.ndata = 1;
282362306a36Sopenharmony_ci		vcpu->run->system_event.data[0] = control->ghcb_gpa;
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci		return 0;
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci	default:
282862306a36Sopenharmony_ci		/* Error, keep GHCB MSR value as-is */
282962306a36Sopenharmony_ci		break;
283062306a36Sopenharmony_ci	}
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	trace_kvm_vmgexit_msr_protocol_exit(svm->vcpu.vcpu_id,
283362306a36Sopenharmony_ci					    control->ghcb_gpa, ret);
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return ret;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ciint sev_handle_vmgexit(struct kvm_vcpu *vcpu)
283962306a36Sopenharmony_ci{
284062306a36Sopenharmony_ci	struct vcpu_svm *svm = to_svm(vcpu);
284162306a36Sopenharmony_ci	struct vmcb_control_area *control = &svm->vmcb->control;
284262306a36Sopenharmony_ci	u64 ghcb_gpa, exit_code;
284362306a36Sopenharmony_ci	int ret;
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	/* Validate the GHCB */
284662306a36Sopenharmony_ci	ghcb_gpa = control->ghcb_gpa;
284762306a36Sopenharmony_ci	if (ghcb_gpa & GHCB_MSR_INFO_MASK)
284862306a36Sopenharmony_ci		return sev_handle_vmgexit_msr_protocol(svm);
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	if (!ghcb_gpa) {
285162306a36Sopenharmony_ci		vcpu_unimpl(vcpu, "vmgexit: GHCB gpa is not set\n");
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci		/* Without a GHCB, just return right back to the guest */
285462306a36Sopenharmony_ci		return 1;
285562306a36Sopenharmony_ci	}
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	if (kvm_vcpu_map(vcpu, ghcb_gpa >> PAGE_SHIFT, &svm->sev_es.ghcb_map)) {
285862306a36Sopenharmony_ci		/* Unable to map GHCB from guest */
285962306a36Sopenharmony_ci		vcpu_unimpl(vcpu, "vmgexit: error mapping GHCB [%#llx] from guest\n",
286062306a36Sopenharmony_ci			    ghcb_gpa);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci		/* Without a GHCB, just return right back to the guest */
286362306a36Sopenharmony_ci		return 1;
286462306a36Sopenharmony_ci	}
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	svm->sev_es.ghcb = svm->sev_es.ghcb_map.hva;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	trace_kvm_vmgexit_enter(vcpu->vcpu_id, svm->sev_es.ghcb);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	sev_es_sync_from_ghcb(svm);
287162306a36Sopenharmony_ci	ret = sev_es_validate_vmgexit(svm);
287262306a36Sopenharmony_ci	if (ret)
287362306a36Sopenharmony_ci		return ret;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 0);
287662306a36Sopenharmony_ci	ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, 0);
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	exit_code = kvm_ghcb_get_sw_exit_code(control);
287962306a36Sopenharmony_ci	switch (exit_code) {
288062306a36Sopenharmony_ci	case SVM_VMGEXIT_MMIO_READ:
288162306a36Sopenharmony_ci		ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
288262306a36Sopenharmony_ci		if (ret)
288362306a36Sopenharmony_ci			break;
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci		ret = kvm_sev_es_mmio_read(vcpu,
288662306a36Sopenharmony_ci					   control->exit_info_1,
288762306a36Sopenharmony_ci					   control->exit_info_2,
288862306a36Sopenharmony_ci					   svm->sev_es.ghcb_sa);
288962306a36Sopenharmony_ci		break;
289062306a36Sopenharmony_ci	case SVM_VMGEXIT_MMIO_WRITE:
289162306a36Sopenharmony_ci		ret = setup_vmgexit_scratch(svm, false, control->exit_info_2);
289262306a36Sopenharmony_ci		if (ret)
289362306a36Sopenharmony_ci			break;
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci		ret = kvm_sev_es_mmio_write(vcpu,
289662306a36Sopenharmony_ci					    control->exit_info_1,
289762306a36Sopenharmony_ci					    control->exit_info_2,
289862306a36Sopenharmony_ci					    svm->sev_es.ghcb_sa);
289962306a36Sopenharmony_ci		break;
290062306a36Sopenharmony_ci	case SVM_VMGEXIT_NMI_COMPLETE:
290162306a36Sopenharmony_ci		++vcpu->stat.nmi_window_exits;
290262306a36Sopenharmony_ci		svm->nmi_masked = false;
290362306a36Sopenharmony_ci		kvm_make_request(KVM_REQ_EVENT, vcpu);
290462306a36Sopenharmony_ci		ret = 1;
290562306a36Sopenharmony_ci		break;
290662306a36Sopenharmony_ci	case SVM_VMGEXIT_AP_HLT_LOOP:
290762306a36Sopenharmony_ci		ret = kvm_emulate_ap_reset_hold(vcpu);
290862306a36Sopenharmony_ci		break;
290962306a36Sopenharmony_ci	case SVM_VMGEXIT_AP_JUMP_TABLE: {
291062306a36Sopenharmony_ci		struct kvm_sev_info *sev = &to_kvm_svm(vcpu->kvm)->sev_info;
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci		switch (control->exit_info_1) {
291362306a36Sopenharmony_ci		case 0:
291462306a36Sopenharmony_ci			/* Set AP jump table address */
291562306a36Sopenharmony_ci			sev->ap_jump_table = control->exit_info_2;
291662306a36Sopenharmony_ci			break;
291762306a36Sopenharmony_ci		case 1:
291862306a36Sopenharmony_ci			/* Get AP jump table address */
291962306a36Sopenharmony_ci			ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, sev->ap_jump_table);
292062306a36Sopenharmony_ci			break;
292162306a36Sopenharmony_ci		default:
292262306a36Sopenharmony_ci			pr_err("svm: vmgexit: unsupported AP jump table request - exit_info_1=%#llx\n",
292362306a36Sopenharmony_ci			       control->exit_info_1);
292462306a36Sopenharmony_ci			ghcb_set_sw_exit_info_1(svm->sev_es.ghcb, 2);
292562306a36Sopenharmony_ci			ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, GHCB_ERR_INVALID_INPUT);
292662306a36Sopenharmony_ci		}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci		ret = 1;
292962306a36Sopenharmony_ci		break;
293062306a36Sopenharmony_ci	}
293162306a36Sopenharmony_ci	case SVM_VMGEXIT_UNSUPPORTED_EVENT:
293262306a36Sopenharmony_ci		vcpu_unimpl(vcpu,
293362306a36Sopenharmony_ci			    "vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
293462306a36Sopenharmony_ci			    control->exit_info_1, control->exit_info_2);
293562306a36Sopenharmony_ci		ret = -EINVAL;
293662306a36Sopenharmony_ci		break;
293762306a36Sopenharmony_ci	default:
293862306a36Sopenharmony_ci		ret = svm_invoke_exit_handler(vcpu, exit_code);
293962306a36Sopenharmony_ci	}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	return ret;
294262306a36Sopenharmony_ci}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ciint sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
294562306a36Sopenharmony_ci{
294662306a36Sopenharmony_ci	int count;
294762306a36Sopenharmony_ci	int bytes;
294862306a36Sopenharmony_ci	int r;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci	if (svm->vmcb->control.exit_info_2 > INT_MAX)
295162306a36Sopenharmony_ci		return -EINVAL;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	count = svm->vmcb->control.exit_info_2;
295462306a36Sopenharmony_ci	if (unlikely(check_mul_overflow(count, size, &bytes)))
295562306a36Sopenharmony_ci		return -EINVAL;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	r = setup_vmgexit_scratch(svm, in, bytes);
295862306a36Sopenharmony_ci	if (r)
295962306a36Sopenharmony_ci		return r;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	return kvm_sev_es_string_io(&svm->vcpu, size, port, svm->sev_es.ghcb_sa,
296262306a36Sopenharmony_ci				    count, in);
296362306a36Sopenharmony_ci}
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_cistatic void sev_es_vcpu_after_set_cpuid(struct vcpu_svm *svm)
296662306a36Sopenharmony_ci{
296762306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
297062306a36Sopenharmony_ci		bool v_tsc_aux = guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP) ||
297162306a36Sopenharmony_ci				 guest_cpuid_has(vcpu, X86_FEATURE_RDPID);
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci		set_msr_interception(vcpu, svm->msrpm, MSR_TSC_AUX, v_tsc_aux, v_tsc_aux);
297462306a36Sopenharmony_ci	}
297562306a36Sopenharmony_ci}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_civoid sev_vcpu_after_set_cpuid(struct vcpu_svm *svm)
297862306a36Sopenharmony_ci{
297962306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
298062306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *best;
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	/* For sev guests, the memory encryption bit is not reserved in CR3.  */
298362306a36Sopenharmony_ci	best = kvm_find_cpuid_entry(vcpu, 0x8000001F);
298462306a36Sopenharmony_ci	if (best)
298562306a36Sopenharmony_ci		vcpu->arch.reserved_gpa_bits &= ~(1UL << (best->ebx & 0x3f));
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	if (sev_es_guest(svm->vcpu.kvm))
298862306a36Sopenharmony_ci		sev_es_vcpu_after_set_cpuid(svm);
298962306a36Sopenharmony_ci}
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_cistatic void sev_es_init_vmcb(struct vcpu_svm *svm)
299262306a36Sopenharmony_ci{
299362306a36Sopenharmony_ci	struct vmcb *vmcb = svm->vmcb01.ptr;
299462306a36Sopenharmony_ci	struct kvm_vcpu *vcpu = &svm->vcpu;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ES_ENABLE;
299762306a36Sopenharmony_ci	svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK;
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	/*
300062306a36Sopenharmony_ci	 * An SEV-ES guest requires a VMSA area that is a separate from the
300162306a36Sopenharmony_ci	 * VMCB page. Do not include the encryption mask on the VMSA physical
300262306a36Sopenharmony_ci	 * address since hardware will access it using the guest key.  Note,
300362306a36Sopenharmony_ci	 * the VMSA will be NULL if this vCPU is the destination for intrahost
300462306a36Sopenharmony_ci	 * migration, and will be copied later.
300562306a36Sopenharmony_ci	 */
300662306a36Sopenharmony_ci	if (svm->sev_es.vmsa)
300762306a36Sopenharmony_ci		svm->vmcb->control.vmsa_pa = __pa(svm->sev_es.vmsa);
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	/* Can't intercept CR register access, HV can't modify CR registers */
301062306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_CR0_READ);
301162306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_CR4_READ);
301262306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_CR8_READ);
301362306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_CR0_WRITE);
301462306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_CR4_WRITE);
301562306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_CR8_WRITE);
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_SELECTIVE_CR0);
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	/* Track EFER/CR register changes */
302062306a36Sopenharmony_ci	svm_set_intercept(svm, TRAP_EFER_WRITE);
302162306a36Sopenharmony_ci	svm_set_intercept(svm, TRAP_CR0_WRITE);
302262306a36Sopenharmony_ci	svm_set_intercept(svm, TRAP_CR4_WRITE);
302362306a36Sopenharmony_ci	svm_set_intercept(svm, TRAP_CR8_WRITE);
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	vmcb->control.intercepts[INTERCEPT_DR] = 0;
302662306a36Sopenharmony_ci	if (!sev_es_debug_swap_enabled) {
302762306a36Sopenharmony_ci		vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_READ);
302862306a36Sopenharmony_ci		vmcb_set_intercept(&vmcb->control, INTERCEPT_DR7_WRITE);
302962306a36Sopenharmony_ci		recalc_intercepts(svm);
303062306a36Sopenharmony_ci	} else {
303162306a36Sopenharmony_ci		/*
303262306a36Sopenharmony_ci		 * Disable #DB intercept iff DebugSwap is enabled.  KVM doesn't
303362306a36Sopenharmony_ci		 * allow debugging SEV-ES guests, and enables DebugSwap iff
303462306a36Sopenharmony_ci		 * NO_NESTED_DATA_BP is supported, so there's no reason to
303562306a36Sopenharmony_ci		 * intercept #DB when DebugSwap is enabled.  For simplicity
303662306a36Sopenharmony_ci		 * with respect to guest debug, intercept #DB for other VMs
303762306a36Sopenharmony_ci		 * even if NO_NESTED_DATA_BP is supported, i.e. even if the
303862306a36Sopenharmony_ci		 * guest can't DoS the CPU with infinite #DB vectoring.
303962306a36Sopenharmony_ci		 */
304062306a36Sopenharmony_ci		clr_exception_intercept(svm, DB_VECTOR);
304162306a36Sopenharmony_ci	}
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	/* Can't intercept XSETBV, HV can't modify XCR0 directly */
304462306a36Sopenharmony_ci	svm_clr_intercept(svm, INTERCEPT_XSETBV);
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	/* Clear intercepts on selected MSRs */
304762306a36Sopenharmony_ci	set_msr_interception(vcpu, svm->msrpm, MSR_EFER, 1, 1);
304862306a36Sopenharmony_ci	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_CR_PAT, 1, 1);
304962306a36Sopenharmony_ci	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 1, 1);
305062306a36Sopenharmony_ci	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 1, 1);
305162306a36Sopenharmony_ci	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 1, 1);
305262306a36Sopenharmony_ci	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 1, 1);
305362306a36Sopenharmony_ci}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_civoid sev_init_vmcb(struct vcpu_svm *svm)
305662306a36Sopenharmony_ci{
305762306a36Sopenharmony_ci	svm->vmcb->control.nested_ctl |= SVM_NESTED_CTL_SEV_ENABLE;
305862306a36Sopenharmony_ci	clr_exception_intercept(svm, UD_VECTOR);
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	/*
306162306a36Sopenharmony_ci	 * Don't intercept #GP for SEV guests, e.g. for the VMware backdoor, as
306262306a36Sopenharmony_ci	 * KVM can't decrypt guest memory to decode the faulting instruction.
306362306a36Sopenharmony_ci	 */
306462306a36Sopenharmony_ci	clr_exception_intercept(svm, GP_VECTOR);
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	if (sev_es_guest(svm->vcpu.kvm))
306762306a36Sopenharmony_ci		sev_es_init_vmcb(svm);
306862306a36Sopenharmony_ci}
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_civoid sev_es_vcpu_reset(struct vcpu_svm *svm)
307162306a36Sopenharmony_ci{
307262306a36Sopenharmony_ci	/*
307362306a36Sopenharmony_ci	 * Set the GHCB MSR value as per the GHCB specification when emulating
307462306a36Sopenharmony_ci	 * vCPU RESET for an SEV-ES guest.
307562306a36Sopenharmony_ci	 */
307662306a36Sopenharmony_ci	set_ghcb_msr(svm, GHCB_MSR_SEV_INFO(GHCB_VERSION_MAX,
307762306a36Sopenharmony_ci					    GHCB_VERSION_MIN,
307862306a36Sopenharmony_ci					    sev_enc_bit));
307962306a36Sopenharmony_ci}
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_civoid sev_es_prepare_switch_to_guest(struct sev_es_save_area *hostsa)
308262306a36Sopenharmony_ci{
308362306a36Sopenharmony_ci	/*
308462306a36Sopenharmony_ci	 * All host state for SEV-ES guests is categorized into three swap types
308562306a36Sopenharmony_ci	 * based on how it is handled by hardware during a world switch:
308662306a36Sopenharmony_ci	 *
308762306a36Sopenharmony_ci	 * A: VMRUN:   Host state saved in host save area
308862306a36Sopenharmony_ci	 *    VMEXIT:  Host state loaded from host save area
308962306a36Sopenharmony_ci	 *
309062306a36Sopenharmony_ci	 * B: VMRUN:   Host state _NOT_ saved in host save area
309162306a36Sopenharmony_ci	 *    VMEXIT:  Host state loaded from host save area
309262306a36Sopenharmony_ci	 *
309362306a36Sopenharmony_ci	 * C: VMRUN:   Host state _NOT_ saved in host save area
309462306a36Sopenharmony_ci	 *    VMEXIT:  Host state initialized to default(reset) values
309562306a36Sopenharmony_ci	 *
309662306a36Sopenharmony_ci	 * Manually save type-B state, i.e. state that is loaded by VMEXIT but
309762306a36Sopenharmony_ci	 * isn't saved by VMRUN, that isn't already saved by VMSAVE (performed
309862306a36Sopenharmony_ci	 * by common SVM code).
309962306a36Sopenharmony_ci	 */
310062306a36Sopenharmony_ci	hostsa->xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
310162306a36Sopenharmony_ci	hostsa->pkru = read_pkru();
310262306a36Sopenharmony_ci	hostsa->xss = host_xss;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	/*
310562306a36Sopenharmony_ci	 * If DebugSwap is enabled, debug registers are loaded but NOT saved by
310662306a36Sopenharmony_ci	 * the CPU (Type-B). If DebugSwap is disabled/unsupported, the CPU both
310762306a36Sopenharmony_ci	 * saves and loads debug registers (Type-A).
310862306a36Sopenharmony_ci	 */
310962306a36Sopenharmony_ci	if (sev_es_debug_swap_enabled) {
311062306a36Sopenharmony_ci		hostsa->dr0 = native_get_debugreg(0);
311162306a36Sopenharmony_ci		hostsa->dr1 = native_get_debugreg(1);
311262306a36Sopenharmony_ci		hostsa->dr2 = native_get_debugreg(2);
311362306a36Sopenharmony_ci		hostsa->dr3 = native_get_debugreg(3);
311462306a36Sopenharmony_ci		hostsa->dr0_addr_mask = amd_get_dr_addr_mask(0);
311562306a36Sopenharmony_ci		hostsa->dr1_addr_mask = amd_get_dr_addr_mask(1);
311662306a36Sopenharmony_ci		hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2);
311762306a36Sopenharmony_ci		hostsa->dr3_addr_mask = amd_get_dr_addr_mask(3);
311862306a36Sopenharmony_ci	}
311962306a36Sopenharmony_ci}
312062306a36Sopenharmony_ci
312162306a36Sopenharmony_civoid sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
312262306a36Sopenharmony_ci{
312362306a36Sopenharmony_ci	struct vcpu_svm *svm = to_svm(vcpu);
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	/* First SIPI: Use the values as initially set by the VMM */
312662306a36Sopenharmony_ci	if (!svm->sev_es.received_first_sipi) {
312762306a36Sopenharmony_ci		svm->sev_es.received_first_sipi = true;
312862306a36Sopenharmony_ci		return;
312962306a36Sopenharmony_ci	}
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	/*
313262306a36Sopenharmony_ci	 * Subsequent SIPI: Return from an AP Reset Hold VMGEXIT, where
313362306a36Sopenharmony_ci	 * the guest will set the CS and RIP. Set SW_EXIT_INFO_2 to a
313462306a36Sopenharmony_ci	 * non-zero value.
313562306a36Sopenharmony_ci	 */
313662306a36Sopenharmony_ci	if (!svm->sev_es.ghcb)
313762306a36Sopenharmony_ci		return;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	ghcb_set_sw_exit_info_2(svm->sev_es.ghcb, 1);
314062306a36Sopenharmony_ci}
3141