Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 41 additions & 15 deletions drivers/misc/fastrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ struct fastrpc_map {
u64 len;
u64 raddr;
u32 attr;
u32 flags;
struct kref refcount;
};

Expand Down Expand Up @@ -869,7 +870,7 @@ static const struct dma_buf_ops fastrpc_dma_buf_ops = {
};

static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
u64 len, u32 attr, struct fastrpc_map **ppmap)
u64 len, u32 attr, struct fastrpc_map **ppmap, int mflags)
{
struct fastrpc_session_ctx *sess = fl->sctx;
struct fastrpc_map *map = NULL;
Expand All @@ -886,6 +887,7 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,

map->fl = fl;
map->fd = fd;
map->flags = mflags;
map->buf = dma_buf_get(fd);
if (IS_ERR(map->buf)) {
err = PTR_ERR(map->buf);
Expand Down Expand Up @@ -961,13 +963,13 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
return err;
}

static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
u64 len, u32 attr, struct fastrpc_map **ppmap)
static int fastrpc_map_create(struct fastrpc_user *fl, int fd, u64 len, u32 attr,
struct fastrpc_map **ppmap, bool take_ref, int mflags)
{
if (!fastrpc_map_lookup(fl, fd, ppmap, true))
if (!fastrpc_map_lookup(fl, fd, ppmap, take_ref))
return 0;

return fastrpc_map_attach(fl, fd, len, attr, ppmap);
return fastrpc_map_attach(fl, fd, len, attr, ppmap, mflags);
}

/*
Expand Down Expand Up @@ -1038,23 +1040,25 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx)
int i, err;

for (i = 0; i < ctx->nscalars; ++i) {
bool take_ref = i < ctx->nbufs;
int mflags = 0;

if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1 ||
ctx->args[i].length == 0)
continue;

if (i < ctx->nbufs)
err = fastrpc_map_create(ctx->fl, ctx->args[i].fd,
ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
else
err = fastrpc_map_attach(ctx->fl, ctx->args[i].fd,
ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
/* Set the DMA handle mapping flag for DMA handles */
if (i >= ctx->nbufs)
mflags = FASTRPC_MAP_DMA_HANDLE;

err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, ctx->args[i].length,
ctx->args[i].attr, &ctx->maps[i], take_ref, mflags);
if (err) {
dev_err(dev, "Error Creating map %d\n", err);
return -EINVAL;
}

}

return 0;
}

Expand Down Expand Up @@ -1247,6 +1251,16 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
list[i].num = ctx->args[i].length ? 1 : 0;
list[i].pgidx = i;
if (ctx->maps[i]) {
/* It is possible that map is created with
* mflags FASTRPC_MAP_DMA_HANDLE and take_ref
* is false. Check if map still exists or is
* being freed as take_ref is false
*/
if (fastrpc_map_lookup(ctx->fl, ctx->args[i].fd,
&ctx->maps[i], false)) {
ctx->maps[i] = NULL;
return -EINVAL;
}
pages[i].addr = ctx->maps[i]->phys;
pages[i].size = ctx->maps[i]->size;
}
Expand Down Expand Up @@ -1296,8 +1310,13 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
if (!fdlist[i])
break;
if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
/* Validate the map flags for DMA handles and skip freeing map if invalid */
if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false) &&
mmap->flags == FASTRPC_MAP_DMA_HANDLE) {
/* Allow DMA handle maps to free only once */
mmap->flags = 0;
fastrpc_map_put(mmap);
}
}

return ret;
Expand Down Expand Up @@ -1649,7 +1668,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
fl->pd = USER_PD;

if (init.filelen && init.filefd) {
err = fastrpc_map_create(fl, init.filefd, init.filelen, 0, &map);
err = fastrpc_map_create(fl, init.filefd, init.filelen, 0, &map, true, 0);
if (err)
goto err;
}
Expand Down Expand Up @@ -2275,8 +2294,15 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp)
if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;

/*
* Prevent mapping backward compatible DMA handles here, as they are
* already mapped in the remote call.
*/
if (req.flags == FASTRPC_MAP_DMA_HANDLE)
return -EINVAL;

/* create SMMU mapping */
err = fastrpc_map_create(fl, req.fd, req.length, 0, &map);
err = fastrpc_map_create(fl, req.fd, req.length, 0, &map, true, 0);
if (err) {
dev_err(dev, "failed to map buffer, fd = %d\n", req.fd);
return err;
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/misc/fastrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ enum fastrpc_map_flags {
FASTRPC_MAP_FD = 2,
FASTRPC_MAP_FD_DELAYED,
FASTRPC_MAP_FD_NOMAP = 16,
/* Map the DMA handle in the invoke call for backward compatibility */
FASTRPC_MAP_DMA_HANDLE = 0x20000,
FASTRPC_MAP_MAX,
};

Expand Down