Device Tree unter Linux auslesen

OP #3285773
Lesenswert?

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 #3286280
Lesenswert?

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 #3287932
Lesenswert?

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 #3298284
Lesenswert?

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 #3476371
Lesenswert?

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 #3476382
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren