summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernard Ogden <benie.ogden@linaro.org>2014-06-19 14:50:13 +0100
committerBernard Ogden <benie.ogden@linaro.org>2014-06-19 14:50:13 +0100
commitd09453815371069a214466c470d7ae0b64390411 (patch)
tree90d7cb5225b7dfb613c071cd18213061ebbb20b0
Initial commit
-rw-r--r--Kbuild4
-rw-r--r--Makefile2
-rw-r--r--modex.c223
3 files changed, 229 insertions, 0 deletions
diff --git a/Kbuild b/Kbuild
new file mode 100644
index 0000000..bbaacee
--- /dev/null
+++ b/Kbuild
@@ -0,0 +1,4 @@
+EXTRA_CFLAGS += -g
+
+obj-m += modex.o
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e2878e8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+all:
+ make ARCH=arm -C /usr/src/linux-headers-3.2.0-38-highbank SUBDIRS=`pwd` modules
diff --git a/modex.c b/modex.c
new file mode 100644
index 0000000..4745910
--- /dev/null
+++ b/modex.c
@@ -0,0 +1,223 @@
+/*
+ * This is a simple character device driver to illustrate the support for debug of Linux kernel modules
+ *
+ * Copyright (C) ARM Limited, 2010. 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <asm/uaccess.h>
+
+
+#define MODEX_MAJOR 42
+#define MODEX_MINOR 0
+#define DEVICE_NAME "modex"
+
+
+static int modex_open(struct inode *inode, struct file *file);
+static int modex_release(struct inode *inode, struct file *file);
+static ssize_t modex_read (struct file *file, char *buffer, size_t length, loff_t * offset);
+static ssize_t modex_write (struct file *file, const char *buffer, size_t length, loff_t * offset);
+static int __init modex_init(void);
+static void __exit modex_exit(void);
+
+static volatile int test_mode /* = 0 */; /* can be set from debugger */
+
+struct file_operations modex_fops =
+{
+ .owner = THIS_MODULE,
+ .open = modex_open,
+ .release = modex_release,
+ .read = modex_read,
+ .write = modex_write,
+};
+
+static struct device *modex_cdev;
+static struct class *modex_class;
+
+
+static int modex_open(struct inode *inode, struct file *file)
+{
+ return 0 ;
+}
+
+
+static int modex_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+
+static ssize_t modex_read(struct file *file, char *buffer, size_t length, loff_t *offset)
+{
+ char msg_buffer[920];
+ char* msg = msg_buffer;
+ int bytes_written;
+ const char* ctype[] = { "No cache",
+ "I$ only",
+ "D$ only",
+ "I & D $",
+ "Unified",
+ "RESERVED - should not see this",
+ "RESERVED - should not see this",
+ "RESERVED - should not see this" };
+ int msg_len;
+ volatile unsigned int actlr, midr, clidr, ccsidr_l1d, ccsidr_l2u;
+ unsigned int l1d = 0; unsigned int l2u = 2;
+ asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (actlr)); //read actlr
+ asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (midr)); //read midr
+ asm("mrc p15, 1, %0, c0, c0, 1" : "=r" (clidr));
+ asm volatile("mcr p15, 2, %0, c0, c0, 0\nisb" :: "r" (l1d)); //set csselr (cache size selection register)
+ asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr_l1d));
+ asm volatile("mcr p15, 2, %0, c0, c0, 0\nisb" :: "r" (l2u)); //set csselr (cache size selection register)
+ asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr_l2u));
+ bytes_written = snprintf(msg, sizeof msg_buffer,
+ "ACTLR: %#.8x\n"
+ "MIDR: %#.8x\n"
+ "CLIDR: %#.8x\n"
+ " LoUU: %d\n"
+ " LoC: %d\n"
+ " LoUIS: %d\n"
+ " L7: %s\n"
+ " L6: %s\n"
+ " L5: %s\n"
+ " L4: %s\n"
+ " L3: %s\n"
+ " L2: %s\n"
+ " L1: %s\n"
+ , actlr, midr, clidr,
+ (clidr >> 27) & 0x7,
+ (clidr >> 24) & 0x7,
+ (clidr >> 21) & 0x7,
+ ctype[(clidr >> 18) & 0x7],
+ ctype[(clidr >> 15) & 0x7],
+ ctype[(clidr >> 12) & 0x7],
+ ctype[(clidr >> 9) & 0x7],
+ ctype[(clidr >> 6) & 0x7],
+ ctype[(clidr >> 3) & 0x7],
+ ctype[(clidr >> 0) & 0x7]);
+ if((clidr >> 0) & 0x7) { //there is some cache
+ bytes_written += snprintf(msg + bytes_written, sizeof msg_buffer - bytes_written, "Following data only reliable if the named cache exists!\n");
+ }
+ if((clidr >> 3) & 0x7) {
+ bytes_written += snprintf(msg + bytes_written, sizeof msg_buffer - bytes_written,
+ "CCSIDR L2U$: %#.8x\n"
+ " Sets: %d\n"
+ " Assoc: %d\n"
+ " Line Size: 2^%d words\n",
+ ccsidr_l2u,
+ ((ccsidr_l2u >> 13) & 0x7fff) + 1,
+ ((ccsidr_l2u >> 3) & 0x03ff) + 1,
+ ((ccsidr_l2u >> 0) & 0x0007) + 2);
+ }
+ if((clidr >> 0) & 0x7) {
+ bytes_written += snprintf(msg + bytes_written, sizeof msg_buffer - bytes_written,
+ "CCSIDR L1D$: %#.8x\n"
+ " Sets: %d\n"
+ " Assoc: %d\n"
+ " Line Size: 2^%d words\n",
+ ccsidr_l1d,
+ ((ccsidr_l1d >> 13) & 0x7fff) + 1,
+ ((ccsidr_l1d >> 3) & 0x03ff) + 1,
+ ((ccsidr_l1d >> 0) & 0x0007) + 2);
+ }
+ msg_len = strlen(msg);
+
+ if (*offset >= msg_len)
+ return 0; /* EOF */
+
+ if (*offset + length >= msg_len)
+ length = msg_len - *offset;
+
+ if ( copy_to_user(buffer, msg + *offset, length) )
+ return -EFAULT;
+ *offset += length;
+
+ return length;
+}
+
+
+static ssize_t modex_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
+{
+ char x;
+
+ if ( copy_from_user(&x, buffer, 1) ) // only interested in the first byte passed in
+ return -EFAULT;
+ printk(KERN_INFO "modex received value: '%c' %d\n", x, x);
+ switch (x) {
+ case 'A':
+ if (test_mode) {
+ printk(KERN_INFO "modex test mode about to abort\n");
+ /* cause an abort */
+ x = *(int*)test_mode;
+ printk(KERN_INFO "modex didn't expect to get here! '%c' %d\n", x, x);
+ }
+ break;
+ case 'P':
+ if (test_mode) {
+ panic("panic from modex test mode");
+ }
+ break;
+ case '+':
+ test_mode = 1;
+ printk(KERN_INFO "modex test mode enabled\n");
+ break;
+ case '-':
+ test_mode = 0;
+ printk(KERN_INFO "modex test mode disabled\n");
+ break;
+ default:
+ break;
+ }
+
+ return length;
+}
+
+
+static int __init modex_init(void)
+{
+ int ret;
+
+ /* Register character device driver */
+ ret = register_chrdev(MODEX_MAJOR, DEVICE_NAME, &modex_fops);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "modex could not initialize\n");
+ return ret;
+ }
+
+ /* Create a class /sys/class/modex/modex, then create a device node /dev/modex */
+ modex_class = class_create(THIS_MODULE, DEVICE_NAME);
+ modex_cdev = device_create(modex_class, NULL, MKDEV (MODEX_MAJOR, MODEX_MINOR), NULL, DEVICE_NAME);
+ printk(KERN_INFO "modex initialized\n");
+
+ return 0;
+}
+
+
+static void __exit modex_exit(void)
+{
+ device_destroy(modex_class, MKDEV (MODEX_MAJOR, MODEX_MINOR));
+ class_destroy(modex_class);
+ unregister_chrdev(MODEX_MAJOR, DEVICE_NAME);
+
+ printk(KERN_INFO "modex exited\n");
+}
+
+
+module_init(modex_init);
+module_exit(modex_exit);
+
+
+MODULE_AUTHOR("ARM");
+MODULE_VERSION("1.01");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Example module");