Im vorherigen Teil wurde ein mehr oder weniger funktionierender Speichercontroller implementiert, oder vielmehr ein Wrapper über IP Core von Quartus, einem Adapter für TileLink. Heute sehen Sie unter der Überschrift „Wir portieren RocketChip mit einem Cyclone auf ein wenig bekanntes chinesisches Motherboard“ eine funktionierende Konsole. Der Prozess zog sich ein wenig hin: Ich dachte bereits, ich würde Linux schnell starten und weitermachen, aber es war nicht da. In diesem Teil möchte ich den Prozess des Startens von U-Boot-, BBL- und schüchternen Linux-Kernel-Initialisierungsversuchen untersuchen. Aber es gibt eine Konsole - U-Boot-ovsky, die ziemlich fortgeschritten ist und viel von dem bietet, was Sie von einer vollwertigen Konsole erwarten.
In der Hardware wird eine über SPI angeschlossene SD-Karte sowie UART hinzugefügt. Im Softwareteil wird BootROM von xip
auf sdboot
und tatsächlich werden die folgenden sdboot
(auf der SD-Karte) hinzugefügt.
Doping der Hardware
Die Aufgabe: Sie müssen zum "großen" Kern wechseln und den UART (von Raspberry) und den SD-Adapter verbinden (es wurde eine Art Catalex-Karte mit sechs Pins verwendet: GND, VCC, MISO, MOSI, SCK, CS).
Im Prinzip war alles ganz einfach. Aber bevor ich das merkte, wurde ich ein wenig hin und her geworfen: Nach dem vorherigen Mal entschied ich, dass Sie wieder nur etwas wie HasPeripheryUART
in das System
mischen müssen (und die Implementierung entsprechend), dasselbe für die SD-Karte - und das war's wird bereit sein. Dann habe ich mich entschlossen zu sehen, wie es in einem „seriösen“ Design implementiert wurde. Was haben wir aus Ernst gemacht? Arty passt anscheinend nicht - das Monster bleibt unleahshed.DevKitConfigs
. Und plötzlich stellte sich heraus, dass es überall Überlagerungen gab, die durch die Parameter durch Schlüssel hinzugefügt wurden. Ich denke, dass dies wahrscheinlich sehr flexibel und konfigurierbar ist, aber ich möchte zunächst etwas anfangen ... Aber Sie haben nicht die gleichen, nur einfacheren Krücken? .. Dann bin ich auf vera.iofpga.FPGAChip
für FPGAs Microsemi und sofort in Anführungszeichen gezogen Ich habe versucht, meine Implementierung analog durchzuführen. Der Vorteil hierbei ist mehr oder weniger das gesamte "Motherboard-Layout" in einer Datei.
Es stellte sich heraus, dass Sie System.scala
nur Zeilen hinzufügen System.scala
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 Hauptteil der System
Klasse fügt der dts-Datei Informationen über die Häufigkeit hinzu, mit der dieser Teil unseres SoC arbeitet. Soweit ich weiß, ist DTS / DTB ein statisches Analogon der Plug-and-Play-Technologie für eingebettete Geräte: Der dts-description-Baum wird in eine binäre dtb-Datei kompiliert und vom Loader an den Kernel übertragen, damit die Hardware ordnungsgemäß konfiguriert werden kann. Interessanterweise ist ohne eine Zeile mit tlclock
alles perfekt synthetisiert, aber es funktioniert nicht, um BootROM zu kompilieren (ich werde Sie daran erinnern, dass es jetzt sdboot
) - während der Kompilierung wird die dts-Datei analysiert und ein Header mit dem TL_CLK
Makro erstellt, für das Frequenzteiler korrekt konfiguriert werden können externe Schnittstellen.
Sie müssen auch die „Verkabelung“ leicht reparieren:
Platform.scala:
class PlatformIO(implicit val p: Parameters) extends Bundle { ...
Offen gesagt wurden Registerketten einfach analog zu einigen anderen Stellen im Quellcode hinzugefügt. Höchstwahrscheinlich sollten sie vor Metastabilität schützen. Vielleicht haben einige Blöcke bereits einen eigenen Schutz, aber zuerst möchte ich zumindest "auf hohem Niveau" laufen. Eine interessantere Frage für mich ist, warum MISO und MOSI an unterschiedlichen dq
hängen. Ich habe die Antwort immer noch nicht gefunden, aber es scheint, dass der Rest des Codes auf eine solche Verbindung setzt.
Physikalisch habe ich gerade die Konstruktionsschlussfolgerungen den losen Kontakten am Block zugewiesen und den Spannungsauswahl-Jumper auf 3,3 V umgestellt.
SD-AdapterBlick von oben:

Ansicht von unten:

Debuggen des Software-Teils: Tools
Lassen Sie uns zunächst über die verfügbaren Debugging-Tools und ihre Einschränkungen sprechen.
Minicom
Zuerst müssen wir irgendwie lesen, was der Bootloader und der Kernel ausgeben. Dazu benötigen wir unter Linux (in diesem Fall unter RaspberryPi) das Minicom-Programm. Im Allgemeinen ist jedes Programm zum Arbeiten mit einer seriellen Schnittstelle geeignet.
Beachten Sie, dass beim Start der Name des -D /dev/ttyS0
nach der Option -D
als -D /dev/ttyS0
angegeben werden muss. Nun, die wichtigsten Informationen: Verwenden Sie zum Beenden Ctrl-A, X
Ich hatte wirklich einen Fall, in dem diese Kombination nicht funktionierte - dann kann man einfach killall -KILL minicom
aus einer benachbarten SSH-Sitzung sagen.
Es gibt noch eine andere Funktion. Insbesondere gibt es zwei UARTs auf RaspberryPi, und beide Ports können bereits für etwas angepasst werden: einer für Bluetooth, über den anderen wird die Kernelkonsole standardmäßig angezeigt. Glücklicherweise kann dieses Verhalten gemäß diesem Handbuch neu konfiguriert werden .
Speicher umschreiben
Beim Debuggen musste ich zum Testen der Hypothese manchmal den Bootloader (sorry) direkt vom Host in den RAM laden . Vielleicht kann dies direkt von GDB aus erfolgen, aber am Ende ging ich den einfachen Weg: Ich kopierte die erforderliche Datei nach Raspberry, schickte auch Port 4444 (Telnet von OpenOCD) über SSH und verwendete den Befehl load_image
. Wenn Sie es ausführen, scheint alles eingefroren zu sein, aber in Wirklichkeit "schläft es nicht, es blinkt nur langsam" : Es lädt die Datei, es macht es nur mit einer Geschwindigkeit von ein paar Kilobyte pro Sekunde.
Funktionen zum Installieren von Haltepunkten
Wahrscheinlich mussten viele beim Debuggen regulärer Programme nicht darüber nachdenken, aber Haltepunkte werden nicht immer in der Hardware festgelegt. Manchmal erfordert das Setzen eines Haltepunkts das vorübergehende Schreiben einer speziellen Anweisung an die richtige Stelle direkt im Maschinencode . So funktionierte beispielsweise mein Standardbefehl b
in GDB. Folgendes folgt daraus:
- Sie können keinen Punkt in BootROM einfügen, da ROM
- Sie können einen Haltepunkt für den von der SD-Karte in den RAM geladenen Code festlegen, müssen jedoch warten, bis er geladen ist. Andernfalls schreiben wir keinen Code neu, aber der Loader schreibt unseren Haltepunkt neu
Ich bin sicher, dass Sie explizit nach der Verwendung von Hardware-Haltepunkten fragen können, aber es gibt trotzdem eine begrenzte Anzahl davon.
Schneller BootROM-Austausch
In der Anfangsphase des Debuggens besteht häufig der Wunsch, BootROM zu reparieren und es erneut zu versuchen. Es gibt jedoch ein Problem: BootROM ist Teil des in das FPGA geladenen Designs, und seine Synthese dauert einige Minuten (und dies geschieht, nachdem das BootROM-Image selbst fast sofort aus C und Assembler kompiliert wurde ...). Glücklicherweise ist tatsächlich alles viel schneller : Die Abfolge der Aktionen ist wie folgt:
- bootrom.mif neu generieren (Ich habe zu MIF anstelle von HEX gewechselt, weil ich mit HEX immer einige Probleme hatte und MIF das native Alter-Format ist.)
- in Quartus sagen
Processing -> Update Memory Initialization File
- Geben Sie in Assembler (in der linken Spalte von Tasks) den Befehl Start erneut ein
Für alles über alles - ein paar zehn Sekunden.
SD-Kartenvorbereitung
Hier ist alles relativ einfach, aber Sie müssen geduldig sein und über etwa 14 GB Festplattenspeicher verfügen:
git clone https://github.com/sifive/freedom-u-sdk git submodule update --recursive --init make
Dann müssen Sie eine saubere SD-Karte einlegen, die keine benötigte SD-Karte enthält, und diese ausführen
sudo make DISK=/dev/sdX format-boot-loader
... wobei sdX
das der Karte zugewiesene Gerät ist. ACHTUNG: Die Daten auf der Karte werden gelöscht, überschrieben und generell! Es lohnt sich kaum, die gesamte Assembly unter sudo
, da dann alle Assembly-Artefakte im Besitz von root
sind und die Assembly die sudo
Zeit unter sudo
werden muss.
Das Ergebnis ist eine in GPT markierte Karte mit vier Abschnitten, von denen einer FAT mit uEnv.txt
und ein herunterladbares Bild im FIT-Format ist (es enthält mehrere Teilbilder mit jeweils einer eigenen Download-Adresse). Der andere Abschnitt ist leer und soll in Ext4 formatiert sein für Linux. Zwei weitere Abschnitte sind kryptisch : U-Boot lebt auf einem (sein Offset ist, wie ich es verstehe, in BootROM verkabelt), auf dem anderen scheint es, dass seine Umgebungsvariablen leben, aber ich benutze sie noch nicht.
Stufe Eins, BootROM
Volksweisheit sagt: "Wenn es beim Programmieren Tänze mit einem Tamburin gibt, dann in der Elektronik - auch mit einem Feuerlöscher." Es ist nicht einmal so, dass ich, als ich das Board fast verbrannt hätte, entschieden habe, dass "Nun, GND ist der gleiche niedrige Pegel" (anscheinend würde der Widerstand immer noch nicht schaden ...). Es geht mehr um die Tatsache, dass wenn Von dort wachsen keine Hände, und die Elektronik bringt immer wieder Überraschungen: Als ich den Stecker auf die Platine gelötet habe, konnte ich die Kontakte immer noch nicht normal auflösen. Das Video zeigt, wie sich das Lot direkt über die Verbindung verteilt. Tragen Sie einfach den Lötkolben auf. Ich habe ihn "ausgelöscht". jedenfalls. Nun, vielleicht war das Lot nicht für die Temperatur des Lötkolbens geeignet, vielleicht etwas anderes ... Als ich sah, dass ich bereits ein Dutzend Kontakte hatte, spuckte ich im Allgemeinen aus und begann zu debuggen. Und dann begann eine mysteriöse Sache: Ich habe RX / TX von UART aus verbunden, ich lade die Firmware - sie schreibt
INIT CMD0 ERROR
Nun, alles ist logisch - ich habe das SD-Kartenmodul nicht angeschlossen. Wir beheben die Situation, laden die Firmware ... und schweigen ... Was ich gerade nicht geändert habe, und der Sarg öffnete sich gerade: Einer der Modulausgänge musste mit VCC verbunden werden. In meinem Fall unterstützte das Modul 5 V für die Stromversorgung. Ohne nachzudenken, steckte ich einen Draht vom Modul auf die gegenüberliegende Seite der Platine. Infolgedessen verdrehte sich der schief gelötete Stecker und der UART-Kontakt ging einfach verloren. facepalm.jpg Im Allgemeinen "gibt ein schlechter Kopf den Beinen keine Ruhe" und krumme Hände - dem Kopf ...
Am Ende sah ich die lang erwarteten bei Minicom
INIT CMD0 CMD8 ACMD41 CMD58 CMD16 CMD18 LOADING /
Außerdem, es bewegt sich Die Ladeanzeige dreht sich. Ich erinnere mich direkt an die Schuljahre und den gemächlichen Start von MinuetOS von einer Diskette. Es sei denn, der Antrieb schleift.
Das Problem ist, dass nach der BOOT-Nachricht nichts passiert. Es ist also Zeit, eine Verbindung über OpenOCD auf Raspberry und GDB auf dem Host herzustellen und zu sehen, was es ist.
Erstens zeigte die Verbindung mit GDB sofort, dass $pc
(Programmzähler, Adresse des aktuellen Befehls) auf 0x0
fliegt - dies geschieht wahrscheinlich nach einem Mehrfachfehler. Daher fügen wir unmittelbar nach der Ausgabe der BOOT
Nachricht eine Endlosschleife hinzu. Dies wird ihn für eine kurze Zeit verzögern ...
diff --git a/bootrom/sdboot/sd.cb/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; }
Solch kniffliger Code wird "aus Gründen der Zuverlässigkeit" verwendet: Ich habe irgendwo gehört, dass eine Endlosschleife anscheinend ein undefiniertes Verhalten ist, und hier ist es unwahrscheinlich, dass der Compiler dies errät (ich erinnere mich, dass sich BootROM bei 0x10000
).

Es scheint, aber was noch zu erwarten ist - eine harte Einbettung, welche Art von Quelle gibt es. Aber schließlich hat der Autor in diesem Artikel den Code debuggt ... Krex-fex-pex:
(gdb) file builds/zeowaa-e115/sdboot.elf A program is being debugged already. Are you sure you want to change the file? (y or n) y Reading symbols from builds/zeowaa-e115/sdboot.elf...done.

Nur müssen Sie nicht die MIF-Datei und nicht bin laden, sondern die Originalversion im ELF-Format.
Nun, mit dem n-ten Versuch, die Adresse zu erraten, an der die Ausführung fortgesetzt wird (dies ist ein weiterer Grund, warum der Compiler nicht hätte erraten sollen, dass die Schleife unendlich ist). Das Team
set variable $pc=0xADDR
Mit dieser Option können Sie den Wert des Registers unterwegs ändern (in diesem Fall die Adresse des aktuellen Befehls). Mit seiner Hilfe können Sie die im Speicher (und in den Speicherregistern) aufgezeichneten Werte ändern.
Am Ende kam ich zu dem Schluss (nicht sicher, ob es korrekt ist), dass wir ein "SD-Karten-Image des falschen Systems" haben und nicht zum Anfang der heruntergeladenen Daten gehen müssen, sondern zu 0x89800
Bytes weiter:
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 .rodata
Möglicherweise wurde dies auch durch die Tatsache beeinflusst, dass ich keine unnötige 4-GB-Karte zur Hand hatte. Ich nahm sie auf 2 GB und ersetzte sie im Makefile durch DEMO_END=11718750
durch DEMO_END=3078900
(suchen Sie nicht nach der Bedeutung im spezifischen Wert - sie existiert nicht, gerade jetzt wird das Bild platziert auf die Karte).
Stufe zwei, U-Boot
Jetzt "fallen" wir immer noch, aber wir sind bereits unter der Adresse 0x0000000080089a84
. Hier muss ich zugeben: Tatsächlich geht die Präsentation nicht "mit allen Stopps", sondern wird teilweise "nach" geschrieben. Daher habe ich hier bereits die richtige dtb-Datei aus unserem SoC CONFIG_SYS_TEXT_BASE=0x80089800
Variable CONFIG_SYS_TEXT_BASE=0x80089800
in den HiFive_U-Boot
CONFIG_SYS_TEXT_BASE=0x80089800
HiFive_U-Boot
(anstelle von 0x08000000
), sodass die Download-Adresse mit der tatsächlichen übereinstimmt. Jetzt herunterladen Karte der nächsten Ebene ein anderes Bild:
(gdb) file ../freedom-u-sdk/work/HiFive_U-Boot/u-boot (gdb) tui en
Und wir sehen:
│304 /* │ │305 * trap entry │ │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) │
Und wir springen zwischen den Zeilen 308 und 309. Und es ist nicht überraschend, da $sp
den Wert 0xfffffffe31cdc0a0
enthält. trap_entry
läuft es aufgrund von Zeile 307 auch ständig weg. Daher werden wir versuchen, einen Haltepunkt für trap_entry
und dann erneut zu 0x80089800
(U-Boot-Einstiegspunkt) zu wechseln, und wir hoffen, dass vor dem Übergang nicht die richtige Einstellung der Register erforderlich ist ... Es scheint zu 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 Continuing. 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 = 0x81cf950
So lala, der Stapelzeiger, sagen wir unverblümt: Er zeigt im Allgemeinen über den RAM hinaus (es sei denn, wir haben natürlich noch eine Adressübersetzung, aber hoffen wir auf eine einfache Option).
Versuchen wir, den Zeiger durch 0x881cf950
zu ersetzen. Als Ergebnis kommen wir zu der Tatsache, dass handle_trap
aufgerufen und aufgerufen wird, während _exit_trap
mit dem Argument epc=2148315240
(in Dezimalzahl) epc=2148315240
:
(gdb) x/10i 2148315240 0x800cb068 <strnlen+12>: lbu a4,0(a5) 0x800cb06c <strnlen+16>: bnez a4,0x800cb078 <strnlen+28> 0x800cb070 <strnlen+20>: sub a0,a5,a0 0x800cb074 <strnlen+24>: ret 0x800cb078 <strnlen+28>: addi a5,a5,1 0x800cb07c <strnlen+32>: j 0x800cb064 <strnlen+8> 0x800cb080 <strdup>: addi sp,sp,-32 0x800cb084 <strdup+4>: sd s0,16(sp) 0x800cb088 <strdup+8>: sd ra,24(sp) 0x800cb08c <strdup+12>: li s0,0
Wir setzen den Haltepunkt auf strnlen
, fahren fort und sehen:
(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=<optimized out>, precision=<optimized out>, flags=<optimized out>) 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 %08x , ra %08lx\n", fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lx\n", 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 %08x , ra %08lx\n", 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 %08x , ra %08lx\n", args=args@entry=0x881cc188) at lib/vsprintf.c:717 #5 0x00000000800ccb50 in printf (fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lx\n") at lib/vsprintf.c:792 #6 0x000000008008a9f0 in _exit_trap (regs=<optimized out>, epc=2148315240, code=<optimized out>) at arch/riscv/lib/interrupts.c:92 #7 handle_trap (mcause=<optimized out>, epc=<optimized out>, regs=<optimized out>) 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 PC
Es scheint, dass _exit_trap
Debugging-Informationen zu der aufgetretenen Ausnahme geben möchte, dies schlägt jedoch fehl . Etwas mit unserem Quellcode wird also nicht mehr angezeigt. set directories ../freedom-u-sdk/HiFive_U-Boot/
Oh! Jetzt angezeigt!
Führen Sie es erneut aus und sehen Sie auf dem Stack-Trace die Ursache des ursprünglichen Problems, das den ersten Fehler verursacht hat ( mcause == 5
). Wenn ich richtig verstehe, was hier auf Seite 37 geschrieben steht, bedeutet diese Ausnahme einen Load access fault
. Der Grund ist anscheinend, weil hier
arch / riscv / cpu / HiFive / start.S:
call_board_init_f: li t0, -16 li t1, CONFIG_SYS_INIT_SP_ADDR and sp, t1, t0 /* force 16 byte alignment */ #ifdef CONFIG_DEBUG_UART jal debug_uart_init #endif call_board_init_f_0: mv a0, sp jal board_init_f_alloc_reserve mv sp, a0 jal board_init_f_init_reserve mv a0, zero /* a0 <-- boot_flags = 0 */ la t5, board_init_f jr t5 /* jump to board_init_f() */
$sp
hat den gleichen falschen Wert und innerhalb von board_init_f_init_reserve
tritt ein Fehler auf. Das scheint der Schuldige zu sein: eine Variable mit dem expliziten Namen CONFIG_SYS_INIT_SP_ADDR
. Es ist in der Datei HiFive_U-Boot/include/configs/HiFive-U540.h
. Irgendwann dachte ich sogar, oder beenden Sie den Bootloader für den Prozessor - vielleicht ist es einfacher, den Prozessor leicht zu reparieren? Aber dann sah ich, dass es eher wie ein Artefakt aus den nicht vollständig #if 0
Einstellungen für eine andere Speicherkonfiguration war, und Sie können versuchen, dies zu tun:
diff --git a/include/configs/HiFive-U540.hb/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\0" /* 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 */
Irgendwann die Menge Krücken technologische Verbindungselemente erreichten einen kritischen Punkt. Nach ein wenig Qual kam ich zu der Notwendigkeit, den richtigen Port auf meinem Board zu machen. Dazu müssen Sie eine bestimmte Anzahl von Dateien für unsere Konfiguration kopieren und korrigieren.
Nun, ungefähr hier ist ein kleiner Tisch trosinenko@trosinenko-pc:/hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot$ git show --name-status commit 39cd67d59c16ac87b46b51ac1fb58f16f1eb1048 (HEAD -> zeowaa-1gb) Author: Anatoly Trosinenko <anatoly.trosinenko@gmail.com> Date: Tue Jul 2 17:13:16 2019 +0300 Initial support for 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.h
Details finden Sie im Repository .
Wie sich herausstellte, haben auf dieser SiFive-Karte die Register einiger Geräte unterschiedliche Adressen. Es stellte sich auch heraus, dass U-Boot durch den Kconfig-Mechanismus konfiguriert wird, der bereits aus dem Linux-Kernel bekannt ist. Sie können beispielsweise den Befehl make menuconfig
, und Sie sehen eine praktische make menuconfig
mit Parameterbeschreibungen in ?
usw. Nachdem ich die Beschreibung der dritten Karte aus den Beschreibungen der beiden Karten ausgeblendet und von dort aus alle erbärmlichen PLL-Rekonfigurationen verworfen hatte (anscheinend hängt dies irgendwie mit der PCIe-Steuerung vom Host-Computer zusammen, aber dies ist nicht korrekt), bekam ich eine Firmware, die, wenn das Wetter auf dem Mars stimmt Es gab mir eine UART-Nachricht darüber, von welchem Commit-Hash es gesammelt wurde und wie viel DRAM ich habe (aber ich habe diese Informationen auch im Header registriert).
Es ist schade, dass das Board danach normalerweise nicht mehr mit dem Prozessor-JTAG reagiert und das Booten von der SD-Karte in meiner Konfiguration leider nicht schnell ist. Andererseits zeigte BootROM manchmal die Meldung an, dass ERROR
nicht booten konnte, und U-Boot tauchte sofort auf. Damals dämmerte es mir: Anscheinend ist der Speicher nach dem Neustart des Bitstreams im FPGA nicht ausgefranst, es hat keine Zeit, sich „aufzureißen“ usw. Kurz gesagt, Sie können einfach, wenn LOADING /
message angezeigt wird, eine Verbindung mit einem Debugger und einer Befehlssatzvariablen set variable $pc=0x80089800
und diese lange Last umgehen (natürlich unter der Annahme, dass sie zuletzt ziemlich früh set variable $pc=0x80089800
wurde und keine Zeit über dem ursprünglichen Code hatte herunterladen).
Übrigens, und es ist im Allgemeinen normal, dass der Prozessor vollständig hängt und der JTAG-Debugger mit Nachrichten keine Verbindung herstellen kann
Error: unable to halt hart 0 Error: dmcontrol=0x80000001 Error: dmstatus =0x00030c82
Also warte! Ich habe es schon gesehen! Ähnliches passiert mit dem TileLink-Deadlock, aber irgendwie vertraue ich dem Autor des Speichercontrollers nicht - ich habe es selbst geschrieben ... Plötzlich, nach dem allerersten erfolgreichen Wiederaufbau des Prozessors nach der Bearbeitung des Controllers, sah ich:
INIT CMD0 CMD8 ACMD41 CMD58 CMD16 CMD18 LOADING BOOT U-Boot 2018.09-g39cd67d-dirty (Jul 03 2019 - 13:50:33 +0300) DRAM: 1 GiB MMC: BEFORE LOAD ENVBEFORE FDTCONTROLADDRBEFORE LOADADDRIn: serial Out: serial Err: serial Hit any key to stop autoboot: 3
In: serial
— , environment. , « »? ! : U-Boot 2^24 SD-, , , , , ELF-, . : , , .
, ? , - ...
(gdb) x/x 0x0200bff8 0x200bff8: 0x00000000
, ?
(gdb) set variable *0x0200bff8=310000000 (gdb) c
Dann:
Hit any key to stop autoboot: 0 MMC_SPI: 0 at 0:1 hz 20000000 mode 0
: . , - :
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: if (c == '\e') { *esc = 1; *key = KEY_NONE; } break; case 1: if (c == '[') { ...
, : :
case DTSTimebase => BigInt(0)
… , « — 0». WithNBigCores
1MHz (, , U-Boot). , , : , 25MHz! . «» ...
Hit any key to stop autoboot: 0 MMC_SPI: 0 at 0:1 hz 20000000 mode 0 ## Unknown partition table type 0 libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND ** No partition table - mmc 0 ** ## Info: input data size = 34 = 0x22 Running uEnv.txt boot2... ## Error: "boot2" not defined HiFive-Unleashed #
! , , , , mmc_spi 1 10000000 0; mmc part
, SPI 20MHz 10MHz. Warum? , 20MHz, . , , , , : ( — 25MHz) , . , 115200Hz UART- , , 25000000 20000000 1, .. 25MHz. , , , , - ( )… , — , , . 25MHz — Core i9.
HiFive-Unleashed # env edit mmcsetup edit: mmc_spi 1 10000000 0; mmc part HiFive-Unleashed # boot MMC_SPI: 1 at 0:1 hz 10000000 mode 0 Partition Map for MMC device 0 -- Partition Type: EFI Part Start LBA End LBA Name Attributes Type GUID Partition GUID 1 0x00000800 0x0000ffde "Vfat Boot" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 type: data guid: 76bd71fd-1694-4ff3-8197-bfa81699c2fb 2 0x00040800 0x002efaf4 "root" attrs: 0x0000000000000000 type: 0fc63daf-8483-4772-8e79-3d69d8477de4 type: linux guid: 9f3adcc5-440c-4772-b7b7-283124f38bf3 3 0x0000044c 0x000007e4 "uboot" attrs: 0x0000000000000000 type: 5b193300-fc78-40cd-8002-e86c45580b47 guid: bb349257-0694-4e0f-9932-c801b4d76fa3 4 0x00000400 0x0000044b "uboot-env" attrs: 0x0000000000000000 type: a09354ac-cd63-11e8-9aff-70b3d592f0fa guid: 4db442d0-2109-435f-b858-be69629e7dbf libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND 2376 bytes read in 0 ms Running uEnv.txt boot2... 15332118 bytes read in 0 ms ## Loading kernel from FIT Image at 90000000 ... Using 'config-1' configuration Trying 'bbl' kernel subimage Description: BBL/SBI/riscv-pk Type: Kernel Image Compression: uncompressed Data Start: 0x900000d4 Data Size: 74266 Bytes = 72.5 KiB Architecture: RISC-V OS: Linux Load Address: 0x80000000 Entry Point: 0x80000000 Hash algo: sha256 Hash value: 28972571467c4ad0cf08a81d9cf92b9dffc5a7cb2e0cd12fdbb3216cf1f19cbd Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at 90000000 ... Using 'config-1' configuration Trying 'fdt' fdt subimage Description: unavailable Type: Flat Device Tree Compression: uncompressed Data Start: 0x90e9d31c Data Size: 6911 Bytes = 6.7 KiB Architecture: RISC-V Load Address: 0x81f00000 Hash algo: sha256 Hash value: 10b0244a5a9205357772ea1c4e135a4f882409262176d8c7191238cff65bb3a8 Verifying Hash Integrity ... sha256+ OK Loading fdt from 0x90e9d31c to 0x81f00000 Booting using the fdt blob at 0x81f00000 ## Loading loadables from FIT Image at 90000000 ... Trying 'kernel' loadables subimage Description: Linux kernel Type: Kernel Image Compression: uncompressed Data Start: 0x900123e8 Data Size: 10781356 Bytes = 10.3 MiB Architecture: RISC-V OS: Linux Load Address: 0x80200000 Entry Point: unavailable Hash algo: sha256 Hash value: 72a9847164f4efb2ac9bae736f86efe7e3772ab1f01ae275e427e2a5389c84f0 Verifying Hash Integrity ... sha256+ OK Loading loadables from 0x900123e8 to 0x80200000 ## Loading loadables from FIT Image at 90000000 ... Trying 'ramdisk' loadables subimage Description: buildroot initramfs Type: RAMDisk Image Compression: gzip compressed Data Start: 0x90a5a780 Data Size: 4467411 Bytes = 4.3 MiB Architecture: RISC-V OS: Linux Load Address: 0x82000000 Entry Point: unavailable Hash algo: sha256 Hash value: 883dfd33ca047e3ac10d5667ffdef7b8005cac58b95055c2c2beda44bec49bd0 Verifying Hash Integrity ... sha256+ OK Loading loadables from 0x90a5a780 to 0x82000000
, , . . mcause , $pc
si
trap_entry
. U-Boot mcause = 0..4, . , , , : conf/rvboot-fit.txt
:
fitfile=image.fit # below much match what's in FIT (ugha)
, , , , SIF0
— - PCIe :
-bootargs=console=ttySIF0,921600 debug +bootargs=console=ttyS0,125200 debug
SHA-256 MD5: ( , ), , MD5 — . Was ist das Ergebnis? ( ), :
... Verifying Hash Integrity ... md5+ OK Loading loadables from 0x90a5a758 to 0x82000000 libfdt fdt_check_header(): FDT_ERR_BADMAGIC chosen { linux,initrd-end = <0x00000000 0x83000000>; linux,initrd-start = <0x00000000 0x82000000>; riscv,kernel-end = <0x00000000 0x80a00000>; riscv,kernel-start = <0x00000000 0x80200000>; bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait"; }; libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND chosen { linux,initrd-end = <0x00000000 0x83000000>; linux,initrd-start = <0x00000000 0x82000000>; riscv,kernel-end = <0x00000000 0x80a00000>; riscv,kernel-start = <0x00000000 0x80200000>; bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait"; }; Loading Kernel Image ... OK Booting kernel in 3
...
(gdb) x/x 0x0200bff8 0x200bff8: 0x00000000
, , , , . , , , , :
0x00000000bff6dbb0 in ?? () (gdb) set variable *0x0200bff8=1000000 (gdb) c Continuing. ^C Program received signal SIGINT, Interrupt. 0x00000000bff6dbb0 in ?? () (gdb) set variable *0x0200bff8=2000000 (gdb) c Continuing. ^C Program received signal SIGINT, Interrupt. 0x00000000bff6dbb0 in ?? () (gdb) set variable *0x0200bff8=3000000 (gdb) c Continuing.
...
Loading Kernel Image ... OK Booting kernel in 3 2 1 0 ## Starting application at 0x80000000 ...
, — , , !
-
0000000080001c20 <poweroff>: 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 <softfloat_countLeadingZeros8+0x558> 80001c2e: e406 sd ra,8(sp) 80001c30: f7fff0ef jal ra,80001bae <printm> 80001c34: 8522 mv a0,s0 80001c36: 267000ef jal ra,8000269c <finisher_exit> 80001c3a: 00010797 auipc a5,0x10 80001c3e: 41e78793 addi a5,a5,1054 # 80012058 <htif> 80001c42: 639c ld a5,0(a5) 80001c44: c399 beqz a5,80001c4a <poweroff+0x2a> 80001c46: 72c000ef jal ra,80002372 <htif_poweroff> 80001c4a: 45a1 li a1,8 80001c4c: 4501 li a0,0 80001c4e: dc7ff0ef jal ra,80001a14 <send_ipi_many> 80001c52: 10500073 wfi 80001c56: bff5 j 80001c52 <poweroff+0x32>
Berkeley Boot Loader. htif
— host interface, tethered- ( ARM), - standalone. , , , :
void poweroff(uint16_t code) { printm("Power off\r\n"); finisher_exit(code); if (htif) { htif_poweroff(); } else { send_ipi_many(0, IPI_HALT); while (1) { asm volatile ("wfi\n"); } } }
:
CLINT
val io = IO(new Bundle { val rtcTick = Bool(INPUT) }) val time = RegInit(UInt(0, width = timeWidth)) when (io.rtcTick) { time := time + UInt(1) }
RTC, MockAON, : «, ? ? !» , , System.scala
:
val rtcDivider = RegInit(0.asUInt(16.W))
Linux kernel
, :
BBL FDT 0xF0000000
, ! , … HiFive_U-Boot/arch/riscv/lib/boot.c , 0x81F00000
, U-Boot.
BBL , . mem_prop
, riscv-pk/machine/fdt.c : , fdt ram device_type = "memory"
— , , , — .
( , ):
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.
, riscv,kernel-start
riscv,kernel-end
DTB, . query_chosen
, BBL 32- , <0x0 0xADDR>
, , , . chosen
chosen { #address-cells = <1>; #size-cells = <0>; ... }
: 0x0
.
100500 , :
Versteckter Text Verifying Hash Integrity ... md5+ OK Loading loadables from 0x90a5a758 to 0x82000000 libfdt fdt_check_header(): FDT_ERR_BADMAGIC chosen { linux,initrd-end = <0x83000000>; linux,initrd-start = <0x82000000>; riscv,kernel-end = <0x80a00000>; riscv,kernel-start = <0x80200000>; #address-cells = <0x00000001>; #size-cells = <0x00000000>; bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait"; stdout-path = "uart0:38400n8"; }; libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND chosen { linux,initrd-end = <0x83000000>; linux,initrd-start = <0x82000000>; riscv,kernel-end = <0x80a00000>; riscv,kernel-start = <0x80200000>; #address-cells = <0x00000001>; #size-cells = <0x00000000>; bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait"; stdout-path = "uart0:38400n8"; }; Loading Kernel Image ... OK Booting kernel in 3 2 1 0 ## Starting application at 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: Ignoring memory range 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 Wed Jul 3 21:29:21 MSK 2019 [ 0.000000] bootconsole [early0] enabled [ 0.000000] Initial ramdisk at: 0x(____ptrval____) (16777216 bytes) [ 0.000000] Zone ranges: [ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000bfffffff] [ 0.000000] Normal [mem 0x00000000c0000000-0x00000bffffffffff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x0000000080200000-0x00000000bfffffff] [ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x00000000bfffffff] [ 0.000000] On node 0 totalpages: 261632 [ 0.000000] DMA32 zone: 3577 pages used for memmap [ 0.000000] DMA32 zone: 0 pages reserved [ 0.000000] DMA32 zone: 261632 pages, LIFO batch:63 [ 0.000000] software IO TLB: mapped [mem 0xbb1fc000-0xbf1fc000] (64MB)
( BBL, — ).
, , , RocketChip JTAG trap- — .
Program received signal SIGTRAP, Trace/breakpoint trap. 0xffffffe0000024ca in ?? () (gdb) bt #0 0xffffffe0000024ca in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?) (gdb) file work/linux/vmlinux A program is being debugged already. Are you sure you want to change the file? (y or n) y Reading symbols from work/linux/vmlinux...done. (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 stopped: frame did not save the PC
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);
, CPU not found, running software emulation . running. .
atomic_t hart_lottery; unsigned long boot_cpu_hartid;
linux/arch/riscv/kernel/setup.c — . , - , ...
.
Fortsetzung folgt. , , singlestep-.
( ):
