Skip to content

Commit

Permalink
iommufd: File descriptor, context, kconfig and makefiles
Browse files Browse the repository at this point in the history
This is the basic infrastructure of a new miscdevice to hold the iommufd
IOCTL API.

It provides:
 - A miscdevice to create file descriptors to run the IOCTL interface over

 - A table based ioctl dispatch and centralized extendable pre-validation
   step

 - An xarray mapping user ID's to kernel objects. The design has multiple
   inter-related objects held within in a single IOMMUFD fd

 - A simple usage count to build a graph of object relations and protect
   against hostile userspace racing ioctls

The only IOCTL provided in this patch is the generic 'destroy any object
by handle' operation.

Signed-off-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
  • Loading branch information
jgunthorpe committed Aug 19, 2022
1 parent 07b1919 commit a9a0de9
Show file tree
Hide file tree
Showing 10 changed files with 572 additions and 1 deletion.
1 change: 1 addition & 0 deletions Documentation/userspace-api/ioctl/ioctl-number.rst
Expand Up @@ -105,6 +105,7 @@ Code Seq# Include File Comments
'8' all SNP8023 advanced NIC card
<mailto:mcr@solidum.com>
';' 64-7F linux/vfio.h
';' 80-FF linux/iommufd.h
'=' 00-3f uapi/linux/ptp_clock.h <mailto:richardcochran@gmail.com>
'@' 00-0F linux/radeonfb.h conflict!
'@' 00-0F drivers/video/aty/aty128fb.c conflict!
Expand Down
10 changes: 10 additions & 0 deletions MAINTAINERS
Expand Up @@ -10606,6 +10606,16 @@ L: linux-mips@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/sgi/ioc3-eth.c

IOMMU FD
M: Jason Gunthorpe <jgg@nvidia.com>
M: Kevin Tian <kevin.tian@intel.com>
L: iommu@lists.linux-foundation.org
S: Maintained
F: Documentation/userspace-api/iommufd.rst
F: drivers/iommu/iommufd/
F: include/uapi/linux/iommufd.h
F: include/linux/iommufd.h

IOMAP FILESYSTEM LIBRARY
M: Christoph Hellwig <hch@infradead.org>
M: Darrick J. Wong <djwong@kernel.org>
Expand Down
1 change: 1 addition & 0 deletions drivers/iommu/Kconfig
Expand Up @@ -177,6 +177,7 @@ config MSM_IOMMU

source "drivers/iommu/amd/Kconfig"
source "drivers/iommu/intel/Kconfig"
source "drivers/iommu/iommufd/Kconfig"

config IRQ_REMAP
bool "Support for Interrupt Remapping"
Expand Down
2 changes: 1 addition & 1 deletion drivers/iommu/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += amd/ intel/ arm/
obj-y += amd/ intel/ arm/ iommufd/
obj-$(CONFIG_IOMMU_API) += iommu.o
obj-$(CONFIG_IOMMU_API) += iommu-traces.o
obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
Expand Down
13 changes: 13 additions & 0 deletions drivers/iommu/iommufd/Kconfig
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
config IOMMUFD
tristate "IOMMU Userspace API"
select INTERVAL_TREE
select IOMMU_API
default n
help
Provides /dev/iommu the user API to control the IOMMU subsystem as
it relates to managing IO page tables that point at user space memory.

This would commonly be used in combination with VFIO.

If you don't know what to do here, say N.
5 changes: 5 additions & 0 deletions drivers/iommu/iommufd/Makefile
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
iommufd-y := \
main.o

obj-$(CONFIG_IOMMUFD) += iommufd.o
110 changes: 110 additions & 0 deletions drivers/iommu/iommufd/iommufd_private.h
@@ -0,0 +1,110 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
*/
#ifndef __IOMMUFD_PRIVATE_H
#define __IOMMUFD_PRIVATE_H

#include <linux/rwsem.h>
#include <linux/xarray.h>
#include <linux/refcount.h>
#include <linux/uaccess.h>

struct iommufd_ctx {
struct file *file;
struct xarray objects;
};

struct iommufd_ctx *iommufd_fget(int fd);

struct iommufd_ucmd {
struct iommufd_ctx *ictx;
void __user *ubuffer;
u32 user_size;
void *cmd;
};

/* Copy the response in ucmd->cmd back to userspace. */
static inline int iommufd_ucmd_respond(struct iommufd_ucmd *ucmd,
size_t cmd_len)
{
if (copy_to_user(ucmd->ubuffer, ucmd->cmd,
min_t(size_t, ucmd->user_size, cmd_len)))
return -EFAULT;
return 0;
}

enum iommufd_object_type {
IOMMUFD_OBJ_NONE,
IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE,
};

/* Base struct for all objects with a userspace ID handle. */
struct iommufd_object {
struct rw_semaphore destroy_rwsem;
refcount_t users;
enum iommufd_object_type type;
unsigned int id;
};

static inline bool iommufd_lock_obj(struct iommufd_object *obj)
{
if (!down_read_trylock(&obj->destroy_rwsem))
return false;
if (!refcount_inc_not_zero(&obj->users)) {
up_read(&obj->destroy_rwsem);
return false;
}
return true;
}

struct iommufd_object *iommufd_get_object(struct iommufd_ctx *ictx, u32 id,
enum iommufd_object_type type);
static inline void iommufd_put_object(struct iommufd_object *obj)
{
refcount_dec(&obj->users);
up_read(&obj->destroy_rwsem);
}

/**
* iommufd_put_object_keep_user() - Release part of the refcount on obj
* @obj - Object to release
*
* Objects have two protections to ensure that userspace has a consistent
* experience with destruction. Normally objects are locked so that destroy will
* block while there are concurrent users, and wait for the object to be
* unlocked.
*
* However, destroy can also be blocked by holding users reference counts on the
* objects, in that case destroy will immediately return EBUSY and will not wait
* for reference counts to go to zero.
*
* This function releases the destroy lock and destroy will return EBUSY.
*
* It should be used in places where the users will be held beyond a single
* system call.
*/
static inline void iommufd_put_object_keep_user(struct iommufd_object *obj)
{
up_read(&obj->destroy_rwsem);
}
void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj);
void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,
struct iommufd_object *obj);
void iommufd_object_finalize(struct iommufd_ctx *ictx,
struct iommufd_object *obj);
bool iommufd_object_destroy_user(struct iommufd_ctx *ictx,
struct iommufd_object *obj);
struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
size_t size,
enum iommufd_object_type type);

#define iommufd_object_alloc(ictx, ptr, type) \
container_of(_iommufd_object_alloc( \
ictx, \
sizeof(*(ptr)) + BUILD_BUG_ON_ZERO( \
offsetof(typeof(*(ptr)), \
obj) != 0), \
type), \
typeof(*(ptr)), obj)

#endif

0 comments on commit a9a0de9

Please sign in to comment.