Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'x86_sev_for_v6.16_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull AMD SEV update from Borislav Petkov:
"Add a virtual TPM driver glue which allows a guest kernel to talk to a
TPM device emulated by a Secure VM Service Module (SVSM) - a helper
module of sorts which runs at a different privilege level in the
SEV-SNP VM stack.

The intent being that a TPM device is emulated by a trusted entity and
not by the untrusted host which is the default assumption in the
confidential computing scenarios"

* tag 'x86_sev_for_v6.16_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/sev: Register tpm-svsm platform device
tpm: Add SNP SVSM vTPM driver
svsm: Add header with SVSM_VTPM_CMD helpers
x86/sev: Add SVSM vTPM probe/send_command functions

+360 -1
+68 -1
arch/x86/coco/sev/core.c
··· 1462 1462 return ret; 1463 1463 } 1464 1464 1465 + /** 1466 + * snp_svsm_vtpm_probe() - Probe if SVSM provides a vTPM device 1467 + * 1468 + * Check that there is SVSM and that it supports at least TPM_SEND_COMMAND 1469 + * which is the only request used so far. 1470 + * 1471 + * Return: true if the platform provides a vTPM SVSM device, false otherwise. 1472 + */ 1473 + static bool snp_svsm_vtpm_probe(void) 1474 + { 1475 + struct svsm_call call = {}; 1476 + 1477 + /* The vTPM device is available only if a SVSM is present */ 1478 + if (!snp_vmpl) 1479 + return false; 1480 + 1481 + call.caa = svsm_get_caa(); 1482 + call.rax = SVSM_VTPM_CALL(SVSM_VTPM_QUERY); 1483 + 1484 + if (svsm_perform_call_protocol(&call)) 1485 + return false; 1486 + 1487 + /* Check platform commands contains TPM_SEND_COMMAND - platform command 8 */ 1488 + return call.rcx_out & BIT_ULL(8); 1489 + } 1490 + 1491 + /** 1492 + * snp_svsm_vtpm_send_command() - Execute a vTPM operation on SVSM 1493 + * @buffer: A buffer used to both send the command and receive the response. 1494 + * 1495 + * Execute a SVSM_VTPM_CMD call as defined by 1496 + * "Secure VM Service Module for SEV-SNP Guests" Publication # 58019 Revision: 1.00 1497 + * 1498 + * All command request/response buffers have a common structure as specified by 1499 + * the following table: 1500 + * Byte Size     In/Out    Description 1501 + * Offset    (Bytes) 1502 + * 0x000     4          In        Platform command 1503 +  *                         Out       Platform command response size 1504 + * 1505 + * Each command can build upon this common request/response structure to create 1506 + * a structure specific to the command. See include/linux/tpm_svsm.h for more 1507 + * details. 1508 + * 1509 + * Return: 0 on success, -errno on failure 1510 + */ 1511 + int snp_svsm_vtpm_send_command(u8 *buffer) 1512 + { 1513 + struct svsm_call call = {}; 1514 + 1515 + call.caa = svsm_get_caa(); 1516 + call.rax = SVSM_VTPM_CALL(SVSM_VTPM_CMD); 1517 + call.rcx = __pa(buffer); 1518 + 1519 + return svsm_perform_call_protocol(&call); 1520 + } 1521 + EXPORT_SYMBOL_GPL(snp_svsm_vtpm_send_command); 1522 + 1465 1523 static struct platform_device sev_guest_device = { 1466 1524 .name = "sev-guest", 1525 + .id = -1, 1526 + }; 1527 + 1528 + static struct platform_device tpm_svsm_device = { 1529 + .name = "tpm-svsm", 1467 1530 .id = -1, 1468 1531 }; 1469 1532 ··· 1538 1475 if (platform_device_register(&sev_guest_device)) 1539 1476 return -ENODEV; 1540 1477 1541 - pr_info("SNP guest platform device initialized.\n"); 1478 + if (snp_svsm_vtpm_probe() && 1479 + platform_device_register(&tpm_svsm_device)) 1480 + return -ENODEV; 1481 + 1482 + pr_info("SNP guest platform devices initialized.\n"); 1542 1483 return 0; 1543 1484 } 1544 1485 device_initcall(snp_init_platform_device);
+7
arch/x86/include/asm/sev.h
··· 415 415 #define SVSM_ATTEST_SERVICES 0 416 416 #define SVSM_ATTEST_SINGLE_SERVICE 1 417 417 418 + #define SVSM_VTPM_CALL(x) ((2ULL << 32) | (x)) 419 + #define SVSM_VTPM_QUERY 0 420 + #define SVSM_VTPM_CMD 1 421 + 418 422 #ifdef CONFIG_AMD_MEM_ENCRYPT 419 423 420 424 extern u8 snp_vmpl; ··· 516 512 int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req, 517 513 struct snp_guest_request_ioctl *rio); 518 514 515 + int snp_svsm_vtpm_send_command(u8 *buffer); 516 + 519 517 void __init snp_secure_tsc_prepare(void); 520 518 void __init snp_secure_tsc_init(void); 521 519 ··· 589 583 static inline void snp_msg_free(struct snp_msg_desc *mdesc) { } 590 584 static inline int snp_send_guest_request(struct snp_msg_desc *mdesc, struct snp_guest_req *req, 591 585 struct snp_guest_request_ioctl *rio) { return -ENODEV; } 586 + static inline int snp_svsm_vtpm_send_command(u8 *buffer) { return -ENODEV; } 592 587 static inline void __init snp_secure_tsc_prepare(void) { } 593 588 static inline void __init snp_secure_tsc_init(void) { } 594 589
+10
drivers/char/tpm/Kconfig
··· 234 234 help 235 235 This driver proxies for firmware TPM running in TEE. 236 236 237 + config TCG_SVSM 238 + tristate "SNP SVSM vTPM interface" 239 + depends on AMD_MEM_ENCRYPT 240 + help 241 + This is a driver for the AMD SVSM vTPM protocol that a SEV-SNP guest 242 + OS can use to discover and talk to a vTPM emulated by the Secure VM 243 + Service Module (SVSM) in the guest context, but at a more privileged 244 + level (usually VMPL0). To compile this driver as a module, choose M 245 + here; the module will be called tpm_svsm. 246 + 237 247 source "drivers/char/tpm/st33zp24/Kconfig" 238 248 endif # TCG_TPM
+1
drivers/char/tpm/Makefile
··· 45 45 obj-$(CONFIG_TCG_ARM_CRB_FFA) += tpm_crb_ffa.o 46 46 obj-$(CONFIG_TCG_VTPM_PROXY) += tpm_vtpm_proxy.o 47 47 obj-$(CONFIG_TCG_FTPM_TEE) += tpm_ftpm_tee.o 48 + obj-$(CONFIG_TCG_SVSM) += tpm_svsm.o
+125
drivers/char/tpm/tpm_svsm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. 4 + * 5 + * Driver for the vTPM defined by the AMD SVSM spec [1]. 6 + * 7 + * The specification defines a protocol that a SEV-SNP guest OS can use to 8 + * discover and talk to a vTPM emulated by the Secure VM Service Module (SVSM) 9 + * in the guest context, but at a more privileged level (usually VMPL0). 10 + * 11 + * [1] "Secure VM Service Module for SEV-SNP Guests" 12 + * Publication # 58019 Revision: 1.00 13 + */ 14 + 15 + #include <linux/module.h> 16 + #include <linux/kernel.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/tpm_svsm.h> 19 + 20 + #include <asm/sev.h> 21 + 22 + #include "tpm.h" 23 + 24 + struct tpm_svsm_priv { 25 + void *buffer; 26 + }; 27 + 28 + static int tpm_svsm_send(struct tpm_chip *chip, u8 *buf, size_t len) 29 + { 30 + struct tpm_svsm_priv *priv = dev_get_drvdata(&chip->dev); 31 + int ret; 32 + 33 + ret = svsm_vtpm_cmd_request_fill(priv->buffer, 0, buf, len); 34 + if (ret) 35 + return ret; 36 + 37 + /* 38 + * The SVSM call uses the same buffer for the command and for the 39 + * response, so after this call, the buffer will contain the response 40 + * that can be used by .recv() op. 41 + */ 42 + return snp_svsm_vtpm_send_command(priv->buffer); 43 + } 44 + 45 + static int tpm_svsm_recv(struct tpm_chip *chip, u8 *buf, size_t len) 46 + { 47 + struct tpm_svsm_priv *priv = dev_get_drvdata(&chip->dev); 48 + 49 + /* 50 + * The internal buffer contains the response after we send the command 51 + * to SVSM. 52 + */ 53 + return svsm_vtpm_cmd_response_parse(priv->buffer, buf, len); 54 + } 55 + 56 + static struct tpm_class_ops tpm_chip_ops = { 57 + .flags = TPM_OPS_AUTO_STARTUP, 58 + .recv = tpm_svsm_recv, 59 + .send = tpm_svsm_send, 60 + }; 61 + 62 + static int __init tpm_svsm_probe(struct platform_device *pdev) 63 + { 64 + struct device *dev = &pdev->dev; 65 + struct tpm_svsm_priv *priv; 66 + struct tpm_chip *chip; 67 + int err; 68 + 69 + priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); 70 + if (!priv) 71 + return -ENOMEM; 72 + 73 + /* 74 + * The maximum buffer supported is one page (see SVSM_VTPM_MAX_BUFFER 75 + * in tpm_svsm.h). 76 + */ 77 + priv->buffer = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0); 78 + if (!priv->buffer) 79 + return -ENOMEM; 80 + 81 + chip = tpmm_chip_alloc(dev, &tpm_chip_ops); 82 + if (IS_ERR(chip)) 83 + return PTR_ERR(chip); 84 + 85 + dev_set_drvdata(&chip->dev, priv); 86 + 87 + err = tpm2_probe(chip); 88 + if (err) 89 + return err; 90 + 91 + err = tpm_chip_register(chip); 92 + if (err) 93 + return err; 94 + 95 + dev_info(dev, "SNP SVSM vTPM %s device\n", 96 + (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2"); 97 + 98 + return 0; 99 + } 100 + 101 + static void __exit tpm_svsm_remove(struct platform_device *pdev) 102 + { 103 + struct tpm_chip *chip = platform_get_drvdata(pdev); 104 + 105 + tpm_chip_unregister(chip); 106 + } 107 + 108 + /* 109 + * tpm_svsm_remove() lives in .exit.text. For drivers registered via 110 + * module_platform_driver_probe() this is ok because they cannot get unbound 111 + * at runtime. So mark the driver struct with __refdata to prevent modpost 112 + * triggering a section mismatch warning. 113 + */ 114 + static struct platform_driver tpm_svsm_driver __refdata = { 115 + .remove = __exit_p(tpm_svsm_remove), 116 + .driver = { 117 + .name = "tpm-svsm", 118 + }, 119 + }; 120 + 121 + module_platform_driver_probe(tpm_svsm_driver, tpm_svsm_probe); 122 + 123 + MODULE_DESCRIPTION("SNP SVSM vTPM Driver"); 124 + MODULE_LICENSE("GPL"); 125 + MODULE_ALIAS("platform:tpm-svsm");
+149
include/linux/tpm_svsm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2023 James.Bottomley@HansenPartnership.com 4 + * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. 5 + * 6 + * Helpers for the SVSM_VTPM_CMD calls used by the vTPM protocol defined by the 7 + * AMD SVSM spec [1]. 8 + * 9 + * The vTPM protocol follows the Official TPM 2.0 Reference Implementation 10 + * (originally by Microsoft, now part of the TCG) simulator protocol. 11 + * 12 + * [1] "Secure VM Service Module for SEV-SNP Guests" 13 + * Publication # 58019 Revision: 1.00 14 + */ 15 + #ifndef _TPM_SVSM_H_ 16 + #define _TPM_SVSM_H_ 17 + 18 + #include <linux/errno.h> 19 + #include <linux/string.h> 20 + #include <linux/types.h> 21 + 22 + #define SVSM_VTPM_MAX_BUFFER 4096 /* max req/resp buffer size */ 23 + 24 + /** 25 + * struct svsm_vtpm_request - Generic request for single word command 26 + * @cmd: The command to send 27 + * 28 + * Defined by AMD SVSM spec [1] in section "8.2 SVSM_VTPM_CMD Call" - 29 + * Table 15: vTPM Common Request/Response Structure 30 + * Byte Size     In/Out    Description 31 + * Offset    (Bytes) 32 + * 0x000     4          In        Platform command 33 +  *                         Out       Platform command response size 34 + */ 35 + struct svsm_vtpm_request { 36 + u32 cmd; 37 + }; 38 + 39 + /** 40 + * struct svsm_vtpm_response - Generic response 41 + * @size: The response size (zero if nothing follows) 42 + * 43 + * Defined by AMD SVSM spec [1] in section "8.2 SVSM_VTPM_CMD Call" - 44 + * Table 15: vTPM Common Request/Response Structure 45 + * Byte Size     In/Out    Description 46 + * Offset    (Bytes) 47 + * 0x000     4          In        Platform command 48 +  *                         Out       Platform command response size 49 + * 50 + * Note: most TCG Simulator commands simply return zero here with no indication 51 + * of success or failure. 52 + */ 53 + struct svsm_vtpm_response { 54 + u32 size; 55 + }; 56 + 57 + /** 58 + * struct svsm_vtpm_cmd_request - Structure for a TPM_SEND_COMMAND request 59 + * @cmd: The command to send (must be TPM_SEND_COMMAND) 60 + * @locality: The locality 61 + * @buf_size: The size of the input buffer following 62 + * @buf: A buffer of size buf_size 63 + * 64 + * Defined by AMD SVSM spec [1] in section "8.2 SVSM_VTPM_CMD Call" - 65 + * Table 16: TPM_SEND_COMMAND Request Structure 66 + * Byte Size Meaning 67 + * Offset    (Bytes) 68 + * 0x000     4          Platform command (8) 69 + * 0x004     1          Locality (must-be-0) 70 + * 0x005     4          TPM Command size (in bytes) 71 + * 0x009     Variable   TPM Command 72 + * 73 + * Note: the TCG Simulator expects @buf_size to be equal to the size of the 74 + * specific TPM command, otherwise an TPM_RC_COMMAND_SIZE error is returned. 75 + */ 76 + struct svsm_vtpm_cmd_request { 77 + u32 cmd; 78 + u8 locality; 79 + u32 buf_size; 80 + u8 buf[]; 81 + } __packed; 82 + 83 + /** 84 + * struct svsm_vtpm_cmd_response - Structure for a TPM_SEND_COMMAND response 85 + * @buf_size: The size of the output buffer following 86 + * @buf: A buffer of size buf_size 87 + * 88 + * Defined by AMD SVSM spec [1] in section "8.2 SVSM_VTPM_CMD Call" - 89 + * Table 17: TPM_SEND_COMMAND Response Structure 90 + * Byte Size Meaning 91 + * Offset    (Bytes) 92 + * 0x000     4          Response size (in bytes) 93 + * 0x004     Variable   Response 94 + */ 95 + struct svsm_vtpm_cmd_response { 96 + u32 buf_size; 97 + u8 buf[]; 98 + }; 99 + 100 + /** 101 + * svsm_vtpm_cmd_request_fill() - Fill a TPM_SEND_COMMAND request to be sent to SVSM 102 + * @req: The struct svsm_vtpm_cmd_request to fill 103 + * @locality: The locality 104 + * @buf: The buffer from where to copy the payload of the command 105 + * @len: The size of the buffer 106 + * 107 + * Return: 0 on success, negative error code on failure. 108 + */ 109 + static inline int 110 + svsm_vtpm_cmd_request_fill(struct svsm_vtpm_cmd_request *req, u8 locality, 111 + const u8 *buf, size_t len) 112 + { 113 + if (len > SVSM_VTPM_MAX_BUFFER - sizeof(*req)) 114 + return -EINVAL; 115 + 116 + req->cmd = 8; /* TPM_SEND_COMMAND */ 117 + req->locality = locality; 118 + req->buf_size = len; 119 + 120 + memcpy(req->buf, buf, len); 121 + 122 + return 0; 123 + } 124 + 125 + /** 126 + * svsm_vtpm_cmd_response_parse() - Parse a TPM_SEND_COMMAND response received from SVSM 127 + * @resp: The struct svsm_vtpm_cmd_response to parse 128 + * @buf: The buffer where to copy the response 129 + * @len: The size of the buffer 130 + * 131 + * Return: buffer size filled with the response on success, negative error 132 + * code on failure. 133 + */ 134 + static inline int 135 + svsm_vtpm_cmd_response_parse(const struct svsm_vtpm_cmd_response *resp, u8 *buf, 136 + size_t len) 137 + { 138 + if (len < resp->buf_size) 139 + return -E2BIG; 140 + 141 + if (resp->buf_size > SVSM_VTPM_MAX_BUFFER - sizeof(*resp)) 142 + return -EINVAL; // Invalid response from the platform TPM 143 + 144 + memcpy(buf, resp->buf, resp->buf_size); 145 + 146 + return resp->buf_size; 147 + } 148 + 149 + #endif /* _TPM_SVSM_H_ */