用户空间显示指定物理地址的内容

本文发布时间: 2019-Mar-22
linux上开发驱动时,经常要查看某个物理地址的内存,最方便的方法当然是在shell上输入命令。不过好像没有现成的工具(或者是我不知道 :< )。在vxworks上开发时,感觉最有用的就是vxworks那强大的调试函数,几乎所有想到的东西都能够通过一个调试函数显示出来。下面就实现一个简单的调试集程序,目前的功能只有显示指定物理地址的内容,类似于vxworks的dump(d)函数。不过预留了扩展接口,可以方便的加入其他调试工具。实现思路与调用的函数都很简单,可以算的上是朴素的实现了,但却很有用,起码我可以查看很多设备寄存器的一,首先是定义需求1. 有一个可以接受命令的输入工具;2. 可以执行d命令,完成指定物理地址内容的打印;二,设计思路1. 在进程空间增加一个命令处理程序。2. 通过字符设备的write函数把解析后的命令传入linux内核空间。3. 在内核中根据传入的命令找到对应处理函数。4. 调用处理函数(这里就是显示指定物理地址内容)三,接口设计1. 命令解析 int CmdParser(USR_CMD *cmd, int argc, char *argv[]);2. 字符设备 Device name: asbdebug Device type: char device API: open/close/write3. 内核中d命令对应的函数 void DumpMem(USR_CMD *cmd);4. USR_CMD定义struct USR_CMD { char name[ASB_NAME_MAX]; u32 para[4]; };四,实现细节1. main函数int main(int argc, char *argv[]){ int fd; ssize_t size; struct USR_CMD cmd; int i; // parse cmd if (-1 == CmdParser(&cmd, argc, argv)) { Printf(“CmdParser error.\n”); Return (-1); } // open device fd = open("/dev/hqdebug", O_RDWR); if (-1 == fd) { printf("open failed: %x\n", errno); return (-1); } // write cmd to device size = write(fd, (char*)&cmd, sizeof(cmd)); if (-1 == size) { printf("write failed: %x\n", errno); return (-1); } // close device close(fd); return 0;}2. parse函数这里是最简单的解析函数,只能接受4个参数,而且参数类型支持的也不完善,不过对于d命令已经够了。int CmdParser(USR_CMD *cmd, int argc, char *argv[]){ ssize_t size; int i; if (argc < 2) { printf("too few para:%d\n", argc); return (-1); } if (argc > 6) { printf("too many para:%d\n", argc); return (-1); } memset(cmd, 0, sizeof(struct USR_CMD)); strcpy(cmd->name, argv[1]); for (i = 2; i < argc; i ) { if (('0' == *(argv[i])) && ('x' == *(argv[i] 1))) { // hex parse sscanf(argv[i], "0x%x", &cmd->para[i-2]); } else if ('"' == *(argv[i])) { // string parse } else { cmd->para[i-2] = atoi(argv[i]); } }3. 设备驱动字符设备是最简单的驱动,细节就不写了,只看看write函数。这里通过命令匹配的方法找到该命令对应的函数入口。static ssize_t chr_write (struct file *f, const char __user *addr, size_t size, loff_t *off){ void (*ptr)(u32 para[4]); struct USR_CMD cmd; int i; // get cmd from user space to kernel space; copy_from_user((char*)&cmd, addr, sizeof(struct USR_CMD)); printk(KERN_INFO"show command: %s", cmd.name); // get function ptr by name; for (i = 0; i < mychrdev01.listSize; i ) { if (0 == strcmp(cmd.name, mychrdev01.cmdList[i].name)) { ptr = mychrdev01.cmdList[i].ptr; break; } } if (i >= mychrdev01.listSize) { printk(KERN_ERR"error command: %s", cmd.name); return (-1); } // run function ptr; ptr(cmd.para); return 0;}4. 打印函数static void memdump(u32 para[4]){ int i; char *base; u32 size = para[1]; base = (char*)ioremap(para[0], size); for (i = 0; i < size; i ) { if ((i%4 == 0) && i) printk(" "); if (i%(4*4) == 0) printk("\nx: ", (u32)(para[0] i)); printk("x", *(base i)); }printk("\n%"); iounmap(base);}这里重点关注ioremap函数,因为用物理地址无法直接使用,所以用ioremap把它映射到内核空间在操作。在最后,别忘了退出时使用iounmap解除映射。


(以上内容不代表本站观点。)
---------------------------------
本网站以及域名有仲裁协议。
本網站以及域名有仲裁協議。

2024-Mar-04 02:11pm
栏目列表