Как я могу перевести процессор ARM в разные режимы с помощью программы на C?
Я иду через другой режим процессора ARM. Я хочу проверить состояние процессора (например, значения регистра), пока он находится в другом режиме.
Так может ли кто-нибудь помочь мне узнать пример кода, чтобы перевести процессор в другой режим?
Например, я нашел код для неопределенного режима:asm volatile (".short 0xffff\n");
2 ответа
Если вы хотите протестировать режимы из пользовательского пространства, это сложный вопрос. Возможно, нет никакого способа перейти в режим FIQ, если в системе нет периферийного устройства FIQ. Ваша система может вообще не использовать режим монитора и т. Д. Чтобы перейти в режим отмены, вы можете использовать недопустимый указатель или использовать mmap
, Однако, чтобы ответить на все переключатели режима из пространства пользователя, было бы похоже на книгу (или невозможно) без помощи ядра. Создание тестового модуля с файлом /proc или /sys и использование описанных ниже методов для реализации кода ядра было бы самым простым методом.
Вы должны знать, что не все переходы переключения режимов разрешены. Например, вы никогда не можете переключаться из пользовательского режима в любой другой режим, кроме как через механизмы исключений. Другая проблема заключается в том, что в каждом режиме ARM есть регистры. Одним из них является очень важным sp
(или указатель стека) и lr
(или регистр ссылок), который является фундаментальным для кода "C".
Как правило, более безопасно использовать макрос встроенного ассемблера для ограничения ваших тестовых фрагментов, чем использовать вызовы функций. Тестовый код не должен вызывать внешние подпрограммы. Это может быть сложно, так как использование плавающей запятой и т. Д. Может привести к тому, что компилятор вставит скрытые вызовы подпрограммы. Вы должны проверить сгенерированный ассемблер и предоставить комментарии для других.
/* 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))
Тангр имеет правильный режим определяет,
#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, и без изменения исходного кода ее будет очень трудно достичь и она будет зависеть от конкретной системы, если таковая имеется.
Для этого вам понадобится встроенная сборка, так как 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