写在前面
本随笔是非常菜的菜鸡写的。如有问题请及时提出。
可以联系:1160712160@qq.com
GitHhub:https://github.com/WindDevil (目前啥也没有
本章目的
- 保障系统安全
- 多应用支持
本章需要实现的新功能
- 构造包含操作系统内核和多个应用程序的单一执行程序
- 通过批处理支持多个程序的自动加载和运行
- 操作系统利用硬件特权级机制,实现对操作系统自身的保护
- 实现特权级的穿越
- 支持跨特权级的系统调用功能
本章的宗旨和思想
操作系统历史上最伟大的想象力飞跃之一是计算机可能通过软件来安排自己的工作负荷的想法
本章我们的目标让泥盆纪“邓式鱼”操作系统能够感知多个应用程序的存在,并一个接一个地运行这些应用程序,当一个应用程序执行完毕后,会启动下一个应用程序,直到所有的应用程序都执行完毕。
实践体验
同样是运行们在上一章clone
到的代码,之前是储存在了/home/winddevil/App/rCore-Tutorial-v3
,这里的winddevil
是我的用户名,要更改成你的用户名,使用指令转到这个文件夹:
cd /home/winddevil/App/rCore-Tutorial-v3
使用git
指令切换分支,切换到第二章的源码
git checkout ch2
运行源码,实际上这段指令的意思是进入os
文件夹,编译并且运行:
cd os
make run
运行结果:
[rustsbi] RustSBI version 0.3.1, adapting to RISC-V SBI v1.0.0
.______ __ __ _______.___________. _______..______ __
| _ \ | | | | / | | / || _ \ | |
| |_) | | | | | | (----`---| |----`| (----`| |_) || |
| / | | | | \ \ | | \ \ | _ < | |
| |\ \----.| `--' |.----) | | | .----) | | |_) || |
| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__|
[rustsbi] Implementation : RustSBI-QEMU Version 0.2.0-alpha.2
[rustsbi] Platform Name : riscv-virtio,qemu
[rustsbi] Platform SMP : 1
[rustsbi] Platform Memory : 0x80000000..0x88000000
[rustsbi] Boot HART : 0
[rustsbi] Device Tree Region : 0x87000000..0x87000f02
[rustsbi] Firmware Address : 0x80000000
[rustsbi] Supervisor Address : 0x80200000
[rustsbi] pmp01: 0x00000000..0x80000000 (-wr)
[rustsbi] pmp02: 0x80000000..0x80200000 (---)
[rustsbi] pmp03: 0x80200000..0x88000000 (xwr)
[rustsbi] pmp04: 0x88000000..0x00000000 (-wr)
[kernel] Hello, world!
[kernel] num_app = 5
[kernel] app_0 [0x8020b038, 0x8020c330)
[kernel] app_1 [0x8020c330, 0x8020d6d0)
[kernel] app_2 [0x8020d6d0, 0x8020ec48)
[kernel] app_3 [0x8020ec48, 0x8020ffd0)
[kernel] app_4 [0x8020ffd0, 0x80211350)
[kernel] Loading app_0
Hello, world!
[kernel] Application exited with code 0
[kernel] Loading app_1
Into Test store_fault, we will insert an invalid store operation...
Kernel should kill this application!
[kernel] PageFault in application, kernel killed it.
[kernel] Loading app_2
3^10000=5079(MOD 10007)
3^20000=8202(MOD 10007)
3^30000=8824(MOD 10007)
3^40000=5750(MOD 10007)
3^50000=3824(MOD 10007)
3^60000=8516(MOD 10007)
3^70000=2510(MOD 10007)
3^80000=9379(MOD 10007)
3^90000=2621(MOD 10007)
3^100000=2749(MOD 10007)
Test power OK!
[kernel] Application exited with code 0
[kernel] Loading app_3
Try to execute privileged instruction in U Mode
Kernel should kill this application!
[kernel] IllegalInstruction in application, kernel killed it.
[kernel] Loading app_4
Try to access privileged CSR in U Mode
Kernel should kill this application!
[kernel] IllegalInstruction in application, kernel killed it.
All applications completed!
这个运行log
我们主要关注Loading
和kill
两个单词,主要体现了:
- 操作系统可以自己读取并且运行任务
- 如果程序运行失败,操作系统可以杀掉程序并且保住自己
那么我们之后的工作也要聚焦到这两点的实现.
本章代码树
官方给出的代码树:
看了之后有一种似懂非懂的状态,这是很正常的,应该及时去看之前实现的Lib-OS
的架构是什么样的,进行横向对比才能有收获:
可以看到第二章的系统相对于第一章的系统增加了U-Mode
,并且在SBI
的基础上实现了不同于第一章仅仅输出字符串,关机,处理panic
的功能,而是实现了Trap_Handler
和syscall_service
.从名字上我们就可以看出来Trap_Handler
是程序陷入问题的时候调用的一个服务,保证操作系统不会因为一个任务运行失败就挂掉,而syscall_service
则是另一个feature
即解决"计算机给自己分配工作"的问题.
这里再提一嘴M
,S
,U
,分别代表Master
,Supervise
,User
.
本章代码导读
这里一定要好好看看官方文档.
这里有个评论很有道理帮我们通过Linux
和Windows
的行为以及之前学过的Rt-Thread
的行为解释当前的系统是怎么运行应用的:
一般来说执行一个用户态应用程序的流程是,读取elf文件,创建新的进程页表,把elf文件里面的可执行文件段分别map到这个地址空间内的不同区域,切换页表然后设置特权等级。但是现在好像还没有文件系统,也没有类似C语言里面map的功能(后面应该会有),所以就靠链接器把用户态应用程序直接写入内核映像里,执行的时候直接跳转到这片内存区域即可.