Hallo zusammen,
ich bin dran, ein Embedded Linux zum Laufen zu bringen, oder versuche es
zumindest. :-)
Ich bin schon mal soweit, dass ich ein xipImage kriege, und das bootet
auch teilweise, jedenfalls kann ich mir printk() Meldungen ausgeben.
Jedoch irgendwo noch bevor der init-Prozess gestartet wird, läuft was
schief, und ich habe noch nicht rausgefunden, was.
Jetzt die Frage - kann ich diesen Kernel einfach normal mit GDB
debuggen?
Es handelt sich um ein ARM7 System, der Kernel soll vom ext. Flash
direkt in-place ausgeführt werden, also ohne dekompression etc.
Zum Debuggen möchte ich gerne ddd benutzen; was muss ich tun, um die
Symbole in ddd geladen zu kriegen? "Normale" Programme kann ich auf dem
Target so debuggen, aber beim Kernel bin ich mir nicht so sicher.
(Dass es bei multithreading dann schwierig wird, ist natürlich klar,
aber solange der Kernel nicht richtig hoch kommt, sollte es so mit ddd
ja klappen, oder?)
Gruss Tobias
Moin Tobias,
da ich bald das selbe Problem haben werde und gerade beim einlesen bin,
bin ich gerade über kgdb gestolpert.
http://scottt.tw/linux-tutorials/
letztes tutorial. kgdb scheint ein gdb modul für den Kernel zu sein. Wie
gesagt ich hab da auch noch keine Erfahrung, Kenne Linux bisher nur als
Desktop Nutzer und da auch nur wenig von console usw.
Falls du für mich n Tip hast wo man sich gut einlesen kann gern :)
MfG
Tec
Musst du wirklich so tief einsteigen?
Was kommt denn als Fehler bevor es nicht mehr weitergeht? Versuch mal
alles was du nicht brauchst zu deaktivieren bzw. gibts da auch afaik ein
paar Optionen, dass er die Module nicht automatisch beim Hochfahren läd.
Tobias Plüss schrieb:> Ich bin schon mal soweit, dass ich ein xipImage kriege, und das bootet> auch teilweise, jedenfalls kann ich mir printk() Meldungen ausgeben.> Jedoch irgendwo noch bevor der init-Prozess gestartet wird, läuft was> schief, und ich habe noch nicht rausgefunden, was.> Jetzt die Frage - kann ich diesen Kernel einfach normal mit GDB> debuggen?
Pah, das ist Highlevel :-)
Kernel mit Debug-Symbols compilieren und dann den gdb mit JTAG anbinden.
Da kommst du wirklich bis zur Drahtebene.
http://elinux.org/Debugging_The_Linux_Kernel_Using_Gdb
Tobias Plüss schrieb:> ich bin dran, ein Embedded Linux zum Laufen zu bringen, oder versuche es> zumindest. :-)
jeder hat mal angefangen, also mach nur weiter
> Ich bin schon mal soweit, dass ich ein xipImage kriege, und das bootet> auch teilweise, jedenfalls kann ich mir printk() Meldungen ausgeben.
fein das ist doch schon mal was.
> Jedoch irgendwo noch bevor der init-Prozess gestartet wird, läuft was> schief, und ich habe noch nicht rausgefunden, was.
Wie verhält sich das "läuft was schief" genau?
Endlesslop, Crashdump etc.. beschrieb das mal etwas genauer um dir zu
helfen ist das entscheidend, vielleicht kann man an diesen Informationen
schon das Problem soweit eingrenzen das man das schwere geschütz
Debugger im Schrank lassen kann. ggf kannst du die Aussgabe der
Rootconsole mitzuschneiden. (gnu/screen kann das zum Beipiel)
> Jetzt die Frage - kann ich diesen Kernel einfach normal mit GDB> debuggen?
Nein das geht nicht. es gibt wie schon ewähnt den kgdb, aber der geht
auch nicht immer einfach so. Ausserdem brauchts du auf den host ein gdb
welcher für das Taget ARM7 ist. Alles andere ist quatsch. Wichtig ist
auch die System.map dort liegen die debugg informationen für dein
Kernel.
Alternativ liefern auch Hersteller wie Lauterbach, Windriver, Montavista
und der erzeuger deines BSP meistens bessere oder schlechtere Tools für
das Kernel debuggen.
Der Lauterbach debugger ist toll aber mit mehren Kilo Euros so teuer,
das man denn auch nur dann kauft wenn man das Hauptberuflich macht.
>> Es handelt sich um ein ARM7 System, der Kernel soll vom ext. Flash> direkt in-place ausgeführt werden, also ohne dekompression etc.>
geht, für das debuggen und Entwickeln ist es aber meisten eleganter, den
Bootloader zu sagen den Kernel via TFTP zu laden das geht in der Regel
schneller mal was auszu probieren. Btw das root als NFS ist aus denn
grund auch nicht schlecht.
> Zum Debuggen möchte ich gerne ddd benutzen; was muss ich tun, um die> Symbole in ddd geladen zu kriegen? "Normale" Programme kann ich auf dem> Target so debuggen, aber beim Kernel bin ich mir nicht so sicher.
Auch das geht mit den passenden Arm7 gdb und denn kernel mit kgdb.
Ich glaube der ddd parameter war --target-*
Aber wichtiger bei solchen Problemen ist ddd als "debuggen druch Denken"
zu übersetzten und sich nicht auf seine GUI zu verlassen, wie ob schon
angedeutet kann man bie vielen Fehlern durch scharfes Hinsehen und
logisch denken vieles schon erschlagen bevor andere Ihren gdb und ddd
zum laufen gebracht haben. Ausserdem behaupten einige das man mit einen
debugger die symtome bekämpft und nicht die Ursachen.
Hallo zusammen,
erstmal danke für eure zahlreichen Antworten!
Nun, einen JTAG-Debugger für mein Target sowie eine passende GDB
executable habe ich natürlich. Das funktioniert auch, habe ich für
"gewöhnliche" Programme schon getestet. Was ich vorerst mal tun will,
ist ja nicht einmal, irgendwelches Scheduler-Zeugs zu testen, sondern
ich will zunächst nur mal nachvollziehen, was denn nicht geht.
Da ich die Hardware selber gebaut habe, gibt es auch kein fertiges BSP,
was ich einfach hernehmen kann und das läuft, sondern ich musste da
selber was schreiben gemäss "ARM Linux porting guide".
Mein Kernel bootet eigentlich soweit hoch, dass er bis dort kommt, wo
/sbin/init aufgerufen werden sollte. Mein Problem ist halt, dass der
UART-TReiber bisher auch noch nicht richtig geladen wurde - ich habe
einen 16c550 kompatiblen UART, aber aus irgend einem Grunde geht
printk() nicht ordentlich, sondern ich habe mir mit early_printk() was
zurechtgebogen. :-/
Auf jeden Fall habe ich meinen Tick-Interrupt mal so gemacht, dass bei
jedem Interrupt eine Meldung via early_printk() auf der Seriellen
ausgegeben wird; den Timer habe ich mal mit 10 Hz angesetzt, was locker
passt. Der Tick Interrupt kommt dann einige 100 mal, bis der Kernel
schliesslich versucht, init zu laden, was anscheinend fehl schlägt, und
dann stürzt die Kiste ab (Reset). Sieht mir ganz danach aus, als ob da
irgendwie ein ungültiger Pointer oder sowas wäre, aber bis jetzt konnte
ich es noch nicht so ganz nachvollziehen.... :-(
Ich will heute Abend mal mit dem Tutorial versuchen, den GDB anzuwerfen
und mir mit ddd das mal anzuschauen, bin gespannt ob ich was sehe
(wenigstens unversucht will ich es nicht lassen ;-) ).
Gruss
Moin zusammen,
danke nochmals für eure Hilfe.
Was ich in der Zwischenzeit versucht habe:
ich habe ein xipImage neu erstellt und dieses ins Flash geladen. Das
xipImage bootet (halt fehlerhaft noch bis jetzt) und ich wollte mal den
Debugger anwerfen. Wie erwähnt habe ich für mein Target einen J-Link mit
GDB-Server. Das Debuggen funktioniert so, habe ich mit früheren
Programmen schon getestet, allerdings ist mir nicht klar, welche der
vielen beim Compilieren erzeugten Dateien ich im Debugger laden muss,
damit ich die Symbole geladen kriege. xipImage enthält keine Symbole,
ebenso wenig wie vmlinux. Wo sind denn diese Symbole drin?
Dann noch was anderes.
Ich habe bemerkt, dass mein Kernel eigentlich korrekt booten würde, wenn
ich im Timerinterrupt die UART-Ausgaben weglasse. Stattdessen lasse ich
bei jedem Timer-Tick einen Pin toggeln; auf dem Oszi lässt sich dies
hervorragend nachvollziehen und der Timer-Tick scheint zu funktionieren!
Allerdings ist der Timer das einzige, was mein Kernel bis jetzt im
Stande ist, zu initialisieren :-) Zwar habe ich einen m.E. korrekten
"Device Tree" erstellt, wie dies gefordert wird, aber dort drin werden
meine Devices nicht gefunden, z.B. der UART wird nicht initialisiert
etc. Was könnte da das Problem sein? Wenn ich es halt debuggen könnte,
wäre es schon viel einfacher, aber das geht halt leider noch nicht,
daher kann ich auch nur eine so schwammige Fehlerbeschreibung geben :-(
Ich würde mal drauf tippen das irgendwas mit der Config vom 16550 nicht
stimmt.
Hast du den DeviceTree mit r2 an den Kernel übergeben ?
Die Symbole sind in der Datei System.map im Builddir vom Kernel.
Benutzt du den vanilla Kernel oder den von uClinx.org ?
Schau mal bei beiden nach welche Platform deiner CPU/SoC am nächsten
kommt. Das ARM Porting Guide ist eigentlich dafür gedacht wenn du bei
Null anfangen musst.
Hallo zusammen,
so, ich bin nun ein ganzes Stück weiter!
Ich konnte nun alle meine early_print() raus schmeissen, denn mein
Kernel kann jetzt so weit booten, dass der UART erkannt wird und die
normalen Kernel-Meldungen erscheinen!
1
Booting Linux on physical CPU 0x0
2
Linux version 3.8.5+ (tobias@zap) (gcc version 4.7.3 20130312 (release) [ARM/emb
3
edded-4_7-branch revision 196615] (GNU Tools for ARM Embedded Processors) ) #135
[<80002f04>] (dump_backtrace+0x0/0x104) from [<800ebab0>] (dump_stack+0x18/0x1c)
34
r6:a001c9c8 r5:a000aa20 r4:a00a47f0 r3:00000001
35
[<800eba98>] (dump_stack+0x0/0x1c) from [<800ebb34>] (panic+0x80/0x1c4)
36
[<800ebab4>] (panic+0x0/0x1c4) from [<8012b0ec>] (bcm2835_time_init+0x88/0xb8)
37
r3:ffffffff r2:ffffffea r1:ffffffff r0:8011b38e
38
r7:a00a4be0
39
[<8012b064>] (bcm2835_time_init+0x0/0xb8) from [<80120fe0>] (time_init+0x28/0x38
40
)
41
r4:a001c740
42
[<80120fb8>] (time_init+0x0/0x38) from [<8011e6f8>] (start_kernel+0x18c/0x2b4)
43
[<8011e56c>] (start_kernel+0x0/0x2b4) from [<8000001c>] (0x8000001c)
44
r7:a0013e1c r6:a000aa1c r5:a001301c r4:00000000
leider erkennt ihr, dass nicht alles ganz so funktioniert; das "Register
remapping" scheint nicht zu funktionieren. Ich schätze, wenn ich keine
MMU habe, dann wird auch map_io() vom Machine Record nie aufgerufen,
richtig? und ohne MMU brauche ich auch kein Remapping?
Wie kriege ich dann jeweils die Basisadresse meiner Devices?
Hi Hans Ulli,
nein die Fehlermeldung kommt von meinem Code, habe da was kopiert und
auf meine Bedürfnisse angepasst.
Er scheitert halt beim Statement hier:
1
node=of_find_matching_node(NULL,timer_match);
2
if(node==NULL){
3
panic("can't find node!");
4
}
5
base=of_iomap(node,0);
6
7
/* mapping successful? */
8
if(base==NULL)
9
{
10
panic("Can't remap registers");
11
}
Die node für den Timer findet er also, das macht er korrekt. Aber
of_iomap() schlägt fehl. Aber die Frage ist halt, ob ich das wirklich
brauche, auch wenn ich keine MMU habe?
Edit:
mein KConfig sieht so aus:
Tobias Plüss schrieb:> Die node für den Timer findet er also, das macht er korrekt. Aber> of_iomap() schlägt fehl. Aber die Frage ist halt, ob ich das wirklich> brauche, auch wenn ich keine MMU habe?>
of_iomap brauchst du hier nicht, weil wie gesagt keine MMU.
Aber du brauchst ja deine BASE Addresse vom Device aka Timer.
In der Funktion of_iomap () ist auch die Lösung zu finden ...
1
void __iomem *of_iomap(struct device_node *np, int index)
2
{
3
struct resource res;
4
5
if (of_address_to_resource(np, index, &res))
6
return NULL;
7
8
return ioremap(res.start, resource_size(&res));
9
}
Wenn du folgenden Teil benutzt :
1
struct resource res;
2
3
if (of_address_to_resource(np, index, &res))
4
return NULL;
liegt in res.start deine BASE Addresse.
In einigen (alten) Treiberen wurde nach dem "get_resource" noch ioremap
"zu Fuss" gemacht"
> Also nichts mit Multiplattform.
War meine erste Annahme nach einigem grepen
Was mich auch noch stutzig mach(te) war/ist folgende Ausgabe.
bcm2835_time_init
Hmmm ...
kennst du ein gutes und preisgünstiges Board ??
Wichtig ist auch das es ein Gehäuse dafür gibt, ich habe keine Lust zum
basteln.
Vielleicht würde es mich mal reizen mal mit einem NOMMU System zu
spielen.
Ich kenne jetzt schon MIPS und ARM Systeme aber alles mit MMU ...
Die Netzwerkperformance (Ethernet/Wifi) und USB dürften wohl
unterirdisch sein.
Achja
Den CodingStyle solltest du mal überdenken ...
Die geschweiften Klammer sind nicht K&R.
Was jetzt mit den Spaces vor und nach den Klammern ist, lass ich ertsmal
da ich es selbst nach einigen Jahren(zehnten ?) noch nicht verinnerlicht
habe .
Hallo Hans Ulli,
danke für den Hinweis. Das habe ich auch schon gesehen, aber war mir
nicht sicher. Aber danke für deine Bestätigung, ich habe es jetzt bei
mir so implementiert!
Was ich mich noch frage:
Es gibt ja die Timer-Initfunktion, welche auch im machine Record
vermerkt wird (mit der sys_timer-Struktur). Meine Timer-Init sieht jetzt
wie folgt aus:
Testen konnte ich es noch nicht, aber es erscheint mir nun alles relativ
plausibel. Was ich damit machen will - im Device Tree habe ich bei einem
Timer einen Property "system-timer;" erstellt. Denjenigen Timer suche
ich heraus, und benutze den dann. Dann ermittle ich aus dem Device Tree
die Basisadresse des Timers, und lege Pointer auf die einzelnen Register
in der Struktur timer ab (bei /* set all register addresses */).
Jetzt habe ich hierzu noch ein paar Fragen:
1. zu welchem Zeitpunkt soll ich den Timer wirklich initialisieren,
sodass der auch im Stande ist, Interrupts zu generieren? Ich habe mal
unten als Kommentar eingefügt, an welcher Stelle ich das machen würde.
Sicher bin ich mir aber nicht; im Code für den BCM2835 (bcm2835_timer.c)
kann ich nicht erkennen, wo da der Timer wirklich gestartet wird.
2. setup_sched_clock(): wozu genau braucht man das? verstehe ich das
richtig, dass der Scheduler die dort angegebene Callbackfunktion
aufruft, und so die verstrichene Zeit zu bestimmen? rate (letzter
Parameter) ist die Anzahl der Timerinterrupts pro Sekunde?
3. clocksource_mmio_init(): sieht für mich irgendwie nach dem selben aus
wie setup_sched_clock(). Wozu dient das?
Hoffe du hilfst mir weiter. :-)
Vielen Dank & Gruss
Ich antworte erstmal schnell auf die Fragen ...
Der Rest folgt dann noch heute Abend
Tobias Plüss schrieb:> Jetzt habe ich hierzu noch ein paar Fragen:> 1. zu welchem Zeitpunkt soll ich den Timer wirklich initialisieren,> sodass der auch im Stande ist, Interrupts zu generieren? Ich habe mal> unten als Kommentar eingefügt, an welcher Stelle ich das machen würde.> Sicher bin ich mir aber nicht; im Code für den BCM2835 (bcm2835_timer.c)> kann ich nicht erkennen, wo da der Timer wirklich gestartet wird.
Das müsste normalerweise noch dem init des Kernels ablaufen.
Also nach CPU, MMU init, davor kommt noch die Meldung mit BogoMips.
Der Timer wird ja auch benutzt um den internen udelay zu kalibieren,
diesen braucht auch zum Teil beim Device Init.
>> 2. setup_sched_clock(): wozu genau braucht man das? verstehe ich das> richtig, dass der Scheduler die dort angegebene Callbackfunktion> aufruft, und so die verstrichene Zeit zu bestimmen? rate (letzter> Parameter) ist die Anzahl der Timerinterrupts pro Sekunde?>
Ja.
Soweit ich das auf ich schnelle in verschiedene Sourcen Lese korreliert
das mit der Anzahl der Zyklen bis zum "Timerüberlauf" siehe Timer in
arch/arm/mach-sa1100/time.c
obwohl ich eigentlich zu den Sourcen in
arch/arm/mach-lpc32xx/timer.c
tendiere, das ist näher am LPC24XX.
Ich würde da ggf. einen Mix von allen dreien machen
> 3. clocksource_mmio_init(): sieht für mich irgendwie nach dem selben aus> wie setup_sched_clock(). Wozu dient das?>
Aus dem Kopf wusste ich es auch nicht aber
gitk drivers/clocksource/mmio.c
gibt schon mal den Anfang
1
Autor: Russell King <rmk+kernel@arm.linux.org.uk> 2011-05-08 15:06:52
2
Eintragender: Russell King <rmk+kernel@arm.linux.org.uk> 2011-05-23 19:04:51
3
Zweig: master and many more (566)
4
Folgt auf: master-2011-05-16, v2.6.39
5
Vorgänger von: v3.0-rc1
6
7
clocksource: add common mmio clocksource
8
9
Add a generic mmio clocksource, covering both 32-bit and 16-bit register
10
access sizes, for up or down counters. This can be used to easily
11
create clocksources for simple counter-based implementations.
So jetzt muss ich erstmal sehen was
readl_relaxed()
heist, readl usw. kenne ich ja schon ...
Martin schrieb:> Portierst/entwickelst Du für einen NXP Prozessor?> Darf man Fragen für welchen?
Ich Tippe mal auf das Bootlog
Machine: LPC24XX SoC (Flattened Device Tree), model: LPC2468 Board
Flags: nZCv IRQs on FIQs off Mode SVC_32 ISA ARM Segment kernel
52
Process (null) (pid: -481230803, stack limit = 0xe24ff43e)
Das initialisieren des Timers funktioniert, der Interrupt wird
aufgerufen. Soweit klappt es also! aber mit dem Clockevents oder so
scheint noch was nicht gut zu sein - das muss ich morgen rausfinden.
Gruss
Ich hab die Busybox compiliert und ein root file system kreiert. Das
wird anscheinend auch geladen, aber man sieht es nicht, weil der UART
nicht zu funktionieren scheint :-) warum auch immer. Was müsste man da
wohl noch tun?
BTW, was ist das Modul "brd" ?
Gruss
Moin,
anstatt ständig Kernel Logs zu posten wäre es ganz schön zu wissen was
du gemacht hast um es zum Laufen zu bringen. Quasi für die Nachwelt.
Gruss,
Tobi
Das ist der Treiber die RAMDISK.
Wenn ich das Log richtig lese (wobei mir irgendwie noch einige Zeilen
fehlen)
ist das RootFS schon da, weil ja das brd (RAMDISK_DEV) geladen wird.
Tobi schrieb:> Moin,>> anstatt ständig Kernel Logs zu posten wäre es ganz schön zu wissen was> du gemacht hast um es zum Laufen zu bringen. Quasi für die Nachwelt.
gibt es denn überhaupt Interesse ??
Der Tobias Plüss ist erst am Anfang der Anfang der Kernelentwicklung ...
Als Anfang würde ich erst mal dazu raten ein RootFS mal selber zu bauen
und dann mal auf einem Zielsystem ARM oder MIPS per chroot zu starten
...
ggf. würde ich auch mal zu Gentoo/Sabayon raten, da es dort eine sehr
gute Unterstüzung für CrossCompiler Development eingebaut ist.