mikrocontroller.net

Forum: PC-Programmierung PCI Express Memory Mapping


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Asterix (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <stdio.h>

int main (int argc, char **argv) {
 unsigned int i, bus = 0, dev = 0, fun = 0, reg = 0, pci_index, pci_data;
 unsigned char a, *rsdp, *rsdt, *mcfg, *rsdt_1, *mcfg_0;

 pci_index = (1 << 31) | (bus << 16) | (dev << 11) | (fun << 8)
  | reg;

 for (mcfg = (void *) 0; mcfg < (void *) 0xffffffff; mcfg += 1) {
  if ('M' == mcfg[0] && 'C' == mcfg[1] && 'F' == mcfg[2]
   && 'G' == mcfg[3]) {
   a = 0;
   for (i = 0; i < *((unsigned int *) mcfg[4]); i++) {
    a += mcfg[i];
    if (4096 > *((unsigned int *) mcfg[4]))
     printf ("%u, %hhu\n", a, mcfg[i]);
   }
   if (!a) {
    for (i = 44; i < *((unsigned int *) mcfg[4]); i += 16) {
     printf (stdout, "PCI Segment Group: %hu\n", (short *) mcfg[i+8]);
     printf (stdout, "From Bus Nr: %hhu\n", (char *) mcfg[i+10]);
     printf (stdout, "To Bus Nr: %hhu\n", (char *) mcfg[i+11]);
     printf (stdout, "Upper Address: %x\n", (void *) mcfg[i]);
     printf (stdout, "Lower Address: %x\n", (void *) mcfg[i+4]);
    }
   } else {
    fprintf (stdout, "Checksum Missmatch in MCFG\n");
   }
  }
 }
 return 0;
}

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

Autor: foobar (Gast)
Datum:

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

Autor: Asterix (Gast)
Datum:

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

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

Autor: foobar (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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].

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Warum verwendest Du nicht die ACPI-Libraries?

https://www.acpica.org/downloads

Autor: Asterix (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
PCI Express Scan 1.0 Alpha
Copyright (R) 2019  Asterix
Released to the Public Domain

RSDP found at 0xf0110 Checksum OK
Signature: RSD PTR 
Checksum: 0xc7
OEMID: 0x4f4e454c4f56
Revision: 0x2
RSDT Address: 0xbaffe0ac

Valid RSDT found at 0cbaffe0ac
Signature: RSDT
Length: 0x54
Revision: 0x1
Checksum: 0x25
OEMID: 0x4f4e454c4f56
OEM Table ID: 0x302d424320202031
OEM Revision: 0x1
Creator ID: 0x4f4e454c
Creator Revisoin: 0x1
Entry at 0xbaffe0d0 pointing to table FACP at 0xbafef000
Entry at 0xbaffe0d4 pointing to table SLIC at 0xbaffd000
Entry at 0xbaffe0d8 pointing to table SSDT at 0xbaffb000
Entry at 0xbaffe0dc pointing to table ASF! at 0xbaff0000
Entry at 0xbaffe0e0 pointing to table HPET at 0xbafed000
Entry at 0xbaffe0e4 pointing to table APIC at 0xbafec000
Entry at 0xbaffe0e8 pointing to table MCFG at 0xbafeb000
Entry at 0xbaffe0ec pointing to table SSDT at 0xbafea000
Entry at 0xbaffe0f0 pointing to table SSDT at 0xbafe9000
Entry at 0xbaffe0f4 pointing to table UEFI at 0xbafe8000
Entry at 0xbaffe0f8 pointing to table UEFI at 0xbafe7000
Entry at 0xbaffe0fc pointing to table UEFI at 0xbafe6000

MCFG found
Signature: MCFG
Length: 0x3c
Revision: 0x1
Checksum: 0x17
OEMID: 0x4f4e454c4f56
OEM Table ID: 0x302d424320202031
OEM Revision: 0x1
Creator ID: 0x204c5450
Creator Revisoin: 0x1
Lower Base Address Part: 0xf8000000
Upper Base Address Part: 0x0
PCI Offset Number: 0x0
Start PCI Bus Number: 0x0
End PCI Bus Number: 0x3f

Vendor ID: 0x8086, Device ID: 0x104 at Address: 0xf8000000
Vendor ID: 0x8086, Device ID: 0x116 at Address: 0xf8010000
Vendor ID: 0x8086, Device ID: 0x1c3a at Address: 0xf80b0000
Vendor ID: 0x8086, Device ID: 0x1c2d at Address: 0xf80d0000
Vendor ID: 0x8086, Device ID: 0x1c20 at Address: 0xf80d8000
Vendor ID: 0x8086, Device ID: 0x1c10 at Address: 0xf80e0000
Vendor ID: 0x8086, Device ID: 0x1c12 at Address: 0xf80e1000
Vendor ID: 0x8086, Device ID: 0x1c16 at Address: 0xf80e3000
Vendor ID: 0x8086, Device ID: 0x1c26 at Address: 0xf80e8000
Vendor ID: 0x8086, Device ID: 0x1c49 at Address: 0xf80f8000
Vendor ID: 0x8086, Device ID: 0x1c03 at Address: 0xf80fa000
Vendor ID: 0x8086, Device ID: 0x1c22 at Address: 0xf80fb000
Vendor ID: 0x168c, Device ID: 0x2b at Address: 0xf8200000
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.

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Asterix (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
typedef int int32;
...
int32 i = 42;
printf ("%d", i);

TurboC++ hat 16 Bit Integer und 32 Bit Long
typedef long int32;
...
int32 i = 42;
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?

Autor: foobar (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);
#include <inttypes.h>
...
int32_t = 42;
printf("%"PRId32"\n", i)
...

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
foobar schrieb:
> #include <inttypes.h>

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

Autor: cppbert3 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: rbx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: foobar (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: cppbert3 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Asterix (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?
#include <stdio.h>

#define d4 "%d"

typedef int i32;

int main (void) {
        i32 i = 42;

        printf (d4"\n", i);

        return 0;
}

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

Autor: foobar (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
typedef uint32_t u32;
typedef int32_t  s32;
#define FU32     PRIu32
#define FS32     PRId32
...

Autor: Asterix (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.