cxl/mbox: Move cxl_mem_command construction to helper funcs
authorAlison Schofield <alison.schofield@intel.com>
Thu, 31 Mar 2022 01:27:11 +0000 (18:27 -0700)
committerDan Williams <dan.j.williams@intel.com>
Tue, 12 Apr 2022 23:07:00 +0000 (16:07 -0700)
Sanitizing and constructing a cxl_mem_command from a userspace
command is part of the validation process prior to submitting
the command to a CXL device. Move this work to helper functions:
cxl_to_mem_cmd(), cxl_to_mem_cmd_raw().

This declutters cxl_validate_cmd_from_user() in preparation for
adding new validation steps.

Signed-off-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Link: https://lore.kernel.org/r/7d9b826f29262e3a484cb4bb7b63872134d60bd7.1648687552.git.alison.schofield@intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/core/mbox.c

index be61a0d..1f2175f 100644 (file)
@@ -207,76 +207,42 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
        return true;
 }
 
-/**
- * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND.
- * @cxlds: The device data for the operation
- * @send_cmd: &struct cxl_send_command copied in from userspace.
- * @out_cmd: Sanitized and populated &struct cxl_mem_command.
- *
- * 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 @out_cmd that is
- * safe to send to the hardware.
- *
- * See handle_mailbox_cmd_from_user()
- */
-static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
-                                     const struct cxl_send_command *send_cmd,
-                                     struct cxl_mem_command *out_cmd)
+static int cxl_to_mem_cmd_raw(struct cxl_mem_command *mem_cmd,
+                             const struct cxl_send_command *send_cmd,
+                             struct cxl_dev_state *cxlds)
 {
-       const struct cxl_command_info *info;
-       struct cxl_mem_command *c;
-
-       if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX)
-               return -ENOTTY;
-
-       /*
-        * The user can never specify an input payload larger than what hardware
-        * supports, but output can be arbitrarily large (simply write out as
-        * much data as the hardware provides).
-        */
-       if (send_cmd->in.size > cxlds->payload_size)
+       if (send_cmd->raw.rsvd)
                return -EINVAL;
 
        /*
-        * Checks are bypassed for raw commands but a WARN/taint will occur
-        * later in the callchain
+        * Unlike supported commands, the output size of RAW commands
+        * gets passed along without further checking, so it must be
+        * validated here.
         */
-       if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW) {
-               const struct cxl_mem_command temp = {
-                       .info = {
-                               .id = CXL_MEM_COMMAND_ID_RAW,
-                               .flags = 0,
-                               .size_in = send_cmd->in.size,
-                               .size_out = send_cmd->out.size,
-                       },
-                       .opcode = send_cmd->raw.opcode
-               };
-
-               if (send_cmd->raw.rsvd)
-                       return -EINVAL;
+       if (send_cmd->out.size > cxlds->payload_size)
+               return -EINVAL;
 
-               /*
-                * Unlike supported commands, the output size of RAW commands
-                * gets passed along without further checking, so it must be
-                * validated here.
-                */
-               if (send_cmd->out.size > cxlds->payload_size)
-                       return -EINVAL;
+       if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode))
+               return -EPERM;
 
-               if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode))
-                       return -EPERM;
+       *mem_cmd = (struct cxl_mem_command) {
+               .info = {
+                       .id = CXL_MEM_COMMAND_ID_RAW,
+                       .size_in = send_cmd->in.size,
+                       .size_out = send_cmd->out.size,
+               },
+               .opcode = send_cmd->raw.opcode
+       };
 
-               memcpy(out_cmd, &temp, sizeof(temp));
+       return 0;
+}
 
-               return 0;
-       }
+static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd,
+                         const struct cxl_send_command *send_cmd,
+                         struct cxl_dev_state *cxlds)
+{
+       struct cxl_mem_command *c = &cxl_mem_commands[send_cmd->id];
+       const struct cxl_command_info *info = &c->info;
 
        if (send_cmd->flags & ~CXL_MEM_COMMAND_FLAG_MASK)
                return -EINVAL;
@@ -287,10 +253,6 @@ static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
        if (send_cmd->in.rsvd || send_cmd->out.rsvd)
                return -EINVAL;
 
-       /* Convert user's command into the internal representation */
-       c = &cxl_mem_commands[send_cmd->id];
-       info = &c->info;
-
        /* Check that the command is enabled for hardware */
        if (!test_bit(info->id, cxlds->enabled_cmds))
                return -ENOTTY;
@@ -307,15 +269,58 @@ static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
        if (info->size_out >= 0 && send_cmd->out.size < info->size_out)
                return -ENOMEM;
 
-       memcpy(out_cmd, c, sizeof(*c));
-       out_cmd->info.size_in = send_cmd->in.size;
+       *mem_cmd = (struct cxl_mem_command) {
+               .info = {
+                       .id = info->id,
+                       .flags = info->flags,
+                       .size_in = send_cmd->in.size,
+                       .size_out = send_cmd->out.size,
+               },
+               .opcode = c->opcode
+       };
+
+       return 0;
+}
+
+/**
+ * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND.
+ * @cxlds: The device data for the operation
+ * @send_cmd: &struct cxl_send_command copied in from userspace.
+ * @out_cmd: Sanitized and populated &struct cxl_mem_command.
+ *
+ * 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 @out_cmd that is
+ * safe to send to the hardware.
+ *
+ * See handle_mailbox_cmd_from_user()
+ */
+static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
+                                     const struct cxl_send_command *send_cmd,
+                                     struct cxl_mem_command *out_cmd)
+{
+       if (send_cmd->id == 0 || send_cmd->id >= CXL_MEM_COMMAND_ID_MAX)
+               return -ENOTTY;
+
        /*
-        * XXX: out_cmd->info.size_out will be controlled by the driver, and the
-        * specified number of bytes @send_cmd->out.size will be copied back out
-        * to userspace.
+        * The user can never specify an input payload larger than what hardware
+        * supports, but output can be arbitrarily large (simply write out as
+        * much data as the hardware provides).
         */
+       if (send_cmd->in.size > cxlds->payload_size)
+               return -EINVAL;
 
-       return 0;
+       /* Sanitize and construct a cxl_mem_command */
+       if (send_cmd->id == CXL_MEM_COMMAND_ID_RAW)
+               return cxl_to_mem_cmd_raw(out_cmd, send_cmd, cxlds);
+       else
+               return cxl_to_mem_cmd(out_cmd, send_cmd, cxlds);
 }
 
 int cxl_query_cmd(struct cxl_memdev *cxlmd,