\documentclass[11pt,a4paper]{article}
\usepackage[german]{babel}
\usepackage[utf8]{inputenc} % can use Umlauts now ü instead of "u
\begin{document}

\title{Bootmanager und FAT--Reparatur: Zehnter Fort(h)schritt ({\ttfamily putdiskimage})}
\shorttitle{Bootmanager und FAT--Reparatur}
\author{Fred Behringer}
\maketitle

\begin{multicols}{2}

Der vorliegende Teil 10 meiner Artikelserie kann als Fortsetzung von
Teil 8 betrachtet werden. In Teil 8 wurde gezeigt, wie man bei einem
PC (bei mir konkret mit AMD--K6--2 als CPU) eine 3.5--HD--Diskette als
Hex--Abbild ,an einem Stück` im RAM unterbringen kann
(\texttt{getdiskimage}). Hier nun folgt ein Programm zum Zurückschreiben auf
die (oder auf eine andere) Diskette (\texttt{putdiskimage}).  Das Ganze spielt
sich im Real--Mode ab, als Zusammenspiel von BIOS, Assembler und
Forth. Es wird kein Int15h, kein DPMI, kein RAM--Management und
insbesondere kein Abstecher in den Protected--Mode benötigt. Zentrales
Mittel ist der (erweiterte) BIOS--Interrupt 13h (hier in der
Schreibversion als 13h/3). Es wird auch kein 32--Bit--Forth--Assembler
gebraucht. Der im 16--Bit--Turbo--Forth enthaltene 16--Bit--Assembler
genügt --- wenn er mit einigen wenigen Ergänzungen versehen
wird. Wichtig für die Analyse ist der mit viel Überlegung entwickelte
32--Bit--Dump--Apparat (\texttt{dump-32}). Selbstverständlich ist vorgesehen, das
Disk\-image im RAM als Arbeitsfeld für Disk--Modifikationen, wie z.B. die
Aufgaben aus Teil 4, zu verwenden. Die Automatisierung der dazu
nötigen Parameter--Eingaben (Spielwiese für High--Level--Forth) soll für
später zurückgestellt bleiben. Ich habe einige Dinge aus Teil 8 hier
noch einmal aufgeführt. Für das Zurückschreiben des Disketten--Images
auf Diskette kommt man damit mit der Eingabe

\verb|forth include bootma10| [ret]

durch, wobei forth.com das 16--Bit--Turbo--Forth--System ist und
\texttt{bootma10.fth} das Programm aus dem Listing des vorliegenden
Artikels. Will man ein vollständiges Programm (zum Lesen, Verarbeiten
und Schreiben) haben, dann gehe man so vor, wie im Abschnitt
,Schnelleinstieg` beschrieben.

Bei den hier entwickelten Mitteln zeigt sich die Stärke von Forth, wo
man ganz schnell Dinge gestalten kann, die (im vorliegenden
Beispielsfall) von Diskcopy (aus dem altehrwürdigen DOS) oder Rawwrite
(z.B. \cite{JN00}) nicht immer erledigt werden können.


\section{Voraussetzungen}

Es mögen die in Teil 8 gemachten Voraussetzungen gelten. Aber auch nur
diese. Weitere werden hier nicht benötigt. Am leichtesten tut man
sich, wenn man das Listing aus Teil 8 mit dem Listing des vorliegenden
Teils 10 zusammenführt und als einheitliches Ganzes
betrachtet. Redundante Definitionen können dabei der Einfachheit
halber beibehaltewn werden. Sie stören nicht.

Ich gehe davon aus, dass ab der in der \texttt{2Variablen imgbuf} aufbewahrten
RAM--Adresse der von (\texttt{getdiskimage}) sektorweise hexadezimal abgelegte
Inhalt einer 3.5--HD--Diskette liegt, die den in Teil 8 \cite{FB1a}
gemachten Voraussetzungen genügt. Natürlich --- und das ist im
vorliegenden Teil volle Absicht --- kann das ein ,intelligent`
abgeänderter Disketten--Image--Inhalt sein! An sich ist es völlig
egal, wo das Disketten--Image für das hier zu entwickelnde
putdiskimage herkommt. Es muss halt so aufgebaut sein, dass es beim
Zurückschreiben eine sinnvolle Diskette ergibt. Die Übertragung des
Disketten--Images aus dem RAM in die ,reale` Diskette ist der
eigentliche Gegenstand des diesmaligen Teils 10 meiner
Artikelserie. imgbuf soll als Punktzahl (32 Bit) eingegeben worden
sein! Der Wert \texttt{2000000.} (Punktzahl!) wäre ein guter Wert für
Eigenexperimente.

Turbo--Forth unterscheidet nicht zwischen Groß-- und
Kleinschreibung. Ich bevorzuge im Vorliegenden die Kleinschreibung.

Sämtlichen Programmteilen liegt die Zahlenbasis hex zugrunde.


\section{Schnelleinstieg}

Es sei \verb|   forth.com| das 16--Bit--Turbo--Forth--System.\\
Es sei \verb|bootma-8.fth| das Forth--Programm aus Teil 8 der Artikelserie.\\
Es sei \verb|bootma10.fth| das Forth--Programm des vorliegenden Teils 10.

Man gebe ein:

\verb|forth include bootma-8 include bootma10| [ret] .

Damit steht dann alles zur Verfügung, um

\begin{enumerate}
\item[(1)] von einer 3.5--HD--Diskette in Laufwerk a: ein Image ins RAM zu
  schreiben,
\item[(2)] das Image zu analysieren und gegebenenfalls zu verändern,
\item[(3)] das Image dann auf (dieselbe oder eine andere) Diskette zu schreiben.
\end{enumerate}

Man erreicht das (beispielsweise) durch Eingabe von:

\begin{enumerate}
\item[(1)] \verb|2000000. getdiskimage|\\ Wert (Punktzahl!) weitgehend beliebig wählbar,
\item[(2)] \verb|2000000. 100. dump-32|\\ Anfangs--Screen (auch \texttt{100.} ist Punktzahl!).
\item[(3)] \verb|2000000. putdiskimage|\\ Zurück. Eventuelle Fehlermeldungen beachten.
\end{enumerate}

\subsection{Achtung}

Das Forthwort \texttt{dump-32} bezieht sich (zumindest in der Voreinstellung)
auf $\mathrm{fs=0}$. Wenn man beim Experimentieren beispielsweise per

\begin{verbatim}
4711 2000000. cc!-32 2000000. cc@-32 
\end{verbatim}

etwas Falsches herausbekommt, hatte sich das Segment fs ursprünglich
wahrscheinlich auf einen anderen Wert als 0 eingestellt. (Bei mir
stellt sich fs gleich nach Beginn auf $\mathrm{fs=f000}$ ein.) Abhilfe schafft
die Eingabe \texttt{0 fs!} vor der eben vorgeschlagenen Überprüfung mit 4711.

\subsection{Schnelle Plausibilitätsüberprüfung}

Um sicherzugehen, dass bei den Eingaben 1 bis 3 ,alles mit rechten
Dingen zugegangen ist,`

gebe man ein: \verb|100000. 100. dump-32|

Bei mir begann dann die erste Zeile des Dumpings rechts mit der
Eingangs--Kennung \dots{}VDISK3.3\dots{} für die RAM--Disk.

Erklärung: Die zweifach includete Programmeingabe des vorausgegangenen
Abschnitts stellt das System auf hex ein (und dabei soll es
bleiben!). Die RAM--Adresse \texttt{100000.} (der Punkt gehört zur Zahl)
enthält das erste Byte des ,Extended Memorys.` Dorthin legt das
DOS--System bei mir normalerweise eine RAM--Disk (von 30\,MB
Länge). Eine Eintragung in der config.sys sorgt dafür. Wenn ich das
Disketten--Image nach \texttt{2000000.} lege, wird die RAM--Disk, wie man sich
leicht ausrechnet, von dem Disketten--Image, welches aus getdiskimage
hervorging, nicht angetastet. Ich kann und konnte also während meiner
Experimente die RAM--Disk voll ausnutzen und alle benötigten Dateien
in der RAM--Disk vorhalten.


\subsection{Die Punkte 1 bis 3 auch auseinanderziehbar}

Man gebe ein:

\verb|forth include bootma-8| [ret] .

Dann: 

\begin{enumerate}
\item[(1)]  \verb|2000000. getdiskimage|

(ohne die Nummerierung und mit Abschluss [ret].) Dann kann man sich das Disketten--Image ansehen, es überprüfen und es gegebenfalls auch abändern per:

\item[(2)] \verb|2000000. 100. dump-32|

und Weiterschalten über die Plustaste, wobei die Änderungen per \texttt{c!-32}
etc. vorgenommen werden können. Dann kann man aus dem ganzen
Forth--System auch ruhig wieder herausgehen:

\item[(2a)] \verb|bye|

Das Disketten--Image bleibt (zumindest bei dem gewählten höheren
Adresswert) erhalten, solange man das DOS--System nicht per Affengriff
(oder sogar per Netzschalter) ausschaltet. Dann kann man eingeben:

\verb|forth include bootma10| [ret] .

Nun ist alles fürs Schreiben auf Diskette vorbereitet. Man lege, so
man will, eine neue Diskette ins Laufwerk und leite das Schreiben ein
durch:

\item[(3)] \verb|2000000. putdiskimage|

\end{enumerate}

\section{Falsifizierung}

Nicht jedem genügt die eben angeführte
Plausibilitätsbetrachtung. Gerade bei solchen Übernahmen von
,Fremdprogrammen` wie dem im vorliegenden Artikel kann sich leicht ein
Abschreibefehler einschleichen. Eine genauere Überprüfung wäre
besser. Natürlich kann man mit noch so genauen Methoden nicht
nachprüfen, ob das vorgeschlagene Verfahren immer zum Ziel führt. Man
kann aber das Vertrauen in das generelle Funktionieren des
(abgetippten oder sonstwie beschafften) Programms erhöhen,
beispielsweise dadurch, dass man die ,geklonte` Diskette wieder
einliest, diesmal aber beispielsweise an die Adresse 3000000. (andere
Werte tun es natürlich auch):

\begin{enumerate}
\item[(1a)] \verb|3000000. getdiskimage|
\end{enumerate}

Und dann kann man die Bytes ab \texttt{2000000.} mit denen ab
\texttt{3000000.} vergleichen. Im Listing habe ich dafür das Forth--Wort
\texttt{falsify} vorgesehen.

Das Wort \texttt{falsify} ist nur einer von vielen denkbaren
Falsifikatoren, aber sicher ein plausibler: Das Image der
Ursprungsdiskette wird Byte für Byte mit dem Image der geklonten
Diskette verglichen. Bei den Bytes aus dem ersten Image, die sich vom
korrespondierenden Byte aus dem zweiten Image unterscheiden, wird ein
Aufaddierer (im Listing heißt er \texttt{falsi})
inkrementiert. Liefert \texttt{falsi} nach Beenden des Vorgangs den
Wert 0, dann ist das Vertrauen in das richtige Funktionieren (des
Klon--Programms) groß. Ganz sicher kann man natürlich nicht sein, denn
es könnten ja beispielsweise sowohl im Lese-- wie auch im
Schreib--Programm die CHS--Reihenfolgen zu CSH vertauscht worden sein
(siehe Bemerkungen in Teil 8), was auf den Wert von falsi keinen
Einfluss hätte. Sicher ist nur, dass im Gegenbeispielsfall (wenn falsi
einen Wert ungleich null liefert) das Klonen nicht erfolgreich
war. Außerdem könnte sich ja auch in den Falsifikator \texttt{falsify}
ein Fehler (beim Abtippen oder schon beim Entwerfen) eingeschlichen
haben. Und das würde das Thema Falsifizierung weiterverkomplizieren:
Kann ein Falsifikator (als Aussage gefasst) in die zu falsifizierende
Aussage einbezogen werden, ohne dass das Ganze, ähnlich der Menge
aller Mengen, die sich selbst nicht enthalten, zu einem Widerspruch in
sich führt.

Liegt ein Fehler vor, dann stellt der von \texttt{falsi} gelieferte
Wert ein Maß dafür dar, wie ,stark` die geklonte Diskette von der
Ursprungsdiskette abweicht. (Diesen Gedanken könnte man natürlich
ausbauen: ,Forth und die Philosophie.`)

Über ,Falsifizierung` (im Popperschen Sinne) kann man sich per ,Google
--- Wikipedia --- Falsifizierung` Informationen verschaffen.


\subsection{Falsifikator für was?}

Ich versuche es einmal mit folgender Formulierung:

Das Forth--Wort \texttt{falsify} (siehe Listing) ist ein Falsifikator für die
Vermutung "`Die durch ad1 und ad2 charakterisierten Disketten--Images
sind zwei Images ein und derselben Diskette."'

\begin{enumerate}
\item Sind die Strings ad1 und ad2 byteweise gleich, dann kann man den
  Satz vom unzureichenden Grund aus der Entscheidungstheorie anwenden
  und sagen, es liegt kein Grund vor, an der eben aufgestellten
  Vermutung zu zweifeln. Sicher sein kann man natürlich nicht: Eine
  beliebige gleichlaufende Umordnung beider Strings würde ja zum
  gleichen Ergebnis führen, und darunter wären auf jeden Fall auch
  solche, die gar keine Images von Disketten sein können. Beispiel:
  ,Null--Images.`

\item Sicher ist aber eines (Falsifizierungsfall): Ist auch nur ein
  einziges Paar von Bytes aus den beiden Disk--Images im RAM
  voneinander verschieden, dann ist unsere Vermutung zu Fall
  gebracht. Dann kann es sich nicht um zwei Images ein und derselben
  Diskette handeln.

\item Das Ganze ist natürlich stark abhängig von einer sauberen
  Definition dessen, was wir unter einem Disketten--Image verstehen
  wollen.
\end{enumerate}


\subsection{Kaputte Diskette wegwerfen?}

Angenommen, das eine Image stammt von einer als einwandfrei erkannten
,Original--Diskette.` Weiterhin angenommen, wir haben damit per
putdiskimage eine Kopie--Diskette erstellt. Und schließlich
angenommen, wir haben von dieser Kopie--Diskette aus
,Sicherheitsgründen` ebenfalls ein Image (,zweites Image`) per
getdiskimage angefertigt. Der Bytepaar--Vergleich läuft in meinem
Programm (kann natürlich auch anders eingerichtet wrden) von höheren
zu niedrigeren Adressen. Es bot sich an, die Adresse des zuletzt
ermittelten Unstimmigkeits--Paars (falls es überhaupt ein solches
gibt) in der Bildschirm--Statistik festzuhalten. Das geschieht denn
auch (siehe Listing). Damit haben wir ein schnelles Mittel an der
Hand, herauszubekommen, ab welchem Byte auf die Image--Werte kein
Verlass mehr ist.


\subsection{Einbettung des Disk--Images in eine Datei im RAM}

Inzwischen habe ich mich über Teil 8 hinaus mit dem ,Handling` des
Images der Diskette (im RAM, zur Aufbewahrung oder/und zur Weitergabe)
beschäftigt und in Teil 9 der Artikelserie \cite{FB1b} Vorschläge
unterbreitet.


\section{Programm--Aufbau}

Dem in Teil 8 Gesagten lag der Leseteil des Interrupts 13h, also
dessen Funktion 2, zugrunde. Hier in Teil 10 ist es der Schreibteil,
also die Funktion 3 von Int 13h. Entsprechend stark ausgeprägt ist die
Analogie des vorliegenden Programms putdiskimage zu getdiskimage aus
Teil 8.


\subsection{Hauptlast im vorliegenden Artikel}

trägt das Zubringer--Wort (putdiskimage), die Klammern gehören zum
Forth--Wort, das vollständig in Forth--Assembler geschrieben ist. Das
High--Level--Wort putdiskimage ruft (putdiskimage) auf und nutzt die
im Forth--System schon vorhandene Organisationsgewalt aus. Es läuft so
ziemlich alles im vorliegenden Teil 10 analog zu dem in Teil 8
Gesagten. Zur Erinnerung darf ich ein paar Erklärungen in Form von
Beispielen (mit konkreten Eingabewerten) aufziehen.


\subsection{\ttfamily 2000000. getdiskimage}

legt ein Disketten--Abbild nach Adresse \texttt{2000000.} --- der Punkt gehört
zum Forth--Wort. Das zugrunde gelegte Turbo--Forth ist ein
16--Bit--System. Eine 3.5--HD--Diskette fasst 1.44 Megabyte. Mit
(einfachgenauen) 16--Bit--Zahlen für die Adressen komme ich also (auch
schon wegen des begrenzten PC--RAM--Bereichs) nicht
durch. Punktzahlen, wie die eben genannte, sind doppeltgenau (32 Bit
breit). Über mögliche RAM--Organisationen (wie beim Aufbau von
Dateisystemen) habe ich hier (immer noch) nicht weiter
nachgedacht. Ich bewege mich mit Turbo--Forth in einem DOS--System und
agiere nach dem Motto: Mein RAM gehört mir und ich kann damit machen,
was ich will. (Übrigens befolgt ja DOS ein solches Motto mit
.com--Dateien, die bei Aufruf (zunächst einmal) den gesamten
PC--RAM--Speicher zur Verfügung gestellt bekommen, auch.) \texttt{2000000.} ist
ein leicht merkbarer ,runder` Wert. Ich habe mit Erfolg auch mit
anderen Werten experimentiert. (Der Eingabe--Parameter ist eine
Punktzahl, doppeltgenau, also 32 Bit breit. Den Punkt nicht
vergessen!)


\subsection{High--Low--Vertauschung in Forth}

Man beachte die bei doppeltgenauen Zahlen (Punktzahlen) üblicherweise
vorzufindende Vertauschung von höherwertigem und niederwertigem
Anteil! Formt man aus einer Turbo--Forth--Punktzahl (z.B. aus dem
Inhalt von imgbuf) dann eine 32--Bit--Assembler--(Ganz--)Zahl (wie
beispielsweise zum Einlagern in das CPU--Register eax), dann muss aus
der Punktzahl erst eine Little--Endian--Zahl gemacht werden!


\subsection{Nachträgliche Veränderungen am Disk--Image}

lassen sich mit den über \texttt{dump-32} gewonnenen
Adress--Informationen per \texttt{!-32}, \texttt{@-32} etc. gezielt
vornehmen. Wegen näherer Erklärungen vergleiche man das in Teil 8
Gesagte. Will man solche Veränderungen per \texttt{dump-32}
überprüfen, dann achte man darauf, vorher (oder zumindest
zwischendurch) $\mathrm{fs = 0}$ zu setzen (zu erreichen über 0 fs!),
da \texttt{dump-32} (allerdings nur im Default--Fall) mit einem
nullgesetzten Segment fs arbeitet. (Im Real--Mode berücksichtigt das
System die Segment--Register fs und gs nur 16 Bit breit.)


\subsection{Ich verwende eine 16/32--Bit--Mischung}

Will man beispielsweise den Disk--Spuren--Puffer trackbuf komfortabel
über \texttt{dump-32} auslesen (statt einfach über das in Turbo--Forth
eingebaute dump), dann lese man sich vorher den Abschnitt mit der
gleichen Überschrift in Teil 8 und die daran anknüpfenden Abschnitte
aufmerksam durch!


\subsection{Liefert {\ttfamily putdiskimage} des vorliegenden Teils 10
  einen Schreibfehler,}

dann wird der Schreibversuch für die gerade anstehende Disketten--Spur
wiederholt. Nach drei hintereinander aufgetretenen Schreibfehlern wird
das Programm abgebrochen. Am Bildschirm wird beim Aussprung dann die
erreichte Seite, die erreichte Spur, die Adresse des zuletzt
übertragenen Bytes und die Angabe, ob ein Fehler vorliegt oder nicht,
angezeigt.


\section{Abschließendes Experiment mit Nulldiskette}

Ich habe eine voll beschriebene DOS--Diskette ins Laufwerk a: gelegt und mein Gesamtsystem aufgerufen:

\begin{enumerate}
\item[(1)] \verb|forth include bootma-8 include bootma10| [ret] 
\item[(2)] \verb|2000000. getdiskimage    | [ret] $\longrightarrow$ Kein Lesefehler
\item[(3)] \verb|2000000. 3000000. falsify| [ret] $\longrightarrow$ \texttt{151b8e} unstimmige Bytepaare
\item[(4)] \verb|3000000. putdiskimage    | [ret] $\longrightarrow$ Kein Schreibfehler
\item[(5)] \verb|2000000. getdiskimage    | [ret] $\longrightarrow$ Kein Lesefehler
\item[(6)] \verb|2000000. 3000000, falsify| [ret] $\longrightarrow$ Kein unstimmiges Bytepaar
\end{enumerate}


\subsection{Interpretation}

Alle Bytes, insbesondere auch die ab \texttt{2000000.} bis
\texttt{2161f00.} und die ab \texttt{3000000.} bis \texttt{3161f00.}
waren anfangs null. In Punkt 2 wurde ein Disk--Image nach
\texttt{2000000.} gelegt. Das Falsifizieren in Punkt 3 lieferte nicht
die Höchstzahl an unstimmigen Bytepaaren (\texttt{161f00}): Die
Diskette enthielt ja auch Nullbytes --- und die wurden mit 0
verglichen, was zu stimmigen Bytepaaren führte. In Punkt 4 wurde eine
,Nulldiskette` hergestellt (alle Bytes, aber auch wirklich alle,
gleich 0)! Davon wurde in Punkt 5 ein Disk--Image angefertigt und nach
\texttt{2000000.} gelegt. Und das Falsifizieren in Punkt 6 ließ
erkennen, dass die Diskette jetzt tatsächlich zur Nulldiskette
geworden war.


\subsection{Diskette schreddern}

Der ursprüngliche Disketten--Inhalt, oh Schreck, war natürlich weg
;--) War aber nicht weiter schlimm, da das ja sowieso eine
Experimentier--Diskette war. Ich hätte in Punkt 5 und 6 mit
z.B. \texttt{4000000. statt mit 2000000.} arbeiten können --- und das
ursprüngliche Image aus \texttt{2000000.} anschließend
zurückschreiben. Jedenfalls habe ich auf diese Weise gezeigt, wie man
eine Diskette inhaltlich ganz schnell und ganz leicht schreddern
kann. Forth macht's (auch mir als Amateur) möglich! Dazu brauche ich
keine Spezialprogramme aus dem Internet.


\subsection{Turbo--Forth, und kein ZF?}

Auch im vorliegenden Artikel gilt das in Teil 8 im Abschnitt mit der
gleichen Überschrift Gesagte. Das Thema ,Anpassung an ZF` verschiebe
ich auf später.


\begin{thebibliography}{FB99}
\bibitem[FB98]{FB98} Behringer, Fred:   Real--Mode--32--Bit--Erweiterung für Turbo--Forth.
       Vierte Dimension 2/1998.

\bibitem[FB08]{FB08} Behringer, Fred:   Erster Teil meiner VD--Artikel--Serie.
       Vierte Dimension 3/2008.

\bibitem[FB09]{FB09} Behringer, Fred:   Vierter Teil meiner VD--Artikel--Serie.
       Vierte Dimension 2/2009.

\bibitem[FB1a]{FB1a} Behringer, Fred:   Achter Teil meiner VD--Artikel--Serie.
       Vierte Dimension 1/2011.

\bibitem[FB1b]{FB1b} Behringer, Fred:   Neunter Teil meiner VD--Artikel--Serie.
       Vierte Dimension 2/2011.

\bibitem[JN00]{JN00} Newbigin, John:    \url{http://www.chrysocome.net/rawwrite} \dots{} (2000).
\end{thebibliography}
\end{multicols}

\section{Listing}
\begin{quote}
\begin{small}
\listinginput[1]{1}{2011-03/bootma10.fth}
\end{small}
\end{quote}

\end{document}