0%

第一阶段

一阶段的rustlings是挺好的rust入门题目,也是没有什么阻碍的完成了100道题。

第二阶段

lab1

这一个lab没什么难度,实现taskinfo不需要太多os相关的知识。

lab2

这一个lab开始上强度了,需要弄懂很多os知识。

关于sys_get_timesys_task_info,题目有提到splitted by two pages问题,但是直接整个转换成物理地址写入也能过测试,

我理解的处理splitted by two pages的方法是,对每一个字段,获取他的物理地址,然后写入。

或者像buffers那样,直接逐字节拷贝进Vec<&'static mut [u8]>

不知道上面的方法是否正确。

关于mmapmunmap,本来是想保存在MemorySet.areas下,但是考虑到回收的内存段可能是分配的内存段的子集,要实现MapArea的分裂,还有性能问题,

就直接在MemorySet下挂一个btree管理了(感觉在mmap这种需求下抽象成MapArea反而是一种负担)。

lab3

lab3感觉比lab2简单,spwan直接复用TaskControlBlock::new再进行一些操作,stride也是采用了简单的实现。

本来想实现,即使stride溢出,也能选择正确的程序(无符号相减,结果转有符号与0比),因为时间问题直接用u64解决咕咕咕了。

补充

感觉test还是少了。

rCore学习记录

在Lab开始之前

配置环境

本来想直接用物理机直接进行配置实验环境的

但是ArchLinux默认的qemu版本是8.1,和仓库中rustsbi要求的版本有冲突。

所以最后还是改用了docker来搭建环境……😢

1
2
3
4
make build_docker

# 用同一个docker容器进行全部实验,不想实验一次创建一次
docker run -it -v ${PWD}:/mnt -w /mnt rCore bash

修改ci-user中的makefile

1
2
3
4
5
6
env:
rustup uninstall nightly && rustup install nightly
(rustup target list | grep "riscv64gc-unknown-none-elf (installed)") || rustup target add riscv64gc-unknown-none-elf
cargo install cargo-binutils
rustup component add rust-src
rustup component add llvm-tools-preview

rustup uninstall nightly && rustup install nightly 注释掉,避免每次本地测试的时候都下载一遍

Lab 1

lab1 本身难度其实并不大。感觉主要还是结合之前的章节熟悉一下 rCore 项目代码的整体结构,

但是由于我对系统结构还不是很熟悉,所以还是花了比较多的时间。

  • 实现 sys_task_info 系统调用:

在 TCB 中添加记录系统调用次数的信息,每次系统调用时,根据 syscall id 更新相应数据。

我这里就直接粗暴地用桶方法记录了这些信息。

后面写到 lab3 的时候,发现我之前 sys_task_info 中的获取时间的方式有些问题。正确的应该需要记录进程第一次运行的时间,然后记录时间差。

Lab 2

感觉在前三个 lab 中,lab2 算是相对比较难的一个了。主要的时间都花在了这里。

因为有了虚拟内存的机制,所以要重写 lab1 中系统调用

  • 实现 mmap 和 munmap 系统调用

    • mmap

    需要注意,port参数不能直接转成MapPermission,两者有区别,并非仅仅是类型不同。
    在进行map前,需要检查对应的虚拟内存地址是不是已经被使用过了,这里可以检查 vpn_range的 start 和 end 看看是否被使用
    下面的munmap同理

    • munmap

    基本上就是map的逆操作

可以根据代码画个结构图,方便理解虚拟内存的结构。

Lab 3

  • 实现 sys_spawn 系统调用:

感觉还是比较简单,使用 translated_str 把 path 指针转成 程序名称,然后就可以创建进程,加入进程队列。要记得把新建的进程push到父进程的child中。

  • 实现 stride 调度:

TCB 上再添加上 priority, stride 的信息,然后每次进程切换的时候更新一下。

进程插入进程队列时比较下 stride 的大小就行。

总结

回顾学习的过程,我觉得完成lab重要的是要有一个清晰的思路,明白自己要做什么,明白要怎么做,要对lab有一个整体上的认识。自己阅读代码的能力还是差了一些,以后要加强。

通过学习rCore,我感觉我对于操作系统的理解更深了,不像以前只是浮于表面,只记得一些概念,而对于操作系统的实现没有真切地感知。

最后要感谢老师、助教们辛苦的付出,让我们能够学习到这样好的开源课程,让我们有机会更加深入了解操作系统。


自我介绍

我是一个来自于山东某普通一本的学生。爱好广泛,不过最喜欢的是计算机。在小的时候就非常喜欢看数码方面的内容,比如各种手机电脑,对其中的参数,性能,价格方面都有自己的见解。也经常关注圈子的各种最新的资讯等。但由于生活在乡下等种种原因,与计算机的接触也仅限于此了,什么编程语言,操作系统几乎都没听说过,唯一擅长的就成了处理各种电脑坏了的问题。。。

来打大学之后,对计算机有了更深了一步的了解,这更加提起了我的兴趣。中途接受学校课程学过C,Java,Python,JavaScript等语言。由于平时喜欢玩Minecraft(使用Java编写), 所以当时对Java产生了浓厚的兴趣,觉得自己要好好学习Java,既能满足我对游戏上需求(为游戏编写mod), 也能成为我以后能靠着吃饭的技术。

但。。。随着我对编程语言的认识越来越深,加上种种原因,我渐渐的对Java失去了兴趣。现在看来,Python也是一门我非常喜欢的语言,但是它效率又太低。本着对编程语言的信仰,我希望能学会一门效率非常高的现代语言,现在来看,它就是Rust

与大家相遇的故事

相对来说,当今用的人非常多的Java,JavaScript,或者加上Go,这类语言现在来看就像是为写业务而存活的,他们大多出现在某产品的前端,或后端中,做成网页或者客户端。而我对于计算机的热爱并不是做网页,学到现在,相对于用这些语言写业务来说,我更喜欢原理和技术上的事情。而且我是一个喜欢挑战相对更难的事情的人(并不是说写业务简单,我只是说可能在我的视角里原理和技术上的问题是相对来说更加解决的),所以我故意没有学习搞业务的东西。

我觉得能写一个OS是一件非常厉害的事情,非常酷炫的事情,比网页要厉害得多(个人而言),正好与上学期接触了某一个课程,是与计算机组成原理和操作系统有关的课程,这激发了我的兴趣与斗志,我希望能在最后的课程设计上写出来一个简单的OS,能脱离我们现在的操作系统,直接在裸机上运行的那种。而且在这之前,我正好凭着兴趣自学了Rust,毕竟Rust靠安全和很多新颖的设计著称,而且拥有非常高的性能,我想这不写操作系统正合适!

于是我在网上搜索了Rust和操作系统相关的资料,找到了rCore和blogos, 由于先找到的blogos,于是就照着blogos做了起来。当然,结果没有那么的好,由于有限的时间,加上知识的匮乏,最终只完成到了简单的中断部分,但我觉得这是一个非常好的经历,在我真正去自己写操作系统的时候,我发现并学习到了很多很有意思的设计,而且感觉成就感满满,虽然我做的内容不多,但我觉得我收获很多。我最后也是把它交了上去,虽然是个半成品,不过毕竟时间比较短,这也不算是次的作品了。

之前看过rCore的book,上面有训练营的链接,但我每次看到的时候,都发现已经开展了一段时间了,也不知道怎么参加, 不知道确切的时间。不过在这学期,我有个朋友发了训练营的链接,正好碰上正式开启的直播,朋友知道我学过Rust,就鼓励我参加。虽然深知困难,但我觉得依然要抓住机会,于是就报名了咱们的训练营,不过有点遗憾的是我朋友并没有参加本次训练营。

第一阶段

第一阶段对我来说还是相对轻松的。。。(也许)。其实虽然开启直播后马上就开第一阶段了,但是我却还是在开启了一周后才报的名,原因是在某个小岗位上写业务相关的东西(虽然不喜欢但有时候觉得还是得写写……)。不过由于提前学过Rust,直接做rustlings就可以了,然后就是比较顺利的用半周差不多的,每天的空余时间写了写就过了,然后剩下的时间就去忙校内安排的课程了(课太多了),再加上正好体测加各种实验实在忙不过来,等再次反应过来第二阶段都过了半周了。。。

其实我还是挺愿意写一个rustlings100题的题解的,不知道有没有空。毕竟用github page+hexo搭过简单的博客,还是很愿意写这些东西与大家讨论分享的,能学的很多很多的新知识和新方法。

第二阶段

第二阶段对我来说就比较煎熬了。。。

一窍不通

毕竟前面说,等我反应过来二阶段已经过完半周了,正好有空我抽出来了很多很多时间去研究第二阶段。我错过了第一节课的直播,且正好没有录播……而且我也没找到多少关于二阶段的资源,我甚至不知道哪些是二阶段的资料,Github的那个仓库怎么用我也不知道,命令也跑不通,题也不知道是什么……反正一头雾水。而且感觉自己落下很多了,也不好意思发消息问。没办法就硬回去看群里的消息,几百条划上去从头硬看,好不容易能翻出点东西来,就去尝试了。我甚至不知道到底是clone哪个仓库,到底是自己的还是README.md里面的仓库,我寻思不管啥先拉下来再说,拉下来然后也没跑通。后来翻消息发现有指导书和一个哥们发的公众号,于是花了一天也是把环境搭好了。但之后怎么跑呢,反正也是不知道……好不容易后来看到朱老师说从某一条指令开始运行,再加上第二次直播,我立马就明白了每一条是干啥用的,后来就成功能跑起来了。

初入茅庐

后来就是针对任务书进行学习,ch1,ch2,ch3相对来说我还是容易理解的,因为之前做过一次差不多的缘故,理解起来相对容易一些。不过读代码可就没有那么容易了,太煎熬了,我刚开始学急了,不知道从哪里下手。不过现在来说好像因为过去一段时间了,不是很记得当时是啥状态了。而且当时很讨厌unsafe这种东西,但是这里又有很多这玩意,我每次都会发出疑问,我真的可以直接修改内存吗,真的可以吗,真的吗?总是就是很不习惯,因为之前也没有接触过。不过后来也是慢慢稳住了,真的要冷静下来看代码,掌握一点技巧读起来也不会那么困难。系统的主要结构都会放在结构体中,然后提供一些方法,其实无非就是那老几样,找到头找到尾,捋清了关系,程序的运行逻辑也就慢慢的清楚了。而且幸运的是,我第一次尝试make test,就直接全部通过了,这给了我非常大的信心,然后我尝试去挑战ch4……嗯……差点人直接在ch4没了。

怎么说呢,ch4我感觉确实是看book好一点,ch4之前我也是看指导书,到了ch4之后我看了一遍指导书,感觉一头雾水,就只好去硬扒代码,但这代码吃素的?直接给我上嘴脸,看的我一头雾水。而且这次我没有基础了,上次做也没有做到内存这块,这学期老师讲的也没听懂(校内),这里卡了我好久。而我这段时间是几乎天天看这个东西,课上看这个,晚上也看,看到24点,研究代码,但……效果一般。后来看群里又去扒了一遍book,半天就扒完了,豁然开朗,第二天就做出来了,如释重负的感觉。兴奋的我提交之前,提交之后又没有做任何改动摁跑了几次make test,太开心了。(而且代码里面还有一些我的心理路程和各种翻译,虽然删了一些……)

实现上来说的话,就是差不多大体搞清楚了框架,address.rs就是usize包装成了各种地址页号之类的,两个allocator感觉我说不太清楚,而且感觉可能用不到就没再继续细看,然后memory_set和page_table就关键一些,一个是页表,一个MemorySet存页表和相应的地址空间,MapArea虚拟页号的连续区间。当然,我觉得大大简化难度的是原本就提供了一些方法,我直接拿去用了。读着读着我就觉得这个insert_framed_area就很适合去做这个实验,尝试了一下测试通过了,然后接触映射的我就照着insert_framed_area反过来写了几个函数,包装了一些。然后我写代码的时候还有一点洁癖,比较喜欢整洁一点……然后不喜欢破坏原本的结构,还有封装性,我很少会把原本private的东西改成public,反正……就是洁癖……然后也是非常顺利的通过了。

渐入佳境

ch4困扰了我好几天,半周多,ch5就好很多了,ch5我仍然看的book,而且这次不是我学的相对薄弱的地址了,这次进程相关的内容我正好前一阵子做业务的时候接触过很多了,理解起来相对容易一些,然后也是差不多两天左右时间通过了,找到技巧之后,感觉一切都好了起来,而且每章的那个新增结构,加上每个结构体前面的描述,基本上不用看具体的代码就能理解个大概。不过……第二阶段结束了,勉勉强强及格吧,还是得加把劲。

未完待续

关于收获

感觉这次二阶段收获还是蛮多的。同时压力也比较大(因为一开始觉得二阶段结束没全做完就无法参与三阶段了),晚上睡觉都想这些事,不过后来宽限了条件加上实验顺利通过了一些就感觉好了。

三次实验,每次做完都很高兴很高兴,
第一次是因为调试了很多次终于能正常跑起来了,而且是一次过。这无疑起了个好头,我很想分享此次的喜悦,原本想写一个blog,帮同样迷茫的朋友度过第一关,条件就是如果我能两天拿下ch4我就写,然后……我半周多才拿下ch4,就没有后续了。
第二次是因为历尽千辛万苦终于过了ch4,相对于我一开始面对ch4的内容,毫无头绪,到大体上理解结构,非常感慨,而且离进入三阶段也非常近了。
第三次是因为能成功进入三阶段了,努力没有白费,而且自己也没有那么笨,至少及格了。

而且对于学习上,也懂了很多。一开始我总是逃避去细看代码,尤其是汇编,一但遇到难读的我就不喜欢去细看,导致我花了更多的时间,偷懒最终还是要付出代价的。
而看懂了源码,弄懂了结构,就不会出现没有头绪的感觉,而是感觉自己点子很多,实验根本不在话下的感觉。都是些很模块化的东西,而且还提供了很多现成的方法,可以去使用和效仿。
我还学会了要勇敢面对自己害怕的事情,不能逃避。这件事不光是对写OS这件事而言,其实我以前非常讨厌unsafe,关在unsafe里的东西,我不知为何就不喜欢去想它的作用,有些名字特别长的函数我就会自己觉得自己看不懂,就非常苦恼。以前我总是逃避他,越逃避它,它就越折磨你。我这次是深有体会的,就这个,unsafe,裸指针,内存分配,我硬着头皮把我只要有疑问的全搞明白了,虚拟内存这里的各种名词(我才知道好几个不同的名字指的是同一个东西),每个名词都认明白是什么意思。虽然我弄明白他们需要花时间,但是我真的弄懂之后,后面的工作会好做很多很多。

最后感谢各位老师同学举办了这次活动能让我收获这么多,同时也感谢在群里面交流和帮我解决问题的大佬小佬们。咱们国家的计算机行业有大家在,以后一定会发展的越来越好,越来越强大!!

初次接触

作为一个工作党,第一次接触OS训练营课程是通过西安邮电大学的陈丽君教授推荐的,当时看到训练营很兴奋,虽然已经作为工作党已经10多年,那会上大学没有这么好的平台和开源课程,隐约记得06年左右的时候只了解过陈渝教授的网上公开课,但是对实际做的事情并没有深入了解和学习。
这次是通过训练营可以深入学习了。陈老师的课程也越来越丰富,之前的就课程也恶补了一些,这次的训练营是以Rust为主要语言基础,循序渐进一步一部的学习OS的开发过程,主要分成三个阶段,第一阶段以rustling为基础的和第二阶段的Rust语言编程,第二阶段的Rcore的OS实践学习,第三阶段的不通选题的实现,比如ArceOS等。
对于我个人已经参加了三期。之前第一期,仅完成了rustling,第二期,尝试完成了rustling和ucore,因为对rust语言编程还是一头雾水,这次,经过坚持完成到了第二次的rcore,但是还有core 的5个大实验只完成了3个实验,虽然可以过关,还是想冲一波完成实验4,但看了两天文档,仅仅有点思路了,但是没时间完成了,先提交博客过关,只能后面找时间完成了!下面是过程中的一些即简要总结。

第一阶段总结

这个阶段前40题都是一些基本语法,有编程经验的稍微琢磨下都可以完成。等到了泛型,闭包和trait就看似一头雾水了。个人总结做题可以参考官方的手册,但是深入学习语言建议可以参照https://course.rs/basic/base-type/numbers.html,rust语言圣经比较通俗的,比较翻译的和原汁原味的编程书是不一样的,或者直接对照看英文也是可以的。
rustling在做题过程中一定要多看 lint和注释里,因为题目的目的都是里面,同时看来处理对应的参数连接,会快一点。
比如:iterators5.rs实验中,需要多查看手册,我开始移植准备用比较for循环的笨办法去实验,么有理解题目的目标的意思,花费了很多时间,即使完成了实验,但是学迭代的fold用法没有理解和掌握,目前没有达到还是浪费了很多时间,因为rust里面的迭代用的很多,需要慢慢体会,同时还是学会使用手册,只要查看下fold手册,或者浏览下迭代器的用法,就一目了然。
https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold
还有就是rust手册还是需要整体先过一遍,再去做题会事半功倍,及时不全完成,但是至少目录要过一遍。

第二阶段总结

第二阶段做的还是比较吃力,一共5个大实验,我仅完成了3个,后面两个只能等后面时间完成。
实验1,整体难度不大,目标是通过syscall实现获取系统时钟和taskinfo的信息,这个时候的rcore还是比较原始,没有MMU,没有进程只有作业的状态,因此实现起来没有内存和进程的限制,只要理解代码和流程和实验的环境就可以完成。
实验2,由于增加了用户空间和内核空间去区分,因此系统之间的调用的数据交换要使用特定的机制完成,这里主要考察了translated_byte_buffer的用法,核心是memoery_set的进制如何使用和对其理解。这里为了代码简洁也查了很多资料,最后使用copy_from_slice,也对切片的使用更深的认识,但是最后看了老师的参考代码,还是有不一样的。
实验3,群里有人说比较难,但个人认为实验难度的不能很难,因为spawn基本上相当于fork+exec,还是考察进程中memory_set,program_brk,task_cx,user_sp,等拷贝和处理
第二阶段如果有一些操作系统的基础会好很多,推荐大家阅读陈海波教授的《现代操作系统:原理与实现》通俗易懂。

总结

通过本课程,除了敲开了对rust编程语言和OS开发的大门,更多的是认识了这么多老师和同学,更加认识了自己。非常感谢清华的老师和同学能提供这样一个开发的平台,晚上各位老师的讲解和答疑,是我们一个指引,也是对我们这些初学者是一个道路的指引,相信这样的训练营将会给我们的国家带来软件的繁荣,再次感谢无私风险的老师和同学们!!!

背景

我是一名计算机专业的学生,现在进入大三上学期,学校已经安排了操作系统课程,但老师教授的偏理论性缺少实践的过程。我本来已经在学习MIT 6.S081操作系统课程,朋友推荐了rCore,采用Rust语言编写的操作系统课程,觉得非常棒交流环境很好而且是国产然后配套资源也很全,就报名学习了。一起学rCore吧!

我也认为在本科阶段,就需要认真学习理解计算机核心课程包括操作系统,应该学习计算机底层知识去了解探索计算机科学领域的魅力和故事,打下扎实基础,毕竟是计算机专业的本科生,大学毕业后可能没有足够的时间与精力去做这些事情。

Read more »

2023开源操作系统训练营第二阶段总结报告

学习动机与兴趣

使用rust已经很久了, 但是一直没有机会可以深入学习Rust编程和操作系统原理。对于Rust,它的内存安全性、”零开销抽象”和Cargo包管理工具等特性吸引了我(ps: cpp的包管理差的有点子多)。在训练营里面, 我可以深入了解了RISC-V架构。虽然之前可能只是听说过,但在训练营中,我学习了SBI和RISC-V指令集的使用。相对于传统的x86架构,RISC-V的指令集更为简洁,文档也相对清晰,这为理解底层原理提供了很好的机会。

实验内容与技术挑战

训练营的实验内容广泛,涵盖了操作系统的核心概念,包括多道程序的放置与加载、虚拟内存管理、进程管理、文件系统、管道和线程支持等。但是目前 文件系统和异步这方面的内容还没有看太明白。

在实验中,我遇到了不少技术挑战。例如,在虚拟内存管理实验中,我们需要处理虚拟地址到物理地址的映射,而在进程管理实验中,我们必须正确处理任务切换和多任务调度。这些挑战锻炼了问题解决能力和编程技巧。

同时 UPSafeCell的使用,也给我的工作中有一定启发。 我通过使用sdk中UnsafeCell结构体, 结合atomic变量来完成ReadGuard。 成功去除了锁依赖, 使用无锁编程的方式解决并发效率问题。 这种学习并能实践的感觉,让我觉得不虚此行。

学习总结

整个训练营让我更深入地理解了操作系统的原理和底层机制。通过实际的内核开发和编程实践,积累了宝贵的经验,不仅掌握了Rust编程,还深刻理解了操作系统的内部工作原理。我对于Rust的掌握也有了显著提高。

开始

从暑假开始,我就打算重新学习操作系统的相关知识。最开始的打算是学习 Jyy 老师在今年上半年开的操作系统课程。可能是自己太菜了(对 Lab 和 Pa 完全没有思路)于是我转向了学习其前置课程 - 南大开的 ICS 课程。在暑假经过 PA 的一系列训练过后。 我觉得自己可以转向操作系统这座大山了。

此时,我突然看见 Rust 中文语言社区推的一个清华开源操作系统的学习活动。我抱着试一试的态度加入了(这就引出了下面的内容)

过程

第一阶段

老实的说,这一阶段对我而言更像是个“体力活”。在参加之前,我接触过 Rust 这门语言(这是另外一个故事)很巧的是我之前也写过 Rustlings (虽然没写完)

总的来说,这一阶段的训练更像是“康复训练” 唤醒了我对 Rust 的“感情” 🤪

第二阶段

第二阶段的训练相对于第一阶段而言对我更具挑战性,此前我完全没有接触过在线评测的实验这是其一,我从没有认真思考过 System Call 的行为。 我知道在 Linux 上可以通过 strace 来查看命令/程序在运行过程中使用过的 System Call 的行为。但对于具体的 System call 的行为,我并没有试着去思考过。这是我过去在学习过程中,没有考虑到的问题。从此看来,这比我具体学到什么编程方法/技巧,更值得记住。

由于学校课程安排和其他一些事情,让我无法静下心来完成第二阶段的所有训练。但在昨天基本都已经结束了。终于可以将重心放在完成剩下的训练上了!

小结

我认为知识一直存在在某个地方,只要在某一方面不断的探索就会发现的,但在前期的过程是如此的艰难,当我得知这个方面不只我一个人在探索,并时常有好消息传来。这相比起“找到”知识这件事本身更激励我。

可能是操作系统在大众眼中是神秘的、有挑战的让我周边没人敢去了解。但在这个时间的某些地方依旧有一群人在向它发起挑战。这件事对我来说有不一样的意义。

最后,我想向过去两周里默默付出的老师、助教们和群友们。在他们身上我看见了开源的精神和意义。

总体总结

​ 参与本次开源操作系统训练营,我开始学习了rust语言,rust语言的官方文档做得很好,rust语言圣经也很方便学习。不得不说,rust语言的学习十分陡峭,虽然在一阶段写了rustlings,在第二阶段完成了前三个lab,但是我感觉我对rust的语言理解还在比较浅的层次,生命周期和所有权的概念还有待加强,有时候我感觉我写的rust代码并不够rust,还是停留以前其他的编程语言观念,实际写代码的过程都是编译器在教导我如何写代码,通过报错和查看文档来解决问题。然后rcore的文档十分完整,既有操作系统概念上的阐述与总结,又有实践层面上的代码解释。在学习的过程中,我又加深了对操作系统的理解。

二阶段实验总结

​ 能够完成各个LAB的关键,是在于理解本章实现的操作系统的各个模块负责的功能,在通过阅读文档的解释,以及阅读代码进行理解后,才能知道要应该在哪个模块添加代码以实现功能。

LAB 1

​ 本章的操作系统是多道程序与分时操作系统,主要是需要理清多道程序是如何调度的。实验要求我们实验一个sys_taskinfo系统调用,来获取当前任务的任务信息。所以根据以前的操作系统知识,很自然的就能想到应该在进程控制块中加入我们需要收集的信息。我在实现的时候存在数据冗余问题,我先在TaskManagerInner中加入了一个任务信息Taskinfo字段,又加入了一个任务创建时间create_time字段,实际上Taskinfo.status和Taskinfo.time是多存的不必要的信息,因此我在后面的章节之后进行了重构,只加入了create_time和syscall_times两个字段。

LAB 2

​ 在本章节中,内核加入了虚拟空间机制,让进程的实现更加完整。实验要求我们移植get_time和taskinfo系统调用,并增加sys_mmap和sys_munmap系统调用。由于rcore的实现是双页表,内核页表和进程页表是分开的,进行系统调用的时候会切换页表,移植操作就需要进行地址转换拿到进程空间的地址来进行写入。内存映射的系统调用实现根据提示能做出来比较简单的实现便能通过测试,但是实际在取消内存映射的时候,可能需要对内存区域进行分割和合并的操作,例如可能会涉及内存管理算法什么的,似乎题目没做要求,我还没有实现,做完后续实验填坑吧。

LAB 3

​ 在本章节中,内核实现了进程机制,使得能够进程能够创建子进程(fork)、用新的程序覆盖已有程序内容(exec)。实验要求我们移植向前的代码并实现Spawn系统调用(fork+exec),再实现stride调度算法。

  • 在移植的过程中遇到的问题便是前两章记录进程创建时间是用get_time_ms函数,而在本章节中会因为精度不够而无法通过测试,改用get_time_us进行记录,返回任务存活时间时/1000便能得到结果。
  • 实现spwan系统调用,主要就是参考fork和exec的实现,将两者有机的结合起来,不需要复制父进程的内存空间,转而从elf文件中获取。
  • 实现stride调度算法:由于本章将TaskManager进行了拆分,调度实际是再manager中进行,根据提示,将原先的双端队列替换成小顶堆,在任务调出时对stride进行+pass,调度任务的时候每次从小顶堆中弹出stride值最小的进程便能实现。主要难点是BinaryHeap的使用。

Lab 4&5 to be continue.


#关于Rust

之前从未了解过这门语言,想来学习它快有一个月了,感觉和传统的C系语言大不相同,尤其是刚开始学习时,最为痛苦,完全陌生。但随着学习的深入,了解到其相关特性,又不得不承认其设计的巧妙,希望能够在以后的日子,多些相关代码,进一步提升自己的Rust编程水平。

#关于操作系统

之前对于操作系统的了解仅仅停留在书本上面,对于相关代码和具体实现细节,也是知之甚少,所以在第二阶段的时候,感觉进展缓慢,但好在随着学习的深入,总算能解决一些问题,能够有所收获。

#关于未来学习计划

希望在将来,能够在训练营中学到更多有用的东西,感谢训练营的老师们,提供了这么一个好的环境,感谢!

开始阶段

有一年私有云平台开发经验的 Go 开发工程师,有些许的 Rust 基础, 没有 Rust 相关的项目,对操作系统相关的东西一知不解。

在群友的闲聊下发现有 “Linux 源码趣读” 的系列文章,趁空闲的时间过了一遍,对操作系统的整体结构有一定认识,群友说这个讲的蛮浅显的,但是感觉对我这种没有啥操作系统基础的还是有很大的帮助的。

学习感受

一章一章的剥开操作系统的面纱,硬件机制、操作系统理论整体联络起来,渐渐实现一个可用的操作系统。

就目前完成到 ch5 来讲,Guide 的 ch4、ch5 的这部分内容不怎么连贯,基础比较差的我就只能硬读了。听说 rCore-Tutorial V3 的内容更全一点,等后面也对照这学习一下每章节的内容。

学习总结

似乎任何事情都逃不过这句话:“会者不难, 难者不会”,真正的难其实是对未知的恐惧。目前算是完成了这次训练营的基本过线目标:完成前三个作业。现在回头来看,都无非是对操作系统概念的学习和理解,并把这些理解到的概念真正转化成工程代码的一个过程。例如实验中你本就拥有一个完整的模拟环境,运算设备、硬件机制、目前标准的系统调用接口参考、经典理论(SV39 分页机制)等等,需要用自己理解操作系统概念去把这些东西组合在一起,最终提供一个基于底层基础设备提供的机制,为上层用户提供一个可靠的、安全的运行环境。

未知的事物并不可怕,可怕的是你认为它是永远无法被理解的。

ch0

这一部分是构建实验环境:本质上就是安装 Rust 工具链和编译安装 Qemu 模拟器。在尝试使用 classroom 在线环境失败后,决定本地部署环境。据目前所了解到的虚拟环境模拟工具来看(需要一个 Ubuntu 的系统环境),有传统虚拟机软件(Parallel、VMWare 等)、MutilPass(Ubuntu 系统特供)以及更加流行的 Docker 容器模拟,由于对桌面环境不是强需便直接排除了,、MutilPass 和 Docker 自己都比较熟悉,因更倾向于 MutilPass 的使用方式,所以最开始拿 MutilPass 创建的 Ubuntu 虚拟机安装环境,通过 VSCode 的 ssh 插件直接远程虚拟机开始基础环境部署,运行第一个 “Hello World!”。

后续训练营的群友有推荐使用 Orbstack 这款软件,了解之下发现确实好用,随而更换到这个软件,它的优势:
1、共享宿主机内核:CPU 全部共享到虚拟机、内存几乎接近全部也是给到虚拟机,创建一个 Ubuntu 虚拟机只要十几秒。
2、提供 Docker 命令:可以替换掉 Docker, 又可以少装一个软件了。
3、提供单节点 K8s 集群:像 Docker 一样,更加轻量、启动快。
4、唯一缺点:目前只支持了 MacOS 系统(刚好是 Mac),可能是因为是使用 Swift 开发的,看后续是否会支持 Linux。

ch1

这一部分主要是一步一步的讲解了如何从零开始构建一个可以运行在 Qemu 上的 Rust 操作系统程序:Hello World!,接触到了一些基础概念:系统级标准输出、系统级异常处理、内存基本布局,这些在具体的代码转化后是如何展现的,以及操作系统的入口:entry.asm 文件。

简单来讲,系统加电后会固定去读区特定的位置,也就是操作系统入口文件里的这部分内容,从而就进入了我们编写的 Rust 操作系统程序的 rust_main 入口,当然固定读取的操作是硬件提供的。

ch2

这一部分实现一个最简单的批处理系统。电脑内存本质上就只一个线性的存储结构:这一部分将系统程序需要占用的部分之外的存储结构以固定的布局方式排列在内存上,通过一个程序一个程序的加载执行来达到一次运行可以完成多个任务的系统。这部分也涉及到了 SU 态相关的东西。

ch3

操作系统在一定程度来讲算是一个处于“死循环”的程序,因为各种“中断”操作将读写设备、CPU 计算、任务处理等灵活的控制起来。这部分主要利用了“时钟中断”和任务切换这两部分内容来完成了一个分时多任务系统,通过时钟控制 CPU 不被某个程序长时间占用,这也是最基本的任务调度实现。

这一章的作业是提供一个系统调用来获取当前执行任务的基本信息,不考虑其他影响因素:也就是记录任务的启动时间、各种系统调用的次数和状态,当前已经存在“任务”的存储模型 Task,在其中记录信息并在状态流转处记录即可。

ch4

这一章介绍了 SV39 多级页表机制理论,基于该理论实现了实验里的多级页表,物理地址、虚拟地址的基本定义和对应的基本操作,以及 MMU 机制和 sapt 的理论定义模型,包含了对多级页表的重要解释,同时也通过图介绍了整个内存中操作系统和用户程序的布局。

这一章的作业是在开启多级页表机制下,适配 ch3 的作业实现,并完成 内存分配 mmap、和内存释放 mummap 系统调用: 基本的思路就是如何在多级分页开启的时候从内存获取到对应数据结构的地址并赋值,有物理地址和虚拟地址间的转换、页表的访问权限设置相关的内容。

ch5

这一章基于多级页表机制对任务执行这块进行再次抽象,加入了任务编号、任务队列管理,主要是对任务抽象的部分是需要花些时间需要理解理解。

这一章的作业是老作业迁移适配外,在实现 spawm 和 priority 系统调用接口功能:最主要的还是在对分级页表比较熟悉的情况下,对已经实现的任务管理功能,如 exec、fork 等实现的理解后,spawn 其实就是创建一个新的 TaskControlBlock 并添加到任务队列,并绑定给当前 TaskControlBlock 的 child 下,但同时也别忘记了给这个新的 TaskControlBlock 绑定 parent。另一个 priority 就用户可以设置这个值来简单的控制下程序执行的顺序,来让某些程序优先执行。

后续计划

看时间情况继续学习后续的 ch6、ch7、ch8 的内容,完成整个训练营任务。