Assembling Pi

B.1 Einführung

1.9.6 Interrupts: Aufbau und Funktion der Vector Table

Die Vector Table in der ARMv7-A Architektur beginnt bei der Speicheradresse 0 und ordnet verschiedene Speicheradressen den unterschiedlichen Exception-Typen zu:

Jede dieser Adressen ist einem spezifischen Exception-Typ zugeordnet und verweist auf die entsprechenden Routinen zur Verarbeitung der Exceptions. Die Einträge in der Tabelle enthalten Verzweigungen zu den jeweiligen Interrupthandlern. Da die Exception Vector Table jedoch nur eine begrenzte Anzahl von Einträgen umfasst, verweist jeder Eintrag auf eine generische Interrupt-Handler-Routine für den entsprechenden Interrupt-Typ. Diese generische Routine muss dann feststellen, welcher spezifische Interrupt tatsächlich aufgetreten ist. Das bedeutet, dass die Vektortabelle selbst lediglich anzeigt, dass ein Interrupt einer bestimmten Art eingetreten ist, jedoch nicht, welcher spezifische Interrupt es genau war.

Beispiel für die Implementierung der Interrupt-Vektor Tabelle:

Es muss eine weitere Quelldatei namens vector.s erstellt werden, und die entsprechenden Kommandos zum Assemblieren und Linken müssen anschließend in die build.sh-Datei eingefügt werden.

Die Vektor-Tabelle definiert die Adressen der Handler für verschiedene Ausnahmen. Jeder Eintrag lädt die Adresse des entsprechenden Handlers in das Programmzähler-Register (pc), was einen Sprung zur Handler-Funktion bewirkt:

.section .text
vector:
    ldr pc, reset_handler
    ldr pc, undefined_handler
    ldr pc, swi_handler
    ldr pc, prefetch_handler
    ldr pc, data_handler
    ldr pc, unused_handler
    ldr pc, irq_handler
    ldr pc, fiq_handler

Jeder Handler wird als ein Wort definiert, das auf die entsprechende Funktion zeigt:

        
reset_handler:      .word reset
undefined_handler:  .word hang
swi_handler:        .word hang
prefetch_handler:   .word hang
data_handler:       .word hang
unused_handler:     .word hang
irq_handler:        .word irq
fiq_handler:        .word hang

Die reset-Funktion ist der Einstiegspunkt nach einem System-Reset:

reset:
    b   start

Reset führt einen unbedingten Sprung (b) zur start-Funktion aus, die den eigentlichen Initialisierungsprozess übernimmt.

Die irq-Funktion behandelt IRQ-Interrupts, in unserem Fall werden wir nur einen Timerinterrupt implementieren:

@ Timerinterrupt
irq:
    cpsid i                        @ interrupts ausmaskieren
    push {r0-r3, r12, lr}          @ speichere Prozessorstatus
    bl irq_handler_ext             @ springe zu Extended Interrupt Handler
    pop {r0-r3, r12, lr}           @ prozessorstatus wiederherstellen
    sub pc, lr, #4                 @ returnadresse anpassen
  1. cpsid i: Deaktiviert weitere Interrupts, um die kritische Sektion vor gleichzeitigen Unterbrechungen zu schützen.
  2. push {r0-r3, r12, lr}: Sichert die Register r0 bis r3, r12 und das Link-Register (lr) auf dem Stack, um den aktuellen Zustand zu bewahren.
  3. bl irq_handler_ext: Ruft die erweiterte Interrupt-Handler-Funktion irq_handler_ext auf, welche die spezifische Interrupt-Verarbeitung (des Timer-Interrupts) übernimmt.
  4. pop {r0-r3, r12, lr}: Stellt die zuvor gesicherten Register wieder her.
  5. sub pc, lr, #4: Korrigiert die Rücksprungadresse, um zur aufrufenden Funktion zurückzukehren.

Die hang-Funktion wird für nicht implementierte oder unerwartete Ausnahmen verwendet. Sie sorgt dafür, dass das System in einer Endlosschleife verbleibt:

@ Dauerschleife bei nicht implementierten Interrupts
hang:
    wfi
    b hang
zurück Hauptmenü weiter
1.9 Interrupts
1.9.1 Was sind Interrupts?
1.9.2 Die Interruptvektortabelle
1.9.3 Die Interrupt Service Routine/ der Interrupt-Handler
1.9.4 Der Interruptcontroller
1.9.5 Interrupts im Raspberry Pi 2B
1.9.6 Aufbau und Funktion der Vector Table
1.9.7 Privilegierungslevel und ihre Rolle bei Interrupts
1.9.8 Implementierung eines IRQ-Handlers