NVIDIA-MXM 30-Sekunden Patch

Diese Anleitung richtet sich explizit an Besitzer einer NVIDIA Grafikkarte, da ich keinerlei Informationen/Erfahrungen mit ATI Karten bezüglich eines solchen Problems habe!

Zudem möchte ich darauf hinweisen, dass bei jedem eingriff ins Grafik-BIOS die Gefahr besteht, die Grafikkarte unbrauchbar zu machen! JEDER TUT DIES AUF EIGENE GEFAHR! Und wer nicht haargenau weiß, was er tut, sollte am besten schon hier aufhören zu lesen!

Zustande kommen und Daseinsberechtigung der Fehlermeldung

30sekunden fehler

Bei einigen Notebooks wird die Fehlermeldung falsch dargestellt.

Viele, die ihr Notebook mit einer leistungsfähigeren Grafikkarte ausrüsten, haben nach dem Upgrade ein Problem bzw. Ärgernis: Eine nervige, unumgehbare Fehlermeldung mit einem 30-Sekunden Countdown, oftmals begleitet von einem nervigen Piepsen.

Zustande kommt diese Meldung, wenn man ein Notebook mit einer anderen, leistungsfähigeren Grafikkarte ausstattet, die ursprünglich nicht in diesem Modell verbaut war, so auch bei meinem Amilo Pi1536, welches ich mit einer bei ebay ersteigerten GF9600GT ausgerüstet habe.

Diese Meldung dient, auch wenn es für einige den Anschein hat NICHT nur dazu, denjenigen einen Stein in den Weg zu legen, die günstig an mehr mobile Grafikleistung kommen wollen!

Der Hintergrund für diese Meldung ist folgender: Die Grafikkarte prüft während der Initialisierung des BIOS die Systemkonfiguration des Notebooks, hierbei explizit die Leistungsfähigkeit der Schaltwandler und des Kühlsystems. Diese Informationen sind vermutlich entweder in einem EEPROM irgendwo auf dem Notebookmainboard oder im Notebook-BIOS hinterlegt.

Würde die Karte dies nicht prüfen und in ein Notebook eingebaut werden, welches entweder über zu schwachbrüstige Schaltwandler verfügt (MXM schreibt zwar eine Mindestbelastbarkeit vor, aber Ihr wisst ja, wie das mit Vorschriften so ist...) oder das Kühlsystem nicht genügend Abwärme abführen kann, hat man ein Problem.

(Beim Kühlsystem gibt es afaik keine Vorschriften, wenn eine 10W Karte verbaut ist, der MXM-Slot aber 30W Karten verkraftet, muss das Kühlsystem längst nicht mit mehr als 10W zurecht kommen.)

Nebenbei verhindert die Grafikkarte in einem solchen System auch das Hochtakten in den 3D-Leistungsmodus, um Spannungswandler und Kühlsystem nicht zu überlasten.

Diese Hürde lässt sich allerdings sehr einfach umgehen, indem man z.B. mit NiBiTor das Grafik-BIOS so modifiziert, dass der low-end 3D-Takt dem 3D Leistungsmodus entspricht (Nähere Informationen hierzu findet man auf einschlägigen Foren, da dies nun wirklich ein alter Hut ist möchte ich an dieser Stelle auch nicht näher darauf eingehen).

Also fassen wir zusammen: Das ganze kann man als Sicherheitsmechanismus ansehen, um den unwissenden Bastler davor zu bewahren, Notebook und Grafikkarte abzufackeln oder ähnlich.

Neben dem unwissendem Bastler, gibt es allerdings auch diejenigen, die wissen was sie tun. Für diese Leute ist dieser Sicherheitsmechanismus zurecht nur nervig und unnötig. (Hab ich schon gesagt, dass auch nur diese Leute hier weiterlesen sollten?...Wirklich, wir übernehmen keinerlei Haftung für Schäden, die durch nachmachen der in diesem Artikel beschriebenen Arbeitsschritte entstehen!)

BIOS nach Wunsch

Da mir das nicht abschaltbare piepsen tierisch auf die Nerven gegangen ist, habe ich mich mit einem Image meines BIOS an jemanden gewandt, der Assembler kann.

Kurze Zeit später hatte ich mehrere modifizierte Images vorliegen, die ich auf eigene Gefahr hin ausprobieren durfte. („...die ich auf EIGENE GEFAHR HIN ausprobieren durfte“... mir kommt´s so vor, als hätte ich diesen Wortlaut hier bereits verwendet...)

BIOS-Backup für den Ernstfall

Die nun folgenden Schritte sind nicht zwangsweise nötig, da die weiter unten beschriebene Modifikation bereits erfolgreich getestet wurde und somit eigentlich einwandfrei funktionieren sollte (auch hierfür übernehmen wir keinerlei Garantie!)

Da beim durchprobieren der einzelnen BIOS-Versionen mit den unterschiedlichen Veränderungen die Gefahr bestand, die nicht gerade billige Grafikkarte unbrauchbar zu machen, hatte ich wenig Lust, das Image einfach drüber zu bügeln und anschließend vor einem dauerhaft Schwarzen Bildschirm zu sitzen (was bei einer Version auch vor kam...).

Also musste eine Kopie des BIOS her, allerdings nicht nur ein einfaches Image, denn wie soll man das denn wieder drauf flashen wenn das System nur noch als Briefbeschwerer taugt?

(Hierher kommt auch der Begriff, die Hardware zu bricken. Wenn man die Grafikkarte bzw. deren BIOS zerschossen hat, taugt sie nur noch als Briefbeschwerer, wofür man genau so gut einen Ziegelstein, engl. Brick, nutzen könnte. Okay, es gibt Mittel und Wege, über die jedoch kaum einer verfügt.)

Das anfertigen einer Kopie des BIOS ist zum Glück Kinderleicht! (ACHTUNG, IRONIE!)

Okay, sind wir ehrlich, für jemanden mit ausreichender SMD-Löterfahrung, guten Nerven und ruhiger Hand, einer vernünftigen Ausrüstung (Lötstation mit feiner Spitze, 0,5mm Lötzinn oder feiner, feiner Litze, geeignetes Werkzeug zum zwischen IC Pins rumstochern, mindestens 1 Tägigem, vorhergehendem Kaffeeentzug...) sollte es kein Problem darstellen. (Alle anderen: Bittebittebitte mit Sahne oben drauf, nicht nachmachen!)

Dual-BIOS

Als erstes besorgt man sich wenn möglich ein baugleiches EEPROM, oder zumindest einen für das verbaute EEPROM geeigneten Ersatztyp.

Bei einigen Grafikkarten werden EEPROMs mit „Fastread“ Fähigkeit verbaut. Allerdings wird diese Funktion nicht immer genutzt, wodurch man das EEPROM wie in meinem Fall durch ein 08/15 EEPROM austauschen kann. Dass es bei meiner Karte funktioniert hat, heißt aber nicht, dass es bei allen gehen muss!

Als nächstes schneidet man sich ein paar nicht zu lange, dünne Drahtstücke zurecht, die man an die Pins des EEPROMs lötet. Mit diesen Drahtstücken kann man nun praktisch das leere EEPROM zum Original parallel schalten. Viele werden jetzt denken „Was, EEPROMs mit unterschiedlichem Inhalt einfach parallel schalten, das kann doch nicht gehen!“

Nunja, um ehrlich zu sein war bei dieser Aktion auch ein guter Schuss Hoffnung dabei.

dualbios

Damit das ganze funktioniert muss man allerdings folgendes beachten/machen: GANZ WICHTIG: Der SO-Pin (Pin 2) des leeren EEPROMs darf NICHT! Angeschlossen werden!

Der Data Hold pin des leeren EEPROMs muss bis zu dem Zeitpunkt des finalen ENTER-Drückens auf GND gelegt sein und erst unmittelbar vor dem Flashvorgang auf High gelegt werden.

Ich habe dies durch anlöten eines Pull-Up Widerstands (Werte zw. 10K und 100k eignen sich am besten) und dranhalten einer Masseleitung gelöst, die ich unmittelbar vor dem Flashvorgang einfach weggenommen habe. Da der SO-Pin nicht angeschlossen, sollte es theoretisch auch ohne das HOLDen des Zweitchips funktionieren... Aber sicher ist sicher.

Auch ganz wichtig: Der Zweitchip sollte die eingehenden Daten schneller abarbeiten können als das Original, andernfalls kann zu Problemen beim Flashvorgang kommen und die Kopie bleibt funktionsunfähig. Nun kann man einfach mit nvflash das Originalbios auslesen und neu schreiben. Somit überschreibt man das verbaute BIOS nochmals, wobei gleichzeitig eine Kopie auf dem zweiten EEPROM landet.

Das externe Beschreiben eines leeren EEPROMs mit dem BIOS-Image und umlöten der beiden ICs habe ich natürlich auch getestet... Erfolglos, daher dieser Aufwand.

Ob die Kopie funktioniert, kann man einfach testen, indem man den fehlenden Pin auch anlötet und Pin 7 des verbauten Originals ablötet und VORSICHTIG! ABRISSGEFAHR! hoch biegt.

Nun Pin 7 mit einer Drahtschlaufe auf GND legen. Dadurch wird das Original EEPROM still gelegt. Pin 7 des zweit EEPROMs muss natürlich von nun an durchgehend High sein, also einfach die Masseleitung weg lassen und der SO-Pin muss angeschlossen werden.

Sollte das Notebook nun korrekt booten, hat man erfolgreich eine funktionsfhäige Kopie des BIOS hergestellt, die man im Falle eines Fehlers einlöten kann, wenn sich die Grafikkarte nicht mehr zum funktionieren überreden lassen will.

Andernfalls hat man entweder etwas falsch gemacht, oder ein Problem. Ein teures Problem.

Ich empfehle an dieser Stelle den hoch gebogenen Pin nicht wieder runter zu biegen! Einfach die Drähte wieder ablöten und den hoch gebogenen Pin mit einer ausreichenden menge Lötzinn leitend mit der Platine verbinden. Hier fließen keine Hohen Ströme und es liegen auch keine hohen Frequenzen an. Beim runter biegen des Pins riskiert man, ihn ab zu brechen, da das Material erfahrungsgemäß meist nur eine Biegung überlebt ohne zu brechen.

Software-MOD

An dieser Stelle übergebe ich einfach an den Mann vom Fach bezüglich Assembler:

"Sag mal, du kannst doch Assembler, oder?" - dieser Satz verheißt selten etwas gutes. In der Regel heißt das, dass man total sinnlose, dafür aber langweilige Kosmetikpatches vornehmen darf, die es erfordern, das ganze BIOS neuzuschreiben. Und das ganze, damit "modded by Ganxta Hopper Inc." beim booten angezeigt wird.
Naja, nach näherem Betrachten (und nachdem Björn mit dem Gepiepse die Aufmerksamkeit des gesamten Physikhörsaals auf sich gezogen hat - ohne die Aufmerksamkeit der Komilitoninnen gewinnbringend zu nutzen) ließ ich mich dann doch noch überreden, sonst gäbs hier ja nichts zu lesen...

Die Bedienung von debug.exe

Ich habe hierfür den uralten DOS (Dis)Assembler debug.exe verwendet. Er ist sehr primitiv, aber für kleine Patches sehr gut geeignet. Da ich auch nur "ein bisschen" assemblieren kann, habe ich keine "Power-Tools" für 16-bit x86 code zur Verfügung. Vorteil: Dadurch kann man alles mit einem beliebigen DOS-System nachvollziehen.
Debug.exe ist ein echt historisches Programm, dessen Wurzeln noch vor DOS 1.0 zurückreichen. Dementsprechend ist die Bedienung. Standardmäßig kennt Debug.exe nicht mal Dateien, ein Dateiname wird beim Start mitgegeben und kann dann nicht mehr verändert werden. Also sollte man nie an der Originaldatei arbeiten, denn man kann nicht "mal schnell in eine andere Datei speichern". Also: Debug starten und laden geht so (Eingaben in kursiv):

D:\>copy 9600.ROM 9601.ROM
D:\>debug 9601.ROM
-l0
-

- ist der Prompt von debug. Es gibt keine weiteren Infos. Das muss man im Kopf behalten... Also: die wichtigsten Befehle sind:
u<Adresseanfang>.<Adresseende>
Disassembliert einen Adressbereich. Wenn man kein Ende angibt, wird soviel disassembliert, wie bequem auf einen Screen passt (oder 1977 passte...). Wird keine Adresse angegeben, wird da weitergemacht, wo man zuletzt aufgehört hat.
d<Adresseanfang>.<Adresseende>
Zeigt einen Speicherbereich hexadezimal an. Auch hier kann man Adressenangaben weglassen, siehe "u"
a<Adresse>
Assembliere an der angegebenen Adresse, oder an der aktuellen Adresse. Debug gibt dann die aktuelle Adresse aus, und erwartet eine Zeile Assemblercode. Eine leere Zeile beendet die Eingabe.
w<Adresse>
l<Adresse>

Schreibt/Liest ab <Adresse>. Wir beginnen immer bei Adresse 0, das macht das ganze einfacher. CP/M-Programme (.COM) werden ab Adresse $100 geladen, das ist deshalb auch der Standard. Also muss die 0 extra angegeben werden.

Als extra Hinweis wäre zu nennen, dass Debug grundsätzlich hexadezimal denkt, ohne das zu kennzeichnen. Weiterhin haben die Adressen zwei Teile: Der erste Teil ist die Segmentadresse (eine Perversion, die es nur bei Intel gibt - grrrr, ich will nicht wissen, in welches S&M-Studio Intel-Ingenieure nachts gehen), der zweite Teil der Offset (also die Adresse im Speicherbereich, der uns zusteht). Wenn wir das ROM nach $0 laden, dann entspricht der Offset der Adresse im ROM, und wir können alles weitere vernachlässigen.

So, los gehts.

Drei Ansätze bieten sich: Das eine ist der Zugriff auf den PC speaker, Eine Suche nach dem Code bringt folgendes ans Tageslicht (die Kommentare liefert debug selbstverständlich nicht, die sind von mir^^):
-u227D
07BE:227D 50            PUSH    AX
07BE:227E 51            PUSH    CX
07BE:227F B0B6          MOV     AL,B6	;select timer mode
07BE:2281 E643          OUT     43,AL	
07BE:2283 B033          MOV     AL,33	;set divider
07BE:2285 E642          OUT     42,AL	;=$533
07BE:2287 B005          MOV     AL,05	;Beep frequency
07BE:2289 E642          OUT     42,AL	;is 896Hz
07BE:228B E461          IN      AL,61	;get old KBC statereg
07BE:228D 50            PUSH    AX	;keep it
07BE:228E 0C03          OR      AL,03	;turn PC speaker on
07BE:2290 E661          OUT     61,AL
07BE:2292 B90300        MOV     CX,0003	;some delay. 
07BE:2295 E82B00        CALL    22C3	
07BE:2298 58            POP     AX	;restore old state
07BE:2299 E661          OUT     61,AL	;(PC speaker off)
07BE:229B 59            POP     CX	
07BE:229C 58            POP     AX
07BE:229D C3            RET
Hier könnte man jetzt entweder die Frequenz aus dem Hörbereich drehen (Teiler z.B. statt $0533 auf $0002 setzen) oder den Befehl, der den PC speaker einschaltet, entfernen (Ja, der PC Speaker wird am Tastaturcontroller eingeschaltet!), also $2290 durch NOP NOP ($9090) zu ersetzen. Doch dann bliebe der 30 Sekunden Countdown.

Der nächste Ansatz ist die suche nach der Zahl 30($1E). Wie durch ein Wunder kommt die nur einmal vor, und zwar in dieser Routine:
-ua64A
07BE:A64A 50            PUSH    AX			;save registers
07BE:A64B 51            PUSH    CX
07BE:A64C 06            PUSH    ES
07BE:A64D 55            PUSH    BP
07BE:A64E 2EF606210302  TEST    BYTE PTR CS:[0321],02	;do some tests
07BE:A654 744F          JZ      A6A5			;we don't
07BE:A656 2EF606210301  TEST    BYTE PTR CS:[0321],01	;understand
07BE:A65C 7447          JZ      A6A5
07BE:A65E B01E          MOV     AL,1E			;counter=30, replace by1
07BE:A660 8D2E3DA6      LEA     BP,[A63D]		;load string addr
07BE:A664 8CC9          MOV     CX,CS			;string is <SP><SP><CR><LF>
07BE:A666 8EC1          MOV     ES,CX
07BE:A668 EB37          JMP     A6A1			;Jump into loop
07BE:A66A FEC8          DEC     AL			;decrement counter
07BE:A66C 50            PUSH    AX			;This part displays
07BE:A66D 9C            PUSHF				;the counter
07BE:A66E D40A          AAM     0A			;Not 100% understood
07BE:A670 053030        ADD     AX,3030			
07BE:A673 86E0          XCHG    AH,AL
07BE:A675 3C30          CMP     AL,30
07BE:A677 7502          JNZ     A67B
07BE:A679 B020          MOV     AL,20
07BE:A67B 26894600      MOV     ES:[BP+00],AX
07BE:A67F B403          MOV     AH,03
07BE:A681 32FF          XOR     BH,BH
07BE:A683 E8B576        CALL    1D3B			;char out
07BE:A686 2E8A1E4E34    MOV     BL,CS:[344E]
07BE:A68B B90400        MOV     CX,0004
07BE:A68E B413          MOV     AH,13
07BE:A690 9D            POPF
07BE:A691 0F94C0        SETZ    AL
07BE:A694 E8A476        CALL    1D3B			;char out
07BE:A697 58            POP     AX
07BE:A698 E8E27B        CALL    227D			;BEEP! , replace by NOP NOP NOP
07BE:A69B B9E803        MOV     CX,03E8
07BE:A69E E8F7AB        CALL    5298			;I think this is a delay
07BE:A6A1 3C00          CMP     AL,00			;still some time to go?
07BE:A6A3 77C5          JA      A66A			;loop 30 times
07BE:A6A5 5D            POP     BP
07BE:A6A6 07            POP     ES
07BE:A6A7 59            POP     CX
07BE:A6A8 58            POP     AX
07BE:A6A9 C3            RET
Hier könnten wir schonmal den Countdown herabsetzen und den BEEP wegpatchen.
Ein dritten Ansatz liefert die Fehlermeldung, die zwar nicht korrekt angezeigt wird, aber dennoch im ROM vorhanden ist:
-dc860
07BE:C860        45 52 52 4F 52 3A-20 4D 58 4D 20 53 74 72     ERROR: MXM Str
07BE:C870  75 63 74 75 72 65 20 6E-6F 74 20 66 6F 75 6E 64   ucture not found
07BE:C880  20 6F 72 20 69 6E 76 61-6C 69 64 2E 0D 0A 0A 52    or invalid....R
07BE:C890  65 66 6C 61 73 68 20 4D-58 4D 20 52 4F 4D 20 6F   eflash MXM ROM o
07BE:C8A0  72 20 61 64 64 20 4D 58-4D 20 53 74 72 75 63 74   r add MXM Struct
07BE:C8B0  75 72 65 20 61 6E 64 20-61 73 73 6F 63 69 61 74   ure and associat
07BE:C8C0  65 64 20 63 61 6C 6C 62-61 63 6B 73 20 74 6F 20   ed callbacks to
07BE:C8D0  53 42 49 4F 53 21 0D 0A-50 4F 53 54 20 77 69 6C   SBIOS!..POST wil
07BE:C8E0  6C 20 62 65 20 68 61 6C-74 65 64 20 66 6F 72 20   l be halted for
07BE:C8F0  33 30 20 73 65 63 6F 6E-64 73 20 61 6E 64 20 70   30 seconds and p
07BE:C900  65 72 66 6F 72 6D 61 6E-63 65 20 77 69 6C 6C 20   erformance will
07BE:C910  62 65 20 6C 69 6D 69 74-65 64 20 74 6F 0D 0A 62   be limited to..b
07BE:C920  61 6C 61 6E 63 65 64 20-70 65 72 66 6F 72 6D 61   alanced performa
07BE:C930  6E 63 65 20 6D 6F 64 65-20 75 6E 74 69 6C 20 74   nce mode until t
07BE:C940  68 69 73 20 69 73 20 72-65 73 6F 6C 76 65 64 2E   his is resolved.
07BE:C950  2E 2E 00               -                          ...
So ist das also. Wir sollen also das System BIOS fixen. Naja, wie in der Politik bekämpfen wir Symptome, nicht Probleme. Scheint ja ein anerkanntes Verfahren zu sein ;-)
So, mal gucken, wo der String geladen wird.
-uc953
07BE:C953 2EF60620030F  TEST    BYTE PTR CS:[0320],0F	;these seem to be
07BE:C959 7501          JNZ     C95C			;the tests whether
07BE:C95B C3            RET				;whether the error
07BE:C95C 2EF606210302  TEST    BYTE PTR CS:[0321],02	;is being output
07BE:C962 7408          JZ      C96C			;or not
07BE:C964 32D2          XOR     DL,DL			;set no char inversion
07BE:C966 BE62C8        MOV     SI,C862			;load pointer to string in SI
07BE:C969 E84101        CALL    CAAD			;and call string out
07BE:C96C C3            RET				;
Sieht ja einfach aus. Es gibt irgendnen Test, dann wird der String ins Register SI (Source index) geladen, dass für den Zweck auch gedacht ist, und $CAAD wird aufgerufen. Mal schaun:
-ucaad						;String output
07BE:CAAD B40E          MOV     AH,0E			;assume pointer in DI
07BE:CAAF 32FF          XOR     BH,BH			;Non-Understood setup
07BE:CAB1 2E8A1E4E34    MOV     BL,CS:[344E]		;More of it
07BE:CAB6 268A05        MOV     AL,ES:[DI]		;Get charachter from [DI],
07BE:CAB9 0AD2          OR      DL,DL			;not SI
07BE:CABB 7402          JZ      CABF			;if DL nonzero, invert 
07BE:CABD F6D0          NOT     AL			;the charachter
07BE:CABF 0AC0          OR      AL,AL			;is the char a 0 (Terminator)?
07BE:CAC1 7406          JZ      CAC9			;If so, exit
07BE:CAC3 E87552        CALL    1D3B			;Otherwise print
07BE:CAC6 47            INC     DI			;and increment pointer
07BE:CAC7 EBE4          JMP     CAAD			;loop
07BE:CAC9 C3            RET
WAS ZUM TEUFEL? SI wird nie ausgewertet! Entweder verstehe ich irgendwas nicht, oder da ist was faul. Aber halt - die Meldung wird ja nicht korrekt angezeigt... Das kann also gut sein, dass das falsche Register angesprochen wird. Die Option, Strings zu "verschlüsseln", in dem man alle Zeichen invertiert, ist auch komisch. Naja, vielleicht haben sie was zu verbergen. Wo wird $CAAD denn noch aufgerufen?
Zum Beispiel hier:
-ucaca
07C2:CACA 60            PUSHA				;Output some messages
07C2:CACB 06            PUSH    ES
07C2:CACC 32D2          XOR     DL,DL
07C2:CACE 0E            PUSH    CS
07C2:CACF 07            POP     ES
07C2:CAD0 BFEC00        MOV     DI,00EC			;"G96P616 NB9P-GS VGA BIOS"
07C2:CAD3 E8BCFE        CALL    C992			
07C2:CAD6 E8D4FF        CALL    CAAD			;$CAAD should be called with pointer in DI
07C2:CAD9 BF3D01        MOV     DI,013D			;"Version 62.94.1F.00.08" 
07C2:CADC E8CEFF        CALL    CAAD			
07C2:CADF 2EF606480001  TEST    BYTE PTR CS:[0048],01
07C2:CAE5 740A          JZ      CAF1
07C2:CAE7 FECA          DEC     DL			;DL=$FF, invert all chars
07C2:CAE9 BFBF01        MOV     DI,01BF			;"Engineering Release - Not For Production Use"
07C2:CAEC E8BEFF        CALL    CAAD
07C2:CAEF FEC2          INC     DL
07C2:CAF1 BF5701        MOV     DI,0157			;"Copyright (C) 1996-2008 NVIDIA Corp"
07C2:CAF4 E8B6FF        CALL    CAAD
07C2:CAF7 2EF606340020  TEST    BYTE PTR CS:[0034],20	;print amount of RAM... boring.
...
07C2:CB46 C3            RET
Hier wird die Stringadresse in DI (destination index) gegeben. Zwar gibt SI mehr Sinn, aber der Unterschied zwischen DI und SI ist nur der Name, die Register sind ansonsten austauschbar. Und $CAAD ERWARTET die Stringadresse in DI, und das wurde ansonsten auch richtig gemacht.
Ok, ich brauche ein T-Shirt "I FIX NVIDIA'S BUGS".

So, was wissen wir jetzt?
  • Wir können die Piepsroutine stummlegen
  • Wir können den Countdown auf 1 setzen
  • - Warum die Meldung versaut ist
  • - Wo wir eine andere Meldung reinpatchen können
  • Jetzt gings ans Testen. Also patchen, mit NiBiTor die Checksumme anzeigen lassen und korrigieren, bis NiBiTor sagt "alles ok", dann flashen, dabei die Karte bricken (zum Glück gabs ein Backup!). Und nochmal...
    Was ich alles probiert habe, will ich euch mal ersparen, nur so viel:
    Das ändern von SI in DI ändert die Meldung, macht sie aber nicht lesbar.
    Der Countdown lässt sich auf 1 ändern, aber nicht auf 0. Naja, eine Sekunde ist zu verschmerzen.
    Die Beeps lassen sich wegpatchen, aber einer bleibt. Ob der vom System oder Video BIOS kommt, konnten wir bisher nicht klären. Björn vermutet, dass er vom System BIOS kommt, ich halte es für unwahrscheinlich, da er genau die gleiche Frequenz hat. Klarheit kann nur bringen, $227D komplett stummzuschalten. Aber für weiteres Patchen fehlte die Lust, schließlich ist es auch etwas riskant.

    Die letztlich durchgeführten patches sehen so aus:
    
    -aa65e
    07BE:A65E MOV     AL,1
    07BE:A660 
    -aa698
    07BE:A698 NOP
    07BE:A699 NOP
    07BE:A69A NOP
    07BE:A69B
    -w0
    FE00 Bytes written.
    -q
    D:\>
    
    Jetzt nur noch die Prüfsumme anpassen (NiBiTor gibt die korrekte Prüfsumme aus, einfach, in das letzte Byte der Datei mittels Hexeditor schreiben) und Flashen - WENN MAN EIN BACKUP HAT. Ich habe es gebraucht, und das obwohl ich eins hatte. Wenn man keins hat - dann braucht mans 100%ig, auch wenn man "mal nur kurz" und wenns dann heißt: könnt ihr nicht: ich habs gesagt.
    Die Adressen scheinen übrigens nicht in allen BIOSen gleich zu sein, auch wenn der Code identisch größtenteils ist. Ihr müsst euch daher die Codestellen, die es zu patchen gilt also selbst raussuchen. Sie werden vermutlich nur um ein paar Bytes verschoben sein (Stichprobe 1, also für Mediziner ausreichend).

    Wir haben bisher keine Möglichkeit, ein ROM ohne funktionierendes ROM zu beschreiben (kommt aber noch, sobald ich Björn um ein funzendes ROM erleichtert habe), also (auch wenns sich wiederholt): Wenn ihr keine Kopie habt und einen Fehler macht, können wir eure Karte nicht retten. Und wir kennen auch keinen, der das kann. Es wäre schade, wenn eine nagelneue 9600 deswegen als MOSFET-Spender endet.