aboutsummaryrefslogtreecommitdiff
path: root/driver/gator_cookies.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/gator_cookies.c')
-rw-r--r--driver/gator_cookies.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
new file mode 100644
index 0000000..4e39667
--- /dev/null
+++ b/driver/gator_cookies.c
@@ -0,0 +1,224 @@
+/**
+ * Copyright (C) ARM Limited 2010-2011. 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 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
+#define MAX_COLLISIONS 2
+
+static DEFINE_PER_CPU(uint32_t, cookie_next_key);
+static DEFINE_PER_CPU(uint64_t *, cookie_keys);
+static DEFINE_PER_CPU(uint32_t *, cookie_values);
+
+static uint32_t *gator_crc32_table;
+
+static uint32_t cookiemap_code(uint32_t value) {
+ uint32_t cookiecode = (value >> 24) & 0xff;
+ cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
+ cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
+ cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
+ cookiecode &= (COOKIEMAP_ENTRIES-1);
+ return cookiecode * MAX_COLLISIONS;
+}
+
+static uint32_t gator_chksum_crc32(char *data)
+{
+ register unsigned long crc;
+ unsigned char *block = data;
+ int i, length = strlen(data);
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < length; i++) {
+ crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
+ }
+
+ return (crc ^ 0xFFFFFFFF);
+}
+
+/*
+ * Exists
+ * Pre: [0][1][v][3]..[n-1]
+ * Post: [v][0][1][3]..[n-1]
+ */
+static uint32_t cookiemap_exists(uint64_t key) {
+ int cpu = raw_smp_processor_id();
+ uint32_t cookiecode = cookiemap_code(key);
+ uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
+ uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
+ int x;
+
+ for (x = 0; x < MAX_COLLISIONS; x++) {
+ if (keys[x] == key) {
+ uint32_t value = values[x];
+ for (; x > 0; x--) {
+ keys[x] = keys[x-1];
+ values[x] = values[x-1];
+ }
+ keys[0] = key;
+ values[0] = value;
+ return value;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Add
+ * Pre: [0][1][2][3]..[n-1]
+ * Post: [v][0][1][2]..[n-2]
+ */
+static void cookiemap_add(uint64_t key, uint32_t value) {
+ int cpu = raw_smp_processor_id();
+ int cookiecode = cookiemap_code(key);
+ uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
+ uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
+ int x;
+
+ for (x = MAX_COLLISIONS-1; x > 0; x--) {
+ keys[x] = keys[x-1];
+ values[x] = keys[x-1];
+ }
+ keys[0] = key;
+ values[0] = value;
+}
+
+static inline uint32_t get_cookie(int cpu, int tgid, struct vm_area_struct *vma)
+{
+ struct path *path;
+ uint64_t key;
+ int cookie;
+ char *text;
+
+ if (!vma || !vma->vm_file) {
+ return INVALID_COOKIE;
+ }
+ path = &vma->vm_file->f_path;
+ if (!path || !path->dentry) {
+ return INVALID_COOKIE;
+ }
+
+ text = (char*)path->dentry->d_name.name;
+ key = gator_chksum_crc32(text);
+ key = (key << 32) | (uint32_t)text;
+
+ cookie = cookiemap_exists(key);
+ if (cookie) {
+ goto output;
+ }
+
+ cookie = per_cpu(cookie_next_key, cpu)+=nr_cpu_ids;
+ cookiemap_add(key, cookie);
+
+ gator_buffer_write_packed_int(cpu, PROTOCOL_COOKIE);
+ gator_buffer_write_packed_int(cpu, cookie);
+ gator_buffer_write_string(cpu, text);
+
+output:
+ return cookie;
+}
+
+static int get_exec_cookie(int cpu, struct task_struct *task)
+{
+ unsigned long cookie = NO_COOKIE;
+ struct mm_struct *mm = task->mm;
+ struct vm_area_struct *vma;
+
+ if (!mm)
+ return cookie;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (!vma->vm_file)
+ continue;
+ if (!(vma->vm_flags & VM_EXECUTABLE))
+ continue;
+ cookie = get_cookie(cpu, task->tgid, vma);
+ break;
+ }
+
+ return cookie;
+}
+
+static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
+{
+ unsigned long cookie = NO_COOKIE;
+ struct mm_struct *mm = task->mm;
+ struct vm_area_struct *vma;
+
+ if (!mm)
+ return cookie;
+
+ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
+ if (addr < vma->vm_start || addr >= vma->vm_end)
+ continue;
+
+ if (vma->vm_file) {
+ cookie = get_cookie(cpu, task->tgid, vma);
+ *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
+ } else {
+ /* must be an anonymous map */
+ *offset = addr;
+ }
+
+ break;
+ }
+
+ if (!vma)
+ cookie = INVALID_COOKIE;
+
+ return cookie;
+}
+
+static void cookies_initialize(void)
+{
+ uint32_t crc, poly;
+ int cpu, size;
+ int i, j;
+
+ for_each_present_cpu(cpu) {
+ per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
+
+ size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
+ per_cpu(cookie_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
+ memset(per_cpu(cookie_keys, cpu), 0, size);
+
+ size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
+ per_cpu(cookie_values, cpu) = (uint32_t*)kmalloc(size, GFP_KERNEL);
+ memset(per_cpu(cookie_values, cpu), 0, size);
+ }
+
+ // build CRC32 table
+ poly = 0x04c11db7;
+ gator_crc32_table = (uint32_t*)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 8; j > 0; j--) {
+ if (crc & 1) {
+ crc = (crc >> 1) ^ poly;
+ } else {
+ crc >>= 1;
+ }
+ }
+ gator_crc32_table[i] = crc;
+ }
+}
+
+static void cookies_release(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu) {
+ kfree(per_cpu(cookie_keys, cpu));
+ per_cpu(cookie_keys, cpu) = NULL;
+
+ kfree(per_cpu(cookie_values, cpu));
+ per_cpu(cookie_values, cpu) = NULL;
+ }
+
+ kfree(gator_crc32_table);
+ gator_crc32_table = NULL;
+}