很多情况下,我们在调试linux内核子系统或者内核驱动时,经常会用printk将调试信息打印到文件系统中或者串口终端。
但是在某些情况下,在linux系统刚启动时,或者某些场景下无法使用printk打印调试信息到文件系统,系统也无法起来,这个时候都无法查看堆栈信息。
这种情况下,如果板子上还有串口外设可以用,那我们就还有办法。
具体的办法就是通过在C语言代码中内联汇编操作串口寄存器打印,当然如果在汇编中,那就直接操作串口寄存器就好了。
同时这个方法不仅仅适用于linux内核,其他有串口的操作系统内核也可以操作,比如rtos这些。
一、arm32模式下内联汇编操作串口寄存器
假设当前板子上一路串口,寄存器基地址为0x30530000,同时已经配置好波特率还有时钟频率了,我们想让这路串口输出字符“1”,那应该如下操作:
__arm__ __volatile__(
"ldr r0, #0x30530000\n\t"
"ldr r1, #0x00000031\n\t"
"str r1, [r0]\n\t"
);
1、"ldr r0, #0x30530000\n\t"
这里表示ldr将数值0x30530000加载到指定的通用寄存器r0中。
2、 "ldr r0, #0x00000031\n\t"
这里表示ldr将数值0x00000031,也就是字符“1”,加载到指定的通用寄存器r1中。
3、 "str r1, [r0]\n\t"
这里表示寄存器r1的数值写入寄存器r0的地址中,也就是直接写入数据。
二、arm64模式下内联汇编操作串口寄存器
假设当前板子上一路串口,寄存器基地址为0x30530000,同时已经配置好波特率还有时钟频率了,我们想让这路串口输出字符“1”,那应该如下操作:
__arm__ __volatile__(
"ldr x0, #0x30530000\n\t"
"ldr x1, #0x00000031\n\t"
"str x1, [x0]\n\t"
);
1、"ldr x0, #0x30530000\n\t"
这里表示ldr将数值0x30530000加载到指定的通用寄存器x0中。
2、 "ldr x1, #0x00000031\n\t"
这里表示ldr将数值0x00000031,也就是字符“1”,加载到指定的通用寄存器x1中。
3、 "str x1, [x0]\n\t"
这里表示寄存器x1的数值写入寄存器x0的地址中,也就是直接写入数据。
三、arm32与arm64模式下汇编操作的注意细节
在arm32和arm64模式下的汇编其实有个地方是要注意的。
arm32模式下通用寄存器是用r0,arm64模式下通用寄存器是用x0。