Почему моя инструкция по SWI зависает? (BeagleBone Black, процессор ARM Cortex-A8)

Я начинаю писать игрушечную ОС для BeagleBone Black, в которой используется ARM Cortex-A8 на основе TI Sitara AM3359 SoC и загрузчика U-Boot. У меня есть простое автономное приложение hello world, записывающее в UART0, которое я пока могу загрузить через U-Boot, и теперь я пытаюсь перейти к обработчикам прерываний, но я не могу заставить SWI делать что-либо, кроме как повесить устройство.

Согласно AM335x TRM (начиная со страницы 4099, если вам интересно), таблица векторов прерываний отображается в ПЗУ по адресу 0x20000. Обработчик SWI ПЗУ переходит в ОЗУ по адресу 0x4030ce08, который переходит к адресу, хранящемуся в 0x4030ce28. (Изначально это уникальный мертвый цикл по адресу 0x20084.)

Мой код устанавливает SP всех режимов процессора ARM в их собственные области в верхней части ОЗУ и разрешает прерывания в CPSR, а затем выполняет инструкцию SWI, которая всегда зависает. (Возможно, переход к какой-нибудь инструкции по мертвому циклу?) Я просмотрел кучу примеров и прочитал всю документацию, которую смог найти, и не вижу, что мне не хватает.

В настоящее время мое единственное взаимодействие с платой осуществляется через последовательное соединение на UART0 с моим Linux-боксом. U-Boot инициализирует UART0 и позволяет загружать двоичный файл через последовательное соединение.

Вот соответствующая сборка:

.arm
.section ".text.boot"

.equ usr_mode,          0x10
.equ fiq_mode,          0x11
.equ irq_mode,          0x12
.equ svc_mode,          0x13
.equ abt_mode,          0x17
.equ und_mode,          0x1b
.equ sys_mode,          0x1f

.equ swi_vector,        0x4030ce28

.equ rom_swi_b_addr,    0x20008
.equ rom_swi_addr,      0x20028
.equ ram_swi_b_addr,    0x4030CE08
.equ ram_swi_addr,      0x4030CE28

.macro setup_mode mode, stackpointer
    mrs r0, cpsr
    mov r1, r0
    and r1, r1, #0x1f
    bic r0, r0, #0x1f
    orr r0, r0, #\mode
    msr cpsr_csfx, r0
    ldr sp, =\stackpointer
    bic r0, r0, #0x1f
    orr r0, r0, r1
    msr cpsr_csfx, r0
.endm

.macro disable_interrupts
    mrs r0, cpsr
    orr r0, r0, #0x80
    msr cpsr_c, r0
.endm

.macro enable_interrupts
    mrs r0, cpsr
    bic r0, r0, #0x80
    msr cpsr_c, r0
.endm

.global _start
_start:
    // Initial SP
    ldr r3, =_C_STACK_TOP
    mov sp, r3

    // Set up all the modes' stacks
    setup_mode fiq_mode, _FIQ_STACK_TOP
    setup_mode irq_mode, _IRQ_STACK_TOP
    setup_mode svc_mode, _SVC_STACK_TOP
    setup_mode abt_mode, _ABT_STACK_TOP
    setup_mode und_mode, _UND_STACK_TOP
    setup_mode sys_mode, _C_STACK_TOP

    // Clear out BSS
    ldr r0, =_bss_start
    ldr r1, =_bss_end
    mov r5, #0
    mov r6, #0
    mov r7, #0
    mov r8, #0

    b _clear_bss_check$

_clear_bss$:
    stmia r0!, {r5-r8}

_clear_bss_check$:
    cmp r0, r1
    blo _clear_bss$

    // Load our SWI handler's address into
    // the vector table
    ldr r0, =_swi_handler
    ldr r1, =swi_vector
    str r0, [r1]

    // Debug-print out these SWI addresses
    ldr r0, =rom_swi_b_addr
    bl print_mem

    ldr r0, =rom_swi_addr
    bl print_mem

    ldr r0, =ram_swi_b_addr
    bl print_mem

    ldr r0, =ram_swi_addr
    bl print_mem

    enable_interrupts

swi_call$:
    swi #0xCC
    bl kernel_main
    b _reset


.global _swi_handler
_swi_handler:
    // Get the SWI parameter into r0
    ldr r0, [lr, #-4]
    bic r0, r0, #0xff000000

    // Save lr onto the stack
    stmfd sp!, {lr}
    bl print_uint32
    ldmfd sp!, {pc}

Эти отладочные отпечатки дают ожидаемые значения:

00020008: e59ff018
00020028: 4030ce08
4030ce08: e59ff018
4030ce28: 80200164

(Согласно objdump, 0x80200164 действительно _swi_handler. 0xe59ff018 - это инструкция «ldr pc, [pc, # 0x20]».)

Что мне не хватает? Кажется, что это должно сработать.


person justinian    schedule 15.07.2013    source источник
comment
Что должен делать SWI CC? Возможно, это требует определенной настройки регистров или режимов? Просто догадывайтесь, как без отладчика, вам будет трудно увидеть, что именно произошло.   -  person Michael Dorgan    schedule 16.07.2013
comment
Да, к сожалению, у меня нет отладчика JTAG. SWI игнорирует свой аргумент и вызывает программное прерывание, которое переходит в соответствующее место в таблице векторов прерываний. Предположительно, он должен попасть в ветвь таблицы ROM в таблицу RAM, а затем перейти в _swi_handler. Значение 0xCC, которое я передал, предназначено только для целей тестирования - первые две инструкции в _swi_handler должны загрузить инструкцию SWI в r0 и очистить SWI, оставив только аргумент.   -  person justinian    schedule 16.07.2013
comment
Кто знает? Нам нужно увидеть значение на 0x0 платы (или где бы то ни было реальный вектор). В ARM это не векторная таблица, а векторный код. Я не знаю, имеет ли это какое-то отношение. Как 0x0+swi_offset попадает в вашу рутину? Я бы переключил GPIO, чтобы знать, что он приближается к рутине. Процессоры Cortex позволяют отображать таблицу исключений на значения, отличные от 0x0 и 0xffff0000.   -  person artless noise    schedule 16.07.2013
comment
Правильно, как я уже сказал, таблица находится по адресу 0x20008, который, как показывает отладка, является ветвью к [0x20028] или 0x4030ce08. Точно так же 0x4030ce08 - это переход к [0x4030ce28], который содержит адрес моего обработчика 0x80200164. Переключение GPIO - хорошая идея ... это даже проще, чем последовательное сообщение, которое у меня сейчас есть.   -  person justinian    schedule 16.07.2013
comment
Сделайте переключатель GPIO максимально простым. Загружать каждый регистр явно и не использовать стек или какую-либо память. Либо ваш обработчик SWI не получает управления, либо среда не подходит. Иногда полезно констатировать очевидное ;-)   -  person artless noise    schedule 16.07.2013


Ответы (2)


Встроенное ПО на плате изменяет режим выполнения ARM и расположение векторных таблиц, связанных с различными режимами. В моем случае (фрагмент кода с открытым кодом, выполняемый на уровне привилегий 1 и запускаемый программой BBB uBoot) активная таблица векторов находится по адресу 0x9f74b000.

В общем, вы можете использовать что-то вроде следующей функции, чтобы найти активную таблицу векторов:

static inline unsigned int *get_vectors_address(void)
{
    unsigned int v;

    /* read SCTLR */
    __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 0\n"
            : "=r" (v) : : );
    if (v & (1<<13))
        return (unsigned int *) 0xffff0000;
    /* read VBAR */
    __asm__ __volatile__("mrc p15, 0, %0, c12, c0, 0\n"
            : "=r" (v) : : );
    return (unsigned int *) v;
}
person Marco Cesati    schedule 11.05.2014
comment
Ах. С тех пор как я все еще работал с процессором, я предполагал, что векторная таблица все еще будет по адресу в TRM, поэтому я вообще не проверял VBAR. Спасибо! Меня отстранили от этого проекта другие проекты, но я вернусь и попробую сегодня вечером. Спасибо! - person justinian; 12.05.2014

изменение

ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
stmfd sp!, {lr}
bl print_uint32
ldmfd sp!, {pc}

to

stmfd sp!, {r0-r3, r12, lr}
ldr r0, [lr, #-4]
bic r0, r0, #0xff000000
bl print_uint32
ldmfd sp!, {r0-r3, r12, pc}^

PS: вы не восстанавливаете SPSR в CPSR прерванной задачи И вы также очищаете регистры, которые не сохраняются переключателем режима процессора.

person sgupta    schedule 05.08.2013
comment
Спасибо. Это не была моя текущая проблема, но я уверен, что в конечном итоге это была бы проблема. - person justinian; 07.08.2013
comment
Хм, поскольку это процессор Cortex-A8, вы пробовали вмешиваться в регистр VBAR и создавать свою собственную таблицу векторов? См. 3.2.68. c12, безопасный или незащищенный векторный регистр базового адреса в cortex-A8 TRM. Онлайн-версия: infocenter.arm. ru / help / index.jsp? topic = / com.arm.doc.ddi0344k / - person sgupta; 08.08.2013
comment
да, я предположил, что ARM только из-за жестко запрограммированной дельты lr OP, и он нигде не упоминает большой палец. - person sgupta; 11.04.2014