;****************************************************************************** ;* * ;* SECDRIVE - Treiber fr einen 2. HD-Kontroller im PC * ;* * ;* Historie: 12. 8.1993 Grundsteinlegung, Definitionen * ;* 16. 8.1993 Dispatcher * ;* Basislesefunktionen * ;* 17. 8.1993 Partitionsinformationen zusammenkratzen * ;* 18. 8.1993 Laufwerksparameter initialisieren * ;* 19. 8.1993 Zylinder/Sektorregister setzen * ;* Partitiossektorbaum durchgehen * ;* 24. 8.1993 BPB aufbauen * ;* 25. 8.1993 Parameterbersetzung * ;* Einlesen * ;* Sektoren schreiben * ;* 26. 8.1993 Fehlerbehandlung * ;* Verify * ;* 1. Restore-Versuch mit Seek * ;* 7. 9.1993 Versuch Version 1.39 mit Proc's * ;* 28. 9.1993 etwas gekrzt * ;* 27.12.1994 leichte Korrekturen im Restore * ;* 28.12.1994 Trennung Low-Level-Routinen begonnen * ;* 19. 1.1995 Fehlermeldungen im Klartext * ;* * ;****************************************************************************** ;****************************************************************************** ;* globale Definitionen * ;****************************************************************************** ; A C H T U N G : Mono.SYS muá fr Debugging geladen sein !!!! debug equ 0 debug2 equ 0 include bitfuncs.inc cpu 80186 ; WD 1003 fordert min. 80286 Diag_NoError equ 01h ; Selbstdiagnosecodes: kein Fehler Diag_ContError equ 02h ; Controller-Fehler Diag_SBufError equ 03h ; Sektorpuffer defekt Diag_ECCError equ 04h ; Fehlerkorrektor defekt Diag_ProcError equ 05h ; Steuerprozessor defekt Diag_Timeout equ 06h ; Controller antwortet nicht ParTab struct BFlag db ? ; Partitionseintrag: Partition aktiv ? FHead db ? ; Startkopf FSecCyl dw ? ; Startzylinder/sektor Type db ? ; Partitionstyp LHead db ? ; Endkopf LSecCyl dw ? ; Endzylinder/sektor LinSec dd ? ; Anzahl Sektoren NSecs dd ? ; linearer Startsektor endstruct DErr_WrProtect equ 00h ; Treiberfehlercodes: Schreibschutz DErr_InvUnit equ 01h ; unbekannte Ger„tenummer DErr_NotReady equ 02h ; Laufwerk nicht bereit DErr_Unknown equ 03h ; Unbekannes Treiberkommando DErr_CRCError equ 04h ; Prfsummenfehler DErr_InvBlock equ 05h ; ungltiger Request-Header DErr_TrkNotFnd equ 06h ; Spur nicht gefunden DErr_InvMedia equ 07h ; Unbekanntes Tr„gerformat DErr_SecNotFnd equ 08h ; Sektor nicht gefunden DErr_PaperEnd equ 09h ; Papierende im Drucker DErr_WrError equ 0ah ; allg. Schreibfehler DErr_RdError equ 0bh ; allg. Schreibfehler DErr_GenFail equ 0ch ; allg. Fehler DErr_InvChange equ 0fh ; unerlaubter Diskettenwechsel DErr_UserTerm equ 0ffh ; Fehlercode Abbruch durch Benutzer SecSize equ 512 ; Sektorgr”áe in Bytes MaxPDrives equ 2 ; Maximalzahl physikalischer Laufwerke MaxDrives equ 10 ; Maximalzahl verwaltbarer Laufwerke MaxParts equ 4 ; Maximalzahl Partitionen in einem Sektor MaxRetry equ 2 ; max. 2 Lese/Schreibversuche StackSize equ 512 ; etwas mehr wg. Rekursion DrPar_Offset equ 1aeh ; Offset Parametertabelle im Part.-Sektor ParTab_Offset equ 1beh ; Offset Partitionstabelle " " " ParSecID_Offset equ 1feh ; Offset Partitionssektorflag (55aa) BPBOfs equ 11 ; Offset BPB im Bootsektor INT_DOS equ 21h ; DOS-Funktionsaufruf INT_Mono equ 60h ; Haken zum VT100-Treiber INT_Clock equ 1ah ; BIOS-Uhreneinstieg INT_Keyboard equ 16h ; BIOS-Tastatureinstieg DOS_WrString equ 9 ; DOS-Funktionen DOS_WrChar equ 6 DOS_RdString equ 10 DOS_RdChar equ 8 HD_ID equ 0f8h ; Media-ID fr Festplatten CR equ 13 LF equ 10 BEL equ 7 ESC equ 27 ;****************************************************************************** ; Makros * ;****************************************************************************** ;jmp macro adr ; !jmp long adr ; endm beep macro push ax mov ax,0e07h int 10h pop ax endm PrMsg macro Adr ; Meldung ausgeben push dx ; Register retten lea dx,[Adr] mov ah,DOS_WrString int INT_DOS pop dx ; Register zurck endm PrChar macro Zeichen ; Zeichen ausgeben push dx ; Register retten push ax mov dl,Zeichen mov ah,DOS_WrChar int INT_DOS pop ax pop dx ; Register zurck endm ;------------------------------------------------------------------------------ btst macro op,bit ; ein einzelnes Bit testen test op,(1<ausgeben... jmp Adr ; ...Abbruch GoOn: endm ;****************************************************************************** ;* Treiberkopf * ;****************************************************************************** assume cs:code,ds:nothing,ss:nothing,es:nothing org 0 DriverHead: dd -1 ; Zeiger auf Nachfolger dw 0000100000000010b ; Attribut ; ^ ^ ^ ; ³ ³ ÀÄ kann 32-Bit-Setornummern verarbeiten ; ³ ÀÄÄÄÄÄÄÄÄÄÄÄ kennt Close/Open/Removeable ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Blocktreiber dw StrategyProc ; Zeiger auf Strategieroutine dw InterruptProc ; Zeiger auf eigentlichen Treibercode NrOfVols: db 0 ; Zahl log. Laufwerke db "SECDRIV" ; bei Blocktreibern unbenutzt ;****************************************************************************** ;* residente Daten * ;****************************************************************************** Rh_Ptr dd ? ; Speicher fr Request-Header JmpTable dw Init ; Sprungtabelle: Initialisierung dw MediaCheck ; Medium gewechselt ? dw BuildBPB ; Parameterblock laden dw IOCTLRead ; Steuerdaten vom Treiber dw Read ; Daten lesen dw ND_Read ; Lesen, ohne Pufferstatus zu „ndern dw InputStatus ; Daten im Eingabepuffer ? dw InputFlush ; Eingabepuffer l”schen dw Write ; Daten schreiben dw Write_Verify ; Daten mit Prflesen schreiben dw OutputStat ; Ausgabepuffer leer ? dw OutputFlush ; Ausgabepuffer l”schen dw IOCTLWrite ; Steuerdaten zum Treiber dw DeviceOpen ; DOS hat eine Datei darauf ge”ffnet dw DeviceClose ; DOS hat eine Datei darauf geschlossen dw Removeable ; Ist Datentr„ger wechselbar ? dw OutputTillBusy ; Ausgabe, bis Puffer voll dw GenIOCTL ; genormtes IOCTL dw GetLogical ; Laufwerkszuordnung lesen dw SetLogical ; Laufwerkszuordnung setzen dw IOCTLQuery ; Abfrage, ob GenIOCTL untersttzt SectorBuffer: db SecSize dup (?) ; Sektorpuffer fr Treiber selber db StackSize dup (?) ; Treiberstack DriverStack: BPBSize equ 36 DrTab struct ; Laufwerkstabelle: StartHead db ? ; Startkopf StartCyl dw ? ; Startzylinder StartSec db ? ; Startsektor LinStart dd ? ; lin. Startsektor SecCnt dd ? ; Gesamtsektorzahl Drive db ? ; Laufwerk BPB db BPBSize dup (?) ; BPB endstruct DrTab db DrTab_Len*MaxDrives dup (?) DrTab_BPBs dd 2*MaxDrives dup (?) DrCnt db 0 ; Anzahl gefundener Laufwerke DrOfs db 0 ; erster freier Laufwerksbuchstabe DrPar struct ; Plattenparametersatz: Cyls dw ? ; Zylinderzahl Heads db ? ; Kopfzahl RedWr dw ? ; Startzylinder reduzierter Schreibstrom PrComp dw ? ; Startzylinder Pr„kompensation ECCLen db ? ; max. korrigierbarer Fehlerburst (Bits) CByte db ? ; Wert frs Plattensteuerregister TOut db ? ; genereller Timeout FTOut db ? ; Timeout Formatierung CTOut db ? ; Timeout fr Prfung LZone dw ? ; Landezylinder NSecs db ? ; Sektorzahl Dummy db ? ; unbenutzt endstruct DrPars db DrPar_Len*MaxPDrives dup (0) ;****************************************************************************** ;* Strategieroutine * ;****************************************************************************** StrategyProc: mov word ptr [Rh_Ptr],bx ; Zeiger speichern mov word ptr [Rh_Ptr+2],es retf ;****************************************************************************** ;* Treiberdispatcher * ;****************************************************************************** Rh struct Size db ? ; gemeinsame Headerteile: L„nge Block Unit db ? ; angesprochenes Laufwerk Func db ? ; Treibersubfunktion Status dw ? ; Ergebnis Resvd db 8 dup (?) ; unbenutzt endstruct InterruptProc: pusha ; alle Register retten cli ; Stack umschalten mov si,ss ; alten zwischenspeichern mov di,sp mov ax,cs ; neuen setzen mov ss,ax lea sp,[DriverStack] push di ; alten auf neuem (!) speichern push si sti mov ax,cs ; DS auf Treibersegment mov ds,ax assume ds:code les bx,[Rh_Ptr] ; Zeiger laden mov word ptr es:[bx+Rh_Status],0 ; Status l”schen mov al,es:[bx+Rh_Func] ; Subfunktion ausrechnen if debug call PrByte endif mov ah,0 add ax,ax mov si,ax jmp JmpTable[si] jmp Init ;****************************************************************************** ;* gemeinsames Ende * ;****************************************************************************** StateError: btst al,1 ; Bit 1: Spur 0 nicht gefunden jz StateError_N1 mov al,DErr_TrkNotFnd jmp StateError_End StateError_N1: btst al,2 ; Bit 2: abgebrochenes Kommando jz StateError_N2 btst ah,5 ; Bit S5: Schreibfehler jz StateError_N21 mov al,DErr_WrError jmp StateError_End StateError_N21: btst ah,4 ; Bit S4: Positionierung nicht vollst„ndig jnz StateError_N22 mov al,DErr_TrkNotFnd jmp StateError_End StateError_N22: btst ah,6 ; Bit S6: Laufwerk nicht bereit jnz StateError_N23 mov al,DErr_NotReady jmp StateError_End StateError_N23: mov al,DErr_GenFail ; Notnagel 1 jmp StateError_End StateError_N2: test al,11h ; Bit 0/4: Sektor nicht gefunden jz StateError_N3 mov al,DErr_SecNotFnd jmp StateError_End StateError_N3: btst al,6 ; Bit 6: Prfsummenfehler jz StateError_N4 mov al,DErr_CRCError jmp StateError_End StateError_N4: mov al,DErr_GenFail ; Notnagel 2 StateError_End: les bx,[Rh_Ptr] ; Code einspeichern mov es:[bx+Rh_Status],al jmp Error Unknown: les bx,[Rh_Ptr] mov byte ptr es:[bx+Rh_Status],DErr_Unknown ; unbek. Funktion Error: or byte ptr es:[bx+Rh_Status+1],80h ; Fehler-Flag setzen jmp Done Busy: les bx,[Rh_Ptr] or byte ptr es:[bx+Rh_Status+1],2 ; Busy-Flag setzen Done: les bx,[Rh_Ptr] or byte ptr es:[bx+Rh_Status+1],1 ; Done-Flag setzen if debug call NxtLine endif cli ; Stack zurckschalten pop si pop di ; alten in SI:DI laden mov sp,di ; einschreiben mov ss,si sti popa ; Register zurck retf ;****************************************************************************** ;* Debugginghilfe * ;****************************************************************************** if debug||debug2 HexTab db "0123456789ABCDEF" PrByte: push es ; Register retten push di push bx push ax lea bx,[HexTab] db 0d4h,10h ; AAM 16 push ax mov al,ah xlat mov ah,0eh int 10h pop ax xlat mov ah,0eh int 10h pop ax ; Register zurck pop bx pop di pop es ret PrWord: xchg ah,al ; Hi-Byte call PrByte xchg ah,al call PrByte ret PrChar: push ax mov ah,0eh int 10h pop ax ret NxtLine: push ax ; Register retten push bx push dx mov ax,0e0dh int 10h mov ax,0e0ah int 10h pop dx ; Register zurck pop bx pop ax endif ;****************************************************************************** ;* residente Subfunktionen * ;****************************************************************************** ;****************************************************************************** ;* eine logische Laufwerksnummer berprfen * ;* In : AL = Laufwerk * ;* Out : C = 1, falls Fehler * ;****************************************************************************** proc ChkDrive cmp al,[DrCnt] ; C=1, falls < (d.h. OK) cmc ; Deshalb noch einmal drehen jnc OK ; C=0, alles in Butter les bx,[Rh_Ptr] ; ansonsten Fehlerstatus setzen mov byte ptr es:[bx+Rh_Status],DErr_InvUnit OK: ret endp ;****************************************************************************** ;* Adresse der phys. Laufwerkstabelle errechnen * ;* In : AL = Laufwerk * ;* Out : DI = Adresse * ;****************************************************************************** proc GetPTabAdr mov ah,DrPar_Len ; relative Adresse berechnen mul ah lea di,[DrPars] ; Offset dazu add di,ax ret endp ;****************************************************************************** ;* Adresse eines Partitionsdeskriptors errechnen * ;* In : AL = log. Laufwerk * ;* Out : DI = Adresse * ;****************************************************************************** proc GetTabAdr mov ah,DrTab_Len ; relative Adresse berechnen mul ah lea di,[DrTab] ; Offset dazu add di,ax ret endp ;****************************************************************************** ;* logische Parameter in physikalische bersetzen * ;* In : BL = log. Laufwerk * ;* DX:AX = relative Sektornummer * ;* Out : AL = phys. Laufwerk * ;* AH = Kopf * ;* BX = Zylinder * ;* CH = Sektor * ;****************************************************************************** proc TranslateParams push di ; Register retten xchg bx,ax ; Adresse Parametertabelle holen call GetTabAdr add bx,[di+DrTab_LinStart] ; in absolute Sektornummer adc dx,[di+DrTab_LinStart+2] ; umrechnen mov al,[di+DrTab_Drive] ; phys. Laufwerksnummer holen push ax ; bis zum Ende retten call GetPTabAdr ; von dieser phys. Platte die Tabelle holen mov ax,bx ; Sektor# wieder nach DX:AX mov bl,[di+DrPar_NSecs] ; Sektorzahl auf 16 Bit mov bh,0 ; aufblasen div bx mov ch,dl ; Modulo-Rest ist Sektornummer auf inc ch ; Spur: Vorsicht, Numerierung ab 1 !!! sub dx,dx ; wieder auf 32 Bit erweitern mov bl,[di+DrPar_Heads] ; Kopfnummer herausfummeln div bx mov bx,ax ; Quotient ist Zylinder pop ax ; Laufwerk zurck mov ah,dl ; Rest ist Kopf pop di ; Register zurck ret endp ;****************************************************************************** ;* Einbindung Low-Level-Routinen * ;****************************************************************************** ; definiert werden mssen: ; LowLevelIdent: Meldung ber untersttzte Hardware ausgeben ; ContDiag: Kontroller-Selbsttest durchfhren ; Ergebniskode in AL ; Recalibrate: Laufwerk [AL] auf Zylinder 0 fahren ; Fehlerflag in C, Fehlerkode in AX ; SetDriveParams: dem Kontroller die Geometrie fr Laufwerk [AL] einbleuen ; Fehlerflag in C ; ReadSectors: von Laufwerk [AL] ab Zylinder [BX], Kopf [AH], Sektor [CH] ; [CL] Sektoren in Puffer ab ES:DI lesen ; Fehlerflag in C, Fehlerkode in AX ; WriteSectors: auf Laufwerk [AL] ab Zylinder [BX], Kopf [AH], Sektor [CH] ; [CL] Sektoren von Puffer ab ES:SI schreiben ; Fehlerflag in C, Fehlerkode in AX ; VeriSectors: auf Laufwerk [AL] ab Zylinder [BX], Kopf [AH], Sektor [CH] ; [CL] Sektoren verifizieren ; Fehlerflag in C, Fehlerkode in AX ; FormatUnit: Laufwerk [AL] mit Interleave [AH] formatieren, Fehlerkode ; in AX ; FormatTrack: Zylinder [BX], Kopf [AH] auf Laufwerk [AL] mit Interleave ; [CL] formatieren, Fehlerkode in AX ; MarkBad: Zylinder [BX], Kopf [AH] auf Laufwerk [AL] als defekt ; markieren, Fehlerkode in AX include "lowlevel.inc" ;****************************************************************************** ;* Bootsektor eines log. Laufwerkes lesen * ;* In : AL = Laufwerksnummer * ;* Out : C+AX = Fehlerstatus * ;****************************************************************************** proc ReadBootSec push es ; Register retten push bx push cx push di call GetTabAdr ; Eintrag in Laufwerkstabelle ermitteln mov al,[di+DrTab_Drive] ; davon ersten Sektor lesen mov ah,[di+DrTab_StartHead] mov bx,[di+DrTab_StartCyl] mov cl,1 mov ch,[di+DrTab_StartSec] mov di,cs mov es,di lea di,[SectorBuffer] call ReadSectors pop di ; Register zurck pop cx pop bx pop es ret endp ;****************************************************************************** ;* Funktion 1: Test, ob Medium gewechselt * ;****************************************************************************** proc MediaCheck Rh_MediaID equ Rh_Resvd+8 ; erwartetes Media-ID Rh_Return equ Rh_MediaID+1 ; Ergebnis-Flag Rh_VolName equ Rh_Return+1 ; Adresse alter Laufwerksname cmp byte ptr es:[bx+Rh_MediaID],HD_ID ; gltige ID ? je OK mov byte ptr es:[bx+Rh_Status],DErr_InvMedia ; nein... jmp Error OK: mov byte ptr es:[bx+Rh_Return],1 ; nie gewechselt jmp Done endp ;****************************************************************************** ;* Funktion 2: BPB aufbauen * ;****************************************************************************** proc BuildBPB Rh2 struct db Rh_Len dup (?) MediaID db ? ; erwartetes Media-ID FATSector dd ? ; Pufferadresse 1. FAT-Sektor BPBAddress dd ? ; Adresse neuer BPB endstruct mov al,es:[bx+Rh_Unit] call ChkDrive ; Laufwerksnummer gltig ? ljc Error ; nein-->Fehler & Ende call ReadBootSec ; Bootsektor lesen ljc StateError ; bei Fehlern Ende les bx,[Rh_Ptr] ; Zeiger neu laden mov al,es:[bx+Rh_Unit] ; Tabellenadresse aufbauen call GetTabAdr lea di,[di+DrTab_BPB] ; DI auf BPB-Speicher mov es:[bx+Rh2_BPBAddress],di ; BPB-Zeiger abspeichern mov es:[bx+Rh2_BPBAddress+2],cs mov si,cs ; BPB umkopieren mov es,si lea si,[SectorBuffer+BPBOfs] cld mov cx,BPBSize rep movsb jmp Done endp ;****************************************************************************** IOCTLRead: jmp Unknown ;****************************************************************************** ;* Funktion 4: Sektoren lesen * ;****************************************************************************** Rh4 struct db Rh_len dup (?) MediaID db ? ; Media-ID Laufwerk BufOfs dw ? ; Adresse Datenpuffer BufSeg dw ? NSecs dw ? ; Anzahl zu lesender Bl”cke FirstSec dw ? ; Startsektor bzw. $FFFF fr 32-Bit-Nummern VolID dd ? ; Adresse Laufwerksname LFirstSec dw ? ; lange Startsektornummer HFirstSec dw ? endstruct Read: mov al,es:[bx+Rh_Unit] ; Laufwerksnummer prfen call ChkDrive ljc Error mov ch,al ; Laufwerksnummer retten mov ax,es:[bx+Rh4_FirstSec] ; Sektor holen (BIGDOS beachten) sub dx,dx cmp ax,-1 jne Read_SmallSec mov ax,es:[bx+Rh4_LFirstSec] mov dx,es:[bx+Rh4_HFirstSec] Read_SmallSec: mov cl,es:[bx+Rh4_NSecs] ; Sektorzahl laden (muá <=128 sein) les di,es:[bx+Rh4_BufOfs] ; Zieladresse laden mov bl,ch ; Laufwerksnummer nach BL if debug push ax push cx mov cx,ax mov al,' ' call PrChar mov al,bl ; Laufwerksnummer call PrByte mov al,' ' call PrChar mov ax,dx ; Startsektor call PrWord mov ax,cx call PrWord mov al,' ' call PrChar pop cx mov al,cl ; Sektorzahl call PrByte mov al,' ' call PrChar mov ax,es ; Startadresse call PrWord mov al,':' call PrChar mov ax,di call PrWord pop ax endif call TranslateParams ; umrechnen lassen call ReadSectors ; der eigentliche Lesevorgang ljc StateError ; bei Fehlern... jmp Done ; ansonsten o.k. ;****************************************************************************** ND_Read: jmp Unknown InputStatus: jmp Unknown InputFlush: jmp Unknown ;****************************************************************************** ;* Funktion 8: Sektoren schreiben * ;****************************************************************************** Rh8 struct db Rh_len dup (?) MediaID db ? ; Media-ID Laufwerk BufOfs dw ? ; Adresse Datenpuffer BufSeg dw ? NSecs dw ? ; Anzahl zu lesender Bl”cke FirstSec dw ? ; Startsektor bzw. $FFFF fr 32-Bit-Nummern VolID dd ? ; Adresse Laufwerksname LFirstSec dw ? ; lange Startsektornummer HFirstSec dw ? endstruct DoWrite: if debug2 mov al,es:[bx+Rh_Unit] call PrByte mov al,' ' call PrChar mov ax,es:[bx+Rh8_FirstSec] call PrWord mov al,' ' mov ax,es:[bx+Rh8_HFirstSec] call PrWord mov ax,es:[bx+Rh8_LFirstSec] call PrWord call NxtLine endif mov al,es:[bx+Rh_Unit] mov ch,al ; Laufwerksnummer retten mov ax,es:[bx+Rh8_FirstSec] ; Sektor holen (BIGDOS beachten) sub dx,dx cmp ax,-1 jne DWrite_SmallSec mov ax,es:[bx+Rh8_LFirstSec] mov dx,es:[bx+Rh8_HFirstSec] DWrite_SmallSec:mov cl,es:[bx+Rh8_NSecs] ; Sektorzahl laden (muá <=128 sein) les si,es:[bx+Rh8_BufOfs] ; Zieladresse laden mov bl,ch ; Laufwerksnummer nach BL if debug push ax push cx mov cx,ax mov al,' ' call PrChar mov al,bl ; Laufwerksnummer call PrByte mov al,' ' call PrChar mov ax,dx ; Startsektor call PrWord mov ax,cx call PrWord mov al,' ' call PrChar pop cx mov al,cl ; Sektorzahl call PrByte mov al,' ' call PrChar mov ax,es ; Startadresse call PrWord mov al,':' call PrChar mov ax,si call PrWord pop ax endif call TranslateParams ; umrechnen lassen call WriteSectors ; der eigentliche Lesevorgang ret Write: mov al,es:[bx+Rh_Unit] ; Laufwerksnummer prfen call ChkDrive ljc Error call DoWrite ljc StateError ; bei Fehlern... jmp Done ; ansonsten o.k. ;****************************************************************************** ;* Funktion 9: Sektoren schreiben mit šberprfung * ;****************************************************************************** Rh9 struct db Rh_len dup (?) MediaID db ? ; Media-ID Laufwerk BufOfs dw ? ; Adresse Datenpuffer BufSeg dw ? NSecs dw ? ; Anzahl zu lesender Bl”cke FirstSec dw ? ; Startsektor bzw. $FFFF fr 32-Bit-Nummern VolID dd ? ; Adresse Laufwerksname LFirstSec dw ? ; lange Startsektornummer HFirstSec dw ? endstruct Write_Verify: mov al,es:[bx+Rh_Unit] ; Laufwerksnummer prfen call ChkDrive ljc Error call DoWrite ; schreiben ljc StateError ; bei Fehlern vorher abbrechen les bx,[Rh_Ptr] ; Parameter nochmal fr Verify laden mov al,es:[bx+Rh_Unit] mov ch,al mov ax,es:[bx+Rh9_FirstSec] sub dx,dx cmp ax,-1 jne VWrite_SmallSec mov ax,es:[bx+Rh9_LFirstSec] mov dx,es:[bx+Rh9_HFirstSec] VWrite_SmallSec:mov cl,es:[bx+Rh9_NSecs] mov bl,ch call TranslateParams ; nochmal umrechen... call VeriSectors ; und prflesen jmp Done ; alles gut gegangen ;****************************************************************************** OutputStat: jmp Unknown OutputFlush: jmp Unknown IOCTLWrite: jmp Unknown ;****************************************************************************** ;* kein Device wechselbar, ™ffnen/Schleáen interessiert nicht * ;****************************************************************************** DeviceOpen: jmp Done DeviceClose: jmp Done Removeable: jmp Done ;****************************************************************************** OutputTillBusy: jmp Unknown GenIOCTL: jmp Unknown GetLogical: jmp Unknown SetLogical: jmp Unknown IOCTLQuery: jmp Unknown ;****************************************************************************** ;* Funktion 0: Initialisierung * ;****************************************************************************** include "secparam.inc" Rh0 struct db Rh_len dup (?) Units db ? ; Zahl bedienter Laufwerke EndOfs dw ? ; Endadresse Offset EndSeg dw ? ; Endadresse Segment ParamOfs dw ? ; Parameter Offsetadresse ParamSeg dw ? ; Parameter Segmentadresse FirstDrive db ? ; erstes freies Laufwerk MsgFlag db ? ; Flag, ob DOS Fehler ausgeben darf endstruct Init: PrMsg HelloMsg ; Meldung ausgeben call LowLevelIdent ; Startmeldung des Low-Level-Treibers mov byte ptr es:[bx+Rh0_Units],0 ; noch keine Laufwerke mov al,es:[bx+Rh0_FirstDrive] ; Startlaufwerk retten mov [DrOfs],al mov ax,cs ; ES auf gem. Segment mov es,ax ; Schritt 1: Controller prfen PrMsg DiagMsg0 call ContDiag ; Diagnose ausfhren sub al,Diag_NoError cmp al,6 ; auáerhalb ? jae Diag_Over add al,al ; Meldung ausrechnen mov ah,0 mov si,ax mov dx,DiagMsgTable[si] mov ah,9 int INT_DOS or si,si ; fehlerfrei ? ljnz Init_Err ; Nein, Fehler jmp Init_ChkDrives ; Ja, weiter zum Laufwerkstest Diag_Over: push ax PrMsg UndefDiagMsg ; undefinierter Fehlercode pop ax add al,Diag_NoError ; Meldung rckkorrigieren db 0d4h,10h ; AAM 16 add ax,'00' push ax mov al,ah mov ah,14 int 10h pop ax mov ah,14 int 10h PrChar CR PrChar LF jmp Init_Err ; Schritt 2: Laufwerke testen ; Menaufruf? Init_ChkDrives: mov ax,40h ; CTRL gedrckt ? mov es,ax btst byte ptr es:[17h],2 jz Init_Menu call DiskMenu ; Schritt 2a: Laufwerk rekalibrieren Init_Menu: mov al,[MomDrive] call Recalibrate ljc Init_NextDrive ; Fehler: Laufwerk berspringen ; Schritt 2b: Masterpartitionssektor lesen ReadMaster: mov al,[MomDrive] mov ah,0 ; Kopf... sub bx,bx ; ...Zylinder... mov cx,0101h ; ...ein Sektor ab Sektor 1 mov di,ds mov es,di lea di,[SectorBuffer] ; in den Sektorpuffer call ReadSectors JmpOnError [MomDrive],Init_NextDrive ; Fehler ? ; Schritt 2c: Laufwerksparameter initialisieren lea si,[SectorBuffer+DrPar_Offset] ; Quelladresse im Sektor mov al,[MomDrive] ; Zieladresse ausrechnen call GetPTabAdr mov cx,DrPar_Len cld rep movsb sub di,DrPar_Len ; Laufwerk nicht initialisiert ? cmp word ptr[di+DrPar_Cyls],0 je DoQuery cmp byte ptr[di+DrPar_Heads],0 je DoQuery cmp byte ptr[di+DrPar_NSecs],0 jne NoQuery DoQuery: mov al,[MomDrive] ; wenn ja, dann nachfragen mov ah,1 ; Rckschreiben hier erlaubt call QueryParams or al,al ; =0-->Laufwerk ignorieren jz Init_NextDrive dec al ; =1-->nochmal lesen jz ReadMaster ; ansonsten weitermachen NoQuery: mov al,[MomDrive] ; Laufwerksparameter ausgeben... call PrintPDrive mov al,[MomDrive] ; ...und dem Controller einbleuen call SetDriveParams JmpOnError [MomDrive],Init_NextDrive mov al,[MomDrive] call Recalibrate JmpOnError [MomDrive],Init_NextDrive ; Schritt 2d: durch die Partitionssektoren hangeln mov al,[MomDrive] ; Laufwerk : momentanes cbw ; Kopf : 0 push ax sub ax,ax push ax ; Zylinder : 0 inc ax ; Sektor : 1 push ax dec ax push ax ; lin. Sektornummer 0 push ax call ScanParts Init_NextDrive: inc [MomDrive] ; Z„hler weitersetzen cmp [MomDrive],MaxPDrives ljb Init_ChkDrives cmp [DrCnt],0 ; keine Partitionen gefunden ? jne Init_PDrives PrMsg ErrMsgNoDrives ; ja: meckern jmp Init_Err Init_PDrives: PrMsg LDriveMsg mov [MomDrive],0 ; Parameter der Partitionen ausgeben lea bp,[DrTab_BPBs] ; und BPB-Tabelle aufbauen cld Init_PLDrives: mov al,[MomDrive] call PrintLDrive mov al,[MomDrive] ; Bootsdektor lesen call ReadBootSec lea si,[SectorBuffer+BPBOfs] ; BPB rauskopieren mov al,[MomDrive] call GetTabAdr lea di,[di+DrTab_BPB] mov ax,cs mov es,ax mov ds:[bp],di ; Adresse nebenbei ablegen add bp,2 mov cx,BPBSize rep movsb inc [MomDrive] mov al,[MomDrive] cmp al,[DrCnt] jb Init_PLDrives PrChar LF ; sieht besser aus... les bx,[Rh_Ptr] ; Zeiger auf BPB-Zeiger einschreiben lea ax,[DrTab_BPBs] mov es:[bx+Rh0_ParamOfs],ax mov es:[bx+Rh0_ParamSeg],cs jmp Init_OK ; Initialisierung erfolgeich zu Ende Init_Err: PrMsg WKeyMsg xor ah,ah ; damit Meldung lesbar bleibt int 16h sub ax,ax ; Treiber aus Speicher entfernen jmp Init_End Init_OK: mov al,[DrCnt] ; Laufwerkszahl holen les bx,[Rh_Ptr] mov es:[bx+Rh0_Units],al ; im Request Header eintragen mov [NrOfVols],al ; im Treiberkopf eintragen lea ax,[Init] ; residenten Teil installieren Init_End: les bx,[Rh_Ptr] mov es:[bx+Rh0_EndOfs],ax ; Endadresse setzen mov es:[bx+Rh0_EndSeg],cs jmp Done ;****************************************************************************** ;* transiente Unterroutinen * ;****************************************************************************** ;****************************************************************************** ;* Partitionsbaum durchgehen * ;* In : dw Kopf/Laufwerk * ;* dw Zylinder * ;* dw Sektor * ;* dd lineare Nummer des Sektors * ;****************************************************************************** ScParts_DrHd equ 12 ; Parameteradressen auf Stack ScParts_Cyl equ 10 ScParts_Sec equ 8 ScParts_LinSec equ 4 ScParts_ParTab equ 0-(MaxParts*ParTab_Len) ; Kopie Partitionstabelle ScParts_LocSize equ 0-ScParts_ParTab ; belegter Stack ScanParts: enter ScParts_LocSize,0 ; Partitionssektor lesen mov ax,[bp+ScParts_DrHd] mov bx,[bp+ScParts_Cyl] mov ch,[bp+ScParts_Sec] mov cl,1 mov di,cs mov es,di lea di,[SectorBuffer] call ReadSectors JmpOnError [MomDrive],ScanParts_End ; Partitionssektorkennung o.k. ? cmp word ptr SectorBuffer[ParSecID_Offset],0aa55h ljne ScanParts_End ; Partitionstabelle auslesen lea si,[SectorBuffer+ParTab_Offset] ; Quelladresse mov di,ss ; Zieladresse auf Stack mov es,di lea di,[bp+ScParts_ParTab] mov cx,MaxParts*ParTab_Len ; L„nge cld rep movsb ; Partitionstabelle durchgehen mov si,ScParts_ParTab ; vorne anfangen mov cx,MaxParts ; alle durchgehen ScanParts_Scan: push cx mov al,[bp+si+ParTab_Type] ; Typ der Partition lesen lea bx,[AccPartTypes-1] ; auf Suchtabelle ScanParts_LAcc: inc bx ; einen Eintrag weiter cmp byte ptr [bx],0 ; Tabellenende ? je ScanParts_Next ; ja-->war nix cmp al,[bx] ; gefunden ? jne ScanParts_LAcc ; mov bx,[bp+si+ParTab_LinSec] ; linearen Startsektor ausrechnen mov cx,[bp+si+ParTab_LinSec+2] add bx,[bp+ScParts_LinSec] ; in CX:BX adc cx,[bp+ScParts_LinSec+2] cmp al,5 ; extended partition ? jne ScanParts_Enter push si ; ja: Zeiger fr Rekursion retten mov al,[bp+ScParts_DrHd] ; Laufwerk & Kopf zusammenbauen mov ah,[bp+si+ParTab_FHead] push ax mov ax,[bp+si+ParTab_FSecCyl] ; Zylinder ausfiltern xchg ah,al shr ah,6 push ax mov al,[bp+si+ParTab_FSecCyl] ; Sektor ausfiltern and ax,63 push ax push cx push bx call ScanParts pop si ; Zeiger zurck jmp ScanParts_Next ScanParts_Enter:mov al,[DrCnt] ; Partition in Tabelle eintragen call GetTabAdr ; dazu Adresse neuen Eintrags holen cld mov ax,cs ; Ziel im Segment mov es,ax mov al,[bp+si+ParTab_FHead] ; Kopf kopieren stosb mov ax,[bp+si+ParTab_FSecCyl] ; Zylinder kopieren xchg ah,al shr ah,6 stosw mov al,[bp+si+ParTab_FSecCyl] ; Sektor kopieren and al,63 stosb mov ax,bx ; linearen Startsektor kopieren stosw mov ax,cx stosw mov ax,[bp+si+ParTab_NSecs] ; Sektorzahl kopieren stosw mov ax,[bp+si+ParTab_NSecs+2] stosw mov al,[bp+ScParts_DrHd] ; Laufwerksnummer kopieren stosb inc [DrCnt] ; ein log. Laufwerk mehr ScanParts_Next: add si,ParTab_Len ; auf n„chste Partition pop cx dec cx ljnz ScanParts_Scan ScanParts_End: leave ret 10 ;****************************************************************************** ;* Daten eines physikalischen Laufwerks ausgeben * ;* In : AL = Laufwerk * ;****************************************************************************** proc PrintPDrive push cx ; Register retten push dx push di cbw ; AH l”schen push ax ; Laufwerk ausgeben PrMsg PDriveMsg1 pop ax push ax inc ax mov cl,1 call WriteDec PrMsg PDriveMsg2 pop ax ; Adresse Laufwerkstabelle berechnen call GetPTabAdr mov ax,[di+DrPar_Cyls] ; Zylinder ausgeben mov cl,5 call WriteDec PrMsg PDriveMsg3 mov al,[di+DrPar_Heads] ; K”pfe ausgeben mov ah,0 mov cl,3 call WriteDec PrMsg PDriveMsg4 mov al,[di+DrPar_NSecs] ; Sektoren ausgeben mov ah,0 mov cl,4 call WriteDec PrMsg PDriveMsg5 mov al,[di+DrPar_Heads] ; Gesamtsektorzahl berechnen mul byte ptr [di+DrPar_NSecs] mul word ptr [di+DrPar_Cyls] call WriteMBytes PrMsg PDriveMsg6 pop di ; Register zurck pop dx pop cx ret endp ;****************************************************************************** ;* Daten eines logischen Laufwerks ausgeben * ;* In : AL = Laufwerk * ;****************************************************************************** proc PrintLDrive push cx ; Register retten push dx push di mov dx,ax ; Laufwerk retten push dx mov cx,3 ; ausgeben call WriteSpc add dl,[DrOfs] add dl,'A' mov ah,DOS_WrChar int INT_DOS PrChar ':' pop ax ; Tabelle holen call GetTabAdr mov al,[di+DrTab_Drive] ; Laufwerk ausgeben... inc al cbw mov cl,9 call WriteDec mov ax,[di+DrTab_StartCyl] ; ...Zylinder... mov cl,10 call WriteDec mov al,[di+DrTab_StartHead] ; ...Kopf... cbw mov cl,7 call WriteDec mov al,[di+DrTab_StartSec] ; ...Sektor... cbw mov cl,8 call WriteDec mov cx,2 call WriteSpc mov ax,[di+DrTab_SecCnt] ; ...Gr”áe mov dx,[di+DrTab_SecCnt+2] call WriteMBytes PrMsg PDriveMsg6 ; Meldung wiederverwertet... pop di ; Register zurck pop dx pop cx ret endp ;****************************************************************************** ;* Fehlercode eines Laufwerks ausgeben * ;* In : AL = Fehlercode * ;* AH = Laufwerksnummer (0,1...) * ;****************************************************************************** proc WrErrorCode push bx ; Register retten push cx push dx add ah,'1' ; LW-Nummer in ASCII umrechnen... mov [DrvErrorMsg2],ah ; ...und einschreiben mov ch,al ; Kode sichern PrMsg DrvErrorMsg mov cl,7 ; bei Bit 0 anfangen ErrLoop: rol ch,1 ; fagl. Bit in Carry jnc NoErrBit mov bl,cl ; Bit gefunden: Index ausrechnen mov bh,0 add bx,bx mov dx,[bx+Pointers] mov ah,DOS_WrString int INT_DOS NoErrBit: dec cl ; n„chstes Bit jnz ErrLoop pop dx ; Register zurck pop cx pop bx ret DrvErrorMsg: db "Fehler auf Festplatte " DrvErrorMsg2: db "0:",CR,LF,'$' Pointers dw Msg0,Msg1,Msg2,Msg3,Msg4,Msg5,Msg6,Msg7 Msg0 db " Adreámarke nicht gefunden",CR,LF,'$' Msg1 db " Spur 0 nicht gefunden",CR,LF,'$' Msg2 db " Kommandoabbruch",CR,LF,'$' Msg3 db "$" Msg4 db " Sektor nicht gefunden",CR,LF,'$' Msg5 db "$" Msg6 db " Datenfehler",CR,LF,'$' Msg7 db " Sektor als defekt markiert",CR,LF,'$' endp ;****************************************************************************** ;* Sektorenzahl als MBytes ausgeben * ;* In: DX:AX = Sektorzahl * ;****************************************************************************** proc WriteMBytes SecsPerMByte equ (2^20)/SecSize push cx ; Register retten push dx add ax,SecsPerMByte/20 ; wg. Rundung adc dx,0 mov cx,SecsPerMByte ; durch 2048 teilen = MByte div cx push dx ; Nachkommastellen retten mov cl,6 call WriteDec PrChar '.' ; Nachkommastelle pop ax ; holen cwd mov cx,SecsPerMByte/10 ; Sektoren pro 100 KByte div cx mov cl,1 ; ausgeben call WriteDec pop dx ; Register zurck pop cx ret endp ;****************************************************************************** ;* transiente Daten * ;****************************************************************************** HelloMsg: db CR,LF,"Sekund„rlaufwerkstreiber V0.4",CR,LF,'$' ErrMsgNoDrives: db CR,LF,"Fehler: keine Partitionen gefunden",CR,LF,'$' DiagMsg0: db CR,LF,"Controller-Selbsttest: ",'$' DiagMsg1: db "OK",CR,LF,'$' DiagMsg2: db "Controller fehlerhaft",CR,LF,'$' DiagMsg3: db "Sektorpuffer defekt",CR,LF,'$' DiagMsg4: db "Fehlerkorrektur defekt",CR,LF,'$' DiagMsg5: db "Steuerprozessor defekt",CR,LF,'$' DiagMsg6: db "Timeout",CR,LF,'$' DiagMsgTable dw DiagMsg1,DiagMsg2,DiagMsg3,DiagMsg4,DiagMsg5,DiagMsg6 UndefDiagMsg db "Unbekannter Fehlercode #$" WKeyMsg: db "Weiter mit beliebiger Taste...",CR,LF,'$' PDriveMsg1: db "Festplatte $" PDriveMsg2: db " :$" PDriveMsg3: db " Zylinder,$" PDriveMsg4: db " K”pfe,$" PDriveMsg5: db " Sektoren,$" PDriveMsg6: db " MByte",CR,LF,'$' LDriveMsg: db CR,LF,"vorhandene Partitionen:",CR,LF db "Laufwerk Platte Zylinder Kopf" db " Sektor Kapazit„t",CR,LF,'$' AccPartTypes db 1 ; akzeptierte Partitionstypen: DOS 2.x FAT12 db 4 ; DOS 3.x FAT16 db 5 ; DOS 3.3 extended db 6 ; DOS 3.31 >32 MByte db 0 ; Tabellenende MomDrive db 0 ; momentan gescanntes Laufwerk end