From cb4d45a0276d187f64ffffbd43795291f6c9435e Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Mon, 30 Nov 2020 21:01:16 +0530 Subject: [PATCH 01/24] msm: kgsl: Allocate user_ctxt_record based on preemption feature flag Allocation of memory to user_ctxt_record is done based on adreno_device flag. If a context is created when preemption is disabled, the memory to user_ctxt_record is not allocated. Now if we enable preemption, through the sysfs knob, the device flag is again set. We may try to access user_ctxt_record in preemption_pre_ibsubmit(). So allocate memory to user_ctxt_record based on the preemption feature flag instead of preemption device flag. Change-Id: I947ef5a1bfbd8bff471427fae60d7fcd507b85a2 Signed-off-by: Puranam V G Tejaswi Signed-off-by: Harshitha Sai Neelati --- drivers/gpu/msm/adreno_a6xx_preempt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index c02af14413cd..32740a018909 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -783,7 +783,7 @@ void a6xx_preemption_context_destroy(struct kgsl_context *context) struct kgsl_device *device = context->device; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - if (!adreno_is_preemption_enabled(adreno_dev)) + if (!ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) return; gpumem_free_entry(context->user_ctxt_record); @@ -798,7 +798,7 @@ int a6xx_preemption_context_init(struct kgsl_context *context) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); uint64_t flags = 0; - if (!adreno_is_preemption_enabled(adreno_dev)) + if (!ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) return 0; if (context->flags & KGSL_CONTEXT_SECURE) From 934cf8f650be6ba8d71c2405b55010c21a684618 Mon Sep 17 00:00:00 2001 From: Vamsi krishna Gattupalli Date: Mon, 14 Dec 2020 11:06:27 +0530 Subject: [PATCH 02/24] msm:ADSPRPC :Fix to avoid Use after free in fastrpc_internal_munmap Added a check to validate map before freeing it to avoid Use after free scenario. Change-Id: I484391ff7c55c0689530a928a2821ee5a1a0e10c Signed-off-by: Vamsi krishna Gattupalli --- drivers/char/adsprpc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 882d3fe11f24..51fb97074556 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2755,8 +2755,13 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl, mutex_unlock(&fl->fl_map_mutex); if (err) goto bail; + VERIFY(err, map != NULL); + if (err) { + err = -EINVAL; + goto bail; + } VERIFY(err, !fastrpc_munmap_on_dsp(fl, map->raddr, - map->phys, map->size, map->flags)); + map->phys, map->size, map->flags)); if (err) goto bail; mutex_lock(&fl->fl_map_mutex); From 81f366d210f9aa855780060780ff5a95d2d59a92 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Wed, 30 Dec 2020 16:30:50 +0530 Subject: [PATCH 03/24] msm: kgsl: Protect the memdesc->gpuaddr in SVM use cases When SVM is being used there can only be one GPU address assigned to the memory descriptor. Don't allow the GPU address to be changed after it has been negotiated the first time by a process. Change-Id: Ic0dedbad2a1b3ccdc2c1598a6c501b2be288d64e Signed-off-by: Jordan Crouse Signed-off-by: Harshitha Sai Neelati Signed-off-by: Pranav Patel --- drivers/gpu/msm/kgsl.c | 29 ++++++++++++++++++++++++++--- drivers/gpu/msm/kgsl.h | 5 +++++ drivers/gpu/msm/kgsl_iommu.c | 7 ++++++- drivers/gpu/msm/kgsl_mmu.c | 10 ++++++++-- drivers/gpu/msm/kgsl_sharedmem.c | 1 + 5 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 6053d29ee013..4a1e302bef0c 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4269,19 +4269,34 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, { int ret; + /* + * Protect access to the gpuaddr here to prevent multiple vmas from + * trying to map a SVM region at the same time + */ + spin_lock(&entry->memdesc.lock); + + if (entry->memdesc.gpuaddr) { + spin_unlock(&entry->memdesc.lock); + return (unsigned long) -EBUSY; + } + ret = kgsl_mmu_set_svm_region(private->pagetable, (uint64_t) addr, (uint64_t) size); - if (ret != 0) - return ret; + if (ret != 0) { + spin_unlock(&entry->memdesc.lock); + return (unsigned long) ret; + } entry->memdesc.gpuaddr = (uint64_t) addr; + spin_unlock(&entry->memdesc.lock); + entry->memdesc.pagetable = private->pagetable; ret = kgsl_mmu_map(private->pagetable, &entry->memdesc); if (ret) { kgsl_mmu_put_gpuaddr(&entry->memdesc); - return ret; + return (unsigned long) ret; } kgsl_memfree_purge(private->pagetable, entry->memdesc.gpuaddr, @@ -4344,6 +4359,14 @@ static unsigned long _search_range(struct kgsl_process_private *private, result = _gpu_set_svm_region(private, entry, cpu, len); if (!IS_ERR_VALUE(result)) break; + /* + * _gpu_set_svm_region will return -EBUSY if we tried to set up + * SVM on an object that already has a GPU address. If + * that happens don't bother walking the rest of the + * region + */ + if ((long) result == -EBUSY) + return -EBUSY; trace_kgsl_mem_unmapped_area_collision(entry, cpu, len); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 87bdde8b3924..2d5f34d33115 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -229,6 +229,11 @@ struct kgsl_memdesc { struct page **pages; unsigned int page_count; unsigned int cur_bindings; + /* + * @lock: Spinlock to protect the gpuaddr from being accessed by + * multiple entities trying to map the same SVM region at once + */ + spinlock_t lock; }; /* diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index a5d12e0e60ea..82536f444ef8 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2523,6 +2523,11 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable, goto out; } + /* + * This path is only called in a non-SVM path with locks so we can be + * sure we aren't racing with anybody so we don't need to worry about + * taking the lock + */ ret = _insert_gpuaddr(pagetable, addr, size); if (ret == 0) { memdesc->gpuaddr = addr; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index a0fd3ece4e78..8e33ff0fa940 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -450,10 +450,16 @@ void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc) if (PT_OP_VALID(pagetable, put_gpuaddr) && (unmap_fail == 0)) pagetable->pt_ops->put_gpuaddr(memdesc); + memdesc->pagetable = NULL; + + /* + * If SVM tries to take a GPU address it will lose the race until the + * gpuaddr returns to zero so we shouldn't need to worry about taking a + * lock here + */ if (!kgsl_memdesc_is_global(memdesc)) memdesc->gpuaddr = 0; - memdesc->pagetable = NULL; } EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 498600dec691..636b4c02f4b2 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -801,6 +801,7 @@ void kgsl_memdesc_init(struct kgsl_device *device, (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT, ilog2(PAGE_SIZE)); kgsl_memdesc_set_align(memdesc, align); + spin_lock_init(&memdesc->lock); } int From 918ff3fbdfa770369fbaaaf67a1b079956e268b4 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 28 Dec 2020 16:06:42 +0530 Subject: [PATCH 04/24] msm: kgsl: Stop using memdesc->usermem It shouldn't be illegal for memory descriptors to have multiple virtual memory mappings under certain circumstances. If that is the case tracking a single usermem address for each memdesc no longer makes much sense. Get rid of the memdesc->usermem member and use an atomic counter to track mappings instead. Change-Id: Ic0dedbad31bafcd1019ccc8e68657cb7e3c72727 Signed-off-by: Jordan Crouse Signed-off-by: Harshitha Sai Neelati Signed-off-by: Pranav Patel --- drivers/gpu/msm/kgsl.c | 64 ++++++++++++++++++-------------- drivers/gpu/msm/kgsl.h | 11 +++--- drivers/gpu/msm/kgsl_debugfs.c | 22 +++++++---- drivers/gpu/msm/kgsl_sharedmem.c | 6 +-- drivers/gpu/msm/kgsl_trace.h | 8 ++-- 5 files changed, 62 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 6053d29ee013..28ae06da783c 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -265,6 +265,7 @@ kgsl_mem_entry_create(void) kref_get(&entry->refcount); } + atomic_set(&entry->map_count, 0); return entry; } #ifdef CONFIG_DMA_SHARED_BUFFER @@ -459,9 +460,6 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) type = kgsl_memdesc_usermem_type(&entry->memdesc); entry->priv->stats[type].cur -= entry->memdesc.size; - if (type != KGSL_MEM_ENTRY_ION) - entry->priv->gpumem_mapped -= entry->memdesc.mapsize; - spin_unlock(&entry->priv->mem_lock); kgsl_mmu_put_gpuaddr(&entry->memdesc); @@ -2129,7 +2127,7 @@ static int check_vma(unsigned long hostptr, u64 size) return true; } -static int memdesc_sg_virt(struct kgsl_memdesc *memdesc) +static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, unsigned long useraddr) { int ret = 0; long npages = 0, i; @@ -2152,13 +2150,13 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc) } down_read(¤t->mm->mmap_sem); - if (!check_vma(memdesc->useraddr, memdesc->size)) { + if (!check_vma(useraddr, memdesc->size)) { up_read(¤t->mm->mmap_sem); ret = -EFAULT; goto out; } - npages = get_user_pages(memdesc->useraddr, sglen, write, pages, NULL); + npages = get_user_pages(useraddr, sglen, write, pages, NULL); up_read(¤t->mm->mmap_sem); ret = (npages < 0) ? (int)npages : 0; @@ -2196,7 +2194,6 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, entry->memdesc.pagetable = pagetable; entry->memdesc.size = (uint64_t) size; - entry->memdesc.useraddr = hostptr; entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR; if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) { @@ -2204,15 +2201,15 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, /* Register the address in the database */ ret = kgsl_mmu_set_svm_region(pagetable, - (uint64_t) entry->memdesc.useraddr, (uint64_t) size); + (uint64_t) hostptr, (uint64_t) size); if (ret) return ret; - entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr; + entry->memdesc.gpuaddr = (uint64_t) hostptr; } - return memdesc_sg_virt(&entry->memdesc); + return memdesc_sg_virt(&entry->memdesc, hostptr); } #ifdef CONFIG_DMA_SHARED_BUFFER @@ -2297,8 +2294,7 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, return ret; } - /* Setup the user addr/cache mode for cache operations */ - entry->memdesc.useraddr = hostptr; + /* Setup the cache mode for cache operations */ _setup_cache_mode(entry, vma); up_read(¤t->mm->mmap_sem); return 0; @@ -3311,7 +3307,12 @@ long kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv, param->flags = (unsigned int) entry->memdesc.flags; param->size = (size_t) entry->memdesc.size; param->mmapsize = (size_t) kgsl_memdesc_footprint(&entry->memdesc); - param->useraddr = entry->memdesc.useraddr; + /* + * Entries can have multiple user mappings so thre isn't any one address + * we can report. Plus, the user should already know their mappings, so + * there isn't any value in reporting it back to them. + */ + param->useraddr = 0; kgsl_mem_entry_put(entry); return result; @@ -3780,9 +3781,6 @@ static int _sparse_bind(struct kgsl_process_private *process, if (memdesc->gpuaddr) return -EINVAL; - if (memdesc->useraddr != 0) - return -EINVAL; - pagetable = memdesc->pagetable; /* Clear out any mappings */ @@ -4062,7 +4060,12 @@ long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv, param->flags = entry->memdesc.flags; param->size = entry->memdesc.size; param->va_len = kgsl_memdesc_footprint(&entry->memdesc); - param->va_addr = (uint64_t) entry->memdesc.useraddr; + /* + * Entries can have multiple user mappings so thre isn't any one address + * we can report. Plus, the user should already know their mappings, so + * there isn't any value in reporting it back to them. + */ + param->va_addr = 0; kgsl_mem_entry_put(entry); return 0; @@ -4169,24 +4172,21 @@ static void kgsl_gpumem_vm_open(struct vm_area_struct *vma) if (kgsl_mem_entry_get(entry) == 0) vma->vm_private_data = NULL; + + atomic_inc(&entry->map_count); } static int kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct kgsl_mem_entry *entry = vma->vm_private_data; - int ret; if (!entry) return VM_FAULT_SIGBUS; if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault) return VM_FAULT_SIGBUS; - ret = entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); - if ((ret == 0) || (ret == VM_FAULT_NOPAGE)) - entry->priv->gpumem_mapped += PAGE_SIZE; - - return ret; + return entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); } static void @@ -4197,7 +4197,13 @@ kgsl_gpumem_vm_close(struct vm_area_struct *vma) if (!entry) return; - entry->memdesc.useraddr = 0; + /* + * Remove the memdesc from the mapped stat once all the mappings have + * gone away + */ + if (!atomic_dec_return(&entry->map_count)) + entry->priv->gpumem_mapped -= entry->memdesc.size; + kgsl_mem_entry_put(entry); } @@ -4236,7 +4242,8 @@ get_mmap_entry(struct kgsl_process_private *private, } } - if (entry->memdesc.useraddr != 0) { + /* Don't allow ourselves to remap user memory */ + if (entry->memdesc.flags & KGSL_MEMFLAGS_USERMEM_ADDR) { ret = -EBUSY; goto err_put; } @@ -4563,9 +4570,10 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_file = file; - entry->memdesc.useraddr = vma->vm_start; + if (atomic_inc_return(&entry->map_count) == 1) + entry->priv->gpumem_mapped += entry->memdesc.size; - trace_kgsl_mem_mmap(entry); + trace_kgsl_mem_mmap(entry, vma->vm_start); return 0; } diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 87bdde8b3924..41dbe2c0e4b1 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -196,11 +196,9 @@ struct kgsl_memdesc_ops { * @pagetable: Pointer to the pagetable that the object is mapped in * @hostptr: Kernel virtual address * @hostptr_count: Number of threads using hostptr - * @useraddr: User virtual address (if applicable) * @gpuaddr: GPU virtual address * @physaddr: Physical address of the memory object * @size: Size of the memory object - * @mapsize: Size of memory mapped in userspace * @priv: Internal flags and settings * @sgt: Scatter gather table for allocated pages * @ops: Function hooks for the memdesc memory type @@ -215,11 +213,9 @@ struct kgsl_memdesc { struct kgsl_pagetable *pagetable; void *hostptr; unsigned int hostptr_count; - unsigned long useraddr; uint64_t gpuaddr; phys_addr_t physaddr; uint64_t size; - uint64_t mapsize; unsigned int priv; struct sg_table *sgt; struct kgsl_memdesc_ops *ops; @@ -277,6 +273,11 @@ struct kgsl_mem_entry { struct work_struct work; spinlock_t bind_lock; struct rb_root bind_tree; + /* + * @map_count: Count how many vmas this object is mapped in - used for + * debugfs accounting + */ + atomic_t map_count; }; struct kgsl_device_private; diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index ead45852f28f..2a6e60883637 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2008-2017,2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2008-2017,2020-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -152,7 +152,11 @@ static int print_mem_entry(void *data, void *ptr) flags[3] = get_alignflag(m); flags[4] = get_cacheflag(m); flags[5] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-'; - flags[6] = (m->useraddr) ? 'Y' : 'N'; + /* + * Show Y if at least one vma has this entry + * mapped (could be multiple) + */ + flags[6] = atomic_read(&entry->map_count) ? 'Y' : 'N'; flags[7] = kgsl_memdesc_is_secured(m) ? 's' : '-'; flags[8] = m->flags & KGSL_MEMFLAGS_SPARSE_PHYS ? 'P' : '-'; flags[9] = '\0'; @@ -163,12 +167,16 @@ static int print_mem_entry(void *data, void *ptr) kgsl_get_egl_counts(entry, &egl_surface_count, &egl_image_count); - seq_printf(s, "%pK %pK %16llu %5d %9s %10s %16s %5d %16llu %6d %6d", + seq_printf(s, "%pK %d %16llu %5d %9s %10s %16s %5d %16d %6d %6d", (uint64_t *)(uintptr_t) m->gpuaddr, - (unsigned long *) m->useraddr, - m->size, entry->id, flags, + /* + * Show zero for the useraddr - we can't reliably track + * that value for multiple vmas anyway + */ + 0, m->size, entry->id, flags, memtype_str(usermem_type), - usage, (m->sgt ? m->sgt->nents : 0), m->mapsize, + usage, (m->sgt ? m->sgt->nents : 0), + atomic_read(&entry->map_count), egl_surface_count, egl_image_count); if (entry->metadata[0] != 0) @@ -239,7 +247,7 @@ static int process_mem_seq_show(struct seq_file *s, void *ptr) if (ptr == SEQ_START_TOKEN) { seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s\n", "gpuaddr", "useraddr", "size", "id", "flags", "type", - "usage", "sglen", "mapsize", "eglsrf", "eglimg"); + "usage", "sglen", "mapcount", "eglsrf", "eglimg"); return 0; } else return print_mem_entry(s, ptr); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 498600dec691..37491532ffd8 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -445,8 +445,6 @@ static int kgsl_page_alloc_vmfault(struct kgsl_memdesc *memdesc, get_page(page); vmf->page = page; - memdesc->mapsize += PAGE_SIZE; - return 0; } @@ -577,8 +575,6 @@ static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc, else if (ret == -EFAULT) return VM_FAULT_SIGBUS; - memdesc->mapsize += PAGE_SIZE; - return VM_FAULT_NOPAGE; } diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index 478fc5feddac..b40a16122e86 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017,2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017,2020-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -432,9 +432,9 @@ TRACE_EVENT(kgsl_mem_alloc, TRACE_EVENT(kgsl_mem_mmap, - TP_PROTO(struct kgsl_mem_entry *mem_entry), + TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned long useraddr), - TP_ARGS(mem_entry), + TP_ARGS(mem_entry, useraddr), TP_STRUCT__entry( __field(unsigned long, useraddr) @@ -446,7 +446,7 @@ TRACE_EVENT(kgsl_mem_mmap, ), TP_fast_assign( - __entry->useraddr = mem_entry->memdesc.useraddr; + __entry->useraddr = useraddr; __entry->gpuaddr = mem_entry->memdesc.gpuaddr; __entry->size = mem_entry->memdesc.size; kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage), From 4ce0db5024fc81b5ec0f3dbc887c110eb9aeba9b Mon Sep 17 00:00:00 2001 From: Archana Sriram Date: Mon, 14 Dec 2020 16:55:35 +0530 Subject: [PATCH 05/24] msm: kgsl: Correct the refcount on current process PID In kgsl_process_private_new() function there is inconsistency in the refcount of current process PID. Fix this to avoid overflowing of reference counter leading to use after free of this struct. Change-Id: I6291b9a05e139337e7f8471d0f9409fc839969a3 Signed-off-by: Archana Sriram --- drivers/gpu/msm/kgsl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 6053d29ee013..cc9783805d11 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -916,17 +916,24 @@ static struct kgsl_process_private *kgsl_process_private_new( list_for_each_entry(private, &kgsl_driver.process_list, list) { if (private->pid == cur_pid) { if (!kgsl_process_private_get(private)) { - put_pid(cur_pid); private = ERR_PTR(-EINVAL); } + /* + * We need to hold only one reference to the PID for + * each process struct to avoid overflowing the + * reference counter which can lead to use-after-free. + */ + put_pid(cur_pid); return private; } } /* Create a new object */ private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL); - if (private == NULL) + if (private == NULL) { + put_pid(cur_pid); return ERR_PTR(-ENOMEM); + } kref_init(&private->refcount); From a7fd5812f90fcb5d8314f09966f326da54d4a301 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Fri, 19 Feb 2021 23:35:25 +0530 Subject: [PATCH 06/24] msm: kgsl: Access map_count only if entry is successfully allocated In kgsl_mem_entry_create, access map_count only if entry is allocated successfully to avoid invalid access. Change-Id: I57bce1aec2da6a27b6d13dbee96ed86a45c9660c Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 3a84ce41d788..c9e853007c86 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -263,9 +263,9 @@ kgsl_mem_entry_create(void) kref_init(&entry->refcount); /* put this ref in userspace memory alloc and map ioctls */ kref_get(&entry->refcount); + atomic_set(&entry->map_count, 0); } - atomic_set(&entry->map_count, 0); return entry; } #ifdef CONFIG_DMA_SHARED_BUFFER From 60dc8c0a099cf2bb0f681c49a6d4785ce46fa5f0 Mon Sep 17 00:00:00 2001 From: Sharath Chandra Vurukala Date: Fri, 4 Sep 2020 20:20:25 +0530 Subject: [PATCH 07/24] net:sockev: hold file reference till the sock event is sent hold file reference till the sock event is sent. Change-Id: I14d581f210c86e5771bec22a9aca7c78630e9ac1 Signed-off-by: Sharath Chandra Vurukala --- net/socket.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/socket.c b/net/socket.c index f16035c7ad33..4fac892daba9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1426,9 +1426,10 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) (struct sockaddr *) &address, addrlen); } - fput_light(sock->file, fput_needed); if (!err) sockev_notify(SOCKEV_BIND, sock); + + fput_light(sock->file, fput_needed); } return err; } @@ -1455,9 +1456,10 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog) if (!err) err = sock->ops->listen(sock, backlog); - fput_light(sock->file, fput_needed); if (!err) sockev_notify(SOCKEV_LISTEN, sock); + + fput_light(sock->file, fput_needed); } return err; } From ddc41aeaf8432ac2f419ad43d13cb5c5a86b1d6a Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Mon, 1 Feb 2021 17:02:57 +0530 Subject: [PATCH 08/24] crypto: Fix possible stack out-of-bound error Adding fix to check the upper limit on the length of the destination array while copying elements from source address to avoid stack out of bound error. Change-Id: I39d5768fa97f9d269cfb101a389bb771d13c7538 Signed-off-by: Monika Singh --- drivers/crypto/msm/qce50.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index cf539f1107dc..3215b9543ff4 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -1,7 +1,7 @@ /* * QTI Crypto Engine driver. * - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -870,6 +870,11 @@ static int _ce_setup_cipher(struct qce_device *pce_dev, struct qce_req *creq, break; case CIPHER_ALG_3DES: if (creq->mode != QCE_MODE_ECB) { + if (ivsize > MAX_IV_LENGTH) { + pr_err("%s: error: Invalid length parameter\n", + __func__); + return -EINVAL; + } _byte_stream_to_net_words(enciv32, creq->iv, ivsize); pce = cmdlistinfo->encr_cntr_iv; pce->data = enciv32[0]; @@ -918,6 +923,11 @@ static int _ce_setup_cipher(struct qce_device *pce_dev, struct qce_req *creq, } } if (creq->mode != QCE_MODE_ECB) { + if (ivsize > MAX_IV_LENGTH) { + pr_err("%s: error: Invalid length parameter\n", + __func__); + return -EINVAL; + } if (creq->mode == QCE_MODE_XTS) _byte_stream_swap_to_net_words(enciv32, creq->iv, ivsize); From c86a1b0afc95080103764aebc6069cd768c89e82 Mon Sep 17 00:00:00 2001 From: Jeya R Date: Thu, 18 Mar 2021 14:04:49 +0530 Subject: [PATCH 09/24] msm: adsprpc: overflow vulnerability by race condition in adsprpc driver Create local copy of current->comm to avoid the possibility of modification in race condition. Change-Id: Ie10f6577ed7edb9279a36039348e7a1ad25239f9 Acked-by: Nishant Chaubey Signed-off-by: Jeya R --- drivers/char/adsprpc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 51fb97074556..debb82d9ca4f 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -3604,22 +3604,26 @@ static int fastrpc_set_process_info(struct fastrpc_file *fl) { int err = 0, buf_size = 0; char strpid[PID_SIZE]; + char cur_comm[TASK_COMM_LEN]; + memcpy(cur_comm, current->comm, TASK_COMM_LEN); + cur_comm[TASK_COMM_LEN-1] = '\0'; fl->tgid = current->tgid; snprintf(strpid, PID_SIZE, "%d", current->pid); - buf_size = strlen(current->comm) + strlen("_") + strlen(strpid) + 1; + buf_size = strlen(cur_comm) + strlen("_") + strlen(strpid) + 1; fl->debug_buf = kzalloc(buf_size, GFP_KERNEL); if (!fl->debug_buf) { err = -ENOMEM; return err; } - snprintf(fl->debug_buf, UL_SIZE, "%.10s%s%d", - current->comm, "_", current->pid); + snprintf(fl->debug_buf, buf_size, "%.10s%s%d", + cur_comm, "_", current->pid); fl->debugfs_file = debugfs_create_file(fl->debug_buf, 0644, debugfs_root, fl, &debugfs_fops); if (!fl->debugfs_file) pr_warn("Error: %s: %s: failed to create debugfs file %s\n", - current->comm, __func__, fl->debug_buf); + cur_comm, __func__, fl->debug_buf); + return err; } From f1a84321f9e3d112d73e054b398f85bce4980341 Mon Sep 17 00:00:00 2001 From: Jeya R Date: Thu, 10 Jun 2021 13:03:44 +0530 Subject: [PATCH 10/24] msm: adsprpc: Fix race condition in internal_control Protect add and update qos request with mutex to avoid race condition when multiple threads try to add or update request simultaneously. Change-Id: Id33b81bf85246ec69c72bad59cca068e627bb21d Acked-by: Deepika Singh Signed-off-by: Jeya R --- drivers/char/adsprpc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index debb82d9ca4f..2ef635838671 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -407,6 +407,7 @@ struct fastrpc_file { struct mutex perf_mutex; struct pm_qos_request pm_qos_req; int qos_request; + struct mutex pm_qos_mutex; struct mutex map_mutex; struct mutex fl_map_mutex; int refcount; @@ -3096,6 +3097,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl) mutex_destroy(&fl->perf_mutex); mutex_destroy(&fl->fl_map_mutex); mutex_destroy(&fl->map_mutex); + mutex_destroy(&fl->pm_qos_mutex); kfree(fl); return 0; } @@ -3597,6 +3599,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) hlist_add_head(&fl->hn, &me->drivers); spin_unlock(&me->hlock); mutex_init(&fl->perf_mutex); + mutex_init(&fl->pm_qos_mutex); return 0; } @@ -3697,12 +3700,14 @@ static int fastrpc_internal_control(struct fastrpc_file *fl, VERIFY(err, latency != 0); if (err) goto bail; + mutex_lock(&fl->pm_qos_mutex); if (!fl->qos_request) { pm_qos_add_request(&fl->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency); fl->qos_request = 1; } else pm_qos_update_request(&fl->pm_qos_req, latency); + mutex_unlock(&fl->pm_qos_mutex); break; case FASTRPC_CONTROL_SMMU: if (!me->legacy) From f5f9e4b492d45cc985fcf78734798282e1c49dd1 Mon Sep 17 00:00:00 2001 From: Swathi K Date: Fri, 16 Jul 2021 12:43:17 +0530 Subject: [PATCH 11/24] msm: adsprpc: Handle UAF in process shell memory Added flag to indicate memory used in process initialization. And, this memory would not removed in internal unmap to avoid UAF or double free. Change-Id: Ifa621dee171b3d1f98b82302c847f4d767f3e736 Signed-off-by: Swathi K --- drivers/char/adsprpc.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 2ef635838671..0d27c744e39a 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -352,6 +352,7 @@ struct fastrpc_mmap { int uncached; int secure; uintptr_t attr; + bool is_filemap; /*flag to indicate map used in process init*/ }; enum fastrpc_perfkeys { @@ -697,9 +698,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, spin_lock(&me->hlock); hlist_for_each_entry_safe(map, n, &me->maps, hn) { - if (map->raddr == va && + if (map->refs == 1 && map->raddr == va && map->raddr + map->len == va + len && - map->refs == 1) { + /*Remove map if not used in process initialization*/ + !map->is_filemap) { match = map; hlist_del_init(&map->hn); break; @@ -711,9 +713,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, return 0; } hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - if (map->raddr == va && + if (map->refs == 1 && map->raddr == va && map->raddr + map->len == va + len && - map->refs == 1) { + /*Remove map if not used in process initialization*/ + !map->is_filemap) { match = map; hlist_del_init(&map->hn); break; @@ -853,6 +856,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, map->fl = fl; map->fd = fd; map->attr = attr; + map->is_filemap = false; if (mflags == ADSP_MMAP_HEAP_ADDR || mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { unsigned long dma_attrs = DMA_ATTR_SKIP_ZEROING | @@ -2233,6 +2237,8 @@ static int fastrpc_init_process(struct fastrpc_file *fl, mutex_lock(&fl->fl_map_mutex); VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, 0, init->file, init->filelen, mflags, &file)); + if (file) + file->is_filemap = true; mutex_unlock(&fl->fl_map_mutex); if (err) goto bail; From 2b282ad1d815447e0ad4c2bf8cc59552c2e4dc3a Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Thu, 8 Jul 2021 11:17:16 +0530 Subject: [PATCH 12/24] disp: msm: sde: add null check for drm file in msm_release Drm file is not set to NULL after freeing it from drm release. This can result in use-after-free issues in some scenarios. Add a mutex lock and other proper null checks to prevent such issues. Change-Id: Ic35b0a76166b0f47a354b1737e6f4c3ac1437ed4 Signed-off-by: Nirmal Abraham Signed-off-by: Althaf Neelanchirayil --- drivers/gpu/drm/msm/msm_drv.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index ff8c1cd9aba8..9e2f08c89d78 100755 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, 2020-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -57,6 +57,8 @@ #define MSM_VERSION_MINOR 2 #define MSM_VERSION_PATCHLEVEL 0 +static DEFINE_MUTEX(msm_release_lock); + static void msm_fb_output_poll_changed(struct drm_device *dev) { struct msm_drm_private *priv = NULL; @@ -1420,13 +1422,25 @@ void msm_mode_object_event_notify(struct drm_mode_object *obj, static int msm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; - struct drm_minor *minor = file_priv->minor; - struct drm_device *dev = minor->dev; - struct msm_drm_private *priv = dev->dev_private; + struct drm_minor *minor; + struct drm_device *dev; + struct msm_drm_private *priv; struct msm_drm_event *node, *temp, *tmp_node; u32 count; unsigned long flags; LIST_HEAD(tmp_head); + int ret = 0; + + mutex_lock(&msm_release_lock); + + if (!file_priv) { + ret = -EINVAL; + goto end; + } + + minor = file_priv->minor; + dev = minor->dev; + priv = dev->dev_private; spin_lock_irqsave(&dev->event_lock, flags); list_for_each_entry_safe(node, temp, &priv->client_event_list, @@ -1454,7 +1468,11 @@ static int msm_release(struct inode *inode, struct file *filp) kfree(node); } - return drm_release(inode, filp); + ret = drm_release(inode, filp); + filp->private_data = NULL; +end: + mutex_unlock(&msm_release_lock); + return ret; } /** From b87350e73216e590c29c7291827bafd2f4ebfcb1 Mon Sep 17 00:00:00 2001 From: Rajesh Kemisetti Date: Wed, 6 Jan 2021 19:33:46 +0530 Subject: [PATCH 13/24] msm: kgsl: Deregister gpu address on memdesc_sg_virt failure When memdesc_sg_virt returns error in kgsl_setup_anon_useraddr function, the gpu address registered in SVM region will not be deregistered. This change deregisters the gpu address on memdesc_sg_virt failure. Change-Id: Ic99167e283a0c6331bb9f5f0b608b6cdb3c918e4 Signed-off-by: Neeraja P Signed-off-by: Rajesh Kemisetti --- drivers/gpu/msm/kgsl.c | 10 ++++++++-- drivers/gpu/msm/kgsl_mmu.c | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index c9e853007c86..edfb2cabff08 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2195,6 +2195,8 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, { /* Map an anonymous memory chunk */ + int ret; + if (size == 0 || offset != 0 || !IS_ALIGNED(size, PAGE_SIZE)) return -EINVAL; @@ -2204,7 +2206,6 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR; if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) { - int ret; /* Register the address in the database */ ret = kgsl_mmu_set_svm_region(pagetable, @@ -2216,7 +2217,12 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, entry->memdesc.gpuaddr = (uint64_t) hostptr; } - return memdesc_sg_virt(&entry->memdesc, hostptr); + ret = memdesc_sg_virt(&entry->memdesc, hostptr); + + if (ret && kgsl_memdesc_use_cpu_map(&entry->memdesc)) + kgsl_mmu_put_gpuaddr(&entry->memdesc); + + return ret; } #ifdef CONFIG_DMA_SHARED_BUFFER diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 8e33ff0fa940..456c0e1dacfe 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -439,7 +439,8 @@ void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc) if (memdesc->size == 0 || memdesc->gpuaddr == 0) return; - if (!kgsl_memdesc_is_global(memdesc)) + if (!kgsl_memdesc_is_global(memdesc) && + (KGSL_MEMDESC_MAPPED & memdesc->priv)) unmap_fail = kgsl_mmu_unmap(pagetable, memdesc); /* From e25a3ff8d8b1872ac16ebe1d828b784527eba6fe Mon Sep 17 00:00:00 2001 From: Deepak Kumar Singh Date: Tue, 21 Sep 2021 16:23:04 +0530 Subject: [PATCH 14/24] soc: qcom: glink: wait for tx blocked signal response Until tx blocked signal response is received, allowing tx may again fill the fifo. As tx_blocked_signal_sent is already true glink will not be able to send tx blocked signal again to remote host. Do not allow tx unless response for previous tx blocked signal is received. CRs-Fixed: 3039195 Change-Id: Ib8137740f5a02958645934b55e33673394412919 Signed-off-by: Deepak Kumar Singh --- drivers/soc/qcom/glink_smem_native_xprt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index 0b4b5f4dbbdf..dd6eecc3a629 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -701,11 +701,12 @@ static int fifo_tx(struct edge_info *einfo, const void *data, int len) DEFINE_WAIT(wait); spin_lock_irqsave(&einfo->write_lock, flags); - while (fifo_write_avail(einfo) < len) { + while (fifo_write_avail(einfo) < len || einfo->tx_blocked_signal_sent) { send_tx_blocked_signal(einfo); prepare_to_wait(&einfo->tx_blocked_queue, &wait, TASK_UNINTERRUPTIBLE); - if (fifo_write_avail(einfo) < len && !einfo->in_ssr) { + if ((fifo_write_avail(einfo) < len + || einfo->tx_blocked_signal_sent) && !einfo->in_ssr) { spin_unlock_irqrestore(&einfo->write_lock, flags); schedule(); spin_lock_irqsave(&einfo->write_lock, flags); @@ -2094,7 +2095,7 @@ static int tx_data(struct glink_transport_if *if_ptr, uint16_t cmd_id, } /* Need enough space to write the command and some data */ - if (size <= sizeof(cmd)) { + if (size <= sizeof(cmd) || einfo->tx_blocked_signal_sent) { einfo->tx_resume_needed = true; send_tx_blocked_signal(einfo); spin_unlock_irqrestore(&einfo->write_lock, flags); From 77d3ec60d1a29cea2548b77ed7b980349d9acdfb Mon Sep 17 00:00:00 2001 From: Kamal Agrawal Date: Mon, 13 Sep 2021 15:59:25 +0530 Subject: [PATCH 15/24] msm: kgsl: Fix out of bound write in adreno_profile_submit_time Make sure there is enough room in the memory descriptor to store the entire profiling buffer object. Change-Id: I1e1c73097bb2bba9645b0a3c66fdbbc71d8ba8fa Signed-off-by: Kamal Agrawal --- drivers/gpu/msm/kgsl_drawobj.c | 35 +++++++++++----------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index 1bfc9050bb47..b0dd4ac598b3 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2019,2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -569,6 +569,7 @@ static void add_profiling_buffer(struct kgsl_device *device, { struct kgsl_mem_entry *entry; struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj); + u64 start; if (!(drawobj->flags & KGSL_DRAWOBJ_PROFILING)) return; @@ -585,7 +586,14 @@ static void add_profiling_buffer(struct kgsl_device *device, gpuaddr); if (entry != NULL) { - if (!kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) { + start = id ? (entry->memdesc.gpuaddr + offset) : gpuaddr; + /* + * Make sure there is enough room in the object to store the + * entire profiling buffer object + */ + if (!kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size) || + !kgsl_gpuaddr_in_memdesc(&entry->memdesc, start, + sizeof(struct kgsl_drawobj_profiling_buffer))) { kgsl_mem_entry_put(entry); entry = NULL; } @@ -598,28 +606,7 @@ static void add_profiling_buffer(struct kgsl_device *device, return; } - - if (!id) { - cmdobj->profiling_buffer_gpuaddr = gpuaddr; - } else { - u64 off = offset + sizeof(struct kgsl_drawobj_profiling_buffer); - - /* - * Make sure there is enough room in the object to store the - * entire profiling buffer object - */ - if (off < offset || off >= entry->memdesc.size) { - dev_err(device->dev, - "ignore invalid profile offset ctxt %d id %d offset %lld gpuaddr %llx size %lld\n", - drawobj->context->id, id, offset, gpuaddr, size); - kgsl_mem_entry_put(entry); - return; - } - - cmdobj->profiling_buffer_gpuaddr = - entry->memdesc.gpuaddr + offset; - } - + cmdobj->profiling_buffer_gpuaddr = start; cmdobj->profiling_buf_entry = entry; } From cd3a09b4df784a932b3e56410ffa54648145a674 Mon Sep 17 00:00:00 2001 From: srikanthreddy ponogoti Date: Wed, 20 Oct 2021 16:41:38 +0530 Subject: [PATCH 16/24] disp: msm: sde: protect file private structure with mutex lock Access file private data structures inside the mutex lock only to avoid use-after-free issues. Change-Id: Ibae25aa31eeb7a7afada3dd0ecc236615223dfc9 Signed-off-by: srikanthreddy ponogoti --- drivers/gpu/drm/msm/msm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 9e2f08c89d78..a755c19dbfa8 100755 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1421,7 +1421,7 @@ void msm_mode_object_event_notify(struct drm_mode_object *obj, static int msm_release(struct inode *inode, struct file *filp) { - struct drm_file *file_priv = filp->private_data; + struct drm_file *file_priv; struct drm_minor *minor; struct drm_device *dev; struct msm_drm_private *priv; @@ -1433,6 +1433,7 @@ static int msm_release(struct inode *inode, struct file *filp) mutex_lock(&msm_release_lock); + file_priv = filp->private_data; if (!file_priv) { ret = -EINVAL; goto end; From a511cc2fc4e7ad81a6b9cc6d3285862e5f9f284e Mon Sep 17 00:00:00 2001 From: Akhil P Oommen Date: Wed, 20 Oct 2021 12:50:29 +0530 Subject: [PATCH 17/24] msm: kgsl: Update register protection config Update the register protection configuration as per the latest recommendation. Change-Id: I70365268e8e4c7ee4ff28538f22e970822e4edf0 Signed-off-by: Akhil P Oommen --- drivers/gpu/msm/adreno_a6xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 754e41987fe6..5a3a26d0083f 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018,2020 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018,2020-2021, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -277,6 +277,7 @@ static struct a6xx_protected_regs { { 0x8D0, 0x23, 0 }, { 0x980, 0x4, 0 }, { 0xA630, 0x0, 1 }, + { 0x1b400, 0x1fff, 1 }, }; /* IFPC & Preemption static powerup restore list */ From ca935e323f5990b50708243df136a9c5942ac2c7 Mon Sep 17 00:00:00 2001 From: Kamal Agrawal Date: Mon, 26 Jul 2021 16:16:48 +0530 Subject: [PATCH 18/24] msm: kgsl: Fix memory leak for anonymous buffers Currently, clean up is not done properly for anonymous buffer (KGSL_MEM_ENTRY_USER). Fix it by freeing up resources allocated during memdesc_sg_virt. Change-Id: I75bff2e718b494c102a8075a5f27323e1823b212 Signed-off-by: Kamal Agrawal Signed-off-by: Rajesh Kemisetti --- drivers/gpu/msm/kgsl.c | 97 +++++++++++++++----------------- drivers/gpu/msm/kgsl_sharedmem.c | 1 + 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index edfb2cabff08..4c6078edb66e 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -269,8 +269,12 @@ kgsl_mem_entry_create(void) return entry; } #ifdef CONFIG_DMA_SHARED_BUFFER -static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta) +static void kgsl_destroy_ion(struct kgsl_memdesc *memdesc) { + struct kgsl_mem_entry *entry = container_of(memdesc, + struct kgsl_mem_entry, memdesc); + struct kgsl_dma_buf_meta *meta = entry->priv_data; + if (meta != NULL) { dma_buf_unmap_attachment(meta->attach, meta->table, DMA_FROM_DEVICE); @@ -278,14 +282,45 @@ static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta) dma_buf_put(meta->dmabuf); kfree(meta); } -} -#else -static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta) -{ + /* + * Ion takes care of freeing the sg_table for us so + * clear the sg table to ensure kgsl_sharedmem_free + * doesn't try to free it again + */ + memdesc->sgt = NULL; } + +static struct kgsl_memdesc_ops kgsl_dmabuf_ops = { + .free = kgsl_destroy_ion, +}; #endif +static void kgsl_destroy_anon(struct kgsl_memdesc *memdesc) +{ + int i = 0, j; + struct scatterlist *sg; + struct page *page; + + for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) { + page = sg_page(sg); + for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) { + /* + * Mark the page in the scatterlist as dirty if they + * were writable by the GPU. + */ + if (!(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY)) + set_page_dirty_lock(nth_page(page, j)); + + /* + * Put the page reference taken using get_user_pages + * during memdesc_sg_virt. + */ + put_page(nth_page(page, j)); + } + } +} + void kgsl_mem_entry_destroy(struct kref *kref) { @@ -307,41 +342,8 @@ kgsl_mem_entry_destroy(struct kref *kref) atomic_long_sub(entry->memdesc.size, &kgsl_driver.stats.mapped); - /* - * Ion takes care of freeing the sg_table for us so - * clear the sg table before freeing the sharedmem - * so kgsl_sharedmem_free doesn't try to free it again - */ - if (memtype == KGSL_MEM_ENTRY_ION) - entry->memdesc.sgt = NULL; - - if ((memtype == KGSL_MEM_ENTRY_USER) - && !(entry->memdesc.flags & KGSL_MEMFLAGS_GPUREADONLY)) { - int i = 0, j; - struct scatterlist *sg; - struct page *page; - /* - * Mark all of pages in the scatterlist as dirty since they - * were writable by the GPU. - */ - for_each_sg(entry->memdesc.sgt->sgl, sg, - entry->memdesc.sgt->nents, i) { - page = sg_page(sg); - for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) - set_page_dirty_lock(nth_page(page, j)); - } - } - kgsl_sharedmem_free(&entry->memdesc); - switch (memtype) { - case KGSL_MEM_ENTRY_ION: - kgsl_destroy_ion(entry->priv_data); - break; - default: - break; - } - kfree(entry); } EXPORT_SYMBOL(kgsl_mem_entry_destroy); @@ -2189,6 +2191,10 @@ out: return ret; } +static struct kgsl_memdesc_ops kgsl_usermem_ops = { + .free = kgsl_destroy_anon, +}; + static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, struct kgsl_mem_entry *entry, unsigned long hostptr, size_t offset, size_t size) @@ -2204,6 +2210,7 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, entry->memdesc.pagetable = pagetable; entry->memdesc.size = (uint64_t) size; entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR; + entry->memdesc.ops = &kgsl_usermem_ops; if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) { @@ -2495,11 +2502,6 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, return 0; unmap: - if (kgsl_memdesc_usermem_type(&entry->memdesc) == KGSL_MEM_ENTRY_ION) { - kgsl_destroy_ion(entry->priv_data); - entry->memdesc.sgt = NULL; - } - kgsl_sharedmem_free(&entry->memdesc); out: @@ -2596,6 +2598,7 @@ static int kgsl_setup_dma_buf(struct kgsl_device *device, entry->priv_data = meta; entry->memdesc.pagetable = pagetable; entry->memdesc.size = 0; + entry->memdesc.ops = &kgsl_dmabuf_ops; /* USE_CPU_MAP is not impemented for ION. */ entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ION; @@ -2801,14 +2804,6 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, return result; error_attach: - switch (kgsl_memdesc_usermem_type(&entry->memdesc)) { - case KGSL_MEM_ENTRY_ION: - kgsl_destroy_ion(entry->priv_data); - entry->memdesc.sgt = NULL; - break; - default: - break; - } kgsl_sharedmem_free(&entry->memdesc); error: /* Clear gpuaddr here so userspace doesn't get any wrong ideas */ diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index dc150bdf53e2..aa25ee888c96 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -996,6 +996,7 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) if (memdesc->sgt) { sg_free_table(memdesc->sgt); kfree(memdesc->sgt); + memdesc->sgt = NULL; } if (memdesc->pages) From 63b454fefb183771fd26dfb680c94f059ba4dcf2 Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Fri, 7 Jan 2022 02:20:41 +0530 Subject: [PATCH 19/24] msm: kgsl: Perform cache flush on the pages obtained using get_user_pages() Consider a scenario where user allocates anonymous memory but does not write to it. Here the physical pages are not yet allocated. Now when this memory is requested to be imported, a list of newly allocated zero pages is obtained using get_user_pages(). Currently cache flush is not done for these pages and hence GPU sees stale data. Fix this by performing cache flush on these pages. Change-Id: Id1e8aa20e8a9de112761732ed92f30c01088840b Signed-off-by: Puranam V G Tejaswi Signed-off-by: Sebanti Das Signed-off-by: Kamal Agrawal --- drivers/gpu/msm/kgsl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 4c6078edb66e..5d76314cd809 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,5 @@ /* Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2179,6 +2180,15 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, unsigned long useraddr) ret = sg_alloc_table_from_pages(memdesc->sgt, pages, npages, 0, memdesc->size, GFP_KERNEL); + + if (ret) + goto out; + + ret = kgsl_cache_range_op(memdesc, 0, memdesc->size, + KGSL_CACHE_OP_FLUSH); + + if (ret) + sg_free_table(memdesc->sgt); out: if (ret) { for (i = 0; i < npages; i++) From f61222b5e81034ab47facb32c4a1bb69634449a4 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Tue, 1 Mar 2022 20:17:37 +0530 Subject: [PATCH 20/24] msm: kgsl: Add a sysfs node to control performance counter reads Currently performance counters are global and can be read by anyone. Change the behaviour to disable reading global counters as default and add a sysfs node to enable/disable reads. Change-Id: Ic3785acd9bd7425c2a844ed103d7b870d9f80adf Signed-off-by: Mohammed Mirza Mandayappurath Manzoor Signed-off-by: Harshitha Sai Neelati Signed-off-by: Pankaj Gupta Signed-off-by: Sebanti Das --- drivers/gpu/msm/adreno.c | 3 +++ drivers/gpu/msm/adreno.h | 6 ++++++ drivers/gpu/msm/adreno_compat.c | 9 +++++++++ drivers/gpu/msm/adreno_ioctl.c | 9 +++++++++ drivers/gpu/msm/adreno_sysfs.c | 33 ++++++++++++++++++++++++++++++++- 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index be168688ae8d..284dba3f1c5d 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2018,2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1426,6 +1427,8 @@ static int adreno_probe(struct platform_device *pdev) adreno_debugfs_init(adreno_dev); adreno_profile_init(adreno_dev); + adreno_dev->perfcounter = false; + adreno_sysfs_init(adreno_dev); kgsl_pwrscale_init(&pdev->dev, CONFIG_QCOM_ADRENO_DEFAULT_GOVERNOR); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 43125221826a..e3e2e962daf6 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,5 @@ /* Copyright (c) 2008-2018,2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -578,6 +579,11 @@ struct adreno_device { bool gpuhtw_llc_slice_enable; unsigned int zap_loaded; unsigned int soc_hw_rev; + /* + * @perfcounter: Flag to clear perfcounters across contexts and + * controls perfcounter ioctl read + */ + bool perfcounter; }; /** diff --git a/drivers/gpu/msm/adreno_compat.c b/drivers/gpu/msm/adreno_compat.c index 1f806dabea25..3b15d0318a19 100644 --- a/drivers/gpu/msm/adreno_compat.c +++ b/drivers/gpu/msm/adreno_compat.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -260,6 +261,14 @@ static long adreno_ioctl_perfcounter_read_compat( struct kgsl_perfcounter_read_compat *read32 = data; struct kgsl_perfcounter_read read; + /* + * When performance counter zapping is enabled, the counters are cleared + * across context switches. Reading the counters when they are zapped is + * not permitted. + */ + if (!adreno_dev->perfcounter) + return -EPERM; + read.reads = (struct kgsl_perfcounter_read_group __user *) (uintptr_t)read32->reads; read.count = read32->count; diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index ff9a69a29130..04ae62abe3b8 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2018,2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -141,6 +142,14 @@ static long adreno_ioctl_perfcounter_read(struct kgsl_device_private *dev_priv, struct adreno_device *adreno_dev = ADRENO_DEVICE(dev_priv->device); struct kgsl_perfcounter_read *read = data; + /* + * When performance counter zapping is enabled, the counters are cleared + * across context switches. Reading the counters when they are zapped is + * not permitted. + */ + if (!adreno_dev->perfcounter) + return -EPERM; + return (long) adreno_perfcounter_read_group(adreno_dev, read->reads, read->count); } diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index a7aa93927a6c..9c10edd0a843 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -1,4 +1,5 @@ /* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -353,6 +354,31 @@ static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) return preempt->count; } +static unsigned int _perfcounter_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->perfcounter; +} + +static int _perfcounter_store(struct adreno_device *adreno_dev, + unsigned int val) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (adreno_dev->perfcounter == val) + return 0; + + mutex_lock(&device->mutex); + + /* Power down the GPU before changing the state */ + kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + adreno_dev->perfcounter = val; + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + + mutex_unlock(&device->mutex); + + return 0; +} + static ssize_t _sysfs_store_u32(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -457,6 +483,7 @@ static ADRENO_SYSFS_BOOL(hwcg); static ADRENO_SYSFS_BOOL(throttling); static ADRENO_SYSFS_BOOL(ifpc); static ADRENO_SYSFS_RO_U32(ifpc_count); +static ADRENO_SYSFS_BOOL(perfcounter); @@ -480,6 +507,7 @@ static const struct device_attribute *_attr_list[] = { &adreno_attr_ifpc.attr, &adreno_attr_ifpc_count.attr, &adreno_attr_preempt_count.attr, + &adreno_attr_perfcounter.attr, NULL, }; @@ -637,8 +665,11 @@ int adreno_sysfs_init(struct adreno_device *adreno_dev) ret = kgsl_create_device_sysfs_files(device->dev, _attr_list); /* Add the PPD directory and files */ - if (ret == 0) + if (ret == 0) { + /* Notify userspace */ + kobject_uevent(&device->dev->kobj, KOBJ_ADD); ppd_sysfs_init(adreno_dev); + } return 0; } From 58f8d1d2706ca76133ca3c1316651cddfe402550 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Tue, 1 Mar 2022 20:29:09 +0530 Subject: [PATCH 21/24] msm: kgsl: Zap performance counters across context switches Performance counter values need not be retained across contexts unless specifically requested for debug. Zap the counters by initialising perfcounter SRAM with 0's using GPU_RBBM_PERFCTR_SRAM_INIT_CMD. Add pm4 packets during context switches and add a KMD postamble packet to clear the counters during preemption. Do not enable perfcounter save and restore unless requested. Change-Id: I371779ce659c07a1cc664327f5ecdcf0374201d8 Signed-off-by: Mohammed Mirza Mandayappurath Manzoor Signed-off-by: Sebanti Das Signed-off-by: Pankaj Gupta --- drivers/gpu/msm/a6xx_reg.h | 3 ++ drivers/gpu/msm/adreno.h | 8 +++++ drivers/gpu/msm/adreno_a6xx_preempt.c | 49 ++++++++++++++++++++++++--- drivers/gpu/msm/adreno_iommu.c | 19 +++++++++++ drivers/gpu/msm/adreno_perfcounter.c | 7 ++-- drivers/gpu/msm/adreno_pm4types.h | 7 ++++ drivers/gpu/msm/adreno_ringbuffer.c | 3 +- 7 files changed, 89 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index e3a664e62577..0dc9bc1f0a99 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -395,6 +396,8 @@ #define A6XX_RBBM_PERFCTR_RBBM_SEL_2 0x509 #define A6XX_RBBM_PERFCTR_RBBM_SEL_3 0x50A #define A6XX_RBBM_PERFCTR_GPU_BUSY_MASKED 0x50B +#define A6XX_RBBM_PERFCTR_SRAM_INIT_CMD 0x50e +#define A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS 0x50f #define A6XX_RBBM_ISDB_CNT 0x533 diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index e3e2e962daf6..ea8ad562234a 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -35,6 +35,9 @@ #define DEVICE_3D_NAME "kgsl-3d" #define DEVICE_3D0_NAME "kgsl-3d0" +/* Index to preemption scratch buffer to store KMD postamble */ +#define KMD_POSTAMBLE_IDX 100 + /* ADRENO_DEVICE - Given a kgsl_device return the adreno device struct */ #define ADRENO_DEVICE(device) \ container_of(device, struct adreno_device, dev) @@ -252,6 +255,9 @@ struct adreno_gpudev; /* Time to allow preemption to complete (in ms) */ #define ADRENO_PREEMPT_TIMEOUT 10000 +#define PREEMPT_SCRATCH_ADDR(dev, id) \ + ((dev)->preempt.scratch.gpuaddr + (id * sizeof(u64))) + #define ADRENO_INT_BIT(a, _bit) (((a)->gpucore->gpudev->int_bits) ? \ (adreno_get_int(a, _bit) < 0 ? 0 : \ BIT(adreno_get_int(a, _bit))) : 0) @@ -288,6 +294,7 @@ enum adreno_preempt_states { * skipsaverestore: To skip saverestore during L1 preemption (for 6XX) * usesgmem: enable GMEM save/restore across preemption (for 6XX) * count: Track the number of preemptions triggered + * @postamble_len: Number of dwords in KMD postamble pm4 packet */ struct adreno_preemption { atomic_t state; @@ -299,6 +306,7 @@ struct adreno_preemption { bool skipsaverestore; bool usesgmem; unsigned int count; + u32 postamble_len; }; diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 32740a018909..a5068687185e 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2018,2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -544,13 +545,27 @@ unsigned int a6xx_preemption_pre_ibsubmit( if (context) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); struct adreno_ringbuffer *rb = drawctxt->rb; - uint64_t dest = adreno_dev->preempt.scratch.gpuaddr + - sizeof(u64) * rb->id; + uint64_t dest = PREEMPT_SCRATCH_ADDR(adreno_dev, rb->id); *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 2); cmds += cp_gpuaddr(adreno_dev, cmds, dest); *cmds++ = lower_32_bits(gpuaddr); *cmds++ = upper_32_bits(gpuaddr); + + /* + * Add a KMD post amble to clear the perf counters during + * preemption + */ + if (!adreno_dev->perfcounter) { + u64 kmd_postamble_addr = + PREEMPT_SCRATCH_ADDR(adreno_dev, KMD_POSTAMBLE_IDX); + + *cmds++ = cp_type7_packet(CP_SET_AMBLE, 3); + *cmds++ = lower_32_bits(kmd_postamble_addr); + *cmds++ = upper_32_bits(kmd_postamble_addr); + *cmds++ = ((CP_KMD_AMBLE_TYPE << 20) | GENMASK(22, 20)) + | (adreno_dev->preempt.postamble_len | GENMASK(19, 0)); + } } return (unsigned int) (cmds - cmds_orig); @@ -563,8 +578,7 @@ unsigned int a6xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb = adreno_dev->cur_rb; if (rb) { - uint64_t dest = adreno_dev->preempt.scratch.gpuaddr + - sizeof(u64) * rb->id; + uint64_t dest = PREEMPT_SCRATCH_ADDR(adreno_dev, rb->id); *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 2); cmds += cp_gpuaddr(adreno_dev, cmds, dest); @@ -769,6 +783,33 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) addr += A6XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE; } + /* + * First 8 dwords of the preemption scratch buffer is used to store the + * address for CP to save/restore VPC data. Reserve 11 dwords in the + * preemption scratch buffer from index KMD_POSTAMBLE_IDX for KMD + * postamble pm4 packets + */ + if (!adreno_dev->perfcounter) { + u32 *postamble = preempt->scratch.hostptr + + (KMD_POSTAMBLE_IDX * sizeof(u64)); + u32 count = 0; + + postamble[count++] = cp_type7_packet(CP_REG_RMW, 3); + postamble[count++] = A6XX_RBBM_PERFCTR_SRAM_INIT_CMD; + postamble[count++] = 0x0; + postamble[count++] = 0x1; + + postamble[count++] = cp_type7_packet(CP_WAIT_REG_MEM, 6); + postamble[count++] = 0x3; + postamble[count++] = A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS; + postamble[count++] = 0x0; + postamble[count++] = 0x1; + postamble[count++] = 0x1; + postamble[count++] = 0x0; + + preempt->postamble_len = count; + } + ret = a6xx_preemption_iommu_init(adreno_dev); err: diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c index db6dff212b64..032a19c1d37a 100644 --- a/drivers/gpu/msm/adreno_iommu.c +++ b/drivers/gpu/msm/adreno_iommu.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +14,7 @@ #include "adreno.h" #include "kgsl_sharedmem.h" #include "a3xx_reg.h" +#include "a6xx_reg.h" #include "adreno_pm4types.h" #define A5XX_PFP_PER_PROCESS_UCODE_VER 0x5FF064 @@ -586,6 +588,12 @@ static unsigned int _adreno_iommu_set_pt_v2_a6xx(struct kgsl_device *device, cmds += _adreno_iommu_add_idle_cmds(adreno_dev, cmds); cmds += cp_wait_for_me(adreno_dev, cmds); + /* Clear performance counters during contect switches */ + if (!adreno_dev->perfcounter) { + *cmds++ = cp_type4_packet(A6XX_RBBM_PERFCTR_SRAM_INIT_CMD, 1); + *cmds++ = 0x1; + } + /* CP switches the pagetable and flushes the Caches */ *cmds++ = cp_packet(adreno_dev, CP_SMMU_TABLE_UPDATE, 4); *cmds++ = lower_32_bits(ttbr0); @@ -605,6 +613,17 @@ static unsigned int _adreno_iommu_set_pt_v2_a6xx(struct kgsl_device *device, cmds += _adreno_iommu_add_idle_cmds(adreno_dev, cmds); + /* Wait for performance counter clear to finish */ + if (!adreno_dev->perfcounter) { + *cmds++ = cp_type7_packet(CP_WAIT_REG_MEM, 6); + *cmds++ = 0x3; + *cmds++ = A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS; + *cmds++ = 0x0; + *cmds++ = 0x1; + *cmds++ = 0x1; + *cmds++ = 0x0; + } + return cmds - cmds_orig; } diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c index 50207509d783..c62bdba1f23d 100644 --- a/drivers/gpu/msm/adreno_perfcounter.c +++ b/drivers/gpu/msm/adreno_perfcounter.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -143,7 +144,8 @@ void adreno_perfcounter_restore(struct adreno_device *adreno_dev) struct adreno_perfcount_group *group; unsigned int counter, groupid; - if (counters == NULL) + /* Do not save/restore if not requested */ + if (counters == NULL || !adreno_dev->perfcounter) return; for (groupid = 0; groupid < counters->group_count; groupid++) { @@ -177,7 +179,8 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) unsigned int counter, groupid; int ret = 0; - if (counters == NULL) + /* Do not save/restore if not requested */ + if (counters == NULL || !adreno_dev->perfcounter) return; if (gpudev->oob_set) diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h index cf30a834546b..f36c713d0ddd 100644 --- a/drivers/gpu/msm/adreno_pm4types.h +++ b/drivers/gpu/msm/adreno_pm4types.h @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2017,2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -55,6 +56,9 @@ /* switches SMMU pagetable, used on a5xx only */ #define CP_SMMU_TABLE_UPDATE 0x53 +/* Designate command streams to be executed before/after state restore */ +#define CP_SET_AMBLE 0x55 + /* Set internal CP registers, used to indicate context save data addresses */ #define CP_SET_PSEUDO_REGISTER 0x56 @@ -162,6 +166,9 @@ #define CP_LOADSTATE_STATETYPE_SHIFT 0x00000000 #define CP_LOADSTATE_EXTSRCADDR_SHIFT 0x00000002 +/* Used to define amble type in SET_AMBLE packet to execute during preemption */ +#define CP_KMD_AMBLE_TYPE 3 + static inline uint pm4_calc_odd_parity_bit(uint val) { return (0x9669 >> (0xf & ((val) ^ diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index c37a3c2f703e..78020d66e284 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -555,7 +556,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (gpudev->preemption_pre_ibsubmit && adreno_is_preemption_enabled(adreno_dev)) - total_sizedwords += 27; + total_sizedwords += 31; if (gpudev->preemption_post_ibsubmit && adreno_is_preemption_enabled(adreno_dev)) From 50d74c6b6283761d5885374de6580da44633d32f Mon Sep 17 00:00:00 2001 From: Abhishek Barman Date: Tue, 7 Dec 2021 12:50:34 +0530 Subject: [PATCH 22/24] msm: kgsl: Fix gpuaddr_in_range() to check upper bound Currently gpuaddr_in_range() accepts only the gpuaddr & returns true if it lies in valid range. But this does not mean that the entire buffer is within range. Modify the function to accept size as a parameter and check that both starting & ending points of buffer lie within mmu range. Change-Id: I1d722295b9a27e746bfdb6d3bf409ffe722193cb Signed-off-by: Rohan Sethi Signed-off-by: Abhishek Barman Signed-off-by: Kamal Agrawal --- drivers/gpu/msm/adreno_dispatch.c | 4 +++- drivers/gpu/msm/kgsl.c | 2 +- drivers/gpu/msm/kgsl_iommu.c | 10 ++++++---- drivers/gpu/msm/kgsl_mmu.c | 8 +++++--- drivers/gpu/msm/kgsl_mmu.h | 7 +++++-- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index b4bc750a9c1a..7c08a3236003 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1155,7 +1156,8 @@ static inline bool _verify_ib(struct kgsl_device_private *dev_priv, } /* Make sure that the address is mapped */ - if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, ib->gpuaddr)) { + if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, ib->gpuaddr, + ib->size)) { pr_context(device, context, "ctxt %d invalid ib gpuaddr %llX\n", context->id, ib->gpuaddr); return false; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 5d76314cd809..c8b8bf1b3229 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1257,7 +1257,7 @@ kgsl_sharedmem_find(struct kgsl_process_private *private, uint64_t gpuaddr) if (!private) return NULL; - if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr)) + if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr, 0)) return NULL; spin_lock(&private->mem_lock); diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 82536f444ef8..2749cf995b36 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,4 +1,5 @@ /* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2566,20 +2567,21 @@ static int kgsl_iommu_svm_range(struct kgsl_pagetable *pagetable, } static bool kgsl_iommu_addr_in_range(struct kgsl_pagetable *pagetable, - uint64_t gpuaddr) + uint64_t gpuaddr, uint64_t size) { struct kgsl_iommu_pt *pt = pagetable->priv; if (gpuaddr == 0) return false; - if (gpuaddr >= pt->va_start && gpuaddr < pt->va_end) + if (gpuaddr >= pt->va_start && (gpuaddr + size) < pt->va_end) return true; - if (gpuaddr >= pt->compat_va_start && gpuaddr < pt->compat_va_end) + if (gpuaddr >= pt->compat_va_start && + (gpuaddr + size) < pt->compat_va_end) return true; - if (gpuaddr >= pt->svm_start && gpuaddr < pt->svm_end) + if (gpuaddr >= pt->svm_start && (gpuaddr + size) < pt->svm_end) return true; return false; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 456c0e1dacfe..344814e31d90 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2017,2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -613,10 +614,11 @@ enum kgsl_mmutype kgsl_mmu_get_mmutype(struct kgsl_device *device) EXPORT_SYMBOL(kgsl_mmu_get_mmutype); bool kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pagetable, - uint64_t gpuaddr) + uint64_t gpuaddr, uint64_t size) { if (PT_OP_VALID(pagetable, addr_in_range)) - return pagetable->pt_ops->addr_in_range(pagetable, gpuaddr); + return pagetable->pt_ops->addr_in_range(pagetable, + gpuaddr, size); return false; } @@ -652,7 +654,7 @@ EXPORT_SYMBOL(kgsl_mmu_get_qtimer_global_entry); */ static bool nommu_gpuaddr_in_range(struct kgsl_pagetable *pagetable, - uint64_t gpuaddr) + uint64_t gpuaddr, uint64_t size) { return (gpuaddr != 0) ? true : false; } diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 430a14081d35..f292200129be 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,5 @@ /* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -102,7 +103,8 @@ struct kgsl_mmu_pt_ops { int (*set_svm_region)(struct kgsl_pagetable *, uint64_t, uint64_t); int (*svm_range)(struct kgsl_pagetable *, uint64_t *, uint64_t *, uint64_t); - bool (*addr_in_range)(struct kgsl_pagetable *pagetable, uint64_t); + bool (*addr_in_range)(struct kgsl_pagetable *pagetable, + uint64_t, uint64_t); int (*mmu_map_offset)(struct kgsl_pagetable *pt, uint64_t virtaddr, uint64_t virtoffset, struct kgsl_memdesc *memdesc, uint64_t physoffset, @@ -194,7 +196,8 @@ unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr); unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, u64 ttbr0, uint64_t addr); enum kgsl_mmutype kgsl_mmu_get_mmutype(struct kgsl_device *device); -bool kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, uint64_t gpuaddr); +bool kgsl_mmu_gpuaddr_in_range(struct kgsl_pagetable *pt, uint64_t gpuaddr, + uint64_t size); int kgsl_mmu_get_region(struct kgsl_pagetable *pagetable, uint64_t gpuaddr, uint64_t size); From db2b3cf93d3528ec576a3f1e49a38fa8e97d417c Mon Sep 17 00:00:00 2001 From: Abhishek Barman Date: Wed, 20 Apr 2022 19:51:19 +0530 Subject: [PATCH 23/24] msm: kgsl: Remove 'fd' dependency to get dma_buf handle Get the dma_buf handle directly from 'vm_file' after doing necessary checks on the file. Change-Id: Id5eec16588d64e4e28483b32bb52d4d3d9b86b99 Signed-off-by: ravnar Signed-off-by: Sanjay Yadav Signed-off-by: Abhishek Barman Signed-off-by: Kamal Agrawal --- drivers/gpu/msm/kgsl.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index c8b8bf1b3229..aeeebeb5e4aa 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2243,15 +2243,6 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, } #ifdef CONFIG_DMA_SHARED_BUFFER -static int match_file(const void *p, struct file *file, unsigned int fd) -{ - /* - * We must return fd + 1 because iterate_fd stops searching on - * non-zero return, but 0 is a valid fd. - */ - return (p == file) ? (fd + 1) : 0; -} - static void _setup_cache_mode(struct kgsl_mem_entry *entry, struct vm_area_struct *vma) { @@ -2289,8 +2280,6 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, vma = find_vma(current->mm, hostptr); if (vma && vma->vm_file) { - int fd; - ret = check_vma_flags(vma, entry->memdesc.flags); if (ret) { up_read(¤t->mm->mmap_sem); @@ -2306,10 +2295,13 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, return -EFAULT; } - /* Look for the fd that matches this the vma file */ - fd = iterate_fd(current->files, 0, match_file, vma->vm_file); - if (fd != 0) - dmabuf = dma_buf_get(fd - 1); + /* + * Take a refcount because dma_buf_put() decrements the + * refcount + */ + get_file(vma->vm_file); + + dmabuf = vma->vm_file->private_data; } if (IS_ERR_OR_NULL(dmabuf)) { From 7c3ffbe3d5d3126d40a8e58bddda2393a89d0f39 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Gattupalli Date: Tue, 7 Jun 2022 11:06:20 +0530 Subject: [PATCH 24/24] msm: ADSPRPC: Restrict untrusted applications from attaching to GuestOS Untrusted application can attach to guestOS and staticPD if it can somehow make INIT IOCTL call with ATTACH flag. This is a potential security issue as the untrusted application can crash guestOS or staticPD. Restrict attach to guestOS or staticPD request if request is being made using non-secure device node. Change-Id: I322c7b242fd0baaf1c1bce2d83b992fecb0ca593 Acked-by: Ekansh Gupta Signed-off-by: Vamsi Krishna Gattupalli --- drivers/char/adsprpc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 0d27c744e39a..bb6c09ccbe4a 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2192,6 +2192,12 @@ static int fastrpc_init_process(struct fastrpc_file *fl, remote_arg_t ra[1]; int tgid = fl->tgid; + if (fl->dev_minor == MINOR_NUM_DEV) { + err = -ECONNREFUSED; + pr_err("adsprpc: %s: untrusted apk trying to attach to privileged DSP PD\n", + __func__); + return err; + } ra[0].buf.pv = (void *)&tgid; ra[0].buf.len = sizeof(tgid); ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; @@ -2314,6 +2320,13 @@ static int fastrpc_init_process(struct fastrpc_file *fl, unsigned int pageslen; } inbuf; + if (fl->dev_minor == MINOR_NUM_DEV) { + err = -ECONNREFUSED; + pr_err("adsprpc: %s: untrusted apk trying to attach to audio PD\n", + __func__); + return err; + } + if (!init->filelen) goto bail;