启动引导代码

程序启动时先执行 start.S

start.S 中第一段程序

_start:
  /* clear bit in csr MSTATUS_MIE field to turn off global interrupt. */
  csrc CSR_MSTATUS, MSTATUS_MIE

    /* Jump to logical address first to ensure correct operation of RAM region  */
  la        a0, _start
  li        a1, 0x20000000

    /* test if this is boot on SRAM */
  bleu  a1, a0, _start0800

    /* test if this is boot on main Flash */
  srli  a1, a1, 2
  bleu  a1, a0, _start0800

    /* else must be boot on bootloader */
  la        a0, _start0800
  add       a0, a0, a1
  jr      a0

第一行 csrc CSR_MSTATUS, MSTATUS_MIE 分析, csrc 是 CSR 寄存器操作符之一:

Pseudoinstruction Base Instruction Meaning
csrr rd, csr csrrs rd, csr, x0 Read CSR
csrw csr, rs csrrw x0, csr, rs Write CSR
csrs csr, rs csrrs x0, csr, rs Set bits in CSR
csrc csr, rs csrrc x0, csr, rs Clear bits in CSR

CSR 寄存器全称为 Control and Status Registers


启动引导代码_第1张图片

启动引导代码_第2张图片

启动引导代码_第3张图片

而 MSTATUS 寄存器控制在机器模式下的状态

Field Bit Reset Value Description
MIE 3 0x00000000 表示全局中断使能,1 enable, 中断能够被正常响应;0 disable,中断被屏蔽
MPIE 7 0x00000000 表示全局中断使能,1 enable, 中断能够被正常响应;0 disable,中断被屏蔽
MPP 12:11 0x00000000 表示全局中断使能,1 enable, 中断能够被正常响应;0 disable,中断被屏蔽
FS 14:13 0x00000000 表示浮点单元的状态,0b00 All off; 0b01 initial; 0b10 Clean; 0b11 Dirty
XS 16:15 0x00000000 表示用户自定义的扩展单元状态
SD 31 0x00000000 只读,SD = (FS==0b11 || XS == 0b11)

因此第一行的含义为关闭全局中断

la a0, _start 将 _start 的地址装载到 a0 中
如果程序正常从 Flash 启动,a0 的值为 0x8000 XXXX

li a1, 0x20000000 将 a1 的值写为 0x2000 0000 (SRAM 地址)

bleu a1, a0, _start0800 判断是否从 SRAM 启动

srli a1, a1, 2
bleu a1, a0, _start0800 将 a1 右移后继续判断,这时判断是否从 Flash 启动

la a0, _start0800
add a0, a0, a1
jr a0 否则就是从 bootloader 启动

========


_start0800:
  /* set the the NMI base to share with mtvec by setting CSR_MMISC_CTL */
  li t0, 0x200
  csrs CSR_MMISC_CTL, t0

    /* initialize the mtvt */
  la t0, vector_base
  csrw CSR_MTVT, t0

    /* initialize and enable the mtvt2 */
  la t0, irq_entry
  csrw CSR_MTVT2, t0
  csrs CSR_MTVT2, 0x1

  /* initialize the CSR MTVEC for the Trap ane NMI base addr */
  la t0, trap_entry
  csrw CSR_MTVEC, t0

    #ifdef __riscv_flen
    /* enable FPU */
    li t0, MSTATUS_FS
    csrs mstatus, t0
    csrw fcsr, x0
    #endif

    /* for the code below, inline assembler options are used to produce
      ```
      auipc gp, %pcrel_hi(__global_pointer$)
      addi gp, gp, %pcrel_lo(__global_pointer$)
      ```
      instead of
      ```
      addi gp, gp, 0
      ```
      (https://sourceware.org/binutils/docs-2.31/as/RISC_002dV_002dDirectives.html#RISC_002dV_002dDirectives)
    */
    .option push
    .option norelax
    la gp, __global_pointer$
    .option pop

    la sp, _sp

    /* Load data section */
    la a0, _data_lma
    la a1, _data
    la a2, _edata
    bgeu a1, a2, LoopCopyDataInit

li t0, 0x200
csrs CSR_MMISC_CTL, t0 将 CSR_MMISC_CTL 的第九位设为 1

CSR_MMISC_CTL

Field Bit Reset Value Description
NMI_CAUSE_FFF 9 0x00000000 0: mnvec 的值为处理器 RESET 之后的 PC 地址,NMI 的 mcause.EXCCODE 为 0x1; 1: mnvec 的值与 mtvec 一致,NMI 的 mcause.EXCCODE 为 0xFFF

la t0, vector_base
csrw CSR_MTVT, t0 初始化中断向量,将地址装载到 CSR_MTVT 中

CSR_MTVT 用于保存 ECLIC 中断向量表的基地址,至少为 64byte 对齐

la t0, irq_entry
csrw CSR_MTVT2, t0
csrs CSR_MTVT2, 0x1 初始化 IRQ 入口地址,并打开 MTVT2

CSR_MTVT2 用于指定 ECLIC 非向量模式中断的 common-code 入口地址

Field Bit Reset Value Description
COMMON-CODE-ENTRY 31:2 common-code 地址
MTVT2EN 0 0 使能位,0: ECLIC 非向量模式中断 common-code 地址由 mtvec 决定;1: 0: ECLIC 非向量模式中断 common-code 地址由上面的地址位决定

la t0, trap_entry
csrw CSR_MTVEC, t0 仅配置异常的处理地址(中断的已在上面通过 MTVT & MTVT2 配置完成)

CSR_MTVEC 用于配置中断和异常处理程序的入口地址

Field Bit Reset Value Description
ADDR 31:6 mtvec 地址
MODE 5:0 控制中断处理模式 0b000011 为 ECLIC 模式;其他数值为 RISC-V 默认中断模式

再来说一下向量中断和非向量中断

向量中断发生时,处理器直接进行中断查表并跳转到相应地址,不保存上下文,因此中断处理函数必须是 Leaf-Function,即不能再调用其他的子函数。因为无需处理上下文,向量中断非常快

非向量中断发生时,处理器会先跳转到一段 common-code,执行上下文保存和正在 pending 中断的判断,按照中断优先级来处理,因此可以实现中断嵌套(即在处理一段中断时发生了更高优先级的中断,而跳转到新的中断处理)和中断咬尾(即几个中断顺序处理,切换之间无需恢复上下文),但时间开销较大

我们一般使用非向量中断

启动引导代码_第4张图片
image.png

你可能感兴趣的:(启动引导代码)