2010-06-02 12 views
2

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 
+0

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. –

Répondre

3

À moins que je suis malentendu quelque chose, il ressemble à fiq_handler Les points à 0, non fiq_flip_pins:

asm("fiq_handler: .long 0"); 

Un autre problème possible (en supposant qu'il y ait du code qui corrige le pointeur fiq_handler quand fiq_test est copié) est que vous avez ceci à la fin de fiq_flip_pins:

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

Vous aurez besoin d'avoir un code qui saute sur ces données ou avoir votre propre séquence de retour pour fiq_flip_pins avant ce mot de données, sinon la CPU essaiera d'exécuter tout opcode 0xFC2A4000 est, et j'imagine que c'est pas susceptible d'être quelque chose de bénin.

+0

Le fiq_handler est défini sur fiq_flip_pins lorsque je configure le FIQ. Je viens d'ajouter l'assemblage pour fiq_flip_pins à mon post principal, il y avait trop de caractères à mettre ici. –

+0

Michael, j'ai mal compris ce que tu disais. J'ai ajouté un appel "bx lr" avant la valeur IOMUX_ADDR12_k et ça marche. Quelque chose de si simple ... Merci beaucoup! –