RISCV——内核及汇编
小狼@http://blog.csdn.net/xiaolangyangyang
1、寄存器组(ABI)
2、异常及中断
XV6 trap(二)RISCV中断异常处理/定时器中断
- mie:中断开关
- mip:中断状态
- mstatus.mie:全局中断开关
RISCV异常及中断向量有两种方式:一是全部异常及中断使用同一个入口,二是使用向量表,D1s芯片使用的是第一种方式,全部异常及中断使用同一入口,再通过scause判断是异常还是中断,以及异常或中断编号,如下图所示:
3、特权模式
RISC-V特权模式与寄存器
4、启动代码分析
/* linker.ld */
/* 起始地址是0x27000 */SECTIONS
{/** 设置benos的加载入口地址为0x27000** 这里“.”表示location counter,当前位置*/. = 0x27000,/** 这里是第一个段text.boot,起始地址就是0x27000* 这个段存放了benos的第一条指令*/_text_boot = .;.text.boot : { *(.text.boot) }_etext_boot = .;/** text代码段*/. = ALIGN(8);_text = .;_stext = .;.text :{*(.text)}. = ALIGN(8);_etext = .;/** 只读数据段*/_rodata = .;.rodata : { *(.rodata) }_erodata = .;/** 数据段*/_data = .;.data : { *(.data) }_edata = .;/** bss段** ALIGN(8)表示8个字节对齐* bss_begin的起始地址以8字节对齐*/. = ALIGN(0x8);_bss = .;.bss : { *(.bss*) } _ebss = .;
}
/* boot.S */
/* 启动代码,需要设置SP指针 */.section ".text.boot".globl _start
_start:/* 关闭中断 */csrw sie, zerocall __init_uartcall print_asm/* 设置栈, 栈的大小为4KB */la sp, stacks_startli t0, 4096add sp, sp, t0/* 跳转到C语言 */tail kernel_mainprint_asm:/*此时SP栈空间还没分配,把返回地址ra保存到临时寄存器中*/mv s1, rala a0, boot_stringcall put_string_uart/*恢复返回地址ra*/mv ra, s1ret.section .data
.align 12
.global stacks_start
stacks_start:.skip 4096.section .rodata
.align 3
.globl boot_string
boot_string:.string "\r\nBooting at asm\r\n"
/* entry.S */
/* 主要定义了异常及中断入口 */#include "asm/asm-offsets.h"
#include "asm/csr.h".macro kernel_entryaddi sp, sp, -(PT_SIZE)sd x1, PT_RA(sp)sd x3, PT_GP(sp)sd x5, PT_T0(sp)sd x6, PT_T1(sp)sd x7, PT_T2(sp)sd x8, PT_S0(sp)sd x9, PT_S1(sp)sd x10, PT_A0(sp)sd x11, PT_A1(sp)sd x12, PT_A2(sp)sd x13, PT_A3(sp)sd x14, PT_A4(sp)sd x15, PT_A5(sp)sd x16, PT_A6(sp)sd x17, PT_A7(sp)sd x18, PT_S2(sp)sd x19, PT_S3(sp)sd x20, PT_S4(sp)sd x21, PT_S5(sp)sd x22, PT_S6(sp)sd x23, PT_S7(sp)sd x24, PT_S8(sp)sd x25, PT_S9(sp)sd x26, PT_S10(sp)sd x27, PT_S11(sp)sd x28, PT_T3(sp)sd x29, PT_T4(sp)sd x30, PT_T5(sp)sd x31, PT_T6(sp)csrr s1, sstatussd s1, PT_SSTATUS(sp)/*保存sepc*/csrr s2, sepcsd s2, PT_SEPC(sp)/*保存sbadaddr*/csrr s3, sbadaddrsd s3, PT_SBADADDR(sp)/*保存scause*/csrr s4, scausesd s4, PT_SCAUSE(sp)/*保存ssratch*/csrr s5, sscratchsd s5, PT_TP(sp)/*保存SP*/addi s0, sp, PT_SIZE sd s0, PT_SP(sp)
.endm.macro kernel_exitld a0, PT_SSTATUS(sp)csrw sstatus, a0ld a2, PT_SEPC(sp)csrw sepc, a2ld x1, PT_RA(sp)ld x3, PT_GP(sp)ld x4, PT_TP(sp)ld x5, PT_T0(sp)ld x6, PT_T1(sp)ld x7, PT_T2(sp)ld x8, PT_S0(sp)ld x9, PT_S1(sp)ld x10, PT_A0(sp)ld x11, PT_A1(sp)ld x12, PT_A2(sp)ld x13, PT_A3(sp)ld x14, PT_A4(sp)ld x15, PT_A5(sp)ld x16, PT_A6(sp)ld x17, PT_A7(sp)ld x18, PT_S2(sp)ld x19, PT_S3(sp)ld x20, PT_S4(sp)ld x21, PT_S5(sp)ld x22, PT_S6(sp)ld x23, PT_S7(sp)ld x24, PT_S8(sp)ld x25, PT_S9(sp)ld x26, PT_S10(sp)ld x27, PT_S11(sp)ld x28, PT_T3(sp)ld x29, PT_T4(sp)ld x30, PT_T5(sp)ld x31, PT_T6(sp)ld x2, PT_SP(sp)
.endm/*do_exception_vector必须4字节对齐否则写入stvec寄存器会不成功*/
.align 2
.global do_exception_vector
do_exception_vector:kernel_entrycsrw sscratch, x0la ra, ret_from_exceptionmv a0, sp /* pt_regs */mv a1, s4tail do_exceptionret_from_exception:restore_all:kernel_exitsret.global trigger_load_access_fault
trigger_load_access_fault:li a0, 0x100001ld a0, (a0)ret
5、调试
体验第一个程序
平头哥IP核C906的JTAG调试器DIY教程(一)
平头哥IP核C906的JTAG调试器DIY教程(二)
《T-HEAD+CPU调试技巧.pdf》
6、各特权态的指令
- 各个特权级都拥有的指令:
ECALL:U态陷入S态,S态陷入M态
EBREAK:产生断点异常
FENCE.I:产生一个内存读写屏障
SRET/URET:M太返回S态,S态返回U态
- S态引入的指令:
SFENCE.VMA:主要用于刷新页表
- M态引入的指令:
WFI:让当前处理器核心进入睡眠状态
7、各特权态的CSR
- CSR寄存器有自己的一套独立的地址空间,访问CSR需要使用专用的指令
- 每一个处理器核心都有自己一套独立的4K CSR,这4K CSR分别对应到4个特权态(U\S\V\M),对于每个特权态,最多有1024个CSR可使用
- 访问没有权限的CSR会Trap,访问不存在的CSR会Trap,写只读CSR会Trap,对于可选寄存器的操作会被忽略
【百问网DongshanPI-D1S开发板体验】2环境搭建
全志D1s开发板裸机开发之坏境搭建
DongshanPi-D1s快速上手 | 开发环境搭建
韦东山D1S板子——xfel工具无法烧写bin文件到spi norFlash问题解决
RISC-V 架构 - 精讲