平头哥E90X的head.S分析

关闭中断

    /* disable interrupt */
    li t0, MR_MIE      --- t0=0x08
    csrc mstatus, t0   --- mstatus = mstatus | ~t0
    csrw mie, zero     --- mie = zero

mstatus第4bit清0,mie清0。

设置异常处理入口

    /* setup the address of exception handler */
    la      a0, risc_v_trap_handler
    ori     a0, a0, 3
    csrw    mtvec, a0

E90X异常和中断使用了CLINT和CLIC两个控制器,对于异常的服务程序入口函数有MTVEC寄存器指定,这里的异常指的是同步异常,这类异常没法屏蔽,通常是执行指令、取指令、非法内存访问等的异常。MTVEC寄存器的低2位,设置为3,表示使用模式3,该模式下CPU使用MTVEC[31:6]<<6作为异常(同步异常)的服务程序入口地址并跳转执行。

设置中断处理入口

    /* setup the address of vector interrupt handler */
    la      a0, interrupt_vectors
    csrw    mtvt, a0

当MTVEC的低两位设置MODE[1:0]=3时,CPU使用MTVEC[31:6]<<6作为异常(同步异常)的服务程序入口地址并跳转执行,而对于中断服务程序入口分两种情况,当使能了CLIC.CLICINTATTR中的shv域设置是否为硬件矢量中断,如果是硬件矢量中断,CPU首先使用MTVT+4*中断ID为地址,去取中断服务程序入口地址,并跳转到该入口地址执行,如果是非矢量中断,CPU使用MTVEC[31:6]<<作为中断服务程序入口地址并跳转执行。MTVT为矢量中断基址寄存器,在CLIC模式存在。在E907中MODE[1:0]硬件固定设置为3,软件不可设置。

中断向量表

.section .vectors, \"xx\", @progbits
    .balign 64
    .globl  clic_interrupt_vectors
    .type   clic_interrupt_vectors, @object
    clic_interrupt_vectors:
    .rept   (PLAT_CLIC_IRQ_CNT)
    .long   clic_interrupt_handler
    .endr
.text

这里默认设置为中断硬件矢量模式,所以需要注册向量表,但是这里向量表统一入口为clic_interrupt_handler。

清除BSS段

    # clear mscratch register.
    csrw   mscratch,zero

    /* Clear bss section */
    la      a0, __bss_start__
    la      a1, __bss_end__
    bgeu    a0, a1, 2f   --- 2f标签后面跟着一个字符(如f)是一种常见的命名约定,帮助区分不同类型的标签,这里暗示这是一个向前跳转的目标(forward jump target),如果a0>=a1,向前跳转到标签2的地方。
1:
    sw      zero, (a0)
    addi    a0, a0, 4
    bltu    a0, a1, 1b ---1bb也是一个标签,但与之前的2f不同,它指示了一个向后跳转(backward jump)的目标。这里的b后缀表明这是一个向后的跳转,意味着如果条件满足(即a0 < a1)

2:
   xxxx

上面的汇编代码的作用就是获取到bss段的起始地址,然后写入0;

设置栈SP

    /* setup stack pointer for C runtime environment */
    la      sp, __init_process_stack_end__

init_process_stack_end是在链接脚本中栈空间结束地址,这里直接复制为sp即可。