Device Tree unter Linux auslesen

OP #3285773
Es geht um einen Altera FPGA mit NIOS II Prozessor, auf dem Linux 3.7 
läuft. Der Kernel verwendet einen Device Tree zur Geräteerkennung, was 
auch korrekt funktioniert. Nun würde ich gerne Teile des Device Trees 
auslesen, um sie für eigene Treiber zu nutzen. Z.B. würde ich gerne die 
property "reg" aus folgendem Knoten lesen:

1
memory@0 {
2
  device_type = "memory";
3
  reg = < 0x11000000 0x00080000
4
    0x11085000 0x00000400
5
    0x00000000 0x08000000>;
6
};

Im /proc-Dateisystem sieht die property folgendermassen aus:

1
root:/proc/device-tree/memory@0> hexdump -C reg 
2
00000000  17 03 00 21 26 f0 3f 20  17 00 40 81 26 f2 03 28  |...!&.? ..@.&..(|
3
00000010  17 01 c0 80 17 00 c0 89                           |........|
4
00000018

Wat is'n das fürn sinnloser Brei? Wo sind meine reg-Werte 0x11000000 
usw.? Ich habe auch versucht, die Werte direkt aus meinem Treiber 
(Kernelmodul) zu lesen:

1
dt_node = of_find_node_by_path("/memory@0");
2

3
struct property *pp;
4
u32 reg[6];
5
for_each_property_of_node(dt_node, pp) {
6
  printk("property name: %s, length: %d\n", pp->name, pp->length);
7
  if (pp->length == 24) {
8
    if (!of_property_read_u32_array(dt_node, pp->name, reg, 6))
9
  printk("reg: %x %x %x %x\n", reg[0], reg[1], reg[2], reg[3]);
10
  }
11
}

Der Code hat mich mit folgendem Output beglückt:

1
[ 1881.948000] property name: ���=, length: 7
2
[ 1881.948000] property name: &I>0�������1��, length: 24
3
[ 1881.948000] reg: 17030021 26f03f20 17004081 26f20328
4
[ 1881.948000] property name: name, length: 7

Leider wieder der gleiche Datenmüll wie in der /proc-Datei. Was mache 
ich falsch?
Gast
Benutzt du eine initrd Ramdisk oder ein intramfs? Bei letzterem hatte 
ich schon das prblem, das /proc/device-tree überschreiben worden ist, 
wenn das RAM knapp geworden is...
Gast
Ich weiss nicht mehr woran es lag, allerdings war /proc/device-tree 
Mist, solange ich ein initramfs benutzt habe...

Andere Möglichkeit:
Kleines C-Programm um den device-tree als binary aus dem speicher zu 
holen und dann mit der libfdt auslesen. Klappt super.
Gast
Also die libfdt ist ja ziemlich selbsterklärend. Man muss nur den Buffer 
mit dem Device-Tree-Binary übergeben, und kann dann ziemlich alles damit 
anstellen.

Wo der Device-Tree liegt hängt natürlich von deinem Board ab. Irgendwo 
im Flash, also evtl in einem der /dev/mtdX

Der Device-Tree wird ja vom Bootloader beim Start an den Kernel 
übergeben, also irgendwo im Speicehr wird er schon sein.

Die unelegante(aber sehr effektive) Methode wäre /dev/mem zu beutzen um 
den Speicher zu lesen...
OP
Ich hab die Wurzel des Problems gefunden: Der Device-Tree-Speicher wird 
vom Kernel freigegeben, sobald er nicht mehr benötigt wird, d.h. nachdem 
der Tree vom Kernel ausgewertet wurde. Wenn ich mein Modul, das den Baum 
liest, direkt in den Kernel kompiliere, sehe ich die richtigen Werte 
statt binären Datenmüll. Hat jemand eine Idee, wie man es unterbinden 
kann, dass der Kernel den Devtree-Speicher freigibt?
OP
Für die Nachwelt: Das Freigeben des Device-Tree-Speichers durch den 
Kernel kann mit einer einfachen Code-Modifikation vermieden werden. Vor 
dem Aufruf von unflatten_device_tree() sind folgende Zeilen einzufügen:
1
void *fdt_copy;
2
fdt_copy = alloc_bootmem(size);
3
memcpy(fdt_copy, initial_boot_params, size);
4
initial_boot_params = fdt_copy;

Dies erstellt eine Kopie des Device-Trees in einem Speicherbereich, der 
nicht freigegeben wird. Wo genau unflatten_device_tree() aufgerufen 
wird, ist architekturabhängig.
Gast
segfault (core dumped) schrieb:
> Für die Nachwelt: Das Freigeben des Device-Tree-Speichers durch den
> Kernel kann mit einer einfachen Code-Modifikation vermieden werden. Vor
> dem Aufruf von unflatten_device_tree() sind folgende Zeilen einzufügen:
> void *fdt_copy;
> fdt_copy = alloc_bootmem(size);
> memcpy(fdt_copy, initial_boot_params, size);
> initial_boot_params = fdt_copy;
> Dies erstellt eine Kopie des Device-Trees in einem Speicherbereich, der
> nicht freigegeben wird. Wo genau unflatten_device_tree() aufgerufen
> wird, ist architekturabhängig.

irgendwie sieht das merkürdig aus.

da kannst du auch gleich
1
initial_boot_params = alloc_bootmem(1);

oder
1
initial_boot_params = null;

schreiben.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 13 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.