Local Advanced Programmable Interrupt Controller — Änderungen 4113 → 4381

Zeile 151: Zeile 151:
  
 
== Timer ==
 
== Timer ==
−
Der locale APIC besitzt einen sehr genauen Timer, welcher eigentlich allen anderen Timern wie dem [[PIT]] oder der Real-time Clock vorgezogen werden sollte. Wenn das System mit mehreren Prozessoren (siehe auch [[SMP]]) oder mit dem [[I/O APIC]] (Symmetric Mode) läuft, dann ist er eigentlich die einzige Wahl, denn der PIT ist meistens nur mit dem PIC verbunden und damit nur an den BSP angeschlossen. Er kann somit nicht effizient für SMP verwendet werden.
+
Der locale APIC besitzt einen sehr genauen Timer, welcher eigentlich allen anderen Timern wie dem [[PIT]] oder der Real-time Clock vorgezogen werden sollte. Wenn das System mit mehreren Prozessoren (siehe auch [[SMP]]) oder mit dem [[I/O APIC]] (Symmetric Mode) läuft, dann ist er eigentlich die einzige Wahl, denn der PIT ist meistens nur mit dem PIC verbunden und damit nur an den [[Symmetrisches Multiprozessorsystem#Unterteilung der Prozessoren|BSP]] angeschlossen. Er kann somit nicht effizient für SMP verwendet werden.
  
 
=== Register ===
 
=== Register ===
Zeile 189: Zeile 189:
 
==== Codebeispiel: ====
 
==== Codebeispiel: ====
 
Dieser Code gehört in den anderen Init-Code für den APIC / Symmetric Mode. Er stellt den PIT auf den gewünschten Wert für den APIC Timer ein (hier 10ms), lässt die ISR des PITs den nötigen Wert für den Initial Count Value des APIC Timers berechnen und stellt diesen dann zugleich ein. Er setzt voraus, dass in der Variable [apicregs] die Adresse der APIC Register gespeichert ist.
 
Dieser Code gehört in den anderen Init-Code für den APIC / Symmetric Mode. Er stellt den PIT auf den gewünschten Wert für den APIC Timer ein (hier 10ms), lässt die ISR des PITs den nötigen Wert für den Initial Count Value des APIC Timers berechnen und stellt diesen dann zugleich ein. Er setzt voraus, dass in der Variable [apicregs] die Adresse der APIC Register gespeichert ist.
−
<asm> xor ebp,ebp ;EBP nullen, damit nachher in PIT-ISR erkenbar, wie oft der Timer-Interrupt aufgerufen wurde
+
<asm>   xor ebp,ebp           ;EBP nullen, damit nachher in PIT-ISR erkenbar, wie oft der Timer-Interrupt aufgerufen wurde
  
−
mov al,00110110b ;den PIT auf den gewünschten Wert (hier 10ms) einstellen
+
    mov al,00110110b       ;den PIT auf den gewünschten Wert (hier 10ms) einstellen
−
out 43h,al
+
    out 43h,al
−
+
   
−
mov ax,11931
+
    mov ax,11931
−
out 40h,al
+
    out 40h,al
−
mov al,ah
+
    mov al,ah
−
out 40h,al
+
    out 40h,al
  
−
sti ;IRQs freigeben
+
    sti               ;IRQs freigeben
−
timerschleife: ;Solange Warten, bis das Einschalten und Messen des APIC Timers sicher fertig ist  
+
timerschleife:               ;Solange Warten, bis das Einschalten und Messen des APIC Timers sicher fertig ist  
−
cmp ebp,0x3 ;Die Zählvariable hat dann den Wert 3
+
    cmp ebp,0x3           ;Die Zählvariable hat dann den Wert 3
−
jne timerschleife
+
    jne timerschleife
−
cli
+
    cli
  
−
mov eax,[apicregs] ;Den zuvor ermittelten Platz der APIC Register laden
+
    mov eax,[apicregs]       ;Den zuvor ermittelten Platz der APIC Register laden                          
−
mov ecx,DWORD[apiczähler] ;Den Gemessenen Wert für den Initial Count des APIC Timers nach ECX laden
+
    mov ecx,DWORD[apiczähler]   ;Den Gemessenen Wert für den Initial Count des APIC Timers nach ECX laden
  
−
mov ebp,[eax+0x3e0] ;Alle Register des APIC Timers neu schreiben, um den neuen Initial Count einzustellen
+
    mov ebp,[eax+0x3e0]       ;Alle Register des APIC Timers neu schreiben, um den neuen Initial Count einzustellen
−
mov DWORD[eax+0x3e0],0xb
+
    mov DWORD[eax+0x3e0],0xb
  
−
mov ebp,[eax+0x320] ;Zuerst irgendein Register lesen, wegen Bug in manchem APICS
+
    mov ebp,[eax+0x320]       ;Zuerst irgendein Register lesen, wegen Bug in manchem APICS
−
mov DWORD[eax+0x320],0x20031
+
    mov DWORD[eax+0x320],0x20031
  
−
mov ebp,[eax+0x380] ;Nach Lesen eines Wertes, den neuen Wert des Zählers aus ECX ins Initial Count Register schreiben
+
    mov ebp,[eax+0x380]       ;Nach Lesen eines Wertes, den neuen Wert des Zählers aus ECX ins Initial Count Register schreiben
−
mov [eax+0x380],ecx</asm>
+
    mov [eax+0x380],ecx</asm>
  
  
 
Dieser Code muss als ISR des PITs eingetragen sein. Er kümmert sich zuerst um das Starten des APIC Timers und in einem zweiten Durchgang das Ablesen des heruntergezählten Wertes im Current Count Register. Er setzt voraus, dass in der Variable [apicregs] die Adresse der APIC Register gespeichert ist.
 
Dieser Code muss als ISR des PITs eingetragen sein. Er kümmert sich zuerst um das Starten des APIC Timers und in einem zweiten Durchgang das Ablesen des heruntergezählten Wertes im Current Count Register. Er setzt voraus, dass in der Variable [apicregs] die Adresse der APIC Register gespeichert ist.
 
<asm>APICkalibrieren:
 
<asm>APICkalibrieren:
−
inc ebp ;Variable um zwischen Einschalten und Messen (des Current Count) des APIC Timers zu unterscheiden  
+
    inc ebp               ;Variable um zwischen Einschalten und Messen (des Current Count) des APIC Timers zu unterscheiden  
−
mov eax,[apicregs] ;Den zuvor ermittelten Platz der APIC Register laden
+
    mov eax,[apicregs]       ;Den zuvor ermittelten Platz der APIC Register laden  
  
−
cmp ebp,0x1
+
    cmp ebp,0x1
−
jne ApicSchonGestartet
+
    jne ApicSchonGestartet
  
  
−
mov edx,[eax+0x3e0] ;Zuerst irgendein Wert auslesen, dannach Divide Configuration Register auf Divide Value = 1 setzen
+
    mov edx,[eax+0x3e0]       ;Zuerst irgendein Wert auslesen, dannach Divide Configuration Register auf Divide Value = 1 setzen
−
mov DWORD[eax+0x3e0],0xb
+
    mov DWORD[eax+0x3e0],0xb
  
−
mov edx,[eax+0x320] ;Zuerst Wert auslesen, dannach LVT-Timer Register setzen (peridischer Timer auf Vektor 31)
+
    mov edx,[eax+0x320]       ;Zuerst Wert auslesen, dannach LVT-Timer Register setzen (peridischer Timer auf Vektor 31)
−
mov DWORD[eax+0x320],0x20031
+
    mov DWORD[eax+0x320],0x20031
  
−
mov edx,[eax+0x380] ;Initial Count Register auf das Maximum setzen --> möglichst viel Werte zum Kalibrieren möglich
+
    mov edx,[eax+0x380]       ;Initial Count Register auf das Maximum setzen --> möglichst viel Werte zum Kalibrieren möglich
−
mov DWORD[eax+0x380],0xFFFFFFFF
+
    mov DWORD[eax+0x380],0xFFFFFFFF
−
+
   
−
jmp schlussKalib
+
    jmp schlussKalib
  
  
 
ApicSchonGestartet:
 
ApicSchonGestartet:
−
cmp ebp,0x3 ;Wenn der Timer schon zum 3. Mal ausgelöst, muss nichts mehr getan werden
+
    cmp ebp,0x3           ;Wenn der Timer schon zum 3. Mal ausgelöst, muss nichts mehr getan werden
−
je schlussKalib
+
    je schlussKalib
  
−
;Wenn Timer schon gestartet wurde, dann wird jetzt das Current Count Register gemessen
+
                    ;Wenn Timer schon gestartet wurde, dann wird jetzt das Current Count Register gemessen
−
mov ecx,0xFFFFFFFF ;Unterschied des Current Count in der Zeit des PITs ausrechnen
+
    mov ecx,0xFFFFFFFF       ;Unterschied des Current Count in der Zeit des PITs ausrechnen
−
sub ecx,[eax+0x390]
+
    sub ecx,[eax+0x390]
−
mov DWORD[apiczähler],ecx
+
    mov DWORD[apiczähler],ecx
−
+
   
 
schlussKalib:
 
schlussKalib:
−
mov al,20h ;EOI senden an den PIC, da dieser verwendet wurde zum Kalibrieren
+
    mov al,20h           ;EOI senden an den PIC, da dieser verwendet wurde zum Kalibrieren
−
      out 20h,al
+
          out 20h,al
−
+
   
−
iret</asm>
+
    iret</asm>
  
 
== Weblinks ==
 
== Weblinks ==