gator: ARM DS-5.6 Streamline gator driver
[android-sdk/arm-ds5-gator.git] / gator_cookies.c
1 /**
2  * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
10 #define COOKIEMAP_ENTRIES       1024            /* must be power of 2 */
11 #define TRANSLATE_SIZE          256
12 #define MAX_COLLISIONS          2
14 static uint32_t *gator_crc32_table;
15 static uint32_t translate_buffer_mask;
17 static DEFINE_PER_CPU(char *, translate_text);
18 static DEFINE_PER_CPU(uint32_t, cookie_next_key);
19 static DEFINE_PER_CPU(uint64_t *, cookie_keys);
20 static DEFINE_PER_CPU(uint32_t *, cookie_values);
21 static DEFINE_PER_CPU(int, translate_buffer_read);
22 static DEFINE_PER_CPU(int, translate_buffer_write);
23 static DEFINE_PER_CPU(unsigned int *, translate_buffer);
25 static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod);
26 static void wq_cookie_handler(struct work_struct *unused);
27 DECLARE_WORK(cookie_work, wq_cookie_handler);
29 static uint32_t cookiemap_code(uint64_t value64) {
30         uint32_t value = (uint32_t)((value64 >> 32) + value64);
31         uint32_t cookiecode = (value >> 24) & 0xff;
32         cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
33         cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
34         cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
35         cookiecode &= (COOKIEMAP_ENTRIES-1);
36         return cookiecode * MAX_COLLISIONS;
37 }
39 static uint32_t gator_chksum_crc32(char *data)
40 {
41    register unsigned long crc;
42    unsigned char *block = data;
43    int i, length = strlen(data);
45    crc = 0xFFFFFFFF;
46    for (i = 0; i < length; i++) {
47       crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
48    }
50    return (crc ^ 0xFFFFFFFF);
51 }
53 /*
54  * Exists
55  *  Pre:  [0][1][v][3]..[n-1]
56  *  Post: [v][0][1][3]..[n-1]
57  */
58 static uint32_t cookiemap_exists(uint64_t key) {
59         unsigned long x, flags, retval = 0;
60         int cpu = smp_processor_id();
61         uint32_t cookiecode = cookiemap_code(key);
62         uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
63         uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
65         // Can be called from interrupt handler or from work queue
66         local_irq_save(flags);
67         for (x = 0; x < MAX_COLLISIONS; x++) {
68                 if (keys[x] == key) {
69                         uint32_t value = values[x];
70                         for (; x > 0; x--) {
71                                 keys[x] = keys[x-1];
72                                 values[x] = values[x-1];
73                         }
74                         keys[0] = key;
75                         values[0] = value;
76                         retval = value;
77                         break;
78                 }
79         }
80         local_irq_restore(flags);
82         return retval;
83 }
85 /*
86  * Add
87  *  Pre:  [0][1][2][3]..[n-1]
88  *  Post: [v][0][1][2]..[n-2]
89  */
90 static void cookiemap_add(uint64_t key, uint32_t value) {
91         int cpu = smp_processor_id();
92         int cookiecode = cookiemap_code(key);
93         uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
94         uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
95         int x;
97         for (x = MAX_COLLISIONS-1; x > 0; x--) {
98                 keys[x] = keys[x-1];
99                 values[x] = keys[x-1];
100         }
101         keys[0] = key;
102         values[0] = value;
105 static void translate_buffer_write_int(int cpu, unsigned int x)
107         per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
108         per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
111 static unsigned int translate_buffer_read_int(int cpu)
113         unsigned int value = per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_read, cpu)++];
114         per_cpu(translate_buffer_read, cpu) &= translate_buffer_mask;
115         return value;
118 static void wq_cookie_handler(struct work_struct *unused)
120         struct task_struct *task;
121         struct vm_area_struct *vma;
122         int cpu = smp_processor_id();
123         unsigned int cookie, commit;
125         commit = per_cpu(translate_buffer_write, cpu);
126         while (per_cpu(translate_buffer_read, cpu) != commit) {
127                 task = (struct task_struct *)translate_buffer_read_int(cpu);
128                 vma = (struct vm_area_struct *)translate_buffer_read_int(cpu);
129                 cookie = get_cookie(cpu, task, vma, NULL);
130         }
133 // Retrieve full name from proc/pid/cmdline for java processes on Android
134 static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma)
136         void *maddr;
137         unsigned int len;
138         unsigned long addr;
139         struct mm_struct *mm;
140         struct page *page = NULL;
141         struct vm_area_struct *page_vma;
142         int bytes, offset, retval = 0, ptr;
143         char * buf = per_cpu(translate_text, cpu);
145         // Push work into a work queue if in atomic context as the kernel functions below might sleep
146         if (in_irq()) {
147                 // Check if already in buffer
148                 ptr = per_cpu(translate_buffer_read, cpu);
149                 while (ptr != per_cpu(translate_buffer_write, cpu)) {
150                         if (per_cpu(translate_buffer, cpu)[ptr] == (int)task)
151                                 goto out;
152                         ptr = (ptr + 2) & translate_buffer_mask;
153                 }
155                 translate_buffer_write_int(cpu, (unsigned int)task);
156                 translate_buffer_write_int(cpu, (unsigned int)vma);
157                 schedule_work(&cookie_work);
158                 goto out;
159         }
161         mm = get_task_mm(task);
162         if (!mm)
163                 goto out;
164         if (!mm->arg_end)
165                 goto outmm;
166         addr = mm->arg_start;
167         len = mm->arg_end - mm->arg_start;
169         if (len > TRANSLATE_SIZE)
170                 len = TRANSLATE_SIZE;
172         down_read(&mm->mmap_sem);
173         while (len) {
174                 if (get_user_pages(task, mm, addr, 1, 0, 1, &page, &page_vma) <= 0)
175                         goto outsem;
177                 maddr = kmap(page);
178                 offset = addr & (PAGE_SIZE-1);
179                 bytes = len;
180                 if (bytes > PAGE_SIZE - offset)
181                         bytes = PAGE_SIZE - offset;
183                 copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
185                 kunmap(page);   // release page allocated by get_user_pages()
186                 page_cache_release(page);
188                 len -= bytes;
189                 buf += bytes;
190                 addr += bytes;
192                 *text = per_cpu(translate_text, cpu);
193                 retval = 1;
194         }
196         // On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
197         if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
198                 retval = 0;
200 outsem:
201         up_read(&mm->mmap_sem);
202 outmm:
203         mmput(mm);
204 out:
205         return retval;
208 static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod)
210         unsigned long flags, cookie;
211         struct path *path;
212         uint64_t key;
213         char *text;
215         if (mod) {
216                 text = mod->name;
217         } else {
218                 if (!vma || !vma->vm_file) {
219                         return INVALID_COOKIE;
220                 }
221                 path = &vma->vm_file->f_path;
222                 if (!path || !path->dentry) {
223                         return INVALID_COOKIE;
224                 }
226                 text = (char*)path->dentry->d_name.name;
227         }
229         key = gator_chksum_crc32(text);
230         key = (key << 32) | (uint32_t)task->tgid;
232         cookie = cookiemap_exists(key);
233         if (cookie) {
234                 return cookie;
235         }
237         if (strcmp(text, "app_process") == 0 && !mod) {
238                 if (!translate_app_process(&text, cpu, task, vma))
239                         return INVALID_COOKIE;
240         }
242         // Can be called from interrupt handler or from work queue
243         local_irq_save(flags);
245         cookie = per_cpu(cookie_next_key, cpu)+=nr_cpu_ids;
246         cookiemap_add(key, cookie);
248         gator_buffer_write_packed_int(cpu, PROTOCOL_COOKIE);
249         gator_buffer_write_packed_int(cpu, cookie);
250         gator_buffer_write_string(cpu, text);
252         local_irq_restore(flags);
254         return cookie;
257 static int get_exec_cookie(int cpu, struct task_struct *task)
259         unsigned long cookie = NO_COOKIE;
260         struct mm_struct *mm = task->mm;
261         struct vm_area_struct *vma;
263         if (!mm)
264                 return cookie;
266         for (vma = mm->mmap; vma; vma = vma->vm_next) {
267                 if (!vma->vm_file)
268                         continue;
269                 if (!(vma->vm_flags & VM_EXECUTABLE))
270                         continue;
271                 cookie = get_cookie(cpu, task, vma, NULL);
272                 break;
273         }
275         return cookie;
278 static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
280         unsigned long cookie = NO_COOKIE;
281         struct mm_struct *mm = task->mm;
282         struct vm_area_struct *vma;
284         if (!mm)
285                 return cookie;
287         for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
288                 if (addr < vma->vm_start || addr >= vma->vm_end)
289                         continue;
291                 if (vma->vm_file) {
292                         cookie = get_cookie(cpu, task, vma, NULL);
293                         *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
294                 } else {
295                         /* must be an anonymous map */
296                         *offset = addr;
297                 }
299                 break;
300         }
302         if (!vma)
303                 cookie = INVALID_COOKIE;
305         return cookie;
308 static int cookies_initialize(void)
310         uint32_t crc, poly;
311         int i, j, cpu, size, err = 0;
313         int translate_buffer_size = 512; // must be a power of 2
314         translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
316         for_each_present_cpu(cpu) {
317                 per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
319                 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
320                 per_cpu(cookie_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
321                 memset(per_cpu(cookie_keys, cpu), 0, size);
323                 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
324                 per_cpu(cookie_values, cpu) = (uint32_t*)kmalloc(size, GFP_KERNEL);
325                 memset(per_cpu(cookie_values, cpu), 0, size);
327                 per_cpu(translate_buffer, cpu) = (unsigned int *)kmalloc(translate_buffer_size, GFP_KERNEL);
328                 if (!per_cpu(translate_buffer, cpu)) {
329                         err = -ENOMEM;
330                         goto cookie_setup_error;
331                 }
333                 per_cpu(translate_buffer_write, cpu) = 0;
334                 per_cpu(translate_buffer_read, cpu) = 0;
336                 per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL);
337                 if (!per_cpu(translate_text, cpu)) {
338                         err = -ENOMEM;
339                         goto cookie_setup_error;
340                 }
341         }
343         // build CRC32 table
344         poly = 0x04c11db7;
345         gator_crc32_table = (uint32_t*)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
346         for (i = 0; i < 256; i++) {
347                 crc = i;
348                 for (j = 8; j > 0; j--) {
349                         if (crc & 1) {
350                                 crc = (crc >> 1) ^ poly;
351                         } else {
352                                 crc >>= 1;
353                         }
354                 }
355                 gator_crc32_table[i] = crc;
356         }
358 cookie_setup_error:
359         return err;
362 static void cookies_release(void)
364         int cpu;
366         for_each_present_cpu(cpu) {
367                 kfree(per_cpu(cookie_keys, cpu));
368                 per_cpu(cookie_keys, cpu) = NULL;
370                 kfree(per_cpu(cookie_values, cpu));
371                 per_cpu(cookie_values, cpu) = NULL;
373                 kfree(per_cpu(translate_buffer, cpu));
374                 per_cpu(translate_buffer, cpu) = NULL;
375                 per_cpu(translate_buffer_read, cpu) = 0;
376                 per_cpu(translate_buffer_write, cpu) = 0;
378                 kfree(per_cpu(translate_text, cpu));
379                 per_cpu(translate_text, cpu) = NULL;
380         }
382         kfree(gator_crc32_table);
383         gator_crc32_table = NULL;