Je travaille sur un noyau armv6 et j'ai un FIQ qui fonctionne bien quand je fais tout mon travail. Cependant, j'ai besoin de passer à un code supplémentaire trop grand pour la zone de mémoire FIQ.Problème appelant le code C de Linux à partir du gestionnaire FIQ
Le gestionnaire FIQ est copié de fiq_start à fiq_end à 0xFFFF001C lors de son enregistrement
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 se prépare à la fonction suivante:
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);
Je sais que depuis le gestionnaire FiQ fonctionne en dehors de toute les API normales du noyau et que c'est une interruption de priorité assez élevée, je dois m'assurer que tout ce que j'appelle est déjà passé en mémoire. Je fais cela en ayant la fonction fiq_flip_pins définie dans le noyau monolithique et non comme un module qui obtient vmalloc.
Si je ne branche pas à la fonction fiq_flip_pins et que je fais le travail dans la fonction test_fiq_handler, tout fonctionne comme prévu. C'est la branche qui me cause des problèmes en ce moment. Juste après la dérivation, je reçois une panique du noyau à propos d'une demande de pagination. Je ne comprends pas pourquoi je reçois la demande de pagination.
fiq_flip_pins est dans le noyau à: 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)
Comme il n'y a pas d'appels API dans mon code, je dois supposer que quelque chose va mal dans l'appel C et à l'arrière. Toute aide pour résoudre ce problème est appréciée.
est ici l'assemblée avec des commentaires pour 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
Il est tout à fait acceptable d'avoir une seule instruction de branchement vers le gestionnaire d'interruption réel, comme pour les autres types d'exception. L'arrangement spécial consistant à placer le FIQ à la fin pour que le gestionnaire entier puisse y être placé est au bénéfice des gestionnaires d'interruptions à haute fréquence où le nombre de cycles compte réellement. –