Blame | Last modification | View Log | Download | RSS feed
;*****************************************************************************;* Sekundaerlaufwerkstreiber, Modul SecParam *;* liefert Laufwerksparameter, falls fehlend im Bootsektor *;* stellt das ganze Formatiermenue zur Verfuegung *;*****************************************************************************section SecParam;*****************************************************************************;* gemeinsam benutzte Meldungen *;*****************************************************************************TrackMsg db "Spur (0..Spurzahl-1) : $"HeadMsg db "Kopf (0..Kopfzahl-1) : $"ConfirmMsg db "Sind Sie sicher ?$"InterleaveMsg db "Interleave (1..Sektorzahl-1) : $";*****************************************************************************;* Routine BreakOnESC *;* schaut nach, ob ESC gedrueckt wurde *;* Ausgabe: C=1, falls ja *;*****************************************************************************GlobProc BreakOnESCpush ax ; Register rettenmov ah,1 ; Tastaturpuffer antestenint INT_Keyboardclc ; Annahme nicht gedruecktjz Endemov ah,0 ; Zeichen da: dies abholenint INT_Keyboardcmp al,ESC ; ist es ESC ?clc ; Annahme neinjne Endestc ; jawoll!Ende: pop ax ; Register zurueckretendp;*****************************************************************************;* Routine YesNo *;* fragt nach Ja oder Nein *;* Ausgabe: C=0, falls ja *;*****************************************************************************proc YesNopush ax ; Register rettenQueryLoop: mov ah,DOS_RdChar ; ein Zeichen lesenint INT_DOScmp al,'a' ; Kleinbuchstaben ?jb Uppercmp al,'z'ja Upperadd al,'A'sub al,'a'Upper:cmp al,'J' ; akzeptierte Zeichen fuer Jaclcje YNDonecmp al,'Y'clcje YNDonecmp al,'N' ; akzeptierte Zeichen fuer Neinstcje YNDonePrChar BEL ; alles andere anmeckernjmp QueryLoopYNDone: PrChar al ; Zeichen als Echo ausgebenPrChar CR ; ZeilenvorschubPrChar LFpop ax ; Register zurueckretendp;*****************************************************************************;* Routine ReadNumber *;* liest einen Wert von 0..n in AX ein *;* Eingabe: AX = Maximalwert *;* DI = Zeiger auf Meldung *;* Ausgabe: AX = eingelesene Zahl *;*****************************************************************************proc ReadNumberpush bx ; Register rettenpush cxpush dxpush simov si,ax ; Maximalwert rettenInLoop: mov dx,di ; Meldung ausgebenmov ah,DOS_WrStringint INT_DOSlea dx,[KeyBuffer] ; Zahl als String einlesenmov ah,DOS_RdStringint INT_DOSPrChar CRPrChar LFmov ax,0 ; jetzt Zeichen verarbeitenmov cl,[KeyBuffer+1]mov ch,0lea bx,[KeyBuffer+2]jcxz InvFormat ; Nullschleife abfangenConvLoop: mov dx,10 ; bisheriges Ergebnis hochmultiplizierenmul dxmov dl,[bx] ; ein Zeichen holeninc bxsub dl,'0' ; ASCII-Offset abziehenjc InvFormat ; bei Formatfehler abbrechencmp dl,9 ; nur 0..9 erlaubtja InvFormatadd al,dl ; dazuaddierenadc ah,0loop ConvLoopjmp ChkRange ; fertig: weiter zur BereichspruefungInvFormat: PrMsg InvMsg ; wenn fehlerhaft, meckernjmp InLoop ; und nochmal versuchenChkRange: cmp ax,si ; ausserhalb Bereich ?jbe OKPrMsg OverMsg ; ja: meckern...jmp InLoop ; ...und auf ein neuesOK: pop si ; Register zurueckpop dxpop cxpop bxretKeyBufferLen equ 30 ; 30 Zeichen sollten fuer Zahlen reichen...KeyBuffer db KeyBufferLen ; Maimallaenge fuer DOSdb 0 ; effektive Laenge Eingabedb KeyBufferLen dup (0) ; Platz fuer EingabeInvMsg db "Ung",UUML,"ltiges Zahlenformat",CR,LF,'$'OverMsg db "Bereichs",UUML,"berschreitung",CR,LF,'$'endp;******************************************************************************;* eine Anzahl Leerzeichen ausgeben *;* In : CX = Anzahl *;******************************************************************************globproc WriteSpcpush dx ; Register rettenjcxz NULL ; Nullschleife abfangenLoop: mov ah,DOS_WrCharmov dl,' 'int INT_DOSloop LoopNULL: pop dx ; Register zurueckretendp;******************************************************************************;* vorzeichenlose Zahl dezimal ausgeben *;* In : AX = Zahl *;* CL = min. Stellenzahl *;******************************************************************************globproc WriteDecpush di ; Register rettenpush cxpush dxmov ch,0 ; CH zaehlt effektive ZeichenzahlInLoop: sub dx,dx ; Stellendivisionmov di,10 ; gewuenschtes Zahlensystemdiv dimov di,ax ; war es vorher 0 ?or di,dx ; (wenn Quotient & Rest 0)jnz NZero ; nein-->normal ausgebenor ch,ch ; noch erste Stelle ?jz NZero ; dann auf jeden Fall 0 ausgebenmov dl,0f0h ; ansonsten Leerzeichen fuer leading 0NZero: push dx ; Zeichen speichern...inc ch ; ...und mitzaehlencmp ch,cl ; Mindestzahl ausgegeben ?jb InLoop ; nein-->weiteror ax,ax ; ansonsten: 0 ?jnz InLoop ; nein, weitermachenshr cx,8 ; effektive Zahl nach CXOLoop: pop dx ; ein Zeichen runterholenadd dl,'0' ; in ASCII konvertierenmov ah,DOS_WrChar ; ueber DOS ausgebenint INT_DOSloop OLooppop dxpop cxpop di ; Register zurueckretendp;******************************************************************************;* vorzeichenlose Zahl hexadezimal ausgeben *;* In : AX = Zahl *;* CL = min. Stellenzahl *;******************************************************************************globproc WriteHexpush di ; Register rettenpush cxpush dxmov ch,0 ; CH zaehlt effektive ZeichenzahlInLoop: sub dx,dx ; Stellendivisionmov di,16 ; gewuenschtes Zahlensystemdiv dimov di,ax ; war es vorher 0 ?or di,dx ; (wenn Quotient & Rest 0)jnz NZero ; nein-->normal ausgebenor ch,ch ; noch erste Stelle ?jz NZero ; dann auf jeden Fall 0 ausgebenmov dl,0f0h ; ansonsten Leerzeichen fБr leading 0NZero: push dx ; Zeichen speichern...inc ch ; ...und mitzaehlencmp ch,cl ; Mindestzahl ausgegeben ?jb InLoop ; nein-->weiteror ax,ax ; ansonsten: 0 ?jnz InLoop ; nein, weitermachenshr cx,8 ; effektive Zahl nach CXOLoop: pop dx ; ein Zeichen runterholenadd dl,'0' ; in ASCII konvertierencmp dl,'9'jbe NoHexadd dl,7NoHex: mov ah,DOS_WrChar ; ueber DOS ausgebenint INT_DOSloop OLooppop dxpop cxpop di ; Register zurueckretendp;*****************************************************************************;* Routine GeometryDefined - stellt fest, ob Geometrie fuer ei Laufwerk defi-*;* niert ist *;* Eingabe: AL = Laufwerksnummer *;* Ausgabe: C = 0, falls OK *;*****************************************************************************proc GeometryDefinedpush di ; Register rettencall GetPTabAdr ; Tabellenadresse bildencmp word ptr[di+DrPar_Cyls],0 ; Zylinderzahl 0 ?stcje Fincmp byte ptr[di+DrPar_Heads],0 ; Kopfzahl 0 ?stcje Fincmp byte ptr[di+DrPar_NSecs],0 ; Sektorzahl 0 ?stcje Finclc ; alles OKFin: pop di ; Register zurueckretendp;*****************************************************************************;* Routine QueryRedefine - fragt nach, ob Geometrie neu definert werden soll *;* Eingabe: AL = Laufwerk *;* Ausgabe: C = 0, falls ja *;*****************************************************************************proc QueryRedefineadd al,'1' ; Laufwerksnummer in ASCII umrechnenmov [UndefMsg2],al ; in Meldung einschreibenPrMsg UndefMsgPrMsg DoQueryMsg ; nachfragen, ob Definition erwuenschtcall YesNoretUndefMsg db "Geometrie f",UUML,"r Laufwerk "UndefMsg2 db " undefiniert.",CR,LF,"$"DoQueryMsg db "Geometrie neu definieren ? $"endp;*****************************************************************************;* Routine ReadGeomety - liest Laufwerksgeometrie vom Benutzer ein *;* Eingabe: AL = phys. Laufwerksnummer *;*****************************************************************************proc ReadGeometrypush ax ; Register rettenpush sipush dicall GetPTabAdr ; Zeiger auf Parametertabelle holenmov si,dilea di,[CylInpMsg] ; Zylinderzahl erfragenmov ax,1024call ReadNumbermov [si+DrPar_Cyls],axlea di,[HeadInpMsg] ; Kopfzahl erfragenmov ax,16call ReadNumbermov [si+DrPar_Heads],allea di,[RWCInpMsg] ; RWC-Zylinder erfragenmov ax,65535call ReadNumbermov [si+DrPar_RedWr],axlea di,[PreInpMsg] ; Praekompensations-Zylinder erfragenmov ax,65535call ReadNumbermov [si+DrPar_PrComp],axlea di,[ECCInpMsg] ; ECC-Laenge erfragenmov ax,11call ReadNumbermov [si+DrPar_ECCLen],axmov al,[si+DrPar_Heads] ; Steuerbyte Bit 3=1, falls Plattedec aland al,8 ; mehr als 8 Koepfe hatmov [si+DrPar_CByte],almov al,0 ; Timeouts unbenutztmov [si+DrPar_TOut],almov [si+DrPar_FTOut],almov [si+DrPar_CTOut],almov ax,[si+DrPar_Cyls] ; Parkzylinder=Zylinderzahl+1inc axmov [si+DrPar_LZone],axlea di,[SecInpMsg] ; Sektorzahl erfragenmov ax,255call ReadNumbermov [si+DrPar_NSecs],alpop di ; Register zurueckpop sipop axretCylInpMsg db "Anzahl Zylinder (max. 1024) : $"HeadInpMsg db "Anzahl K",OUML,"pfe (max. 16) : $"RWCInpMsg db "Startzylinder f",UUML,"r reduzierten Schreibstrom (max. 65535) : $"PreInpMsg db "Startzylinder f",UUML,"r Pr",AUML,"kompensation (max. 65535) : $"ECCInpMsg db "max. ECC-Fehlerburstl",AUML,"nge (5 oder 11) : $"SecInpMsg db "Sektorzahl (max. 255) : $"endp;*****************************************************************************;* Routine WriteGeoToDisk - schreibt Laufwerksgeometrie auf Platte *;* Eingabe: AL = phys. Laufwerksnummer *;* Ausgabe: C+AX = Fehlerstatus *;*****************************************************************************proc WriteGeoToDiskpush bx ; Register rettenpush cxpush dxpush sipush dipush esmov dx,ds ; alles im folgenden im Datensegmentmov es,dxmov dl,al ; Laufwerksnummer rettenmov ah,0 ; Kopf 0,sub bx,bx ; Spur 0,mov cx,0101h ; Sektor 1 lesenlea di,[SectorBuffer]call ReadSectorsjc GeoError ; Abbruch bei Fehlermov al,dl ; Geometrietabelle adressierencall GetPTabAdrmov si,di ; selbige in MBR einschreibenlea di,[SectorBuffer+DrPar_Offset]mov cx,DrPar_Len/2cldrep movswmov al,dl ; jetzt den ganzen Kram zurueckschreibenmov ah,0sub bx,bxmov cx,0101hlea si,[SectorBuffer]call WriteSectorsjc GeoErrorFin: pop es ; Register zurueckpop dipop sipop dxpop cxpop bxretGeoError: mov ah,bl ; Fehlerausgabecall WrErrorCodejmp Finendp;*****************************************************************************;* Routine QueryParams *;* Eingabe: AL = Laufwerksnummer *;* AH = 1, falls Rueckschreiben erlaubt *;* Ausgabe: AL = 0: Laufwerk vergessen *;* AL = 1: Mastersektor neu lesen *;* AL = 2: Tabelle nur transient eingetragen, kein Neulesen *;*****************************************************************************globproc QueryParamspush bx ; Register rettenpush cxpush dxpush sipush dipush esmov bx,ax ; Laufwerksnummer rettencall QueryRedefine ; nachfragen, ob Neudefinition erwuenschtmov al,0 ; Abbruch bei Neinljc Terminatemov al,bl ; Geometrie einlesencall ReadGeometryshr bh,1 ; Rueckschreiben erlaubt ?cmc ; C=1-->verbotenjc NoWriteBackPrMsg WriteBackMsg ; nachfragen, ob Rueckschreiben erwuenschtcall YesNoNoWriteBack: mov al,2 ; Neulesen bei Nein verhindernjc Terminatemov al,blcall WriteGeoToDiskjc WrErrormov al,1 ; Ergebnis: MBR-Lesen wiederholenjmp TerminateWrError: mov al,0 ; Schreibfehler: Laufwerk ignorierenTerminate: pop es ; Register zurueckpop dipop sipop dxpop cxpop bxretWriteBackMsg db "Parametersatz zur",UUML,"ckschreiben ? $"endp;****************************************************************************;* Laufwerksnummer einlesen *;* Ausgabe: AL = Laufwerksnummer *;****************************************************************************proc InputDrivepush dx ; Register rettenRdLoop: PrMsg PromptMsg ; Anfrage ausgebenmov ah,DOS_RdChar ; ein Zeichen holenint INT_DOSmov dl,al ; Zeichen rettenPrChar dl ; Laufwerk als Echo zurueckgebenPrChar CRPrChar LFsub dl,'1' ; nur 1 oder 2 erlaubtjc RdLoopcmp dl,MaxPDrivesjae RdLoopmov al,dl ; Laufwerk in AL zurueckgebenpop dx ; Register zurueckretPromptMsg db "Laufwerksnummer (1 oder 2) : $"endp;****************************************************************************;* MenБ fБr Plattenfunktionen *;****************************************************************************proc SelectDiskpush ax ; Register sichernpush bxpush cxpush dxpush sipush dipush esmov dh,ah ; Rueckschreibeflag sicherncall InputDrivemov dl,al ; Laufwerksnummer sichernmov al,dl ; Geometrie noch undefiniert ?call GeometryDefinedjnc IsOK ; Nein, alles in Buttermov al,dl ; nicht definiert: versuchen,mov ah,0 ; Geometrie vom MBR zu lesenmov bx,dsmov es,bxsub bx,bxmov cx,0101hlea di,[SectorBuffer]call ReadSectorsjnc CopyTable ; kein Fehler->Tabelle auslesenmov dh,0 ; wenn Fehler, nie zurueckschreibenjmp ReadManual ; und manuell probierenCopyTable: lea si,[SectorBuffer+DrPar_Offset]mov al,dlcall GetPTabAdrmov cx,DrPar_Len/2cldrep movswmov al,dl ; Geometrie jetzt da ?call GeometryDefinedjnc IsOK ; falls ja, EndeReadManual: mov al,dl ; fragen, ob Redefinition erwuenschtcall QueryRedefinejc NotOK ; falls nein, Abbruchmov al,dl ; ansonsten einlesencall ReadGeometryshr dh,1 ; zurueckschreiben ?jnc IsOKmov al,dl ; ja...call WriteGeoToDisk ; Fehler ignorierenIsOK: mov [MomDrive],dl ; Laufwerk akzeptiertNotOK: pop es ; Register zurueckpop dipop sipop dxpop cxpop bxpop axretendp;----------------------------------------------------------------------------proc ChangeGeometrycmp [MomDrive],-1 ; Laufwerk ueberhaupt schon definiert ?jne DriveDefinedcall InputDrive ; nein: lesen & einschreibenmov [MomDrive],alDriveDefined: mov al,[MomDrive] ; neue Geometrie einlesencall ReadGeometrymov al,[MomDrive]call WriteGeoToDisk ; die auch gleich zu schreiben versuchenretendp;----------------------------------------------------------------------------proc VerifyDiskpusha ; restlos alles...mov al,[MomDrive] ; erstmal sicherstellen, dass dercall SetDriveParams ; Kontroller die Geometrie kenntmov al,[MomDrive] ; die Geometrie brauchen wir auchcall GetPTabAdrPrMsg ESCMsgsub bp,bp ; Fehlerzaehlermov si,bp ; Zylinderzaehlermov dx,bp ; FolgefehlerzaehlerCylLoop: mov dl,0 ; KopfzaehlerHeadLoop: PrMsg CylMsg ; zu testende Spur ausgebenmov ax,simov cl,4call WriteDecPrMsg HeadMsgmov al,dlmov ah,0mov cl,2call WriteDecPrChar CRmov al,[MomDrive] ; eine Spur testenmov ah,dlmov bx,simov cl,[di+DrPar_NSecs]mov ch,1call VeriSectorsjnc NoError ; evtl. Fehlerbehandlungpush axPrChar LFpop axmov ah,[MomDrive]call WrErrorCodeinc bp ; Fehlerzaehler raufinc dhtest dh,7 ; alle 8 Fehler in Reihe nachfragenjnz NextTrackPrMsg GoOnMsgcall YesNojc Terminatejmp NextTrackNoError: mov dh,0 ; eine Spur gut->Folgenzaehler loeschenNextTrack: call BreakONESC ; Abbruch ?jc Terminateinc dl ; naechster Kopfcmp dl,[di+DrPar_Heads]jb HeadLoopinc si ; naechster Zylindercmp si,[di+DrPar_Cyls]ljb CylLoopTerminate: mov ax,bp ; Fehlerzahl ausgebenmov cl,5call WriteDecPrMsg ErrorMsgpopa ; Register zurueckretEscMsg db "Verifizieren..",CR,LF,"Abbruch mit <ESC>",CR,LF,'$'CylMsg db "Zylinder $"HeadMsg db ", Kopf $"GoOnMsg db "Test fortsetzen? $"ErrorMsg: db " Fehler gefunden ",CR,LF,'$'endp;----------------------------------------------------------------------------proc FormatDiskpush ax ; Register rettenpush bxpush cxpush dipush esmov al,[MomDrive] ; erstmal sicherstellen, dass dercall SetDriveParams ; Kontroller die Geometrie kenntmov al,[MomDrive]call GetPTabAdrInterLoop: mov al,[di+DrPar_NSecs] ; Maximum=Sektorzahl-1dec almov ah,0lea di,[InterleaveMsg] ; Interleave erfragencall ReadNumberor ax,ax ; Null wollen wir nichtjz InterLoopmov bl,al ; Interleave rettenPrMsg ConfirmMsg ; sicherheitshalber nachfragencall YesNojc FinPrMsg NewLinePrMsg FormatMsgmov ah,bl ; Interleave zurueckmov al,[MomDrive]call FormatUnitjc FormatError ; Fehler beim Formatieren ?NoFormatError: PrMsg WriteMsglea di,[SectorBuffer] ; MBR erzeugencldmov cx,SecSize/2-1 ; letztes Wort anders!mov ax,dsmov es,axsub ax,ax ; prinzipiell erstmal alles Nullenrep stoswmov word ptr[di],0aa55h ; Gueltigkeitsflag am Endemov al,[MomDrive] ; Geometrietabelle eintragencall GetPTabAdrmov si,dilea di,[SectorBuffer+DrPar_Offset]mov cx,DrPar_Len/2rep movswmov al,[MomDrive] ; Sektor schreibenmov ah,0 ; MBR auf Kopf 0,mov bx,0 ; Spur 0,mov cx,0101h ; Sektor 1lea si,[SectorBuffer]call WriteSectorsjc FormatError ; Fehler beim Schreiben ?Fin: pop es ; Register zurueckpop dipop cxpop bxpop axretFormatError: cmp al,DErr_UserTerm ; Abbruch durch Benutzer ?je Fin ; dann nicht meckernpush ax ; Fehlercode rettenpushfPrMsg NewLinepopfpop axmov ah,[MomDrive] ; Fehlermeldung ausgebencall WrErrorCodejmp FinFormatMsg db "Formatieren...",CR,LF,'$'WriteMsg db "MBR schreiben...",CR,LF,'$'endp;----------------------------------------------------------------------------proc BadTrackpush bxpush sipush dimov al,[MomDrive] ; Zeiger auf Geometrietabellecall GetPTabAdr ; holenmov si,dilea di,[TrackMsg] ; Spurnummer abfragenmov ax,[si+DrPar_Cyls]dec axcall ReadNumbermov bx,axlea di,[HeadMsg] ; Kopfnummer abfragenmov ax,[si+DrPar_Heads]dec axcall ReadNumbermov ah,alpush ax ; sicherheitshalber noch bestaetigenPrMsg ConfirmMsgcall YesNopop axjc NoErrormov al,[MomDrive] ; Spur markierencall MarkBadjnc NoErrorpush ax ; Fehlercode rettenpushfPrMsg NewLinepopfpop axmov ah,[MomDrive]call WrErrorCodeNoError:pop dipop sipop bxretendp;----------------------------------------------------------------------------proc FormTrackpush bxpush sipush dimov al,[MomDrive] ; Zeiger auf Geometrietabellecall GetPTabAdr ; holenmov si,dilea di,[TrackMsg] ; Spurnummer abfragenmov ax,[si+DrPar_Cyls]dec axcall ReadNumbermov bx,axlea di,[HeadMsg] ; Kopfnummer abfragenmov ax,[si+DrPar_Heads]dec axcall ReadNumbermov ah,alpush ax ; Kopf rettenInterLoop: mov al,[si+DrPar_NSecs] ; Interleave-Maximum=Sektorzahl-1dec almov ah,0lea di,[InterleaveMsg] ; Interleave erfragencall ReadNumberor ax,ax ; Null wollen wir nichtjz InterLoopmov cl,al ; Interleave passend ablegenPrMsg ConfirmMsg ; nochmal nachfragencall YesNopop axjc NoErrormov al,[MomDrive] ; Kopf zurueckcall FormatTrackjnc NoErrorpush ax ; Fehlercode rettenpushfPrMsg NewLinepopfpop axmov ah,[MomDrive]call WrErrorCodeNoError:pop dipop sipop bxretendp;----------------------------------------------------------------------------; packt eine Sektorkoordinate ins BIOS-Format; -->Zylinder=BX, Kopf=AH, Sektor=AL; <--Zylinder/Sektor=BX, Kopf=AHproc PackCoordinateshl bh,6or bh,alxchg bl,bhretendpproc UnpackCoordinatexchg bh,bl ; Zylinderbytes in richtige Reihenfolgemov al,bh ; Sektor ausmaskierenand al,00111111bshr bh,6 ; Zylinder korrigierenretendp; berechnet aus einer Sektorkoordinate die lineare Sektornummer; -->Zylinder/Sektor=BX, Kopf=AH, Geometriezeiger=SI; <--Sektornummer=DX/AXproc LinearizeCoordinatepush bxpush cxmov cx,ax ; Kopf rettenmov al,bh ; Zylinder rekonstruierenmov ah,blshr ah,6mov dl,[si+DrPar_Heads]mov dh,0mul dx ; = Anzahl Spuren bis Zylinderbeginnadd al,ch ; Startkopf dazuaddierenadc ah,0 ; bisher hoffentlich nur 16 Bit...mov dl,[si+DrPar_NSecs]mov dh,0mul dx ; = Anzahl Spuren bis Spurbeginnand bl,3fh ; letztendlich Sektor-1 dazudec bladd al,bladc ah,0adc dx,0pop cxpop bxretendpproc MakePartpush bxpush cxpush dxpush sipush dipush esPrMsg ConfirmMsg ; sind wir sicher ?call YesNoljc Endmov al,[MomDrive] ; Laufwerk rekalibrierencall Recalibrateljc PartErrormov al,[MomDrive] ; alten MBR auslesenmov ah,0mov bx,0mov cx,0101hmov si,dsmov es,silea di,[SectorBuffer]call ReadSectorsljc PartErrormov al,[MomDrive] ; Plattengeometrie holencall GetPTabAdrmov si,dilea di,[SectorBuffer+ParTab_Offset] ; an erste Tabelle schreibenmov byte ptr [di+ParTab_BFlag],80h ; Partition aktivcmp byte ptr[si+DrPar_Heads],1 ; nur ein Kopf ?ja MoreHeadsmov bx,1 ; ja: Start auf Zyl. 1, Kopf 0mov ah,0jmp WriteStartMoreHeads: sub bx,bx ; nein: Start auf Zyl. 0, Kopf 1mov ah,1WriteStart: mov al,01h ; Startsektor immer 1call PackCoordinatemov [di+ParTab_FHead],ahmov [di+ParTab_FSecCyl],bxcall LinearizeCoordinate ; linearen Start schreibenmov [di+ParTab_LinSec],axmov [di+ParTab_LinSec+2],dxpush dxpush axmov bx,[si+DrPar_Cyls] ; Ende: Zylinder n-2, Kopf n-1, Sektor nsub bx,2mov ah,[si+DrPar_Heads]dec ahmov al,[si+DrPar_NSecs]call PackCoordinatemov [di+ParTab_LHead],ahmov [di+ParTab_LSecCyl],bxcall LinearizeCoordinate ; Sektorzahl berechnenpop bx ; dazu Start abziehensub ax,bxpop bxsbb dx,bxadd ax,1 ; !!! Laenge=Stop-Start+1adc dx,0mov [di+ParTab_NSecs],axmov [di+ParTab_NSecs+2],dxor dx,dx ; falls >64K Sektoren,jz NoBigDOS ; eine BigDOS-Partitionmov bl,6jmp TypeFoundNoBigDOS: cmp ax,32679 ; ab 32680 Sektoren 16-Bit-FATjb NoFAT16mov bl,04jmp TypeFoundNoFAT16: mov bl,1 ; kleine 12-Bit-PartitionTypeFound: mov [di+ParTab_Type],bladd di,ParTab_Len ; die anderen 3 Partitionen loeschenmov cx,3*(ParTab_Len/2)sub ax,axcldrep stoswmov al,[MomDrive] ; neuen MBR schreibenmov ah,0mov bx,0mov cx,0101hlea si,[SectorBuffer]call WriteSectorsljc PartErrorEnd: pop espop dipop sipop dxpop cxpop bxretPartError: push ax ; Fehlercode rettenpushfPrMsg NewLinepopfpop axmov ah,[MomDrive] ; Fehlermeldung ausgebencall WrErrorCodejmp EndConfirmMsg: db "ACHTUNG! Alle bisherigen Partitionen auf der",CR,LFdb "Festplatte werden gel",OUML,"scht! Fortfahren? $"endp;----------------------------------------------------------------------------proc FormatPartpushamov ax,ds ; wir arbeiten nur im Datensegmentmov es,axPrMsg ConfirmMsg ; vorher nachfragencall YesNoljc Endemov al,[MomDrive] ; Laufwerk rekalibrierencall Recalibrateljc LFormError; Schritt 1: MBR lesenmov al,[MomDrive] ; MBR auslesen, um Partitions-mov ah,0 ; daten zu bekommenmov bx,0mov cx,0101hlea di,[SectorBuffer]call ReadSectorsljc LFormError; Schritt 2: Partitionsdaten in BPB kopierenlea di,[SectorBuffer+ParTab_Offset] ; auf Partitionsdatenmov al,[di+ParTab_Type] ; muss primaere Partition seincmp al,1 ; DOS 2.x FAT12?je ParTypeOKcmp al,4 ; DOS 3.x FAT16?je ParTypeOKcmp al,6 ; DOS 4.x BIGDOS?je ParTypeOKPrMsg InvParTypeMsg ; nichts dergleichen: Abbruchjmp EndeParTypeOK: mov word ptr[BPB_SysID],'AF' ; FAT-Kennung in BPB eintragenmov word ptr[BPB_SysID+2],'1T' ; FAT12/FAT16mov word ptr[BPB_SysID+5],' 'mov ah,'2' ; Annahme FAT12cmp al,1je ParIsFAT12 ; wenn Typ=1, OKmov ah,'6' ; ansonsten FAT16ParIsFAT12: mov byte ptr[BPB_SysID+4],ahmov ax,[di+ParTab_NSecs] ; Sektorzahl in BPB schreibenmov dx,[di+ParTab_NSecs+2]mov word ptr[BPB_NumSecs32],axmov word ptr[BPB_NumSecs32+2],dxor dx,dx ; falls < 64K Sektoren,jz ParIsNotBig ; Groesse auch unten eintragen,sub ax,ax ; ansonsten 0ParIsNotBig: mov [BPB_NumSecs16],axmov ax,word ptr[di+ParTab_LinSec] ; Startsektor umkopierenmov dx,word ptr[di+ParTab_LinSec+2]mov word ptr[BPB_LinStart],axmov word ptr[BPB_LinStart+2],dx; Schritt 3: Partitionsdaten in Partitionstabelle kopieren, damit wir die; linearen Schreib/Lesefunktionen nutzen koennenmov [DrCnt],1 ; nur ein Laufwerk belegtmov ah,[di+ParTab_FHead] ; Startkoordinate ablegenmov bx,[di+ParTab_FSecCyl]call UnpackCoordinatemov [DrTab+DrTab_StartHead],ahmov word ptr [DrTab+DrTab_StartCyl],bxmov [DrTab+DrTab_StartSec],almov ax,[di+ParTab_LinSec]mov word ptr [DrTab+DrTab_LinStart],axmov ax,[di+ParTab_LinSec+2]mov word ptr [DrTab+DrTab_LinStart+2],axmov ax,[di+ParTab_NSecs]mov word ptr [DrTab+DrTab_SecCnt],axmov ax,[di+ParTab_NSecs+2]mov word ptr [DrTab+DrTab_SecCnt+2],axmov al,[MomDrive] ; Laufwerk einschreibenmov [DrTab+DrTab_Drive],almov byte ptr[DrTab+DrTab_BPB],0 ; kein BPB; Schritt 4: konstante Felder in BPB eintragenmov [BPB_SecSize],SecSize ; Sektorgroesse konstant 512 Bytemov [BPB_ResvdSecs],1 ; nur Bootsektor reserviertmov [BPB_NumFATs],2 ; 2 FATs ist DOS-Standardmov [BPB_MediaID],0f8h ; Media-Byte fuer Platten konstantmov al,[MomDrive]call GetPTabAdrmov ah,0mov al,[di+DrPar_NSecs]; Plattenzylinder und -koepfemov [BPB_SecsPerTrk],axmov al,[di+DrPar_Heads]mov [BPB_Heads],axmov al,[MomDrive] ; Plattennummer+80hadd al,80hmov [BPB_PhysNo],axmov [BPB_ExtID],29h ; Erkennung, dass erw. BPB gueltigmov ah,0 ; Seriennummer=Uhrzeitint INT_Clockmov word ptr[BPB_SerialNo],cxmov word ptr[BPB_SerialNo+2],dxlea di,[BPB_Name] ; Name ist leermov cx,11mov al,' 'cldrep stosb; Schritt 5: einige Sachen vom Anwender erfragenDirEntLoop: mov ax,1024 ; mehr ist wohl kaum sinnvolllea di,[DirEntriesMsg]call ReadNumbercmp ax,SecSize/32 ; weniger als ein Sektor ergibtjb DirEntLoop ; keinen Sinnmov [BPB_DirLen],ax ; Anzahl in BPB eintragenmov dx,0 ; Directory-Sektorzahl berechnenmov bx,SecSize/32div bxor dx,dx ; ggfs. aufrundenjz DirLenEveninc axDirLenEven: mov [DirLen],ax; Schritt 6: Clusterlaenge berechnenmov ax,word ptr[BPB_NumSecs32] ; # Sektoren in Datenfeldmov dx,word ptr[BPB_NumSecs32+2] ; und FATs berechnensub ax,[BPB_ResvdSecs]sbb dx,0sub ax,[DirLen]sbb dx,0mov bl,1 ; Annahme: moeglichst wenig Sektoren pro ClusterClusterLoop: or dx,dx ; wenn noch mehr als 64K Cluster,jnz ClusterNxtLoop ; auf jeden Fall zu groсcmp ax,4080 ; bei weniger als 4K Clusternjb ClusterEndLoop ; auf jeden Fall OKcmp [BPB_SysID+4],'2' ; sonst bei FAT12je ClusterNxtLoop ; auf jeden Fall zu vielcmp ax,65510 ; bei FAT16 Vergleich auf 64Kjb ClusterEndLoopClusterNxtLoop: shl bl,1 ; zu viel: Cluster verdoppelnjs ClusterEndLoop ; bei 128 Sektoren/Cluster abbrechenshr dx,1 ; Clusterzahl halbiert sichrcr ax,1jmp ClusterLoopClusterEndLoop: mov [BPB_SecsPerClust],bl ; Ergebnis einschreibenadd ax,2 ; Dummy-Eintraege in FATadc dx,0mov bx,341 ; Anzahl FAT-Sektoren berechnencmp [BPB_SysID+4],'2'jz Cluster12mov bx,256Cluster12: div bxor dx,dx ; Sektorzahl aufrundenjz FATLenEveninc axFATLenEven: mov [BPB_SecsPerFAT],ax ; Anzahl FAT-Sektoren einschreiben; Schritt 7: Bootsektor aufbauenPrMsg WrBootSectMsglea di,[SectorBuffer]cldmov al,0ebh ; Dummy-Sprung einschreibenstosbmov al,0fehstosbmov al,90hstosbmov ax,'ES' ; OEM-ID einschreibenstoswmov ax,'DC'stoswmov ax,'IR'stoswmov ax,'EV'stoswlea si,[BPBBuffer] ; BPB einschreibenmov cx,BPB_Lengthrep movsbmov cx,SectorBuffer+SecSize ; Rest vom Bootsektor nullensub cx,dimov al,0rep stosbmov ax,0 ; Bootsektor ist log. Sektor 0mov dx,axmov bl,0 ; Partition 0call TranslateParamsmov cl,1 ; nur ein Sektorlea si,[SectorBuffer]call WriteSectorsljc LFormError; Schritt 8: Directory & FATs ausnullenlea di,[SectorBuffer] ; Sektorpuffer wird benutztmov cx,SecSize/2cldsub ax,axrep stoswPrMsg WrFATMsgmov ax,[BPB_ResvdSecs] ; Startsektor FATs holensub dx,dxlea si,[SectorBuffer]mov cx,[BPB_SecsPerFAT]add cx,cx ; beide FATs nullenFATZeroLoop: push ax ; Sektornummer und -zahl rettenpush cxpush dxmov bl,0call TranslateParamsmov cl,1call WriteSectorspop dxpop cxpop axljc LFormErroradd ax,1 ; naechster Sektoradc dx,0loop FATZeroLooppush ax ; !!! PrMsg zerstoert AX-RegisterPrMsg WrDirMsgpop axmov cx,[DirLen] ; dito fuer DirectoryDirZeroLoop: push axpush cxpush dxmov bl,0call TranslateParamsmov cl,1call WriteSectorspop dxpop cxpop axljc LFormErroradd ax,1 ; naechster Sektoradc dx,0loop DirZeroLoop; Schritt 9: Sektoren testen und FAT initialisierenmov ax,[BPB_ResvdSecs] ; Datensektorbeginn berechnensub dx,dxmov [FAT1Pos],ax ; Beginn 1. FAT hinter Bootsektormov [FAT1Pos+2],dxadd ax,[BPB_SecsPerFAT] ; Beginn 2. FAT hinter 1. FATadc dx,0mov [FAT2Pos],axmov [FAT2Pos+2],dxadd ax,[BPB_SecsPerFAT]adc dx,0add ax,[DirLen] ; Datenbeginn hinter Directoryadc dx,0mov [DataPos],ax ; diesen Startsektor rettenmov [DataPos+2],dxmov ax,word ptr[BPB_NumSecs32] ; Anzahl Cluster berechnenmov dx,word ptr[BPB_NumSecs32+2]sub ax,[DataPos]sbb dx,[DataPos+2]mov bl,[BPB_SecsPerClust] ; / SecsPerClustermov bh,0div bxmov [ClusterCnt],axcall ClearFATBuffer ; erste Elemente in FAT schreibenmov ah,0ffhmov al,[BPB_MediaID]call WriteFATmov al,0ffhcall WriteFATPrMsg ESCMsgmov ax,[DataPos] ; Schleifenvorbereitungmov dx,[DataPos+2]mov cx,[ClusterCnt]VerifyLoop: push ax ; Zaehler rettenmov bp,cxpush dxmov bl,0 ; immer Laufwerk 0call TranslateParams ; Cluster testlesenmov cl,[BPB_SecsPerClust]test bp,15 ; nur alle 16 Cluster schreibenjnz NoWriteVeripush ax ; Clusternummer ausgebenpush cxPrMsg ClusterMsgmov ax,[ClusterCnt]sub ax,bpadd ax,2 ; erster Datencluster hat Nummer 2mov cl,5call WriteDecPrChar CRpop cxpop axNoWriteVeri: call VeriSectorsmov ax,0 ; Annahme OK (SUB wuerde C loeschen...)jnc Verify_OKmov ax,0fff7hVerify_OK: call WriteFATpop dx ; Zaehler zurueckmov cx,bppop axadd al,[BPB_SecsPerClust]adc ah,0adc dx,0call BreakOnESC ; Abbruch durch Benutzer ?jc Endeloop VerifyLoopcmp [FATBufferFill],0 ; Puffer rausschreibenje NoFATFlushcall FlushFATBufferNoFATFlush:Ende: PrMsg NewLinemov [DrCnt],0 ; sonst kommt jemand ins Schleudern...poparetLFormError: push ax ; Fehlercode rettenpushfPrMsg NewLinepopfpop axmov ah,[MomDrive] ; Fehlermeldung ausgebencall WrErrorCodejmp EndeWriteFAT: push bx ; einen FAT-Eintrag schreibenmov bx,axcall WriteFATNibble ; Bit 0..3 schreibenmov al,bl ; Bit 4..7 schreibenshr al,4call WriteFATNIbblemov al,bh ; Bit 8..11 schreibencall WriteFATNibblecmp [BPB_SysID+4],'2' ; evtl. Bit 12..15 schreibenje WriteFAT12mov al,bhshr al,4call WriteFATNibbleWriteFAT12: pop bxretWriteFATNibble: push bxand al,15 ; Bit 0..3 ausmaskierenjz SkipWriteNibble ; Nullen brauchen wir nicht schreibenmov [MustFlushFAT],1 ; vermerken, dass Puffer nicht genullt istmov bx,[FATBufferFill] ; Bit 1.. enthalten Adresseshr bx,1jnc WriteFATLower ; oben oder unten schreibenshl al,4WriteFATLower: or FATBuffer[bx],alSkipWriteNibble:inc [FATBufferFill]cmp [FATBufferFill],SecSize*2 ; Sektor voll ?jne WriteFAT_NFlushcall FlushFATBufferWriteFAT_NFlush:pop bxretFlushFATBuffer: push bxpush cxpush dxpush sicmp [MustFlushFAT],0 ; nix zu tun ?je SkipFlushDiskmov ax,[FAT1Pos] ; erste FAT schreibenmov dx,[FAT1Pos+2]mov bl,0call TranslateParamsmov cl,1lea si,[FATBuffer]call WriteSectorsmov ax,[FAT2Pos] ; zweite FAT schreibenmov dx,[FAT2Pos+2]mov bl,0call TranslateParamsmov cl,1lea si,[FATBuffer]call WriteSectorsSkipFlushDisk: call ClearFATBuffer ; Zeiger wieder auf 0add [FAT1Pos],1 ; FAT-Sektornummern weiterzaehlenadc [FAT1Pos+2],0add [FAT2Pos],1adc [FAT2Pos+2],0pop sipop dxpop cxpop bxretClearFATBuffer: push cxpush dicldlea di,[FATBuffer]mov cx,SecSize/2sub ax,axrep stoswpop dipop cxmov [FATBufferFill],axmov [MustFlushFAT],alretConfirmMsg db "ACHTUNG! Alle Daten gehen verloren! Fortfahren? $"InvParTypeMsg db CR,LF,"Partition 1 hat ung",UUML,"ltigen Typ oder ist undefiniert!",CR,LF,'$'DirEntriesMsg db "Anzahl Eintr",AUML,"ge im Wurzelverzeichnis (16..1024) : $"WrBootSectMsg db "Schreibe Boot-Sektor...",CR,LF,'$'WrFATMsg db "Initialisiere FATs...",CR,LF,'$'WrDirMsg db "Initialisiere Wurzelverzeichnis...",CR,LF,'$'ESCMsg db "Abbruch mit <ESC>",CR,LF,'$'ClusterMsg db "Teste Cluster $"DirLen dw ? ; # Directory-SektorenClusterCnt dw ?FAT1Pos dw 2 dup (?) ; speichern Sektorzaehler waehrend TestFAT2Pos dw 2 dup (?)DataPos dw 2 dup (?)BPBBuffer: ; Zwischenspeicher fuer BPBBPB_SecSize dw ? ; Sektorgroesse in BytesBPB_SecsPerClust db ? ; Sektoren pro ClusterBPB_ResvdSecs dw ? ; reservierte Sektoren (Bootsektor)BPB_NumFATs db ? ; Anzahl FATsBPB_DirLen dw ? ; Anzahl Eintraege im DirectoryBPB_NumSecs16 dw ? ; Anzahl Sektoren, falls <32 MByteBPB_MediaID db ? ; Media-ErkennungsbyteBPB_SecsPerFAT dw ? ; Sektoren pro FATBPB_SecsPerTrk dw ? ; Sektoren pro SpurBPB_Heads dw ? ; Anzahl KoepfeBPB_LinStart dd ? ; linearer Startsektor auf LaufwerkBPB_NumSecs32 dd ? ; Anzahl Sektoren, falls >=32 MByteBPB_PhysNo dw ? ; physikalische Laufwerks-NummerBPB_ExtID db ? ; Erkennung, daс es ein erweiterter Boot-Record istBPB_SerialNo dd ? ; SeriennummerBPB_Name db 11 dup (?) ; NameBPB_SysID db 7 dup (?) ; SystemerkennungBPB_Length equ $-BPBBuffer ; Laenge BPBFATBuffer db SecSize dup (?) ; Puffer, um FATs aufzubauenMustFlushFAT db ? ; Flag, ob FAT-Puffer geschrieben werden muсFATBufferFill dw ? ; Anzahl Nibbles in FAT-Pufferendp;----------------------------------------------------------------------------globproc DiskMenupush ax ; Register rettenpush cxpush dimov [spsave],sp ; Stack umschaltenmov [sssave],ssmov ax,csmov ss,axlea sp,[Stack]MenuLoop: mov al,[MomDrive] ; Festplatten-Nr. in Kopfmeldung einschreibenadd al,'1'cmp al,'0'jnz DrivePresent ; falls Laufwerk noch undefiniert, - ausgebenmov al,'-'DrivePresent: mov [MenuMsg_Drv],alPrMsg MenuMsgmov al,[MomDrive]cmp al,-1 ; falls <>-1, Geometrie ausgebenje NoDrivePresentcall GetPTabAdr ; dazu Tabelle holenmov ax,[di+DrPar_Cyls]mov cl,5call WriteDecPrMsg CylMsgmov al,[di+DrPar_Heads]mov ah,0mov cl,3call WriteDecPrMsg HeadMsgmov al,[di+DrPar_NSecs]mov ah,0mov cl,3call WriteDecPrMsg SecMsgNoDrivePresent:PrMsg MenuListmov ah,DOS_RdCharint INT_DOSpush axPrChar alPrMsg TwoLinespop axcmp al,'0' ; 0 = Menue verlassenlje MenuEndcmp al,'1' ; 1 = Platte wechselnjne NoSelectDiskmov ah,1 ; Rueckschreiben erlaubtcall SelectDiskjmp MenuLoopNoSelectDisk:cmp al,'2' ; 2 = Geometrie wechselnjne NoChangeGeometrycall ChangeGeometryjmp MenuLoopNoChangeGeometry:cmp [MomDrive],-1 ; fuer alles weitere muс Platte gesetzt seinjne DiskIsSelectedpush axshl ax,8 ; Annahme: Geometrie nicht zurueckschreibencmp ah,'3'je NoWriteBackinc al ; fuer alles ausser low-level schonNoWriteBack: call SelectDisk ; implizit Laufwerk erfragenPrMsg NewLinepop axcmp [MomDrive],-1lje MenuLoop ; wenn immer noch nicht gesetzt, AbbruchDiskIsSelected:cmp al,'3' ; 3 = Platte low-levelnjne NoFormatDiskcall FormatDiskjmp MenuLoopNoFormatDisk:cmp al,'4' ; 4 = Spur formatierenjne NoFormTrackcall FormTrackjmp MenuLoopNoFormTrack:cmp al,'5' ; 5 = Platte prueflesenjne NoBadTrackcall BadTrackjmp MenuLoopNoBadTrack:cmp al,'6' ; 6 = Platte verifizierenjne NoVerifyDiskcall VerifyDiskjmp MenuLoopNoVerifyDisk:cmp al,'7' ; 7 = Partition anlegenjne NoMakePartcall MakePartjmp MenuLoopNoMakePart:cmp al,'8' ; 8 = Partition formatierenjne NoFormatPartcall FormatPartjmp MenuLoopNoFormatPart: PrChar BEL ; alle anderen Angaben anmeckernjmp MenuLoopMenuEnd: mov ss,[sssave] ; Stack zurueckmov sp,[spsave]pop dipop cxpop ax ; Register zurueckretMenuMsg db CR,LF,"SECDRIVE Men",UUML," Platte:"MenuMsg_Drv db '-',CR,LF,'$'CylMsg db " Zylinder,$"HeadMsg db " K",OUML,"pfe,$"SecMsg db " Sektoren",CR,LF,'$'MenuList db CR,LFdb "1 = Platte wechseln",CR,LFdb "2 = Geometrie neu definieren",CR,LFdb "3 = Platte formatieren",CR,LFdb "4 = Spur formatieren",CR,LFdb "5 = Defekte Spuren markieren",CR,LFdb "6 = Platte verifizieren",CR,LFdb "7 = Partition erstellen",CR,LFdb "8 = Partition log. formatieren",CR,LFdb "------------------------",CR,LFdb "0 = Men",UUML," verlassen",CR,LF,'$'spsave dw ?sssave dw ?db 1024 dup (?) ; ProgrammstackStack:endpMomDrive db -1TwoLines: db CR,LFNewLine: db CR,LF,'$'endsection