RISC-V体系结构的U-Boot引导过程

news/2024/12/2 20:52:59/

RISC-V体系结构的U-Boot引导过程

flyfish

BootLoader

Boot是Bootstrap(鞋带)的缩写,它来自于一句谚语:“Pull oneself up by one’s own bootstraps”,直译的意思是“拽着鞋带把自己拉起来”
干这件事,得先问问牛顿行不行?牛爵爷也只是看一眼就忙着炼金去了。
早期计算机的启动,存在这样一个问题:必须先运行程序,然后计算机才能启动,但是计算机不启动就不能运行程序。为了解决这个问题人们把一小段程序先刷入ROM,通电后,第一件事就是读取它,之后计算机就能正常运行了。这个过程称为“拉鞋带”,简称为Boot。BootLoader是Boot和Loader两个单词的组合。Boot是引导,Loader是加载器。

当计算机上电时,开始的时候RAM里是没有操作系统的,因为操作系统,存放在比如硬盘、CD、DVD、Flash存储卡、U盘等
这些叫非易失性存储设备上,加电后计算机会首先执行ROM中的小程序,之后才会访问非易失性存储设备中的操作系统和数据,并将其加载到RAM中。

在嵌入式系统中整个系统的加载启动任务就完全由BootLoader来完成。BootLoader是CPU上电后运行的第一段程序,它的作用就是对嵌入式系统中的硬件进行初始化,创建内核需要的参数并将这些参数传递给内核,最终启动了操作系统内核,起到引导和加载内核的作用。PC上用的可以是BIOS这样的固件程序。可以看传递参数的一个例子。
在这里插入图片描述

一个 Boot Loader加上了universal就成了宇宙级的Boot Loader,全宇宙通用的Boot Loader就是U-Boot(Universal Boot Loader),U-Boot也只是BootLoader其中的一种,还是其他的例如

LILO(LInux LOader)
GRUB(GRand Unified Boot loader)
blob(blob bootloader)
RedBoot
vivi

如果看到了Bootstrap Loader或者 Bootstrap都是BootLoader的意思

RISC-V

RISC-V发音 RISC five
RISC-V是基于精简指令集计算(RISC)原理的开源指令集体系结构(ISA)。

ISA:instruction set architecture 指令集体系结构
RISC:reduced instruction set computing 精简指令集计算,有的地方写作 Reduced Instruction Set Computer
简单与复杂相对 Complex Instruction Set Computer

RISC-V的寄存器
U-Boot将使用gp保存指向全局数据的指针

x0: hard-wired zero (zero)
x1: return address (ra)
x2:	stack pointer (sp)
x3:	global pointer (gp)
x4:	thread pointer (tp)
x5:	link register (t0)
x8:	frame pointer (fp)
x10-x11:	arguments/return values (a0-1)
x12-x17:	arguments (a2-7)
x28-31:	 temporaries (t3-6)
pc:	program counter (pc)

U-Boot可以在M模式或S模式下运行,具体取决于它是否在提供SBI的固件初始化之前运行。固件在RISC-V引导过程中是必需的,因为它充当SEE来处理S模式U-Boot或操作系统的异常。

SBI:Supervisor Binary Interface,SBI是Supervisor(S模式操作系统)和Supervisor执行环境(SEE,Supervisor Execution Environment)之间的调用约定,其调用风格就像System call一样。OpenSBI是一个SBI实现,可以在不同的模式下与U-Boot一起使用。
OpenSBI:RISC-V Open Source Supervisor Binary Interface。
SEE:Supervisor Execution Environment

看下SBI的位置
在这里插入图片描述

M-mode U-Boot

<-----------( M-mode )----------><--( S-mode )-->
+----------+   +--------------+    +------------+
|  U-Boot  |-->| SBI firmware |--->|     OS     |
+----------+   +--------------+    +------------+

S-mode U-Boot

<-------------( M-mode )----------><----------( S-mode )------->
+------------+   +--------------+    +----------+   +----------+
| U-Boot SPL |-->| SBI firmware |--->|  U-Boot  |-->|    OS    |
+------------+   +--------------+    +----------+   +----------+

在这里插入图片描述

在引导阶段之间,hartid通过a0寄存器,设备树的起始地址通过a1寄存器。hart是RISC-V使用的术语,指的是硬件线程(RISC-V hardware thread )。hart通常在其他上下文中称为核(core)或CPU。

一般的多阶段启动

在这里插入图片描述

常用的多引导阶段

在这里插入图片描述

具有有关下一引导阶段的动态信息的OpenSBI固件

在这里插入图片描述

ZSBL:Zero Stage Boot Loader)
FSBL:First Stage Boot Loader,U-Boot SPL

在这里插入图片描述

M-mode : machine-mode
U-mode : user-mode
S-mode : supervisor-mode

u-boot.lds
buildroot/output/build/uboot-origin_master/u-boot.lds
ld就是The GNU linker
lds是The GNU linker script

ld为什么是linker呢,d哪里去了?
原文答案

意思是
Linux自带了自己的链接器,名为ld。(该名称实际上是“load”的缩写,而“loader”最初是在20世纪70年代Unix的第一个时代被称为链接器的名称.最初的操作系统中没有linker,都是操作系统loader干了所有的活。后来复杂了就有了linker,所以ld(loader)成了链接器的简写。

u-boot.lds内容

OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
OUTPUT_ARCH("riscv")
ENTRY(_start)
SECTIONS
{. = 0x42000000;. = ALIGN(4);.__image_copy_start : {*(.__image_copy_start)}.head :{arch/riscv/cpu/spare_head.o (.data*)}.text : {arch/riscv/cpu/start.o (.text)}.efi_runtime : {__efi_runtime_start = .;*(.text.efi_runtime*)*(.rodata.efi_runtime*)*(.data.efi_runtime*)__efi_runtime_stop = .;}.text_rest : {*(.text*)}. = ALIGN(4);.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }. = ALIGN(4);.data : {*(.data*)}. = ALIGN(4);.got : {__got_start = .;*(.got.plt) *(.got)__got_end = .;}. = ALIGN(4);.u_boot_list : {KEEP(*(SORT(.u_boot_list*)));}. = ALIGN(4);.efi_runtime_rel : {__efi_runtime_rel_start = .;*(.rel*.efi_runtime)*(.rel*.efi_runtime.*)__efi_runtime_rel_stop = .;}. = ALIGN(4);.image_copy_end : {*(.__image_copy_end)}/DISCARD/ : { *(.rela.plt*) }.rela.dyn : {__rel_dyn_start = .;*(.rela*)__rel_dyn_end = .;}. = ALIGN(4);.dynsym : {__dyn_sym_start = .;*(.dynsym)__dyn_sym_end = .;}. = ALIGN(4);ASSERT(. < 0x42000000 + 0x100000, "uboot size exceeds size limit")_end = .;.bss : {__bss_start = .;*(.bss*). = ALIGN(8);__bss_end = .;}
}

解释

OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")

输出可执行文件是elf格式, 64位riscv指令,小端
elf格式
在这里插入图片描述
大端 和 小端(Big-endian和Little-endian )
链接视图和执行视图

在这里插入图片描述
Section举例

.bss
.comment
.data
.data1
.debug
.dynamic
.dynstr
.dynsym
.fini
.got 
.hash 
.init 
.interp 
.line 
.note
.plt 
.relname 
.relaname
.rodata
.rodata1 
.shstrtab 
.strtab 
.symtab 
.text

ELF文件结构

ELF Header
Program Header Table
Sections
Section Header Table

在这里插入图片描述

OUTPUT_ARCH("riscv")

输出可执行文件的平台为riscv

ENTRY(_start)

输出可执行文件的起始代码段为_start

 . = 0x42000000;

指定可执行文件的全局入口点,地址是在0x42000000。

 .__image_copy_start : {*(.__image_copy_start)}

u-boot将自己copy到RAM,此为需要copy的程序的start

 . = ALIGN(4);

做完一件事之后,有可能4bytes不对齐了,所以看到多处ALIGN(4)

 .image_copy_end : {*(.__image_copy_end)}

u-boot自拷贝的数据完成了,包括的section有

.__image_copy_start
.head
.text
.efi_runtime
.text_rest
.rodata
.data 
.got 
.u_boot_list
.efi_runtime_rel
.image_copy_end

u-boot.map
从u-boot.map中可以查找地址 例如

image_copy_start	uboot copy的首地址
image_copy_end	        uboot copy的结束地址rel_dyn_start	.rel.dyn 段起始地址
rel_dyn_end	.rel.dyn 段结束地址bss_start	.bss 段起始地址
bss_end	        .bss 段结束地址

image_copy_start

                0x0000000042000000                . = 0x420000000x0000000042000000                . = ALIGN (0x4).__image_copy_start0x0000000042000000        0x0*(.__image_copy_start).__image_copy_start... ...

image_copy_end

... ...
.efi_runtime_rel0x00000000420c53a0        0x00x00000000420c53a0                __efi_runtime_rel_start = .*(.rel*.efi_runtime)*(.rel*.efi_runtime.*)0x00000000420c53a0                __efi_runtime_rel_stop = .0x00000000420c53a0                . = ALIGN (0x4).image_copy_end*(.__image_copy_end)

查看编译之后生成的u-boot文件
buildroot/output/build/uboot-origin_master/u-boot

ELF 头:Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 类别:                              ELF64数据:                              2 补码,小端序 (little endian)Version:                           1 (current)OS/ABI:                            UNIX - System VABI 版本:                          0类型:                              EXEC (可执行文件)系统架构:                          RISC-V版本:                              0x1入口点地址:               0x42000640程序头起点:          64 (bytes into file)Start of section headers:          10029872 (bytes into file)标志:             0x1, RVC, soft-float ABISize of this header:               64 (bytes)Size of program headers:           56 (bytes)Number of program headers:         2Size of section headers:           64 (bytes)Number of section headers:         27Section header string table index: 26程序头:Type           Offset             VirtAddr           PhysAddrFileSiz            MemSiz              Flags  AlignLOAD           0x0000000000001000 0x0000000042000000 0x00000000420000000x00000000000d6020 0x000000000010fa20  RWE    0x1000DYNAMIC        0x00000000000c4818 0x00000000420c3818 0x00000000420c38180x0000000000000110 0x0000000000000110  RW     0x8Section to Segment mapping:段节...00     .head .text .text_rest .rodata .dynstr .hash .gnu.hash .data .dynamic .got .u_boot_list .rela.dyn .dynsym .bss 01     .dynamic Dynamic section at offset 0xc4818 contains 13 entries:标记        类型                         名称/0x0000000000000004 (HASH)               0x420a18400x000000006ffffef5 (GNU_HASH)           0x420a21a00x0000000000000005 (STRTAB)             0x420a032c0x0000000000000006 (SYMTAB)             0x420d40d00x000000000000000a (STRSZ)              5391 (bytes)0x000000000000000b (SYMENT)             24 (bytes)0x0000000000000015 (DEBUG)              0x00x0000000000000007 (RELA)               0x420c53a00x0000000000000008 (RELASZ)             60720 (bytes)0x0000000000000009 (RELAENT)            24 (bytes)0x000000006ffffffb (FLAGS_1)            标志: PIE0x000000006ffffff9 (RELACOUNT)          25270x0000000000000000 (NULL)               0x0

根据链接文件u-boot.lds找到入口文件start.S
buildroot/output/build/uboot-origin_master/arch/riscv/cpu/start.S

......
#ifdef CONFIG_32BIT
#define LREG			lw
#define SREG			sw
#define REGBYTES		4
#define RELOC_TYPE		R_RISCV_32
#define SYM_INDEX		0x8
#define SYM_SIZE		0x10
#else
#define LREG			ld
#define SREG			sd
#define REGBYTES		8
#define RELOC_TYPE		R_RISCV_64
#define SYM_INDEX		0x20
#define SYM_SIZE		0x18
#endif.section .data
secondary_harts_relocation_error:.ascii "Relocation of secondary harts has failed, error %d\n".section .text
.globl _start
_start:
#if CONFIG_IS_ENABLED(RISCV_MMODE)csrr	a0, CSR_MHARTID
#endif/** Save hart id and dtb pointer. The thread pointer register is not* modified by C code. It is used by secondary_hart_loop.*/mv	tp, a0mv	s1, a1/** Set the global data pointer to a known value in case we get a very* early trap. The global data pointer will be set its actual value only* after it has been initialized.*/mv	gp, zero/** Set the trap handler. This must happen after initializing gp because* the handler may use it.*/la	t0, trap_entrycsrw	MODE_PREFIX(tvec), t0/** Mask all interrupts. Interrupts are disabled globally (in m/sstatus)* for U-Boot, but we will need to read m/sip to determine if we get an* IPI*/csrw	MODE_PREFIX(ie), zero#if CONFIG_IS_ENABLED(SMP)/* check if hart is within range *//* tp: hart id */li	t0, CONFIG_NR_CPUSbge	tp, t0, hart_out_of_bounds_loop/* set xSIE bit to receive IPIs */
#if CONFIG_IS_ENABLED(RISCV_MMODE)li	t0, MIE_MSIE
#elseli	t0, SIE_SSIE
#endifcsrs	MODE_PREFIX(ie), t0
#endif
......

命令

bootelf - Boot from an ELF image in memorybootp - boot image via network using BOOTP/TFTP protocoldhcp - boot image via network using DHCP/TFTP protocoldiskboot - boot from ide devicenboot - boot from NAND devicenfs - boot image via network using NFS protocolrarpboot - boot image via network using RARP/TFTP protocolscsiboot - boot from SCSI devicetftpboot - boot image via network using TFTP protocolusbboot - boot from USB device

参考
部分图片来自Western Digital Corporation or its affiliates.
https://www.thegoodpenguin.co.uk/blog/an-overview-of-opensbi/
https://github.com/riscv-software-src/opensbi
https://github.com/u-boot
https://linux-sunxi.org/U-Boot
https://u-boot.readthedocs.io/en/latest/


http://www.ppmy.cn/news/247834.html

相关文章

13.Linux创建快捷方式

在 Linux 中&#xff0c;创建快捷方式&#xff08;类似于 Windows 中的快捷方式&#xff09;可以使用 ln 命令实现。 ln 命令用于创建硬链接或软链接&#xff08;也称为符号链接&#xff09;&#xff0c;它将两个文件名链接在一起&#xff0c;这使得一个名称可以引用另一个名称…

PCIe 资料

pcie 编辑 PCI-Express(peripheral component interconnect express)是一种高速串行计算机扩展总线标准&#xff0c;它原来的名称为“3GIO”&#xff0c;是由英特尔在2001年提出的&#xff0c;旨在替代旧的PCI&#xff0c;PCI-X和AGP总线标准。PCIe属于高速串行点对点双通道高…

不会真的有人看不懂 Linux 小白都能看懂的大数据入门(一) 图文

一、概述 1.1 Linux的历史 操作系统&#xff0c;英语Operating System简称为OS。说道操作系统就需要先讲一讲Unix&#xff0c;UNIX操作系统&#xff0c;是一个强大的多用户、多任务操作系统&#xff0c;支持多种处理器架构&#xff0c;按照操作系统的分类&#xff0c;属于分时…

人工智能在游戏领域的应用

举围棋这个例子&#xff0c;非常简单的几条规则可以创造一个上下几千年的人们探索一生还远远无法穷尽的世界。对于更复杂的规则&#xff0c;有了AI的帮助&#xff0c;就更加神奇和伟大了。更何况AI还可以用来帮助创造新的世界&#xff0c;比如说游戏内容生成。 以后借助AI的力…

java非固态运行速度,终于知道为什么SSD会越用越慢,解决方法来了!

每当选购电脑时&#xff0c;你会发现&#xff0c;配置存储介绍总是不一样&#xff0c;要么纯固态(SSD)&#xff0c;要么纯机械&#xff0c;要么固态机械的组合硬盘。 两者的主要区别在于固态是半导体存储&#xff0c;机械则是电磁存储。固态硬盘最大读取速度在400-600MB/s&…

五分钟成为记忆王

一、记忆的面纱 1、记忆的含义 &#xff08;1&#xff09;就在我嘴边上  有多少次你这样说过&#xff0c;就在我嘴边上&#xff0c;又有过多少次在你需要什么时候&#xff0c;任凭你如何拼命地想&#xff0c;就是想不起来。  当然&#xff0c;这问题不是你一个人才有&…

30个接口自动化测试面试题,看过的已经在上班了

1. 什么是接口自动化测试&#xff1f; 答&#xff1a;接口自动化测试是指使用自动化工具对接口进行测试&#xff0c;验证接口的正确性、稳定性和性能等方面的指标。2. 为什么要进行接口自动化测试&#xff1f; 答&#xff1a;接口自动化测试可以提高测试效率&#xff0c;减少人…

HanLP Demo(学习笔记)

需求&#xff0c; 实习需要学习这个。感觉蛮好玩的..... 我是这样做的&#xff1a; 根据网上的资料&#xff0c;自己整理&#xff0c;因为是开源的&#xff0c;所以配合Demo理解&#xff0c;不是算法层次的,嗯&#xff0c;更新中.... data包没下载下来&#xff0c;家里这边…