Проблема вызова кода Linux C из обработчика FIQ - PullRequest
2 голосов
/ 03 июня 2010

Я работаю над ядром armv6 и у меня есть инструмент FIQ, который отлично работает, когда я делаю всю свою работу в нем. Однако мне нужно перейти к некоторому дополнительному коду, который слишком велик для области памяти FIQ.

Обработчик FIQ копируется из fiq_start в fiq_end в 0xFFFF001C при регистрации

static void test_fiq_handler(void)
{
    asm volatile("\
    .global fiq_start\n\
    fiq_start:");

    // clear gpio irq
    asm("ldr r10, GPIO_BASE_ISR");
    asm("ldr r9, [r10]");
    asm("orr r9, #0x04");
    asm("str r9, [r10]");

    // clear force register
    asm("ldr r10, AVIC_BASE_INTFRCH");
    asm("ldr r9, [r10]");
    asm("mov r9, #0");
    asm("str r9, [r10]");

    // prepare branch register
    asm("   ldr r11,    fiq_handler");

    // save all registers, build sp and branch to C
    asm("   adr r9, regpool");
    asm("   stmia   r9, {r0 - r8, r14}");
    asm("   adr sp, fiq_sp");
    asm("   ldr sp, [sp]");
    asm("   add lr, pc,#4");
    asm("   mov pc, r11");

#if 0
    asm("ldr r10, IOMUX_ADDR12");
    asm("ldr r9, [r10]");
    asm("orr r9, #0x08                        @ top/vertex LED");
    asm("str r9,[r10]                            @turn on LED");
    asm("bic r9, #0x08                        @ top/vertex LED");
    asm("str r9,[r10]                            @turn on LED");
#endif

    asm("   adr r9, regpool");
    asm("   ldmia   r9, {r0 - r8, r14}");

   // return
    asm("subs pc, r14, #4");

    asm("IOMUX_ADDR12:      .word 0xFC2A4000");
    asm("AVIC_BASE_INTCNTL: .word 0xFC400000");
    asm("AVIC_BASE_INTENNUM:    .word 0xFC400008");
    asm("AVIC_BASE_INTDISNUM:   .word 0xFC40000C");
    asm("AVIC_BASE_FIVECSR: .word 0xFC400044");
    asm("AVIC_BASE_INTFRCH:     .word 0xFC400050");
    asm("GPIO_BASE_ISR:          .word 0xFC2CC018");

    asm(".globl fiq_handler");
    asm("fiq_sp:    .long fiq_stack+120");
    asm("fiq_handler:   .long 0");
    asm("regpool:   .space 40");

    asm(".pool");

    asm(".align 5");
    asm("fiq_stack: .space 124");

    asm(".global fiq_end");
    asm("fiq_end:");
}

fiq_hander получает следующую функцию:

static void fiq_flip_pins(void)
{
    asm("ldr r10, IOMUX_ADDR12_k");
    asm("ldr r9, [r10]");
    asm("orr r9, #0x08                        @ top/vertex LED");
    asm("str r9,[r10]                            @turn on LED");
    asm("bic r9, #0x08                        @ top/vertex LED");
    asm("str r9,[r10]                            @turn on LED");
    asm("IOMUX_ADDR12_k:    .word 0xFC2A4000");
}
EXPORT_SYMBOL(fiq_flip_pins);

Я знаю, что поскольку обработчик FIQ работает за пределами любого обычного API ядра и что это прерывание с довольно высоким приоритетом, я должен убедиться, что все, что я вызываю, уже помещено в память. Я делаю это с помощью функции fiq_flip_pins, определенной в монолитном ядре, а не как модуль, который получает vmalloc.

Если я не перехожу на функцию fiq_flip_pins, а вместо этого выполняю работу в функции test_fiq_handler, все работает должным образом. Это ветвление вызывает у меня проблемы в данный момент. Сразу после ветвления у меня возникает паника ядра по поводу пейджингового запроса. Я не понимаю, почему я получаю пейджинговый запрос.

fiq_flip_pins находится в ядре по адресу: c00307ec t fiq_flip_pins

Unable to handle kernel paging request at virtual address 736e6f63
pgd = c3dd0000
[736e6f63] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT
Modules linked in: hello_1
CPU: 0    Not tainted  (2.6.31-207-g7286c01-svn4 #122)
PC is at strnlen+0x10/0x28
LR is at string+0x38/0xcc
pc : [<c016b004>]    lr : [<c016c754>]    psr: a00001d3
sp : c3817ea0  ip : 736e6f63  fp : 00000400
r10: c03cab5c  r9 : c0339ae0  r8 : 736e6f63
r7 : c03caf5c  r6 : c03cab6b  r5 : ffffffff  r4 : 00000000
r3 : 00000004  r2 : 00000000  r1 : ffffffff  r0 : 736e6f63
Flags: NzCv  IRQs off  FIQs off  Mode SVC_32  ISA ARM  Segment user
Control: 00c5387d  Table: 83dd0008  DAC: 00000015
Process sh (pid: 1663, stack limit = 0xc3816268)
Stack: (0xc3817ea0 to 0xc3818000)

Поскольку в моем коде нет вызовов API, я должен предположить, что что-то идет не так в вызове C и обратно. Любая помощь в решении этой проблемы приветствуется.

Вот сборка с комментариями для fiq_flip_pins:

static void fiq_flip_pins(void)
{
    asm("ldr r10, IOMUX_ADDR12_k");
   0:   e59fa010    ldr sl, [pc, #16]   ; 18 <IOMUX_ADDR12_k>
    asm("ldr r9, [r10]");
   4:   e59a9000    ldr r9, [sl]
    asm("orr r9, #0x08                        @ top/vertex LED");
   8:   e3899008    orr r9, r9, #8  ; 0x8
    asm("str r9,[r10]                            @turn on LED");
   c:   e58a9000    str r9, [sl]
    asm("bic r9, #0x08                        @ top/vertex LED");
  10:   e3c99008    bic r9, r9, #8  ; 0x8
     asm("str r9,[r10]                            @turn on LED");
  14:   e58a9000    str r9, [sl]

00000018 <IOMUX_ADDR12_k>:
  18:   fc2a4000    .word   0xfc2a4000
    asm("IOMUX_ADDR12_k:    .word 0xFC2A4000");
}
  1c:   e12fff1e    bx  lr

1 Ответ

3 голосов
/ 03 июня 2010

Если я что-то не так понимаю, похоже, что fiq_handler указывает на адрес 0, а не fiq_flip_pins:

asm("fiq_handler:   .long 0");

Другая возможная проблема (при условии, что есть код, исправляющий указатель fiq_handler при копировании fiq_test), заключается в том, что у вас это в конце fiq_flip_pins:

asm("IOMUX_ADDR12_k:    .word 0xFC2A4000");

Вам понадобится некоторый код, который перепрыгивает через эти данные, или ваша собственная последовательность возврата для fiq_flip_pins перед этим словом данных, в противном случае ЦП попытается выполнить любой код операции 0xFC2A4000, и я полагаю, что это маловероятно быть чем-то добрым.

...