Liebes Forum,
mit dem folgenden Programm habe ich versucht unter MS-DOS einen
Speicherdump des ersten Megabyte zu erstellen. – Sinn des ganzen ist es
PnP Geräte zu finden, die sich laut PnP BIOS Spezifikation im
Speicherbereich 0xF0000 - 0xFFFFF finden lassen und durch einen $PnP
String an ihrem Anfang, das es zu suchen gilt, erkennen lassen. – Nur
ist es nun so, dass mein Programm (kompiliert und ausgeführt mit Turbo
C++ 1.01 unter FreeDOS 1.2) nur ein einziges Speichersegment zu lesen
scheint.
Die Ausgabe sagt zwar, dass alle Segmente addresiert würden, im Dump
wiederholt sich allerdings alles. Zu erkennen war es daran das, dass
sich ein stehendes Bild ergab, wenn ich im Hexeditor nach "pnp" gesucht
habe und die Taste festgehelten habe.
1
#include<stdlib.h>
2
#include<stdio.h>
3
4
intmain(intargc,char**argv){
5
longi;
6
unsignedcharfar*mem;
7
longstart=0x00000;
8
longstop=0xfffff;
9
FILE*file;
10
11
file=fopen("memory.dmp","wb");
12
13
for(i=start;i<stop;i+=16){
14
mem=(voidfar*)i;
15
printf("%p\n",mem);
16
fwrite(mem,16,1,file);
17
}
18
19
fclose(file);
20
return0;
21
}
Da viele online Resourcen über DOS heutzutage down sind und nur noch
durch tote Links in Erinnerung geblieben sind, würde ich mich freuen,
falls mir jemand erklären könnte wo das Problem in meinem Code ist. Das
Huge Model hab ich in den Optionen schon gewählt und zwei "far" habe ich
auch. Nur gehen tut es nicht.
Vielen Dank
WIMRE wird der Segment-Teil der Adresse in der oberen Hälfte des
Pointers gespeichert. Die physische Adresse 0xfabcd wird also als
0xfabc000d geschrieben (oder auch 0xf000abcd).
> WIMRE wird der Segment-Teil der Adresse in der oberen Hälfte des> Pointers gespeichert.
War das nicht der Unterschied zwischen far und huge? Far: 16 bit
segment plus 16 bit offset in 32bit. Huge: 20 bit address in 32bit,
splitten nach seg/offset bei Zugriff.
Alles lange her ... ich vermute, fwrite kommt mit den Pointern nicht
klar, kann nur 16 bit. Mal nen huge-Pointer probiert, selbst
dereferenziert und per fputc ausgegeben?
Man muss denke ich auch darauf achten, dass das Programm mit dem
richtigen Speichermodell compiliert wird.
Mario M. schrieb:> WIMRE wird der Segment-Teil der Adresse in der oberen Hälfte des> Pointers gespeichert. Die physische Adresse 0xfabcd wird also als> 0xfabc000d geschrieben (oder auch 0xf000abcd).
Eigentlich war es üblich, Segment- und Offsetadresse durch Doppelpunkt
getrennt zu schreiben, da die beiden ja nicht einfach aneinander gehängt
werden. Die physische Adresse ergibt sich aus
Segmentadresse*16 + Offsetadresse. Dann ist auch logisch, dass sich
alles wiederholt, weil bei Erhöhung der Segmentadresse um 1 alles
nochmal durchlaufen wird - lediglich um 16 Bytes verschoben.
foobar schrieb:>> WIMRE wird der Segment-Teil der Adresse in der oberen Hälfte des>> Pointers gespeichert.>> War das nicht der Unterschied zwischen far und huge? Far: 16 bit> segment plus 16 bit offset in 32bit. Huge: 20 bit address in 32bit,> splitten nach seg/offset bei Zugriff.>> Alles lange her ... ich vermute, fwrite kommt mit den Pointern nicht> klar, kann nur 16 bit. Mal nen huge-Pointer probiert, selbst> dereferenziert und per fputc ausgegeben?
Danke, das wusste ich noch gar nicht, dass es auch ein huge
Schlüsselwort gibt. Wobei ich das Huge Model schon eingestellt hatte.
Der Dump funktioniert und hat es wohl sogar schon vorher. Bei genauerem
hinsehen am Segmentbeginn Stelle ich fest, dass sie schon
unterschiedlich sind. Allerdings ist da immernoch ein stehendes Bild bei
der Suche nach pnp (Das Programm hat pnp im Namen). Es liegt scheinbar
etwas so 10x im Speicher.
Rolf M. schrieb:> Man muss denke ich auch darauf achten, dass das Programm mit dem> richtigen Speichermodell compiliert wird.>> Mario M. schrieb:>> WIMRE wird der Segment-Teil der Adresse in der oberen Hälfte des>> Pointers gespeichert. Die physische Adresse 0xfabcd wird also als>> 0xfabc000d geschrieben (oder auch 0xf000abcd).>> Eigentlich war es üblich, Segment- und Offsetadresse durch Doppelpunkt> getrennt zu schreiben, da die beiden ja nicht einfach aneinander gehängt> werden. Die physische Adresse ergibt sich aus> Segmentadresse*16 + Offsetadresse. Dann ist auch logisch, dass sich> alles wiederholt, weil bei Erhöhung der Segmentadresse um 1 alles> nochmal durchlaufen wird - lediglich um 16 Bytes verschoben.
Die Programausgabe sagt das auch so, scheint richtig zu sein:
1
0000:0000
2
0000:0010
3
0000:0020
4
…
5
000F:FFD0
6
000F:FFE0
7
000F:FFF0
Um zu meinem eigentlichen Anliegen zu kommen – Plug 'n' Play – einen
$PnP String habe ich nicht im Speicher gefunden. Dabei ist doch heute
alles PnP.
Fragen zu einem PCI Bus Scan gehören wohl eher in einen neuen Thread.
Trotzdem wäre ich euch dankbar, falls jemand der in der DOS Ära schon
aktiv war, den ein oder anderen Buchtipp zum Thema hätte.
Asterix schrieb:> Die Programausgabe sagt das auch so, scheint richtig zu sein:> 0000:0000> 0000:0010> 0000:0020> …> 000F:FFD0> 000F:FFE0> 000F:FFF0
Ja, aber 0001:0000 ist nicht die Adresse bei 64k, also 0x10000, sondern
bei 16 Byte, also 0x10. Es ist ein und die selbe Speicherstelle wie
0000:0010.
Rolf M. schrieb:> Asterix schrieb:>> Die Programausgabe sagt das auch so, scheint richtig zu sein:>> 0000:0000>> 0000:0010>> 0000:0020>> …>> 000F:FFD0>> 000F:FFE0>> 000F:FFF0>> Ja, aber 0001:0000 ist nicht die Adresse bei 64k, also 0x10000, sondern> bei 16 Byte, also 0x10. Es ist ein und die selbe Speicherstelle wie> 0000:0010.
Danke, jetz funktioniert das Programm. In der Segmentadresse*16 +
Offsetadresse Konfiguration bekomm ich zwar leider in meiner for
Schleife einen Overflow. Einen größeren Integer hab ich nicht und eine
do while will ich nicht, deswegen hab ich die Segmentadresse soweit
verkleinert, dass ich sie mit 65536 multiplizieren kann. Leider habe ich
das Gefühl das Ganze fundamental falsch zu verwenden, da es ja
eigentlich eine Optimierung auf kurze Datentypen ist.
Hier noch der Vollständigkeit halber das neue Programm:
Jetzt kann ich im spezifizierten Bereich auch zweimal den String $PnP
finden. Bin schon gespannt was das wohl für Geräte sind, schlißlich hat
der Laptop mehr als zwei Komponenten.
foobar schrieb:>> WIMRE wird der Segment-Teil der Adresse in der oberen Hälfte des>> Pointers gespeichert.>> War das nicht der Unterschied zwischen far und huge? Far: 16 bit> segment plus 16 bit offset in 32bit. Huge: 20 bit address in 32bit,> splitten nach seg/offset bei Zugriff.>> Alles lange her ... ich vermute, fwrite kommt mit den Pointern nicht> klar, kann nur 16 bit. Mal nen huge-Pointer probiert, selbst> dereferenziert und per fputc ausgegeben?
Aus dem was in der Turbo C++ Hilfe zum Large und Huge Model steht, werd
ich auch noch nicht ganz schlau. Bedeutet das, dass ich im Large Model
Funktionspointer verwenden müsste und im Huge Model tuts auch ein
Voidpointer? Hab von der Hilfe mal zwei Screenshots angehängt.
Man kann auch das Debug Programm in FreeDos benutzen. Das kann man
umschalten zwischen 16 und 32 Bit und sich außerdem MMX/SSE/FPU Register
anzeigen lassen.
Mit dem Watcom-Compiler kann man "Protected-Mode"-Programme erstellen,
wenn man die "386"-Version des Compilers aufruft.
https://en.wikipedia.org/wiki/Watcom_C/C%2B%2Bhttps://en.wikipedia.org/wiki/Open_Watcom_Assembler
Da das Vi-Programm auch in einer 32-Bit-Protected-Mode-Variante
vorliegt, kann man es direkt in der Windows(8)konsole benutzen, man
braucht keinen Emulator.
Technisch gesehen - also wenn man weiß, was man im Hexeditor
hinzuschreiben hat, kann man in FreeDos das kleinste "Speichermodell"
nehmen (nur ein Segment, Sprünge (möglichst) nur innerhalb von 100h.
(z.B.)
Im Real Mode werden zum Zugriff auf den Speicher die Segmentregister
benötigt.
Abhängig vom Speichermodell werden die teilweise auf konstante Werte
gesetzt um das umkopieren zu sparen.
Im Large Model darf ein Datenobjekt (Array, Struct, Pointer) nur 64 kB
groß sein.
Beim Zugriff wird nur der Index geändert, Data Segment Register (DS)
zeigt auf den Anfang.
Im Huge Model wird auch das DS geändert.
Das braucht mehr Code, daher verzichtet man darauf gerne.
Dirk B. schrieb:> Das braucht mehr Code, daher verzichtet man darauf gerne.
Vor allem können Segmentregister nicht direkt beschrieben/bearbeitet
werden. Man muss immer den Umweg über ein anderes Register oder den
Stack gehen. Das bei jedem Speicherzugriff machen zu müssen, ist schon
aufwändig. Bei Large kann man wenigstens durch ein Array iterieren, ohne
das bei jeder einzelnen Iteration machen zu müssen.
georg schrieb:> Wozu überhaupt der ganze Aufwand? DEBUG genügt doch für den angefragten> Zweck. Und für viele andere.
Wozu Fahrrad fahren lernen, es gibt Bus/Papa/Mama.
Vielen Dank für die vielen Antworten. Der PnP Scanner ist jetzt fertig.
In der DosBox findet er zwar leider nichts, auf meinem Laptop bekomm ich
jedoch die folgende Ausgabe. Hab das Prgramm und den Quellcode mal in
den Anhang gepackt.
1
PnP Hardware Scanner 1.0 Alpha
2
Copyright (R) 2019 Asterix
3
Released to the Public Domain
4
5
PnP Device Found at F000:0940
6
Signature: $PnP
7
Version: 10
8
Length: 33
9
Control Field: 0
10
Checksum: 85
11
Event Notification Flag Address: b7a0000
12
Real Mode 16-Bit Offset to Entry Point: 91
13
Real Mode 16-Bit Code Segment Address: 0
14
16-Bit Protected Mode Offset to Entry Point: 68
15
16-Bit Protected Mode Code Segment Base Address: b7a0000
16
OEM Device Identifier: b7a0000
17
Real Mode 16-Bit Data Segment Address: 0
18
16-Bit Protected Mode Data Segment Base Address: b7a0000
Bleibt nur die Frage was das für ein Gerät ist. Die OEM hat ja soweit
ich weiß was mit EISA zu tun.
georg schrieb:> Wozu überhaupt der ganze Aufwand? DEBUG genügt doch für den angefragten> Zweck. Und für viele andere.>> Georg
Storytime – Es war einmal ein Computernutzer mit seiner x86 kompatiblen
Maschine und ihrem Linux. Der dachte sich eines Tages: "I'd prefer
starting my Linux by typing LIN on a DOS prompt over all those
bootloaders." Und alsbald war auch schon DOS installiert. Ein kleines
Skriptchen mit dem wunderschönen Namen LIN.BAT war auch gleich
geschrieben. Und So nahmen die Dinge ihren Lauf.
Es kam der Tag, da blieb der Computernutzer für eine Weile im DOS bevor
er LIN eingab. Er hat ein paar Treiber installiert. Fürs CD-Laufwerk und
die Maus ja sogar für die Netzwerkkarte gabs einen. Damit stand dem
ersten alten Spiel auch nichts mehr im Wege, was dagegen gesprochen
hätte, es nicht auch zu installieren. –
Ja und so kommt das, dass man im 21. Jahrhundert versucht PC Hardware im
Real Mode zu finden. Das Progrämmchen kann vermutlich nur ISA. PCIe ist
soweit ich weiß unter 0xE0000000 - 0xF0000000 zu finden. Schön Memory
Mapped. Werd mal versuchen da mit DEBUG hinzuschauen.
Kennt jemand noch Webseiten zum Thema? Sowas wie vogons oder osdev zum
Beispiel.
S. R. schrieb:> Asterix schrieb:>> Kennt jemand noch Webseiten zum Thema?>> Sowas wie vogons oder osdev zum Beispiel.>> Die deutsche Variante von osdev wäre auf> http://www.lowlevel.eu/wiki/Hauptseite zu finden. :-)
Dankeschön, die kannte ich noch nicht.
S. R. schrieb:> Asterix schrieb:>> Storytime>> Kann LOADLIN überhaupt noch aktuelle Kernel starten?
Nein, da hast Du recht LOADLIN hat da Probleme. Mit LINLD von hier
https://busybox.net/~vda/linld und ein klein wenig concat Magic für die
Microcodeupdates gehts. Die LIN.BAT sieht ungefähr so aus:
cppbert3 schrieb:> https://superuser.com/questions/727226/how-to-list-hardware-in-dos>> Hier werden ein paar dos tools aufgefuehrt hwinfo sieht ganz gut aus
Das stimmt, HWINFO ist gut. Einzige Schattenseite ist, dass es Unmengen
konventionellen Speicher braucht.
Als nächstes werde ich mich mal dem ACPI widmen. Damit kann man die
Basisadresse der PCI(e) Memory Map finden. Soweit ich das verstanden
habe, ist mit dem PCIe Interface ja auch Zugriff auf PCI Geräte möglich.
Hier noch jemand der das mal umreißt
https://www.waste.org/~winkles/hardware/pci.htm und da die ACPI
Spezifikation
https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
fürs Tabellenlayout.
Leider habe ich Turbo C++ schon wieder zu gunsten von NASM und SmallerC
verlassen. Damit lassen sich Unreal Mode Programme leichter schreiben.
Die DSDT hab ich damit schon gefunden.