In Es wurde ein mehr oder weniger funktionierender Speichercontroller realisiert, genauer gesagt eine Wrapper über den IP Core aus Quartus, der als Schnittstelle zu TileLink dient. Heute in der Rubrik „Portierung von RocketChip auf eine wenig bekannte chinesische Platine mit Cyclone“ sehen Sie eine funktionierende Konsole. Der Prozess hat sich etwas verzögert: Ich dachte schon, ich könnte Linux schnell starten und dann weitermachen, aber dem war nicht so. In diesem Teil lade ich Sie ein, den Startprozess von U-Boot, BBL und die zaghaften Versuche der Initialisierung des Linux-Kernels zu betrachten. Aber die Konsole existiert – es ist eine U-Boot-Konsole, und sie ist ziemlich fortgeschritten und bietet vieles, was Sie von einer vollwertigen Konsole erwarten.
In der Hardware wird eine SD-Karte hinzukommen, die über den SPI-Bus angeschlossen ist, sowie UART. Im Softwareteil wird BootROM ersetzt durch xip findet man sdboot und es werden die folgenden Boot-Stufen hinzugefügt (auf der SD-Karte).
Feintuning der Hardware
Die Aufgabe lautet: Wir müssen auf einen „großen“ Kern umsteigen und UART (vom Raspberry) sowie einen SD-Adapter anschließen (es wurde eine Platine von Catalex mit sechs Pins verwendet: GND, VCC, MISO, MOSI, SCK, CS).
Im Grunde war alles ziemlich einfach. Doch bevor ich es realisierte, wurde ich etwas hin und her geworfen: Nach dem letzten Mal beschloss ich, dass ich wieder einfach ein wenig mischen muss in System so etwas wie HasPeripheryUART (und entsprechend in die Implementierung), ebenso für die SD-Karte – und dann wäre alles bereit. Dann wollte ich sehen, wie es in einem „ernsten“ Design umgesetzt ist. Also, was haben wir hier aus dem Ernsthaften? Arty scheint nicht zu passen – es bleibt das Ungetüm unleahshed.DevKitConfigs. Und plötzlich stellte sich heraus, dass überall irgendwelche Overlays existieren, die durch Parameter mit Schlüsseln hinzugefügt werden. Ich vermute, dass das wahrscheinlich sehr flexibel und konfigurierbar ist, aber ich hätte gerne etwas, um wenigstens zu starten… Haben Sie nichts Ähnliches, nur einfacher und klobiger?.. Hier bin ich dann auf vera.iofpga.FPGAChip für das FPGA Microsemi gestoßen und habe sofort Zitate entnommen und versucht, meine eigene Implementierung analog zu erstellen, zum Glück ist hier mehr oder weniger die gesamte „Verdrahtung der Hauptplatine“ in einer Datei.
Tatsächlich musste ich einfach in System.scala ein paar Zeilen hinzufügen
class System(implicit p: Parameters) extends RocketSubsystem
...
with HasPeripherySPI
with HasPeripheryUART
...
{
val tlclock = new FixedClockResource("tlclk", p(DevKitFPGAFrequencyKey))
...
}
class SystemModule[+L <: System](_outer: L)
extends RocketSubsystemModuleImp(_outer)
...
with HasPeripheryUARTModuleImp
with HasPeripheryGPIOModuleImp
...Eine Zeile im Klassentext System fügt Informationen über die Frequenz hinzu, mit der dieser Teil unseres SoC arbeitet, in die dts-Datei. Soweit ich verstehe, ist DTS/DTB so etwas wie ein statisches Analog der Plug-and-Play-Technologie für eingebettete Geräte: Der dts-Beschreibungsbaum wird in eine binäre dtb-Datei kompiliert und an den Bootloader übergeben, damit er die Hardware richtig konfigurieren kann. Interessanterweise funktioniert alles einwandfrei ohne die Zeile mit tlclock , aber die BootROM zu kompilieren (ich erinnere daran, dass das jetzt sdboot) nicht möglich sein wird — während des Kompilierungsprozesses analysiert es die dts-Datei und erstellt einen Header mit dem Makro TL_CLK, das es ihm ermöglicht, die Taktdelayer für die externen Interfaces korrekt einzustellen.
Es wird auch notwendig sein, die "Verdrahtung" ein wenig anzupassen:
Platform.scala:
class PlatformIO(implicit val p: Parameters) extends Bundle {
...
// UART
io.uart_tx := sys.uart(0).txd
sys.uart(0).rxd := RegNext(RegNext(io.uart_rx))
// SD-Karte
io.sd_cs := sys.spi(0).cs(0)
io.sd_sck := sys.spi(0).sck
io.sd_mosi := sys.spi(0).dq(0).o
sys.spi(0).dq(0).i := false.B
sys.spi(0).dq(1).i := RegNext(RegNext(io.sd_miso))
sys.spi(0).dq(2).i := false.B
sys.spi(0).dq(3).i := false.B
}Die Registerketten wurden ehrlich gesagt nur analog zu anderen Stellen im ursprünglichen Code hinzugefügt. Höchstwahrscheinlich sollen sie vor . Möglicherweise gibt es in einigen Blöcken bereits eigenen Schutz, aber zunächst möchte ich zumindest "auf einem qualitativ hochwertigen Niveau" starten. Eine für mich interessantere Frage ist, warum MISO und MOSI an verschiedenen dq? Ответа я пока так и не нашёл, но, похоже, остальной код рассчитывает именно на такое подключение.
Physisch habe ich die Design-Pins einfach auf die freien Kontakte des Steckers zugewiesen und den Spannungswahl-Jumper auf 3.3V versetzt.
SD-Adapter
Obenansicht:

Unteransicht:

Debugging der Software: Werkzeuge
Zunächst sprechen wir über die vorhandenen Debugging-Tools und deren Einschränkungen.
Minicom
Zunächst benötigen wir eine Möglichkeit, das zu lesen, was der Bootloader und der Kernel ausgeben. Dazu benötigen wir auf Linux (in diesem Fall auf dem RaspberryPi) das Programm Minicom. Generell eignet sich jedes Programm für die serielle Portkommunikation.
Bitte beachten Sie, dass beim Starten der Portgerätenamen wie folgt angegeben werden müssen: -D /dev/ttyS0 — nach der Option -D. Und die wichtigste Information: Zum Beenden verwenden Sie Ctrl-A, X. Ich hatte tatsächlich einen Fall, in dem diese Kombination nicht funktionierte — dann kann man einfach im benachbarten SSH-Sitzung eingeben: killall -KILL minicom.
Es gibt auch eine weitere Besonderheit. Genauer gesagt gibt es auf dem Raspberry Pi zwei UARTs, und beide Ports können möglicherweise bereits für etwas verwendet werden: einer für Bluetooth, der andere gibt standardmäßig die Kernel-Konsole aus. Glücklicherweise kann dieses Verhalten umkonfiguriert werden .
Speicherübertragung
Beim Debuggen musste ich manchmal zur Überprüfung meiner Hypothese den Bootloader (Entschuldigung) direkt aus dem Host in den Arbeitsspeicher laden. Vielleicht kann man das auch direkt über GDB machen, aber ich habe mich letztendlich für den einfachen Weg entschieden: Ich habe die benötigte Datei auf den Raspberry kopiert, auch den Port 4444 (telnet von OpenOCD) über SSH durchgereicht und den Befehl load_image. Wenn Sie diesen Befehl ausführen, scheint es, als ob alles eingefroren ist, aber tatsächlich «es schläft nicht, es blinzelt einfach langsam»: es lädt die Datei, macht es aber mit einer Geschwindigkeit von ein paar Kilobytes pro Sekunde.
Besonderheiten beim Setzen von Breakpoints
Wahrscheinlich haben sich die meisten von uns darüber bei der Fehlersuche normaler Programme keine Gedanken gemacht, aber Breakpoints werden nicht immer hardwareseitig gesetzt. Manchmal besteht das Setzen eines Breakpoints darin, eine spezielle Anweisung vorübergehend an die richtige Stelle einzufügen. direkt im Maschinencode.Zum Beispiel hatte ich mit dem Standardbefehl b in GDB Erfolg. Hier folgt daraus:
- Es ist nicht möglich, einen Breakpoint innerhalb des BootROM zu setzen, da das ROM
- es möglich ist, einen Breakpoint im Code zu setzen, der in den RAM von der SD-Karte geladen wurde, man muss jedoch warten, bis er geladen ist. Andernfalls schreiben wir einen Teil des Codes nicht um, sondern der Bootloader überschreibt unseren Breakpoint.
Ich bin mir sicher, dass man explizit darum bitten kann, hardwareseitige Breakpoints zu verwenden, aber die Anzahl ist in jedem Fall begrenzt.
Schnelles Überschreiben des BootROM.
In der Anfangsphase der Fehlersuche verspürt man oft den Wunsch, das BootROM zu ändern und es noch einmal zu versuchen. Aber es gibt ein Problem: Das BootROM ist Teil des Designs, das in das FPGA geladen wird, und dessen Synthese dauert mehrere Minuten (und das nach fast sofortiger Kompilierung des BootROM-Abbildes aus C und Assembler…). Zum Glück geht alles deutlich schneller.: Die Abfolge der Schritte ist wie folgt:
- bootrom.mif neu generieren (ich bin auf MIF statt HEX umgestiegen, weil ich mit HEX ständig Probleme hatte; MIF ist das native Format von Altera)
- in Quartus angeben
Processing -> Update Memory Initialization File - in der Kategorie Assembler (in der linken Spalte Tasks) den Befehl Start again geben
Für alles zusammen — ein paar Dutzend Sekunden.
SD-Karte vorbereiten
Das Ganze ist relativ einfach, aber man braucht Geduld und etwa 14 GB freien Speicherplatz auf der Festplatte:
git clone https://github.com/sifive/freedom-u-sdk
git submodule update --recursive --init
makeDanach muss eine leere, genauer gesagt, eine die keine wichtigen Daten enthält, SD-Karte eingelegt werden, und folgender Befehl ist auszuführen
sudo make DISK=/dev/sdX format-boot-loader… wo sdX — das Gerät, das der Karte zugewiesen ist. ACHTUNG: Die Daten auf der Karte werden gelöscht, überschrieben und einfach weg sein! Es ist wahrscheinlich nicht ratsam, den gesamten Build von sudoauszuführen, denn dann gehören alle Build-Artefakte dazu rootund der Build muss von sudo ausgeführt werden.
Am Ende erhält man eine Karte, die im GPT formatiert ist und vier Partitionen hat, wobei eine davon FAT mit uEnv.txt und einem bootfähigen Image im FIT-Format (es enthält mehrere Unterbilder, jedes mit seiner eigenen Ladeadresse) ist, die andere Partition bleibt leer und soll in Ext4 für Linux formatiert werden. Zwei weitere Partitionen sind ebenfalls — mysteriös: Auf einem lebt U-Boot (seine Adresse, soweit ich das verstehe, ist im BootROM gespeichert), auf dem anderen scheinen seine Umgebungsvariablen zu leben, aber die benutze ich bisher nicht.
Ebene eins, BootROM
Volksweisheit sagt: „Wenn es beim Programmieren Tänze mit einem Tamburin gibt, dann auch in der Elektronik — und dabei noch mit einem Feuerlöscher.“ Es geht nicht einmal darum, dass ich einmal fast das Board verbrannt hätte, weil ich dachte: ‚Nun, GND ist doch dasselbe wie das niedrigste Niveau‘. (offensichtlich würde ein Widerstand nicht schaden…) Es geht vielmehr darum, dass, wenn die Hände nicht von dort kommen, die Elektronik weiterhin Überraschungen bereithält: Beim Löten eines Anschlusses auf dem Board konnte ich die Kontakte einfach nicht richtig löten — im Video zeigt man, wie das Löten sich von selbst über die gesamte Verbindung verteilt, man muss nur den Lötkolben ansetzen, bei mir ‚kleckerte‘ es einfach so herum. Nun, vielleicht war das Lötzinn nicht für die Temperatur des Lötkolbens geeignet, vielleicht noch etwas anderes… Auf jeden Fall, als ich sah, dass ich bereits ein Dutzend Kontakte hatte, gab ich auf und begann mit der Fehlersuche. Und da ging es los mysteriös: Ich habe RX/TX vom UART angeschlossen, lade die Firmware — sie schreibt
INIT
CMD0
ERRORNun, das ist logisch – das SD-Kartenmodul habe ich nicht angeschlossen. Wir beheben die Situation, laden die Firmware… Und dann Ruhe… Was habe ich nicht alles überlegt, und dabei war die Lösung ganz einfach: Ein Anschluss des Moduls musste mit VCC verbunden werden. In meinem Fall unterstützte das Modul 5V zur Stromversorgung, also habe ich kurzerhand den Draht, der vom Modul kam, auf die gegenüberliegende Seite der Platine gesteckt. Letztendlich hat sich der schlecht verlötete Anschluss verzogen, und der UART-Kontakt ging einfach verloren. facepalm.jpg Im Grunde genommen, "ein törichter Kopf gibt den Füßen keine Ruhe" und ungelenke Hände – dem Kopf auch nicht...
Schließlich sah ich in Minicom das lang erwartete
INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LADE /Darüber hinaus bewegt sich der Ladeindikator. Erinnerungen an die Schulzeit kommen hoch, als MinuetOS gemütlich von der Diskette geladen wurde. Lediglich das Laufwerk quietscht nicht.
Das Problem ist, dass nach der BOOT-Meldung nichts passiert. Es ist also Zeit, sich über OpenOCD mit dem Raspberry zu verbinden, von dort aus GDB auf dem Host und zu sehen, was da vor sich geht.
Zunächst zeigte die Verbindung mit GDB sofort, dass $pc (Program Counter, Adresse des aktuellen Befehls) ins Leere läuft 0x0 – wahrscheinlich geschieht dies nach mehreren Fehlern. Daher, direkt nach der Meldung BOOT Wir fügen eine Endlosschleife hinzu. Das wird ihn kurz aufhalten...
diff --git a/bootrom/sdboot/sd.c b/bootrom/sdboot/sd.c
index c6b5ede..bca1b7f 100644
--- a/bootrom/sdboot/sd.c
+++ b/bootrom/sdboot/sd.c
@@ -224,6 +224,8 @@ int main(void)
kputs("BOOT");
+ while(*(volatile char *)0x10000){}
+
__asm__ __volatile__ ("fence.i" : : : "memory");
return 0;
}Dieser raffinierte Code wird "zur Zuverlässigkeit" verwendet: Ich habe irgendwo gehört, dass eine Endlosschleife angeblich Undefined Behavior ist, und der Compiler wird dies hier kaum erraten (Ich erinnere daran, dass sich die 0x10000 BootROM befindet.

Es scheint, was sollte man auch erwarten – hartes Embedded, was für Quellcode kann man hier schon annehmen. Aber der Autor hat den C-Code debugged… Krux-Fex-Pex:
(gdb) file builds/zeowaa-e115/sdboot.elf
Ein Programm wird bereits debuggiert.
Sind Sie sicher, dass Sie die Datei ändern möchten? (j oder n) j
Lese Symbole aus builds/zeowaa-e115/sdboot.elf...fertig.
Man muss nicht die MIF-Datei oder die bin laden, sondern die originale Version im ELF-Format.
Jetzt kann man mit einigem Versuch die Adresse erraten, an der die Ausführung fortgesetzt wird (das ist ein weiterer Grund, warum der Compiler nicht hätte erraten dürfen, dass die Schleife endlos ist). Der Befehl
set variable $pc=0xADDRerlaubt es, den Wert des Registers zur Laufzeit zu ändern (in diesem Fall die Adresse des aktuellen Befehls). Mit ihm können auch Werte im Speicher (und memory-mapped Register) geändert werden.
Letztendlich bin ich zu dem (nicht ganz sicheren) Schluss gekommen, dass wir ein „SD-Karten-Image des falschen Systems“ haben und wir nicht zu den ursprünglich geladenen Daten, sondern weiter zu 0x89800 Bytes gehen müssen:
diff --git a/bootrom/sdboot/head.S b/bootrom/sdboot/head.S
index 14fa740..2a6c944 100644
--- a/bootrom/sdboot/head.S
+++ b/bootrom/sdboot/head.S
@@ -13,7 +13,7 @@ _prog_start:
smp_resume(s1, s2)
csrr a0, mhartid
la a1, dtb
- li s1, PAYLOAD_DEST
+ li s1, (PAYLOAD_DEST + 0x89800)
jr s1
.section .rodataVielleicht hat auch die Tatsache eine Rolle gespielt, dass ich, ohne eine unnötige 4-GB-Karte zur Hand zu haben, eine 2-GB-Karte genommen und durch Ausprobieren im Makefile ersetzt habe. DEMO_END=11718750 findet man DEMO_END=3078900 (Suchen Sie keinen Sinn in der konkreten Bedeutung – es gibt keinen, das Image passt einfach jetzt auf die Karte).
Ebene zwei, U-Boot
Jetzt „fallen“ wir immer noch, landen aber bereits bei der Adresse 0x0000000080089a84. Hier muss ich gestehen: In Wirklichkeit wird die Darstellung nicht „mit allen Haltepunkten” gehalten, sondern teilweise bereits „nachträglich” geschrieben. Daher habe ich hier bereits die richtige dtb-Datei von unserem SoC eingelegt und die Einstellungen angepasst. HiFive_U-Boot Variable CONFIG_SYS_TEXT_BASE=0x80089800 (statt 0x08000000), damit die Ladeadresse mit der tatsächlichen übereinstimmt. Jetzt laden wir das nächste Level mit einem anderen Image:
(gdb) file ../freedom-u-sdk/work/HiFive_U-Boot/u-boot
(gdb) tui enUnd sehen:
│304 /* │
│305 * Trap-Eintrag │
│306 */ │
│307 trap_entry: │
│308 addi sp, sp, -32*REGBYTES │
>│309 SREG x1, 1*REGBYTES(sp) │
│310 SREG x2, 2*REGBYTES(sp) │
│311 SREG x3, 3*REGBYTES(sp) │Wir springen zwischen den Zeilen 308 und 309. Und das ist nicht überraschend, wenn man bedenkt, dass in $sp der Wert liegt 0xfffffffe31cdc0a0. Leider „entwischt“ er ständig aufgrund von Zeile 307. Deshalb versuchen wir, einen Haltepunkt auf trap_entryzu setzen, und dann wieder zu 0x80089800 (Einstiegspunkt U-Boot), und hoffen, dass er keine korrekte Einstellung der Register vor dem Sprung erfordert… Sieht so aus, als würde es funktionieren:
(gdb) b trap_entry
Breakpoint 1 at 0x80089a80: file /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S, line 308.
(gdb) set variable $pc=0x80089800
(gdb) c
Forts.
Breakpoint 1, trap_entry () at /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S:308
(gdb) p/x $sp
$4 = 0x81cf950Nicht gerade ein idealer Stackzeiger, um es milde auszudrücken: zeigt in eine Richtung, die überhaupt nicht zum RAM führt (es sei denn, wir haben noch keine Adressübersetzung, aber wir hoffen auf die einfachere Variante).
Versuchen wir, den Zeiger auf 0x881cf950. Letztendlich kommen wir zu dem Schluss, dass handle_trap wird aufgerufen und wir gehen zu _exit_trap ) mit dem Argument epc=2148315240 (im Dezimalformat):
(gdb) x/10i 2148315240
0x800cb068 : lbu a4,0(a5)
0x800cb06c : bnez a4,0x800cb078
0x800cb070 : sub a0,a5,a0
0x800cb074 : ret
0x800cb078 : addi a5,a5,1
0x800cb07c : j 0x800cb064
0x800cb080 : addi sp,sp,-32
0x800cb084 : sd s0,16(sp)
0x800cb088 : sd ra,24(sp)
0x800cb08c : li s0,0Setzen Sie einen Breakpoint auf strnlen, fahren Sie fort und sehen Sie:
(gdb) bt
#0 strnlen (s=s@entry=0x10060000 "", count=18446744073709551615) at lib/string.c:283
#1 0x00000000800cc14c in string (buf=buf@entry=0x881cbd4c "", end=end@entry=0x881cc15c "", s=0x10060000 "", field_width=, precision=, flags=) at lib/vsprintf.c:265
#2 0x00000000800cc63c in vsnprintf_internal (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=0x800d446e "s , epc x , ra lxn", fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", args=0x881cc1a0,
args@entry=0x881cc188) at lib/vsprintf.c:619
#3 0x00000000800cca54 in vsnprintf (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", args=args@entry=0x881cc188) at lib/vsprintf.c:710
#4 0x00000000800cca68 in vscnprintf (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", args=args@entry=0x881cc188) at lib/vsprintf.c:717
#5 0x00000000800ccb50 in printf (fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn") at lib/vsprintf.c:792
#6 0x000000008008a9f0 in _exit_trap (regs=, epc=2148315240, code=) at arch/riscv/lib/interrupts.c:92
#7 handle_trap (mcause=, epc=, regs=) at arch/riscv/lib/interrupts.c:55
#8 0x0000000080089b10 in trap_entry () at /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S:343
Backtrace stopped: frame did not save the PCEs scheint, _exit_trap möchte Debugging-Informationen über die aufgetretene Ausnahme ausgeben, aber es funktioniert nicht. Anscheinend werden unsere Quelltexte wieder nicht angezeigt. set directories ../freedom-u-sdk/HiFive_U-Boot/ Oh! Jetzt werden sie angezeigt!
Nun gut, starten wir erneut und sehen wir im Stack-Trace, was das ursprüngliche Problem verursacht hat, das den ersten Fehler ausgelöst hat (mcause == 5). Wenn ich richtig verstanden habe, was auf Seite 37 steht, dann bedeutet diese Ausnahme Load access fault . Der Grund scheint zu sein, dass hierarch/riscv/cpu/HiFive/start.S:
call_board_init_f: li t0, -16 li t1, CONFIG_SYS_INIT_SP_ADDR and sp, t1, t0 /* erzwinge 16-Byte-Ausrichtung */#ifdef CONFIG_DEBUG_UART jal debug_uart_init #endifcall_board_init_f_0: mv a0, sp jal board_init_f_alloc_reserve mv sp, a0 jal board_init_f_init_reservemv a0, zero /* a0 <-- boot_flags = 0 */ la t5, board_init_f jr t5 /* springe zu board_init_f() */
den gleichen inkorrekten Wert hat und innerhalb
$sp board_init_f_init_reserve ein Fehler auftritt. Es scheint, das ist der Übeltäter: die Variable mit dem unmissverständlichen Namen CONFIG_SYS_INIT_SP_ADDR . Sie ist in der DateiHiFive_U-Boot/include/configs/HiFive-U540.h . Irgendwann dachte ich sogar, vielleicht sollte ich den Bootloader für den Prozessor anpassen — vielleicht wäre es einfacher, den Prozessor ein wenig zu ändern? Aber dann sah ich, dass es mehr wie ein Artefakt von nicht vollständig angepassten Einstellungen für eine andere Speicherkonfiguration aussieht, und ich könnte versuchen, es so zu machen:. Irgendwann hatte ich sogar gedacht, vielleicht sollte ich den Bootloader für den Prozessor anpassen – es wäre vielleicht einfacher, den Prozessor leicht zu ändern? Doch dann bemerkte ich, dass es eher wie ein Artefakt aufgrund unvollständiger Einstellungen für eine andere Speicherkonfiguration aussah, und ich könnte versuchen, es so zu machen:#if 0-
diff --git a/include/configs/HiFive-U540.h b/include/configs/HiFive-U540.h
index ca89383..245542c 100644
--- a/include/configs/HiFive-U540.h
+++ b/include/configs/HiFive-U540.h
@@ -65,12 +65,9 @@
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_0
#endif
#if 1
-/*#define CONFIG_NR_DRAM_BANKS 1*/
+#define CONFIG_NR_DRAM_BANKS 1
#define PHYS_SDRAM_0 0x80000000 /* SDRAM Bank #1 */
-#define PHYS_SDRAM_1
- (PHYS_SDRAM_0 + PHYS_SDRAM_0_SIZE) /* SDRAM Bank #2 */
-#define PHYS_SDRAM_0_SIZE 0x80000000 /* 2 GB */
-#define PHYS_SDRAM_1_SIZE 0x10000000 /* 256 MB */
+#define PHYS_SDRAM_0_SIZE 0x40000000 /* 1 GB */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_0
#endif
/*
@@ -81,7 +78,7 @@
#define CONSOLE_ARG "console=ttyS0,115200 "
/* Init Stack Pointer */
-#define CONFIG_SYS_INIT_SP_ADDR (0x08000000 + 0x001D0000 -
+#define CONFIG_SYS_INIT_SP_ADDR (0x80000000 + 0x001D0000 -
GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_LOAD_ADDR 0xa0000000 /* partway up SDRAM */An einem bestimmten Punkt erreichte die Anzahl der Hacks einen kritischen Punkt. Nach einigem Überlegen erkannte ich die Notwendigkeit, einen korrekten Port für mein Board zu erstellen. Dazu müssen wir eine Reihe von Dateien kopieren und an unsere Konfiguration anpassen.
Nun, ungefähr so viel
trosinenko@trosinenko-pc:/hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot$ git show --name-status
commit 39cd67d59c16ac87b46b51ac1fb58f16f1eb1048 (HEAD -> zeowaa-1gb)
Author: Anatoly Trosinenko
Date: Tue Jul 2 17:13:16 2019 +0300
Erster Support für das Zeowaa A-E115FB Board
M arch/riscv/Kconfig
A arch/riscv/cpu/zeowaa-1gb/Makefile
A arch/riscv/cpu/zeowaa-1gb/cpu.c
A arch/riscv/cpu/zeowaa-1gb/start.S
A arch/riscv/cpu/zeowaa-1gb/timer.c
A arch/riscv/cpu/zeowaa-1gb/u-boot.lds
M arch/riscv/dts/Makefile
A arch/riscv/dts/zeowaa-1gb.dts
A board/Zeowaa/zeowaa-1gb/Kconfig
A board/Zeowaa/zeowaa-1gb/MAINTAINERS
A board/Zeowaa/zeowaa-1gb/Makefile
A board/Zeowaa/zeowaa-1gb/Zeowaa-A-E115FB.c
A configs/zeowaa-1gb_defconfig
A include/configs/zeowaa-1gb.hDetails können eingesehen werden unter .
Es stellte sich heraus, dass die Register einiger Geräte auf diesem SiFive-Board andere Adressen haben. Zudem wurde klar, dass U-Boot mit dem bereits aus dem Linux-Kernel bekannten Kconfig-Mechanismus konfiguriert werden kann — zum Beispiel kann man verwenden make menuconfig, und Ihnen wird eine benutzerfreundliche Textoberfläche angezeigt, die die Beschreibung der Parameter anzeigt. ? Und so weiter. Insgesamt habe ich aus den Beschreibungen zweier Platten die Beschreibung einer dritten erstellt, indem ich sämtliche pompösen PLL-Umbauten (offenbar hat das etwas mit der Steuerung vom Host-Computer über PCIe zu tun, aber das ist nicht sicher) weggelassen habe. Ich erhielt eine Firmware, die mir bei passendem Wetter auf dem Mars über UART mitteilte, aus welchem Commit-Hash sie zusammengestellt wurde und wie viel DRAM ich habe (aber diese Information habe ich selbst im Header angegeben).
Es ist nur schade, dass die Platine danach normalerweise auf die Prozessor-JTAG-Übertragung nicht mehr reagierte, und das Booten von der SD-Karte — nun ja, das ist in meiner Konfiguration leider keine schnelle Angelegenheit. Auf der anderen Seite zeigte mir manchmal die BootROM die Meldung, dass FEHLER, das Booten fehlgeschlagen ist, und sofort erschien U-Boot. Da fiel es mir wie Schuppen von den Augen: Offenbar wird der Bitstream im FPGA nach einem Neustart nicht überschrieben, er hat nicht genug Zeit zum "Enttrainieren" usw. Kurz gesagt, man kann einfach beim Erscheinen der Meldung LADEN / den Debugger anschließen und den Befehl set variable $pc=0x80089800ausführen, wodurch man sich diese lange Bootzeit spart (vorausgesetzt, es ist beim letzten Mal früh genug kaputtgegangen, sodass nichts Neues über dem ursprünglichen Code geladen wurde).
Übrigens, ist es normal, dass der Prozessor komplett hängt und der JTAG-Debugger keine Verbindung herstellen kann, mit den Nachrichten?
Fehler: nicht in der Lage, hart 0 anzuhalten
Fehler: dmcontrol=0x80000001
Fehler: dmstatus =0x00030c82Moment mal! Das habe ich schon mal gesehen! So etwas passiert bei einem Deadlock im TileLink, und dem Autor des Speicherkontrollers vertraue ich irgendwie nicht — das hat er selbst geschrieben… Plötzlich, nach dem ersten erfolgreichen Neukompilieren des Prozessors nach der Bearbeitung des Controllers, sah ich:
INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LADEN
BOOT
U-Boot 2018.09-g39cd67d-dirty (03. Juli 2019 - 13:50:33 +0300)
DRAM: 1 GiB
MMC:
VOR DEM LADEN ENVBEFORE FDTCONTROLADDRBEFORE LADENADDRIn: serial
Out: serial
Err: serial
Drücken Sie eine Taste, um den Autoboot zu stoppen: 3Auf diese seltsame Zeile davor In: serial Ignorieren Sie das — ich habe versucht, auf einem hängenden Prozessor zu verstehen, ob es korrekt mit der Umgebung funktioniert. Was bedeutet "Es hängt schon seit zehn Minuten"? Hat es wenigstens geschafft, sich zu relocieren und ins Boot-Menü zu wechseln! Eine kleine Anmerkung: Auch wenn U-Boot in den ersten 2^24 Bytes von der SD-Karte geladen wird, kopiert es sich beim Start an einen anderen Ort, entweder an die im Konfigurationsheader angegebene Adresse oder einfach in die höheren Adressen des Arbeitsspeichers. Es führt die Relokation der ELF-Symbole durch und übergibt die Kontrolle dorthin. Anscheinend haben wir diese Stufe bestanden und als Bonus einen Prozessor erhalten, der danach nicht vollständig einfriert.
Also, warum funktioniert der Timer nicht? Es scheint, als ob die Uhr aus irgendeinem Grund überhaupt nicht läuft...
(gdb) x/x 0x0200bff8
0x200bff8: 0x00000000Was passiert, wenn wir die Zeiger manuell bewegen?
(gdb) set variable *0x0200bff8=310000000
(gdb) cDaraus folgt:
Drücken Sie eine beliebige Taste, um den Autoboot zu stoppen: 0
MMC_SPI: 0 bei 0:1 hz 20000000 mode 0Fazit: Die Uhr läuft nicht. Wahrscheinlich funktioniert auch die Tastatureingabe nicht aus demselben Grund:
HiFive_U-Boot/cmd/bootmenu.c:
static void bootmenu_loop(struct bootmenu_data *menu,
enum bootmenu_key *key, int *esc)
{
int c;
while (!tstc()) {
WATCHDOG_RESET();
mdelay(10);
}
c = getc();
switch (*esc) {
case 0:
/* Erstes Zeichen der ANSI Escape-Sequenz 'e' */
if (c == 'e') {
*esc = 1;
*key = KEY_NONE;
}
break;
case 1:
/* Zweites Zeichen von ANSI '[' */
if (c == '[') {
...Das Problem war, dass ich ein wenig übertrieben habe: Ich habe im Prozessor-Config einen Schlüssel hinzugefügt:
case DTSTimebase => BigInt(0)… basierend auf dem, was im Kommentar gesagt wurde: 'Wenn Sie nicht wissen - lassen Sie es 0'. Und doch WithNBigCores stellte es genau auf 1MHz ein (so wie es übrigens in der U-Boot-Konfiguration angegeben war). Aber ich bin, verdammtes, genau und penibel: da weiß ich nicht, hier 25MHz! Letztendlich funktioniert nichts. Ich habe meine "Verbesserungen" entfernt und…
Drücken Sie eine Taste, um den Autoboot zu stoppen: 0
MMC_SPI: 0 bei 0:1 Hz 20000000 Modus 0
## Unbekannter Partitionstabellentyp 0
libfdt fdt_path_offset() gab FDT_ERR_NOTFOUND zurück
** Keine Partitionstabelle - mmc 0 **
## Info: Eingabedatengröße = 34 = 0x22
Starte uEnv.txt boot2...
## Fehler: "boot2" nicht definiert
HiFive-Unleashed #Man kann sogar Befehle eingeben! Zum Beispiel, ein wenig herumzupfen, kann man schließlich erraten, einzugeben mmc_spi 1 10000000 0; mmc part, wobei die SPI-Frequenz von 20 MHz auf 10 MHz gesenkt wurde. Warum? Nun, im Konfigurationsfile wurde eine maximale Frequenz von 20 MHz angegeben, und diese steht dort immer noch. Aber soweit ich verstanden habe, funktionieren die Schnittstellen, zumindest hier, folgendermaßen: Der Code teilt die Frequenz der Hardwareeinheit (bei mir sind das überall 25 MHz) durch die Ziel-Frequenz und stellt den resultierenden Wert als Teiler im entsprechenden Steuerregister ein. Das Problem ist, dass für einen 115200 Hz UART die Frequenz annähernd stimmen würde, aber wenn man 25000000 durch 20000000 teilt, ergibt das 1, d.h. es wird mit 25 MHz betrieben. Vielleicht ist das in Ordnung, aber wenn Einschränkungen festgelegt werden, muss es dafür einen Grund geben (auch wenn das nicht sicher ist)... Insgesamt ist es einfacher, dies einzutragen und weiterzumachen — weit und, leider, für lange Zeit. 25 MHz — das ist nichts für einen Core i9.
Konsolenausgabe
HiFive-Unleashed # env edit mmcsetup
edit: mmc_spi 1 10000000 0; mmc part
HiFive-Unleashed # boot
MMC_SPI: 1 bei 0:1 hz 10000000 Modus 0
Partitionstabelle für MMC-Gerät 0 -- Partitionstyp: EFI
Part Start LBA End LBA Name
Attribute
Typ GUID
Partition GUID
1 0x00000800 0x0000ffde "Vfat Boot"
attrs: 0x0000000000000000
typ: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
typ: data
guid: 76bd71fd-1694-4ff3-8197-bfa81699c2fb
2 0x00040800 0x002efaf4 "root"
attrs: 0x0000000000000000
typ: 0fc63daf-8483-4772-8e79-3d69d8477de4
typ: linux
guid: 9f3adcc5-440c-4772-b7b7-283124f38bf3
3 0x0000044c 0x000007e4 "uboot"
attrs: 0x0000000000000000
typ: 5b193300-fc78-40cd-8002-e86c45580b47
guid: bb349257-0694-4e0f-9932-c801b4d76fa3
4 0x00000400 0x0000044b "uboot-env"
attrs: 0x0000000000000000
typ: a09354ac-cd63-11e8-9aff-70b3d592f0fa
guid: 4db442d0-2109-435f-b858-be69629e7dbf
libfdt fdt_path_offset() gab FDT_ERR_NOTFOUND zurück
2376 Bytes in 0 ms gelesen
Lade uEnv.txt boot2...
15332118 Bytes in 0 ms gelesen
## Laden des Kernels aus FIT-Image bei 90000000 ...
Verwendung von 'config-1' Konfiguration
Versuch des 'bbl' Kernel-Subimage
Beschreibung: BBL/SBI/riscv-pk
Typ: Kernel-Image
Kompression: unkomprimiert
Datenstart: 0x900000d4
Datengröße: 74266 Bytes = 72.5 KiB
Architektur: RISC-V
OS: Linux
Ladeadresse: 0x80000000
Einstiegspunkt: 0x80000000
Hash-Algorithmus: sha256
Hash-Wert: 28972571467c4ad0cf08a81d9cf92b9dffc5a7cb2e0cd12fdbb3216cf1f19cbd
Überprüfung der Hash-Integrität ... sha256+ OK
## Laden von fdt aus FIT-Image bei 90000000 ...
Verwendung von 'config-1' Konfiguration
Versuch des 'fdt' fdt-Subimages
Beschreibung: nicht verfügbar
Typ: Flat Device Tree
Kompression: unkomprimiert
Datenstart: 0x90e9d31c
Datengröße: 6911 Bytes = 6.7 KiB
Architektur: RISC-V
Ladeadresse: 0x81f00000
Hash-Algorithmus: sha256
Hash-Wert: 10b0244a5a9205357772ea1c4e135a4f882409262176d8c7191238cff65bb3a8
Überprüfung der Hash-Integrität ... sha256+ OK
Lade fdt von 0x90e9d31c zu 0x81f00000
Booten mit dem fdt Blob bei 0x81f00000
## Laden von Ladebildern aus FIT-Image bei 90000000 ...
Versuch des 'kernel' Ladebilder-Subimages
Beschreibung: Linux Kernel
Typ: Kernel-Image
Kompression: unkomprimiert
Datenstart: 0x900123e8
Datengröße: 10781356 Bytes = 10.3 MiB
Architektur: RISC-V
OS: Linux
Ladeadresse: 0x80200000
Einstiegspunkt: nicht verfügbar
Hash-Algorithmus: sha256
Hash-Wert: 72a9847164f4efb2ac9bae736f86efe7e3772ab1f01ae275e427e2a5389c84f0
Überprüfung der Hash-Integrität ... sha256+ OK
Lade Ladebilder von 0x900123e8 zu 0x80200000
## Laden von Ladebildern aus FIT-Image bei 90000000 ...
Versuch des 'ramdisk' Ladebilder-Subimages
Beschreibung: buildroot initramfs
Typ: RAMDisk-Image
Kompression: gzip-komprimiert
Datenstart: 0x90a5a780
Datengröße: 4467411 Bytes = 4.3 MiB
Architektur: RISC-V
OS: Linux
Ladeadresse: 0x82000000
Einstiegspunkt: nicht verfügbar
Hash-Algorithmus: sha256
Hash-Wert: 883dfd33ca047e3ac10d5667ffdef7b8005cac58b95055c2c2beda44bec49bd0
Überprüfung der Hash-Integrität ... sha256+ OK
Lade Ladebilder von 0x90a5a780 zu 0x82000000Okay, wir sind auf ein neues Level gekommen, aber es hängt immer noch. Manchmal gibt es auch Ausnahmen. Man kann mcause sehen, indem man den Code an der angegebenen Adresse abfängt. $pc und danach si auf trap_entry. Der Handler aus U-Boot kann nur für mcause = 0..4 ausgeben, also bereitet euch darauf vor, in einer fehlerhaften Bootschleife zu landen. Ich bin in die Konfiguration gegangen, habe geschaut, was ich geändert habe, und mich erinnert: dort in conf/rvboot-fit.txt geschrieben:
fitfile=image.fit
# darunter muss alles mit dem in FIT übereinstimmen (ugha)Nun, lassen Sie uns alle Dateien anpassen, die Kernel-Startparameter ungefähr so ersetzen, da der Verdacht besteht, dass SIF0 — ist die Ausgabe irgendwo über PCIe:
-bootargs=console=ttySIF0,921600 debug
+bootargs=console=ttyS0,125200 debugUnd zur Abrundung werden wir den Hash-Algorithmus von SHA-256 auf MD5 ändern: Kryptosicherheit ist mir nicht wichtig (zumal während des Debuggens), es wird als extrem langsam angesehen, und um Integritätsfehler beim Booten zu erfassen, ist MD5 mehr als ausreichend. Was haben wir am Ende? Wir sind merklich schneller durch die vorherige Stufe gekommen (wegen des einfacheren Hashings), und die nächste ist geöffnet:
...
Überprüfen der Hash-Integrität ... md5+ OK
Laden der Ladeteile von 0x90a5a758 bis 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
chosen {
linux,initrd-end = ;
linux,initrd-start = ;
riscv,kernel-end = ;
riscv,kernel-start = ;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
};
libfdt fdt_path_offset() gab FDT_ERR_NOTFOUND zurück
chosen {
linux,initrd-end = ;
linux,initrd-start = ;
riscv,kernel-end = ;
riscv,kernel-start = ;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
};
Kernelbild wird geladen ... OK
Kernel wird gestartet in
3DieUhr tickt nicht...
(gdb) x/x 0x0200bff8
0x200bff8: 0x00000000Ups, es scheint, als wäre die Uhrzeitanpassung ein Placebo gewesen, auch wenn es damals so schien, als würde es helfen. Ja, es muss natürlich repariert werden, aber lassen Sie uns zuerst die Zeiger manuell drehen und sehen, was passiert:
0x00000000bff6dbb0 in ?? ()
(gdb) set variable *0x0200bff8=1000000
(gdb) c
Fortfahren.
^C
Programm erhielt das Signal SIGINT, Unterbrechung.
0x00000000bff6dbb0 in ?? ()
(gdb) set variable *0x0200bff8=2000000
(gdb) c
Fortfahren.
^C
Programm erhielt das Signal SIGINT, Unterbrechung.
0x00000000bff6dbb0 in ?? ()
(gdb) set variable *0x0200bff8=3000000
(gdb) c
Fortfahren.In der Zwischenzeit...
Kernelbild wird geladen ... OK
Kernel wird gestartet in
3
2
1
0
## Anwendung startet bei 0x80000000 ...Nein, ich werde die Uhr automatisieren – vielleicht denkt sie daran, den Timer zu kalibrieren!
Die Adresse der aktuellen Anweisung zeigt währenddessen irgendwo auf
0000000080001c20 :
80001c20: 1141 addi sp,sp,-16
80001c22: e022 sd s0,0(sp)
80001c24: 842a mv s0,a0
80001c26: 00005517 auipc a0,0x5
80001c2a: 0ca50513 addi a0,a0,202 # 80006cf0
80001c2e: e406 sd ra,8(sp)
80001c30: f7fff0ef jal ra,80001bae
80001c34: 8522 mv a0,s0
80001c36: 267000ef jal ra,8000269c
80001c3a: 00010797 auipc a5,0x10
80001c3e: 41e78793 addi a5,a5,1054 # 80012058
80001c42: 639c ld a5,0(a5)
80001c44: c399 beqz a5,80001c4a
80001c46: 72c000ef jal ra,80002372
80001c4a: 45a1 li a1,8
80001c4c: 4501 li a0,0
80001c4e: dc7ff0ef jal ra,80001a14
80001c52: 10500073 wfi
80001c56: bff5 j 80001c52innerhalb des geladenen Berkeley Boot Loaders. Persönlich stört mich dabei die Erwähnung htif — Host-Schnittstelle, die für den tethered Start des Kernels verwendet wird (also in Kooperation mit dem Host-ARM), ich hatte an standalone gedacht. Wenn man diese Funktion in den Quellcodes findet, sieht man jedoch, dass es nicht so schlimm ist:
void poweroff(uint16_t code)
{
printm("Power offrn");
finisher_exit(code);
if (htif) {
htif_poweroff();
} else {
send_ipi_many(0, IPI_HALT);
while (1) { asm volatile ("wfin"); }
}
}Quest: Starte die Uhr
Die Registersuche im CLINT führt uns zu
val io = IO(new Bundle {
val rtcTick = Bool(INPUT)
})
val time = RegInit(UInt(0, width = timeWidth))
when (io.rtcTick) { time := time + UInt(1) }der an den RTC angeschlossen ist, oder an das geheimnisvolle MockAON, über das ich ursprünglich dachte: „So, was haben wir denn hier? Unklar? Abstecken!“ Da ich immer noch nicht verstehe, was für ein Taktzauber dort abgeht, werde ich diese Logik einfach neu implementieren in System.scala:
val rtcDivider = RegInit(0.asUInt(16.W)) // zur Sicherheit unterstütze ich bis 16 GHz, ich bin optimistisch :)
val mhzInt = p(DevKitFPGAFrequencyKey).toInt
// Angenommen, die Frequenz ist eine ganze Zahl in Megahertz
rtcDivider := Mux(rtcDivider === (mhzInt - 1).U, 0.U, rtcDivider + 1.U)
outer.clintOpt.foreach { clint =>
clint.module.io.rtcTick := rtcDivider === 0.U
}Auf dem Weg zum Linux-Kernel
Die Erzählung hat sich bereits in die Länge gezogen und wird etwas monoton, daher beschreibe ich es kurz:
BBL ging von der Existenz eines FDT an der Adresse 0xF0000000, und ich habe es schon korrigiert! Na, dann suchen wir weiter… Ich habe gefunden in HiFive_U-Boot/arch/riscv/lib/boot.c, ersetzt durch 0x81F00000, wie in der U-Boot-Konfiguration angegeben.
Dann hat BBL sich beschwert, dass kein Speicher vorhanden ist. Mein Weg führte zur Funktion mem_prophat ergeben, dass in riscv-pk/machine/fdt.c: von dort habe ich erfahren, dass der fdt ram-Knoten als device_type = "memory" markiert werden muss — dann muss vielleicht der Prozessor-Generator angepasst werden, aber vorerst schreibe ich es einfach von Hand — ich habe diese Datei sowieso manuell übertragen.
Jetzt habe ich eine Nachricht erhalten (im formatierten Format mit Zeilenumbrüchen):
This is bbl's dummy_payload. To boot a real kernel, reconfigure bbl
with the flag --with-payload=PATH, then rebuild bbl. Alternatively,
bbl can be used in firmware-only mode by adding device-tree nodes
for an external payload and use QEMU's -bios and -kernel options.Es scheint, dass die Optionen richtig angegeben werden riscv,kernel-start und riscv,kernel-end im DTB, aber sie werden als Nullen geparst. Die Fehlersuche query_chosen hat gezeigt, dass BBL versucht, eine 32-Bit-Adresse zu parsen, und es auf ein Paar trifft <0x0 0xADDR>, wobei der erste Wert anscheinend die niederwertigen Stellen betrifft. Ich habe zur Sektion chosen
chosen {
#address-cells = ;
#size-cells = ;
...
}hinzugefügt und die Generierung der Werte angepasst: nicht als 0x0 erstes Element zu schreiben.
Diese 100500 einfachen Schritte ermöglichen es, einfach und unkompliziert zu sehen, wie der Pinguin abstürzt:
Versteckter Text
Überprüfung der Hash-Integrität ... md5+ OK
Laden von Ladeinheiten von 0x90a5a758 bis 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
gewählt {
linux,initrd-end = ;
linux,initrd-start = ;
riscv,kernel-end = ;
riscv,kernel-start = ;
#address-cells = ;
#size-cells = ;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
stdout-path = "uart0:38400n8";
};
libfdt fdt_path_offset() zurückgegeben FDT_ERR_NOTFOUND
gewählt {
linux,initrd-end = ;
linux,initrd-start = ;
riscv,kernel-end = ;
riscv,kernel-start = ;
#address-cells = ;
#size-cells = ;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
stdout-path = "uart0:38400n8";
};
Laden des Kernel-Images ... OK
Kernel wird gestartet in
3
2
1
0
## Anwendung starten bei 0x80000000 ...
bbl-loader
SIFIVE, INC.
5555555555555555555555555
5555 5555
5555 5555
5555 5555
5555 5555555555555555555555
5555 555555555555555555555555
5555 5555
5555 5555
5555 5555
5555555555555555555555555555 55555
55555 555555555 55555
55555 55555 55555
55555 5 55555
55555 55555
55555 55555
55555 55555
55555 55555
55555 55555
555555555
55555
5
SiFive RISC-V Core IP
[ 0.000000] OF: fdt: Ignoriere den Speicherbereich 0x80000000 - 0x80200000
[ 0.000000] Linux-Version 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc-Version 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 SMP Mi Jul 3 21:29:21 MSK 2019
[ 0.000000] Bootkonsole [early0] aktiviert
[ 0.000000] Initialramdisk bei: 0x(____ptrval____) (16777216 Bytes)
[ 0.000000] Zonenbereich:
[ 0.000000] DMA32 [Speicher 0x0000000080200000-0x00000000bfffffff]
[ 0.000000] Normal [Speicher 0x00000000c0000000-0x00000bffffffffff]
[ 0.000000] Beweglicher Zonenstart für jeden Knoten
[ 0.000000] Frühe Speicher-Knotenbereiche
[ 0.000000] Knoten 0: [Speicher 0x0000000080200000-0x00000000bfffffff]
[ 0.000000] Initmem-Einrichtungs-Knoten 0 [Speicher 0x0000000080200000-0x00000000bfffffff]
[ 0.000000] Auf Knoten 0 insgesamt Seiten: 261632
[ 0.000000] DMA32-Zone: 3577 Seiten verwendet für Memmap
[ 0.000000] DMA32-Zone: 0 Seiten reserviert
[ 0.000000] DMA32-Zone: 261632 Seiten, LIFO-Gruppe:63
[ 0.000000] Software IO TLB: gemappt [Speicher 0xbb1fc000-0xbf1fc000] (64MB)(Das Logo wird von BBL angezeigt, und das, was mit Zeitstempeln zu tun hat, ist der Kern).
Zum Glück weiß ich nicht, wie es überall ist, aber bei RocketChip kann man beim Anschluss eines Debuggers über JTAG direkt aus der Box Fallen abfangen — der Debugger stoppt genau an dieser Stelle.
Das Programm hat das Signal SIGTRAP empfangen, Trace-/Breakpoint-Falle.
0xffffffe0000024ca in ?? ()
(gdb) bt
#0 0xffffffe0000024ca in ?? ()
Backtrace gestoppt: vorheriger Frame identisch mit diesem Frame (beschädigter Stack?)
(gdb) file work/linux/vmlinux
Ein Programm wird bereits debugged.
Sind Sie sicher, dass Sie die Datei ändern möchten? (y oder n) y
Lese Symbole aus work/linux/vmlinux... erledigt.
(gdb) bt
#0 0xffffffe0000024ca in setup_smp () at /hdd/trosinenko/fpga/freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:75
#1 0x0000000000000000 in ?? ()
Backtrace gestoppt: Frame hat nicht den PC gespeichert.freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:
void __init setup_smp(void)
{
struct device_node *dn = NULL;
int hart;
bool found_boot_cpu = false;
int cpuid = 1;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
hart = riscv_of_processor_hartid(dn);
if (hart < 0)
continue;
if (hart == cpuid_to_hartid_map(0)) {
BUG_ON(found_boot_cpu);
found_boot_cpu = 1;
continue;
}
cpuid_to_hartid_map(cpuid) = hart;
set_cpu_possible(cpuid, true);
set_cpu_present(cpuid, true);
cpuid++;
}
BUG_ON(!found_boot_cpu); // < HIER SIND SIE
}Wie in einem alten Witz gesagt wurde, CPU nicht gefunden, Softwareemulation läuft.. Oder nicht läuft. Verloren im einzelnen Prozessorkern.
/* The lucky hart to first increment this variable will boot the other cores */
atomic_t hart_lottery;
unsigned long boot_cpu_hartid;Ein guter Kommentar in linux/arch/riscv/kernel/setup.c — das ist so etwas wie ein Farbanstrich nach Tom Sawyers Methode. Insgesamt gab es heute aus irgendeinem Grund keine Gewinner, der Preis wird auf die nächste Auflage verschoben…
Ich schlage vor, diesen ohnehin schon langen Artikel zu beenden.
Fortsetzung folgt. Darin wird es einen Kampf gegen einen listigen Fehler geben, der sich versteckt, wenn man sich ihm langsam mit einem Singlestep nähert.
Text-Screencast des Downloads (externer Link):
Quelle: habr.com
