Linux kernel ARM excepción stack init

Estoy utilizando Linux kernel 3.0.35 en Freescale i.MX6 (ARM Cortex-A9). Después de ejecutar en un kernel OOPS traté de entender la inicialización de la stack de excepción. Esto es lo que he descubierto hasta ahora.

En cpu_init () en arch / arm / kernel / setup.c , veo que la stack de excepciones se inicializa:

struct stack { u32 irq[3]; u32 abt[3]; u32 und[3]; } ____cacheline_aligned; static struct stack stacks[NR_CPUS]; void cpu_init(void) { struct stack *stk = &stacks[cpu]; ... /* * setup stacks for re-entrant exception handlers */ __asm__ ( "msr cpsr_c, %1\n\t" "add r14, %0, %2\n\t" "mov sp, r14\n\t" "msr cpsr_c, %3\n\t" "add r14, %0, %4\n\t" "mov sp, r14\n\t" "msr cpsr_c, %5\n\t" "add r14, %0, %6\n\t" "mov sp, r14\n\t" "msr cpsr_c, %7" : : "r" (stk), PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), "I" (offsetof(struct stack, irq[0])), PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE), "I" (offsetof(struct stack, abt[0])), PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE), "I" (offsetof(struct stack, und[0])), PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE) : "r14"); 

Veo que cada stack tiene espacio para solo tres palabras. Así es como lo usa el macro vector_stub en arch / arm / kernel / entry-armv.S . Guarda R0, LR ( PC principal ) y SPSR ( CPSR padre ) en esas tres palabras. Luego salta a __irq_svc . Eso comienza con un macro svc_entry que crea un marco de stack

  .macro svc_entry, stack_hole=0 UNWIND(.fnstart ) UNWIND(.save {r0 - pc} ) sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4) 

Así es también como veo el código desmontado de KGDB:

 Dump of assembler code for function __irq_svc: 0xc01402c0 : 44 d0 4d e2 sub sp, sp, #68 ; 0x44 0xc01402c4 : 04 00 1d e3 tst sp, #4 0xc01402c8 : 04 d0 4d 02 subeq sp, sp, #4 0xc01402cc : fe 1f 8d e8 stm sp, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12} 0xc01402d0 : 0e 00 90 e8 ldm r0, {r1, r2, r3} 0xc01402d4 : 30 50 8d e2 add r5, sp, #48 ; 0x30 0xc01402d8 : 00 40 e0 e3 mvn r4, #0 0xc01402dc : 44 00 8d e2 add r0, sp, #68 ; 0x44 0xc01402e0 : 04 00 80 02 addeq r0, r0, #4 0xc01402e4 : 04 10 2d e5 push {r1} ; (str r1, [sp, #-4]!) 0xc01402e8 : 0e 10 a0 e1 mov r1, lr 0xc01402ec : 1f 00 85 e8 stm r5, {r0, r1, r2, r3, r4} 0xc01402f0 : ad 96 a0 e1 lsr r9, sp, #13 0xc01402f4 : 89 96 a0 e1 lsl r9, r9, #13 0xc01402f8 : 04 80 99 e5 ldr r8, [r9, #4] 0xc01402fc : 01 70 88 e2 add r7, r8, #1 0xc0140300 : 04 70 89 e5 str r7, [r9, #4] 0xc0140304 : 54 50 9f e5 ldr r5, [pc, #84] ; 0xc0140360 0xc0140308 : 00 50 95 e5 ldr r5, [r5] 0xc014030c : 0c 60 95 e5 ldr r6, [r5, #12] 0xc0140310 : 4c e0 9f e5 ldr lr, [pc, #76] ; 0xc0140364 0xc0140314 : 07 0b c6 e3 bic r0, r6, #7168 ; 0x1c00 0xc0140318 : 1d 00 50 e3 cmp r0, #29 0xc014031c : 00 00 50 31 cmpcc r0, r0 0xc0140320 : 0e 00 50 11 cmpne r0, lr 0xc0140324 : 00 00 50 21 cmpcs r0, r0 0xc0140328 : 0d 10 a0 11 movne r1, sp 0xc014032c : 28 e0 4f 12 subne lr, pc, #40 ; 0x28 0xc0140330 : 32 eb ff 1a bne 0xc013b000  0xc0140334 : 04 80 89 e5 str r8, [r9, #4] 0xc0140338 : 00 00 99 e5 ldr r0, [r9] 0xc014033c : 00 00 38 e3 teq r8, #0 0xc0140340 : 00 00 a0 13 movne r0, #0 0xc0140344 : 02 00 10 e3 tst r0, #2 0xc0140348 : 06 00 00 1b blne 0xc0140368  0xc014034c : 40 40 9d e5 ldr r4, [sp, #64] ; 0x40 0xc0140350 : 04 f0 6f e1 msr SPSR_fsxc, r4 0xc0140354 : 1f f0 7f f5 clrex 0xc0140358 : ff ff dd e8 ldm sp, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, pc}^ End of assembler dump. 

Durante una excepción, SP es el R13 bancarizado. Si estoy siguiendo correctamente, no hay espacio para este marco en esa stack. Eso significa que debo haberme perdido algo. ¿Hay algún otro lugar donde se inicializan las stacks de excepción?

tl; dr – Cambiamos modos a supervisor y usamos esa stack.

Falta el punto clave de donde se entrega el control a la CPU a través de la tabla vectorial y se cambia el modo. Ver: entry-armv.S y __vectors_start . El vector stubs es el código donde el control se envía inicialmente después del b rancho en la tabla principal de vectores. La macro vector_stub guarda tres elementos; un lr , r0 corregido y el spsr del modo exceptuado (como ha notado).

El punto que extrañas es que, después de esto, todas las excepciones cambian a SVC_MODE y, como tal, usan la stack de tareas current , que también tiene la estructura thread_info . la conmutación de modo es un concepto difícil de conseguir en el ensamblador de nivel de sistema ARM. Los registros que se establecieron previamente ahora son completamente diferentes. Preste atención a las instrucciones de tipo msr y cps . Las cosas pueden cambiar completamente después de ellos; Me he sentido confundido por docenas de veces.

El spsr se usa como índice en una tabla vector_stub , que normalmente saltará a __irq_svc o __irq_usr . Simplemente desplácese hacia abajo para mirar la parte inferior del arm de entrada. S que ya encontró.

Relacionado: Dirección física de la tabla de vectores ARM-Linux