在上一部分中 ,实现了或多或少可以工作的存储器控制器,或者说是Quartus上IP Core的包装器,它是TileLink的适配器。 今天,在“我们将RocketChip移植到带有Cyclone的鲜为人知的中国主板”标题下,您将看到一个工作控制台。 这个过程拖了一点点:我已经以为我会快速启动Linux并继续前进,但是还没有。 在这一部分中,我建议看一下启动U-Boot,BBL和胆小的Linux内核尝试初始化的过程。 但是有一个控制台-U-Boot-ovsky,它非常先进,具有您从功能完善的控制台中获得的很多期望。
在硬件中,将添加通过SPI和UART连接的SD卡。 在软件部分,BootROM将由xip
替换为sdboot
,实际上,将添加以下引导阶段(在SD卡上)。
掺杂硬件
因此,任务是:您需要切换到“大”内核,并连接UART(来自Raspberry)和SD适配器(使用了具有六个引脚的Catalex板:GND,VCC,MISO,MOSI,SCK,CS)。
原则上,一切都非常简单。 但是在意识到这一点之前,我有点HasPeripheryUART
:在上一次之后,我决定再次需要将类似HasPeripheryUART
东西HasPeripheryUART
System
(以及相应的实现)中,就像SD卡一样-就是这样准备好了。 然后,我决定看看它是如何在“严肃的”设计中实现的。 那么我们从严肃中得到了什么? 显然, unleahshed.DevKitConfigs
Arty)不适合-怪物仍未unleahshed.DevKitConfigs
。 突然发现,到处都是通过键通过参数添加某种类型的叠加层。 我想这可能是非常灵活和可配置的,但是我想从头开始... 但是您没有相同的东西,只是 vera.iofpga.FPGAChip
?..然后我遇到了vera.iofpga.FPGAChip
用于FPGA Microsemi和 马上把引号 我尝试类推实现,这里的好处或多或少是在一个文件中整个“主板布局”。
原来,实际上,您只需要向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 ...
System
类正文中的一行将有关SoC这部分工作频率的信息添加到dts文件中。 据我了解,DTS / DTB是嵌入式设备即插即用技术的静态模拟:dts描述树被编译成二进制dtb文件,并由加载程序传输到内核,以便它可以正确配置硬件。 有趣的是,没有tlclock
行,所有内容都可以完美地合成,但是无法编译BootROM(我会提醒您,现在它将是sdboot
)-在编译过程中,它解析dts文件并创建带有TL_CLK
宏的标头,这可以为其正确地配置分频器外部接口。
您还需要稍微修正一下“接线”:
Platform.scala:
class PlatformIO(implicit val p: Parameters) extends Bundle { ...
坦率地说,寄存器链只是通过与源代码中的其他一些地方类似的方式添加的。 他们很可能应该防止亚稳 。 也许某些块已经有自己的保护,但是首先我想至少“高水平”运行。 对我来说更有趣的问题是,为什么MISO和MOSI挂在不同的dq
? 我仍然没有找到答案,但是似乎其余的代码都依靠这样的连接。
在物理上,我只是将设计结论分配给模块上的松动触点,然后将电压选择跳线重新排列为3.3V。
SD适配器顶视图:

底视图:

调试软件部分:工具
首先,让我们谈谈可用的调试工具及其限制。
迷你通
首先,我们需要以某种方式读取引导加载程序和内核输出。 为此,在Linux上(本例中为RaspberryPi上的一个),我们需要Minicom程序。 一般来说,适用于串行端口的任何程序均适用。
请注意,在启动时,必须在-D
选项之后将端口设备名称指定为-D /dev/ttyS0
。 好吧,主要信息:要退出,请使用Ctrl-A, X
我确实遇到了这种组合不起作用的情况-然后您可以从相邻的SSH会话中简单地说出killall -KILL minicom
。
还有另一个功能。 具体来说,RaspberryPi上有两个UART,并且两个端口都已经可以适应某种情况:一个用于蓝牙,另一个通过内核,默认情况下会显示内核控制台。 幸运的是,可以根据本手册重新配置此行为。
改写内存
在调试时,为了检验假设,有时我不得不直接从主机将引导加载程序 (抱歉) 加载到RAM中。 也许可以直接从GDB完成,但是最后我采用了一种简单的方法:我将必需的文件复制到Raspberry,还通过SSH发送了端口4444(来自OpenOCD的telnet)并使用了load_image
命令。 当您执行它时,似乎所有内容都被冻结了,但实际上“它不休眠,它只是缓慢闪烁” :它加载文件,它以每秒几千字节的速度运行。
安装断点的功能
可能,许多人在调试常规程序时不必考虑这一点,但是断点并不总是在硬件中设置的。 有时设置断点涉及直接在机器代码中临时将特殊指令临时写到正确的位置。 例如,这就是我在GDB中的标准b
命令的工作方式。 这是从中得出的结果:
- 你不能在BootROM里面放一点,因为ROM
- 您可以在从SD卡加载到RAM的代码上设置一个断点,但是需要等到它被加载后才能设置。 否则,我们将不会重写一段代码,但是加载器会重写我们的断点
我敢肯定,您可以明确要求使用硬件断点,但是无论如何它们数量有限。
快速BootROM交换
在调试的初始阶段,通常需要修复BootROM并重试。 但是有一个问题:BootROM是载入FPGA的设计的一部分,它的合成过程大约需要几分钟(这是在几乎立即从C和Assembler编译BootROM映像本身之后完成的)。 幸运的是,实际上,一切都快得多 :操作顺序如下:
- 重新生成bootrom.mif(我切换到MIF而不是HEX,因为使用HEX时我总是遇到一些问题,并且MIF是本机的Alter格式)
- 在Quartus中说
Processing -> Update Memory Initialization File
- 在汇编器上(在“任务”的左列中),再次命令“启动”
对于一切的一切-几十秒。
SD卡准备
这里的一切都相对简单,但是您需要耐心等待,并具有大约14Gb的磁盘空间:
git clone https://github.com/sifive/freedom-u-sdk git submodule update --recursive --init make
然后,您需要插入一个干净的,或者说不包含任何所需内容的SD卡,然后执行
sudo make DISK=/dev/sdX format-boot-loader
...其中sdX
是分配给卡的设备。 注意:卡上的数据通常会被删除,覆盖! 从sudo
下进行整个程序集几乎不值得,因为这样所有程序集工件将由root
拥有,并且程序集必须始终在sudo
下进行。
结果是在GPT中标记的卡分为四个部分,其中一个是带有uEnv.txt
FAT和一个FIT格式的可下载图像(它包含几个子图像,每个子图像都有自己的下载地址),另一部分为空白,应该在Ext4中格式化。对于Linux。 还有两个部分是神秘的 :U-Boot驻留在一个位置(据我所知,它的偏移量连接在BootROM中),另一方面,它的环境变量似乎处于活动状态,但我尚未使用它们。
一级,BootROM
民间智慧说:“在编程中,如果要用铃鼓跳舞,那么在电子产品中也要用灭火器跳舞。” 甚至还没有一次,我几乎烧毁了电路板,并确定“好,GND处于相同的低电平” (显然,电阻器仍然不会伤害...)更多的是,如果双手不会从那里伸出来,然后电子设备就不会停止带来惊喜:当我将连接器焊接到板上时,我仍然无法正常溶解触点-视频显示了焊料如何直接在整个连接中扩散,只需将烙铁放入,它就落在我身上无论如何。 好吧,也许焊锡不适合烙铁的温度,也许还有其他东西……总的来说,当我看到已经有十几个触点时,我吐口水并开始调试。 然后神秘的事情开始了:我从UART连接了RX / TX,我加载了固件-它写
INIT CMD0 ERROR
好吧,一切都是合乎逻辑的-我没有连接SD卡模块。 我们解决了这种情况,加载了固件……然后保持沉默……我只是没有改变主意,只是打开了棺材:必须将模块输出之一连接到VCC。 就我而言,该模块支持5V电源,因此,我三思而后行,将一根从模块延伸到板子另一侧的电线粘了起来。 结果,弯曲的焊接连接器扭曲了,而UART的触点完全丢失了。 facepalm.jpg一般来说,“头坏不能使腿得到休息”,而弯曲的手-头...
最后,我看到了期待已久的Minicom
INIT CMD0 CMD8 ACMD41 CMD58 CMD16 CMD18 LOADING /
而且, 它移动 加载指示灯正在旋转。 我直接回想起学年和从软盘轻松启动MinuetOS。 除非驱动器打磨。
问题是BOOT消息后什么也没发生。 因此,是时候通过Raspberry上的OpenOCD,主机上的GDB连接到它了,看看它是什么了。
首先,立即与GDB连接表明$pc
(程序计数器,当前指令的地址)飞到0x0
这可能是在多次错误之后发生的。 因此,在发出BOOT
消息后,立即添加无限循环。 这将使他延迟一会儿...
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; }
此类棘手的代码用于“可靠性”:我在某处听说,无限循环是未定义行为,在这里编译器不太可能猜测(我记得BootROM位于0x10000
)。

看起来,但还有什么期望-苛刻的嵌入式技术,那里有什么样的资源。 但是毕竟,在那篇文章中,作者调试了代码... 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.

仅您不需要加载MIF文件和bin文件,而是ELF格式的原始版本。
现在,通过第n次尝试猜测将继续执行的地址(这是编译器不应该猜测循环是无限的另一个原因)。 团队
set variable $pc=0xADDR
允许您随时更改寄存器的值(在这种情况下,是当前指令的地址)。 借助它的帮助,您可以更改记录在内存(和内存映射寄存器)中的值。
最后,我得出的结论(不确定什么是正确的)是,我们有一个“错误系统的sd卡映像”,我们不必走到下载数据的最开始,而是走0x89800
字节:
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
也许这还受到以下事实的影响:我手头没有多余的4Gb卡,我将其带到2Gb,然后将其替换为Makefile中的DEMO_END=11718750
, DEMO_END=3078900
(不要查找特定值的含义-它不存在,只是现在放置了图像卡)。
第二级,U-Boot
现在我们仍然在“下降”,但是我们已经在地址0x0000000080089a84
。 在这里,我不得不承认:实际上,演示文稿并没有“全力以赴”,而是部分地写在“之后”,因此在这里,我已经设法从SoC中放入正确的dtb文件,在HiFive_U-Boot
CONFIG_SYS_TEXT_BASE=0x80089800
调整CONFIG_SYS_TEXT_BASE=0x80089800
变量。 (而不是0x08000000
),以便下载地址与实际地址匹配。 立即下载 下一级地图 另一张图片:
(gdb) file ../freedom-u-sdk/work/HiFive_U-Boot/u-boot (gdb) tui en
我们看到:
│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) │
我们在第308行和第309行之间跳转。这并不奇怪,因为$sp
包含值0xfffffffe31cdc0a0
。 trap_entry
,由于307行,它也会不断“消失”。因此,我们将尝试在trap_entry
上设置一个断点,然后再次切换到0x80089800
(U-Boot入口点),我们希望它在过渡之前不需要正确设置寄存器...似乎有效:
(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
一般而言,让我们直言不讳地说堆栈指针:它通常指向RAM之外(当然,除非我们仍然有地址转换,但我们希望有一个简单的选择)。
让我们尝试将指针替换为0x881cf950
。 结果,我们得到一个事实,即调用并调用了_exit_trap
,而在_exit_trap
中_exit_trap
了参数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
我们在strnlen
上设置断点,继续查看:
(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
似乎_exit_trap
希望提供有关发生的异常的调试信息, 但是它失败 。 因此,带有我们源代码的内容不会再次显示。 set directories ../freedom-u-sdk/HiFive_U-Boot/
哦! 现在显示!
好吧,再次运行它,并在堆栈上查看导致第一个错误的原始问题的原因( mcause == 5
)。 如果我正确理解第37页的内容,则此异常表示Load access fault
。 显然是因为这里
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
具有相同的不正确值,并且board_init_f_init_reserve
内部发生错误。 罪魁祸首:一个显式名称为CONFIG_SYS_INIT_SP_ADDR
的变量。 它在文件HiFive_U-Boot/include/configs/HiFive-U540.h
。 在某个时候,我什至认为,或者也许很好,完成了处理器的引导程序-也许稍微修复一下处理器会更容易? 但是后来我看到,它更像是来自另一个内存配置不完全的#if 0
设置中的工件,您可以尝试执行以下操作:
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 */
在某个时候,数量 拐杖 技术紧固件达到了临界点。 经过一番折磨之后,我开始需要在板上放置正确的端口。 为此,您需要为我们的配置复制并更正一定数量的文件。
好吧,大概这是一张小桌子 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
详细信息可以在存储库中找到。
事实证明,在此SiFive板上,某些设备的寄存器具有不同的地址。 事实证明,U-Boot是由Linux内核已经熟悉的Kconfig机制配置的,例如,您可以命令make menuconfig
,您将看到一个方便的文本界面,带有参数说明,如?
所示?
等 通常,从两块板的描述中看不到第三块的描述,然后从那里扔掉任何可怜的PLL重新配置(显然,这与主机的PCIe控制有关,但这不准确),我得到了一些固件,如果在火星上天气合适的话它给了我一条UART消息,关于该消息是从哪个提交哈希中收集的,以及我有多少DRAM(但我也将此信息注册在了标头中)。
遗憾的是,此后主板通常停止对处理器JTAG的响应,而从SD卡下载的速度在我的配置中并不快。 另一方面,有时BootROM会显示一条ERROR
消息:无法启动ERROR
,并且U-Boot立即弹出。 那是我的曙光:显然,重新启动比特流后,FPGA中的内存没有磨损,没有时间“被撕毁”,等等。 简而言之,您可以简单地在出现LOADING /
消息时,连接调试器和命令set variable $pc=0x80089800
,从而绕过这种漫长的下载过程(当然,假设上次中断很早,并且没有时间在原始代码上下载)。
顺便说一句,通常情况是处理器完全挂起,并且带有消息的JTAG调试器无法连接到它,这是正常的。
Error: unable to halt hart 0 Error: dmcontrol=0x80000001 Error: dmstatus =0x00030c82
所以等等! 我已经看到了! - 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. 怎么了 , 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 — . 结果如何? ( ), :
... 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 , :
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-.
( ):
