Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1366347
  • 博文数量: 118
  • 博客积分: 3888
  • 博客等级: 中校
  • 技术积分: 2940
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-10 18:15
个人简介

一看二做三总结

文章分类

全部博文(118)

分类: LINUX

2014-01-26 11:09:01

本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。

作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.net

背景:
开发设备驱动时,经常需要查看物理设备的寄存器内容,比如在powerpc平台开发时,有时需要查看IMMR指向的cpu寄存器空间的内容,IMMR物理地址是0xe0000000,这个地址无法在shell中直接查看。只能到内核中才能查看,非常不方便。因此希望开发一些小工具,用于实现类似功能。


1. 我
首先是实现一个memdump函数用于打印某段内存的值,这种直接操作物理地址空间的操作,当然只能在内核中做。

这里需要用到ioremap函数,因为即使在内核也不能直接操作物理地址,需要把它映射到内核空间上。
当然最后还需要使用iounmap解除映射。


点击(此处)折叠或打开

  1. static void memdump(u32 para[4])
  2. {
  3.     int i;
  4.     char *base;
  5.     u32 size = para[1];
  6.     
  7.     base = (char*)ioremap(para[0], size);
  8.     
  9.     for (i = 0; i < size; i++) {
  10.         if ((i%4 == 0) && i)
  11.             printk(" ");

  12.         if (i%(4*4) == 0)
  13.             printk("\n%08x: ", (u32)(para[0] + i));

  14.         printk("%02x", *(base + i));
  15.     }

  16.     printk("\n%");
  17.     iounmap(base);
  18. }


2. 我们的目标是在shell中能够查看,所以需要有方法在shell中调用该函数。我们可以做一个简单的字符设备驱动,然后通过read、write的方式调用它。另外为了以后可以很方便的增加新的功能,这里实现了一个简单的命令解析器。


struct MyCmd用于定义已实现的命令格式。驱动中实现的所有命令都存在myCmdList中,本例中只是先了一个“d“命令。struct USR_CMD用于用户向内核传送命令,只有当USR_CMD中的命令能够与myCmdList中的命令匹配上时,才会调用对应命令,否则返回失败。


点击(此处)折叠或打开

  1. struct USR_CMD {
  2.     char name[ASB_NAME_MAX]; // 命令
  3.     u32 para[4]; // 参数
  4. };
  5.     
  6. struct MyCmd {
  7.     char *name; // 命令
  8.     void (*ptr)(u32 para[4]); // 参数
  9. }

  10. struct MyCmd myCmdList[] = {"d", memdump};

  11. static ssize_t chr_write (struct file *f, const char __user *addr, size_t size, loff_t *off)
  12. {
  13.     void (*ptr)(u32 para[4]);
  14.     struct USR_CMD cmd;
  15.     int i;
  16.     
  17.     // get cmd from user space to kernel space;
  18.     copy_from_user((char*)&cmd, addr, sizeof(struct USR_CMD));
  19.     printk(KERN_INFO"show command: %s", cmd.name);
  20.     
  21.     // get function ptr by name;
  22.     for (i = 0; i < sizeof(myCmdList)/sizeof(struct MyCmd); i++) {
  23.         if (0 == strcmp(cmd.name, myCmdList[i].name)) {
  24.             ptr = myCmdList[i].ptr;
  25.             break;
  26.         }
  27.     }
  28.     if (i >= sizeof(myCmdList)/sizeof(struct MyCmd)) {
  29.         printk(KERN_ERR"error command: %s", cmd.name);
  30.         return (-1);
  31.     }
  32.     
  33.     // run function ptr;
  34.     ptr(cmd.para);
  35.     
  36.     return 0;
  37. }

3. 实现命令解释器,用于把从shell输入的命令变成上面定义的USR_CMD格式。

点击(此处)折叠或打开

  1. int CmdParser(USR_CMD *cmd, int argc, char *argv[])
  2.     {
  3.         ssize_t size;
  4.         int i;
  5.         if (argc < 2) {
  6.             printf("too few para:%d\n", argc);
  7.             return (-1);
  8.         }
  9.         if (argc > 6) {
  10.             printf("too many para:%d\n", argc);
  11.             return (-1);
  12.         }
  13.         memset(cmd, 0, sizeof(struct USR_CMD));
  14.         strcpy(cmd->name, argv[1]);
  15.         for (i = 2; i < argc; i++) {
  16.             if (('0' == *(argv[i])) && ('x' == *(argv[i]+1))) {
  17.                 // hex parse
  18.                 sscanf(argv[i], "0x%x", &cmd->para[i-2]);
  19.             } else if ('"' == *(argv[i])) {
  20.             // string parse
  21.         } else {
  22.             cmd->para[i-2] = atoi(argv[i]);
  23.         }
  24.     }
  25.  



 4.  最后实现用户空间入口

点击(此处)折叠或打开

  1. int main(int argc, char *argv[])
  2. {
  3.     int fd;
  4.     ssize_t size;
  5.     struct USR_CMD cmd;
  6.     int i;
  7.     
  8.     // parse cmd
  9.     if (-1 == CmdParser(&cmd, argc, argv))
  10.     {
  11.         Printf(“CmdParser error.\n”);
  12.         Return (-1);
  13.     }
  14.     
  15.     // open device
  16.     fd = open("/dev/hqdebug", O_RDWR);
  17.     if (-1 == fd) {
  18.     printf("open failed: %x\n", errno);
  19.     return (-1);
  20.     }
  21.     
  22.     // write cmd to device
  23.     size = write(fd, (char*)&cmd, sizeof(cmd));
  24.     if (-1 == size) {
  25.     printf("write failed: %x\n", errno);
  26.     return (-1);
  27.     }
  28.     
  29.     // close device
  30.     close(fd);
  31.     
  32.     return 0;
  33. }
在用户空间编译连接上面的 函数,我们命名为hqdbg。

5. 调用
以powepc上的IMMR为例,IMMR的地址一般为0xe0000000。
在shell 上输入:
> ./hqdbg d 0xe0000000 0x1000

则会在shell上显示从0xe0000000开始的长度为0x1000的一段内存。

本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。

作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.net


阅读(4882) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~