diff options
author | Bernard Ogden <benie.ogden@linaro.org> | 2014-06-19 14:50:13 +0100 |
---|---|---|
committer | Bernard Ogden <benie.ogden@linaro.org> | 2014-06-19 14:50:13 +0100 |
commit | d09453815371069a214466c470d7ae0b64390411 (patch) | |
tree | 90d7cb5225b7dfb613c071cd18213061ebbb20b0 |
Initial commit
-rw-r--r-- | Kbuild | 4 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | modex.c | 223 |
3 files changed, 229 insertions, 0 deletions
@@ -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 @@ -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"); |