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

Commit 69a0892b authored by Terence Hampson's avatar Terence Hampson
Browse files

msm: mdss: validate buffer size is enough for intended use



Make sure buffer size is enough for intended use, as soon as we
acquire buffer handle. Prior to this change validation was done
when mapping the buffer. Failing the validation at this later
point was resulting in a layer update drop, with no clean
way to handle the validation. By validating earlier, request
to commit the frame can fail and client can determine fall back
behaviour.

Change-Id: Ie14317c5d5125d6bd23fedfdbbaa877897f8786b
Signed-off-by: default avatarTerence Hampson <thampson@codeaurora.org>
parent 13848461
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -1218,11 +1218,12 @@ void mdss_mdp_get_v_h_subsample_rate(u8 chroma_samp,
	u8 *v_sample, u8 *h_sample);
struct mult_factor *mdss_mdp_get_comp_factor(u32 format,
	bool rt_factor);
int mdss_mdp_data_get(struct mdss_mdp_data *data, struct msmfb_data *planes,
		int num_planes, u32 flags, struct device *dev, bool rotator,
		int dir);
int mdss_mdp_data_map(struct mdss_mdp_data *data, bool rotator, int dir);
void mdss_mdp_data_free(struct mdss_mdp_data *data, bool rotator, int dir);
int mdss_mdp_data_get_and_validate_size(struct mdss_mdp_data *data,
	struct msmfb_data *planes, int num_planes, u32 flags,
	struct device *dev, bool rotator, int dir,
	struct mdp_layer_buffer *buffer);
u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase);

+11 −8
Original line number Diff line number Diff line
@@ -847,15 +847,18 @@ static struct mdss_mdp_data *__map_layer_buffer(struct msm_fb_data_type *mfd,

	image.memory_id = buffer->planes[0].fd;
	image.offset = buffer->planes[0].offset;
	ret = mdss_mdp_data_get(src_data, &image, 1, flags,
			&mfd->pdev->dev, false, DMA_TO_DEVICE);
	if (ret) {
		mdss_mdp_overlay_buf_free(mfd, src_data);
		src_data = ERR_PTR(ret);
	} else {
	ret = mdss_mdp_data_get_and_validate_size(src_data, &image, 1,
			flags, &mfd->pdev->dev, false, DMA_TO_DEVICE,
			buffer);
	if (ret)
		goto end_buf_free;

	src_data->num_planes = 1;
	}
	return src_data;

end_buf_free:
	mdss_mdp_overlay_buf_free(mfd, src_data);
	src_data = ERR_PTR(ret);
end:
	return src_data;
}
+7 −2
Original line number Diff line number Diff line
@@ -2170,6 +2170,7 @@ static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	struct mdss_mdp_pipe *pipe;
	struct mdss_mdp_data *src_data;
	struct mdp_layer_buffer buffer;
	int ret;
	u32 flags;

@@ -2205,8 +2206,12 @@ static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
		pr_err("unable to allocate source buffer\n");
		ret = -ENOMEM;
	} else {
		ret = mdss_mdp_data_get(src_data, &req->data, 1, flags,
			&mfd->pdev->dev, false, DMA_TO_DEVICE);
		buffer.width = pipe->img_width;
		buffer.height = pipe->img_height;
		buffer.format = pipe->src_fmt->format;
		ret = mdss_mdp_data_get_and_validate_size(src_data, &req->data,
			1, flags, &mfd->pdev->dev, false, DMA_TO_DEVICE,
			&buffer);
		if (IS_ERR_VALUE(ret)) {
			mdss_mdp_overlay_buf_free(mfd, src_data);
			pr_err("src_data pmem error\n");
+15 −4
Original line number Diff line number Diff line
@@ -1004,6 +1004,7 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd,
			    struct msmfb_overlay_data *req)
{
	struct mdss_mdp_rotator_session *rot;
	struct mdp_layer_buffer buffer;
	int ret;
	u32 flgs;
	struct mdss_mdp_data src_buf;
@@ -1023,8 +1024,12 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd,
	mdss_iommu_ctrl(1);
	mutex_lock(&rot->lock);

	ret = mdss_mdp_data_get(&src_buf, &req->data, 1, flgs,
		&mfd->pdev->dev, true, DMA_TO_DEVICE);
	buffer.width = rot->src_rect.w;
	buffer.height = rot->src_rect.h;
	buffer.format = rot->format;
	ret = mdss_mdp_data_get_and_validate_size(&src_buf,
		&req->data, 1, flgs, &mfd->pdev->dev, true,
		DMA_TO_DEVICE, &buffer);
	if (ret) {
		pr_err("src_data pmem error\n");
		goto dst_buf_fail;
@@ -1040,8 +1045,14 @@ int mdss_mdp_rotator_play(struct msm_fb_data_type *mfd,
	memcpy(&rot->src_buf, &src_buf, sizeof(struct mdss_mdp_data));

	mdss_mdp_data_free(&rot->dst_buf, true, DMA_FROM_DEVICE);
	ret = mdss_mdp_data_get(&rot->dst_buf, &req->dst_data, 1, flgs,
		&mfd->pdev->dev, true, DMA_FROM_DEVICE);
	buffer.width = rot->dst.w;
	buffer.height = rot->dst.h;
	buffer.format = mdss_mdp_get_rotator_dst_format(rot->format,
		rot->flags & MDP_ROT_90, rot->bwc_mode);

	ret = mdss_mdp_data_get_and_validate_size(&rot->dst_buf,
		&req->dst_data, 1, flgs, &mfd->pdev->dev, true,
		DMA_FROM_DEVICE, &buffer);
	if (ret) {
		pr_err("dst_data pmem error\n");
		mdss_mdp_data_free(&rot->src_buf, true, DMA_TO_DEVICE);
+52 −3
Original line number Diff line number Diff line
@@ -1197,9 +1197,9 @@ err_unmap:
	return ret;
}

int mdss_mdp_data_get(struct mdss_mdp_data *data, struct msmfb_data *planes,
		int num_planes, u32 flags, struct device *dev, bool rotator,
		int dir)
static int mdss_mdp_data_get(struct mdss_mdp_data *data,
		struct msmfb_data *planes, int num_planes, u32 flags,
		struct device *dev, bool rotator, int dir)
{
	int i, rc = 0;

@@ -1259,6 +1259,55 @@ void mdss_mdp_data_free(struct mdss_mdp_data *data, bool rotator, int dir)
	data->num_planes = 0;
}

int mdss_mdp_data_get_and_validate_size(struct mdss_mdp_data *data,
	struct msmfb_data *planes, int num_planes, u32 flags,
	struct device *dev, bool rotator, int dir,
	struct mdp_layer_buffer *buffer)
{
	struct mdss_mdp_format_params *fmt;
	struct mdss_mdp_plane_sizes ps;
	int ret, i;
	unsigned long total_buf_len = 0;

	fmt = mdss_mdp_get_format_params(buffer->format);
	if (!fmt) {
		pr_err("Format %d not supported\n", buffer->format);
		return -EINVAL;
	}

	ret = mdss_mdp_data_get(data, planes, num_planes,
		flags, dev, rotator, dir);
	if (ret)
		return ret;

	mdss_mdp_get_plane_sizes(fmt, buffer->width, buffer->height, &ps, 0, 0);

	for (i = 0; i < num_planes ; i++) {
		unsigned long plane_len = (data->p[i].srcp_dma_buf) ?
				data->p[i].srcp_dma_buf->size : data->p[i].len;

		if (plane_len < planes[i].offset) {
			pr_err("Offset=%d larger than buffer size=%lu\n",
				planes[i].offset, plane_len);
			ret = -EINVAL;
			goto buf_too_small;
		}
		total_buf_len += plane_len - planes[i].offset;
	}

	if (total_buf_len < ps.total_size) {
		pr_err("Buffer size=%lu, expected size=%d\n", total_buf_len,
			ps.total_size);
		ret = -EINVAL;
		goto buf_too_small;
	}
	return 0;

buf_too_small:
	mdss_mdp_data_free(data, rotator, dir);
	return ret;
}

int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase)
{
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
Loading