解决rust-analyzer
的问题
创建:.vscode/settings.json
:
1 | { |
这里一定要注意对
rust-analyzer
进行Restart Server
,这个操作也可以见我的这篇博客.
直接用vscode打开wsl环境下的工程
直接在wsl
的cmd
下输入code .
.
这里可能会显示在安装VSCode Server
,不是在安装VSCode
本身,而是在安装一个服务,安装好自己就帮你打开了.
组件化内核
不同的内核要求就有不同的设计.
Linux是宏内核就照着宏内核设计.
那么组件化内核就照着组件化内核设计.
复杂的内核=很多小的内核合起来的
宏内核和Hypervisor与Unikernel没有明显的界限,因为这实际上是一个设计模式.
- 协作性
- 定位容易,维护难度低
- 开发效率高
用组件化内核替代原本的宏内核.但是这个内核是组件化开发的,最终组成一个总的内核.
UniKernel
有一个非常不同的地方应用和内核都在内核态并且在同一个地址空间里,互相是可见的.
RTOS似乎就是一个UniKernel.
那么打包完是同一个image.
那么宏内核是内核是一个image应用是另一个image,用syscall来打通.
因为是同一特权级,所以安全性不太行.
那么如果UniKernel需要保证安全性,那么就需要Hypervisor来帮你解决这个问题.
不同的组件可以用axruntime来组织.
裸机->逻辑程序
裸机->unikernel->OS程序
用OS去实现RTOS.
用裸机+虚拟化实现类似于
docker
的功能.
实验支撑的开发
每一节课是一个针对每个需求的内核.
那么新的内核是从旧的内核组建而成的.
宏内核和Unikernel的区别是加了用户特权级和用户的地址空间.看起来是增加了两个组件形成的,实际上到了很远的一条路.
让Unikernel实现Hypervisor,这样就可以实现虚拟化.从Host升级到Guest.
宏内核的东西比较复杂
实验环境的建立
使用WSL2+Ubuntu 22.04.2 LTS环境.
Windows Terminal - Windows官方下载 | 微软应用商店 | Microsoft Store
框架
引导过程
是通过axhal.
实际上使用的是_start
这个指针.
通过一系列的asm操作来进行完成页表和函数调用和MMU的启动的支持.
日志级别控制与features
使用Cargo.toml
来控制features
.
使用环境变量:
- 具体环境变量
- 使用通用环境变量
三个部分汇集起来到axfeat
课后练习-支持带颜色的打印输出
[print_with_color]: 支持带颜色的打印输出。
要求:
- 修改一个组件的实现
- 执行make run A=exercises/print_with_color
这一点非常重要
预期:字符串输出带颜色。(具体颜色不做要求)
提示:在不同层次的组件上修改,影响的输出范围不同。
例如,修改axstd可能只影响println!的输出;修改axhal则可能一并影响ArceOS启动信息的颜色。
通过修改APP层实现
修改exercises\print_with_color\src\main.rs
:
1 | ... ... |
分支名称:
print_with_color_app
通过修改ulib:axstd
来实现
在ulib\axstd\src\macros.rs
:
1 |
|
分支名称:
print_with_color_axstd
通过修改axhal:write_bytes
来实现
修改modules\axhal\src\lib.rs
:
1 | ... ... |
分支名称:
print_with_color_axhal
通过修改axlog:ax_println
来实现(不了)
可以看到:modules\axruntime\src\lib.rs
里调用了这个宏,
1 | ... ... |
并且这个宏的位置在modules\axlog\src\lib.rs
,我们修改它:
1 | ... ... |
这里只能使得如下部分变成红色,而不能满足题意:
1 | d8888 .d88888b. .d8888b. |
分支名称:
print_with_color_axlog
问题和疑问
make
是怎么编译的?axruntime
是怎么加载的编译好的APP并且运行的?sbi
用的什么?
为axstd
支持Collections
具体可以看这里的介绍:集合类型 - Rust语言圣经(Rust Course)
最开始我学Rust
的时候没有内化这个概念.
实际上集合类型就是Vector
和HashMap
以及String
这样的类型.
其实到这里我们自己就可以总结出了:
类型长度可变->指针地址和大小变量存在栈上,具体内容存在堆上->需要堆的支持->需要动态内存分配器.
那么实际上要支持Collections
就是要支持一个动态内存分配器.
rCore
中对动态内存分配器的描述:[rCore学习笔记 028] Rust 中的动态内存分配 - winddevil - 博客园
rCore
中引用的动态内存分配器:[rCore学习笔记 029] 动态内存分配器实现-以buddy_system_allocator源码为例 - winddevil - 博客园
这里注意这张图,在Unikernel
中,内存管理器也是和APP放在一起的,主要的思想还是APP和Kernel在同一特权级.
alloc
实现接口
这个是需要实现两个功能:
- 实现
byteAllocator
和pageAllocatir
. byteAllocator
只需要实现rust
自带的一个Trait
即#[global_alloctor]
即可pageAllocator
的实现方式是用了一个全局变量来实现相应的功能的
这里的源代码在modules/axalloc/src/lib.rs
这里看.
这里是实现了一个
GlobalAllocator
类,然后实例化一个
- 实现
GlobalAlloc
的Trait
给它,有alloc
和dealloc
这两个方法,即可实现内存分配.用#[global_alloctor]
标注这个实例即可.- 为
GlobalAllocator
实现了alloc_pages
和dealloc_pages
,通过直接获取这个实例
这里实现的时候trait
的fn
和struct
本身的fn
重合,这是允许的.
调用时,
MyTrait::do_something(&struct)
和struct.do_something
两种调用形式是调用的不同的方法.
实现方法:
- 最开始的时候页分配器是先分配一部分内存给字节分配器的
- 先找字节分配器分配,任何如果不够了找页分配器追加
在当前为了给HashMap
提供分配器的是core
库里allocator
里自带的TlsfByteAllocator
作为字节分配器,BitmapPageAllocator
作为页分配器.
那么为了实现自己的字节分配器就需要要给它实现两个Trait
,即BaseAllocator
和ByteAllocator
.
这个下一节可能会讲到.
课后练习-支持HashMap类型
这里要搞懂关于库的文件夹的互相依赖关系.
为什么core
里没HashMap
?
因为HashMap
需要的随机数生成器涉及到体系结构.
那么这里的random()
是来自于axhal
就非常的合理了.
有关于Cargo.toml
两个Cargo.toml
:
.\Cargo.toml
ulib\axstd\Cargo.toml
使用cargo tree -p axstd -e features
可以很好地看到features
结构.
有关于结构问题
这里注意一点,在ulib/axstd/src/lib.rs
里已经引用了collections
,
1 | pub use alloc::{boxed, collections, format, string, vec}; |
而在exercises/support_hashmap/src/main.rs
里引用的是:
1 | use std::collections::HashMap; |
在rust
这个项目里发现,library\alloc
的collection
里并没有HashMap
,HashMap
是在library\std
的collection
里.
所以其实我们是要把这两个collection
的内容合并.
直接使用hashbrown
创建ulib/axstd/src/collections/mod.rs
:
1 | // 合并alloc::collections里的内容 |
在ulib/axstd/Cargo.toml
加入hashbrown
:
1 | ... ... |
完全仿写std
库
自己实现以hashbrown::HashMap
为base
的HashMap
.
通过题中给出的random
实现RandomState
.
想在axstd
中调用axhal/random
,需要在ulib/axstd/Cargo.toml
里加入:
1 | [dependencies] |
#TODO
拉链法实现
#TODO