summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'driver/gator_cookies.c')
-rw-r--r--driver/gator_cookies.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
new file mode 100644
index 0000000..64be841
--- /dev/null
+++ b/driver/gator_cookies.c
@@ -0,0 +1,384 @@
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 */
9
10#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
11#define TRANSLATE_SIZE 256
12#define MAX_COLLISIONS 2
13
14static uint32_t *gator_crc32_table;
15static uint32_t translate_buffer_mask;
16
17static DEFINE_PER_CPU(char *, translate_text);
18static DEFINE_PER_CPU(uint32_t, cookie_next_key);
19static DEFINE_PER_CPU(uint64_t *, cookie_keys);
20static DEFINE_PER_CPU(uint32_t *, cookie_values);
21static DEFINE_PER_CPU(int, translate_buffer_read);
22static DEFINE_PER_CPU(int, translate_buffer_write);
23static DEFINE_PER_CPU(unsigned int *, translate_buffer);
24
25static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod);
26static void wq_cookie_handler(struct work_struct *unused);
27DECLARE_WORK(cookie_work, wq_cookie_handler);
28
29static 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}
38
39static uint32_t gator_chksum_crc32(char *data)
40{
41 register unsigned long crc;
42 unsigned char *block = data;
43 int i, length = strlen(data);
44
45 crc = 0xFFFFFFFF;
46 for (i = 0; i < length; i++) {
47 crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
48 }
49
50 return (crc ^ 0xFFFFFFFF);
51}
52
53/*
54 * Exists
55 * Pre: [0][1][v][3]..[n-1]
56 * Post: [v][0][1][3]..[n-1]
57 */
58static 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]);
64
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);
81
82 return retval;
83}
84
85/*
86 * Add
87 * Pre: [0][1][2][3]..[n-1]
88 * Post: [v][0][1][2]..[n-2]
89 */
90static 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;
96
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;
103}
104
105static void translate_buffer_write_int(int cpu, unsigned int x)
106{
107 per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
108 per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
109}
110
111static unsigned int translate_buffer_read_int(int cpu)
112{
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;
116}
117
118static void wq_cookie_handler(struct work_struct *unused)
119{
120 struct task_struct *task;
121 struct vm_area_struct *vma;
122 int cpu = smp_processor_id();
123 unsigned int cookie, commit;
124
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 }
131}
132
133// Retrieve full name from proc/pid/cmdline for java processes on Android
134static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma)
135{
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);
144
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 }
154
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 }
160
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;
168
169 if (len > TRANSLATE_SIZE)
170 len = TRANSLATE_SIZE;
171
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;
176
177 maddr = kmap(page);
178 offset = addr & (PAGE_SIZE-1);
179 bytes = len;
180 if (bytes > PAGE_SIZE - offset)
181 bytes = PAGE_SIZE - offset;
182
183 copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
184
185 kunmap(page); // release page allocated by get_user_pages()
186 page_cache_release(page);
187
188 len -= bytes;
189 buf += bytes;
190 addr += bytes;
191
192 *text = per_cpu(translate_text, cpu);
193 retval = 1;
194 }
195
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;
199
200outsem:
201 up_read(&mm->mmap_sem);
202outmm:
203 mmput(mm);
204out:
205 return retval;
206}
207
208static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod)
209{
210 unsigned long flags, cookie;
211 struct path *path;
212 uint64_t key;
213 char *text;
214
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 }
225
226 text = (char*)path->dentry->d_name.name;
227 }
228
229 key = gator_chksum_crc32(text);
230 key = (key << 32) | (uint32_t)task->tgid;
231
232 cookie = cookiemap_exists(key);
233 if (cookie) {
234 return cookie;
235 }
236
237 if (strcmp(text, "app_process") == 0 && !mod) {
238 if (!translate_app_process(&text, cpu, task, vma))
239 return INVALID_COOKIE;
240 }
241
242 // Can be called from interrupt handler or from work queue
243 local_irq_save(flags);
244
245 cookie = per_cpu(cookie_next_key, cpu)+=nr_cpu_ids;
246 cookiemap_add(key, cookie);
247
248 gator_buffer_write_packed_int(cpu, PROTOCOL_COOKIE);
249 gator_buffer_write_packed_int(cpu, cookie);
250 gator_buffer_write_string(cpu, text);
251
252 local_irq_restore(flags);
253
254 return cookie;
255}
256
257static int get_exec_cookie(int cpu, struct task_struct *task)
258{
259 unsigned long cookie = NO_COOKIE;
260 struct mm_struct *mm = task->mm;
261 struct vm_area_struct *vma;
262
263 if (!mm)
264 return cookie;
265
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 }
274
275 return cookie;
276}
277
278static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
279{
280 unsigned long cookie = NO_COOKIE;
281 struct mm_struct *mm = task->mm;
282 struct vm_area_struct *vma;
283
284 if (!mm)
285 return cookie;
286
287 for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
288 if (addr < vma->vm_start || addr >= vma->vm_end)
289 continue;
290
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 }
298
299 break;
300 }
301
302 if (!vma)
303 cookie = INVALID_COOKIE;
304
305 return cookie;
306}
307
308static int cookies_initialize(void)
309{
310 uint32_t crc, poly;
311 int i, j, cpu, size, err = 0;
312
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;
315
316 for_each_present_cpu(cpu) {
317 per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
318
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);
322
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);
326
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 }
332
333 per_cpu(translate_buffer_write, cpu) = 0;
334 per_cpu(translate_buffer_read, cpu) = 0;
335
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 }
342
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 }
357
358cookie_setup_error:
359 return err;
360}
361
362static void cookies_release(void)
363{
364 int cpu;
365
366 for_each_present_cpu(cpu) {
367 kfree(per_cpu(cookie_keys, cpu));
368 per_cpu(cookie_keys, cpu) = NULL;
369
370 kfree(per_cpu(cookie_values, cpu));
371 per_cpu(cookie_values, cpu) = NULL;
372
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;
377
378 kfree(per_cpu(translate_text, cpu));
379 per_cpu(translate_text, cpu) = NULL;
380 }
381
382 kfree(gator_crc32_table);
383 gator_crc32_table = NULL;
384}