Skip to content

7月14日学习笔记

lirui edited this page Jul 14, 2020 · 3 revisions

第二讲 操作系统与系统结构和程序设计语言

RISC-V特权模式架构

设置CSR(控制状态寄存器)实现隔离

防止应用程序访问设备和敏感的CPU寄存器

例如地址空间配置寄存器

强制隔离以避免对整个系统的可用性/可靠性/安全影响

运行的程序通常隔离的单元

防止恶意程序、病毒、木马破坏或监视应用程序或干扰操作系统

读写内存:mstatus/satp CSR

使用100%的CPU:mstatus/stvec CSR

mstatus/satp/stvec CSR页表异常处理

有虚拟内存的好处/坏处

灵活的不连续内存分配

多个运行程序的地址空间相互隔离/共享

进一步隔离应用程序与OS内核

多了访问页表的开销

RISC-V中断机制

中断是异步发生,是来自处理器外部的I/O设备的信号的结果

Timer可以稳定定时地产生中断

防止应用程序死占着CPU不放,让OS Kernel能得到执行权

Attention:不同的是,可以由高特权模式下的软件授权低特权模式软件处理中断 (可以实现在用户态中断,利用信号机制,进程间通信很高效地支持)

2.3 Rust语言与系统编程

1)系统编程语言;2)高级语言编译到机器指令

系统编程语言(system language)定义现在似乎没有特别严谨和一致的定义,系统编程语言用于构建控制底层计算机硬件的软件系统,并提供由用于构建应用程序和服务的更高级应用程序编程语言使用的软件平台,开发OS的系统编程语言很多,还离不开汇编语言。

Rust主要特性:1)内存+线程安全;2)高级语言特性;3)成熟的工具链;4)社区(OS示例代码+文档)生态

汇编代码:有限的抽象,无类型的位置参数-没有局部变量-仅寄存器

机器指令

函数调用:换为相对于PC的跳转或绝对跳转

函数返回

调用约定:如何传递参数?a0,a1...a7,放在堆栈上;值如何返回?a0,a1;谁保存寄存器?指定为已保存的呼叫者或被呼叫者;ra可以使保存被呼叫者的寄存器吗?

遵循约定,各种代码之间才能相互操作

理解stack

2.4 RISC-V CPU启动

QEMU:

RISC-V

CPU:RV64 ISA with MMU/TLB

MEM: ROM, RAM, IO-MEM, etc

I/O:Timer,UART>

Interrupt: PLIC(Platform-Level interrupt Controller)-Device

Interrupt:CLINT(Core Local interruptor)-Timer, IPI

RISC-V CPU 启动过程

初始化CPU/Regs

初始化内存

初始化基本外设

执行ROM中固化的代码

第三讲 中断、异常和系统调用

3.1 基本概念和原理

系统调用(system call):应用程序主动向操作系统发出的服务请求

异常(exception)非法指令或者其它原因导致当前指令执行失败,如内存出错后的处理请求

中断(hardware interrupt)来自硬件设备(外设、device)的处理请求

why 需要?

OS内核是被信任的第三方

OS内核可以执行特权指令,管理硬件

OS内核提供了各种service

中断:外设

异常:应用程序意想不到的行为

系统调用:应用程序请求OS服务

响应方式:

中断:异步

异常:同步

系统调用:异步或同步

处理机制:

中断:持续,对应用程序透明

异常:杀死或者重新执行

系统调用:等待和持续

3.2 硬件架构与支持

Fu540-C000 可以跑Linux

Core Local interruptor (CLINT):处理CPU内部产生的异常、或者时钟中断,或者系统调用

Platform-Level interrupt Controller(PLIC):和外设打交道,外设产生中断需要通过它让CPU知道

三种标准的中断源:

软件中断通过向内存映射寄存器中存数来触发,如IPI

时钟中断,如stimecmp > stime

由平台级中断控制器引发外部中断

建立中断机制:

让CPU能响应中断

sstatus:保存全局中断使能位

sie:指出CPU目前能处理或忽略的中断

stvec:中断入口地址

3.3中断处理机制

3.3.1 中断处理机制-overview

建立中断机制

建立中断服务例程(设备驱动)

让CPU能响应中断

响应并处理中断

保存/恢复现场

3.3.2 中断处理机制-Detail

初始化:设置sie的TI使能STIE位

初始化:设置sstatus的使能中断SIE位

初始化:实现中断服务总控函数

初始化:设置stvec指向中断服务总控函数的入口地址

如何建立中断服务例程?

设备驱动初始化部分,产生中断如何响应

初始化:设置时钟中断触发次数

初始化:设置sie的TI使能STIE位

服务例程:调用OpenSBI提供的接口设置下次时钟中断触发时间

保存与恢复现场(运行时上下文)

SAVE_ALL 寄存器

x[0-32]:通用寄存器

sstatus:系统的状态

sepc:触发异常/中断的指令地址

scause:指示发生异常/中断的种类

stval:保存了发生异常/中断的附加信息

产生中断后:

硬件设置:

sepc:保存中断的指令地址

pc:设置为stvec

scause:设置中断的来源

sstatus:SIE位置零以禁用中断

stval:保存了中断相关的附加信息

软件保存:

x[0-32]:通用寄存器

pc:设置为stvec

scause:设置中断的来源

sstatus:SIE位置零以禁用中断

stval:保存了中断相关的附加信息

3.3 中断处理机制-summary

产生中断后:

硬件设置

软件保存被打断现场

执行软件实现的中断服务例程

软件恢复被打断现场

继续执行

硬件中断服务例程可被打断:

不同硬件中断源可能在硬件中断处理时出现

中断请求会保持到CPU做出响应

硬件中断服务例程中需要临时禁止中断请求

3.4 系统调用

应用程序要输出字符串时,会触发系统调用write()

系统调用接口与具体语言无关,它们是一层基于硬件的寄存器,内存的一种约定,遵循这种约定就可以调用这个系统调用

操作系统服务的应用编程接口

通常由高级语言编写(C、go和rust等)

程序通常访问高层次的API接口

三种最常用的应用程序编程接口:

Win API:用于windows 32/64

POSIX API:用于POSIX-based OS

Java API:用于Java虚拟机(JVM)

操作系统这一层用的是ABI,需要基于硬件的约定进行操作和访问

系统调用的实现概述:分两部分

在用户态发出系统调用请求,系统调用接口一般是由库来实现的,std libc或者std rust

用户态:通过运行库来管理

第二部分是在内核态

内核态:对应系统调用号

内核态:实现系统调用功能

系统调用

RISC-V中,ecall(发出请求)和sret(返回结果)指令用于系统调用

堆栈切换和特权级的转换

函数调用

RISC-V中,call和ret指令用于系统调用,call和ret都是汇编级的伪指令,对应机器码,有个转跳指令

无堆栈切换和特权级的转换

系统调用的开销会超过函数调用

主要开销:1、切换内核堆栈;2、验证参数;3、可能切换页表;4、需要拷贝数据

具体实现:

应用发起请求:

std lib发出系统调用请求

发出设置系统调用号和参数,发出ecall

硬件设置

sepc:保存请求后的指令地址

pc:设置为stvec

scause:设置为ecall from u-mode

sstatus:SIE位置零以禁用中断

stval:保存了相关的附加信息

软件保存被打断现场

执行软件实现的中断服务例程

软件恢复现场

应用继续执行

Clone this wiki locally