从零手写操作系统之RVOS外设中断实现-04

这篇具有很好参考价值的文章主要介绍了从零手写操作系统之RVOS外设中断实现-04。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


本系列参考: 学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春 整理而来,主要作为xv6操作系统学习的一个前置基础。

RVOS是本课程基于RISC-V搭建的简易操作系统名称。

课程代码和环境搭建教程参考github仓库: https://github.com/plctlab/riscv-operating-system-mooc/blob/main/howto-run-with-ubuntu1804_zh.md

前置知识:

  • RVOS环境搭建-01
  • RVOS操作系统内存管理简单实现-02
  • RVOS操作系统协作式多任务切换实现-03
  • RISC-V 学习篇之特权架构下的中断异常处理

RISC-V 中断(Interrupt)的分类

从零手写操作系统之RVOS外设中断实现-04


RISC-V Trap (中断)处理中涉及的寄存器

从零手写操作系统之RVOS外设中断实现-04


寄存器 mie、mip

mstatus寄存器中的MIE位用于控制全局中断是否开启,而mie作为次级中断控制寄存器,用于在全局中断打开的情况下,控制某个具体的中断类型是否开启:
从零手写操作系统之RVOS外设中断实现-04
mip寄存器用于告诉我们是否发生了某类中断。


中断处理流程

  • 中断发生时 Hart 自动执行如下状态转换
    从零手写操作系统之RVOS外设中断实现-04
  • 退出中断 :编程调用 MRET 指令

从零手写操作系统之RVOS外设中断实现-04


PLIC 介绍

外部中断(external interrupt )

我们的外设想要和CPU进行通信,就需要通过中断的方式进行通信,那么考虑到外设的可插拔性,我们需要做好中断信号的转换和汇聚处理:
从零手写操作系统之RVOS外设中断实现-04


PLIC

中断信号转换和汇聚的工作由PLIC完成,也就是中断平台控制器:
从零手写操作系统之RVOS外设中断实现-04
PLIC 是 “Platform-Level Interrupt Controller” 的缩写,它是一种用于处理中断的硬件模块,常用于处理器系统中。PLIC 负责管理和分发各种中断信号,并将它们传递给适当的处理器核心或其他设备。

PLIC 的主要功能包括:

  1. 中断管理:PLIC 能够接收来自不同外设的中断请求,并为每个中断分配一个唯一的中断号。
  2. 中断优先级:PLIC 支持设置中断优先级,以确保高优先级的中断能够及时响应。
  3. 中断分发:根据中断的优先级和目标处理器核心的可用性,PLIC 将中断请求分发给适当的处理器核心。
  4. 中断确认和清除:当处理器核心接收到中断时,PLIC 负责确认中断并在中断处理完成后清除中断状态。

PLIC 在大型多核处理器系统中特别有用,因为它可以协调多个处理器核心之间的中断处理。每个处理器核心可以向 PLIC 注册其中断处理程序,并通过 PLIC 获取适当的中断。

PLIC 的具体实现和配置取决于具体的处理器架构和系统设计。在 RISC-V 架构中,PLIC 是标准的中断控制器,用于处理中断请求和分发。在某些 SOC 中,例如 FU540-C000,PLIC 是其中的一部分,用于管理系统中的中断。


PLIC Interrupt Source

从零手写操作系统之RVOS外设中断实现-04
PLIC(Platform-Level Interrupt Controller)中的中断源是指可以触发中断请求的硬件设备或其他事件。每个中断源都有一个唯一的标识符或中断号,用于在 PLIC 中进行识别和管理。

PLIC 中的中断源可以是各种外设或模块,例如:

  1. 定时器:定时器可以生成周期性的中断请求,用于实现定时功能。
  2. 外部设备:外部设备(如串口、网络控制器、GPIO 等)可以触发中断请求,通知处理器有数据可用或事件发生。
  3. 总线错误:当在总线上发生错误时,例如内存访问错误或设备通信错误,可以生成中断请求来通知系统。
  4. 异常和故障:处理器内部的异常或故障条件,例如除以零、内存访问异常等,也可以作为中断源。

在 PLIC 中,每个中断源都被分配一个唯一的中断号,这些中断号用于识别和区分不同的中断源。当某个中断源产生中断请求时,PLIC 根据中断号和优先级确定中断的处理顺序,并将中断请求发送给适当的处理器核心。

具体的 PLIC 中断源数量和配置取决于处理器架构和 SOC 设计。在 FU540-C000 等特定 SOC 中,具体的中断源和中断号分配可能会有所不同。

上图显示的串口设备的中断源为10

中断源–>中断号—>中断向量–>中断服务程序(ISR)–>中断返回


PLIC 编程接口 - 寄存器

从零手写操作系统之RVOS外设中断实现-04
从零手写操作系统之RVOS外设中断实现-04

  • 优先级寄存器的作用就是根据其设置的优先级级别,确定中断的处理顺序。通过设置不同中断源的优先级,可以在处理多个中断时,确保高优先级的中断得到及时处理,提高系统的响应性能。
  • 举一个简单的例子,假设系统有两个中断源:定时器中断和串口中断。定时器中断的处理优先级设置为高,串口中断的处理优先级设置为低。
  • 如果定时器中断和串口中断同时发生,由于定时器中断的优先级高于串口中断,系统会首先处理定时器中断。

从零手写操作系统之RVOS外设中断实现-04
从零手写操作系统之RVOS外设中断实现-04
从零手写操作系统之RVOS外设中断实现-04
从零手写操作系统之RVOS外设中断实现-04
在PLIC(Platform-Level Interrupt Controller)中,"claim"寄存器和"complete"寄存器是用于处理中断请求和中断完成的寄存器。

  1. Claim寄存器(claim register):用于处理中断请求。每个处理器核心在PLIC中有一个claim寄存器。当处理器核心准备处理中断时,它会读取claim寄存器,以获取待处理的中断源(interrupt source)。当处理器核心读取claim寄存器时,PLIC会将最高优先级的未处理中断源的标识位设置为1,并将中断源的ID(interrupt ID)写入claim寄存器。这样,处理器核心就可以知道要处理的中断源是哪一个,并将其从PLIC中“claim”(申请)出来。

  2. Complete寄存器(complete register):用于处理中断完成。每个处理器核心在PLIC中有一个complete寄存器。当一个处理器核心完成对某个中断源的处理后,它会将中断源的ID写入complete寄存器,PLIC会更新中断的状态,并将该中断标记为已完成。这意味着该中断不再是待处理状态,而是已经处理完毕。然后,PLIC会继续检查是否有其他中断源处于就绪状态,并将就绪的中断源写入到相应的可认领寄存器中,以通知处理器核心有新的中断可供处理。

这样,其他处理器核心可以通过读取认领寄存器来获取待处理的中断,并开始处理这些中断。当一个处理器核心正在处理一个中断时,其他处理器核心可以认领并处理其他已经就绪的中断,从而实现并行处理多个中断。

因此,PLIC在将中断标记为已完成后,会继续处理其他已经就绪的中断,并允许其他处理器核心去处理这些中断。这样可以提高系统的并发性和响应性。


操作流程

大家可以对照下图,看看各个寄存器在PILC电路图中的位置,以及其作用域范围:
从零手写操作系统之RVOS外设中断实现-04

从零手写操作系统之RVOS外设中断实现-04


采用中断方式从 UART 实现输入

实现思路:
从零手写操作系统之RVOS外设中断实现-04
代码实现:
从零手写操作系统之RVOS外设中断实现-04

  • 初始化plic设备
void plic_init(void)
{
    //获取hartId
	int hart = r_tp();
  
	/* 
	 * Set priority for UART0.
	 *
	 * Each PLIC interrupt source can be assigned a priority by writing 
	 * to its 32-bit memory-mapped priority register.
	 * The QEMU-virt (the same as FU540-C000) supports 7 levels of priority. 
	 * A priority value of 0 is reserved to mean "never interrupt" and 
	 * effectively disables the interrupt. 
	 * Priority 1 is the lowest active priority, and priority 7 is the highest. 
	 * Ties between global interrupts of the same priority are broken by 
	 * the Interrupt ID; interrupts with the lowest ID have the highest 
	 * effective priority.
	 */
	//设置UART中断源的优先级 
	*(uint32_t*)PLIC_PRIORITY(UART0_IRQ) = 1;
 
	/*
	 * Enable UART0
	 *
	 * Each global interrupt can be enabled by setting the corresponding 
	 * bit in the enables registers.
	 */
	 //设置当前hart对应的enable寄存器中UART位为1,即针对当前hart开启UART中断源
	*(uint32_t*)PLIC_MENABLE(hart)= (1 << UART0_IRQ);

	/* 
	 * Set priority threshold for UART0.
	 *
	 * PLIC will mask all interrupts of a priority less than or equal to threshold.
	 * Maximum threshold is 7.
	 * For example, a threshold value of zero permits all interrupts with
	 * non-zero priority, whereas a value of 7 masks all interrupts.
	 * Notice, the threshold is global for PLIC, not for each interrupt source.
	 */
	 //针对当前hart设置中断源优先级阈值为0
	*(uint32_t*)PLIC_MTHRESHOLD(hart) = 0;

	/* enable machine-mode external interrupts. */
	//打开mie次级中断控制器中外部中断使能
	w_mie(r_mie() | MIE_MEIE);

	/* enable machine-mode global interrupts. */
	//开启全局中断
	w_mstatus(r_mstatus() | MSTATUS_MIE);
}
  • 获取待处理的最高优先级中断
/* 
 * DESCRIPTION:
 *	Query the PLIC what interrupt we should serve.
 *	Perform an interrupt claim by reading the claim register, which
 *	returns the ID of the highest-priority pending interrupt or zero if there 
 *	is no pending interrupt. 
 *	A successful claim also atomically clears the corresponding pending bit
 *	on the interrupt source.
 * RETURN VALUE:
 *	the ID of the highest-priority pending interrupt or zero if there 
 *	is no pending interrupt.
 */
int plic_claim(void)
{
    //获取当前hart id
	int hart = r_tp();
	//返回待处理的中断源ID
	int irq = *(uint32_t*)PLIC_MCLAIM(hart);
	return irq;
}
  • 通过PLIC某个中断处理完毕
/* 
 * DESCRIPTION:
  *	Writing the interrupt ID it received from the claim (irq) to the 
 *	complete register would signal the PLIC we've served this IRQ. 
 *	The PLIC does not check whether the completion ID is the same as the 
 *	last claim ID for that target. If the completion ID does not match an 
 *	interrupt source that is currently enabled for the target, the completion
 *	is silently ignored.
 * RETURN VALUE: none
 */
void plic_complete(int irq)
{
	int hart = r_tp();
	//将处理完毕的中断源id写入complete寄存器
	*(uint32_t*)PLIC_MCOMPLETE(hart) = irq;
}

从零手写操作系统之RVOS外设中断实现-04

  • 在trap_handler中增加对外部中断的处理—外部中断的中断号为11

从零手写操作系统之RVOS外设中断实现-04

reg_t trap_handler(reg_t epc, reg_t cause)
{
	reg_t return_pc = epc;
	reg_t cause_code = cause & 0xfff;
	
	if (cause & 0x80000000) {
		/* Asynchronous trap - interrupt */
		switch (cause_code) {
		case 3:
			uart_puts("software interruption!\n");
			break;
		case 7:
			uart_puts("timer interruption!\n");
			break;
	   //处理外部中断		
		case 11:
			uart_puts("external interruption!\n");
			external_interrupt_handler();
			break;
		default:
			uart_puts("unknown async exception!\n");
			break;
		}
	} else {
		/* Synchronous trap - exception */
		printf("Sync exceptions!, code = %d\n", cause_code);
		panic("OOPS! What can I do!");
		//return_pc += 4;
	}

	return return_pc;
}
  • 外部中断实际处理函数
void external_interrupt_handler()
{
    //获取中断源ID
	int irq = plic_claim();
    //处理UART中断源
	if (irq == UART0_IRQ){
      		uart_isr();
	} else if (irq) {
	    //其他中断源不进行处理
		printf("unexpected interrupt irq = %d\n", irq);
	}
	//中断源合法,告知PLIC中断源处理完毕 
	if (irq) {
		plic_complete(irq);
	}
}

从零手写操作系统之RVOS外设中断实现-04

  • 在uart设备初始化逻辑中开启接收中断
    从零手写操作系统之RVOS外设中断实现-04
  • 将接收中断使能位设置为 1,表示允许接收中断的触发。当有数据到达 UART 接收缓冲区时,将触发接收中断请求,从而执行相应的中断处理程序。
/*
 * handle a uart interrupt, raised because input has arrived, called from trap.c.
 */
void uart_isr(void)
{
	while (1) {
	    //获取uart接收到字符
		int c = uart_getc();
		//将字符写出
		if (c == -1) {
			break;
		} else {
			uart_puts("uart revice word: ");
			uart_putc((char)c);
			uart_putc('\n');
		}
	}
}

测试

void start_kernel(void)
{
	uart_init();
	uart_puts("Hello, RVOS!\n");

	page_init();

	trap_init();
    //新增plic模块初始化
	plic_init();

	sched_init();

	os_main();

	schedule();

	uart_puts("Would not go here!\n");
	while (1) {}; // stop here!
}

从零手写操作系统之RVOS外设中断实现-04文章来源地址https://www.toymoban.com/news/detail-471584.html

到了这里,关于从零手写操作系统之RVOS外设中断实现-04的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 操作系统原理 —— 什么是中断?(四)

    我们先来看看早期的计算机的工作流程: 如上图,在早期的计算机假设有三个程序需要执行,执行顺序是:先执行程序1,等待程序1结束之后,再开始执行程序2,以此类推,所以它们是串行执行的,这种方式效率就比较低,为了能够使计算机能够同时执行多个程序,从而引入

    2023年04月24日
    浏览(91)
  • 【STM32】HAL库-以太网外设-LAN8720A-LWIP-无操作系统

    KEIL:MDK_ARM_5.27 MCU:STM32F429IGT6 PHY_IC:LAN8720A LWIP:LWIP2.1.2 STM32CUBEMX:6.6.1 HAL:V1.27.1 LAN8720A使用RMII接口与STM32的ETH外设进行数据通信 STM32使用SMI接口读/写LAN8720A的寄存器 LAN8720A由外部25MHz晶振提供时钟,LED2/NINTSEL引脚配置为下拉,故PHY(LAN8720A)提供50MHz时钟给RMII的NINT/REFCLKO(此时引脚

    2024年02月08日
    浏览(52)
  • 【操作系统】聊聊不可中断进程和僵尸进程

    当我们输入top命令之后 其中S代表的是当前进程的状态 R (Running 或 Runnable) 进程在CPU的就绪队列中,正在运行或者等待运行。 D (Disk Sleep) 不可中断睡眠,进程正在跟硬件交互,不运行被其他进程或者中断打断。 Z (Zombie) 进程已经结束,但是父进程没有回收资源 (描述符、PID等

    2024年02月07日
    浏览(47)
  • 《操作系统真象还原》学习笔记:第七章 中断

    由于 CPU 获知了计算机中发生的某些事,CPU 暂停正在执行的程序,转而去执行处理该事件的程序,当这段程序执行完毕后,CPU 继续执行刚才的程序。整个过程称为中断处理,也称为中断。 把中断按事件来源分类,来自CPU外部的中断就称为外部中断,来自CPU内部的中断就称为

    2024年02月11日
    浏览(54)
  • 【操作系统】抖动、缺页中断率、页面置换算法

    对于进程P的一个长度为A的页面访问序列,如果进程P在运行中发生缺页中断的次数为F,则f = F/A称为缺页中断率。 1、进程分得的主存页框数:页框数多则缺页中断率低,页框数少则缺页中断率高。 2、页面大小:页面大则缺页中断率低,页面小则缺页中断率高。 3、页面替换

    2024年01月20日
    浏览(52)
  • 头歌操作系统 课堂练习2.1 外部中断 答案

    第一关:时钟中断的发生 作答要求: 根据相关知识进行实际操作,一直输入 c 直到 0/1 将第一行完全填满。回答问题:当第一行 0/1 字符全部输出完毕的时候一共发生了几次时钟中断,即第一行完全填满时 jiffies 记录的已发生次数为多少? 一、设置版本1内核为分析对象 首先

    2024年02月12日
    浏览(117)
  • 开发一个RISC-V上的操作系统(六)—— 中断(interrupt)和异常(exception)

    目录 往期文章传送门 一、控制流 (Control Flow)和 Trap 二、Exceptions, Traps, and Interrupts  Contained Trap Requested Trap Invisible Trap Fatal Trap 异常和中断的异同 三、RISC-V的异常处理 mtvec(Machine Trap-Vector Base-Address) mepc(Machine Exception Program Counter)  mcause(Machine Cause)  mstatus(Machine S

    2024年02月13日
    浏览(96)
  • C语言与硬件交互:中断处理、低级I/O操作与系统调用(一)

    目录 一、引言 二、中断处理 定义与作用 C语言中的中断处理机制 实例分析 中断处理注意事项 C语言,作为一种兼具底层控制力与较高抽象层次的编程语言,凭借其简洁明了的语法、高效的执行效率以及与硬件资源的紧密联系,在嵌入式系统、操作系统开发、实时控制、设备

    2024年04月14日
    浏览(33)
  • 2.树莓派4B 64位操作系统 从零搭建深度学习项目运行环境

    探索目标 树莓派的系统烧录 树莓派的基础配置 树莓派的开机连接 树莓派的文件传输 树莓派的软件安装 树莓派的运行环境 树莓派的系统备份 测试运行现有模型 1.1 系统选择 1.1.1 Raspbian OS:官方的树莓派操作系统 ​ Raspbian OS 是官方支持的树莓派板卡操作系统。它集成了很多

    2024年01月16日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包