当前课程知识点:操作系统 > 第四讲 实验一 bootloader启动ucore os > 4.9 练习六 > 4.9 练习六
练习六呢 主要是能够去
建立中断向量表
那这个相对来说复杂一点
它需要知道向量表的这个细节
就是一个中断向量表的一项
到底应该是包含哪些中断描述符
中断描述符到底是由哪些信息组成的
可以看出来 在这里面呢
跟中断相关的集中在这个地方
我们说
要让X86的中断系统能够正常工作
那需要做几件事情
这个事情 首先在初始化阶段能够看到
pic_init 这是完成中断控制器的初始化
这是一个外设
是一个特殊的设备
8259的一个中断控制器
这里面有一些相关的细节
这些细节也是主要是
完成对8259一个管理和配制
那么我们大致可以理解为
把8259配置好之后
相应的外设就能够产生中断
并被CPU所接收和处理
为接受后续的时钟中断打开一个基础
那有了这个跟外设相关的
中断控制器初始化完毕之后呢
我们还需要让CPU建立好一个
中断描述符表
也或者简称为中断向量表
那么中断描述符表呢
就是这里面 叫IDT
它的一个初始化过程
那么IDT 我们在前面介绍基础知识的时候
已经跟大家讲过
就是80386这个中断描述符表的
每一项代表什么意思
这里面就把这个项建立好
这里面这个索引
这个中断描述符表可以理解为
是一个大的数组
每一个索引 能代表一个中断号
当一个中断产生之后
它会有对应这个中断号
比如说时钟中断 它会有对应的中断号
这个中断号会用来作为index
来查IDT描述符表
这个表里面对应index一项呢
记录了当产生中断之后
所要去应对中断服务例程的地址
这个地址有两部分信息
一部分是所谓段描述符
或者叫段选择子
第二部分是这个偏移
可以根据段选择子中的内容
来查找我们前面介绍过的段描述符
段描述符存在什么地方呢
段描述符存在全局描述符表中
它一样 因为有了选择子这个index
就可以基于这个index
来查找段描述符
查找段描述符之后 我们就知道
这个有关这个中断服务例程的基址
再加上它的offset
就形成了中断服务例程的这个提示地址
这个整个查找过程是由硬件完成的
但是IDT这个表
就中断描述符表
和我们刚才说的全局描述符表
是由我们软件来建立的
这里面都是由uCore来建立的
怎么能够让我们CPU知道说你建好这个表呢
那这条特殊的指令
比如LIDT 就是load idt
就完成了对中断描述符表的加载
从而使CPU知道中断描述符表在什么地方
它就知道了
这是它的一个起始地址
当建立完这个8259
这个中断控制器的初始化
以及IDT中断描述符表初始化之后
最后还需要一步 就是Enable中断
就是使能中断 这个是在这儿
叫intr enable
如果说你某一个外设
要想让它能够产生中断的话
那么你对特定的外设也做相应的初始化
所以说如果我们这里面
是需要处理时钟中断的话
那么时钟一个初始化过程也需要完成
这里面呢 也是有很多跟外设相关的
跟时钟外设相关的
8253这个芯片相关的一些设置
我们不用太追究细节
可以大致理解为它每一百个tick
会产生一次中断
这里就是大致的一个介绍
当完成了这个时钟外设的初始化之后呢
有了这三步
PIC IDT Clock这三步初始化
那么我们就会使能中断
使能中断就是一个很特殊的指令
STI 这也是一条机器指令
那么这条指令在什么地方呢
STI其实也是一个内嵌汇编
就是我们说的内联汇编
ASM就是STI一条指令
这条指令就完成了使能中断这么一个控制
那么CLI呢
实际上是另外一条指令
就是屏蔽中断
那其实有一个小问题
一开始Bootloader启动的时候
是处于中断使能
还是中断是屏蔽的呢
你怎么知道的呢
这个问题大家可以考虑一下
好 完成了这个中断向量表的初始化之后
其实包括各种外设的初始化之后
就可以产生中断了
产生中断之后
我们的中断服务例程怎么来响应它
这个是需要进一步去完成的内容
做实验内容需要去完成的
那我们在这里面呢
其实是在trap.c里面会有一个函数
这个trap函数来接管
但是比较有意思的一个问题是
这个trap是中断服务例程的入口地址吗
其实不是
中断服务例程的入口地址
在这个文件里面 叫vector.S
这个汇编文件里面
在这里面定义了255个中断号的
所对应的起始地址
当然我们这里面用不了这么多
我们大致可以看着在前面有相应的一些处理
那么它处理的入口
都是叫__alltraps这个地方
当产生64号中断的时候
我们建立中断描述符表
会使得我们CPU指针
执行指令这个指针
跳到EIP指到这个地方来
vector64 这个地址
会进一步跳到__alltraps里面
__alltraps在trap entry里面
这是__alltraps
__alltraps会保存一系列的寄存器
这里面就讲到了
我们讲80386这个中断处理机制
会讲到硬件产生中断之后会保存
保存被打断的地址和它的flag寄存器等等
但是它保存并不完整 那么为了能够
回到被打断的地方重新执行呢
我们需要确保
环境能够完全恢复到跟以前一样
所以我们把后续
在执行中断服务例程中
用到的寄存器的内容呢
都要先保存起来
以避免破坏返回去的那个环境
这里面看到叫push DS ES等等
这都是完成保存
那这些保存信息都
放在这个内核的中断站里面
最后这里看到
它这里面会有一个call trap
那么这个call trap 实际上调用了一个函数
这个函数实际上在trap.c里面
就在这儿
那么trap.c呢会进一步调trap dispatch
那trap dispatch呢
就会查找这个相应中断号
如果说它发现是时钟中断
这里面有这么一个标记
时钟中断号需要注意这个
加起来值就是32
如果发现32
它认为时钟中断会把这个ticks
这是全局的变量
把ticks做一个加操作
如果ticks满了一定次数
这里面设置的次数是100次吧
那就会print一个ticks
就打印出一个信息出来
那这个信息出在什么地方呢
这里很重要的结构
就是trapframe 这个数据结构
在这个结构里面 我们可以看到
实际上它保存了被打断那一刻的
很重要的寄存器的信息
比如说下面这一段
这一段是我们说到的
是在这个硬件一旦产生中断之后
我们硬件CPU会自动保存一些信息
而接下来这些信息呢
是我们的软件来保存的
那么这一条信息是什么呢
这条信息是考虑的是
将来有可能出现从用户态产生中断
会切换到内核态
那么就会多保存一些信息
就是ESP SS
那么这条信息呢
实际上是我们说
如果出现不同特权级的转换
比如说用户态产生中断之后
会切到内核态
那么这就出现一个特权级的转换
那么它需要保存更多的一些信息
要把用户态栈的信息给保存下来
就保存这个地方
以便于能够正确的恢复
从内核态恢复到用户态去进一步执行
对于X86而言
用户态一般我们设置在特权级3
而内核态设置在特权级0在这里面
这是练习六大致的一个介绍
扩展练习呢 其实是给一些
觉得前面六个练习
还觉得不够挑战的同学准备的
主要是能够实现不同特权级的一个切换
怎么能够通过中断机制
来实现不同特权级的切换
这里面重点就是要设置好
返回到某一个特权级
它所保存的信息
保存那些寄存器的信息应该怎么设置
这里面有很多小的细节
如果有同学感兴趣的话可以进一步去学习
那么我们就把练习一到扩展练习
都给大家做了一个简单的介绍
希望大家能够基于刚才介绍更好的完成实验
有同学也说 这个一开始看代码量其实挺大的
我们也给大家说到了
就是关于每一个lab
其实有一系列小的Project组成的
如果大家比较好奇说
想看到这个lab是怎么一步一步建立起来
那么我们还可以查找相应的Project的信息
我们也会在网上公布
大家可以去看一看
到底是如何一步一步的
一个一个小的Project
构成了一个大的lab
然后最终形成一共8个lab
那么它其实有几十个小的Project组成
这是我们这个lab1的一个介绍
好 谢谢大家
-0.1 Piazza讨论区
--html
-0.2 在线实验平台
--实验平台使用帮助
--平台使用帮助
-0.2在线实验平台
--Raw HTML
-1.1 课程概述
--视频
-第一讲 操作系统概述--练习
-1.2 教学安排
--视频
-1.3 什么是操作系统
--Video
-1.4 为什么学习操作系统,如何学习操作系统
--Video
-1.5 操作系统实例
--视频
-1.6 操作系统的演变
--视频
-1.7 操作系统结构
--视频
-2.1 前言和国内外现状
-2.2 OS实验目标
-2.3 8个OS实验概述
-2.4 实验环境搭建
-2.5 x86-32硬件介绍
-2.6 ucore部分编程技巧
-2.7 演示实验操作过程
--Q6
--Q7
--Q10
-3.1 BIOS
--3.1 BIOS
-3.2 系统启动流程
-3.3 中断、异常和系统调用比较
-第三讲 启动、中断、异常和系统调用--3.3 中断、异常和系统调用比较
-3.4 系统调用
--3.4 系统调用
-第三讲 启动、中断、异常和系统调用--3.4 系统调用
-3.5 系统调用示例
-3.6 ucore+系统调用代码
-4.1 启动顺序
--4.1 启动顺序
-4.2 C函数调用的实现
-4.3 GCC内联汇编
-4.4 x86中断处理过程
-4.5 练习一
--4.5 练习一
-4.6 练习二
--4.6 练习二
-4.7 练习三
--4.7 练习三
-4.8 练习四 练习五
-4.9 练习六
--4.9 练习六
-5.1 计算机体系结构和内存层次
-5.2 地址空间和地址生成
-5.3 连续内存分配
-5.4 碎片整理
--5.4 碎片整理
-5.5 伙伴系统
--5.5 伙伴系统
-第五讲 物理内存管理: 连续内存分配--5.6 练习
-6.1 非连续内存分配的需求背景
-6.2 段式存储管理
-- 6.2 段式存储管理
-6.3 页式存储管理
-6.4 页表概述
--6.4 页表概述
-6.5 快表和多级页表
-6.6 反置页表
--6.6 反置页表
-6.7 段页式存储管理
-第六讲 物理内存管理: 非连续内存分配--6.8 练习
-7.1 了解x86保护模式中的特权级
-第七讲 实验二 物理内存管理--7.1 了解x86保护模式中的特权级
-7.2 了解特权级切换过程
-第七讲 实验二 物理内存管理--7.2 了解特权级切换过程
-7.3 了解段/页表
-第七讲 实验二 物理内存管理--7.3 了解段/页表
-7.4 了解UCORE建立段/页表
-第七讲 实验二 物理内存管理--7.4 了解UCORE建立段/页表
-7.5 演示lab2实验环节
-8.1 虚拟存储的需求背景
-8.2 覆盖和交换
-8.3 局部性原理
-8.4 虚拟存储概念
-8.5 虚拟页式存储
-8.6 缺页异常
--8.6 缺页异常
-9.1 页面置换算法的概念
-9.2 最优算法、先进先出算法和最近最久未使用算法
-第九讲 页面置换算法--9.2 最优算法、先进先出算法和最近最久未使用算法
-9.3 时钟置换算法和最不常用算法
-第九讲 页面置换算法--9.3 时钟置换算法和最不常用算法
-9.4 Belady现象和局部置换算法比较
-第九讲 页面置换算法--9.4 Belady现象和局部置换算法比较
-9.5 工作集置换算法
-第九讲 页面置换算法--9.5 工作集置换算法
-9.6 缺页率置换算法
-第九讲 页面置换算法--9.6 缺页率置换算法
-9.7 抖动和负载控制
-10.1 实验目标:虚存管理
-第十讲 实验三 虚拟内存管理--10.1 实验目标:虚存管理
-10.2 回顾历史和了解当下
-第十讲 实验三 虚拟内存管理--10.2 回顾历史和了解当下
-10.3 处理流程、关键数据结构和功能
-第十讲 实验三 虚拟内存管理--10.3 处理流程、关键数据结构和功能
-10.4 页访问异常
-第十讲 实验三 虚拟内存管理--10.4 页访问异常
-10.5 页换入换出机制
-第十讲 实验三 虚拟内存管理--10.5 页换入换出机制
-11.1 进程的概念
-第十一讲 进程和线程--11.1 进程的概念
-11.2 进程控制块
-第十一讲 进程和线程--11.2 进程控制块
-11.3 进程状态
-第十一讲 进程和线程--11.3 进程状态
-11.4 三状态进程模型
-11.5 挂起进程模型
-第十一讲 进程和线程--11.5 挂起进程模型
-11.6 线程的概念
-第十一讲 进程和线程--11.6 线程的概念
-11.7 用户线程
-第十一讲 进程和线程--11.7 用户线程
-11.8 内核线程
-第十一讲 进程和线程--11.8 内核线程
-12.1 进程切换
-第十二讲 进程控制--12.1 进程切换
-12.2 进程创建
-第十二讲 进程控制--12.2 进程创建
-12.3 进程加载
-第十二讲 进程控制--12.3 进程加载
-12.4 进程等待与退出
-第十二讲 进程控制--12.4 进程等待与退出
-13.1 总体介绍
-13.2 关键数据结构
-13.3 执行流程
-13.4 实际操作
-14.1 总体介绍
-14.2 进程的内存布局
-14.3 执行ELF格式的二进制代码-do_execve的实现
--14.3 执行ELF格式的二进制代码-do_execve的实现
-14.4 执行ELF格式的二进制代码-load_icode的实现
--14.4 执行ELF格式的二进制代码-load_icode的实现
-14.5 进程复制
-14.6 内存管理的copy-on-write机制
-15.1 处理机调度概念
-第十五讲 处理机调度--15.1 处理机调度概念
-15.2 调度准则
-15.3 先来先服务、短进程优先和最高响应比优先调度算法
--15.3 先来先服务、短进程优先和最高响应比优先调度算法
-第十五讲 处理机调度--15.3 先来先服务、短进程优先和最高响应比优先调度算法
-15.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架
--15.4 时间片轮转、多级反馈队列、公平共享调度算法和ucore调度框架
-第十五讲 处理机调度--15.4 时间片轮转、多级反馈队列、公平共享调度算法和uc
-15.5 实时调度和多处理器调度
-第十五讲 处理机调度--15.5 实时调度和多处理器调度
-15.6 优先级反置
-第十五讲 处理机调度--15.6 优先级反置
-16.1 总体介绍和调度过程
-16.2 调度算法支撑框架
-16.3 时间片轮转调度算法
-16.4 Stride调度算法
-17.1 背景
--17.1 背景
-17.2 现实生活中的同步问题
-第十七讲 同步互斥--17.2 现实生活中的同步问题
-17.3 临界区和禁用硬件中断同步方法
-第十七讲 同步互斥--17.3 临界区和禁用硬件中断同步方法
-17.4 基于软件的同步方法
-第十七讲 同步互斥--17.4 基于软件的同步方法
-17.5 高级抽象的同步方法
-第十七讲 同步互斥--17.5 高级抽象的同步方法
-18.1 信号量
--18.1 信号量
-第十八讲 信号量与管程--18.1 信号量
-18.2 信号量使用
-第十八讲 信号量与管程--18.2 信号量使用
-18.3 管程
--18.3 管程
-第十八讲 信号量与管程--18.3 管程
-18.4 哲学家就餐问题
-18.5 读者-写者问题
-19.1 总体介绍
-19.2 底层支撑
-第十九讲 实验七 同步互斥--19.2 底层支撑
-19.3 信号量设计实现
-第十九讲 实验七 同步互斥--19.3 信号量设计实现
-19.4 管程和条件变量设计实现
-第十九讲 实验七 同步互斥--19.4 管程和条件变量设计实现
-19.5 哲学家就餐问题
-20.1 死锁概念
-第二十讲 死锁和进程通信--20.1 死锁概念
-20.2 死锁处理方法
-第二十讲 死锁和进程通信--20.2 死锁处理方法
-20.3 银行家算法
-第二十讲 死锁和进程通信--20.3 银行家算法
-20.4 死锁检测
-第二十讲 死锁和进程通信--20.4 死锁检测
-20.5 进程通信概念
-第二十讲 死锁和进程通信--20.5 进程通信概念
-20.6 信号和管道
-第二十讲 死锁和进程通信--20.6 信号和管道
-20.7 消息队列和共享内存
-第二十讲 死锁和进程通信--20.7 消息队列和共享内存
-21.1 文件系统和文件
-第二十一讲 文件系统--21.1 文件系统和文件
-21.2 文件描述符
-第二十一讲 文件系统--21.2 文件描述符
-21.3 目录、文件别名和文件系统种类
-第二十一讲 文件系统--21.3 目录、文件别名和文件系统种类
-21.4 虚拟文件系统
-第二十一讲 文件系统--21.4 虚拟文件系统
-21.5 文件缓存和打开文件
-第二十一讲 文件系统--21.5 文件缓存和打开文件
-21.6 文件分配
-第二十一讲 文件系统--21.6 文件分配
-21.7 空闲空间管理和冗余磁盘阵列RAID
-第二十一讲 文件系统--21.7 空闲空间管理和冗余磁盘阵列RAID
-22.1 总体介绍
-第二十二讲 实验八 文件系统--22.1 总体介绍
-22.2 ucore 文件系统架构
-第二十二讲 实验八 文件系统--22.2 ucore 文件系统架构
-22.3 Simple File System分析
-第二十二讲 实验八 文件系统--22.3 Simple File System分析
-22.4 Virtual File System分析
-第二十二讲 实验八 文件系统--22.4 Virtual File System分
-22.5 I/O设备接口分析
-第二十二讲 实验八 文件系统--22.5 I/O设备接口分析
-22.6 执行流程分析
-23.1 I/O特点
--视频
-第二十三讲 I/O子系统--23.1 I/O特点
-23.2 I/O结构
--816C80A0F5E3B8809C33DC5901307461
-第二十三讲 I/O子系统--23.2 I/O结构
-23.3 I/O数据传输
--C58221E14388B9DB9C33DC5901307461
-第二十三讲 I/O子系统--23.3 I/O数据传输
-23.4 磁盘调度
--567A3F1FCBFB3F4C9C33DC5901307461
-第二十三讲 I/O子系统--23.4 磁盘调度
-23.5 磁盘缓存
--C327536B80D25CE79C33DC5901307461
-第二十三讲 I/O子系统--23.5 磁盘缓存
-html
--html