From: Cho KyongHo Date: Fri, 9 Feb 2018 07:18:43 +0000 (+0900) Subject: android: ion: add nozero and sync_force flags X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=7e825b8e000c8008454a1206429ab3dd958b53cf;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git android: ion: add nozero and sync_force flags Allocation with ION_FLAG_NOZERED returns buffers without clearing data written by previous users. ION should not allow userspace accessing the buffer due to the security reason. ION_FLAG_SYNC_FORCE is also introduced for some users that want to decide the point of cache maintenance by itself. With the flag, ION performs cache flush to the allocated even for cached buffers. those users want this redundant cache flush to prevent buffer corruption by victim dirty cache lines about the buffer after DMA write without proper cache maintenance. Change-Id: Ib3c4f9c93a6cd0240ae12b8c061142355e2b1605 Signed-off-by: Cho KyongHo --- diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 3c3c5ffcbad8..79522c7735ad 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -295,6 +295,12 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) return -EINVAL; } + if ((buffer->flags & ION_FLAG_NOZEROED) != 0) { + pr_err("%s: mmap() to nozeroed buffer is not allowed\n", + __func__); + return -EACCES; + } + if (!(buffer->flags & ION_FLAG_CACHED)) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index 6936bef71753..69f3ee43384a 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -341,7 +341,7 @@ struct ion_page_pool { struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order, bool cached); void ion_page_pool_destroy(struct ion_page_pool *pool); -struct page *ion_page_pool_alloc(struct ion_page_pool *pool); +struct page *ion_page_pool_alloc(struct ion_page_pool *pool, bool nozero); void ion_page_pool_free(struct ion_page_pool *pool, struct page *page); /** ion_page_pool_shrink - shrinks the size of the memory cached in the pool diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 1437078cf9c6..62c5b4b860e5 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -46,6 +46,8 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long size = PAGE_ALIGN(len); unsigned long nr_pages = size >> PAGE_SHIFT; unsigned long align = cma_heap->align_order; + bool cacheflush = !(flags & ION_FLAG_CACHED) || + ((flags & ION_FLAG_SYNC_FORCE) != 0); int ret = -ENOMEM; pages = cma_alloc(cma_heap->cma, nr_pages, align, GFP_KERNEL); @@ -55,20 +57,22 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, return -ENOMEM; } - if (PageHighMem(pages)) { - unsigned long nr_clear_pages = nr_pages; - struct page *page = pages; - - while (nr_clear_pages > 0) { - void *vaddr = kmap_atomic(page); - - memset(vaddr, 0, PAGE_SIZE); - kunmap_atomic(vaddr); - page++; - nr_clear_pages--; + if (!(flags & ION_FLAG_NOZEROED)) { + if (PageHighMem(pages)) { + unsigned long nr_clear_pages = nr_pages; + struct page *page = pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + page++; + nr_clear_pages--; + } + } else { + memset(page_address(pages), 0, size); } - } else { - memset(page_address(pages), 0, size); } table = kmalloc(sizeof(*table), GFP_KERNEL); @@ -84,7 +88,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, buffer->priv_virt = pages; buffer->sg_table = table; - if (!(flags & ION_FLAG_CACHED)) + if (cacheflush) __flush_dcache_area(page_to_virt(pages), len); return 0; diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 184fc29417f7..98df137319c0 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -27,10 +27,15 @@ #include "ion.h" -static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) +static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool, bool nozero) { - struct page *page = alloc_pages(pool->gfp_mask, pool->order); + gfp_t gfpmask = pool->gfp_mask; + struct page *page; + + if (nozero) + gfpmask &= ~__GFP_ZERO; + page = alloc_pages(gfpmask, pool->order); if (!page) return NULL; return page; @@ -74,7 +79,7 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) return page; } -struct page *ion_page_pool_alloc(struct ion_page_pool *pool) +struct page *ion_page_pool_alloc(struct ion_page_pool *pool, bool nozero) { struct page *page = NULL; @@ -88,7 +93,7 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool) mutex_unlock(&pool->mutex); if (!page) { - page = ion_page_pool_alloc_pages(pool); + page = ion_page_pool_alloc_pages(pool, nozero); if (!pool->cached) __flush_dcache_area(page_to_virt(page), 1 << (PAGE_SHIFT + pool->order)); diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 09ae4bca428e..b5c3bce9feb3 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -64,15 +64,17 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, unsigned long order) { bool cached = ion_buffer_cached(buffer); + bool nozero = buffer->flags & ION_FLAG_NOZEROED; + bool cleancache = buffer->flags & ION_FLAG_SYNC_FORCE; struct ion_page_pool *pool; struct page *page; - if (!cached) + if (!cached || cleancache) pool = heap->uncached_pools[order_to_index(order)]; else pool = heap->cached_pools[order_to_index(order)]; - page = ion_page_pool_alloc(pool); + page = ion_page_pool_alloc(pool, nozero); return page; } diff --git a/drivers/staging/android/uapi/ion.h b/drivers/staging/android/uapi/ion.h index 9e21451149d0..f6dece538655 100644 --- a/drivers/staging/android/uapi/ion.h +++ b/drivers/staging/android/uapi/ion.h @@ -56,6 +56,18 @@ enum ion_heap_type { * when the buffer is mapped for dma */ #define ION_FLAG_CACHED 1 +/* + * the allocated buffer is not cleared with zeroes to avoid initialization + * overhead. Mapping to userspace is not allowed. + */ +#define ION_FLAG_NOZEROED 8 +/* + * the allocated buffer does not have dirty cache line allocated. In other + * words, ION flushes the cache even though allocation flags includes + * ION_FLAG_CACHED. This is required by some H/W drivers that wants to reduce + * overhead by explicit cache maintenance. + */ +#define ION_FLAG_SYNC_FORCE 32 /** * DOC: Ion Userspace API