RISCV基础开发(三)

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2021年8月14日17:32:18 评论 3,023

中断和异常处理

在RISCV架构设计中,有一系列的控制和状态寄存器( Control and Status Registers)简称CSR,在三种特权级别下都有其对应的CSR,比如m模式下的命名都为mxxxx,s模式下的都为sxxxx等等。这些寄存器的作用类似于arm架构中的那些cp15寄存器,用于设置异常向量表、设置页表基址、获取异常信息等等。这些寄存器大多数都需要通过“csr”这类指令来进行访问,也有一部分寄存器是采用mmio映射的,可以使用普通访存指令访问,比如timer相关的寄存器(后面会讲)。这些寄存器比较重要的就是和中断异常相关的,下面我们来一起看看这些寄存器。

1. M模式下重要的CSR

M模式下的比较重要的寄存器如下所示,当然除了下图列出之外的寄存器,m模式下还有其他的一些寄存器,具体的请参考RISCV特权架构官方文档。

RISCV基础开发(三)

上图中的寄存器被分为四类,其中和Trap相关的寄存器比较重要,用于中断和异常处理:

  • 信息类:主要用于获取当前芯片id和cpu核id等信息。
  • Trap设置:用于设置中断和异常相关寄存器。
  • Trap处理:用于处理中断和异常相关寄存器。
  • 内存保护:作用类似于conterx-m中的mpu功能。

下面我们来着重介绍前三类寄存器。

1.1 Machine Information Registers

mvendorid、 marchid 和 mimpid 可以获取芯片制造商、架构和实现相关信息,最重要的还是 mhartid 这个寄存器,RISCV中每个cpu核都被称为一个hart,通过mhartid可以获取当前cpu核的id号。

1.2 Machine Trap Setup

在RISCV中,中断(interrupt)和异常(exception)被统称为trap。在arm中我们知道中断和异常是通过中断向量表中不同入口调用不同的处理函数处理的,但是在riscv中,所有中断和异常一般都是使用的同一个处理入口。在x86和arm下都存在中断向量表的概念,用于定义不同异常和中断的处理入口,但是在riscv下,一般是不存在中断向量表这个概念的,只存在trap处理入口这个概念。为了表述上的方便,后续的章节都将trap处理入口称为中断入口,但是要明白这个入口不仅仅是处理中断的,同时也是处理异常的入口。中断入口在m模式和s模式下都有专门的寄存器需要设置,在本小节我们只看m模式下的相关寄存器,在使用中断和异常处理之前需要进行一些设置,下面就来看看这些寄存器如何设置。

1.2.1 mtvec

mtvec寄存器全名为Machine Trap-Vector Base-Address Register,用于设置中断入口地址,其寄存器格式如下:

RISCV基础开发(三)

可以看出mtvec需要中断入口地址是4字节对齐的,因为最低两个bit是用于设置中断模式的,其模式定义如下:

RISCV基础开发(三)

  • Direct模式:所有的中断和异常使用同一个中断入口地址,一般都会设置为这种模式。
  • Vectored模式:所有异常使用同一个入口地址,但是不同的中断使用不同的入口地址。

1.2.2 mstatus

这个寄存器顾名思义是用来控制cpu核当前的一些状态信息的,比如全局中断使能等,寄存器的格式如下:

RISCV基础开发(三)

  • 红框内的位域用来控制全局中断的使能,SIE控制S模式下全局中断,MIE控制M模式下全局中断。这个有点像arm里cpsr中的F位,只是在RISCV架构下还分为S模式和M模式来控制,像但是不完全像。
  • 绿框里的位域用来记录发生中断之前MIE和SIE的值。SPIE记录的是SIE的值,MPIE记录的是MIE的值。
  • 蓝色框内位域用来记录当特权级别由低到高发生变化时(比如执行ecall指令),之前的特权级别。当变化后的特权级别是S模式时,SPP表示变化之前的特权级别是S模式还是U模式,所以只需要1位就可以表示;当变化后的特权级别是M模式时,MPP表示变化之前是S模式还是U模式还是M模式,由于有三种情况,所以需要使用2位来表示。
  • 注意:当发生中断时,SIE和MIE被硬件自动设置为0,用来屏蔽中断,这个行为和大部分架构都一样,同时MPIE和SPIE被硬件自动设置为MIE和SIE的值,如果特权级别还发生改变的话,之前的特权级别是记录在SPP或者MPP中的。当从中断中返回时,SIE和MIE被自动设置为MPIE和SPIE的值,同时MPIE和SPIE被自动设置为1,特权级别恢复为MPP或者SPP记录的级别,然后MPP或者SPP被设置为U模式。

1.2.3 mie

在RISCV下,将中断(interrupt)又细分为三种类型:定时中断(timer)、核间中断(soft)、中断控制器中断(external)。定时中断可以用于产生系统的tick,核间中断用于不同cpu核之间通信,中断控制器则负责所有外设中断。这个设计和arm下有点不一样,在arm多核下,架构中的定时器中断、核间中断和外设中断都是统一由中断控制器管理的,而在RISCV中定时器和核间中断是分离出来的,这两个中断被称为CLINT(Core Local Interrupt),而管理其他外设中断的中断控制器则被称为PLIC(Platform-Level Interrupt Controller)。每个核都有自己的定时器和产生核间中断的寄存器可以设置,这些寄存器的访问不同于其他的控制状态寄存器,采用的是MMIO映射方式访问,比如下图所示为SIFIVE FU540的CLINT寄存器表:

RISCV基础开发(三)

图中的msip用于产生m模式下的核间中断,mtime可以读取出当前计数器的值,mtimecmp用于设置比较值,当mtime的值增加到mtimecmp的值时就可以产生中断。这些寄存器的具体用法在后续的裸机程序编写章节会讲解,这里只需要简单了解即可。

上述讲解的三种中断类型在m模式和s模式下都有相应的中断使能位设置,这是通过mie寄存器实现的,mie寄存器的格式如下:

RISCV基础开发(三)

  • MSIE、MTIE、MEIE这三个位域分别控制m模式下核间中断、定时中断、中断控制器中断的使能状态。
  • SSIE、STIE、SEIE这三个位域分别控制s模式下核间中断、定时中断、中断控制器中断的使能状态。

1.2.4 medeleg 和 mideleg

RISCV下默认所有中断和异常都是在m模式下处理的,但是有些时候我们需要将中断和异常直接交给s模式处理,这就是RISCV中的中断托管机制。通过mideleg寄存器,可以将三种中断交给s模式处理,通过medeleg寄存器,可以将异常交给s模式处理。下面来具体看看这些寄存器格式。

当我们想把中断交给s模式处理时,我们可以设置mideleg寄存器,这个寄存器格式如下:

RISCV基础开发(三)

  • bit[1]用于控制是否将核间中断交给s模式处理。
  • bit[5]用于控制是否将定时中断交给s模式处理。
  • bit[9]用于控制是否将中断控制器管理的中断交给s模式处理。

注意对于核间中断和定时中断而言,即使使能了mideleg中对应的bit位,当产生相应中断时,还是先进入m模式进行处理,然后可以通过设置mip寄存器(下一小节讲解),在退出m模式中断时就可以进入s模式的中断处理函数中处理。

当我们想把异常交给s模式处理时,我们可以设置medelrg寄存器,这个寄存器格式如下:

RISCV基础开发(三)

可以看出来有很多异常是可以设置到s模式下处理的,但是实际使用时并不是所有异常都要交给s模式处理的,比如bit[9]代表的异常还是要交给m模式处理,因为像获取芯片id、cpu核id、设置timer等操作只能在m模式下进行,所以s模式通过SBI接口(后面会讲)使用“ecall”切换到m模式调用不同的服务,所以bit[9]代表的异常必须被m模式处理而不能交给s模式处理。

1.3 Machine Trap Handling

当产生中断或者异常时,会有一些信息保存在相应的寄存器中,下面我们就一起来看看这些寄存器。

1.3.1 mepc

在arm架构中,当发生中断或异常时,硬件自动将要返回的地址保存在lr寄存器中。类似的,在RISCV下产生中断或异常时,硬件自动将返回地址保存在mepc寄存器中,当在中断处理中返回时,硬件自动将mepc中的地址赋值给pc运行。

要注意的时,在RISCV架构中,当产生的时异常时,mepc中保存的是产生异常那条指令的地址,而不是其下一条指令地址,这么设计的原因是希望产生异常时,软件开发人员对相应异常做出处理,当处理完之后再次给一个运行之前产生异常指令的机会,比如缺页异常就是通过这种机制来运行的。当不需要再次运行产生异常那条指令时,需要在中断处理时手动将mepc的值加4,这样中断返回时就是运行产生异常那条指令的下一条指令。当产生的是中断时,mepc直接保存的就是被中断指令的下一条指令的地址,所以需要做修正。

1.3.2 mcause和mtval

当产生中断和异常时,mcause寄存器中会记录当前产生的中断或者异常类型,而mtval则针对某些异常会记录一些辅助信息。我们来看看mcause寄存器的格式:

RISCV基础开发(三)

寄存器的最高位用来表示产生的是中断还是异常,1表示中断0表示异常。剩下的位域表示中断或者异常的具体类型,如下所示:

RISCV基础开发(三)

可以看出来中断有6种类型,分别表示m和s模式下的定时、核间、中断控制器这三种中断,而异常的类型就比较多了。

1.3.3 mip

这个寄存器可以表明当前是否产生了某种中断,其格式如下所示。

RISCV基础开发(三)

  • MSIP表示m模式核间中断,此位只读,其状态反应的是CLINT中对应的核间中断设置寄存器最低位的状态,设置CLINT核间中断设置寄存器最低位为1则产生核间中断,置0则清除核间中断。
  • MTIP表示m模式定时中断,此位只读,其状态通过设置CLINT中对应的mtimecmp寄存器来清零。
  • MEIP表示m模式中断控制器中断,此位只读,其状态通过具体的中断控制器寄存器设置来清零。
  • SSIP表示s模式核间中断,此位在s模式只读(s模式下有sip寄存器,下面会讲),在m模式下可读写,通过设置此位,可以进入s模式核间中断处理。
  • STIP表示s模式定时中断,此位在m模式下可读写,通过设置此位,可以进入s模式定时中断处理。
  • SEIP表示s模式中断控制器中断,此位在m模式下可读写,通过设置此位,可以进入s模式中断控制器中断处理。

2. S模式下重要的CSR

S模式下的CSR寄存器大部分都和M模式下的类似,只不过是可以在s模式下进行访问而已。因为在m模式可以访问其他模式下的寄存器,在其他模式下只能访问他自己模式下的csr寄存器。S模式下的一些csr寄存器如下所示。

RISCV基础开发(三)

可以看出大部分的寄存器都和m模式下的类似,作用也是一样的,这里就不再赘述了。我们这里看一个m模式下没有的寄存器satp,这个寄存器是s模式下用来设置页表基址的,其格式如下。

RISCV基础开发(三)

  • PPN位域用于填写页表在内存中的物理基址。
  • ASID可以先不关心,当作都为0。
  • MODE位域用来选择是否开启页表,如果是64位还用来选择虚拟地址翻译的位数,如下:

RISCV基础开发(三)

如果是0 表示禁用页表翻译功能,64位架构下一般虚拟地址选用sv39。

gewenbin
  • 本文由 发表于 2021年8月14日17:32:18
  • 转载请务必保留本文链接:http://www.databusworld.cn/10468.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: