1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 16:36:18 +04:00
rCore/docs/1_OS/Log.md

324 lines
17 KiB
Markdown
Raw Normal View History

2018-05-25 18:15:37 +04:00
## 日志
这里以天为单位,以周为周期,按时间倒序维护了开发日志。
2018-06-15 07:50:51 +04:00
### 第15周
#### 2018.06.06FS-Process
- 学习xv6/uCore中文件系统上层接口
- 尝试在Rust中实现RootFS和FileManager
#### 2018.06.04:完成同步互斥
- 完成了信号量、条件变量,哲学家就餐问题
- 简易实现了std::sync::mpsc中的FIFO消息传递通道
#### 2018.06.03:新的物理帧分配器
- 实现了新的物理帧分配器支持回收。其本质是一个0-2^k的整数分配器内部用bitset维护并形成树状级联结构每16bit对应上层1bit用x86专有指令bsr相当于整数log2实现快速分配。目前使用容量为64Kb的分配器可维护256MB内存空间实际占用内存9KB以内。
- 由于Rust语言的限制该类无法实现const fn构造函数只能使用lazy_static等tradeoff进行运行时初始化。这时必须开启至少O1优化使用RVO返回值优化防止在栈上构造再复制到全局变量否则会栈溢出。
#### 2018.06.02:重构内存管理模块
- 大幅调整了内存管理模块对外统一使用MemorySet管理一个线程的内存简化了使用方式。
#### 2018.06.01:同步互斥进阶
- 完成了OS内用锁实现的哲学家就餐问题和OS外用条件变量的实现。
- 关于Rust并发模型Rust的所有权机制使得它可以轻松支持【锁数据】而不是【锁代码】。这使得在实现上述哲学家就餐问题时用锁非常自然而用条件变量管程则不太直观。
### 第14周
#### 2018.05.31:同步互斥初步
* 将spin::Mutex代码fork了一份到内核中在其中实现了一个接口框架可以自由替换底层支持。在此框架下已经实现了自旋锁(spin_lock)、禁止中断的自旋锁(spin_lock_irqsave),接下来就可以实现自动调度的锁了。
* 实现了禁止中断自旋锁后即可打开syscall的中断了。
* 为了方便内核态的线程操作将原有的process模块又封装了一层thread接口长得和标准库一模一样std::thread。这样具体的同步互斥问题如哲学家就餐可以先在外部环境中依赖std库实现并测试然后方便地移植到OS环境中。
* 在此过程中又学习了关于内核抢占、同步互斥锁等相关资料感觉又是个大坑。并且发现我实现的RustOS一直是内核可抢占的主要依赖时钟中断进行线程切换不知要不要改掉。
2018-05-25 18:15:37 +04:00
### 第13周
本周完成的主要工作:
- 重新实现中断处理入口
- 实现内核态switch和调度器
- 从disk0中读取用户程序
- 支持运行大部分ucore用户程序
#### 2018.05.24 / 25最终报告
#### 2018.05.23实现了调度器IDE驱动
- 参考uCore实现了RRScheduler和StrideScheduler并可以正确执行priority程序。
- 直接Copy了隔壁15组port的ucore的IDE驱动代码略作修改后就可以使用了。
- 为SFS模块增加了一个BlockedDevice接口为它实现Device接口即支持以字节为单位读写方便对接真实设备。
#### 2018.05.22实现了xv6/ucore中的switch(),调整了切换进程的方式
- 为了实现调度器我阅读了xv6的文档结果发现自己之前对它切换进程方式的理解都是错的[捂脸] 长教训以后一定硬着头皮读懂已有代码不能闭门造车233
- 之前每次中断后运行的内核态代码和内核栈是不可切换的切换进程的方法是在结束中断处理时指定新的rsp地址这样就可以从别的中断帧恢复环境。这样带来的限制是像sys_wait这种异步操作实现起来很麻烦。
- 有了switch()之后就可以自由地在内核线程之间切换。我今天实现了这个并用它简化了sys_wait。
- 引入switch()后要运行一个新的线程变得更加复杂初始的内核栈上要有TrapFrame+Context。此外我发现调用switch进入scheduler线程再switch到其它线程这一过程好像用中断也可以实现类似上述第2条描述的方法
#### 2018.05.21可以正常跑uCore大部分的用户程序
- 实现了在用户程序发生异常时kill掉它又支持了一批uCore的用户程序。有了昨天统一中断处理的基础这个就很容易了。
- 使用mksfs将xv6的64位用户程序也做成了SFS磁盘将它和ucore程序的SFS磁盘一起添加到git中。
- 修复了Release模式下SMP启动的Bug添加了一些volatile。
- 修复了waitpid可以正常跑exit和sleep了。
此时还不支持内核线程的切换详见05.22的说明),所以(int*)store要先保存下来不太自然。
#### 2018.05.20可以正常跑uCore一半的用户程序
写了一个简易事件处理器,支持定期调度+唤醒线程
- 最初实现的是【推模式】逻辑比较复杂用户提供回调函数当事件发生时自动调用。由于Rust的安全约束非常严格为了通过编译代码非常复杂。
- 最后实现的是【拉模式】,逻辑比较简单,用户只提供事件内容,在每个时刻都主动询问当前是否有事件,并做处理。这种方式下事件处理器很轻巧,可以内嵌在使用者中,调用关系简洁。
重写了中断处理入口
- 原来使用Redox的处理方式
- 每个中断有不同的入口,保存的中断帧可以有不同形式(性能考虑?)。
- 但现在需要每种中断都能够进行进程切换,这就需要一个统一的中断帧和处理过程。
- 现在改用ucore/xv6的处理方式
- 建立中断向量表vectors补齐错误码跳转到统一的处理函数alltraps。
- ucore/xv6中vectors.S是用一个perl脚本生成的在Rust中改用build.rs生成。
- 如此修改后逻辑更加简洁清晰而且修复了一个长期阴魂不散的Bug
精简了IDT的代码
- 最初使用x86_64库的IDT结构之后由于类型不匹配的原因改用Redox的代码
- 现在随着我姿势水平的提高学会了绕过类型约束的unsafe黑魔法重新用起了x86_64库砍掉了100行的基础代码
- 历史总是螺旋式上升的,马克思诚不我欺也
Travis上编译问题
- 目前在macOS和docker上均可通过编译
- 但在Travis上会出现链接问题不知如何解决
#### 2018.05.19引入log模块支持向终端输出彩色文字
- 可以用五种不同级别输出调试信息errorwarninfodebugtrace
- 它们在终端以不同颜色显示使用了Linux终端控制符
#### 2018.05.18可以从sfs.img中加载用户程序
- 将sfs.img做成.o硬链接到kernel配合之前写好的SFS模块读取数据
### 第12周
本周完成的主要工作:
- 可以运行用户程序xv6的64位程序 + ucore的32位程序
#### 2018.05.18可以在CLion中配合gdb调试
- x86_64的QEMU在gdb链接时会报错Remote 'g' packet reply is too long
- 其实《Writing an OS in Rust》已经给出了[解决方案](https://os.phil-opp.com/set-up-gdb/)。然而我build gdb时编译出错。。
- 最后解决方案macOS下使用brew安装 altkatz/gcc_cross_compilers/x64-elf-gcc。这个自带上述bug的补丁在CLion中配置使用这个gdb即可。
#### 2018.05.17可以运行ucore的32位用户程序
- 不能直接在Long Mode下跑因为有些指令是环境相关的例如push 0x64会使得esp -= 8
- 因此需要进入Compatibility Mode这方面资料好像很少。[OSDev的一个贴子](https://forum.osdev.org/viewtopic.php?f=1&t=24594)指出只需载入32位的CS即可即修改L-Bit但经测试无效OS会将其识别为16位CS。之后我把xv6的UCODE和UDATA 32位段描述符直接复制过来就可以正常跑了。经测试DS也需要是32位的。
- 目前已经实现了若干ucore系统调用可以跑hello程序了
#### 2018.05.14Shared-memory & Copy-on-write
- 利用Rust的Trait特性将扩展代码都写在一个文件中[代码](https://github.com/wangrunji0408/RustOS/blob/dev/src/arch/x86_64/paging/cow.rs)。同时包含文档和测试。
#### 2018.05.13:可以运行用户态程序
- 可直接运行xv6 x86_64中的用户程序二进制兼容下一步兼容ucore的32位用户程序
- 实现了一个最简单的syscallwrite可将字符输出到屏幕上
- 试图实现fork时遇到bug…
#### 2018.05.12添加MemorySet / Area结构
- 对应ucore中的mm&vma用来描述虚拟内存集/段
- 将【内核页表重映射 remap_the_kernel】过程用此结构重构
- 为下一步加载用户态程序做准备
### 第11周
本周完成的主要工作:
- 通过兼容层将Rust SFS对接到ucore_os_lab上
#### 2018.05.07完成与ucore_os_lab的对接
- [总结报告](https://github.com/wangrunji0408/SimpleFileSystem-Rust/blob/master/docs/rust_port_report.md)(后半部分)
- [整合后的ucore](https://github.com/wangrunji0408/ucore_os_lab/tree/rust-fs/labcodes_answer/lab8_result)
#### 2018.05.06把SFS链接到uCore
将Rust lib链接到ucore遇到的问题
- 真的痛苦,估计得掉层皮
- 遇到最多的是链接丢失问题。ucore_os_lab的linker script少写了一些section包括`*.data.*``*.got.*``*.bss.*`导致Rust lib链接过去后丢失了一些段比较坑的是这不会有任何提示。没有成功重定位的地址都是0运行时直接Page fault。为了找出出错位置各种gdbobjdump全上了还得看汇编追踪寄存器真是大坑。
- 另一个小问题是Rust lib会引用一些LLVM内置函数如udivdi3都是除法运算相关链接时会报undefined symbol。但实际上并没有代码用到它们。《Writing an OS in Rust》中提到了这个问题它的解决方案是链接时加--gc-sections选项将未用到的段删掉结果我对ucore如此操作之后所有段都没了都boot不起来。。。最后是在C中强行定义这些符号解决的。
关于ucore VFS兼容层的设计
- ucore VFS中fs和inode头部是具体FS的struct。Rust VFS使用Rc指针相互引用。为了将它们合并起来考虑过两种方案在头部放Rc指针或放Rust SFS的结构本体。前者相当于将Rust VFS作为ucore SFS后者则是直接将Rust VFS合并到ucore VFS。
- 放指针还需建立Rust INode => ucore INode的反向引用要么侵入式地增加Rust INode的字段要么在兼容层搞一个全局Map。这种方式耦合较低但多一层指针跳转性能可能略差。
- 放结构需要在Rust new出SFS结构时做文章 委托ucore分配多一点空间并做VFS的初始化得魔改Rust的全局内存分配器。这种方式耦合较高需对Rust结构的实际内存布局有深入理解。
- 根据【把方便留给别人把困难留给自己】【最大兼容最小耦合】的原则我选了放指针的方案目前还在Debug中`_(:3」∠)_`
### 第10周
本周完成的主要工作:
- 进程模块:只实现了内核线程切换
- 文件系统作为独立模块实现完毕接下来尝试链接到ucore lab8
#### 2018.05.04 / 05SFS文件系统
- 基本功能实现完毕,附有单元测试
- 正在尝试和ucore lab8链接
- 阶段性[移植报告](https://github.com/wangrunji0408/SimpleFileSystem-Rust/blob/master/docs/rust_port_report.md)
#### 2018.04.29 / 05.01SFS文件系统
[GitHub仓库](https://github.com/wangrunji0408/SimpleFileSystem-Rust)
基础结构移植完毕各项功能正在重写计划导出C接口兼容ucore预计1k行代码可搞定
#### 2018.04.26 / 27内核线程切换
- 实现了简单的内核线程切换
每个线程拥有一个[内核栈],它是当线程运行中发生中断时内核使用的栈,保存着线程的[上下文]信息(中断帧)。对于内核线程而言,其[运行栈]和[内核栈]是统一的。
与ucore不同的是
- 每个线程的内核栈上只保存自己的[上下文],调度器不能修改它的内容。且[上下文]只需保存这一份,调度器也不需要访问它的内容。
- 恢复[上下文]不使用汇编,而是依靠[中断服务例程]结束时从[内核栈]中pop[中断帧]。
为了实现这点,[中断服务例程]保存完[中断帧]后把当前rsp传给调度器调度器将其保存并用下一个待执行线程的rsp更新之在最后一次从此线程切出时保存。[中断服务例程]结束时重置rsp切换到另一个线程的[内核栈]上,恢复[中断帧]。
- 实现了int触发内核态和用户态切换lab1 challenge
进入用户态前需在TSS中设置返回内核态时的rsp。FIXME初始化多核后会导致设置失效。
确认以下设置否则会出现GPF
- 段描述符DPL=3
- 页表中设置相应页为[用户可访问]
### 第9周
本周应付期中考试、大作业等事务,进展不大。
#### 2018.04.25:页置换算法
实现“改进的时钟置换算法”
### 第8周
本周完成的主要工作:
- 将Kernel虚地址移到高区
- 完成lab1的移植主要是各种驱动
- 完成多核的初始化
接下来可以进行的工作:
- 完善内存管理完善allocatormm&vma结构页替换算法
- 其它驱动的移植例如IDERucore组
- 进程管理模块
#### 2018.04.19:内存模块
在外部模块定义了页替换模块接口实现了FIFO算法并实现了Mock页表用来单元测试。
#### 2018.04.18:多核启动
完成多核AP的启动和初始化LocalAPICGDTIDT
#### 2018.04.17:设备中断
完成以下设备初始化和中断串口键盘PIT时钟
#### 2018.04.15 高地址
完成高地址修改,合并到主分支
- 2天前页表重映射后崩溃的原因是新页表中权限设置错误blog_os根据kernel.elf中各段的属性来设置页的权限使用objdump查看elf的段信息后确认有问题根本原因是linker script写的不对我使用rodata32/bbs32/text32来标记BootLoader中的各段以把它们和Kernel中的区别开但这导致ld无法正确设置它们的属性某些应该可写的段被设置为只读最终造成PageFault。解决方案是把名称改成rodata.32/bss.32/text.32。
- [参考教程](https://wiki.osdev.org/Higher_Half_x86_Bare_Bones)
- 【新技能】在没有初始化中断时出现TripleFault的Debug方法利用qemu
- 加入参数-d int即可显示每次中断时的CPU信息
- 发生PageFault时检查RPI出错位置和CR2访存目标
#### 2018.04.14:设备初始化
- 页表建立临时映射以满足各设备初始化时访问特殊物理地址的需求。TODO撤除or直接映射全部设备空间
- 完成以下初始化LocalAPIC链接CIOAPICGDT导入xv6 x86_64的描述符PIC复制Redox
- PIC和APIC都实现了产生时钟中断
- [关于实现中断的问题手册](https://wiki.osdev.org/I_Cant_Get_Interrupts_Working)
#### 2018.04.13:高地址
尝试将Kernel虚地址移到高地址区遇到很多问题
- 需要修改linker将kernel虚地址置为高地址区但实地址还在低地址区AT指令
- 需要修改初始页表将四级页表项的1st和510th同时映射到低1GB物理空间。由于BootLoader执行时PC使用实地址因此在进入Rust之后才能把1st页表项撤销掉。
- 页表重映射remap_the_kernel修改后还没有调试成功重置CR3的瞬间会崩掉
- 经过测试初始化IDT只能在页表重映射后进行放到前面会直接崩掉在开启IDT前不好Debug。
### 第7周
#### 2018.04.12中期汇报文档和PPT
- [中期汇报文档](https://github.com/wangrunji0408/RustOS/blob/dev/docs/MidReport.md)
- [中期汇报PPT](https://github.com/wangrunji0408/RustOS/blob/dev/docs/MidPresentation.pdf)
#### 2018.04.11学习xv6C语言绑定
- 阅读xv6代码
- 实现了Rust对C的绑定
- 直接extern符号链接即可不需要bindgen
- bindgen输出的代码中把std::raw::*替换成原生类型即可
- RISCV Rust Toolchain找到了一个日本人写的[采坑系列文章](http://msyksphinz.hatenablog.com/entry/2017/11/29/021030)写于2017.12成功在HiFive上跑起来了。
#### 2018.04.09TravisCIC语言绑定
- 从内部退出QEMU的方法
- 运行qemu时加入 -device isa-debug-exit
- 执行outb(0x501, k)会退出qemu错误码为2k+1
- [在Travis中运行qemu的方法](https://github.com/jdub/travis-qemu-example)
- 结合上述方法可以在Travis上做集成测试
- qemu环境下单测比较困难rust自带的测试框架也无法使用
- 尝试Rust FFIC语言绑定
- [Rust-Bindgen](https://rust-lang-nursery.github.io/rust-bindgen/)
- 已经对xv6生成了绑定
- 但它依赖std库不好集成到只依赖core的RustOS中
- 另一个移植思路是用C绑定Rust把原有的模块逐个用Rust重写对C提供临时接口保持OS始终完整
#### 2018.04.07ACPI
初步完成ACPI的移植
之后的底层驱动部分,考虑 找Rust库 > 从RustOS里摘 > 从xv6移植。
### 第6周
#### 2018.04.04RISCV
找到了RISCV Rust Toolchain的Docker编译样例项目失败看上去除了作者本人还没有别人成功过。
#### 2018.04.0232位boot
在blog_os x86_64框架下实现x86的boot
#### 2018.04.01RISCV
构建RISCV32/64 Docker
尝试构建RISCV Rust Toolchain失败