diff --git a/drivers/Makefile b/drivers/Makefile index 57f7c3e60a11..ebd788efc603 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -194,3 +194,4 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_SDW) += sdw/ +obj-y += test_driver/ diff --git a/drivers/test_driver/Makefile b/drivers/test_driver/Makefile new file mode 100755 index 000000000000..5ebca002ffb0 --- /dev/null +++ b/drivers/test_driver/Makefile @@ -0,0 +1,19 @@ +obj-y += test_driver.o + +#KERNELDIR ?=/lib/modules/$(shell uname -r)/build +##KERNELDIR ?=$(HOME)/disk2/cht_r2/out/target/product/r2_cht_mrd/obj/kernel/lib/modules/3.14.79-x86_64-gb1e6894/build/ +##Documentation/kbuild/kbuild.txt + +#module: + #$(MAKE) -C $(KERNELDIR) M=$(shell pwd) modules + #rm -rf *.c~ + #rm -rf *.mod* + #rm -rf *.o + #rm -rf modules.order + #rm -rf Module.symvers + +#clean: + #rm -rf *.ko *.o *.mod* modules* Mo* .*.cmd .tmp_versions + #make -C $(KERNELDIR) M=`pwd` clean + +#obj-m=test_driver.o diff --git a/drivers/test_driver/test_app/.gitignore b/drivers/test_driver/test_app/.gitignore new file mode 100755 index 000000000000..ab43963d7e20 --- /dev/null +++ b/drivers/test_driver/test_app/.gitignore @@ -0,0 +1,2 @@ +test +a.out diff --git a/drivers/test_driver/test_app/Makefile b/drivers/test_driver/test_app/Makefile new file mode 100755 index 000000000000..e89d9b6841ac --- /dev/null +++ b/drivers/test_driver/test_app/Makefile @@ -0,0 +1,11 @@ + +#CFLAGS += -O2 -msse2 +LDFLAGS += -static + +all: test + rm test.o + +test: test.o + +clean: + rm -f test.o test diff --git a/drivers/test_driver/test_app/auto_create_device_file.txt b/drivers/test_driver/test_app/auto_create_device_file.txt new file mode 100755 index 000000000000..7b33c351091d --- /dev/null +++ b/drivers/test_driver/test_app/auto_create_device_file.txt @@ -0,0 +1,15 @@ +在加载驱动程序时自动创建: +Linux内核提供了一组函数,可以在模块加载时自动在/dev目录下创建相对应的设备节点, +并在卸载模块时删除该节点,能实现这样操作的前提是用户空间已经移植了udev(简化版本的mdev)。 + +相关的函数和结构: +(1)struct class,是一个设备结构体, + 注册一个类结构,会在/sys/class目录下创建对应的文件夹, + /dev目录下有自动生成设备节点的信息。 + +(2)struct class_device结构体。 + class_create() + class_device_create() + +在成功挂载驱动程序之后,在/sys/class下就产生了一个led文件夹,里面有一个leds文件的包含信息; +并且已经自动在/dev目录下创建好了leds字符设备文件,不用手动创建。 diff --git a/drivers/test_driver/test_app/test.c b/drivers/test_driver/test_app/test.c new file mode 100755 index 000000000000..1a67b3fd5a31 --- /dev/null +++ b/drivers/test_driver/test_app/test.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "../test_driver.h" + +int read_cpuid(int fd, exx_reg_val_t *reg) +{ + int ret = 0; + + ioctl(fd, READ_CPUID, (unsigned int *)reg); + printf("%s: eax_ret_val=0x%x, ebx_ret_val=0x%x, ecx_ret_val=0x%x, edx_ret_val=0x%x\n",\ + __func__, reg->eax_ret_val, reg->ebx_ret_val, reg->ecx_ret_val, reg->edx_ret_val); + return ret; +} + +int read_msr(int fd, unsigned long msr_reg, unsigned long msr_val) +{ + int ret = 0; + unsigned long msr_register = msr_reg; + + ioctl(fd, GET_MSR_REG_VAL, (unsigned int *)&msr_reg); + if (msr_reg == ~0x0) + ret = -1; + msr_val = msr_reg; + printf("%s: msr_reg=0x%lx msr_val=0x%lx ret=%d\n",\ + __func__, msr_register, (unsigned long)msr_reg, ret); + return ret; +} + +int write_msr(int fd, unsigned long msr_reg, unsigned long msr_val) +{ + int ret = 0; + msr_reg_val_t msr_para; + msr_para.reg = msr_reg; + msr_para.val = msr_val; + msr_para.ret = 0xff; + ioctl(fd, SET_MSR_REG_VAL, (unsigned int *)&msr_para); + printf("%s: msr_reg=0x%lx msr_val=0x%lx ret=%ld\n",\ + __func__, msr_reg, msr_para.val, msr_para.ret); + return ret; +} + +int main(int argc, const char *argv[]) +{ + int fd; + int ret; + unsigned long msr_reg = 0x17; //reg:0x17, display cpu model + unsigned long msr_val; + int val = 0; + unsigned long long addr; + unsigned int len; + mem_dump_t *mem_dump = NULL; + char wr_flag = 0; + +if (argc < 3) { + fd = open("/dev/hello_class", O_RDWR, 0664); + if (0 > fd) { + printf("%s: test : open : error\n", __func__); + return -1; + } + + //read cpuid + exx_reg_val_t reg = {0}; + reg.eax_val = 0x7; + reg.ecx_val = 0; + read_cpuid(fd, ®); + + //read_msr + msr_reg = 0x17; + if (argc > 1) + msr_reg = (unsigned long)atoi(argv[1]); + printf("\n%s: msr_reg=0x%lx\n", __func__, msr_reg); + ret = read_msr(fd, msr_reg, msr_val); + if (ret < 0) { + printf("%s: read msr failed, ret=0x%x\n", __func__, ret); + close(fd); + return -1; + } + + close(fd); + return 0; +} +else if (argc < 4) +{ + sscanf(argv[1], "%llx", &addr); + sscanf(argv[2], "%x", &len); + + mem_dump = malloc(sizeof(mem_dump_t) + len * sizeof(unsigned char)); + if(!mem_dump) { + printf("mem alloc failed\n"); + return 0; + } + + memset(mem_dump, 0, sizeof(mem_dump_t) + len * sizeof(unsigned char)); + + mem_dump->addr = addr; + mem_dump->len = len; + + printf("mem_base = 0x%llx\n", mem_dump->addr); + printf("mem_size = 0x%x\n", mem_dump->len); + printf("dump_addr = %p\n", mem_dump->buf); + + fd = open("/dev/hello_class", O_RDWR); + if(fd == -1) { + printf("Failed to open device %s\n", "/dev/hello_class"); + return -1; + } + + ioctl(fd, DUMP_MEM, mem_dump); + + for (int i = 0; i < mem_dump->len; i++) { + if((i != 0) && (i % 4 == 0)) + printf(" "); + if((i != 0) && (i % 16 == 0)) + printf("\n"); + printf("%02x", mem_dump->buf[i]); + } + + printf("\n"); + ioctl(fd, CHECK_FEATURE, &val); + if (val) + printf("X86_FEATURE_RETPOLINE is set\n"); + else + printf("X86_FEATURE_RETPOLINE is not set\n"); + + close(fd); + + if(mem_dump) + free(mem_dump); + + return 0; + +} +else +{ + wr_flag = *(char*)argv[2]; + sscanf(argv[3], "%lx", &msr_reg); + + fd = open("/dev/hello_class", O_RDWR, 0664); + if (0 > fd) { + printf("%s: test : open : error\n", __func__); + return -1; + } + //read_msr + if (wr_flag == 'r') + { + ret = read_msr(fd, msr_reg, msr_val); + if (ret < 0) { + printf("%s: read msr failed, ret=0x%x\n", __func__, ret); + close(fd); + return -1; + } + } + else if(wr_flag == 'w') + { + sscanf(argv[4], "%lx", &msr_val); + ret = write_msr(fd, msr_reg, msr_val); + } + + close(fd); + return 0; +} + +} diff --git a/drivers/test_driver/test_driver.c b/drivers/test_driver/test_driver.c new file mode 100755 index 000000000000..55e2dfa088dc --- /dev/null +++ b/drivers/test_driver/test_driver.c @@ -0,0 +1,381 @@ +#include +#include +#include +#include +#include +#include "test_driver.h" +#include +#include +#include +#include + +#define CLASS_DEV_CREATE +#ifdef CLASS_DEV_CREATE +#include +#include +#endif + + +static ssize_t dump_mem(unsigned char *arg) +{ + printk("KERNEL:writing...\n"); + mem_dump_t mem; + if(copy_from_user(&mem, arg, sizeof(mem_dump_t))) + { + return -EFAULT; + } + + printk("addr to read = 0x%lx\n", mem.addr); + printk("size to read = 0x%x\n", mem.len); + printk("user addr = %p\n", ((mem_dump_t *)arg)->buf); + if(copy_to_user(((mem_dump_t *)arg)->buf, mem.addr, mem.len)) + { + printk("copy_to_user failed\n"); + return -EFAULT; + } + return mem.len; +} + +static int read_cpuid(exx_reg_val_t *reg) +{ + int ret; + + __asm__ ( + "mov %4, %%eax\n\t" + "mov %6, %%ecx\n\t" + "cpuid\n\t" + "mov %%eax, %0\n\t" + "mov %%ebx, %1\n\t" + "mov %%ecx, %2\n\t" + "mov %%edx, %3\n\t" + + : "=r" (reg->eax_ret_val),\ + "=r" (reg->ebx_ret_val),\ + "=r" (reg->ecx_ret_val),\ + "=r" (reg->edx_ret_val)/*output*/ + + : "r" (reg->eax_val), \ + "r"(reg->ebx_val),\ + "r"(reg->ecx_val), \ + "r"(reg->edx_val),"0" (0) /*input*/ + : "%eax", "%ebx","%ecx", "%edx"); + + printk("eax:0x%x, ecx:0x%x\n", reg->eax_val, reg->ecx_val); + printk("edx_ret:0x%x\n", reg->edx_ret_val); + + return 0; +} + +/* + * bit29 is set, msr exist + * */ +static int get_msr_bit(char which_bit) +{ + int ret; + + __asm__ ( + "mov $0x07, %%eax\n\t" + "mov $0x0, %%ecx\n\t" + "cpuid\n\t" + "mov %%edx, %0\n\t" + : "=r" (ret) /*output*/ + : "0" (0) /*input*/ + : "%eax", "%ebx","%ecx", "%edx"); + + printk("edx = %x\n", ret); + //ret = (ret >> 29) & 1; + ret = (ret >> which_bit) & 1; + printk("edx[29] = %x\n", ret); + + return ret; //bit29 +} + +#define N 128 +#define DEV_NAME "hello_class" +MODULE_LICENSE("GPL"); + +char data[N]; + +static int major = 220; +static int minor = 1; +unsigned long long g_magic_data_addr; + +#ifdef CLASS_DEV_CREATE +static struct class *cls; +static struct device *device; +#endif + +static int hello_open(struct inode *inode, struct file *fl) +{ + printk("hello_open\n"); + return 0; +} + +static int hello_release(struct inode *inode, struct file *file) +{ + printk("hello_release\n"); + + return 0; +} + +static ssize_t hello_read(struct file *file, char __user *buf, + size_t size, loff_t *loff) +{ + unsigned long i; + if (size > N) + size = N; + if (size < 0) + return -EINVAL; + char * magic_addr, read_addr; + + unsigned long long magic_data[200][2] = {0}; + for (i=0; i < 200; i++) { + magic_data[i][0] = 0xaa; + magic_data[i][1] = 0x55;; + + } + + + magic_addr = (char*)magic_data; + magic_addr = ((unsigned long)magic_addr+0x1000) & (~0xfff); + magic_addr -= 200; + for (i=0; i < 2000000; i++) { + printk("read %llx = %02x\n", (unsigned long)magic_addr+(i%200),(char *)magic_addr[i % 200]); + } + + if (copy_to_user(buf, &magic_addr, sizeof(unsigned long long))) + return -ENOMEM; + + + printk("hello_read: %llx\n", g_magic_data_addr); + return size; +} + +static ssize_t hello_write(struct file *file, const char __user *buff, + size_t size, loff_t *loff) +{ + if (size > N) + size = N; + if (size < 0) + return -EINVAL; + + memset(data, '\0', sizeof(data)); + + if (0 != copy_from_user(data, buff, size)) + return -ENOMEM; + + printk("hello_write\n"); + printk("data = %s\n", data); + + return size; +} + +static long hello_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + bool feature_val = 0; + switch(cmd) { + case MSR_IA32_ARCH_CAPABILITIES_IS_EXIST: + { + unsigned int bit_val; +#define WHICH_BIT 29 //bit29 + bit_val = (unsigned int)get_msr_bit(WHICH_BIT); + //bit_val = 1; //test for user space + copy_to_user((unsigned long *)arg, &bit_val, sizeof(unsigned int)); + + printk("MSR_IA32_ARCH_CAPABILITIES_IS_EXIST\n"); + break; + } + case GET_MSR_REG_VAL: + { + unsigned long msr_reg; + unsigned long msr_val; + int err = -1; + u32 val_low = 0x55, val_high = 0x55; + //msr_reg = 0x17; //test: display cpu model + + copy_from_user(&msr_reg, (unsigned long *)arg, sizeof(unsigned long)); + printk("msr_reg=0x%x\n", msr_reg); + + err = rdmsr_safe(msr_reg, &val_low, &val_high); + if (err < 0) + { + printk("rdmsr_safe: read msr 0x%x failed\n", msr_reg); + msr_val = ~0x0; + } else { + msr_val = (unsigned long)val_high; + msr_val <<=32; + msr_val |= (unsigned long)val_low; + } + + printk("val_low=0x%x, val_high=0x%x, msr_val=0x%llx; err=0x%x\n", val_low, val_high, msr_val, err); + + copy_to_user((unsigned long *)arg, &msr_val, sizeof(unsigned long)); + + printk("GET_MSR_REG_VAL\n"); + break; + } + case SET_MSR_REG_VAL: + { + unsigned long msr_reg; + unsigned long msr_val; + int err = -1; + u32 val_low = 0x55, val_high = 0x55; + msr_reg_val_t msr_para; + + copy_from_user(&msr_para, arg, sizeof(msr_reg_val_t)); + msr_reg = msr_para.reg; + val_low = msr_para.val & 0x00000000FFFFFFFF; + val_high = msr_para.val >> 32; + printk("msr_reg=0x%x, low=0x%x, high=0x%x\n", msr_reg, val_low, val_high); + + err = wrmsr_safe(msr_reg, val_low, val_high); + msr_para.ret = err; + if (err < 0) + { + printk("wrmsr_safe: write msr 0x%x failed\n", msr_reg); + } + + printk("val_low=0x%x, val_high=0x%x, err=0x%x\n", val_low, val_high, err); + + copy_to_user((unsigned long *)arg, &msr_para, sizeof(msr_reg_val_t)); + + printk("SET_MSR_REG_VAL\n"); + break; + } + case READ_CPUID: + { + exx_reg_val_t reg = {0}; + copy_from_user(®, (unsigned long *)arg, sizeof(exx_reg_val_t)); + //reg.eax_val = 0x7; + //reg.ecx_val = 0; + + read_cpuid(®); + + copy_to_user((unsigned long *)arg, ®, sizeof(exx_reg_val_t)); + printk("eax_tet_val = 0x%x\n", reg.eax_ret_val); + printk("ebx_tet_val = 0x%x\n", reg.ebx_ret_val); + printk("ecx_tet_val = 0x%x\n", reg.ecx_ret_val); + printk("edx_tet_val = 0x%x\n", reg.edx_ret_val); + printk("READ_CPUID\n"); + break; + } + case DUMP_MEM: + printk("KERNEL:dump_mem begin...\n"); + dump_mem((unsigned char *)arg); + printk("KERNEL:dump_mem done...\n"); + break; + case CHECK_FEATURE: + feature_val = test_bit(X86_FEATURE_RETPOLINE, (unsigned long *)(boot_cpu_data.x86_capability)); + copy_to_user(arg, &feature_val, sizeof(feature_val)); + break; + + default: + printk("enter default\n"); + break; + } + + printk("hello_unlocked_ioctl\n"); + + return 0; +} + +static struct cdev cdev; +static struct file_operations hello_ops = { + .owner = THIS_MODULE, + .open = hello_open, + .read = hello_read, + .write = hello_write, + .release = hello_release, + .unlocked_ioctl = hello_unlocked_ioctl, +}; + + +typedef struct magic_heap { + char * name; + int magic[100]; +} magic_heap_t; + +int test_thread(void* data) +{ + printk("test_driver: enter %s\n", __func__); + magic_heap_t *magic_heap_p; + int i; + + unsigned long magic_data[20][2] = {0}; + for (i=0; i < 20; i++) { + magic_data[i][0] = &magic_data[i][0]; + magic_data[i][1] = &magic_data[i][0];; + + } + g_magic_data_addr = (unsigned long long)magic_data; + + + printk("test_driver magic_data addr: 0x%llx\n", magic_data); + + magic_heap_p = (magic_heap_t *)kmalloc(sizeof(magic_heap_t), GFP_KERNEL); + magic_heap_p->name = "my_magic_heap"; + for (i = 0; i < 100; i++) { + magic_heap_p->magic[i] = 0xdeadbeef; + } + printk("test_driver magic_heap_p: 0x%llx\n", magic_heap_p); + + + i = 0; + while(1) { + //printk("test_driver: magic_data %d: %x\n", magic_data[i % 20][0], magic_data[i % 20][1]); + //printk("test_driver: magic_heap_p->magic %x\n", magic_heap_p->magic[i % 100]); + msleep(5000); + i++; + } + return 0; +} + +static int hello_init(void) +{ + int ret; + + printk("hello_init\n"); + dev_t devno = MKDEV(major, minor); + ret = register_chrdev_region(devno, 1, DEV_NAME); + if (0 != ret) { + //alloc_chrdev_region(&devno,0,1,DEV_NAME); + printk("register_chrdev_region : error\n"); + } + + cdev_init(&cdev, &hello_ops); + ret = cdev_add(&cdev, devno, 1); + if (0 != ret) { + printk("cdev_add\n"); + unregister_chrdev_region(devno, 1); + return -1; + } + +#ifdef CLASS_DEV_CREATE + cls = class_create(THIS_MODULE, DEV_NAME); + device_create(cls, device, devno, NULL, DEV_NAME); +#endif + + printk("hello_init\n"); + + kthread_run(test_thread, NULL, "my_test_thread"); + return 0; +} + +static void hello_exit(void) +{ + dev_t devno = MKDEV(major, minor); + +#ifdef CLASS_DEV_CREATE + device_destroy(cls, devno); + class_destroy(cls); +#endif + + cdev_del(&cdev); + unregister_chrdev_region(devno, 1); + + printk("hello_exit\n"); +} + +module_init(hello_init); +module_exit(hello_exit); diff --git a/drivers/test_driver/test_driver.h b/drivers/test_driver/test_driver.h new file mode 100755 index 000000000000..c30e93a54c57 --- /dev/null +++ b/drivers/test_driver/test_driver.h @@ -0,0 +1,38 @@ +#ifndef __TEST_DRIVER_H +#define __TEST_DRIVER_H +#define MSR_IA32_ARCH_CAPABILITIES_IS_EXIST _IO('K',0) +#define GET_MSR_REG_VAL _IO('K',1) +#define SET_MSR_REG_VAL _IO('K',2) +#define READ_CPUID _IO('K',3) + +typedef struct exx_reg_val{ + int eax_val; + int ebx_val; + int ecx_val; + int edx_val; + + int eax_ret_val; + int ebx_ret_val; + int ecx_ret_val; + int edx_ret_val; +} exx_reg_val_t; + + +#define DUMP_MEM _IO('k', 1) +#define CHECK_FEATURE _IO('o', 1) + + +typedef struct mem_dump { + unsigned long long addr; + unsigned int len; + unsigned int padding; + unsigned char buf[0]; +} mem_dump_t; + +typedef struct msr_reg_val{ + unsigned long reg; + unsigned long val; + long ret; +} msr_reg_val_t; + +#endif diff --git a/mm/usercopy.c b/mm/usercopy.c index 14faadcedd06..ef720e36bc5d 100644 --- a/mm/usercopy.c +++ b/mm/usercopy.c @@ -277,14 +277,15 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user) */ return; default: - usercopy_abort("process stack", NULL, to_user, 0, n); + //usercopy_abort("process stack", NULL, to_user, 0, n); + break; } /* Check for bad heap object. */ check_heap_object(ptr, n, to_user); /* Check for object in kernel to avoid text exposure. */ - check_kernel_text_object((const unsigned long)ptr, n, to_user); + //check_kernel_text_object((const unsigned long)ptr, n, to_user); } EXPORT_SYMBOL(__check_object_size);