Forum: PC-Programmierung PCI Express Memory Mapping


von Asterix (Gast)


Lesenswert?

Könnte mir bitte jemand enen Tipp geben, was mit meinem Code nicht 
stimmt. Er soll die ACPI MCFG Tabelle im Speicher finden. Jetzt war ich 
schon auf einem guten Weg und hab den RSDP und die RSDT gefunden. Nur in 
der RSDT gab es keinen Hinweis auf die MCFG. Das folgende Programm sucht 
deshalb mit Brute Force Methoden nach der MCFG Tabelle im ganzen 
Speicher bis 4 GB. Allerdings bin ich mir auch beim Tabellenlayout, was 
ich auf osdev https://wiki.osdev.org/PCI_Express gefunden habe, 
besonders bei der Prüfsumme nicht ganz sicher.
1
#include <stdio.h>
2
3
int main (int argc, char **argv) {
4
 unsigned int i, bus = 0, dev = 0, fun = 0, reg = 0, pci_index, pci_data;
5
 unsigned char a, *rsdp, *rsdt, *mcfg, *rsdt_1, *mcfg_0;
6
7
 pci_index = (1 << 31) | (bus << 16) | (dev << 11) | (fun << 8)
8
  | reg;
9
10
 for (mcfg = (void *) 0; mcfg < (void *) 0xffffffff; mcfg += 1) {
11
  if ('M' == mcfg[0] && 'C' == mcfg[1] && 'F' == mcfg[2]
12
   && 'G' == mcfg[3]) {
13
   a = 0;
14
   for (i = 0; i < *((unsigned int *) mcfg[4]); i++) {
15
    a += mcfg[i];
16
    if (4096 > *((unsigned int *) mcfg[4]))
17
     printf ("%u, %hhu\n", a, mcfg[i]);
18
   }
19
   if (!a) {
20
    for (i = 44; i < *((unsigned int *) mcfg[4]); i += 16) {
21
     printf (stdout, "PCI Segment Group: %hu\n", (short *) mcfg[i+8]);
22
     printf (stdout, "From Bus Nr: %hhu\n", (char *) mcfg[i+10]);
23
     printf (stdout, "To Bus Nr: %hhu\n", (char *) mcfg[i+11]);
24
     printf (stdout, "Upper Address: %x\n", (void *) mcfg[i]);
25
     printf (stdout, "Lower Address: %x\n", (void *) mcfg[i+4]);
26
    }
27
   } else {
28
    fprintf (stdout, "Checksum Missmatch in MCFG\n");
29
   }
30
  }
31
 }
32
 return 0;
33
}

Dieses Programm wurde mit SmallerC und FASM kompiliert und auf FreeDOS 
ausgefürt.

von foobar (Gast)


Lesenswert?

Läuft unter FreeDOS und greift direkt flat auf 4GB zu?  Das soll gehen?

von Asterix (Gast)


Lesenswert?

foobar schrieb:
> Läuft unter FreeDOS und greift direkt flat auf 4GB zu?  Das soll gehen?

Im Unreal Mode.
1
smlrcc -dosu -o pciescan.exe main.c

von foobar (Gast)


Lesenswert?

> Im Unreal Mode.

Ah, ok. Ist komplett an mir vorbeigegangen.

> ... besonders bei der Prüfsumme nicht ganz sicher.

Dann such doch erstmal ohne Prüfsummentest.

> for (i = 0; i < *((unsigned int *) mcfg[4]); i++)

Ich denke, da fehlt ein "&" vor dem mcfg[4].

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Warum verwendest Du nicht die ACPI-Libraries?

https://www.acpica.org/downloads

von Asterix (Gast)


Angehängte Dateien:

Lesenswert?

Rufus Τ. F. schrieb:
> Warum verwendest Du nicht die ACPI-Libraries?
>
> https://www.acpica.org/downloads

Danke für den Tipp, ob das wohl auf DOS compiliert?

Habs mittlerweile auch so hinbekommen, mit jetzt etwas besser 
organisiertem Code wars mir möglich mich durch die ACPI Tabellen zu 
hangeln. Es werden die Tabellen auf dem Weg zur MCFG ausgegeben und dann 
folgen alle PCI/PCIe Geräte mit ihren Addressen. Die Ausgabe sieht wie 
folgt aus:
1
PCI Express Scan 1.0 Alpha
2
Copyright (R) 2019  Asterix
3
Released to the Public Domain
4
5
RSDP found at 0xf0110 Checksum OK
6
Signature: RSD PTR 
7
Checksum: 0xc7
8
OEMID: 0x4f4e454c4f56
9
Revision: 0x2
10
RSDT Address: 0xbaffe0ac
11
12
Valid RSDT found at 0cbaffe0ac
13
Signature: RSDT
14
Length: 0x54
15
Revision: 0x1
16
Checksum: 0x25
17
OEMID: 0x4f4e454c4f56
18
OEM Table ID: 0x302d424320202031
19
OEM Revision: 0x1
20
Creator ID: 0x4f4e454c
21
Creator Revisoin: 0x1
22
Entry at 0xbaffe0d0 pointing to table FACP at 0xbafef000
23
Entry at 0xbaffe0d4 pointing to table SLIC at 0xbaffd000
24
Entry at 0xbaffe0d8 pointing to table SSDT at 0xbaffb000
25
Entry at 0xbaffe0dc pointing to table ASF! at 0xbaff0000
26
Entry at 0xbaffe0e0 pointing to table HPET at 0xbafed000
27
Entry at 0xbaffe0e4 pointing to table APIC at 0xbafec000
28
Entry at 0xbaffe0e8 pointing to table MCFG at 0xbafeb000
29
Entry at 0xbaffe0ec pointing to table SSDT at 0xbafea000
30
Entry at 0xbaffe0f0 pointing to table SSDT at 0xbafe9000
31
Entry at 0xbaffe0f4 pointing to table UEFI at 0xbafe8000
32
Entry at 0xbaffe0f8 pointing to table UEFI at 0xbafe7000
33
Entry at 0xbaffe0fc pointing to table UEFI at 0xbafe6000
34
35
MCFG found
36
Signature: MCFG
37
Length: 0x3c
38
Revision: 0x1
39
Checksum: 0x17
40
OEMID: 0x4f4e454c4f56
41
OEM Table ID: 0x302d424320202031
42
OEM Revision: 0x1
43
Creator ID: 0x204c5450
44
Creator Revisoin: 0x1
45
Lower Base Address Part: 0xf8000000
46
Upper Base Address Part: 0x0
47
PCI Offset Number: 0x0
48
Start PCI Bus Number: 0x0
49
End PCI Bus Number: 0x3f
50
51
Vendor ID: 0x8086, Device ID: 0x104 at Address: 0xf8000000
52
Vendor ID: 0x8086, Device ID: 0x116 at Address: 0xf8010000
53
Vendor ID: 0x8086, Device ID: 0x1c3a at Address: 0xf80b0000
54
Vendor ID: 0x8086, Device ID: 0x1c2d at Address: 0xf80d0000
55
Vendor ID: 0x8086, Device ID: 0x1c20 at Address: 0xf80d8000
56
Vendor ID: 0x8086, Device ID: 0x1c10 at Address: 0xf80e0000
57
Vendor ID: 0x8086, Device ID: 0x1c12 at Address: 0xf80e1000
58
Vendor ID: 0x8086, Device ID: 0x1c16 at Address: 0xf80e3000
59
Vendor ID: 0x8086, Device ID: 0x1c26 at Address: 0xf80e8000
60
Vendor ID: 0x8086, Device ID: 0x1c49 at Address: 0xf80f8000
61
Vendor ID: 0x8086, Device ID: 0x1c03 at Address: 0xf80fa000
62
Vendor ID: 0x8086, Device ID: 0x1c22 at Address: 0xf80fb000
63
Vendor ID: 0x168c, Device ID: 0x2b at Address: 0xf8200000
64
Vendor ID: 0x10ec, Device ID: 0x8168 at Address: 0xf8300000

Eine mit SmallerC und NASM kompilierte EXE samt Quellcode hab ich 
angehängt. Die Ausgabe ist von meinem Laptop. Unter DOSBox werden keine 
ACPI Tabellen gefunden.

PS: Falls meinen Code jemand gelesen haben sollte, ein paar typedefs 
wären sicher hilfreich gewesen, allerdings ist mir nie ganz klar 
geworden wie sich die mit printf() in einer portablen Art und Weise 
einsetzen lassen. Für Tipps wäre ich Euch dankbar.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Asterix schrieb:
> ob das wohl auf DOS compiliert?

Da Du eh' einen DOS-Extender und einen 32-Bit-Compiler verwendest, warum 
nicht?

> ein paar typedefs wären sicher hilfreich gewesen, allerdings ist mir
> nie ganz klar geworden wie sich die mit printf() in einer portablen Art
> und Weise einsetzen lassen.

Stell 'ne konkrete Frage, dann kann Dir vielleicht geholfen werden.
Warum muss da was "portabel" sein?

von Asterix (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
>> ein paar typedefs wären sicher hilfreich gewesen, allerdings ist mir
>> nie ganz klar geworden wie sich die mit printf() in einer portablen Art
>> und Weise einsetzen lassen.
>
> Stell 'ne konkrete Frage, dann kann Dir vielleicht geholfen werden.
> Warum muss da was "portabel" sein?

Ok, ich versuchs nochmal:

SmallerC hat 32 Bit Integer
1
typedef int int32;
2
...
3
int32 i = 42;
4
printf ("%d", i);

TurboC++ hat 16 Bit Integer und 32 Bit Long
1
typedef long int32;
2
...
3
int32 i = 42;
4
printf ("%ld", i);

Mit ein paar typedefs am Anfang des Programms ließen sich einfach an 
einer zentralen Stelle die Längen der verwendeten Datentypen für einen 
gegeben Compiler einstellen. Allerdings müssen dann die printf()s wieder 
alle angepasst werden. Deswegen würde ich gerne erfahren ob bzw. wie 
sich das vermeiden lässt.

Rufus Τ. F. schrieb:
> Asterix schrieb:
>> ob das wohl auf DOS compiliert?
>
> Da Du eh' einen DOS-Extender und einen 32-Bit-Compiler verwendest, warum
> nicht?

Ok? Würde mich freuen wenn Du mir das erläutern könntest. Nach meinem 
Wissensstand gibt es:

-Real Mode (16 Bit)
-Protected Mode (16/32/64 Bit)

Jetzt dacht ich mit einem DOS-Extender lande ich im Protected Mode. 
Während mit dem Unreal Mode gemeint wäre auf 32-Bit zu schalten und dann 
zurück in den Real Mode zu gehen, so dass sich die 32-Bit-Register 
weiternutzen lassen, allerdings ohne Speicherschutz?

von foobar (Gast)


Lesenswert?

> Allerdings müssen dann die printf()s wieder
> alle angepasst werden. Deswegen würde ich gerne erfahren ob bzw. wie
> sich das vermeiden lässt.
> ...
> int32 i = 42;
> printf ("%ld\n", i);
1
#include <inttypes.h>
2
...
3
int32_t = 42;
4
printf("%"PRId32"\n", i)
5
...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

foobar schrieb:
> #include <inttypes.h>

Ob der fossile Turbo-C-Compiler für DOS, der hier verwendet wird, diese 
Datei kennt?

von cppbert3 (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> foobar schrieb:
>> #include <inttypes.h>
>
> Ob der fossile Turbo-C-Compiler für DOS, der hier verwendet wird, diese
> Datei kennt?

Bestimmt nicht

von rbx (Gast)


Lesenswert?


von foobar (Gast)


Lesenswert?

>>> #include <inttypes.h>
>>
>> Ob der fossile Turbo-C-Compiler für DOS, der hier verwendet wird, diese
>> Datei kennt?
>
> Bestimmt nicht

Ist halt eine verbreitete API - warum was Neues erfinden?  An inttypes.h 
ist nichts Magisches - für einen konkreten Compiler kann man das selbst 
erstellen, evtl reduziert auf die benötigten bzw unterstützten Elemente.

von cppbert3 (Gast)


Lesenswert?

foobar schrieb:
>>>> #include <inttypes.h>
>>>
>>> Ob der fossile Turbo-C-Compiler für DOS, der hier verwendet wird, diese
>>> Datei kennt?
>>
>> Bestimmt nicht
>
> Ist halt eine verbreitete API - warum was Neues erfinden?  An inttypes.h
> ist nichts Magisches - für einen konkreten Compiler kann man das selbst
> erstellen, evtl reduziert auf die benötigten bzw unterstützten Elemente.

Das sind die typedefs die er erwaehnt hat, aber printf liefert dann 
immer noch warnungen, weil dessen implementierung bei so alten kompiler 
auch noch starke unterschiede aufweisen

Aber wieso ueberhaupt mehrere kompiler supporten?

von Asterix (Gast)


Lesenswert?

rbx schrieb:
> Asterix schrieb:
>> allerdings ohne Speicherschutz?
>
> http://www.os2museum.com/wp/a-brief-history-of-unreal-mode/
>
> ( http://qlibdos32.sourceforge.net/files/dpmispec.zip )
>
> ( https://open-watcom.github.io/travis-ci-ow-builds/pguide.pdf )

Danke, diese QLib finde ich sehr interessant. Die merk ich mir mal vor 
für den Tag an dem ich mich mit DPMI beschäftigen werde.

foobar schrieb:
>> Allerdings müssen dann die printf()s wieder
>> alle angepasst werden. Deswegen würde ich gerne erfahren ob bzw. wie
>> sich das vermeiden lässt.
>> ...
>> int32 i = 42;
>> printf ("%ld\n", i);
> #include <inttypes.h>
> ...
> int32_t = 42;
> printf("%"PRId32"\n", i)
> ...

Das scheint mir der richtige Weg zu sein. Jetzt müssen sich nur noch 
meine Augen an diesen zuerst etwas unästhetischen Anblick gewöhnen. :)

cppbert3 schrieb:
> foobar schrieb:
>>>>> #include <inttypes.h>
>>>>
>>>> Ob der fossile Turbo-C-Compiler für DOS, der hier verwendet wird, diese
>>>> Datei kennt?
>>>
>>> Bestimmt nicht
>>
>> Ist halt eine verbreitete API - warum was Neues erfinden?  An inttypes.h
>> ist nichts Magisches - für einen konkreten Compiler kann man das selbst
>> erstellen, evtl reduziert auf die benötigten bzw unterstützten Elemente.
>
> Das sind die typedefs die er erwaehnt hat, aber printf liefert dann
> immer noch warnungen, weil dessen implementierung bei so alten kompiler
> auch noch starke unterschiede aufweisen
>
> Aber wieso ueberhaupt mehrere kompiler supporten?

Wieder mal alles kein Hexenwerk. Hab mal genauer reingeschaut und 
festgestellt, dass PRId32 auch nur ein String Makro ist, also "d" oder 
"ld" etc. – was auch sonst. Drum hab ich mal selbst was definiert. Jetzt 
stellt sich mir nur die Frage ob ich in Zukunft das Prozentzeichen in 
die Konstante lege oder nicht. Wie ihr gleich seht tendiere ich stark 
dazu, spricht aus Eurer Sicht was dagegen?
1
#include <stdio.h>
2
3
#define d4 "%d"
4
5
typedef int i32;
6
7
int main (void) {
8
        i32 i = 42;
9
10
        printf (d4"\n", i);
11
12
        return 0;
13
}

Das hat bei mir unter Linux mit GCC 8.3.0 mit -Wall und -Wextra ohne 
meckern kompiliert.

von foobar (Gast)


Lesenswert?

>> printf("%"PRId32"\n", i)
> ... etwas unästhetischen Anblick

Ja, es ist häßlich, aber nicht wirklich anders zu lösen ohne printf zu 
ändern und außerdem Standard.

> Drum hab ich mal selbst was definiert.

NIH-Syndrom.

> Jetzt stellt sich mir nur die Frage ob ich in Zukunft das
> Prozentzeichen in die Konstante lege oder nicht.

Nicht. Sonst kannst du keine Flags und Breiten mehr spezifizieren.

Wenn dir ANSI-Namen zu häßlich sind, mach dir Aliase:
1
typedef uint32_t u32;
2
typedef int32_t  s32;
3
#define FU32     PRIu32
4
#define FS32     PRId32
5
...

von Asterix (Gast)


Lesenswert?

foobar schrieb:
>>> printf("%"PRId32"\n", i)
>> ... etwas unästhetischen Anblick
>
> Ja, es ist häßlich, aber nicht wirklich anders zu lösen ohne printf zu
> ändern und außerdem Standard.

Deswegen sag ich gewöhnen. Hab mal irgendwo gelesen, dass bei 
Programmierern wenn sie Code sehen die gleichen Hirnareale anspringen 
wie bei einem Maler wenn er ein Bild sieht. Wahrscheinlich wirds nicht 
lange dauern bis ich PRId32 schöner finde als %d.

>> Drum hab ich mal selbst was definiert.
>
> NIH-Syndrom.

Damit kämpf ich zwar auch von Zeit zu Zeit, wobei es mir hier mir mehr 
um C89 geht.

>> Jetzt stellt sich mir nur die Frage ob ich in Zukunft das
>> Prozentzeichen in die Konstante lege oder nicht.
>
> Nicht. Sonst kannst du keine Flags und Breiten mehr spezifizieren.

Danke Dir, dass ist ein wertvoller Tipp.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.