chapter3练习
=======================================
- 本节难度:编程试水
本章任务
-----------------------------------------------------
- 注意本节任务最终对应一次 lab 提交。
- 老规矩,先 ``make test BASE=1`` 看下啥情况。
- 理解框架的多任务加载机制,了解此时用户和内核的大概内存布局。在此基础上,实现本章编程作业 sys_task_info。
- 不再加 ``BASE=1``,直接运行 ``make test`` 来验证你的完成情况。
- 最终,完成实验报告并 push 你的 ch3 分支到远程仓库。push 代码后会自动执行 CI,代码给分以 CI 给分为准。
获取任务信息
++++++++++++++++++++++++++
ch3 中,我们的系统已经能够支持多个任务分时轮流运行,我们希望引入一个新的系统调用 ``sys_task_info`` 以获取任务的信息,定义如下:
.. code-block:: C
int sys_task_info(TaskInfo *ti);
- syscall ID: 410
- 查询当前正在执行的任务信息,任务信息包括任务控制块相关信息(任务状态)、任务使用的系统调用次数、任务总运行时长。
.. code-block:: C
typedef enum {
UnInit,
Ready,
Running,
Exited,
} TaskStatus;
struct TaskInfo {
TaskStatus status;
unsigned int syscall_times[MAX_SYSCALL_NUM];
int time;
};
- 参数:
- ti: 待查询任务信息
- 返回值:执行成功返回0,错误返回-1
- 说明:
- 相关结构已在框架中给出,只需添加逻辑实现功能需求即可。
- 在我们的实验中,系统调用号一定小于 500,所以直接使用一个长为 ``MAX_SYSCALL_NUM=500`` 的数组做桶计数。
- 我们约定调用 sys_task_info 时对本次系统调用也进行计数,因此返回的 syscall_times 中对 sys_task_info 的计数一定不会是 0。
- 简单起见运行时间 time 返回系统调用时刻距离任务首次被调度时刻的时长即可;一种更有意义但是难度稍微高一些的做法是返回任务处于 Running 状态的运行时长:包含用户态时间和内核态时间,不包含调度到其他任务的时间。你可以思考下后者如何实现,但是为了通过测例建议使用前者(即考虑 real time)。
- 我们约定 time 的单位是 ms,为了得到时间可以使用 `get_cycle` 配合 CPU_FREQ,参考系统调用中 `sys_gettimeofday` 的实现或许会对你有所启发。
- 由于查询的是当前任务的状态,因此 TaskStatus 一定是 Running。(助教起初想设计根据任务 id 查询,但是既不好定义任务 id 也不好写测例,遂放弃 QAQ)
- 提示:
- 大胆修改已有框架!除了配置文件,你几乎可以随意修改已有框架的内容。
- 程序运行时间可以通过调用 ``get_time()`` 获取。
- 系统调用次数可以考虑在进入内核态系统调用异常处理函数之后,进入具体系统调用函数之前维护。
- 阅读 proc 的实现,思考如何维护内核控制块信息(可以在控制块可变部分加入其他需要的信息)。
实验要求
+++++++++++++++++++++++++++++++++++++++++
- 完成分支: ch3。
- 实验目录要求
.. code-block::
├── os(内核实现)
│ └── ...
├── reports (不是 report)
│ ├── lab1.md/pdf
│ └── ...
├── ...
- 通过所有测例:
CI 使用的测例与本地相同,测试中,user 文件夹及其它与构建相关的文件将被替换,请不要试图依靠硬编码通过测试。
.. note::
你的实现只需且必须通过测例,建议读者感到困惑时先检查测例。
.. ch3问答作业::
.. 实验结果
+++++++++++++++++++++++++++++++++++++++++
本实验采用了github classroom的自动评分功能,完成实验提交(git push)后会触发自动测试,实验测试结果可以在在线统计中查看。
问答作业
--------------------------------------------
1. 正确进入 U 态后,程序的特征还应有:使用 S 态特权指令,访问 S 态寄存器后会报错。请同学们可以自行测试这些内容(参考 `前三个测例 `_ ,描述程序出错行为,同时注意注明你使用的 sbi 及其版本。
2. 请结合用例理解 `trampoline.S `_ 中两个函数 `userret` 和 `uservec` 的作用,并回答如下几个问题:
1. L79: 刚进入 `userret` 时,`a0`、`a1` 分别代表了什么值。
2. L87-L88: `sfence` 指令有何作用?为什么要执行该指令,当前章节中,删掉该指令会导致错误吗?
.. code-block:: assembly
csrw satp, a1
sfence.vma zero, zero
3. L96-L125: 为何注释中说要除去 `a0`?哪一个地址代表 `a0`?现在 `a0` 的值存在何处?
.. code-block:: assembly
# restore all but a0 from TRAPFRAME
ld ra, 40(a0)
ld sp, 48(a0)
ld t5, 272(a0)
ld t6, 280(a0)
4. `userret`:中发生状态切换在哪一条指令?为何执行之后会进入用户态?
5. L29: 执行之后,a0 和 sscratch 中各是什么值,为什么?
.. code-block:: assembly
csrrw a0, sscratch, a0
6. L32-L61: 从 trapframe 第几项开始保存?为什么?是否从该项开始保存了所有的值,如果不是,为什么?
.. code-block:: assembly
sd ra, 40(a0)
sd sp, 48(a0)
...
sd t5, 272(a0)
sd t6, 280(a0)
7. 进入 S 态是哪一条指令发生的?
8. L75-L76: `ld t0, 16(a0)` 执行之后,`t0`中的值是什么,解释该值的由来?
.. code-block:: assembly
ld t0, 16(a0)
jr t0
.. ch3报告要求::
报告要求
-------------------------------
- 简单总结你实现的功能(200字以内,不要贴代码)。
- 完成问答题。
- 推荐markdown文档格式。
- 加入 :doc:`/honorcode` 的内容。否则,你的提交将视作无效,本次实验的成绩将按“0”分计。
- CI 网站提交,注明姓名学号。
- 注意目录要求,报告命名 ``lab1.md`` 或 ``lab1.pdf``,位于 ``reports`` 目录下。命名错误视作没有提交。后续实验同理。
- (optional) 你对本次实验设计及难度/工作量的看法,以及有哪些需要改进的地方,欢迎畅所欲言。
.. warning::
请勿抄袭,报告会进行抽样查重!