\ **************************************************** \ * * \ * BOOTMA-4.FTH * \ * * \ * Zutaten fuer FAT-Reparatur und Bootmaster unter * \ * Turbo-FORTH-83 und ZF * \ * * \ * Fred Behringer - Forth-Gesellschaft - 10.5.2009 * \ * * \ **************************************************** \ ==================================================== \ Bei Arbeiten mit ZF: \ zf fload bootma-4.fth - .fth nicht vergessen! \ attributs off wegnehmen! attributs in ZF unbekannt. \ Ansonsten scheint auch unter ZF alles zu gehen. \ ==================================================== attributs off \ Fuer den Fall, dass kein ANSI.SYS in der \ CONFIG.SYS ist. Oder dann aber ANSI.COM aus dem \ Internet hereingooglen und ins System (in die \ AUTOEXEC.BAT) legen! Bei Arbeiten mit ZF \ auf jeden Fall wegnehmen. hex 210 allot here \ Platz fuer mind. 1 Sektor = 512d Bytes here 0f and - \ sectbuf an Paragraphenanfang 200 - \ Anfang des Sektorpuffers constant sectbuf \ Liefert Adresse des Sektorpuffers \ Sektor-Puffer am Bildschirm anzeigen : showsectbuf ( -- ) sectbuf 200 dump ; \ Nur die ersten 100 Bytes davon anzeigen : showsectbuf100 ( -- ) sectbuf 100 dump ; \ ======================================================================== \ Vorweg: Alle Forth- und DOS-Befehle sind im Vorliegenden von Gross- und \ Kleinschreibung unabhaengig. Das vorliegende Programm BOOTMA-4.FTH ist von \ den bisherigen Programmen BOOTMA-1.FTH bis BOOTMA-3.FTH aus den VD-Heften \ 3/2008 bis 1/2009 unabhaengig. Zur Herstellung einer Hilfsdiskette boote \ man den PC von der Festplatte (beispielsweise unter DOS 6.2) mit dem \ gewuenschten Forth und dem Programm aus dem vorliegenden Artikel. Man lege \ die zu praeparierende Diskette ein und lade das vorliegende Programm (in \ Turbo-Forth per include, in ZF per fload) ein. Danach ist die eingelegte \ Diskette praepariert. Fuer eine unmittelbare Analyse stehen die Worte \ showsectbuf und showsectbuf100 aus Teil 1 dieser Artikelserie und \ natuerlich auch das in Forth eingebaute dump zur Verfuegung. Will man \ daneben auch die bisher entwickelten Forth-Worte aus den Teilen 1 bis 3 der \ vorliegenden Artikelserie zur Verfuegung haben, so wird man den oben \ stehenden Programmteil (bis zur Definition von showsectbuf100), da in den \ Teilen 1 bis 3 schon vorhanden, weglassen. Sowohl das ROM-BIOS im Segment \ F000 wie auch das ins RAM kopierte BIOS lassen sich im System Turbo-Forth \ bequem ueber das segmentuebergreifende ldump analysieren. Wie ZF-Fans das \ machen, muss ich erst noch erkunden. Die zu erstellende Hilfsdiskette \ braucht nicht formatiert, also auch nicht mit irgendeinem Betriebssystem \ versehen zu sein (vergleiche aber unbedingt das weiter unten im Zusammenhang \ mit DEBUG Gesagte). Zum Beweis habe ich eine 3.5"-Diskette (von 720 KB) \ genommen und deren Bootsektor mit den Forth-Hilfsmitteln aus der \ vorliegenden Artikelserie durchgaengig auf 0 gesetzt. Anschliessend habe \ ich diese Diskette unter Turbo-Forth durch INCLUDEn des vorliegenden \ Listings zu einer Hilfsdiskette (zum BIOS-Kopieren ins RAM) umfunktioniert: \ Geht sehr gut. Allerdings nimmt es nicht wunder, dass man bei einer \ solcherart fuer DOS unbrauchbar gemachten Diskette nicht mehr nach Laufwerk \ a: schalten kann ('Allgemeiner Fehler beim Lesen von Laufwerk A'): \ Die diskettenbezogenen (formatspezifischen) Parameter (fuer das \ BIOS-Umkopieren werden sie nicht benoetigt) sind ja jetzt (nach dem 0-Setzen) \ nicht mehr vorhanden. Nimmt man dagegen zur Anfertigung einer \ Umkopier-Hilfsdiskette eine ganz normal von DOS anerkannte Diskette \ (bootbar oder nicht), dann geht es. Ich habe das u.a. mit einer FreeDos-, \ einer DOS-6.2- und einer OS/2-Warp-Diskette ueberprueft. \ ======================================================================== code (getdiskbootsect) ( -- fl ) \ fl <> 0 --> Bootsektor-Lesefehler si push \ si (= ip) momentan freigeben 1 # di mov \ Bei Aussprung: OK, wenn di = 0 3 # si mov \ Zaehler fuer drei Leseversuche ansetzen ds push \ ds --> es es pop begin si dec \ Schleifenzaehler um 1 herabsetzen ah ah xor dl dl xor 13 int \ Diskettensystem zuruecksetzen dx dx xor \ dl = Diskette a:, dh = Seite 0 1 # cx mov \ Spur 0, Sektor 1 sectbuf # bx mov \ bx auf den Anfang des Puffers setzen. 201 # ax mov \ Zum Lesen des Bootsektors 13 int \ Platten-und-Disketten-Interrupt aufrufen. u>= if \ Falls cf = 0, si si xor \ dann Aussprung vorbereiten di dec \ und OK-Indikator auf 0 setzen. then 0 # si cmp 0= \ Sonst di = 1 belassen und Test auf Schleifenende until si pop \ si (= ip) wiederherstellen di push \ Stackwert <> 0 --> Leseversuche vergeblich next end-code : getdiskbootsect ( -- ) (getdiskbootsect) if cr abort" Bootsektor-Lesefehler" then ; \ getdiskbootsect ist eine Spezialisierung von (getsect) aus VD-Heft 3/2008. \ Statt der Kennnummer der ersten Festplatte, also 80, wird die Kennnummer der \ Diskettenstation a:, also 0, eingesetzt. (Fuer ein eventuell noch vorhandenes \ Disketten-Laufwerk b: waere hier 1 einzusetzen.) Einen MBR gibt es bei \ Disketten nicht. Der erste Sektor einer Diskette ist also der Bootsektor. Der \ Bootsektor wird von getdiskbootsect in den Sektorpuffer sectbuf geschrieben \ und kann dort weiterverarbeitet werden. \ Fehlerfrage: Urspruenglich wollte ich in meiner Artikelserie der Einfachheit \ halber eigentlich auf jedwede Fehlerabfrage verzichten. Schliesslich nimmt \ man ja in Forth-Programmen auch bei arithmetischen oder logischen Operationen \ fuer gewoehnlich keine Fehlerueberpruefung vor. Nun habe ich aber beobachtet, \ dass bei einem vereinfachten getdiskbootsect (ohne Mehrfachversuchsschleife \ und Diskettensystemruecksetzung) das Einlesen des Bootsektors nicht klappte - \ und das nicht nur manchmal nicht, sondern nach Einschalten des Computers \ immer nicht. Wurde dagegen getdiskbootsect anschliessend erneut aufgerufen, \ also nach dem Einschalten ein zweites Mal, dann ging es - bei meinen \ Versuchen 'immer'. Frage: Woran liegt das? Habe ich da vielleicht etwas \ Grundsaetzliches nicht beachtet? \ Das gleich folgende Forth-Wort putdiskbootsect mit dem dazugehoerigen \ (putdiskbootsect) ist das Pendant zu getdiskbootsect. Alle Bemerkungen \ uebertragen sich sinngemaess. Der Inhalt des Sektorpuffers sectbuf wird in \ den Bootsektor der im Laufwerk a: liegenden Diskette geschrieben. Eine nicht \ eingelegte Diskette oder eventuelle Schreibfehler werden durch die Meldung \ 'Bootsektor-Schreibfehler' angezeigt. code (putdiskbootsect) ( -- fl ) \ fl <> 0 --> Bootsektor-Schreibfehler si push \ si (= ip) momentan freigeben 1 # di mov \ Bei Aussprung: OK, wenn di = 0 3 # si mov \ Zaehler fuer drei Leseversuche ansetzen ds push \ ds --> es es pop begin si dec \ Schleifenzaehler um 1 herabsetzen ah ah xor dl dl xor 13 int \ Diskettensystem zuruecksetzen dx dx xor \ dl = Diskette a:, dh = Seite 0 1 # cx mov \ Spur 0, Sektor 1 sectbuf # bx mov \ bx auf den Anfang des Puffers setzen. 301 # ax mov \ Zum Beschreiben des Bootsektors 13 int \ Platten-und-Disketten-Interrupt aufrufen. u>= if \ Falls cf = 0, si si xor \ dann Aussprung vorbereiten di dec \ und OK-Indikator auf 0 setzen. then 0 # si cmp 0= \ Sonst di = 1 belassen und Test auf Schleifenende until si pop \ si (= ip) wiederherstellen di push \ Stackwert <> 0 --> Schreibversuche vergeblich next end-code : putdiskbootsect ( -- ) (putdiskbootsect) if cr abort" Bootsektor-Schreibfehler" then ; \ Zunaechst einmal haette ich mir gern eine Colon-Definition gewuenscht, die \ (beispielsweise beim Einlesen per include, bzw. fload) sofort ausgefuehrt \ wird und dann wieder verschwindet. In Turbo-Forth hat das Namenlos-Wort :: \ diese Wirkung. Das Wort :noname aus ANS-Forth waere zwar auch 'namenlos', \ wuerde aber wohl nach seiner Ausfuehrung nicht mehr aus dem Dictionary \ verschwinden. In ZF gibt es keines dieser beiden Worte. In ZF gibt es aber, \ genau wie in Turbo-Forth, das Wort forget. Mit diesem baue ich mir eine \ Hilfskonstruktion, die sowohl in Turbo-Forth wie auch in ZF verwendbar ist \ und die die Wirkung von :: hat. (Statt xxx kann natuerlich jeder andere \ noch nicht verbrauchte Name verwendet werden.) \ Bootsektor der DOS-formatierten Hilfsdiskette nach sectbuf einlesen getdiskbootsect \ Code zum Ueberspringen von 1Eh Bytes an den Anfang von sectbuf schreiben 0eb sectbuf c! 01c sectbuf 1 + c! 090 sectbuf 2 + c! \ Formatspezifische Parameterdaten der eingelegten Diskette ueberspringen und \ dann den Rest des nach den Angaben von Wolfgang Lorenz aus der Zeitschrift \ TOOL (1991) angefertigten Bootsektors nach sectbuf kopieren. 033 0FF 0FA 08E 0D7 0BC 000 07C 0FB 0B8 000 010 08E 0C0 0BE 03D 07C 090 08E 0DF 0B9 058 001 0FC 0F3 0A4 0EA 000 000 000 010 033 0C0 08E 0D8 08B 01E 013 004 083 0EB 040 089 01E 013 004 0B1 006 0D3 0E3 08E 0C3 0BA 000 0F0 08E 0DA 033 0F6 033 0FF 0B9 000 080 0F3 0A5 08E 0DE 0AD 0AD 03B 0C2 075 003 089 05C 0FE 081 0FE 000 004 072 0F1 039 016 0AA 004 075 004 089 01E 0AA 004 0BE 0E0 000 08A 0C7 0E8 044 000 08A 0C3 0E8 03F 000 0BE 0AC 000 0E8 04F 000 033 0C0 08E 0D8 08E 0C0 0BF 003 000 0B8 001 002 0BB 000 07C 0B9 001 000 0BA 080 000 0CD 013 073 01B 032 0E4 0B2 080 0CD 013 04F 075 0E7 0BE 0F3 000 0E8 027 000 032 0E4 0CD 016 0BE 0F0 000 0E8 01D 000 0CD 019 0EA 000 07C 000 000 050 0B1 004 0D2 0E8 0E8 003 000 058 024 00F 004 090 027 014 040 027 02E 088 004 046 0C3 0B8 00D 00E 0CD 010 02E 0AC 022 0C0 075 0F8 0C3 044 061 073 020 052 04F 04D 02D 042 049 04F 053 020 062 065 069 020 024 046 030 030 030 020 077 075 072 064 065 020 061 06E 020 064 069 065 020 053 065 067 06D 065 06E 074 061 064 072 065 073 073 065 020 024 03F 03F 03F 03F 020 075 06D 06B 06F 070 069 065 072 074 02E 00D 00A 00A 000 04C 065 073 065 06E 020 064 065 073 020 042 04F 04F 054 02D 053 065 06B 074 06F 072 073 020 076 06F 06E 020 064 065 072 020 046 065 073 074 070 06C 061 074 074 065 020 06E 069 063 068 074 020 06D 094 067 06C 069 063 068 02E 00D 00A 053 079 073 074 065 06D 02D 044 069 073 06B 065 074 074 065 020 065 069 06E 06C 065 067 065 06E 020 075 06E 064 020 054 061 073 074 065 020 064 072 081 063 06B 065 06E 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 055 0AA \ Hex-Listings wie diese waren zu Zeiten der Home-Computer en vogue. Inzwischen \ sind sie verpoent. Die Tabelle der oben stehenden Hexzahlen schien mir aber \ der schnellste Weg zu sein, an mein Ziel zu gelangen, naemlich mit \ Forth-Mitteln eine Diskette herzustellen, die beim Hochfahren des PCs das \ ROM-BIOS ins RAM kopiert und von dort aus zur Verfuegung stellt. Anliegen \ im vorliegenden Artikel 4 meiner Serie war mir eigentlich die Bearbeitung \ von Disketten-Bootsektoren mit Forth-Mitteln. Es haette nur unnoetig viel \ Platz im VD-Heft gekostet, wenn ich, wie ich es urspruenglich vorhatte, den \ Assembler-Quelltext des Konstruktions-Programms von Wolfgang Lorenz aus der \ Zeitschrift TOOL (1991) hier zuvor erst nach Forth-Assembler uebertragen und \ von dort dann in mein eigenes Hilfsdisketten-Erzeug-Programm eingebaut haette. \ Bei Interesse kann man sich den Ueberblick ueber das hinter der Hex-Tabelle \ stehende Assembler-Programm (nach erfolgreicher Erstellung einer \ Hilfsdiskette) rueckwirkend mit dem DOS-Debugger DEBUG wie folgt verschaffen \ (natuerlich ohne Kommentar-Schraegstriche!): \ DEBUG \ -L 0100 0 0 1 \ -D 0100 02FF \ -U 0100 02FF \ -Q \ Man erhaelt damit die Bildschirmanzeige des Ganzen, den Hex-Dump und das \ disassemblierte Programm. Schoen fuer mich (ich wollte mir das Eintippen \ ersparen) fuer die halbautomatische Uebernahme des Hex-Dumps war die \ Moeglichkeit, unter DOS das von -D erzeugte Debug-Elaborat in eine Textdatei \ zu bannen (von wo aus ich die Hexwerte ueber ein x-beliebiges \ Textverarbeitungssystem uebernehmen konnte), und zwar durch Eingabe von: \ ECHO L 0100 0 0 1 >XXX.TXT \ ECHO D 0100 02FF >>XXX.TXT \ ECHO Q >>XXX.TXT \ DEBUG HEXDUMP.TXT \ DEL XXX.TXT \ Dabei gehe ich davon aus, dass die von Wolfgang Lorenz stammende Datei \ RAMBIOS.EXE schon die Hilfsdiskette erzeugt hat und die Hilfsdiskette im \ Laufwerk a: liegt. Die eben genannten fuenf Zeilen (natuerlich ohne die \ Kommentar-Striche) sind in einer Batch-Datei zusammenzufassen und die \ Batch-Datei muss dann von der DOS-Kommandozeile aus aufgerufen werden. Die \ Hilfsdiskette muss fuer das Arbeiten mit DEBUG aus einer Diskette entstanden \ sein, die (vorher schon) von DOS anerkannt wurde (vergleiche das am Anfang \ dieses Listings Gesagte ueber mein Experiment mit dem 0-Setzen der \ diskettenbezogenen Parameter im Bootsektor). \ Die eben besprochenen Experimente mit DEBUG habe ich natuerlich nicht vom \ Diskettenlaufwerk aus gemacht, sondern von Laufwerk c: (Festplatte). Zum \ Abschluss des Themas DEBUG noch ein weiteres Experiment, mit dem dann alle \ Eventualitaeten erlaeutert sein duerften: Ich habe mir per DISKCOPY eine \ 1:1-Kopie einer DOS-6.2-Boot-Diskette hergestellt. Von der Kopie habe ich \ einige DOS-Programme, die ich fuer mein Vorhaben bestimmt nicht mehr \ benoetige, entfernt. Dann habe ich FORTH.COM (also Turbo-Forth), \ BOOTMA-4.FTH (also das vorliegende Listing), DEBUG.COM (von DOS 6.2) und \ die oben besprochene Batch-Datei (unter dem Namen DUMPBOOT.BAT) mit auf \ die kopierte Diskette gepackt. Diese habe ich in den Diskettenschacht \ gelegt und dann den Computer von Diskette gebootet. Von der kopierten \ Diskette (also immer noch von Laufwerk a: aus) habe ich dann FORTH [ret] \ und daraufhin INCLUDE BOOTMA-4 [ret] eingegeben - und siehe da: Im \ Diskettenschacht lag dann eine praeparierte Diskette (eine 'Hilfsdiskette' \ im oben erwaehnten Sinne), von der aus aber immer noch DOS-Programme \ aufgerufen werden konnten. So konnte ich denn als Abschluss dieses \ Experimentes durch Eingeben von DUMPBOOT den Bootsektor der kopierten \ Diskette (eben der frisch gefertigten Hilfsdiskette) in die Datei \ HEXDUMP.TXT schreiben und auf sich selbst (auf die Hilfsdiskette) speichern. \ Nicht unschoen waere es fuer den vorliegenden Bericht gewesen, haette ich \ mit den Stichwoertern 'TOOL', 'Wolfgang Lorenz' und 'RAM-BIOS' den \ geneigten Leser einfach auf Google und das Internet verweisen koennen. Ich \ hatte aber leider keinen Sucherfolg. \ Das folgende Wort xxx legt die oben stehende Tabelle, die sich ja inzwischen \ auf dem Forth-Datenstack befindet, ab dem Offset 1e in den Puffer sectbuf. In \ Turbo-Forth haette man auch :: 1e2 0 do sectbuf 1ff + i - c! loop ; schreiben \ koennen und waere dann ohne xxx und forget xxx ausgekommen. In ZF ist aber \ kein :: zu finden. : xxx 1e2 0 do sectbuf 1ff + i - c! loop ; xxx forget xxx \ Jetzt wird der so angepasste Puffer sectbuf als neuer Bootsektor in die \ Hilfsdiskette geschrieben. putdiskbootsect \ Ab jetzt (in diesem Include-Vorgang) ist (und bleibt) das Praeparier-Programm \ von Wolfgang Lorenz aus der Zeitschrift TOOL (1991) in den Puffer sectbuf \ geladen und kann von dort aus (beliebig oft, zum Herstellen weiterer \ Hilfsdisketten ;-) als neuer Bootsektor in eine anzufertigende Hilfsdiskette \ geschrieben werden. \ Der ganze Vorgang des Herstellens der Hilfsdiskette laeuft ab dem Einladen \ des vorliegenden Forth-Programms (per include bei Turbo-Forth oder per fload \ in ZF) ohne weiteres Zutun interpretativ ab. Will man vorsichtig (oder \ neugierig) vorgehen, dann kann man putdiskbootsect auch zunaechst einmal per \ '\' auskommentieren und es erst spaeter durch manuelle Eingabe von der \ Forth-Kommandozeile aus wirken lassen. Ein INCLUDEn (FLOADen) des vorliegenden \ Programms bei offengelassenem Disketten-Schacht hat dieselbe Wirkung. \ Die Hilfsdiskette wird natuerlich normalerweise nur ein einziges Mal \ hergestellt und leistet ab dann beliebig oft ihre oben erwaehnten Dienste: \ BIOS ins RAM kopieren, Interrupts auf das RAM-BIOS ausrichten und PC von \ der im BIOS-Setup eingestellten Festplatte booten. Dass man schon in diesen \ Herstellungs-Prozess nach eigenem Gutduenken eingreifen kann, ist klar: Man \ braucht ja 'nur' vor dem Uebertragen des Hilfsdisketten-Bootsektors (mit \ Forth-Mitteln) den Inhalt des Puffers sectbuf geeignet zu veraendern. Dass \ man das RAM-BIOS patchen kann, ist klar. Zum eventuellen Vergleich liegt das \ ROM-BIOS ausserdem nach wie vor bei F000:0000 und ueber die Lage des RAM-BIOS \ gibt die Bildschirm-Meldung, unmittelbar nachdem der PC ueber die Hilfsdiskette \ gebootet wurde, Auskunft. \ Vorsicht beim Patchen! Die 'verbogenen' Interrupt-Vektoren liegen (bis zum \ 'Sitzungsende') festgezurrt und wuerden es uebelnehmen, wenn das RAM-BIOS an \ irgendeiner Stelle auseinandergezogen werden wuerde.