RISC-V体系结构的U-Boot引导过程 第一阶段

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后面的标号

RISC-V体系结构的U-Boot引导过程 第一阶段_第1张图片

#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
依据下表
RISC-V体系结构的U-Boot引导过程 第一阶段_第2张图片

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 
#include 

#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
RISC-V体系结构的U-Boot引导过程 第一阶段_第3张图片

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之间触发的中断
RISC-V体系结构的U-Boot引导过程 第一阶段_第4张图片

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

你可能感兴趣的:(嵌入式深度学习,risc-v,flyfish,riscv,uboot)