linux/drivers/virt/coco/sev-guest/sev-guest.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * AMD Secure Encrypted Virtualization (SEV) guest driver interface
 *
 * Copyright (C) 2021-2024 Advanced Micro Devices, Inc.
 *
 * Author: Brijesh Singh <[email protected]>
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/set_memory.h>
#include <linux/fs.h>
#include <linux/tsm.h>
#include <crypto/aead.h>
#include <linux/scatterlist.h>
#include <linux/psp-sev.h>
#include <linux/sockptr.h>
#include <linux/cleanup.h>
#include <linux/uuid.h>
#include <linux/configfs.h>
#include <uapi/linux/sev-guest.h>
#include <uapi/linux/psp-sev.h>

#include <asm/svm.h>
#include <asm/sev.h>

#define DEVICE_NAME
#define AAD_LEN
#define MSG_HDR_VER

#define SNP_REQ_MAX_RETRY_DURATION
#define SNP_REQ_RETRY_DELAY

#define SVSM_MAX_RETRIES

struct snp_guest_crypto {};

struct snp_guest_dev {};

/*
 * The VMPCK ID represents the key used by the SNP guest to communicate with the
 * SEV firmware in the AMD Secure Processor (ASP, aka PSP). By default, the key
 * used will be the key associated with the VMPL at which the guest is running.
 * Should the default key be wiped (see snp_disable_vmpck()), this parameter
 * allows for using one of the remaining VMPCKs.
 */
static int vmpck_id =;
module_param(vmpck_id, int, 0444);
MODULE_PARM_DESC();

/* Mutex to serialize the shared buffer access and command handling. */
static DEFINE_MUTEX(snp_cmd_mutex);

static bool is_vmpck_empty(struct snp_guest_dev *snp_dev)
{}

/*
 * If an error is received from the host or AMD Secure Processor (ASP) there
 * are two options. Either retry the exact same encrypted request or discontinue
 * using the VMPCK.
 *
 * This is because in the current encryption scheme GHCB v2 uses AES-GCM to
 * encrypt the requests. The IV for this scheme is the sequence number. GCM
 * cannot tolerate IV reuse.
 *
 * The ASP FW v1.51 only increments the sequence numbers on a successful
 * guest<->ASP back and forth and only accepts messages at its exact sequence
 * number.
 *
 * So if the sequence number were to be reused the encryption scheme is
 * vulnerable. If the sequence number were incremented for a fresh IV the ASP
 * will reject the request.
 */
static void snp_disable_vmpck(struct snp_guest_dev *snp_dev)
{}

static inline u64 __snp_get_msg_seqno(struct snp_guest_dev *snp_dev)
{}

/* Return a non-zero on success */
static u64 snp_get_msg_seqno(struct snp_guest_dev *snp_dev)
{}

static void snp_inc_msg_seqno(struct snp_guest_dev *snp_dev)
{}

static inline struct snp_guest_dev *to_snp_dev(struct file *file)
{}

static struct snp_guest_crypto *init_crypto(struct snp_guest_dev *snp_dev, u8 *key, size_t keylen)
{}

static void deinit_crypto(struct snp_guest_crypto *crypto)
{}

static int enc_dec_message(struct snp_guest_crypto *crypto, struct snp_guest_msg *msg,
			   u8 *src_buf, u8 *dst_buf, size_t len, bool enc)
{}

static int __enc_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg,
			 void *plaintext, size_t len)
{}

static int dec_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg,
		       void *plaintext, size_t len)
{}

static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, u32 sz)
{}

static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 type,
			void *payload, size_t sz)
{}

static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code,
				  struct snp_guest_request_ioctl *rio)
{}

static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code,
				struct snp_guest_request_ioctl *rio, u8 type,
				void *req_buf, size_t req_sz, void *resp_buf,
				u32 resp_sz)
{}

struct snp_req_resp {};

static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
{}

static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg)
{}

static int get_ext_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_ioctl *arg,
			  struct snp_req_resp *io)

{}

static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
{}

static void free_shared_pages(void *buf, size_t sz)
{}

static void *alloc_shared_pages(struct device *dev, size_t sz)
{}

static const struct file_operations snp_guest_fops =;

static u8 *get_vmpck(int id, struct snp_secrets_page *secrets, u32 **seqno)
{}

struct snp_msg_report_resp_hdr {};

struct snp_msg_cert_entry {};

static int sev_svsm_report_new(struct tsm_report *report, void *data)
{}

static int sev_report_new(struct tsm_report *report, void *data)
{}

static bool sev_report_attr_visible(int n)
{}

static bool sev_report_bin_attr_visible(int n)
{}

static struct tsm_ops sev_tsm_ops =;

static void unregister_sev_tsm(void *data)
{}

static int __init sev_guest_probe(struct platform_device *pdev)
{}

static void __exit sev_guest_remove(struct platform_device *pdev)
{}

/*
 * This driver is meant to be a common SEV guest interface driver and to
 * support any SEV guest API. As such, even though it has been introduced
 * with the SEV-SNP support, it is named "sev-guest".
 *
 * sev_guest_remove() lives in .exit.text. For drivers registered via
 * module_platform_driver_probe() this is ok because they cannot get unbound
 * at runtime. So mark the driver struct with __refdata to prevent modpost
 * triggering a section mismatch warning.
 */
static struct platform_driver sev_guest_driver __refdata =;

module_platform_driver_probe();

MODULE_AUTHOR();
MODULE_LICENSE();
MODULE_VERSION();
MODULE_DESCRIPTION();
MODULE_ALIAS();