public inbox for linux-arch@vger.kernel.org
 help / color / mirror / Atom feed
From: Tianyu Lan <ltykernel@gmail.com>
To: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
	decui@microsoft.com, tglx@linutronix.de, mingo@redhat.com,
	bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
	hpa@zytor.com, arnd@arndb.de, Neeraj.Upadhyay@amd.com,
	tiala@microsoft.com, kvijayab@amd.com,
	romank@linux.microsoft.com
Cc: linux-arch@vger.kernel.org, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 5/5] x86/Hyper-V: Add Hyper-V specific hvcall to set backing page
Date: Thu, 18 Sep 2025 11:00:23 -0400	[thread overview]
Message-ID: <20250918150023.474021-6-tiala@microsoft.com> (raw)
In-Reply-To: <20250918150023.474021-1-tiala@microsoft.com>

Secure AVIC hardware provides APIC backing page
to aid the guest in limiting which interrupt
vectors can be injected into the guest. Hyper-V
introduces a new register HV_X64_REGISTER_SEV_GPA_PAGE
to notify hypervisor with APIC backing page and call
it in Secure AVIC driver.

Setting APIC backing page for APs takes place before
allocating hyperv_pcpu_input_arg and so allocate
hv_vp_early_input_arg to handle such case.

Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
Signed-off-by: Tianyu Lan <tiala@microsoft.com>
---
 arch/x86/hyperv/hv_init.c           | 24 +++++++++++++++++-
 arch/x86/hyperv/ivm.c               | 38 ++++++++++++++++++++++++++++
 arch/x86/include/asm/mshyperv.h     |  2 ++
 arch/x86/kernel/apic/x2apic_savic.c |  9 ++++++-
 include/hyperv/hvgdk_mini.h         | 39 +++++++++++++++++++++++++++++
 5 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index a38bb96c9f5e..3fa8e91cd03f 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -39,6 +39,7 @@
 void *hv_hypercall_pg;
 EXPORT_SYMBOL_GPL(hv_hypercall_pg);
 
+void *hv_vp_early_input_arg;
 union hv_ghcb * __percpu *hv_ghcb_pg;
 
 /* Storage to save the hypercall page temporarily for hibernation */
@@ -412,6 +413,7 @@ void __init hyperv_init(void)
 	u64 guest_id;
 	union hv_x64_msr_hypercall_contents hypercall_msr;
 	int cpuhp;
+	int ret;
 
 	if (x86_hyper_type != X86_HYPER_MS_HYPERV)
 		return;
@@ -419,6 +421,22 @@ void __init hyperv_init(void)
 	if (hv_common_init())
 		return;
 
+	if (cc_platform_has(CC_ATTR_SNP_SECURE_AVIC)) {
+		hv_vp_early_input_arg = kcalloc(num_possible_cpus(),
+					     PAGE_SIZE,
+					     GFP_KERNEL);
+		if (hv_vp_early_input_arg) {
+			ret = set_memory_decrypted((u64)hv_vp_early_input_arg,
+					     num_possible_cpus());
+			if (ret) {
+				kfree(hv_vp_early_input_arg);
+				goto common_free;
+			}
+		} else {
+			goto common_free;
+		}
+	}
+
 	/*
 	 * The VP assist page is useless to a TDX guest: the only use we
 	 * would have for it is lazy EOI, which can not be used with TDX.
@@ -433,7 +451,7 @@ void __init hyperv_init(void)
 		ms_hyperv.hints &= ~HV_X64_ENLIGHTENED_VMCS_RECOMMENDED;
 
 		if (!hv_isolation_type_tdx())
-			goto common_free;
+			goto free_vp_early_input_arg;
 	}
 
 	if (ms_hyperv.paravisor_present && hv_isolation_type_snp()) {
@@ -591,6 +609,10 @@ void __init hyperv_init(void)
 free_vp_assist_page:
 	kfree(hv_vp_assist_page);
 	hv_vp_assist_page = NULL;
+free_vp_early_input_arg:
+	set_memory_encrypted((u64)hv_vp_early_input_arg, num_possible_cpus());
+	kfree(hv_vp_early_input_arg);
+	hv_vp_early_input_arg = NULL;
 common_free:
 	hv_common_free();
 }
diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c
index ade6c665c97e..e69dae57730c 100644
--- a/arch/x86/hyperv/ivm.c
+++ b/arch/x86/hyperv/ivm.c
@@ -291,6 +291,44 @@ static void snp_cleanup_vmsa(struct sev_es_save_area *vmsa)
 		free_page((unsigned long)vmsa);
 }
 
+enum es_result hv_set_savic_backing_page(u64 gfn)
+{
+	u64 control = HV_HYPERCALL_REP_COMP_1 | HVCALL_SET_VP_REGISTERS;
+	struct hv_set_vp_registers_input *input
+		= hv_vp_early_input_arg + smp_processor_id() * PAGE_SIZE;
+	union hv_x64_register_sev_gpa_page value;
+	unsigned long flags;
+	int retry = 5;
+	u64 ret;
+
+	local_irq_save(flags);
+
+	value.enabled = 1;
+	value.reserved = 0;
+	value.pagenumber = gfn;
+
+	memset(input, 0, struct_size(input, element, 1));
+	input->header.partitionid = HV_PARTITION_ID_SELF;
+	input->header.vpindex = HV_VP_INDEX_SELF;
+	input->header.inputvtl = ms_hyperv.vtl;
+	input->element[0].name = HV_X64_REGISTER_SEV_AVIC_GPA;
+	input->element[0].value.reg64 = value.u64;
+
+	do {
+		ret = hv_do_hypercall(control, input, NULL);
+	} while (ret == HV_STATUS_TIME_OUT && retry--);
+
+	if (!hv_result_success(ret))
+		pr_err("Failed to set Secure AVIC backing page %llx.\n", ret);
+
+	local_irq_restore(flags);
+
+	if (hv_result_success(ret))
+		return ES_OK;
+	else
+		return ES_VMM_ERROR;
+}
+
 int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
 {
 	struct sev_es_save_area *vmsa = (struct sev_es_save_area *)
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index abc4659f5809..b140558816de 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -43,6 +43,7 @@ static inline unsigned char hv_get_nmi_reason(void)
 extern bool hyperv_paravisor_present;
 
 extern void *hv_hypercall_pg;
+extern void *hv_vp_early_input_arg;
 
 extern union hv_ghcb * __percpu *hv_ghcb_pg;
 
@@ -252,6 +253,7 @@ int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
 bool hv_ghcb_negotiate_protocol(void);
 void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason);
 int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu);
+enum es_result hv_set_savic_backing_page(u64 gfn);
 #else
 static inline bool hv_ghcb_negotiate_protocol(void) { return false; }
 static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {}
diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c
index dbc5678bc3b6..60bdb524de53 100644
--- a/arch/x86/kernel/apic/x2apic_savic.c
+++ b/arch/x86/kernel/apic/x2apic_savic.c
@@ -14,6 +14,7 @@
 
 #include <asm/apic.h>
 #include <asm/sev.h>
+#include <asm/mshyperv.h>
 
 #include "local.h"
 
@@ -342,6 +343,7 @@ static void savic_setup(void)
 	void *ap = this_cpu_ptr(savic_page);
 	enum es_result res;
 	unsigned long gpa;
+	unsigned long gfn;
 
 	/*
 	 * Before Secure AVIC is enabled, APIC MSR reads are intercepted.
@@ -350,6 +352,7 @@ static void savic_setup(void)
 	apic_set_reg(ap, APIC_ID, native_apic_msr_read(APIC_ID));
 
 	gpa = __pa(ap);
+	gfn = gpa >> PAGE_SHIFT;
 
 	/*
 	 * The NPT entry for a vCPU's APIC backing page must always be
@@ -361,7 +364,11 @@ static void savic_setup(void)
 	 * VMRUN, the hypervisor makes use of this information to make sure
 	 * the APIC backing page is mapped in NPT.
 	 */
-	res = savic_register_gpa(gpa);
+	if (hv_isolation_type_snp())
+		res = hv_set_savic_backing_page(gfn);
+	else
+		res = savic_register_gpa(gpa);
+
 	if (res != ES_OK)
 		sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SAVIC_FAIL);
 
diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h
index 1be7f6a02304..e3092469aafe 100644
--- a/include/hyperv/hvgdk_mini.h
+++ b/include/hyperv/hvgdk_mini.h
@@ -1170,6 +1170,28 @@ union hv_register_value {
 	union hv_arm64_pending_synthetic_exception_event pending_synthetic_exception_event;
 };
 
+/* HvSetVpRegisters hypercall with variable size reg name/value list*/
+struct hv_set_vp_registers_input {
+	struct {
+		u64 partitionid;
+		u32 vpindex;
+		u8  inputvtl;
+		u8  padding[3];
+	} header;
+	struct {
+		u32 name;
+		u32 padding1;
+		u64 padding2;
+		union {
+			union hv_register_value value;
+			struct {
+				u64 valuelow;
+				u64 valuehigh;
+			};
+		};
+	} element[];
+} __packed;
+
 /* NOTE: Linux helper struct - NOT from Hyper-V code. */
 struct hv_output_get_vp_registers {
 	DECLARE_FLEX_ARRAY(union hv_register_value, values);
@@ -1210,6 +1232,15 @@ struct hv_input_get_vp_registers {
 	u32 names[];
 } __packed;
 
+union hv_x64_register_sev_gpa_page {
+	u64 u64;
+	struct {
+		u64 enabled:1;
+		u64 reserved:11;
+		u64 pagenumber:52;
+	};
+} __packed;
+
 struct hv_input_set_vp_registers {
 	u64 partition_id;
 	u32 vp_index;
@@ -1230,6 +1261,14 @@ struct hv_send_ipi {	 /* HV_INPUT_SEND_SYNTHETIC_CLUSTER_IPI */
 
 #define	HV_VTL_MASK			GENMASK(3, 0)
 
+/*
+ * Registers are only accessible via HVCALL_GET_VP_REGISTERS hvcall and
+ * there is not associated MSR address.
+ */
+#define	HV_X64_REGISTER_VSM_VP_STATUS	0x000D0003
+#define	HV_X64_VTL_MASK			GENMASK(3, 0)
+#define	HV_X64_REGISTER_SEV_AVIC_GPA    0x00090043
+
 /* Hyper-V memory host visibility */
 enum hv_mem_host_visibility {
 	VMBUS_PAGE_NOT_VISIBLE		= 0,
-- 
2.25.1


  parent reply	other threads:[~2025-09-18 15:01 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-18 15:00 [PATCH 0/5] x86/Hyper-V: Add AMD Secure AVIC for Hyper-V platform Tianyu Lan
2025-09-18 15:00 ` [PATCH 1/5] x86/hyperv: Don't use hv apic driver when Secure AVIC is available Tianyu Lan
2025-09-18 15:00 ` [PATCH 2/5] drivers: hv: Allow vmbus message synic interrupt injected from Hyper-V Tianyu Lan
2025-09-18 15:00 ` [PATCH 3/5] x86/hyperv: Don't use auto-eoi when Secure AVIC is available Tianyu Lan
2025-09-18 15:00 ` [PATCH 4/5] x86/hyperv: Allow Hyper-V to inject STIMER0 interrupts Tianyu Lan
2025-09-18 15:00 ` Tianyu Lan [this message]
2025-09-18 15:09   ` [PATCH 5/5] x86/Hyper-V: Add Hyper-V specific hvcall to set backing page Borislav Petkov
2025-09-18 17:11     ` Tianyu Lan
2025-09-18 19:59       ` Borislav Petkov
2025-09-30 23:05 ` [PATCH 0/5] x86/Hyper-V: Add AMD Secure AVIC for Hyper-V platform Wei Liu
2025-10-13 17:18   ` Wei Liu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250918150023.474021-6-tiala@microsoft.com \
    --to=ltykernel@gmail.com \
    --cc=Neeraj.Upadhyay@amd.com \
    --cc=arnd@arndb.de \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=decui@microsoft.com \
    --cc=haiyangz@microsoft.com \
    --cc=hpa@zytor.com \
    --cc=kvijayab@amd.com \
    --cc=kys@microsoft.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=romank@linux.microsoft.com \
    --cc=tglx@linutronix.de \
    --cc=tiala@microsoft.com \
    --cc=wei.liu@kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox