10 Jahre Abschied: A20-Gate in Intel-Prozessoren
Im Juni 2013 erschien Intels Core i-4000 alias Haswell. Es war Intels erste CPU ohne A20-Gate, welches viele Programmierer jahrzehntelang nervte.
- Andreas Stiller
Nur 29 Jahre nachdem IBM eines der unsinnigsten Hardwarefeatures der PC-Geschichte in den IBM PC AT eingeführt hatte, wagte es Intel bei der Haswell-Generation der Core-i-Prozessoren, den heiligen Pfad der Kompatibilität zu verlassen. Ab dem 1. Juni 2013 sollte es nicht mehr möglich sein, einfach eine Adressleitung per Befehl konstant auf Null zu setzen. Denn das war die Aufgabe eines putzigen Gates: Die Leitung A20 auf Wunsch auf null zu setzen. Bereits viele Jahre zuvor hatten Intel und Microsoft mit der Hardware-Spezifikation PC2001 beschlossen, das Gate endlich zu beerdigen – aber das sollte dann doch noch über 10 Jahre dauern.
Wozu sollte das umstrittene Gate A20 eigentlich gut sein, fragt man sich? Zu nichts eigentlich, es sei denn, man ist Microsoft-Programmierer und will eine Eigenheit des ersten PC-Prozessors 8086/88 ausnutzen, die durch die Segmentierung des Adressraums möglich war; Genaueres dazu weiter unten. Manche Alt-Software jedenfalls brauchte das A20-Gate, sei es beabsichtigt oder durch Schlamperei in der Programmierung, wie beim DOS-CP/M-Emulator, bei Microsoft Pascal oder Microsoft Exepack.
A20-Wildwuchs
IBM hatte jedenfalls beim PC AT mit Intel 80286 offenbar noch ein Gatter sowie einen Schaltport am Tastaturcontroller frei und dachte: Ach, dann simulieren wir doch auf Wunsch den Adressraum eines 8086/88. Und das klappte zunächst relativ problemlos, bis dann Mitte der 1990er-Jahre DOS-Erweiterungen und andere Betriebssysteme wie Windows und OS/2 kamen. Da musste man mitunter das Gate häufig umschalten, aber die Umschaltung via Tastaturcontroller war extrem langsam. Und so gab's schwups über ein Dutzend alternative Wege, im BIOS zumeist als „Fast A20 Gate“ bezeichnet.
IBM selbst führte 1988 mit der PS/2-Linie den weitaus schnelleren Umschaltport 92h ein. HP fing beim Vectra bestimmte Befehle an den Tastaturcontroller ab, um viel schneller umzuschalten. Manche Prozessoren belauschten die Portzugriffe und machten das gleich intern, andere nutzten Port 0xee. Um den Wildwuchs einzudämmen, wurde später der Interrupt 15h AX=24xx im BIOS definiert.
Als mit dem 486er interne Caches eingeführt wurden, kamen weitere Probleme hinzu, denn die musste man löschen, weil sie durcheinanderkommen, wenn sich draußen an den Adressen etwas ändert. Auch das klappte nicht immer. Cyrix hatte ein pfiffiges „Clip-on Upgrade“ namens 486slc2 entwickelt, das man einfach auf einen 386SX aufstecken konnte. Das Upgrade lief mit doppeltem Takt und hatte einen kleinen Cache, aber am Sockel fehlte die Leitung #A20m, die den aktuellen Gatterzustand zurückmeldete. Da mussten sich Cyrix schon was einfallen lassen, wie man das trotzdem irgendwie hinkriegt.
Fehler, Probleme, Workarounds ...
Bis hin zu DOS 4.0 war das Gate nach dem Booten zunächst grundsätzlich aktiv, doch mit DOS 5.0 und Himem ging das Dilemma los: Allüberall sah man „A20-Gate kann nicht geschaltet werden“ und das war's. Der Treiber himem.sys in config.sys kannte bei DOS 6.22 etwa 16 Varianten, loggte aber häufig die Systeme falsch ein.
Und wer mit Microsoft Exepack gepackte Programme – ein Packer, der gerne für Spiele verwendet wurde – starten wollte, bekam nicht selten nur blöde Fehlermeldungen „Packed File is Corrupt“. Microsoft blamierte sich völlig mit absurden Begründungen im Knowledge-Base-Beitrag Q58225 und selbst im Jahr 2000 noch in Q72360.
Microsoft hatte lediglich den Workaround parat, dass man zuvor irgendetwas in die unteren 64K laden muss, damit die gepackten Programme oberhalb von 64K zu liegen kommen. Dass das Problem am nicht geschalteten A20-Gate liegt, wurde nicht kommuniziert, obwohl es etwa bei Microsoft Pascal durchaus bekannt war, wie ein ominöses US-Patent US4779187A des Microsoft-Mitarbeiters James Levin schon 1985 offenbarte.
In den späteren Jahren häuften sich zahllose Hardware-Probleme rund um das A20-Gate. Intels „Specification Updates“, die seit dem Pentium-FDIV-Bug regelmäßig herausgegeben werden, waren voll davon, eine Auflistung würde den Rahmen komplett sprengen. Nicht zuletzt gab es auch Sicherheitsprobleme, wenn man einfach so Adressleitungen umschalten und dann Speicherbereiche auslesen konnte, wo man eigentlich nicht hin durfte.
Totgesagte ...
Bei den Servern wurde von Intel die offizielle Beerdigung des stumpfsinnigen Gates schon mit der CPU-Familie Nehalem vollzogen. Bei den Desktopsystemen dann vor 10 Jahren mit Haswell – zumindest gab es kein #A20m-Signal mehr.
Allerdings hat man inzwischen neuere Kommunikationsmöglichkeiten zwischen CPU und Peripherie, etwa das Virtual Legacy Wire (VLW) des Direct Media Interface (DMI). Dessen Protokoll hat jede Menge Platz für allerhand Spitzfindigkeiten. Und so findet man auch bei aktuellen Intel-Chipsätzen im Platform Controller Hub (PCH) das Init-Register Port 92, mit dem man ein Init-Signal setzen kann. Es besitzt noch fünf reservierte Bits ... falls ein Mainboard-Hersteller also wirklich will, gibt es offenbar auch jetzt noch A20-Unterstützung. Das bestätigte mir vor einigen Jahren auch ein Intel-Entwickler – wirklich herausgeschmissen hat Intel dieses Feature also nie.
Bei AMD sieht die Sache von Haus aus anders aus. Hier gab's nie eine offizielle Beerdigung. Selbst beim neuesten Epyc-Prozessor Genoa gibts die A20-BIOS-Einstellung zu A20: „upon request“.
CP/M-Ăśberbleibsel und A20-Gate
Wer’s ein bisschen genauer wissen will, muss tief in die Architektur eines 8086/88-Prozessors blicken. Dieser Prozessor „baute“ die 20-bittige physische Adresse aus zwei 16-Bit-Registern zusammen, einem Segment- und einem Offset-Register. Intel hätte einfach ein 4-Bit-Segment mit einem 16-Bit-Offset zu einer 20-Bit-Adresse zusammensetzen können – aber nein, ein 16 Bit-Wert im Segmentregister wurde um vier Bits nach links verschoben und dazu der Offset addiert.
Das fĂĽhrt dazu, dass man ein und dieselbe physische Adresse auf vielerlei Art generieren konnte, etwa 12345h mit 1234h:5h oder mit 1230h:35h oder auch 235h:FFF5h und so weiter auf insgesamt also 4096 Wegen. Besonders sparsame Programmierer konnten dann allein durch die Wahl der Segment-Offset-Kombination gleich noch einen Parameter mit auf den Weg geben, ohne den Stack zu bemĂĽhen.
Aber wie sieht’s dann beispielsweise mit F01Dh:FEF0h aus? Das ergäbe 1000C0h, doch der Prozessor hat lediglich 20 Adressleitungen, und die reichen nur bis FFFFFh. Folglich könnte er dann einen Fehlerinterrupt „Address Overflow“ generieren, aber das hat sich Intel gespart. Stattdessen gehen die aus dem Segmentregister herausgeschobenen oberen vier Bit einfach verloren – dann landet das Ganze wieder unten auf 000C0h (Wrap Around). Maximal ist somit via Wrap Around (FFFFh:FFFFh) => 0FFEFh erreichbar.
Diese Adresse 000C0h ist nicht ganz zufällig gewählt, vielmehr hat sie eine besondere Bewandtnis, denn sie ist die Adresse des Interrupt 30h. Microsoft belegte sie mit dem Einsprung in die CP/M-Emulation. CP/M – alte Rentner werden’s noch wissen – war das wichtigste Betriebssystem der 8-Bit-Prozessoren 8080, 8085 und Z80. Und ein Programmierer von Seattle Computer Products, Tim Paterson, orientierte sich bei seinem Quick'n-Dirty-x86-DOS stark an CP/M – noch bevor es ihm von Bill Gates „abgeluchst“ wurde.
Er baute so einen kleinen CP/M-Emulator für den Standard-Einsprung „Call 5“ ein, der den Aufruf in die entsprechende MSDOS-21h-Funktion wandelte. Jedes ausführbare Programm bekam in seinem Program Segment Prefix (PSP) ganz vorn im Offset 5 seinen CP/M-kompatiblen Einsprung zum Int 30 bequem via Call CS:5h. Dabei nutzte man die oben beschriebene Möglichkeit, 000C0h via Wrap Around zu adressieren und dabei gleich noch die benötigte Programmsegmentgröße zu übertragen.
Die Dosbox-Entwickler, die den ganzen Kram nachprogrammieren mussten, kommentieren diesen Sprung zum CP/M-Entry: „Let's hope nobody really uses this address“.
Wer sich den Program Segment Prefix etwas genauer auf Wikipedia anschauen möchte: nehmen Sie die englische Version, die deutsche ist da doch etwas konfus. Mehr zum Thema gibts im OS/2-Museum.
Ein echter Software-Interrupt, den man über Int 30h hätte aufrufen können, war das übrigens nicht, sondern da stand ein Far Jump, der fünf Bytes benötigte und somit auch den folgenden Interrupt 31h „zerstörte“. Paterson schrieb 1980 dazu, dass man das nur kurz für Alt-Software bräuchte: „This is not recommended for new programs“. Doch das stieß bei Microsoft offenbar auf taube Ohren.
(ciw)