我正在经历不同的ARM处理器模式。我想在处于不同模式时检查处理器状态(例如:寄存器值)。
那么有人可以帮我找出样本代码以将处理器置于不同的模式吗?
例如,我找到了未定义模式的代码:
asm volatile (".short 0xffff\n");
答案 0 :(得分:6)
如果您希望从用户空间测试模式,这是一个难题。如果系统中没有 FIQ 外围设备,则可能无法进入 FIQ 模式。您的系统可能根本没有使用监控模式等。要进入中止模式,您可以使用无效指针,或使用mmap
。但是,如果没有内核的帮助,从用户空间回答所有模式切换将是书本(或不可能)。使用 / proc 或 / sys 文件创建测试模块并使用以下技术实现内核代码将是最直接的方法。
您应该知道并非所有模式切换都允许。例如,除非通过异常机制,否则您可能永远不会从用户模式切换到任何其他模式。另一个问题是每个ARM模式都有寄存器。其中一个是非常重要的sp
(或堆栈指针)和lr
(或链接寄存器)that is fundamental to 'C' code。
使用内联汇编程序的宏来绑定测试片段通常比使用函数调用更安全。测试代码不得调用外部例程。这可能很困难,因为使用浮点等可能导致编译器插入隐藏的子例程调用。您应该检查生成的汇编程序并为其他人提供注释。
/* Get the current mode for restoration. */
static inline unsigned int get_cpsr(void)
{
unsigned int rval;
asm (" mrs %0, cpsr\n" : "=r" (rval));
return rval;
}
您可以将其放在头文件中。编译器将内联代码,因此,您只需将msr
指令放在例程中。
要更改模式,请使用类似
的定义 /* Change the mode */
#define change_mode(mode) asm("cps %0" : : "I"(mode))
Tangr有正确的模式定义,
#define MODE_USR 0x10 /* Never use this one, as there is no way back! */
#define MODE_FIQ 0x11 /* banked r8-r14 */
#define MODE_IRQ 0x12
#define MODE_SVC 0x13
#define MODE_MON 0x16
#define MODE_ABT 0x17
#define MODE_UND 0x1B
#define MODE_SYS 0x1F /* Same as user... */
您还需要恢复以前的模式,
#define restore_mode(mode) \
mode &= 0x1f; \
asm(" msr cpsr, %0\n" : : "r"(mode) : "cc")
将它们放在一起如下,
void test_abort(void)
{
unsigned int old_mode = get_cpsr() & 0x1f;
change_mode(MODE_ABT);
/* Your test code here... must not call functions. */
restore_mode(old_mode);
}
这直接回答了你的问题。但是,由于所有困难,编写汇编程序以实现测试通常更容易。我相信您正在尝试利用现有的Linux代码来测试所有模式。这不是ARM-Linux的设计目标,如果没有修改源代码,它将很难实现,并且如果它是高度系统特定的。
答案 1 :(得分:2)
你需要内联汇编,因为C没有内置的方法来实现你想要的。这不是最有效的方法(我的GCC仍会生成无用的mov r3, #0
指令)。
你最好在裸装配中实现这个功能。
#define MODE_USR 0x10
#define MODE_FIQ 0x11
#define MODE_IRQ 0x12
#define MODE_SVC 0x13
#define MODE_ABT 0x17
#define MODE_UND 0x1B
#define MODE_SYS 0x1F
#define MODE_MASK 0x1F
void switch_mode(int mode) {
register unsigned long tmp = 0;
mode &= ~MODE_MASK;
asm volatile(
"mrs %[tmp], cpsr_all \n"
"bic %[tmp], %[tmp], %[mask] \n"
"orr %[tmp], %[tmp], %[mode] \n"
"msr cpsr_all, %[tmp] \n"
: : [mode] "r" (mode), [mask] "I" (MODE_MASK), [tmp] "r" (tmp)
);
}
该功能仅设置程序状态寄存器中的模式位。您可以在ARM参考手册中找到适用于您的确切体系结构的常量。
以下是我的编译器生成的代码:
00000000 <switch_mode>:
0: e3c0001f bic r0, r0, #31 ; sane-ify the input
4: e3a03000 mov r3, #0 ; useless instruction generated by gcc
8: e10f3000 mrs r3, CPSR ; saves the current psr
c: e3c3301f bic r3, r3, #31 ; clear mode bits
10: e1833000 orr r3, r3, r0 ; set mode bits to the inputted bits
14: e129f003 msr CPSR_fc, r3 ; set current psr to the modified one
18: e12fff1e bx lr