前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >opensbi下的riscv64裸机编程2(中断与异常)

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

作者头像
bigmagic
发布2021-01-08 11:37:15
2.2K0
发布2021-01-08 11:37:15
举报
文章被收录于专栏:嵌入式iot

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进行处理,这样可以大大的增加操作系统的灵活性。

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

2.1 CSPs

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

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

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

代码语言:javascript
复制
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提供中断向量表的基地址。

该寄存器的值是在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)

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

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

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)

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

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

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

2.2 异常开关的寄存器

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

Supervisor Interrupt Enable(sie)

Supervisor Interrupt Pending(sip)

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

  • 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的接口进行访问。

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

代码语言:javascript
复制
https://github.com/bigmagic123/riscv64_opensbi_baremetal/tree/master/03_interrupt

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

3.1 设置中断向量表

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

代码语言:javascript
复制
  .global table_val_set
table_val_set:
    la t0, trap_entry
    csrw stvec, t0
    jr ra

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

3.2 开启中断设置

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

所以只需要设置即可。

代码语言:javascript
复制
void enable_timer_interrupt(void)
{
  w_sie(r_sie() | SIE_STIE);
}

3.3 初始化timer

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

代码语言:javascript
复制
void set_timer(uint64 stime_value)
{
    SBI_TIMER(stime_value);
}

// get current time
uint64 get_cycle()
{
    return r_time();
}

void clock_set_next_event()
{
    set_timer(get_cycle() + TIMEBASE);
}

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

3.4 开启中断

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

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

代码语言:javascript
复制
void interrupt_enable(void)
{
    w_sstatus(r_sstatus() | SSTATUS_SIE);
}

3.5 中断处理

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

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

代码语言:javascript
复制
  .global trap_entry
trap_entry:
    csrr a0, scause
    csrrc a1, stval, zero
    csrr  a2, sepc
    mv    a3, s0
    /* scause, stval, sepc, sp */
    call  handle_trap

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

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

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

然后进入hande_trap

代码语言:javascript
复制
uintptr_t handle_trap(uintptr_t scause, uintptr_t stval, uintptr_t sepc, uintptr_t sp)
{
    tfp_printf("handle_trap %08lx:%08lx:%08lx:%08lx\n", scause, stval, sepc, sp);
    while (1);
    return 0;
}

4.测试及校验

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

代码语言:javascript
复制
%.o: %.c %.s
        $(CC) $(CFLAGS) -c $< -o $@

Makefile的语法规则基本

代码语言:javascript
复制
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的系统可以直接处理,这样比较简洁。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式IoT 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 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.总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档