RISCV基础开发(八)

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2021年8月21日10:05:55 评论 1,185

QEMU裸机开发之M模式中断设置

1. CSR寄存器操作

从本章节开始我们需要对CSR相关寄存器设置,所以将这些寄存器的读写访问封装成一些接口定义在“csr.h”中,这些接口基本都参考自xv6,如下所示。

RISCV基础开发(八)

2. 中断初始化

在可以使用中断和异常处理之前,需要进行一些设置,所以需要在“start.c”中添加中断初始化代码,如下所示。

#include "uart.h"
#include "csr.h"

// in kernel.ld.
extern char __stack_start[];

// in entry.S.
void machine_trap_entry(void);

static void machine_trap_init(void)
{
    //this stack is used for machine_trap_entry in entry.S
    mscratch_set((unsigned long)(__stack_start + 4096 * 2));

    // set the machine-mode trap handler.
    mtvec_set((unsigned long)machine_trap_entry);

    // enable machine-mode interrupts.
    mstatus_set(mstatus_get() | MSTATUS_MIE);

    // enable machine-mode timer and soft interrupts.
    mie_set(mie_get() | MIE_MTIE | MIE_MSIE);
}

void start(void)
{
    printf("%s %d.\r\n", __func__, __LINE__);

    machine_trap_init();
}

首先设置了m模式下的中断栈地址,“__stack_start”是定义在链接脚本中的,这个地址往上第二个4KB空间就是m模式中断和异常栈,RISCV架构不像arm那样每个模式都有自己的sp寄存器,所以先将栈地址保存在“mscratch”寄存器中,在实际发生中断和异常时,“mscratch”中保存的值会被软件取出并赋值给sp寄存器。

“mtvec_set”设置了中断和异常的处理地址,这个和arm架构后来提供的中断基址设置寄存器功能类似。通过“mstatus_set”使能了m模式的中断总使能位,类似arm中cpsr中的“F”位,这样cpu才能响应和处理中断。最后通过“mie_set”使能了定时器和核间中断,在本系列裸机学习中我们不关注中断控制器中断,所以这里只使能了这两个中断。

在初始化好了中断之后,我们还需要实现中断处理函数,这个在下一小节讲解。

3.中断处理

3.1 中断入口

在“entry.S”中,我们需要实现m模式中断和异常处理的入口,如下所示。

#
# machine-mode trap entry.
#
.globl machine_trap_entry
.align 4
machine_trap_entry:

    # mscratch holds mmode trap stack address,
    # swap current sp and mmode trap stack address
    csrrw sp, mscratch, sp

    // call the C trap handler in trap.c
    call machine_trap

    # restore old sp value
    csrrw sp, mscratch, sp

    mret

“machine_trap_entry”处理裸机也很简单,就是从“mscratch”中将事先保存的中断栈地址设置到sp寄存器中,然后调用c函数“machine_trap”进行具体的中断处理,结束后再恢复sp寄存器,最后通过“mret”指令退出中断处理函数。RISCV不像arm架构不会自动切换使用中断栈,所以这些工作都交给了软件开发者,另外这里简化了处理工作,在实际的系统中断处理函数中还需要保存通用寄存器等,这里为了说明中断基本处理原理,省去了这些操作。

3.2 中断C函数处理

m模式中断和异常c函数放在“trap.c”中,如下所示。

#include "uart.h"

// interrupts and exceptions from kernel code go here via machine_trap_entry.
void machine_trap(void)
{ 
    printf("%s %d.\r\n", __func__, __LINE__);
}

这里目前只添加了一条打印,用于表明确实进入了中断处理。

4. 测试

由于需要触发中断才能测试中断处理是不是真的被执行了,所以本章节只是准备好这些设置和处理,在下一章节中,通过核间中断来一起验证和测试。

5. 工程源码

链接:https://pan.baidu.com/s/1TnTYr7mywdKj5bxpdmWnyA,提取码:q772,见lesson3。

gewenbin
  • 本文由 发表于 2021年8月21日10:05:55
  • 转载请务必保留本文链接:http://www.databusworld.cn/10525.html
匿名

发表评论

匿名网友 填写信息

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