Skip to content

Commit 85b60ca

Browse files
nikunjadbp3tk0v
authored andcommitted
x86/sev: Add Secure TSC support for SNP guests
Add support for Secure TSC in SNP-enabled guests. Secure TSC allows guests to securely use RDTSC/RDTSCP instructions, ensuring that the parameters used cannot be altered by the hypervisor once the guest is launched. Secure TSC-enabled guests need to query TSC information from the AMD Security Processor. This communication channel is encrypted between the AMD Security Processor and the guest, with the hypervisor acting merely as a conduit to deliver the guest messages to the AMD Security Processor. Each message is protected with AEAD (AES-256 GCM). [ bp: Zap a stray newline over amd_cc_platform_has() while at it, simplify CC_ATTR_GUEST_SNP_SECURE_TSC check ] Signed-off-by: Nikunj A Dadhania <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 1e0b23b commit 85b60ca

File tree

7 files changed

+146
-3
lines changed

7 files changed

+146
-3
lines changed

arch/x86/coco/core.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ static __maybe_unused __always_inline bool amd_cc_platform_vtom(enum cc_attr att
6565
* up under SME the trampoline area cannot be encrypted, whereas under SEV
6666
* the trampoline area must be encrypted.
6767
*/
68-
6968
static bool noinstr amd_cc_platform_has(enum cc_attr attr)
7069
{
7170
#ifdef CONFIG_AMD_MEM_ENCRYPT
@@ -97,6 +96,9 @@ static bool noinstr amd_cc_platform_has(enum cc_attr attr)
9796
case CC_ATTR_GUEST_SEV_SNP:
9897
return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
9998

99+
case CC_ATTR_GUEST_SNP_SECURE_TSC:
100+
return sev_status & MSR_AMD64_SNP_SECURE_TSC;
101+
100102
case CC_ATTR_HOST_SEV_SNP:
101103
return cc_flags.host_sev_snp;
102104

arch/x86/coco/sev/core.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ static u64 sev_hv_features __ro_after_init;
9696
/* Secrets page physical address from the CC blob */
9797
static u64 secrets_pa __ro_after_init;
9898

99+
/*
100+
* For Secure TSC guests, the BSP fetches TSC_INFO using SNP guest messaging and
101+
* initializes snp_tsc_scale and snp_tsc_offset. These values are replicated
102+
* across the APs VMSA fields (TSC_SCALE and TSC_OFFSET).
103+
*/
104+
static u64 snp_tsc_scale __ro_after_init;
105+
static u64 snp_tsc_offset __ro_after_init;
106+
99107
/* #VC handler runtime per-CPU data */
100108
struct sev_es_runtime_data {
101109
struct ghcb ghcb_page;
@@ -1277,6 +1285,12 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
12771285
vmsa->vmpl = snp_vmpl;
12781286
vmsa->sev_features = sev_status >> 2;
12791287

1288+
/* Populate AP's TSC scale/offset to get accurate TSC values. */
1289+
if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC)) {
1290+
vmsa->tsc_scale = snp_tsc_scale;
1291+
vmsa->tsc_offset = snp_tsc_offset;
1292+
}
1293+
12801294
/* Switch the page over to a VMSA page now that it is initialized */
12811295
ret = snp_set_vmsa(vmsa, caa, apic_id, true);
12821296
if (ret) {
@@ -3126,3 +3140,96 @@ int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req
31263140
return 0;
31273141
}
31283142
EXPORT_SYMBOL_GPL(snp_send_guest_request);
3143+
3144+
static int __init snp_get_tsc_info(void)
3145+
{
3146+
struct snp_guest_request_ioctl *rio;
3147+
struct snp_tsc_info_resp *tsc_resp;
3148+
struct snp_tsc_info_req *tsc_req;
3149+
struct snp_msg_desc *mdesc;
3150+
struct snp_guest_req *req;
3151+
int rc = -ENOMEM;
3152+
3153+
tsc_req = kzalloc(sizeof(*tsc_req), GFP_KERNEL);
3154+
if (!tsc_req)
3155+
return rc;
3156+
3157+
/*
3158+
* The intermediate response buffer is used while decrypting the
3159+
* response payload. Make sure that it has enough space to cover
3160+
* the authtag.
3161+
*/
3162+
tsc_resp = kzalloc(sizeof(*tsc_resp) + AUTHTAG_LEN, GFP_KERNEL);
3163+
if (!tsc_resp)
3164+
goto e_free_tsc_req;
3165+
3166+
req = kzalloc(sizeof(*req), GFP_KERNEL);
3167+
if (!req)
3168+
goto e_free_tsc_resp;
3169+
3170+
rio = kzalloc(sizeof(*rio), GFP_KERNEL);
3171+
if (!rio)
3172+
goto e_free_req;
3173+
3174+
mdesc = snp_msg_alloc();
3175+
if (IS_ERR_OR_NULL(mdesc))
3176+
goto e_free_rio;
3177+
3178+
rc = snp_msg_init(mdesc, snp_vmpl);
3179+
if (rc)
3180+
goto e_free_mdesc;
3181+
3182+
req->msg_version = MSG_HDR_VER;
3183+
req->msg_type = SNP_MSG_TSC_INFO_REQ;
3184+
req->vmpck_id = snp_vmpl;
3185+
req->req_buf = tsc_req;
3186+
req->req_sz = sizeof(*tsc_req);
3187+
req->resp_buf = (void *)tsc_resp;
3188+
req->resp_sz = sizeof(*tsc_resp) + AUTHTAG_LEN;
3189+
req->exit_code = SVM_VMGEXIT_GUEST_REQUEST;
3190+
3191+
rc = snp_send_guest_request(mdesc, req, rio);
3192+
if (rc)
3193+
goto e_request;
3194+
3195+
pr_debug("%s: response status 0x%x scale 0x%llx offset 0x%llx factor 0x%x\n",
3196+
__func__, tsc_resp->status, tsc_resp->tsc_scale, tsc_resp->tsc_offset,
3197+
tsc_resp->tsc_factor);
3198+
3199+
if (!tsc_resp->status) {
3200+
snp_tsc_scale = tsc_resp->tsc_scale;
3201+
snp_tsc_offset = tsc_resp->tsc_offset;
3202+
} else {
3203+
pr_err("Failed to get TSC info, response status 0x%x\n", tsc_resp->status);
3204+
rc = -EIO;
3205+
}
3206+
3207+
e_request:
3208+
/* The response buffer contains sensitive data, explicitly clear it. */
3209+
memzero_explicit(tsc_resp, sizeof(*tsc_resp) + AUTHTAG_LEN);
3210+
e_free_mdesc:
3211+
snp_msg_free(mdesc);
3212+
e_free_rio:
3213+
kfree(rio);
3214+
e_free_req:
3215+
kfree(req);
3216+
e_free_tsc_resp:
3217+
kfree(tsc_resp);
3218+
e_free_tsc_req:
3219+
kfree(tsc_req);
3220+
3221+
return rc;
3222+
}
3223+
3224+
void __init snp_secure_tsc_prepare(void)
3225+
{
3226+
if (!cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC))
3227+
return;
3228+
3229+
if (snp_get_tsc_info()) {
3230+
pr_alert("Unable to retrieve Secure TSC info from ASP\n");
3231+
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_SECURE_TSC);
3232+
}
3233+
3234+
pr_debug("SecureTSC enabled");
3235+
}

arch/x86/include/asm/sev-common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ struct snp_psc_desc {
206206
#define GHCB_TERM_NO_SVSM 7 /* SVSM is not advertised in the secrets page */
207207
#define GHCB_TERM_SVSM_VMPL0 8 /* SVSM is present but has set VMPL to 0 */
208208
#define GHCB_TERM_SVSM_CAA 9 /* SVSM is present but CAA is not page aligned */
209+
#define GHCB_TERM_SECURE_TSC 10 /* Secure TSC initialization failed */
209210

210211
#define GHCB_RESP_CODE(v) ((v) & GHCB_MSR_INFO_MASK)
211212

arch/x86/include/asm/sev.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ enum msg_type {
146146
SNP_MSG_VMRK_REQ,
147147
SNP_MSG_VMRK_RSP,
148148

149+
SNP_MSG_TSC_INFO_REQ = 17,
150+
SNP_MSG_TSC_INFO_RSP,
151+
149152
SNP_MSG_TYPE_MAX
150153
};
151154

@@ -174,6 +177,21 @@ struct snp_guest_msg {
174177
u8 payload[PAGE_SIZE - sizeof(struct snp_guest_msg_hdr)];
175178
} __packed;
176179

180+
#define SNP_TSC_INFO_REQ_SZ 128
181+
182+
struct snp_tsc_info_req {
183+
u8 rsvd[SNP_TSC_INFO_REQ_SZ];
184+
} __packed;
185+
186+
struct snp_tsc_info_resp {
187+
u32 status;
188+
u32 rsvd1;
189+
u64 tsc_scale;
190+
u64 tsc_offset;
191+
u32 tsc_factor;
192+
u8 rsvd2[100];
193+
} __packed;
194+
177195
struct snp_guest_req {
178196
void *req_buf;
179197
size_t req_sz;
@@ -463,6 +481,8 @@ void snp_msg_free(struct snp_msg_desc *mdesc);
463481
int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
464482
struct snp_guest_request_ioctl *rio);
465483

484+
void __init snp_secure_tsc_prepare(void);
485+
466486
#else /* !CONFIG_AMD_MEM_ENCRYPT */
467487

468488
#define snp_vmpl 0
@@ -503,6 +523,7 @@ static inline struct snp_msg_desc *snp_msg_alloc(void) { return NULL; }
503523
static inline void snp_msg_free(struct snp_msg_desc *mdesc) { }
504524
static inline int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req,
505525
struct snp_guest_request_ioctl *rio) { return -ENODEV; }
526+
static inline void __init snp_secure_tsc_prepare(void) { }
506527

507528
#endif /* CONFIG_AMD_MEM_ENCRYPT */
508529

arch/x86/include/asm/svm.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,9 @@ struct sev_es_save_area {
417417
u8 reserved_0x298[80];
418418
u32 pkru;
419419
u32 tsc_aux;
420-
u8 reserved_0x2f0[24];
420+
u64 tsc_scale;
421+
u64 tsc_offset;
422+
u8 reserved_0x300[8];
421423
u64 rcx;
422424
u64 rdx;
423425
u64 rbx;
@@ -564,7 +566,7 @@ static inline void __unused_size_checks(void)
564566
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x1c0);
565567
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x248);
566568
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x298);
567-
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x2f0);
569+
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x300);
568570
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x320);
569571
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x380);
570572
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0x3f0);

arch/x86/mm/mem_encrypt.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ void __init mem_encrypt_init(void)
9494
/* Call into SWIOTLB to update the SWIOTLB DMA buffers */
9595
swiotlb_update_mem_attributes();
9696

97+
snp_secure_tsc_prepare();
98+
9799
print_mem_encrypt_feature_info();
98100
}
99101

include/linux/cc_platform.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ enum cc_attr {
8181
*/
8282
CC_ATTR_GUEST_SEV_SNP,
8383

84+
/**
85+
* @CC_ATTR_GUEST_SNP_SECURE_TSC: SNP Secure TSC is active.
86+
*
87+
* The platform/OS is running as a guest/virtual machine and actively
88+
* using AMD SEV-SNP Secure TSC feature.
89+
*/
90+
CC_ATTR_GUEST_SNP_SECURE_TSC,
91+
8492
/**
8593
* @CC_ATTR_HOST_SEV_SNP: AMD SNP enabled on the host.
8694
*

0 commit comments

Comments
 (0)