diff --git "a/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223shj.md" "b/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223shj.md" new file mode 100644 index 0000000000..64c563eb7b --- /dev/null +++ "b/source/_posts/2024\347\247\213\345\206\254\345\255\243\345\274\200\346\272\220\346\223\215\344\275\234\347\263\273\347\273\237\350\256\255\347\273\203\350\220\245\347\254\254\344\270\211\351\230\266\346\256\265\346\200\273\347\273\223shj.md" @@ -0,0 +1,95 @@ +--- +title: 2024秋冬季开源操作系统训练营第三阶段总结-shj +date: 2024-11-31 11:11:11 +categories: + - 2024秋冬季开源操作系统训练营第三阶段总结 +tags: + - author: Foreverhighness + - repo: https://github.com/Foreverhighness/oscamp +--- + +## Submit Blog + +`rcore-blog` 这个 repo 已经挺大的了,网不好的 clone 下来还挺费时间的。 + +实际上可以直接在 Github 上写东西提 PR 不需要本地 clone 下来,Github 网站本身就提供了这样的功能。 + +打开 [`rcore-blog`](https://github.com/rcore-os/blog) 项目主页,在绿色按钮 `Code` 左边有个 `Add file` 的按钮,可以直接用 `Create new file` 写所需要的 Blog 或者用 `Upload files` 直接上传写好的 md 文件。 + +需要注意的点是要切到 `rcore-blog/source/_posts` 这个目录下,不然文件的位置不对。 + +虽然直接在网站上写,文件里的内容还是要注意一下加上 Blog 需要的分类/标签/作者信息等,这些东西随便打开一个 md 文件复制一下就行。 + +缺点是数学公式支持和插入本地图片可能麻烦点。 + +注意一下 Commit changes 里上面是 Commit message, 下面只是辅助描述,一般只用改上面就行。 + +## print_with_color + +引用了我很喜欢的一个库 `ansi_rgb`, 秒了。 + +## hashmap + +在 axstd 里开个 `mod collections`, 再引入 `hashbrown`, 秒了, + +## alt_alloc + +测试里实际上没有用到 Page alloc 的接口,写完 Byte alloc 就通过了。 + +## rename and mv in shell + +有意思的来了,实际上 `fs::ax_rename` 没有很好的处理 './' 和 '/' 这些前缀后缀。 + +我认为在 shell 的逻辑里处理文件访问文件名是一个错误的抽象,因此我写的时候决定不在 shell 代码里处理路径问题。 + +观察到 ls 命令可以处理前缀后缀,一路跳转后决定在 `modules/axfs/src/fs/fatfs.rs` 中 `DirWrapper::rename()` 中进行处理,刚好旁边就有 `remove` 方法可以参考。 + +## lab1 + +觉得没意思就没写,看群里大佬们玩挺花的,我自己想能不能玩点 hack, 最后确认到 main 地址是可以获取的,main 的 text 内存是可读可写的。 + +也就意味着可以整花活来跳转到自定义的 `main` 函数当中去,但是想到这样就要做 platform 的适配,感觉工作量并不小,就没整。 + +## set populating to false + +从 `AddrSpace` 为入口开始找参考的辅助函数,发现直接就有 `handle_page_fault` 可以用,一调用就过了,看看 m2 的参考才知道 `user` flag 的作用。 + +## mmap + +这个练习用到的 api 挺多,需要找找 `find_free_area`, `api::fs`, `LinuxError`, `AxError`. + +因为 rust 没有 goto, 所以错误处理需要包一层 `fn() -> Result`, 这样才能用 `?` 来减少代码量。 + +`?` 只能在 `Result` 和 `Option` 上用就已经很强大了,如果 [`try_trait_v2`] 稳定了都不用包一层 fn 了,不敢想象有多爽。 + +[`try_trait_v2`]: https://rust-lang.github.io/rfcs/3058-try-trait-v2.html + +# simple hypervisor + +这个练习不错,有一定难度。 + +首先处理 `csrr a1, mhartid` 这条指令。 + +尝试了下直接用 `asm!("csrr {rd}, mhartid", out(reg) rd)` 进行代理,不过如我所料的是 hypervisor 也没有 M 权限,所以不能这样弄。 + +但是可以注意到 `mhartid` 的语义是 cpu id, 所以可以直接用 `axhal::cpu::this_cpu_id()` 的值就行。 + +不过事实上根据语义应当返回的值是 vcpu id, 也就是 hypervisor 让 Guest 看到的 cpu_id, 但是我懒得添加相关的逻辑了。 + +把值写到上下文的 `a1` 寄存器之后需要把 `spec` 也加上指令长度。 + +然后处理缺页,注意到 `src/task.rs` 里有 `TaskExt` 的定义,并且压根没用上,可以知道大概需要用上。 + +但是我偷懒没去用,而是直接改了 `vmexit_handler` 和 `run_guest` 的接口,加一个 `uspace` 参数,这样就能在 `vmexit_handler` 里修改页表了。 + +对于一个内核来说,所有内存地址都是可以访问的,所以直接用 `uspace.map_alloc()` 就行了,权限可以全加上。 + +一个很有意思的点是 hypervisor 寻址用的是 `satp`, Guest 机器寻址用的是 `hgatp`. 所以写入用 `uspace.write` 来进行。 + +## Emulator mode device + +直接把注释去掉就能通,所以改起来挺简单的。把 `populate` flag 置为 false 会导致 `Supervisor Page Fault` 错误。 + +刚好文件里就直接给出了一个 `load_vm_image` 辅助函数,直接拿来用把参数改改就完成了。`size` 可以通过 `fs::metadata` 来获取。 + +之前提到过 aspace 目前不支持 File 类型的 Backend, 不然就可以把 `populate` 置为 false 了,会快上不少。