File Index
Files and directories
Sign in
FILE

tpm_svsm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/char/tpm/tpm_svsm.c 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
 24struct tpm_svsm_priv {
 25	void *buffer;
 26};
 27
 28static int tpm_svsm_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz,
 29			 size_t cmd_len)
 30{
 31	struct tpm_svsm_priv *priv = dev_get_drvdata(&chip->dev);
 32	int ret;
 33
 34	ret = svsm_vtpm_cmd_request_fill(priv->buffer, 0, buf, cmd_len);
 35	if (ret)
 36		return ret;
 37
 38	/*
 39	 * The SVSM call uses the same buffer for the command and for the
 40	 * response, so after this call, the buffer will contain the response.
 41	 *
 42	 * Note: we have to use an internal buffer because the device in SVSM
 43	 * expects the svsm_vtpm header + data to be physically contiguous.
 44	 */
 45	ret = snp_svsm_vtpm_send_command(priv->buffer);
 46	if (ret)
 47		return ret;
 48
 49	return svsm_vtpm_cmd_response_parse(priv->buffer, buf, bufsiz);
 50}
 51
 52static struct tpm_class_ops tpm_chip_ops = {
 53	.flags = TPM_OPS_AUTO_STARTUP,
 54	.send = tpm_svsm_send,
 55};
 56
 57static int __init tpm_svsm_probe(struct platform_device *pdev)
 58{
 59	struct device *dev = &pdev->dev;
 60	struct tpm_svsm_priv *priv;
 61	struct tpm_chip *chip;
 62	int err;
 63
 64	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
 65	if (!priv)
 66		return -ENOMEM;
 67
 68	/*
 69	 * The maximum buffer supported is one page (see SVSM_VTPM_MAX_BUFFER
 70	 * in tpm_svsm.h).
 71	 */
 72	priv->buffer = (void *)devm_get_free_pages(dev, GFP_KERNEL, 0);
 73	if (!priv->buffer)
 74		return -ENOMEM;
 75
 76	chip = tpmm_chip_alloc(dev, &tpm_chip_ops);
 77	if (IS_ERR(chip))
 78		return PTR_ERR(chip);
 79
 80	dev_set_drvdata(&chip->dev, priv);
 81
 82	chip->flags |= TPM_CHIP_FLAG_SYNC;
 83	err = tpm2_probe(chip);
 84	if (err)
 85		return err;
 86
 87	err = tpm_chip_register(chip);
 88	if (err)
 89		return err;
 90
 91	dev_info(dev, "SNP SVSM vTPM %s device\n",
 92		 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2");
 93
 94	return 0;
 95}
 96
 97static void __exit tpm_svsm_remove(struct platform_device *pdev)
 98{
 99	struct tpm_chip *chip = platform_get_drvdata(pdev);
100
101	tpm_chip_unregister(chip);
102}
103
104/*
105 * tpm_svsm_remove() lives in .exit.text. For drivers registered via
106 * module_platform_driver_probe() this is ok because they cannot get unbound
107 * at runtime. So mark the driver struct with __refdata to prevent modpost
108 * triggering a section mismatch warning.
109 */
110static struct platform_driver tpm_svsm_driver __refdata = {
111	.remove = __exit_p(tpm_svsm_remove),
112	.driver = {
113		.name = "tpm-svsm",
114	},
115};
116
117module_platform_driver_probe(tpm_svsm_driver, tpm_svsm_probe);
118
119MODULE_DESCRIPTION("SNP SVSM vTPM Driver");
120MODULE_LICENSE("GPL");
121MODULE_ALIAS("platform:tpm-svsm");
~/ Read-only file preview.