Forum: Compiler & IDEs Linux Kernel compilieren


von Alfons (Gast)


Lesenswert?

Hallo Leute,

ich möchte einen Linux Kernel selber bauen. Bevor ihr mir jetzt Google 
um die Ohren haut -- jaaa, ich weiss, es gibt 1000 Seiten zu dem Thema 
:-) aber, ich habe eine sehr spezifische Frage dazu.

Ich arbeite am PC schon unter Linux. Dort habe ich mir diesen Compiler 
installiert:

https://launchpad.net/gcc-arm-embedded

der funktioniert auch und man kann damit Programme compilieren. Soweit 
so gut. Damit möchte ich nun den Linux Kernel compilieren! Das 
Zielsystem ist ein ARM7TDMI, da ich sowas gleich auf dem Tisch liegen 
habe und testen kann (nachher wird es dann ein 'echtes' System mit MMU 
etc.). Ich habe

make ARCH=arm versatile_defconfig

ausgeführt, und anschliessend

make ARCH=arm menuconfig

gemacht. Dort habe ich einfach so ziemlich alles deaktiviert, um 
mögliche Fehlerquellen auszuschalten - es soll vorerst mal so wenig wie 
möglich mit rein compiliert werden. So, das hat auch funktioniert!

Nachdem menuconfig durch war, habe ich

make ARCH=arm all

ausgeführt. Das hat ungefähr 20 Minuten gerattert, und jetzt habe ich ne 
Meldung


...
  GEN     .version
  CHK     include/generated/compile.h
  UPD     include/generated/compile.h
  CC      init/version.o
  LD      init/built-in.o
arm-none-eabi-ld: no machine record defined
make: *** [vmlinux] Error 1


Was bedeutet dies? muss ich in menuconfig noch mehr Sachen einstellen, 
oder bedeutet dies etwa, dass dieser Linker gar nicht für meine 
Plattform funktioniert? ich steh grade auf dem Schlauch, aber ich bin 
sicher hier gibt es ein paar Leute die sowas schon mal gemacht haben und 
mir weiterhelfen können.


Gruss

von holger (Gast)


Lesenswert?

>Das Zielsystem ist ein ARM7TDMI

Auf so einem ARM läuft kein Linux. Wenn überhaupt dann uCLinux.
Das aber auch nur wenn du mindestens 2MB RAM hast.

von Alfons (Gast)


Lesenswert?

Ja, aber uClinux ist jetzt im normalen Kernel dabei. Siehe Wikipedia.
Dass ich keine MMU habe weiss ich wohl, danke trotzdem.
Und RAM habe ich 32MB, sollte auch reichen ;-)

von ... (Gast)


Lesenswert?

Mit diesem Compiler kannst du Linux nicht kompilieren. Du musst den 
Compiler so compilieren, das er die C-Bibliothek und die Header von 
deinem Cross-Linux verwendet. Bei "cross linux from scratch" ist das im 
Detail beschrieben.

von Alfons (Gast)


Lesenswert?

Hallo,

also ich bin nun schon wesentlich weiter!
Ich habe unter menuconfig die ARM7TDMI CPU aktiviert, sowie den Support 
für Ethernet aktiviert. Ich kann den Kernel nun compilieren!

und zwar mit

make ARCH=arm VERSATILE_DEFCONFIG=y all

und unter arm/boot habe ich dann zwei interessante Dateien:

Image (3.3MB)
zImage (1.7MB)

in einem anderen Tutorial habe ich gelesen, dass man diese nur erhält, 
wenn alles erfolgreich compiliert worden ist. Also, die Dateien habe ich 
schon mal. So wie ich das jetzt verstehe, müsste man diese nun auf das 
Target ins SDRAM laden (vorher dekomprimieren bei zImage) und dann kann 
man das Dingens ausführen, richtig?

Mir stellt sich noch die Frage, wie ich dem Teil verklickere, dass ich 
einen LPC2468 habe, der mit einem PHY ans Ethernet angeschlossen ist. 
Von sich aus kann der Kernel das ja nicht einfach so wissen.... :-/


Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Das ist kein Compiler Fehler.

Alfons schrieb:
> arm-none-eabi-ld: no machine record defined

Das sagt fast schon alles aus ;-)

Schau mal unter
System Type -> Versatile platform type
da muss eine Option aktiviert sein.

Welche genau solltest du selber wissen (Hardwareabhängig).
ARM7TDMI beschreibt nur die CPU.
Wo jetzt die serielle Schnittstelle usw. zu finden ist, das beschreibt 
der mach-record in
arch/arm/mach-*

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

ja wie gesagt, der Kernel compiliert jetzt schon mal! :-)
ich hab die zImage und die Image Datei. Das ist schonmal gut, oder? mit 
denen kann man mal was machen, ja?

Ich frage mich jetzt noch, wie man das dem Kernel verklickern kann, dass 
ich da noch einen PHY dran habe (initialisierung der IO Pins?) und dass 
ich gerne eine Shell auf der seriellen Schnittstelle starten möchte (so 
für erste Testzwecke, das sollte doch möglich sein via UART, oder?).

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> und unter arm/boot habe ich dann zwei interessante Dateien:
>
> Image (3.3MB)
> zImage (1.7MB)
>
> in einem anderen Tutorial habe ich gelesen, dass man diese nur erhält,
> wenn alles erfolgreich compiliert worden ist. Also, die Dateien habe ich
> schon mal. So wie ich das jetzt verstehe, müsste man diese nun auf das
> Target ins SDRAM laden (vorher dekomprimieren bei zImage) und dann kann
> man das Dingens ausführen, richtig?

Es gibt noch ein uImage, das für den Bootloader uBoot gedacht ist.

Alfons schrieb:
>
> Mir stellt sich noch die Frage, wie ich dem Teil verklickere, dass ich
> einen LPC2468 habe, der mit einem PHY ans Ethernet angeschlossen ist.
> Von sich aus kann der Kernel das ja nicht einfach so wissen.... :-/
>

PHY und MAC sind wichtig.
soweit ich weis gibt es für den LPC2468 auch einen mach Record.
Gibt es eine Herstellerbezeichnung von dem Board.

ggf. Teste mal diese Config
lpc32xx_defconfig

von Alfons (Gast)


Lesenswert?

Ein uImage taucht bei mir nicht auf. Das kann ich aber sicher im 
menuconfig irgendwo einstellen, oder?

Woher kann ich den mach-Record für den 2468 her kriegen? ich erinnere 
mich, auch mal sowas gesehen zu haben, aber unter kernel.org gibts das 
nicht, und ich weiss nicht mehr wo ich das teil gefunden habe.

Von dem Board gibt es leider keine Herstellerbezeichnung, da ich es 
selber gebaut habe ;-) Aber es gibt z.B. das Embedded Artists LPC2468 
OEM Board, oder dasjenige von Olimex, von denen ich weiss dass da 
uClinux drauf läuft. Also muss es auch den mach record geben ;-)

"Teste diese config" heisst

make ARCH=arm lpc32xx_defconfig

ja?

von Hans Ulli K. (Gast)


Lesenswert?

Ich bin noch am suchen.

Ich hatte auch mal eine amch Record für den lpc24xx gefunden und wollte 
diesen mal mit meinen Source vergleichen, habe aber leider die Seite 
gleschlossen.

Ich habe dafür ein paar andere git-Trees gefunden.
http://git.lpclinux.com/

Ist das zufällig die Platine von Embedded Projects ??

von Hans Ulli K. (Gast)


Lesenswert?

So Quelle war auf Google source
http://code.google.com/p/te-lpc2478lcd35/

Leider ein svn Repo ...
Aber zum ansehen reicht es mir ...

von Hans Ulli K. (Gast)


Lesenswert?

Wenn mann sich die Datei
arch/arm/mach-lpc22xx/lpc2468_devices.c
ansehe, sehe ich
DMA, TIMER, USB, GPIO.

Der Kernel ist etwas alt
2.6.24.2

Und der lpc24xx ist mit dem lpc24xx verwandt.

Du brauchst ausserdem noch eine libc und einige Tools.

von Andreas B. (andreas_b77)


Lesenswert?

Ein uImage musst du explizit erzeugen, das ist nicht in der 
Konfiguration:
1
make uImage



Ach ja:

... schrieb:
> Mit diesem Compiler kannst du Linux nicht kompilieren. Du musst den
> Compiler so compilieren, das er die C-Bibliothek und die Header von
> deinem Cross-Linux verwendet.

Was ein Schmarrn, der Kernel verwendet keine libc und keine Header die 
er nicht selber mitbringt.

von Alfons (Gast)


Lesenswert?

Hallo Hans Ulli,

danke für den Link, genau diesen Code habe ich gemeint!
Davon kann man ja schon mal ein wenig abkupfern, auch wenns für einen 
veralteten Kernel ist. Ich verwende ja den neuesten Kernel (3.6 oder 
sowas in der Art).

Die libc bringt mein Compiler mit, denke ich... sonst würde der Kernel 
ja auch so schon nicht compilieren, oder? Welche Tools meinst du, die 
ich noch benötige?


Andreas,

dane für den Hinweis. Ich werde das heute Abend gleich testen. Im Moment 
sitze ich am Windows-Rechner ;-)

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Hans Ulli,
>
> danke für den Link, genau diesen Code habe ich gemeint!
> Davon kann man ja schon mal ein wenig abkupfern, auch wenns für einen
> veralteten Kernel ist. Ich verwende ja den neuesten Kernel (3.6 oder
> sowas in der Art).
>

Der Code ist aber nicht in mainline ...
Hier noch eine Mial von dem Entwickler der ein Howto geschrieben hat

http://mailman.uclinux.org/pipermail/uclinux-dev/2007-May/042858.html

Zu den gefundennen git Trees gibt es noch eine Homepage

http://www.lpclinux.com

Ich würde erstmal die Kernelversion in der Mail testen7starten. Erst 
danach ein update auf eine aktuelle Version starten.
Es ändern sich viele Schnittstellen innerhalb des Kernels.

> Die libc bringt mein Compiler mit, denke ich... sonst würde der Kernel
> ja auch so schon nicht compilieren, oder? Welche Tools meinst du, die
> ich noch benötige?
>

Nein die libc ist nicht im Kernel drin. Die wird auch nicht gebraucht um 
den Kernel zu bauen. Das darf es auch nicht, weil sonst hättest du das 
Henne und Ei Problem.

Mit Tools meine ich eine Shell usw.

Habe gerade nochmal in buildroot, da gibt es eine Option für ARM7TDMI.
Da wird ein komplettes RootFS gebaut. Diese kannst du dann ggf. als cpio 
Archiv dem Kernel "unterschieben" (Wird dann zusammen mit dem Kernel 
eine Datei) und dann per TFTP übertragen.

>
> Andreas,
>
> dane für den Hinweis. Ich werde das heute Abend gleich testen. Im Moment
> sitze ich am Windows-Rechner ;-)

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

meinst du direkt mit dem aktuellen Kernel zu starten ist keine gute 
Idee? Da gibt es prinzipiell ja auch eine Option für ARM7TDMI...


Zu den Tools - ich dachte das ist irgendwie Bestandteil des Kernels. 
Dann halt doch nicht :-) Die Frage ist - was brauche ich denn noch alles 
dazu? Filesystem, Netzwerk & Co bringt der Kernel ja mit, aber eine 
Shell wiederum nicht?

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli,
>
> meinst du direkt mit dem aktuellen Kernel zu starten ist keine gute
> Idee? Da gibt es prinzipiell ja auch eine Option für ARM7TDMI...
>

Ein aktueller Kernel ist keine gute Idee.
Das die Option für einen ARM7TDMI vorhanden ist, hat nichts damit zu 
tun.

Der Kernel ist, sagen wir mal, zu 99% in C geschrieben.
Der Rest ist in Assembler und eben die Machine Init Routinen.
Letztere sind je nach CPU und Speicheraufteilung unterschiedlich.

Daher immer diese Kernelversion nutzen, die auf dem Board ist. Das da 
auch die Patches für das Board drin sein sollten ist selbstverständlich.
Erst wenn dieser läuft kann man damit beginnen einen (relativ) aktuellen 
Kernel zu verwenden.

Dazu solltest du auch ein Versionkontrollsystem nutzen.
git ist im Linux Kernel die Wahl

>
> Zu den Tools - ich dachte das ist irgendwie Bestandteil des Kernels.
> Dann halt doch nicht :-) Die Frage ist - was brauche ich denn noch alles
> dazu? Filesystem, Netzwerk & Co bringt der Kernel ja mit, aber eine
> Shell wiederum nicht?

schau mal, wie ich gesagt habe, nach buildroot.
Die bauen ein RootFS wie du es haben willst ...

Am bekanntesten ist die Kombination uClibc und busybox. Da kommst du als 
statischen Build so auf 1-2 MByte für das RootFS.

Und wie gesagt, wenn du dieses RootFS als cpio Archiv bauen lässt kannst 
du es in den Kernel-Configs angebeben und der Kernel "baut" das mit ein.

Da brauchst du dir keine gedanken zu machen wo dein RootFS im Speicher 
von deinem Board ist um es wieder dem Kernel zu übergeben.

von Alfons (Gast)


Lesenswert?

Hallo Ulli

vielen herzlichen Dank für deine Hilfe.

Ich meinte bisher immer, dass ich ARM sehr gut kenne, und auch in C und 
ASM sehr fit bin, aber ich merke, die Materie ist sehr komplex. Da kann 
man sich nicht einfach so einarbeiten, ich gebs auf... Das kriege ich 
nicht gebacken, noch mit busybox etc., dazu bin ich was Linux anbelangt 
einfach zu wenig fit. Ich kaufe das fertig ein, das ist am 
einfachsten.... schade eigentlich.
Einen veralteten Kernel will ich nicht benutzen, eigentlich hätte ich 
die aktuelle Version ja auch so weit gehabt, dass das Dingens 
kompiliert.

Naja, danke trotzdem :-)

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli
>
> vielen herzlichen Dank für deine Hilfe.
>
> Ich meinte bisher immer, dass ich ARM sehr gut kenne, und auch in C und
> ASM sehr fit bin, aber ich merke, die Materie ist sehr komplex. Da kann
> man sich nicht einfach so einarbeiten, ich gebs auf... Das kriege ich
> nicht gebacken, noch mit busybox etc., dazu bin ich was Linux anbelangt
> einfach zu wenig fit. Ich kaufe das fertig ein, das ist am
> einfachsten.... schade eigentlich.
> Einen veralteten Kernel will ich nicht benutzen, eigentlich hätte ich
> die aktuelle Version ja auch so weit gehabt, dass das Dingens
> kompiliert.
>

Ja das die Sache nicht einfach ist weiss ich selber aus eigener 
Erfahrung.
Der Kernel ist einfach compilert. Ich habe ja selber vor ca. 4-5 Jahren 
mit dem Kernel Kram angefangen. (Und ich mach das nur privat ...)

Das Problem sind immer die Board spezifischen Sachen. Wobei schon mal 
bei dem RootFS das buildroot System dir fast alles abnimmt.

Wie gesagt wenn du Glück hast und es sind keine spezifischen Devices 
drin. Welche mit einer blöden NDA "lizenziert" werden müssen (also nur 
Treiber die Mainline sind), dann ist der Update auf eine aktuelle 
Kernelversion relativ einfach.

So was ich gesehen habe ist die Platform LCP24XX interessant. 32MiB RAM 
so um 128 MiB Flash. NoMMU ist schon was neues für mich, da ich nur mit 
Sytemen mit MMU zu tun hatte.

Gibt es da irgendwie Module/Boards mit WLAN und/oder Zigbee o.a.

So nur als Interesse halber, zur Zeit habe ich mit meiner Iomega 
Iconnect zu tun, das DING will nicht mit einem aktuellen Kernel booten, 
wenn ich die Option Device Tree(*) aktiviere. Da häng es irgendwo in der 
Bootloader/Kernel Schnittstelle ...

(*) Device Tree
ist eine "neue" Art eine Machinen Definition wo die Schnittstellen usw. 
beschrieben werden.
Da hat der Gottvater Linus Torvalds drüber aufgeregt, das es für jeden 
ARM SoC eigene Startcodes benötigt.

> Naja, danke trotzdem :-)

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

also, ich sehe das so:

Meine CPU ist ja vom Kernel grundsätzlich mal unterstützt (ARM7, bzw. 
ARM v4). Von daher ist das ja schon mal gut, denn für ARM7 gibt es 
fertige Compiler, die ganzen hässlichen Assemblersachen sind schon 
erledigt, etc., soweit so gut. Was ich nun machen würde:
zuallererst einmal einen Treiber schreiben für die ser. Schnittstelle. 
Ich habe mir von einem Freund extra ein Buch geborgt "Linux Device 
Drivers", wo u.a. auch "Character devices" erklärt werden. Meine 
Hardware, wo der Kernel drauf laufen soll, habe ich im Griff, also ich 
weiss sehr genau, wie diese serielle Schnittstelle von der SW her 
angesprochen werden soll etc.
Dann würde ich unter arch/arm/ einen neuen Ordner "mach-lpc2468" 
anlegen, und dort meine eigenen Board-spezifischen Sachen ablegen. In 
irgend einem Makefile muss man das dann noch eintragen, habe ich 
gesehen, und wenn man das alles gemacht hat, dann kann man beim make 
menuconfig diese HW als Target auswählen, richtig?
Wenn ich das dann alles habe, dann würde ich den Kernel einfach mal 
compilieren, ein nicht komprimiertes Image erzeugen und das mit meinem 
Debugger aus das Target runter laden. Den Bootloader lasse ich erst mal 
aussen vor, der ist eine andere Baustelle ;-)

Beim Kernel kann man ja noch Parameter zum Start mit übergeben, und dort 
würde ich dann sowas sagen wie

console=ttyS0

oder ähnlich, und wenn der Kernel wirklich läuft, sollten dann ja auf 
der ser. Schnittstelle ein paar Meldungen zu sehen sein, oder? ;-)

Und wenn das mal geht, dann Schrittweise drauf aufbauen.

Die Sache ist halt die, das habe ich glaube ich verschwiegen bzw. nicht 
so deutlich gesagt: Ich soll das auf der Arbeit auch machen, dort für 
einen etwas grösseren ARM (ARM9), und da mich das persönlich sehr 
interessiert und auch damit ich ein paar erste Erfahrungen sammeln kann, 
möchte ich das halt schon mal ein wenig ausprobieren. Hier zu Hause habe 
ich ein ARM7 Board, wo SDRAM mit drauf ist, von daher ginge das ja, 
Speicher steht genug zur Verfügung und Schnittstellen wie seriell und 
Ethernet auch ;-)

Meinst du, das wäre ein gangbarer weg? Wie gesagt, meine CPU wird ja 
grundsätzlich unterstützt, ich muss "nur noch" rausfinden, was ich sonst 
noch alles an HW-Spezialitäten konfigurieren muss. Und mit dem LPC22xx 
Sourcecode von Google habe ich ja schon mal einen Startpunkt, wo ich ein 
paar Sachen abgucken kann, dann sollte es doch machbar sein, oder?

Ganz einfach so aufgeben kann ich das Projekt dann doch nicht, es 
interessiert mich selber zu sehr :-) zudem muss es früher oder später 
sowieso gemacht werden, von daher.......

Schönen Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli,
>
> also, ich sehe das so:
>
> Meine CPU ist ja vom Kernel grundsätzlich mal unterstützt (ARM7, bzw.
> ARM v4). Von daher ist das ja schon mal gut, denn für ARM7 gibt es
> fertige Compiler, die ganzen hässlichen Assemblersachen sind schon
> erledigt, etc., soweit so gut. Was ich nun machen würde:
> zuallererst einmal einen Treiber schreiben für die ser. Schnittstelle.
> Ich habe mir von einem Freund extra ein Buch geborgt "Linux Device
> Drivers", wo u.a. auch "Character devices" erklärt werden. Meine
> Hardware, wo der Kernel drauf laufen soll, habe ich im Griff, also ich
> weiss sehr genau, wie diese serielle Schnittstelle von der SW her
> angesprochen werden soll etc.
> Dann würde ich unter arch/arm/ einen neuen Ordner "mach-lpc2468"
> anlegen, und dort meine eigenen Board-spezifischen Sachen ablegen. In
> irgend einem Makefile muss man das dann noch eintragen, habe ich
> gesehen, und wenn man das alles gemacht hat, dann kann man beim make
> menuconfig diese HW als Target auswählen, richtig?

Das Buch "Linux Device Driver" gibt es auch online kostenlos
suche mal nach *LDD3e.pdf*, das ist praktisch mein Begleiter auf dem 
Notebook.
Die meisten Treiber brauchst du nicht schreiben, die sind teilweise 
schon vorhanden. Bei der seriellen Schnittstelle brauchst du nur die 
Addresse des 16550A/8250 kompatiblen Baustein im SoC und noch ein paar 
Parameter anzugeben.
GPIO ist als "Lib" im Kernel, also auch nur Bereiche usw. angeben.
Bei der Netzwerkkarte dürfte es auch so sein.
ABER :
Seit Device Tree ist es nach meiner Meinung noch einfacher:
Wenn die Hardware im Kernel bekannt ist (keine neuen Treiber) brauchst 
nur nur dieses File. Es ist eine Art von XML. Und seit v3.9-rc1 kannst 
du diese compilierte Datei an deinen Kernel hängen ohne eine neunen 
Bootloader zu haben.

> Wenn ich das dann alles habe, dann würde ich den Kernel einfach mal
> compilieren, ein nicht komprimiertes Image erzeugen und das mit meinem
> Debugger aus das Target runter laden. Den Bootloader lasse ich erst mal
> aussen vor, der ist eine andere Baustelle ;-)
>
> Beim Kernel kann man ja noch Parameter zum Start mit übergeben, und dort
> würde ich dann sowas sagen wie
>
> console=ttyS0
>
> oder ähnlich, und wenn der Kernel wirklich läuft, sollten dann ja auf
> der ser. Schnittstelle ein paar Meldungen zu sehen sein, oder? ;-)
>

Im Prinzipo ja.
Debugger aka gdb ist schwer, habe ich auch gar nicht genutzt. printk ist 
hier mein Freund ...
Auch würde ich wie gesagt erstmal sehen ob ein "alter" Kernel läuft um 
sicher zu stellen, das du keine HW Fehler hast.

Wenn der LPC24XX mit LPC32XX von der HW (nur die Bausteine selber, nicht 
die Addressen) würde ich mal das arch/arm/boot/dts/lpc32xx.dtsi File 
ansehen. ggf. auch eine Config Optionen einfügen damit die "speziellen" 
Schnittstellen von NXP eingebunden werden.

Hier mal die aktuelle Startmeldung vom iconnect-Kernel mit Device Tree, 
den Fehler habe ich gefunden. Und wie immer LESEN des HELP Textes lohnt 
sich immer ;-)
1
[    0.000000] Booting Linux on physical CPU 0x0
2
[    0.000000] Linux version 3.9.0-rc3-iconnect (elektroman@X200s) (gcc version 4.5.3 (Gentoo 4.5.3-r1 p1.0, pie-0.4.5) ) #58 Mon Mar 25 12:17:25 CET 2013
3
[    0.000000] CPU: Feroceon 88FR131 [56251311] revision 1 (ARMv5TE), cr=00053977
Wennst du so weit kommst
1
[    6.289470] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
2
[    6.296987] Please append a correct "root=" boot option; here are the available partitions:
3
[    6.305420] 1f00            1024 mtdblock0  (driver?)
4
[    6.310519] 1f01            2048 mtdblock1  (driver?)
5
[    6.315600] 1f02          521216 mtdblock2  (driver?)
6
[    6.320693] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
hast du sehr viel gewonnen. Der Kernel will auf das RootFS zugreifen, da 
ich ihm nicht gezeigt habe.


> oder ähnlich, und wenn der Kernel wirklich läuft, sollten dann ja auf
> der ser. Schnittstelle ein paar Meldungen zu sehen sein, oder? ;-)
>
> Und wenn das mal geht, dann Schrittweise drauf aufbauen.
>
> Die Sache ist halt die, das habe ich glaube ich verschwiegen bzw. nicht
> so deutlich gesagt: Ich soll das auf der Arbeit auch machen, dort für
> einen etwas grösseren ARM (ARM9), und da mich das persönlich sehr
> interessiert und auch damit ich ein paar erste Erfahrungen sammeln kann,
> möchte ich das halt schon mal ein wenig ausprobieren. Hier zu Hause habe
> ich ein ARM7 Board, wo SDRAM mit drauf ist, von daher ginge das ja,
> Speicher steht genug zur Verfügung und Schnittstellen wie seriell und
> Ethernet auch ;-)
>

Da ist der Weg ähnlich, nur die MMU versaut dir ein wenig dein Gehirn. 
Ich habe bei einer Platform ein wenig gebraucht um da durchzusteigen, 
besonders weil der Code auch so alt war v2.6.15 und die da teilweise 
seltsame Code Constructs hatten.

> Meinst du, das wäre ein gangbarer weg? Wie gesagt, meine CPU wird ja
> grundsätzlich unterstützt, ich muss "nur noch" rausfinden, was ich sonst
> noch alles an HW-Spezialitäten konfigurieren muss. Und mit dem LPC22xx
> Sourcecode von Google habe ich ja schon mal einen Startpunkt, wo ich ein
> paar Sachen abgucken kann, dann sollte es doch machbar sein, oder?
>

Ja.
Nimm aber wie ich gesagt habe git, als Source-Code Verwaltung. Die ist 
da viel einfacher als SVN und CVS, besonders wenn du ans Mergen von 
zweigen kommst. Branches kannst du dir so viele anlegen wie du willst, 
da gibt es keine Begrenzung im System.

Und wenn der Code sauber ist kannst du ihn ja Mainline schicken.
Anleitungen gibt es dazu von Greg Kroah-Hartmann (youtube) und noch 
einem anderen dessen Name mir jetzt nicht einfällt.

> Ganz einfach so aufgeben kann ich das Projekt dann doch nicht, es
> interessiert mich selber zu sehr :-) zudem muss es früher oder später
> sowieso gemacht werden, von daher.......
>
> Schönen Gruss

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

ja ich habe mir auch überlegt, dass z.B. der 16550-UART-Treiber bereits 
existieren sollte. Allrdings ist dann noch die Frage, wie das Handling 
der Interrupts vonstatten geht?
Denn die ARM7-Controller haben ja einen sehr herstellerspezifischen 
Interruptcontroller, da kannder Kernel ja unmöglich alle Spezialitäten 
"wissen".

Deb Code bei mainline einzureichen, daran hatte ich auch schon gedacht. 
Wenn dann erst mal alles läuft.... :-)

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli,
>
> ja ich habe mir auch überlegt, dass z.B. der 16550-UART-Treiber bereits
> existieren sollte. Allrdings ist dann noch die Frage, wie das Handling
> der Interrupts vonstatten geht?
> Denn die ARM7-Controller haben ja einen sehr herstellerspezifischen
> Interruptcontroller, da kannder Kernel ja unmöglich alle Spezialitäten
> "wissen".
>
> Deb Code bei mainline einzureichen, daran hatte ich auch schon gedacht.
> Wenn dann erst mal alles läuft.... :-)

Ich habe mal eben den SVN Code ausgechecket und mal grep drüber laufen 
lassen.
Das gibt mir ein
find -type f -print0 | xargs -0 grep -l LPC2
aus
1
./arch/arm/boot/compressed/head.S
2
./arch/arm/Kconfig
3
./arch/arm/Kconfig-nommu
4
./arch/arm/kernel/entry-armv.S
5
./arch/arm/kernel/head-common.S
6
./arch/arm/kernel/head-nommu.S
7
./arch/arm/mach-lpc22xx/head.S
8
./arch/arm/mach-lpc22xx/irq.c
9
./arch/arm/mach-lpc22xx/Kconfig
10
./arch/arm/mach-lpc22xx/Kconfig-boards
11
./arch/arm/mach-lpc22xx/Kconfig-lpc2468
12
./arch/arm/mach-lpc22xx/lpc2468_devices.c
13
./arch/arm/mach-lpc22xx/lpc2468_ea_board.c
14
./arch/arm/mach-lpc22xx/lpc_2478stk.c
15
./arch/arm/mach-lpc22xx/lpc_e2468.c
16
./arch/arm/mach-lpc22xx/Makefile
17
./arch/arm/mach-lpc22xx/old/arch.c
18
./arch/arm/mach-lpc22xx/old/head.S
19
./arch/arm/mach-lpc22xx/old/irq.c
20
./arch/arm/mach-lpc22xx/old/Kconfig
21
./arch/arm/mach-lpc22xx/old/lpc2468_devices.c
22
./arch/arm/mach-lpc22xx/old/Makefile
23
./arch/arm/mach-lpc22xx/old/time.c
24
./arch/arm/mach-lpc22xx/time.c
25
./arch/arm/Makefile
26
./arch/arm/mm/Kconfig
27
./arch/arm/mm/Makefile
28
./arch/arm/mm/proc-arm7tdmi.S
29
./arch/arm/mm/proc-lpc22xx.S
30
./arch/arm/tools/mach-types
31
./drivers/i2c/busses/i2c-lpc22xx.c
32
./drivers/i2c/busses/Kconfig
33
./drivers/i2c/busses/Makefile
34
./drivers/mtd/devices/Kconfig
35
./drivers/mtd/devices/Makefile
36
./drivers/mtd/devices/mtd-lpc22xx-flash.c
37
./drivers/mtd/maps/Kconfig
38
./drivers/mtd/maps/lpc2468-ea-flash.c
39
./drivers/mtd/maps/Makefile
40
./drivers/net/arm/Kconfig
41
./drivers/net/arm/lpc22xx_eth.c
42
./drivers/net/arm/lpc22xx_eth.h
43
./drivers/net/arm/Makefile
44
./drivers/net/pcmcia/pcnet_cs.c
45
./drivers/rtc/Kconfig
46
./drivers/rtc/Makefile
47
./drivers/rtc/rtc-lpc22xx.c
48
./drivers/rtc/rtc-lpc22xx.h
49
./drivers/serial/8250.c
50
./drivers/video/Kconfig
51
./drivers/video/Kconfig.old
52
./drivers/video/lpc2468_registers.h
53
./drivers/video/Makefile
54
./include/asm-arm/arch-lpc22xx/Copy of lpc22xx.h
55
./include/asm-arm/arch-lpc22xx/dma.h
56
./include/asm-arm/arch-lpc22xx/entry-macro.S
57
./include/asm-arm/arch-lpc22xx/gpio.h
58
./include/asm-arm/arch-lpc22xx/hardware.h
59
./include/asm-arm/arch-lpc22xx/irq.h
60
./include/asm-arm/arch-lpc22xx/irqs.h
61
./include/asm-arm/arch-lpc22xx/keyboard.h
62
./include/asm-arm/arch-lpc22xx/log
63
./include/asm-arm/arch-lpc22xx/lpc22xx.h
64
./include/asm-arm/arch-lpc22xx/nvram.h
65
./include/asm-arm/arch-lpc22xx/serial.h
66
./include/asm-arm/arch-lpc22xx/time.h
67
./include/asm-arm/arch-lpc22xx/uncompress.h
68
./include/asm-arm/arch-lpc22xx/vmalloc.h_old
69
./include/linux/i2c-id.h
aus. Ich habe nur die wichtigen Dateien genommen.

Und das sind nur die "offensichtlichen" Änderngen um Code mit Kconfig.
Die anderen bekommst du nur mit diif ggf. diffstat heraus.
In dem Fall habe ich immer mit zwei Verzeichnissen gerarbeitet.
"Original Code" vom BSP
und der "Master" git mit der entsprechenden Version inkl. Subversion) 
hier also v2.6.24.2

Sowie "dein" Controller in
arch/arm/mach-lpc22xx/irq.c
wo ja der "mach" spezifische Teil sein soll. arch/arm/mach-lpc22xx

Die Jungs haber schon vorher weit alles abstrahiert was geht ...

Wenn du wie gesagt vor hast mainline zu gehen, hier meine zwei 
Empfehlungen die du dir ansehen solltes :

Wie schreibt man eine Patch und sendet ihn
http://www.youtube.com/watch?v=LLBrBBImJt4

Arbeiten mit Git in der Gruppe (nenn ich mal so)
http://www.youtube.com/watch?v=j45cs5_nY2k

Beim letzteren wird gezeigt was der Unterschied zwischen einem Rebase 
und einem Merge ist. Und wo die Fehlerquellen sind WICHTIG, wenn in 
der Gruppe gearbeitet wird.

von Alfons (Gast)


Lesenswert?

N'Abend Ulli,

ich habe soeben dieses Dokument gefunden:

http://www.linux-arm.org/pub/LinuxKernel/WebHome/aleph-porting.pdf

dort wird verhältnismässig vieles erklärt. Fragt sich, wie akkurat das 
mit dem aktuellen Kernel noch ist.... wie gesagt möchte ich einen 
einigermassen aktuellen Kernel benutzen, nicht mehr 2.6, der ist ja 
wirklich alt. Zumal gemäss Wikipedia und vielen anderen Quellen die 
MMU-lose Variante bereits im aktuellen Kernel enthalten ist.

Okay, ich werde mich mal an das obengenannte Dokument halten. Ich habe 
vorhin schon mal einen einfachen Bootloader für mein Board gebastelt, 
der die ganze HW initialisiert, den SDRAM-Controller startet usw., sowie 
einen seriellen Port initialisiert und ein paar Meldungen ausgibt. Mein 
Ziel ist es dann, die Feiertage über Ostern sinnvoll zu nutzen ;-))) und 
einen wirklich minimalistischen 3.6er-Kernel (oder ähnlich) zu bauen, 
der nur mal die serielle Schnitte enthält, und mal ein paar Meldungen 
ausspuckt.

Wenn ich so schaue in den obengenannten Dokumenten, dann enthält der 
Kernel bereits ein paar allernotwendigste Routinen zur Textausgabe, auch 
den Interruptcontroller kann man mit irq.c recht gut abstrahieren 
(struct irq_chip usw.).

Weisst du grade, welchen Treiber ich bei menuconfig einbinden muss, 
damit er den 16550er UART findet? bzw. dessen Basisadresse müsste man ja 
auch noch irgendwo einstellen können, das finde ich grade nicht.


Aber herzlichen Dank schonmal für deine Hilfe.
Wenns dir recht ist melde ich mich später nochmal per PN, über Mail ist 
es sicherlich bequemer, einige Fragen zu klären ;-)


Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Ich habe mal (echt) nur kurz das PDF überflogen ...

DAS DING IST URALT und stinkt schon.

Ich gehe mal davon aus da wenigstens 30% der beschriebenen Sachen nicht 
mehr stimmen und andere Teile gelöscht worden sind.

Besonders was es sich mit dem
include/asm-arm/arch-lpc22xx/ (alter Code) auf sich halt stimmt nicht 
mehr.

Und den anderem Kram kann ich auch nicht genau sagen ...
Warum ... legt dir mal ein git Repo irgendwo an github und Co lassen 
grüssen.

Wie sieht es mit dem Speicher aus ??
Was ist an Addresse  0xa0008000 ??
Die CPU ist eine "2468" CPU nur für den Baustein ??
Lerne git, ohne fange mal mit an ...

von Hans Ulli K. (Gast)


Lesenswert?

So bin gerade was am push'en

Clone dir bitte linux von kernel.org
1
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Dass wird ein neues Verzeichnis "linux" erzeugen mit dem Repo von 
kernel.org

dann meine "Updates" für lpc24xx (nur der Anfang) fetch'en mit
1
git remote add ulli git@github.com:ulli-kroll/linux.git
2
git fetch ulli
Im Branch
lpc24xx/v3.8/mach-lpc24xx
habe ich schon mal angefangen zu spielen

Dieser ist wie der Name schon sagt v3.8 basiert.
Das meiste habe C&P vom Google Repo genommen und nach und nach 
angepasst.
Zur Zeit hängt der Compiler jetzt bei irq.c
So wie es an der Fehlermeldung sehe, liegt das an dem fehlenden sysdev.h 
das ich im laufe der Zeit herausgenommen habe. Da muss eine Anpassung 
nach einem platform device oder so gemacht werden. Beispiel dürfte in 
mach-lpc32XX oder so zu finden sein.

Checkout des Branches mit z.B.
1
git checkout -b lpc24xx/v3.8/mach-lpc24xx ulli/lpc24xx/v3.8/mach-lpc24xx

Viel Spass
Ach ja.
Die Mail Addresse stimmt, aber ich habe z.Zt. wenig Lust da zu 
Antworten. Habe andere Sachenzu tun und wollte erst in ca. 4-6 Monaten 
wieder voll einsteigen ...

Ulli

chroot bed && sleep

von Alfons (Gast)


Angehängte Dateien:

Lesenswert?

Hey Ulli,

herzlichen Dank für deine Hilfe!

ich habe inzwischen angefangen, das selbe zu tun :-)
Ich habe von Google Repository ein bisschen abgeschrieben. bei irq.c 
habe ich den teil mit dem sysdev auskommentiert, nun compiliert der 
Kernel schon mal ;-) allerdings kommt ganz am Schluss wieder die 
hässliche Meldung:

"no machine record defined"

aber ich sehe inzwischen den Wald vor lauter Bäumen nicht mehr -_- ich 
muss mich auch erst mal hinlegen und das ein wenig verdauen ;-)

Wenn du mal kurz Zeit hast kannst du dir ja meine Kconfig-Dateien 
anschauen, ich hab da inzwischen ziemlich rumgedoktert, um den Fehler zu 
beheben, leider bislang erfolglos.

Da bei arm.linux.co.uk schon mal jemand den mach-Typ LPC24xx registriert 
hat, dieser jedoch nicht mainlined ist, habe ich einfach mal diesen 
mach-Record übernommen:

lpc24xx   MACH_LPC24XX    LPC24XX   2967

Ob es vielleicht daran liegt?


Gruss

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

so habe den Fehler gefunden. Man muss in einer C-Datei noch ein Makro 
einfügen:

DT_MACHINE_START(LPC24XX_DT, "LPC24XX SoC (Flattened Device Tree)")
  .atag_offset  = 0x100,
  .map_io    = NULL,
  .init_irq  = lpc22xx_init_irq,
  .timer    = NULL, /*??? &lpc32xx_timer*/
  .init_machine  = lpc2468_machine_init,
  .dt_compat  = lpc24xx_dt_compat,
  .restart  = NULL, /*?? lpc23xx_restart*/
MACHINE_END

ich habe das einfach mal vom LPC32xx kopiert und die Namen einfach 
angepasst, in der Hoffnung, dass das Teil so schon mal halbwegs 
funktioniert.

Nun: endlich kann ich den Kernel für meine Architektur compilieren! Ich 
habe mal die Option "excute in Place" angewählt und spiele das xipImage 
als binäre Datei in das externe Flash meines Controllers. Dann habe ich 
einen simplen Bootloader gebastelt, der einfach den Uart sowie 
Memorycontroller initialisiert und an die Basisadresse des ext. Flash 
springt, wo dann das xipImage liegt. Wenn ich da mit dem Debugger drüber 
steppe, dann passiert auch tatsächlich etwas, was einigermassen sinnvoll 
erscheint! irgendwelche Daten werden da herum kopiert, vom Flash ins 
SDRAM, gewisse SDRAM Bereiche werden mit 0x00 gefüllt und der 
Stackpointer wird initialisiert und zeigt dann irgendwo ins SDRAM. 
Irgendwo wird noch (so vermute ich) die Machine ID geladen, welche ich 
mit "Hardwire the machine ID" auf 0x00007700 gesetzt habe; er errechnet 
aber dann beim Target einen Wert von 0x41007700, vergleicht dies, stellt 
fest, dass es nicht übereinstimmt, und geht in einen Endlosloop. Daher 
habe ich dann einfach mal die Machine ID mit dem Debugger gefaket, 
sodass der Vergleich erfolgreich ist; danach passieren weitere Dinge, 
auf dem Terminal (ttyS0) erfolgt aber kein Zugriff, ausserdem kommt er 
irgendwann wieder in einen Endlosloop (wo er vielleicht auf einen 
Timerinterrupt wartet?).

Wie könnte man jetzt weiter vorgehen?

mein Setup ist wie folgt:

SDRAM 0xa0000000
Size 0x04000000
Ext. Flash 0x80000000
Size 0x00400000

"Remap Vectors to RAM" habe ich aktiviert und die Basisadresse des int. 
RAM 0x40000000 angegeben, damit er da nicht irgendwie ins Flash zu 
schreiben versucht.

So, naja jedenfalls passiert schon mal IRGENDWAS, das ist schon toll ;-) 
wenn ich bis am WE noch eine Ausgabe auf der seriellen hin kriege, bin 
ich glücklich.


Erst mal aber

sudo mv /dev/bed


Gruss

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

ich mal wieder. Hab noch ein wenig debugged.
Ich habe mal von Hand im Kconfig eingefügt

config EARLY_PRINTK
  bool
  default y


damit ich mit early_printk() Sachen ausgeben kann.

Nun, ich stelle fest anhand des Terminals:
der Kernel bootet jetzt, und zwar bis hier:

setup.c, funktion setup_arch(), beim Aufruf von paging_init() gibts ein 
Problem. Bei pagint_init() geht er in die nommu.c, wo er versucht die 
Vektoren umzukopieren. Das funktioniert, anschliessend geht er zum 
bootmem_int(), und hier schlägts dann fehl:

init.c, bootmem_init(), aufruf von arm_bootmem_init().
Dann geht er irgendwann in die mark_bootmem(). Codeauszug, mit meinen 
printk()'s:

1
static int __init mark_bootmem(unsigned long start, unsigned long end,
2
        int reserve, int flags)
3
{
4
  unsigned long pos;
5
  bootmem_data_t *bdata;
6
7
  pos = start;
8
  list_for_each_entry(bdata, &bdata_list, list) {
9
    int err;
10
    unsigned long max;
11
    if (pos < bdata->node_min_pfn ||
12
        pos >= bdata->node_low_pfn) {
13
      BUG_ON(pos != start);
14
      early_printk("BUG on %d (pos=%x, bdata=0x%p, min_pfn=%x, low_pfn=%x.)\n\r", pos != start, pos, bdata, bdata->node_min_pfn, bdata->node_low_pfn);
15
      continue;
16
    }
17
18
    max = min(bdata->node_low_pfn, end);
19
    early_printk("mark bootmem node: max=%x.\n\r", max);
20
    err = mark_bootmem_node(bdata, pos, max, reserve, flags);
21
    early_printk("mark bootmem node (max=%x) done.\n\r", max);
22
    if (reserve && err) {
23
      early_printk("mark bootmem: start=%x, pos=%x.\n\r", start, pos);
24
      mark_bootmem(start, pos, 0, 0);
25
      return err;
26
    }
27
28
    if (max == end)
29
      return 0;
30
    pos = bdata->node_low_pfn;
31
    early_printk("pos: %x.\n\r",pos);
32
  }
33
  early_printk("bootmem stuff done.\n\r");
34
  BUG();
35
  early_printk("leave mark_bootmem.\n\r");
36
}

Auf dem Terminal kommt dann das:


1
...
2
copy vectors: 0x8011d4c4 to 0x40000000 size 32.
3
remap vectors ok.
4
bootmem init.
5
bootmem limits: min 000a0000, max_low 000a1000, max_high 000a1000.
6
init bootmem node a001d260, a0fff a0000.
7
mark bootmem node: max=a1000.
8
nid=0 start=a0000 end=a1000 reserve=0 flags=0
9
mark bootmem node (max=a1000) done.
10
reserve bootmem start=0x40000,end=0x40001  (mm/bootmem.c 476)
11
BUG on 262144 (pos=a000c55c, bdata=0x  (null), min_pfn=a0000, low_pfn=a1000.)
12
bootmem stuff done.

Interessant:
wenn ich die printk() Zeile entferne, dann resetiert sich der Prozessor 
dauernd wieder.



Hast du eine Idee, wo ich suchen müsste?
Interessant ist, dass er da mit bootmem etwas versucht zu machen, wo 
meine Interruptvektoren liegen.

Also ich habe bei mir folgendes:
den Kernel als XIP konfiguriert und auf Adresse 0x80000000 gelinkt, weil 
da ein FLASH liegt. SDRAM liegt bei 0xA0000000. So, und die 
Vektortabelle des ARM7 ist eigentlich im Flash, aber NXP bietet die 
möglichkeit des "memory remappings", d.h. die Vektortabelle wird auf 
Adresse 0x40000000 verschoben, dort liegt ein RAM. Und genau dies habe 
ich im menuconfig auch aktiviert (Remap Vectors to RAM) und die Adresse 
0x40000000 angegeben.

Wo könnte ich weitersuchen?

Bis bald hoffentlich,

Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Übergibst du dem Kernel dem Speicherbereich für das RAM per ATAG ?

Wenn du den DeviceTree benutzt musst du ihn auch dem Kernel per 
Parameter übergeben.

Howto für ATAG
http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html
http://armputer.pbworks.com/f/porting_to_arm.pdf

Für Device Tree
http://elinux.org/Device_Trees
So wie es aussieht ist die einzige brauchbare Doku für das Register, 
wo dieser DT-Blob dem Kernel übergeben wird, entweder der Kernel source 
oder der u-Boot source.
Für akuelle Kernel ab 3.8-rc1 gibt es wir sagt einem "Trick" um diesem 
Block an dem Kernel anzuhängen. Es ist aber nur der Weg für zImage 
beschrieben. (Helptext ist ist Kconfig).

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Also ich habe bei mir folgendes:
> den Kernel als XIP konfiguriert und auf Adresse 0x80000000 gelinkt, weil
> da ein FLASH liegt. SDRAM liegt bei 0xA0000000. So, und die
> Vektortabelle des ARM7 ist eigentlich im Flash, aber NXP bietet die
> möglichkeit des "memory remappings", d.h. die Vektortabelle wird auf
> Adresse 0x40000000 verschoben, dort liegt ein RAM. Und genau dies habe
> ich im menuconfig auch aktiviert (Remap Vectors to RAM) und die Adresse
> 0x40000000 angegeben.
>
> Wo könnte ich weitersuchen?
>
> Bis bald hoffentlich,
>
> Gruss

Was für eine Sch**ss* ...
Das Kopieren der Vectortabelle erfolgt in arch/arm/kernel/trace.c
und ist im mainline nur ein Stub.
Wie die das jetzt im LPC32XX (wenn dort auch so was vorhanden ist) 
umgangen haben weiss ich nocht nicht.
EDIT:
Der LPC32XX hat eine MMU ...

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

hmm kann dir grade nicht so ganz folgen was du meinst.
Was, Sche... ?? mein Code, oder was?

Ich habe den "Fehler" mittlerweile gefunden. Der Code versucht, auf den 
RAM zuzugreifen, den ich aber in der Memory map nicht drin hatte. Ich 
rufe jetzt testweise mal vorher noch arm_add_memory() auf, in der 
setup.c Funktion setup_arch(). Dort mache ich das Memory bekannt, und 
dann geht auch die inisialisierung des Bootmem. Ich tippe mal darauf, 
dass man normalerweise mit den ATAGs das Memory vorher bekannt gibt und 
dann ist dieser Kram mit add_memory() nicht nötig.....

Nun denn, der Code läuft nun mittlerweile bis zur page_alloc.c, Funktion 
memmap_init_zone(). Dort gibt es folgenden Code:
1
page = pfn_to_page(pfn);
2
    early_printk("(mem_map + ((pfn) - ARCH_PFN_OFFSET)) = 0x%x + ((0x%x) - 0x%x)", mem_map, pfn, ARCH_PFN_OFFSET);
3
    early_printk("memmap init zone: pfn=0x%x page=0x%x &pfn=0x%x\n\r", pfn, page, &pfn);
4
    early_printk("page->flags = 0x%x\n\r", page->flags);
5
    set_page_links(page, zone, nid, pfn);

Nun, der Pointer "page" zeigt dann auf die Adresse 0x9f4e3c00, wie ich 
im Terminal lesen kann:
1
memmap init zone entered:size = 0x610a0,nid=0x0,zone=0x0,start_pfn=0x40000
2
(mem_map + ((pfn) - ARCH_PFN_OFFSET)) = 0xa00e5000 + ((0x40000) - 0xa00a0)memmap
3
 init zone: pfn=0x40000 page=0x9f4e3c00 &pfn=0xa00a9ebc
Dort liegt natürlich kein RAM und der Prozessor wird erwartungsgemäss 
angehalten.

Ich frage mich, woher die Werte kommen.... Ob es wirklich nur daran 
liegt, dass ich noch keine ATAGs habe? Wie gesagt - ich boote den Kernel 
ohne ATAGs, weil ich nicht rausgefunden habe, wie dies genau 
funktionieren soll. Daher habe ich das einfach mal weggelassen, und ich 
boote ihn einfach, indem ich an die richtige Adresse springe und vorher 
ins Register r2 noch die Machine ID lade (0x41007700 für ARM7TDMI).

Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Die ATAG ist einfach eine LISTE.

Parameter für ATAG Boot:

r0 = 0
r1 = machine number
r2 = &(ATAG list)

Normalerweise wird die ATAG Liste nach validen Tags geprüft (soweit 
ich mich noch erinnern kann)
Es macht aber nicht wenn du in r2 eien Addresse angibst die den Inhalt 
0x00000000L (Ende der Liste) hat.

Was ich mit Sch**ss* meinete ist einfach :
Der Code zum Kopieren der INT-Vector Tabelle ist in den Original Source 
in arch/arm/kernel/trace.c im Mainline-Kernel ist dieser code nicht.
Auch steht dort keine Info welches Register gesetzt werden muss um 
diesem Bereich der CPU bekannt zu machen, diese denkt ja noch immer die 
Tabelle ist im ROM
Es kann auch sein das noch mehr Kram Außerhalb des mach-lpc22xx 
Verzeichnisses vorhanden ist.

von Hans Ulli K. (Gast)


Lesenswert?

uClinux macht es im 3.6 Kernel etwas anders.
Dort gibt es eine early_trap_init Function ...

von Alfons (Gast)


Lesenswert?

Hi Ulli,

genau, die early_tra_init() kopiert mittels memcpy() die Vektoren.

Ich habe jetzt meinen einfachen "quick & dirty bootloader" angepasst, 
dass er mal ein paar ATAGs schreibt. Ich setzt ATAG_MEM, ATAG_CORE und 
ATAG_NONE. so gebe ich die memory map bekannt. Und es funktioniert 
tatsächlich! nun konnte ich meinen debug code raus löschen und der 
kernel kommt nun etwas weiter. Dank deiner Hilfe!! :D
Jetzt habe ich wirklich nur noch das Problem mit der page_alloc.c, 
Funktion memmap_init_zone(). Dort gibts einen Crash, weil er auf eine 
falsche Adresse zugreifen will. Die interessanterweise ausserhalb meiner 
Memory Map liegt....

Folgendes kommt in meinem Terminal jetzt:
1
memmap_init(0x64000, 0x0, 0x0, 0x40000);
2
memmap init zone entered:size = 0x64000,nid=0x0,zone=0x0,start_pfn=0x40000
3
(mem_map + ((pfn) - ARCH_PFN_OFFSET)) = 0xa0045000 + ((0x40000) - 0xa0000)
4
memmap init zone: pfn=0x40000 page=0x9f445000 &pfn=0xa0009ebc

Und die Adresse 0x9f445000 liegt unterhalb meines SDRAMs, dort ist kein 
Speicher. Es gibt bei der Berechnng da einen überauf:
1
page = pfn_to_page(pfn);

Da wird eine ungültige Adresse für "page" berechnet und dann wird da auf 
eine ungültige struct page zugegriffen. Was geht da wohl schief?


Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
>
1
> memmap_init(0x64000, 0x0, 0x0, 0x40000);
2
> memmap init zone entered:size =
3
> 0x64000,nid=0x0,zone=0x0,start_pfn=0x40000
4
> (mem_map + ((pfn) - ARCH_PFN_OFFSET)) = 0xa0045000 + ((0x40000) -
5
> 0xa0000)
6
> memmap init zone: pfn=0x40000 page=0x9f445000 &pfn=0xa0009ebc
7
>

Die erste Zeile sieht mir interessant aus.

von Alfons (Gast)


Lesenswert?

Hallo Ulli,
danke das schaue ich mir heute Abend an.

In der Zwischenzeit habe ich mit initramfs befasst und mir mal dies zu 
gemüte geführt:

http://www.aclevername.com/articles/linux-xilinx-tutorial/minimalist-initramfs.html

Damit kann ich eine cpio- Datei erzeugen und beim menuconfig des Kernels 
angeben. Ich würde jetzt busybox runterladen und dann compilieren und da 
einfach in den ordner rein kopieren, ist das ne möglichkeit?

schönen Gruss, bis bald, melde mich heut Abend nochmal!

von Hans Ulli K. (Gast)


Lesenswert?

Ja das müßte gehen.

Hier noch andere Quellen.

http://en.gentoo-wiki.com/wiki/Initramfs
http://jootamam.net/howto-initramfs-image.htm

Letztere hat noch ein minimales init.

Wichtig ist auch hier die FAQ von busybox
http://www.busybox.net/FAQ.html

Unter dem Punkt "Job Control" gibt es da was wichtiges :
Wenn dein Terminal auf /dev/console liegt ist die Job Control 
ausgeschaltet. Also Terminal auf /dev/ttyS0 legen. Logischerweise gilt 
dies für dein RootFS auf deinem Ziel System.

Die busybox braucht logischweiser auch noch einen libc. Hier ist die 
uClibc die Wahl, da du hier einstellen kannst ob du eine MMU hast. 
Insgesammt dürfte eine statische busybox 1-2 MiB groß sein.

UND JETZT KOMMT DER HAKEN
z.Zt. ist der Support für DeviceTree und InitramFS mehr als schlecht, 
besser gesagt NULL. Auf meiner iconncect bekomme ich keinen Kernel mit 
InitramFS und DeviceTree ans laufen ...

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

so ich habe den Fehler gefunden, der das Problem

> memmap_init(0x64000, 0x0, 0x0, 0x40000);

verursacht. In der arm_bootmem_free() (init.c) wird folgendes gemacht:

zone_size[0] = max_low - min;

Und wenn ich mir da ein paar Variablen ausgeben lasse erhalte ich 
folgendes:

zone_size[0]=0x64000; max_low = 0xa4000, min = 0x40000

Was natürlich korrekt gerechnet ist, aber trotzdem falsch. Denn der 
Speicherbereich ist ja nicht zusammenhängend! Ich hab gesehen, dass es 
sowas gibt wie CONFIG_MEM_DISCONTIG oder ähnlich, ich denke es könnte 
sich damit beheben lassen?

Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Was natürlich korrekt gerechnet ist, aber trotzdem falsch. Denn der
> Speicherbereich ist ja nicht zusammenhängend! Ich hab gesehen, dass es
> sowas gibt wie CONFIG_MEM_DISCONTIG oder ähnlich, ich denke es könnte
> sich damit beheben lassen?
>
> Gruss

Welchen Speicher meinst du jetzt ?
Ich ohne USB und Netzwerk starten.
Nicht das da ein Treiber verkehrt ist. Und die beiden Treiber benutzen 
den On-Chip-RAM

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

so, gute Nachricht: ENDLICH habe ich es geschafft, dass was tolles 
passiert. Mir läuft die start_kernel() erfolgreich durch, setup_arch(), 
timer_init() und so weiter werden alle aufgerufen, und die 
start_kernel() läuft erfolgreich durch! YES! Was allerdings jetzt noch 
nicht funktioniert ist

a) printk(),
b) Timer und IRQ, um die habe ich mich noch nicht gekümmert.

Ich darf einfach bei der ATAG-Liste keinen nicht-zusammenhängenden 
Speicher engeben, dann funktioniert es! ist ja aber auch nicht weiter 
schlimm, denn der interne RAM ist sowieso nur 64k gross, das stört nicht 
wenn der nicht benutzt wird.

Ich habe gesehen, dass nachdem start_kernel durchgelaufen ist, das I und 
das F bit im CPSR noch gesetzt sind? Da muss ich wohl einen 
vollständigen Interruptcontroller noch programmieren und dem Kernel beim 
Start bekannt geben, damit die Timerinterrupts funktionieren? Denn bei 
der timer_init() habe ich mal einen Timer initialisiert, sodass er jede 
Sekunde einen Interupt generiert, der IRQ tritt aber nicht ein weil ja 
die Interrupts im CPSR noch deaktiviert sind......


Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli,
>
> so, gute Nachricht: ENDLICH habe ich es geschafft, dass was tolles
> passiert. Mir läuft die start_kernel() erfolgreich durch, setup_arch(),
> timer_init() und so weiter werden alle aufgerufen, und die
> start_kernel() läuft erfolgreich durch! YES! Was allerdings jetzt noch
> nicht funktioniert ist
>
> a) printk(),
> b) Timer und IRQ, um die habe ich mich noch nicht gekümmert.
>
> Ich darf einfach bei der ATAG-Liste keinen nicht-zusammenhängenden
> Speicher engeben, dann funktioniert es! ist ja aber auch nicht weiter
> schlimm, denn der interne RAM ist sowieso nur 64k gross, das stört nicht
> wenn der nicht benutzt wird.
>

Die 64k "interes SRAM" wird vom USB und Ethernet benutzt. Dieser wird 
auch im File
arch/arm/mach-lpc22xx/lpc2468_devices.c
"reserviert". Soweit ich es im Ethernet Treiber gelesen habe sind dort 
die Deskriptoren für rx/tx Buffer abgelegt.

von Alfons (Gast)


Lesenswert?

Moin Ulli,

so ich hab mal wieder ein paar Neuigkeiten!
ich habe gestern Abend noch ein wenig mit dem Device Tree rum geübt. Nun 
habe ich meinen Bootloader so modifiziert, dass er anstatt der 
ATAG-Liste den Device Tree ins Memory lädt und die Basisadresse ins 
Register r2 lädt, bevor zum Kernel gesprungen wird.

Tja, auf der seriellen Schnittstelle sehe ich am PC Terminal dann:
"Loading device Tree" :-) Das Ding wird nun also erfolgreich eingelesen, 
auch die Initialisierung eines Timers (Timer 0 des LPC2468) klappt und 
der Tick-Interrupt wird aufgerufen. "jiffies" zählt hoch usw., also 
eigentlich schonmal ganz gut oder?

Nur leider stürzt der Kernel nach einer gewissen Anzahl ticks aus mir 
unerklärlichen Gründen ab; ich merke das daran, dass die ganzen 
Boot-Messages nochmal erscheinen. Das muss ich noch Debuggen. Noch eine 
Frage zum Interruptcontroller:
Der LPC2468 hat einen VIC. Ist das wirklich der selbe VIC, wie unter 
arch/arm/common/vic.c ? Ich habe den mal in den Device Tree genommen, 
und die richtige Basisadresse eingegeben und damit oben beschriebenes 
Verhalten erzielt. Muss ich in meinem Board-spezifischen Code noch 
weitere Initialisierungen für den VIC vornehmen, oder macht das der 
Kernel selbst, wenn er weiss, dass das ein VIC ist?

Weiter: ich habe im Device Tree noch den UART0 angegeben mit seiner 
Basisadresse; unter "compatible" habe ich vermerkt: "ns16550a". Im make 
manuconfig habe ich dann unter "Device Drivers", "Character Devices" 
angegeben, dass die 8250 Treiber eingebunden werden sollen. Das klappt 
auch, aber die initialisierung des UARTs wird nicht aufgerufen? Im 
Prinzip sollte doch dann die Konsole auf dem Terminal erscheinen, oder? 
Es kommen aber immer nur die Meldungen raus, die ich mit meinem 
early_printk() erzeuge. Vielleicht hast du noch einen Tipp für mich.



Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Moin Ulli,
>
> so ich hab mal wieder ein paar Neuigkeiten!
> ich habe gestern Abend noch ein wenig mit dem Device Tree rum geübt. Nun
> habe ich meinen Bootloader so modifiziert, dass er anstatt der
> ATAG-Liste den Device Tree ins Memory lädt und die Basisadresse ins
> Register r2 lädt, bevor zum Kernel gesprungen wird.
>
> Tja, auf der seriellen Schnittstelle sehe ich am PC Terminal dann:
> "Loading device Tree" :-) Das Ding wird nun also erfolgreich eingelesen,
> auch die Initialisierung eines Timers (Timer 0 des LPC2468) klappt und
> der Tick-Interrupt wird aufgerufen. "jiffies" zählt hoch usw., also
> eigentlich schonmal ganz gut oder?
>

Schon mal gut,dann läuft der Timer IRQ

> Nur leider stürzt der Kernel nach einer gewissen Anzahl ticks aus mir
> unerklärlichen Gründen ab; ich merke das daran, dass die ganzen
> Boot-Messages nochmal erscheinen. Das muss ich noch Debuggen. Noch eine
> Frage zum Interruptcontroller:
> Der LPC2468 hat einen VIC. Ist das wirklich der selbe VIC, wie unter
> arch/arm/common/vic.c ? Ich habe den mal in den Device Tree genommen,
> und die richtige Basisadresse eingegeben und damit oben beschriebenes
> Verhalten erzielt. Muss ich in meinem Board-spezifischen Code noch
> weitere Initialisierungen für den VIC vornehmen, oder macht das der
> Kernel selbst, wenn er weiss, dass das ein VIC ist?
>

Wenn du im Datenblatt vom LPC24XX nachschaust (Datei UM10237.pdf) Seite 
113/114 wirst du sehen, das der Controller im IRQ oder FIQ "geschaltet" 
werden kann. FIQ benutzt die Vector Interrupt Tabelle, daher der VIC. In 
den original Source von der google Seite wird der Controller im IRQ 
Modus betrieben. Siehe Zeile 114
1
  /* set all to IRQ mode, not FIQ */
2
  VICIntSelect = 0x00000000;

Ich gahe mal davon aus, das das locking innerhalb des Kernels nur von 
einem "Laufenden" Interrupt ausgeht (so war dies auf dem PC). Es mach 
auch die Sache etwas einfacher.

> Weiter: ich habe im Device Tree noch den UART0 angegeben mit seiner
> Basisadresse; unter "compatible" habe ich vermerkt: "ns16550a". Im make
> manuconfig habe ich dann unter "Device Drivers", "Character Devices"
> angegeben, dass die 8250 Treiber eingebunden werden sollen. Das klappt
> auch, aber die initialisierung des UARTs wird nicht aufgerufen? Im
> Prinzip sollte doch dann die Konsole auf dem Terminal erscheinen, oder?
> Es kommen aber immer nur die Meldungen raus, die ich mit meinem
> early_printk() erzeuge. Vielleicht hast du noch einen Tipp für mich.
>

So wie es aussieht ist es ein 16550 kompatibler Chip also mit 16Byte 
send/recieve FIFO.
Nur hier gibt es noch einen Unterschieb. Original Code
1
#ifdef CONFIG_ARCH_LPC22XX
2
    if (scratch2 != 0 || scratch3&0x07 != 0x07) {
3
#else
4
    if (scratch2 != 0 || scratch3 != 0x0F) {
5
#endif
6
      /*
7
       * We failed; there's nothing here
8
       */
9
      DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
10
               scratch2, scratch3);
11
      goto out;
12
    }

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

bezüglich des Timer IRQ - den habe ich auch als IRQ und nicht als FIQ 
geschaltet. Man kann mit dem VIC des LPC24xx sowohl IRQs als auch FIQs 
verwalten. Somit habe ich

VICIntSelect = 0;

in meinem Code übernommen. Auch die Anpassung für den UART habe ich so 
übernommen. Die Frage ist: versucht der Kernel überhaupt, meinen Treiber 
zu laden? Ich habe mal bei der init-Funktion folgendes eingebaut:

ealry_printk("uart initialised");

Dann sollte auf dem Terminal eine Meldung kommen, wenn der UART Treiber 
geladen wird. Das passiert aber nicht. Muss ich im Menuconfig ggf. noch 
eine Option einschalten, um das Laden des Treibers zu bewirken? Ich habe

Charachter Devices --> Console on Serial Port

aktiviert, sowie

8250 Driver

habe ich auch aktiviert. Bringt aber bis jetzt noch nichts :-) Ob wohl 
mein Device Tree richtig gelesen wird? Keine Ahnung, kann ich das 
irgendwie prüfen?


Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:

> in meinem Code übernommen. Auch die Anpassung für den UART habe ich so
> übernommen. Die Frage ist: versucht der Kernel überhaupt, meinen Treiber
> zu laden? Ich habe mal bei der init-Funktion folgendes eingebaut:
>
> ealry_printk("uart initialised");
>
> Dann sollte auf dem Terminal eine Meldung kommen, wenn der UART Treiber
> geladen wird. Das passiert aber nicht. Muss ich im Menuconfig ggf. noch
> eine Option einschalten, um das Laden des Treibers zu bewirken? Ich habe
>

Hast du überhaupt in deinem
boardinit ()
den Device Tree "geparsed" ??

siehe
Documentation/devicetree/usage-model.txt


Ein gutes Beispiel finde ich kann man in der Datei
arch/arm/mach-kirkwood/board-dt.c
in der Funktion
kirkwood_dt_init ()
sehen
1
  of_platform_populate(NULL, kirkwood_dt_match_table,
2
           kirkwood_auxdata_lookup, NULL);
Ich habe jetzt nicht im aktuellen 3.8 Kernel nachgesehen, aber da 
dürften die Board init's für die Iomega Iconnect und Raidsonic IB62x0 
NAS fehlen. Diese Platformen habe ich ...

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

nee, die of_platform_populate() hatte ich bis jetzt nicht drin :O

aber irgendwie geht jetzt wieder gar nichts mehr, ich weiss nicht obs 
gestern zufall war dass der timer interrupt funktioniert hat oder was 
los war - jetzt stürzt der rechner wieder ab, auch die machine_init() 
wird nicht aufgerufen.

Was mein Bootloader im Prinzip macht, ist, die DTB-Datei ins Memory zu 
laden. Wenn ich das Teil an eine andere Adresse als die Basisadresse des 
SDRAM lade oder gar mit ins Flash nehme, dann funktioniert gar nichts, 
so erkennt der Kernel wenigstens die magic number.....

ich weiss grade nicht wo weiter suchen. Ich meld mich dann nochmal....

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

ich habe den Verdacht dass mit meinem Device Tree File was nicht in 
Ordnung ist. Ich habe zwar versucht, so gut wie es mir aufgrund meines 
Verständnisses möglich war, mich an die Spezifikation in 
Documentation/devicetree/botting-without-of.txt zu halten. Das kan dabei 
heraus:
1
/include/ "skeleton.dtsi"
2
3
/ {
4
  compatible = "nxp,lpc2468";
5
  model = "LPC2468 testboard";
6
  interrupt-parent = <&vic>;
7
8
  cpus {
9
    cpu@0 {
10
      compatible = "arm,arm7tdmi";
11
    };
12
  };
13
  
14
  memory {
15
    device_type = "memory";
16
    reg = <0xa0000000 0x4000000>;
17
  };
18
19
  ahb {
20
    #address-cells = <1>;
21
    #size-cells = <1>;
22
    compatible = "simple-bus";
23
    ranges;
24
25
    mac: ethernet@FFE00000 {
26
      compatible = "nxp,lpc-eth";
27
      reg = <0xFFE00000  0x1000>;
28
      interrupts = <0x1d 0>;
29
    };
30
    
31
    vic: interrupt-controller@FFFFF000 {
32
        compatible = "arm,vic";
33
        interrupt-controller;
34
        reg = <0xFFFFF000 0x1000>;
35
        #interrupt-cells = <2>;
36
    };
37
38
    apb {
39
      #address-cells = <1>;
40
      #size-cells = <1>;
41
      compatible = "simple-bus";
42
      ranges;
43
44
      uart0: serial@E000C000 {
45
        compatible = "ns16550a";
46
        reg = <xE000C000 0x100>;
47
        interrupts = <10 0>;
48
        clock-frequency = <72000000>;
49
        status = "okay";
50
      };
51
    };
52
  };
53
};

kann das stimmen? Beim Interruptcontroller bin ich mir halt nicht ganz 
so sucher. Eventuell muss ich dazu selber was erfinden... :-O

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli,
>
> ich habe den Verdacht dass mit meinem Device Tree File was nicht in
> Ordnung ist. Ich habe zwar versucht, so gut wie es mir aufgrund meines
> Verständnisses möglich war, mich an die Spezifikation in
> Documentation/devicetree/botting-without-of.txt zu halten. Das kan dabei
> heraus:
>

Ich kenne Device Tree auch nicht, aber man hat ja Sourcen ...
Also man nehme eine vergleichbare ARCH mit DT -> LCP33XX
arch/arm/boot/dts/lpc32xx.dtsi (ein inlucde FILE, kein BOARD File)

>
1
> /include/ "skeleton.dtsi"
2
> 
3
> / {
4
>   compatible = "nxp,lpc2468";
5
>   model = "LPC2468 testboard";
6
>   interrupt-parent = <&vic>;
7
> 
8
>   cpus {
9
>     cpu@0 {
10
>       compatible = "arm,arm7tdmi";
11
>     };
12
>   };
13
> 
14
>   memory {
15
>     device_type = "memory";
16
>     reg = <0xa0000000 0x4000000>;
17
>   };
18
>

Könnte passen, ich muß mal woanders lesen was memory:reg bedeutet.

>
1
>   ahb {
2
>     #address-cells = <1>;
3
>     #size-cells = <1>;
4
>     compatible = "simple-bus";
5
>     ranges;
6
>
Hier hat LPC32XX noch
1
  
2
ranges = <0x20000000 0x20000000 0x30000000>;
Sieht aus wie Addressen für DRAM

>     mac: ethernet@FFE00000 {
>       compatible = "nxp,lpc-eth";
>       reg = <0xFFE00000  0x1000>;
>       interrupts = <0x1d 0>;
>     };

Passt, ggf. Addresse und IRQ prüfen.

>
>     vic: interrupt-controller@FFFFF000 {
>         compatible = "arm,vic";
>         interrupt-controller;
>         reg = <0xFFFFF000 0x1000>;
>         #interrupt-cells = <2>;
>     };

Dort steht was von MIC ?? Controller, kein VIC

>
>     apb {
>       #address-cells = <1>;
>       #size-cells = <1>;
>       compatible = "simple-bus";
>       ranges;

Auch hier fehlt ggf der Adderess range
>
>       uart0: serial@E000C000 {
>         compatible = "ns16550a";
>         reg = <xE000C000 0x100>;
>         interrupts = <10 0>;
>         clock-frequency = <72000000>;
>         status = "okay";
>       };

Hier wurde der LPC3220 Controller benutzt -> PORT_LPC3220
in drivers/tty/serial/8250/8250.c
kann man lesen
1
  [PORT_LPC3220] = {
2
    .name    = "LPC3220",
3
    .fifo_size  = 64,
4
    .tx_loadsz  = 32,
5
    .fcr    = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO |
6
          UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
7
    .flags    = UART_CAP_FIFO,
IRQ Controller muss ich wie gesagt nochmal genauer lesen

von Alfons (Gast)


Angehängte Dateien:

Lesenswert?

Hi Ulli,

danke. Was die ganzen kryptischen Konstrukte im Device Tree angeht, habe 
ich das angehängte PDF gefunden, vielleicht ist das für dich auch 
interessant. Es geht dort zwar um PowerPC, aber der Device Tree ist ja 
grundsätzlich der selbe.

Noch eine Frage - in der init_machine() habe ich ja 
of_platform_populate().
Wann wird denn init_machine() aufgerufen? Bei mir ist er irgendwie gar 
nie soweit gekommen, dass er die Funktion aufgerufen hätte.

Ich frage mich, ob es daran liegt, dass ich noch irgendwas beim Booten 
falsch mache. Gemäss /Documentation/devicetree/booting-without-of.txt 
sollte es ja reichen, wenn man den Device Tree ins Memory kopiert und 
dann die Basisadresse in r2 übergibt.... So mache ich das auch. Und er 
wird auch erkannt, aber ich hab das Gefühl irgend ein kleines Detail 
fehlt noch, dass er init_machine() nicht aufruft.... :-/ Die Frage ist 
auch, wohin der Device Tree geladen werden muss. Ich nehme mal an, der 
darf nicht einfach irgendwo im Memory stehen, sonst wird er ja ggf. 
überschrieben? Darf er im Flash liegen?

Dann noch was - wenn ich den Kernel "in-Place" aus dem Flash laufen 
lasse - muss ich den Memory-Bereich, wo das Flash liegt, im Device Tree 
auch angeben? theoretisch macht das ja keinen Sinn, da der Kernel 
sowieso nicht ins Flash schreiben darf, sonst würde er sich ja selbst 
überschreiben :-)



Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hi Ulli,
>
> danke. Was die ganzen kryptischen Konstrukte im Device Tree angeht, habe
> ich das angehängte PDF gefunden, vielleicht ist das für dich auch
> interessant. Es geht dort zwar um PowerPC, aber der Device Tree ist ja
> grundsätzlich der selbe.

ich glaube er wird demnächst auch auf MIPS laufen, ich haben sowas auf 
der OpenWRT Mailingliste gelesen.

>
> Noch eine Frage - in der init_machine() habe ich ja
> of_platform_populate().
> Wann wird denn init_machine() aufgerufen? Bei mir ist er irgendwie gar
> nie soweit gekommen, dass er die Funktion aufgerufen hätte.
>

in
arch/arm/kernel/seutp.c habe ich was gefunden.
Was mir in dem Code gerade auffällt, falls es dir nicht schon bekannt 
ist :
Alle Bezeichner (Funktionen und Variablen) mit Unterschrich (Underscore) 
sind "versteckt". Je länger der Unterschrich ist umso verstecker sind 
diese und umso mehr Ärger bekommt man, wenn diese benutzt werden.

> Ich frage mich, ob es daran liegt, dass ich noch irgendwas beim Booten
> falsch mache. Gemäss /Documentation/devicetree/booting-without-of.txt
> sollte es ja reichen, wenn man den Device Tree ins Memory kopiert und
> dann die Basisadresse in r2 übergibt.... So mache ich das auch. Und er
> wird auch erkannt, aber ich hab das Gefühl irgend ein kleines Detail
> fehlt noch, dass er init_machine() nicht aufruft.... :-/ Die Frage ist
> auch, wohin der Device Tree geladen werden muss. Ich nehme mal an, der
> darf nicht einfach irgendwo im Memory stehen, sonst wird er ja ggf.
> überschrieben? Darf er im Flash liegen?

Die Doku ist meitens für den "normalen" Fall geschrieben, wenn das 
zImage im Speicher liegt. Da reloziert und entpackt sich ja 
bekanntermaßen.

>
> Dann noch was - wenn ich den Kernel "in-Place" aus dem Flash laufen
> lasse - muss ich den Memory-Bereich, wo das Flash liegt, im Device Tree
> auch angeben? theoretisch macht das ja keinen Sinn, da der Kernel
> sowieso nicht ins Flash schreiben darf, sonst würde er sich ja selbst
> überschreiben :-)
>

Vergleiche das mal den den anderen Arches, dort wird seit einiger Zeit 
"In-Place" gemacht und das zu Zeiten ohne Device Tree. Dort wurden alle 
Speicherbereiche mit angegeben.
Ich muss mir nochmal durchlesen wie die ATAGS und/oder DeviceTree an 
dem entpackten Kernel übergeben werden.

Der Kopf war schenller als ich gedacht habe.
in
arch/arm/boot/bootp startet der Kernel.
ich muss das mal prüfen mit einem XIP Kernel-Build

von Alfons (Gast)


Lesenswert?

Hi Ulli,

hmm ja die Setup.c "verpackt" einfach den Aufruf von init_machine() in 
customize_machine() :-) Zudem ist da noch

arch_initcall(customize_machine);

woraus ich allerdings leider auch nicht sehe, wann das Dingens 
aufgerufen wird.

Bezüglich des ganzen Memory Gedöns - ich werde also heute Abend mal 
versuchen, nicht mit XIP zu arbeiten, sondern mit dem zImage. Der soll 
sich selber seinen Speicher zurecht suchen, den er braucht ;-) Dann 
lasse ich den DT mal im Flash, das muss ja irgendwie gehen...

von Hans Ulli K. (Gast)


Lesenswert?

Arghh.
Der "richtige" Start ist in
arch/arm/kernel/head.S
muss ja auch Assembler sein, da ja noch kein Stack, MMU usw, 
initialisiert ist.
Der Compressor und das zImage sind ja "ungültig", und darauf kann man 
sich nicht verlassen.

Auch sieht man hier wieder das Register "r2" aber nur r2. Die ATAGS 
werden im DT falls nach DT "portiert", das habe ich im Bootcode gelesen.
Und auch jetzt verstanden warum das gemacht wurde:
Die  brauchten den stabilen code in head.S und setup.c kaum anzufassen 
um den DT zu implementieren, eine Fehlerquelle weniger.

In
arch/arm/kernel/setup.c
dürfte mein Kandidat zum starten dies hier sein
void __init setup_arch(char **cmdline_p)
Meine Vermutung das läuft irgendwie über eine Art Tabelle
struct machine_desc *machine_desc __initdata;

Das werde ich mir vielleicht heute nochmal genauer ansehen.

von Alfons (Gast)


Lesenswert?

Hallo Ulli,

so, ich hab das Ding jetzt so weit, dass er bis zur customize_machine() 
startet. Der Timer wird initialisiert und "tickt" dann nachher auch ;-) 
kann man sehen auf dem Terminal. Und nach einigen (5 oder so) 
Timer-Ticks kommt dann die machine_init(). Sieht also schon mal gut aus. 
Heute werde ich da noch die of_platform_populate() rein schreiben bei 
der machine_ini(), und dann sollte auch der UART usw. korrekt 
funktionieren nachher oder? of_platform_populate() "nimmt" sich, so wie 
ich das sehen kann, den Device Tree vor und schaut da drin, welche 
Devices es so gibt und initialisiert die mal. Richtig?

Ein Problem habe ich allerdings noch immer. WO muss ich den Device Tree 
ablegen? Ich habe mal versucht, die dtb-Datei als binäre Daten im Flash 
abzulegen. Das funktionierte nicht, offenbar muss sie im RAM sein. Lede 
ich die Datei aber im RAM unterhalb von 0xa0000000 ab, so funktioniert 
gar nichts; dann bleibt er schon bei bootmem_init() hängen, weil er 
meint, von 0x40000000 bis 0xa4000000 sei durchgehender Speicher, aber 
ich habe den ja nicht contiguous, sondern mit "Löchern" drin :-( also 
muss ich den Device Tree ins SDRAM speichern, und dort besteht irgendwie 
immer die Gefahr, dass der Kernel ihn selbst überschreibt... Hast du 
eine Idee?

Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hallo Ulli,
>
> so, ich hab das Ding jetzt so weit, dass er bis zur customize_machine()
> startet. Der Timer wird initialisiert und "tickt" dann nachher auch ;-)
> kann man sehen auf dem Terminal. Und nach einigen (5 oder so)
> Timer-Ticks kommt dann die machine_init(). Sieht also schon mal gut aus.
> Heute werde ich da noch die of_platform_populate() rein schreiben bei
> der machine_ini(), und dann sollte auch der UART usw. korrekt
> funktionieren nachher oder?

Wenn der IRQ für den UART funktioniert, dann ja.
Im Fehlerfall würde ich dort erstmal suchen, zuerst sehen ab der IRQ 
auch "requestet" wird
siehe
/drivers/tty/serial/8250/8250_core.c
Funktion
1
static int serial_link_irq_chain(struct uart_8250_port *up)
ggf. kann man hier noch ein printk einfügen.
Oder sich was andere ausdenken ..., ggf. den Output über earlyprintk 
laufen lassen (hier den direkten Einsprungpunkt suchen und nutzen !)
Debugen per gdb und Co. ist hier schwer

git grep
Und einige Terminals sind hier nützlich.

> of_platform_populate() "nimmt" sich, so wie
> ich das sehen kann, den Device Tree vor und schaut da drin, welche
> Devices es so gibt und initialisiert die mal. Richtig?
>

Soweit richtig

> Ein Problem habe ich allerdings noch immer. WO muss ich den Device Tree
> ablegen? Ich habe mal versucht, die dtb-Datei als binäre Daten im Flash
> abzulegen. Das funktionierte nicht, offenbar muss sie im RAM sein.

Laut Doku soll dies auch im RAM liegen. Ich tippe darauf das nacher 
vielleicht die Sache "freigegeben" wird (muss aber nicht sein).

> Lede
> ich die Datei aber im RAM unterhalb von 0xa0000000 ab, so funktioniert
> gar nichts; dann bleibt er schon bei bootmem_init() hängen, weil er
> meint, von 0x40000000 bis 0xa4000000 sei durchgehender Speicher, aber
> ich habe den ja nicht contiguous, sondern mit "Löchern" drin :-( also
> muss ich den Device Tree ins SDRAM speichern, und dort besteht irgendwie
> immer die Gefahr, dass der Kernel ihn selbst überschreibt... Hast du
> eine Idee?
>

Zur Zeit noch nicht.
Das mit den memory holes ist ja übel.
Zwischendurch ist mir eingefallen was es vielleicht mit dem 
(DIS)CONTINOUS memory allocation zu tun hat.
Das war glaube ich eine "Erfindung" von Samusung für deren Video Chip 
auf dem Smartphone/Tablet um hier Fenster effektiv zu 
kopieren/verschieben.
Genauers weiss ich aber nicht mehr, nur das es im diesem Fall sogar 
ein Video von einer Hackerkonferenz gab, wo dieses Feature vorgestellt 
wurde. Da wurde erzählt wie es Mainline wurde, Samsung wollte da andere 
Wege gehen ...

Warum jetzt von der HW so viele Löcher drin sind ist seltsam. Bei dieser 
Config kommen garantiert Probleme vor mit der Speicherverwaltung.
Was passiert wenn du am Ende eines Bereiches bist und der Userspace 
(ggf. auch Kernel) mach ein realloc().
Auch sind andere Sachen vorstellbar, ich kann mich aus MS-DOS Zeiten 
noch dran erinnern, das man die memalloc INT Aufruf "tunen" konnte. Nach 
FIRST, BEST, LAST Speicherbereichen. Die 8086 CPU hatte ja auch keine 
MMU :(, da wurde halt der Speicher "knapp" weil zuviele kleine Bereich 
alloziert wurden.

Zwischendurch bin ich wegen dem append DT und initramfs weitergekommen 
und kann sagen es geht nicht, weil da einige Pointer verkehrt 
berechnet werden. Was aber auch in der Doku richtig (für mich aber 
leider falsch) ist :(

Dazu musste ich etwas länger nachdenken, dreimal den Compiler 
anwerfen und das Ergebnis ansehen. Kein Test auf der HW war nötig.
Jetzt muss ich nur noch sehen ob ich die Sache im Build patchen kann. So 
wie ich es haben will, dann ist es auch etwas universeller ...


> Gruss

von Alfons (Gast)


Lesenswert?

Hi Ulli,

also dann ist es normal und richtig, dass die Memory-Verwaltung nicht 
korrekt funktioniert, wenn so grosse Löcher im Memory vorhanden sind?
sehr seltsam. Aber gut, dann muss ich damit leben, dass das interne RAM 
nicht nutzbar ist.

Wegen dem appended DTB - das funktioniert also mit dem offiziellen 
Kernel nicht ? Das ist auch gut zu wissen. Dann muss ich damit nichts 
mehr rum pröbeln. Muss nur noch rausfinden, WO der DTB abgelegt werden 
muss, ob am Anfang (Offset 0 wohl kaum) oder am Ende (0xa3fff000 oder 
sowas). In der Mitte wohl kaum, da wird der ja überschrieben...

Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Alfons schrieb:
> Hi Ulli,
>
> also dann ist es normal und richtig, dass die Memory-Verwaltung nicht
> korrekt funktioniert, wenn so grosse Löcher im Memory vorhanden sind?
> sehr seltsam. Aber gut, dann muss ich damit leben, dass das interne RAM
> nicht nutzbar ist.

Das interne RAM (64kib ??) ist laut dem Kernel auf google, für die 
Diskriptoren von Ethernet (und USB ?) genutzt. Status in uClinux und 
mainline Kernel nicht bekannt.
Mit den memory Holes ist von mir nur eine Vermutung, weil ich ja keine 
MMU habe die mir den Speicher "verschiebt".
Ich würde erstmal die größten zusammenhängen Speicher verwenden und 
nicht mehr. Dann wenn der Kernel sauber läuft (also bis in den 
Userspace oder ins vfs), das mit den Holes testen.
Ich habe damit potenzielle Fehlerquellen weniger.

>
> Wegen dem appended DTB - das funktioniert also mit dem offiziellen
> Kernel nicht ? Das ist auch gut zu wissen. Dann muss ich damit nichts
> mehr rum pröbeln. Muss nur noch rausfinden, WO der DTB abgelegt werden
> muss, ob am Anfang (Offset 0 wohl kaum) oder am Ende (0xa3fff000 oder
> sowas). In der Mitte wohl kaum, da wird der ja überschrieben...
>

Der Speicherbereich vom DTB wird sowieso nacher "überschrieben"
Nach dem machine_init() und Co. ist der DTB wertlos.

Auch sollten die Device Treiber beim Init nur minimal Speicher 
anfordern. Erst beim open() wird/sollte der größte Teil alloziert 
werden.
z.B.
ifconfig up
macht ein net_if->open()
und da werden die ganzen Buffer alloziert.

append DTB und initramfs.

append DTB geht alleine problemlos, das ist aber auch erst ab 3.9-rc1 
(mainline) drin, soweit ich es gesehen habe.
Wenn jetzt append DTB und initramfs (auch nur die Option ?) aktiviert 
ist, wird das "integrierte" cpio Archiv leider in der Berechnung des 
Offsets auf den DTB vergessen. Und das auch nur deshalb weil alleine 
dazu nur die Größe von zImage (oder Image steht irgendwo im Code ;-) ) 
genommen wird.
Genaueres kann ich aber erst in ein paar Tagen sagen. Das habe ich 
allein aus der Größe von vmlinux und den Files im usr Verzeichnis 
gesehen.

Wie gesagt zuerst hatte ich auf der HW nur
"booting Linux"
gesehen, und das kommt von "earlyprintk" danach kam nichts mehr.

Und ich möchte mein DTB an dem zImage mit intergrierten initranmfs 
cpio Archiv hängen. Also
zImage + cpio + DTB
Alles andere ist in meinem Sinne Blödsinn, ich kann dann die HW Platform 
nicht einfach ändern.
Ein
zImage + DTB + cpio
ginge auch ist aber kompliziert, da sich ja die Größe vom DTB ändern 
kann.
Mal sehen ...

Was mir zwischendurch durch den Ausflug nach MS-DOS eingefallen ist :
Du hast doch auf SoC eine Menge freier I/O Pins ...
Du kannst doch einen vielleicht dafür benutzten um dir eine "Debug" 
Ausgabe für den UART IRQ zu basteln.
Einfach bei jedem Interrupt den Output toggeln ...

So habe ich in etwa früher auf dem C64 die Interrupt Routinen "debuged", 
da habe ich den Rahmen von Bildschirm immer geändert.

Schau erstmal das der Kernel nur mit UART, RAM ggf. MTD compiliert wird.
Alle anderen Sachen raus, der DT kann ruhig komplett sein.

Ich weiss jetzt nicht ob du schon mit git angefangen hasst.
Aber dazu noch ein Tipp von mir :
Wenn du soweit bist mach für jede Änderung die logisch ist, auch wenn 
es nur eine Zeile ist, ein git add/commit.
Damit kannst zu auch ohne HW coden, bzw. brauchst den Compiler nicht 
laufen zu lassen. Die Zeiten für TFTP und Co. rechne ich auch mal dazu.
Ich habe da mal einen Treiber "überarbeitet" und erst nach einiger Zeit 
merkt (als ich einen HW Test machte) das das ein Fehler im Code war.
Ein git bisect hatte mir in dem Fall geholfen.
Ich habe ingesammt Zeit gespart und brauchte unterwegs die HW nicht mit 
mir herum schleppen ;-)




> Gruss

von Hans Ulli K. (Gast)


Lesenswert?

Was mir gerade noch auffällt, ich weis jetzt nicht ob du diese Option 
eingeschaltet hast.
1
*
2
 *  linux/arch/arm/kernel/debug.S
3
 *
4
 *  Copyright (C) 1994-1999 Russell King
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation.
9
 *
10
 *  32-bit debugging code
11
 */
12
#include <linux/linkage.h>
13
#include <asm/assembler.h>
14
15
    .text
16
17
/*
18
 * Some debugging routines (useful if you've got MM problems and
19
 * printk isn't working).  For DEBUGGING ONLY!!!  Do not leave
20
 * references to these in a production kernel!
21
 */
Wird aktiviert mit "Kernel low-level debugging functions" in Hacking.

Die Schnittstelle wird in head.S in arch/arm/kernel
suche nach dem addruart Makro usw.
Den Aufruf dazu muss du mit deiner HW anpassen.
Das DING läuft vor earlyprintk

von Alfons (Gast)


Lesenswert?

Hi Ulli,

ich so danke für deine Ausführungen. Ich bin jetzt auch wieder einen 
Schritt weiter. Also das mit den Löchern im Memory funktioniert wirklich 
nicht, da kann ich machen was ich will. Aber, was jetzt geht - er bootet 
reproduzierbar bis rest_init(); in der init/main.c!!! Das Problem, 
warum es bisher nicht sauber gelaufen ist, war bei meiner HW. Ich hatte 
vorher noch nie wirklichen Code aus dem externen Flash laufen lassen, 
sondern immer nur aus dem SDRAM, und das hat auch immer funktioniert. 
Aus dem Flash geht es jetzt auch, wenn man den Memorycontroller 
richtig initialisiert vor dem booten :-D ich musste Burst- Zugriffe 
aktivieren und ein paar Waitstates mehr einfügen, und siehe da, der 
Timer wird initialisiert und tickt, und er kommt immer reproduzierbar 
bis rest_init() hoch. Super! Jetzt muss ich nur noch rausfinden, was 
dann passiert.

Mein DT wird mit of_platform_populate() anscheinend auch "angeguckt", 
aber der UART scheint noch nicht zu funktionieren, da hakt noch was. 
Eine Debug-Ausgabe sagt zwar, dass die Init des 8250 aufgerufen wird, 
mehr passiert dann allerdings auch nicht. Morgen muss ich dem noch 
weiter auf den Grund gehen, erstmal Feierabend machen.

Zu deinem Vorschlag mit Git - selbstverständlich habe ich eine 
Versionsverwaltung. Ich benutze allerdings SVN, weil ich da schon alles 
drin habe und ich alles beieinander haben möchte. Also habe ich den Code 
mal da eingechekt.


Gruss

von Hans Ulli K. (Gast)


Lesenswert?

In rest_init() wird wie der Name es sagt /sbin/init gestartet.

Es gehen auch andere Programme :
Ist hier zu lesen Zeil 851 in init/main.c
1
  if (!run_init_process("/sbin/init") ||
2
      !run_init_process("/etc/init") ||
3
      !run_init_process("/bin/init") ||
4
      !run_init_process("/bin/sh"))
Am einfachsten ist es direkt die Shell zu starten.
Ab hier hast du aber schon zwei Prozesse am laufen ...

Ja SVN hatte ich auch mal benutzt, auch zu Zeiten wo ich mit dem Kernel 
angefangen Kernel habe.
Als ich später mal ein paar Branches hatte und die wollte ich dann 
Mergen, hat mein Kleinhirn die weisse Fahne gehisst.
Der umstiegt von SVN nach git hatte denn etwas lange gedauert, da ich 
ja in dem File und/oder Directory Schema gedacht habe.
Jetzt würde ich nichts anderes verwenden.
Es gibt auch hg und bazar die sind irgendwie ähnlich.

So zum Thema DT und initramfs kannn ich jetzt sagen :
Soweit ein kleine cpio Archiv vorhanden ist, startet der Kernel 
"normal", findet aber ein korruptes Archiv und entpackt dies nicht.
Wenn das RootFS größer ist (um 2MiB gepackt), dann kommt nur
"Linux booting"

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.