Interrupt Teil 2 (PI4)
Im vorhergehenden Kapitel haben wir einen Interrupt für den Timer erstellt. Dies ist zur Zeit auch der einzige, der in unserem System, welches wir entwickeln, zur Verfügung haben. Im nächsten Kapitel wird es dann aufwendig. Wir werden uns um den USB-Eingang kümmern und zunächst einen Treiber für die Tatstatur und anschließend noch auf Mausbewegungen reagieren.
Dazu werden wir dann auch Interrupts benötigen, die ausgelöst werden, wenn jemand auf die Tastatur verwendet, oder dann später auch die Maus bedient.
Damit wir dann grundsätzlich Interrupts programmieren können, werden wir unseren Code etwas erweitern und alle Arten von Interrupts erlauben. Leider werden wir hier nicht viel sehen, aber es ist essentiell, um später unser System zu erweitern.
Vektortabelle
.align 11
.globl VectorTable
VectorTable:
// Vektoren für EL1t (Current Exception Level SP_el0)
.align 7
b sync_exception // Synchronous Exception
.align 7
b irq_handler // IRQ - Normal Interrupt
.align 7
b fiq_handler // FIQ - Fast Interrupt
.align 7
b serror_handler // SError - System Error
// Vektoren für EL1h (Current Exception Level SP_el1)
.align 7
b sync_exception // Synchronous Exception
.align 7
b irq_handler // IRQ - Normal Interrupt
.align 7
b fiq_handler // FIQ - Fast Interrupt
.align 7
b serror_handler // SError - System Error
// Vektoren für EL0 64-bit Modus
.align 7
b hvc_handler // Synchronous EL0 (64-bit), Hypervisor Call
.align 7
b not_used // IRQ EL0 (64-bit)
.align 7
b not_used // FIQ EL0 (64-bit)
.align 7
b not_used // Error EL0 (64-bit)
// Vektoren für EL0 32-bit Modus
.align 7
b not_used // Synchronous EL0 (32-bit)
.align 7
b not_used // IRQ EL0 (32-bit)
.align 7
b not_used // FIQ EL0 (32-bit)
.align 7
b not_used // Error EL0 (32-bit)
Bisher haben wir "nur" den normalen Interrupt unterstützt. Mit diesem Beispiel werden wir auch das "fast Interrupt" programmieren. Genaus gehen wir auch auf Fehler (sync_exception und serror_handler) ein, wenn etwas nicht so läuft wie wir es wollen.
Einige Vectoren verwenden wir nicht. Hier springen wir zu "not_used".
Exceptions
Fangen wir zunächst mit den Exceptions (Abweichungen) an. Da das System hier auf einen Fehler läuft, werden wir in diesem auf eine Sicherung der Register verzichten und direkt in die Fehlerbehandlung gehen:
sync_exception:
mov x0,#0 //Fehlercode
b ExceptionHandler
serror_handler:
mov x0,#1 //Fehlercode
b ExceptionHandler
not_used:
mov x0,#2 //Fehlercode
b ExceptionHandler
Wir übergeben jeweils in x0 (Erster Parameter für die C-Funktion) einen Fehlercode, den wir verwenden können, um uns dann in C entsprechend zu reagieren. Dazu schreiben wir ein kleine C-Programm:
void ExceptionHandler (int code)
{
const char *Exmsg;
switch (code)
{
case 0:
Exmsg = "sync_exception";
break;
case 1:
Exmsg = "serror_handler";
break;
case 2:
Exmsg = "not used";
break;
default:
Exmsg = "Unbekannter Code\n";
break;
}
printf ("Error: Exception '%s' ausgelöst\n", Exmsg);
Stop();
}