% Content-encoding: UTF-8 \documentclass[ngerman]{article} \usepackage[utf8]{inputenc} \usepackage{multicol,babel} \setcounter{secnumdepth}{0} \setcounter{tocdepth}{0} \begin{document} \renewcommand{\figurename}{Tabelle} \title{Bootmanager und FAT–Reparatur: Dritter Fort(h)schritt (LBA)} \ifx\shorttitle\undefined\else \shorttitle{Bootmanager 3 — LBA} \fi \author{Fred Behringer} \maketitle Im vorliegenden Artikel werden einige Forth--Worte entwickelt, mit deren Hilfe man bei Bedarf von der CHS--Adressierung zur LBA--Adressierung übergehen kann. \begin{multicols}{2} \section{Ein Wort vorweg über Turbo--Forth und \texttt{ANSI.SYS}} Noch unter DOS 6.2 gab es den Geräte--Treiber \texttt{ANSI.SYS}, der in der \texttt{CONFIG.SYS} per \texttt{DEVICE=ANSI.SYS} eingebunden wurde und der System--Attribute über \emph{Escape--Sequenzen} zu steuern gestattete. Im Laufe der Zeit bin ich immer wieder dazu übergegangen, Turbo--Forth auch unter FreeDOS oder DOS 7.0 (Win 95) oder DOS 8.0 (Win 98) oder in der DOS--Box von Windows ME zu verwenden, und ich habe mich immer wieder über die Meldung \emph{Falsche DOS--Version} geärgert und darüber, dass das \texttt{ANSI.SYS} aus DOS 6.2 nicht akzeptiert wurde. Turbo--Forth läuft dann trotzdem, aber die Escape--Sequenzen werden nicht mehr ausgeführt, sondern am Bildschirm in nicht verständlichen Buchstaben direkt angezeigt. Noch im ersten Teil meiner Artikelserie habe ich für solche Fälle empfohlen, die \texttt{ATTRIBUTS OFF} zu schalten. Das wiederum kann ZF nicht vertragen: ZF kennt keine \texttt{ATTRIBUTS}. Also empfahl ich, \texttt{ATTRIBUTS OFF} im Listing per \verb|\| auszukommentieren. In Turbo--Forth wird von \texttt{ANSI.SYS} hauptsächlich das \emph{fettgedruckte} OK oder die \emph{fettgedruckte} Fehlermeldung hinter \verb|ABORT"| verwendet. An sich kein großes Problem: Man kann ja ohne Weiteres auch darauf verzichten. Aber schade ist es eben doch. Und auch auf reiner DOS--Ebene (außerhalb von Turbo--Forth) verwende ich ANSI.SYS zur Angabe der Uhrzeit oben rechts auf dem Bildschirm und auf Windows--DOS--Box--Ebene zur individuellen Gestaltung des Prompt--Zusatzes der Art von \emph{Zurück zu Windows über EXIT}. Ich hätte mir immer wieder mal ein ANSI.COM gewünscht, einen Escape--Sequenzen--Treiber, der an beliebiger Stelle (auch nachträglich) aufgerufen werden kann (beispielsweise in der \texttt{AUTOEXEC.BAT}) und der das Turbo--Forth--System, an das ich mich gewöhnt habe, nicht verstümmelt. Ich wurde nie das Gefühl los, irgendwo mal etwas über ein solches \texttt{ANSI.COM} gelesen zu haben. Das ständige Halbwissen, das man mit sich herumschleppt, und der gelegentliche Drang, in den eigenen bisherigen Arbeiten herumzustöbern, hat mir (auch bei diesem Problem wieder) geholfen. (Schade, dass ich dazu im vorliegenden Fall ein geschlagenes Jahr gebraucht habe.) Also: \texttt{ANSI.COM} von Michael J.\ Mefford aus dem PC Magazine des Jahres 1988 heißt die Lösung, entwickelt 1988 (als von Turbo--Forth und ZF noch kaum die Rede war)! Sie funktioniert prima! Und damit sind meine Bemerkungen aus dem ersten Artikel dieser Serie über \texttt{ATTRIBUTS OFF} hinfällig: Man google sich zu den ersten 10 Eintragungen (von 13 Millionen!) durch und beschaffe sich \texttt{ANSI.COM}! (Googlen ist eine schöne Sache, wenn man erst einmal genau weiß, was man eigentlich sucht.) Ganz nebenbei wird mit \texttt{ANSI.COM} noch ein weiteres Problem gelöst: Wie will man denn beispielsweise unter Windows ME einen DOS--Geräte--Treiber einbauen? In der CONFIG.SYS? Darauf reagiert doch ME gar nicht! Aber \texttt{ANSI.COM}, als ganz gewöhnliches DOS--Programm nachträglich eingebracht (von XP rede ich ja nicht), wird in der DOS--Box von ME sauber ausgeführt. Allerdings muss man \texttt{ANSI.COM} bei jedem Abstecher zur DOS--Box erneut aufrufen! Von XP habe ich hier nicht gesprochen! Aber die Welt besteht ja nicht nur aus XP. Und die Forth--Welt schon gar nicht. Eine ASM--Fassung von \texttt{ANSI.SYS} oder \texttt{ANSI.COM}, also den Quelltext, habe ich bei meiner Übung im Googlen auch gefunden! Mal sehen, vielleicht mache ich mir eine Forth--Fassung daraus. Übung macht den Meister! \section{Eigentliche Einleitung} Im ersten und zweiten Teil dieser Artikelserie habe ich über die Hauptpartitionstabelle (den Master--Boot--Record: MBR) nachgedacht, über die Partitionstabellen der logischen Laufwerke der erweiterten Partition und über die zu den primären Partitionen und den logischen Laufwerken gehörigen Bootsektoren. (Jedes logische Laufwerk hat neben dem \emph{Bootsektor} auch eine eigene \emph{Partitionstabelle}. Das System hangelt sich zum gewünschten logischen Laufwerk von Partitionstabelle zu Partitionstabelle durch.) Ich durfte mich darüber wundern, dass die (bei mir) jenseits der DOS--8GB--Grenze liegende primäre Partition mit Windows ME etwas aus der Reihe fiel: Ihre Adresse (man prüfe das nach) ließ sich mit den von mir angebotenen Forth--Worten (getsect) und (putsect) nicht ermitteln. Im vorliegenden Artikel gehe ich der Frage nach, warum nicht: Mit der bis zu einer Plattenkapazität von 8 GB funktionierenden CHS--Adressierung der (physikalischen) Sektoren lässt sich das nicht machen. Da müssen \emph{logische} Sektoren her, da muss die LBA--Adressierung angreifen. Natürlich muss bei alldem gesichert sein, dass das BIOS die \emph{erweiterten Interrupt--13h--Funktionen} (41h--48h) überhaupt verarbeiten kann. (Die ganz frühen PCs können das nicht.) Auf meiner hier zu besprechenden Experimentieranlage ist der erweiterte Int13h vorhanden, schon deshalb, weil ich ja sonst die (bei mir) 5 GB große (primäre) ME--Partition beim Installieren von Windows ME gar nicht so weit nach hinten, nämlich ans Ende der (ansonsten für meine Experimente ausreichend großen) 20--GB--Platte, hätte legen können. Was mich im vorliegenden Teil 3 meiner Serie über Festplattenpartitionen (über das FAT--Dateisystem und dergleichen) interessiert, ist also die LBA--Adressierung. Das ist insbesondere der \emph{erweiterte Interrupt 13h} mit den Funktionen AH=41h bis AH=48h, und da ganz besonders die beiden Funktionen AH=42h (extended reading) und AH=43h (extended writing). (Feinheiten der Absicherung gegen mögliche Eingabe--, Lese-- oder Schreibfehler lasse ich weg. Es geht mir um das Gerüst. Alles Fehlende lässt sich in Forth ja leicht nachträglich einbauen.) Die LBA--Sektoren werden über die gesamte Festplatte hinweg von 0 bis zum Höchstsektor der Platte hochgezählt (\emph{logische} oder \emph{lineare} Block--Adressierung). Ich will versuchen, den Zusammenhang zwischen der (älteren) CHS--Adressierung (über den Interrupt 13h mit vor allen Dingen den Funktionen AH=2 und AH=3) und der LBA--Adressierung plausibel zu machen. Im vorliegenden Artikel soll dementsprechend über den Einbau der Funktionen 42h und 43h des erweiterten Interrupts 13h in eine Forth--Umgebung (ausprobiert mit Turbo--Forth und ZF) gesprochen werden. \section{Eine Lanze brechen für Turbo--Forth} Alle Entwicklungsarbeiten (in den VD--Artikeln 1 bis 3 zum vorliegenden Thema) habe ich in Turbo--Forth (TF) durchgeführt und mit ZF überprüft. TF und ZF haben den Vorteil, dass man das System nicht erst um Erlaubnis zu bitten braucht, wenn man den vollen Zugriff (\emph{Administrator--Rechte}) auf die eigene Maschine haben möchte. TF und ZF haben aber den Nachteil, dass sie nur in 16--Bit--Breite arbeiten. Bei der LBA--Adressierung reicht das nicht, so dass mit \emph{doppelter Genauigkeit} gearbeitet werden muss. \section{Konvertierung von CHS nach LBA (Logical Block Addressing)} Für den Fall, dass es interessieren sollte, von welcher Art von \emph{Festplatte} ich rede: Meine Betrachtungen beziehen sich auf IDE--Platten. Eine vereinfachte Darstellung derer Wirkungsweise läuft wie folgt: Eine Festplatte besteht aus einer oder mehreren Scheiben. Jede Scheibe hat zwei Seiten. Jeder Scheibenseite (die zu 0/1 der ersten Scheibe, 0/1 der zweiten Scheibe usw. durchnummeriert werden) ist genau ein Schreib/Lese--Kopf (head) zugeordnet. Bei der Festplattenverwaltung zur eindeutigen Adressierung der einzelnen Sektoren (siehe gleich) wird nur von \emph{Kopf} gesprochen, auch wenn in der bildlichen Vorstellung eigentlich \emph{Scheibe} (oder zumindest \emph{Scheibenseite}) gemeint ist. Die Köpfe (also eigentlich die Scheibenseiten) werden vom BIOS in konzentrisch angeordnete \emph{Spuren} (tracks) unterteilt. Jede Spur enthält eine bestimmte Anzahl von \emph{Sektoren} (sectors), eine Zahl, die von Spur zu Spur gleich bleibt. Jeder Sektor enthält eine bestimmte Zahl von Bytes. Üblich sind 512 Bytes pro Sektor. Die Daten werden sektorweise gelesen oder geschrieben. Die auftretenden Zahlen für Köpfe, Spuren und Sektoren geben nicht unbedingt die wirklichen Verhältnisse wieder. Sie sind bei der Festplatte nur für die Verwaltung wichtig. Die eigentliche \emph{Geometrie} der Festplatte kann (vom Hersteller) durch (interne) Umrechnungs--Vorrichtungen angepasst worden sein. (Man braucht es also nicht wörtlich zu nehmen, wenn man vom BIOS--Setup erfährt, dass die Platte 255 Köpfe hat --- und man braucht die Platte auf gar keinen Fall auseinanderzunehmen, um nachzuprüfen, ob das wirklich stimmt ;-) Man hätte sich auch vorstellen können, dass bei der Zählung der Sektoren erst alle Spuren einer Scheibenseite durchlaufen werden, dann die nächste Seite, dann die nächste Scheibe usw. Das ist nicht der Fall. Es wird eine neue Einteilungs--Einheit eingeführt, die des \emph{Zylinders} (cylinder): Alle (übereinanderliegenden) Spuren derselben (auf die jeweilige Scheibenseite bezogenen) Nummer gehören zu ein und demselben Zylinder. Bei der Zählung (dem Durchnummerieren) der Sektoren werden erst die Sektoren der ersten Spur der ersten Scheibenseite drangenommen, dann die der ersten Spur der zweiten Scheibenseite, dann die der ersten Spur der ersten Seite der zweiten Scheibe und so weiter, bis der erste Zylinder durch ist. Dann dasselbe Zählverfahren in Bezug auf den zweiten Zylinder. Und so weiter. (Wenn man liest, dass ein \emph{Kopf} 63 Sektoren hat, dann ist das entsprechend zu verstehen: Ich komme in meiner Vorstellung gut durch, wenn ich bei Ordinalzahlen (bei Nummern) von \emph{Kopf} rede, bei Kardinalzahlen (bei Anzahlen) aber von \emph{Spur}: Sektor 5 bei Kopf 4, aber 63 Sektoren pro Spur. Warum aber, so frage ich, hätte man nicht gleich von Spuren statt von Köpfen reden können? \emph{Spur 4} nimmt sich bestimmt nicht schlechter aus als \emph{Kopf 4}. Aber über \emph{63 Sektoren pro Kopf} stolpert natürlich jeder. Die \emph{Spuren} müssten eben von oben nach unten gezählt werden, und nicht in konzentrischer Reihenfolge. Und wäre das schlimm? Bei den \emph{Köpfen} kommt ja noch hinzu, dass sie alle gleichzeitig auf die Festplatte zugreifen (können), in der Zählung aber sequentiell eingeordnet werden müssen. Lange Rede, kurzer Sinn: Es ist letztendlich völlig egal, wie man sich den Aufbau einer Festplatte vorstellt, wichtig sind die Zahlen, die den fest eingebürgerten Begriffen \emph{Zylinder}, \emph{Kopf} und \emph{Sektor} (engl. (C)ylinder, (H)ead, (S)ector) zugeordnet sind. Und wenn man nun mal beim Begriff \emph{Kopf} (head) bleibt, braucht man nicht mehr über den Begriff \emph{Spur} zu philosophieren. Der ist (für die Plattenverwaltung) überflüssig. Dann hat eben beispielsweise \emph{jeder Kopf 63 Sektoren} --- und beim Begriff SPT (sector per track) im Wikipedia wäre eben nicht, wie dort geschehen, \emph{Track} gleich \emph{Zylinder} zu setzen, sondern gleich \emph{Kopf}. (Mir geht es bei der Entwicklung eines Forth--Wortes zur Umrechnung von CHS nach LBA (siehe Listing) um ein Verstehen der zugehörigen Formel --- und da ist die Angabe \emph{SPT : Sektoren/Track (Track \^{ }= Zylinder)} im Artikel \emph{Cylinder Head Sector} \url{http://de.wikipedia.org/wiki/Cylinder_Head_Sector} aus der freien Enzyklopädie Wikipedia nicht sehr hilfreich. Eben nicht SPT = Sektoren pro Zylinder! SPT = Sektoren pro Spur! Und das heißt SPT = Sektoren pro Kopf!) Zu beachten ist bei der CHS--Zählweise (und das ist sehr wichtig!), dass Zylinder und Kopf bei 0 beginnen, die Sektor--Zählung aber bei 1. Der Master--Boot--Record (MBR) hat also die Adresse C--H--S = 0--0--1 (und nicht etwa 0--0--0). In der LBA--Zählweise dagegen (siehe gleich) hat der MBR tatsächlich die Nummer 0. (Man versuche, mit dem ehrwürdigen DEBUG aus DOS an den MBR heranzukommen, nicht durch Nachbilden der im Vorliegenden entwickelten Assembler--Befehle, sondern über den DEBUG--Load--Befehl \texttt{l} (kleines l)!) Bei den frühen Festplatten stieß man mit der CHS--Adressierung bald an Grenzen: Unter Beibehaltung der Kompatibilität musste etwas Neues eingeführt werden, ohne das \emph{Alte} deshalb gleich aufgeben zu müssen. Dieses Neue heißt LBA (Logical oder Linear Block Addressing). Dabei gibt es nur noch \emph{Sektoren} (keine Köpfe und Zylinder mehr), und die werden die ganze Platte hindurch durchnummeriert, auch über eventuell bestehende Platten--Partitionen hinweg. Zur besseren Unterscheidung werden Sektoren der CHS--Betrachtungsweise auch \emph{physikalische} Sektoren genannt, Sektoren der LBA--Betrachtungsweise \emph{logische} Sektoren. Die Zählung der logischen Sektoren beginnt bei 0 ! Der MBR hat also die LBA--Nummer 0. Zum besseren Verständnis möchte ich die folgenden Bezeichnungen einführen: \begin{tabular}{lcl} C &=& Zylindernummer\\ H &=& Kopfnummer\\ S &=& Sektornummer (phys.\ Sektor)\\ s &=& Sektornummer (log.\ Sektor)\\ S/K &=& Sektoren pro Kopf\\ K/Z &=& Köpfe pro Zylinder\\ \end{tabular} Bei gegebener Zylindernummer C, Kopfnummer H und Nummer S des physikalischen Sektors berechnet sich die Nummer s des zugeordneten logischen Sektors zu: $$ s = ((C*K/Z + H) * S/K) + S - 1 $$ Dabei liefert \begin{footnotesize} \begin{tabular}{llcrl} Zylinder $\!\!\!$&$C$$\!\!\!$&:&$\!\!\!$$C * K/Z * S/K$&$\!\!\!$logische Sektoren,\\ Kopf $\!\!\!$&$H$$\!\!\!$&:&$\!\!\!$$H * S/K$&$\!\!\!$logische Sektoren und\\ Phys. Sektor$\!\!\!$&$S-1$$\!\!\!$&:&$\!\!\!$$s$&$\!\!\!$logische Sektoren.\\ \end{tabular} \end{footnotesize} (Bei $s$ zählt 0 mit, bei $S$ nicht.) \section{Der zugrundegelegte Computer als Beispiel} Das BIOS meiner (hier besprochenen) Anlage gibt beim Aufrufen des BIOS--Setups für die in Frage stehende Festplatte 2491 Zylinder, 255 Köpfe und 63 Sektoren aus. Das weiter unten erwähnte Programm \emph{Partition Table Doctor} liefert als Anzahl logischer (also LBA--) Sektoren den Wert 40017915 (alle Angaben dezimal). Geht man von der üblichen Zahl von 512 Bytes pro Sektor aus, dann entspricht der Wert 40017915 * 512 in etwa einer Festplatten--Kapazität von 20 Gigabyte. Das BIOS--Setup liefert für \emph{size} den Wert 20490 MB . Geht man die Nummerierung der LBA--Sektoren durch, dann erhält man: \begin{center} \begin{tabular}{rrrr} Cyl. & Head & Sector & LBA--Sector\\ 0--2490 & 0--254 & 1--63 & 0--40017914\\ 0 & 0 & 1 & 0 \\ 0 & 0 & 2 & 1 \\ . & . & .. & .. \\ 0 & 0 & 63 & 62 \\ 0 & 1 & 1 & 63 \\ 0 & 1 & 2 & 64 \\ . & . & .. & ... \\ 0 & 1 & 63 & 125 \\ 0 & 2 & 1 & 126 \\ 0 & 2 & 2 & 127 \\ . & . & .. & ... \\ 0 & 2 & 63 & 188 \\ 0 & 3 & 1 & 189 \\ . & . & .. &..... \\ 0 & 254 & 1 &16002 \\ 0 & 254 & 2 &16003 \\ . & ... & .. &..... \\ 0 & 254 & 63 &16064 \\ 1 & 0 & 1 &16065 \\ 1 & 0 & 2 &16066 \\ . & . & .. &..... \\ 1 & 0 & 63 &16127 \\ . & . & .. &..... \\ \end{tabular} \end{center} Der \emph{erste} logische Sektor hat die Nummer 0 und entspricht dem CHS--Wert 0--0--1. Das geht dann die Reihe der physikalischen Sektoren entlang so durch bis zum logischen Sektor 62, der dem CHS--Wert 0--0--63 entspricht. Dann wird (bei gleichem Zylinder) zum nächsten Kopf übergegangen: Der logische Sektor 63 (also der 64. LBA--Sektor) entspricht dem CHS--Wert 0--1--1 (Der CHS--Sektor beginnt wieder bei 1, und nicht etwa bei 0). Und wieder alle physikalischen Sektoren durch bis zum logischen Sektor 125, der dem CHS--Wert 0--1--63 entspricht. Der logische Sektor 126 entspricht dem CHS--Wert 0--2--1. Und so weiter und so fort. Wenn alle Kopfnummern ausgeschöpft sind, wird zum nächsten Zylinder übergegangen. Der logische Sektor 16127 entspricht dem CHS--Wert 1--0--63, usw. Ich möchte nicht verschweigen, dass mir bei der Ermittlung und Überprüfung der hier wiedergegebenen Werte das Programm \emph{Partition Table Doctor} der PTDD Group at \url{http://www.ptdd.com} (selbstgebrannte Live--CD aus einer ganz kleinen ISO--Datei der Begleit--DVD von c't 24/2008) eine große Hilfe war. Allerdings habe ich auch hier wieder für meine FAT--Reparatur--Absichten einige Dinge schmerzlich vermisst. Aber gerade dieser Umstand zeigt mir erneut, eine wie sehr viel noch größere Hilfe mir ein Forth--Werkzeugkasten voller entsprechender Hilfsmittel zur eigenen Gestaltung wäre. Ich befinde mich auf dem besten Wege, mir einen solchen selbst zusammenzustellen, und habe vor, diesen Gedanken zügig weiterzuverfolgen. Nebenbei bemerkt: Im VD--Heft 4/2008 wurde in einem der dortigen Artikel über die Suche nach einer geeigneten DOS--Emulation für ein DOS--freies System nachgedacht. Die ebenerwähnte Live--CD baut auf einer abgespeckten FreeDOS--Version auf. FreeDOS kann man sich beispielsweise von \url{http://www.freedos.org} besorgen. Es liefert dem PC eine vollwertige, der MS--DOS--Version 6.2 mehr als ebenbürtige DOS--Umgebung mit \texttt{a:} als Laufwerk. Ein eventuell schon vorhandenes reales (Disketten--)Laufwerk \texttt{a:} wird dann nach \texttt{b:} verbannt. Noch nebenbeier bemerkt: Traue nie einem Programm, das du nicht selbst vermurkst hast! Das Laufwerk b: (5,25") lasse ich normalerweise als im BIOS abgemeldet mitlaufen. Es lag auf der Hand, dass ich mal schnell wissen wollte, was passiert, wenn ich b: im BIOS wieder einschalte. Wird dann \texttt{a:} nach \texttt{b:} und daraufhin \texttt{b:} nach --- ja wohin eigentlich --- verschoben? Nichts passiert! Die FreeDOS--basierte Partition--Table--Doctor--Live--CD bootet dann einfach nicht. Und wenn ich beide Disketten--Laufwerke im BIOS abhänge? Dann erhält die DOS--Emulation wie gehabt den Laufwerkbuchstaben \texttt{a:}. Man lernt nie aus! Schöner wäre es gewesen, und es hätte mir Arbeit erspart, wenn ich diese Informationen gleich zu Anfang hätte nachlesen können. Man stelle mir nicht die Frage: \emph{Wozu willst du das eigentlich wissen?} Ich will es halt wissen! Und mit Forth als schnell anpassbares Analyse--Werkzeug darf ich mir eine solche Haltung auch erlauben. \section{Konvertierung von LBA nach CHS} Natürlich kann man die ganze Angelegenheit auch umkehren: Von LBA nach CHS. Damit könnte man --- aus welchem Grund auch immer --- ein mit den INT13h--Funktionen 42h und 43h in Assembler erstelltes Sektoren--Lese/Schreib--Programm über die Funktionen 2h und 3h von INT13h neu fassen --- soweit die CHS--Grenze hier nicht eine Schranke setzt. Wie man (durch Vergleich mit der obigen Formel für die Berechnung der logischen Sektornummer LBA aus den CHS--Angaben heraus) leicht nachprüft, lautet die \emph{Umkehrformel}: \begin{eqnarray*} (s+1)/(S/K * K/Z) &=& C + Rest1\\ Rest1/(S/K) &=& H + Rest2\\ Rest2 &=& S\\ \end{eqnarray*} \section{Links} \begin{small} \url{http://de.wikipedia.org/wiki/Cylinder_Head_Sector} \\ \url{http://www.ptdd.com}\\ \url{http://www.freedos.org} \end{small} \end{multicols} \section{Listing} \begin{quote} \listinginput[1]{1}{2009-01/BOOTMA-3.FTH} \end{quote} \vfill \begin{center} \includegraphics[width=0.4\textwidth]{2009-01/Bootsector}\\ nach einer Idee von Jessica Ledbetter (jledbetter@acm.org) \end{center} \vfill \end{document}