RISC-V体系结构的U-Boot引导过程 第一阶段
flyfish
.globl _start
_start:
.globl使符号对链接器可见相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局变量,外部可以访问.u-boot.lds里的ENTRY(_start)也是这里的_start。
即指定入口为_start,_start就是整个start.S的开始的地方,是整个uboot的代码的开始
_start:表示其是一个标号Label,类似于C语言goto后面的标号
#if CONFIG_IS_ENABLED(RISCV_MMODE)
csrr a0, CSR_MHARTID
#endif
RISCV_MMODE 就是 machine mode
RISCV_SMODE就是supervisor mode
依据
choice
prompt "Run Mode"
default RISCV_MMODE
config RISCV_MMODE
bool "Machine"
help
Choose this option to build U-Boot for RISC-V M-Mode.
config RISCV_SMODE
bool "Supervisor"
help
Choose this option to build U-Boot for RISC-V S-Mode.
#define CSR_MHARTID 0xf14
执行该语句csrr a0, CSR_MHARTID
之后a0寄存器存储了hartid
依据下表
la t0, trap_entry
la t0, trap_entry
LA是Load Address,语法是LA rd, symbol
la指令的格式,将内存地址symbol加载到rd寄存器中
trap_entry 可以看mtrap.S
这里是将trap_entry加载到临时寄存器t0中
#include <common.h>
#include <asm/encoding.h>
#ifdef CONFIG_32BIT
#define LREG lw
#define SREG sw
#define REGBYTES 4
#else
#define LREG ld
#define SREG sd
#define REGBYTES 8
#endif
.text
/* trap entry */
.align 2
.global trap_entry
trap_entry:
addi sp, sp, -32 * REGBYTES
SREG x1, 1 * REGBYTES(sp)
SREG x2, 2 * REGBYTES(sp)
SREG x3, 3 * REGBYTES(sp)
SREG x4, 4 * REGBYTES(sp)
SREG x5, 5 * REGBYTES(sp)
SREG x6, 6 * REGBYTES(sp)
SREG x7, 7 * REGBYTES(sp)
SREG x8, 8 * REGBYTES(sp)
SREG x9, 9 * REGBYTES(sp)
SREG x10, 10 * REGBYTES(sp)
SREG x11, 11 * REGBYTES(sp)
SREG x12, 12 * REGBYTES(sp)
SREG x13, 13 * REGBYTES(sp)
SREG x14, 14 * REGBYTES(sp)
SREG x15, 15 * REGBYTES(sp)
SREG x16, 16 * REGBYTES(sp)
SREG x17, 17 * REGBYTES(sp)
SREG x18, 18 * REGBYTES(sp)
SREG x19, 19 * REGBYTES(sp)
SREG x20, 20 * REGBYTES(sp)
SREG x21, 21 * REGBYTES(sp)
SREG x22, 22 * REGBYTES(sp)
SREG x23, 23 * REGBYTES(sp)
SREG x24, 24 * REGBYTES(sp)
SREG x25, 25 * REGBYTES(sp)
SREG x26, 26 * REGBYTES(sp)
SREG x27, 27 * REGBYTES(sp)
SREG x28, 28 * REGBYTES(sp)
SREG x29, 29 * REGBYTES(sp)
SREG x30, 30 * REGBYTES(sp)
SREG x31, 31 * REGBYTES(sp)
csrr a0, MODE_PREFIX(cause)
csrr a1, MODE_PREFIX(epc)
csrr a2, MODE_PREFIX(tval)
mv a3, sp
jal handle_trap
csrw MODE_PREFIX(epc), a0
LREG x1, 1 * REGBYTES(sp)
LREG x3, 3 * REGBYTES(sp)
LREG x4, 4 * REGBYTES(sp)
LREG x5, 5 * REGBYTES(sp)
LREG x6, 6 * REGBYTES(sp)
LREG x7, 7 * REGBYTES(sp)
LREG x8, 8 * REGBYTES(sp)
LREG x9, 9 * REGBYTES(sp)
LREG x10, 10 * REGBYTES(sp)
LREG x11, 11 * REGBYTES(sp)
LREG x12, 12 * REGBYTES(sp)
LREG x13, 13 * REGBYTES(sp)
LREG x14, 14 * REGBYTES(sp)
LREG x15, 15 * REGBYTES(sp)
LREG x16, 16 * REGBYTES(sp)
LREG x17, 17 * REGBYTES(sp)
LREG x18, 18 * REGBYTES(sp)
LREG x19, 19 * REGBYTES(sp)
LREG x20, 20 * REGBYTES(sp)
LREG x21, 21 * REGBYTES(sp)
LREG x22, 22 * REGBYTES(sp)
LREG x23, 23 * REGBYTES(sp)
LREG x24, 24 * REGBYTES(sp)
LREG x25, 25 * REGBYTES(sp)
LREG x26, 26 * REGBYTES(sp)
LREG x27, 27 * REGBYTES(sp)
LREG x28, 28 * REGBYTES(sp)
LREG x29, 29 * REGBYTES(sp)
LREG x30, 30 * REGBYTES(sp)
LREG x31, 31 * REGBYTES(sp)
LREG x2, 2 * REGBYTES(sp)
addi sp, sp, 32 * REGBYTES
MODE_PREFIX(ret)
csrw MODE_PREFIX(tvec), t0
根据定义
#if CONFIG_IS_ENABLED(RISCV_SMODE)
#define MODE_PREFIX(__suffix) s##__suffix
#else
#define MODE_PREFIX(__suffix) m##__suffix
#endif
MODE_PREFIX(tvec)就是mtvec或者stvec
mtvec(Machine Trap Vector)
中断(interrupt)和异常(exception)在RISCV里被统称为trap
csrw MODE_PREFIX(ie), zero
机器模式中断使能控制寄存器(MIE)
机器模式中断使能控制寄存器(MIE)用于控制不同中断类型的使能和屏蔽。该寄存器的位长是 64 位,
寄存器的读写权限是机器模式可读写,即非机器模式访问都会导致非法指令异常。
MSIE-机器模式软件中断使能位:
• 当 MSIE 为 0 时,机器模式软件中断无效。
• 当 MSIE 为 1 时,机器模式软件中断有效
屏蔽所有中断。对于U-Boot,全局禁用中断(处于m/sstatus),但我们需要读取m/sip以确定是否获得IPI
MODE_PREFIX(ie) 就是mie或者sie
m/sstatus 表示mstatus和sstatus
mstatus表示Machine Status,M模式下的处理器状态寄存器
m/sip 表示 mip和sip
mip表示Machine Interrupt Pending, M模式下的中断待定寄存器
表示哪些中断处于待定(Pending,)状态
IPI,全称是Inter-Processor Interrupt,是在SoC内多个core之间触发的中断
li t0, CONFIG_NR_CPUS
bge tp, t0, hart_out_of_bounds_loop
缩写
Branch if equal (BEQ)
Branch if not equal (BNE)
Branch if less than (BLT)
Branch if less than unsigned (BLTU)
Branch if greater than equal (BGE)
语法
bge reg1, reg2, label # if reg1 >= reg2, branch to label
beq reg1, reg2, label # if reg1 == reg2, branch to label
bne reg1, reg2, label # if reg1 != reg2, branch to label
tp寄存器里是hart id,t0寄存器里是Maximum number of CPUs
如果 tp >=t0 跳转 到 hart_out_of_bounds_loop
bge blt rs1,rs2,imm 如果rs1 >= rs2(有符号方式),跳转
此处跳转到hart_out_of_bounds_loop
li是 Load Immediate
加载立即数
CONFIG_NR_CPUS
是预定义的,表示Maximum number of CPUs
CONFIG_NR_CPUS=32
或者
#define CONFIG_NR_CPUS 1
SMP, Symmetric Multi-Processor
#if CONFIG_IS_ENABLED(RISCV_MMODE)
li t0, MIE_MSIE
#else
li t0, SIE_SSIE
#endif
csrs MODE_PREFIX(ie), t0
#endif
根据条件编译 加载立即数 MIE_MSIE 还是SIE_SSIE到t0
SIE (Interrupt Enable)
SIP (Interrupt Pending)
#define MIE_MSIE (_AC(0x1, UL) << IRQ_M_SOFT)
#define SIE_SSIE (_AC(0x1, UL) << IRQ_S_SOFT)
#define IRQ_S_SOFT 1
#define IRQ_M_SOFT 3
_AC的意思
用于处理常量的宏
#ifdef __ASSEMBLY__
#define _AC(X,Y) X
#define _AT(T,X) X
#else
#define __AC(X,Y) (X##Y)
#define _AC(X,Y) __AC(X,Y)
#define _AT(T,X) ((T)(X))
#endif
在C语言里
#define CONNECT(x,y) x##y
表示连接
int n = CONNECT(12,34);
n的值是1234
RISC-V 程序计数器 (PC)程序计数寄存器(Program Counter Register)
RISC-V 引入了一个特殊的通用寄存器 X0 。
RISC-V 通用寄存器 X0 的的特性就是:读出来的值永远为 0 ,写入的值将会被丢弃
RISC-V 将 PC 单独拿出来作为一个特殊的寄存器来对待.
RISC-V 很多伪指令的实现都是通过 X0 通用寄存器与常用的普通指令相结合而实现的
每当完成取指令操作后,PC = PC + 1 这里的 +1 是增加【一条指令的长度 ÷ 寻址粒度】
初始堆栈指针地址
/*
* Set stackpointer in internal/ex RAM to call board_init_f
*/
call_board_init_f:
li t0, -16
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
li t1, CONFIG_SPL_STACK
#else
li t1, SYS_INIT_SP_ADDR
#endif
and sp, t1, t0 /* force 16 byte alignment */
加法指令
and and rd,rs1,rs2
将rs1寄存器的值 和 rs2寄存器的值相加,将结果写入到rd寄存器中
and sp, t1, t0
sp栈指针寄存的初始化
对于我们的初始堆栈指针地址,最常见的情况是,我们定义了一个静态初始RAM地址位置(CFG_SYS_INIT_RAM_ADDR)
和大小(CFG_SYS_INIT_RAM_SIZE)
,并从中减去生成的全局数据(GENERATED_GBL_DATA_SIZE)
大小。
#ifdef CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR
#define SYS_INIT_SP_ADDR CONFIG_CUSTOM_SYS_INIT_SP_ADDR
#else
#ifdef CONFIG_MIPS
#define SYS_INIT_SP_ADDR (CFG_SYS_SDRAM_BASE + CFG_SYS_INIT_SP_OFFSET)
#else
#define SYS_INIT_SP_ADDR \
(CFG_SYS_INIT_RAM_ADDR + CFG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
#endif
#endif
CONFIG_SPL_BUILD和CONFIG_SPL_STACK配置的情况下
不同的板子配置也是不同的
#define CONFIG_SPL_TEXT_BASE 0x60 /* sram start+header */
#define CONFIG_SPL_MAX_SIZE 0x5fa0 /* 24KB on sun4i/sun7i */
#define LOW_LEVEL_SRAM_STACK 0x00008000 /* End of sram */
#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK