msm: kgsl: improve postmortem and cff bounds checking
Some hangs are fooling the postmortem dump code into
running off the end of a buffer. Fix this by making
its bounds check logic work better by reusing the
logic from kgsl_find_region().
CRs-Fixed: 319312
Change-Id: If6cc01369f4b0634d7e19494b8d021643abb8a39
Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 0379a6a..e519cd4 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -937,29 +937,25 @@
return status;
}
-uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int *size)
+const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+ unsigned int pt_base,
+ unsigned int gpuaddr,
+ unsigned int size)
{
- uint8_t *result = NULL;
+ struct kgsl_memdesc *result = NULL;
struct kgsl_mem_entry *entry;
struct kgsl_process_private *priv;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *ringbuffer = &adreno_dev->ringbuffer;
- if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr)) {
- return kgsl_gpuaddr_to_vaddr(&ringbuffer->buffer_desc,
- gpuaddr, size);
- }
+ if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
+ return &ringbuffer->buffer_desc;
- if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr)) {
- return kgsl_gpuaddr_to_vaddr(&ringbuffer->memptrs_desc,
- gpuaddr, size);
- }
+ if (kgsl_gpuaddr_in_memdesc(&ringbuffer->memptrs_desc, gpuaddr, size))
+ return &ringbuffer->memptrs_desc;
- if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr)) {
- return kgsl_gpuaddr_to_vaddr(&device->memstore,
- gpuaddr, size);
- }
+ if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
+ return &device->memstore;
mutex_lock(&kgsl_driver.process_mutex);
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
@@ -969,8 +965,7 @@
entry = kgsl_sharedmem_find_region(priv, gpuaddr,
sizeof(unsigned int));
if (entry) {
- result = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
- gpuaddr, size);
+ result = &entry->memdesc;
spin_unlock(&priv->mem_lock);
mutex_unlock(&kgsl_driver.process_mutex);
return result;
@@ -981,14 +976,24 @@
BUG_ON(!mutex_is_locked(&device->mutex));
list_for_each_entry(entry, &device->memqueue, list) {
- if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr)) {
- result = kgsl_gpuaddr_to_vaddr(&entry->memdesc,
- gpuaddr, size);
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
+ result = &entry->memdesc;
break;
}
}
return result;
+
+}
+
+uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
+ unsigned int gpuaddr, unsigned int size)
+{
+ const struct kgsl_memdesc *memdesc;
+
+ memdesc = adreno_find_region(device, pt_base, gpuaddr, size);
+
+ return memdesc ? kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr) : NULL;
}
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0776a24..3043fd2 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -93,8 +93,13 @@
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
unsigned int value);
-uint8_t *kgsl_sharedmem_convertaddr(struct kgsl_device *device,
- unsigned int pt_base, unsigned int gpuaddr, unsigned int *size);
+const struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
+ unsigned int pt_base,
+ unsigned int gpuaddr,
+ unsigned int size);
+
+uint8_t *adreno_convertaddr(struct kgsl_device *device,
+ unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index cc69360..c6b850e 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -247,9 +247,8 @@
static void dump_ib(struct kgsl_device *device, char* buffId, uint32_t pt_base,
uint32_t base_offset, uint32_t ib_base, uint32_t ib_size, bool dump)
{
- unsigned int memsize;
- uint8_t *base_addr = kgsl_sharedmem_convertaddr(device, pt_base,
- ib_base, &memsize);
+ uint8_t *base_addr = adreno_convertaddr(device, pt_base,
+ ib_base, ib_size*sizeof(uint32_t));
if (base_addr && dump)
print_hex_dump(KERN_ERR, buffId, DUMP_PREFIX_OFFSET,
@@ -277,14 +276,13 @@
int i, j;
uint32_t value;
uint32_t *ib1_addr;
- unsigned int memsize;
dump_ib(device, "IB1:", pt_base, base_offset, ib1_base,
ib1_size, dump);
/* fetch virtual address for given IB base */
- ib1_addr = (uint32_t *)kgsl_sharedmem_convertaddr(device, pt_base,
- ib1_base, &memsize);
+ ib1_addr = (uint32_t *)adreno_convertaddr(device, pt_base,
+ ib1_base, ib1_size*sizeof(uint32_t));
if (!ib1_addr)
return;
@@ -466,7 +464,7 @@
const uint32_t *rb_vaddr;
int num_item = 0;
int read_idx, write_idx;
- unsigned int ts_processed, rb_memsize;
+ unsigned int ts_processed;
static struct ib_list ib_list;
@@ -681,11 +679,16 @@
KGSL_LOG_DUMP(device, "RB: rd_addr:%8.8x rb_size:%d num_item:%d\n",
cp_rb_base, rb_count<<2, num_item);
- rb_vaddr = (const uint32_t *)kgsl_sharedmem_convertaddr(device,
- cur_pt_base, cp_rb_base, &rb_memsize);
+
+ if (adreno_dev->ringbuffer.buffer_desc.gpuaddr != cp_rb_base)
+ KGSL_LOG_POSTMORTEM_WRITE(device,
+ "rb address mismatch, should be 0x%08x\n",
+ adreno_dev->ringbuffer.buffer_desc.gpuaddr);
+
+ rb_vaddr = adreno_dev->ringbuffer.buffer_desc.hostptr;
if (!rb_vaddr) {
KGSL_LOG_POSTMORTEM_WRITE(device,
- "Can't fetch vaddr for CP_RB_BASE\n");
+ "rb has no kernel mapping!\n");
goto error_vfree;
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index bf1d223..7a42dcd 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -774,9 +774,7 @@
BUG_ON(private == NULL);
list_for_each_entry(entry, &private->mem_list, list) {
- if (gpuaddr >= entry->memdesc.gpuaddr &&
- ((gpuaddr + size) <=
- (entry->memdesc.gpuaddr + entry->memdesc.size))) {
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
result = entry;
break;
}
@@ -786,20 +784,6 @@
}
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
-uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
- unsigned int gpuaddr, unsigned int *size)
-{
- BUG_ON(memdesc->hostptr == NULL);
-
- if (memdesc->gpuaddr == 0 || (gpuaddr < memdesc->gpuaddr ||
- gpuaddr >= memdesc->gpuaddr + memdesc->size))
- return NULL;
-
- *size = memdesc->size - (gpuaddr - memdesc->gpuaddr);
- return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
-}
-EXPORT_SYMBOL(kgsl_gpuaddr_to_vaddr);
-
/*call all ioctl sub functions with driver locked*/
static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
@@ -1680,11 +1664,6 @@
result = -EINVAL;
goto done;
}
- if (!entry->memdesc.hostptr)
- entry->memdesc.hostptr =
- kgsl_gpuaddr_to_vaddr(&entry->memdesc,
- param->gpuaddr, &entry->memdesc.size);
-
if (!entry->memdesc.hostptr) {
KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
param->gpuaddr);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 3bb722d..1135adb 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -145,8 +145,6 @@
#endif
void kgsl_mem_entry_destroy(struct kref *kref);
-uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
- unsigned int gpuaddr, unsigned int *size);
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
struct kgsl_process_private *private, unsigned int gpuaddr,
size_t size);
@@ -175,14 +173,24 @@
#endif
static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
- unsigned int gpuaddr)
+ unsigned int gpuaddr, unsigned int size)
{
- if (gpuaddr >= memdesc->gpuaddr && (gpuaddr + sizeof(unsigned int)) <=
- (memdesc->gpuaddr + memdesc->size)) {
+ if (gpuaddr >= memdesc->gpuaddr &&
+ ((gpuaddr + size) <= (memdesc->gpuaddr + memdesc->size))) {
return 1;
}
return 0;
}
+static inline uint8_t *kgsl_gpuaddr_to_vaddr(const struct kgsl_memdesc *memdesc,
+ unsigned int gpuaddr)
+{
+ if (memdesc->hostptr == NULL || memdesc->gpuaddr == 0 ||
+ (gpuaddr < memdesc->gpuaddr ||
+ gpuaddr >= memdesc->gpuaddr + memdesc->size))
+ return NULL;
+
+ return memdesc->hostptr + (gpuaddr - memdesc->gpuaddr);
+}
static inline int timestamp_cmp(unsigned int new, unsigned int old)
{
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index 437d6f5..e9455cb 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -391,7 +391,6 @@
bool clean_cache)
{
const void *src;
- uint host_size;
if (!kgsl_cff_dump_enable)
return;
@@ -411,12 +410,9 @@
}
memdesc = &entry->memdesc;
}
- BUG_ON(memdesc->gpuaddr == 0);
- BUG_ON(gpuaddr == 0);
-
- src = kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr, &host_size);
- if (src == NULL || host_size < sizebytes) {
- KGSL_CORE_ERR("did not find mapping for "
+ src = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
+ if (memdesc->hostptr == NULL) {
+ KGSL_CORE_ERR("no kernel mapping for "
"gpuaddr: 0x%08x, m->host: 0x%p, phys: 0x%08x\n",
gpuaddr, memdesc->hostptr, memdesc->physaddr);
return;
@@ -561,7 +557,6 @@
{
static uint level; /* recursion level */
bool ret = true;
- uint host_size;
uint *hostaddr, *hoststart;
int dwords_left = sizedwords; /* dwords left in the current command
buffer */
@@ -582,10 +577,9 @@
}
memdesc = &entry->memdesc;
}
-
- hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr, &host_size);
+ hostaddr = (uint *)kgsl_gpuaddr_to_vaddr(memdesc, gpuaddr);
if (hostaddr == NULL) {
- KGSL_CORE_ERR("did not find mapping for "
+ KGSL_CORE_ERR("no kernel mapping for "
"gpuaddr: 0x%08x\n", gpuaddr);
return true;
}