used to read/write memory/registers from user mode

/*
** regtool.c, regtool driver, used to read/write memory/registers from user mode
** Copyright (C) 2013 liaods < dongsheng.liao@gmail.com >
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
*/
#include <linux/module.h>
#include <linux/major.h>
#include <linux/io.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/fs.h>

#define DRIVER_NAME "regtool"

#define REGTOOL_GET 0x1234
#define REGTOOL_SET 0x5678

#define REGTOOL_MAX_ADDR 0xffffffff
#define REGTOOL_SIZE 1024

#define REGTOOL_MAJOR 280

typedef enum {
    CMD_REGCTL_BYTE = 0,
    CMD_REGCTL_WORD = 1,
    CMD_REGCTL_DWORD = 2,
} regtool_type_t;

typedef struct {
    u32 addr;
    u32 value;
    regtool_type_t type;
} regtool_data_t;

static long regtool_ioctl(struct file *file,
    unsigned int cmd, unsigned long arg)
{
    void __user *argp = (void __user *)arg;
    regtool_data_t data;
    void __iomem *virt;

    memset((void *)&data, 0, sizeof(data));

    if( copy_from_user((void *)&data, argp, sizeof(data)) )
        return -EFAULT;

    if( data.addr >= REGTOOL_MAX_ADDR )
        return -EINVAL;

    virt = ioremap_nocache(data.addr, REGTOOL_SIZE);
    if ( virt == NULL )
    {
        printk("remap failed!\n");
        return -ENOMEM;
    }

    switch( cmd )
    {
        case REGTOOL_GET:
            if( data.type == CMD_REGCTL_BYTE )
            {
                data.value = readb(virt);
            }
            else if( data.type == CMD_REGCTL_WORD )
            {
                data.value = readw(virt);
            }
            else if( data.type == CMD_REGCTL_DWORD )
            {
                data.value = readl(virt);
            }
            iounmap(virt);
            if( copy_to_user(argp, (void *)&data, sizeof(data)))
                return -EFAULT;
            break;

        case REGTOOL_SET:
            if( data.type == CMD_REGCTL_BYTE )
            {
                writeb((u8)data.value, (unsigned char *)virt);
            }
            else if( data.type == CMD_REGCTL_WORD )
            {
                writew((u16)data.value, (unsigned short *)virt);
            }
            else if( data.type == CMD_REGCTL_DWORD )
            {
                writel((u32)data.value, (unsigned long *)virt);
            }
            iounmap(virt);
            break;
            
        default:
            iounmap(virt);
            return -EINVAL;
    }
    return 0;
}

static int regtool_open(struct inode *inode, struct file *file)
{
    return 0;
}

static int regtool_close(struct inode *inode, struct file *file)
{
    return 0;
}

static struct file_operations regtool_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = regtool_ioctl,
    .open = regtool_open,
    .release = regtool_close,
};


static int __init regtool_init(void)
{
    int ret = register_chrdev(REGTOOL_MAJOR, DRIVER_NAME, &regtool_fops);
    printk("major=%d\n", REGTOOL_MAJOR);
    return ret;
}

static void __exit regtool_exit(void)
{
    unregister_chrdev(REGTOOL_MAJOR, DRIVER_NAME);
}

module_init(regtool_init);
module_exit(regtool_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("liaods");



/*
** regtool.c, used to get/set registers from user space
** usage: regtool address < b | w | d > < get | < set value > >
** Copyright (C) 2013 liaods <dongsheng.liao@gmail.com>
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <string.h>
#include <unistd.h>

#define REGTOOL_DEV "/dev/regtool"
#define REGTOOL_GET 0x1234
#define REGTOOL_SET 0x5678

#define REGTOOL_MAX_ADDR 0x50b00000

typedef enum {
    CMD_REGCTL_BYTE = 0,
    CMD_REGCTL_WORD = 1,
    CMD_REGCTL_DWORD = 2,	
} regtcl_type_t;

typedef struct {
    unsigned long addr;
    unsigned long value;
    regtcl_type_t type;
} regtool_data_t;



int main(int argc, char **argv)
{
    int i=0, j=0;
    int fd;
    regtool_data_t data;
    int cmd = -1;
    
    memset((void *)&data, 0, sizeof(data));
    
    if( argc != 4 && argc != 5)
    {
        printf("Usage: %s address <b|w|d> <get [length] | <set value> >\n", argv[0]);
        printf(" b ( 8bit) w( 16bit) d(32 bit) \n\n");
        printf(" example:\n");
        printf(" %s 0x28000000 d get \n", argv[0]);
        printf(" %s 0x28000000 d get 0x100\n", argv[0]);
        printf(" %s 0x28000000 d set 0x12345678\n\n", argv[0]);
        return -1;
    }
    

    
    system("mknod /dev/regtool c 280 0 > /dev/null 2>&1");
    fd = open(REGTOOL_DEV, O_RDWR, 0);

    if ( fd < 0 )
    {
        printf("open %s failed\n", REGTOOL_DEV);
        return -1;
    }
    
    sscanf(argv[1], "%x", (unsigned int *)&data.addr);
    
    if( strcmp("b", argv[2]) == 0 )
        data.type = CMD_REGCTL_BYTE;
    else if ( strcmp("w", argv[2]) == 0 )
        data.type = CMD_REGCTL_WORD;
    else if ( strcmp("d", argv[2]) == 0 )
        data.type = CMD_REGCTL_DWORD;
    else
    {
        printf("invalid argument, argv[2] must be \"b\" , \"w\" or \"d\" \n");
        close(fd);
        return -1;
    }
        
    if( strcmp("get", argv[3]) == 0 )
        cmd = REGTOOL_GET;
    else if ( strcmp("set", argv[3]) == 0 )
        cmd = REGTOOL_SET;
    else
    {
        printf("invalid argument, argv[3] must be \"get\" or \"set\" \n");
        close(fd);
        return -1;
    }
    
    if( argc == 5 )
    {
        sscanf(argv[4], "%x", (unsigned int *)&data.value);
        if ( cmd == REGTOOL_GET && data.value > 0 )
        {
            i = data.value;
            for( j= 0; j < i; j+= (1<<data.type))
            {
                if( ioctl(fd, cmd, &data) )
                {
                    printf("ioctl failed!\n");
                    close(fd);
                    return -1;
                }
    
                printf("type=%d, address:0x%.8x, value=0x%.8x\n",
                    data.type, (unsigned int)data.addr, (unsigned int)data.value);
                data.addr += (1<<data.type);
            }
            close(fd);
            return 0;
        }
    }
    
    if( ioctl(fd, cmd, &data) )
    {
        printf("ioctl failed!\n");
        close(fd);
        return -1;
    }
    
    printf("address:0x%.8x, type=%d, value=0x%.8x\n",
        (unsigned int)data.addr, data.type, (unsigned int)data.value);
    close(fd);
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值