0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

opensbi下的riscv64裸机编程:中断与异常

嵌入式IoT 来源:嵌入式IoT 作者:嵌入式IoT 2021-01-07 10:30 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

opensbi下的riscv64裸机编程2(中断与异常)

1.本文说明

2.riscv特权模式下的异常

2.1 CSPs

2.2 异常开关的寄存器

2.3 与中断相关的指令

3.中断测试

3.1 设置中断向量表

3.2 开启中断设置

3.3 初始化timer

3.4 开启中断

3.5 中断处理

4.测试及校验

5.总结

1.本文说明

任何时候,中断和异常的产生都是十分值得关注的,这些将破坏程序原有的执行逻辑。按照芯片的设计来说,中断和异常大致上可以分为三类异常(Exception)、陷入(Trap)、外部中断(Interrupt)。

异常(Exception)

在一条指令执行的过程中发生了错误,可以通过异常处理函数进行处理,最常见的异常包括无效的内存地址访问、非法指令异常、缺页异常等等。当发生这些异常后可以进行处理。

陷入(Trap)

主动的让其进入异常处理函数,常见的是系统调用syscall。而在riscv上为ecall或者进入断点的ebreak。

外部中断(Interrupt)

一般由外部事件触发,比如定时器中断、GPIO中断等。这些异常是不可预知的。

对于一般的中断处理流程,进入中断后需要进行上下文的保存与恢复。

2.riscv特权模式下的异常

涉及到中断和异常,RISCV的特权模式是不能绕开的。在RISCV中,无论在任何模式发生的异常,硬件线程都会将控制权交给M-Mode的异常处理程序。然而对于类Unix的操作系统来说,异常都是由操作系统来处理。而操着系统运行的模式是S-Mode,所以RISCV也可以选择将异常重新导向到S-Mode,也支持异常委托机制(Machine Interrupt Delegaintion)将异常直接通过S-Mode进行处理,这样可以大大的增加操作系统的灵活性。

33788338-5074-11eb-8b86-12bb97331649.png

一般来说M-Mode是必须实现的,S-Mode也一般会有,而U-Mode是选择性扩展的。目前的RISCV芯片中例如蜂鸟的E203与K210都只支持了RISCV架构中的Machine Mode。

2.1 CSPs

实际上RISCV在实现系统指令集的时候,是支持多种模式的扩展的,这一系列的指令集通过Control and Status Registers (CSRs)来进行控制。

CSR地址是扩展了12位,也就是可以设计最大4096个指令。

33cd0dae-5074-11eb-8b86-12bb97331649.png

通过下面的网站可以看到当前CSRs的实现状态。

http://www.five-embeddev.com/quickref/csrs.html

这里只针对S-Mode下的异常处理进行分析,M-Mode下的异常处理类似。

Name Number Feature/Extensions Description
sepc 0x0141 supervisor Supervisor Exception Program Counter
scause 0x0142 supervisor Supervisor Exception Cause
stval 0x0143 supervisor Supervisor bad address or instruction.
stvec 0x0105 supervisor Supervisor Trap Vector Base Address
sstatus 0x0100 supervisor Supervisor Status

Supervisor Exception Program Counter (sepc)

当中断发生时,存放需要跳转的PC值。这里需要利用stvec提供中断向量表的基地址。

341d7fc8-5074-11eb-8b86-12bb97331649.png

该寄存器的值是在32位下是4字节对齐的。

Supervisor Cause Register (scause)

该寄存器表示中断发生的原因。下面的表格中表述了中断的发生原因:

Interrupt Exception Code Description
1 0 Reserved
1 1 Supervisor software interrupt
1 2–4 Reserved
1 5 Supervisor timer interrupt
1 6–8 Reserved
1 9 Supervisor external interrupt
1 10–15 Reserved
1 ≥16 Designated for platform use
0 0 Instruction address misaligned
0 1 Instruction access fault
0 2 Illegal instruction
0 3 Breakpoint
0 4 Load address misaligned
0 5 Load access fault
0 6 Store/AMO address misaligned
0 7 Store/AMO access fault
0 8 Environment call from U-mode
0 9 Environment call from S-mode
0 10–11 Reserved
0 12 Instruction page fault
0 13 Load page fault
0 14 Reserved
0 15 Store/AMO page fault
0 16–23 Reserved
0 24–31 Designated for custom use
0 32–47 Reserved
0 48–63 Designated for custom use
0 ≥64 Reserved

Supervisor Trap Value (stval) Register

由于scause不足以表示异常发生的所有信息,比如发生了缺页异常,就会将stavl设置成需要访问但是不在内存中的地址。以便于操作系统将这个地址加载进来。

Supervisor Trap Vector Base Address Register (stvec)

设置中断处理的基地址,同时设置模式

345c5ce8-5074-11eb-8b86-12bb97331649.png

对于基地址的模式有如下两种:

Value Name Description
0 Direct All exceptions set pc to BASE.
1 Vectored Asynchronous interrupts set pc to BASE+4×cause.
≥2 Reserved

Direct:顾名思义,当异常发生的时候,每次都会跳转到这个地址,然后通过这个地址的中断处理程序去判断哪种中断。

Vectored:在这种模式下,会跳转到BASE + 4 * cause 进行处理流程。每种异常的cause都不一样。

Supervisor Status Register (sstatus)

控制中断的状态等等,也可以控制全局中断的时能等等。

351940c4-5074-11eb-8b86-12bb97331649.png

SIE域表示全局中断使能。当该MIE域值为1时,表示所有中断的全局开关打开,当MIE域的值为0时候,表示全局关闭所有中断。

SPIE用于保存进入异常之前MIE域的值。

2.2 异常开关的寄存器

对于S-Mode中断的Enable与Pending,还需要关注两个寄存器。sie与sip。

Supervisor Interrupt Enable(sie)

353dac16-5074-11eb-8b86-12bb97331649.png

Supervisor Interrupt Pending(sip)

358046fc-5074-11eb-8b86-12bb97331649.png

可以看到有三种类型的中断,由芯片厂家进行自定义设计。

Supervisor software interrupt

Supervisor timer interrupt

Supervisor external interrupt

2.3 与中断相关的指令

CSR Read Write(csrrw)

csrrw dst, csr, src:将指定的CSR寄存器写入dst,同时将src的值写入CSR。

CSR Read(csrr)

csrr dst,csr:读一个CSR寄存器到dst。

CSR Clear(csrc)

csrc(i) csr, rs1:将指定的位清零。

CSR Set(csrs)

csrs(i) csr, rs1:将指定的位置一。

3.中断测试

由于在qemu上,中断的产生可以通过定时器来发生,所以需要理解riscv上对timer的使用。timer又需要通过sbi的接口进行访问。

相关的代码文件可以参考:

https://github.com/bigmagic123/riscv64_opensbi_baremetal/tree/master/03_interrupt

已经实现了timer中断的产生过程。

3.1 设置中断向量表

本程序需要设置中断向量表,前面提到过,中断向量的跳转有两种模式:Direct与Vectored。Direct可以直接转到固定的pc地址,然后由统一的入口进行处理,这种比较容易实现,所以设置为这种模式。

.globaltable_val_set table_val_set: lat0,trap_entry csrwstvec,t0 jrra

直接将trap_entry函数的入口写到stvec的寄存器中。由于函数地址4字节对其,所以设置后模式为Direct。

3.2 开启中断设置

要开启时钟中断,这样才能产生时钟,而根据手册,开启时钟中断实际上是设置Supervisor Interrupt Enable(sie),也就是设置SIE的寄存器开启。

353dac16-5074-11eb-8b86-12bb97331649.png

所以只需要设置即可。

voidenable_timer_interrupt(void) { w_sie(r_sie()|SIE_STIE); }

3.3 初始化timer

对于timer的填充,其实就是设置中断的值。当timer达到设定的值后会产生中断。

voidset_timer(uint64stime_value) { SBI_TIMER(stime_value); } //getcurrenttime uint64get_cycle() { returnr_time(); } voidclock_set_next_event() { set_timer(get_cycle()+TIMEBASE); }

函数填充了下一个tick的值。

3.4 开启中断

中断的开启通过sstatus全局的状态寄存器设置。

351940c4-5074-11eb-8b86-12bb97331649.png

通过设置SIE位就可以达到使能或者关闭中断的作用。

voidinterrupt_enable(void) { w_sstatus(r_sstatus()|SSTATUS_SIE); }

3.5 中断处理

中断处理需要保存当前的上下文寄存器(寄存器压栈操作),然后跳转到中断处理函数去处理具体的中断。当处理完成之后返回现场(寄存器出栈)。

这里先不做这么复杂的工作,中断产生后直接跳转到中断处理函数中,只执行一次。

.globaltrap_entry trap_entry: csrra0,scause csrrca1,stval,zero csrra2,sepc mva3,s0 /*scause,stval,sepc,sp*/ callhandle_trap

其中a0为第一个参数,保存中断发生的原因。

a1是中断发生的具体信息。

a2表示了中断异常返回值。

然后进入hande_trap。

uintptr_thandle_trap(uintptr_tscause,uintptr_tstval,uintptr_tsepc,uintptr_tsp) { tfp_printf("handle_trap%08lx:%08lx:%08lx:%08lx ",scause,stval,sepc,sp); while(1); return0; }

4.测试及校验

因为工程文件的增加,所以使用了Makefile进行工程的构建工作。

%.o:%.c%.s $(CC)$(CFLAGS)-c$< -o $@

Makefile的语法规则基本

TARGET…:DEPENDENCIES… COMMAND

这里也不过多的涉及了。

输入make后,在fw_bin目录下执行run.sh脚本即可。

最后可以看到中断的原因

最高位是8,相应的中断描述为Supervisor timer interrupt。

5.总结

riscv的异常和中断的处理模式在M-Mode或者S-Mode下都可以设计,具体要看芯片的设计方式,如果设计在M-Mode,对于操作系统来说,可以通过转发或者代理给S-Mode的操作系统,如果S-Mode存在中断处理,那么处于S-Mode的系统可以直接处理,这样比较简洁。

责任编辑:xj

原文标题:opensbi下的riscv64裸机编程2(中断与异常)

文章出处:【微信公众号:嵌入式IoT】欢迎添加关注!文章转载请注明出处。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程
    +关注

    关注

    90

    文章

    3707

    浏览量

    96764
  • 裸机
    +关注

    关注

    0

    文章

    41

    浏览量

    6908
  • RISC-V
    +关注

    关注

    48

    文章

    2792

    浏览量

    51902

原文标题:opensbi下的riscv64裸机编程2(中断与异常)

文章出处:【微信号:Embeded_IoT,微信公众号:嵌入式IoT】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【CIE全国RISC-V创新应用大赛】+MUSE Pi Pro RiscV UEFI固件开发

    /edk2-non-osi 1.4 RiscV64工具链的前缀定义 为RiscV64工具链指定前缀变量,参考如下命令: #define RISCV64 prefix export
    发表于 11-13 00:20

    riscv底层原理分析gd32vf103的中断行为

    riscv底层原理分析gd32vf103的中断行为 1.概述 2.中断向量表初始化 3.详细分析一irq_entry 4.关于gd32vf103
    发表于 10-31 08:04

    全志D1开发板(哪吒 RISCV64)开箱评测

    riscv的生态建设远远没有arm强大,但是也在开源思想的引领,开始逐步走向大众的视野。 这块哪吒 RISCV64的板子,从主要的核的特性上来看,与目前市面上可见的riscv开发板相
    发表于 10-31 07:50

    riscv实现自定义指令并用qemu运行

    利用qemu模拟硬件平台,实现特定指令解析,同时写裸机代码来测试该指令的运行情况。当然,如果实现的很好,是需要修改riscv的gcc的,让自己的扩展指令加入。这里不做修改,后面会详细描述细节。 自定义
    发表于 10-31 07:37

    d1哪吒开发板的启动流程分析

    需要理解的是fel模式对SRAM,DDR等操作,这样在做裸机开发的时候,才能将程序下载进去。有了这些理解,在做riscv的底层编程的时候,才能透彻的理解其启动的流程和原理。
    发表于 10-29 06:44

    用哪吒D1开发板体验riscv向量底层编程

    RISCV V扩展即向量指令扩展(RVV),这部分作为研究AI加速计算领域有着非常关键的作用。既然的D1支持了rvv扩展(0.7.1,最新的版本已经0.10版本),那么就实际的从底层原理角度分析一
    发表于 10-29 06:21

    riscv virt64编译后 ls无法运行怎么解决?

    用仓库里的默认配置编译qemu-virt64-riscv 生成后运行,显示 [E/DBG] virtio-blk0 mount failed ls看不到文件夹 msh />ls No such directory
    发表于 09-22 06:38

    求助,关于K230启动流程疑问求解

    ) (riscv64-unknown-linux-gnu-gcc (Xuantie-900 linux-5.10.4 glibc gcc Toolchain V2.6.0 B-20220715) 10.2.0
    发表于 07-11 06:42

    【Milk-V Duo S 开发板免费体验】2 - 安装编译环境并测试Hello world!

    ARM64 2. RISCV64 Which would you like: 我使用的是 RISCV 系统,则选择 2。 这个脚本会克隆GitHub - milkv-duo/host-tools,不过只有
    发表于 07-07 21:18

    【Milk-V Duo S 开发板免费体验】应用开发环境搭建

    选择 2。 由于 DuoS 支持 RISCV 和 ARM 两种架构,还需要按提示继续选择: Select Arch: 1. ARM64 2. RISCV64 Which would you like
    发表于 07-01 21:22

    【M-K1HSE开发板免费体验】超高性能与颜值RISCV64位8核视美泰M-K1HSE开发板

    【超高性能与颜值RISCV64位8核视美泰M-K1HSE开发板】 https://www.bilibili.com/video/BV1dQKZzsERi/?share_source
    发表于 06-26 23:14

    请问Openvino是否支持 Risc-V (riscv64) 架构?

    在spacemit k1型板(bpi-f3)上编译OpenVINO™,但失败。 使用 riscv64 构建OpenVINO™并崩溃。
    发表于 06-24 07:26

    AS32X601驱动系列教程 PLIC_中断应用详解

    进一步加深一使用过程。 回顾之前的启动文件章节,有如下一段代码: 在RISCV指令集中,在机器模式中断
    的头像 发表于 05-23 17:10 525次阅读
    AS32X601驱动系列教程 PLIC_<b class='flag-5'>中断</b>应用详解

    在starvision2上移植FreeRTOS,objdump后发现static变量的地址是0,怎么解决?

    truncated to fit: R_RISCV_HI20 against `TaskBnum.5' (这个main.c是我从一个移植教程里面偷来的) 我查了一,说可能是
    发表于 03-10 07:21

    基于OpenSBI的linux nommu实现

    Linux内核6.10提供了对没有mmu的riscv处理器工作在S模式的内核的支持,本文介绍基于OpenSBI的linuxnommu的实现,供大家参考。1、OpenSBI介绍SBI
    的头像 发表于 02-08 13:43 1054次阅读
    基于<b class='flag-5'>OpenSBI</b>的linux nommu实现