En la parte anterior , se implementó un controlador de memoria más o menos funcional, o más bien, un contenedor sobre IP Core de Quartus, que es un adaptador para TileLink. Hoy, bajo el título "Llevamos RocketChip a una placa base china poco conocida con Cyclone", verá una consola que funciona. El proceso se prolongó un poco: ya pensé que lanzaría Linux rápidamente y seguiría adelante, pero no estaba allí. En esta parte, propongo analizar el proceso de inicio de U-Boot, BBL y los intentos tímidos de kernel de Linux para inicializar. Pero hay una consola: U-Boot-ovsky, y bastante avanzada, que tiene mucho de lo que esperas de una consola completa.
En el hardware, se agregará una tarjeta SD conectada a través de SPI, así como UART. En la parte del software, BootROM se reemplazará de xip
a sdboot
y, de hecho, se sdboot
las siguientes etapas de arranque (en la tarjeta SD).
Dopando el hardware
Entonces, la tarea: debe cambiar al núcleo "grande" y conectar el UART (desde Raspberry) y el adaptador SD (se utilizó algún tipo de placa Catalex con seis pines: GND, VCC, MISO, MOSI, SCK, CS).
En principio, todo era bastante simple. Pero antes de darme cuenta de esto, me arrojaron un poco de lado a lado: después de la vez anterior, decidí que nuevamente solo necesita mezclar algo como HasPeripheryUART
en el System
(y la implementación, respectivamente), lo mismo para la tarjeta SD, y eso es todo. Estará listo Entonces decidí ver cómo se implementaba en un diseño "serio". Entonces, ¿qué hemos sacado en serio? Arty, al parecer, no encaja: el monstruo permanece sin unleahshed.DevKitConfigs
. unleahshed.DevKitConfigs
. Y de repente resultó que había en todas partes algún tipo de superposiciones que se agregaron a través de los parámetros mediante teclas. Supongo que esto es probablemente muy flexible y configurable, pero me gustaría comenzar algo para empezar ... Pero no tienes lo mismo, ¿simplemente muletas más fáciles? ... Luego me encontré con vera.iofpga.FPGAChip
para FPGAs Microsemi y enseguida sacó entre comillas Traté de hacer mi implementación por analogía, el beneficio aquí es más o menos todo el "diseño de la placa base" en un archivo.
Resultó, realmente, solo necesitas agregar líneas a 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 ...
Una línea en el cuerpo de la clase System
agrega información sobre la frecuencia con la que esta parte de nuestro SoC funciona al archivo dts. Según tengo entendido, DTS / DTB es un análogo estático de la tecnología plug-and-play para dispositivos integrados: el árbol de descripción dts se compila en un archivo binario dtb y el cargador lo transmite al núcleo para que pueda configurar correctamente el hardware. Curiosamente, sin una línea con tlclock
todo está perfectamente sintetizado, pero no funcionará para compilar BootROM (te recordaré ahora que será sdboot
): durante la compilación analiza el archivo dts y crea un encabezado con la macro TL_CLK
, gracias a la cual puede configurar correctamente los divisores de frecuencia para interfaces externas
También deberá arreglar ligeramente el "cableado":
Platform.scala:
class PlatformIO(implicit val p: Parameters) extends Bundle { ...
Las cadenas de registro, francamente, se agregaron simplemente por analogía con algunos otros lugares en el código fuente. Lo más probable es que deberían proteger contra la metaestabilidad . Quizás algunos bloques ya tienen su propia protección, pero primero quiero correr al menos "a un alto nivel". Una pregunta más interesante para mí es ¿por qué MISO y MOSI cuelgan en diferentes dq
? Todavía no he encontrado la respuesta, pero parece que el resto del código cuenta con esa conexión.
Físicamente, acabo de asignar las conclusiones del diseño a los contactos sueltos en el bloque y reorganicé el puente de selección de voltaje a 3.3V.
Adaptador SDVista superior:

Vista inferior:

Depuración de la parte de software: herramientas
Primero, hablemos sobre las herramientas de depuración disponibles y sus limitaciones.
Minicom
Primero, necesitaremos leer de alguna manera qué es el cargador de arranque y la salida del kernel. Para hacer esto, en Linux (en este caso, el de RaspberryPi), necesitamos el programa Minicom. En términos generales, cualquier programa para trabajar con un puerto serie es adecuado.
Tenga en cuenta que al inicio, el nombre del dispositivo del puerto debe especificarse como -D /dev/ttyS0
- después de la opción -D
. Bueno, la información principal: para salir, use Ctrl-A, X
Realmente tuve un caso en el que esta combinación no funcionó, entonces simplemente puede decir killall -KILL minicom
desde una sesión SSH adyacente.
Hay otra característica. Específicamente, hay dos UART en RaspberryPi, y ambos puertos ya se pueden adaptar para algo: uno para Bluetooth, y el otro, la consola del kernel se muestra de forma predeterminada. Afortunadamente, este comportamiento se puede reconfigurar de acuerdo con este manual .
Reescribiendo memoria
Al depurar, para probar la hipótesis, a veces tenía que cargar el gestor de arranque (lo siento) en la RAM directamente desde el host. Tal vez esto se puede hacer directamente desde GDB, pero al final tomé el camino simple: copié el archivo necesario a Raspberry, también envié el puerto 4444 (telnet desde OpenOCD) a través de SSH y utilicé el comando load_image
. Cuando lo ejecuta, parece que todo está congelado, pero en realidad "no duerme, simplemente parpadea lentamente" : carga el archivo, simplemente lo hace a una velocidad de un par de kilobytes por segundo.
Características de la instalación de puntos de interrupción
Probablemente, muchos no tuvieron que pensar en esto al depurar programas regulares, pero los puntos de interrupción no siempre se establecen en el hardware. A veces, establecer un punto de interrupción implica escribir temporalmente una instrucción especial en el lugar correcto directamente en el código de máquina . Por ejemplo, así es como funcionó mi comando b
estándar en GDB. Esto es lo que sigue de esto:
- no puedes poner un punto dentro de BootROM, porque ROM
- Puede establecer un punto de interrupción en el código cargado en la RAM desde la tarjeta SD, pero debe esperar hasta que se cargue. De lo contrario, no reescribiremos un código, pero el cargador reescribirá nuestro punto de interrupción
Estoy seguro de que puede solicitar explícitamente el uso de puntos de interrupción de hardware, pero de todos modos hay un número limitado de ellos.
Cambio rápido de BootROM
En la etapa inicial de depuración, a menudo existe el deseo de arreglar BootROM e intentar nuevamente. Pero hay un problema: BootROM es parte del diseño cargado en el FPGA, y su síntesis es cuestión de varios minutos (y esto es después de compilar casi instantáneamente la propia imagen de BootROM desde C y Assembler ...). Afortunadamente, de hecho, todo es mucho más rápido : la secuencia de acciones es la siguiente:
- regenerate bootrom.mif (cambié a MIF en lugar de HEX, porque con HEX siempre tuve algunos problemas, y MIF es el formato nativo de Alter)
- in Quartus say
Processing -> Update Memory Initialization File
- en Ensamblador (en la columna izquierda de Tareas), comando Comenzar de nuevo
Para todo sobre todo, un par de decenas de segundos.
Preparación de la tarjeta SD
Aquí todo es relativamente simple, pero debe ser paciente y tener aproximadamente 14 Gb de espacio en disco:
git clone https://github.com/sifive/freedom-u-sdk git submodule update --recursive --init make
Luego debe insertar una tarjeta SD limpia o, mejor dicho, que no contenga todo lo que necesita, y ejecutar
sudo make DISK=/dev/sdX format-boot-loader
... donde sdX
es el dispositivo asignado a la tarjeta. ATENCIÓN: ¡los datos en la tarjeta serán eliminados, sobrescritos y en general! No vale la pena hacer todo el ensamblaje desde debajo de sudo
, porque entonces todos los artefactos de ensamblaje serán propiedad de root
, y el ensamblaje tendrá que hacerse desde debajo de sudo
tiempo.
El resultado es una tarjeta marcada en GPT con cuatro secciones, una de las cuales es FAT con uEnv.txt
y una imagen descargable en formato FIT (contiene varias uEnv.txt
, cada una con su propia dirección de descarga), la otra sección está en blanco, se supone que está formateada en Ext4 para Linux Dos secciones más son crípticas : U-Boot vive en una (su compensación, según tengo entendido, está cableada en BootROM), en la otra, parece que sus variables de entorno viven, pero aún no las uso.
Nivel uno, BootROM
La sabiduría popular dice: "Si en la programación hay bailes con una pandereta, luego en electrónica, también con un extintor de incendios". Ni siquiera es que una vez casi quemé el tablero, decidiendo que "Bueno, GND es el mismo nivel bajo" (aparentemente, la resistencia aún no dolería ...) Se trata más del hecho de que si las manos no crecen a partir de ahí, entonces la electrónica no deja de traer sorpresas: cuando solde el conector a la placa, todavía no puedo disolver los contactos normalmente: el video muestra cómo la soldadura se extiende directamente a través de la conexión, simplemente coloque el soldador, se me cayó encima. de todos modos Bueno, tal vez la soldadura no era adecuada para la temperatura del soldador, tal vez otra cosa ... En general, cuando vi que ya tenía una docena de contactos, escupí y comencé a depurar. Y entonces comenzó algo misterioso : conecté RX / TX desde UART, cargué el firmware, escribe
INIT CMD0 ERROR
Bueno, todo es lógico: no conecté el módulo de la tarjeta SD. Arreglamos la situación, cargamos el firmware ... Y silenciamos ... Lo que simplemente no cambió de opinión, y el ataúd simplemente se abrió: una de las salidas del módulo tenía que estar conectada a VCC. En mi caso, el módulo soportaba 5V de potencia, así que sin pensarlo dos veces, pegué un cable que se extendía desde el módulo al lado opuesto de la placa. Como resultado, el conector soldado torcidamente se retorció y el contacto UART simplemente se perdió. facepalm.jpg En general, "una cabeza mala no da descanso a las piernas", y manos torcidas - a la cabeza ...
Al final, vi el tan esperado en Minicom
INIT CMD0 CMD8 ACMD41 CMD58 CMD16 CMD18 LOADING /
Por otra parte, se mueve El indicador de carga está girando. Recuerdo directamente los años escolares y el arranque pausado de MinuetOS desde un disquete. A menos que la unidad muela.
El problema es que no pasa nada después del mensaje BOOT. Entonces, es hora de conectarse a través de OpenOCD en Raspberry, GDB en el host y ver qué es.
En primer lugar, la conexión con GDB mostró inmediatamente que $pc
(contador del programa, dirección de la instrucción actual) vuela a 0x0
; esto probablemente ocurre después de un error múltiple. Por lo tanto, inmediatamente después de emitir el mensaje BOOT
, agregamos un bucle infinito. Esto lo retrasará por un momento ...
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; }
Tal código complicado se usa "por confiabilidad": escuché en alguna parte que, al parecer, un bucle infinito es un comportamiento indefinido, y aquí es poco probable que el compilador adivine (recuerdo que BootROM se encuentra en 0x10000
).

Parece, pero qué más esperar: una incrustación dura, qué tipo de fuente hay. Pero después de todo, en ese artículo, el autor depuró el código ... 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.

Solo necesita cargar no el archivo MIF y no bin, sino la versión original en formato ELF.
Ahora, con el enésimo intento de adivinar la dirección donde continuará la ejecución (esta es otra razón por la cual el compilador no debería haber adivinado que el bucle es infinito). El equipo
set variable $pc=0xADDR
le permite cambiar el valor del registro sobre la marcha (en este caso, la dirección de la instrucción actual). Con su ayuda, puede cambiar los valores registrados en la memoria (y los registros mapeados en memoria).
Al final, llegué a la conclusión (no estoy seguro si es correcto) de que tenemos una "imagen de tarjeta SD del sistema incorrecto", y que necesitamos ir no al principio de los datos descargados, sino a 0x89800
bytes más:
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
Tal vez esto también se vio afectado por el hecho de que no tenía una tarjeta innecesaria de 4 Gb a mano, la llevé a 2 Gb y la reemplacé en el Makefile con DEMO_END=11718750
con DEMO_END=3078900
(no busque el significado en un valor específico; no existe, ahora la imagen está colocada a la tarjeta).
Nivel dos, arranque en U
Ahora todavía estamos "cayendo", pero ya estamos en la dirección 0x0000000080089a84
. Aquí tengo que admitir: de hecho, la presentación no va "con todas las paradas", sino que está parcialmente escrita "después", así que aquí ya logré poner el archivo dtb correcto de nuestro SoC, ajustar la variable CONFIG_SYS_TEXT_BASE=0x80089800
en la HiFive_U-Boot
(en lugar de 0x08000000
) para que la dirección de descarga coincida con la actual. Descargar ahora mapa del siguiente nivel otra imagen:
(gdb) file ../freedom-u-sdk/work/HiFive_U-Boot/u-boot (gdb) tui en
Y vemos:
│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) │
Y saltamos entre las líneas 308 y 309. Y no es sorprendente, dado que $sp
contiene el valor 0xfffffffe31cdc0a0
. Por desgracia, también se "escapa" constantemente debido a la línea 307. Por lo tanto, intentaremos establecer un punto de interrupción en trap_entry
y luego 0x80089800
nuevamente a 0x80089800
(punto de entrada de U-Boot), y esperamos que no requiera la configuración correcta de registros antes de la transición ... Parece funcionar:
(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
Entonces, el puntero de la pila, digamos sin rodeos: generalmente apunta más allá de la RAM (a menos que, por supuesto, todavía tengamos traducción de direcciones, pero esperemos una opción simple).
Intentemos reemplazar el puntero con 0x881cf950
. Como resultado, llegamos al hecho de que se llama y se llama a _exit_trap
, mientras se deja en _exit_trap
con el argumento epc=2148315240
(en decimal):
(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
Establecemos un punto de interrupción en strnlen
, continuamos y vemos:
(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
Parece que _exit_trap
quiere dar información de depuración sobre la excepción que ocurrió, pero falla . Entonces, algo con nuestro código fuente no se muestra nuevamente. set directories ../freedom-u-sdk/HiFive_U-Boot/
¡Oh! Ahora se muestra!
Bueno, ejecútelo nuevamente y vea en la pila rastrear la causa del problema original que causó el primer error ( mcause == 5
). Si entiendo correctamente lo que está escrito aquí en la página 37, entonces esta excepción significa Load access fault
. La razón, aparentemente, es porque aquí
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
tiene el mismo valor incorrecto y se produce un error dentro de board_init_f_init_reserve
. Ese parece ser el culpable: una variable con el nombre explícito CONFIG_SYS_INIT_SP_ADDR
. Está definido en el archivo HiFive_U-Boot/include/configs/HiFive-U540.h
. En algún momento, incluso pensé, o tal vez, bueno, terminar el gestor de arranque para el procesador, ¿tal vez es más fácil arreglar ligeramente el procesador? Pero luego vi que era más como un artefacto de la configuración no completamente #if 0
para una configuración de memoria diferente, y puede intentar hacer esto:
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 */
En algún momento, la cantidad muletas Los sujetadores tecnológicos alcanzaron un punto crítico. Después de un pequeño tormento, llegué a la necesidad de hacer el puerto correcto en mi placa. Para hacer esto, debe copiar y corregir una cierta cantidad de archivos para nuestra configuración.
Bueno, aproximadamente, aquí hay una mesita 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
Los detalles se pueden encontrar en el repositorio .
Al final resultó que, en esta placa SiFive, los registros de algunos dispositivos tienen direcciones diferentes. También resultó que U-Boot está configurado por el mecanismo Kconfig, ya familiarizado con el kernel de Linux; por ejemplo, puede ordenar make menuconfig
, y verá una interfaz de texto conveniente con las descripciones de los parámetros que se muestran en ?
etc. En general, después de cegar la descripción de la tercera de las descripciones de las dos placas, descartando cualquier patética reconfiguración de PLL desde allí (aparentemente, esto está de alguna manera conectado con el control PCIe desde la computadora host, pero esto no es exacto), obtuve un firmware, que, si el clima es correcto en Marte Me dio un mensaje UART sobre de qué hash de confirmación se recopiló y cuánta DRAM tengo (pero también registré esta información en el encabezado).
Es una pena que después de esto, la placa generalmente dejara de responder con el procesador JTAG, y el arranque desde la tarjeta SD, por desgracia, no es rápido en mi configuración. Por otro lado, a veces BootROM mostraba un mensaje de que ERROR
no podía arrancar, y U-Boot apareció inmediatamente. Fue entonces cuando caí en la cuenta: aparentemente, después de reiniciar el flujo de bits, la memoria no se deshilacha en el FPGA, no tiene tiempo para "romperse", etc. En resumen, puede simplemente cuando aparece el mensaje LOADING /
, conectarse con un depurador y una set variable $pc=0x80089800
comandos set variable $pc=0x80089800
, evitando así esta descarga larga (por supuesto, suponiendo que se rompió bastante temprano y no tuvo tiempo encima del código original descargar).
Por cierto, y generalmente es normal que el procesador se cuelgue completamente y que el depurador JTAG con mensajes no pueda conectarse a él
Error: unable to halt hart 0 Error: dmcontrol=0x80000001 Error: dmstatus =0x00030c82
¡Entonces espera! Ya lo vi! - 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. Por qué , 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 — . Cual es el resultado? ( ), :
... 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 , :
Texto oculto 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-.
( ):
