Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
ART-Pi Smart
ART-Pi Smart 下调试物理内存小工具
发布于 2022-04-27 18:59:26 浏览:689
订阅该版
[tocm] #### dbg_mm : ART-Pi Smart 调试物理地址的驱动 因为 **ART-Pi Smart** 使用了 **MMU** 来管理内存,这在一定程度为调试外设驱动增加了复杂度,为了方便在命令行下调试物理内存,我写了一个 ``dbg_mm`` 驱动,导出 了两个命令: * rdbg_mm 物理地址 数据长度 # 备注地址要 4 字节对齐,长度以 4 字节为单位,地址和数据都要 0x/0X 开头 * wdbg_mm 物理地址 数据0 数据1 .... # 备注地址要 4 字节对齐,数据 16 进制表示,地址和数据都要 0x/0X 开头 查看 ART-Pi Smart 的内存地址映射是这样的: ![](https://s3.bmp.ovh/imgs/2022/04/27/6185a8c0a160acee.png) 根据上述映射关系,实现的 dbg_mm 驱动的源码是这样的: ``` C /****************************************************************************** * File: drv_dbg_mm.c * * Author: iysheng@163.com * Created: 04/26/22 * Description: 调试物理内存驱动 *****************************************************************************/ #include
#include
#include
#include "ioremap.h" #include
#include
#define LOG_LVL LOG_LVL_DBG #define LOG_TAG "dbg.mm" #include
typedef enum { DBG_MM_SET_WIDTH_BITS, DBG_MM_GET_WIDTH_BITS, DBG_MM_SET_ADDR_STEP, DBG_MM_GET_ADDR_STEP, }dbg_mm_cmd_E; static struct rt_device gs_dbg_mm_dev; /* 默认支持字节访问,但是 IMX6ULL 对数据访问总线宽度有严格的限制 * 在访问外设寄存器时,如果 width 宽度不匹配导致崩溃 * */ static int __gs_width_in_bits = 8; /* 地址 step 默认和位宽保持一致 */ static int __gs_addr_step = 1; #define PV_LEN 0x20000000 static void dbg_mm_hex_smart(rt_uint32_t paddr, rt_uint32_t addr, rt_size_t len) { rt_size_t i = 0, j = 0; for (; i < len; i += 4) { rt_kprintf("0x%08x:", paddr + i * __gs_addr_step); for (j = 0; j < 4; j++) { if (j + i < len) { switch (__gs_width_in_bits / 8) { case 1: rt_kprintf("0x%02x ", *((rt_uint8_t *)addr)); break; case 2: rt_kprintf("0x%04x ", *((rt_uint16_t *)addr)); break; case 4: rt_kprintf("0x%08x ", *((rt_uint32_t *)addr)); break; } addr += __gs_addr_step; } else { break; } } rt_kprintf("\n"); } } static void dbg_mm_copy_smart(rt_uint32_t dst, rt_uint32_t src, rt_size_t len) { rt_size_t i = 0; for (; i < len; i++) { switch (__gs_width_in_bits / 8) { case 1: *((rt_uint8_t *)dst) = *((rt_uint8_t *)src); break; case 2: *((rt_uint16_t *)dst) = *((rt_uint16_t *)src); break; case 4: *((rt_uint32_t *)dst) = *((rt_uint32_t *)src); break; default: break; } dst += __gs_addr_step; src += __gs_addr_step; } } static rt_err_t dbg_mm_init(rt_device_t dev) { return RT_EOK; } static rt_err_t dbg_mm_open(rt_device_t dev, rt_uint16_t oflag) { return RT_EOK; } static rt_err_t dbg_mm_close(rt_device_t dev) { return RT_EOK; } static rt_err_t dbg_mm_control(rt_device_t dev, int cmd, void *args) { int ret = RT_EOK; switch (cmd) { case DBG_MM_SET_WIDTH_BITS: __gs_width_in_bits = *((int *)args); break; case DBG_MM_GET_WIDTH_BITS: *((int *)args) = __gs_width_in_bits; break; case DBG_MM_SET_ADDR_STEP: __gs_addr_step = *((int *)args); break; case DBG_MM_GET_ADDR_STEP: *((int *)args) = __gs_addr_step; break; default: break; } return ret; } static rt_size_t dbg_mm_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { rt_uint32_t * pvaddr = RT_NULL; int io_remaped = 0; if (pos >= KERNEL_VADDR_START + PV_OFFSET && pos < KERNEL_VADDR_START + PV_OFFSET + PV_LEN) { pvaddr = (rt_uint32_t *)(pos - PV_OFFSET); } else if (pos < KERNEL_VADDR_START + PV_OFFSET) { pvaddr = (rt_uint32_t *)rt_ioremap((void *)pos, __gs_addr_step * size); if (!pvaddr) { LOG_E("Failed io remap@%#x.", pos); return 0; } io_remaped = 1; } //LOG_I("Rpa@%#x v@%#x.", pos, pvaddr); dbg_mm_copy_smart((rt_uint32_t)buffer, (rt_uint32_t)pvaddr, size); dbg_mm_hex_smart(pos, (rt_uint32_t)pvaddr, size); if (io_remaped) { rt_iounmap((void *)pvaddr); } return size; } extern void rt_hw_cpu_dcache_clean(void *addr, int size); static rt_size_t dbg_mm_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { rt_uint32_t pvaddr = 0; int io_remaped = 0; if (pos > KERNEL_VADDR_START + PV_OFFSET && pos < KERNEL_VADDR_START + PV_OFFSET + PV_LEN) { pvaddr = (rt_uint32_t)(pos - PV_OFFSET); } else if (pos < KERNEL_VADDR_START + PV_OFFSET) { pvaddr = (rt_uint32_t)rt_ioremap((void *)pos, size * __gs_addr_step); if (!pvaddr) { LOG_E("Failed io remap@%#x.", pos); return 0; } io_remaped = 1; } //LOG_I("pa@%#x v@%#x len=%u.", pvaddr, buffer, size); dbg_mm_copy_smart((rt_uint32_t)pvaddr, (rt_uint32_t)buffer, size); dbg_mm_hex_smart(pos, (rt_uint32_t)pvaddr, size); if (io_remaped) { rt_iounmap((void *)pvaddr); } else { rt_hw_cpu_dcache_clean((void *)pvaddr, size * __gs_addr_step); } return size; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops dbg_mm_ops = { dbg_mm_init, dbg_mm_open, dbg_mm_close, dbg_mm_read, dbg_mm_write, dbg_mm_control }; #endif int rt_hw_dbg_mm_init(void) { /* set device type */ gs_dbg_mm_dev.type = RT_Device_Class_Miscellaneous; /* initialize device interface */ #ifdef RT_USING_DEVICE_OPS gs_dbg_mm_dev.ops = &dbg_mm_ops ; #else gs_dbg_mm_dev.init = dbg_mm_init; gs_dbg_mm_dev.open = dbg_mm_open; gs_dbg_mm_dev.close = dbg_mm_close; gs_dbg_mm_dev.read = dbg_mm_read; gs_dbg_mm_dev.write = dbg_mm_write; gs_dbg_mm_dev.control = dbg_mm_control; #endif /* register to device manager */ rt_device_register(&gs_dbg_mm_dev, "dbg_mm", RT_DEVICE_FLAG_RDWR); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_dbg_mm_init); /* * dbg_mm <-w> <-b width> <-s step> addr
* */ long dbg_mm(int argc, char * argv[]) { int i = 0; rt_uint32_t paddr = 0x0; rt_size_t len = 1; int widths_in_bits = 0, addr_in_step = -1, read_or_write = 0 /* 默认读数据 */; rt_uint32_t buffer[128]; int opt; optind = 0; while ((opt = getopt(argc, argv, "wb:s:")) != -1) { switch (opt) { case 'b':widths_in_bits = atoi(optarg);break; case 's':addr_in_step = atoi(optarg);break; /* 修改为写数据 */ case 'w':read_or_write = 1;break; default:break; } } if (widths_in_bits) { if (!gs_dbg_mm_dev.ops->control(&gs_dbg_mm_dev, DBG_MM_SET_WIDTH_BITS, &widths_in_bits)) { LOG_I("widths_int_bits:%d.", widths_in_bits); } } else { if (!gs_dbg_mm_dev.ops->control(&gs_dbg_mm_dev, DBG_MM_GET_WIDTH_BITS, &widths_in_bits)) { LOG_I("widths_int_bits:%d.", widths_in_bits); } } if (addr_in_step != -1) { if (!gs_dbg_mm_dev.ops->control(&gs_dbg_mm_dev, DBG_MM_SET_ADDR_STEP, &addr_in_step)) { LOG_I("addr_in_step:%d.", addr_in_step); } } else { if (!gs_dbg_mm_dev.ops->control(&gs_dbg_mm_dev, DBG_MM_GET_ADDR_STEP, &addr_in_step)) { LOG_I("addr_in_step:%d.", addr_in_step); } } if (optind >= argc) { LOG_E("invalid format"); return -2; } if (rt_strstr(argv[optind], "0x") || rt_strstr(argv[optind], "0X")) { sscanf(argv[optind++], "0x%x", &paddr); if (paddr % (widths_in_bits / 8)) { LOG_E("addr should align with:%d", widths_in_bits / 8); return -3; } } else { LOG_E("invalid address format, use 0x/0X prefix please."); return -4; } if (!read_or_write) { if (optind < argc) { len = atoi(argv[optind]); } #ifdef RT_USING_DEVICE_OPS gs_dbg_mm_dev.ops->read(&gs_dbg_mm_dev, paddr, buffer, len); #else gs_dbg_mm_dev.read(&gs_dbg_mm_dev, paddr, buffer, len); #endif } else { for (i = 0; i < argc - optind; i++) { if (rt_strstr(argv[i + optind], "0x") || rt_strstr(argv[i + optind], "0X")) { switch (addr_in_step) { case 1: sscanf(argv[i + optind], "0x%hhx", (rt_uint8_t *)((rt_uint32_t)buffer + i * addr_in_step)); break; case 2: sscanf(argv[i + optind], "0x%hx", (rt_uint16_t *)((rt_uint32_t)buffer + i * addr_in_step)); break; case 4: sscanf(argv[i + optind], "0x%x", (rt_uint32_t *)((rt_uint32_t)buffer + i * addr_in_step)); break; default: break; } } else { LOG_E("invalid data format, use 0x/0X prefix please."); return -3; } } #ifdef RT_USING_DEVICE_OPS gs_dbg_mm_dev.ops->write(&gs_dbg_mm_dev, paddr, buffer, i); #else gs_dbg_mm_dev.write(&gs_dbg_mm_dev, paddr, buffer, i); #endif } return 0; } MSH_CMD_EXPORT(dbg_mm, read dbg mm); ``` 实现的效果是这样的: ![](https://s3.bmp.ovh/imgs/2022/04/27/640797ae7c67ed23.png) 为什么实现的这么复杂呢,因为我调试的时候发现,IMX6ULL 对外设地址的对齐访问要求的比较严格。以``0x20e01e0`` 这个地址为例,查看手册: ![](https://s3.bmp.ovh/imgs/2022/04/27/221b40b0e6c568c1.png) 这个地址是 32 bit的,如果我以1字节对齐访问就是出现这样的错误: ``` text [0mbacktrace: [33m[98553] W/BACKTRACE: unwind: Unsupported personality routine 81019b40 in the index at c00ed168 [0m data abort:Execption: r00:0xc0144234 r01:0xf01951e0 r02:0xf01951e0 r03:0xc0144234 r04:0xc0002e5c r05:0xdeadbeef r06:0xdeadbeef r07:0xdeadbeef r08:0xdeadbeef r09:0xdeadbeef r10:0xdeadbeef fp :0xc01441f4 ip :0x00000000 sp :0xc01441d8 lr :0xc0002f3c pc :0xc0002ca0 cpsr:0x60000013 dfsr:0x00001008 ttbr0:0x8012c018 dfar:0xf01951e0 0xf01951e0 -> 0x020e01e0 thread pri status sp stack size max used left tick error -------- --- ------- ---------- ---------- ------ ---------- --- tshell 20 running 0x000001dc 0x00001000 38% 0x00000007 -09 sysinfo_ 25 suspend 0x0000011c 0x00004000 02% 0x0000012c 000 sys_work 23 suspend 0x00000088 0x00001000 03% 0x0000000a 000 usbd 8 suspend 0x000000ec 0x00001000 05% 0x00000014 -09 link_d1 30 suspend 0x000000c4 0x00001000 11% 0x00000002 000 tcpip 10 suspend 0x00000110 0x00002000 08% 0x0000000f -09 etx 12 suspend 0x000000d4 0x00002000 03% 0x00000010 -09 erx 12 suspend 0x000000dc 0x00002000 08% 0x00000008 -09 mmcsd_de 22 suspend 0x000000dc 0x00001000 15% 0x00000002 -09 tidle0 31 ready 0x00000068 0x00002000 02% 0x0000000b 000 timer 4 suspend 0x00000084 0x00001000 03% 0x00000009 000 main 10 suspend 0x000000cc 0x00001000 34% 0x00000007 000 shutdown... (0) assertion failed at function:rt_hw_cpu_shutdown, line number:87 ``` 再举一个例子``0x21a0000``地址为例: ![](https://s3.bmp.ovh/imgs/2022/04/27/4b93ca098131dac1.png) 如果我以32bit对齐访问,还是会出问题: ``` backtrace: [109559] W/BACKTRACE: unwind: Unsupported personality routine 81019b40 in the index at c00ed168 data abort:Execption: r00:0xc0144234 r01:0xf0195000 r02:0xf0195000 r03:0xc0144234 r04:0xc0002e5c r05:0xdeadbeef r06:0xdeadbeef r07:0xdeadbeef r08:0xdeadbeef r09:0xdeadbeef r10:0xdeadbeef fp :0xc01441f4 ip :0x00000000 sp :0xc01441d8 lr :0xc0002f3c pc :0xc0002cc8 cpsr:0x60000013 dfsr:0x00001008 ttbr0:0x8012c018 dfar:0xf0195000 0xf0195000 -> 0x021a0000 thread pri status sp stack size max used left tick error -------- --- ------- ---------- ---------- ------ ---------- --- tshell 20 running 0x000001dc 0x00001000 38% 0x00000002 -09 sysinfo_ 25 suspend 0x0000011c 0x00004000 02% 0x0000012c 000 sys_work 23 suspend 0x00000088 0x00001000 03% 0x0000000a 000 usbd 8 suspend 0x000000ec 0x00001000 05% 0x00000014 -09 link_d1 30 suspend 0x000000c4 0x00001000 11% 0x00000002 000 tcpip 10 suspend 0x00000110 0x00002000 08% 0x00000011 -09 etx 12 suspend 0x000000d4 0x00002000 03% 0x00000010 -09 erx 12 suspend 0x000000dc 0x00002000 08% 0x0000000b -09 mmcsd_de 22 suspend 0x000000dc 0x00001000 15% 0x00000002 -09 tidle0 31 ready 0x00000068 0x00002000 02% 0x00000003 000 timer 4 suspend 0x00000084 0x00001000 03% 0x00000009 000 main 10 suspend 0x000000cc 0x00001000 34% 0x00000007 000 ``` 为了保证可以改善上述问题,我开发了这个驱动用来调试物理内存。根据上述例子,查看的步骤是这样的: ```bash msh />dbg_mm -b 32 -s 4 0x20e01e0 [86777] I/dbg.mm: widths_int_bits:32. [86782] I/dbg.mm: addr_in_step:4. 0x020e01e0:0x00000010 msh />dbg_mm -b 16 -s 4 0x21a0000 5 [37268] I/dbg.mm: widths_int_bits:16. [37272] I/dbg.mm: addr_in_step:4. 0x021a0000:0x0000 0x001f 0x0080 0x0081 0x021a0010:0x0078 ``` 这个工具还支持修改指定的物理地址,我以内存为例记录下方法: ```bash msh />dbg_mm -b 16 -s 2 0x90000000 16 [30352] I/dbg.mm: widths_int_bits:16. [30356] I/dbg.mm: addr_in_step:2. 0x90000000:0x1111 0x1111 0x2222 0x0000 0x90000008:0x3333 0x3333 0x0067 0x0000 0x90000010:0x0012 0x0000 0x1900 0x0000 0x90000018:0x9dbc 0xc00b 0x00e1 0x0500 msh />dbg_mm -b 16 -s 2 -w 0x90000000 0xaaaa 0xbbbb 0xcccc 0xdddd 0xeeee 0xffff [69352] I/dbg.mm: widths_int_bits:16. [69356] I/dbg.mm: addr_in_step:2. 0x90000000:0xaaaa 0xbbbb 0xcccc 0xdddd 0x90000008:0xeeee 0xffff ``` 使用上述命令的时候还是要小心不要越界,否则还是会崩溃的。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
iysheng
这家伙很懒,什么也没写!
文章
10
回答
15
被采纳
4
关注TA
发私信
相关文章
1
求助vscode开发art-pi smart开发板的问题
2
vscode下载rt-smart用户态代码时udb有问题
3
RGB565 显示图片异常
4
浮点数打印,从内核态直接打印和从用户态访问设备再触发打印,效果不一致
5
csi 开启 DMA_REQ_EN_RFF 前提下,开启 CSI 就卡住无打印
6
求助如何移植rt-thread到野火imx6ull开发板上
7
RT-thread smart 用户态程序运行出错
8
art-pi-smart 编译报错
9
ART-PI Smart User 运行LED 程序崩溃
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部