linux/drivers/virt/nitro_enclaves/ne_misc_dev.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2020-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 */

/**
 * DOC: Enclave lifetime management driver for Nitro Enclaves (NE).
 * Nitro is a hypervisor that has been developed by Amazon.
 */

#include <linux/anon_inodes.h>
#include <linux/capability.h>
#include <linux/cpu.h>
#include <linux/device.h>
#include <linux/file.h>
#include <linux/hugetlb.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/nitro_enclaves.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/range.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <uapi/linux/vm_sockets.h>

#include "ne_misc_dev.h"
#include "ne_pci_dev.h"

/**
 * NE_CPUS_SIZE - Size for max 128 CPUs, for now, in a cpu-list string, comma
 *		  separated. The NE CPU pool includes CPUs from a single NUMA
 *		  node.
 */
#define NE_CPUS_SIZE

/**
 * NE_EIF_LOAD_OFFSET - The offset where to copy the Enclave Image Format (EIF)
 *			image in enclave memory.
 */
#define NE_EIF_LOAD_OFFSET

/**
 * NE_MIN_ENCLAVE_MEM_SIZE - The minimum memory size an enclave can be launched
 *			     with.
 */
#define NE_MIN_ENCLAVE_MEM_SIZE

/**
 * NE_MIN_MEM_REGION_SIZE - The minimum size of an enclave memory region.
 */
#define NE_MIN_MEM_REGION_SIZE

/**
 * NE_PARENT_VM_CID - The CID for the vsock device of the primary / parent VM.
 */
#define NE_PARENT_VM_CID

static long ne_ioctl(struct file *file, unsigned int cmd, unsigned long arg);

static const struct file_operations ne_fops =;

static struct miscdevice ne_misc_dev =;

struct ne_devs ne_devs =;

/*
 * TODO: Update logic to create new sysfs entries instead of using
 * a kernel parameter e.g. if multiple sysfs files needed.
 */
static int ne_set_kernel_param(const char *val, const struct kernel_param *kp);

static const struct kernel_param_ops ne_cpu_pool_ops =;

static char ne_cpus[NE_CPUS_SIZE];
static struct kparam_string ne_cpus_arg =;

module_param_cb();
/* https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html#cpu-lists */
MODULE_PARM_DESC();

/**
 * struct ne_cpu_pool - CPU pool used for Nitro Enclaves.
 * @avail_threads_per_core:	Available full CPU cores to be dedicated to
 *				enclave(s). The cpumasks from the array, indexed
 *				by core id, contain all the threads from the
 *				available cores, that are not set for created
 *				enclave(s). The full CPU cores are part of the
 *				NE CPU pool.
 * @mutex:			Mutex for the access to the NE CPU pool.
 * @nr_parent_vm_cores :	The size of the available threads per core array.
 *				The total number of CPU cores available on the
 *				primary / parent VM.
 * @nr_threads_per_core:	The number of threads that a full CPU core has.
 * @numa_node:			NUMA node of the CPUs in the pool.
 */
struct ne_cpu_pool {};

static struct ne_cpu_pool ne_cpu_pool;

/**
 * struct ne_phys_contig_mem_regions - Contiguous physical memory regions.
 * @num:	The number of regions that currently has.
 * @regions:	The array of physical memory regions.
 */
struct ne_phys_contig_mem_regions {};

/**
 * ne_check_enclaves_created() - Verify if at least one enclave has been created.
 * @void:	No parameters provided.
 *
 * Context: Process context.
 * Return:
 * * True if at least one enclave is created.
 * * False otherwise.
 */
static bool ne_check_enclaves_created(void)
{}

/**
 * ne_setup_cpu_pool() - Set the NE CPU pool after handling sanity checks such
 *			 as not sharing CPU cores with the primary / parent VM
 *			 or not using CPU 0, which should remain available for
 *			 the primary / parent VM. Offline the CPUs from the
 *			 pool after the checks passed.
 * @ne_cpu_list:	The CPU list used for setting NE CPU pool.
 *
 * Context: Process context.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_setup_cpu_pool(const char *ne_cpu_list)
{}

/**
 * ne_teardown_cpu_pool() - Online the CPUs from the NE CPU pool and cleanup the
 *			    CPU pool.
 * @void:	No parameters provided.
 *
 * Context: Process context.
 */
static void ne_teardown_cpu_pool(void)
{}

/**
 * ne_set_kernel_param() - Set the NE CPU pool value via the NE kernel parameter.
 * @val:	NE CPU pool string value.
 * @kp :	NE kernel parameter associated with the NE CPU pool.
 *
 * Context: Process context.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_set_kernel_param(const char *val, const struct kernel_param *kp)
{}

/**
 * ne_donated_cpu() - Check if the provided CPU is already used by the enclave.
 * @ne_enclave :	Private data associated with the current enclave.
 * @cpu:		CPU to check if already used.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * True if the provided CPU is already used by the enclave.
 * * False otherwise.
 */
static bool ne_donated_cpu(struct ne_enclave *ne_enclave, unsigned int cpu)
{}

/**
 * ne_get_unused_core_from_cpu_pool() - Get the id of a full core from the
 *					NE CPU pool.
 * @void:	No parameters provided.
 *
 * Context: Process context. This function is called with the ne_enclave and
 *	    ne_cpu_pool mutexes held.
 * Return:
 * * Core id.
 * * -1 if no CPU core available in the pool.
 */
static int ne_get_unused_core_from_cpu_pool(void)
{}

/**
 * ne_set_enclave_threads_per_core() - Set the threads of the provided core in
 *				       the enclave data structure.
 * @ne_enclave :	Private data associated with the current enclave.
 * @core_id:		Core id to get its threads from the NE CPU pool.
 * @vcpu_id:		vCPU id part of the provided core.
 *
 * Context: Process context. This function is called with the ne_enclave and
 *	    ne_cpu_pool mutexes held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_set_enclave_threads_per_core(struct ne_enclave *ne_enclave,
					   int core_id, u32 vcpu_id)
{}

/**
 * ne_get_cpu_from_cpu_pool() - Get a CPU from the NE CPU pool, either from the
 *				remaining sibling(s) of a CPU core or the first
 *				sibling of a new CPU core.
 * @ne_enclave :	Private data associated with the current enclave.
 * @vcpu_id:		vCPU to get from the NE CPU pool.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_get_cpu_from_cpu_pool(struct ne_enclave *ne_enclave, u32 *vcpu_id)
{}

/**
 * ne_get_vcpu_core_from_cpu_pool() - Get from the NE CPU pool the id of the
 *				      core associated with the provided vCPU.
 * @vcpu_id:	Provided vCPU id to get its associated core id.
 *
 * Context: Process context. This function is called with the ne_enclave and
 *	    ne_cpu_pool mutexes held.
 * Return:
 * * Core id.
 * * -1 if the provided vCPU is not in the pool.
 */
static int ne_get_vcpu_core_from_cpu_pool(u32 vcpu_id)
{}

/**
 * ne_check_cpu_in_cpu_pool() - Check if the given vCPU is in the available CPUs
 *				from the pool.
 * @ne_enclave :	Private data associated with the current enclave.
 * @vcpu_id:		ID of the vCPU to check if available in the NE CPU pool.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_check_cpu_in_cpu_pool(struct ne_enclave *ne_enclave, u32 vcpu_id)
{}

/**
 * ne_add_vcpu_ioctl() - Add a vCPU to the slot associated with the current
 *			 enclave.
 * @ne_enclave :	Private data associated with the current enclave.
 * @vcpu_id:		ID of the CPU to be associated with the given slot,
 *			apic id on x86.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_add_vcpu_ioctl(struct ne_enclave *ne_enclave, u32 vcpu_id)
{}

/**
 * ne_sanity_check_user_mem_region() - Sanity check the user space memory
 *				       region received during the set user
 *				       memory region ioctl call.
 * @ne_enclave :	Private data associated with the current enclave.
 * @mem_region :	User space memory region to be sanity checked.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_sanity_check_user_mem_region(struct ne_enclave *ne_enclave,
					   struct ne_user_memory_region mem_region)
{}

/**
 * ne_sanity_check_user_mem_region_page() - Sanity check a page from the user space
 *					    memory region received during the set
 *					    user memory region ioctl call.
 * @ne_enclave :	Private data associated with the current enclave.
 * @mem_region_page:	Page from the user space memory region to be sanity checked.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_sanity_check_user_mem_region_page(struct ne_enclave *ne_enclave,
						struct page *mem_region_page)
{}

/**
 * ne_sanity_check_phys_mem_region() - Sanity check the start address and the size
 *                                     of a physical memory region.
 * @phys_mem_region_paddr : Physical start address of the region to be sanity checked.
 * @phys_mem_region_size  : Length of the region to be sanity checked.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_sanity_check_phys_mem_region(u64 phys_mem_region_paddr,
					   u64 phys_mem_region_size)
{}

/**
 * ne_merge_phys_contig_memory_regions() - Add a memory region and merge the adjacent
 *                                         regions if they are physically contiguous.
 * @phys_contig_regions : Private data associated with the contiguous physical memory regions.
 * @page_paddr :          Physical start address of the region to be added.
 * @page_size :           Length of the region to be added.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int
ne_merge_phys_contig_memory_regions(struct ne_phys_contig_mem_regions *phys_contig_regions,
				    u64 page_paddr, u64 page_size)
{}

/**
 * ne_set_user_memory_region_ioctl() - Add user space memory region to the slot
 *				       associated with the current enclave.
 * @ne_enclave :	Private data associated with the current enclave.
 * @mem_region :	User space memory region to be associated with the given slot.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_set_user_memory_region_ioctl(struct ne_enclave *ne_enclave,
					   struct ne_user_memory_region mem_region)
{}

/**
 * ne_start_enclave_ioctl() - Trigger enclave start after the enclave resources,
 *			      such as memory and CPU, have been set.
 * @ne_enclave :		Private data associated with the current enclave.
 * @enclave_start_info :	Enclave info that includes enclave cid and flags.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_start_enclave_ioctl(struct ne_enclave *ne_enclave,
				  struct ne_enclave_start_info *enclave_start_info)
{}

/**
 * ne_enclave_ioctl() - Ioctl function provided by the enclave file.
 * @file:	File associated with this ioctl function.
 * @cmd:	The command that is set for the ioctl call.
 * @arg:	The argument that is provided for the ioctl call.
 *
 * Context: Process context.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static long ne_enclave_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{}

/**
 * ne_enclave_remove_all_mem_region_entries() - Remove all memory region entries
 *						from the enclave data structure.
 * @ne_enclave :	Private data associated with the current enclave.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 */
static void ne_enclave_remove_all_mem_region_entries(struct ne_enclave *ne_enclave)
{}

/**
 * ne_enclave_remove_all_vcpu_id_entries() - Remove all vCPU id entries from
 *					     the enclave data structure.
 * @ne_enclave :	Private data associated with the current enclave.
 *
 * Context: Process context. This function is called with the ne_enclave mutex held.
 */
static void ne_enclave_remove_all_vcpu_id_entries(struct ne_enclave *ne_enclave)
{}

/**
 * ne_pci_dev_remove_enclave_entry() - Remove the enclave entry from the data
 *				       structure that is part of the NE PCI
 *				       device private data.
 * @ne_enclave :	Private data associated with the current enclave.
 * @ne_pci_dev :	Private data associated with the PCI device.
 *
 * Context: Process context. This function is called with the ne_pci_dev enclave
 *	    mutex held.
 */
static void ne_pci_dev_remove_enclave_entry(struct ne_enclave *ne_enclave,
					    struct ne_pci_dev *ne_pci_dev)
{}

/**
 * ne_enclave_release() - Release function provided by the enclave file.
 * @inode:	Inode associated with this file release function.
 * @file:	File associated with this release function.
 *
 * Context: Process context.
 * Return:
 * * 0 on success.
 * * Negative return value on failure.
 */
static int ne_enclave_release(struct inode *inode, struct file *file)
{}

/**
 * ne_enclave_poll() - Poll functionality used for enclave out-of-band events.
 * @file:	File associated with this poll function.
 * @wait:	Poll table data structure.
 *
 * Context: Process context.
 * Return:
 * * Poll mask.
 */
static __poll_t ne_enclave_poll(struct file *file, poll_table *wait)
{}

static const struct file_operations ne_enclave_fops =;

/**
 * ne_create_vm_ioctl() - Alloc slot to be associated with an enclave. Create
 *			  enclave file descriptor to be further used for enclave
 *			  resources handling e.g. memory regions and CPUs.
 * @ne_pci_dev :	Private data associated with the PCI device.
 * @slot_uid:		User pointer to store the generated unique slot id
 *			associated with an enclave to.
 *
 * Context: Process context. This function is called with the ne_pci_dev enclave
 *	    mutex held.
 * Return:
 * * Enclave fd on success.
 * * Negative return value on failure.
 */
static int ne_create_vm_ioctl(struct ne_pci_dev *ne_pci_dev, u64 __user *slot_uid)
{}

/**
 * ne_ioctl() - Ioctl function provided by the NE misc device.
 * @file:	File associated with this ioctl function.
 * @cmd:	The command that is set for the ioctl call.
 * @arg:	The argument that is provided for the ioctl call.
 *
 * Context: Process context.
 * Return:
 * * Ioctl result (e.g. enclave file descriptor) on success.
 * * Negative return value on failure.
 */
static long ne_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{}

#if defined(CONFIG_NITRO_ENCLAVES_MISC_DEV_TEST)
#include "ne_misc_dev_test.c"
#endif

static int __init ne_init(void)
{}

static void __exit ne_exit(void)
{}

module_init();
module_exit(ne_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();