Kernel中如何操作CPU及外设寄存器
01
ARM Coretex-A9寄存器
对于ARM Coretex-A9处理器而言其寄存器主要包括两大部分,分别是通用寄存器以及系统控制寄存器。
上图所示的通用寄存器,主要是在代码运行过程中使用到,CPU通过该部分寄存器执行代码并完成相关的运算操作。对于调试过程中比较关心的是SP、LR、PC以及R0~R3几个寄存器。而其他寄存器在特定场景下也有应用,例如U-Boot在代码重定向的过程中使用到了R9寄存器来暂存gd_t的地址。调试过程中,当代码崩溃的时候我们第一步是看PC是多少,以此通过追踪反汇编文件来定位到具体的指令处。
MRC和MCR指令如下图所示:
02
调试工具操作CPU寄存器
当希望改写CPU通用寄存器的时候,可以通过wreg来实现:
同样,CP15寄存器也可以操作:
03
C代码中内嵌汇编
1#define _ARM_MRC(coproc, opcode1, Rt, CRn, CRm, opcode2) \
2 asm volatile ("mrc p" #coproc ", " #opcode1 ", %[output], c" #CRn ", c" #CRm ", " #opcode2 "\n" : [output] "=r" (Rt))
3#define _ARM_MCR(coproc, opcode1, Rt, CRn, CRm, opcode2) \
4 asm volatile ("mcr p" #coproc ", " #opcode1 ", %[input], c" #CRn ", c" #CRm ", " #opcode2 "\n" :: [input] "r" (Rt))
5
6void func1(void)
7{
8 u32 ttbr0,ttbr1;
9 _ARM_MRC(15, 0, ttbr0, 2, 0, 0);
10 _ARM_MRC(15, 0, ttbr1, 2, 0, 1);
11 printk("ttbr0 0x%08x ttbr1 0x%08x\n", ttbr0, ttbr1);
12}
对于其他寄存器的操作,U-Boot中\arch\arm\include\asm\system.h的代码可以借鉴,通过移植该部分代码可以实现我们的需求:
1static inline unsigned int get_cr(void)
2{
3 unsigned int val;
4
5 if (is_hyp())
6 asm volatile("mrc p15, 4, %0, c1, c0, 0 @ get CR" : "=r" (val)
7 :
8 : "cc");
9 else
10 asm volatile("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val)
11 :
12 : "cc");
13 return val;
14}
15
16static inline void set_cr(unsigned int val)
17{
18 if (is_hyp())
19 asm volatile("mcr p15, 4, %0, c1, c0, 0 @ set CR" :
20 : "r" (val)
21 : "cc");
22 else
23 asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" :
24 : "r" (val)
25 : "cc");
26 isb();
27}
04
devmem
对于kernel已经挂在文件系统之后,操作外设寄存器的方法有很多,但是比较倾向于使用devmem这个命令,该命令可以直接操作物理内存空间,不必考虑虚拟地址和物理地址之间的映射。该命令由busybox提供,通过配置busybox可以在生成的文件系统中包含它。
通过devmem操作寄存器的过程如下
推荐阅读:
评论