El procesador ingresa en "modo indefinido" cuando encuentra una instrucción no válida.
No todos los posibles patrones de bits son instrucciones válidas, y contrariamente a procesadores antiguos donde ocurre al menos algo , el procesador detecta estos patrones y luego genera una excepción.
El controlador para esta excepción se ejecuta normalmente, pero el modo del procesador se cambia para que los registros R13_und
y R14_und
se asignen a R13
y R14
. Esto es necesario porque el controlador requiere una pila local e información sobre la dirección que falla.
La pila para el controlador debe estar separada porque no se garantiza que el código que se ejecuta actualmente tenga una pila válida. El simple hecho de usar cualquier elemento que contenga R13
en este punto sería un problema de seguridad, ya que el controlador se ejecuta con privilegio de supervisor. Por lo tanto, el sistema operativo al inicio reserva espacio de pila para el controlador no definido y coloca la dirección superior de pila en R13_und
(cambiando brevemente al modo UND):
mrs r0, cpsr
bic r1, r0, #0x1f
orr r1, r1, #MODE_UND
msr cpsr_c, r1
ldr r13, =_und_stack_top
msr cpsr_c, r0
El registro R14
también está sombreado, porque se sobrescribe en la entrada de excepción, pero el manejador puede decidir emular la instrucción ofensiva y regresar al flujo regular del programa, lo que requeriría restaurar R14
(para lo cual una pila Se requiere, lo que de nuevo no está garantizado).
Por ejemplo,
bl do_something
...
do_something:
vstm r13!, {s3}
...
vldm r13!, {s3}
La función do_something
almacena s3
en la pila, porque la modifica y desea restaurarla al final, pero no guarda r14
, porque no llama a ninguna subrutina. Si la CPU no tiene una FPU, se llama al controlador no definido para la instrucción vstm
.
Vector de excepción real:
undefined:
b undefined_handler
Controlador:
undefined_handler:
stm r13!, {r0-r4,r14} // this goes on the UND handler stack
ldr r0, -8[r14] // look at the offending instruction
... // emulate instruction
ldm r13!, {r0-r4,r14} // restore everything from stack
subs r15, r14, #8 // return from exception
El valor r14
para do_something
se ocultó en el registro r14_USR
, al que no se puede acceder desde el modo no definido. Si el controlador estuviera interesado en eso, cambiaría al modo Sistema (que es un modo privilegiado). con acceso a los registros de USR), copie el valor a otro registro y vuelva al modo UND para obtener acceso a su propia pila de nuevo.