Break-Helfer

HardBreakers Zusammenspiel mit AFD-Pro und anderen Debuggern

Wissen | Know-how

Auch in den Zeiten von Turbo Debug und CodeView, SoftICE und Periscope hält sich bei deutschen Entwicklern immer noch der gute alte AFD (Advanced Fullscreen Debugger), der in Gestalt der neueren AFD-Pro-Version nicht nur mit Symbolen umgehen kann, sondern auch Erweiterungen gegenüber recht aufgeschlossen ist. Dieser Beitrag demonstriert dies am Beispiel des c't-Projektes HardBreaker. Mit einem residenten Tool klappt aber auch das Zusammenspiel mit CodeView, dem alten AFD und anderen.

Aufmacher

War Borlands Turbo-Debugger via Schnittstelle zu einem Treiber schon halbwegs "freundlich" zu Hardware-Debuggern, so gilt das für den AFD-Pro von AdTec, weil in Schönbuch, erst recht. Diesen kann man nämlich so konfigurieren, daß er einen vorher vereinbarten Interrupt aufruft, wenn der Bediener einen ihm unbekannten Befehl eintippt. Als Parameter übergibt er der Interrupt-Routine die gesamte gerade eingegebene Kommandozeile.

Das individuelle Interrupt-Programm kann daraufhin den "unbekannten" Befehl analysieren und entsprechend reagieren. Es ist leicht einzusehen, daß diese Bedienphilosophie wesentlich flexibler ist als alles, was von anderen Debuggern zu diesem Thema angeboten wird (Makros, Treiber ...). Obwohl AFD-Pro schon von Haus aus mit umfangreichen Features dienen kann, kann man auf diesem Weg noch alle erdenklichen Befehle "nachrüsten" - nur läßt sich leider nicht der Disassembler selbst erweitern, etwa auf 386er Code. Für den HardBreaker ist dieser User Interrupt jedoch optimal, läßt er sich somit doch in selbstgestrickter, eingängiger Syntax direkt von der AFD-Pro-Kommandoebene aus steuern. Der Interrupt Handler bekommt den Namen AFD-HB. Er läßt sich auf zweierlei Art einbinden:

  • resident: AFD-HB wird vor dem Starten von AFD-Pro als residentes Programm (TSR) geladen
  • transient: es wird ein Rahmenprogramm aufgerufen, das nicht nur das eigentliche Ansteuerprogramm für den HardBreaker enthält, sondern auch den Aufruf von AFD-Pro selbst (über die DOS-Funktion 4BH = EXEC)

Die zweite Variante hat den Vorteil, daß mit nur einem Programmstart das komplette Paket geladen und gestartet werden kann. Außerdem ermöglicht sie eine ordentliche Terminierung, nämlich das Löschen verbliebener Breakpoints (unbedingt zu empfehlen!), das Restaurieren des verbogenen Interrupts sowie das restlose Entfernen aus dem Speicher. Die residente Alternative hat hingegen den Vorteil, einfacher überschaubar zu sein.

Den für die Kommunikation zwischen AFD-Pro und dieser Routine eingesetzten Interrupt kann man im Prinzip frei wählen. Hier sind aber immer wieder Kollisionen mit anderen Programmen möglich, heutzutage auch des öfteren mit den User-Defined-Plattentypen, die die BIOSse gerne bei 0:300h (Interrupt C0h) ablegen. Wir haben den Interrupt D0H in der Hoffnung gewählt, daß er noch frei ist.

Nach dem Laden des Interrupt Handlers startet man den Software-Debugger mit AFD-Pro /UD0. Über /U bekommt der AFD-Pro den gewünschten Interrupt mitgeteilt. Mit unterlegtem AFD-HB "kennt" der AFD-Pro nun auch die in beistehender Tabelle aufgelisteten Befehle. Groß- oder Kleinschreibung ist egal, Speicher- und Portadressen kann man auch als Bereich eingeben, mit der Einschränkung, die durch die bitmäßige Maskierung gegeben ist. Der HardBreaker vergleicht eben nicht auf größer oder kleiner, sondern kann nur Teile der Adresse maskieren, und legt darüber bestimmte Adreßbereiche fest, etwa die Portadressen 3F0h...3F7h.

Bei allen Eingaben ist zu beachten, daß AFD-HB die Parameter genau so erwartet wie oben angegeben: kein Zeichen mehr, keines weniger! Alle Adreßangaben erwartet er als vierstellige Hexzahlen, also gegebenenfalls mit führenden Nullen. Auf eine umfangreichere Analyse des Befehlseingabestrings haben wir in AFD-HB verzichtet, es hätte das Listing noch mehr aufgebläht (notfalls selbst Hand anlegen!). Zugriff auf Symbole (wie beim Turbo Debug) sind allerdings definitiv nicht möglich.

Was passiert nun im einzelnen, wenn etwa der neue Befehl

  HBR I 0378-037A   

eingetippt wird? Da AFD-Pro diese Sequenz nicht als internen Befehl kennt, ruft es den Interrupt D0H auf. In den Registern DS:SI übergibt es einen Zeiger auf die Eingabezeile und in CX dessen Länge.

Das Ansteuerprogramm AFD-HB findet nun schnell heraus, daß in der Eingabezeile ein korrekter HardBreaker-Befehl steht, der einen Portbereich beschreibt. Alsdann bereitet es die Adressen auf und beschreibt die zuständigen Register des HD-Boards. Schließlich gibt es die Kontrolle wieder an AFD-Pro ab, mit einem Pointer auf einen Meldetext (ES:DX). AFD-Pro ist dann so "freundlich", diesen Text an der richtigen Stelle in seiner Bildschirmmaske auszugeben. Wenn jetzt in dem Testprogramm irgendwo von Port 378h...3FAh gelesen wird, müßte sich AFD-Pro mit seinem Menü melden.

Mit einem "Trick" läßt sich jedoch auch das bewerkstelligen - wenn auch etwas mühselig. Man muß dann aber doch eine eigene INT-2-Service-Routine in den AFD-HB einhängen und den INT 2 dahin verbiegen. Allerdings muß man den AFD dann per Patch daran hindern, den INT 2 wieder mit seinem Handler zu überschreiben, wie er es bei jedem "G" oder "F1/2" zu tun pflegt.

Der eigene oder geänderte INT-2-Handler setzt die Parity-Flipflops zurück und springt dann eine vordefinierte Adresse an (hier 60:0), an der nur ein IRET steht. Wenn man dann einen Software-Breakpoint auf 60:0 setzt, lassen sich hier alle Registerverknüpfungen, Eventzähler oder Trace-Modi des AFD in gewohnter Weise nutzen. Den eigentlichen NMI-auslösenden Code sieht man erst nach Druck auf F1, also nach der Rückkehr per IRET ins Programm. Bei 386- und 486-Systemen darf man sich aber nicht wundern, wenn der Prozessor hier doch noch ein paar Befehle ausgeführt hat, bevor er auf den NMI reagierte.

Mit dem Aufruf "HBR P" installiert AFD-HB seinen eigenen INT-2-Handler und patcht den ADPRO V 1.03 dementsprechend.

Pluspunkte kann der TD bei der Anzeige der NMI-Ursache einsammeln, beim AFD-Pro muß man sich den gesetzten Breakpoint entweder merken oder sich ihn durch HBR ? wieder in Erinnerung rufen. Schließlich kann man beim TD bequem mit Symbolen auch bei den Breakpoints hantieren.

Alles in allem ist der AFD-Pro mit seinen HardBreaker Features die ideale Ergänzung zum Turbo-Debugger, was der eine nicht kann, kann der andere und umgekehrt.

AFD und sein -Pro fangen NMIs und sonstige Exceptions korrekt ab und landen nicht wie der Turbo Debug etwa bei einem unbekannten Opcode (INT 06) einfach im Nirwana. Der AFD-Entwickler hat den NMI als gewollte Debugger-Hilfe gesehen und von vornherein einen Taster als NMI-Quelle vorgesehen (inklusive Software-Entprellung). Für die Praxis heißt das, daß man ein "gebreaktes" Programm ganz einfach mit dem Befehl G wieder starten kann.

Bekanntlich läßt sich mit QUIT R der AFD auch resident laden. Ein danach gestartetes Programm kann man entweder mit Ctrl-Esc (klappt nicht in der DOS-Box von Windows) oder einem NMI unterbrechen. Das funktioniert natürlich auch in Kombination mit dem HardBreaker. Ein kompletter Testlauf könnte also so aussehen:

  • AFD-HB.COM starten und damit resident installieren
  • AFD-Pro starten
  • mit dem Befehl HBR I 0378 einen Hardware-Breakpoint bei Lesezugriffen auf den Port 0378H setzen
  • AFD-Pro mit dem Befehl QUIT R resident installieren und verlassen
  • jetzt kann man das zu untersuchende Programm starten

Vor dem endgültigen Verlassen des Debuggers und auch vor einem Warm- oder Kaltstart (!) sollte ein aktivierter Hardware-Breakpoint unbedingt mit dem Befehl HBR C gelöscht werden (HardBreaker Breakpoints "überleben" selbst den Reset-Taster). Wird das vergessen, so hängt sich der Rechner wahrscheinlich bereits im nächsten Programm oder im POST mit einem "Parity Error" auf (beim oben eingestellten Breakpoint sogar ganz sicher).

Noch ein paar Worte zur "Geschwindigkeit" des HardBreaker. Wer bisher noch keinen rechten Nutzen eines Hardware-Debuggers erkennen konnte, sollte doch mal mit eingeschaltetem Software-Breakpoint (zum Beispiel mit DX=0378) anstatt eines Hardware-Breakpoints arbeiten. Beim kurzen und relativ schnellen Testprogrammen wie dem HBT.EXE vom HardBreaker ist der Unterschied zwar noch nicht gar so gravierend, aber größere Programme können ganz schön "langweilig" werden.

Der hiesige Vorschlag nutzt der Einfachheit halber die gleiche User-Interrupt-Routine auf INT D0h wie der AFD-Pro, die also auch hier zuvor zu installieren ist. Der gewählte Hotkey ist absichtlich etwas kompliziert gewählt (Links-Shift, Rechts-Shift und PrintScreen). Bekanntlich läßt sich der PrintScreen (INT 05h) bequem abfangen und auf AFD-HB umbiegen. Die Syntax ist die gleiche wie bei AFD-Pro (s. Tabelle), nur kann (genauer muß) man sich das "HBR" am Anfang schenken.

Mit C wird ein aktivierter Hardware-Breakpoint gelöscht, was sich immer dann dringend empfiehlt, wenn die Session beendet wird. Der zusätzliche Menüpunkt Z sorgt dafür, daß das NMI-Flipflop nach einem aufgetretenen NMI wieder zurückgesetzt und damit scharfgemacht wird. Das Zurücksetzen muß aber nur bei Debuggern passieren, die das nach dem Auftreten eines NMI nicht bereits automatisch machen (bei CodeView also überflüssig). Ein Testlauf mit CodeView könnte so aussehen:

  • AFD-HB.COM installieren
  • CodeView starten mit CV /W HBT.EXE
  • mit Shift-Links + Shift-Rechts + Druck aktivieren
  • beispielsweise "i 0378" eingeben
  • nach der Meldung "OK, eingestellt" mit CR quittieren
  • Testprogramm HBT.EXE mit G starten

Bereits im ersten Teil dieser Serie war von möglichen (gewollten oder ungewollten) "Behinderungen" des HardBreaker die Rede.

An vier Punkten können einem Hardware-Debugger Steine in den Weg gelegt werden:

NMI-Erzeugung: Ein amoklaufendes Testprogramm könnte die NMI-Erzeugung direkt auf dem HardBreaker ausschalten (über das Register Basisadresse+5). Abhilfe: Die ersten Hardware-Breakpoints auf die HardBreaker-Register selbst setzen. Sie dürfen von keinem Prüfling verändert werden!

NMI-Weiterleitung zum Prozessor: Das Testprogramm könnte über das NMI-Freigaberegister (im XT Port A0H und im AT Port 70H) den NMI blockieren. Der HardBreaker würde dann zwar den gewünschten NMI erzeugen, dieser würde aber nicht bis zum Prozessor durchkommen. Abhilfe: einen Hardware-Breakpoint auf das NMI-Freigaberegister setzen. Es darf nicht verändert werden! Zweite Möglichkeit: direkte Anschaltung des NMI-Eingangs am Prozessor (beschrieben in Teil 1).

Sprung zur NMI-Interruptroutine: Wird der für den NMI zuständige Interruptvektor Nr. 2 auf eine Routine verbogen, die nur das NMI-Flipflop resettet und dann mit einem IRET in das Testprogramm zurückkehrt, hat"s praktisch keinen NMI gegeben! Jedenfalls keinen von außen "sichtbaren". Abhilfe: einen Hardware Breakpoint auf die Speicheradressen 0000:0008-0000:000B setzen. Sie dürfen nicht verändert werden!

Abarbeitung der Interruptroutine: Last, but not least sollte natürlich darauf geachtet werden, daß der untersuchende Debugger nicht von einem renitenten Prüfling zerstört wird. Abhilfe: eine ganz kleine NMI-Serviceroutine, die bei einem auftretenden Hardware-Breakpoint nur den Code der Umgebung (10 Byte davor, 10 Byte danach) ausgibt. Dieser Code kann dann in aller Ruhe im Disassemblerlisting gesucht werden. (as)

[1] AFD-Pro Benutzerhandbuch, AdTec


Zu diesem Artikel existieren Programmbeispiele

0493_228.doc
0493_228.zip

[#anfang Seitenanfang]


Befehl              Bedeutung  HBR R xxxx:yyyy     Memory-Read  HBR W xxxx:yyyy     Memory-Write  HBR A xxxx:yyyy     Memory-Read/Write (Access)  HBR I zzzz          Port-Read  HBR O zzzz          Port-Write  HBR B zzzz          Port-Read/Write (Both)  HBR P               eigenen INT-2-Handler installieren  HBR Z               NMI scharfmachen  HBR C               Hardware-Breakpoint löschen  HBR ?               momentan gesetzten HBP anzeigen   xxxx:yyyy           bezeichnet eine Memory-Adresse  xxxx:yyyy-xxxx:yyyy bezeichnet einen Memory-Adreßbereich  zzzz                bezeichnet eine Port-Adresse  zzzz-zzzz           bezeichnet einen Port-Adreßbereich

[#anfang Seitenanfang]


  1 PAGE 94,132    2 %NOMACS    3 %NOSYMS    4 %TRUNC    5 ;******************************************************************;    6 ;*    Funktion:  HardBreaker - Serviceroutine                     *;    7 ;*    - User-Interrupt  nach der Konvention des AFD-Pro           *;    8 ;*    - wird als TSR-Programm geladen                             *;    9 ;*    - der Aufruf von AFD-Pro : AFDPRO /U<INTERRUPT-NUMMER>      *;   10 ;*    - alternativer Aufruf für AFD und Codeview et al            *;   11 ;*     via Hotkey Left-Shift, Right-Shift, PrintScreen            *;   12 ;*----------------------------------------------------------------*;   13 ;*    Autor          :  WOLFGANG SCHRADER                         *;   14 ;*    Letzte Änderung:  02.02.93/as                               *;   15 ;*----------------------------------------------------------------*;   16 ;*    assemblieren   :  TASM xxx                                  *;   17 ;*                      TLINK /T xxx                              *;   18 ;******************************************************************;   19 ; HB-Modi:    0011         = HardBreaker-Board aktivieren   20 ;             1010         = HardBreaker-Board testen (´Dauer-NMI´)   21 ;             1100         = HardBreaker-Board testen (´Dauer-NMI´)   22 ;             alle anderen = HardBreaker-Board inaktiv   23   24 HB_INT  EQU     0D0H   25 OUT_HB  MACRO   REGISTER,WERT   26         MOV     AL,WERT   27         MOV     DX,WORD PTR [CS:HB_PORT]   28         ADD     DX,REGISTER   29         OUT     DX,AL   30         MOV     BYTE PTR [CS:HB_MIRROR+REGISTER],AL   31         ENDM   32   33 IN_HB   MACRO   34         MOV     DX,WORD PTR [CS:HB_PORT]   35         IN      AL,DX   36         NOT     AL               ;wg. IC20, 74HC540 = invertierend   37         ENDM   38   39 SETINT  MACRO  INTNR, NEWINT, OLDINT   40      IFNB    <OLDINT>              ; Oldint angegeben ?   41         MOV     AL,INTNR           ; dann merken   42         MOV     AH,35H   43         INT     21H   44         MOV     WORD PTR OLDINT,BX   45         MOV     WORD PTR OLDINT+2,ES   46       ENDIF   47         MOV    AL,INTNR   48         MOV    AH,25H   49         MOV    DX, OFFSET NEWINT   50         INT    21H   51       ENDM   52   53 PRINT   MACRO   MESSAGE   54         MOV     DX, OFFSET MESSAGE   55         MOV     AH,9   56         INT     21H   57         ENDM   58 ;-------------------------------------------------------------------   59         JUMPS   60 CODE    SEGMENT PARA   61         ASSUME  CS:CODE   62         ORG     0100H   63   64 START:  JMP     INIT   65   66 ;===================================================================   67 ; Diese Interrupt-Routine wird von AFD-Pro aufgerufen wenn ein   68 ; unbekannter Befehl eingetippt wird, beziehungsweise per Hotkey   69 ;   70 ; beim Aufruf:     DS:SI = Ptr auf Befehlseingabestring (in AFD-Pro)   71 ;                  CX    = dessen Länge   72 ;                  AX    = Interruptnr für diese Routine (unbenutzt)   73 ;                  ES:DI = Pointer auf diese Routine (unbenutzt)   74 ; beim Rücksprung: AL    = Fehlercode (OK = 0)   75 ;                  ES:DX = Pointer auf Fehlertext   76 ;                  SI    = Stelle im Eingabestring, ab der das   77 ;                          Kommando nicht mehr zu identifizieren war   78   79 TSR:    MOV     [CS:CMD_SEG],DS    ; Ptr auf Befehlseingabestring   80         MOV     [CS:CMD_OFF],SI    ; sichern   81         MOV     [CS:CMD_LEN],CX    ; Länge sichern   82         MOV     [CS:CMD_INT],AL    ; Int merken   83         PUSH    CS   84         POP     ES   85         LEA     DI,B_TAB           ; ES:DI = Befehlstabelle   86         MOV     DX,0               ; Zähler für Befehlstabelle   87 SCAN:   MOV     AL,[ES:DI]         ; Pointer auf Befehlstabelle   88         CMP     AL,´$´             ; Befehl zu Ende ?   89         JE      CMD_OK             ; ja !   90         CMP     AL,0               ; Befehlstabelle zu Ende ?   91         JE      S_NOCMD            ; ja !   92         MOV     AH,[DS:SI]         ; Pointer auf Eingabezeile   93         CMP     AH,´Z´             ; Zeichen kleiner als ´Z´ ?   94         JB      SC_1               ; ja !   95         SUB     AH,20H             ; kleine BU ---> große BU   96 SC_1:   CMP     AL,AH              ; beide Zeichen gleich ?   97         JNE     NEXT_BEF           ; nein !   98         INC     DI                 ; nächstes char: Befehlstabelle   99         INC     SI                 ; nächstes char: Eingabezeile  100         JMP     SCAN               ; Loop  101  102 NEXT_BEF:  103         INC     DI                 ; min. 1 Zeichen ist nicht gleich  104         MOV     AL,[ES:DI]         ; nächsten Befehl suchen  105         CMP     AL,´$´             ; Befehl zu Ende ?  106         JNE     NEXT_BEF           ; nein !  107         INC     DI                 ; Ptr f. nächsten Befehl in ES:DI  108         INC     DX                 ; Befehlszähler  109         MOV     SI,[CS:CMD_OFF]    ; Ptr auf Eingabezeile in DS:SI  110         JMP     SCAN               ; Loop  111  112 CMD_OK: SHL     DX,1               ; DX := DX * 2  113         MOV     BX,OFFSET SP_TAB   ; BX = Anfang der Sprungtabelle  114         ADD     BX,DX              ; CS:BX = Ptr auf Befehls-Routine  115         JMP     [CS:BX]            ; Befehls-Routine starten  116  117 CMD_SEG         DW      ?          ; Ptr auf Befehlseingabestring  118 CMD_OFF         DW      ?  119 CMD_LEN         DW      ?  120 CMD_INT         DB      ?  121  122 HEX_SEG         DW      ?          ; Pointer auf Hexzahlenbereich  123 HEX_OFF         DW      ?  124 HEX_LEN         DW      ?  125  126 HB_MIRROR       DB      6 DUP (?)  ; Spiegel der HB-Register 0-5  127 HB_PORT         DW      ?          ; Basis-Port des HardBreakers  128 RECHNER_TYP     DB      ?          ; AT = 1, alles andere = 0  129 BR_TYP          DB      0FFH       ; eingestellter Breakpoint-Typ  130 BR_ZUART        DB      ?          ; gewünschte Zugriffsart  131 VON_ADR_H       DW      ?          ; bei Range: Anfang  132 VON_ADR_L       DW      ?          ;  133 BIS_ADR_H       DW      ?          ; bei Range: Ende  134 BIS_ADR_L       DW      ?          ;  135 ;-------------------------------------------------------------------  136 S_CLEAR:MOV     [BR_TYP],0FFH      ; Befehls-Typ := 0FFH (gelöscht)  137         JMP     RESET_BP  138 ;-------------------------------------------------------------------  139 S_READ: MOV     [BR_TYP],0         ; Befehls-Typ := 0  140         MOV     [BR_ZUART],01000000B; HWBP-Typ: EMEMR = 1  141         JMP     SET_MEM_BP  142 ;-------------------------------------------------------------------  143 S_WRITE:MOV     [BR_TYP],1         ; Befehls-Typ := 1  144         MOV     [BR_ZUART],10000000B; HWBP-Typ: EMEMW = 1  145         JMP     SET_MEM_BP  146 ;-------------------------------------------------------------------  147 S_A:    MOV     [BR_TYP],2         ; Befehls-Typ := 2  148         MOV     [BR_ZUART],11000000B; HWBP-Typ: EMEMR = 1 +   149         JMP     SET_MEM_BP                      EMEMW = 1  150 ;-------------------------------------------------------------------  151 S_INPUT:MOV     [BR_TYP],3         ; Befehls-Typ := 3  152         MOV     [BR_ZUART],00010000B; HWBP-Typ: EIOR = 1  153         JMP     SET_IO_BP  154 ;-------------------------------------------------------------------  155 S_OUTPUT:MOV    [BR_TYP],4         ; Befehls-Typ := 4  156         MOV     [BR_ZUART],00100000B; HWBP-Typ: EIOW = 1  157         JMP     SET_IO_BP  158 ;-------------------------------------------------------------------  159 S_B:    MOV     [BR_TYP],5         ; Befehls-Typ := 5  160         MOV     [BR_ZUART],00110000B; HWBP-Typ: EIOR = 1 und   161         JMP     SET_IO_BP                       EIOW = 1  162 ;-------------------------------------------------------------------  163 ; Zahlen im Eingabestring analysieren und I/O-Breakpoint einstellen  164  165 SET_IO_BP:  166         MOV     AX,[CS:CMD_SEG]  167         MOV     [CS:HEX_SEG],AX    ; Pointer auf Befehl + Hexzahlen  168         MOV     AX,[CS:CMD_OFF]  169         ADD     AX,4  170         MOV     [CS:HEX_OFF],AX    ; im Befehlseingabestring sichern  171         MOV     AX,[CS:CMD_LEN]  172         SUB     AX,4  173         MOV     [CS:HEX_LEN],AX    ; Länge des Hexzahlenbereichs  174  175         CALL    ANAL               ; 1. vierstellige Hexzahl lesen  176         JC      S_ERROR            ; Fehler in den Hexzahlen  177         CMP     BX,0400H  178         JNB     S_ERROR            ; Portangabe zu groß  179         MOV     [VON_ADR_H],0000H  ;  180         MOV     [VON_ADR_L],BX     ; Testwert od. Anfang (bei Range)  181  182         CMP     BYTE PTR [DS:SI],´-´  183         JE      SET_IO1            ; Bereichsangabe ---> set_io1  184         CMP     BYTE PTR [DS:SI],´ ´  185         JE      SET_T              ; nur 1 Hexzahl ---> set_t  186         JMP     S_ERROR  187  188 SET_IO1:INC     SI  189         CALL    ANAL               ; vierstellige Hexzahl lesen  190         JC      S_ERROR            ; Fehler in den Hexzahlen  191         CMP     BX,0400H  192         JNB     S_ERROR            ; Portangabe zu groß  193         MOV     [BIS_ADR_H],0000H  ;  194         MOV     [BIS_ADR_L],BX     ; Ende (nur bei Range)  195         JMP     SET_R              ; 2 Hexzahlen ---> set_r  196 ;-------------------------------------------------------------------  197 ; Zahlen im Eingabestring analysieren und MEM-Breakpoint einstellen  198  199 SET_MEM_BP:  200         MOV     AX,[CS:CMD_SEG]  201         MOV     [CS:HEX_SEG],AX    ; Pointer auf Befehl + Hexzahlen  202         MOV     AX,[CS:CMD_OFF]  203         ADD     AX,4  204         MOV     [CS:HEX_OFF],AX    ; im Befehlseingabestring sichern  205         MOV     AX,[CS:CMD_LEN]  206         SUB     AX,4  207         MOV     [CS:HEX_LEN],AX    ; Länge des Hexzahlenbereichs  208  209         CALL    ANAL           ; 1. vierstellige Hexzahl lesen (Seg)  210         JC      S_ERROR            ; Fehler in den Hexzahlen  211         CMP     BYTE PTR [DS:SI],´:´  212         JNE     S_ERROR            ; Doppelpunkt fehlt  213         MOV     [VON_ADR_H],BX  214  215         INC     SI  216         CALL    ANAL          ; 2. vierstellige Hexzahl lesen (Offs)  217         JC      S_ERROR            ; Fehler in den Hexzahlen  218         MOV     [VON_ADR_L],BX     ; Testwert od. Anfang (bei Range)  219  220         MOV     BX,[VON_ADR_H]     ; SEG und OFFS normalisieren  221         MOV     CL,4  222         ROL     BX,CL              ; oberes Nibble nach hinten  223         MOV     CX,BX  224         AND     CX,000FH  225         MOV     [VON_ADR_H],CX  226         AND     BX,0FFF0H  227         ADD     [VON_ADR_L],BX  228         ADC     [VON_ADR_H],0  229  230         CMP     BYTE PTR [DS:SI],´-´  231         JE      SET_M1             ; Bereichsangabe ---> set_m1  232         CMP     BYTE PTR [DS:SI],´ ´  233         JE      SET_T              ; nur 2 Hexzahlen ---> set_t  234         JMP     S_ERROR  235  236 SET_M1: INC     SI  237         CALL    ANAL          ; 3. vierstellige Hexzahl lesen (Seg)  238         JC      S_ERROR            ; Fehler in den Hexzahlen  239         CMP     BYTE PTR [DS:SI],´:´  240         JNE     S_ERROR            ; Doppelpunkt fehlt  241         MOV     [BIS_ADR_H],BX  242  243         INC     SI  244         CALL    ANAL          ; 4. vierstellige Hexzahl lesen (Offs)  245         JC      S_ERROR            ; Fehler in den Hexzahlen  246         MOV     [BIS_ADR_L],BX     ; Testwert od. Anfang (bei Range)  247         MOV     BX,[BIS_ADR_H]     ; SEG und OFFS normalisieren  248         MOV     CL,4  249         ROL     BX,CL              ; oberes Nibble nach hinten  250         MOV     CX,BX  251         AND     CX,000FH  252         MOV     [BIS_ADR_H],CX  253         AND     BX,0FFF0H  254         ADD     [BIS_ADR_L],BX  255         ADC     [BIS_ADR_H],0  256  257         JMP     SET_R              ; 4 Hexzahlen ---> set_r  258 ;------------------------------------------------------------------  259         ;--- [Von_Adr_H], [Von_Adr_L] = Test- oder Anfangsadresse  260         ;--- [Bis_Adr_H], [Bis_Adr_L] = Endadresse (bei Range)  261  262         ;--- HWBP für Adresse = Testwert angefordert --------------  263 SET_T:  MOV     AX,0000H  264         MOV     BX,0000H           ; keine Wildcards=keine Maske  265         JMP     SET_5  266  267         ;--- HWBP für Adressen-Bereich angefordert ----------------  268 SET_R:  MOV     BX,BIS_ADR_L       ; Höherw. Bereichs-Adresse  (LSW)  269         SUB     BX,VON_ADR_L       ; Niederw. Bereichs-Adresse (LSW)  270         MOV     BX,BIS_ADR_H       ; Höherw. Bereichs-Adresse  (MSW)  271         SBB     BX,VON_ADR_H       ; Niederw. Bereichs-Adresse (MSW)  272         JC      S_ERROR            ; C=1: niederw. Adr > höherw. Adr  273  274         MOV     AX,VON_ADR_L  275         XOR     AX,BIS_ADR_L  276         MOV     BX,VON_ADR_H  277         XOR     BX,BIS_ADR_H       ; unvollständige Maske in BX,AX  278  279         MOV     CX,16              ; Masken auffüllen  280         MOV     DX,1  281 SET_1:  CMP     AX,DX              ; AX - Maske auffüllen  282         JB      SET_2  283         SUB     DX,1  284         OR      AX,DX  285         ADD     DX,1  286 SET_2:  ROL     DX,1  287         LOOP    SET_1  288  289         MOV     CX,16  290         MOV     DX,1  291 SET_3:  CMP     BX,DX              ; BX - Maske auffüllen  292         JB      SET_4  293         SUB     DX,1  294         OR      BX,DX  295         ADD     DX,1  296 SET_4:  ROL     DX,1  297         LOOP    SET_3              ; vollständige Maske in BX:AX  298  299         ;--- Adressenmasken einstellen -----------------------------  300  301 SET_5:  OUT_HB  3,AL               ; ODER-Maske einstellen an  302         OUT_HB  4,AH               ; den ICs 6-10  303         AND     BL,00001111B  304         OUT_HB  5,BL  305  306         MOV     AL,BYTE PTR [VON_ADR_L+0]; XOR-Maske einstellen  307         NOT     AL  308         OUT_HB  0,AL  309  310         MOV     AL,BYTE PTR [VON_ADR_L+1]  311         NOT     AL  312         OUT_HB  1,AL  313  314         MOV     AL,BYTE PTR [VON_ADR_H+0]  315         NOT     AL  316         AND     AL,00001111B  317         OR      AL,[BR_ZUART]      ; Zugriffsart  318         OUT_HB  2,AL  319  320         ;------ HW-Breakpoint einschalten --------------------------  321  322         MOV     AL,BYTE PTR [CS:HB_MIRROR+5]  323         AND     AL,00001111B  324         OR      AL,00110000B  325         OUT_HB  5,AL  326  327         ;------ Buffer für Hexzahlenstring löschen -----------------  328         CLD  329         MOV     AL,´ ´  330         MOV     CX,27  331         MOV     DI,OFFSET MSG_CMD  332         REP     STOSB              ; ´ ´ ---(CX)---> ES:DI  333  334         ;------ Hexzahlenstring umladen (für die Ausgabe in S_LIST)  335         MOV     DS,[CS:HEX_SEG]    ; Pointer auf Befehl + Hexzahlen  336         MOV     SI,[CS:HEX_OFF]    ; im Befehlseingabestring  337         MOV     CX,[CS:HEX_LEN]  338         MOV     DI,OFFSET MSG_CMD  339         REP     MOVSB              ; DS:SI ---(CX)---> ES:DI  340  341         CALL    RES_NMI            ; NMI freigeben  342         JMP     S_LIST  343 ;------------------------------------------------------------------  344 ; HardBreaker ausschalten  345  346 RESET_BP:  347         CALL    LOCK_NMI           ; NMI sperren  348   349         MOV     AL,BYTE PTR [CS:HB_MIRROR+5]  350         AND     AL,00001111B  351         OUT_HB  5,AL  352  353         JMP     S_LIST  354 ;-------------------------------------------------------------------  355 ; aktuellen Hardware-Breakpoint ausgeben  356  357 S_RESETFF:  358         CALL    RES_NMI  359 S_LIST: MOV     AL,[BR_TYP]  360         CMP     AL,0FFH            ; HBR gelöscht ?  361         JE      SL_1               ; ja !  362         MOV     DX,OFFSET MSG_5    ; ES:DX = Pointer auf Text  363         JMP     OK_EXIT  364 SL_1:   MOV     DX,OFFSET MSG_3    ; ES:DX = Pointer auf Text  365         JMP     OK_EXIT  366   367 S_PATCH:PUSH   ES  368         MOV     AX,0  369         MOV     ES,AX  370         MOV     BYTE PTR ES:[600H],0CFH; IRET nach 60h:0  371         LES     DX, ES:[06CH]      ; Adresse von INT 1Bh  372         CMP     DX, 0E21H          ; ist es AFD-Pro V.103?  373         MOV     DX, OFFSET MSG_4A  374         JNZ     OK_PATCH  375         MOV     BYTE PTR ES:[458EH], 075H; Patch:Disable AFDPRO-INT2  376         MOV     DX, OFFSET MSG_4B  377 OK_PATCH:  378         POP     ES  379  380 OK_EXIT:CMP    [CS:CMD_INT],HB_IN T; via AFD aufgerufen ?  381         JNZ     EXIT2  382         PUSH    ES  383         MOV     ES,[CS:CMD_SEG]    ; Ptr auf Befehlseingabestring  384         MOV     DI,[CS:CMD_OFF]  385         MOV     CX,[CS:CMD_LEN]  386         CLD  387         MOV     AL,´ ´             ; alte Eingabezeile löschen  388         REP     STOSB              ; ´ ´ ---(CX)---> ES:DI  389         POP     ES  390 EXIT2:  391         MOV     SI,[CS:CMD_OFF]    ; Cursor =>1. Zeich. in CMD-Zeile  392         MOV     AL,1               ; AFD soll Meldung ausgeben  393         JMP     TSR_EXIT  394 ;------------------------------------------------------------------  395 ; kein HardBreaker - Befehl  396  397 S_NOCMD:MOV     DX,OFFSET MSG_1    ; ES:DX = Pointer auf Text  398         MOV     SI,[CS:CMD_OFF]    ; Pointer auf Eingabezeile holen  399         ADD     SI,[CS:CMD_LEN]    ; Cursor hinter letztes Zeichen  400         MOV     AL,1               ; AFD soll Meldung ausgeben  401         JMP     TSR_EXIT  402 ;------------------------------------------------------------------  403 ; fehlerhafter HardBreaker - Befehl  404  405 S_ERROR:MOV     DX,OFFSET MSG_2    ; ES:DX = Pointer auf Text  406         MOV     AL,1               ; AFD soll Meldung ausgeben  407 TSR_EXIT:  408         IRET                       ; zurück zu AFD-Pro  409 ;==================================================================  410 ; Texte und Tabellen  411  412 B_TAB:  DB      ´HBR R $´  413         DB      ´HBR W $´  414         DB      ´HBR A $´  415         DB      ´HBR I $´  416         DB      ´HBR O $´  417         DB      ´HBR B $´  418         DB      ´HBR C $´  419         DB      ´HBR ? $´  420         DB      ´HBR P $´  421         DB      ´HBR Z $´  422         DB      0  423  424 SP_TAB: DW      OFFSET S_READ      ; Set HBR bei READ  425         DW      OFFSET S_WRITE     ; Set HBR bei WRITE  426         DW      OFFSET S_A         ; Set HBR bei READ/WRITE (access)  427         DW      OFFSET S_INPUT     ; Set HBR bei INPUT  428         DW      OFFSET S_OUTPUT    ; Set HBR bei OUTPUT  429         DW      OFFSET S_B         ; Set HBR bei INPUT/OUTPUT (both)  430         DW      OFFSET S_CLEAR     ; Clear Hardware-Breakpoint  431         DW      OFFSET S_LIST      ; Hardware-Breakpoint anzeigen  432         DW      OFFSET S_PATCH     ; Patch AFDPro V 1.03 !!  433         DW      OFFSET S_RESETFF   ;  434 MSG_1   DB      ´> unbekannter Befehl ...                  ´,0  435 MSG_2   DB      ´> Fehler im HardBreaker-Befehl            ´,0  436 MSG_3   DB      ´> Hardware-BR gelöscht                    ´,0  437 MSG_4A  DB      ´> NMI => 60:0                             ´,0  438 MSG_4B  DB      ´> NMI => 60:0, AFDPRO V1.03 gepatcht      ´,0  439 MSG_5   DB      ´> Hardware-BR: ´  440 MSG_CMD DB      27 DUP (´ ´), 0  441 ;------------------------------------------------------------------  442 ; Hexzahl im Eingabestring analysieren  443 ; beim Aufruf:     DS:SI = Pointer auf String (ab da Analyse)  444 ; beim Rücksprung: BX    = Zahl  445 ;                  wenn OK ---> CF = 0  446  447 ANAL:   MOV     CX,4  448         MOV     BX,0000H  449         MOV     DX,1000H  450 ANAL_1: MOV     AL,[DS:SI]  451         CALL    ASCII2BIN  452         JC      ANAL_2             ; keine HEX-Zahl ---> Error  453         PUSH    DX  454         MUL     DX  455         POP     DX  456         ADD     BX,AX  457         SHR     DX,1               ; ab 286er tut´s auch SHR DX,4  458         SHR     DX,1  459         SHR     DX,1  460         SHR     DX,1  461         INC     SI  462         LOOP    ANAL_1  463         CLC                        ; Clear Carry = ok  464 ANAL_2: RET  465 ;-------------------------------------------------------------------  466 ; ASCII-HexZahl in BIN-Zahl wandeln  467 ; beim Aufruf:      AL = ASCII-Hexzahl  468 ; beim Rücksprung:  AL = BIN-Zahl  469 ;                   wenn OK ---> CF = 0  470   471 ASCII2BIN:  472         CMP     AL,´0´  473         JB      ASCII_E            ; wenn kleiner        ---> Error  474         CMP     AL,´9´  475         JBE     ASCII_1            ; wenn kleiner/gleich    ---> ok  476         SUB     AL,7  477         CMP     AL,3FH             ; = ´0FH´  478         JBE     ASCII_1            ; wenn dann kleiner/gleich -> ok  479         SUB     AL,20H  480         CMP     AL,3FH             ; = ´0FH´  481         JBE     ASCII_1            ; wenn dann kleiner/gleich -> ok  482 ASCII_E:STC                        ; Set Carry = Fehler  483         RET  484 ASCII_1:AND     AX,000FH           ; Ascii ---> Bin  485         CLC                        ; Clear Carry = ok  486         RET  487 ;-------------------------------------------------------------------  488 ; NMI-Flipflop auf dem Motherboard resetten  489   490 RES_NMI:PUSHF  491         PUSH    AX  492   493         CMP     BYTE PTR [CS:RECHNER_TYP],1; AT = 1  494         JE      RES_1  495                                    ; NMI-Freigaberoutine f. XT  496         IN      AL,061H  497         OR      AL,00110000B       ; D4,D5 = 1  498         OUT     061H,AL  499         AND     AL,11001111B       ; D4,D5 = 0  500         OUT     061H,AL  501         MOV     AL,10000000B       ; D7 = 1  502         OUT     0A0H,AL            ; NMI freigeben  503         JMP     RES_3  504  505 RES_1:  IN      AL,061H            ; NMI-Freigaberoutine f. AT  506         OR      AL,00001100B       ; D2,D3 = 0  507         OUT     061H,AL  508         AND     AL,11110011B       ; D2,D3 = 0  509         OUT     061H,AL  510         MOV     AL,1EH             ; D7 = 0 und Dummyport 1Eh  511         IN      AL,61H             ; Warte bis  512         TEST    AL,40H             ; kein NMI mehr da  513         JNZ     RES_1  514         OUT     070H,AL            ; NMI freigeben  515  516 RES_3:  POP     AX  517         POPF  518         RET  519 ;-------------------------------------------------------------------  520 ; NMI auf dem Motherboard sperren  521  522 LOCK_NMI:  523         PUSHF  524         PUSH    AX  525         CMP     BYTE PTR [CS:RECHNER_TYP],1; AT = 1  526         JE      LK_1  527   528         MOV     AL,00000000B  529         OUT     0A0H,AL            ; NMI sperren im XT  530         JMP     LK_2  531   532 LK_1:   MOV     AL,9EH             ; NMI aus und Dummyport 1Eh  533         OUT     070H,AL            ; NMI sperren im AT  534   535 LK_2:   POP     AX  536         POPF  537         RET  538   539 ; INT-2-Handler (Reset NMI-FF, wertet Memory Parity nicht aus)  540 OLDINT2 DD ?  541 INT02:  CALL RES_NMI  542         DB  0EAH,00,00,60H,00 ; hier kann man Breakpoints einhängen  543   544 ;== neue INTERRUPT-SERVICE-ROUTINE für INT 5 (Print Screen) ========  545  546 TEXT_1   DB      ´HardBreaker: HBR ´,0  547 OLDINT5  DD ?  548 ZEILE    DB ´HBR n yyyy-zzzz                                ´  549  550 ;-------------------------------------------------------------------  551  552 ; String in CS:SI ausgeben, Schlußzeichen = #0  553  554 PRINT_MSG:  555         LODSB  556         CMP     AL,0  557         JE      PRINT_EX  558         MOV     AH,14  559         INT     10H  560         JMP     PRINT_MSG  561 PRINT_EX:  562         RET  563   564 JMP_OLD5:  565         PUSHF  566         JMP     DWORD PTR CS:[OLDINT5]; Original-Interrupt  567  568 ISR_05H:PUSH    AX DS  569         MOV     AX,0040H  570         MOV     DS,AX  571         TEST    BYTE PTR DS:[0017H],3H; SHIFT-LEFT + SHIFT-RIGHT ?  572         POP     DS AX  573         JZ      JMP_OLD5  574         JO      JMP_OLD5  575  576 ;------ HardBreaker-Einstellroutine --------------------------------  577  578 EST_1:  PUSH    AX BX CX DX SI DI DS ES  579         STI  580         PUSH    CS  581         POP     DS  582         MOV     SI,OFFSET TEXT_1  583         CALL    PRINT_MSG  584         MOV     DI,OFFSET ZEILE +4  585 GETKEY: MOV     AH,0               ; Warte auf Zeichen  586         INT     16H  587         CMP     AL,0DH             ; CR ?  588         JZ      READY              ; dann ist Eingabe fertig  589         MOV     BYTE PTR [DI],AL   ; Zeichen abspeichern  590         MOV     AH,0EH             ; und anzeigen  591         INT     10H  592         CMP     AL,08H             ; ist Zeichen Delete ?  593         JNZ     NXTCHAR            ; nein, dann nächstes Zeichen  594         CMP     DI,OFFSET ZEILE    ; schon am Anfang der Zeile  595         JZ      GETKEY             ; dann ignorieren  596         DEC     DI                 ; sonst ein Zeichen zurück  597         JMP     GETKEY  598 NXTCHAR:INC     DI  599         JMP     GETKEY  600  601 READY:  MOV     BYTE PTR [DI],´ ´  ; zum Schluß ein Blank  602         MOV     CX,DI              ;  603         MOV     SI, OFFSET ZEILE   ;  604         SUB     CX,SI  605         MOV     AL,5               ; Kennung für INT5-Aufruf  606         INT     HB_INT  607         CMP     AL,1               ; Rückmeldetext da?  608         JNZ     EXIT5              ; exit, falls nicht  609         PUSH    ES  610         POP     DS  611         MOV     SI,DX  612         CALL    PRINT_MSG  613  614 EXIT5:  POP    ES DS DI SI DX CX BX AX  615         IRET  616  617 ;------ Installations-Routine --------------------------------------  618 INIT:   PUSH    CS  619         POP     DS  620         ASSUME  DS:CODE  621         MOV     AL,HB_INT          ; Interrupt-Nr. D0H  622         MOV     AH,35H             ; Vektor holen  623         INT     21H  624         CMP     BX,0               ; Vektor.Offs = 0000 ?  625         JNE     INIT_6  626  627         ;------ OK, AFD-HB installieren ! --------------------------  628         MOV     DX,0200H  629 INIT_0: MOV     CX,4  630 INIT_1: IN      AL,DX  631         NOT     AL                 ; wg. 74HC540  632         SHR     AL,1               ; bei >= 286 auch SHR AL,4  633         SHR     AL,1  634         SHR     AL,1  635         SHR     AL,1  636         AND     AL,00000011B  637         CMP     DL,AL  638         JNZ     INIT_2  639         INC     DX  640         LOOP    INIT_1  641         JMP     INIT_3  642  643 INIT_2: ADD     DX,0080H           ;200H, 280H, 300H, 380H  644         AND     DX,03F0H  645         CMP     DX,0000H  646         JNZ     INIT_0             ;Loop solange Port nicht 400H  647  648         PRINT    MSG1              ;"HardBreaker nicht gefunden"  649         MOV     AX,0000H  650         RET  651                                    ;OK, HardBreaker gefunden  652 INIT_3: AND     DX,03F0H           ;unteres Nibble ist immer 0  653         MOV     HB_PORT,DX         ; Basisadresse merken  654         OUT_HB  5,0                ;Modus 0, HB=inaktiv  655         IN_HB  656         CMP     AL,01000000B  657         JNZ     INIT_5             ;---> Board kaputt, SW1 gedrückt  658  659         ;------ HB-Basis-Portadresse ausgeben ----------------------  660 INIT_3A:  661         MOV     CX,HB_PORT  662         ADD     CH,30H             ; Hi_Byte der Adresse  663         MOV     BYTE PTR [MSG3],CH  664         CMP     CL,0               ; 200h oder 300h  665         JZ      INIT_4  666         MOV     BYTE PTR [MSG3],´8´  667 INIT_4: PRINT   MSG2               ;"... installiert"  668  669         ; Board ok, jetzt Routine  und INTs 5 und 2 installieren  670  671         SETINT HB_INT, TSR         ; Interrupt-Nr. D0H  672         SETINT 05, ISR_05H, OLDINT5; Interrupt-Nr. 05H  673         SETINT 02, INT02, OLDINT2  ; Interrupt-Nr. 02H  674  675         MOV     AX,0F000H          ; BIOS-Segment  676         MOV     ES,AX  677         CMP     BYTE PTR [ES:0FFFEH],0FCH; Rechnertyp-Kennung  678         JNE     INIT_7  679         MOV     AL,01H             ; = AT  680 INIT_7: MOV     BYTE PTR [CS:RECHNER_TYP],AL  681         MOV     DX,OFFSET INIT  682         ADD     DX,15  683         MOV     CL,4  684         SHR     DX,CL  685         MOV     AX,3100H  686         INT     21H                ; AFD-HB resident machen + Ende  687  688 INIT_5: PRINT   MSG7               ;"HardBreaker kaputt"  689         MOV     AX,4C00H  690         INT     21H                ; Programmende  691  692         ;------ AFD-HB war schon installiert ! ---------------------  693  694 INIT_6: PRINT MSG8  695         MOV     AX,4C00H  696         INT     21H                ; Programmende  697 ;-------------------------------------------------------------------  698 NL      EQU     13,10  699 BEEP    EQU     7,7,13,10,´$´  700 MSG1    DB      NL,´HardBreaker-Board ist nicht gesteckt ...´,BEEP  701 MSG2    DB      NL,´AFD-Hardbreaker auf INT D0H installiert !´  702         DB      NL,´HardBreaker-Basisport:´  703 MSG3    DB      ´200H´,NL,´$´  704 MSG7    DB  NL,´HardBreaker defekt oder Break-Taster gedrückt´,BEEP  705 MSG8    DB  NL,´AFD-HB war schon auf INT D0H installiert !´,BEEP  706 ;------------------------------------------------------------------  707         CODE    ENDS  708         END     START  

Kommentare

Anzeige
Anzeige