实验五:可在内核态和用户态之间进行切换的 ucore
在操作系统原理中,一直强调操作系统运行在内核态(特权态),应用程序运行在用户态(非特权态)。但为什么说处于用户态的应用程序就不能访问内核态的数据,而内核态的操作系统可以访问用户态的数据?我们有没有一个 project 来体验内核态和用户态的区别是什么?更进一步体验如何在内核态和用户态之间进行切换呢?project4.1.1 为此进行了尝试。
实验目标
通过学习和实践,读者可以了解如何 CPU 处不同特权态下的执行特点和限制,理解如何从内核态切换到用户态,以及如何从用户态切换到内核态。
proj4.1.1 概述
实现描述
proj4.1.1 建立在 proj4.1(当然是基于 proj4)基础之上,主要完成了用户态(非特权态)与内核态相互切换的过程。相对于 proj4,主要增加了两部分工作,一部分是从用户态返回内核态的准备工作,即建立任务段(Task Segment)和任务段描述符(SEG_TSS),设置陷阱中断号(T_SWITCH_TOK)和对应的中断处理例程。另外一部分是对内核栈进行各种特殊处理,使得能够完成内核态切换到用户态或用户态切换到内核态的工作。
项目组成
这里我们通过 proj4.1.1 来完成此事。proj4.1.1 整体目录结构如下所示:
proj4.1.1
| - kern
| | - init
| | ` - init.c
| | - mm
| | | - memlayout.h
| | | - mmu.h
| | | - pmm.c
| | ` - pmm.h
| ` - trap
| | - trap.c
| | - trapentry.S
| | - trap.h
| ` - vectors.S
……
相对于 proj4,改动不多,主要修改和增加的文件如下:
- memlayout.h:定义了全局描述符的索引值和一些段描述符的属性。
- pmm.[ch]:为了能够使 CPU 从用户态转换到内核态,在 ucore 初始化时,设置任务段和任务段描述符,重新加载任务段和段描述符表;
- trap.c:设置自定义的陷阱中断 T_SWITCH_TOK(用于用户态切换到内核态)和实现对自定义的陷阱中断 T_SWITCH_TOK/T_SWITCH_TOU 的中断处理例程,使得 CPU 能够在内核态和用户态之间切换。
编译运行
编译并运行 proj4.1.1 的命令如下:
make
make qemu
则可以得到如下显示界面
通过上图,我们可以看到 ucore 在切换到用户态之前,先显示了当前 CPU 的特权级(CS 的最低两位),CS/DS/ES/SS 的值(即对应的段描述符表的索引值),可以看到特权级为 0。根据 lgdt 函数(位于 kern/mm/pmm.c 中)的处理,CS 的值是内核代码段描述符的索引下标,DS/ES/SS 的值是内核数据段描述符的索引下标;而在切换到用户态后,又显示了一下,当前 CPU 的特权级为 3, CS 的值为 1b,DS/ES/SS 的值为 23,把这四个寄存器的值&0xfc,则分别为 0x18(SEG_UTEXT)和 0x20(SEG_UDATA),说明确实运行在用户态了。在执行了系统调用 T_SWITCH_TOK 后,又回到了内核态。下面我们将分析到底发生了什么事情。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论