Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 367ed6a7 authored by Mitchel Humpherys's avatar Mitchel Humpherys Committed by Gerrit - the friendly Code Review server
Browse files

msm: ADSPRPC: Clear output buffers before cache invalidation



Cache operations via userspace address has a risk of a page
fault as on arm64 these addresses are marked as write protect
and fixed up on first access. To avoid aborts happening when
the mmap semaphore is locked at this time, clear non-overlapped
output buffers before caches could be invalidated.

Change-Id: Iedb42e6d3dca4530b1cf065ea87fee1befea3bc6
Acked-by: default avatarSathish Ambley <sambley@qti.qualcomm.com>
Signed-off-by: default avatarMitchel Humpherys <mitchelh@codeaurora.org>
parent f265ab81
Loading
Loading
Loading
Loading
+57 −25
Original line number Diff line number Diff line
@@ -774,6 +774,53 @@ static int get_page_list(uint32_t kernel, struct smq_invoke_ctx *ctx)
	return err;
}

static inline int is_overlapped_outbuf(struct smq_invoke_ctx *ctx, int oix)
{
	int inbufs, outbufs;

	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
	outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc);
	if (!ctx->overps[oix]->mstart)
		return 1;
	oix = oix + 1;
	if ((oix < inbufs + outbufs) && !ctx->overps[oix]->mstart &&
			ctx->overps[oix]->raix < inbufs)
		return 1;
	return 0;
}

static int clear_user_outbufs(struct smq_invoke_ctx *ctx)
{
	remote_arg_t *pra = ctx->pra;
	remote_arg_t *rpra = ctx->rpra;
	uintptr_t ptr, end;
	int oix, err = 0;
	int inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
	int outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc);

	for (oix = 0; oix < inbufs + outbufs; ++oix) {
		int i = ctx->overps[oix]->raix;
		if ((i < inbufs) || (pra[i].buf.pv != rpra[i].buf.pv) ||
			is_overlapped_outbuf(ctx, oix))
			continue;
		VERIFY(err, 0 == clear_user(rpra[i].buf.pv,
				(rpra[i].buf.len < 8) ? rpra[i].buf.len : 8));
		if (err)
			goto bail;
		ptr = buf_page_start(rpra[i].buf.pv) + PAGE_SIZE;
		end = (uintptr_t)rpra[i].buf.pv + rpra[i].buf.len;
		for (; ptr < end; ptr += PAGE_SIZE) {
			VERIFY(err, 0 == clear_user((void *)ptr,
					((end - ptr) < 8) ? end - ptr : 8));
			if (err)
				goto bail;
		}
	}

 bail:
	return err;
}

static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
			remote_arg_t *upra)
{
@@ -906,8 +953,14 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
		rlen -= mlen;
	}

	for (i = 0; i < inbufs; ++i) {
		if (rpra[i].buf.len)
	if (!kernel) {
		VERIFY(err, 0 == clear_user_outbufs(ctx));
		if (err)
			goto bail;
	}
	for (oix = 0; oix < inbufs + outbufs; ++oix) {
		int i = ctx->overps[oix]->raix;
		if (rpra[i].buf.len && ctx->overps[oix]->mstart)
			dmac_flush_range(rpra[i].buf.pv,
				  (char *)rpra[i].buf.pv + rpra[i].buf.len);
	}
@@ -990,28 +1043,6 @@ static void inv_args_pre(uint32_t sc, remote_arg_t *rpra)
	}
}

static void inv_args_idx(struct smq_invoke_ctx *ctx, int id)
{
	struct fastrpc_apps *me = &gfa;
	struct smq_invoke_buf *list;
	struct smq_phy_page *pages;
	struct page *page;
	struct scatterlist sg;

	if (me->channel[ctx->fdata->cid].smmu.enabled) {
		dmac_inv_range(ctx->rpra[id].buf.pv,
			(char *)ctx->rpra[id].buf.pv + ctx->rpra[id].buf.len);
		return;
	}
	list = smq_invoke_buf_start(ctx->rpra, ctx->sc);
	pages = smq_phy_page_start(ctx->sc, list);
	page = phys_to_page(pages[list[id].pgidx].addr);
	sg_init_table(&sg, 1);
	sg_set_page(&sg, page, pages[list[id].pgidx].size, 0);
	sg_dma_address(&sg) = pages[list[id].pgidx].addr;
	dma_sync_sg_for_cpu(NULL, &sg, 1, DMA_FROM_DEVICE);
}

static void inv_args(struct smq_invoke_ctx *ctx)
{
	uint32_t sc = ctx->sc;
@@ -1026,7 +1057,8 @@ static void inv_args(struct smq_invoke_ctx *ctx)
		if (buf_page_start(rpra) == buf_page_start(rpra[i].buf.pv))
			inv = 1;
		else if (rpra[i].buf.len)
			inv_args_idx(ctx, i);
			dmac_inv_range(rpra[i].buf.pv,
				(char *)rpra[i].buf.pv + rpra[i].buf.len);
	}

	if (inv || REMOTE_SCALARS_OUTHANDLES(sc))