Linux kernel 从FIQ处理程序调用linux C代码时出现问题
我正在开发一个armv6内核,并且有一个FIQ hander,当我在其中完成所有工作时,它工作得非常好。但是,我需要转移到一些对FIQ内存区域来说太大的附加代码 注册时,FIQ处理程序从FIQ_开始复制到FIQ_结束,复制到0xFFFF001CLinux kernel 从FIQ处理程序调用linux C代码时出现问题,linux-kernel,arm,linux-device-driver,embedded-linux,Linux Kernel,Arm,Linux Device Driver,Embedded Linux,我正在开发一个armv6内核,并且有一个FIQ hander,当我在其中完成所有工作时,它工作得非常好。但是,我需要转移到一些对FIQ内存区域来说太大的附加代码 注册时,FIQ处理程序从FIQ_开始复制到FIQ_结束,复制到0xFFFF001C static void test_fiq_handler(void) { asm volatile("\ .global fiq_start\n\ fiq_start:"); // clear gpio irq
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_引脚位于内核中的以下位置:
c00307ec t fiq_翻转销
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)
无法处理虚拟地址736e6f63处的内核分页请求
pgd=c3dd0000
[736e6f63]*pgd=00000000
内部错误:Oops:5[#1]抢占
模块链接:hello_1
CPU:0未受污染(2.6.31-207-g7286c01-svn4#122)
PC位于strnlen+0x10/0x28
LR位于字符串+0x38/0xcc处
pc:[]lr:[]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
标志:NzCv IRQs关闭FIQs关闭模式SVC_32 ISA ARM段用户
控件:00c5387d表:83dd0008 DAC:00000015
过程sh(pid:1663,堆栈限制=0xc3816268)
堆栈:(0xc3817ea0到0xc3818000)
因为我的代码中没有API调用,所以我不得不假设C调用和返回中出现了问题。任何解决此问题的帮助都将不胜感激
以下是带有fiq_flip_管脚注释的组件:
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
静态无效fiq\U翻转销(无效)
{
asm(“ldr r10,Imoux_ADDR12_k”);
0:e59fa010 ldr sl[pc,#16];18
asm(“ldr r9,[r10]”;
4:e59a9000 ldr r9[sl]
asm(“orr r9,#0x08@顶部/顶点LED”);
8:e3899008或r9,r9,#8;0x8
asm(“str r9,[r10]@打开LED”);
c:e58a9000 str r9[sl]
asm(“bic r9,#0x08@顶部/顶点LED”);
10:e3c99008 bic r9,r9,#8;0x8
asm(“str r9,[r10]@打开LED”);
14:e58a9000 str r9[sl]
00000018 :
18:fc2a4000。字0xfc2a4000
asm(“IOMUX地址:word 0xFC2A4000”);
}
1c:E12FF1E bx lr
除非我误解了什么,否则它看起来像是fiq\u handler
指向地址0
,而不是fiq\u flip\u pins
:
asm("fiq_handler: .long 0");
asm("IOMUX_ADDR12_k: .word 0xFC2A4000");
另一个可能的问题(假设在复制fiq\u测试
时有代码修复fiq\u处理程序
指针)是在fiq\u翻转引脚
的末尾有此问题:
asm("fiq_handler: .long 0");
asm("IOMUX_ADDR12_k: .word 0xFC2A4000");
您需要有一些跳过该数据的代码,或者在该数据字之前有自己的fiq\u flip\u pins
返回序列,否则CPU将尝试执行任何操作码0xFC2A4000,我想这不太可能是良性的。fiq\u处理程序在设置fiq时设置为fiq\u flip\u pins。我刚刚在我的主要帖子中添加了fiq_flip_pins的组件,这里的角色太多了。Michael,我误解了你的意思。我在IOMUX_ADDR12_k值之前添加了一个“bx lr”调用,它正在工作。这么简单的事情…非常感谢!与其他异常类型一样,将一条分支指令发送到实际中断处理程序是完全可以接受的。将FIQ放在末尾以便整个处理程序可以放在那里的特殊安排是为了高频中断处理程序的好处,在高频中断处理程序中,周期数实际上是计数的。