// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ #include <linux/security.h> #include <linux/debugfs.h> #include <linux/ktime.h> #include <linux/mutex.h> #include <linux/unaligned.h> #include <cxlpci.h> #include <cxlmem.h> #include <cxl.h> #include "core.h" #include "trace.h" static bool cxl_raw_allow_all; /** * DOC: cxl mbox * * Core implementation of the CXL 2.0 Type-3 Memory Device Mailbox. The * implementation is used by the cxl_pci driver to initialize the device * and implement the cxl_mem.h IOCTL UAPI. It also implements the * backend of the cxl_pmem_ctl() transport for LIBNVDIMM. */ #define cxl_for_each_cmd(cmd) … #define CXL_CMD(_id, sin, sout, _flags) … #define CXL_VARIABLE_PAYLOAD … /* * This table defines the supported mailbox commands for the driver. This table * is made up of a UAPI structure. Non-negative values as parameters in the * table will be validated against the user's input. For example, if size_in is * 0, and the user passed in 1, it is an error. */ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = …; /* * Commands that RAW doesn't permit. The rationale for each: * * CXL_MBOX_OP_ACTIVATE_FW: Firmware activation requires adjustment / * coordination of transaction timeout values at the root bridge level. * * CXL_MBOX_OP_SET_PARTITION_INFO: The device memory map may change live * and needs to be coordinated with HDM updates. * * CXL_MBOX_OP_SET_LSA: The label storage area may be cached by the * driver and any writes from userspace invalidates those contents. * * CXL_MBOX_OP_SET_SHUTDOWN_STATE: Set shutdown state assumes no writes * to the device after it is marked clean, userspace can not make that * assertion. * * CXL_MBOX_OP_[GET_]SCAN_MEDIA: The kernel provides a native error list that * is kept up to date with patrol notifications and error management. * * CXL_MBOX_OP_[GET_,INJECT_,CLEAR_]POISON: These commands require kernel * driver orchestration for safety. */ static u16 cxl_disabled_raw_commands[] = …; /* * Command sets that RAW doesn't permit. All opcodes in this set are * disabled because they pass plain text security payloads over the * user/kernel boundary. This functionality is intended to be wrapped * behind the keys ABI which allows for encrypted payloads in the UAPI */ static u8 security_command_sets[] = …; static bool cxl_is_security_command(u16 opcode) { … } static void cxl_set_security_cmd_enabled(struct cxl_security_state *security, u16 opcode) { … } static bool cxl_is_poison_command(u16 opcode) { … } static void cxl_set_poison_cmd_enabled(struct cxl_poison_state *poison, u16 opcode) { … } static struct cxl_mem_command *cxl_mem_find_command(u16 opcode) { … } static const char *cxl_mem_opcode_to_name(u16 opcode) { … } /** * cxl_internal_send_cmd() - Kernel internal interface to send a mailbox command * @cxl_mbox: CXL mailbox context * @mbox_cmd: initialized command to execute * * Context: Any context. * Return: * * %>=0 - Number of bytes returned in @out. * * %-E2BIG - Payload is too large for hardware. * * %-EBUSY - Couldn't acquire exclusive mailbox access. * * %-EFAULT - Hardware error occurred. * * %-ENXIO - Command completed, but device reported an error. * * %-EIO - Unexpected output size. * * Mailbox commands may execute successfully yet the device itself reported an * error. While this distinction can be useful for commands from userspace, the * kernel will only be able to use results when both are successful. */ int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *mbox_cmd) { … } EXPORT_SYMBOL_NS_GPL(…); static bool cxl_mem_raw_command_allowed(u16 opcode) { … } /** * cxl_payload_from_user_allowed() - Check contents of in_payload. * @opcode: The mailbox command opcode. * @payload_in: Pointer to the input payload passed in from user space. * * Return: * * true - payload_in passes check for @opcode. * * false - payload_in contains invalid or unsupported values. * * The driver may inspect payload contents before sending a mailbox * command from user space to the device. The intent is to reject * commands with input payloads that are known to be unsafe. This * check is not intended to replace the users careful selection of * mailbox command parameters and makes no guarantee that the user * command will succeed, nor that it is appropriate. * * The specific checks are determined by the opcode. */ static bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in) { … } static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox, struct cxl_memdev_state *mds, u16 opcode, size_t in_size, size_t out_size, u64 in_payload) { … } static void cxl_mbox_cmd_dtor(struct cxl_mbox_cmd *mbox) { … } static int cxl_to_mem_cmd_raw(struct cxl_mem_command *mem_cmd, const struct cxl_send_command *send_cmd, struct cxl_memdev_state *mds) { … } static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd, const struct cxl_send_command *send_cmd, struct cxl_memdev_state *mds) { … } /** * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. * @mbox_cmd: Sanitized and populated &struct cxl_mbox_cmd. * @mds: The driver data for the operation * @send_cmd: &struct cxl_send_command copied in from userspace. * * Return: * * %0 - @out_cmd is ready to send. * * %-ENOTTY - Invalid command specified. * * %-EINVAL - Reserved fields or invalid values were used. * * %-ENOMEM - Input or output buffer wasn't sized properly. * * %-EPERM - Attempted to use a protected command. * * %-EBUSY - Kernel has claimed exclusive access to this opcode * * The result of this command is a fully validated command in @mbox_cmd that is * safe to send to the hardware. */ static int cxl_validate_cmd_from_user(struct cxl_mbox_cmd *mbox_cmd, struct cxl_memdev_state *mds, const struct cxl_send_command *send_cmd) { … } int cxl_query_cmd(struct cxl_memdev *cxlmd, struct cxl_mem_query_commands __user *q) { … } /** * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. * @mds: The driver data for the operation * @mbox_cmd: The validated mailbox command. * @out_payload: Pointer to userspace's output payload. * @size_out: (Input) Max payload size to copy out. * (Output) Payload size hardware generated. * @retval: Hardware generated return code from the operation. * * Return: * * %0 - Mailbox transaction succeeded. This implies the mailbox * protocol completed successfully not that the operation itself * was successful. * * %-ENOMEM - Couldn't allocate a bounce buffer. * * %-EFAULT - Something happened with copy_to/from_user. * * %-EINTR - Mailbox acquisition interrupted. * * %-EXXX - Transaction level failures. * * Dispatches a mailbox command on behalf of a userspace request. * The output payload is copied to userspace. * * See cxl_send_cmd(). */ static int handle_mailbox_cmd_from_user(struct cxl_memdev_state *mds, struct cxl_mbox_cmd *mbox_cmd, u64 out_payload, s32 *size_out, u32 *retval) { … } int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) { … } static int cxl_xfer_log(struct cxl_memdev_state *mds, uuid_t *uuid, u32 *size, u8 *out) { … } /** * cxl_walk_cel() - Walk through the Command Effects Log. * @mds: The driver data for the operation * @size: Length of the Command Effects Log. * @cel: CEL * * Iterate over each entry in the CEL and determine if the driver supports the * command. If so, the command is enabled for the device and can be used later. */ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel) { … } static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_memdev_state *mds) { … } enum { … }; /* See CXL 2.0 Table 170. Get Log Input Payload */ static const uuid_t log_uuid[] = …; /** * cxl_enumerate_cmds() - Enumerate commands for a device. * @mds: The driver data for the operation * * Returns 0 if enumerate completed successfully. * * CXL devices have optional support for certain commands. This function will * determine the set of supported commands for the hardware and update the * enabled_cmds bitmap in the @mds. */ int cxl_enumerate_cmds(struct cxl_memdev_state *mds) { … } EXPORT_SYMBOL_NS_GPL(…); void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_log_type type, enum cxl_event_type event_type, const uuid_t *uuid, union cxl_event *evt) { … } EXPORT_SYMBOL_NS_GPL(…); static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_log_type type, struct cxl_event_record_raw *record) { … } static int cxl_clear_event_record(struct cxl_memdev_state *mds, enum cxl_event_log_type log, struct cxl_get_event_payload *get_pl) { … } static void cxl_mem_get_records_log(struct cxl_memdev_state *mds, enum cxl_event_log_type type) { … } /** * cxl_mem_get_event_records - Get Event Records from the device * @mds: The driver data for the operation * @status: Event Status register value identifying which events are available. * * Retrieve all event records available on the device, report them as trace * events, and clear them. * * See CXL rev 3.0 @8.2.9.2.2 Get Event Records * See CXL rev 3.0 @8.2.9.2.3 Clear Event Records */ void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status) { … } EXPORT_SYMBOL_NS_GPL(…); /** * cxl_mem_get_partition_info - Get partition info * @mds: The driver data for the operation * * Retrieve the current partition info for the device specified. The active * values are the current capacity in bytes. If not 0, the 'next' values are * the pending values, in bytes, which take affect on next cold reset. * * Return: 0 if no error: or the result of the mailbox command. * * See CXL @8.2.9.5.2.1 Get Partition Info */ static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds) { … } /** * cxl_dev_state_identify() - Send the IDENTIFY command to the device. * @mds: The driver data for the operation * * Return: 0 if identify was executed successfully or media not ready. * * This will dispatch the identify command to the device and on success populate * structures to be exported to sysfs. */ int cxl_dev_state_identify(struct cxl_memdev_state *mds) { … } EXPORT_SYMBOL_NS_GPL(…); static int __cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd) { … } /** * cxl_mem_sanitize() - Send a sanitization command to the device. * @cxlmd: The device for the operation * @cmd: The specific sanitization command opcode * * Return: 0 if the command was executed successfully, regardless of * whether or not the actual security operation is done in the background, * such as for the Sanitize case. * Error return values can be the result of the mailbox command, -EINVAL * when security requirements are not met or invalid contexts, or -EBUSY * if the sanitize operation is already in flight. * * See CXL 3.0 @8.2.9.8.5.1 Sanitize and @8.2.9.8.5.2 Secure Erase. */ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd) { … } static int add_dpa_res(struct device *dev, struct resource *parent, struct resource *res, resource_size_t start, resource_size_t size, const char *type) { … } int cxl_mem_create_range_info(struct cxl_memdev_state *mds) { … } EXPORT_SYMBOL_NS_GPL(…); int cxl_set_timestamp(struct cxl_memdev_state *mds) { … } EXPORT_SYMBOL_NS_GPL(…); int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, struct cxl_region *cxlr) { … } EXPORT_SYMBOL_NS_GPL(…); static void free_poison_buf(void *buf) { … } /* Get Poison List output buffer is protected by mds->poison.lock */ static int cxl_poison_alloc_buf(struct cxl_memdev_state *mds) { … } int cxl_poison_state_init(struct cxl_memdev_state *mds) { … } EXPORT_SYMBOL_NS_GPL(…); int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host) { … } EXPORT_SYMBOL_NS_GPL(…); struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) { … } EXPORT_SYMBOL_NS_GPL(…); void __init cxl_mbox_init(void) { … }