从 FIQ 处理程序调用 Linux C 代码时出现问题

发布于 2024-09-03 14:17:09 字数 4414 浏览 9 评论 0原文

我正在开发一个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

I'm working on an armv6 core and have an FIQ hander that works great when I do all of my work in it. However I need to branch to some additional code that's too large for the FIQ memory area.

The FIQ handler gets copied from fiq_start to fiq_end to 0xFFFF001C when registered

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 gets set to the following function:

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);

I know that since the FIQ handler operates outside of any normal kernel API's and that it is a rather high priority interrupt I must ensure that whatever I call is already swapped into memory. I do this by having the fiq_flip_pins function defined in the monolithic kernel and not as a module which gets vmalloc.

If I don't branch to the fiq_flip_pins function, and instead do the work in the test_fiq_handler function everything works as expected. It's the branching that's causing me problems at the moment. Right after branching I get a kernel panic about a paging request. I don't understand why I'm getting the paging request.

fiq_flip_pins is in the kernel at:
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)

Since there are no API calls in my code I have to assume that something is going wrong in the C call and back. Any help solving this is appreciated.

Here's the assembly with comments for 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

定格我的天空 2024-09-10 14:17:09

除非我误解了什么,否则看起来 fiq_handler 指向地址 0,而不是 fiq_flip_pins

asm("fiq_handler:   .long 0");

另一个可能的问题(假设有修复的代码)当 fiq_test 被复制时,将 fiq_handler 指针向上)是你在 fiq_flip_pins 的末尾有这个:

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

你需要一些代码跳过该数据或在该数据字之前有您自己的 fiq_flip_pins 返回序列,否则 CPU 将尝试执行任何操作码 0xFC2A4000,我想这不太可能是良性的。

Unless I'm misunderstanding something, it looks like fiq_handler points to address 0, not fiq_flip_pins:

asm("fiq_handler:   .long 0");

Another possible problem (assuming that there's code that fixes up the fiq_handler pointer when fiq_test is copied over) is that you have this at the end of fiq_flip_pins:

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

You'll need to have some code that jumps over that data or have your own return sequence for fiq_flip_pins prior to that data word, otherwise the CPU will try to execute whatever opcode 0xFC2A4000 is, and I imagine it's not likely to be something benign.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文