Dans la partie précédente , un contrôleur de mémoire plus ou moins fonctionnel a été implémenté, ou plutôt, un wrapper sur IP Core de Quartus, qui est un adaptateur pour TileLink. Aujourd'hui, sous la rubrique «Nous portons RocketChip sur une carte mère chinoise peu connue avec un cyclone», vous verrez une console fonctionnelle. Le processus a traîné un peu: je pensais déjà que je lancerais rapidement Linux et continuerais, mais il n’était pas là . Dans cette partie, je propose d'examiner le processus de démarrage de U-Boot, BBL et les tentatives timides du noyau Linux pour s'initialiser. Mais il existe une console - U-Boot-ovsky, et assez avancée, ayant une grande partie de ce que vous attendez d'une console à part entière.
Dans le matériel, une carte SD connectée via SPI, ainsi que UART, sera ajoutée. Dans la partie logicielle, BootROM sera remplacé de xip
Ă sdboot
et, en fait, les étapes de démarrage suivantes (sur la carte SD) seront ajoutées.
Dopage du matériel
Donc, la tâche: vous devez basculer vers le "grand" noyau et connecter l'UART (de Raspberry) et l'adaptateur SD (une sorte de carte Catalex à six broches a été utilisée: GND, VCC, MISO, MOSI, SCK, CS).
En principe, tout était assez simple. Mais avant de réaliser cela, j'ai été un peu HasPeripheryUART
: après la fois précédente, j'ai décidé qu'il fallait à nouveau mélanger quelque chose comme HasPeripheryUART
dans le System
(et l'implémentation, respectivement), la même chose pour la carte SD - et c'est tout sera prêt. Ensuite, j'ai décidé de voir comment il était mis en œuvre dans une conception «sérieuse». Alors qu'avons-nous retiré de sérieux? Arty, apparemment, ne convient pas - le monstre n'est pas unleahshed.DevKitConfigs
. Et soudain, il s'est avéré qu'il y avait partout une sorte de superpositions qui étaient ajoutées par le biais des paramètres par touches. Je suppose que c'est probablement très flexible et configurable, mais je voudrais commencer quelque chose pour commencer ... Mais vous n'avez pas la même chose, juste des béquilles plus faciles? .. Ensuite, je suis tombé sur vera.iofpga.FPGAChip
pour FPGAs Microsemi et tout de suite tiré entre guillemets J'ai essayé de faire mon implémentation par analogie, l'avantage ici est plus ou moins l'ensemble de la "disposition de la carte mère" dans un seul fichier.
Il s'est avéré que vous avez juste besoin d'ajouter des lignes à 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 ...
Une ligne dans le corps de la classe System
ajoute des informations sur la fréquence à laquelle cette partie de notre SoC fonctionne dans le fichier dts. Autant que je sache, DTS / DTB est un analogue statique de la technologie plug-and-play pour les appareils embarqués: l'arborescence de description dts est compilée dans un fichier dtb binaire et transmise par le chargeur au noyau afin qu'il puisse configurer correctement le matériel. Fait intéressant, sans ligne avec tlclock
tout est parfaitement synthétisé, mais cela ne fonctionnera pas pour compiler BootROM (je vous rappelle maintenant que ce sera sdboot
) - pendant la compilation, il analyse le fichier dts et crée un en-tête avec la macro TL_CLK
, grâce à laquelle il peut configurer correctement les diviseurs de fréquence pour interfaces externes.
Vous devrez également corriger légèrement le «câblage»:
Platform.scala:
class PlatformIO(implicit val p: Parameters) extends Bundle { ...
Franchement, les chaînes de registres ont été ajoutées simplement par analogie avec certains autres endroits du code source. Très probablement, ils devraient protéger contre la métastabilité . Peut-être que certains blocs ont déjà leur propre protection, mais je veux d'abord exécuter au moins "à un niveau élevé". Une question plus intéressante pour moi est pourquoi MISO et MOSI s'accrochent-ils à un dq
différent? Je n'ai toujours pas trouvé la réponse, mais il semble que le reste du code compte sur une telle connexion.
Physiquement, je viens d'attribuer les conclusions de conception aux contacts desserrés sur le bloc et de réorganiser le cavalier de sélection de tension à 3,3 V.
Adaptateur SDVue de dessus:

Vue de dessous:

Débogage de la partie logicielle: outils
Tout d'abord, parlons des outils de débogage disponibles et de leurs limites.
Minicom
Tout d'abord, nous devrons en quelque sorte lire ce que le chargeur de démarrage et la sortie du noyau. Pour ce faire, sous Linux (dans ce cas, celui sur RaspberryPi), nous avons besoin du programme Minicom. De manière générale, tout programme pour travailler avec un port série convient.
Notez qu'au démarrage, le nom du périphérique de port doit être spécifié sous la forme -D /dev/ttyS0
- après l'option -D
. Eh bien, les informations principales: pour quitter, utilisez Ctrl-A, X
J'ai vraiment eu un cas où cette combinaison n'a pas fonctionné - alors vous pouvez simplement dire killall -KILL minicom
d'une session SSH adjacente.
Il y a une autre fonctionnalité. Plus précisément, il y a deux UART sur RaspberryPi, et les deux ports peuvent déjà être adaptés pour quelque chose: l'un pour Bluetooth, à travers l'autre, la console du noyau est affichée par défaut. Heureusement, ce comportement peut être reconfiguré selon ce manuel .
Réécriture de la mémoire
Lors du débogage, pour tester l'hypothèse, j'ai parfois dû charger le bootloader (désolé) dans la RAM directement depuis l'hôte. Peut-être que cela peut être fait directement à partir de GDB, mais à la fin j'ai fait le chemin le plus simple: j'ai copié le fichier nécessaire sur Raspberry, j'ai également envoyé le port 4444 (telnet depuis OpenOCD) via SSH et utilisé la commande load_image
. Lorsque vous l'exécutez, il semble que tout est figé, mais en réalité «il ne dort pas, il clignote juste lentement» : il charge le fichier, il le fait juste à une vitesse de quelques kilo-octets par seconde.
Caractéristiques de l'installation des points d'arrêt
Beaucoup n'ont probablement pas eu à y penser lors du débogage de programmes réguliers, mais les points d'arrêt ne sont pas toujours définis dans le matériel. Parfois, la définition d'un point d'arrêt implique l'écriture temporaire d'une instruction spéciale au bon endroit directement dans le code machine . Par exemple, voici comment ma commande b
standard dans GDB a fonctionné. Voici ce qui en découle:
- vous ne pouvez pas mettre un point à l'intérieur de BootROM, car la ROM
- Vous pouvez définir un point d'arrêt sur le code chargé dans la RAM à partir de la carte SD, mais vous devez attendre qu'il soit chargé. Sinon, nous ne réécrirons pas un morceau de code, mais le chargeur réécrira notre point d'arrêt
Je suis sûr que vous pouvez explicitement demander à utiliser des points d'arrêt matériels, mais il y en a de toute façon un nombre limité.
Échange rapide BootROM
Au stade initial du débogage, il y a souvent un désir de réparer BootROM et de réessayer. Mais il y a un problème: BootROM fait partie de la conception chargée dans le FPGA, et sa synthèse est une question de plusieurs minutes (et c'est après avoir compilé presque instantanément l'image BootROM elle-même depuis C et Assembler ...). Heureusement, en fait, tout est beaucoup plus rapide : la séquence d'actions est la suivante:
- régénérer bootrom.mif (je suis passé à MIF au lieu de HEX, car avec HEX j'ai toujours eu quelques problèmes, et MIF est le format Alter natif)
- dans Quartus, dites
Processing -> Update Memory Initialization File
- sur Assembleur (dans la colonne de gauche de Tâches), recommencer la commande
Pour tout sur tout - quelques dizaines de secondes.
Préparation de la carte SD
Tout est relativement simple ici, mais vous devez ĂŞtre patient et disposer d'environ 14 Go d'espace disque:
git clone https://github.com/sifive/freedom-u-sdk git submodule update --recursive --init make
Ensuite, vous devez insérer une carte SD propre, ou plutôt, ne contenant rien dont vous avez besoin, et exécuter
sudo make DISK=/dev/sdX format-boot-loader
... oĂą sdX
est le périphérique affecté à la carte. ATTENTION: les données de la carte seront supprimées, écrasées et en général! Cela ne vaut guère la peine de faire l'assembly entier sous sudo
, car alors tous les artefacts d'assembly seront la propriété de root
, et l'assemblage devra ĂŞtre fait sous sudo
temps.
Le résultat est une carte balisée en GPT avec quatre sections, dont l'une est FAT avec uEnv.txt
et une image téléchargeable au format FIT (elle contient plusieurs sous-images, chacune avec sa propre adresse de téléchargement), l'autre section est vierge, elle est censée être formatée en Ext4 pour Linux. Deux autres sections sont cryptiques : U-Boot vit sur l'une (son décalage, si je comprends bien, est câblé dans BootROM), sur l'autre, il semble que ses variables d'environnement vivent, mais je ne les utilise pas encore.
Niveau un, BootROM
La sagesse populaire dit: "Si dans la programmation il y a des danses avec un tambourin, alors dans l'électronique - aussi avec un extincteur." Ce n'est même pas une fois que j'ai presque brûlé la carte, décidant que "Eh bien, GND est le même bas niveau" (apparemment, la résistance ne ferait toujours pas de mal ...) C'est plus sur le fait que si les mains ne poussent pas à partir de là , puis l'électronique ne cesse de surprendre: lorsque j'ai soudé le connecteur sur la carte, je ne pouvais toujours pas dissoudre les contacts normalement - la vidéo montre comment la soudure se propage directement tout au long de la connexion, il suffit de mettre le fer à souder, c'est descendu sur moi de toute façon. Eh bien, peut-être que la soudure n'était pas adaptée à la température du fer à souder, peut-être autre chose ... En général, quand j'ai vu que j'avais déjà une douzaine de contacts, j'ai craché et commencé à déboguer. Et puis une chose mystérieuse a commencé: j'ai connecté RX / TX depuis UART, je charge le firmware - il écrit
INIT CMD0 ERROR
Eh bien, tout est logique - je n'ai pas connecté le module de carte SD. On corrige la situation, on charge le firmware ... Et le silence ... Ce que je viens de ne pas changer d'avis, et le coffret vient de s'ouvrir: une des sorties du module devait être connectée au VCC. Dans mon cas, le module prend en charge 5V pour l'alimentation, donc sans y réfléchir à deux fois, j'ai coincé un fil qui s'étend du module vers le côté opposé de la carte. En conséquence, le connecteur soudé de travers s'est tordu et le contact UART a simplement été perdu. facepalm.jpg En général, "une mauvaise tête ne donne pas de repos aux jambes", et des mains tordues - à la tête ...
Au final, j'ai vu le tant attendu chez Minicom
INIT CMD0 CMD8 ACMD41 CMD58 CMD16 CMD18 LOADING /
De plus, ça bouge l'indicateur de chargement tourne. Je me souviens directement des années scolaires et du démarrage tranquille de MinuetOS à partir d'une disquette. Sauf si le lecteur grince.
Le problème est que rien ne se passe après le message BOOT. Il est donc temps de se connecter via OpenOCD sur Raspberry, GDB sur l'hôte et de voir ce que c'est.
Premièrement, la connexion utilisant GDB a immédiatement montré que $pc
(compteur de programme, adresse de l'instruction en cours) vole vers 0x0
- cela se produit probablement après une erreur multiple. Par conséquent, immédiatement après l'émission du message BOOT
, nous ajoutons une boucle infinie. Cela le retardera un court instant ...
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; }
Un code aussi délicat est utilisé «pour la fiabilité»: j'ai entendu quelque part que, semble-t-il, une boucle infinie est un comportement indéfini, et ici le compilateur a peu de chances de deviner (je me souviens que BootROM est situé à 0x10000
).

Il semblerait, mais à quoi d'autre s'attendre - un dur intégré, quel type de source est là . Mais après tout, dans cet article, l' auteur a débogué le code ... 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.

Seulement, vous devez charger non pas le fichier MIF et non bin, mais la version originale au format ELF.
Maintenant, avec la nième tentative de deviner l'adresse où l'exécution se poursuivra (c'est une autre raison pour laquelle le compilateur n'aurait pas dû deviner que la boucle est infinie). L'équipe
set variable $pc=0xADDR
vous permet de modifier la valeur du registre lors de vos déplacements (dans ce cas, l'adresse de l'instruction en cours). Avec son aide, vous pouvez modifier les valeurs enregistrées en mémoire (et les registres mappés en mémoire).
En fin de compte, je suis arrivé à la conclusion (je ne sais pas si c'est correct) que nous avons une «image de carte SD du mauvais système», et nous devons aller non pas au tout début des données téléchargées, mais à 0x89800
octets plus loin:
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
Peut-être que cela était également affecté par le fait que je n'avais pas de carte 4Gb inutile sous la main, je l'ai prise à 2 Go et l'ai remplacée dans le Makefile par DEMO_END=11718750
par DEMO_END=3078900
(ne cherchez pas le sens dans une valeur spécifique - elle n'existe pas, juste maintenant l'image est placée à la carte).
Niveau deux, U-Boot
Maintenant, nous «tombons» encore, mais nous sommes déjà à l'adresse 0x0000000080089a84
. Ici, je dois admettre: en fait, la présentation ne va pas «avec tous les arrêts», mais est partiellement écrite «après», donc ici j'ai déjà réussi à mettre le fichier dtb correct de notre SoC, ajustez la variable CONFIG_SYS_TEXT_BASE=0x80089800
dans les CONFIG_SYS_TEXT_BASE=0x80089800
HiFive_U-Boot
(au lieu de 0x08000000
) afin que l'adresse de téléchargement corresponde à celle réelle. Téléchargez maintenant carte de niveau suivant une autre image:
(gdb) file ../freedom-u-sdk/work/HiFive_U-Boot/u-boot (gdb) tui en
Et nous voyons:
│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) │
Et nous sautons entre les lignes 308 et 309. Et ce n'est pas surprenant, étant donné que $sp
contient la valeur 0xfffffffe31cdc0a0
. Hélas, il "s'enfuit" constamment en raison de la ligne 307. Par conséquent, nous allons essayer de définir un point d'arrêt sur trap_entry
, puis basculer Ă nouveau sur 0x80089800
(point d'entrée U-Boot), et nous espérons qu'il ne nécessite pas le réglage correct des registres avant la transition ... Cela semble fonctionner:
(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
Pour ainsi dire, le pointeur de pile, disons carrément: il pointe généralement au-delà de la RAM (à moins, bien sûr, que nous ayons encore la traduction d'adresse, mais espérons une option simple).
Essayons de remplacer le pointeur par 0x881cf950
. En conséquence, nous arrivons au fait que handle_trap
est appelé et appelé, tout en laissant dans _exit_trap
avec l'argument epc=2148315240
(en décimal):
(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
Nous définissons un point d'arrêt sur strnlen
, continuons et voyons:
(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
Il semble que _exit_trap
veuille fournir des informations de débogage sur l'exception qui s'est produite, mais il échoue . Donc, quelque chose avec notre code source ne s'affiche plus. set directories ../freedom-u-sdk/HiFive_U-Boot/
Oh! Maintenant affiché!
Eh bien, exécutez-le à nouveau et voyez sur la pile la cause du problème d'origine à l'origine de la première erreur ( mcause == 5
). Si je comprends bien ce qui est écrit ici à la page 37, alors cette exception signifie Load access fault
. La raison, apparemment, est qu'ici
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
a la mĂŞme valeur incorrecte et une erreur se produit dans board_init_f_init_reserve
. Cela semble ĂŞtre le coupable: une variable avec le nom explicite CONFIG_SYS_INIT_SP_ADDR
. Il est défini dans le fichier HiFive_U-Boot/include/configs/HiFive-U540.h
. À un moment donné, j'ai même pensé, ou peut-être, enfin, terminer le chargeur de démarrage pour le processeur - peut-être qu'il est plus facile de réparer légèrement le processeur? Mais j'ai vu que cela ressemblait plus à un artefact des paramètres pas complètement #if 0
pour une configuration de mémoire différente, et vous pouvez essayer de le faire:
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 */
À un moment donné, la quantité béquilles les attaches technologiques ont atteint un point critique. Après un petit tourment, je suis venu à la nécessité de faire le bon port sur ma carte. Pour ce faire, vous devez copier et corriger un certain nombre de fichiers pour notre configuration.
Eh bien, environ, voici une petite table 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
Les détails peuvent être trouvés dans le référentiel .
Il s'est avéré que sur cette carte SiFive, les registres de certains appareils ont des adresses différentes. Il s'est également avéré que U-Boot est configuré par le mécanisme Kconfig, déjà familier du noyau Linux - par exemple, vous pouvez commander make menuconfig
, et vous verrez une interface de texte pratique avec des descriptions de paramètres indiquées dans ?
etc. En général, après avoir masqué la description de la troisième des descriptions de deux cartes, jetant toute reconfiguration de pathos PLL à partir de là (apparemment, cela est en quelque sorte connecté au contrôle PCIe de l'ordinateur hôte, mais ce n'est pas précis), j'ai obtenu un firmware, qui, si la météo est bonne sur Mars Il m'a donné un message UART sur le hachage de validation à partir duquel il a été collecté et sur la quantité de DRAM dont je dispose (mais j'ai également enregistré ces informations dans l'en-tête).
Il est dommage qu'après cela, la carte cesse généralement de répondre avec le processeur JTAG, et le démarrage à partir de la carte SD n'est, hélas, pas rapide dans ma configuration. D'un autre côté, BootROM affichait parfois un message indiquant que ERROR
ne pouvait pas démarrer et U-Boot apparaissait immédiatement. C'est alors qu'il m'est apparu: apparemment, après le redémarrage du bitstream, la mémoire n'est pas effilochée dans le FPGA, elle n'a pas le temps de "se déchirer", etc. En bref, vous pouvez simplement lorsque le message LOADING /
apparaît, vous connecter avec un débogueur et une set variable $pc=0x80089800
commandes set variable $pc=0x80089800
, contournant ainsi ce long téléchargement (bien sûr, en supposant qu'il s'est rompu pour la dernière fois assez tôt et n'a pas eu le temps en plus du code d'origine télécharger).
Soit dit en passant, et il est généralement normal que le processeur se bloque complètement et que le débogueur JTAG avec des messages ne puisse pas s'y connecter
Error: unable to halt hart 0 Error: dmcontrol=0x80000001 Error: dmstatus =0x00030c82
Alors attends! Je l'ai déjà vu! - TileLink, - — … , :
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
:
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. Pourquoi? , 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 — . Quel est le résultat? ( ), :
... 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 , :
Texte masqué 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 — . , - , ...
.
. , , singlestep-.
( ):
