kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Nikunj A Dadhania <nikunj@amd.com>
To: <linux-kernel@vger.kernel.org>, <thomas.lendacky@amd.com>,
	<x86@kernel.org>, <kvm@vger.kernel.org>
Cc: <bp@alien8.de>, <mingo@redhat.com>, <tglx@linutronix.de>,
	<dave.hansen@linux.intel.com>, <dionnaglaze@google.com>,
	<pgonda@google.com>, <seanjc@google.com>, <pbonzini@redhat.com>,
	<nikunj@amd.com>
Subject: [PATCH v7 10/16] x86/sev: Add Secure TSC support for SNP guests
Date: Wed, 20 Dec 2023 20:43:52 +0530	[thread overview]
Message-ID: <20231220151358.2147066-11-nikunj@amd.com> (raw)
In-Reply-To: <20231220151358.2147066-1-nikunj@amd.com>

Add support for Secure TSC in SNP enabled guests. Secure TSC allows
guest to securely use RDTSC/RDTSCP instructions as the parameters
being used cannot be changed by hypervisor once the guest is launched.

During the boot-up of the secondary cpus, SecureTSC enabled guests
need to query TSC info from AMD Security Processor. This communication
channel is encrypted between the AMD Security Processor and the guest,
the hypervisor is just the conduit to deliver the guest messages to
the AMD Security Processor. Each message is protected with an
AEAD (AES-256 GCM). Use minimal AES GCM library to encrypt/decrypt SNP
Guest messages to communicate with the PSP.

Use the guest enc_init hook to fetch SNP TSC info from the AMD Security
Processor and initialize the snp_tsc_scale and snp_tsc_offset. During
secondary CPU initialization set VMSA fields GUEST_TSC_SCALE (offset 2F0h)
and GUEST_TSC_OFFSET(offset 2F8h) with snp_tsc_scale and snp_tsc_offset
respectively.

Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
Tested-by: Peter Gonda <pgonda@google.com>
---
 arch/x86/include/asm/sev-common.h |   1 +
 arch/x86/include/asm/sev-guest.h  |  20 ++++++
 arch/x86/include/asm/sev.h        |   2 +
 arch/x86/include/asm/svm.h        |   6 +-
 arch/x86/kernel/sev.c             | 107 ++++++++++++++++++++++++++++--
 arch/x86/mm/mem_encrypt_amd.c     |   6 ++
 6 files changed, 133 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h
index b463fcbd4b90..6adc8e27feeb 100644
--- a/arch/x86/include/asm/sev-common.h
+++ b/arch/x86/include/asm/sev-common.h
@@ -159,6 +159,7 @@ struct snp_psc_desc {
 #define GHCB_TERM_NOT_VMPL0		3	/* SNP guest is not running at VMPL-0 */
 #define GHCB_TERM_CPUID			4	/* CPUID-validation failure */
 #define GHCB_TERM_CPUID_HV		5	/* CPUID failure during hypervisor fallback */
+#define GHCB_TERM_SECURE_TSC		6	/* Secure TSC initialization failed */
 
 #define GHCB_RESP_CODE(v)		((v) & GHCB_MSR_INFO_MASK)
 
diff --git a/arch/x86/include/asm/sev-guest.h b/arch/x86/include/asm/sev-guest.h
index ed5c158ec29b..c82c78571020 100644
--- a/arch/x86/include/asm/sev-guest.h
+++ b/arch/x86/include/asm/sev-guest.h
@@ -39,6 +39,8 @@ enum msg_type {
 	SNP_MSG_ABSORB_RSP,
 	SNP_MSG_VMRK_REQ,
 	SNP_MSG_VMRK_RSP,
+	SNP_MSG_TSC_INFO_REQ = 17,
+	SNP_MSG_TSC_INFO_RSP,
 
 	SNP_MSG_TYPE_MAX
 };
@@ -83,6 +85,23 @@ struct sev_guest_platform_data {
 	struct snp_req_data input;
 };
 
+#define SNP_TSC_INFO_REQ_SZ 128
+
+struct snp_tsc_info_req {
+	/* Must be zero filled */
+	u8 rsvd[SNP_TSC_INFO_REQ_SZ];
+} __packed;
+
+struct snp_tsc_info_resp {
+	/* Status of TSC_INFO message */
+	u32 status;
+	u32 rsvd1;
+	u64 tsc_scale;
+	u64 tsc_offset;
+	u32 tsc_factor;
+	u8 rsvd2[100];
+} __packed;
+
 struct snp_guest_dev {
 	struct device *dev;
 	struct miscdevice misc;
@@ -102,6 +121,7 @@ struct snp_guest_dev {
 		struct snp_report_req report;
 		struct snp_derived_key_req derived_key;
 		struct snp_ext_report_req ext_report;
+		struct snp_tsc_info_req tsc_info;
 	} req;
 	unsigned int vmpck_id;
 };
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index f8377b49b88d..880cfee3c3ad 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -201,6 +201,7 @@ void __init __noreturn snp_abort(void);
 void snp_accept_memory(phys_addr_t start, phys_addr_t end);
 u64 snp_get_unsupported_features(u64 status);
 u64 sev_get_status(void);
+void __init snp_secure_tsc_prepare(void);
 #else
 static inline void sev_es_ist_enter(struct pt_regs *regs) { }
 static inline void sev_es_ist_exit(void) { }
@@ -224,6 +225,7 @@ static inline void snp_abort(void) { }
 static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
 static inline u64 snp_get_unsupported_features(u64 status) { return 0; }
 static inline u64 sev_get_status(void) { return 0; }
+static inline void __init snp_secure_tsc_prepare(void) { }
 #endif
 
 #endif
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 87a7b917d30e..3a8294bbd109 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -410,7 +410,9 @@ struct sev_es_save_area {
 	u8 reserved_0x298[80];
 	u32 pkru;
 	u32 tsc_aux;
-	u8 reserved_0x2f0[24];
+	u64 tsc_scale;
+	u64 tsc_offset;
+	u8 reserved_0x300[8];
 	u64 rcx;
 	u64 rdx;
 	u64 rbx;
@@ -542,7 +544,7 @@ static inline void __unused_size_checks(void)
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x1c0);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x248);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x298);
-	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x2f0);
+	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x300);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x320);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x380);
 	BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x3f0);
diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
index 5e8afdc6af9e..1d6200b57643 100644
--- a/arch/x86/kernel/sev.c
+++ b/arch/x86/kernel/sev.c
@@ -76,6 +76,10 @@ static u64 sev_hv_features __ro_after_init;
 /* Secrets page physical address from the CC blob */
 static u64 secrets_pa __ro_after_init;
 
+/* Secure TSC values read using TSC_INFO SNP Guest request */
+static u64 snp_tsc_scale __ro_after_init;
+static u64 snp_tsc_offset __ro_after_init;
+
 /* #VC handler runtime per-CPU data */
 struct sev_es_runtime_data {
 	struct ghcb ghcb_page;
@@ -957,6 +961,83 @@ void snp_guest_cmd_unlock(void)
 }
 EXPORT_SYMBOL_GPL(snp_guest_cmd_unlock);
 
+static struct snp_guest_dev tsc_snp_dev __initdata;
+
+static int __snp_send_guest_request(struct snp_guest_dev *snp_dev, struct snp_guest_req *req,
+				    struct snp_guest_request_ioctl *rio);
+
+static int __init snp_get_tsc_info(void)
+{
+	struct snp_tsc_info_req *tsc_req = &tsc_snp_dev.req.tsc_info;
+	static u8 buf[SNP_TSC_INFO_REQ_SZ + AUTHTAG_LEN];
+	struct snp_guest_request_ioctl rio;
+	struct snp_tsc_info_resp tsc_resp;
+	struct snp_guest_req req;
+	int rc, resp_len;
+
+	/*
+	 * The intermediate response buffer is used while decrypting the
+	 * response payload. Make sure that it has enough space to cover the
+	 * authtag.
+	 */
+	resp_len = sizeof(tsc_resp) + AUTHTAG_LEN;
+	if (sizeof(buf) < resp_len)
+		return -EINVAL;
+
+	memset(tsc_req, 0, sizeof(*tsc_req));
+	memset(&req, 0, sizeof(req));
+	memset(&rio, 0, sizeof(rio));
+	memset(buf, 0, sizeof(buf));
+
+	if (!snp_assign_vmpck(&tsc_snp_dev, 0))
+		return -EINVAL;
+
+	/* Initialize the PSP channel to send snp messages */
+	rc = snp_setup_psp_messaging(&tsc_snp_dev);
+	if (rc)
+		return rc;
+
+	req.msg_version = MSG_HDR_VER;
+	req.msg_type = SNP_MSG_TSC_INFO_REQ;
+	req.vmpck_id = tsc_snp_dev.vmpck_id;
+	req.req_buf = tsc_req;
+	req.req_sz = sizeof(*tsc_req);
+	req.resp_buf = buf;
+	req.resp_sz = resp_len;
+	req.exit_code = SVM_VMGEXIT_GUEST_REQUEST;
+
+	rc = __snp_send_guest_request(&tsc_snp_dev, &req, &rio);
+	if (rc)
+		goto err_req;
+
+	memcpy(&tsc_resp, buf, sizeof(tsc_resp));
+	pr_debug("%s: Valid response status %x scale %llx offset %llx factor %x\n",
+		 __func__, tsc_resp.status, tsc_resp.tsc_scale, tsc_resp.tsc_offset,
+		 tsc_resp.tsc_factor);
+
+	snp_tsc_scale = tsc_resp.tsc_scale;
+	snp_tsc_offset = tsc_resp.tsc_offset;
+
+err_req:
+	/* The response buffer contains the sensitive data, explicitly clear it. */
+	memzero_explicit(buf, sizeof(buf));
+	memzero_explicit(&tsc_resp, sizeof(tsc_resp));
+	memzero_explicit(&req, sizeof(req));
+
+	return rc;
+}
+
+void __init snp_secure_tsc_prepare(void)
+{
+	if (!cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC))
+		return;
+
+	if (snp_get_tsc_info())
+		sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SECURE_TSC);
+
+	pr_debug("SecureTSC enabled\n");
+}
+
 static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
 {
 	struct sev_es_save_area *cur_vmsa, *vmsa;
@@ -1057,6 +1138,12 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
 	vmsa->vmpl		= 0;
 	vmsa->sev_features	= sev_status >> 2;
 
+	/* Setting Secure TSC parameters */
+	if (cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC)) {
+		vmsa->tsc_scale = snp_tsc_scale;
+		vmsa->tsc_offset = snp_tsc_offset;
+	}
+
 	/* Switch the page over to a VMSA page now that it is initialized */
 	ret = snp_set_vmsa(vmsa, true);
 	if (ret) {
@@ -2632,18 +2719,13 @@ static int __handle_guest_request(struct snp_guest_dev *snp_dev, struct snp_gues
 	return rc;
 }
 
-int snp_send_guest_request(struct snp_guest_dev *snp_dev, struct snp_guest_req *req,
-			   struct snp_guest_request_ioctl *rio)
+static int __snp_send_guest_request(struct snp_guest_dev *snp_dev, struct snp_guest_req *req,
+				    struct snp_guest_request_ioctl *rio)
 {
 	struct sev_guest_platform_data *pdata;
 	u64 seqno;
 	int rc;
 
-	if (!snp_dev || !snp_dev->pdata || !req || !rio)
-		return -ENODEV;
-
-	lockdep_assert_held(&snp_guest_cmd_mutex);
-
 	pdata = snp_dev->pdata;
 
 	/* Get message sequence and verify that its a non-zero */
@@ -2686,6 +2768,17 @@ int snp_send_guest_request(struct snp_guest_dev *snp_dev, struct snp_guest_req *
 
 	return 0;
 }
+
+int snp_send_guest_request(struct snp_guest_dev *snp_dev, struct snp_guest_req *req,
+			   struct snp_guest_request_ioctl *rio)
+{
+	if (!snp_dev || !snp_dev->pdata || !req || !rio)
+		return -ENODEV;
+
+	lockdep_assert_held(&snp_guest_cmd_mutex);
+
+	return __snp_send_guest_request(snp_dev, req, rio);
+}
 EXPORT_SYMBOL_GPL(snp_send_guest_request);
 
 bool snp_assign_vmpck(struct snp_guest_dev *dev, unsigned int vmpck_id)
diff --git a/arch/x86/mm/mem_encrypt_amd.c b/arch/x86/mm/mem_encrypt_amd.c
index 70b91de2e053..c81b57ca03b6 100644
--- a/arch/x86/mm/mem_encrypt_amd.c
+++ b/arch/x86/mm/mem_encrypt_amd.c
@@ -214,6 +214,11 @@ void __init sme_map_bootdata(char *real_mode_data)
 	__sme_early_map_unmap_mem(__va(cmdline_paddr), COMMAND_LINE_SIZE, true);
 }
 
+static void __init amd_enc_init(void)
+{
+	snp_secure_tsc_prepare();
+}
+
 static unsigned long pg_level_to_pfn(int level, pte_t *kpte, pgprot_t *ret_prot)
 {
 	unsigned long pfn = 0;
@@ -467,6 +472,7 @@ void __init sme_early_init(void)
 	x86_platform.guest.enc_status_change_finish  = amd_enc_status_change_finish;
 	x86_platform.guest.enc_tlb_flush_required    = amd_enc_tlb_flush_required;
 	x86_platform.guest.enc_cache_flush_required  = amd_enc_cache_flush_required;
+	x86_platform.guest.enc_init                  = amd_enc_init;
 
 	/*
 	 * AMD-SEV-ES intercepts the RDMSR to read the X2APIC ID in the
-- 
2.34.1


  parent reply	other threads:[~2023-12-20 15:15 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-20 15:13 [PATCH v7 00/16] Add Secure TSC support for SNP guests Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 01/16] virt: sev-guest: Use AES GCM crypto library Nikunj A Dadhania
2024-01-25 10:36   ` Borislav Petkov
2024-01-27  3:54     ` Nikunj A. Dadhania
2023-12-20 15:13 ` [PATCH v7 02/16] virt: sev-guest: Replace dev_dbg with pr_debug Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 03/16] virt: sev-guest: Add SNP guest request structure Nikunj A Dadhania
2024-01-25 11:59   ` Borislav Petkov
2024-01-27  4:01     ` Nikunj A. Dadhania
2024-01-31 13:58     ` Nikunj A. Dadhania
2024-02-01 10:29       ` Borislav Petkov
2024-02-01 11:10         ` Nikunj A. Dadhania
2024-02-01 14:07           ` Borislav Petkov
2024-02-02  3:50             ` Nikunj A. Dadhania
2024-02-02 16:14               ` Borislav Petkov
2024-02-05  9:23                 ` Nikunj A. Dadhania
2024-02-06 10:04                   ` Borislav Petkov
2024-01-26 21:16   ` Tom Lendacky
2024-01-27  4:05     ` Nikunj A. Dadhania
2023-12-20 15:13 ` [PATCH v7 04/16] virt: sev-guest: Add vmpck_id to snp_guest_dev struct Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 05/16] x86/sev: Cache the secrets page address Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 06/16] virt: sev-guest: Move SNP Guest command mutex Nikunj A Dadhania
2024-01-26 22:11   ` Tom Lendacky
2024-01-27  4:06     ` Nikunj A. Dadhania
2023-12-20 15:13 ` [PATCH v7 07/16] x86/sev: Move and reorganize sev guest request api Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 08/16] x86/mm: Add generic guest initialization hook Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 09/16] x86/cpufeatures: Add synthetic Secure TSC bit Nikunj A Dadhania
2023-12-20 15:13 ` Nikunj A Dadhania [this message]
2024-02-01 15:46   ` [PATCH v7 10/16] x86/sev: Add Secure TSC support for SNP guests Paolo Bonzini
2024-02-01 15:48     ` Paolo Bonzini
2023-12-20 15:13 ` [PATCH v7 11/16] x86/sev: Change TSC MSR behavior for Secure TSC enabled guests Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 12/16] x86/sev: Prevent RDTSC/RDTSCP interception " Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 13/16] x86/kvmclock: Skip kvmclock when Secure TSC is available Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 14/16] x86/sev: Mark Secure TSC as reliable Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 15/16] x86/cpu/amd: Do not print FW_BUG for Secure TSC Nikunj A Dadhania
2023-12-20 15:13 ` [PATCH v7 16/16] x86/sev: Enable Secure TSC for SNP guests Nikunj A Dadhania
2024-01-25  6:08 ` [PATCH v7 00/16] Add Secure TSC support " Nikunj A. Dadhania
2024-01-26  1:00   ` Dionna Amalie Glaze
2024-01-27  4:10     ` Nikunj A. Dadhania

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=20231220151358.2147066-11-nikunj@amd.com \
    --to=nikunj@amd.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=dionnaglaze@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=pgonda@google.com \
    --cc=seanjc@google.com \
    --cc=tglx@linutronix.de \
    --cc=thomas.lendacky@amd.com \
    --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;
as well as URLs for NNTP newsgroup(s).