mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
video: rockchip: rga3: Fix memory out-of-bounds on iova
When the virtual address has an in-page offset, iova needs to be offset to the corresponding starting point. Update driver version to 1.2.1 Signed-off-by: Yu Qiaowei <cerf.yu@rock-chips.com> Change-Id: I01e5109bd684f573920773d0d1e08685d1214a40
This commit is contained in:
@@ -75,7 +75,7 @@
|
||||
|
||||
#define DRIVER_MAJOR_VERISON 1
|
||||
#define DRIVER_MINOR_VERSION 2
|
||||
#define DRIVER_REVISION_VERSION 0
|
||||
#define DRIVER_REVISION_VERSION 1
|
||||
|
||||
#define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \
|
||||
"." STR(DRIVER_REVISION_VERSION))
|
||||
@@ -181,6 +181,12 @@ struct rga_dma_buffer {
|
||||
|
||||
dma_addr_t iova;
|
||||
unsigned long size;
|
||||
/*
|
||||
* The offset of the first page of the sgt.
|
||||
* Since alloc iova must be page aligned, the offset of the first page is
|
||||
* identified separately.
|
||||
*/
|
||||
size_t offset;
|
||||
|
||||
/* The core of the mapping */
|
||||
int core;
|
||||
@@ -194,6 +200,9 @@ struct rga_virt_addr {
|
||||
int page_count;
|
||||
unsigned long size;
|
||||
|
||||
/* The offset of the first page of the virtual address */
|
||||
size_t offset;
|
||||
|
||||
int result;
|
||||
};
|
||||
|
||||
|
||||
@@ -497,7 +497,8 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
|
||||
unsigned long size;
|
||||
unsigned long start_addr;
|
||||
unsigned int count;
|
||||
int order = 0;
|
||||
int pages_order = 0;
|
||||
int page_table_order = 0;
|
||||
|
||||
uint32_t *page_table = NULL;
|
||||
struct page **pages = NULL;
|
||||
@@ -543,18 +544,20 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
|
||||
count = rga_buf_size_cal(channel_info->yrgb_addr, channel_info->uv_addr,
|
||||
channel_info->v_addr, format,
|
||||
channel_info->vir_w, channel_info->vir_h,
|
||||
&start_addr, &size);
|
||||
&start_addr, NULL);
|
||||
size = count * PAGE_SIZE;
|
||||
|
||||
/* alloc pages and page_table */
|
||||
order = get_order(size / 4096 * sizeof(struct page *));
|
||||
pages = (struct page **)__get_free_pages(GFP_KERNEL, order);
|
||||
pages_order = get_order(count * sizeof(struct page *));
|
||||
pages = (struct page **)__get_free_pages(GFP_KERNEL, pages_order);
|
||||
if (pages == NULL) {
|
||||
pr_err("Can not alloc pages for pages\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_buffer;
|
||||
}
|
||||
|
||||
page_table = (uint32_t *)__get_free_pages(GFP_KERNEL, order);
|
||||
page_table_order = get_order(count * sizeof(uint32_t *));
|
||||
page_table = (uint32_t *)__get_free_pages(GFP_KERNEL, page_table_order);
|
||||
if (page_table == NULL) {
|
||||
pr_err("Can not alloc pages for page_table\n");
|
||||
ret = -ENOMEM;
|
||||
@@ -604,7 +607,12 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
|
||||
goto out_free_sg;
|
||||
}
|
||||
|
||||
channel_info->yrgb_addr = iova;
|
||||
/*
|
||||
* When the virtual address has an in-page offset, it needs to be offset to
|
||||
* the corresponding starting point.
|
||||
*/
|
||||
channel_info->yrgb_addr = iova + (channel_info->yrgb_addr & (~PAGE_MASK));
|
||||
|
||||
alloc_buffer->iova = iova;
|
||||
alloc_buffer->size = size;
|
||||
alloc_buffer->cookie = cookie;
|
||||
@@ -613,8 +621,8 @@ static int rga_viraddr_get_channel_info(struct rga_img_info_t *channel_info,
|
||||
|
||||
sg_free_table(&sgt);
|
||||
|
||||
free_pages((unsigned long)pages, order);
|
||||
free_pages((unsigned long)page_table, order);
|
||||
free_pages((unsigned long)pages, pages_order);
|
||||
free_pages((unsigned long)page_table, page_table_order);
|
||||
|
||||
*rga_dma_buffer = alloc_buffer;
|
||||
|
||||
@@ -625,10 +633,10 @@ out_free_sg:
|
||||
rga_iommu_dma_free_iova(cookie, iova, size);
|
||||
|
||||
out_free_pages_table:
|
||||
free_pages((unsigned long)page_table, order);
|
||||
free_pages((unsigned long)page_table, page_table_order);
|
||||
|
||||
out_free_pages:
|
||||
free_pages((unsigned long)pages, order);
|
||||
free_pages((unsigned long)pages, pages_order);
|
||||
|
||||
out_free_buffer:
|
||||
kfree(alloc_buffer);
|
||||
|
||||
@@ -216,6 +216,7 @@ static int rga_alloc_sgt(struct rga_virt_addr *virt_addr,
|
||||
|
||||
virt_dma_buf->sgt = sgt;
|
||||
virt_dma_buf->size = virt_addr->size;
|
||||
virt_dma_buf->offset = virt_addr->offset;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -267,10 +268,11 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p,
|
||||
/* Calculate page size. */
|
||||
count = rga_buf_size_cal(viraddr, viraddr, viraddr, format,
|
||||
memory_parm->width, memory_parm->height,
|
||||
&start_addr, &size);
|
||||
&start_addr, NULL);
|
||||
size = count * PAGE_SIZE;
|
||||
|
||||
/* alloc pages and page_table */
|
||||
order = get_order(size / 4096 * sizeof(struct page *));
|
||||
order = get_order(count * sizeof(struct page *));
|
||||
pages = (struct page **)__get_free_pages(GFP_KERNEL, order);
|
||||
if (pages == NULL) {
|
||||
pr_err("%s can not alloc pages for pages\n", __func__);
|
||||
@@ -301,6 +303,7 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p,
|
||||
virt_addr->pages_order = order;
|
||||
virt_addr->page_count = count;
|
||||
virt_addr->size = size;
|
||||
virt_addr->offset = viraddr & (~PAGE_MASK);
|
||||
virt_addr->result = result;
|
||||
|
||||
return 0;
|
||||
@@ -702,7 +705,7 @@ dma_addr_t rga_mm_lookup_iova(struct rga_internal_buffer *buffer, int core)
|
||||
|
||||
for (i = 0; i < buffer->dma_buffer_size; i++)
|
||||
if (buffer->dma_buffer[i].core == core)
|
||||
return buffer->dma_buffer[i].iova;
|
||||
return buffer->dma_buffer[i].iova + buffer->dma_buffer[i].offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user