diff --git a/README.md b/README.md index 146dffd..d32620d 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,29 @@ The main repository of Starry-OS, which will assemble all kernel components into ## Structure -TODO \ No newline at end of file +![avatar](./doc/figures/Starry.svg) + +## Build and run + +```sh +# Run in unikernel architecture + +# $ make A=apps/ ARCH= run + +# The is the application stored in the ./apps folder. + +# The can be x86_64, risc64 and aarch64. + +$ make A=apps/helloworld ARCH=x86_64 run + +# Run in monolithic architecture + +# Make the testcases image first + +# $ ./build_img.sh + +$ ./build_img.sh x86_64 + +$ make A=apps/monolithic_userboot ARCH=x86_64 run +``` + diff --git a/doc/OS-Train-Repo/REPORT.md b/doc/OS-Train-Repo/REPORT.md deleted file mode 100644 index 3167f48..0000000 --- a/doc/OS-Train-Repo/REPORT.md +++ /dev/null @@ -1,135 +0,0 @@ -# StarryOS 的 syscall 层模块化 - -## 训练目标 - -本次训练的目标是将 ArceOS 宏内核化成果之一的 Starry 内核的 syscall 层进行进一步的模块化划分,从而做到更好地与 Unikernel 架构兼容,同时支持自选功能启动。 - - - -## Starry 的 Unikernel 兼容 - -### 模块划分 - -将ArceOS与宏内核的关系划分如下: - -* ArceOS中可直接沿用:log、driver以及一系列解耦的crate -* ArceOS中需要调整适配:任务调度、特权级转化等 -* ArceOS中需要添加:地址空间、进程、信号、文件系统、用户库等内容 - -![avatar](../figures/train-week2-1.png) - -### 使用 feature 区分 - -我们通过使用 Rust 支持的条件编译特性 feature 来进行两种架构不同运行流的兼容: - -feature 的使用基本有两种情况: - -1. 通过 feature 添加成员域或者额外处理语句 -2. 通过 feature 选择不同的分支语句 - -一个使用例子如下: - - - -![avatar](../figures/train-report1.png) - -依据 ArceOS 良好的模块化特性,我们能够仅在顶层模块的少数语句中加入条件编译区分就实现了区分两种架构不同执行流的目的。 - - - -之后便是对已有的 ArceOS 测例进行调试的过程,调试的相关信息放在了[Starry/doc/OS-Train-Repo/Week3.md at main · Azure-stars/Starry (github.com)](https://github.com/Azure-stars/Starry/blob/main/doc/OS-Train-Repo/Week3.md) - - - -## 自选架构启动 - -底层架构处理好了之后,需要考虑的是用户如何方便地选择不同的架构启动。 - - - -以 C 语言为例,我们希望通过代码链接到不同的库来启动不同架构的内容。 - - - -* Unikernel:晏巨广学长致力 ArceOS 的 musl-libc 支持,将 C 代码链接到 axlibc 上之后,应用程序可以直接调用 Unikernel 接口。 - - - -* 宏内核:应用程序和用户库编译为 ELF 文件之后加载到文件镜像,通过汇编指令跳转到 axhal 层,由内核转发到 syscall 层来处理。 - -由于额外实现一个与 ArceOS 接口解耦、用于和用户程序进行编译的库没有太大意义,所以我采用了用户程序直接和本地自带的 libc 用户库编译的方式。 - -对编译方式进行修改:当指定`STRUCT=Monolithic`时,采用宏内核启动,此时会对指定的源代码进行如下操作: - -1. 通过外部编译器,如 riscv-musl-gcc 编译器对源代码进行编译 -2. 将得到的可执行文件打包到文件镜像中 -3. 启动宏内核,读取外部的可执行文件,开始运行 - - - -当采用宏内核运行 `helloworld`程序时,执行指令如下: - -```shell -$ make A=apps/c/helloworld STRUCT=Monolithic run -``` - -有如下运行结果: - -avatar - - - -## Syscall 层的进一步细分 - -### 背景 - -原有的 syscall 层包含了内核的几乎所有可选功能,当选用宏内核启动的时候需要对所有可选功能进行实现,这会导致编译与启动均消耗较多时间 - -我们计划根据指定运行的应用程序选择对应的可选功能启动,即定制化内核。 - - - -### 实现方式 - -根据应用程序运行所用到的 syscall 功能来决定启动哪些内核的可选功能。 - -当前的处理方式是按照所需要的syscall所属的模块,来批量提供这个模块中的所有syscall(如只要求open,可能会同时提供同类的open、write、close) - -将当前的模块划分为如下部分: - -* syscall_utils:提供一些通用的接口和系统调用用到的结构体定义 -* syscall_task:主管任务模块,包括进程管理、调度、互斥资源管理等 -* syscall_fs:文件系统对外封装,包括打开、关闭、读写文件等Linux相关语义支持 -* syscall_mem:内存管理模块封装,包括动态分配堆内存、修改页面权限等操作 -* syscall_net:网络控制模块,提供 socket 等网络相关结构的支持 -* syscall_entry:系统调用入口,通过不同的 feature 启动不同的模块,并且加入对应的底层模块 - -每一个 syscall 模块下面还有各自的可选功能,比如 syscall_task 模块还带有信号、futex等可选功能。 - -通过选用不同的功能 feature,将定制的模块加入到内核镜像中一起启动。通过测试可以发现选用不同的 feature 时内核镜像大小确实有明显的区别,因此确实做到了模块的定制化插入。 - - - -## 从源代码到内核的自动化启动 - -* 背景:在完成了 syscall 层的模块化之后,仍然需要通过手动修改 cargo.toml 或者编译指令的方式来进行可选启动,思考是否存在根据给定的应用程序的代码自动启动的方式。 - -* 实现方式:通过工具分析应用程序可能用到的 syscall,根据 syscall 来选择需要引入的 syscall 功能 -* 分析工具选择:静态分析工具rust-objdump -* 分析方法:利用 rust-objdump 来解析即将运行的应用程序镜像得到汇编代码,获取所有系统调用入口对应的系统调用号,从而得到一个 syscall list,传给内核转化为对应需要启动的功能 - -* 执行效果:执行如下指令: - - ```shell - $ make A=apps/c/helloworld STRUCT=Monolithic LOG=off run - ``` - - 会自动生成一个 `features.txt` 传递给 内核,用于选择对应的 feature 和 syscall 功能启动。 - - 查看内核编译指令,确实是按照对应的 feature 启动了,并且没有加入额外的无关 feature。 - - - -## 总结 - -本次训练是在操作系统比赛的基础上对 Starry 的进一步维护,优化了其内部结构,也做到了设计初期想要做到的双架构兼容,并且额外实现了自动化定制内核的功能,可以为将来基于 ArceOS 的宏内核开发以及操作系统比赛提供参考。 \ No newline at end of file diff --git a/doc/OS-Train-Repo/Week1.md b/doc/OS-Train-Repo/Week1.md deleted file mode 100644 index dc466cf..0000000 --- a/doc/OS-Train-Repo/Week1.md +++ /dev/null @@ -1,111 +0,0 @@ -# Week1 - -> Author:郑友捷 - -本周主要工作为确定选题。 - -## 选题简介 - -StarryOS 的可插拔 syscall 模块实现 - -## 选题说明 - -当前的 StarryOS 是基于 Unikernel 架构的 ArceOS 并进行一定改造得到的宏内核。理论上它可以在编译期通过调整编译参数实现宏内核和 Unikernel 两种架构的选择性启动。但是由于比赛时期紧张,同时比赛的测例运行需求比较特殊,导致 StarryOS 现在对 Unikernel 架构的启动支持不是很好。 - -另外,由于比赛需求,StarryOS 启动宏内核时需要将即将运行的用户程序通过 riscv-gcc 编译为可执行二进制文件加入到文件镜像之后才能被运行,但运行 Unikernel 时只需要把用户程序的高级代码源码加载进来一同编译即可。为了更好地保持兼容性,我们希望把两种架构的启动入口都做成通过高级代码源码启动。 - - - -## 选题即将做的工作 - -1. 类比于rCore,添加一个用户库,将用户程序的函数调用转化为`ecall`汇编调用。 -2. 改造编译参数,通过条件编译实现不同架构启动 -3. 构造测例,测试不同架构下的程序性能: - 1. 负载测试性能 - 2. 安全测试 -4. 其他。。。 - - - -# 本周工作 - -## 在 Starry 代码基础上运行原有的 ArceOS 应用 - -原本 Starry 代码是基于 ArceOS 开发的,也始终保持着和 ArceOS 上游的同步。但是由于比赛时期较赶,且缺少规范的 CI-CD,并没有保证 Starry 代码可以始终通过原有 ArceOS 测例。但是现在为了做到两种架构的实时兼容,需要先保证能够通过各自的测例。 - - - -* 尝试通过 ArceOS 原有的 Hello World 测例 - -在尝试通过 Hello World 测例时,由于之前开发的时候对 Starry 更改的绝大多数内容都使用了条件编译,因此并不需要修改过多内容。 - -1. 首先尝试直接编译运行,看看能不能跑。。 - - - - 发现报错: - - ````shell - error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait - ```` - - - - 根据报错,应该是少了全局分配器。但是运行 ArceOS 原有代码时,发现并不需要实现全局分配器也可以编译出这个测例,所以应该是 Starry 在某一个地方引入了一个需要用到堆分配内存的代码,但没有做好兼容。 - - - -2. 对比 ArceOS 代码检查了一段时间,找不到问题,感觉文件量太大不好对比。 - - - -3. 后面思考:`global allocator`是用到堆内存分配机制,在不引入特殊语句的情况下,我们一般只会通过`extern crate alloc`引入`alloc`和与它相关的数据结构,才能做到访问、分配堆内存。 - - 因此尝试全局搜索所有引入了`alloc`的模块,逐个注释掉这些模块对`alloc`的直接引用,进行排查。 - - 仍然报错。。 - - - -4. 但是这个思路应该是对的,于是我根据所有引入了 `alloc` 的模块,看看编译时他们是否被引入,从而确定`alloc`是否被间接引用了。 - - - - 最后发现问题出在`axfs_ramfs`上,它实现了 ramfs 相关的文件系统信息。在 HelloWorld 测例中它不应该被引入,但是编译时发现它出现在了被编译清单上。 - - avatar - - - - 继续检查,发现`axhal`模块引用了这个 crate,最后查明是 trap 处理时使用到了这个 crate 下的一个文件。 - - avatar - - 这个文件是为了统计中断发生的次数,是当时决赛临时添加的一个文件,没有做好兼容导致出现了问题。 - - 将这个文件加上条件编译,同时设置`axfs_ramfs`为可选引入模块,从而解决了问题。 - -* task/yield 测例 - - 需要对 axtask 中一系列结构体成员与其对应的方法加上对应的条件编译语句。为了简约起见,为`TaskInner`新加了一个`impl`,集中存放为宏内核实现加上的内容。 - -* net/bwbench 测例 - - 没有串口输出,需要打开 `LOG=info` 开关才可以看到对应输出,部分输出截取如下: - - ```shell - [ 1.066117 0 axnet::smoltcp_impl::bench:35] Transmit: 0.773GBytes, Bandwidth: 6.184Gbits/sec. - [ 2.065980 0 axnet::smoltcp_impl::bench:35] Transmit: 0.840GBytes, Bandwidth: 6.720Gbits/sec. - [ 3.065980 0 axnet::smoltcp_impl::bench:35] Transmit: 0.744GBytes, Bandwidth: 5.956Gbits/sec. - [ 4.066010 0 axnet::smoltcp_impl::bench:35] Transmit: 0.768GBytes, Bandwidth: 6.150Gbits/sec. - [ 5.066014 0 axnet::smoltcp_impl::bench:35] Transmit: 0.745GBytes, Bandwidth: 5.962Gbits/sec. - [ 6.066012 0 axnet::smoltcp_impl::bench:35] Transmit: 0.742GBytes, Bandwidth: 5.937Gbits/sec. - [ 7.066013 0 axnet::smoltcp_impl::bench:35] Transmit: 0.741GBytes, Bandwidth: 5.930Gbits/sec. - [ 8.066012 0 axnet::smoltcp_impl::bench:35] Transmit: 0.747GBytes, Bandwidth: 5.978Gbits/sec. - [ 9.066032 0 axnet::smoltcp_impl::bench:35] Transmit: 0.744GBytes, Bandwidth: 5.955Gbits/sec. - ``` - - - - - diff --git a/doc/OS-Train-Repo/Week2.md b/doc/OS-Train-Repo/Week2.md deleted file mode 100644 index 80bcc4e..0000000 --- a/doc/OS-Train-Repo/Week2.md +++ /dev/null @@ -1,322 +0,0 @@ -# Week 2 - -> Author:郑友捷 - -## 和向老师讨论 - -第一次交流想要做一个宏内核和 Unikernel 的兼容,计划通过改变编译选项,让相同的源代码能够在不同的架构下运行,从而方便我们在开发应用代码时引入特权级等调试方式。但在第二次交流的时候,老师提到想让我做一个定制化的宏内核,也就是说可以根据需要去选择根据不同的模块来启动宏内核。 - -我理解这应该是一个进阶的过程,第一次交流是编译时调整架构启动,第二次是对宏内核进行尝试类似于 Unikernel 拆分模块的功能。 - -我想之后我的计划是: - -1. 先做到第一步,并设计一些测例来测试 Unikernel 启动下和宏内核启动下的区别。 -2. 若有时间,再尝试第二步,即试着拆分出一些模块,估计是从小往大拆,这一步之前没有尝试过,所以不确定难度多大。 - - - -## 本周工作 - -将宏内核的相关内容和 Unikernel 工作尽可能进行分开,从而尽可能实现两者对共同底层模块的复用与区分。 - - - -### 通过 feature 划分 - -当前想要做到的是编译期进行架构的区别,因此我选择通过 feature 的方式对两者进行区分。 - - - -由于宏内核默认是启动所有的模块,从而构成一个整体(讨论的定制化宏内核除外),因此我们设置一个 feature 为 monolithic,代表启动宏内核架构。当这个 feature 启动时,其他所有的模块都会被包含进来,如文件系统、信号模块、进程控制等等。 - - - -### 模块划分 - -为了更好地进行模块复用,我们先需要对 Starry 中的模块关系进行划分,将其根据 **宏内核是否需要** 和 **ArceOS 是否拥有** 两个标准进行划分。 - -![image-20231007202335681](../figures/train-week2-1.png) - -具体对应到 Starry 上拥有的模块关系如下: - -* ArceOS 中可直接沿用:log、driver 以及一系列解耦的 crate -* ArceOS 中需要适配:任务模块 axtask 、trap异常处理 axhal 等 -* ArceOS 中需要添加:地址空间、进程、信号、文件系统、用户库 - - - -接下来就上面三种情况提到的不同模块进行详细讨论: - -#### 可以直接沿用的模块 - -对于 ArceOS 中可以直接沿用的内容,我们不需要对其进行更改,可以直接复用。 - -但需要注意的是,为了实现宏内核,需要在 ArceOS 原有模块或者 crate 的基础上添加一些新的功能。 - -具体对应的内容有: - -* crate:大部分可以复用,但是对于 page table 需要添加一些函数方便查询与插入。 -* axlog:可以直接复用 -* axdriver: 为了更加快速地读取比赛测例,需要添加 ramdisk 支持,将外部磁盘的内容拷贝到 ramdisk 上。 - - - -#### 需要适配的模块 - -这部分提到的模块需要做出较大部分的修改。相比于上一部分提到的模块,这里的模块需要在不同架构下进行不同 的处理,所以需要引入 feature 进行分支处理。 - -**值得强调的是,当前宏内核的适配部分仅适配了 riscv 架构,并未适配其他架构。** - -##### axhal - -在宏内核情况下,需要对更多的 trap 进行额外的处理,如用户系统调用异常、 page fault 异常等内容。具体修改内容在`axhal/src/arch/riscv/trap.rs`部分。部分修改如下: - -```rust -match scause.cause() { - Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc), - Trap::Interrupt(_) => crate::trap::handle_irq_extern(scause.bits()), - #[cfg(feature = "monolithic")] - Trap::Exception(E::UserEnvCall) => { - enable_irqs(); - // jump to next instruction anyway - tf.sepc += 4; - // get system call return value - let result = handle_syscall( - tf.regs.a7, - [ - tf.regs.a0, tf.regs.a1, tf.regs.a2, tf.regs.a3, tf.regs.a4, tf.regs.a5, - ], - ); - // cx is changed during sys_exec, so we have to call it again - tf.regs.a0 = result as usize; - } - #[cfg(feature = "monolithic")] - Trap::Exception(E::InstructionPageFault) => { - ... - } - - #[cfg(feature = "monolithic")] - Trap::Exception(E::LoadPageFault) => { - ... - } - - #[cfg(feature = "monolithic")] - Trap::Exception(E::StorePageFault) => { - ... - } - - _ => { - panic!( - "Unhandled trap {:?} @ {:#x}:\n{:#x?}", - scause.cause(), - tf.sepc, - tf - ); - } -} -``` - -##### axtask - -任务模块需要修改的内容较多。在宏内核下,原先 ArceOS 的任务模块承担了宏内核中的线程方面的功能。而为了保证**尽量不对 ArceOS 原有模块过多修改**,方便 ArceOS 复用,因此我们将 进程 和 线程控制块分开了。 - -在这种设计下,线程需要在原有基础上记录更多内容,比如所属进程 ID、计时器信息、CPU亲和力信息(用于实现`SCHED_SETAFFINITY`等系统调用)等,用于完成一系列的 Linux 系统调用。 - -我考虑了两种设计方法: - -1. 在原有任务结构的基础上通过 feature 的方式添加成员域 -2. 新建一个任务结构,继承原有的任务结构,以 trait 的方式实现宏内核相关的内容,在不同架构下选用不同的结构 - -为了实现方便起见,我选用了第一种。 - -因此我对任务结构的修改如下: - -```rust -pub struct TaskInner { - id: TaskId, - name: String, - is_idle: bool, - is_init: bool, - - entry: Option<*mut dyn FnOnce()>, - state: AtomicU8, - - in_wait_queue: AtomicBool, - #[cfg(feature = "irq")] - in_timer_list: AtomicBool, - - #[cfg(feature = "preempt")] - need_resched: AtomicBool, - #[cfg(feature = "preempt")] - preempt_disable_count: AtomicUsize, - - exit_code: AtomicI32, - wait_for_exit: WaitQueue, - - kstack: Option, - ctx: UnsafeCell, - - #[cfg(feature = "tls")] - tls: TlsArea, - - #[cfg(feature = "monolithic")] - process_id: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 是否是所属进程下的主线程 - is_leader: AtomicBool, - - #[cfg(feature = "monolithic")] - /// 初始化的trap上下文 - pub trap_frame: UnsafeCell, - - #[cfg(feature = "monolithic")] - pub page_table_token: usize, - - #[cfg(feature = "monolithic")] - set_child_tid: AtomicU64, - - #[cfg(feature = "monolithic")] - clear_child_tid: AtomicU64, - - // 时间统计, 无论是否为宏内核架构都可能被使用到 - #[allow(unused)] - time: UnsafeCell, - - #[cfg(feature = "monolithic")] - pub cpu_set: AtomicU64, - - #[cfg(feature = "monolithic")] - pub sched_status: UnsafeCell, - - #[cfg(feature = "monolithic")] - /// 退出时是否向父进程发送SIG_CHILD - pub send_sigchld_when_exit: bool, -} -``` - -可以看到其上添加了许多 feature 信息,看上去虽然有些冗余,但也可以勉强完成两者区分的目的,同时不会过度影响上层模块对于 TaskInner 结构的使用。 - - - -另外,除去对结构体成员域的控制,还需要考虑函数运行语句的分支控制问题。我们以启动语句为例。 - -* 对于 Unikernel 的启动,由于不涉及地址空间的改变,可以直接通过调用任务入口函数的方式来进入到任务的执行中。 -* 对于宏内核的启动,需要涉及到特权级的切换,因此要进行一些额外的处理。 - -两者的启动逻辑并不相同,因此需要通过 feature 进行区分。 - -```rust -#[no_mangle] -#[cfg(feature = "monolithic")] -/// 手动进入用户态 -/// -/// 1. 将对应trap上下文压入内核栈 -/// 2. 返回用户态 -/// -/// args: -/// -/// 1. kernel_sp:内核栈顶 -/// -/// 2. frame_base:对应即将压入内核栈的trap上下文的地址 -pub fn first_into_user(kernel_sp: usize, frame_base: usize) -> ! { - use axhal::arch::disable_irqs; - - let trap_frame_size = core::mem::size_of::(); - let kernel_base = kernel_sp - trap_frame_size; - // 在保证将寄存器都存储好之后,再开启中断 - // 否则此时会因为写入csr寄存器过程中出现中断,导致出现异常 - disable_irqs(); - // 在内核态中,tp寄存器存储的是当前任务的CPU ID - // 而当从内核态进入到用户态时,会将tp寄存器的值先存储在内核栈上,即把该任务对应的CPU ID存储在内核栈上 - // 然后将tp寄存器的值改为对应线程的tls指针的值 - // 因此在用户态中,tp寄存器存储的值是线程的tls指针的值 - // 而当从用户态进入到内核态时,会先将内核栈上的值读取到某一个中间寄存器t0中,然后将tp的值存入内核栈 - // 然后再将t0的值赋给tp,因此此时tp的值是当前任务的CPU ID - // 对应实现在axhal/src/arch/riscv/trap.S中 - unsafe { - riscv::asm::sfence_vma_all(); - core::arch::asm!( - r" - mv sp, {frame_base} - .short 0x2432 // fld fs0,264(sp) - .short 0x24d2 // fld fs1,272(sp) - mv t1, {kernel_base} - LDR t0, sp, 2 - STR gp, t1, 2 - mv gp, t0 - LDR t0, sp, 3 - STR tp, t1, 3 // save supervisor tp,注意是存储到内核栈上而不是sp中,此时存储的应该是当前运行的CPU的ID - mv tp, t0 // tp:本来存储的是CPU ID,在这个时候变成了对应线程的TLS 指针 - csrw sscratch, {kernel_sp} // put supervisor sp to scratch - LDR t0, sp, 31 - LDR t1, sp, 32 - csrw sepc, t0 - csrw sstatus, t1 - POP_GENERAL_REGS - LDR sp, sp, 1 - sret - ", - frame_base = in(reg) frame_base, - kernel_sp = in(reg) kernel_sp, - kernel_base = in(reg) kernel_base, - ); - }; - core::panic!("already in user mode!") -} - -extern "C" fn task_entry() -> ! { - // release the lock that was implicitly held across the reschedule - unsafe { crate::RUN_QUEUE.force_unlock() }; - #[cfg(feature = "irq")] - axhal::arch::enable_irqs(); - let task = crate::current(); - if let Some(entry) = task.entry { - cfg_if::cfg_if! { - if #[cfg(feature = "monolithic")] { - use axhal::KERNEL_PROCESS_ID; - if task.get_process_id() == KERNEL_PROCESS_ID { - // 是初始调度进程,直接执行即可 - unsafe { Box::from_raw(entry)() }; - // 继续执行对应的函数 - } else { - // 需要通过切换特权级进入到对应的应用程序 - let kernel_sp = task.get_kernel_stack_top().unwrap(); - let frame_address = task.get_first_trap_frame(); - first_into_user(kernel_sp, frame_address as usize); - } - } - else { - unsafe { Box::from_raw(entry)() }; - } - - } - } - // only for kernel task - crate::exit(0); -} -``` - - - -通过以上两个模块展示的内容,可以看出 feature 的使用基本有两种情况: - -1. 通过 feature 添加成员域或者额外处理语句 -2. 通过 feature 选择不同的分支语句 - - - -通过上述两种方法,可以在尽可能减小修改量的同时完成两种架构的运行方式区分。 - - - -#### 需要新增的模块 - -相比于 Unikernel,宏内核需要新增地址空间、进程管理等一系列模块,但是这与我们想要做的与 Unikernel 兼容的内容关系不大。因此不在这里过多阐述。 - - - -### Tip - -本周工作内容较多,一周暂时做不完,上面仅提出的是工作的目标,还需要进一步调试。。。 - diff --git a/doc/OS-Train-Repo/Week3.md b/doc/OS-Train-Repo/Week3.md deleted file mode 100644 index 706bdaa..0000000 --- a/doc/OS-Train-Repo/Week3.md +++ /dev/null @@ -1,137 +0,0 @@ -# Week 3 - -## 继承上周工作 - -继续添加 feature 内容,主要工作在对 axtask 模块的添加,需要保证原有内容能够和 ArceOS 源程序进行兼容。。 - -## 在 Starry 代码基础上运行原有的 ArceOS 应用 - -原本 Starry 代码是基于 ArceOS 开发的,也始终保持着和 ArceOS 上游的同步。但是由于比赛时期较赶,且缺少规范的 CI-CD,并没有保证 Starry 代码可以始终通过原有 ArceOS 测例。但是现在为了做到两种架构的实时兼容,需要先保证能够通过各自的测例。 - - - -* 尝试通过 ArceOS 原有的 Hello World 测例 - -在尝试通过 Hello World 测例时,由于之前开发的时候对 Starry 更改的绝大多数内容都使用了条件编译,因此并不需要修改过多内容。 - -1. 首先尝试直接编译运行,看看能不能跑。。 - - - - 发现报错: - - ````shell - error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait - ```` - - - - 根据报错,应该是少了全局分配器。但是运行 ArceOS 原有代码时,发现并不需要实现全局分配器也可以编译出这个测例,所以应该是 Starry 在某一个地方引入了一个需要用到堆分配内存的代码,但没有做好兼容。 - - - -2. 对比 ArceOS 代码检查了一段时间,找不到问题,感觉文件量太大不好对比。 - - - -3. 后面思考:`global allocator`是用到堆内存分配机制,在不引入特殊语句的情况下,我们一般只会通过`extern crate alloc`引入`alloc`和与它相关的数据结构,才能做到访问、分配堆内存。 - - 因此尝试全局搜索所有引入了`alloc`的模块,逐个注释掉这些模块对`alloc`的直接引用,进行排查。 - - 仍然报错。。 - - - -4. 但是这个思路应该是对的,于是我根据所有引入了 `alloc` 的模块,看看编译时他们是否被引入,从而确定`alloc`是否被间接引用了。 - - - - 最后发现问题出在`axfs_ramfs`上,它实现了 ramfs 相关的文件系统信息。在 HelloWorld 测例中它不应该被引入,但是编译时发现它出现在了被编译清单上。 - - avatar - - - - 继续检查,发现`axhal`模块引用了这个 crate,最后查明是 trap 处理时使用到了这个 crate 下的一个文件。 - - avatar - - 这个文件是为了统计中断发生的次数,是当时决赛临时添加的一个文件,没有做好兼容导致出现了问题。 - - 将这个文件加上条件编译,同时设置`axfs_ramfs`为可选引入模块,从而解决了问题。 - -* task/yield 测例 - - 需要对 axtask 中一系列结构体成员与其对应的方法加上对应的条件编译语句。为了简约起见,为`TaskInner`新加了一个`impl`,集中存放为宏内核实现加上的内容。 - -* net/bwbench 测例 - - 没有串口输出,需要打开 `LOG=info` 开关才可以看到对应输出,部分输出截取如下: - - ```shell - [ 1.066117 0 axnet::smoltcp_impl::bench:35] Transmit: 0.773GBytes, Bandwidth: 6.184Gbits/sec. - [ 2.065980 0 axnet::smoltcp_impl::bench:35] Transmit: 0.840GBytes, Bandwidth: 6.720Gbits/sec. - [ 3.065980 0 axnet::smoltcp_impl::bench:35] Transmit: 0.744GBytes, Bandwidth: 5.956Gbits/sec. - [ 4.066010 0 axnet::smoltcp_impl::bench:35] Transmit: 0.768GBytes, Bandwidth: 6.150Gbits/sec. - [ 5.066014 0 axnet::smoltcp_impl::bench:35] Transmit: 0.745GBytes, Bandwidth: 5.962Gbits/sec. - [ 6.066012 0 axnet::smoltcp_impl::bench:35] Transmit: 0.742GBytes, Bandwidth: 5.937Gbits/sec. - [ 7.066013 0 axnet::smoltcp_impl::bench:35] Transmit: 0.741GBytes, Bandwidth: 5.930Gbits/sec. - [ 8.066012 0 axnet::smoltcp_impl::bench:35] Transmit: 0.747GBytes, Bandwidth: 5.978Gbits/sec. - [ 9.066032 0 axnet::smoltcp_impl::bench:35] Transmit: 0.744GBytes, Bandwidth: 5.955Gbits/sec. - ``` - - - - -## 对 syscall 层的抽象 - -我的选题定为了 宏内核和 Unikernel 的兼容启动、对 syscall 层的抽象,想要通过 抽象出 syscall 层来实现两种机构的兼容启动,使得 syscall 层发挥参数检查等安全性作用。 - - - -通过 week 2 的工作,我发现原先的用户库其实可以用来提供 syscall 层的抽象的工作。也就是说,整个用户库提供了对 Linux 系统调用的包装。当用户选择通过宏内核启动时,便可以使得调用的函数通过用户库进行处理,从而达到了参数检查等目的。 - - - -因此,week 2-3 的工作更多是做好底层模块对不同架构的兼容,从而支持用户通过选用不同库调用来走不同的架构处理。 - -## 用户快捷选择架构启动 - -底层架构处理好了之后,需要考虑的是用户如何方便地选择不同的架构启动。 - -传统的 Unikernel 启动是将用户程序和内核同时打包在一起进行编译,而对于宏内核而言,需要先将外部程序打包为一个文件镜像,内核启动之后从文件镜像中读取对应的程序进行加载、启动。 - - - -> 思考:是否可以将内核和应用程序代码打包在一起通过宏内核启动,这样可以和原来的 ArceOS 共享一个编译、启动流程。 - - - -考虑到宏内核加载应用的时候需要分析对应的 ELF 文件,建构起对应的地址空间,如果采用上述的思考方法,会需要对当前的地址空间建构方式进行较大程度的改动。因此还是采用原先外部编译并且打包在文件镜像的方式。 - - - -对编译方式进行修改: - -当指定`STRUCT=Monolithic`时,采用宏内核启动,此时会对指定的源代码进行如下操作: - -1. 通过外部编译器,如 riscv-musl-gcc 编译器对源代码进行编译 -2. 将得到的可执行文件打包到文件镜像中 -3. 启动宏内核,读取外部的可执行文件,开始运行 - - - -成果: - -当采用宏内核运行 `helloworld`程序时,结果如下: - -```shell -$ make A=apps/c/helloworld STRUCT=Monolithic run -``` - - - -有如下运行结果: - -avatar - diff --git a/doc/OS-Train-Repo/Week4.md b/doc/OS-Train-Repo/Week4.md deleted file mode 100644 index e816c5c..0000000 --- a/doc/OS-Train-Repo/Week4.md +++ /dev/null @@ -1,154 +0,0 @@ -# Week 4 - -## 制定测例测试 - -制作了兼容了 Unikernel 和宏内核架构的 OS 之后,一个比较重要的问题便是这种模块化的 OS 是否会对性能造成影响。因此需要对内核进行测试。 - - - -根据宏内核 和 Unikernel 的异同之处,考虑从以下几个方面来进行测例测试: - -* 性能: - * 文件:包括读写等内容 - * 任务:新建线程、任务切换、睡眠 - * 内存分配:动态分配堆内存、对内存空间的读写操作 -* 安全性: - * 非法访问地址测试 - * 堆栈空间溢出测试 - * 。。 - - - -测试对象: - -1. ArceOS 本身 -2. Starry 本身 -4. 本地宏内核 - - - -## 测试结果 - -**若无特殊说明,下列提到的时间 单位均为 ns。** - -### 文件 IO - - - -反复对一个文件进行 打开、读或者写操作 50 次,计算消耗的时间,并重复该操作 10 次 计算平均值。 - - - -| 测例 | ArceOS | Starry | -| --------- | ---------- | ---------- | -| Fileopen | 550282390 | 1066207190 | -| Fileread | 615516760 | 1070663240 | -| Filewrite | 1690372150 | 2218262040 | - - - -### 内存分配 - -测试操作分为两种: - -A:连续申请内存,并一次性全部释放。 - -B:申请一次内存,并立即释放,然后继续申请下一次内存,不断重复。 - - - -进行 Num 次操作 A 和 操作 B,计算消耗的时间。 - -| Num | 10 | 50 | 100 | 500 | 1000 | 5000 | 10000 | -| ------ | ------ | ------- | ------- | -------- | -------- | --------- | --------- | -| ArceOS | 474300 | 1843400 | 3748100 | 19115600 | 39338600 | 184836300 | 377351000 | -| Starry | 812000 | 2808000 | 5693700 | 28515300 | 57336100 | 335300400 | 556783200 | - - - -### 任务调度 - -新建 50 个线程,每一个线程执行 Num 次 yield 函数,计算最后所有线程释放时经过的时间。并将该时间和本地WSL 运行结果对比: - -| Num | Starry | ArceOS | Linux | -| ---- | -------- | ------- | ------- | -| 1 | 54763910 | 3436430 | 1151728 | -| 2 | 54694900 | 388390 | 869095 | -| 5 | 54971370 | 493690 | 881606 | -| 10 | 56682550 | 707700 | 939276 | -| 15 | 58620320 | 922290 | 885656 | -| 20 | 59653070 | 1195070 | 919943 | -| 25 | 60819050 | 1335540 | 902737 | -| 50 | 67460820 | 2258190 | 946170 | -| 60 | 70335530 | 2863900 | 929436 | -| 70 | 72744350 | 3285170 | 908032 | -| 80 | 75324650 | 3654020 | 1070883 | -| 90 | 77637570 | 4034390 | 1040678 | -| 100 | 80407590 | 4202130 | 1042760 | - -发现 Linux 环境下随着 Num 变化,总时间几乎不变,且快于 ArceOS 环境,这是不太合理的。所以思考出现这种现象的原因。 - - - -尝试横向对比与纵向对比。 - -横向对比:对比其他的系统调用,看看是否是因为 yield 这个系统调用的问题导致 ArceOS 变慢。 - -测试 **getpid **系统调用。 - -| Num | ArceOS | Starry | Linux | -| ------ | ------- | --------- | ------- | -| 1000 | 61370 | 3108410 | 65998 | -| 2000 | 107820 | 6384370 | 113409 | -| 5000 | 266620 | 15653880 | 273750 | -| 10000 | 538550 | 31311610 | 565014 | -| 15000 | 812640 | 47527430 | 718736 | -| 20000 | 1224000 | 62507120 | 990795 | -| 25000 | 1303640 | 77740360 | 1209650 | -| 50000 | 2623760 | 155429130 | 2438787 | -| 600000 | 3360740 | 186802430 | 2950229 | -| 70000 | 3682740 | 218574090 | 3463541 | -| 80000 | 4175930 | 248619690 | 3979007 | -| 90000 | 4661770 | 279418020 | 4521014 | -| 100000 | 5395420 | 310067620 | 5000976 | - -发现 ArceOS 和 Linux 时间接近,且 Linux 的运行时间与 Num 成线性关系。 - - - -纵向对比:思考是否会是调度策略的问题,因此在**单线程**环境下运行 Num 次 yield 调用,减少多线程带来的影响。 - -| Num | Starry | ArceOS | Linux | -| ------ | -------- | ------- | ------- | -| 100 | 580640 | 77440 | 13057 | -| 200 | 1151490 | 34590 | 23063 | -| 500 | 2864910 | 94620 | 53362 | -| 1000 | 5806980 | 170770 | 103447 | -| 1500 | 8752370 | 257950 | 158525 | -| 2000 | 11437370 | 350320 | 210769 | -| 2500 | 14163370 | 468890 | 259136 | -| 5000 | 28526900 | 940180 | 514902 | -| 6000 | 34547640 | 1061070 | 661440 | -| 7000 | 39532740 | 1183400 | 716446 | -| 8000 | 45511390 | 1355080 | 840507 | -| 9000 | 51267930 | 1665240 | 921227 | -| 100000 | 57452610 | 1771540 | 1026559 | - -发现 Linux 的运行时间与 Num 成线性关系,且 ArceOS 和 Linux 的运行差距接近。 - - - -思考: - -这种情况的出现可能有以下几个原因: - -1. 本地 WSL 上的 Linux 内核运行的任务调度策略不一定是 ArceOS 和 Starry 默认采用的 FIFO 策略,可能是其他策略,同时新建 50 个线程进行 yield 时,不会真正出现 50 个线程同时存在的情况,从而加快了运行速度,使得运行时间不呈线性。 -2. Linux 内核对 syscall 存在优化,如 sys_yield 也可以特判 syscall_id 然后从 trap_entry 那边直接跳到线程切换的汇编,而不需要拿一个inner锁、等待各种资源量等,加速了处理速度。但 ArceOS 并没有做这些优化。 - - - -### 异常处理 - -ArceOS 作为 Unikernel 架构,运行在单进程体系下,当出现如 SIGSEGV 错误时,会直接报 panic 并且退出内核。但是 Starry 可以在多进程体系下,捕获子进程的 SIGSEGV 信号并进行处理,而不需要退出整个程序。 - -相关测例在 ostrain/process_sigsegv,体现了宏内核运行的稳定性与安全性。 diff --git a/doc/OS-Train-Repo/Week5.md b/doc/OS-Train-Repo/Week5.md deleted file mode 100644 index 86233bf..0000000 --- a/doc/OS-Train-Repo/Week5.md +++ /dev/null @@ -1,3 +0,0 @@ - - -Intel 的用户态中断处理快了 10 倍以上。 \ No newline at end of file diff --git a/doc/OS-Train-Repo/Week6.md b/doc/OS-Train-Repo/Week6.md deleted file mode 100644 index 773a54d..0000000 --- a/doc/OS-Train-Repo/Week6.md +++ /dev/null @@ -1,62 +0,0 @@ -# Week 6 - -## 和向老师讨论情况 - -### 短期目标 - -实现简单的定制化宏内核,大致情况如下: - -1. 制作一个用户库,提供不同类型的 syscall。 -2. 应用程序根据需要选择对应的 syscall,和自身打包在一起编译得到二进制文件,并传递出一个使用的 syscall 清单。 -3. 内核根据给出的 syscall 清单,选择性的提供对应的 syscall 进行服务。当前暂时不考虑去阉割syscall的功能。因此需要根据 syscall 所依赖的模块来选择性地启动内核,提供不同的接口。 - - - -### 需要实现的功能 - -1. 支持分离某些模块:为了支持宏内核的启动,文件驱动、页表空间、进程控制是不能删改的,但是比如信号、网络等大型模块、以及任务模块下的互斥锁实现等小型功能均是可以依据所需要的系统调用来进行定制的。但本次训练不求分离所有模块,只做一些示范性的分离,代表这种分离的思想可行。 -2. 支持定制接口:为了实现这个功能,需要对 syscall 层模块做进一步的模块化。短期目标是按照所需要的syscall所属的模块,来批量提供这个模块中的所有syscall(如只要求open,可能会同时提供同类的open、write、close)。未来若有能力,还会继续细化到单个syscall。 - - - -### 期望效果 - -1. 生成的内核镜像大小有明显变化 -2. 内核减少不必要的检查,从而达到编译速度和运行性能的提高。 -3. 内核模块关系更加清晰,模块不仅可以加还可以删 - - - -### 长期目标 - -在定制内核的要求下,每一个模块之间的关系会更加地清晰。可以仿照redleaf的思想,将模块与程序之间的隔离从特权级之间的隔离转化为编程语言层面的隔离,每一个模块属于一个domain,不同的domain之间通过一个特定的domain进行通信,从而使得模块的插入可以变得更加便捷。 - -而在此基础上可以尝试**让模块的代码和数据分离存储**,即当模块的代码改变时不会影响原有数据和状态。若实现这一点,则使得动态升级模块成为可能。 - - - -## 拆分进展 - -### 大模块拆分--axnet - -网络模块作为一个较为独立的模块,并不会影响核心模块的运行。它也是一个适合入手进行拆分的模块。以这个模块来阐述拆分思路。 - -#### 调整内容 - -首先将与网络关系较大的部分 syscall 如 syscall_bind 等独立出来作为一个类,认为当应用程序调用了属于这个类里面的系统调用时,就需要引入网络相关的模块。 - -之后对文件关系做出如下调整: - -1. 新建 `modules/syscall/syscall_utils` crate,用于存储和系统调用相关的结构体、错误码等,进行统一 -2. 新建`modules/syscall/syscall_net` crate,用于接管所有和网络相关的 syscall 接口实现,并对外提供一个 syscall id 类,里面存储了所有接管的 syscall id。。 -3. 在 `ulib/axstarry` 用户库中,若当前包含了网络模块,则在处理 syscall 时判断当前 syscall 是否属于网络的 id 类,若是则把当前的请求转发给网络模块,否则转发给其他模块。 -4. 之后需要实现的便是根据给定的 syscall id 列表,调整 axstarry 的编译选项,选择是否包括网络模块 `modules/syscall/syscall_net`。 - -#### 效果 - -当前第四步尚未实现,因此手动调整编译选项。在不加入 net 选项时,生成的内核镜像相比于加入时从 500kb 降到了 400kb,内核镜像大小变化较为明显。并且在不加入 net 选项时确实未对外提供网络接口,会提示接口不存在。 - - - - - diff --git a/doc/OS-Train-Repo/Week7.md b/doc/OS-Train-Repo/Week7.md deleted file mode 100644 index 526a2aa..0000000 --- a/doc/OS-Train-Repo/Week7.md +++ /dev/null @@ -1,16 +0,0 @@ -# Week 7 - -本周实际工作内容大致是将 axstarry 依据 syscall 分为了不同的模块,方便后续根据 syscall 进行自动化选择模块启动。 - - - -将当前的模块划分为如下部分: - -* syscall_task:主管任务模块,包括进程管理、调度、互斥资源管理等 -* syscall_fs:文件系统对外封装,包括打开、关闭、读写文件等Linux相关语义支持 -* syscall_mem:内存管理模块封装,包括动态分配堆内存、修改页面权限等操作 -* syscall_net:网络控制模块,提供 socket 等网络相关结构的支持 -* syscall_entry:系统调用入口,通过不同的 feature 启动不同的模块,并且加入对应的底层模块 - - - diff --git a/doc/OS-Train-Repo/Week8.md b/doc/OS-Train-Repo/Week8.md deleted file mode 100644 index 2bd6ceb..0000000 --- a/doc/OS-Train-Repo/Week8.md +++ /dev/null @@ -1,28 +0,0 @@ -# Week 8 - -本周尝试实现自动化选择模块启动。大致流程描述如下: - -1. 根据一个给定的源代码或者二进制文件,得到它相关的 syscall 列表 -2. 根据 syscall 列表,自动生成内核的构建文件,选择对应的模块启动 -3. 启动内核之后,将对应的文件加载进内核中运行 - - - -但是遇到了一个问题,对于源代码的 syscall 列表获取部分: - -1. 若使用静态分析工具,则对于手动调用 syscall 的情况,如果直接使用无条件跳转等指令来进行 syscall,则无法通过静态分析,而需要依赖执行流才能知道当前调用的 syscall id 是什么,如下列指令: - - ```assembly - FUN: - ecall - li a7,10 - jalr FUN - ``` - -2. 若使用动态分析工具,面对交互式程序又无法自动到达程序的每一个可达点,所以可能漏过系统调用。 - - - -找了一圈分析工具,没找到合适的能够处理所有情况的,所以暂时只能选择其中一种来进行分析。 - -选择静态分析工具,通过 `rust-objdump` 来获取二进制文件的汇编代码,并按照执行顺序(假设不发生跳转)来获取所有的 syscall id。 \ No newline at end of file diff --git "a/doc/OS-Train-Repo/\344\270\255\346\234\237\346\212\245\345\221\212.md" "b/doc/OS-Train-Repo/\344\270\255\346\234\237\346\212\245\345\221\212.md" deleted file mode 100644 index 0175545..0000000 --- "a/doc/OS-Train-Repo/\344\270\255\346\234\237\346\212\245\345\221\212.md" +++ /dev/null @@ -1,247 +0,0 @@ -# 中期报告 - -> 姓名:郑友捷 - - - -## 亮点 - -* 对 ArceOS 的 Rust 程序的兼容,即 Unikernel 和 宏内核编译期兼容启动 -* 对同一份源代码,不需要改变本身代码内容,只需要**通过改变编译指令、连接到不同的库,就可以实现不同内核架构启动**,为开发和实际运行提供方便。 - - - -## Starry 的 Unikernel 兼容 - -StarryOS 是基于 Unikernel 架构的 ArceOS 并进行一定改造得到的宏内核。理论上它可以在编译期通过调整编译参数实现宏内核和 Unikernel 两种架构的选择性启动。但是由于比赛时期紧张,同时比赛的测例运行需求比较特殊,导致 StarryOS 对 Unikernel 架构的启动支持不是很好,无法运行 ArceOS 的原生 Rust 程序。 - -### feature 划分 - -当前想要做到的是编译期进行架构的区别,因此我选择**通过 feature 的方式**对两者进行区分。 - - - -由于宏内核默认是启动所有的模块,从而构成一个整体(讨论的定制化宏内核除外),因此我们设置一个 feature 为 monolithic,代表启动宏内核架构。**当这个 feature 启动时,其他所有的模块都会被包含进来,如文件系统、信号模块、进程控制等等**。 - - - -### 模块划分与修改 - -为了更好地进行模块复用,我们先需要对 Starry 中的模块关系进行划分,将其根据 **宏内核是否需要** 和 **ArceOS 是否拥有** 两个标准进行划分。 - -![image-20231007202335681](../figures/train-week2-1.png) - -具体对应到 Starry 上拥有的模块关系如下: - -* ArceOS 中可直接沿用:log、driver 以及一系列解耦的 crate -* ArceOS 中需要适配:任务模块 axtask 、trap异常处理 axhal 等 -* ArceOS 中需要添加:地址空间、进程、信号、文件系统、用户库 - - - -相比于 Unikernel,宏内核需要新增地址空间、进程管理等一系列模块,但是这与我们想要做的与 Unikernel 兼容的内容关系不大。我们更多的是强调适配模块的调整,即如何让复用模块能够**同时为两种架构提供服务**。 - - - -具体的修改详见[Starry/doc/OS-Train-Repo/Week2.md at feat/module · Azure-stars/Starry (github.com)](https://github.com/Azure-stars/Starry/blob/feat/module/doc/OS-Train-Repo/Week2.md)。我们在这里重点强调 axtask 模块的修改。 - - - -任务模块需要修改的内容较多。在宏内核下,原先 ArceOS 的任务模块承担了宏内核中的线程方面的功能。而为了保证**尽量不对 ArceOS 原有模块过多修改**,方便 ArceOS 复用,因此我们将 进程 和 线程控制块分开了。 - -在这种设计下,线程需要在原有基础上记录更多内容,比如所属进程 ID、计时器信息、CPU亲和力信息(用于实现`SCHED_SETAFFINITY`等系统调用)等,用于完成一系列的 Linux 系统调用。 - -我考虑了两种设计方法: - -1. 在原有任务结构的基础上**通过 feature 的方式添加成员域** -2. 新建一个任务结构,**继承原有的任务结构,以 trait 的方式实现宏内核相关的内容**,在不同架构下选用不同的结构 - -为了实现方便起见,我选用了第一种。 - - - -则在这种情况下, feature 的作用可以概括为两点: - -1. 通过 feature 添加成员域或者额外处理语句 - -2. 通过 feature 选择不同的分支语句 - - - - -#### 通过 feature 添加成员域或者额外处理语句 - -我对任务结构的修改如下: - -```rust -pub struct TaskInner { - id: TaskId, - name: String, - is_idle: bool, - is_init: bool, - - 。。。 - - #[cfg(feature = "tls")] - tls: TlsArea, - - #[cfg(feature = "monolithic")] - process_id: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 是否是所属进程下的主线程 - is_leader: AtomicBool, - - #[cfg(feature = "monolithic")] - /// 初始化的trap上下文 - pub trap_frame: UnsafeCell, - - #[cfg(feature = "monolithic")] - pub page_table_token: usize, - - #[cfg(feature = "monolithic")] - set_child_tid: AtomicU64, - - #[cfg(feature = "monolithic")] - clear_child_tid: AtomicU64, - - // 时间统计, 无论是否为宏内核架构都可能被使用到 - #[allow(unused)] - time: UnsafeCell, - - #[cfg(feature = "monolithic")] - pub cpu_set: AtomicU64, - - #[cfg(feature = "monolithic")] - pub sched_status: UnsafeCell, - - #[cfg(feature = "monolithic")] - /// 退出时是否向父进程发送SIG_CHILD - pub send_sigchld_when_exit: bool, -} -``` - -可以看到其上添加了许多 feature 信息,看上去虽然有些冗余,但也可以勉强完成两者区分的目的,同时不会过度影响上层模块对于 TaskInner 结构的使用。 - - - -#### 通过 feature 选择不同的分支语句 - -我们以启动语句为例。 - -* 对于 Unikernel 的启动,由于不涉及地址空间的改变,可以直接通过调用任务入口函数的方式来进入到任务的执行中。 -* 对于宏内核的启动,需要涉及到特权级的切换,因此要进行一些额外的处理,如在内核栈压入 trap 上下文,该操作在`first_into_user`中实现。 - -则对应 Starry 实现如下: - -```rust -extern "C" fn task_entry() -> ! { - // release the lock that was implicitly held across the reschedule - unsafe { crate::RUN_QUEUE.force_unlock() }; - #[cfg(feature = "irq")] - axhal::arch::enable_irqs(); - let task = crate::current(); - if let Some(entry) = task.entry { - cfg_if::cfg_if! { - if #[cfg(feature = "monolithic")] { - use axhal::KERNEL_PROCESS_ID; - if task.get_process_id() == KERNEL_PROCESS_ID { - // 是初始调度进程,直接执行即可 - unsafe { Box::from_raw(entry)() }; - // 继续执行对应的函数 - } else { - // 需要通过切换特权级进入到对应的应用程序 - let kernel_sp = task.get_kernel_stack_top().unwrap(); - let frame_address = task.get_first_trap_frame(); - first_into_user(kernel_sp, frame_address as usize); - } - } - else { - unsafe { Box::from_raw(entry)() }; - } - - } - } - // only for kernel task - crate::exit(0); -} -``` - - - -通过如上 feature 使用方法,对各个模块进行兼容修改,就可以保证每一个模块在是否开启 monolithic feature 的情况下选择正确的处理方法。 - -当然,这种做法的前提是**足够合理的模块划分**,才能保证使用 feature 的场合尽量少,否则和重写一个内核区别不大。而 ArceOS 自身模块化的特性使得原本 modules 的划分便足够细致,因此在改造过程中,用到 feature 比较多的模块便只有 axtask 模块,其他都是只要略加修改便可完成适配。这就是模块化操作系统用来实现多架构兼容的优势。 - - - -### 通过 ArceOS 原先的测例 - -但是由于比赛时期较赶,且缺少规范的 CI-CD,并没有保证 Starry 代码可以始终通过原有 ArceOS 测例。但是现在为了做到两种架构的实时兼容,需要先保证能够通过各自的测例。 - -对于这些测例的具体调试过程体现在日志中,详见[Starry/doc/OS-Train-Repo/Week3.md at feat/module · Azure-stars/Starry (github.com)](https://github.com/Azure-stars/Starry/blob/feat/module/doc/OS-Train-Repo/Week3.md),不在总结报告中赘述。 - - - -## 代码自选架构启动 - -底层架构处理好了之后,需要考虑的是用户如何方便地选择不同的架构启动。 - -以 C 语言为例,我们期望的是代码通过选择链接不同的库,从而启动不同的架构。发现 ArceOS 方面,晏巨广学长正在做 ArceOS 上的 musl-libc 支持。他为 C 的链接库接口提供了对应的 ArceOS_posix_api 支持。若将 C 代码链接到 axlibc 上,便可以启动 Unikernel 来处理这份程序。 - -对于宏内核,考虑到宏内核加载应用的时候需要分析对应的 ELF 文件,建构起对应的地址空间,所以不选择和晏巨广学长一样重写一份链接库,而是将 C 代码在外部编译为可执行文件之后加载到文件镜像中执行,即 C 代码链接的库是外部 C 编译器自带的库。 - -为了方便启动,我修改了 Makefile,对编译方式进行修改: - -* 当指定`STRUCT=Monolithic`时,采用宏内核启动, - - ```shell - $ make A=apps/c/helloworld STRUCT=Monolithic run - ``` - - 此时会对指定的源代码进行如下操作: - -1. 通过外部编译器,如 riscv-musl-gcc 编译器,将源代码连接到外部 C 代码库,对源代码进行编译 - -2. 将得到的可执行文件打包到文件镜像中 - -3. 启动宏内核,读取外部的可执行文件,开始运行 - - 有如下运行结果: - - avatar - - - -* 当不指定时,采用 Unikernel 启动,此时源代码会连接到 axlibc,把应用程序和内核打包为一个镜像进行启动。 - - - - - -## 测试 Starry 和 ArceOS - -制作了兼容了 Unikernel 和宏内核架构的 OS 之后,一个比较重要的问题便是这种模块化的 OS 是否会对性能造成影响。因此需要对内核进行测试。 - -根据宏内核 和 Unikernel 的异同之处,考虑从以下几个方面来进行测例测试: - -* 性能: - * 文件:包括读写等内容 - * 任务:新建线程、任务切换 - * 内存分配:动态分配堆内存 -* 安全性: - * 非法访问地址测试 - - - -详细测试结果在[Starry/doc/OS-Train-Repo/Week4.md at feat/module · Azure-stars/Starry (github.com)](https://github.com/Azure-stars/Starry/blob/feat/module/doc/OS-Train-Repo/Week4.md) - -结论: - -1. 基于同样的底层模块,宏内核相比于 Unikernel 架构,会花费更多的时间在特权级切换、trap 上下文的存储和恢复、参数安全性检查上,因此性能会有一定下降。 - -2. 由于宏内核支持的多进程和信号捕获机制,他能够在任务发生异常的时候捕获并进行对应的处理,而不至于直接使得整个内核终止。 - - 这一点结合上面的自选架构启动,可以帮助应用在开发过程中较为方便地进行调试,即只需要将应用作为子进程进行启动,而父进程**在宏内核下可以较为方便地捕获子进程的错误信息**。当子进程开发完毕,只需要简单的改变链接库,同时脱离父进程单独启动,就可以**在 Unikernel 架构下以较高的性能运行**。 - -3. 本地 Linux 环境虽然是在宏内核下,但是他在一系列方面做了优化,如 syscall 的调用、任务调度策略等,导致直接调用多次 syscall 并不能看出宏内核和 Unikernel 的性能差距,仍需要设计更多具有针对性的测例。 \ No newline at end of file diff --git "a/doc/OS-Train-Repo/\344\270\255\346\234\237\346\212\245\345\221\212.pptx" "b/doc/OS-Train-Repo/\344\270\255\346\234\237\346\212\245\345\221\212.pptx" deleted file mode 100644 index d3a7a0f..0000000 Binary files "a/doc/OS-Train-Repo/\344\270\255\346\234\237\346\212\245\345\221\212.pptx" and /dev/null differ diff --git "a/doc/OS-Train-Repo/\346\234\237\346\234\253\346\212\245\345\221\212.pptx" "b/doc/OS-Train-Repo/\346\234\237\346\234\253\346\212\245\345\221\212.pptx" deleted file mode 100644 index 216984e..0000000 Binary files "a/doc/OS-Train-Repo/\346\234\237\346\234\253\346\212\245\345\221\212.pptx" and /dev/null differ diff --git a/doc/OSCOMP-Repo/Week 9.md b/doc/OSCOMP-Repo/Week 9.md deleted file mode 100644 index 37d2514..0000000 --- a/doc/OSCOMP-Repo/Week 9.md +++ /dev/null @@ -1,291 +0,0 @@ -# Week 9 交流 - -> 郑友捷 - -## 本周工作内容 - -* 实现了`arceos`内核的多地址空间 -* 实现基础的进程支持,支持进程的创建、回收并在此基础上实现了`exec`系统调用 -* 与闭浩扬助教进行交流,了解`Maturin`项目的一些特性 -* 讨论分工情况 - - - -## Arceos地址空间支持:分离编译 - -* 实现文件与用户库在脱离内核库下的单独编译:参考`rcore`编译`user`的方法 -* 实现基础的文件加载与ELF文件读取: - * 文件加载当前仅通过汇编直接写死,类似于`rcore`的`link_app.S`。后续会使用文件系统进行替代。 - * ELF文件读取:仅支持静态编译,与`rcore`类似,未考虑动态链接等情况(`Maturin`实现)。 - - - -## Arceos地址空间支持:页表支持 - -引入地址空间数据结构: - -```rust -pub struct MemorySet { - pub page_table: PageTable, - pub areas: Vec, -} - -pub struct MapArea { - /// global page本身就是多个页面的,且存储了起始地址 - /// 存储了GlobalPage防止其因为生命周期结束而自动释放对应物理页面 - pub pages: GlobalPage, - pub flags: MappingFlags, -} -``` - - - -## Arceos地址空间支持:单页表 - -* 单页表含义:从用户态trap到内核再返回到用户态的这个过程,若没有发生进程切换,则保持地址空间不变,即不切换`satp`。 -* 单页表的优缺点: - * 优点:提高性能,减少更换地址空间导致的换页性能消耗 - * 缺点:安全性下降。 - * 比赛中大多选择单页表保证性能。 -* 内核初始化一个页表,之后作为只读页表,不进行修改。 - -* 为了保证内核在使用用户地址空间时也可以访问内核自身的代码,因此需要把内核的页表项复制到用户的页表中。 - - ```rust - /// 复制内核页表到用户页表 - pub fn copy_from_kernel_memory() -> PageTable { - let page_table = PageTable::try_new().unwrap(); - let idx_len = PAGE_SIZE_4K / ENTRY_COUNT; - for idx in 256usize..512 { - // 由内核初始的虚拟地址决定复制多少大页 - let kernel_pte_address: *const usize = (phys_to_virt(KERNEL_PAGE_TABLE.root_paddr()) - .as_usize() - + idx_len * idx) as *const usize; - let kernel_pte = unsafe { core::slice::from_raw_parts(kernel_pte_address, idx_len) }; - let user_pte_address = - (phys_to_virt(page_table.root_paddr()).as_usize() + idx_len * idx) as *mut usize; - let user_pte = unsafe { core::slice::from_raw_parts_mut(user_pte_address, idx_len) }; - user_pte.copy_from_slice(&kernel_pte); - } - page_table - } - ``` - -* 在读取应用程序的ELF文件的时候,会进行用户地址空间的页表初始化,可以借鉴rcore的框架,复用arceos的接口进行地址空间的初始化。 -* 地址空间仅在任务切换时会进行检查,若切换到的任务属于不同的进程,则会进行地址空间的切换。 - - - -## Arceos进程支持:数据结构 - -* `linux`内核与`Maturin`均将进程控制块与线程控制块进行统一,用一个数据结构进行管理。 - -* `unikraft`(贾越凯助教推荐的微内核)与`rcore`将进程控制块与线程控制块分开管理。 - -* 贾越凯助教建议不在`axtask`直接支持进程控制,防止兼容性不好。 - -* 最终数据结构如下: - - ```rust - /// 进程控制块 - pub struct Process { - /// 进程的pid和初始化的线程的tid是一样的 - pub pid: u64, - /// 内部可变块 - pub inner: SpinNoIrq, - } - - pub struct ProcessInner { - /// 父进程 - pub parent: Option>, - /// 子进程 - pub children: Vec>, - /// 线程列表 - pub tasks: Vec, - /// 地址空间 - pub memory_set: MemorySet, - /// 进程状态 - pub is_zombie: bool, - /// 退出状态码 - pub exit_code: i32, - } - - /// 线程内部可变块 - pub struct TaskInner { - id: TaskId, - name: &'static str, - is_idle: bool, - is_init: bool, - /// 所属进程 - pub process: Arc, - /// 是否是所属进程下的主线程 - is_leader: AtomicBool, - entry: Option<*mut dyn FnOnce()>, - state: AtomicU8, - in_wait_queue: AtomicBool, - in_timer_list: AtomicBool, - #[cfg(feature = "preempt")] - need_resched: AtomicBool, - #[cfg(feature = "preempt")] - preempt_disable_count: AtomicUsize, - /// 存储当前线程的TrapContext - pub trap_frame: UnsafeCell, - kstack: Option, - ctx: UnsafeCell, - } - ``` - - 当前还未添加信号、文件描述符等结构,后续会添加。 - - - -## Arceos进程支持:新建一个进程 - -1. 新建一个地址空间,其页表复制内核页表的内容。 -2. 读取ELF文件,并且将内容写入到地址空间中。 -3. 根据地址空间新建一个进程,分配一个ID。 -4. 新建一个线程`task`作为该进程的主线程,并且标记其父子关系。 -5. 初始化`task`的`trap`上下文,将其写到对应的内核栈上。 - - - -## Arceos进程回收 - -* 回收物理页帧页表 -* 将所有子进程转交给调度进程。 -* 标记退出状态、返回值等等。 - - - -## Arceos进程:exec调用 - -相比于新建进程的区别: - -1. 释放原先所有线程占用的用户态物理资源:直接释放除去内核态外的所有页面。 -2. 读取ELF文件,写入新的程序到原来的地址空间中 -3. 将运行参数写入到对应的用户栈上。 -4. 将新的trap上下文写入到内核栈上。 - - - -## exec调用当前的问题 - -* 问题:若尝试释放用户态占用的物理页面,但是保留内核页帧,此时在为新的任务分配物理页面的时候,会分配原先任务使用的物理页面,体现了复用资源的思想。但是在访问该物理页面的时候会出现`page fault`异常。 - -* 猜测:MMU转化出现了问题,但是在确保satp不变的情况下依旧有这个问题。 -* 解决方法:先保持原先的地址空间不释放,对新的任务申请新的物理页面,之后再将原先的地址空间释放。此时会避免bug出现。但是旧的地址空间页面是否完全释放仍然不能确定。 - - - -## Maturin学习工作 - -* 周一时和闭浩扬学长关于内核加载地址以及`maturin`内核的实现特性进行了线下交流。 -* 在编写进程支持工作时也对`maturin`进一步了解 - - - -### 内核中断与用户中断 - -* 关于内核中断: - * `rcore`:若中断发生在`__alltraps`,则此时未改变`stvec`,会导致死循环。 - * `arceos`:在`trap_vector_base`进入时通过判断`sscratch`是否为0来判断是否为内核中断。但是这种只能适用于第一次进入应用前的中断判断。 - * `maturin`:将内核地址加载在高地址,发生中断时将`sp`的值转化为带符号数。若大于0说明指向了用户栈,是用户中断。若小于0说明指向内核栈,是内核中断。 - -* 内核中断发生时,`maturin`会在原先内核栈的基础上进行trap处理,即内核栈嵌套。 - - - -### 特色应用:gcc - -* gcc关键:动态链接文件的加载 -* 涉及到ELF文件的读取与动态加载 - - - -### linux内核动态加载ELF文件流程如下 - -1. 填充并且检查目标程序ELF头部 - -2. load_elf_phdrs加载目标程序的程序头表 - - > 程序表头: - > - > ```c - > typedef struct { - > unit32_t p_type; #数据类型 - > uint332_t p_flags; #标志位 - > uint64_t p_offset; #在ELF文件中的偏移 - > uint64_t p_vaddr; #虚拟地址 - > uint64_t p_paddr; #物理地址 - > uint64_t p_fllesz; #在硬盘上的大小 - > uint64_t p_memsz; #在内存中大小 - > uint64_t p_align; #内存对齐方式 - > } Elf64_Phdr; - > ``` - > - > 反映某一段segement的类型。 - -3. 如果需要动态链接, 则寻找和处理解释器段 - - > GNU把对于动态链接ELF映像的支持作了分工: - > - > 把ELF映像的装入/启动入在Linux内核中;而把动态链接的实现放在用户空间(glibc),并为此提供一个称为”解释器”(ld-linux.so.2)的工具软件,而解释器的装入/启动也由内核负责。 - -4. 检查并读取解释器的程序表头 - -5. 装入目标程序的段segment - -6. create_elf_tables填写目标文件的参数环境变量等必要信息 - -7. start_kernel宏准备进入新的程序入口 - -### maturin中 - -> 对应写法:`kernel/src/loaders/mod.rs::Elfloader::init_vm`函数。 -> - -1. 先寻找解释器段,若存在解释器段则读取解释器的路径将其添加到启动参数中。 -2. 装入原有ELF文件的静态段 -3. 检查是否需要重定位,若有则说明是动态编译的,若有则需要根据动态加载的`.rela.dyn`等段落提供的内容进行重定位,修改或者添加符号。 -4. 设置用户栈等内存内容。 -5. 设置文件运行的环境变量,将其写入到用户栈上,此时用户栈上带有了运行参数。 -6. 将用户栈写入地址空间。完成加载。 - -上述只是简述,其中有很多细节当前仍然未完全弄清,只能粗浅介绍,请原谅。 - - - -## 关于合作的想法 - -之前分工进行的较为艰难,主要是三人均负责进程部分,但都未实现地址空间等更为基础的东西,导致大家都得从基础开始做。 - -当前的进程支持仍然会有许多bug,不过基础的框架感觉搭起来了。依据初赛内容也许可以分为三个部分: - -1. 进程管理:clone \ wait -2. 内存管理:包括堆的使用和文件加载等等 -3. 文件管理:支持文件系统 - -按照这三个部分进行分工如何? - - - -## 下周安排 - -1. 确定分工,实现clone等系统调用 -2. 继续学习`maturin`的相关特性 - - - - - -## 老师建议 - -1. 对于`syscall`的参数传递、特权级切换等内容,写成一个脚本,对于所有系统调用都是通用的,如通用数据类型的加载以及指针数据的传递。 - -2. 可以参考linux等系统对于进程线程的定义、数据结构定义与实现,一定要做linux的常见集。 - -3. 了解其他组的工作,如做fs文件系统、调度算法、socket等内容,做的足够好的话可以拿来直接用。 - -4. 可以参考到qemu进行更为深层的调试 -5. 考虑lazy分配内存、动态加载文件 -6. 学习其他一等奖项目、Linux系统的整体实现 \ No newline at end of file diff --git a/doc/OSCOMP-Repo/Week10.md b/doc/OSCOMP-Repo/Week10.md deleted file mode 100644 index dfe257a..0000000 --- a/doc/OSCOMP-Repo/Week10.md +++ /dev/null @@ -1,218 +0,0 @@ -# Week 10,11 Repo - -## 上两周工作内容 - -1. 完成了除去文件系统的系统调用之外的所有初赛系统调用,其中一部分已经通过了初赛的测例。 -2. 初步确定了arceos后续开发的思想:解耦化,模块化,泛用化。 - - - -## 进程管理与内存管理 - -### 进程控制块结构 - -```rust -/// 进程的的数据结构 -pub struct Process { - /// 进程的pid和初始化的线程的tid是一样的 - pub pid: u64, - pub inner: SpinNoIrq, -} - -pub struct ProcessInner { - /// 父进程的进程号 - pub parent: u64, - /// 子进程 - pub children: Vec>, - /// 子任务 - pub tasks: Vec, - /// 地址空间,由于存在地址空间共享,因此设计为Arc类型 - pub memory_set: Arc>, - /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量 - pub heap_bottom: usize, - /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小 - pub heap_top: usize, - /// 进程状态 - pub is_zombie: bool, - /// 退出状态码 - pub exit_code: i32, - /// 文件描述符表 - pub fd_table: Vec>>, -} -``` - -### 任务控制块结构 - -```rust -pub struct TaskInner { - id: TaskId, - name: &'static str, - is_idle: bool, - is_init: bool, - /// 所属进程 - process_id: u64, - /// 是否是所属进程下的主线程 - is_leader: AtomicBool, - /// 所包含的页表的token,内核的token统一为0 - page_table_token: usize, - exit_code: AtomicI32, - entry: Option<*mut dyn FnOnce()>, - state: AtomicU8, - - in_wait_queue: AtomicBool, - in_timer_list: AtomicBool, - - #[cfg(feature = "preempt")] - need_resched: AtomicBool, - #[cfg(feature = "preempt")] - preempt_disable_count: AtomicUsize, - /// 存储当前线程的TrapContext - pub trap_frame: UnsafeCell, - kstack: Option, - ctx: UnsafeCell, - time: UnsafeCell, -} -``` - -### 进程与线程之间的交互处理 - -* 交互出现的情况:线程结束时需要回收资源,此时需要找到线程所对应的进程块。 - -* 问题:之前在线程控制块中存储了指向进程的指针,导致进程和线程无法解耦。 - -* 解决方法:线程控制块仅存储进程的ID。当前情况下,线程只会在执行exit调用时会结束,此时将exit的处理交给进程控制块来做。 - - 进程模块主动找到当前的线程并将其结束,并通过一个**ID与进程的哈希对应表**来找到线程对应的进程,进行相关资源的回收。 - - - -### 关于内核架构的设想 - -当前内核模块关系图: - -```mermaid -graph TD; -axsync-->axdisplay -axdriver-->axdisplay - -axhal-->axdriver -axalloc-->axdriver -axconfig-->axdriver - -axdriver-->axfs -axsync-->axfs -axtask-.dev.->axfs - -axtask-->axfs_os -axfs-->axfs_os - -axconfig-->axhal -axalloc-->axhal -axlog-->axhal - -axhal-->axnet -axsync-->axnet -axtask-->axnet -axdriver-->axnet - -axalloc-->axruntime -axconfig-->axruntime -axdriver-->axruntime -axhal-->axruntime -axlog-->axruntime -axnet-->axruntime -axdisplay-->axruntime -axtask-->axruntime -axprocess-->axruntime -axtask-->axsync -axtask-->axprocess -axfs_os-->axprocess -axhal-->axprocess - -axprocess-->axsyscall -axsyscall-->axruntime -axalloc-->axtask -axhal-->axtask -axconfig-->axtask -axlog-->axtask - -axhal-->axmem -axalloc-->axmem - -axmem-->axprocess - -``` - -* 当前如axnet,axdisplay暂时还未归纳到axprocess下,不过也许无伤大雅。 -* 如果要改造为一个宏内核,应当由进程模块来统领其他资源,如task,mem,fs等,并对外提供接口。 -* axsyscall是对axprocess对外接口的进一步抽象化,将其转化为系统调用的模式提供给应用程序。 - - - -## 文件系统的接入 - -### 模块说明 - -* `axfs`:对fat32文件系统的调用实现,支持从fat32文件系统中进行读写操作。 -* `axfs_os`:`axfs`的进一步封装,提供了包括文件描述符等数据结构,方便内核对文件进行管理。 -* `axprocess`包含了对`axfs_os`的调用,通过文件描述符等结构来完成对文件的读写操作。 - - - -### 接入后改动的地方 - -1. process块需要引入文件描述符表,同时应当注意多核并发下的保护。 -2. 读取文件改为从文件系统读取,包括初始化用户程序以及`exec`系统调用。 - - - -### 当前demo运行 - -1. 生成文件镜像: - - 在`arceos`根目录下运行指令生成fat32文件系统镜像: - - ```shell - ./build_img.sh - ``` - -2. 指定运行用户程序: - - 在`module/axprocess/process/init_user_process`中,指定`main_task`运行的应用程序名。 - -3. 运行arceos内核,运行如下指令: - - ```shell - make A=apps/helloworld ARCH=riscv64 LOG=info SMP=1 FS=y run - ``` - - 其中: - - 1. `A=apps/helloworld`仅是为了符合makefile的格式而写。 - 2. `ARCH=riscv64`指定指令集 - 3. `LOG=info`指定输出日志级别 - 4. `SMP=1`指定单核启动 - 5. `FS=y`指定启用文件系统 - -* 当前问题:本人对makefile不是很熟悉,所以启动过程看上去很简陋,期望能得到帮助改造启动指令。 - - - -## 后续工作 - -1. 测试其他初赛用例,保证测例通过。 -2. 与老师讨论下一步: - 1. 了解更多linux系统特性,如irq - 2. 学习更多OS,如kerla,aero内核系统 - 3. 尝试复赛的系统调用 - 4. 泛用化思想实现 - -1. 不同OS运行busybox的方式:Maturin,kerla,aero。 - -areo: https://github.com/Andy-Python-Programmer/aero -kerla: https://github.com/nuta/kerla -2. kerla跑ssh的方式 -3. aero运行图形化界面的方式 -4. 批量通过初赛测例 -5. 图形与网络 -6. 继承往年优秀项目的特性,如GCC \ No newline at end of file diff --git a/doc/OSCOMP-Repo/Week12.md b/doc/OSCOMP-Repo/Week12.md deleted file mode 100644 index 6715161..0000000 --- a/doc/OSCOMP-Repo/Week12.md +++ /dev/null @@ -1,320 +0,0 @@ -# Week 12 - -## Maturin运行决赛测例指令 - -### 生成对应文件镜像并运行 - -目前可以加载 `libc` 测例或 `busybox/lua/lmbench` 测例,默认为 `libc`。 - -生成文件测例方式: - -```shell -cd kernel -make clean -DISK_DIR=busybox make testcases-img -``` - -或直接在`/kernel/Makefile` 里第 12 行直接修改 `DISK_DIR ?= libc` 一项。 - -当前应当可以执行两类测例:`libc`与`busybox`。 - -之后直接执行`make run `即可。 - -### 代码中执行流程: - -1. `kernel/src/file/device/test.rs`中`lazy_static`部分,`TESTCASES_ITER`指明了当前运行的测例,`TEST_STATUS`指明了所有即将运行的测例, - -2. `kernel/src/task/scheduler.rs`中`lazy_static`部分。`IS_TEST_ENV`指明了是在测试环境下。此时会通过执行`load_next_testcase`来读取测例。 - -3. `load_next_testcase`会读取一条指令并利用该指令执行对应的程序。当前的默认`TESTCASES`为 - - ```rust - "busybox sh lua_testcode.sh", // lua 测例 - "busybox sh busybox_testcode.sh", // busybox 测例 - "busybox sh lmbench_testcode.sh", // lmbench 测例 - ``` - -4. 在上述例子中,会启动`busybox`应用程序,并将`sh`以及后续的文件名传递给该应用程序。在`busybox`支持下会执行`sh`指令,进而去执行一系列的测试指令。 - -### 测例说明 - -#### busybox - -##### busy说明 - -BusyBox 是一个开源项目,它提供了大约 400 个常见 UNIX/Linux 命令的精简实现。 - -##### busybox测试过程 - -* 通过上述`testcases`执行`busybox_testcode.sh` - -* 真正执行的指令在`busybox_cmd.txt`中,包括了很多条指令。这些指令是linux对应指令的子集,所需要支持的操作也是linux所需要操作的子集。包括如cat,echo等常见指令。 - - ```sh - echo "#### independent command test" - ash -c exit - sh -c exit - basename /aaa/bbb - cal - clear - date - df - dirname /aaa/bbb - dmesg - du - expr 1 + 1 - false - true - which ls - uname - uptime - printf "abc\n" - ps - pwd - free - hwclock - kill 10 - ls - sleep 1 - echo "#### file opration test" - touch test.txt - echo "hello world" > test.txt - cat test.txt - cut -c 3 test.txt - od test.txt - head test.txt - tail test.txt - hexdump -C test.txt - md5sum test.txt - echo "ccccccc" >> test.txt - echo "bbbbbbb" >> test.txt - echo "aaaaaaa" >> test.txt - echo "2222222" >> test.txt - echo "1111111" >> test.txt - echo "bbbbbbb" >> test.txt - sort test.txt | ./busybox uniq - stat test.txt - strings test.txt - wc test.txt - [ -f test.txt ] - more test.txt - rm test.txt - mkdir test_dir - mv test_dir test - rmdir test - grep hello busybox_cmd.txt - cp busybox_cmd.txt busybox_cmd.bak - rm busybox_cmd.bak - find -name "busybox_cmd.txt" - ``` - -* 对每一条指令都会执行相关操作并且收集结果。 - - - -#### lmbench - -##### lmbench说明 - -lmbench是一个性能测试工具,可以进行相关的性能测试。 - -##### lmbench测试过程 - -* 通过上述`testcases`执行`lmbench_testcode.sh` - -* 测例内容: - - ```sh - #!/bin/bash - echo latency measurements - lmbench_all lat_syscall -P 1 null - lmbench_all lat_syscall -P 1 read - lmbench_all lat_syscall -P 1 write - busybox mkdir -p /var/tmp - busybox touch /var/tmp/lmbench - lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench - lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench - lmbench_all lat_syscall -P 1 open /var/tmp/lmbench - lmbench_all lat_select -n 100 -P 1 file - lmbench_all lat_sig -P 1 install - lmbench_all lat_sig -P 1 catch - lmbench_all lat_sig -P 1 prot lat_sig - lmbench_all lat_pipe -P 1 - lmbench_all lat_proc -P 1 fork - lmbench_all lat_proc -P 1 exec - busybox cp hello /tmp - lmbench_all lat_proc -P 1 shell - lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=1m fsync=1 print=3 - lmbench_all lat_pagefault -P 1 /var/tmp/XXX - lmbench_all lat_mmap -P 1 512k /var/tmp/XXX - busybox echo file system latency - lmbench_all lat_fs /var/tmp - busybox echo Bandwidth measurements - lmbench_all bw_pipe -P 1 - lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX - lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX - lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX - lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX - busybox echo context switch overhead - lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 - ``` - -* 相关提及的指令说明: - - * lmbench_all:运行所有的lmbench测例数据,即执行一条lmbench_all指令 - - * lat_syscall指令:用于测量系统调用的延迟时间。可以指定系统调用执行的次数来提高测试精确度。 - - > lat_syscall测试指令是针对系统调用延迟时间的基准测试,它并不涉及系统调用的吞吐量或其它方面的性能评估。如果需要进行系统调用的吞吐量测试,可以使用lmbench测试工具中的其它测试指令,如lat_pipe或lat_tcp等。 - - * lat_select:用于测量select系统调用的延迟时间。会在指定的进程数中启动一个循环,每次循环会调用select系统调用,并测量该系统调用的延迟时间,以评估系统的性能和稳定性。 - - > select是一种I/O多路复用机制,用于在多个文件描述符上进行等待,直到其中一个或多个文件描述符变为可读、可写或发生异常事件时返回。select系统调用通常用于实现异步I/O或同时处理多个I/O事件的应用程序。 - > - > - > - > 测试select需要一个文件,测例中指定了file作为文件。如果未指定`file`参数,则`lat_select`指令会在内存中创建一个虚拟的文件来进行测试。 - > - > - - * lat_sig:测试信号的处理延迟时间。该指令可以通过模拟发送信号和信号处理函数的执行来测量系统的响应时间。它将会模拟发送信号并等待信号处理函数执行完成,并测量整个过程的延迟时间。 - - * lat_pipe:用于测试管道(pipe)的性能和延迟时间。它将会创建一个管道,然后通过多个进程进行读写操作,测量数据传输和同步的延迟时间。 - - * lat_proc:用于测试进程创建的性能和延迟时间。 - - * lmdd:测试磁盘的读写性能和延迟时间。它将会打开指定的测试文件,然后通过多个线程进行读写操作,测量磁盘的读写性能和延迟时间。它可以测试顺序读写、随机读写等多种模式,可以指定块大小、IO深度等测试参数。 - - * bw_pipe:用于测试进程间管道通信的**带宽**和延迟时间。 - - * bw_file_rd:测试文件读取操作的**带宽性能**。该指令通过多个进程并行读取指定文件,并计算平均吞吐量和标准差等统计信息。 - - * bw_mmap_rd:测试内存映射文件的读取**带宽性能**。该指令通过在多个进程中并行读取指定的内存映射文件,并计算平均吞吐量和标准差等统计信息。 - - * lat_ctx:测试上下文切换的性能。在测试过程中,该指令会创建多个线程,并在不同的线程之间进行上下文切换,从而计算上下文切换的延迟时间和吞吐量等指标。 - - * lat_pagefault:测试页面故障(page fault)的性能。在测试过程中,该指令会模拟页面故障,并计算产生页面故障时的延迟时间和吞吐量等指标。 - - * lat_fs:测试文件系统的性能。该指令通过对指定文件的读写操作,来测试文件系统的延迟和吞吐量等性能指标。 - - * lat_mmap:测试内存映射文件的性能。该指令通过对内存映射文件的读写操作,来测试系统的延迟和吞吐量等性能指标。 - - * 与`bw_mmap_rd`区别: - - `lat_mmap`主要用于测试内存映射文件的延迟性能,即测试对内存映射文件进行读写操作所需要的时间。该指令通过对内存映射文件的读写操作,来测试系统的延迟和吞吐量等性能指标。 - - `bw_mmap_rd`则主要用于测试内存映射文件的带宽性能,即测试对内存映射文件进行连续读取所能达到的最大带宽。该指令通过对内存映射文件进行连续的读取操作,来测试系统的带宽性能指标。 - -#### lua - -##### lua说明 - -Lua是一种轻量级、高效、可嵌入的脚本编程语言。通过其核心代码上提供的交互式程序可以方便的进行编程,交互模式类似于python。 - -##### 测试方式 - -* lua的测试应当要求OS内核能够正确运行lua核心代码的程序`testcases/busybox/lua`,并在此基础上支持lua脚本应用。 - -* 通过上述`testcases`执行`lua_testcode.sh`,并且运行不同的`lua`脚本程序。 - - - -#### libc测例 - -##### libc测例说明 - -libc测例与busybox类测例不同,不需要依靠busybox执行,而是类似于初赛阶段的测例,给出一段代码之后将其在内核上直接运行。其分为三类: - -* 初赛测例部分。 -* libc静态测例:该部分不需要动态加载。 -* libc动态测例:该部分需要动态加载,因此需要我们改造读取elf文件的函数,将其支持动态加载。 - -##### 运行方式 - -在生成文件镜像时指定`DISK_DIR`为`libc`即可。 - - - -## aeroOS研究 - -### OS特性 - -* 64位高半内核:即将应用程序的地址分配在低半部分,将内核代码分配在高半部分的虚拟地址。如将范围留`0x00000000 - 0xBFFFFFFF`用于用户代码,数据,堆栈,库等。具有这种设计的内核被称为“上半部分”。 - - > 优点:方便链接与分配内存 - -* 4级或5级分页 - -* 抢占式percpu机制调度 - - * 抢占式:进程可以在执行时被打断,或者被其他CPU接过控制权 - * percpu:为了避免多个 CPU 对全局数据的竞争而导致的性能损失,percpu 直接为每个 CPU 生成一份独有的数据备份,每个数据备份占用独立的内存,CPU 不应该修改不属于自己的这部分数据,这样就避免了多 CPU 对全局数据的竞争问题。 - -* Modern UEFI bootloader - -* Symmetric Multiprocessing:拥有超过一个以上的处理器,这些处理器都连接到同一个共享的主记忆体上,并由单一作业系统来控制。 - -* On-demand paging:需要时分配页面,即类似于懒分配。 - -### 启动方式 - -1. 安装相应依赖 - - 在管理员模式下运行下列指令安装相应的依赖 - - ```sh - sudo ./tools/deps.sh - ``` - -2. 运行内核 - - 内核启动的详细指令存储在`./aero.py`中,包含了一系列编译选项来选择不同的启动模式。 - - * 直接运行指令 - - ```sh - ./aero.py - ``` - - * 会报错` No such file or directory: 'qemu-system-x86_64'`。查阅`./aero.py`发现其不支持`riscv`指令集,仅支持`x86和aarch`。 - - * 尝试安装`qemu-system-x86_64`:在`rCore-tutorial`的环境配置的基础上,在`qemu-7.0.0`的文件夹下执行指令: - - ```sh - ./configure --target-list=x86_64-softmmu,x86_64-linux-user - make -j$(nproc) - ``` - - 此时执行指令 - - ```sh - qemu-system-x86_64 --version - ``` - - 会输出相关的版本信息,说明安装成功。 - - * 再次尝试运行`./aero.py`,再次报错:`Could not initialize SDL(x11 not available) - exiting`,查询得知是因为`qemu`未安装图形化界面。 - - * 查询指令,再次执行qemu安装,运行下列指令: - - ```sh - ./configure --target-list=x86_64-softmmu,x86_64-linux-user --enable-sdl - make -j$(nproc) - ``` - - * 仍然报错,发现需要Ubuntu系统支持图形化界面。可以采用xcvrv客户端的形式。因此需要进行一系列配置。 - - * 发现问题:若是直接运行给定的`./aero.py`,则无法找到程序入口,因为缺少了`host-rust`依赖安装。若是尝试构建完整的`./aero.py --sysroot`,则会因为众多依赖问题无法完成安装。 - -## 初赛部分 - -* 通过了除去文件管理外的所有测例 -* 实现了自动化测试并且输出测试结果 - - - -## 下周工作 - -1. 合并文件系统 -2. 尝试解决图形化界面OS的配置 -3. 初步开始构建决赛的实现 diff --git a/doc/OSCOMP-Repo/Week13.md b/doc/OSCOMP-Repo/Week13.md deleted file mode 100644 index 32c5d27..0000000 --- a/doc/OSCOMP-Repo/Week13.md +++ /dev/null @@ -1,143 +0,0 @@ -# Week13 - -## 决赛环境配置 - -* 环境为WSL+Ubuntu22.04-LTS - -* 配置必要依赖 - - ```shell - sudo apt install build-essential - sudo apt install musl-tools - sudo apt-get install libncurses5-dev libncursesw5-dev - ``` - -* 配置riscv64-linux-musl-cross - - * 官网下载https://musl.cc/riscv64-linux-musl-cross.tgz - - * 解压压缩包 - - ```shell - tar zxvf musl-1.2.1.tar.gz - ``` - - * 运行配置文件 - - ```shell - ./configure - make - sudo make install - ``` - - * 若无法正常运行musl-gcc,需要配置环境变量。 - - * 此后便可以正常使用`musl-gcc`代替`gcc`进行编译。 - -* 动态链接库加载: - - * 根据`README.md`,它需要一个动态链接库,原本是`/lib/ld-musl-riscv64-sf.so.1`,但它实质上是一个链接文件,指向了`libc.so`,所以将`libc.so`直接手动加入到文件镜像中。 - - > `libc.so`通过由maturin的文件镜像获取 - - * 内核需要手动建立从`/lib/ld-musl-riscv64-sf.so.1`到`libc.so`的链接,即用`libc.so`代替`/lib/ld-musl-riscv64-sf.so.1`。 - - > 原因:fat32不支持符号链接,elf默认请求的是`/lib/ld-musl-riscv64-sf.so.1`,此时通过内核手动建立链接让其转发给`libc.so`。 - -* 编译可执行文件 - - * 在`libc-test`文件夹下的`makefile`修改`MUSL_LIB`和`PREFIX`为当前`musl`的交叉编译版本。本机编译版本为`riscv64-linux-musl-gcc`。 - - * 问题:本机版本为`11.2.1`,使用make编译会进行报错: - - ![image-20230520211208912](C:\Users\zyj57\AppData\Roaming\Typora\typora-user-images\image-20230520211208912.png) - - 出错原因:`dso.obj`是一个动态链接库,加入了`-static`编译参数。会导致错误。 - - - - 闭浩扬学长版本为`8.2.0`,此时make编译不会报错。 - - - - - -## 决赛测例加载 - -* 文件镜像加载:将已经编译好的libc-test可执行文件加载到fat32文件镜像 -* 实现批量自动运行 -* 当前问题: - * 命令行参数加载 - * 动态链接加载 - - - - - -## 期望实现的系统调用 - -```shell -FCNTL64 = 25, -IOCTL = 29, -ACCESS = 48, -CHMOD = 53, -LSEEK = 62, -READV = 65, -WRITEV = 66, -PREAD = 67, -SENDFILE64 = 71, -PSELECT6 = 72, -PPOLL = 73, -READLINKAT = 78, -FSTATAT = 79, -FSTAT = 80, -FSYNC = 82, -FDATASYNC = 83, -UTIMENSAT = 88, -EXIT_GROUP = 94, -SET_TID_ADDRESS = 96, -FUTEX = 98, -SET_ROBUST_LIST = 99, -GET_ROBUST_LIST = 100, -GETITIMER = 102, -SETITIMER = 103, -CLOCK_GET_TIME = 113, -SYSLOG = 116, -KILL = 129, -TKILL = 130, -SIGACTION = 134, -SIGPROCMASK = 135, -SIGTIMEDWAIT = 137, -SIGRETURN = 139, -GETRUSAGE = 165, -UMASK = 166, -PRCTL = 167, -GETUID = 174, -GETEUID = 175, -GETGID = 176, -GETEGID = 177, -GETTID = 178, -SYSINFO = 179, -SOCKET = 198, -BIND = 200, -LISTEN = 201, -ACCEPT = 202, -CONNECT = 203, -GETSOCKNAME = 204, -GETPEERNAME = 205, -SENDTO = 206, -RECVFROM = 207, -SETSOCKOPT = 208, -GETSOCKOPT = 209, -SHUDOWN = 210, -SENDMSG = 211, -RECVMSG = 212, -MPROTECT = 226, -MSYNC = 227, -MADVISE = 233, -ACCEPT4 = 242, -PRLIMIT64 = 261, -RENAMEAT2 = 276, -MEMBARRIER = 283, -``` - diff --git a/doc/OSCOMP-Repo/Week14.md b/doc/OSCOMP-Repo/Week14.md deleted file mode 100644 index 236be04..0000000 --- a/doc/OSCOMP-Repo/Week14.md +++ /dev/null @@ -1,152 +0,0 @@ -# Week14 - -## 本周进展 - -1. 通过了初赛所有测例 -2. 完成了决赛部分测例的运行,同时实现了批量静态链接,即将实现动态链接。 -3. 初步构造了信号结构。 -4. 学习umi等操作系统 - - - -## 通过测例 - -初赛部分测例已经通过,但是存在部分尚未解决的问题: - -1. arceos文件系统当前不支持对物理地址不连续的buff的直接修改,只能通过逐页写入buffer的形式来修改缓冲区。 - - 这种情况仅会出现在lazy alloc中,因为lazy alloc得到的物理地址是不连续的。 - -2. 部分引用了arceos文件系统的内容会导致奇怪的bug,如实现getdirent系统调用时若缓冲区开的太小,即使该部分没有被显式调用,仍然会导致其他测例运行错误。 - - - -## 决赛部分测例运行 - -1. 实现了批量的静态链接,已经可以开始运行。 -2. 在此基础上加入了动态链接的部分,但未经过测试。 - - - -## umi等操作系统学习启示 - -### 杭电的操作系统lastWakeUp - -#### 特点 - -1. 实现了bash界面。 -2. 内存管理进展较快,实现了copy on write。 -3. 实现了并发程序,支持多核运行。 -4. 合作上:采取线下集体开发的形式进行合作,同时也积极请教学长 - -5. 实现了进程和进程组的概念,进程结构如下: - - ```c - // Per-process state - struct proc { - struct spinlock lock; - - // p->lock must be held when using these: - enum procstate state; // Process state - void *chan; // If non-zero, sleeping on chan - int killed; // If non-zero, have been killed - struct list_head head_vma; - int exit_state; // Exit status to be returned to parent's wait - pid_t pid; // Process ID - - // maybe also need thread lock to access, p->tlock must be held - struct spinlock tlock; - - // these are private to the process, so p->lock need not be held. - uint64 kstack; // Virtual address of kernel stack - uint64 sz; // Size of process memory (bytes) - pagetable_t pagetable; // User page table - struct trapframe *trapframe; // data page for trampoline.S - struct context context; // swtch() here to run process - struct file *_ofile[NOFILE]; // Open files - struct inode *_cwd; // Current directory - // struct file *ofile[NOFILE]; // Open files(only in xv6) - // struct inode *cwd; // Current directory(only in xv6) - char name[16]; // Process name (debugging) - - // wait_lock must be held when using this: - struct proc *parent; // Parent process - - struct list_head state_list; // its state queue - struct proc *first_child; // its first child!!!!!!! - struct list_head sibling_list; // its sibling - - int sigpending; // have signal? - struct signal_struct *sig; // signal - sigset_t blocked; // the blocked signal - struct sigpending pending; // pending (private) - struct sigpending shared_pending; // pending (shared) - - tgid_t tgid; // thread group id - int thread_cnt; // the count of threads - struct list_head thread_group; // thread group - struct proc *group_leader; // its proc thread group leader - - pgrp_t pgid; // proc group id - - struct list_head wait_list; // waiting queue - pid_t *ctid; - // struct spinlock wait_lock; - struct semaphore sem_wait_chan_parent; - struct semaphore sem_wait_chan_self; - - long tms_stime; // system mode time(ticks) - long tms_utime; // user mode time(ticks) - long create_time; // create time(ticks) - long enter_time; // enter kernel time(ticks) - }; - - ``` - - - -#### 调试特点 - -1. 使用vscode连接到debugger上,通过vscode上的gdb进行调试。 -2. 使用trace追踪 - - - - - -# umi - -## 进展 - -1. co-trap实现函数式trap分离 - -2. 实现了支持非异步函数和异步函数的函数调用表 - -3. 较好的泛型操作 -4. 较好的异步实现操作 -5. 无栈协程操作 - -## 特点 - -1. 较多的rust高阶操作:包括泛型、宏展开 -2. 内核态中断 -3. 大量的异步操作与生命周期指令 -4. 进程部分将任务的状态作为局部变量传入函数,尽可能减少锁结构,减小锁的粒度。通过减少锁的使用使得调试更为方便。 -5. 协程不是为了性能,而是为了调试方便 -6. 通过feature的方式使得模块与内核解耦合,提供了一个trait供内核使用 -7. ECS系统引入函数调用表,统一使用了map。通过请教本人,该写法可能是为了使得代码更加简洁,同时索引的方式可以减少匹配耗时。 - - - -**其开发过程中很多设计是为了更方便地进行调试使用地,是一个比较新颖的开发方式**。 - -**同时通过提供feature的方式使得模块解耦是一个值得借鉴的思想,我们的arceos的文件系统模块可以利用这一点。** - - - -### 下周安排 - -1. 完成在线评测 -2. 完成动态链接 -3. 实现信号结构 -4. 开始考虑并发多核启动问题 \ No newline at end of file diff --git a/doc/OSCOMP-Repo/Week15.md b/doc/OSCOMP-Repo/Week15.md deleted file mode 100644 index 1becfbc..0000000 --- a/doc/OSCOMP-Repo/Week15.md +++ /dev/null @@ -1,288 +0,0 @@ -# Week15 - -## OS重构 - -### 结构图对比 - -原先Arceos结构图: - -![ArceOS](\figures\ArceOS.svg) - - - -重构后StarryOS架构图: - -![Starry](\figures\Starry.svg) - - - -### 结构说明 - -* crates:与OS设计无关的公共组件 -* modules:与OS设计更加耦合的组件 -* apps:unikernel架构下的用户程序,继承原有ArceOS -* ulib:用户库,继承原有ArceOS - -1. 为了实现宏内核架构体系,需要对原有Arceos的部分核心模块(如axtask)进行修改。为了防止合并时冲突过多,因此在对应模块下建立`macro*`为前缀的文件夹,存放为宏内核架构实现的内容。同时使用条件编译来选择是宏内核架构还是unikernel架构。 - -2. 为了实现linux APP兼容,需要实现一系列面向linux的系统调用。我们将系统调用的具体实现部分放在`starry_libax`部分,即以用户库的形式形成一个linux兼容层。通过调用上述模块提供的一系列接口,实现对应的linux 系统调用,并暴露给外界。这个系统兼容层与原有的`libax`进行对应,分别提供不同的接口与服务。 - - - -3. 模块部分放置可以为宏内核与unikernel尽可能共享的内容,通过条件编译等方式做到尽可能地为不同架构下的兼容层所调用。 - - - -#### 理解:umi等OS的模块与Arceos的模块区别 - -* Umi模块更加接近于Arceos的crates,实现的是某一个特定的功能,如内核堆分配器、随机数生成函数等,其具有较好的可移植性。 -* Arceos的modules实现的是内核中的某一个核心模块,如虚存、信号、文件系统等内容。其需要使用到较多的crates与已经实现的modules。移植时的限制可能会更多一些,如使用一些特定的trait等内容。 -* Arceos的modules自带的模块化特征,可以保证其通过条件编译等手段,组合实现不同架构下的不同模式。如是否使用宏内核架构,内核架构是否启用分页、信号、文件系统等内容。也就是说,模块化OS可以支持多种启动方式,避免无意义的全部编译。 - - - -4. 批量测试、单个测例测试等内容的启动实现在apps中,即通过apps实现内容来操控内核行为。 - - - -## 比赛进度 - -1. 合并后的OS已经可以通过所有初赛测例 -2. 实现了lazy alloc与动态加载 -3. 可以完成libc测例的批量加载并且统计了所有需要实现的系统调用(暂时)。 - - - -## 系统调用 - -需要实现的系统调用: - -```rust -//! 系统调用实现 -//! -//! 目前的系统调用规范参照比赛所提供的类似 Linux 系统调用实现。 -//! -//! 有一些注释的系统调用名,那些是 rCore 的约定实现 -//! -//! 这两种调用间比较容易混淆的区别是,比赛测例是用 C 写的,大部分数组都是 4 Byte, -//! 而 rCore 使用 rust,usize/isize 一般是 8 Byte。 -//! 这导致一些传入地址(非字符串,字符串大家都是统一的 1Byte 类型)的大小有问题, -//! 如 sys_pipe() 在测例环境下需要将输入作为 *mut u32 而不是 *mut usize - -//#![deny(missing_docs)] -UNKNOWN = usize::MAX, // 未识别的系统调用 -GETCWD = 17, -DUP = 23, -DUP3 = 24, -FCNTL64 = 25, -IOCTL = 29, -MKDIR = 34, -UNLINKAT = 35, -LINKAT = 37, -UMOUNT = 39, -MOUNT = 40, -STATFS = 43, -ACCESS = 48, // 不一定要有 -CHDIR = 49, -CHMOD = 53, -OPEN = 56, -CLOSE = 57, -PIPE = 59, -GETDENTS64 = 61, -LSEEK = 62, -READ = 63, -WRITE = 64, -READV = 65, -WRITEV = 66, -PREAD = 67, -SENDFILE64 = 71, -PSELECT6 = 72, -PPOLL = 73, // 不一定要有 -READLINKAT = 78, -FSTATAT = 79, -FSTAT = 80, -FSYNC = 82, -FDATASYNC = 83, // 不一定要有 -UTIMENSAT = 88, -EXIT = 93, -EXIT_GROUP = 94, -SET_TID_ADDRESS = 96, -FUTEX = 98, -NANOSLEEP = 101, -GETITIMER = 102, // 不一定要有 -SETITIMER = 103, // 不一定要有 -CLOCK_GET_TIME = 113, -SYSLOG = 116, // 不一定要有 -YIELD = 124, -KILL = 129, -TKILL = 130, -SIGACTION = 134, -SIGPROCMASK = 135, -SIGTIMEDWAIT = 137, -SIGRETURN = 139, -TIMES = 153, -UNAME = 160, -GETRUSAGE = 165, // 不一定要有 -UMASK = 166, // 不一定要有 -PRCTL = 167, // 不一定要有 -GET_TIME_OF_DAY = 169, -GETPID = 172, -GETPPID = 173, -GETUID = 174, -GETEUID = 175, -GETGID = 176, -GETEGID = 177, -GETTID = 178, -SYSINFO = 179, // 不一定要有 -SOCKET = 198, -BIND = 200, // 不一定要有 -LISTEN = 201, // 不一定要有 -ACCEPT = 202, // 不一定要有 -CONNECT = 203, // 不一定要有 -GETSOCKNAME = 204, // 不一定要有 -GETPEERNAME = 205, // 不一定要有 -SENDTO = 206, -RECVFROM = 207, -SETSOCKOPT = 208, // 不一定要用 -GETSOCKOPT = 209, // 不一定要有 -SHUDOWN = 210, // 不一定要有 -SENDMSG = 211, // 不一定要有 -RECVMSG = 212, // 不一定要有 -BRK = 214, -MUNMAP = 215, -CLONE = 220, -EXECVE = 221, -MMAP = 222, -MPROTECT = 226, -MSYNC = 227, // 不一定要有 -MADVISE = 233, // 不一定要有 -ACCEPT4 = 242, // 不一定要有 -WAIT4 = 260, -PRLIMIT64 = 261, -RENAMEAT2 = 276, // 不一定要有 -MEMBARRIER = 283, -``` - -### 文件系统 - -```rust -GETCWD = 17, -DUP = 23, -DUP3 = 24, -FCNTL64 = 25, -IOCTL = 29, -MKDIR = 34, -UNLINKAT = 35, -LINKAT = 37, -UMOUNT = 39, -MOUNT = 40, -STATFS = 43, -ACCESS = 48, // 不一定要有 -CHDIR = 49, -CHMOD = 53, -OPEN = 56, -CLOSE = 57, -PIPE = 59, -GETDENTS64 = 61, -LSEEK = 62, -READ = 63, -WRITE = 64, -READV = 65, -WRITEV = 66, -PREAD = 67, -SENDFILE64 = 71, -PSELECT6 = 72, -PPOLL = 73, // 不一定要有 -READLINKAT = 78, -FSTATAT = 79, -FSTAT = 80, -FSYNC = 82, -FDATASYNC = 83, // 不一定要有 -UTIMENSAT = 88, -RENAMEAT2 = 276 // 不一定要有 -``` - -### 任务管理 - -```rust -EXIT = 93, -EXIT_GROUP = 94, -SET_TID_ADDRESS = 96, -FUTEX = 98, -NANOSLEEP = 101, -YIELD = 124, -KILL = 129, -TKILL = 130, -UMASK = 166, // 不一定要有 -GETPID = 172, -GETPPID = 173, -GETUID = 174, -GETEUID = 175, -GETGID = 176, -GETEGID = 177, -GETTID = 178, -CLONE = 220, -EXECVE = 221, -WAIT4 = 260, -``` - -### 信号相关 - -```rust -SIGACTION = 134, -SIGPROCMASK = 135, -SIGTIMEDWAIT = 137, -SIGRETURN = 139, -``` - -### socket相关 - -```rust -SOCKET = 198, -BIND = 200, // 不一定要有 -LISTEN = 201, // 不一定要有 -ACCEPT = 202, // 不一定要有 -CONNECT = 203, // 不一定要有 -GETSOCKNAME = 204, // 不一定要有 -GETPEERNAME = 205, // 不一定要有 -SENDTO = 206, -RECVFROM = 207, -SETSOCKOPT = 208, // 不一定要用 -GETSOCKOPT = 209, // 不一定要有 -SHUDOWN = 210, // 不一定要有 -SENDMSG = 211, // 不一定要有 -RECVMSG = 212, // 不一定要有 -ACCEPT4 = 242, // 不一定要有 -``` - -### 内存相关 - -```rust -BRK = 214, -MUNMAP = 215, -MMAP = 222, -MEMBARRIER = 283, -``` - -### 其他相关 - -```rust -GETITIMER = 102, // 不一定要有 -SETITIMER = 103, // 不一定要有 -CLOCK_GET_TIME = 113, -SYSLOG = 116, // 不一定要有 -TIMES = 153, -UNAME = 160, -GETRUSAGE = 165, // 不一定要有 -PRCTL = 167, // 不一定要有 -GET_TIME_OF_DAY = 169, -PRLIMIT64 = 261, -``` - - - -## 后续安排 - -1. 根据系统调用进行分工,在合并后OS上进行开发。初步计划按照上述划分进行分类。 -2. 与大实验同学进行沟通,看看后续可以怎么进行合并。 - diff --git "a/doc/OSCOMP-Repo/\345\220\257\345\212\250\346\265\201\347\250\213.md" "b/doc/OSCOMP-Repo/\345\220\257\345\212\250\346\265\201\347\250\213.md" deleted file mode 100644 index 1e2d7ba..0000000 --- "a/doc/OSCOMP-Repo/\345\220\257\345\212\250\346\265\201\347\250\213.md" +++ /dev/null @@ -1,54 +0,0 @@ -# Arceos 任务调度流程 - -* 单核情况 - -对应代码在`modules/axtask/src/monolithic_task/run_queue.rs/init`函数中: - -```rust -pub(crate) fn init() { - const IDLE_TASK_STACK_SIZE: usize = 0x20000; - let idle_task = TaskInner::new( - || crate::run_idle(), - "idle".into(), - IDLE_TASK_STACK_SIZE, - KERNEL_PROCESS_ID, - 0, - false, - ); - IDLE_TASK.with_current(|i: &mut LazyInit>>| { - i.init_by(idle_task.clone()) - }); - - let main_task = TaskInner::new_init("main".into()); - main_task.set_state(TaskState::Running); - - RUN_QUEUE.init_by(AxRunQueue::new()); - unsafe { CurrentTask::init_current(main_task) } -} -``` - -共包含三个任务: - -* IDLE_TASK:拥有独立的trap上下文和任务上下文,任务上下文指向的入口是`run_idle`函数。 -* gc_task:在执行`AxRunQueue::new()`函数时生成,负责回收已经退出的任务。 -* main_task:内核运行时执行的任务,它的任务上下文为空,在被切换时会把当前的ra等信息写入任务上下文,从而可以在恢复时继续执行内核相关代码。 - - - -当执行完init函数之后,CPU指向main_task,pc不变,继续执行当前代码,直到来到`modules/axruntime/src/lib.rs/rust_main`函数的`unsafe{main();}`入口,从而跳转到Arceos指定的用户程序(**注意:虽然是用户程序,但是运行在arceos框架下,还处于内核态**),开始加载测例,并生成对应的task加入运行队列,之后执行`yield_task`。 - -对应代码在`ulib/starry_libax/src/test.rs/run_testcases.rs`的568行左右的`yield_task`函数。 - -根据调度队列的实现算法(当前是fifo),第一个被调度运行的是gc,而main_task就存储当前内核态的上下文,即停留在刚才提到的`yield`函数,gc检测是否还有任务退出,若没有则阻塞自己,接下来就会执行测例生成的task。 - -而当调度队列中没有下一个任务时,就会切换到IDLE_TASK,此时会执行`run_idle`函数,即不断执行`yield_task`函数,直到有新的任务加入调度队列,则切换到对应任务。 - - - -* 多核启动 - -我们只考虑任务调度相关,则多核情况下,其他核初始化的函数在`modules/axtask/src/monolithic_task/run_queue.rs/init_secondary`中,会新建一个`idle_task`,但是它的功能类似于单核启动下的`main_task`,即初始化时没有任务上下文,但是可以在被切换之后保留内核的任务执行流。 - -初始化完毕之后,每一个非主核指向一个`idle_task`,此时他们会继续执行内核中的初始化代码,最后在`modules/axruntime/src/mp.rs`的`rust_main_secondary`函数中执行`run_idle`函数,即不断地`yield`自己,直到有新的任务加入调度队列。 - -当测例对应的用户态任务执行`clone`系统调用,生成新的任务加入到调度队列时,此时就会随机分配一个CPU核获得该任务并且进行执行。这就是多核启动的原理。 diff --git a/doc/Starry/docs/figures/ArceOS.svg b/doc/Starry/docs/figures/ArceOS.svg deleted file mode 100644 index 625078a..0000000 --- a/doc/Starry/docs/figures/ArceOS.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
ArceOS modules
ArceOS modules
ArceOS crates
ArceOS crates
User Apps
User Apps
Hypervisor
Hypervisor
axnet
axnet
axtask
axtask
axruntime
axruntime
axlog
axlog
axhal
axhal
axdriver
axdriver
allocator
allocator
axalloc
axalloc
scheduler
scheduler
page_table
page_table
linked_list
linked_list
driver_blk
driver_blk
axasync
axasync
smoltcp
smoltcp
buddy
buddy
slab
slab
FIFO
FIFO
RR
RR
e1000
e1000
lwip_rust
lwip_rust
driver_virtio
driver_virtio
driver_net
driver_net
axconfig
axconfig
page_table_entry
page_table_entry
System compatible layer
System compatible layer
linux
linux
arceos
arceos
ArceOS ulib
ArceOS ulib
rust_libax
rust_libax
c_libax
c_libax
c_musl
c_musl
rust_std
rust_std
Rust App
Rust App
C App
C App
Rust App
Rust App
C App
C App
Text is not SVG - cannot display
\ No newline at end of file diff --git "a/doc/Starry/docs/figures/ArceOS\344\273\213\347\273\215.png" "b/doc/Starry/docs/figures/ArceOS\344\273\213\347\273\215.png" deleted file mode 100644 index 204c3c7..0000000 Binary files "a/doc/Starry/docs/figures/ArceOS\344\273\213\347\273\215.png" and /dev/null differ diff --git "a/doc/Starry/docs/figures/ArceOS\345\257\271\346\257\224\345\256\217\345\206\205\346\240\270.png" "b/doc/Starry/docs/figures/ArceOS\345\257\271\346\257\224\345\256\217\345\206\205\346\240\270.png" deleted file mode 100644 index 7d7cdd8..0000000 Binary files "a/doc/Starry/docs/figures/ArceOS\345\257\271\346\257\224\345\256\217\345\206\205\346\240\270.png" and /dev/null differ diff --git a/doc/Starry/docs/figures/Starry.png b/doc/Starry/docs/figures/Starry.png deleted file mode 100644 index 5d347d5..0000000 Binary files a/doc/Starry/docs/figures/Starry.png and /dev/null differ diff --git a/doc/Starry/docs/figures/Starry.svg b/doc/Starry/docs/figures/Starry.svg deleted file mode 100644 index e63c9b1..0000000 --- a/doc/Starry/docs/figures/Starry.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -
ArceOS modules
ArceOS modules
ArceOS crates
ArceOS crates
User Apps
User Apps
Hypervisor
Hypervisor
axnet
axnet
axtask
axtask
axruntime
axruntime
axlog
axlog
axhal
axhal
axdriver
axdriver
allocator
allocator
axalloc
axalloc
scheduler
scheduler
page_table
page_table
linked_list
linked_list
driver_blk
driver_blk
axasync
axasync
smoltcp
smoltcp
buddy
buddy
slab
slab
FIFO
FIFO
RR
RR
e1000
e1000
lwip_rust
lwip_rust
driver_virtio
driver_virtio
driver_net
driver_net
axconfig
axconfig
page_table_entry
page_table_entry
System compatible layer
System compatible layer
arceos
arceos
ArceOS ulib
ArceOS ulib
rust_libax
rust_libax
c_libax
c_libax
Rust App
Rust App
C App
C App
Rust App
Rust App
C App
C App
axmem
axmem
axprocess
axprocess
rust_strray_lib
rust_strray_lib
c_musl
c_musl
linux
linux
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/doc/Starry/docs/figures/axfs.png b/doc/Starry/docs/figures/axfs.png deleted file mode 100644 index 0506e00..0000000 Binary files a/doc/Starry/docs/figures/axfs.png and /dev/null differ diff --git a/doc/Starry/docs/figures/axhal.png b/doc/Starry/docs/figures/axhal.png deleted file mode 100644 index 098a457..0000000 Binary files a/doc/Starry/docs/figures/axhal.png and /dev/null differ diff --git a/doc/Starry/docs/figures/axprocess.png b/doc/Starry/docs/figures/axprocess.png deleted file mode 100644 index 84a37ca..0000000 Binary files a/doc/Starry/docs/figures/axprocess.png and /dev/null differ diff --git a/doc/Starry/docs/figures/axsignal.png b/doc/Starry/docs/figures/axsignal.png deleted file mode 100644 index 20c2744..0000000 Binary files a/doc/Starry/docs/figures/axsignal.png and /dev/null differ diff --git a/doc/Starry/docs/figures/axtask.png b/doc/Starry/docs/figures/axtask.png deleted file mode 100644 index e0047b6..0000000 Binary files a/doc/Starry/docs/figures/axtask.png and /dev/null differ diff --git a/doc/Starry/docs/figures/crate_interface.png b/doc/Starry/docs/figures/crate_interface.png deleted file mode 100644 index 91b4f8b..0000000 Binary files a/doc/Starry/docs/figures/crate_interface.png and /dev/null differ diff --git a/doc/Starry/docs/figures/display.png b/doc/Starry/docs/figures/display.png deleted file mode 100644 index 3bfab41..0000000 Binary files a/doc/Starry/docs/figures/display.png and /dev/null differ diff --git a/doc/Starry/docs/figures/starry_libax.png b/doc/Starry/docs/figures/starry_libax.png deleted file mode 100644 index 891cdf3..0000000 Binary files a/doc/Starry/docs/figures/starry_libax.png and /dev/null differ diff --git "a/doc/Starry/docs/figures/\345\256\217\345\206\205\346\240\270\345\214\226\346\224\271\345\212\250.png" "b/doc/Starry/docs/figures/\345\256\217\345\206\205\346\240\270\345\214\226\346\224\271\345\212\250.png" deleted file mode 100644 index 8813d22..0000000 Binary files "a/doc/Starry/docs/figures/\345\256\217\345\206\205\346\240\270\345\214\226\346\224\271\345\212\250.png" and /dev/null differ diff --git "a/doc/Starry/docs/figures/\346\236\266\346\236\204\345\257\271\346\257\224.png" "b/doc/Starry/docs/figures/\346\236\266\346\236\204\345\257\271\346\257\224.png" deleted file mode 100644 index 29408fe..0000000 Binary files "a/doc/Starry/docs/figures/\346\236\266\346\236\204\345\257\271\346\257\224.png" and /dev/null differ diff --git "a/doc/Starry/docs/figures/\346\250\241\345\235\227\344\276\235\350\265\226.png" "b/doc/Starry/docs/figures/\346\250\241\345\235\227\344\276\235\350\265\226.png" deleted file mode 100644 index 5543330..0000000 Binary files "a/doc/Starry/docs/figures/\346\250\241\345\235\227\344\276\235\350\265\226.png" and /dev/null differ diff --git a/doc/Starry/docs/index.md b/doc/Starry/docs/index.md deleted file mode 100644 index 19eca7d..0000000 --- a/doc/Starry/docs/index.md +++ /dev/null @@ -1,15 +0,0 @@ -# Starry 设计文档 - -> Starry意指布满星星的,寓意本OS的开发学习借鉴了许多前辈的思路,并将其汇总归一为这个内核。 - -## 成员 - -陈嘉钰、郑友捷、王昱栋 - -## 说明 - -* 一个内核 -* 以riscv64指令集运行 -* 支持在qemu、sifive开发板等平台上运行 -* 支持gcc、redis等Linux应用 -* 支持编译时选择启动架构为Unikernel或者宏内核 diff --git "a/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\344\276\235\350\265\226\351\227\256\351\242\230.md" "b/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\344\276\235\350\265\226\351\227\256\351\242\230.md" deleted file mode 100644 index c2b0f94..0000000 --- "a/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\344\276\235\350\265\226\351\227\256\351\242\230.md" +++ /dev/null @@ -1,135 +0,0 @@ -由于ArceOS自身的unikernel架构,不同模块需要保持一定的依赖关系,从而可以方便地通过条件编译等操作来解耦某些模块,使用某些指定的模块来启动内核,从而增强OS的泛用性。 - -### 查看项目的依赖关系 - -项目的依赖关系可以通过对应的toml配置文件进行查看。如下列为axmem模块的toml: - -```toml -# modules/axmem/Cargo.toml -[dependencies] -log = "0.4" -axhal = { path = "../axhal", features = ["paging"] } -axalloc = { path = "../axalloc" } -axconfig = { path = "../axconfig" } -axerrno = { path = "../../crates/axerrno" } -axfs = { path = "../axfs" } -axio = { path = "../../crates/axio" } -spinlock = { path = "../../crates/spinlock" } -xmas-elf = { path = "../../extern_crates/xmas-elf-0.9.0" } -riscv = { path = "../../extern_crates/riscv-0.10.1" } -page_table_entry = { path = "../../crates/page_table_entry" } -``` - -以上就可以看出axmem依赖了axhal/axfs/axconfig等模块。 - -### 循环依赖问题 - -而Starry虽然是宏内核架构,但仍然保持了这一泛用特性,但这也为我们开发带来了一些问题,即循环依赖问题。 - -> 由于ArceOS的模块化设计,不同的modules之间会形成以module为单位的依赖关系,相较于以文件为 -> 单位的依赖关系而言更容易产生循环依赖的问题。 -> -> 一个例子:假如一个项目中有A、B、C三个文件,A依赖B、B依赖C,不会有任何问题;但如果三 -> 个文件被解耦到两个不同的项目 M和N中,M中有A和C,N中有B,那么M和N之间就会发生相互依 -> 赖。 -> 这种情况在我们的开发过程中并不少见。 - - - -当前Starry的模块依赖图如下: - -![modules](../figures/模块依赖.png) - -如axhal需要定义trap入口,而trap实现需要很多模块的支持如axmem的地址空间等,此时就可能出现循环依赖的情况,即axhal依赖于axmem,而axmem依赖于axhal。 - -为了解决这个问题,有以下几种方法: - -1. 优化结构设计,即尽可能将实现的功能进行划分,如地址空间内容独立出来放在axmem,而不是和进程控制一起放在axprocess。 - -2. 通过ArceOS提供的模块crate_interface中的call_interface和def_interface,在底层模块定义好相关的函数之后,交给上层模块去实现。 - -如在axhal中定义了TrapHandler如下: - -```rust -#[def_interface] -pub trait TrapHandler { - /// Handles interrupt requests for the given IRQ number. - fn handle_irq(irq_num: usize); - // more e.g.: handle_page_fault(); - // 需要分离用户态使用 - #[cfg(feature = "monolithic")] - fn handle_syscall(syscall_id: usize, args: [usize; 6]) -> isize; - - #[cfg(feature = "paging")] - fn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame); - - #[cfg(feature = "paging")] - fn handle_access_fault(addr: VirtAddr, flags: MappingFlags); - - /// 处理当前进程的信号 - #[cfg(feature = "signal")] - fn handle_signal(); - - /// 为了lmbench特判,即在出现未能处理的情况,不panic,而是退出当前进程 - #[cfg(feature = "monolithic")] - fn exit(); -} -``` - -而在starry_libax/trap.rs完成了对TrapHandler的实现: - -```rust -#[crate_interface::impl_interface] -impl axhal::trap::TrapHandler for TrapHandlerImpl { - fn handle_irq(irq_num: usize) { - /// .. - } - fn handle_syscall(syscall_id: usize, args: [usize; 6]) -> isize { - /// .. - } - - #[cfg(feature = "paging")] - fn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame) { - /// .. - } - - fn handle_access_fault(addr: VirtAddr, flags: MappingFlags) { - /// .. - } - - #[cfg(feature = "signal")] - fn handle_signal() { - /// .. - } - - fn exit() { - /// .. - } -} -``` - -而在`axruntime/src/trap.rs`中定义了ArceOS原有的unikernel架构下的trap实现: - -```rust -/// 仅用作非宏内核下的trap入口 - -struct TrapHandlerImpl; - -#[crate_interface::impl_interface] -impl axhal::trap::TrapHandler for TrapHandlerImpl { - fn handle_irq(_irq_num: usize) { - #[cfg(feature = "irq")] - { - let guard = kernel_guard::NoPreempt::new(); - axhal::irq::dispatch_irq(_irq_num); - drop(guard); // rescheduling may occur when preemption is re-enabled. - } - } -} -``` - - - -通过不同的TrapHandler的实现,可以实现宏内核和unikernel架构下不同trap实现的支持。 - - diff --git "a/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\345\205\274\345\256\271\351\227\256\351\242\230.md" "b/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\345\205\274\345\256\271\351\227\256\351\242\230.md" deleted file mode 100644 index 83760e9..0000000 --- "a/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\345\205\274\345\256\271\351\227\256\351\242\230.md" +++ /dev/null @@ -1,43 +0,0 @@ - -为了保证Starry在未来的泛用性,我们在比赛开发过程中便有意识地去注意不同架构下的实现兼容,并采用条件编译等方式进行区分。如process部分的结构体的定义为: - -```rust -pub struct ProcessInner { - /// 父进程的进程号 - pub parent: u64, - /// 子进程 - pub children: Vec>, - /// 子任务 - pub tasks: Vec, - /// 地址空间,由于存在地址空间共享,因此设计为Arc类型 - pub memory_set: Arc>, - /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量 - pub heap_bottom: usize, - /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小 - pub heap_top: usize, - /// 进程状态 - pub is_zombie: bool, - /// 退出状态码 - pub exit_code: i32, - // /// 文件描述符表 - // pub fd_table: Vec>>>, - // /// 文件描述符上限,由prlimit设置 - // pub fd_limit: usize, - #[cfg(feature = "fs")] - pub fd_manager: FdManager, - /// 进程工作目录 - pub cwd: String, - #[cfg(feature = "signal")] - /// 信号处理模块 - /// 第一维代表线程号,第二维代表线程对应的信号处理模块 - pub signal_module: BTreeMap, - - /// robust list存储模块 - /// 用来存储线程对共享变量的使用地址 - /// 具体使用交给了用户空间 - pub robust_list: BTreeMap, -} -``` - -其额外限定了fs和signal的feature,规定了信号模块和文件系统模块的条件编译,可以根据编译参数来决定内核是否支持fs和信号模块。 - diff --git "a/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\345\256\217\345\206\205\346\240\270\345\214\226\346\216\242\350\256\250.md" "b/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\345\256\217\345\206\205\346\240\270\345\214\226\346\216\242\350\256\250.md" deleted file mode 100644 index b561fb1..0000000 --- "a/doc/Starry/docs/\345\256\236\347\216\260\351\207\215\347\202\271/\345\256\217\345\206\205\346\240\270\345\214\226\346\216\242\350\256\250.md" +++ /dev/null @@ -1,112 +0,0 @@ - Starry的工作是为一个面向Unikernel设计的OS添加宏内核支持,因此相比于其他从0开始的 -内核,Starry需要考虑更多兼容工作,也要求我们对Unikernel和ArceOS有足够的了解。 - - - -### 前期知识了解 - -首先,我们了解到ArceOS是以Unikernel架构运行的。因此我们查阅了Unikernel和宏内核相关的资料,并且总结出两者之间的一些简单的区别如下: - -![avatar](../figures/架构对比.png) - - - -另外,我们也详细阅读了ArceOS的代码,总结出从ArceOS到宏内核需要完善的内容: - -![avatar](../figures/ArceOS对比宏内核.png) - - - -通过阅读ArceOS与其他宏内核如zCore、rCore的代码实现,将ArceOS与宏内核的关系划分如下: - -* ArceOS中可直接沿用:log、driver以及一系列解耦的crate -* ArceOS中需要调整适配:任务调度、特权级转化等 -* ArceOS中需要添加:地址空间、进程、信号、文件系统、用户库等内容 - - - -### 开发内容 - -依据前期知识的总结,我们在原有ArceOS的基础上做出了如下改动: - -![avatar](../figures/宏内核化改动.png) - - - -在原有ArceOS代码的基础上 - -* 新增了4个模块:分别为 - * axmem:添加多地址空间 - * axprocess:添加进程管理 - * axsignal:添加信号模块 - * axfs:添加适用于宏内核的文件系统接口 -* 改动适配了5个模块:分别为 - * axhal:主要为关于宏内核的trap处理,如syscall、缺页异常等 - * axtask:主要为task信息的补充,如计时器信息 - * axdriver:主要为ramdisk的补充,为比赛加载测例服务 - * axruntime:主要为内核初始化流程中添加宏内核启动相关服务 - * axnet:主要为Linux相关的syscall添加相对应的接口 -* 新增了一个用户库:封装Linux相关的系统调用,处理相应的syscall -* 共涉及代码约12000行 - - - -### 开发重点 - -#### 进程实现 - -为了保证Starry可以较好地去适配Unikernel架构,在比赛初期我们就进程结构与线程是否分离这个问题进行了讨论。 - - - -在Linux中,进程和线程合并在一起,统一由pthread控制块进行管理,某种程度上简化了结构。但我们的Starry需要适配Unikernel,在Unikernel中是单应用程序,没有多进程的概念。因此作为兼容Linux应用和Unikernel的Starry OS,进程如何定义便有了较为重要的意义。 - - - -我们先讨论了两种做法的优点: - -* 合并优点:符合Linux结构,更加直观 -* 分离优点:适配Unikernel实现,更加兼容ArceOS - - - -为了得到更好的比较结果,我们**分头行动,根据两种不同的定义方式实现了两个内核**。经过比较之后,我们决定将进程和线程合并,更好地去适配ArceOS。 - - - -#### 与ArceOS的兼容 - -为了保证和ArceOS代码功能上的兼容,在开发过程中需要一定程度地保留ArceOS原有代码,同时不能影响自己新的功能,防止出现冲突。 - - - -为了解决这个问题,我们用到了三种工具: - -* 条件编译 - - 条件编译贯穿了Starry实现过程,通过指定不同的feature来定制不同的内核实现。同时,也可以用条件编译来在保留ArceOS原有功能的同时,添加上Starry的分支功能,指定不同的feature保证两者可以得到兼容。 - - ```rust - cfg_if::cfg_if! { - if #[cfg(feature = "monolithic")] { - axprocess::process::init_kernel_process(); - } - else { - #[cfg(feature = "multitask")] - axtask::init_scheduler(); - } - } - ``` - -* 封装trait - - 封装trait是Rust提供不同实现兼容的一种常见方式。不同结构通过用不同方式实现同一个trait,可以得到不同的处理方式和功能,从而达到了兼容并存的效果。如文件系统的一系列读写Trait便起到了这个功能。 - -* crate_interface包 - - crate_interface包是由ArceOS实现的一个包,效果类似于trait。它允许用户在底层通过`def_interface`定义某些函数接口,并在上层通过`impl_interface`实现对应函数的具体内容。通过调用多个`impl_interface`便可以做到同一个接口的多种实现方式。 - - crate_interface与trait的一个不同之处在于,crate_interface的实现只能有一个,也就是说如果存在`impl_interface`,那么可能需要用到条件编译等手段使得仅有唯一一个`impl_interface`被实际编译到镜像中。 - - ![avatar](../figures/crate_interface.png) - diff --git "a/doc/Starry/docs/\346\236\266\346\236\204\350\256\276\350\256\241/ArceOS\344\273\213\347\273\215.md" "b/doc/Starry/docs/\346\236\266\346\236\204\350\256\276\350\256\241/ArceOS\344\273\213\347\273\215.md" deleted file mode 100644 index ceae084..0000000 --- "a/doc/Starry/docs/\346\236\266\346\236\204\350\256\276\350\256\241/ArceOS\344\273\213\347\273\215.md" +++ /dev/null @@ -1,18 +0,0 @@ -我们的Starry是基于ArceOS生成的,因此需要简单介绍一下ArceOS实现的内容。 - -ArceOS采用模块化组件化的设计思维,通过使用内核组件 + 组件化的OS框架 来得到 不同形态的OS kernel。 - -* 提供了一套组件化的操作系统框架 -* 提供各种内核组件的实现,各种内核组件可在没有OS kernel的情况下独立运行 - * 如filesystem, network stack等内核组件可以在裸机或用户态以库的形式运行 - * 各种设备驱动等内核组件可以在裸机上运行 -* 理想情况下可以通过选择组件构成unikernel/宏内核/微内核 -* 实际上在我们开始实验时它还只支持unikernel - * 只运行一个用户程序 - * 用户程序与内核链接为同一镜像 - * 不区分地址空间与特权级 - * 安全性由底层 hypervisor 保证 - -当前ArceOS是面向Unikernel设计的,而我们的Starry便是其宏内核化的一次尝试与成果。 - -![avatar](../figures/ArceOS介绍.png) \ No newline at end of file diff --git "a/doc/Starry/docs/\346\236\266\346\236\204\350\256\276\350\256\241/Starry\347\273\223\346\236\204\350\257\264\346\230\216.md" "b/doc/Starry/docs/\346\236\266\346\236\204\350\256\276\350\256\241/Starry\347\273\223\346\236\204\350\257\264\346\230\216.md" deleted file mode 100644 index 7981507..0000000 --- "a/doc/Starry/docs/\346\236\266\346\236\204\350\256\276\350\256\241/Starry\347\273\223\346\236\204\350\257\264\346\230\216.md" +++ /dev/null @@ -1,53 +0,0 @@ -### Starry结构说明 - -* crates:与OS设计无关的公共组件 -* modules:与OS设计更加耦合的组件,各个模块功能简要介绍如下: - * axalloc:实现全局分配器 - * axconfig:定义内核参数 - * axdisplay:简单的图形化实现 - * axdriver:设备驱动管理 - * axfs:文件系统支持 - * axhal:硬件抽象层,定义了一系列的平台API,如trap入口等 - * axlog:log输出层 - * axnet:网络模块 - * axruntime:运行库,定义了内核的启动逻辑 - * axsync:实现同步模块 - * axmem:地址空间模块 - * axprocess:进程模块,也实现了动态加载 - * axsignal:信号模块 - * axtask:定义了任务与调度序列的操作 - -* apps:unikernel架构下的用户程序,继承原有ArceOS -* ulib:用户库,继承原有ArceOS,并添加了starry_libax部分作为Linux兼容层。 - -1. 为了实现宏内核架构体系,需要对原有Arceos的部分核心模块(如axtask)进行修改。为了防止合并时冲突过多,因此在对应模块下建立`monolithic*`为前缀的文件夹,存放为宏内核架构实现的内容。同时使用条件编译来选择是宏内核架构还是unikernel架构。 -2. 为了实现linux APP兼容,需要实现一系列面向linux的系统调用。我们将系统调用的具体实现部分放在`starry_libax`部分,即以用户库的形式形成一个linux兼容层。通过调用上述模块提供的一系列接口,实现对应的linux 系统调用,并暴露给外界。这个系统兼容层与原有的`libax`进行对应,分别提供不同的接口与服务。 - -3. 模块部分放置可以为宏内核与unikernel尽可能共享的内容,通过**条件编译**等方式做到尽可能地为不同架构下的兼容层所调用。 - - - -### 结构图对比 - -原先Arceos结构图: - -![ArceOS](../figures/ArceOS.svg) - -重构后StarryOS架构图: - -![Starry](../figures/Starry.svg) - -Starry的模块依赖图如下: - -![modules](../figures/模块依赖.png) - -### 结构优势 - -1. 用相同的代码组件,利用条件编译等方式可以组建出不同架构的OS内核,从而可以达到使用不同的启动参数来启动不同架构的内核,大大提高内核的泛用性。 -2. 在利用unikernel可插拔的特性的基础上,可以使得实现某一个功能的crate和整体OS进一步解耦,从而利于更新换代。 -3. 解耦的特性利于开发模式的分工,不同开发人员可以负责不同的module或者crate内容,只要实现了对应的接口便可以较好地适配本内核,从而方便其他开发人员参与其中不断完善。 - - - - - diff --git "a/doc/Starry/docs/\346\246\202\350\277\260.md" "b/doc/Starry/docs/\346\246\202\350\277\260.md" deleted file mode 100644 index 2142b1c..0000000 --- "a/doc/Starry/docs/\346\246\202\350\277\260.md" +++ /dev/null @@ -1,25 +0,0 @@ -## 背景 - -Starry是在`ArceOs`[rcore-os/arceos: An experimental modular OS written in Rust.](https://github.com/rcore-os/arceos)基础上进行开发的、以宏内核架构运行Linux应用的内核。原有的ArceOS设计架构为`Unikernel`,后续计划在原有代码结构的基础上设计宏内核架构和微内核架构,而Starry即是ArceOS宏内核架构化的一个成果。 - - - -## 目前测例支持 - -当前测例支持如下: - -* musl-libc:静态链接与动态链接均已支持,实现的特性有动态库加载、线程、信号、futex等 -* lua:已经支持 -* busybox:已经支持大部分指令,通过了比赛的测例 -* lmbench:已经支持,可以使用lmbench测算内核性能 -* iperf/netperf:支持大部分测例,可以实现网络的基本功能 -* UnixBench:已经支持,可以用来测算内核在文件读取、数据基本操作等方面的性能 -* libc-bench:已经支持 - - - -## 使用方式 - -详见主页面的README.md - -相关依赖库均已本地化在`vendor`文件夹中 \ No newline at end of file diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/axsignal.png" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/axsignal.png" deleted file mode 100644 index 20c2744..0000000 Binary files "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/axsignal.png" and /dev/null differ diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png" deleted file mode 100644 index fb1886c..0000000 Binary files "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png" and /dev/null differ diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png:Zone.Identifier" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png:Zone.Identifier" deleted file mode 100644 index 080244f..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png:Zone.Identifier" +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=http://rcore-os.cn/rCore-Tutorial-Book-v3/_images/signal.png diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\344\273\273\345\212\241\350\260\203\345\272\246\346\250\241\345\235\227-axtask.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\344\273\273\345\212\241\350\260\203\345\272\246\346\250\241\345\235\227-axtask.md" deleted file mode 100644 index cfeb457..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\344\273\273\345\212\241\350\260\203\345\272\246\346\250\241\345\235\227-axtask.md" +++ /dev/null @@ -1,242 +0,0 @@ - -任务调度是内核实现过程中非常重要的环节。为了保证和上游arceos仓库较好的进行匹配,因此starry的任务调度机制基本参照了arceos的调度机制,并在此基础上进行了适配宏内核的调整。 - -为了实现宏内核架构体系,需要对原有Arceos的部分核心模块(如axtask)进行修改。为了防止合并时冲突过多,因此在对应模块下建立`monolithic_task`文件夹,存放为宏内核架构实现的内容。同时使用条件编译来选择是宏内核架构还是unikernel架构。 - -以下为Starry实现的任务调度模块的相关功能划分: - -![avatar](../figures/axtask.png) - -对功能的额外补充说明如下: - -#### task - -任务单元是内核运行过程中非常重要的组成部分,任务调度模块的组成如下: - -```rust -pub struct TaskInner { - id: TaskId, - name: String, - is_idle: bool, - is_init: bool, - - entry: Option<*mut dyn FnOnce()>, - state: AtomicU8, - - in_wait_queue: AtomicBool, - #[cfg(feature = "irq")] - in_timer_list: AtomicBool, - - #[cfg(feature = "preempt")] - need_resched: AtomicBool, - #[cfg(feature = "preempt")] - pub preempt_disable_count: AtomicUsize, - - exit_code: AtomicI32, - wait_for_exit: WaitQueue, - - #[cfg(feature = "monolithic")] - kstack: Option, - - ctx: UnsafeCell, - - #[cfg(feature = "monolithic")] - // 对应进程ID - process_id: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 是否是所属进程下的主线程 - is_leader: AtomicBool, - - #[cfg(feature = "monolithic")] - // 所属页表ID,在宏内核下默认会开启分页,是只读的所以不用原子量 - page_table_token: usize, - - #[cfg(feature = "monolithic")] - /// 初始化的trap上下文 - pub trap_frame: UnsafeCell, - - // 时间统计 - #[cfg(feature = "monolithic")] - time: UnsafeCell, - - #[allow(unused)] - #[cfg(feature = "monolithic")] - /// 子线程初始化的时候,存放tid的地址 - set_child_tid: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 子线程初始化时,将这个地址清空;子线程退出时,触发这里的 futex。 - /// 在创建时包含 CLONE_CHILD_SETTID 时才非0,但可以被 sys_set_tid_address 修改 - clear_child_tid: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 退出时是否向父进程发送SIG_CHILD - pub send_sigchld_when_exit: Bool, -} -``` - -可以看出,任务结构体中的某些字段包含着多核安全性,因为虽然一个任务仅会在一个CPU核上运行,但是不同CPU可能会同时访问同一个任务的某一个字段,导致出现多核冲突,因此需要为对应字段加上原子性。 - - - -另外,task字段也提供了某一个任务第一次执行的实现。它需要根据是否为宏内核架构分别进行实现。 - -* Arceos实现:在Arceos下,代码始终在内核态下运行,所以可以直接跳转到任务入口函数执行。因此会把入口函数的地址直接记录在task的entry字段上,并且在第一次执行任务时直接跳转到entry字段的地址即可。 -* Starry实现:在Starry下,任务会进入到用户态运行,此时需要把任务初始化的trap上下文放置到内核栈上,并且进行sret跳转。 - - - -### run_queue - -任务调度是任务模块实现的重点。接下来简要介绍以下starry的任务启动和调度流程。 - - - -当前任务调度机制是fifo队列法,启动和调度方式如下: - -* 单核情况 - - 对应代码在`modules/axtask/src/monolithic_task/run_queue.rs/init`函数中: - - ```rust - pub(crate) fn init() { - const IDLE_TASK_STACK_SIZE: usize = 0x20000; - let idle_task = TaskInner::new( - || crate::run_idle(), - "idle".into(), - IDLE_TASK_STACK_SIZE, - KERNEL_PROCESS_ID, - 0, - false, - ); - IDLE_TASK.with_current(|i: &mut LazyInit>>| { - i.init_by(idle_task.clone()) - }); - - let main_task = TaskInner::new_init("main".into()); - main_task.set_state(TaskState::Running); - - RUN_QUEUE.init_by(AxRunQueue::new()); - unsafe { CurrentTask::init_current(main_task) } - } - ``` - - 共包含三个任务: - - * idle_task:拥有独立的trap上下文和任务上下文,任务上下文指向的入口是`run_idle`函数。 - - * gc_task:在执行`AxRunQueue::new()`函数时生成,负责回收已经退出的任务。 - - * main_task:内核运行时执行的任务,它的任务上下文为空,在被切换时会把当前的ra等信息写入任务上下文,从而可以在恢复时继续执行内核相关代码。 - - 当执行完init函数之后,CPU指向main_task,pc不变,继续执行当前代码,直到来到`modules/axruntime/src/lib.rs/rust_main`函数的`unsafe{main();}`入口,从而跳转到Arceos指定的用户程序(**注意:虽然是用户程序,但是运行在arceos框架下,还处于内核态**),开始加载测例。默认`make run`会运行`apps/syscall/busybox`程序。若测例程序会通过`clone`等方式生成新的任务,那么新任务会被加入到任务调度队列等待被调度。 - - * 若调度队列中还有任务等待被调度,那么就会切换到对应任务。此时若调度的任务是gc,则gc会检测是否还有任务退出。若有任务已经退出等待回收,则gc会回收这些任务。若没有则阻塞gc本身,切换到其他任务。 - - gc的实现方式如下: - - ```rust - fn gc_entry() { - loop { - // Drop all exited tasks and recycle resources. - while !EXITED_TASKS.lock().is_empty() { - // Do not do the slow drops in the critical section. - let task = EXITED_TASKS.lock().pop_front(); - if let Some(task) = task { - // If the task reference is not taken after `spawn()`, it will be - // dropped here. Otherwise, it will be dropped after the reference - // is dropped (usually by `join()`). - // info!("drop task: {}", task.id().as_u64()); - drop(task); - } - } - WAIT_FOR_EXIT.wait(); - } - } - ``` - - * 若调度队列中没有下一个任务时,就会切换到idle_task,此时会执行`run_idle`函数,即不断执行`yield_task`函数,直到有新的任务加入调度队列,则切换到对应任务。 - - run_idle函数实现方式如下: - - ```rust - pub fn run_idle() -> ! { - loop { - yield_now(); - debug!("idle task: waiting for IRQs..."); - #[cfg(feature = "irq")] - axhal::arch::wait_for_irqs(); - } - } - ``` - - -* 多核启动 - - 我们只考虑任务调度相关,则多核情况下,其他核初始化的函数在`modules/axtask/src/monolithic_task/run_queue.rs/init_secondary`中,会新建一个`idle_task`,但是它的功能类似于单核启动下的`main_task`,即初始化时没有任务上下文,但是可以在被切换之后保留内核的任务执行流。 - - 初始化完毕之后,每一个非主核指向一个`idle_task`,此时他们会继续执行内核中的初始化代码,最后在`modules/axruntime/src/mp.rs`的`rust_main_secondary`函数中执行`run_idle`函数,即不断地`yield`自己,直到有新的任务加入调度队列。 - - 当测例对应的用户态任务执行`clone`系统调用,生成新的任务加入到调度队列时,此时就会随机分配一个CPU核获得该任务并且进行执行。这就是多核启动的原理。 - - - -### stat - -stat实现了任务的时间记录功能和计时器功能。 - -记录任务运行时间是通过计算和更新时间戳进行的,每一个stat结构体都拥有如下结构: - -```rust -/// 用户态经过的时间,单位为纳秒 -utime_ns: usize, -/// 内核态经过的时间,单位为纳秒 -stime_ns: usize, -/// 进入用户态时标记当前时间戳,用于统计用户态时间 -user_tick: usize, -/// 进入内核态时标记当前时间戳,用于统计内核态时间 -kernel_tick: usize, -``` - -更新时间戳的时间点共有四个: - -* 从用户态进入内核态 -* 从内核态进入用户态 -* 切换到本任务 -* 本任务被切换走 - -相关更新运行时间的代码如下: - -```rust -/// 从用户态进入内核态,记录当前时间戳,统计用户态时间 -pub fn into_kernel_mode(&mut self, tid: isize) { - let now_time_ns = current_time_nanos() as usize; - let delta = now_time_ns - self.user_tick; - self.utime_ns += delta; - self.kernel_tick = now_time_ns; -} -/// 从内核态进入用户态,记录当前时间戳,统计内核态时间 -pub fn into_user_mode(&mut self, tid: isize) { - // 获取当前时间,单位为纳秒 - let now_time_ns = current_time_nanos() as usize; - let delta = now_time_ns - self.kernel_tick; - self.stime_ns += delta; - self.user_tick = now_time_ns; -} -/// 内核态下,当前任务被切换掉,统计内核态时间 -pub fn swtich_from(&mut self, tid: isize) { - // 获取当前时间,单位为纳秒 - let now_time_ns = current_time_nanos() as usize; - let delta = now_time_ns - self.kernel_tick; - self.stime_ns += delta; -} -/// 内核态下,切换到当前任务,更新内核态时间戳 -pub fn switch_to(&mut self, tid: isize) { - // 获取当前时间,单位为纳秒 - let now_time_ns = current_time_nanos() as usize; - let delta = now_time_ns - self.kernel_tick; - // 更新时间戳,方便当该任务被切换时统计内核经过的时间 - self.kernel_tick = now_time_ns; -} -``` diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\344\277\241\345\217\267\346\250\241\345\235\227-axsignal.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\344\277\241\345\217\267\346\250\241\345\235\227-axsignal.md" deleted file mode 100644 index 57e2eaa..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\344\277\241\345\217\267\346\250\241\345\235\227-axsignal.md" +++ /dev/null @@ -1,50 +0,0 @@ - -axsignal是starry的信号模块,负责实现进程间、任务间等通信机制。当前实现的原理主要借鉴于Linux的信号机制。相关功能划分如下: - -![avatar](assets/axsignal.png) - -其中各部分的额外补充说明如下: - -### action - -action.rs指定了处理某一信号时的具体操作方式。操作方式的指定是通过定义`SigAction`结构体实现的,相关内容如下: - -```rust -pub struct SigAction { - /// 信号处理函数的地址 - /// 1. 如果是上述特殊值 SIG_DFL 或 SIG_IGN,则按描述处理 - /// 2. 若flags没有指定SA_SIGINFO,则函数原型为 fn(sig: SignalNo) -> (),对应C语言原型为 void (*sa_handler)(int) - /// 3. 若flags指定了SA_SIGINFO,则函数原型为 fn(sig: SignalNo, info: &SigInfo, ucontext: &mut UContext) -> (), - /// 对应C语言原型为 void (*sa_sigaction)(int, siginfo_t *, void *)。 - /// - /// 其中,SigInfo和SignalNo的定义见siginfo.rs和signal_no.rs。 - /// UContext即是处理信号时内核保存的用户态上下文,它存储在用户地址空间,会在调用sig_return时被恢复,定义见ucontext.rs。 - pub sa_handler: usize, - /// 信号处理的flags - pub sa_flags: SigActionFlags, - /// 信号处理的跳板页地址,存储了sig_return的函数处理地址 - /// 仅在SA_RESTORER标志被设置时有效 - pub restorer: usize, - /// 该信号处理函数的信号掩码 - pub sa_mask: usize, -} -``` - -其中值得说明的是`restorer`。想要了解这个`restorer`就需要了解Linux规定的信号处理机制流程: - -![avatar](assets/signal.png) - -> 上图引用自rCore教学文档[信号 - rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档 (rcore-os.cn)](http://rcore-os.cn/rCore-Tutorial-Book-v3/chapter7/4signal.html) - -根据上图可知,当进入信号处理阶段之后,若指定了信号处理例程,那么内核会返回用户态,跳转到信号处理函数对应入口进行信号处理。 - -传统的C语言函数中,函数执行结束时,内核会将ra寄存器的值赋给pc,即pc跳转到ra指定的地址上。 - -而对于信号处理函数,自然也需要一个返回地址,即我们刚才提到的`restorer`字段。 - -当信号处理函数执行完毕,会出现以下两种情况: - -1. 用户手动指定了返回地址`restorer`:此时由于我们的信号处理函数编译之后,会在结束时自动跳转到ra上,因此我们只需要在信号处理函数开始前,将`restorer`字段赋给ra寄存器即可。之后信号处理函数执行完毕之后就会跳转到指定地址。 -2. 用户未手动调用返回地址`restorer`:此时内核需要手动帮助用户执行`sig_return`系统调用,其功能是告知内核信号已经处理完毕,方便内核恢复因为处理信号而被打断的trap上下文。而手动处理的方式即是将`restorer`字段设置为一个非法的特殊字段:`SIGNAL_RETURN_TRAP`。当用户态下的信号处理函数执行完毕时,它会自动跳转到ra寄存器指定的地址,即跳转到`SIGNAL_RETURN_TRAP`,从而触发`InstructionPageFault`。此时内核捕获到trap之后,就可以根据触发page fault的地址判断是否触发了`sig_return`。若是,则手动调用`sig_return`系统调用即可。 - -因此,通过对`restorer`的合理使用,我们可以比较巧妙地实现信号处理的返回。 \ No newline at end of file diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\345\255\230\347\256\241\347\220\206\346\250\241\345\235\227-axmem.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\345\255\230\347\256\241\347\220\206\346\250\241\345\235\227-axmem.md" deleted file mode 100644 index c29996e..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\345\255\230\347\256\241\347\220\206\346\250\241\345\235\227-axmem.md" +++ /dev/null @@ -1,73 +0,0 @@ - -axmem 模块中提供了关于地址空间、内存段等结构的抽象。并负责动态加载应用程序、进程的 fork() / spawn()、内存管理(mmap、shmat)等基本任务。 - -### MemorySet - -MemorySet 代表一个进程所拥有(或多个线程共有)的地址空间。从一个用户程序“生命周期”的角度考虑。内核使用`MemorySet::map_elf()`加载 elf 文件中的内容,通过 clone()、mmap()、munmap()、add_shared_mem() 等函数执行由 syscall 传递而来的各种操作,最终在 drop() 中回收资源。 - -地址空间中最为核心的数据结构是页表(page_table)。使用RAII思想,页表(PageTable 类型)拥有页表本身使用的物理页。 - -除页表外,owned_mem 记录了在通过 mmap 以及应用程序加载时所获得的全部虚拟内存段。private_mem 和 sttached_mem 分别记录了进程所拥有的 System V Shared Memory。 - -以及,MemorySet 会记录加载自 ELF 文件的 entry 地址。 - -```rust -/// PageTable + MemoryArea for a process (task) -pub struct MemorySet { - page_table: PageTable, - owned_mem: BTreeMap, - - private_mem: BTreeMap>, - attached_mem: Vec<(VirtAddr, MappingFlags, Arc)>, - - pub entry: usize, -} -``` - -### SharedMem - -本数据结构代表用户程序通过 shmat() syscall 申请的共享内存。同样使用 RAII 思想,SharedMem::pages 中存放共享内存段所实际分配的物理页。这使得当我们 drop SharedMem 时,对应的物理内存也会自动释放。 -SharedMem::info 记录了该段共享内存的属性信息。 - -```rust -pub struct SharedMem { - pages: GlobalPage, - pub info: SharedMemInfo, -} -``` - -对于进程私有的共享内存,SharedMem 会被放入进程的 MemorySet::private_mem 中保存。对于公开的跨进程共享内存,则会存储在全局数据结构 SHARED_MEMS 中。 - -```rust -/// This struct only hold SharedMem that are not IPC_PRIVATE. IPC_PRIVATE SharedMem will be stored -/// in MemorySet::detached_mem. -/// -/// This is the only place we can query a SharedMem using its shmid. -/// -/// It holds an Arc to the SharedMem. If the Arc::strong_count() is 1, SharedMem will be dropped. -pub static SHARED_MEMS: SpinNoIrq>> = SpinNoIrq::new(BTreeMap::new()); -pub static KEY_TO_SHMID: SpinNoIrq> = SpinNoIrq::new(BTreeMap::new()); -``` - -当进程“挂载(映射)”某一共享内存段时,SharedMem 也会被加入 MemorySet::sttached_mem 中,便于执行进程的其他操作时访问。使用 Arc 数据结构可以得到“一段共享内存被多少个进程加载了”的信息,以便及时回收内存。 - -### MapArea - -MapArea 代表一段虚拟内存。在这个数据结构中需要记录虚拟内存的起始地址、属性信息、对应的物理页与文件后端。 - -```rust -pub struct MapArea { - pub pages: Vec>, - /// 起始虚拟地址 - pub vaddr: VirtAddr, - pub flags: MappingFlags, - pub backend: Option, -} -``` - -这里的 pages 使用了 Vec 存储若干单独的物理页,而非一整个物理页段。这是因为连续的一段虚拟内存对应的物理内存可能是不连续的。同时,Option 意味着物理内存可能尚未分配。这是本 OS 具有的 Lazy Load 功能。 -用户态中连续已分配的内存区间可能实际上没有分配,当用户使用到未分配区段时,将触发 PageFault,此时将交由 MapArea::handle_page_fault() 处理,分配实际的物理内存。 - -为了实现 mmap 映射文件的 Lazy Load 功能,MapArea 中记录了一个可选的文件后端 MemBackend。处理 PageFault 时,如果此段内存具有对应的文件后端,则会将文件对应位置的内容写入新分配的内存。此外,为了实现 msync() 等强制同步内存与对应文件的 syscall,提供了 MapArea::sync_page_with_backend() 函数。 - -除了处理内存的懒加载,MapArea 还提供了对连续内存段的编辑功能。shrink_left()、shrink_right()、split()、split3() 函数可以修改当前内存段的大小,并及时释放物理内存。 diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\345\272\225\345\261\202\346\250\241\345\235\227-axhal.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\345\272\225\345\261\202\346\250\241\345\235\227-axhal.md" deleted file mode 100644 index af2605b..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\345\272\225\345\261\202\346\250\241\345\235\227-axhal.md" +++ /dev/null @@ -1,2 +0,0 @@ -### 内核底层模块--axhal - diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\350\277\220\350\241\214\346\227\266\346\250\241\345\235\227-axruntime.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\350\277\220\350\241\214\346\227\266\346\250\241\345\235\227-axruntime.md" deleted file mode 100644 index 04ecdfb..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\350\277\220\350\241\214\346\227\266\346\250\241\345\235\227-axruntime.md" +++ /dev/null @@ -1,18 +0,0 @@ - -axruntime作为内核运行时模块,统筹了其他所有的内核模块。根据内核模块依赖图可知,runtimer模块是最上层的模块,它更多的是调用其他模块对外提供的接口来启动内核,并没有过多的新增功能,因此我们仅在这部分简单阐述Starry内核的启动流程。 - -详细代码参见`axruntime/src/lib.rs:107`,其启动流程如下: - -1. 实现alloc trait,从而实现全局分配器 -2. 建立内核地址空间,划分地址段 -3. 初始化平台配置,包括多核CPU定义的初始化 -4. 建立内核进程,初始化建立idle task和gc task,启动任务调度序列 -5. 启动外置驱动,包括fs、display、net -6. 若有多核则启动多核入口函数 -7. 初始化时钟中断处理函数 -8. 运行主核的主函数,即运行指定的应用程序 - -比赛时需要有几点注意的地方: - -1. 为遵循比赛需求,starry需要读取外部测例镜像。但由于SD卡镜像读取驱动较为复杂,因此比赛中默认将已有的SD卡镜像通过网络传输的方式传递到实际板子的`0x90000000`物理地址处。因此设置内核地址空间时,需要将这段空置出来。当前Starry默认启动的物理内存占用为[0x8000_0000,0x8800_0000)与[0xa000_0000, 0xc000_0000)。对应的特殊处理在`axhal/src/platform/qemu_virt_riscv/mem.rs`中。 -2. 实际上板时,由于fu740不存在virt-io设备,因此需要注意不能直接将虚拟设备进行初始化,否则可能出现问题。 \ No newline at end of file diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\256\217\345\206\205\346\240\270\347\224\250\346\210\267\345\272\223-starry.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\256\217\345\206\205\346\240\270\347\224\250\346\210\267\345\272\223-starry.md" deleted file mode 100644 index 4fa625f..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\345\256\217\345\206\205\346\240\270\347\224\250\346\210\267\345\272\223-starry.md" +++ /dev/null @@ -1,33 +0,0 @@ - -根据starry的模块化设计思路,用户库是在给定模块的基础上进行统合、提供对外统一接口的代码部分。而宏内核架构下对外提供的接口以Linux的系统调用形式进行呈现。因此starry_libax部分主要便是对系统调用的封装实现以及批量测试的实现。 - -![avatar](../figures/starry_libax.png) - -各部分的额外补充说明如下 - -### syscall - -关于syscall模块各自文件功能额外说明如下: - -* epoll:实现poll相关的系统调用的功能,如epoll/ppoll/poll等系统调用,借鉴于[maturin/modules/epoll at master · scPointer/maturin (github.com)](https://github.com/scPointer/maturin/tree/master/modules/epoll) - -* futex:实现任务互斥锁部分,它是用户态多任务协同开发的重点,因此需要谨慎考虑其实现。 - - futex的原理是以一个指定的变量作为futex变量,多个任务在等待获取这个变量的执行权限。但是否会出现多任务同时操作同一个变量的冲突问题不由内核考虑,而是由用户自行考虑并且实现,而内核只需要实现futex相关的操作对应的语义即可。 - - 关于futex的核心操作有两个:wait和wake。以下分别介绍这两种操作的处理方式: - - * wait:当一个任务调用futex的wait操作时,会指定一个futex变量的地址,此时代表着这个任务需要等待该futex的权限。那么这个任务会被加入到该futex变量的等待序列之中。之后任务会按照指定的休眠时间进行休眠,直到被唤醒。 - * wake:当某一个任务完成了对某一个futex变量的操作之后,会调用futex的wake操作,此时代表着释放了该futex变量。内核需要从该futex变量的等待序列中找到一个仍然在休眠的任务,并且手动唤醒它,接管futex变量的权限。 - - 当一个任务wait for一个futex变量时,其被唤醒的方式有三种: - - 1. 原有的futex变量被释放,该任务获得了控制权 - 2. 任务休眠时间到期 - 3. 原有futex变量地址上存储的值被改变 - - 依据上述三种情况,即可实现futex系统调用的相关处理方式。 - -### fs - -fs模块是为了支持文件相关的系统调用而实现的功能,包括文件描述符、链接、挂载等功能。之所以将该模块放在这个部分而不是放在axprocess或者axfs中,是因为文件描述符等内容是与Linux系统调用耦合度较高的内容,是系统调用的特定设置,在其他如微内核的架构中也存在着类似文件系统的功能,但不一定要具化到文件描述符。因此axfs中存放的是文件系统的统一实现,而如文件描述符等较贴近Linux的内容则放在Linux兼容层用户库starry_libax中实现,从而更加贴近模块化内核的设计思路。 \ No newline at end of file diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227-axfs.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227-axfs.md" deleted file mode 100644 index f8d7f83..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227-axfs.md" +++ /dev/null @@ -1,87 +0,0 @@ - -介绍文件系统时,不仅需要介绍axfs这个模块,还需要介绍其依赖的crate以及调用这个模块的package,他们共同构成了文件系统的上下层,使得文件系统可以正常发挥作用。 - -文件系统主要由四个部分组成,分别是外部依赖fatfs、crates/axfs_vfs、modules/axfs以及作为用户库的starry_libax/src/fs。 - -![avatar](../figures/axfs.png) - -各自部分的额外补充说明如下 - -### fatfs - -fatfs作为外部库,提供了一个基础的fat32文件系统。 - -### crates/axfs_vfs - -axfs_vfs提供了对文件和目录的抽象,为本os实现的任何文件系统都需要实现它的定义的VfsOps特征,同时对应文件系统的file/directory结构体需要实现它的VfsNodeOps特征。 - -### modules/axfs - -在modules/axfs中: - -1. axfs::fatfs作为中介连接了文件系统、vfs和块设备三个模块,它封装了外部的fat32提供的文件系统和file/directory,并为它们实现axfs_vfs中的对应特征,同时调用了axfs::dev对硬件进行操作; -2. axfs::fops封装了ax_vfs中的各种VfsNode操作,向上提供给axfs::api模块暴露给外部; -3. axfs::monolithic_fs是将文件系统适配到宏内核的核心,它提供了文件系统信息Kstat、文件输入输出操作FileIO、文件-虚存映射FileExt等结构体和特征的抽象。 - - - -### starry_libax/fs - -在starry_libax中所做的工作主要有: - -1. 定义文件夹、文件、管道等结构体,并为它们实现monolithic_fs中定义的一些特征,以文件为例: - - ```rust - /// 文件描述符 - pub struct FileDesc { - /// 文件路径 - pub path: String, - /// 文件 - pub file: Arc>, - /// 文件打开的标志位 - pub flags: OpenFlags, - /// 文件信息 - pub stat: Mutex, - } - - /// 文件在os中运行时的可变信息 - pub struct FileMetaData { - /// 最后一次访问时间 - pub atime: TimeSecs, - /// 最后一次改变(modify)内容的时间 - pub mtime: TimeSecs, - /// 最后一次改变(change)属性的时间 - pub ctime: TimeSecs, - } - impl Read for FileDesc { - .. - } - - impl Write for FileDesc { - .. - } - - impl Seek for FileDesc { - .. - } - - impl FileExt for FileDesc { - .. - } - /// 为FileDesc实现FileIO trait - impl FileIO for FileDesc { - .. - } - ``` - -2. 实现文件链接、文件系统挂载、目录项遍历等功能。 - - 需要注意的是,fat32文件系统不支持硬连接,我们做的工作实际上是在内存里模拟硬连接的过程。在目前的实现里,每个对于文件的访问传入的“文件路径”实际上都是一个虚拟的路径,只是作为KEY存入模拟硬连接的BTreeMap里,映射到它在文件镜像中的实际位置,包括恒等映射。 - - > 由于硬连接的一些特性,这种模拟在某些情境下会出现一些问题。 - > - > 例如,假设A路径是位于硬盘上的A文件的实际路径,B路径则是后创建的一个指向A文件的硬连接,删除A后因为有B存在,实际上只会减少A文件的硬连接数,不会删除实际文件A。这时再创建一个新的A文件时便会报错。 - > - > 针对这个问题,我们采用过的一个解决办法是对每个实际的文件维护一个记录指向它的硬连接的列表,删除实际路径时,弹出出列表首项并将实际文件移动到对应路径,然后从BTreeMap中删除该项,让它成为新的实际路径。 - -3. 实现所需的各类文件系统相关的系统调用。 diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\347\275\221\347\273\234\346\250\241\345\235\227-axnet.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\347\275\221\347\273\234\346\250\241\345\235\227-axnet.md" deleted file mode 100644 index dd33ab2..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\347\275\221\347\273\234\346\250\241\345\235\227-axnet.md" +++ /dev/null @@ -1,48 +0,0 @@ - -axnet 提供了对网络设备的驱动与封装。StarryOS 使用了开源的 smoltcp 库作为其网络协议栈。并在 smoltcp 提供的 API 基础上,封装了 TCPSocket 与 UDPSocket 两个套接字类型。 - -Linux syscall 所提供的 Socket API 的实现位于 ulib/socket.rs 中。 - -```rust -/// 包装内部的不同协议 Socket -pub struct Socket { - #[allow(dead_code)] - domain: Domain, - socket_type: SocketType, - inner: SocketInner, - close_exec: bool, - recv_timeout: Option, - - reuse_addr: bool, - dont_route: bool, - send_buf_size: usize, - recv_buf_size: usize, - congestion: String, -} -``` - -### Socket - -Socket 封装了由 axnet 提供的 TCP/UDP Socket(SocketInner)。并记录了此 Socket 在 Linux Socket API 层具有的其他信息,如 domain(Address Family)、type,以及一些配置信息,如 recv_timeout、close_exec。 - -此 Socket 类型实现了如 bind()、connect()、accept() 等操作,再 syscall 的实际代码中,只需使用这些函数,无需与 axnet 交互。 - -Socket 与其他文件相关的类型相同,实现了 FileExt 与 FileIO trait,使得 Socket 对象可以存储在进程的 FdTable 中。也因如此,read()、write() 等面向文件实现的 syscall 也可用于 socket。 - -### SocketOption、TcpSocketOption - -Linux Socket API 中关于,可以通过 Socket Option 来修改或获取 Socket 的各项选项。对于不同的选项,分别实现了 get() 与 set() 函数,简洁地实现所需功能。 - -```rust -#[derive(TryFromPrimitive, Debug)] -#[repr(usize)] -#[allow(non_camel_case_types)] -pub enum SocketOption { - SO_REUSEADDR = 2, - SO_DONTROUTE = 5, - SO_SNDBUF = 7, - SO_RCVBUF = 8, - SO_KEEPALIVE = 9, - SO_RCVTIMEO = 20, -} -``` diff --git "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\350\277\233\347\250\213\346\216\247\345\210\266\346\250\241\345\235\227-axprocess.md" "b/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\350\277\233\347\250\213\346\216\247\345\210\266\346\250\241\345\235\227-axprocess.md" deleted file mode 100644 index a6d4704..0000000 --- "a/doc/Starry/docs/\346\250\241\345\235\227\344\273\213\347\273\215/\350\277\233\347\250\213\346\216\247\345\210\266\346\250\241\345\235\227-axprocess.md" +++ /dev/null @@ -1,58 +0,0 @@ - -进程部分是宏内核实现的核心部分,它作为一个资源容器收纳了任务、信号、内存、文件系统等模块的功能,并且进行统筹管理。 - -进程模块的相关功能划分如下 - -![avatar](../figures/axprocess.png) - -进程模块更多是对已有实现模块的一个总结, 因此该部分的额外说明并不会特别多,仅是起一个总结的作用。 - -额外补充如下 - -### process - -process部分实现了进程控制块的主体部分,其进程控制块定义如下: - -```rust -pub struct ProcessInner { - /// 父进程的进程号 - pub parent: u64, - /// 子进程 - pub children: Vec>, - /// 子任务 - pub tasks: Vec, - /// 地址空间,由于存在地址空间共享,因此设计为Arc类型 - pub memory_set: Arc>, - /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量 - pub heap_bottom: usize, - /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小 - pub heap_top: usize, - /// 进程状态 - pub is_zombie: bool, - /// 退出状态码 - pub exit_code: i32, - #[cfg(feature = "fs")] - pub fd_manager: FdManager, - /// 进程工作目录 - pub cwd: String, - #[cfg(feature = "signal")] - /// 信号处理模块 - /// 第一维代表线程号,第二维代表线程对应的信号处理模块 - pub signal_module: BTreeMap, - - /// robust list存储模块 - /// 用来存储线程对共享变量的使用地址 - /// 具体使用交给了用户空间 - pub robust_list: BTreeMap, -} -``` - -可以看出进程控制块内融合了包括文件、信号、互斥锁、内存地址空间等一系列内容,通过feature条件编译的方式可以方便地对模块进行可插拔编译,符合模块化的内核设计思想。 - -### futex - -在进程部分定义了与互斥锁相关的数据结构`FUTEX_WAIT_TASK`,其是一个从地址到任务指针的map映射,存储了每一个futex变量对应的正在等待的任务序列。 - -之所以将该数据结构定义在axprocess模块,是因为需要在进程退出时,清空`FUTEX_WAIT_TASK`中存储的进程Arc指针,从而保证对象能够完整被释放。 - -`futex`的完整实现在`starry/syscall/futex`中。 \ No newline at end of file diff --git "a/doc/Starry/docs/\350\256\276\350\256\241\346\200\235\350\267\257.md" "b/doc/Starry/docs/\350\256\276\350\256\241\346\200\235\350\267\257.md" deleted file mode 100644 index b29e5d7..0000000 --- "a/doc/Starry/docs/\350\256\276\350\256\241\346\200\235\350\267\257.md" +++ /dev/null @@ -1,238 +0,0 @@ - -### 模块划分 - -依据模块化内核的设计思想,我们期望我们的内核能够在尽可能保留原有unikernel的基础上同时兼容宏内核功能,因此我们在arceos的基础上新增了如下模块: - -* axmem:引入地址空间 -* axtask/monolithic_task:修改原有task模块,添加了更多任务状态,从而使得任务可以作为线程的形式被进程调度 -* axsignal:信号模块 -* axprocess:引入进程概念,支持多进程多线程运行,添加了很多与Linux系统调用相关的内容 -* starry_libax:Linux系统调用用户库,包装了作为Linux兼容层的众多对外接口。 - -### 进程引入 - -为了运行Linux相关的应用,我们需要让不同任务之间存在父子等关系,因此我们引入了进程的概念。在标准的Linux中,进程和线程统一用pthread结构体代替,但我们为了保证原有arceos的任务调度结构不受过大影响,因此选择将进程和线程进行分离,进程保存在独立的结构体`Process`中。 - -依据模块化的思想,我们可以将进程视为一个容器,存储了**各类运行时资源,包括虚存、文件描述符、 -线程、信号等**。 -在该种设计理念下,进程仅是对上述资源的一个统一与包装。因此可以通过添加 feature 等方式将进程作为一个可插拔模块,使得内核在宏内核架构与微内核架构中随时进行切换。 - -进程结构设计如下: - -```rust -pub struct ProcessInner { - /// 父进程的进程号 - pub parent: u64, - /// 子进程 - pub children: Vec>, - /// 子任务 - pub tasks: Vec, - /// 地址空间,由于存在地址空间共享,因此设计为Arc类型 - pub memory_set: Arc>, - /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量 - pub heap_bottom: usize, - /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小 - pub heap_top: usize, - /// 进程状态 - pub is_zombie: bool, - /// 退出状态码 - pub exit_code: i32, - /// 文件管理器,存储如文件描述符等内容 - #[cfg(feature = "fs")] - pub fd_manager: FdManager, - /// 进程工作目录 - pub cwd: String, - #[cfg(feature = "signal")] - /// 信号处理模块 - /// 第一维代表线程号,第二维代表线程对应的信号处理模块 - pub signal_module: BTreeMap, - - /// robust list存储模块 - /// 用来存储线程对共享变量的使用地址 - /// 具体使用交给了用户空间 - pub robust_list: BTreeMap, -} -``` - -任务结构如下: - -```rust -/// The inner task structure. -pub struct TaskInner { - id: TaskId, - name: String, - is_idle: bool, - is_init: bool, - /// 任务的入口函数,仅在内核态下有效 - entry: Option<*mut dyn FnOnce()>, - state: AtomicU8, - - in_wait_queue: AtomicBool, - #[cfg(feature = "irq")] - in_timer_list: AtomicBool, - - #[cfg(feature = "preempt")] - need_resched: AtomicBool, - #[cfg(feature = "preempt")] - pub preempt_disable_count: AtomicUsize, - - exit_code: AtomicI32, - wait_for_exit: WaitQueue, - /// 内核栈,对于unikernel不需要 - #[cfg(feature = "monolithic")] - kstack: Option, - - ctx: UnsafeCell, - - #[cfg(feature = "monolithic")] - // 对应进程ID - process_id: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 是否是所属进程下的主线程 - is_leader: AtomicBool, - - #[cfg(feature = "monolithic")] - // 所属页表ID,在宏内核下默认会开启分页,是只读的所以不用原子量 - page_table_token: usize, - - #[cfg(feature = "monolithic")] - /// 初始化的trap上下文 - pub trap_frame: UnsafeCell, - // 时间统计 - #[cfg(feature = "monolithic")] - time: UnsafeCell, - - #[allow(unused)] - #[cfg(feature = "monolithic")] - /// 子线程初始化的时候,存放tid的地址 - set_child_tid: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 子线程初始化时,将这个地址清空;子线程退出时,触发这里的 futex。 - /// 在创建时包含 CLONE_CHILD_SETTID 时才非0,但可以被 sys_set_tid_address 修改 - clear_child_tid: AtomicU64, - - #[cfg(feature = "monolithic")] - /// 退出时是否向父进程发送SIG_CHILD - pub send_sigchld_when_exit: bool, -} -``` - - - - - -该种设计的优势如下: - -* 保留了 ArceOS 的结构,可以较为方便地与其他同学开发结果进行结合 -* 耦合度低,因此可以使内核较为方便地在不同模式间进行切换 - -在该种设计架构下,接受外来系统调用时,需要将部分对线程进行操作的系统调用转发给进程。进程收 -到该系统调用之后,再对当前进程下正在运行的线程进行相应的操作。实例为 yield , exit 等。 - - - -在生成新的任务时,由于是通过Linux的clone调用生成新的任务,因此可以根据clone的参数判断生成的是新的进程还是线程,从而确定线程所属的进程是哪一个,进程与线程之间形成父子关系,而同一进程下的线程形成兄弟关系,从而可以更加方便地进行管理。 - - - -### 地址空间引入 - -#### 任务切换 - -引入了进程之后,由于进程是资源容器集合,因此地址空间相关的存储结构也存放在这里,不同进程之间可以共享或者独享地址空间,因此在切换任务时,只需要额外判断当前所属进程的地址空间的token是否发生改变,就可以完成多地址空间的引入。 - -#### 特权级切换 - -目前内核和用户态使用的是同一个地址空间,可以避免trap时更改页表,减少时空损耗。 - - - -### 特权级切换 - -在Starry中,各种测例运行在用户态下,从内核态进入到用户态的方式有两个:用户程序初始化进入和trap返回。 - -#### 初始化进入 - -对于用户程序初始化进入部分,即是在原有ArceOS基础上添加了额外的判断: - -判断的原则如下:若要执行的任务的入口函数在内核态,则直接调用即可。否则需要通过手写汇编代码保存寄存器,以类似trap返回的机制调用sret进入用户态执行对应的函数。 - -```rust -extern "C" fn task_entry() { - // release the lock that was implicitly held across the reschedule - unsafe { crate::RUN_QUEUE.force_unlock() }; - axhal::arch::enable_irqs(); - let task: CurrentTask = crate::current(); - if let Some(entry) = task.entry { - if task.get_process_id() == KERNEL_PROCESS_ID { - // 对于unikernel,这里是应用程序的入口,由于都在内核态所以可以直接调用函数 - // 对于宏内核,这是初始调度进程,也在内核态,直接执行即可 - unsafe { Box::from_raw(entry)() }; - } else { - // 需要通过切换特权级进入到对应的应用程序 - let kernel_sp = task.get_kernel_stack_top().unwrap(); - - let frame_address = task.get_first_trap_frame(); - // 切换页表已经在switch实现了 - first_into_user(kernel_sp, frame_address as usize); - } - } - // only for kernel task - crate::exit(0); -} - -/// 初始化主进程的trap上下文 -#[no_mangle] -fn first_into_user(kernel_sp: usize, frame_base: usize) -> ! { - let trap_frame_size = core::mem::size_of::(); - let kernel_base = kernel_sp - trap_frame_size; - // 在保证将寄存器都存储好之后,再开启中断 - // 否则此时会因为写入csr寄存器过程中出现中断,导致出现异常 - axhal::arch::disable_irqs(); - // 在内核态中,tp寄存器存储的是当前任务的CPU ID - // 而当从内核态进入到用户态时,会将tp寄存器的值先存储在内核栈上,即把该任务对应的CPU ID存储在内核栈上 - // 然后将tp寄存器的值改为对应线程的tls指针的值 - // 因此在用户态中,tp寄存器存储的值是线程的tls指针的值 - // 而当从用户态进入到内核态时,会先将内核栈上的值读取到某一个中间寄存器t0中,然后将tp的值存入内核栈 - // 然后再将t0的值赋给tp,因此此时tp的值是当前任务的CPU ID - // 对应实现在axhal/src/arch/riscv/trap.S中 - unsafe { - asm::sfence_vma_all(); - core::arch::asm!( - r" - mv sp, {frame_base} - .short 0x2432 // fld fs0,264(sp) - .short 0x24d2 // fld fs1,272(sp) - LDR gp, sp, 2 // load user gp and tp - LDR t0, sp, 3 - mv t1, {kernel_base} - STR tp, t1, 3 // save supervisor tp,注意是存储到内核栈上而不是sp中,此时存储的应该是当前运行的CPU的ID - mv tp, t0 // tp:本来存储的是CPU ID,在这个时候变成了对应线程的TLS 指针 - csrw sscratch, {kernel_sp} // put supervisor sp to scratch - LDR t0, sp, 31 - LDR t1, sp, 32 - csrw sepc, t0 - csrw sstatus, t1 - POP_GENERAL_REGS - LDR sp, sp, 1 - sret - ", - frame_base = in(reg) frame_base, - kernel_sp = in(reg) kernel_sp, - kernel_base = in(reg) kernel_base, - ); - }; - core::panic!("already in user mode!") -} - -``` - - - -#### trap切换 - -trap切换对应的汇编代码在`axhal/src/arch/riscv`,值得关注的是其嵌套trap的处理。在第一次进入trap时,是从用户态进入到内核态,此时会将内核栈的地址赋给sp,将用户栈的地址存在内核栈上,并将sscratch清零。若发生内核嵌套trap,则此时sscratch的值为0,与sp交换之后,sp为0,即发生了内核嵌套trap。 - -因此可以通过交换之后sp是否为0来判断是否发生了内核嵌套trap。 diff --git "a/doc/Starry/docs/\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263.md" "b/doc/Starry/docs/\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263.md" deleted file mode 100644 index fb04cc7..0000000 --- "a/doc/Starry/docs/\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263.md" +++ /dev/null @@ -1,251 +0,0 @@ -### 操作CSR寄存器时关闭时钟中断 - -由于要运行多个测例,每一个测例都是单独的可执行文件,而当测例量加大时,会经常性出现准备开始运行某个测例的时候卡死或者循环发生内核trap的现象,错误的内容是随机的,可能呈现为store fault、卡死甚至unknown trap等内容。 - - - -通过gdb调试,定位了第一次发生错误的地址均在下列函数中: - -```rust -#[no_mangle] -// #[cfg(feature = "user")] -fn first_into_user(kernel_sp: usize, frame_base: usize) -> ! { - let trap_frame_size = core::mem::size_of::(); - let kernel_base = kernel_sp - trap_frame_size; - unsafe { - asm::sfence_vma_all(); - core::arch::asm!( - r" - mv sp, {frame_base} - .short 0x2432 // fld fs0,264(sp) - .short 0x24d2 // fld fs1,272(sp) - LDR gp, sp, 2 // load user gp and tp - LDR t0, sp, 3 - mv t1, {kernel_base} - STR tp, t1, 3 // save supervisor tp,注意是存储到内核栈上而不是sp中,此时存储的应该是当前运行的CPU的ID - mv tp, t0 // tp:本来存储的是CPU ID,在这个时候变成了对应线程的TLS 指针 - csrw sscratch, {kernel_sp} // put supervisor sp to scratch - LDR t0, sp, 31 - LDR t1, sp, 32 - csrw sepc, t0 - csrw sstatus, t1 - POP_GENERAL_REGS - LDR sp, sp, 1 - sret - ", - frame_base = in(reg) frame_base, - kernel_sp = in(reg) kernel_sp, - kernel_base = in(reg) kernel_base, - ); - }; - core::panic!("already in user mode!") -} -``` - -继续定位gdb汇编代码,将错误地址进一步确定为: - -```rust -csrw sstatus, t1 -``` - -当执行这一条汇编代码,会出现不可预测的错误。 - -考虑到sstatus的功能,其可以控制时钟中断、特权级等一系列的内容,通过查阅资料了解到当使用sstatus屏蔽内核中时钟中断时,并非是阻止了中断发出,而是阻止对中断进行处理,一旦内核中时钟中断屏蔽关闭,原先积累的时钟中断会被用来处理。sstatus是控制中断的关键寄存器,查阅资料得知,riscv要求在修改sstatus信息的时候需要保证时钟中断使能关闭,否则会产生不可预料的行为。 - -因此在调用`first_into_user`函数前需要手动调用`axhal::arch::enable_irqs()`关闭中断使能。 - - - -### 读取长度不足 - -当读取`strings.lua`测例时,常会有报错:`strings.lua:1: unexpected symbol`。但其他lua测例运行结果正常且正确。 - -strings.lua内容如下: - -```lua -local str = "Jelly Think" - -result = 0 - --- string.len可以获得字符串的长度 - -if string.len(str) ~= 11 then - result = -1 -end - --- string.rep返回字符串重复n次的结果 - -str = "ab" - -if string.rep(str, 2) ~= "abab" then - result = -1 -end - --- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本 - -str = "Jelly Think" - -if string.lower(str) ~= "jelly think" then - result = -1 -end - --- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本 - -if string.upper(str) == "JELLY THINK" then - result = -1 -end - -return result -``` - - - -考虑是否是文件编码问题:将strings.lua测例内容复制到其他lua文件,运行对应文件,报错不变。将其他lua文件内容复制到strings.lua,运行strings.lua,结果正常,因此排除了编码问题。 - -再考虑内核是否成功读入文件,输出`read`系统调用内容,发现read系统调用确实正确读入并返回了文件长度591。 - -考虑到strings.lua测试内容由多个断言形成,考虑逐个断言逐个断言验证,但发现一旦删除了strings.lua的部分内容之后,运行结果就正常了。即当缩短了strings.lua的长度之后,结果正常。 - -考虑输出read系统调用中读入的buf的内容,发现读入的892位buf中,前512位buf被修改为了0,后面的buf仍然正常。而当限制buf长度为512时,此时前512位buf读取结果正常。 - -arceos原先在fat32节点的读取函数定义如下: - -```rust -fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let mut file = self.0.lock(); - file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient - file.read(buf).map_err(as_vfs_err) -} -``` - -依据上述debug结果,发现starry的文件系统驱动中fat32的块大小定义为512。查询read语义知,每一次实际读取长度不一定等于传入的buf长度,因此不可以直接通过传入buf来实现文件的读入,而需要进行循环判断: - -```rust -n read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult { - let mut file = self.0.lock(); - file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient - // file.read(buf).map_err(as_vfs_err) - let buf_len = buf.len(); - let mut now_offset = 0; - let mut probe = buf.to_vec(); - while now_offset < buf_len { - let ans = file.read(&mut probe).map_err(as_vfs_err); - if ans.is_err() { - return ans; - } - let read_len = ans.unwrap(); - - if read_len == 0 { - break; - } - buf[now_offset..now_offset + read_len].copy_from_slice(&probe[..read_len]); - now_offset += read_len; - probe = probe[read_len..].to_vec(); - } - Ok(now_offset) -} -``` - -依据上述写法,即可实现大文件的读入。 - - - -### 文件的链接与初始化 - -fat32文件系统自身不支持符号链接,因此需要在内核中手动维护一个链接映射。但是不同的文件名称字符串可能指向同一个文件, 因此不能单纯地将传入的文件名作为映射的键值。 - -比如我们建立了一个从`a.out`到`b.out`的链接,此时传入的文件名叫做`./a.out`,此时它应该被连接到`b.out`,但在链接中找不到对应程序。 - -为了规范化起见,starry引用了arceos提供的`canonicalize`函数,将文件名转化为统一格式的绝对路径,并以此建立文件名到链接实际文件的映射。 - -因此从`a.out`到`b.out`的链接,会被转化为`./a.out`到`./b.out`的链接,通过规范的字符串使得误判的情况可以被减少。 - -实现busybox、lua、lmbench过程中,需要用到一系列的链接,对应实现在`starry_libax/test.rs`的`fs_init`函数中。如程序会寻找`/lib/tls_get_new-dtv_dso.so`,而它会被定向到`./tls_get_new-dtv_dso.so`文件,这个过程需要我们手动建立链接。 - - - -另外,busybox等测例也需要我们手动建立一系列的文件系统与文件夹,如dev_fs与ram_fs,其中dev_fs并不允许动态增删文件内容,需要初始化时就确定好。相关的实现在`axfs/src/root.rs`的`init_rootfs`函数,需要添加`dev/shm、dev/misc`等文件夹。 - - - -### 多核情况下libc测例结果不可测 - -musl-libc测例中有一个测例为pthread_cancel,主要是测试线程是否可以正常被取消。但这个测例经常会运行失败,即能够成功退出,但是报错并未取消新建的线程。 - -查阅对应的代码如下: - -```c -static void *start_single(void *arg) -{ - pthread_cleanup_push(cleanup1, arg); - sleep(3); - pthread_cleanup_pop(0); - return 0; -} -int main() { -/* Cancellation cleanup handlers */ - foo[0] = 0; - TESTR(r, pthread_create(&td, 0, start_single, foo), "failed to create thread"); - TESTR(r, pthread_cancel(td), "cancelling"); - TESTR(r, pthread_join(td, &res), "joining canceled thread"); - TESTC(res == PTHREAD_CANCELED, "canceled thread exit status"); - TESTC(foo[0] == 1, "cleanup handler failed to run"); -} -``` - -其测试的原理是在`pthread_cleanup_push`加入线程取消时调用的处理函数。若线程成功被取消,那么`cleanup1`函数会被调用,此时会修改f00[0]为1,代表成功取消。 - -但测试时经常报错:`cleanup handler failed to run`,通过输出f00[0]发现其值仍然为0,即线程取消函数没有被调用。但是输出内核接受到的系统调用以及信号处理流程会发现确实发出并且处理了取消线程的信号。那么问题出在了哪里呢? - - - -输出任务调度队列信息发现,主任务在调用了`pthread_create`之后,并没有被阻塞,反而继续调用了`pthread_cancel`函数,发出了取消线程信号,之后再被`pthread_join`函数阻塞。此时才调度到子线程,并且立即进入了信号处理函数的流程,即立即被取消。此时子线程甚至没有进入到`start_single`函数就被取消了。此时没有注册取消线程函数为`cleanup1`,因此自然不会修改f00[0]。 - - - -但是问题在于`pthread_create`的语义要求本任务会被yield,即子线程应当在创建之后被立即执行。继续debug,输出任务调度列表和对应CPU编号发现,虽然在当前CPU上主任务被yield了,但当前启动了多核,闲置的CPU立即将刚被yield的主任务接管并且继续运行。则此时主任务有概率在子线程开始之前调用cancel函数发出取消信号,从而导致线程取消函数注册失败。 - - - -将内核改为单核启动之后,问题消失。总结而言,在无法改动测例代码的情况下,跑musl-libc测例应当以单核的形式进行,多核可能会遇到各种奇怪的问题。。 - -### lmbench测例的结束 - -运行lmbench测例时发现时,程序总是会访问`0x2,0x4,0x6,0x8`等地址,导致`page fault`。gdb进行debug无果,发现**程序已经输出了预期输出**,之后会直接访问该非法地址。 - - - -询问往年参加比赛的学长,了解到去年的lmbench会在每个测例结束的时候直接让pc跳到堆栈上,从而触发I fault,通过内核捕获该信号并进行特判,从而手动调用exit结束当前的lmbench测例,进入到下一个lmbench测例。 - - - -而在今年编译得到的lmbench版本,pc不再跳转到堆栈,而是跳转到低地址如0x6,此时也是要求内核直接做出特判,结束当前任务。 - -查阅riscv规范得知,非法访问内存,内核处理失败之后应当发送SIGSEGV信号到对应线程,从而结束当前任务。因此修改代码如下: - -```rust -#[cfg(feature = "paging")] -fn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame) { - use axprocess::handle_page_fault; - use axsignal::signal_no::SignalNo; - use axtask::current; - axprocess::time_stat_from_user_to_kernel(); - use crate::syscall::signal::{syscall_sigreturn, syscall_tkill}; - if addr.as_usize() == SIGNAL_RETURN_TRAP { - // 说明是信号执行完毕,此时应当执行sig return - tf.regs.a0 = syscall_sigreturn() as usize; - return; - } - - if handle_page_fault(addr, flags).is_err() { - // 如果处理失败,则发出sigsegv信号 - let curr = current().id().as_u64() as isize; - axlog::error!("kill task: {}", curr); - syscall_tkill(curr, SignalNo::SIGSEGV as isize); - } - axprocess::time_stat_from_kernel_to_user(); -} -``` - -这种情况不仅可以处理pc跳转到低地址的情况,也可以处理跳转到堆栈的情况,更加地规范化。 - diff --git a/doc/Starry/mkdocs.yml b/doc/Starry/mkdocs.yml deleted file mode 100644 index 8ee994d..0000000 --- a/doc/Starry/mkdocs.yml +++ /dev/null @@ -1,87 +0,0 @@ -site_name: Starry -site_description: Starry设计文档 -nav: - - Starry: index.md - - 概述: 概述.md - - 架构设计: - - ArceOS介绍: 架构设计/ArceOS介绍.md - - Starry结构说明: 架构设计/Starry结构说明.md - - 设计思路: 设计思路.md - - 模块介绍: - - 内核底层模块-axhal: 模块介绍/内核底层模块-axhal.md - - 内存管理模块-axmem: 模块介绍/内存管理模块-axmem.md - - 网络模块-axnet: 模块介绍/网络模块-axnet.md - - 信号模块-axsignal: 模块介绍/信号模块-axsignal.md - - 任务调度模块-axtask: 模块介绍/任务调度模块-axtask.md - - 文件系统模块-axfs: 模块介绍/文件系统模块-axfs.md - - 进程控制模块-axprocess: 模块介绍/进程控制模块-axprocess.md - - 内核运行时模块-axruntime: 模块介绍/内核运行时模块-axruntime.md - - 宏内核用户库-starry: 模块介绍/宏内核用户库-starry.md - - 实现重点: - - 依赖问题: 实现重点/依赖问题.md - - 兼容问题: 实现重点/兼容问题.md - - 宏内核化探讨: 实现重点/宏内核化探讨.md - - 问题与解决: 问题与解决.md - -# 主题 -# theme: -# name: 'material' -# language: 'zh' # 配置语言 -# palette: # 颜色 -# primary: 'purple' -# accent: 'indigo' -# feature: -# tabs: true # 横向导航 - -# [UI] -theme: - name: material - palette: - #primary: blue grey - - - scheme: default # 日间模式 - primary: blue # 上方的 - accent: cyan # 链接等可交互元件的高亮色 - toggle: - icon: material/weather-night # 图标 - name: 切换至夜间模式 # 鼠标悬浮提示 - - scheme: slate # 夜间模式 - primary: black - accent: cyan - toggle: - icon: material/weather-sunny - name: 切换至日间模式 - -markdown_extensions: - - admonition # 提示块 - - footnotes # 脚注 - - meta # 定义元数据,通过文章上下文控制,如disqus - - pymdownx.caret # 下划线上标 - - pymdownx.tilde # 删除线下标 - - pymdownx.critic # 增加删除修改高亮注释,可修饰行内或段落 - - pymdownx.details # 提示块可折叠 - - pymdownx.inlinehilite # 行内代码高亮 - - pymdownx.mark # 文本高亮 - - pymdownx.smartsymbols # 符号转换 - - pymdownx.superfences # 代码嵌套在列表里 - - codehilite: # 代码高亮,显示行号 - guess_lang: false - linenums: true - - toc: # 锚点 - permalink: true -# - pymdownx.arithmatex # 数学公式 - # - pymdownx.betterem: # 对加粗和斜体更好的检测 - # smart_enable: all -# - pymdownx.emoji: # 表情 -# emoji_generator: !!python/name:pymdownx.emoji.to_svg -# - pymdownx.magiclink # 自动识别超链接 - - pymdownx.tasklist: # 复选框checklist - custom_checkbox: true - -# PDF导出插件 -plugins: - - search - # - pdf-export #这个插件还有点问题,没有更新 -#扩展样式 -extra_css: - - resources/css/extra.css \ No newline at end of file diff --git a/doc/Starry/site/404.html b/doc/Starry/site/404.html deleted file mode 100644 index ae9af7f..0000000 --- a/doc/Starry/site/404.html +++ /dev/null @@ -1,637 +0,0 @@ - - - - - - - - - - - - - - - - - - - - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- -

404 - Not found

- -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/doc/Starry/site/assets/images/favicon.png b/doc/Starry/site/assets/images/favicon.png deleted file mode 100644 index 1cf13b9..0000000 Binary files a/doc/Starry/site/assets/images/favicon.png and /dev/null differ diff --git a/doc/Starry/site/assets/javascripts/bundle.220ee61c.min.js b/doc/Starry/site/assets/javascripts/bundle.220ee61c.min.js deleted file mode 100644 index 116072a..0000000 --- a/doc/Starry/site/assets/javascripts/bundle.220ee61c.min.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! - * escape-html - * Copyright(c) 2012-2013 TJ Holowaychuk - * Copyright(c) 2015 Andreas Lubbe - * Copyright(c) 2015 Tiancheng "Timothy" Gu - * MIT Licensed - */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: -`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var M=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?M:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():M))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>M),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=_("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

Starry 设计文档

-
-

Starry意指布满星星的,寓意本OS的开发学习借鉴了许多前辈的思路,并将其汇总归一为这个内核。

-
-

成员

-

陈嘉钰、郑友捷、王昱栋

-

说明

-
    -
  • 一个内核
  • -
  • 以riscv64指令集运行
  • -
  • 支持在qemu、sifive开发板等平台上运行
  • -
  • 支持gcc、redis等Linux应用
  • -
  • 支持编译时选择启动架构为Unikernel或者宏内核
  • -
- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/doc/Starry/site/search/search_index.json b/doc/Starry/site/search/search_index.json deleted file mode 100644 index 7d11319..0000000 --- a/doc/Starry/site/search/search_index.json +++ /dev/null @@ -1 +0,0 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Starry \u8bbe\u8ba1\u6587\u6863","text":"

Starry\u610f\u6307\u5e03\u6ee1\u661f\u661f\u7684\uff0c\u5bd3\u610f\u672cOS\u7684\u5f00\u53d1\u5b66\u4e60\u501f\u9274\u4e86\u8bb8\u591a\u524d\u8f88\u7684\u601d\u8def\uff0c\u5e76\u5c06\u5176\u6c47\u603b\u5f52\u4e00\u4e3a\u8fd9\u4e2a\u5185\u6838\u3002

"},{"location":"#_1","title":"\u6210\u5458","text":"

\u9648\u5609\u94b0\u3001\u90d1\u53cb\u6377\u3001\u738b\u6631\u680b

"},{"location":"#_2","title":"\u8bf4\u660e","text":"
  • \u4e00\u4e2a\u5185\u6838
  • \u4ee5riscv64\u6307\u4ee4\u96c6\u8fd0\u884c
  • \u652f\u6301\u5728qemu\u3001sifive\u5f00\u53d1\u677f\u7b49\u5e73\u53f0\u4e0a\u8fd0\u884c
  • \u652f\u6301gcc\u3001redis\u7b49Linux\u5e94\u7528
  • \u652f\u6301\u7f16\u8bd1\u65f6\u9009\u62e9\u542f\u52a8\u67b6\u6784\u4e3aUnikernel\u6216\u8005\u5b8f\u5185\u6838
"},{"location":"%E6%A6%82%E8%BF%B0/","title":"\u6982\u8ff0","text":""},{"location":"%E6%A6%82%E8%BF%B0/#_1","title":"\u80cc\u666f","text":"

Starry\u662f\u5728ArceOsrcore-os/arceos: An experimental modular OS written in Rust.\u57fa\u7840\u4e0a\u8fdb\u884c\u5f00\u53d1\u7684\u3001\u4ee5\u5b8f\u5185\u6838\u67b6\u6784\u8fd0\u884cLinux\u5e94\u7528\u7684\u5185\u6838\u3002\u539f\u6709\u7684ArceOS\u8bbe\u8ba1\u67b6\u6784\u4e3aUnikernel\uff0c\u540e\u7eed\u8ba1\u5212\u5728\u539f\u6709\u4ee3\u7801\u7ed3\u6784\u7684\u57fa\u7840\u4e0a\u8bbe\u8ba1\u5b8f\u5185\u6838\u67b6\u6784\u548c\u5fae\u5185\u6838\u67b6\u6784\uff0c\u800cStarry\u5373\u662fArceOS\u5b8f\u5185\u6838\u67b6\u6784\u5316\u7684\u4e00\u4e2a\u6210\u679c\u3002

"},{"location":"%E6%A6%82%E8%BF%B0/#_2","title":"\u76ee\u524d\u6d4b\u4f8b\u652f\u6301","text":"

\u5f53\u524d\u6d4b\u4f8b\u652f\u6301\u5982\u4e0b\uff1a

  • musl-libc\uff1a\u9759\u6001\u94fe\u63a5\u4e0e\u52a8\u6001\u94fe\u63a5\u5747\u5df2\u652f\u6301\uff0c\u5b9e\u73b0\u7684\u7279\u6027\u6709\u52a8\u6001\u5e93\u52a0\u8f7d\u3001\u7ebf\u7a0b\u3001\u4fe1\u53f7\u3001futex\u7b49
  • lua\uff1a\u5df2\u7ecf\u652f\u6301
  • busybox\uff1a\u5df2\u7ecf\u652f\u6301\u5927\u90e8\u5206\u6307\u4ee4\uff0c\u901a\u8fc7\u4e86\u6bd4\u8d5b\u7684\u6d4b\u4f8b
  • lmbench\uff1a\u5df2\u7ecf\u652f\u6301\uff0c\u53ef\u4ee5\u4f7f\u7528lmbench\u6d4b\u7b97\u5185\u6838\u6027\u80fd
  • iperf/netperf\uff1a\u652f\u6301\u5927\u90e8\u5206\u6d4b\u4f8b\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u7684\u57fa\u672c\u529f\u80fd
  • UnixBench\uff1a\u5df2\u7ecf\u652f\u6301\uff0c\u53ef\u4ee5\u7528\u6765\u6d4b\u7b97\u5185\u6838\u5728\u6587\u4ef6\u8bfb\u53d6\u3001\u6570\u636e\u57fa\u672c\u64cd\u4f5c\u7b49\u65b9\u9762\u7684\u6027\u80fd
  • libc-bench\uff1a\u5df2\u7ecf\u652f\u6301
"},{"location":"%E6%A6%82%E8%BF%B0/#_3","title":"\u4f7f\u7528\u65b9\u5f0f","text":"

\u8be6\u89c1\u4e3b\u9875\u9762\u7684README.md

\u76f8\u5173\u4f9d\u8d56\u5e93\u5747\u5df2\u672c\u5730\u5316\u5728vendor\u6587\u4ef6\u5939\u4e2d

"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/","title":"\u8bbe\u8ba1\u601d\u8def","text":""},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_1","title":"\u6a21\u5757\u5212\u5206","text":"

\u4f9d\u636e\u6a21\u5757\u5316\u5185\u6838\u7684\u8bbe\u8ba1\u601d\u60f3\uff0c\u6211\u4eec\u671f\u671b\u6211\u4eec\u7684\u5185\u6838\u80fd\u591f\u5728\u5c3d\u53ef\u80fd\u4fdd\u7559\u539f\u6709unikernel\u7684\u57fa\u7840\u4e0a\u540c\u65f6\u517c\u5bb9\u5b8f\u5185\u6838\u529f\u80fd\uff0c\u56e0\u6b64\u6211\u4eec\u5728arceos\u7684\u57fa\u7840\u4e0a\u65b0\u589e\u4e86\u5982\u4e0b\u6a21\u5757\uff1a

  • axmem\uff1a\u5f15\u5165\u5730\u5740\u7a7a\u95f4
  • axtask/monolithic_task\uff1a\u4fee\u6539\u539f\u6709task\u6a21\u5757\uff0c\u6dfb\u52a0\u4e86\u66f4\u591a\u4efb\u52a1\u72b6\u6001\uff0c\u4ece\u800c\u4f7f\u5f97\u4efb\u52a1\u53ef\u4ee5\u4f5c\u4e3a\u7ebf\u7a0b\u7684\u5f62\u5f0f\u88ab\u8fdb\u7a0b\u8c03\u5ea6
  • axsignal\uff1a\u4fe1\u53f7\u6a21\u5757
  • axprocess\uff1a\u5f15\u5165\u8fdb\u7a0b\u6982\u5ff5\uff0c\u652f\u6301\u591a\u8fdb\u7a0b\u591a\u7ebf\u7a0b\u8fd0\u884c\uff0c\u6dfb\u52a0\u4e86\u5f88\u591a\u4e0eLinux\u7cfb\u7edf\u8c03\u7528\u76f8\u5173\u7684\u5185\u5bb9
  • starry_libax\uff1aLinux\u7cfb\u7edf\u8c03\u7528\u7528\u6237\u5e93\uff0c\u5305\u88c5\u4e86\u4f5c\u4e3aLinux\u517c\u5bb9\u5c42\u7684\u4f17\u591a\u5bf9\u5916\u63a5\u53e3\u3002
"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_2","title":"\u8fdb\u7a0b\u5f15\u5165","text":"

\u4e3a\u4e86\u8fd0\u884cLinux\u76f8\u5173\u7684\u5e94\u7528\uff0c\u6211\u4eec\u9700\u8981\u8ba9\u4e0d\u540c\u4efb\u52a1\u4e4b\u95f4\u5b58\u5728\u7236\u5b50\u7b49\u5173\u7cfb\uff0c\u56e0\u6b64\u6211\u4eec\u5f15\u5165\u4e86\u8fdb\u7a0b\u7684\u6982\u5ff5\u3002\u5728\u6807\u51c6\u7684Linux\u4e2d\uff0c\u8fdb\u7a0b\u548c\u7ebf\u7a0b\u7edf\u4e00\u7528pthread\u7ed3\u6784\u4f53\u4ee3\u66ff\uff0c\u4f46\u6211\u4eec\u4e3a\u4e86\u4fdd\u8bc1\u539f\u6709arceos\u7684\u4efb\u52a1\u8c03\u5ea6\u7ed3\u6784\u4e0d\u53d7\u8fc7\u5927\u5f71\u54cd\uff0c\u56e0\u6b64\u9009\u62e9\u5c06\u8fdb\u7a0b\u548c\u7ebf\u7a0b\u8fdb\u884c\u5206\u79bb\uff0c\u8fdb\u7a0b\u4fdd\u5b58\u5728\u72ec\u7acb\u7684\u7ed3\u6784\u4f53Process\u4e2d\u3002

\u4f9d\u636e\u6a21\u5757\u5316\u7684\u601d\u60f3\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u8fdb\u7a0b\u89c6\u4e3a\u4e00\u4e2a\u5bb9\u5668\uff0c\u5b58\u50a8\u4e86\u5404\u7c7b\u8fd0\u884c\u65f6\u8d44\u6e90\uff0c\u5305\u62ec\u865a\u5b58\u3001\u6587\u4ef6\u63cf\u8ff0\u7b26\u3001 \u7ebf\u7a0b\u3001\u4fe1\u53f7\u7b49\u3002 \u5728\u8be5\u79cd\u8bbe\u8ba1\u7406\u5ff5\u4e0b\uff0c\u8fdb\u7a0b\u4ec5\u662f\u5bf9\u4e0a\u8ff0\u8d44\u6e90\u7684\u4e00\u4e2a\u7edf\u4e00\u4e0e\u5305\u88c5\u3002\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u6dfb\u52a0 feature \u7b49\u65b9\u5f0f\u5c06\u8fdb\u7a0b\u4f5c\u4e3a\u4e00\u4e2a\u53ef\u63d2\u62d4\u6a21\u5757\uff0c\u4f7f\u5f97\u5185\u6838\u5728\u5b8f\u5185\u6838\u67b6\u6784\u4e0e\u5fae\u5185\u6838\u67b6\u6784\u4e2d\u968f\u65f6\u8fdb\u884c\u5207\u6362\u3002

\u8fdb\u7a0b\u7ed3\u6784\u8bbe\u8ba1\u5982\u4e0b\uff1a

pub struct ProcessInner {\n/// \u7236\u8fdb\u7a0b\u7684\u8fdb\u7a0b\u53f7\npub parent: u64,\n/// \u5b50\u8fdb\u7a0b\npub children: Vec<Arc<Process>>,\n/// \u5b50\u4efb\u52a1\npub tasks: Vec<AxTaskRef>,\n/// \u5730\u5740\u7a7a\u95f4\uff0c\u7531\u4e8e\u5b58\u5728\u5730\u5740\u7a7a\u95f4\u5171\u4eab\uff0c\u56e0\u6b64\u8bbe\u8ba1\u4e3aArc\u7c7b\u578b\npub memory_set: Arc<SpinNoIrq<MemorySet>>,\n/// \u7528\u6237\u5806\u57fa\u5740\uff0c\u4efb\u4f55\u65f6\u5019\u5806\u9876\u90fd\u4e0d\u80fd\u6bd4\u8fd9\u4e2a\u503c\u5c0f\uff0c\u7406\u8bba\u4e0a\u8bb2\u662f\u4e00\u4e2a\u5e38\u91cf\npub heap_bottom: usize,\n/// \u5f53\u524d\u7528\u6237\u5806\u7684\u5806\u9876\uff0c\u4e0d\u80fd\u5c0f\u4e8e\u57fa\u5740\uff0c\u4e0d\u80fd\u5927\u4e8e\u57fa\u5740\u52a0\u5806\u7684\u6700\u5927\u5927\u5c0f\npub heap_top: usize,\n/// \u8fdb\u7a0b\u72b6\u6001\npub is_zombie: bool,\n/// \u9000\u51fa\u72b6\u6001\u7801\npub exit_code: i32,\n/// \u6587\u4ef6\u7ba1\u7406\u5668\uff0c\u5b58\u50a8\u5982\u6587\u4ef6\u63cf\u8ff0\u7b26\u7b49\u5185\u5bb9\n#[cfg(feature = \"fs\")]\npub fd_manager: FdManager,\n/// \u8fdb\u7a0b\u5de5\u4f5c\u76ee\u5f55\npub cwd: String,\n#[cfg(feature = \"signal\")]\n/// \u4fe1\u53f7\u5904\u7406\u6a21\u5757    \n/// \u7b2c\u4e00\u7ef4\u4ee3\u8868\u7ebf\u7a0b\u53f7\uff0c\u7b2c\u4e8c\u7ef4\u4ee3\u8868\u7ebf\u7a0b\u5bf9\u5e94\u7684\u4fe1\u53f7\u5904\u7406\u6a21\u5757\npub signal_module: BTreeMap<u64, SignalModule>,\n\n/// robust list\u5b58\u50a8\u6a21\u5757\n/// \u7528\u6765\u5b58\u50a8\u7ebf\u7a0b\u5bf9\u5171\u4eab\u53d8\u91cf\u7684\u4f7f\u7528\u5730\u5740\n/// \u5177\u4f53\u4f7f\u7528\u4ea4\u7ed9\u4e86\u7528\u6237\u7a7a\u95f4\npub robust_list: BTreeMap<u64, FutexRobustList>,\n}\n

\u4efb\u52a1\u7ed3\u6784\u5982\u4e0b\uff1a

/// The inner task structure.\npub struct TaskInner {\nid: TaskId,\nname: String,\nis_idle: bool,\nis_init: bool,\n/// \u4efb\u52a1\u7684\u5165\u53e3\u51fd\u6570\uff0c\u4ec5\u5728\u5185\u6838\u6001\u4e0b\u6709\u6548\nentry: Option<*mut dyn FnOnce()>,\nstate: AtomicU8,\n\nin_wait_queue: AtomicBool,\n#[cfg(feature = \"irq\")]\nin_timer_list: AtomicBool,\n\n#[cfg(feature = \"preempt\")]\nneed_resched: AtomicBool,\n#[cfg(feature = \"preempt\")]\npub preempt_disable_count: AtomicUsize,\n\nexit_code: AtomicI32,\nwait_for_exit: WaitQueue,\n/// \u5185\u6838\u6808\uff0c\u5bf9\u4e8eunikernel\u4e0d\u9700\u8981\n#[cfg(feature = \"monolithic\")]\nkstack: Option<TaskStack>,\n\nctx: UnsafeCell<TaskContext>,\n\n#[cfg(feature = \"monolithic\")]\n// \u5bf9\u5e94\u8fdb\u7a0bID\nprocess_id: AtomicU64,\n\n#[cfg(feature = \"monolithic\")]\n/// \u662f\u5426\u662f\u6240\u5c5e\u8fdb\u7a0b\u4e0b\u7684\u4e3b\u7ebf\u7a0b\nis_leader: AtomicBool,\n\n#[cfg(feature = \"monolithic\")]\n// \u6240\u5c5e\u9875\u8868ID\uff0c\u5728\u5b8f\u5185\u6838\u4e0b\u9ed8\u8ba4\u4f1a\u5f00\u542f\u5206\u9875\uff0c\u662f\u53ea\u8bfb\u7684\u6240\u4ee5\u4e0d\u7528\u539f\u5b50\u91cf\npage_table_token: usize,\n\n#[cfg(feature = \"monolithic\")]\n/// \u521d\u59cb\u5316\u7684trap\u4e0a\u4e0b\u6587\npub trap_frame: UnsafeCell<TrapFrame>,\n// \u65f6\u95f4\u7edf\u8ba1\n#[cfg(feature = \"monolithic\")]\ntime: UnsafeCell<TimeStat>,\n\n#[allow(unused)]\n#[cfg(feature = \"monolithic\")]\n/// \u5b50\u7ebf\u7a0b\u521d\u59cb\u5316\u7684\u65f6\u5019\uff0c\u5b58\u653etid\u7684\u5730\u5740\nset_child_tid: AtomicU64,\n\n#[cfg(feature = \"monolithic\")]\n/// \u5b50\u7ebf\u7a0b\u521d\u59cb\u5316\u65f6\uff0c\u5c06\u8fd9\u4e2a\u5730\u5740\u6e05\u7a7a\uff1b\u5b50\u7ebf\u7a0b\u9000\u51fa\u65f6\uff0c\u89e6\u53d1\u8fd9\u91cc\u7684 futex\u3002\n/// \u5728\u521b\u5efa\u65f6\u5305\u542b CLONE_CHILD_SETTID \u65f6\u624d\u975e0\uff0c\u4f46\u53ef\u4ee5\u88ab sys_set_tid_address \u4fee\u6539\nclear_child_tid: AtomicU64,\n\n#[cfg(feature = \"monolithic\")]\n/// \u9000\u51fa\u65f6\u662f\u5426\u5411\u7236\u8fdb\u7a0b\u53d1\u9001SIG_CHILD\npub send_sigchld_when_exit: bool,\n}\n

\u8be5\u79cd\u8bbe\u8ba1\u7684\u4f18\u52bf\u5982\u4e0b\uff1a

  • \u4fdd\u7559\u4e86 ArceOS \u7684\u7ed3\u6784\uff0c\u53ef\u4ee5\u8f83\u4e3a\u65b9\u4fbf\u5730\u4e0e\u5176\u4ed6\u540c\u5b66\u5f00\u53d1\u7ed3\u679c\u8fdb\u884c\u7ed3\u5408
  • \u8026\u5408\u5ea6\u4f4e\uff0c\u56e0\u6b64\u53ef\u4ee5\u4f7f\u5185\u6838\u8f83\u4e3a\u65b9\u4fbf\u5730\u5728\u4e0d\u540c\u6a21\u5f0f\u95f4\u8fdb\u884c\u5207\u6362

\u5728\u8be5\u79cd\u8bbe\u8ba1\u67b6\u6784\u4e0b\uff0c\u63a5\u53d7\u5916\u6765\u7cfb\u7edf\u8c03\u7528\u65f6\uff0c\u9700\u8981\u5c06\u90e8\u5206\u5bf9\u7ebf\u7a0b\u8fdb\u884c\u64cd\u4f5c\u7684\u7cfb\u7edf\u8c03\u7528\u8f6c\u53d1\u7ed9\u8fdb\u7a0b\u3002\u8fdb\u7a0b\u6536 \u5230\u8be5\u7cfb\u7edf\u8c03\u7528\u4e4b\u540e\uff0c\u518d\u5bf9\u5f53\u524d\u8fdb\u7a0b\u4e0b\u6b63\u5728\u8fd0\u884c\u7684\u7ebf\u7a0b\u8fdb\u884c\u76f8\u5e94\u7684\u64cd\u4f5c\u3002\u5b9e\u4f8b\u4e3a yield \uff0c exit \u7b49\u3002

\u5728\u751f\u6210\u65b0\u7684\u4efb\u52a1\u65f6\uff0c\u7531\u4e8e\u662f\u901a\u8fc7Linux\u7684clone\u8c03\u7528\u751f\u6210\u65b0\u7684\u4efb\u52a1\uff0c\u56e0\u6b64\u53ef\u4ee5\u6839\u636eclone\u7684\u53c2\u6570\u5224\u65ad\u751f\u6210\u7684\u662f\u65b0\u7684\u8fdb\u7a0b\u8fd8\u662f\u7ebf\u7a0b\uff0c\u4ece\u800c\u786e\u5b9a\u7ebf\u7a0b\u6240\u5c5e\u7684\u8fdb\u7a0b\u662f\u54ea\u4e00\u4e2a\uff0c\u8fdb\u7a0b\u4e0e\u7ebf\u7a0b\u4e4b\u95f4\u5f62\u6210\u7236\u5b50\u5173\u7cfb\uff0c\u800c\u540c\u4e00\u8fdb\u7a0b\u4e0b\u7684\u7ebf\u7a0b\u5f62\u6210\u5144\u5f1f\u5173\u7cfb\uff0c\u4ece\u800c\u53ef\u4ee5\u66f4\u52a0\u65b9\u4fbf\u5730\u8fdb\u884c\u7ba1\u7406\u3002

"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_3","title":"\u5730\u5740\u7a7a\u95f4\u5f15\u5165","text":""},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_4","title":"\u4efb\u52a1\u5207\u6362","text":"

\u5f15\u5165\u4e86\u8fdb\u7a0b\u4e4b\u540e\uff0c\u7531\u4e8e\u8fdb\u7a0b\u662f\u8d44\u6e90\u5bb9\u5668\u96c6\u5408\uff0c\u56e0\u6b64\u5730\u5740\u7a7a\u95f4\u76f8\u5173\u7684\u5b58\u50a8\u7ed3\u6784\u4e5f\u5b58\u653e\u5728\u8fd9\u91cc\uff0c\u4e0d\u540c\u8fdb\u7a0b\u4e4b\u95f4\u53ef\u4ee5\u5171\u4eab\u6216\u8005\u72ec\u4eab\u5730\u5740\u7a7a\u95f4\uff0c\u56e0\u6b64\u5728\u5207\u6362\u4efb\u52a1\u65f6\uff0c\u53ea\u9700\u8981\u989d\u5916\u5224\u65ad\u5f53\u524d\u6240\u5c5e\u8fdb\u7a0b\u7684\u5730\u5740\u7a7a\u95f4\u7684token\u662f\u5426\u53d1\u751f\u6539\u53d8\uff0c\u5c31\u53ef\u4ee5\u5b8c\u6210\u591a\u5730\u5740\u7a7a\u95f4\u7684\u5f15\u5165\u3002

"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_5","title":"\u7279\u6743\u7ea7\u5207\u6362","text":"

\u76ee\u524d\u5185\u6838\u548c\u7528\u6237\u6001\u4f7f\u7528\u7684\u662f\u540c\u4e00\u4e2a\u5730\u5740\u7a7a\u95f4\uff0c\u53ef\u4ee5\u907f\u514dtrap\u65f6\u66f4\u6539\u9875\u8868\uff0c\u51cf\u5c11\u65f6\u7a7a\u635f\u8017\u3002

"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_6","title":"\u7279\u6743\u7ea7\u5207\u6362","text":"

\u5728Starry\u4e2d\uff0c\u5404\u79cd\u6d4b\u4f8b\u8fd0\u884c\u5728\u7528\u6237\u6001\u4e0b\uff0c\u4ece\u5185\u6838\u6001\u8fdb\u5165\u5230\u7528\u6237\u6001\u7684\u65b9\u5f0f\u6709\u4e24\u4e2a\uff1a\u7528\u6237\u7a0b\u5e8f\u521d\u59cb\u5316\u8fdb\u5165\u548ctrap\u8fd4\u56de\u3002

"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#_7","title":"\u521d\u59cb\u5316\u8fdb\u5165","text":"

\u5bf9\u4e8e\u7528\u6237\u7a0b\u5e8f\u521d\u59cb\u5316\u8fdb\u5165\u90e8\u5206\uff0c\u5373\u662f\u5728\u539f\u6709ArceOS\u57fa\u7840\u4e0a\u6dfb\u52a0\u4e86\u989d\u5916\u7684\u5224\u65ad\uff1a

\u5224\u65ad\u7684\u539f\u5219\u5982\u4e0b\uff1a\u82e5\u8981\u6267\u884c\u7684\u4efb\u52a1\u7684\u5165\u53e3\u51fd\u6570\u5728\u5185\u6838\u6001\uff0c\u5219\u76f4\u63a5\u8c03\u7528\u5373\u53ef\u3002\u5426\u5219\u9700\u8981\u901a\u8fc7\u624b\u5199\u6c47\u7f16\u4ee3\u7801\u4fdd\u5b58\u5bc4\u5b58\u5668\uff0c\u4ee5\u7c7b\u4f3ctrap\u8fd4\u56de\u7684\u673a\u5236\u8c03\u7528sret\u8fdb\u5165\u7528\u6237\u6001\u6267\u884c\u5bf9\u5e94\u7684\u51fd\u6570\u3002

extern \"C\" fn task_entry() {\n// release the lock that was implicitly held across the reschedule\nunsafe { crate::RUN_QUEUE.force_unlock() };\naxhal::arch::enable_irqs();\nlet task: CurrentTask = crate::current();\nif let Some(entry) = task.entry {\nif task.get_process_id() == KERNEL_PROCESS_ID {\n// \u5bf9\u4e8eunikernel\uff0c\u8fd9\u91cc\u662f\u5e94\u7528\u7a0b\u5e8f\u7684\u5165\u53e3\uff0c\u7531\u4e8e\u90fd\u5728\u5185\u6838\u6001\u6240\u4ee5\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u51fd\u6570\n// \u5bf9\u4e8e\u5b8f\u5185\u6838\uff0c\u8fd9\u662f\u521d\u59cb\u8c03\u5ea6\u8fdb\u7a0b\uff0c\u4e5f\u5728\u5185\u6838\u6001\uff0c\u76f4\u63a5\u6267\u884c\u5373\u53ef\nunsafe { Box::from_raw(entry)() };\n} else {\n// \u9700\u8981\u901a\u8fc7\u5207\u6362\u7279\u6743\u7ea7\u8fdb\u5165\u5230\u5bf9\u5e94\u7684\u5e94\u7528\u7a0b\u5e8f\nlet kernel_sp = task.get_kernel_stack_top().unwrap();\n\nlet frame_address = task.get_first_trap_frame();\n// \u5207\u6362\u9875\u8868\u5df2\u7ecf\u5728switch\u5b9e\u73b0\u4e86\nfirst_into_user(kernel_sp, frame_address as usize);\n}\n}\n// only for kernel task\ncrate::exit(0);\n}\n\n/// \u521d\u59cb\u5316\u4e3b\u8fdb\u7a0b\u7684trap\u4e0a\u4e0b\u6587\n#[no_mangle]\nfn first_into_user(kernel_sp: usize, frame_base: usize) -> ! {\nlet trap_frame_size = core::mem::size_of::<TrapFrame>();\nlet kernel_base = kernel_sp - trap_frame_size;\n// \u5728\u4fdd\u8bc1\u5c06\u5bc4\u5b58\u5668\u90fd\u5b58\u50a8\u597d\u4e4b\u540e\uff0c\u518d\u5f00\u542f\u4e2d\u65ad\n// \u5426\u5219\u6b64\u65f6\u4f1a\u56e0\u4e3a\u5199\u5165csr\u5bc4\u5b58\u5668\u8fc7\u7a0b\u4e2d\u51fa\u73b0\u4e2d\u65ad\uff0c\u5bfc\u81f4\u51fa\u73b0\u5f02\u5e38\naxhal::arch::disable_irqs();\n// \u5728\u5185\u6838\u6001\u4e2d\uff0ctp\u5bc4\u5b58\u5668\u5b58\u50a8\u7684\u662f\u5f53\u524d\u4efb\u52a1\u7684CPU ID\n// \u800c\u5f53\u4ece\u5185\u6838\u6001\u8fdb\u5165\u5230\u7528\u6237\u6001\u65f6\uff0c\u4f1a\u5c06tp\u5bc4\u5b58\u5668\u7684\u503c\u5148\u5b58\u50a8\u5728\u5185\u6838\u6808\u4e0a\uff0c\u5373\u628a\u8be5\u4efb\u52a1\u5bf9\u5e94\u7684CPU ID\u5b58\u50a8\u5728\u5185\u6838\u6808\u4e0a\n// \u7136\u540e\u5c06tp\u5bc4\u5b58\u5668\u7684\u503c\u6539\u4e3a\u5bf9\u5e94\u7ebf\u7a0b\u7684tls\u6307\u9488\u7684\u503c\n// \u56e0\u6b64\u5728\u7528\u6237\u6001\u4e2d\uff0ctp\u5bc4\u5b58\u5668\u5b58\u50a8\u7684\u503c\u662f\u7ebf\u7a0b\u7684tls\u6307\u9488\u7684\u503c\n// \u800c\u5f53\u4ece\u7528\u6237\u6001\u8fdb\u5165\u5230\u5185\u6838\u6001\u65f6\uff0c\u4f1a\u5148\u5c06\u5185\u6838\u6808\u4e0a\u7684\u503c\u8bfb\u53d6\u5230\u67d0\u4e00\u4e2a\u4e2d\u95f4\u5bc4\u5b58\u5668t0\u4e2d\uff0c\u7136\u540e\u5c06tp\u7684\u503c\u5b58\u5165\u5185\u6838\u6808\n// \u7136\u540e\u518d\u5c06t0\u7684\u503c\u8d4b\u7ed9tp\uff0c\u56e0\u6b64\u6b64\u65f6tp\u7684\u503c\u662f\u5f53\u524d\u4efb\u52a1\u7684CPU ID\n// \u5bf9\u5e94\u5b9e\u73b0\u5728axhal/src/arch/riscv/trap.S\u4e2d\nunsafe {\nasm::sfence_vma_all();\ncore::arch::asm!(\nr\"\n            mv      sp, {frame_base}\n            .short  0x2432                      // fld fs0,264(sp)\n            .short  0x24d2                      // fld fs1,272(sp)\n            LDR     gp, sp, 2                   // load user gp and tp\n            LDR     t0, sp, 3\n            mv      t1, {kernel_base}\n            STR     tp, t1, 3                   // save supervisor tp\uff0c\u6ce8\u610f\u662f\u5b58\u50a8\u5230\u5185\u6838\u6808\u4e0a\u800c\u4e0d\u662fsp\u4e2d\uff0c\u6b64\u65f6\u5b58\u50a8\u7684\u5e94\u8be5\u662f\u5f53\u524d\u8fd0\u884c\u7684CPU\u7684ID\n            mv      tp, t0                      // tp\uff1a\u672c\u6765\u5b58\u50a8\u7684\u662fCPU ID\uff0c\u5728\u8fd9\u4e2a\u65f6\u5019\u53d8\u6210\u4e86\u5bf9\u5e94\u7ebf\u7a0b\u7684TLS \u6307\u9488\n            csrw    sscratch, {kernel_sp}       // put supervisor sp to scratch\n            LDR     t0, sp, 31\n            LDR     t1, sp, 32\n            csrw    sepc, t0\n            csrw    sstatus, t1\n            POP_GENERAL_REGS\n            LDR     sp, sp, 1\n            sret\n        \",\nframe_base = in(reg) frame_base,\nkernel_sp = in(reg) kernel_sp,\nkernel_base = in(reg) kernel_base,\n);\n};\ncore::panic!(\"already in user mode!\")\n}\n
"},{"location":"%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%B7%AF/#trap","title":"trap\u5207\u6362","text":"

trap\u5207\u6362\u5bf9\u5e94\u7684\u6c47\u7f16\u4ee3\u7801\u5728axhal/src/arch/riscv\uff0c\u503c\u5f97\u5173\u6ce8\u7684\u662f\u5176\u5d4c\u5957trap\u7684\u5904\u7406\u3002\u5728\u7b2c\u4e00\u6b21\u8fdb\u5165trap\u65f6\uff0c\u662f\u4ece\u7528\u6237\u6001\u8fdb\u5165\u5230\u5185\u6838\u6001\uff0c\u6b64\u65f6\u4f1a\u5c06\u5185\u6838\u6808\u7684\u5730\u5740\u8d4b\u7ed9sp\uff0c\u5c06\u7528\u6237\u6808\u7684\u5730\u5740\u5b58\u5728\u5185\u6838\u6808\u4e0a\uff0c\u5e76\u5c06sscratch\u6e05\u96f6\u3002\u82e5\u53d1\u751f\u5185\u6838\u5d4c\u5957trap\uff0c\u5219\u6b64\u65f6sscratch\u7684\u503c\u4e3a0\uff0c\u4e0esp\u4ea4\u6362\u4e4b\u540e\uff0csp\u4e3a0\uff0c\u5373\u53d1\u751f\u4e86\u5185\u6838\u5d4c\u5957trap\u3002

\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u4ea4\u6362\u4e4b\u540esp\u662f\u5426\u4e3a0\u6765\u5224\u65ad\u662f\u5426\u53d1\u751f\u4e86\u5185\u6838\u5d4c\u5957trap\u3002

"},{"location":"%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3/","title":"\u95ee\u9898\u4e0e\u89e3\u51b3","text":""},{"location":"%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3/#csr","title":"\u64cd\u4f5cCSR\u5bc4\u5b58\u5668\u65f6\u5173\u95ed\u65f6\u949f\u4e2d\u65ad","text":"

\u7531\u4e8e\u8981\u8fd0\u884c\u591a\u4e2a\u6d4b\u4f8b\uff0c\u6bcf\u4e00\u4e2a\u6d4b\u4f8b\u90fd\u662f\u5355\u72ec\u7684\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u800c\u5f53\u6d4b\u4f8b\u91cf\u52a0\u5927\u65f6\uff0c\u4f1a\u7ecf\u5e38\u6027\u51fa\u73b0\u51c6\u5907\u5f00\u59cb\u8fd0\u884c\u67d0\u4e2a\u6d4b\u4f8b\u7684\u65f6\u5019\u5361\u6b7b\u6216\u8005\u5faa\u73af\u53d1\u751f\u5185\u6838trap\u7684\u73b0\u8c61\uff0c\u9519\u8bef\u7684\u5185\u5bb9\u662f\u968f\u673a\u7684\uff0c\u53ef\u80fd\u5448\u73b0\u4e3astore fault\u3001\u5361\u6b7b\u751a\u81f3unknown trap\u7b49\u5185\u5bb9\u3002

\u901a\u8fc7gdb\u8c03\u8bd5\uff0c\u5b9a\u4f4d\u4e86\u7b2c\u4e00\u6b21\u53d1\u751f\u9519\u8bef\u7684\u5730\u5740\u5747\u5728\u4e0b\u5217\u51fd\u6570\u4e2d\uff1a

#[no_mangle]\n// #[cfg(feature = \"user\")]\nfn first_into_user(kernel_sp: usize, frame_base: usize) -> ! {\nlet trap_frame_size = core::mem::size_of::<TrapFrame>();\nlet kernel_base = kernel_sp - trap_frame_size;\nunsafe {\nasm::sfence_vma_all();\ncore::arch::asm!(\nr\"\n            mv      sp, {frame_base}\n            .short  0x2432                      // fld fs0,264(sp)\n            .short  0x24d2                      // fld fs1,272(sp)\n            LDR     gp, sp, 2                   // load user gp and tp\n            LDR     t0, sp, 3\n            mv      t1, {kernel_base}\n            STR     tp, t1, 3                   // save supervisor tp\uff0c\u6ce8\u610f\u662f\u5b58\u50a8\u5230\u5185\u6838\u6808\u4e0a\u800c\u4e0d\u662fsp\u4e2d\uff0c\u6b64\u65f6\u5b58\u50a8\u7684\u5e94\u8be5\u662f\u5f53\u524d\u8fd0\u884c\u7684CPU\u7684ID\n            mv      tp, t0                      // tp\uff1a\u672c\u6765\u5b58\u50a8\u7684\u662fCPU ID\uff0c\u5728\u8fd9\u4e2a\u65f6\u5019\u53d8\u6210\u4e86\u5bf9\u5e94\u7ebf\u7a0b\u7684TLS \u6307\u9488\n            csrw    sscratch, {kernel_sp}       // put supervisor sp to scratch\n            LDR     t0, sp, 31\n            LDR     t1, sp, 32\n            csrw    sepc, t0\n            csrw    sstatus, t1\n            POP_GENERAL_REGS\n            LDR     sp, sp, 1\n            sret\n        \",\nframe_base = in(reg) frame_base,\nkernel_sp = in(reg) kernel_sp,\nkernel_base = in(reg) kernel_base,\n);\n};\ncore::panic!(\"already in user mode!\")\n}\n

\u7ee7\u7eed\u5b9a\u4f4dgdb\u6c47\u7f16\u4ee3\u7801\uff0c\u5c06\u9519\u8bef\u5730\u5740\u8fdb\u4e00\u6b65\u786e\u5b9a\u4e3a\uff1a

csrw    sstatus, t1\n

\u5f53\u6267\u884c\u8fd9\u4e00\u6761\u6c47\u7f16\u4ee3\u7801\uff0c\u4f1a\u51fa\u73b0\u4e0d\u53ef\u9884\u6d4b\u7684\u9519\u8bef\u3002

\u8003\u8651\u5230sstatus\u7684\u529f\u80fd\uff0c\u5176\u53ef\u4ee5\u63a7\u5236\u65f6\u949f\u4e2d\u65ad\u3001\u7279\u6743\u7ea7\u7b49\u4e00\u7cfb\u5217\u7684\u5185\u5bb9\uff0c\u901a\u8fc7\u67e5\u9605\u8d44\u6599\u4e86\u89e3\u5230\u5f53\u4f7f\u7528sstatus\u5c4f\u853d\u5185\u6838\u4e2d\u65f6\u949f\u4e2d\u65ad\u65f6\uff0c\u5e76\u975e\u662f\u963b\u6b62\u4e86\u4e2d\u65ad\u53d1\u51fa\uff0c\u800c\u662f\u963b\u6b62\u5bf9\u4e2d\u65ad\u8fdb\u884c\u5904\u7406\uff0c\u4e00\u65e6\u5185\u6838\u4e2d\u65f6\u949f\u4e2d\u65ad\u5c4f\u853d\u5173\u95ed\uff0c\u539f\u5148\u79ef\u7d2f\u7684\u65f6\u949f\u4e2d\u65ad\u4f1a\u88ab\u7528\u6765\u5904\u7406\u3002sstatus\u662f\u63a7\u5236\u4e2d\u65ad\u7684\u5173\u952e\u5bc4\u5b58\u5668\uff0c\u67e5\u9605\u8d44\u6599\u5f97\u77e5\uff0criscv\u8981\u6c42\u5728\u4fee\u6539sstatus\u4fe1\u606f\u7684\u65f6\u5019\u9700\u8981\u4fdd\u8bc1\u65f6\u949f\u4e2d\u65ad\u4f7f\u80fd\u5173\u95ed\uff0c\u5426\u5219\u4f1a\u4ea7\u751f\u4e0d\u53ef\u9884\u6599\u7684\u884c\u4e3a\u3002

\u56e0\u6b64\u5728\u8c03\u7528first_into_user\u51fd\u6570\u524d\u9700\u8981\u624b\u52a8\u8c03\u7528axhal::arch::enable_irqs()\u5173\u95ed\u4e2d\u65ad\u4f7f\u80fd\u3002

"},{"location":"%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3/#_1","title":"\u8bfb\u53d6\u957f\u5ea6\u4e0d\u8db3","text":"

\u5f53\u8bfb\u53d6strings.lua\u6d4b\u4f8b\u65f6\uff0c\u5e38\u4f1a\u6709\u62a5\u9519\uff1astrings.lua:1: unexpected symbol\u3002\u4f46\u5176\u4ed6lua\u6d4b\u4f8b\u8fd0\u884c\u7ed3\u679c\u6b63\u5e38\u4e14\u6b63\u786e\u3002

strings.lua\u5185\u5bb9\u5982\u4e0b\uff1a

local str = \"Jelly Think\"\n\nresult = 0\n\n-- string.len\u53ef\u4ee5\u83b7\u5f97\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\n\nif string.len(str) ~= 11 then\n    result = -1\nend\n\n-- string.rep\u8fd4\u56de\u5b57\u7b26\u4e32\u91cd\u590dn\u6b21\u7684\u7ed3\u679c\n\nstr = \"ab\"\n\nif string.rep(str, 2) ~= \"abab\" then\n    result = -1\nend\n\n-- string.lower\u5c06\u5b57\u7b26\u4e32\u5c0f\u5199\u53d8\u6210\u5927\u5199\u5f62\u5f0f\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u6539\u53d8\u4ee5\u540e\u7684\u526f\u672c\n\nstr = \"Jelly Think\"\n\nif string.lower(str) ~= \"jelly think\" then\n    result = -1\nend\n\n-- string.upper\u5c06\u5b57\u7b26\u4e32\u5927\u5199\u53d8\u6210\u5c0f\u5199\u5f62\u5f0f\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u6539\u53d8\u4ee5\u540e\u7684\u526f\u672c\n\nif string.upper(str) == \"JELLY THINK\" then\n    result = -1\nend\n\nreturn result\n

\u8003\u8651\u662f\u5426\u662f\u6587\u4ef6\u7f16\u7801\u95ee\u9898\uff1a\u5c06strings.lua\u6d4b\u4f8b\u5185\u5bb9\u590d\u5236\u5230\u5176\u4ed6lua\u6587\u4ef6\uff0c\u8fd0\u884c\u5bf9\u5e94\u6587\u4ef6\uff0c\u62a5\u9519\u4e0d\u53d8\u3002\u5c06\u5176\u4ed6lua\u6587\u4ef6\u5185\u5bb9\u590d\u5236\u5230strings.lua\uff0c\u8fd0\u884cstrings.lua\uff0c\u7ed3\u679c\u6b63\u5e38\uff0c\u56e0\u6b64\u6392\u9664\u4e86\u7f16\u7801\u95ee\u9898\u3002

\u518d\u8003\u8651\u5185\u6838\u662f\u5426\u6210\u529f\u8bfb\u5165\u6587\u4ef6\uff0c\u8f93\u51faread\u7cfb\u7edf\u8c03\u7528\u5185\u5bb9\uff0c\u53d1\u73b0read\u7cfb\u7edf\u8c03\u7528\u786e\u5b9e\u6b63\u786e\u8bfb\u5165\u5e76\u8fd4\u56de\u4e86\u6587\u4ef6\u957f\u5ea6591\u3002

\u8003\u8651\u5230strings.lua\u6d4b\u8bd5\u5185\u5bb9\u7531\u591a\u4e2a\u65ad\u8a00\u5f62\u6210\uff0c\u8003\u8651\u9010\u4e2a\u65ad\u8a00\u9010\u4e2a\u65ad\u8a00\u9a8c\u8bc1\uff0c\u4f46\u53d1\u73b0\u4e00\u65e6\u5220\u9664\u4e86strings.lua\u7684\u90e8\u5206\u5185\u5bb9\u4e4b\u540e\uff0c\u8fd0\u884c\u7ed3\u679c\u5c31\u6b63\u5e38\u4e86\u3002\u5373\u5f53\u7f29\u77ed\u4e86strings.lua\u7684\u957f\u5ea6\u4e4b\u540e\uff0c\u7ed3\u679c\u6b63\u5e38\u3002

\u8003\u8651\u8f93\u51faread\u7cfb\u7edf\u8c03\u7528\u4e2d\u8bfb\u5165\u7684buf\u7684\u5185\u5bb9\uff0c\u53d1\u73b0\u8bfb\u5165\u7684892\u4f4dbuf\u4e2d\uff0c\u524d512\u4f4dbuf\u88ab\u4fee\u6539\u4e3a\u4e860\uff0c\u540e\u9762\u7684buf\u4ecd\u7136\u6b63\u5e38\u3002\u800c\u5f53\u9650\u5236buf\u957f\u5ea6\u4e3a512\u65f6\uff0c\u6b64\u65f6\u524d512\u4f4dbuf\u8bfb\u53d6\u7ed3\u679c\u6b63\u5e38\u3002

arceos\u539f\u5148\u5728fat32\u8282\u70b9\u7684\u8bfb\u53d6\u51fd\u6570\u5b9a\u4e49\u5982\u4e0b\uff1a

fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {\nlet mut file = self.0.lock();\nfile.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient\nfile.read(buf).map_err(as_vfs_err)\n}\n

\u4f9d\u636e\u4e0a\u8ff0debug\u7ed3\u679c\uff0c\u53d1\u73b0starry\u7684\u6587\u4ef6\u7cfb\u7edf\u9a71\u52a8\u4e2dfat32\u7684\u5757\u5927\u5c0f\u5b9a\u4e49\u4e3a512\u3002\u67e5\u8be2read\u8bed\u4e49\u77e5\uff0c\u6bcf\u4e00\u6b21\u5b9e\u9645\u8bfb\u53d6\u957f\u5ea6\u4e0d\u4e00\u5b9a\u7b49\u4e8e\u4f20\u5165\u7684buf\u957f\u5ea6\uff0c\u56e0\u6b64\u4e0d\u53ef\u4ee5\u76f4\u63a5\u901a\u8fc7\u4f20\u5165buf\u6765\u5b9e\u73b0\u6587\u4ef6\u7684\u8bfb\u5165\uff0c\u800c\u9700\u8981\u8fdb\u884c\u5faa\u73af\u5224\u65ad\uff1a

n read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {\nlet mut file = self.0.lock();\nfile.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient\n// file.read(buf).map_err(as_vfs_err)\nlet buf_len = buf.len();\nlet mut now_offset = 0;\nlet mut probe = buf.to_vec();\nwhile now_offset < buf_len {\nlet ans = file.read(&mut probe).map_err(as_vfs_err);\nif ans.is_err() {\nreturn ans;\n}\nlet read_len = ans.unwrap();\n\nif read_len == 0 {\nbreak;\n}\nbuf[now_offset..now_offset + read_len].copy_from_slice(&probe[..read_len]);\nnow_offset += read_len;\nprobe = probe[read_len..].to_vec();\n}\nOk(now_offset)\n}\n

\u4f9d\u636e\u4e0a\u8ff0\u5199\u6cd5\uff0c\u5373\u53ef\u5b9e\u73b0\u5927\u6587\u4ef6\u7684\u8bfb\u5165\u3002

"},{"location":"%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3/#_2","title":"\u6587\u4ef6\u7684\u94fe\u63a5\u4e0e\u521d\u59cb\u5316","text":"

fat32\u6587\u4ef6\u7cfb\u7edf\u81ea\u8eab\u4e0d\u652f\u6301\u7b26\u53f7\u94fe\u63a5\uff0c\u56e0\u6b64\u9700\u8981\u5728\u5185\u6838\u4e2d\u624b\u52a8\u7ef4\u62a4\u4e00\u4e2a\u94fe\u63a5\u6620\u5c04\u3002\u4f46\u662f\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u79f0\u5b57\u7b26\u4e32\u53ef\u80fd\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\uff0c \u56e0\u6b64\u4e0d\u80fd\u5355\u7eaf\u5730\u5c06\u4f20\u5165\u7684\u6587\u4ef6\u540d\u4f5c\u4e3a\u6620\u5c04\u7684\u952e\u503c\u3002

\u6bd4\u5982\u6211\u4eec\u5efa\u7acb\u4e86\u4e00\u4e2a\u4ecea.out\u5230b.out\u7684\u94fe\u63a5\uff0c\u6b64\u65f6\u4f20\u5165\u7684\u6587\u4ef6\u540d\u53eb\u505a./a.out\uff0c\u6b64\u65f6\u5b83\u5e94\u8be5\u88ab\u8fde\u63a5\u5230b.out\uff0c\u4f46\u5728\u94fe\u63a5\u4e2d\u627e\u4e0d\u5230\u5bf9\u5e94\u7a0b\u5e8f\u3002

\u4e3a\u4e86\u89c4\u8303\u5316\u8d77\u89c1\uff0cstarry\u5f15\u7528\u4e86arceos\u63d0\u4f9b\u7684canonicalize\u51fd\u6570\uff0c\u5c06\u6587\u4ef6\u540d\u8f6c\u5316\u4e3a\u7edf\u4e00\u683c\u5f0f\u7684\u7edd\u5bf9\u8def\u5f84\uff0c\u5e76\u4ee5\u6b64\u5efa\u7acb\u6587\u4ef6\u540d\u5230\u94fe\u63a5\u5b9e\u9645\u6587\u4ef6\u7684\u6620\u5c04\u3002

\u56e0\u6b64\u4ecea.out\u5230b.out\u7684\u94fe\u63a5\uff0c\u4f1a\u88ab\u8f6c\u5316\u4e3a./a.out\u5230./b.out\u7684\u94fe\u63a5\uff0c\u901a\u8fc7\u89c4\u8303\u7684\u5b57\u7b26\u4e32\u4f7f\u5f97\u8bef\u5224\u7684\u60c5\u51b5\u53ef\u4ee5\u88ab\u51cf\u5c11\u3002

\u5b9e\u73b0busybox\u3001lua\u3001lmbench\u8fc7\u7a0b\u4e2d\uff0c\u9700\u8981\u7528\u5230\u4e00\u7cfb\u5217\u7684\u94fe\u63a5\uff0c\u5bf9\u5e94\u5b9e\u73b0\u5728starry_libax/test.rs\u7684fs_init\u51fd\u6570\u4e2d\u3002\u5982\u7a0b\u5e8f\u4f1a\u5bfb\u627e/lib/tls_get_new-dtv_dso.so\uff0c\u800c\u5b83\u4f1a\u88ab\u5b9a\u5411\u5230./tls_get_new-dtv_dso.so\u6587\u4ef6\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u9700\u8981\u6211\u4eec\u624b\u52a8\u5efa\u7acb\u94fe\u63a5\u3002

\u53e6\u5916\uff0cbusybox\u7b49\u6d4b\u4f8b\u4e5f\u9700\u8981\u6211\u4eec\u624b\u52a8\u5efa\u7acb\u4e00\u7cfb\u5217\u7684\u6587\u4ef6\u7cfb\u7edf\u4e0e\u6587\u4ef6\u5939\uff0c\u5982dev_fs\u4e0eram_fs\uff0c\u5176\u4e2ddev_fs\u5e76\u4e0d\u5141\u8bb8\u52a8\u6001\u589e\u5220\u6587\u4ef6\u5185\u5bb9\uff0c\u9700\u8981\u521d\u59cb\u5316\u65f6\u5c31\u786e\u5b9a\u597d\u3002\u76f8\u5173\u7684\u5b9e\u73b0\u5728axfs/src/root.rs\u7684init_rootfs\u51fd\u6570\uff0c\u9700\u8981\u6dfb\u52a0dev/shm\u3001dev/misc\u7b49\u6587\u4ef6\u5939\u3002

"},{"location":"%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3/#libc","title":"\u591a\u6838\u60c5\u51b5\u4e0blibc\u6d4b\u4f8b\u7ed3\u679c\u4e0d\u53ef\u6d4b","text":"

musl-libc\u6d4b\u4f8b\u4e2d\u6709\u4e00\u4e2a\u6d4b\u4f8b\u4e3apthread_cancel\uff0c\u4e3b\u8981\u662f\u6d4b\u8bd5\u7ebf\u7a0b\u662f\u5426\u53ef\u4ee5\u6b63\u5e38\u88ab\u53d6\u6d88\u3002\u4f46\u8fd9\u4e2a\u6d4b\u4f8b\u7ecf\u5e38\u4f1a\u8fd0\u884c\u5931\u8d25\uff0c\u5373\u80fd\u591f\u6210\u529f\u9000\u51fa\uff0c\u4f46\u662f\u62a5\u9519\u5e76\u672a\u53d6\u6d88\u65b0\u5efa\u7684\u7ebf\u7a0b\u3002

\u67e5\u9605\u5bf9\u5e94\u7684\u4ee3\u7801\u5982\u4e0b\uff1a

static void *start_single(void *arg)\n{\npthread_cleanup_push(cleanup1, arg);\nsleep(3);\npthread_cleanup_pop(0);\nreturn 0;\n}\nint main() {\n/* Cancellation cleanup handlers */\nfoo[0] = 0;\nTESTR(r, pthread_create(&td, 0, start_single, foo), \"failed to create thread\");\nTESTR(r, pthread_cancel(td), \"cancelling\");\nTESTR(r, pthread_join(td, &res), \"joining canceled thread\");\nTESTC(res == PTHREAD_CANCELED, \"canceled thread exit status\");\nTESTC(foo[0] == 1, \"cleanup handler failed to run\");\n}\n

\u5176\u6d4b\u8bd5\u7684\u539f\u7406\u662f\u5728pthread_cleanup_push\u52a0\u5165\u7ebf\u7a0b\u53d6\u6d88\u65f6\u8c03\u7528\u7684\u5904\u7406\u51fd\u6570\u3002\u82e5\u7ebf\u7a0b\u6210\u529f\u88ab\u53d6\u6d88\uff0c\u90a3\u4e48cleanup1\u51fd\u6570\u4f1a\u88ab\u8c03\u7528\uff0c\u6b64\u65f6\u4f1a\u4fee\u6539f00[0]\u4e3a1\uff0c\u4ee3\u8868\u6210\u529f\u53d6\u6d88\u3002

\u4f46\u6d4b\u8bd5\u65f6\u7ecf\u5e38\u62a5\u9519\uff1acleanup handler failed to run\uff0c\u901a\u8fc7\u8f93\u51faf00[0]\u53d1\u73b0\u5176\u503c\u4ecd\u7136\u4e3a0\uff0c\u5373\u7ebf\u7a0b\u53d6\u6d88\u51fd\u6570\u6ca1\u6709\u88ab\u8c03\u7528\u3002\u4f46\u662f\u8f93\u51fa\u5185\u6838\u63a5\u53d7\u5230\u7684\u7cfb\u7edf\u8c03\u7528\u4ee5\u53ca\u4fe1\u53f7\u5904\u7406\u6d41\u7a0b\u4f1a\u53d1\u73b0\u786e\u5b9e\u53d1\u51fa\u5e76\u4e14\u5904\u7406\u4e86\u53d6\u6d88\u7ebf\u7a0b\u7684\u4fe1\u53f7\u3002\u90a3\u4e48\u95ee\u9898\u51fa\u5728\u4e86\u54ea\u91cc\u5462\uff1f

\u8f93\u51fa\u4efb\u52a1\u8c03\u5ea6\u961f\u5217\u4fe1\u606f\u53d1\u73b0\uff0c\u4e3b\u4efb\u52a1\u5728\u8c03\u7528\u4e86pthread_create\u4e4b\u540e\uff0c\u5e76\u6ca1\u6709\u88ab\u963b\u585e\uff0c\u53cd\u800c\u7ee7\u7eed\u8c03\u7528\u4e86pthread_cancel\u51fd\u6570\uff0c\u53d1\u51fa\u4e86\u53d6\u6d88\u7ebf\u7a0b\u4fe1\u53f7\uff0c\u4e4b\u540e\u518d\u88abpthread_join\u51fd\u6570\u963b\u585e\u3002\u6b64\u65f6\u624d\u8c03\u5ea6\u5230\u5b50\u7ebf\u7a0b\uff0c\u5e76\u4e14\u7acb\u5373\u8fdb\u5165\u4e86\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u7684\u6d41\u7a0b\uff0c\u5373\u7acb\u5373\u88ab\u53d6\u6d88\u3002\u6b64\u65f6\u5b50\u7ebf\u7a0b\u751a\u81f3\u6ca1\u6709\u8fdb\u5165\u5230start_single\u51fd\u6570\u5c31\u88ab\u53d6\u6d88\u4e86\u3002\u6b64\u65f6\u6ca1\u6709\u6ce8\u518c\u53d6\u6d88\u7ebf\u7a0b\u51fd\u6570\u4e3acleanup1\uff0c\u56e0\u6b64\u81ea\u7136\u4e0d\u4f1a\u4fee\u6539f00[0]\u3002

\u4f46\u662f\u95ee\u9898\u5728\u4e8epthread_create\u7684\u8bed\u4e49\u8981\u6c42\u672c\u4efb\u52a1\u4f1a\u88abyield\uff0c\u5373\u5b50\u7ebf\u7a0b\u5e94\u5f53\u5728\u521b\u5efa\u4e4b\u540e\u88ab\u7acb\u5373\u6267\u884c\u3002\u7ee7\u7eeddebug\uff0c\u8f93\u51fa\u4efb\u52a1\u8c03\u5ea6\u5217\u8868\u548c\u5bf9\u5e94CPU\u7f16\u53f7\u53d1\u73b0\uff0c\u867d\u7136\u5728\u5f53\u524dCPU\u4e0a\u4e3b\u4efb\u52a1\u88abyield\u4e86\uff0c\u4f46\u5f53\u524d\u542f\u52a8\u4e86\u591a\u6838\uff0c\u95f2\u7f6e\u7684CPU\u7acb\u5373\u5c06\u521a\u88abyield\u7684\u4e3b\u4efb\u52a1\u63a5\u7ba1\u5e76\u4e14\u7ee7\u7eed\u8fd0\u884c\u3002\u5219\u6b64\u65f6\u4e3b\u4efb\u52a1\u6709\u6982\u7387\u5728\u5b50\u7ebf\u7a0b\u5f00\u59cb\u4e4b\u524d\u8c03\u7528cancel\u51fd\u6570\u53d1\u51fa\u53d6\u6d88\u4fe1\u53f7\uff0c\u4ece\u800c\u5bfc\u81f4\u7ebf\u7a0b\u53d6\u6d88\u51fd\u6570\u6ce8\u518c\u5931\u8d25\u3002

\u5c06\u5185\u6838\u6539\u4e3a\u5355\u6838\u542f\u52a8\u4e4b\u540e\uff0c\u95ee\u9898\u6d88\u5931\u3002\u603b\u7ed3\u800c\u8a00\uff0c\u5728\u65e0\u6cd5\u6539\u52a8\u6d4b\u4f8b\u4ee3\u7801\u7684\u60c5\u51b5\u4e0b\uff0c\u8dd1musl-libc\u6d4b\u4f8b\u5e94\u5f53\u4ee5\u5355\u6838\u7684\u5f62\u5f0f\u8fdb\u884c\uff0c\u591a\u6838\u53ef\u80fd\u4f1a\u9047\u5230\u5404\u79cd\u5947\u602a\u7684\u95ee\u9898\u3002\u3002

"},{"location":"%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3/#lmbench","title":"lmbench\u6d4b\u4f8b\u7684\u7ed3\u675f","text":"

\u8fd0\u884clmbench\u6d4b\u4f8b\u65f6\u53d1\u73b0\u65f6\uff0c\u7a0b\u5e8f\u603b\u662f\u4f1a\u8bbf\u95ee0x2,0x4,0x6,0x8\u7b49\u5730\u5740\uff0c\u5bfc\u81f4page fault\u3002gdb\u8fdb\u884cdebug\u65e0\u679c\uff0c\u53d1\u73b0\u7a0b\u5e8f\u5df2\u7ecf\u8f93\u51fa\u4e86\u9884\u671f\u8f93\u51fa\uff0c\u4e4b\u540e\u4f1a\u76f4\u63a5\u8bbf\u95ee\u8be5\u975e\u6cd5\u5730\u5740\u3002

\u8be2\u95ee\u5f80\u5e74\u53c2\u52a0\u6bd4\u8d5b\u7684\u5b66\u957f\uff0c\u4e86\u89e3\u5230\u53bb\u5e74\u7684lmbench\u4f1a\u5728\u6bcf\u4e2a\u6d4b\u4f8b\u7ed3\u675f\u7684\u65f6\u5019\u76f4\u63a5\u8ba9pc\u8df3\u5230\u5806\u6808\u4e0a\uff0c\u4ece\u800c\u89e6\u53d1I fault\uff0c\u901a\u8fc7\u5185\u6838\u6355\u83b7\u8be5\u4fe1\u53f7\u5e76\u8fdb\u884c\u7279\u5224\uff0c\u4ece\u800c\u624b\u52a8\u8c03\u7528exit\u7ed3\u675f\u5f53\u524d\u7684lmbench\u6d4b\u4f8b\uff0c\u8fdb\u5165\u5230\u4e0b\u4e00\u4e2almbench\u6d4b\u4f8b\u3002

\u800c\u5728\u4eca\u5e74\u7f16\u8bd1\u5f97\u5230\u7684lmbench\u7248\u672c\uff0cpc\u4e0d\u518d\u8df3\u8f6c\u5230\u5806\u6808\uff0c\u800c\u662f\u8df3\u8f6c\u5230\u4f4e\u5730\u5740\u59820x6\uff0c\u6b64\u65f6\u4e5f\u662f\u8981\u6c42\u5185\u6838\u76f4\u63a5\u505a\u51fa\u7279\u5224\uff0c\u7ed3\u675f\u5f53\u524d\u4efb\u52a1\u3002

\u67e5\u9605riscv\u89c4\u8303\u5f97\u77e5\uff0c\u975e\u6cd5\u8bbf\u95ee\u5185\u5b58\uff0c\u5185\u6838\u5904\u7406\u5931\u8d25\u4e4b\u540e\u5e94\u5f53\u53d1\u9001SIGSEGV\u4fe1\u53f7\u5230\u5bf9\u5e94\u7ebf\u7a0b\uff0c\u4ece\u800c\u7ed3\u675f\u5f53\u524d\u4efb\u52a1\u3002\u56e0\u6b64\u4fee\u6539\u4ee3\u7801\u5982\u4e0b\uff1a

#[cfg(feature = \"paging\")]\nfn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame) {\nuse axprocess::handle_page_fault;\nuse axsignal::signal_no::SignalNo;\nuse axtask::current;\naxprocess::time_stat_from_user_to_kernel();\nuse crate::syscall::signal::{syscall_sigreturn, syscall_tkill};\nif addr.as_usize() == SIGNAL_RETURN_TRAP {\n// \u8bf4\u660e\u662f\u4fe1\u53f7\u6267\u884c\u5b8c\u6bd5\uff0c\u6b64\u65f6\u5e94\u5f53\u6267\u884csig return\ntf.regs.a0 = syscall_sigreturn() as usize;\nreturn;\n}\n\nif handle_page_fault(addr, flags).is_err() {\n// \u5982\u679c\u5904\u7406\u5931\u8d25\uff0c\u5219\u53d1\u51fasigsegv\u4fe1\u53f7\nlet curr = current().id().as_u64() as isize;\naxlog::error!(\"kill task: {}\", curr);\nsyscall_tkill(curr, SignalNo::SIGSEGV as isize);\n}\naxprocess::time_stat_from_kernel_to_user();\n}\n

\u8fd9\u79cd\u60c5\u51b5\u4e0d\u4ec5\u53ef\u4ee5\u5904\u7406pc\u8df3\u8f6c\u5230\u4f4e\u5730\u5740\u7684\u60c5\u51b5\uff0c\u4e5f\u53ef\u4ee5\u5904\u7406\u8df3\u8f6c\u5230\u5806\u6808\u7684\u60c5\u51b5\uff0c\u66f4\u52a0\u5730\u89c4\u8303\u5316\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E4%BE%9D%E8%B5%96%E9%97%AE%E9%A2%98/","title":"\u4f9d\u8d56\u95ee\u9898","text":"

\u7531\u4e8eArceOS\u81ea\u8eab\u7684unikernel\u67b6\u6784\uff0c\u4e0d\u540c\u6a21\u5757\u9700\u8981\u4fdd\u6301\u4e00\u5b9a\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u4ece\u800c\u53ef\u4ee5\u65b9\u4fbf\u5730\u901a\u8fc7\u6761\u4ef6\u7f16\u8bd1\u7b49\u64cd\u4f5c\u6765\u89e3\u8026\u67d0\u4e9b\u6a21\u5757\uff0c\u4f7f\u7528\u67d0\u4e9b\u6307\u5b9a\u7684\u6a21\u5757\u6765\u542f\u52a8\u5185\u6838\uff0c\u4ece\u800c\u589e\u5f3aOS\u7684\u6cdb\u7528\u6027\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E4%BE%9D%E8%B5%96%E9%97%AE%E9%A2%98/#_1","title":"\u67e5\u770b\u9879\u76ee\u7684\u4f9d\u8d56\u5173\u7cfb","text":"

\u9879\u76ee\u7684\u4f9d\u8d56\u5173\u7cfb\u53ef\u4ee5\u901a\u8fc7\u5bf9\u5e94\u7684toml\u914d\u7f6e\u6587\u4ef6\u8fdb\u884c\u67e5\u770b\u3002\u5982\u4e0b\u5217\u4e3aaxmem\u6a21\u5757\u7684toml\uff1a

# modules/axmem/Cargo.toml\n[dependencies]\nlog = \"0.4\"\naxhal = { path = \"../axhal\", features = [\"paging\"] }\naxalloc = { path = \"../axalloc\" }\naxconfig = { path = \"../axconfig\" }\naxerrno = { path = \"../../crates/axerrno\" }\naxfs = { path = \"../axfs\" }\naxio = { path = \"../../crates/axio\" }\nspinlock = { path = \"../../crates/spinlock\" }\nxmas-elf = { path = \"../../extern_crates/xmas-elf-0.9.0\" }\nriscv = { path = \"../../extern_crates/riscv-0.10.1\" }\npage_table_entry = { path = \"../../crates/page_table_entry\" }\n

\u4ee5\u4e0a\u5c31\u53ef\u4ee5\u770b\u51faaxmem\u4f9d\u8d56\u4e86axhal/axfs/axconfig\u7b49\u6a21\u5757\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E4%BE%9D%E8%B5%96%E9%97%AE%E9%A2%98/#_2","title":"\u5faa\u73af\u4f9d\u8d56\u95ee\u9898","text":"

\u800cStarry\u867d\u7136\u662f\u5b8f\u5185\u6838\u67b6\u6784\uff0c\u4f46\u4ecd\u7136\u4fdd\u6301\u4e86\u8fd9\u4e00\u6cdb\u7528\u7279\u6027\uff0c\u4f46\u8fd9\u4e5f\u4e3a\u6211\u4eec\u5f00\u53d1\u5e26\u6765\u4e86\u4e00\u4e9b\u95ee\u9898\uff0c\u5373\u5faa\u73af\u4f9d\u8d56\u95ee\u9898\u3002

\u7531\u4e8eArceOS\u7684\u6a21\u5757\u5316\u8bbe\u8ba1\uff0c\u4e0d\u540c\u7684modules\u4e4b\u95f4\u4f1a\u5f62\u6210\u4ee5module\u4e3a\u5355\u4f4d\u7684\u4f9d\u8d56\u5173\u7cfb\uff0c\u76f8\u8f83\u4e8e\u4ee5\u6587\u4ef6\u4e3a \u5355\u4f4d\u7684\u4f9d\u8d56\u5173\u7cfb\u800c\u8a00\u66f4\u5bb9\u6613\u4ea7\u751f\u5faa\u73af\u4f9d\u8d56\u7684\u95ee\u9898\u3002

\u4e00\u4e2a\u4f8b\u5b50\uff1a\u5047\u5982\u4e00\u4e2a\u9879\u76ee\u4e2d\u6709A\u3001B\u3001C\u4e09\u4e2a\u6587\u4ef6\uff0cA\u4f9d\u8d56B\u3001B\u4f9d\u8d56C\uff0c\u4e0d\u4f1a\u6709\u4efb\u4f55\u95ee\u9898\uff1b\u4f46\u5982\u679c\u4e09 \u4e2a\u6587\u4ef6\u88ab\u89e3\u8026\u5230\u4e24\u4e2a\u4e0d\u540c\u7684\u9879\u76ee M\u548cN\u4e2d\uff0cM\u4e2d\u6709A\u548cC\uff0cN\u4e2d\u6709B\uff0c\u90a3\u4e48M\u548cN\u4e4b\u95f4\u5c31\u4f1a\u53d1\u751f\u76f8\u4e92\u4f9d \u8d56\u3002 \u8fd9\u79cd\u60c5\u51b5\u5728\u6211\u4eec\u7684\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u5e76\u4e0d\u5c11\u89c1\u3002

\u5f53\u524dStarry\u7684\u6a21\u5757\u4f9d\u8d56\u56fe\u5982\u4e0b\uff1a

\u5982axhal\u9700\u8981\u5b9a\u4e49trap\u5165\u53e3\uff0c\u800ctrap\u5b9e\u73b0\u9700\u8981\u5f88\u591a\u6a21\u5757\u7684\u652f\u6301\u5982axmem\u7684\u5730\u5740\u7a7a\u95f4\u7b49\uff0c\u6b64\u65f6\u5c31\u53ef\u80fd\u51fa\u73b0\u5faa\u73af\u4f9d\u8d56\u7684\u60c5\u51b5\uff0c\u5373axhal\u4f9d\u8d56\u4e8eaxmem\uff0c\u800caxmem\u4f9d\u8d56\u4e8eaxhal\u3002

\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u6709\u4ee5\u4e0b\u51e0\u79cd\u65b9\u6cd5\uff1a

  1. \u4f18\u5316\u7ed3\u6784\u8bbe\u8ba1\uff0c\u5373\u5c3d\u53ef\u80fd\u5c06\u5b9e\u73b0\u7684\u529f\u80fd\u8fdb\u884c\u5212\u5206\uff0c\u5982\u5730\u5740\u7a7a\u95f4\u5185\u5bb9\u72ec\u7acb\u51fa\u6765\u653e\u5728axmem\uff0c\u800c\u4e0d\u662f\u548c\u8fdb\u7a0b\u63a7\u5236\u4e00\u8d77\u653e\u5728axprocess\u3002

  2. \u901a\u8fc7ArceOS\u63d0\u4f9b\u7684\u6a21\u5757crate_interface\u4e2d\u7684call_interface\u548cdef_interface\uff0c\u5728\u5e95\u5c42\u6a21\u5757\u5b9a\u4e49\u597d\u76f8\u5173\u7684\u51fd\u6570\u4e4b\u540e\uff0c\u4ea4\u7ed9\u4e0a\u5c42\u6a21\u5757\u53bb\u5b9e\u73b0\u3002

\u5982\u5728axhal\u4e2d\u5b9a\u4e49\u4e86TrapHandler\u5982\u4e0b\uff1a

#[def_interface]\npub trait TrapHandler {\n/// Handles interrupt requests for the given IRQ number.\nfn handle_irq(irq_num: usize);\n// more e.g.: handle_page_fault();\n// \u9700\u8981\u5206\u79bb\u7528\u6237\u6001\u4f7f\u7528\n#[cfg(feature = \"monolithic\")]\nfn handle_syscall(syscall_id: usize, args: [usize; 6]) -> isize;\n\n#[cfg(feature = \"paging\")]\nfn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame);\n\n#[cfg(feature = \"paging\")]\nfn handle_access_fault(addr: VirtAddr, flags: MappingFlags);\n\n/// \u5904\u7406\u5f53\u524d\u8fdb\u7a0b\u7684\u4fe1\u53f7\n#[cfg(feature = \"signal\")]\nfn handle_signal();\n\n/// \u4e3a\u4e86lmbench\u7279\u5224\uff0c\u5373\u5728\u51fa\u73b0\u672a\u80fd\u5904\u7406\u7684\u60c5\u51b5\uff0c\u4e0dpanic\uff0c\u800c\u662f\u9000\u51fa\u5f53\u524d\u8fdb\u7a0b\n#[cfg(feature = \"monolithic\")]\nfn exit();\n}\n

\u800c\u5728starry_libax/trap.rs\u5b8c\u6210\u4e86\u5bf9TrapHandler\u7684\u5b9e\u73b0\uff1a

#[crate_interface::impl_interface]\nimpl axhal::trap::TrapHandler for TrapHandlerImpl {\nfn handle_irq(irq_num: usize) {\n/// ..\n}\nfn handle_syscall(syscall_id: usize, args: [usize; 6]) -> isize {\n/// ..\n}\n\n#[cfg(feature = \"paging\")]\nfn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame) {\n/// ..\n}\n\nfn handle_access_fault(addr: VirtAddr, flags: MappingFlags) {\n/// ..\n}\n\n#[cfg(feature = \"signal\")]\nfn handle_signal() {\n/// ..\n}\n\nfn exit() {\n/// ..\n}\n}\n

\u800c\u5728axruntime/src/trap.rs\u4e2d\u5b9a\u4e49\u4e86ArceOS\u539f\u6709\u7684unikernel\u67b6\u6784\u4e0b\u7684trap\u5b9e\u73b0\uff1a

/// \u4ec5\u7528\u4f5c\u975e\u5b8f\u5185\u6838\u4e0b\u7684trap\u5165\u53e3\n\nstruct TrapHandlerImpl;\n\n#[crate_interface::impl_interface]\nimpl axhal::trap::TrapHandler for TrapHandlerImpl {\nfn handle_irq(_irq_num: usize) {\n#[cfg(feature = \"irq\")]\n{\nlet guard = kernel_guard::NoPreempt::new();\naxhal::irq::dispatch_irq(_irq_num);\ndrop(guard); // rescheduling may occur when preemption is re-enabled.\n}\n}\n}\n

\u901a\u8fc7\u4e0d\u540c\u7684TrapHandler\u7684\u5b9e\u73b0\uff0c\u53ef\u4ee5\u5b9e\u73b0\u5b8f\u5185\u6838\u548cunikernel\u67b6\u6784\u4e0b\u4e0d\u540ctrap\u5b9e\u73b0\u7684\u652f\u6301\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98/","title":"\u517c\u5bb9\u95ee\u9898","text":"

\u4e3a\u4e86\u4fdd\u8bc1Starry\u5728\u672a\u6765\u7684\u6cdb\u7528\u6027\uff0c\u6211\u4eec\u5728\u6bd4\u8d5b\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u4fbf\u6709\u610f\u8bc6\u5730\u53bb\u6ce8\u610f\u4e0d\u540c\u67b6\u6784\u4e0b\u7684\u5b9e\u73b0\u517c\u5bb9\uff0c\u5e76\u91c7\u7528\u6761\u4ef6\u7f16\u8bd1\u7b49\u65b9\u5f0f\u8fdb\u884c\u533a\u5206\u3002\u5982process\u90e8\u5206\u7684\u7ed3\u6784\u4f53\u7684\u5b9a\u4e49\u4e3a\uff1a

pub struct ProcessInner {\n/// \u7236\u8fdb\u7a0b\u7684\u8fdb\u7a0b\u53f7\npub parent: u64,\n/// \u5b50\u8fdb\u7a0b\npub children: Vec<Arc<Process>>,\n/// \u5b50\u4efb\u52a1\npub tasks: Vec<AxTaskRef>,\n/// \u5730\u5740\u7a7a\u95f4\uff0c\u7531\u4e8e\u5b58\u5728\u5730\u5740\u7a7a\u95f4\u5171\u4eab\uff0c\u56e0\u6b64\u8bbe\u8ba1\u4e3aArc\u7c7b\u578b\npub memory_set: Arc<SpinNoIrq<MemorySet>>,\n/// \u7528\u6237\u5806\u57fa\u5740\uff0c\u4efb\u4f55\u65f6\u5019\u5806\u9876\u90fd\u4e0d\u80fd\u6bd4\u8fd9\u4e2a\u503c\u5c0f\uff0c\u7406\u8bba\u4e0a\u8bb2\u662f\u4e00\u4e2a\u5e38\u91cf\npub heap_bottom: usize,\n/// \u5f53\u524d\u7528\u6237\u5806\u7684\u5806\u9876\uff0c\u4e0d\u80fd\u5c0f\u4e8e\u57fa\u5740\uff0c\u4e0d\u80fd\u5927\u4e8e\u57fa\u5740\u52a0\u5806\u7684\u6700\u5927\u5927\u5c0f\npub heap_top: usize,\n/// \u8fdb\u7a0b\u72b6\u6001\npub is_zombie: bool,\n/// \u9000\u51fa\u72b6\u6001\u7801\npub exit_code: i32,\n// /// \u6587\u4ef6\u63cf\u8ff0\u7b26\u8868\n// pub fd_table: Vec<Option<Arc<SpinNoIrq<dyn FileIO>>>>,\n// /// \u6587\u4ef6\u63cf\u8ff0\u7b26\u4e0a\u9650\uff0c\u7531prlimit\u8bbe\u7f6e\n// pub fd_limit: usize,\n#[cfg(feature = \"fs\")]\npub fd_manager: FdManager,\n/// \u8fdb\u7a0b\u5de5\u4f5c\u76ee\u5f55\npub cwd: String,\n#[cfg(feature = \"signal\")]\n/// \u4fe1\u53f7\u5904\u7406\u6a21\u5757    \n/// \u7b2c\u4e00\u7ef4\u4ee3\u8868\u7ebf\u7a0b\u53f7\uff0c\u7b2c\u4e8c\u7ef4\u4ee3\u8868\u7ebf\u7a0b\u5bf9\u5e94\u7684\u4fe1\u53f7\u5904\u7406\u6a21\u5757\npub signal_module: BTreeMap<u64, SignalModule>,\n\n/// robust list\u5b58\u50a8\u6a21\u5757\n/// \u7528\u6765\u5b58\u50a8\u7ebf\u7a0b\u5bf9\u5171\u4eab\u53d8\u91cf\u7684\u4f7f\u7528\u5730\u5740\n/// \u5177\u4f53\u4f7f\u7528\u4ea4\u7ed9\u4e86\u7528\u6237\u7a7a\u95f4\npub robust_list: BTreeMap<u64, FutexRobustList>,\n}\n

\u5176\u989d\u5916\u9650\u5b9a\u4e86fs\u548csignal\u7684feature\uff0c\u89c4\u5b9a\u4e86\u4fe1\u53f7\u6a21\u5757\u548c\u6587\u4ef6\u7cfb\u7edf\u6a21\u5757\u7684\u6761\u4ef6\u7f16\u8bd1\uff0c\u53ef\u4ee5\u6839\u636e\u7f16\u8bd1\u53c2\u6570\u6765\u51b3\u5b9a\u5185\u6838\u662f\u5426\u652f\u6301fs\u548c\u4fe1\u53f7\u6a21\u5757\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%AE%8F%E5%86%85%E6%A0%B8%E5%8C%96%E6%8E%A2%E8%AE%A8/","title":"\u5b8f\u5185\u6838\u5316\u63a2\u8ba8","text":"

Starry\u7684\u5de5\u4f5c\u662f\u4e3a\u4e00\u4e2a\u9762\u5411Unikernel\u8bbe\u8ba1\u7684OS\u6dfb\u52a0\u5b8f\u5185\u6838\u652f\u6301\uff0c\u56e0\u6b64\u76f8\u6bd4\u4e8e\u5176\u4ed6\u4ece0\u5f00\u59cb\u7684 \u5185\u6838\uff0cStarry\u9700\u8981\u8003\u8651\u66f4\u591a\u517c\u5bb9\u5de5\u4f5c\uff0c\u4e5f\u8981\u6c42\u6211\u4eec\u5bf9Unikernel\u548cArceOS\u6709\u8db3\u591f\u7684\u4e86\u89e3\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%AE%8F%E5%86%85%E6%A0%B8%E5%8C%96%E6%8E%A2%E8%AE%A8/#_1","title":"\u524d\u671f\u77e5\u8bc6\u4e86\u89e3","text":"

\u9996\u5148\uff0c\u6211\u4eec\u4e86\u89e3\u5230ArceOS\u662f\u4ee5Unikernel\u67b6\u6784\u8fd0\u884c\u7684\u3002\u56e0\u6b64\u6211\u4eec\u67e5\u9605\u4e86Unikernel\u548c\u5b8f\u5185\u6838\u76f8\u5173\u7684\u8d44\u6599\uff0c\u5e76\u4e14\u603b\u7ed3\u51fa\u4e24\u8005\u4e4b\u95f4\u7684\u4e00\u4e9b\u7b80\u5355\u7684\u533a\u522b\u5982\u4e0b\uff1a

\u53e6\u5916\uff0c\u6211\u4eec\u4e5f\u8be6\u7ec6\u9605\u8bfb\u4e86ArceOS\u7684\u4ee3\u7801\uff0c\u603b\u7ed3\u51fa\u4eceArceOS\u5230\u5b8f\u5185\u6838\u9700\u8981\u5b8c\u5584\u7684\u5185\u5bb9\uff1a

\u901a\u8fc7\u9605\u8bfbArceOS\u4e0e\u5176\u4ed6\u5b8f\u5185\u6838\u5982zCore\u3001rCore\u7684\u4ee3\u7801\u5b9e\u73b0\uff0c\u5c06ArceOS\u4e0e\u5b8f\u5185\u6838\u7684\u5173\u7cfb\u5212\u5206\u5982\u4e0b\uff1a

  • ArceOS\u4e2d\u53ef\u76f4\u63a5\u6cbf\u7528\uff1alog\u3001driver\u4ee5\u53ca\u4e00\u7cfb\u5217\u89e3\u8026\u7684crate
  • ArceOS\u4e2d\u9700\u8981\u8c03\u6574\u9002\u914d\uff1a\u4efb\u52a1\u8c03\u5ea6\u3001\u7279\u6743\u7ea7\u8f6c\u5316\u7b49
  • ArceOS\u4e2d\u9700\u8981\u6dfb\u52a0\uff1a\u5730\u5740\u7a7a\u95f4\u3001\u8fdb\u7a0b\u3001\u4fe1\u53f7\u3001\u6587\u4ef6\u7cfb\u7edf\u3001\u7528\u6237\u5e93\u7b49\u5185\u5bb9
"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%AE%8F%E5%86%85%E6%A0%B8%E5%8C%96%E6%8E%A2%E8%AE%A8/#_2","title":"\u5f00\u53d1\u5185\u5bb9","text":"

\u4f9d\u636e\u524d\u671f\u77e5\u8bc6\u7684\u603b\u7ed3\uff0c\u6211\u4eec\u5728\u539f\u6709ArceOS\u7684\u57fa\u7840\u4e0a\u505a\u51fa\u4e86\u5982\u4e0b\u6539\u52a8\uff1a

\u5728\u539f\u6709ArceOS\u4ee3\u7801\u7684\u57fa\u7840\u4e0a

  • \u65b0\u589e\u4e864\u4e2a\u6a21\u5757\uff1a\u5206\u522b\u4e3a
  • axmem\uff1a\u6dfb\u52a0\u591a\u5730\u5740\u7a7a\u95f4
  • axprocess\uff1a\u6dfb\u52a0\u8fdb\u7a0b\u7ba1\u7406
  • axsignal\uff1a\u6dfb\u52a0\u4fe1\u53f7\u6a21\u5757
  • axfs\uff1a\u6dfb\u52a0\u9002\u7528\u4e8e\u5b8f\u5185\u6838\u7684\u6587\u4ef6\u7cfb\u7edf\u63a5\u53e3
  • \u6539\u52a8\u9002\u914d\u4e865\u4e2a\u6a21\u5757\uff1a\u5206\u522b\u4e3a
  • axhal\uff1a\u4e3b\u8981\u4e3a\u5173\u4e8e\u5b8f\u5185\u6838\u7684trap\u5904\u7406\uff0c\u5982syscall\u3001\u7f3a\u9875\u5f02\u5e38\u7b49
  • axtask\uff1a\u4e3b\u8981\u4e3atask\u4fe1\u606f\u7684\u8865\u5145\uff0c\u5982\u8ba1\u65f6\u5668\u4fe1\u606f
  • axdriver\uff1a\u4e3b\u8981\u4e3aramdisk\u7684\u8865\u5145\uff0c\u4e3a\u6bd4\u8d5b\u52a0\u8f7d\u6d4b\u4f8b\u670d\u52a1
  • axruntime\uff1a\u4e3b\u8981\u4e3a\u5185\u6838\u521d\u59cb\u5316\u6d41\u7a0b\u4e2d\u6dfb\u52a0\u5b8f\u5185\u6838\u542f\u52a8\u76f8\u5173\u670d\u52a1
  • axnet\uff1a\u4e3b\u8981\u4e3aLinux\u76f8\u5173\u7684syscall\u6dfb\u52a0\u76f8\u5bf9\u5e94\u7684\u63a5\u53e3
  • \u65b0\u589e\u4e86\u4e00\u4e2a\u7528\u6237\u5e93\uff1a\u5c01\u88c5Linux\u76f8\u5173\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u5904\u7406\u76f8\u5e94\u7684syscall
  • \u5171\u6d89\u53ca\u4ee3\u7801\u7ea612000\u884c
"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%AE%8F%E5%86%85%E6%A0%B8%E5%8C%96%E6%8E%A2%E8%AE%A8/#_3","title":"\u5f00\u53d1\u91cd\u70b9","text":""},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%AE%8F%E5%86%85%E6%A0%B8%E5%8C%96%E6%8E%A2%E8%AE%A8/#_4","title":"\u8fdb\u7a0b\u5b9e\u73b0","text":"

\u4e3a\u4e86\u4fdd\u8bc1Starry\u53ef\u4ee5\u8f83\u597d\u5730\u53bb\u9002\u914dUnikernel\u67b6\u6784\uff0c\u5728\u6bd4\u8d5b\u521d\u671f\u6211\u4eec\u5c31\u8fdb\u7a0b\u7ed3\u6784\u4e0e\u7ebf\u7a0b\u662f\u5426\u5206\u79bb\u8fd9\u4e2a\u95ee\u9898\u8fdb\u884c\u4e86\u8ba8\u8bba\u3002

\u5728Linux\u4e2d\uff0c\u8fdb\u7a0b\u548c\u7ebf\u7a0b\u5408\u5e76\u5728\u4e00\u8d77\uff0c\u7edf\u4e00\u7531pthread\u63a7\u5236\u5757\u8fdb\u884c\u7ba1\u7406\uff0c\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u7b80\u5316\u4e86\u7ed3\u6784\u3002\u4f46\u6211\u4eec\u7684Starry\u9700\u8981\u9002\u914dUnikernel\uff0c\u5728Unikernel\u4e2d\u662f\u5355\u5e94\u7528\u7a0b\u5e8f\uff0c\u6ca1\u6709\u591a\u8fdb\u7a0b\u7684\u6982\u5ff5\u3002\u56e0\u6b64\u4f5c\u4e3a\u517c\u5bb9Linux\u5e94\u7528\u548cUnikernel\u7684Starry OS\uff0c\u8fdb\u7a0b\u5982\u4f55\u5b9a\u4e49\u4fbf\u6709\u4e86\u8f83\u4e3a\u91cd\u8981\u7684\u610f\u4e49\u3002

\u6211\u4eec\u5148\u8ba8\u8bba\u4e86\u4e24\u79cd\u505a\u6cd5\u7684\u4f18\u70b9\uff1a

  • \u5408\u5e76\u4f18\u70b9\uff1a\u7b26\u5408Linux\u7ed3\u6784\uff0c\u66f4\u52a0\u76f4\u89c2
  • \u5206\u79bb\u4f18\u70b9\uff1a\u9002\u914dUnikernel\u5b9e\u73b0\uff0c\u66f4\u52a0\u517c\u5bb9ArceOS

\u4e3a\u4e86\u5f97\u5230\u66f4\u597d\u7684\u6bd4\u8f83\u7ed3\u679c\uff0c\u6211\u4eec\u5206\u5934\u884c\u52a8\uff0c\u6839\u636e\u4e24\u79cd\u4e0d\u540c\u7684\u5b9a\u4e49\u65b9\u5f0f\u5b9e\u73b0\u4e86\u4e24\u4e2a\u5185\u6838\u3002\u7ecf\u8fc7\u6bd4\u8f83\u4e4b\u540e\uff0c\u6211\u4eec\u51b3\u5b9a\u5c06\u8fdb\u7a0b\u548c\u7ebf\u7a0b\u5408\u5e76\uff0c\u66f4\u597d\u5730\u53bb\u9002\u914dArceOS\u3002

"},{"location":"%E5%AE%9E%E7%8E%B0%E9%87%8D%E7%82%B9/%E5%AE%8F%E5%86%85%E6%A0%B8%E5%8C%96%E6%8E%A2%E8%AE%A8/#arceos","title":"\u4e0eArceOS\u7684\u517c\u5bb9","text":"

\u4e3a\u4e86\u4fdd\u8bc1\u548cArceOS\u4ee3\u7801\u529f\u80fd\u4e0a\u7684\u517c\u5bb9\uff0c\u5728\u5f00\u53d1\u8fc7\u7a0b\u4e2d\u9700\u8981\u4e00\u5b9a\u7a0b\u5ea6\u5730\u4fdd\u7559ArceOS\u539f\u6709\u4ee3\u7801\uff0c\u540c\u65f6\u4e0d\u80fd\u5f71\u54cd\u81ea\u5df1\u65b0\u7684\u529f\u80fd\uff0c\u9632\u6b62\u51fa\u73b0\u51b2\u7a81\u3002

\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u6211\u4eec\u7528\u5230\u4e86\u4e09\u79cd\u5de5\u5177\uff1a

  • \u6761\u4ef6\u7f16\u8bd1

\u6761\u4ef6\u7f16\u8bd1\u8d2f\u7a7f\u4e86Starry\u5b9e\u73b0\u8fc7\u7a0b\uff0c\u901a\u8fc7\u6307\u5b9a\u4e0d\u540c\u7684feature\u6765\u5b9a\u5236\u4e0d\u540c\u7684\u5185\u6838\u5b9e\u73b0\u3002\u540c\u65f6\uff0c\u4e5f\u53ef\u4ee5\u7528\u6761\u4ef6\u7f16\u8bd1\u6765\u5728\u4fdd\u7559ArceOS\u539f\u6709\u529f\u80fd\u7684\u540c\u65f6\uff0c\u6dfb\u52a0\u4e0aStarry\u7684\u5206\u652f\u529f\u80fd\uff0c\u6307\u5b9a\u4e0d\u540c\u7684feature\u4fdd\u8bc1\u4e24\u8005\u53ef\u4ee5\u5f97\u5230\u517c\u5bb9\u3002

cfg_if::cfg_if! {\nif #[cfg(feature = \"monolithic\")] {\naxprocess::process::init_kernel_process();\n}\nelse {\n#[cfg(feature = \"multitask\")]\naxtask::init_scheduler();\n}\n}\n
  • \u5c01\u88c5trait

\u5c01\u88c5trait\u662fRust\u63d0\u4f9b\u4e0d\u540c\u5b9e\u73b0\u517c\u5bb9\u7684\u4e00\u79cd\u5e38\u89c1\u65b9\u5f0f\u3002\u4e0d\u540c\u7ed3\u6784\u901a\u8fc7\u7528\u4e0d\u540c\u65b9\u5f0f\u5b9e\u73b0\u540c\u4e00\u4e2atrait\uff0c\u53ef\u4ee5\u5f97\u5230\u4e0d\u540c\u7684\u5904\u7406\u65b9\u5f0f\u548c\u529f\u80fd\uff0c\u4ece\u800c\u8fbe\u5230\u4e86\u517c\u5bb9\u5e76\u5b58\u7684\u6548\u679c\u3002\u5982\u6587\u4ef6\u7cfb\u7edf\u7684\u4e00\u7cfb\u5217\u8bfb\u5199Trait\u4fbf\u8d77\u5230\u4e86\u8fd9\u4e2a\u529f\u80fd\u3002

  • crate_interface\u5305

crate_interface\u5305\u662f\u7531ArceOS\u5b9e\u73b0\u7684\u4e00\u4e2a\u5305\uff0c\u6548\u679c\u7c7b\u4f3c\u4e8etrait\u3002\u5b83\u5141\u8bb8\u7528\u6237\u5728\u5e95\u5c42\u901a\u8fc7def_interface\u5b9a\u4e49\u67d0\u4e9b\u51fd\u6570\u63a5\u53e3\uff0c\u5e76\u5728\u4e0a\u5c42\u901a\u8fc7impl_interface\u5b9e\u73b0\u5bf9\u5e94\u51fd\u6570\u7684\u5177\u4f53\u5185\u5bb9\u3002\u901a\u8fc7\u8c03\u7528\u591a\u4e2aimpl_interface\u4fbf\u53ef\u4ee5\u505a\u5230\u540c\u4e00\u4e2a\u63a5\u53e3\u7684\u591a\u79cd\u5b9e\u73b0\u65b9\u5f0f\u3002

crate_interface\u4e0etrait\u7684\u4e00\u4e2a\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\uff0ccrate_interface\u7684\u5b9e\u73b0\u53ea\u80fd\u6709\u4e00\u4e2a\uff0c\u4e5f\u5c31\u662f\u8bf4\u5982\u679c\u5b58\u5728impl_interface\uff0c\u90a3\u4e48\u53ef\u80fd\u9700\u8981\u7528\u5230\u6761\u4ef6\u7f16\u8bd1\u7b49\u624b\u6bb5\u4f7f\u5f97\u4ec5\u6709\u552f\u4e00\u4e00\u4e2aimpl_interface\u88ab\u5b9e\u9645\u7f16\u8bd1\u5230\u955c\u50cf\u4e2d\u3002

"},{"location":"%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/ArceOS%E4%BB%8B%E7%BB%8D/","title":"ArceOS\u4ecb\u7ecd","text":"

\u6211\u4eec\u7684Starry\u662f\u57fa\u4e8eArceOS\u751f\u6210\u7684\uff0c\u56e0\u6b64\u9700\u8981\u7b80\u5355\u4ecb\u7ecd\u4e00\u4e0bArceOS\u5b9e\u73b0\u7684\u5185\u5bb9\u3002

ArceOS\u91c7\u7528\u6a21\u5757\u5316\u7ec4\u4ef6\u5316\u7684\u8bbe\u8ba1\u601d\u7ef4\uff0c\u901a\u8fc7\u4f7f\u7528\u5185\u6838\u7ec4\u4ef6 + \u7ec4\u4ef6\u5316\u7684OS\u6846\u67b6 \u6765\u5f97\u5230 \u4e0d\u540c\u5f62\u6001\u7684OS kernel\u3002

  • \u63d0\u4f9b\u4e86\u4e00\u5957\u7ec4\u4ef6\u5316\u7684\u64cd\u4f5c\u7cfb\u7edf\u6846\u67b6
  • \u63d0\u4f9b\u5404\u79cd\u5185\u6838\u7ec4\u4ef6\u7684\u5b9e\u73b0\uff0c\u5404\u79cd\u5185\u6838\u7ec4\u4ef6\u53ef\u5728\u6ca1\u6709OS kernel\u7684\u60c5\u51b5\u4e0b\u72ec\u7acb\u8fd0\u884c
  • \u5982filesystem, network stack\u7b49\u5185\u6838\u7ec4\u4ef6\u53ef\u4ee5\u5728\u88f8\u673a\u6216\u7528\u6237\u6001\u4ee5\u5e93\u7684\u5f62\u5f0f\u8fd0\u884c
  • \u5404\u79cd\u8bbe\u5907\u9a71\u52a8\u7b49\u5185\u6838\u7ec4\u4ef6\u53ef\u4ee5\u5728\u88f8\u673a\u4e0a\u8fd0\u884c
  • \u7406\u60f3\u60c5\u51b5\u4e0b\u53ef\u4ee5\u901a\u8fc7\u9009\u62e9\u7ec4\u4ef6\u6784\u6210unikernel/\u5b8f\u5185\u6838/\u5fae\u5185\u6838
  • \u5b9e\u9645\u4e0a\u5728\u6211\u4eec\u5f00\u59cb\u5b9e\u9a8c\u65f6\u5b83\u8fd8\u53ea\u652f\u6301unikernel
  • \u53ea\u8fd0\u884c\u4e00\u4e2a\u7528\u6237\u7a0b\u5e8f
  • \u7528\u6237\u7a0b\u5e8f\u4e0e\u5185\u6838\u94fe\u63a5\u4e3a\u540c\u4e00\u955c\u50cf
  • \u4e0d\u533a\u5206\u5730\u5740\u7a7a\u95f4\u4e0e\u7279\u6743\u7ea7
  • \u5b89\u5168\u6027\u7531\u5e95\u5c42 hypervisor \u4fdd\u8bc1

\u5f53\u524dArceOS\u662f\u9762\u5411Unikernel\u8bbe\u8ba1\u7684\uff0c\u800c\u6211\u4eec\u7684Starry\u4fbf\u662f\u5176\u5b8f\u5185\u6838\u5316\u7684\u4e00\u6b21\u5c1d\u8bd5\u4e0e\u6210\u679c\u3002

"},{"location":"%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/Starry%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E/","title":"Starry\u7ed3\u6784\u8bf4\u660e","text":""},{"location":"%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/Starry%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E/#starry","title":"Starry\u7ed3\u6784\u8bf4\u660e","text":"
  • crates\uff1a\u4e0eOS\u8bbe\u8ba1\u65e0\u5173\u7684\u516c\u5171\u7ec4\u4ef6
  • modules\uff1a\u4e0eOS\u8bbe\u8ba1\u66f4\u52a0\u8026\u5408\u7684\u7ec4\u4ef6\uff0c\u5404\u4e2a\u6a21\u5757\u529f\u80fd\u7b80\u8981\u4ecb\u7ecd\u5982\u4e0b\uff1a
  • axalloc\uff1a\u5b9e\u73b0\u5168\u5c40\u5206\u914d\u5668
  • axconfig\uff1a\u5b9a\u4e49\u5185\u6838\u53c2\u6570
  • axdisplay\uff1a\u7b80\u5355\u7684\u56fe\u5f62\u5316\u5b9e\u73b0
  • axdriver\uff1a\u8bbe\u5907\u9a71\u52a8\u7ba1\u7406
  • axfs\uff1a\u6587\u4ef6\u7cfb\u7edf\u652f\u6301
  • axhal\uff1a\u786c\u4ef6\u62bd\u8c61\u5c42\uff0c\u5b9a\u4e49\u4e86\u4e00\u7cfb\u5217\u7684\u5e73\u53f0API\uff0c\u5982trap\u5165\u53e3\u7b49
  • axlog\uff1alog\u8f93\u51fa\u5c42
  • axnet\uff1a\u7f51\u7edc\u6a21\u5757
  • axruntime\uff1a\u8fd0\u884c\u5e93\uff0c\u5b9a\u4e49\u4e86\u5185\u6838\u7684\u542f\u52a8\u903b\u8f91
  • axsync\uff1a\u5b9e\u73b0\u540c\u6b65\u6a21\u5757
  • axmem\uff1a\u5730\u5740\u7a7a\u95f4\u6a21\u5757
  • axprocess\uff1a\u8fdb\u7a0b\u6a21\u5757\uff0c\u4e5f\u5b9e\u73b0\u4e86\u52a8\u6001\u52a0\u8f7d
  • axsignal\uff1a\u4fe1\u53f7\u6a21\u5757
  • axtask\uff1a\u5b9a\u4e49\u4e86\u4efb\u52a1\u4e0e\u8c03\u5ea6\u5e8f\u5217\u7684\u64cd\u4f5c

  • apps\uff1aunikernel\u67b6\u6784\u4e0b\u7684\u7528\u6237\u7a0b\u5e8f\uff0c\u7ee7\u627f\u539f\u6709ArceOS

  • ulib\uff1a\u7528\u6237\u5e93\uff0c\u7ee7\u627f\u539f\u6709ArceOS\uff0c\u5e76\u6dfb\u52a0\u4e86starry_libax\u90e8\u5206\u4f5c\u4e3aLinux\u517c\u5bb9\u5c42\u3002

  • \u4e3a\u4e86\u5b9e\u73b0\u5b8f\u5185\u6838\u67b6\u6784\u4f53\u7cfb\uff0c\u9700\u8981\u5bf9\u539f\u6709Arceos\u7684\u90e8\u5206\u6838\u5fc3\u6a21\u5757\uff08\u5982axtask\uff09\u8fdb\u884c\u4fee\u6539\u3002\u4e3a\u4e86\u9632\u6b62\u5408\u5e76\u65f6\u51b2\u7a81\u8fc7\u591a\uff0c\u56e0\u6b64\u5728\u5bf9\u5e94\u6a21\u5757\u4e0b\u5efa\u7acbmonolithic*\u4e3a\u524d\u7f00\u7684\u6587\u4ef6\u5939\uff0c\u5b58\u653e\u4e3a\u5b8f\u5185\u6838\u67b6\u6784\u5b9e\u73b0\u7684\u5185\u5bb9\u3002\u540c\u65f6\u4f7f\u7528\u6761\u4ef6\u7f16\u8bd1\u6765\u9009\u62e9\u662f\u5b8f\u5185\u6838\u67b6\u6784\u8fd8\u662funikernel\u67b6\u6784\u3002

  • \u4e3a\u4e86\u5b9e\u73b0linux APP\u517c\u5bb9\uff0c\u9700\u8981\u5b9e\u73b0\u4e00\u7cfb\u5217\u9762\u5411linux\u7684\u7cfb\u7edf\u8c03\u7528\u3002\u6211\u4eec\u5c06\u7cfb\u7edf\u8c03\u7528\u7684\u5177\u4f53\u5b9e\u73b0\u90e8\u5206\u653e\u5728starry_libax\u90e8\u5206\uff0c\u5373\u4ee5\u7528\u6237\u5e93\u7684\u5f62\u5f0f\u5f62\u6210\u4e00\u4e2alinux\u517c\u5bb9\u5c42\u3002\u901a\u8fc7\u8c03\u7528\u4e0a\u8ff0\u6a21\u5757\u63d0\u4f9b\u7684\u4e00\u7cfb\u5217\u63a5\u53e3\uff0c\u5b9e\u73b0\u5bf9\u5e94\u7684linux \u7cfb\u7edf\u8c03\u7528\uff0c\u5e76\u66b4\u9732\u7ed9\u5916\u754c\u3002\u8fd9\u4e2a\u7cfb\u7edf\u517c\u5bb9\u5c42\u4e0e\u539f\u6709\u7684libax\u8fdb\u884c\u5bf9\u5e94\uff0c\u5206\u522b\u63d0\u4f9b\u4e0d\u540c\u7684\u63a5\u53e3\u4e0e\u670d\u52a1\u3002

  • \u6a21\u5757\u90e8\u5206\u653e\u7f6e\u53ef\u4ee5\u4e3a\u5b8f\u5185\u6838\u4e0eunikernel\u5c3d\u53ef\u80fd\u5171\u4eab\u7684\u5185\u5bb9\uff0c\u901a\u8fc7\u6761\u4ef6\u7f16\u8bd1\u7b49\u65b9\u5f0f\u505a\u5230\u5c3d\u53ef\u80fd\u5730\u4e3a\u4e0d\u540c\u67b6\u6784\u4e0b\u7684\u517c\u5bb9\u5c42\u6240\u8c03\u7528\u3002

"},{"location":"%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/Starry%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E/#_1","title":"\u7ed3\u6784\u56fe\u5bf9\u6bd4","text":"

\u539f\u5148Arceos\u7ed3\u6784\u56fe\uff1a

\u91cd\u6784\u540eStarryOS\u67b6\u6784\u56fe\uff1a

Starry\u7684\u6a21\u5757\u4f9d\u8d56\u56fe\u5982\u4e0b\uff1a

"},{"location":"%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/Starry%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E/#_2","title":"\u7ed3\u6784\u4f18\u52bf","text":"
  1. \u7528\u76f8\u540c\u7684\u4ee3\u7801\u7ec4\u4ef6\uff0c\u5229\u7528\u6761\u4ef6\u7f16\u8bd1\u7b49\u65b9\u5f0f\u53ef\u4ee5\u7ec4\u5efa\u51fa\u4e0d\u540c\u67b6\u6784\u7684OS\u5185\u6838\uff0c\u4ece\u800c\u53ef\u4ee5\u8fbe\u5230\u4f7f\u7528\u4e0d\u540c\u7684\u542f\u52a8\u53c2\u6570\u6765\u542f\u52a8\u4e0d\u540c\u67b6\u6784\u7684\u5185\u6838\uff0c\u5927\u5927\u63d0\u9ad8\u5185\u6838\u7684\u6cdb\u7528\u6027\u3002
  2. \u5728\u5229\u7528unikernel\u53ef\u63d2\u62d4\u7684\u7279\u6027\u7684\u57fa\u7840\u4e0a\uff0c\u53ef\u4ee5\u4f7f\u5f97\u5b9e\u73b0\u67d0\u4e00\u4e2a\u529f\u80fd\u7684crate\u548c\u6574\u4f53OS\u8fdb\u4e00\u6b65\u89e3\u8026\uff0c\u4ece\u800c\u5229\u4e8e\u66f4\u65b0\u6362\u4ee3\u3002
  3. \u89e3\u8026\u7684\u7279\u6027\u5229\u4e8e\u5f00\u53d1\u6a21\u5f0f\u7684\u5206\u5de5\uff0c\u4e0d\u540c\u5f00\u53d1\u4eba\u5458\u53ef\u4ee5\u8d1f\u8d23\u4e0d\u540c\u7684module\u6216\u8005crate\u5185\u5bb9\uff0c\u53ea\u8981\u5b9e\u73b0\u4e86\u5bf9\u5e94\u7684\u63a5\u53e3\u4fbf\u53ef\u4ee5\u8f83\u597d\u5730\u9002\u914d\u672c\u5185\u6838\uff0c\u4ece\u800c\u65b9\u4fbf\u5176\u4ed6\u5f00\u53d1\u4eba\u5458\u53c2\u4e0e\u5176\u4e2d\u4e0d\u65ad\u5b8c\u5584\u3002
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E6%A8%A1%E5%9D%97-axtask/","title":"\u4efb\u52a1\u8c03\u5ea6\u6a21\u5757-axtask","text":"

\u4efb\u52a1\u8c03\u5ea6\u662f\u5185\u6838\u5b9e\u73b0\u8fc7\u7a0b\u4e2d\u975e\u5e38\u91cd\u8981\u7684\u73af\u8282\u3002\u4e3a\u4e86\u4fdd\u8bc1\u548c\u4e0a\u6e38arceos\u4ed3\u5e93\u8f83\u597d\u7684\u8fdb\u884c\u5339\u914d\uff0c\u56e0\u6b64starry\u7684\u4efb\u52a1\u8c03\u5ea6\u673a\u5236\u57fa\u672c\u53c2\u7167\u4e86arceos\u7684\u8c03\u5ea6\u673a\u5236\uff0c\u5e76\u5728\u6b64\u57fa\u7840\u4e0a\u8fdb\u884c\u4e86\u9002\u914d\u5b8f\u5185\u6838\u7684\u8c03\u6574\u3002

\u4e3a\u4e86\u5b9e\u73b0\u5b8f\u5185\u6838\u67b6\u6784\u4f53\u7cfb\uff0c\u9700\u8981\u5bf9\u539f\u6709Arceos\u7684\u90e8\u5206\u6838\u5fc3\u6a21\u5757\uff08\u5982axtask\uff09\u8fdb\u884c\u4fee\u6539\u3002\u4e3a\u4e86\u9632\u6b62\u5408\u5e76\u65f6\u51b2\u7a81\u8fc7\u591a\uff0c\u56e0\u6b64\u5728\u5bf9\u5e94\u6a21\u5757\u4e0b\u5efa\u7acbmonolithic_task\u6587\u4ef6\u5939\uff0c\u5b58\u653e\u4e3a\u5b8f\u5185\u6838\u67b6\u6784\u5b9e\u73b0\u7684\u5185\u5bb9\u3002\u540c\u65f6\u4f7f\u7528\u6761\u4ef6\u7f16\u8bd1\u6765\u9009\u62e9\u662f\u5b8f\u5185\u6838\u67b6\u6784\u8fd8\u662funikernel\u67b6\u6784\u3002

\u4ee5\u4e0b\u4e3aStarry\u5b9e\u73b0\u7684\u4efb\u52a1\u8c03\u5ea6\u6a21\u5757\u7684\u76f8\u5173\u529f\u80fd\u5212\u5206\uff1a

\u5bf9\u529f\u80fd\u7684\u989d\u5916\u8865\u5145\u8bf4\u660e\u5982\u4e0b\uff1a

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E6%A8%A1%E5%9D%97-axtask/#task","title":"task","text":"

\u4efb\u52a1\u5355\u5143\u662f\u5185\u6838\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u975e\u5e38\u91cd\u8981\u7684\u7ec4\u6210\u90e8\u5206\uff0c\u4efb\u52a1\u8c03\u5ea6\u6a21\u5757\u7684\u7ec4\u6210\u5982\u4e0b\uff1a

pub struct TaskInner {\nid: TaskId,\nname: String,\nis_idle: bool,\nis_init: bool,\n\nentry: Option<*mut dyn FnOnce()>,\nstate: AtomicU8,\n\nin_wait_queue: AtomicBool,\n#[cfg(feature = \"irq\")]\nin_timer_list: AtomicBool,\n\n#[cfg(feature = \"preempt\")]\nneed_resched: AtomicBool,\n#[cfg(feature = \"preempt\")]\npub preempt_disable_count: AtomicUsize,\n\nexit_code: AtomicI32,\nwait_for_exit: WaitQueue,\n\n#[cfg(feature = \"monolithic\")]\nkstack: Option<TaskStack>,\n\nctx: UnsafeCell<TaskContext>,\n\n#[cfg(feature = \"monolithic\")]\n// \u5bf9\u5e94\u8fdb\u7a0bID\nprocess_id: AtomicU64,\n\n#[cfg(feature = \"monolithic\")]\n/// \u662f\u5426\u662f\u6240\u5c5e\u8fdb\u7a0b\u4e0b\u7684\u4e3b\u7ebf\u7a0b\nis_leader: AtomicBool,\n\n#[cfg(feature = \"monolithic\")]\n// \u6240\u5c5e\u9875\u8868ID\uff0c\u5728\u5b8f\u5185\u6838\u4e0b\u9ed8\u8ba4\u4f1a\u5f00\u542f\u5206\u9875\uff0c\u662f\u53ea\u8bfb\u7684\u6240\u4ee5\u4e0d\u7528\u539f\u5b50\u91cf\npage_table_token: usize,\n\n#[cfg(feature = \"monolithic\")]\n/// \u521d\u59cb\u5316\u7684trap\u4e0a\u4e0b\u6587\npub trap_frame: UnsafeCell<TrapFrame>,\n\n// \u65f6\u95f4\u7edf\u8ba1\n#[cfg(feature = \"monolithic\")]\ntime: UnsafeCell<TimeStat>,\n\n#[allow(unused)]\n#[cfg(feature = \"monolithic\")]\n/// \u5b50\u7ebf\u7a0b\u521d\u59cb\u5316\u7684\u65f6\u5019\uff0c\u5b58\u653etid\u7684\u5730\u5740\nset_child_tid: AtomicU64,\n\n#[cfg(feature = \"monolithic\")]\n/// \u5b50\u7ebf\u7a0b\u521d\u59cb\u5316\u65f6\uff0c\u5c06\u8fd9\u4e2a\u5730\u5740\u6e05\u7a7a\uff1b\u5b50\u7ebf\u7a0b\u9000\u51fa\u65f6\uff0c\u89e6\u53d1\u8fd9\u91cc\u7684 futex\u3002\n/// \u5728\u521b\u5efa\u65f6\u5305\u542b CLONE_CHILD_SETTID \u65f6\u624d\u975e0\uff0c\u4f46\u53ef\u4ee5\u88ab sys_set_tid_address \u4fee\u6539\nclear_child_tid: AtomicU64,\n\n#[cfg(feature = \"monolithic\")]\n/// \u9000\u51fa\u65f6\u662f\u5426\u5411\u7236\u8fdb\u7a0b\u53d1\u9001SIG_CHILD\npub send_sigchld_when_exit: Bool,\n}\n

\u53ef\u4ee5\u770b\u51fa\uff0c\u4efb\u52a1\u7ed3\u6784\u4f53\u4e2d\u7684\u67d0\u4e9b\u5b57\u6bb5\u5305\u542b\u7740\u591a\u6838\u5b89\u5168\u6027\uff0c\u56e0\u4e3a\u867d\u7136\u4e00\u4e2a\u4efb\u52a1\u4ec5\u4f1a\u5728\u4e00\u4e2aCPU\u6838\u4e0a\u8fd0\u884c\uff0c\u4f46\u662f\u4e0d\u540cCPU\u53ef\u80fd\u4f1a\u540c\u65f6\u8bbf\u95ee\u540c\u4e00\u4e2a\u4efb\u52a1\u7684\u67d0\u4e00\u4e2a\u5b57\u6bb5\uff0c\u5bfc\u81f4\u51fa\u73b0\u591a\u6838\u51b2\u7a81\uff0c\u56e0\u6b64\u9700\u8981\u4e3a\u5bf9\u5e94\u5b57\u6bb5\u52a0\u4e0a\u539f\u5b50\u6027\u3002

\u53e6\u5916\uff0ctask\u5b57\u6bb5\u4e5f\u63d0\u4f9b\u4e86\u67d0\u4e00\u4e2a\u4efb\u52a1\u7b2c\u4e00\u6b21\u6267\u884c\u7684\u5b9e\u73b0\u3002\u5b83\u9700\u8981\u6839\u636e\u662f\u5426\u4e3a\u5b8f\u5185\u6838\u67b6\u6784\u5206\u522b\u8fdb\u884c\u5b9e\u73b0\u3002

  • Arceos\u5b9e\u73b0\uff1a\u5728Arceos\u4e0b\uff0c\u4ee3\u7801\u59cb\u7ec8\u5728\u5185\u6838\u6001\u4e0b\u8fd0\u884c\uff0c\u6240\u4ee5\u53ef\u4ee5\u76f4\u63a5\u8df3\u8f6c\u5230\u4efb\u52a1\u5165\u53e3\u51fd\u6570\u6267\u884c\u3002\u56e0\u6b64\u4f1a\u628a\u5165\u53e3\u51fd\u6570\u7684\u5730\u5740\u76f4\u63a5\u8bb0\u5f55\u5728task\u7684entry\u5b57\u6bb5\u4e0a\uff0c\u5e76\u4e14\u5728\u7b2c\u4e00\u6b21\u6267\u884c\u4efb\u52a1\u65f6\u76f4\u63a5\u8df3\u8f6c\u5230entry\u5b57\u6bb5\u7684\u5730\u5740\u5373\u53ef\u3002
  • Starry\u5b9e\u73b0\uff1a\u5728Starry\u4e0b\uff0c\u4efb\u52a1\u4f1a\u8fdb\u5165\u5230\u7528\u6237\u6001\u8fd0\u884c\uff0c\u6b64\u65f6\u9700\u8981\u628a\u4efb\u52a1\u521d\u59cb\u5316\u7684trap\u4e0a\u4e0b\u6587\u653e\u7f6e\u5230\u5185\u6838\u6808\u4e0a\uff0c\u5e76\u4e14\u8fdb\u884csret\u8df3\u8f6c\u3002
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E6%A8%A1%E5%9D%97-axtask/#run_queue","title":"run_queue","text":"

\u4efb\u52a1\u8c03\u5ea6\u662f\u4efb\u52a1\u6a21\u5757\u5b9e\u73b0\u7684\u91cd\u70b9\u3002\u63a5\u4e0b\u6765\u7b80\u8981\u4ecb\u7ecd\u4ee5\u4e0bstarry\u7684\u4efb\u52a1\u542f\u52a8\u548c\u8c03\u5ea6\u6d41\u7a0b\u3002

\u5f53\u524d\u4efb\u52a1\u8c03\u5ea6\u673a\u5236\u662ffifo\u961f\u5217\u6cd5\uff0c\u542f\u52a8\u548c\u8c03\u5ea6\u65b9\u5f0f\u5982\u4e0b\uff1a

  • \u5355\u6838\u60c5\u51b5

\u5bf9\u5e94\u4ee3\u7801\u5728modules/axtask/src/monolithic_task/run_queue.rs/init\u51fd\u6570\u4e2d\uff1a

pub(crate) fn init() {\nconst IDLE_TASK_STACK_SIZE: usize = 0x20000;\nlet idle_task = TaskInner::new(\n|| crate::run_idle(),\n\"idle\".into(),\nIDLE_TASK_STACK_SIZE,\nKERNEL_PROCESS_ID,\n0,\nfalse,\n);\nIDLE_TASK.with_current(|i: &mut LazyInit<Arc<scheduler::FifoTask<TaskInner>>>| {\ni.init_by(idle_task.clone())\n});\n\nlet main_task = TaskInner::new_init(\"main\".into());\nmain_task.set_state(TaskState::Running);\n\nRUN_QUEUE.init_by(AxRunQueue::new());\nunsafe { CurrentTask::init_current(main_task) }\n}\n

\u5171\u5305\u542b\u4e09\u4e2a\u4efb\u52a1\uff1a

  • idle_task\uff1a\u62e5\u6709\u72ec\u7acb\u7684trap\u4e0a\u4e0b\u6587\u548c\u4efb\u52a1\u4e0a\u4e0b\u6587\uff0c\u4efb\u52a1\u4e0a\u4e0b\u6587\u6307\u5411\u7684\u5165\u53e3\u662frun_idle\u51fd\u6570\u3002

  • gc_task\uff1a\u5728\u6267\u884cAxRunQueue::new()\u51fd\u6570\u65f6\u751f\u6210\uff0c\u8d1f\u8d23\u56de\u6536\u5df2\u7ecf\u9000\u51fa\u7684\u4efb\u52a1\u3002

  • main_task\uff1a\u5185\u6838\u8fd0\u884c\u65f6\u6267\u884c\u7684\u4efb\u52a1\uff0c\u5b83\u7684\u4efb\u52a1\u4e0a\u4e0b\u6587\u4e3a\u7a7a\uff0c\u5728\u88ab\u5207\u6362\u65f6\u4f1a\u628a\u5f53\u524d\u7684ra\u7b49\u4fe1\u606f\u5199\u5165\u4efb\u52a1\u4e0a\u4e0b\u6587\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u6062\u590d\u65f6\u7ee7\u7eed\u6267\u884c\u5185\u6838\u76f8\u5173\u4ee3\u7801\u3002

\u5f53\u6267\u884c\u5b8cinit\u51fd\u6570\u4e4b\u540e\uff0cCPU\u6307\u5411main_task\uff0cpc\u4e0d\u53d8\uff0c\u7ee7\u7eed\u6267\u884c\u5f53\u524d\u4ee3\u7801\uff0c\u76f4\u5230\u6765\u5230modules/axruntime/src/lib.rs/rust_main\u51fd\u6570\u7684unsafe{main();}\u5165\u53e3\uff0c\u4ece\u800c\u8df3\u8f6c\u5230Arceos\u6307\u5b9a\u7684\u7528\u6237\u7a0b\u5e8f\uff08\u6ce8\u610f\uff1a\u867d\u7136\u662f\u7528\u6237\u7a0b\u5e8f\uff0c\u4f46\u662f\u8fd0\u884c\u5728arceos\u6846\u67b6\u4e0b\uff0c\u8fd8\u5904\u4e8e\u5185\u6838\u6001\uff09\uff0c\u5f00\u59cb\u52a0\u8f7d\u6d4b\u4f8b\u3002\u9ed8\u8ba4make run\u4f1a\u8fd0\u884capps/syscall/busybox\u7a0b\u5e8f\u3002\u82e5\u6d4b\u4f8b\u7a0b\u5e8f\u4f1a\u901a\u8fc7clone\u7b49\u65b9\u5f0f\u751f\u6210\u65b0\u7684\u4efb\u52a1\uff0c\u90a3\u4e48\u65b0\u4efb\u52a1\u4f1a\u88ab\u52a0\u5165\u5230\u4efb\u52a1\u8c03\u5ea6\u961f\u5217\u7b49\u5f85\u88ab\u8c03\u5ea6\u3002

  • \u82e5\u8c03\u5ea6\u961f\u5217\u4e2d\u8fd8\u6709\u4efb\u52a1\u7b49\u5f85\u88ab\u8c03\u5ea6\uff0c\u90a3\u4e48\u5c31\u4f1a\u5207\u6362\u5230\u5bf9\u5e94\u4efb\u52a1\u3002\u6b64\u65f6\u82e5\u8c03\u5ea6\u7684\u4efb\u52a1\u662fgc\uff0c\u5219gc\u4f1a\u68c0\u6d4b\u662f\u5426\u8fd8\u6709\u4efb\u52a1\u9000\u51fa\u3002\u82e5\u6709\u4efb\u52a1\u5df2\u7ecf\u9000\u51fa\u7b49\u5f85\u56de\u6536\uff0c\u5219gc\u4f1a\u56de\u6536\u8fd9\u4e9b\u4efb\u52a1\u3002\u82e5\u6ca1\u6709\u5219\u963b\u585egc\u672c\u8eab\uff0c\u5207\u6362\u5230\u5176\u4ed6\u4efb\u52a1\u3002

    gc\u7684\u5b9e\u73b0\u65b9\u5f0f\u5982\u4e0b\uff1a

    fn gc_entry() {\nloop {\n// Drop all exited tasks and recycle resources.\nwhile !EXITED_TASKS.lock().is_empty() {\n// Do not do the slow drops in the critical section.\nlet task = EXITED_TASKS.lock().pop_front();\nif let Some(task) = task {\n// If the task reference is not taken after `spawn()`, it will be\n// dropped here. Otherwise, it will be dropped after the reference\n// is dropped (usually by `join()`).\n// info!(\"drop task: {}\", task.id().as_u64());\ndrop(task);\n}\n}\nWAIT_FOR_EXIT.wait();\n}\n}\n
  • \u82e5\u8c03\u5ea6\u961f\u5217\u4e2d\u6ca1\u6709\u4e0b\u4e00\u4e2a\u4efb\u52a1\u65f6\uff0c\u5c31\u4f1a\u5207\u6362\u5230idle_task\uff0c\u6b64\u65f6\u4f1a\u6267\u884crun_idle\u51fd\u6570\uff0c\u5373\u4e0d\u65ad\u6267\u884cyield_task\u51fd\u6570\uff0c\u76f4\u5230\u6709\u65b0\u7684\u4efb\u52a1\u52a0\u5165\u8c03\u5ea6\u961f\u5217\uff0c\u5219\u5207\u6362\u5230\u5bf9\u5e94\u4efb\u52a1\u3002

    run_idle\u51fd\u6570\u5b9e\u73b0\u65b9\u5f0f\u5982\u4e0b\uff1a

    pub fn run_idle() -> ! {\nloop {\nyield_now();\ndebug!(\"idle task: waiting for IRQs...\");\n#[cfg(feature = \"irq\")]\naxhal::arch::wait_for_irqs();\n}\n}\n
  • \u591a\u6838\u542f\u52a8

\u6211\u4eec\u53ea\u8003\u8651\u4efb\u52a1\u8c03\u5ea6\u76f8\u5173\uff0c\u5219\u591a\u6838\u60c5\u51b5\u4e0b\uff0c\u5176\u4ed6\u6838\u521d\u59cb\u5316\u7684\u51fd\u6570\u5728modules/axtask/src/monolithic_task/run_queue.rs/init_secondary\u4e2d\uff0c\u4f1a\u65b0\u5efa\u4e00\u4e2aidle_task\uff0c\u4f46\u662f\u5b83\u7684\u529f\u80fd\u7c7b\u4f3c\u4e8e\u5355\u6838\u542f\u52a8\u4e0b\u7684main_task\uff0c\u5373\u521d\u59cb\u5316\u65f6\u6ca1\u6709\u4efb\u52a1\u4e0a\u4e0b\u6587\uff0c\u4f46\u662f\u53ef\u4ee5\u5728\u88ab\u5207\u6362\u4e4b\u540e\u4fdd\u7559\u5185\u6838\u7684\u4efb\u52a1\u6267\u884c\u6d41\u3002

\u521d\u59cb\u5316\u5b8c\u6bd5\u4e4b\u540e\uff0c\u6bcf\u4e00\u4e2a\u975e\u4e3b\u6838\u6307\u5411\u4e00\u4e2aidle_task\uff0c\u6b64\u65f6\u4ed6\u4eec\u4f1a\u7ee7\u7eed\u6267\u884c\u5185\u6838\u4e2d\u7684\u521d\u59cb\u5316\u4ee3\u7801\uff0c\u6700\u540e\u5728modules/axruntime/src/mp.rs\u7684rust_main_secondary\u51fd\u6570\u4e2d\u6267\u884crun_idle\u51fd\u6570\uff0c\u5373\u4e0d\u65ad\u5730yield\u81ea\u5df1\uff0c\u76f4\u5230\u6709\u65b0\u7684\u4efb\u52a1\u52a0\u5165\u8c03\u5ea6\u961f\u5217\u3002

\u5f53\u6d4b\u4f8b\u5bf9\u5e94\u7684\u7528\u6237\u6001\u4efb\u52a1\u6267\u884cclone\u7cfb\u7edf\u8c03\u7528\uff0c\u751f\u6210\u65b0\u7684\u4efb\u52a1\u52a0\u5165\u5230\u8c03\u5ea6\u961f\u5217\u65f6\uff0c\u6b64\u65f6\u5c31\u4f1a\u968f\u673a\u5206\u914d\u4e00\u4e2aCPU\u6838\u83b7\u5f97\u8be5\u4efb\u52a1\u5e76\u4e14\u8fdb\u884c\u6267\u884c\u3002\u8fd9\u5c31\u662f\u591a\u6838\u542f\u52a8\u7684\u539f\u7406\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E6%A8%A1%E5%9D%97-axtask/#stat","title":"stat","text":"

stat\u5b9e\u73b0\u4e86\u4efb\u52a1\u7684\u65f6\u95f4\u8bb0\u5f55\u529f\u80fd\u548c\u8ba1\u65f6\u5668\u529f\u80fd\u3002

\u8bb0\u5f55\u4efb\u52a1\u8fd0\u884c\u65f6\u95f4\u662f\u901a\u8fc7\u8ba1\u7b97\u548c\u66f4\u65b0\u65f6\u95f4\u6233\u8fdb\u884c\u7684\uff0c\u6bcf\u4e00\u4e2astat\u7ed3\u6784\u4f53\u90fd\u62e5\u6709\u5982\u4e0b\u7ed3\u6784\uff1a

/// \u7528\u6237\u6001\u7ecf\u8fc7\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u4e3a\u7eb3\u79d2\nutime_ns: usize,\n/// \u5185\u6838\u6001\u7ecf\u8fc7\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u4e3a\u7eb3\u79d2\nstime_ns: usize,\n/// \u8fdb\u5165\u7528\u6237\u6001\u65f6\u6807\u8bb0\u5f53\u524d\u65f6\u95f4\u6233\uff0c\u7528\u4e8e\u7edf\u8ba1\u7528\u6237\u6001\u65f6\u95f4\nuser_tick: usize,\n/// \u8fdb\u5165\u5185\u6838\u6001\u65f6\u6807\u8bb0\u5f53\u524d\u65f6\u95f4\u6233\uff0c\u7528\u4e8e\u7edf\u8ba1\u5185\u6838\u6001\u65f6\u95f4\nkernel_tick: usize,\n

\u66f4\u65b0\u65f6\u95f4\u6233\u7684\u65f6\u95f4\u70b9\u5171\u6709\u56db\u4e2a\uff1a

  • \u4ece\u7528\u6237\u6001\u8fdb\u5165\u5185\u6838\u6001
  • \u4ece\u5185\u6838\u6001\u8fdb\u5165\u7528\u6237\u6001
  • \u5207\u6362\u5230\u672c\u4efb\u52a1
  • \u672c\u4efb\u52a1\u88ab\u5207\u6362\u8d70

\u76f8\u5173\u66f4\u65b0\u8fd0\u884c\u65f6\u95f4\u7684\u4ee3\u7801\u5982\u4e0b\uff1a

/// \u4ece\u7528\u6237\u6001\u8fdb\u5165\u5185\u6838\u6001\uff0c\u8bb0\u5f55\u5f53\u524d\u65f6\u95f4\u6233\uff0c\u7edf\u8ba1\u7528\u6237\u6001\u65f6\u95f4\npub fn into_kernel_mode(&mut self, tid: isize) {\nlet now_time_ns = current_time_nanos() as usize;\nlet delta = now_time_ns - self.user_tick;\nself.utime_ns += delta;\nself.kernel_tick = now_time_ns;\n}\n/// \u4ece\u5185\u6838\u6001\u8fdb\u5165\u7528\u6237\u6001\uff0c\u8bb0\u5f55\u5f53\u524d\u65f6\u95f4\u6233\uff0c\u7edf\u8ba1\u5185\u6838\u6001\u65f6\u95f4\npub fn into_user_mode(&mut self, tid: isize) {\n// \u83b7\u53d6\u5f53\u524d\u65f6\u95f4\uff0c\u5355\u4f4d\u4e3a\u7eb3\u79d2\nlet now_time_ns = current_time_nanos() as usize;\nlet delta = now_time_ns - self.kernel_tick;\nself.stime_ns += delta;\nself.user_tick = now_time_ns;\n}\n/// \u5185\u6838\u6001\u4e0b\uff0c\u5f53\u524d\u4efb\u52a1\u88ab\u5207\u6362\u6389\uff0c\u7edf\u8ba1\u5185\u6838\u6001\u65f6\u95f4\npub fn swtich_from(&mut self, tid: isize) {\n// \u83b7\u53d6\u5f53\u524d\u65f6\u95f4\uff0c\u5355\u4f4d\u4e3a\u7eb3\u79d2\nlet now_time_ns = current_time_nanos() as usize;\nlet delta = now_time_ns - self.kernel_tick;\nself.stime_ns += delta;\n}\n/// \u5185\u6838\u6001\u4e0b\uff0c\u5207\u6362\u5230\u5f53\u524d\u4efb\u52a1\uff0c\u66f4\u65b0\u5185\u6838\u6001\u65f6\u95f4\u6233\npub fn switch_to(&mut self, tid: isize) {\n// \u83b7\u53d6\u5f53\u524d\u65f6\u95f4\uff0c\u5355\u4f4d\u4e3a\u7eb3\u79d2\nlet now_time_ns = current_time_nanos() as usize;\nlet delta = now_time_ns - self.kernel_tick;\n// \u66f4\u65b0\u65f6\u95f4\u6233\uff0c\u65b9\u4fbf\u5f53\u8be5\u4efb\u52a1\u88ab\u5207\u6362\u65f6\u7edf\u8ba1\u5185\u6838\u7ecf\u8fc7\u7684\u65f6\u95f4\nself.kernel_tick = now_time_ns;\n}\n
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E4%BF%A1%E5%8F%B7%E6%A8%A1%E5%9D%97-axsignal/","title":"\u4fe1\u53f7\u6a21\u5757-axsignal","text":"

axsignal\u662fstarry\u7684\u4fe1\u53f7\u6a21\u5757\uff0c\u8d1f\u8d23\u5b9e\u73b0\u8fdb\u7a0b\u95f4\u3001\u4efb\u52a1\u95f4\u7b49\u901a\u4fe1\u673a\u5236\u3002\u5f53\u524d\u5b9e\u73b0\u7684\u539f\u7406\u4e3b\u8981\u501f\u9274\u4e8eLinux\u7684\u4fe1\u53f7\u673a\u5236\u3002\u76f8\u5173\u529f\u80fd\u5212\u5206\u5982\u4e0b\uff1a

\u5176\u4e2d\u5404\u90e8\u5206\u7684\u989d\u5916\u8865\u5145\u8bf4\u660e\u5982\u4e0b\uff1a

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E4%BF%A1%E5%8F%B7%E6%A8%A1%E5%9D%97-axsignal/#action","title":"action","text":"

action.rs\u6307\u5b9a\u4e86\u5904\u7406\u67d0\u4e00\u4fe1\u53f7\u65f6\u7684\u5177\u4f53\u64cd\u4f5c\u65b9\u5f0f\u3002\u64cd\u4f5c\u65b9\u5f0f\u7684\u6307\u5b9a\u662f\u901a\u8fc7\u5b9a\u4e49SigAction\u7ed3\u6784\u4f53\u5b9e\u73b0\u7684\uff0c\u76f8\u5173\u5185\u5bb9\u5982\u4e0b\uff1a

pub struct SigAction {\n/// \u4fe1\u53f7\u5904\u7406\u51fd\u6570\u7684\u5730\u5740\n/// 1. \u5982\u679c\u662f\u4e0a\u8ff0\u7279\u6b8a\u503c SIG_DFL \u6216 SIG_IGN\uff0c\u5219\u6309\u63cf\u8ff0\u5904\u7406\n/// 2. \u82e5flags\u6ca1\u6709\u6307\u5b9aSA_SIGINFO\uff0c\u5219\u51fd\u6570\u539f\u578b\u4e3a fn(sig: SignalNo) -> ()\uff0c\u5bf9\u5e94C\u8bed\u8a00\u539f\u578b\u4e3a void (*sa_handler)(int)\n/// 3. \u82e5flags\u6307\u5b9a\u4e86SA_SIGINFO\uff0c\u5219\u51fd\u6570\u539f\u578b\u4e3a fn(sig: SignalNo, info: &SigInfo, ucontext: &mut UContext) -> ()\uff0c\n/// \u5bf9\u5e94C\u8bed\u8a00\u539f\u578b\u4e3a void (*sa_sigaction)(int, siginfo_t *, void *)\u3002\n///\n/// \u5176\u4e2d\uff0cSigInfo\u548cSignalNo\u7684\u5b9a\u4e49\u89c1siginfo.rs\u548csignal_no.rs\u3002\n/// UContext\u5373\u662f\u5904\u7406\u4fe1\u53f7\u65f6\u5185\u6838\u4fdd\u5b58\u7684\u7528\u6237\u6001\u4e0a\u4e0b\u6587\uff0c\u5b83\u5b58\u50a8\u5728\u7528\u6237\u5730\u5740\u7a7a\u95f4\uff0c\u4f1a\u5728\u8c03\u7528sig_return\u65f6\u88ab\u6062\u590d\uff0c\u5b9a\u4e49\u89c1ucontext.rs\u3002\npub sa_handler: usize,\n/// \u4fe1\u53f7\u5904\u7406\u7684flags\npub sa_flags: SigActionFlags,\n/// \u4fe1\u53f7\u5904\u7406\u7684\u8df3\u677f\u9875\u5730\u5740\uff0c\u5b58\u50a8\u4e86sig_return\u7684\u51fd\u6570\u5904\u7406\u5730\u5740\n/// \u4ec5\u5728SA_RESTORER\u6807\u5fd7\u88ab\u8bbe\u7f6e\u65f6\u6709\u6548\npub restorer: usize,\n/// \u8be5\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u7684\u4fe1\u53f7\u63a9\u7801\npub sa_mask: usize,\n}\n

\u5176\u4e2d\u503c\u5f97\u8bf4\u660e\u7684\u662frestorer\u3002\u60f3\u8981\u4e86\u89e3\u8fd9\u4e2arestorer\u5c31\u9700\u8981\u4e86\u89e3Linux\u89c4\u5b9a\u7684\u4fe1\u53f7\u5904\u7406\u673a\u5236\u6d41\u7a0b\uff1a

\u4e0a\u56fe\u5f15\u7528\u81earCore\u6559\u5b66\u6587\u6863\u4fe1\u53f7 - rCore-Tutorial-Book-v3 3.6.0-alpha.1 \u6587\u6863 (rcore-os.cn)

\u6839\u636e\u4e0a\u56fe\u53ef\u77e5\uff0c\u5f53\u8fdb\u5165\u4fe1\u53f7\u5904\u7406\u9636\u6bb5\u4e4b\u540e\uff0c\u82e5\u6307\u5b9a\u4e86\u4fe1\u53f7\u5904\u7406\u4f8b\u7a0b\uff0c\u90a3\u4e48\u5185\u6838\u4f1a\u8fd4\u56de\u7528\u6237\u6001\uff0c\u8df3\u8f6c\u5230\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u5bf9\u5e94\u5165\u53e3\u8fdb\u884c\u4fe1\u53f7\u5904\u7406\u3002

\u4f20\u7edf\u7684C\u8bed\u8a00\u51fd\u6570\u4e2d\uff0c\u51fd\u6570\u6267\u884c\u7ed3\u675f\u65f6\uff0c\u5185\u6838\u4f1a\u5c06ra\u5bc4\u5b58\u5668\u7684\u503c\u8d4b\u7ed9pc\uff0c\u5373pc\u8df3\u8f6c\u5230ra\u6307\u5b9a\u7684\u5730\u5740\u4e0a\u3002

\u800c\u5bf9\u4e8e\u4fe1\u53f7\u5904\u7406\u51fd\u6570\uff0c\u81ea\u7136\u4e5f\u9700\u8981\u4e00\u4e2a\u8fd4\u56de\u5730\u5740\uff0c\u5373\u6211\u4eec\u521a\u624d\u63d0\u5230\u7684restorer\u5b57\u6bb5\u3002

\u5f53\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u6267\u884c\u5b8c\u6bd5\uff0c\u4f1a\u51fa\u73b0\u4ee5\u4e0b\u4e24\u79cd\u60c5\u51b5\uff1a

  1. \u7528\u6237\u624b\u52a8\u6307\u5b9a\u4e86\u8fd4\u56de\u5730\u5740restorer\uff1a\u6b64\u65f6\u7531\u4e8e\u6211\u4eec\u7684\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u7f16\u8bd1\u4e4b\u540e\uff0c\u4f1a\u5728\u7ed3\u675f\u65f6\u81ea\u52a8\u8df3\u8f6c\u5230ra\u4e0a\uff0c\u56e0\u6b64\u6211\u4eec\u53ea\u9700\u8981\u5728\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u5f00\u59cb\u524d\uff0c\u5c06restorer\u5b57\u6bb5\u8d4b\u7ed9ra\u5bc4\u5b58\u5668\u5373\u53ef\u3002\u4e4b\u540e\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u6267\u884c\u5b8c\u6bd5\u4e4b\u540e\u5c31\u4f1a\u8df3\u8f6c\u5230\u6307\u5b9a\u5730\u5740\u3002
  2. \u7528\u6237\u672a\u624b\u52a8\u8c03\u7528\u8fd4\u56de\u5730\u5740restorer\uff1a\u6b64\u65f6\u5185\u6838\u9700\u8981\u624b\u52a8\u5e2e\u52a9\u7528\u6237\u6267\u884csig_return\u7cfb\u7edf\u8c03\u7528\uff0c\u5176\u529f\u80fd\u662f\u544a\u77e5\u5185\u6838\u4fe1\u53f7\u5df2\u7ecf\u5904\u7406\u5b8c\u6bd5\uff0c\u65b9\u4fbf\u5185\u6838\u6062\u590d\u56e0\u4e3a\u5904\u7406\u4fe1\u53f7\u800c\u88ab\u6253\u65ad\u7684trap\u4e0a\u4e0b\u6587\u3002\u800c\u624b\u52a8\u5904\u7406\u7684\u65b9\u5f0f\u5373\u662f\u5c06restorer\u5b57\u6bb5\u8bbe\u7f6e\u4e3a\u4e00\u4e2a\u975e\u6cd5\u7684\u7279\u6b8a\u5b57\u6bb5\uff1aSIGNAL_RETURN_TRAP\u3002\u5f53\u7528\u6237\u6001\u4e0b\u7684\u4fe1\u53f7\u5904\u7406\u51fd\u6570\u6267\u884c\u5b8c\u6bd5\u65f6\uff0c\u5b83\u4f1a\u81ea\u52a8\u8df3\u8f6c\u5230ra\u5bc4\u5b58\u5668\u6307\u5b9a\u7684\u5730\u5740\uff0c\u5373\u8df3\u8f6c\u5230SIGNAL_RETURN_TRAP\uff0c\u4ece\u800c\u89e6\u53d1InstructionPageFault\u3002\u6b64\u65f6\u5185\u6838\u6355\u83b7\u5230trap\u4e4b\u540e\uff0c\u5c31\u53ef\u4ee5\u6839\u636e\u89e6\u53d1page fault\u7684\u5730\u5740\u5224\u65ad\u662f\u5426\u89e6\u53d1\u4e86sig_return\u3002\u82e5\u662f\uff0c\u5219\u624b\u52a8\u8c03\u7528sig_return\u7cfb\u7edf\u8c03\u7528\u5373\u53ef\u3002

\u56e0\u6b64\uff0c\u901a\u8fc7\u5bf9restorer\u7684\u5408\u7406\u4f7f\u7528\uff0c\u6211\u4eec\u53ef\u4ee5\u6bd4\u8f83\u5de7\u5999\u5730\u5b9e\u73b0\u4fe1\u53f7\u5904\u7406\u7684\u8fd4\u56de\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97-axmem/","title":"\u5185\u5b58\u7ba1\u7406\u6a21\u5757-axmem","text":"

axmem \u6a21\u5757\u4e2d\u63d0\u4f9b\u4e86\u5173\u4e8e\u5730\u5740\u7a7a\u95f4\u3001\u5185\u5b58\u6bb5\u7b49\u7ed3\u6784\u7684\u62bd\u8c61\u3002\u5e76\u8d1f\u8d23\u52a8\u6001\u52a0\u8f7d\u5e94\u7528\u7a0b\u5e8f\u3001\u8fdb\u7a0b\u7684 fork() / spawn()\u3001\u5185\u5b58\u7ba1\u7406\uff08mmap\u3001shmat\uff09\u7b49\u57fa\u672c\u4efb\u52a1\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97-axmem/#memoryset","title":"MemorySet","text":"

MemorySet \u4ee3\u8868\u4e00\u4e2a\u8fdb\u7a0b\u6240\u62e5\u6709\uff08\u6216\u591a\u4e2a\u7ebf\u7a0b\u5171\u6709\uff09\u7684\u5730\u5740\u7a7a\u95f4\u3002\u4ece\u4e00\u4e2a\u7528\u6237\u7a0b\u5e8f\u201c\u751f\u547d\u5468\u671f\u201d\u7684\u89d2\u5ea6\u8003\u8651\u3002\u5185\u6838\u4f7f\u7528MemorySet::map_elf()\u52a0\u8f7d elf \u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\uff0c\u901a\u8fc7 clone()\u3001mmap()\u3001munmap()\u3001add_shared_mem() \u7b49\u51fd\u6570\u6267\u884c\u7531 syscall \u4f20\u9012\u800c\u6765\u7684\u5404\u79cd\u64cd\u4f5c\uff0c\u6700\u7ec8\u5728 drop() \u4e2d\u56de\u6536\u8d44\u6e90\u3002

\u5730\u5740\u7a7a\u95f4\u4e2d\u6700\u4e3a\u6838\u5fc3\u7684\u6570\u636e\u7ed3\u6784\u662f\u9875\u8868\uff08page_table\uff09\u3002\u4f7f\u7528RAII\u601d\u60f3\uff0c\u9875\u8868\uff08PageTable \u7c7b\u578b\uff09\u62e5\u6709\u9875\u8868\u672c\u8eab\u4f7f\u7528\u7684\u7269\u7406\u9875\u3002

\u9664\u9875\u8868\u5916\uff0cowned_mem \u8bb0\u5f55\u4e86\u5728\u901a\u8fc7 mmap \u4ee5\u53ca\u5e94\u7528\u7a0b\u5e8f\u52a0\u8f7d\u65f6\u6240\u83b7\u5f97\u7684\u5168\u90e8\u865a\u62df\u5185\u5b58\u6bb5\u3002private_mem \u548c sttached_mem \u5206\u522b\u8bb0\u5f55\u4e86\u8fdb\u7a0b\u6240\u62e5\u6709\u7684 System V Shared Memory\u3002

\u4ee5\u53ca\uff0cMemorySet \u4f1a\u8bb0\u5f55\u52a0\u8f7d\u81ea ELF \u6587\u4ef6\u7684 entry \u5730\u5740\u3002

/// PageTable + MemoryArea for a process (task)\npub struct MemorySet {\npage_table: PageTable,\nowned_mem: BTreeMap<usize, MapArea>,\n\nprivate_mem: BTreeMap<i32, Arc<SharedMem>>,\nattached_mem: Vec<(VirtAddr, MappingFlags, Arc<SharedMem>)>,\n\npub entry: usize,\n}\n
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97-axmem/#sharedmem","title":"SharedMem","text":"

\u672c\u6570\u636e\u7ed3\u6784\u4ee3\u8868\u7528\u6237\u7a0b\u5e8f\u901a\u8fc7 shmat() syscall \u7533\u8bf7\u7684\u5171\u4eab\u5185\u5b58\u3002\u540c\u6837\u4f7f\u7528 RAII \u601d\u60f3\uff0cSharedMem::pages \u4e2d\u5b58\u653e\u5171\u4eab\u5185\u5b58\u6bb5\u6240\u5b9e\u9645\u5206\u914d\u7684\u7269\u7406\u9875\u3002\u8fd9\u4f7f\u5f97\u5f53\u6211\u4eec drop SharedMem \u65f6\uff0c\u5bf9\u5e94\u7684\u7269\u7406\u5185\u5b58\u4e5f\u4f1a\u81ea\u52a8\u91ca\u653e\u3002 SharedMem::info \u8bb0\u5f55\u4e86\u8be5\u6bb5\u5171\u4eab\u5185\u5b58\u7684\u5c5e\u6027\u4fe1\u606f\u3002

pub struct SharedMem {\npages: GlobalPage,\npub info: SharedMemInfo,\n}\n

\u5bf9\u4e8e\u8fdb\u7a0b\u79c1\u6709\u7684\u5171\u4eab\u5185\u5b58\uff0cSharedMem \u4f1a\u88ab\u653e\u5165\u8fdb\u7a0b\u7684 MemorySet::private_mem \u4e2d\u4fdd\u5b58\u3002\u5bf9\u4e8e\u516c\u5f00\u7684\u8de8\u8fdb\u7a0b\u5171\u4eab\u5185\u5b58\uff0c\u5219\u4f1a\u5b58\u50a8\u5728\u5168\u5c40\u6570\u636e\u7ed3\u6784 SHARED_MEMS \u4e2d\u3002

/// This struct only hold SharedMem that are not IPC_PRIVATE. IPC_PRIVATE SharedMem will be stored\n/// in MemorySet::detached_mem.\n///\n/// This is the only place we can query a SharedMem using its shmid.\n///\n/// It holds an Arc to the SharedMem. If the Arc::strong_count() is 1, SharedMem will be dropped.\npub static SHARED_MEMS: SpinNoIrq<BTreeMap<i32, Arc<SharedMem>>> = SpinNoIrq::new(BTreeMap::new());\npub static KEY_TO_SHMID: SpinNoIrq<BTreeMap<i32, i32>> = SpinNoIrq::new(BTreeMap::new());\n

\u5f53\u8fdb\u7a0b\u201c\u6302\u8f7d\uff08\u6620\u5c04\uff09\u201d\u67d0\u4e00\u5171\u4eab\u5185\u5b58\u6bb5\u65f6\uff0cSharedMem \u4e5f\u4f1a\u88ab\u52a0\u5165 MemorySet::sttached_mem \u4e2d\uff0c\u4fbf\u4e8e\u6267\u884c\u8fdb\u7a0b\u7684\u5176\u4ed6\u64cd\u4f5c\u65f6\u8bbf\u95ee\u3002\u4f7f\u7528 Arc \u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u5f97\u5230\u201c\u4e00\u6bb5\u5171\u4eab\u5185\u5b58\u88ab\u591a\u5c11\u4e2a\u8fdb\u7a0b\u52a0\u8f7d\u4e86\u201d\u7684\u4fe1\u606f\uff0c\u4ee5\u4fbf\u53ca\u65f6\u56de\u6536\u5185\u5b58\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97-axmem/#maparea","title":"MapArea","text":"

MapArea \u4ee3\u8868\u4e00\u6bb5\u865a\u62df\u5185\u5b58\u3002\u5728\u8fd9\u4e2a\u6570\u636e\u7ed3\u6784\u4e2d\u9700\u8981\u8bb0\u5f55\u865a\u62df\u5185\u5b58\u7684\u8d77\u59cb\u5730\u5740\u3001\u5c5e\u6027\u4fe1\u606f\u3001\u5bf9\u5e94\u7684\u7269\u7406\u9875\u4e0e\u6587\u4ef6\u540e\u7aef\u3002

pub struct MapArea {\npub pages: Vec<Option<PhysPage>>,\n/// \u8d77\u59cb\u865a\u62df\u5730\u5740\npub vaddr: VirtAddr,\npub flags: MappingFlags,\npub backend: Option<MemBackend>,\n}\n

\u8fd9\u91cc\u7684 pages \u4f7f\u7528\u4e86 Vec \u5b58\u50a8\u82e5\u5e72\u5355\u72ec\u7684\u7269\u7406\u9875\uff0c\u800c\u975e\u4e00\u6574\u4e2a\u7269\u7406\u9875\u6bb5\u3002\u8fd9\u662f\u56e0\u4e3a\u8fde\u7eed\u7684\u4e00\u6bb5\u865a\u62df\u5185\u5b58\u5bf9\u5e94\u7684\u7269\u7406\u5185\u5b58\u53ef\u80fd\u662f\u4e0d\u8fde\u7eed\u7684\u3002\u540c\u65f6\uff0cOption \u610f\u5473\u7740\u7269\u7406\u5185\u5b58\u53ef\u80fd\u5c1a\u672a\u5206\u914d\u3002\u8fd9\u662f\u672c OS \u5177\u6709\u7684 Lazy Load \u529f\u80fd\u3002 \u7528\u6237\u6001\u4e2d\u8fde\u7eed\u5df2\u5206\u914d\u7684\u5185\u5b58\u533a\u95f4\u53ef\u80fd\u5b9e\u9645\u4e0a\u6ca1\u6709\u5206\u914d\uff0c\u5f53\u7528\u6237\u4f7f\u7528\u5230\u672a\u5206\u914d\u533a\u6bb5\u65f6\uff0c\u5c06\u89e6\u53d1 PageFault\uff0c\u6b64\u65f6\u5c06\u4ea4\u7531 MapArea::handle_page_fault() \u5904\u7406\uff0c\u5206\u914d\u5b9e\u9645\u7684\u7269\u7406\u5185\u5b58\u3002

\u4e3a\u4e86\u5b9e\u73b0 mmap \u6620\u5c04\u6587\u4ef6\u7684 Lazy Load \u529f\u80fd\uff0cMapArea \u4e2d\u8bb0\u5f55\u4e86\u4e00\u4e2a\u53ef\u9009\u7684\u6587\u4ef6\u540e\u7aef MemBackend\u3002\u5904\u7406 PageFault \u65f6\uff0c\u5982\u679c\u6b64\u6bb5\u5185\u5b58\u5177\u6709\u5bf9\u5e94\u7684\u6587\u4ef6\u540e\u7aef\uff0c\u5219\u4f1a\u5c06\u6587\u4ef6\u5bf9\u5e94\u4f4d\u7f6e\u7684\u5185\u5bb9\u5199\u5165\u65b0\u5206\u914d\u7684\u5185\u5b58\u3002\u6b64\u5916\uff0c\u4e3a\u4e86\u5b9e\u73b0 msync() \u7b49\u5f3a\u5236\u540c\u6b65\u5185\u5b58\u4e0e\u5bf9\u5e94\u6587\u4ef6\u7684 syscall\uff0c\u63d0\u4f9b\u4e86 MapArea::sync_page_with_backend() \u51fd\u6570\u3002

\u9664\u4e86\u5904\u7406\u5185\u5b58\u7684\u61d2\u52a0\u8f7d\uff0cMapArea \u8fd8\u63d0\u4f9b\u4e86\u5bf9\u8fde\u7eed\u5185\u5b58\u6bb5\u7684\u7f16\u8f91\u529f\u80fd\u3002shrink_left()\u3001shrink_right()\u3001split()\u3001split3() \u51fd\u6570\u53ef\u4ee5\u4fee\u6539\u5f53\u524d\u5185\u5b58\u6bb5\u7684\u5927\u5c0f\uff0c\u5e76\u53ca\u65f6\u91ca\u653e\u7269\u7406\u5185\u5b58\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E6%A0%B8%E5%BA%95%E5%B1%82%E6%A8%A1%E5%9D%97-axhal/","title":"\u5185\u6838\u5e95\u5c42\u6a21\u5757-axhal","text":""},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E6%A0%B8%E5%BA%95%E5%B1%82%E6%A8%A1%E5%9D%97-axhal/#-axhal","title":"\u5185\u6838\u5e95\u5c42\u6a21\u5757--axhal","text":""},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%86%85%E6%A0%B8%E8%BF%90%E8%A1%8C%E6%97%B6%E6%A8%A1%E5%9D%97-axruntime/","title":"\u5185\u6838\u8fd0\u884c\u65f6\u6a21\u5757-axruntime","text":"

axruntime\u4f5c\u4e3a\u5185\u6838\u8fd0\u884c\u65f6\u6a21\u5757\uff0c\u7edf\u7b79\u4e86\u5176\u4ed6\u6240\u6709\u7684\u5185\u6838\u6a21\u5757\u3002\u6839\u636e\u5185\u6838\u6a21\u5757\u4f9d\u8d56\u56fe\u53ef\u77e5\uff0cruntimer\u6a21\u5757\u662f\u6700\u4e0a\u5c42\u7684\u6a21\u5757\uff0c\u5b83\u66f4\u591a\u7684\u662f\u8c03\u7528\u5176\u4ed6\u6a21\u5757\u5bf9\u5916\u63d0\u4f9b\u7684\u63a5\u53e3\u6765\u542f\u52a8\u5185\u6838\uff0c\u5e76\u6ca1\u6709\u8fc7\u591a\u7684\u65b0\u589e\u529f\u80fd\uff0c\u56e0\u6b64\u6211\u4eec\u4ec5\u5728\u8fd9\u90e8\u5206\u7b80\u5355\u9610\u8ff0Starry\u5185\u6838\u7684\u542f\u52a8\u6d41\u7a0b\u3002

\u8be6\u7ec6\u4ee3\u7801\u53c2\u89c1axruntime/src/lib.rs:107\uff0c\u5176\u542f\u52a8\u6d41\u7a0b\u5982\u4e0b\uff1a

  1. \u5b9e\u73b0alloc trait\uff0c\u4ece\u800c\u5b9e\u73b0\u5168\u5c40\u5206\u914d\u5668
  2. \u5efa\u7acb\u5185\u6838\u5730\u5740\u7a7a\u95f4\uff0c\u5212\u5206\u5730\u5740\u6bb5
  3. \u521d\u59cb\u5316\u5e73\u53f0\u914d\u7f6e\uff0c\u5305\u62ec\u591a\u6838CPU\u5b9a\u4e49\u7684\u521d\u59cb\u5316
  4. \u5efa\u7acb\u5185\u6838\u8fdb\u7a0b\uff0c\u521d\u59cb\u5316\u5efa\u7acbidle task\u548cgc task\uff0c\u542f\u52a8\u4efb\u52a1\u8c03\u5ea6\u5e8f\u5217
  5. \u542f\u52a8\u5916\u7f6e\u9a71\u52a8\uff0c\u5305\u62ecfs\u3001display\u3001net
  6. \u82e5\u6709\u591a\u6838\u5219\u542f\u52a8\u591a\u6838\u5165\u53e3\u51fd\u6570
  7. \u521d\u59cb\u5316\u65f6\u949f\u4e2d\u65ad\u5904\u7406\u51fd\u6570
  8. \u8fd0\u884c\u4e3b\u6838\u7684\u4e3b\u51fd\u6570\uff0c\u5373\u8fd0\u884c\u6307\u5b9a\u7684\u5e94\u7528\u7a0b\u5e8f

\u6bd4\u8d5b\u65f6\u9700\u8981\u6709\u51e0\u70b9\u6ce8\u610f\u7684\u5730\u65b9\uff1a

  1. \u4e3a\u9075\u5faa\u6bd4\u8d5b\u9700\u6c42\uff0cstarry\u9700\u8981\u8bfb\u53d6\u5916\u90e8\u6d4b\u4f8b\u955c\u50cf\u3002\u4f46\u7531\u4e8eSD\u5361\u955c\u50cf\u8bfb\u53d6\u9a71\u52a8\u8f83\u4e3a\u590d\u6742\uff0c\u56e0\u6b64\u6bd4\u8d5b\u4e2d\u9ed8\u8ba4\u5c06\u5df2\u6709\u7684SD\u5361\u955c\u50cf\u901a\u8fc7\u7f51\u7edc\u4f20\u8f93\u7684\u65b9\u5f0f\u4f20\u9012\u5230\u5b9e\u9645\u677f\u5b50\u76840x90000000\u7269\u7406\u5730\u5740\u5904\u3002\u56e0\u6b64\u8bbe\u7f6e\u5185\u6838\u5730\u5740\u7a7a\u95f4\u65f6\uff0c\u9700\u8981\u5c06\u8fd9\u6bb5\u7a7a\u7f6e\u51fa\u6765\u3002\u5f53\u524dStarry\u9ed8\u8ba4\u542f\u52a8\u7684\u7269\u7406\u5185\u5b58\u5360\u7528\u4e3a[0x8000_0000,0x8800_0000)\u4e0e[0xa000_0000, 0xc000_0000)\u3002\u5bf9\u5e94\u7684\u7279\u6b8a\u5904\u7406\u5728axhal/src/platform/qemu_virt_riscv/mem.rs\u4e2d\u3002
  2. \u5b9e\u9645\u4e0a\u677f\u65f6\uff0c\u7531\u4e8efu740\u4e0d\u5b58\u5728virt-io\u8bbe\u5907\uff0c\u56e0\u6b64\u9700\u8981\u6ce8\u610f\u4e0d\u80fd\u76f4\u63a5\u5c06\u865a\u62df\u8bbe\u5907\u8fdb\u884c\u521d\u59cb\u5316\uff0c\u5426\u5219\u53ef\u80fd\u51fa\u73b0\u95ee\u9898\u3002
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%AE%8F%E5%86%85%E6%A0%B8%E7%94%A8%E6%88%B7%E5%BA%93-starry/","title":"\u5b8f\u5185\u6838\u7528\u6237\u5e93-starry","text":"

\u6839\u636estarry\u7684\u6a21\u5757\u5316\u8bbe\u8ba1\u601d\u8def\uff0c\u7528\u6237\u5e93\u662f\u5728\u7ed9\u5b9a\u6a21\u5757\u7684\u57fa\u7840\u4e0a\u8fdb\u884c\u7edf\u5408\u3001\u63d0\u4f9b\u5bf9\u5916\u7edf\u4e00\u63a5\u53e3\u7684\u4ee3\u7801\u90e8\u5206\u3002\u800c\u5b8f\u5185\u6838\u67b6\u6784\u4e0b\u5bf9\u5916\u63d0\u4f9b\u7684\u63a5\u53e3\u4ee5Linux\u7684\u7cfb\u7edf\u8c03\u7528\u5f62\u5f0f\u8fdb\u884c\u5448\u73b0\u3002\u56e0\u6b64starry_libax\u90e8\u5206\u4e3b\u8981\u4fbf\u662f\u5bf9\u7cfb\u7edf\u8c03\u7528\u7684\u5c01\u88c5\u5b9e\u73b0\u4ee5\u53ca\u6279\u91cf\u6d4b\u8bd5\u7684\u5b9e\u73b0\u3002

\u5404\u90e8\u5206\u7684\u989d\u5916\u8865\u5145\u8bf4\u660e\u5982\u4e0b

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%AE%8F%E5%86%85%E6%A0%B8%E7%94%A8%E6%88%B7%E5%BA%93-starry/#syscall","title":"syscall","text":"

\u5173\u4e8esyscall\u6a21\u5757\u5404\u81ea\u6587\u4ef6\u529f\u80fd\u989d\u5916\u8bf4\u660e\u5982\u4e0b\uff1a

  • epoll\uff1a\u5b9e\u73b0poll\u76f8\u5173\u7684\u7cfb\u7edf\u8c03\u7528\u7684\u529f\u80fd\uff0c\u5982epoll/ppoll/poll\u7b49\u7cfb\u7edf\u8c03\u7528\uff0c\u501f\u9274\u4e8ematurin/modules/epoll at master \u00b7 scPointer/maturin (github.com)

  • futex\uff1a\u5b9e\u73b0\u4efb\u52a1\u4e92\u65a5\u9501\u90e8\u5206\uff0c\u5b83\u662f\u7528\u6237\u6001\u591a\u4efb\u52a1\u534f\u540c\u5f00\u53d1\u7684\u91cd\u70b9\uff0c\u56e0\u6b64\u9700\u8981\u8c28\u614e\u8003\u8651\u5176\u5b9e\u73b0\u3002

futex\u7684\u539f\u7406\u662f\u4ee5\u4e00\u4e2a\u6307\u5b9a\u7684\u53d8\u91cf\u4f5c\u4e3afutex\u53d8\u91cf\uff0c\u591a\u4e2a\u4efb\u52a1\u5728\u7b49\u5f85\u83b7\u53d6\u8fd9\u4e2a\u53d8\u91cf\u7684\u6267\u884c\u6743\u9650\u3002\u4f46\u662f\u5426\u4f1a\u51fa\u73b0\u591a\u4efb\u52a1\u540c\u65f6\u64cd\u4f5c\u540c\u4e00\u4e2a\u53d8\u91cf\u7684\u51b2\u7a81\u95ee\u9898\u4e0d\u7531\u5185\u6838\u8003\u8651\uff0c\u800c\u662f\u7531\u7528\u6237\u81ea\u884c\u8003\u8651\u5e76\u4e14\u5b9e\u73b0\uff0c\u800c\u5185\u6838\u53ea\u9700\u8981\u5b9e\u73b0futex\u76f8\u5173\u7684\u64cd\u4f5c\u5bf9\u5e94\u7684\u8bed\u4e49\u5373\u53ef\u3002

\u5173\u4e8efutex\u7684\u6838\u5fc3\u64cd\u4f5c\u6709\u4e24\u4e2a\uff1await\u548cwake\u3002\u4ee5\u4e0b\u5206\u522b\u4ecb\u7ecd\u8fd9\u4e24\u79cd\u64cd\u4f5c\u7684\u5904\u7406\u65b9\u5f0f\uff1a

  • wait\uff1a\u5f53\u4e00\u4e2a\u4efb\u52a1\u8c03\u7528futex\u7684wait\u64cd\u4f5c\u65f6\uff0c\u4f1a\u6307\u5b9a\u4e00\u4e2afutex\u53d8\u91cf\u7684\u5730\u5740\uff0c\u6b64\u65f6\u4ee3\u8868\u7740\u8fd9\u4e2a\u4efb\u52a1\u9700\u8981\u7b49\u5f85\u8be5futex\u7684\u6743\u9650\u3002\u90a3\u4e48\u8fd9\u4e2a\u4efb\u52a1\u4f1a\u88ab\u52a0\u5165\u5230\u8be5futex\u53d8\u91cf\u7684\u7b49\u5f85\u5e8f\u5217\u4e4b\u4e2d\u3002\u4e4b\u540e\u4efb\u52a1\u4f1a\u6309\u7167\u6307\u5b9a\u7684\u4f11\u7720\u65f6\u95f4\u8fdb\u884c\u4f11\u7720\uff0c\u76f4\u5230\u88ab\u5524\u9192\u3002
  • wake\uff1a\u5f53\u67d0\u4e00\u4e2a\u4efb\u52a1\u5b8c\u6210\u4e86\u5bf9\u67d0\u4e00\u4e2afutex\u53d8\u91cf\u7684\u64cd\u4f5c\u4e4b\u540e\uff0c\u4f1a\u8c03\u7528futex\u7684wake\u64cd\u4f5c\uff0c\u6b64\u65f6\u4ee3\u8868\u7740\u91ca\u653e\u4e86\u8be5futex\u53d8\u91cf\u3002\u5185\u6838\u9700\u8981\u4ece\u8be5futex\u53d8\u91cf\u7684\u7b49\u5f85\u5e8f\u5217\u4e2d\u627e\u5230\u4e00\u4e2a\u4ecd\u7136\u5728\u4f11\u7720\u7684\u4efb\u52a1\uff0c\u5e76\u4e14\u624b\u52a8\u5524\u9192\u5b83\uff0c\u63a5\u7ba1futex\u53d8\u91cf\u7684\u6743\u9650\u3002

\u5f53\u4e00\u4e2a\u4efb\u52a1wait for\u4e00\u4e2afutex\u53d8\u91cf\u65f6\uff0c\u5176\u88ab\u5524\u9192\u7684\u65b9\u5f0f\u6709\u4e09\u79cd\uff1a

  1. \u539f\u6709\u7684futex\u53d8\u91cf\u88ab\u91ca\u653e\uff0c\u8be5\u4efb\u52a1\u83b7\u5f97\u4e86\u63a7\u5236\u6743
  2. \u4efb\u52a1\u4f11\u7720\u65f6\u95f4\u5230\u671f
  3. \u539f\u6709futex\u53d8\u91cf\u5730\u5740\u4e0a\u5b58\u50a8\u7684\u503c\u88ab\u6539\u53d8

\u4f9d\u636e\u4e0a\u8ff0\u4e09\u79cd\u60c5\u51b5\uff0c\u5373\u53ef\u5b9e\u73b0futex\u7cfb\u7edf\u8c03\u7528\u7684\u76f8\u5173\u5904\u7406\u65b9\u5f0f\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E5%AE%8F%E5%86%85%E6%A0%B8%E7%94%A8%E6%88%B7%E5%BA%93-starry/#fs","title":"fs","text":"

fs\u6a21\u5757\u662f\u4e3a\u4e86\u652f\u6301\u6587\u4ef6\u76f8\u5173\u7684\u7cfb\u7edf\u8c03\u7528\u800c\u5b9e\u73b0\u7684\u529f\u80fd\uff0c\u5305\u62ec\u6587\u4ef6\u63cf\u8ff0\u7b26\u3001\u94fe\u63a5\u3001\u6302\u8f7d\u7b49\u529f\u80fd\u3002\u4e4b\u6240\u4ee5\u5c06\u8be5\u6a21\u5757\u653e\u5728\u8fd9\u4e2a\u90e8\u5206\u800c\u4e0d\u662f\u653e\u5728axprocess\u6216\u8005axfs\u4e2d\uff0c\u662f\u56e0\u4e3a\u6587\u4ef6\u63cf\u8ff0\u7b26\u7b49\u5185\u5bb9\u662f\u4e0eLinux\u7cfb\u7edf\u8c03\u7528\u8026\u5408\u5ea6\u8f83\u9ad8\u7684\u5185\u5bb9\uff0c\u662f\u7cfb\u7edf\u8c03\u7528\u7684\u7279\u5b9a\u8bbe\u7f6e\uff0c\u5728\u5176\u4ed6\u5982\u5fae\u5185\u6838\u7684\u67b6\u6784\u4e2d\u4e5f\u5b58\u5728\u7740\u7c7b\u4f3c\u6587\u4ef6\u7cfb\u7edf\u7684\u529f\u80fd\uff0c\u4f46\u4e0d\u4e00\u5b9a\u8981\u5177\u5316\u5230\u6587\u4ef6\u63cf\u8ff0\u7b26\u3002\u56e0\u6b64axfs\u4e2d\u5b58\u653e\u7684\u662f\u6587\u4ef6\u7cfb\u7edf\u7684\u7edf\u4e00\u5b9e\u73b0\uff0c\u800c\u5982\u6587\u4ef6\u63cf\u8ff0\u7b26\u7b49\u8f83\u8d34\u8fd1Linux\u7684\u5185\u5bb9\u5219\u653e\u5728Linux\u517c\u5bb9\u5c42\u7528\u6237\u5e93starry_libax\u4e2d\u5b9e\u73b0\uff0c\u4ece\u800c\u66f4\u52a0\u8d34\u8fd1\u6a21\u5757\u5316\u5185\u6838\u7684\u8bbe\u8ba1\u601d\u8def\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%A8%A1%E5%9D%97-axfs/","title":"\u6587\u4ef6\u7cfb\u7edf\u6a21\u5757-axfs","text":"

\u4ecb\u7ecd\u6587\u4ef6\u7cfb\u7edf\u65f6\uff0c\u4e0d\u4ec5\u9700\u8981\u4ecb\u7ecdaxfs\u8fd9\u4e2a\u6a21\u5757\uff0c\u8fd8\u9700\u8981\u4ecb\u7ecd\u5176\u4f9d\u8d56\u7684crate\u4ee5\u53ca\u8c03\u7528\u8fd9\u4e2a\u6a21\u5757\u7684package\uff0c\u4ed6\u4eec\u5171\u540c\u6784\u6210\u4e86\u6587\u4ef6\u7cfb\u7edf\u7684\u4e0a\u4e0b\u5c42\uff0c\u4f7f\u5f97\u6587\u4ef6\u7cfb\u7edf\u53ef\u4ee5\u6b63\u5e38\u53d1\u6325\u4f5c\u7528\u3002

\u6587\u4ef6\u7cfb\u7edf\u4e3b\u8981\u7531\u56db\u4e2a\u90e8\u5206\u7ec4\u6210\uff0c\u5206\u522b\u662f\u5916\u90e8\u4f9d\u8d56fatfs\u3001crates/axfs_vfs\u3001modules/axfs\u4ee5\u53ca\u4f5c\u4e3a\u7528\u6237\u5e93\u7684starry_libax/src/fs\u3002

\u5404\u81ea\u90e8\u5206\u7684\u989d\u5916\u8865\u5145\u8bf4\u660e\u5982\u4e0b

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%A8%A1%E5%9D%97-axfs/#fatfs","title":"fatfs","text":"

fatfs\u4f5c\u4e3a\u5916\u90e8\u5e93\uff0c\u63d0\u4f9b\u4e86\u4e00\u4e2a\u57fa\u7840\u7684fat32\u6587\u4ef6\u7cfb\u7edf\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%A8%A1%E5%9D%97-axfs/#cratesaxfs_vfs","title":"crates/axfs_vfs","text":"

axfs_vfs\u63d0\u4f9b\u4e86\u5bf9\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u62bd\u8c61\uff0c\u4e3a\u672cos\u5b9e\u73b0\u7684\u4efb\u4f55\u6587\u4ef6\u7cfb\u7edf\u90fd\u9700\u8981\u5b9e\u73b0\u5b83\u7684\u5b9a\u4e49\u7684VfsOps\u7279\u5f81\uff0c\u540c\u65f6\u5bf9\u5e94\u6587\u4ef6\u7cfb\u7edf\u7684file/directory\u7ed3\u6784\u4f53\u9700\u8981\u5b9e\u73b0\u5b83\u7684VfsNodeOps\u7279\u5f81\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%A8%A1%E5%9D%97-axfs/#modulesaxfs","title":"modules/axfs","text":"

\u5728modules/axfs\u4e2d\uff1a

  1. axfs::fatfs\u4f5c\u4e3a\u4e2d\u4ecb\u8fde\u63a5\u4e86\u6587\u4ef6\u7cfb\u7edf\u3001vfs\u548c\u5757\u8bbe\u5907\u4e09\u4e2a\u6a21\u5757\uff0c\u5b83\u5c01\u88c5\u4e86\u5916\u90e8\u7684fat32\u63d0\u4f9b\u7684\u6587\u4ef6\u7cfb\u7edf\u548cfile/directory\uff0c\u5e76\u4e3a\u5b83\u4eec\u5b9e\u73b0axfs_vfs\u4e2d\u7684\u5bf9\u5e94\u7279\u5f81\uff0c\u540c\u65f6\u8c03\u7528\u4e86axfs::dev\u5bf9\u786c\u4ef6\u8fdb\u884c\u64cd\u4f5c\uff1b
  2. axfs::fops\u5c01\u88c5\u4e86ax_vfs\u4e2d\u7684\u5404\u79cdVfsNode\u64cd\u4f5c\uff0c\u5411\u4e0a\u63d0\u4f9b\u7ed9axfs::api\u6a21\u5757\u66b4\u9732\u7ed9\u5916\u90e8\uff1b
  3. axfs::monolithic_fs\u662f\u5c06\u6587\u4ef6\u7cfb\u7edf\u9002\u914d\u5230\u5b8f\u5185\u6838\u7684\u6838\u5fc3\uff0c\u5b83\u63d0\u4f9b\u4e86\u6587\u4ef6\u7cfb\u7edf\u4fe1\u606fKstat\u3001\u6587\u4ef6\u8f93\u5165\u8f93\u51fa\u64cd\u4f5cFileIO\u3001\u6587\u4ef6-\u865a\u5b58\u6620\u5c04FileExt\u7b49\u7ed3\u6784\u4f53\u548c\u7279\u5f81\u7684\u62bd\u8c61\u3002
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E6%A8%A1%E5%9D%97-axfs/#starry_libaxfs","title":"starry_libax/fs","text":"

\u5728starry_libax\u4e2d\u6240\u505a\u7684\u5de5\u4f5c\u4e3b\u8981\u6709\uff1a

  1. \u5b9a\u4e49\u6587\u4ef6\u5939\u3001\u6587\u4ef6\u3001\u7ba1\u9053\u7b49\u7ed3\u6784\u4f53\uff0c\u5e76\u4e3a\u5b83\u4eec\u5b9e\u73b0monolithic_fs\u4e2d\u5b9a\u4e49\u7684\u4e00\u4e9b\u7279\u5f81\uff0c\u4ee5\u6587\u4ef6\u4e3a\u4f8b\uff1a
/// \u6587\u4ef6\u63cf\u8ff0\u7b26\npub struct FileDesc {\n/// \u6587\u4ef6\u8def\u5f84\npub path: String,\n/// \u6587\u4ef6\npub file: Arc<Mutex<File>>,\n/// \u6587\u4ef6\u6253\u5f00\u7684\u6807\u5fd7\u4f4d\npub flags: OpenFlags,\n/// \u6587\u4ef6\u4fe1\u606f\npub stat: Mutex<FileMetaData>,\n}\n\n/// \u6587\u4ef6\u5728os\u4e2d\u8fd0\u884c\u65f6\u7684\u53ef\u53d8\u4fe1\u606f\npub struct FileMetaData {\n/// \u6700\u540e\u4e00\u6b21\u8bbf\u95ee\u65f6\u95f4\npub atime: TimeSecs,\n/// \u6700\u540e\u4e00\u6b21\u6539\u53d8(modify)\u5185\u5bb9\u7684\u65f6\u95f4\npub mtime: TimeSecs,\n/// \u6700\u540e\u4e00\u6b21\u6539\u53d8(change)\u5c5e\u6027\u7684\u65f6\u95f4\npub ctime: TimeSecs,\n}\nimpl Read for FileDesc {\n..\n}\n\nimpl Write for FileDesc {\n..\n}\n\nimpl Seek for FileDesc {\n..\n}\n\nimpl FileExt for FileDesc {\n..\n}\n/// \u4e3aFileDesc\u5b9e\u73b0FileIO trait\nimpl FileIO for FileDesc {\n..\n}\n
  1. \u5b9e\u73b0\u6587\u4ef6\u94fe\u63a5\u3001\u6587\u4ef6\u7cfb\u7edf\u6302\u8f7d\u3001\u76ee\u5f55\u9879\u904d\u5386\u7b49\u529f\u80fd\u3002

\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cfat32\u6587\u4ef6\u7cfb\u7edf\u4e0d\u652f\u6301\u786c\u8fde\u63a5\uff0c\u6211\u4eec\u505a\u7684\u5de5\u4f5c\u5b9e\u9645\u4e0a\u662f\u5728\u5185\u5b58\u91cc\u6a21\u62df\u786c\u8fde\u63a5\u7684\u8fc7\u7a0b\u3002\u5728\u76ee\u524d\u7684\u5b9e\u73b0\u91cc\uff0c\u6bcf\u4e2a\u5bf9\u4e8e\u6587\u4ef6\u7684\u8bbf\u95ee\u4f20\u5165\u7684\u201c\u6587\u4ef6\u8def\u5f84\u201d\u5b9e\u9645\u4e0a\u90fd\u662f\u4e00\u4e2a\u865a\u62df\u7684\u8def\u5f84\uff0c\u53ea\u662f\u4f5c\u4e3aKEY\u5b58\u5165\u6a21\u62df\u786c\u8fde\u63a5\u7684BTreeMap\u91cc\uff0c\u6620\u5c04\u5230\u5b83\u5728\u6587\u4ef6\u955c\u50cf\u4e2d\u7684\u5b9e\u9645\u4f4d\u7f6e\uff0c\u5305\u62ec\u6052\u7b49\u6620\u5c04\u3002

\u7531\u4e8e\u786c\u8fde\u63a5\u7684\u4e00\u4e9b\u7279\u6027\uff0c\u8fd9\u79cd\u6a21\u62df\u5728\u67d0\u4e9b\u60c5\u5883\u4e0b\u4f1a\u51fa\u73b0\u4e00\u4e9b\u95ee\u9898\u3002

\u4f8b\u5982\uff0c\u5047\u8bbeA\u8def\u5f84\u662f\u4f4d\u4e8e\u786c\u76d8\u4e0a\u7684A\u6587\u4ef6\u7684\u5b9e\u9645\u8def\u5f84\uff0cB\u8def\u5f84\u5219\u662f\u540e\u521b\u5efa\u7684\u4e00\u4e2a\u6307\u5411A\u6587\u4ef6\u7684\u786c\u8fde\u63a5\uff0c\u5220\u9664A\u540e\u56e0\u4e3a\u6709B\u5b58\u5728\uff0c\u5b9e\u9645\u4e0a\u53ea\u4f1a\u51cf\u5c11A\u6587\u4ef6\u7684\u786c\u8fde\u63a5\u6570\uff0c\u4e0d\u4f1a\u5220\u9664\u5b9e\u9645\u6587\u4ef6A\u3002\u8fd9\u65f6\u518d\u521b\u5efa\u4e00\u4e2a\u65b0\u7684A\u6587\u4ef6\u65f6\u4fbf\u4f1a\u62a5\u9519\u3002

\u9488\u5bf9\u8fd9\u4e2a\u95ee\u9898\uff0c\u6211\u4eec\u91c7\u7528\u8fc7\u7684\u4e00\u4e2a\u89e3\u51b3\u529e\u6cd5\u662f\u5bf9\u6bcf\u4e2a\u5b9e\u9645\u7684\u6587\u4ef6\u7ef4\u62a4\u4e00\u4e2a\u8bb0\u5f55\u6307\u5411\u5b83\u7684\u786c\u8fde\u63a5\u7684\u5217\u8868\uff0c\u5220\u9664\u5b9e\u9645\u8def\u5f84\u65f6\uff0c\u5f39\u51fa\u51fa\u5217\u8868\u9996\u9879\u5e76\u5c06\u5b9e\u9645\u6587\u4ef6\u79fb\u52a8\u5230\u5bf9\u5e94\u8def\u5f84\uff0c\u7136\u540e\u4eceBTreeMap\u4e2d\u5220\u9664\u8be5\u9879\uff0c\u8ba9\u5b83\u6210\u4e3a\u65b0\u7684\u5b9e\u9645\u8def\u5f84\u3002

  1. \u5b9e\u73b0\u6240\u9700\u7684\u5404\u7c7b\u6587\u4ef6\u7cfb\u7edf\u76f8\u5173\u7684\u7cfb\u7edf\u8c03\u7528\u3002
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%9D%97-axnet/","title":"\u7f51\u7edc\u6a21\u5757-axnet","text":"

axnet \u63d0\u4f9b\u4e86\u5bf9\u7f51\u7edc\u8bbe\u5907\u7684\u9a71\u52a8\u4e0e\u5c01\u88c5\u3002StarryOS \u4f7f\u7528\u4e86\u5f00\u6e90\u7684 smoltcp \u5e93\u4f5c\u4e3a\u5176\u7f51\u7edc\u534f\u8bae\u6808\u3002\u5e76\u5728 smoltcp \u63d0\u4f9b\u7684 API \u57fa\u7840\u4e0a\uff0c\u5c01\u88c5\u4e86 TCPSocket \u4e0e UDPSocket \u4e24\u4e2a\u5957\u63a5\u5b57\u7c7b\u578b\u3002

Linux syscall \u6240\u63d0\u4f9b\u7684 Socket API \u7684\u5b9e\u73b0\u4f4d\u4e8e ulib/socket.rs \u4e2d\u3002

/// \u5305\u88c5\u5185\u90e8\u7684\u4e0d\u540c\u534f\u8bae Socket\npub struct Socket {\n#[allow(dead_code)]\ndomain: Domain,\nsocket_type: SocketType,\ninner: SocketInner,\nclose_exec: bool,\nrecv_timeout: Option<TimeVal>,\n\nreuse_addr: bool,\ndont_route: bool,\nsend_buf_size: usize,\nrecv_buf_size: usize,\ncongestion: String,\n}\n
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%9D%97-axnet/#socket","title":"Socket","text":"

Socket \u5c01\u88c5\u4e86\u7531 axnet \u63d0\u4f9b\u7684 TCP/UDP Socket\uff08SocketInner\uff09\u3002\u5e76\u8bb0\u5f55\u4e86\u6b64 Socket \u5728 Linux Socket API \u5c42\u5177\u6709\u7684\u5176\u4ed6\u4fe1\u606f\uff0c\u5982 domain\uff08Address Family\uff09\u3001type\uff0c\u4ee5\u53ca\u4e00\u4e9b\u914d\u7f6e\u4fe1\u606f\uff0c\u5982 recv_timeout\u3001close_exec\u3002

\u6b64 Socket \u7c7b\u578b\u5b9e\u73b0\u4e86\u5982 bind()\u3001connect()\u3001accept() \u7b49\u64cd\u4f5c\uff0c\u518d syscall \u7684\u5b9e\u9645\u4ee3\u7801\u4e2d\uff0c\u53ea\u9700\u4f7f\u7528\u8fd9\u4e9b\u51fd\u6570\uff0c\u65e0\u9700\u4e0e axnet \u4ea4\u4e92\u3002

Socket \u4e0e\u5176\u4ed6\u6587\u4ef6\u76f8\u5173\u7684\u7c7b\u578b\u76f8\u540c\uff0c\u5b9e\u73b0\u4e86 FileExt \u4e0e FileIO trait\uff0c\u4f7f\u5f97 Socket \u5bf9\u8c61\u53ef\u4ee5\u5b58\u50a8\u5728\u8fdb\u7a0b\u7684 FdTable \u4e2d\u3002\u4e5f\u56e0\u5982\u6b64\uff0cread()\u3001write() \u7b49\u9762\u5411\u6587\u4ef6\u5b9e\u73b0\u7684 syscall \u4e5f\u53ef\u7528\u4e8e socket\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E7%BD%91%E7%BB%9C%E6%A8%A1%E5%9D%97-axnet/#socketoptiontcpsocketoption","title":"SocketOption\u3001TcpSocketOption","text":"

Linux Socket API \u4e2d\u5173\u4e8e\uff0c\u53ef\u4ee5\u901a\u8fc7 Socket Option \u6765\u4fee\u6539\u6216\u83b7\u53d6 Socket \u7684\u5404\u9879\u9009\u9879\u3002\u5bf9\u4e8e\u4e0d\u540c\u7684\u9009\u9879\uff0c\u5206\u522b\u5b9e\u73b0\u4e86 get() \u4e0e set() \u51fd\u6570\uff0c\u7b80\u6d01\u5730\u5b9e\u73b0\u6240\u9700\u529f\u80fd\u3002

#[derive(TryFromPrimitive, Debug)]\n#[repr(usize)]\n#[allow(non_camel_case_types)]\npub enum SocketOption {\nSO_REUSEADDR = 2,\nSO_DONTROUTE = 5,\nSO_SNDBUF = 7,\nSO_RCVBUF = 8,\nSO_KEEPALIVE = 9,\nSO_RCVTIMEO = 20,\n}\n
"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9D%97-axprocess/","title":"\u8fdb\u7a0b\u63a7\u5236\u6a21\u5757-axprocess","text":"

\u8fdb\u7a0b\u90e8\u5206\u662f\u5b8f\u5185\u6838\u5b9e\u73b0\u7684\u6838\u5fc3\u90e8\u5206\uff0c\u5b83\u4f5c\u4e3a\u4e00\u4e2a\u8d44\u6e90\u5bb9\u5668\u6536\u7eb3\u4e86\u4efb\u52a1\u3001\u4fe1\u53f7\u3001\u5185\u5b58\u3001\u6587\u4ef6\u7cfb\u7edf\u7b49\u6a21\u5757\u7684\u529f\u80fd\uff0c\u5e76\u4e14\u8fdb\u884c\u7edf\u7b79\u7ba1\u7406\u3002

\u8fdb\u7a0b\u6a21\u5757\u7684\u76f8\u5173\u529f\u80fd\u5212\u5206\u5982\u4e0b

\u8fdb\u7a0b\u6a21\u5757\u66f4\u591a\u662f\u5bf9\u5df2\u6709\u5b9e\u73b0\u6a21\u5757\u7684\u4e00\u4e2a\u603b\u7ed3\uff0c \u56e0\u6b64\u8be5\u90e8\u5206\u7684\u989d\u5916\u8bf4\u660e\u5e76\u4e0d\u4f1a\u7279\u522b\u591a\uff0c\u4ec5\u662f\u8d77\u4e00\u4e2a\u603b\u7ed3\u7684\u4f5c\u7528\u3002

\u989d\u5916\u8865\u5145\u5982\u4e0b

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9D%97-axprocess/#process","title":"process","text":"

process\u90e8\u5206\u5b9e\u73b0\u4e86\u8fdb\u7a0b\u63a7\u5236\u5757\u7684\u4e3b\u4f53\u90e8\u5206\uff0c\u5176\u8fdb\u7a0b\u63a7\u5236\u5757\u5b9a\u4e49\u5982\u4e0b\uff1a

pub struct ProcessInner {\n/// \u7236\u8fdb\u7a0b\u7684\u8fdb\u7a0b\u53f7\npub parent: u64,\n/// \u5b50\u8fdb\u7a0b\npub children: Vec<Arc<Process>>,\n/// \u5b50\u4efb\u52a1\npub tasks: Vec<AxTaskRef>,\n/// \u5730\u5740\u7a7a\u95f4\uff0c\u7531\u4e8e\u5b58\u5728\u5730\u5740\u7a7a\u95f4\u5171\u4eab\uff0c\u56e0\u6b64\u8bbe\u8ba1\u4e3aArc\u7c7b\u578b\npub memory_set: Arc<SpinNoIrq<MemorySet>>,\n/// \u7528\u6237\u5806\u57fa\u5740\uff0c\u4efb\u4f55\u65f6\u5019\u5806\u9876\u90fd\u4e0d\u80fd\u6bd4\u8fd9\u4e2a\u503c\u5c0f\uff0c\u7406\u8bba\u4e0a\u8bb2\u662f\u4e00\u4e2a\u5e38\u91cf\npub heap_bottom: usize,\n/// \u5f53\u524d\u7528\u6237\u5806\u7684\u5806\u9876\uff0c\u4e0d\u80fd\u5c0f\u4e8e\u57fa\u5740\uff0c\u4e0d\u80fd\u5927\u4e8e\u57fa\u5740\u52a0\u5806\u7684\u6700\u5927\u5927\u5c0f\npub heap_top: usize,\n/// \u8fdb\u7a0b\u72b6\u6001\npub is_zombie: bool,\n/// \u9000\u51fa\u72b6\u6001\u7801\npub exit_code: i32,\n#[cfg(feature = \"fs\")]\npub fd_manager: FdManager,\n/// \u8fdb\u7a0b\u5de5\u4f5c\u76ee\u5f55\npub cwd: String,\n#[cfg(feature = \"signal\")]\n/// \u4fe1\u53f7\u5904\u7406\u6a21\u5757    \n/// \u7b2c\u4e00\u7ef4\u4ee3\u8868\u7ebf\u7a0b\u53f7\uff0c\u7b2c\u4e8c\u7ef4\u4ee3\u8868\u7ebf\u7a0b\u5bf9\u5e94\u7684\u4fe1\u53f7\u5904\u7406\u6a21\u5757\npub signal_module: BTreeMap<u64, SignalModule>,\n\n/// robust list\u5b58\u50a8\u6a21\u5757\n/// \u7528\u6765\u5b58\u50a8\u7ebf\u7a0b\u5bf9\u5171\u4eab\u53d8\u91cf\u7684\u4f7f\u7528\u5730\u5740\n/// \u5177\u4f53\u4f7f\u7528\u4ea4\u7ed9\u4e86\u7528\u6237\u7a7a\u95f4\npub robust_list: BTreeMap<u64, FutexRobustList>,\n}\n

\u53ef\u4ee5\u770b\u51fa\u8fdb\u7a0b\u63a7\u5236\u5757\u5185\u878d\u5408\u4e86\u5305\u62ec\u6587\u4ef6\u3001\u4fe1\u53f7\u3001\u4e92\u65a5\u9501\u3001\u5185\u5b58\u5730\u5740\u7a7a\u95f4\u7b49\u4e00\u7cfb\u5217\u5185\u5bb9\uff0c\u901a\u8fc7feature\u6761\u4ef6\u7f16\u8bd1\u7684\u65b9\u5f0f\u53ef\u4ee5\u65b9\u4fbf\u5730\u5bf9\u6a21\u5757\u8fdb\u884c\u53ef\u63d2\u62d4\u7f16\u8bd1\uff0c\u7b26\u5408\u6a21\u5757\u5316\u7684\u5185\u6838\u8bbe\u8ba1\u601d\u60f3\u3002

"},{"location":"%E6%A8%A1%E5%9D%97%E4%BB%8B%E7%BB%8D/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9D%97-axprocess/#futex","title":"futex","text":"

\u5728\u8fdb\u7a0b\u90e8\u5206\u5b9a\u4e49\u4e86\u4e0e\u4e92\u65a5\u9501\u76f8\u5173\u7684\u6570\u636e\u7ed3\u6784FUTEX_WAIT_TASK\uff0c\u5176\u662f\u4e00\u4e2a\u4ece\u5730\u5740\u5230\u4efb\u52a1\u6307\u9488\u7684map\u6620\u5c04\uff0c\u5b58\u50a8\u4e86\u6bcf\u4e00\u4e2afutex\u53d8\u91cf\u5bf9\u5e94\u7684\u6b63\u5728\u7b49\u5f85\u7684\u4efb\u52a1\u5e8f\u5217\u3002

\u4e4b\u6240\u4ee5\u5c06\u8be5\u6570\u636e\u7ed3\u6784\u5b9a\u4e49\u5728axprocess\u6a21\u5757\uff0c\u662f\u56e0\u4e3a\u9700\u8981\u5728\u8fdb\u7a0b\u9000\u51fa\u65f6\uff0c\u6e05\u7a7aFUTEX_WAIT_TASK\u4e2d\u5b58\u50a8\u7684\u8fdb\u7a0bArc\u6307\u9488\uff0c\u4ece\u800c\u4fdd\u8bc1\u5bf9\u8c61\u80fd\u591f\u5b8c\u6574\u88ab\u91ca\u653e\u3002

futex\u7684\u5b8c\u6574\u5b9e\u73b0\u5728starry/syscall/futex\u4e2d\u3002

"}]} \ No newline at end of file diff --git a/doc/Starry/site/sitemap.xml b/doc/Starry/site/sitemap.xml deleted file mode 100644 index 0f8724e..0000000 --- a/doc/Starry/site/sitemap.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/doc/Starry/site/sitemap.xml.gz b/doc/Starry/site/sitemap.xml.gz deleted file mode 100644 index 7b8dc49..0000000 Binary files a/doc/Starry/site/sitemap.xml.gz and /dev/null differ diff --git "a/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\344\276\235\350\265\226\351\227\256\351\242\230/index.html" "b/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\344\276\235\350\265\226\351\227\256\351\242\230/index.html" deleted file mode 100644 index 2db9cb8..0000000 --- "a/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\344\276\235\350\265\226\351\227\256\351\242\230/index.html" +++ /dev/null @@ -1,835 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 依赖问题 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

依赖问题

- -

由于ArceOS自身的unikernel架构,不同模块需要保持一定的依赖关系,从而可以方便地通过条件编译等操作来解耦某些模块,使用某些指定的模块来启动内核,从而增强OS的泛用性。

-

查看项目的依赖关系

-

项目的依赖关系可以通过对应的toml配置文件进行查看。如下列为axmem模块的toml:

-
# modules/axmem/Cargo.toml
-[dependencies]
-log = "0.4"
-axhal = { path = "../axhal", features = ["paging"] }
-axalloc = { path = "../axalloc" }
-axconfig = { path = "../axconfig" }
-axerrno = { path = "../../crates/axerrno" }
-axfs = { path = "../axfs" }
-axio = { path = "../../crates/axio" }
-spinlock = { path = "../../crates/spinlock" }
-xmas-elf = { path = "../../extern_crates/xmas-elf-0.9.0" }
-riscv = { path = "../../extern_crates/riscv-0.10.1" }
-page_table_entry = { path = "../../crates/page_table_entry" }
-
-

以上就可以看出axmem依赖了axhal/axfs/axconfig等模块。

-

循环依赖问题

-

而Starry虽然是宏内核架构,但仍然保持了这一泛用特性,但这也为我们开发带来了一些问题,即循环依赖问题。

-
-

由于ArceOS的模块化设计,不同的modules之间会形成以module为单位的依赖关系,相较于以文件为 -单位的依赖关系而言更容易产生循环依赖的问题。

-

一个例子:假如一个项目中有A、B、C三个文件,A依赖B、B依赖C,不会有任何问题;但如果三 -个文件被解耦到两个不同的项目 M和N中,M中有A和C,N中有B,那么M和N之间就会发生相互依 -赖。 -这种情况在我们的开发过程中并不少见。

-
-

当前Starry的模块依赖图如下:

-

modules

-

如axhal需要定义trap入口,而trap实现需要很多模块的支持如axmem的地址空间等,此时就可能出现循环依赖的情况,即axhal依赖于axmem,而axmem依赖于axhal。

-

为了解决这个问题,有以下几种方法:

-
    -
  1. -

    优化结构设计,即尽可能将实现的功能进行划分,如地址空间内容独立出来放在axmem,而不是和进程控制一起放在axprocess。

    -
  2. -
  3. -

    通过ArceOS提供的模块crate_interface中的call_interface和def_interface,在底层模块定义好相关的函数之后,交给上层模块去实现。

    -
  4. -
-

如在axhal中定义了TrapHandler如下:

-
#[def_interface]
-pub trait TrapHandler {
-    /// Handles interrupt requests for the given IRQ number.
-    fn handle_irq(irq_num: usize);
-    // more e.g.: handle_page_fault();
-    // 需要分离用户态使用
-    #[cfg(feature = "monolithic")]
-    fn handle_syscall(syscall_id: usize, args: [usize; 6]) -> isize;
-
-    #[cfg(feature = "paging")]
-    fn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame);
-
-    #[cfg(feature = "paging")]
-    fn handle_access_fault(addr: VirtAddr, flags: MappingFlags);
-
-    /// 处理当前进程的信号
-    #[cfg(feature = "signal")]
-    fn handle_signal();
-
-    /// 为了lmbench特判,即在出现未能处理的情况,不panic,而是退出当前进程
-    #[cfg(feature = "monolithic")]
-    fn exit();
-}
-
-

而在starry_libax/trap.rs完成了对TrapHandler的实现:

-
#[crate_interface::impl_interface]
-impl axhal::trap::TrapHandler for TrapHandlerImpl {
-    fn handle_irq(irq_num: usize) {
-        /// ..
-    }
-    fn handle_syscall(syscall_id: usize, args: [usize; 6]) -> isize {
-        /// ..
-    }
-
-    #[cfg(feature = "paging")]
-    fn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame) {
-        /// ..
-    }
-
-    fn handle_access_fault(addr: VirtAddr, flags: MappingFlags) {
-        /// ..
-    }
-
-    #[cfg(feature = "signal")]
-    fn handle_signal() {
-        /// ..
-    }
-
-    fn exit() {
-        /// ..
-    }
-}
-
-

而在axruntime/src/trap.rs中定义了ArceOS原有的unikernel架构下的trap实现:

-
/// 仅用作非宏内核下的trap入口
-
-struct TrapHandlerImpl;
-
-#[crate_interface::impl_interface]
-impl axhal::trap::TrapHandler for TrapHandlerImpl {
-    fn handle_irq(_irq_num: usize) {
-        #[cfg(feature = "irq")]
-        {
-            let guard = kernel_guard::NoPreempt::new();
-            axhal::irq::dispatch_irq(_irq_num);
-            drop(guard); // rescheduling may occur when preemption is re-enabled.
-        }
-    }
-}
-
-

通过不同的TrapHandler的实现,可以实现宏内核和unikernel架构下不同trap实现的支持。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\345\205\274\345\256\271\351\227\256\351\242\230/index.html" "b/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\345\205\274\345\256\271\351\227\256\351\242\230/index.html" deleted file mode 100644 index cae4096..0000000 --- "a/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\345\205\274\345\256\271\351\227\256\351\242\230/index.html" +++ /dev/null @@ -1,698 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 兼容问题 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

兼容问题

- -

为了保证Starry在未来的泛用性,我们在比赛开发过程中便有意识地去注意不同架构下的实现兼容,并采用条件编译等方式进行区分。如process部分的结构体的定义为:

-
pub struct ProcessInner {
-    /// 父进程的进程号
-    pub parent: u64,
-    /// 子进程
-    pub children: Vec<Arc<Process>>,
-    /// 子任务
-    pub tasks: Vec<AxTaskRef>,
-    /// 地址空间,由于存在地址空间共享,因此设计为Arc类型
-    pub memory_set: Arc<SpinNoIrq<MemorySet>>,
-    /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量
-    pub heap_bottom: usize,
-    /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小
-    pub heap_top: usize,
-    /// 进程状态
-    pub is_zombie: bool,
-    /// 退出状态码
-    pub exit_code: i32,
-    // /// 文件描述符表
-    // pub fd_table: Vec<Option<Arc<SpinNoIrq<dyn FileIO>>>>,
-    // /// 文件描述符上限,由prlimit设置
-    // pub fd_limit: usize,
-    #[cfg(feature = "fs")]
-    pub fd_manager: FdManager,
-    /// 进程工作目录
-    pub cwd: String,
-    #[cfg(feature = "signal")]
-    /// 信号处理模块    
-    /// 第一维代表线程号,第二维代表线程对应的信号处理模块
-    pub signal_module: BTreeMap<u64, SignalModule>,
-
-    /// robust list存储模块
-    /// 用来存储线程对共享变量的使用地址
-    /// 具体使用交给了用户空间
-    pub robust_list: BTreeMap<u64, FutexRobustList>,
-}
-
-

其额外限定了fs和signal的feature,规定了信号模块和文件系统模块的条件编译,可以根据编译参数来决定内核是否支持fs和信号模块。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\345\256\217\345\206\205\346\240\270\345\214\226\346\216\242\350\256\250/index.html" "b/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\345\256\217\345\206\205\346\240\270\345\214\226\346\216\242\350\256\250/index.html" deleted file mode 100644 index 8eed1dc..0000000 --- "a/doc/Starry/site/\345\256\236\347\216\260\351\207\215\347\202\271/\345\256\217\345\206\205\346\240\270\345\214\226\346\216\242\350\256\250/index.html" +++ /dev/null @@ -1,846 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 宏内核化探讨 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

宏内核化探讨

- -

Starry的工作是为一个面向Unikernel设计的OS添加宏内核支持,因此相比于其他从0开始的 -内核,Starry需要考虑更多兼容工作,也要求我们对Unikernel和ArceOS有足够的了解。

-

前期知识了解

-

首先,我们了解到ArceOS是以Unikernel架构运行的。因此我们查阅了Unikernel和宏内核相关的资料,并且总结出两者之间的一些简单的区别如下:

-

avatar

-

另外,我们也详细阅读了ArceOS的代码,总结出从ArceOS到宏内核需要完善的内容:

-

avatar

-

通过阅读ArceOS与其他宏内核如zCore、rCore的代码实现,将ArceOS与宏内核的关系划分如下:

-
    -
  • ArceOS中可直接沿用:log、driver以及一系列解耦的crate
  • -
  • ArceOS中需要调整适配:任务调度、特权级转化等
  • -
  • ArceOS中需要添加:地址空间、进程、信号、文件系统、用户库等内容
  • -
-

开发内容

-

依据前期知识的总结,我们在原有ArceOS的基础上做出了如下改动:

-

avatar

-

在原有ArceOS代码的基础上

-
    -
  • 新增了4个模块:分别为
  • -
  • axmem:添加多地址空间
  • -
  • axprocess:添加进程管理
  • -
  • axsignal:添加信号模块
  • -
  • axfs:添加适用于宏内核的文件系统接口
  • -
  • 改动适配了5个模块:分别为
  • -
  • axhal:主要为关于宏内核的trap处理,如syscall、缺页异常等
  • -
  • axtask:主要为task信息的补充,如计时器信息
  • -
  • axdriver:主要为ramdisk的补充,为比赛加载测例服务
  • -
  • axruntime:主要为内核初始化流程中添加宏内核启动相关服务
  • -
  • axnet:主要为Linux相关的syscall添加相对应的接口
  • -
  • 新增了一个用户库:封装Linux相关的系统调用,处理相应的syscall
  • -
  • 共涉及代码约12000行
  • -
-

开发重点

-

进程实现

-

为了保证Starry可以较好地去适配Unikernel架构,在比赛初期我们就进程结构与线程是否分离这个问题进行了讨论。

-

在Linux中,进程和线程合并在一起,统一由pthread控制块进行管理,某种程度上简化了结构。但我们的Starry需要适配Unikernel,在Unikernel中是单应用程序,没有多进程的概念。因此作为兼容Linux应用和Unikernel的Starry OS,进程如何定义便有了较为重要的意义。

-

我们先讨论了两种做法的优点:

-
    -
  • 合并优点:符合Linux结构,更加直观
  • -
  • 分离优点:适配Unikernel实现,更加兼容ArceOS
  • -
-

为了得到更好的比较结果,我们分头行动,根据两种不同的定义方式实现了两个内核。经过比较之后,我们决定将进程和线程合并,更好地去适配ArceOS。

-

与ArceOS的兼容

-

为了保证和ArceOS代码功能上的兼容,在开发过程中需要一定程度地保留ArceOS原有代码,同时不能影响自己新的功能,防止出现冲突。

-

为了解决这个问题,我们用到了三种工具:

-
    -
  • 条件编译
  • -
-

条件编译贯穿了Starry实现过程,通过指定不同的feature来定制不同的内核实现。同时,也可以用条件编译来在保留ArceOS原有功能的同时,添加上Starry的分支功能,指定不同的feature保证两者可以得到兼容。

-
cfg_if::cfg_if! {
-    if #[cfg(feature = "monolithic")] {
-        axprocess::process::init_kernel_process();
-    }
-    else {
-        #[cfg(feature = "multitask")]
-        axtask::init_scheduler();
-    }
-}
-
-
    -
  • 封装trait
  • -
-

封装trait是Rust提供不同实现兼容的一种常见方式。不同结构通过用不同方式实现同一个trait,可以得到不同的处理方式和功能,从而达到了兼容并存的效果。如文件系统的一系列读写Trait便起到了这个功能。

-
    -
  • crate_interface包
  • -
-

crate_interface包是由ArceOS实现的一个包,效果类似于trait。它允许用户在底层通过def_interface定义某些函数接口,并在上层通过impl_interface实现对应函数的具体内容。通过调用多个impl_interface便可以做到同一个接口的多种实现方式。

-

crate_interface与trait的一个不同之处在于,crate_interface的实现只能有一个,也就是说如果存在impl_interface,那么可能需要用到条件编译等手段使得仅有唯一一个impl_interface被实际编译到镜像中。

-

avatar

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\236\266\346\236\204\350\256\276\350\256\241/ArceOS\344\273\213\347\273\215/index.html" "b/doc/Starry/site/\346\236\266\346\236\204\350\256\276\350\256\241/ArceOS\344\273\213\347\273\215/index.html" deleted file mode 100644 index 805f080..0000000 --- "a/doc/Starry/site/\346\236\266\346\236\204\350\256\276\350\256\241/ArceOS\344\273\213\347\273\215/index.html" +++ /dev/null @@ -1,676 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - ArceOS介绍 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

ArceOS介绍

- -

我们的Starry是基于ArceOS生成的,因此需要简单介绍一下ArceOS实现的内容。

-

ArceOS采用模块化组件化的设计思维,通过使用内核组件 + 组件化的OS框架 来得到 不同形态的OS kernel。

-
    -
  • 提供了一套组件化的操作系统框架
  • -
  • 提供各种内核组件的实现,各种内核组件可在没有OS kernel的情况下独立运行
  • -
  • 如filesystem, network stack等内核组件可以在裸机或用户态以库的形式运行
  • -
  • 各种设备驱动等内核组件可以在裸机上运行
  • -
  • 理想情况下可以通过选择组件构成unikernel/宏内核/微内核
  • -
  • 实际上在我们开始实验时它还只支持unikernel
  • -
  • 只运行一个用户程序
  • -
  • 用户程序与内核链接为同一镜像
  • -
  • 不区分地址空间与特权级
  • -
  • 安全性由底层 hypervisor 保证
  • -
-

当前ArceOS是面向Unikernel设计的,而我们的Starry便是其宏内核化的一次尝试与成果。

-

avatar

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\236\266\346\236\204\350\256\276\350\256\241/Starry\347\273\223\346\236\204\350\257\264\346\230\216/index.html" "b/doc/Starry/site/\346\236\266\346\236\204\350\256\276\350\256\241/Starry\347\273\223\346\236\204\350\257\264\346\230\216/index.html" deleted file mode 100644 index 06c7720..0000000 --- "a/doc/Starry/site/\346\236\266\346\236\204\350\256\276\350\256\241/Starry\347\273\223\346\236\204\350\257\264\346\230\216/index.html" +++ /dev/null @@ -1,786 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - Starry结构说明 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

Starry结构说明

- -

Starry结构说明

-
    -
  • crates:与OS设计无关的公共组件
  • -
  • modules:与OS设计更加耦合的组件,各个模块功能简要介绍如下:
  • -
  • axalloc:实现全局分配器
  • -
  • axconfig:定义内核参数
  • -
  • axdisplay:简单的图形化实现
  • -
  • axdriver:设备驱动管理
  • -
  • axfs:文件系统支持
  • -
  • axhal:硬件抽象层,定义了一系列的平台API,如trap入口等
  • -
  • axlog:log输出层
  • -
  • axnet:网络模块
  • -
  • axruntime:运行库,定义了内核的启动逻辑
  • -
  • axsync:实现同步模块
  • -
  • axmem:地址空间模块
  • -
  • axprocess:进程模块,也实现了动态加载
  • -
  • axsignal:信号模块
  • -
  • -

    axtask:定义了任务与调度序列的操作

    -
  • -
  • -

    apps:unikernel架构下的用户程序,继承原有ArceOS

    -
  • -
  • -

    ulib:用户库,继承原有ArceOS,并添加了starry_libax部分作为Linux兼容层。

    -
  • -
  • -

    为了实现宏内核架构体系,需要对原有Arceos的部分核心模块(如axtask)进行修改。为了防止合并时冲突过多,因此在对应模块下建立monolithic*为前缀的文件夹,存放为宏内核架构实现的内容。同时使用条件编译来选择是宏内核架构还是unikernel架构。

    -
  • -
  • -

    为了实现linux APP兼容,需要实现一系列面向linux的系统调用。我们将系统调用的具体实现部分放在starry_libax部分,即以用户库的形式形成一个linux兼容层。通过调用上述模块提供的一系列接口,实现对应的linux 系统调用,并暴露给外界。这个系统兼容层与原有的libax进行对应,分别提供不同的接口与服务。

    -
  • -
  • -

    模块部分放置可以为宏内核与unikernel尽可能共享的内容,通过条件编译等方式做到尽可能地为不同架构下的兼容层所调用。

    -
  • -
-

结构图对比

-

原先Arceos结构图:

-

ArceOS

-

重构后StarryOS架构图:

-

Starry

-

Starry的模块依赖图如下:

-

modules

-

结构优势

-
    -
  1. 用相同的代码组件,利用条件编译等方式可以组建出不同架构的OS内核,从而可以达到使用不同的启动参数来启动不同架构的内核,大大提高内核的泛用性。
  2. -
  3. 在利用unikernel可插拔的特性的基础上,可以使得实现某一个功能的crate和整体OS进一步解耦,从而利于更新换代。
  4. -
  5. 解耦的特性利于开发模式的分工,不同开发人员可以负责不同的module或者crate内容,只要实现了对应的接口便可以较好地适配本内核,从而方便其他开发人员参与其中不断完善。
  6. -
- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\246\202\350\277\260/index.html" "b/doc/Starry/site/\346\246\202\350\277\260/index.html" deleted file mode 100644 index dbef50c..0000000 --- "a/doc/Starry/site/\346\246\202\350\277\260/index.html" +++ /dev/null @@ -1,751 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 概述 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

概述

- -

背景

-

Starry是在ArceOsrcore-os/arceos: An experimental modular OS written in Rust.基础上进行开发的、以宏内核架构运行Linux应用的内核。原有的ArceOS设计架构为Unikernel,后续计划在原有代码结构的基础上设计宏内核架构和微内核架构,而Starry即是ArceOS宏内核架构化的一个成果。

-

目前测例支持

-

当前测例支持如下:

-
    -
  • musl-libc:静态链接与动态链接均已支持,实现的特性有动态库加载、线程、信号、futex等
  • -
  • lua:已经支持
  • -
  • busybox:已经支持大部分指令,通过了比赛的测例
  • -
  • lmbench:已经支持,可以使用lmbench测算内核性能
  • -
  • iperf/netperf:支持大部分测例,可以实现网络的基本功能
  • -
  • UnixBench:已经支持,可以用来测算内核在文件读取、数据基本操作等方面的性能
  • -
  • libc-bench:已经支持
  • -
-

使用方式

-

详见主页面的README.md

-

相关依赖库均已本地化在vendor文件夹中

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/axsignal.png" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/axsignal.png" deleted file mode 100644 index 20c2744..0000000 Binary files "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/axsignal.png" and /dev/null differ diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png" deleted file mode 100644 index fb1886c..0000000 Binary files "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png" and /dev/null differ diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png:Zone.Identifier" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png:Zone.Identifier" deleted file mode 100644 index 080244f..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/assets/signal.png:Zone.Identifier" +++ /dev/null @@ -1,3 +0,0 @@ -[ZoneTransfer] -ZoneId=3 -HostUrl=http://rcore-os.cn/rCore-Tutorial-Book-v3/_images/signal.png diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\344\273\273\345\212\241\350\260\203\345\272\246\346\250\241\345\235\227-axtask/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\344\273\273\345\212\241\350\260\203\345\272\246\346\250\241\345\235\227-axtask/index.html" deleted file mode 100644 index 6288d47..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\344\273\273\345\212\241\350\260\203\345\272\246\346\250\241\345\235\227-axtask/index.html" +++ /dev/null @@ -1,946 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 任务调度模块-axtask - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

任务调度模块-axtask

- -

任务调度是内核实现过程中非常重要的环节。为了保证和上游arceos仓库较好的进行匹配,因此starry的任务调度机制基本参照了arceos的调度机制,并在此基础上进行了适配宏内核的调整。

-

为了实现宏内核架构体系,需要对原有Arceos的部分核心模块(如axtask)进行修改。为了防止合并时冲突过多,因此在对应模块下建立monolithic_task文件夹,存放为宏内核架构实现的内容。同时使用条件编译来选择是宏内核架构还是unikernel架构。

-

以下为Starry实现的任务调度模块的相关功能划分:

-

avatar

-

对功能的额外补充说明如下:

-

task

-

任务单元是内核运行过程中非常重要的组成部分,任务调度模块的组成如下:

-
pub struct TaskInner {
-    id: TaskId,
-    name: String,
-    is_idle: bool,
-    is_init: bool,
-
-    entry: Option<*mut dyn FnOnce()>,
-    state: AtomicU8,
-
-    in_wait_queue: AtomicBool,
-    #[cfg(feature = "irq")]
-    in_timer_list: AtomicBool,
-
-    #[cfg(feature = "preempt")]
-    need_resched: AtomicBool,
-    #[cfg(feature = "preempt")]
-    pub preempt_disable_count: AtomicUsize,
-
-    exit_code: AtomicI32,
-    wait_for_exit: WaitQueue,
-
-    #[cfg(feature = "monolithic")]
-    kstack: Option<TaskStack>,
-
-    ctx: UnsafeCell<TaskContext>,
-
-    #[cfg(feature = "monolithic")]
-    // 对应进程ID
-    process_id: AtomicU64,
-
-    #[cfg(feature = "monolithic")]
-    /// 是否是所属进程下的主线程
-    is_leader: AtomicBool,
-
-    #[cfg(feature = "monolithic")]
-    // 所属页表ID,在宏内核下默认会开启分页,是只读的所以不用原子量
-    page_table_token: usize,
-
-    #[cfg(feature = "monolithic")]
-    /// 初始化的trap上下文
-    pub trap_frame: UnsafeCell<TrapFrame>,
-
-    // 时间统计
-    #[cfg(feature = "monolithic")]
-    time: UnsafeCell<TimeStat>,
-
-    #[allow(unused)]
-    #[cfg(feature = "monolithic")]
-    /// 子线程初始化的时候,存放tid的地址
-    set_child_tid: AtomicU64,
-
-    #[cfg(feature = "monolithic")]
-    /// 子线程初始化时,将这个地址清空;子线程退出时,触发这里的 futex。
-    /// 在创建时包含 CLONE_CHILD_SETTID 时才非0,但可以被 sys_set_tid_address 修改
-    clear_child_tid: AtomicU64,
-
-    #[cfg(feature = "monolithic")]
-    /// 退出时是否向父进程发送SIG_CHILD
-    pub send_sigchld_when_exit: Bool,
-}
-
-

可以看出,任务结构体中的某些字段包含着多核安全性,因为虽然一个任务仅会在一个CPU核上运行,但是不同CPU可能会同时访问同一个任务的某一个字段,导致出现多核冲突,因此需要为对应字段加上原子性。

-

另外,task字段也提供了某一个任务第一次执行的实现。它需要根据是否为宏内核架构分别进行实现。

-
    -
  • Arceos实现:在Arceos下,代码始终在内核态下运行,所以可以直接跳转到任务入口函数执行。因此会把入口函数的地址直接记录在task的entry字段上,并且在第一次执行任务时直接跳转到entry字段的地址即可。
  • -
  • Starry实现:在Starry下,任务会进入到用户态运行,此时需要把任务初始化的trap上下文放置到内核栈上,并且进行sret跳转。
  • -
-

run_queue

-

任务调度是任务模块实现的重点。接下来简要介绍以下starry的任务启动和调度流程。

-

当前任务调度机制是fifo队列法,启动和调度方式如下:

-
    -
  • 单核情况
  • -
-

对应代码在modules/axtask/src/monolithic_task/run_queue.rs/init函数中:

-
pub(crate) fn init() {
-    const IDLE_TASK_STACK_SIZE: usize = 0x20000;
-    let idle_task = TaskInner::new(
-        || crate::run_idle(),
-        "idle".into(),
-        IDLE_TASK_STACK_SIZE,
-        KERNEL_PROCESS_ID,
-        0,
-        false,
-    );
-    IDLE_TASK.with_current(|i: &mut LazyInit<Arc<scheduler::FifoTask<TaskInner>>>| {
-        i.init_by(idle_task.clone())
-    });
-
-    let main_task = TaskInner::new_init("main".into());
-    main_task.set_state(TaskState::Running);
-
-    RUN_QUEUE.init_by(AxRunQueue::new());
-    unsafe { CurrentTask::init_current(main_task) }
-}
-
-

共包含三个任务:

-
    -
  • -

    idle_task:拥有独立的trap上下文和任务上下文,任务上下文指向的入口是run_idle函数。

    -
  • -
  • -

    gc_task:在执行AxRunQueue::new()函数时生成,负责回收已经退出的任务。

    -
  • -
  • -

    main_task:内核运行时执行的任务,它的任务上下文为空,在被切换时会把当前的ra等信息写入任务上下文,从而可以在恢复时继续执行内核相关代码。

    -
  • -
-

当执行完init函数之后,CPU指向main_task,pc不变,继续执行当前代码,直到来到modules/axruntime/src/lib.rs/rust_main函数的unsafe{main();}入口,从而跳转到Arceos指定的用户程序(注意:虽然是用户程序,但是运行在arceos框架下,还处于内核态),开始加载测例。默认make run会运行apps/syscall/busybox程序。若测例程序会通过clone等方式生成新的任务,那么新任务会被加入到任务调度队列等待被调度。

-
    -
  • -

    若调度队列中还有任务等待被调度,那么就会切换到对应任务。此时若调度的任务是gc,则gc会检测是否还有任务退出。若有任务已经退出等待回收,则gc会回收这些任务。若没有则阻塞gc本身,切换到其他任务。

    -

    gc的实现方式如下:

    -
    fn gc_entry() {
    -    loop {
    -        // Drop all exited tasks and recycle resources.
    -        while !EXITED_TASKS.lock().is_empty() {
    -            // Do not do the slow drops in the critical section.
    -            let task = EXITED_TASKS.lock().pop_front();
    -            if let Some(task) = task {
    -                // If the task reference is not taken after `spawn()`, it will be
    -                // dropped here. Otherwise, it will be dropped after the reference
    -                // is dropped (usually by `join()`).
    -                // info!("drop task: {}", task.id().as_u64());
    -                drop(task);
    -            }
    -        }
    -        WAIT_FOR_EXIT.wait();
    -    }
    -}
    -
    -
  • -
  • -

    若调度队列中没有下一个任务时,就会切换到idle_task,此时会执行run_idle函数,即不断执行yield_task函数,直到有新的任务加入调度队列,则切换到对应任务。

    -

    run_idle函数实现方式如下:

    -
    pub fn run_idle() -> ! {
    -    loop {
    -        yield_now();
    -        debug!("idle task: waiting for IRQs...");
    -        #[cfg(feature = "irq")]
    -        axhal::arch::wait_for_irqs();
    -    }
    -}
    -
    -
  • -
  • -

    多核启动

    -
  • -
-

我们只考虑任务调度相关,则多核情况下,其他核初始化的函数在modules/axtask/src/monolithic_task/run_queue.rs/init_secondary中,会新建一个idle_task,但是它的功能类似于单核启动下的main_task,即初始化时没有任务上下文,但是可以在被切换之后保留内核的任务执行流。

-

初始化完毕之后,每一个非主核指向一个idle_task,此时他们会继续执行内核中的初始化代码,最后在modules/axruntime/src/mp.rsrust_main_secondary函数中执行run_idle函数,即不断地yield自己,直到有新的任务加入调度队列。

-

当测例对应的用户态任务执行clone系统调用,生成新的任务加入到调度队列时,此时就会随机分配一个CPU核获得该任务并且进行执行。这就是多核启动的原理。

-

stat

-

stat实现了任务的时间记录功能和计时器功能。

-

记录任务运行时间是通过计算和更新时间戳进行的,每一个stat结构体都拥有如下结构:

-
/// 用户态经过的时间,单位为纳秒
-utime_ns: usize,
-/// 内核态经过的时间,单位为纳秒
-stime_ns: usize,
-/// 进入用户态时标记当前时间戳,用于统计用户态时间
-user_tick: usize,
-/// 进入内核态时标记当前时间戳,用于统计内核态时间
-kernel_tick: usize,
-
-

更新时间戳的时间点共有四个:

-
    -
  • 从用户态进入内核态
  • -
  • 从内核态进入用户态
  • -
  • 切换到本任务
  • -
  • 本任务被切换走
  • -
-

相关更新运行时间的代码如下:

-
/// 从用户态进入内核态,记录当前时间戳,统计用户态时间
-pub fn into_kernel_mode(&mut self, tid: isize) {
-    let now_time_ns = current_time_nanos() as usize;
-    let delta = now_time_ns - self.user_tick;
-    self.utime_ns += delta;
-    self.kernel_tick = now_time_ns;
-}
-/// 从内核态进入用户态,记录当前时间戳,统计内核态时间
-pub fn into_user_mode(&mut self, tid: isize) {
-    // 获取当前时间,单位为纳秒
-    let now_time_ns = current_time_nanos() as usize;
-    let delta = now_time_ns - self.kernel_tick;
-    self.stime_ns += delta;
-    self.user_tick = now_time_ns;
-}
-/// 内核态下,当前任务被切换掉,统计内核态时间
-pub fn swtich_from(&mut self, tid: isize) {
-    // 获取当前时间,单位为纳秒
-    let now_time_ns = current_time_nanos() as usize;
-    let delta = now_time_ns - self.kernel_tick;
-    self.stime_ns += delta;
-}
-/// 内核态下,切换到当前任务,更新内核态时间戳
-pub fn switch_to(&mut self, tid: isize) {
-    // 获取当前时间,单位为纳秒
-    let now_time_ns = current_time_nanos() as usize;
-    let delta = now_time_ns - self.kernel_tick;
-    // 更新时间戳,方便当该任务被切换时统计内核经过的时间
-    self.kernel_tick = now_time_ns;
-}
-
- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\344\277\241\345\217\267\346\250\241\345\235\227-axsignal/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\344\277\241\345\217\267\346\250\241\345\235\227-axsignal/index.html" deleted file mode 100644 index b0138a6..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\344\277\241\345\217\267\346\250\241\345\235\227-axsignal/index.html" +++ /dev/null @@ -1,747 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 信号模块-axsignal - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

信号模块-axsignal

- -

axsignal是starry的信号模块,负责实现进程间、任务间等通信机制。当前实现的原理主要借鉴于Linux的信号机制。相关功能划分如下:

-

avatar

-

其中各部分的额外补充说明如下:

-

action

-

action.rs指定了处理某一信号时的具体操作方式。操作方式的指定是通过定义SigAction结构体实现的,相关内容如下:

-
pub struct SigAction {
-    /// 信号处理函数的地址
-    /// 1. 如果是上述特殊值 SIG_DFL 或 SIG_IGN,则按描述处理
-    /// 2. 若flags没有指定SA_SIGINFO,则函数原型为 fn(sig: SignalNo) -> (),对应C语言原型为 void (*sa_handler)(int)
-    /// 3. 若flags指定了SA_SIGINFO,则函数原型为 fn(sig: SignalNo, info: &SigInfo, ucontext: &mut UContext) -> (),
-    /// 对应C语言原型为 void (*sa_sigaction)(int, siginfo_t *, void *)。
-    ///
-    /// 其中,SigInfo和SignalNo的定义见siginfo.rs和signal_no.rs。
-    /// UContext即是处理信号时内核保存的用户态上下文,它存储在用户地址空间,会在调用sig_return时被恢复,定义见ucontext.rs。
-    pub sa_handler: usize,
-    /// 信号处理的flags
-    pub sa_flags: SigActionFlags,
-    /// 信号处理的跳板页地址,存储了sig_return的函数处理地址
-    /// 仅在SA_RESTORER标志被设置时有效
-    pub restorer: usize,
-    /// 该信号处理函数的信号掩码
-    pub sa_mask: usize,
-}
-
-

其中值得说明的是restorer。想要了解这个restorer就需要了解Linux规定的信号处理机制流程:

-

avatar

-
-

上图引用自rCore教学文档信号 - rCore-Tutorial-Book-v3 3.6.0-alpha.1 文档 (rcore-os.cn)

-
-

根据上图可知,当进入信号处理阶段之后,若指定了信号处理例程,那么内核会返回用户态,跳转到信号处理函数对应入口进行信号处理。

-

传统的C语言函数中,函数执行结束时,内核会将ra寄存器的值赋给pc,即pc跳转到ra指定的地址上。

-

而对于信号处理函数,自然也需要一个返回地址,即我们刚才提到的restorer字段。

-

当信号处理函数执行完毕,会出现以下两种情况:

-
    -
  1. 用户手动指定了返回地址restorer:此时由于我们的信号处理函数编译之后,会在结束时自动跳转到ra上,因此我们只需要在信号处理函数开始前,将restorer字段赋给ra寄存器即可。之后信号处理函数执行完毕之后就会跳转到指定地址。
  2. -
  3. 用户未手动调用返回地址restorer:此时内核需要手动帮助用户执行sig_return系统调用,其功能是告知内核信号已经处理完毕,方便内核恢复因为处理信号而被打断的trap上下文。而手动处理的方式即是将restorer字段设置为一个非法的特殊字段:SIGNAL_RETURN_TRAP。当用户态下的信号处理函数执行完毕时,它会自动跳转到ra寄存器指定的地址,即跳转到SIGNAL_RETURN_TRAP,从而触发InstructionPageFault。此时内核捕获到trap之后,就可以根据触发page fault的地址判断是否触发了sig_return。若是,则手动调用sig_return系统调用即可。
  4. -
-

因此,通过对restorer的合理使用,我们可以比较巧妙地实现信号处理的返回。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\345\255\230\347\256\241\347\220\206\346\250\241\345\235\227-axmem/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\345\255\230\347\256\241\347\220\206\346\250\241\345\235\227-axmem/index.html" deleted file mode 100644 index 5582c14..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\345\255\230\347\256\241\347\220\206\346\250\241\345\235\227-axmem/index.html" +++ /dev/null @@ -1,787 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 内存管理模块-axmem - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

内存管理模块-axmem

- -

axmem 模块中提供了关于地址空间、内存段等结构的抽象。并负责动态加载应用程序、进程的 fork() / spawn()、内存管理(mmap、shmat)等基本任务。

-

MemorySet

-

MemorySet 代表一个进程所拥有(或多个线程共有)的地址空间。从一个用户程序“生命周期”的角度考虑。内核使用MemorySet::map_elf()加载 elf 文件中的内容,通过 clone()、mmap()、munmap()、add_shared_mem() 等函数执行由 syscall 传递而来的各种操作,最终在 drop() 中回收资源。

-

地址空间中最为核心的数据结构是页表(page_table)。使用RAII思想,页表(PageTable 类型)拥有页表本身使用的物理页。

-

除页表外,owned_mem 记录了在通过 mmap 以及应用程序加载时所获得的全部虚拟内存段。private_mem 和 sttached_mem 分别记录了进程所拥有的 System V Shared Memory。

-

以及,MemorySet 会记录加载自 ELF 文件的 entry 地址。

-
/// PageTable + MemoryArea for a process (task)
-pub struct MemorySet {
-    page_table: PageTable,
-    owned_mem: BTreeMap<usize, MapArea>,
-
-    private_mem: BTreeMap<i32, Arc<SharedMem>>,
-    attached_mem: Vec<(VirtAddr, MappingFlags, Arc<SharedMem>)>,
-
-    pub entry: usize,
-}
-
-

SharedMem

-

本数据结构代表用户程序通过 shmat() syscall 申请的共享内存。同样使用 RAII 思想,SharedMem::pages 中存放共享内存段所实际分配的物理页。这使得当我们 drop SharedMem 时,对应的物理内存也会自动释放。 -SharedMem::info 记录了该段共享内存的属性信息。

-
pub struct SharedMem {
-    pages: GlobalPage,
-    pub info: SharedMemInfo,
-}
-
-

对于进程私有的共享内存,SharedMem 会被放入进程的 MemorySet::private_mem 中保存。对于公开的跨进程共享内存,则会存储在全局数据结构 SHARED_MEMS 中。

-
/// This struct only hold SharedMem that are not IPC_PRIVATE. IPC_PRIVATE SharedMem will be stored
-/// in MemorySet::detached_mem.
-///
-/// This is the only place we can query a SharedMem using its shmid.
-///
-/// It holds an Arc to the SharedMem. If the Arc::strong_count() is 1, SharedMem will be dropped.
-pub static SHARED_MEMS: SpinNoIrq<BTreeMap<i32, Arc<SharedMem>>> = SpinNoIrq::new(BTreeMap::new());
-pub static KEY_TO_SHMID: SpinNoIrq<BTreeMap<i32, i32>> = SpinNoIrq::new(BTreeMap::new());
-
-

当进程“挂载(映射)”某一共享内存段时,SharedMem 也会被加入 MemorySet::sttached_mem 中,便于执行进程的其他操作时访问。使用 Arc 数据结构可以得到“一段共享内存被多少个进程加载了”的信息,以便及时回收内存。

-

MapArea

-

MapArea 代表一段虚拟内存。在这个数据结构中需要记录虚拟内存的起始地址、属性信息、对应的物理页与文件后端。

-
pub struct MapArea {
-    pub pages: Vec<Option<PhysPage>>,
-    /// 起始虚拟地址
-    pub vaddr: VirtAddr,
-    pub flags: MappingFlags,
-    pub backend: Option<MemBackend>,
-}
-
-

这里的 pages 使用了 Vec 存储若干单独的物理页,而非一整个物理页段。这是因为连续的一段虚拟内存对应的物理内存可能是不连续的。同时,Option 意味着物理内存可能尚未分配。这是本 OS 具有的 Lazy Load 功能。 -用户态中连续已分配的内存区间可能实际上没有分配,当用户使用到未分配区段时,将触发 PageFault,此时将交由 MapArea::handle_page_fault() 处理,分配实际的物理内存。

-

为了实现 mmap 映射文件的 Lazy Load 功能,MapArea 中记录了一个可选的文件后端 MemBackend。处理 PageFault 时,如果此段内存具有对应的文件后端,则会将文件对应位置的内容写入新分配的内存。此外,为了实现 msync() 等强制同步内存与对应文件的 syscall,提供了 MapArea::sync_page_with_backend() 函数。

-

除了处理内存的懒加载,MapArea 还提供了对连续内存段的编辑功能。shrink_left()、shrink_right()、split()、split3() 函数可以修改当前内存段的大小,并及时释放物理内存。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\345\272\225\345\261\202\346\250\241\345\235\227-axhal/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\345\272\225\345\261\202\346\250\241\345\235\227-axhal/index.html" deleted file mode 100644 index a256290..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\345\272\225\345\261\202\346\250\241\345\235\227-axhal/index.html" +++ /dev/null @@ -1,710 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 内核底层模块-axhal - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

内核底层模块-axhal

- -

内核底层模块--axhal

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\350\277\220\350\241\214\346\227\266\346\250\241\345\235\227-axruntime/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\350\277\220\350\241\214\346\227\266\346\250\241\345\235\227-axruntime/index.html" deleted file mode 100644 index ab3b8b0..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\206\205\346\240\270\350\277\220\350\241\214\346\227\266\346\250\241\345\235\227-axruntime/index.html" +++ /dev/null @@ -1,677 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 内核运行时模块-axruntime - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

内核运行时模块-axruntime

- -

axruntime作为内核运行时模块,统筹了其他所有的内核模块。根据内核模块依赖图可知,runtimer模块是最上层的模块,它更多的是调用其他模块对外提供的接口来启动内核,并没有过多的新增功能,因此我们仅在这部分简单阐述Starry内核的启动流程。

-

详细代码参见axruntime/src/lib.rs:107,其启动流程如下:

-
    -
  1. 实现alloc trait,从而实现全局分配器
  2. -
  3. 建立内核地址空间,划分地址段
  4. -
  5. 初始化平台配置,包括多核CPU定义的初始化
  6. -
  7. 建立内核进程,初始化建立idle task和gc task,启动任务调度序列
  8. -
  9. 启动外置驱动,包括fs、display、net
  10. -
  11. 若有多核则启动多核入口函数
  12. -
  13. 初始化时钟中断处理函数
  14. -
  15. 运行主核的主函数,即运行指定的应用程序
  16. -
-

比赛时需要有几点注意的地方:

-
    -
  1. 为遵循比赛需求,starry需要读取外部测例镜像。但由于SD卡镜像读取驱动较为复杂,因此比赛中默认将已有的SD卡镜像通过网络传输的方式传递到实际板子的0x90000000物理地址处。因此设置内核地址空间时,需要将这段空置出来。当前Starry默认启动的物理内存占用为[0x8000_0000,0x8800_0000)与[0xa000_0000, 0xc000_0000)。对应的特殊处理在axhal/src/platform/qemu_virt_riscv/mem.rs中。
  2. -
  3. 实际上板时,由于fu740不存在virt-io设备,因此需要注意不能直接将虚拟设备进行初始化,否则可能出现问题。
  4. -
- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\256\217\345\206\205\346\240\270\347\224\250\346\210\267\345\272\223-starry/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\256\217\345\206\205\346\240\270\347\224\250\346\210\267\345\272\223-starry/index.html" deleted file mode 100644 index 802a145..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\345\256\217\345\206\205\346\240\270\347\224\250\346\210\267\345\272\223-starry/index.html" +++ /dev/null @@ -1,751 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 宏内核用户库-starry - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

宏内核用户库-starry

- -

根据starry的模块化设计思路,用户库是在给定模块的基础上进行统合、提供对外统一接口的代码部分。而宏内核架构下对外提供的接口以Linux的系统调用形式进行呈现。因此starry_libax部分主要便是对系统调用的封装实现以及批量测试的实现。

-

avatar

-

各部分的额外补充说明如下

-

syscall

-

关于syscall模块各自文件功能额外说明如下:

- -

futex的原理是以一个指定的变量作为futex变量,多个任务在等待获取这个变量的执行权限。但是否会出现多任务同时操作同一个变量的冲突问题不由内核考虑,而是由用户自行考虑并且实现,而内核只需要实现futex相关的操作对应的语义即可。

-

关于futex的核心操作有两个:wait和wake。以下分别介绍这两种操作的处理方式:

-
    -
  • wait:当一个任务调用futex的wait操作时,会指定一个futex变量的地址,此时代表着这个任务需要等待该futex的权限。那么这个任务会被加入到该futex变量的等待序列之中。之后任务会按照指定的休眠时间进行休眠,直到被唤醒。
  • -
  • wake:当某一个任务完成了对某一个futex变量的操作之后,会调用futex的wake操作,此时代表着释放了该futex变量。内核需要从该futex变量的等待序列中找到一个仍然在休眠的任务,并且手动唤醒它,接管futex变量的权限。
  • -
-

当一个任务wait for一个futex变量时,其被唤醒的方式有三种:

-
    -
  1. 原有的futex变量被释放,该任务获得了控制权
  2. -
  3. 任务休眠时间到期
  4. -
  5. 原有futex变量地址上存储的值被改变
  6. -
-

依据上述三种情况,即可实现futex系统调用的相关处理方式。

-

fs

-

fs模块是为了支持文件相关的系统调用而实现的功能,包括文件描述符、链接、挂载等功能。之所以将该模块放在这个部分而不是放在axprocess或者axfs中,是因为文件描述符等内容是与Linux系统调用耦合度较高的内容,是系统调用的特定设置,在其他如微内核的架构中也存在着类似文件系统的功能,但不一定要具化到文件描述符。因此axfs中存放的是文件系统的统一实现,而如文件描述符等较贴近Linux的内容则放在Linux兼容层用户库starry_libax中实现,从而更加贴近模块化内核的设计思路。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227-axfs/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227-axfs/index.html" deleted file mode 100644 index cc8f288..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\346\226\207\344\273\266\347\263\273\347\273\237\346\250\241\345\235\227-axfs/index.html" +++ /dev/null @@ -1,824 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 文件系统模块-axfs - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

文件系统模块-axfs

- -

介绍文件系统时,不仅需要介绍axfs这个模块,还需要介绍其依赖的crate以及调用这个模块的package,他们共同构成了文件系统的上下层,使得文件系统可以正常发挥作用。

-

文件系统主要由四个部分组成,分别是外部依赖fatfs、crates/axfs_vfs、modules/axfs以及作为用户库的starry_libax/src/fs。

-

avatar

-

各自部分的额外补充说明如下

-

fatfs

-

fatfs作为外部库,提供了一个基础的fat32文件系统。

-

crates/axfs_vfs

-

axfs_vfs提供了对文件和目录的抽象,为本os实现的任何文件系统都需要实现它的定义的VfsOps特征,同时对应文件系统的file/directory结构体需要实现它的VfsNodeOps特征。

-

modules/axfs

-

在modules/axfs中:

-
    -
  1. axfs::fatfs作为中介连接了文件系统、vfs和块设备三个模块,它封装了外部的fat32提供的文件系统和file/directory,并为它们实现axfs_vfs中的对应特征,同时调用了axfs::dev对硬件进行操作;
  2. -
  3. axfs::fops封装了ax_vfs中的各种VfsNode操作,向上提供给axfs::api模块暴露给外部;
  4. -
  5. axfs::monolithic_fs是将文件系统适配到宏内核的核心,它提供了文件系统信息Kstat、文件输入输出操作FileIO、文件-虚存映射FileExt等结构体和特征的抽象。
  6. -
-

starry_libax/fs

-

在starry_libax中所做的工作主要有:

-
    -
  1. 定义文件夹、文件、管道等结构体,并为它们实现monolithic_fs中定义的一些特征,以文件为例:
  2. -
-
/// 文件描述符
-pub struct FileDesc {
-    /// 文件路径
-    pub path: String,
-    /// 文件
-    pub file: Arc<Mutex<File>>,
-    /// 文件打开的标志位
-    pub flags: OpenFlags,
-    /// 文件信息
-    pub stat: Mutex<FileMetaData>,
-}
-
-/// 文件在os中运行时的可变信息
-pub struct FileMetaData {
-    /// 最后一次访问时间
-    pub atime: TimeSecs,
-    /// 最后一次改变(modify)内容的时间
-    pub mtime: TimeSecs,
-    /// 最后一次改变(change)属性的时间
-    pub ctime: TimeSecs,
-}
-impl Read for FileDesc {
-    ..
-}
-
-impl Write for FileDesc {
-    ..
-}
-
-impl Seek for FileDesc {
-    ..
-}
-
-impl FileExt for FileDesc {
-    ..
-}
-/// 为FileDesc实现FileIO trait
-impl FileIO for FileDesc {
- ..
-}
-
-
    -
  1. 实现文件链接、文件系统挂载、目录项遍历等功能。
  2. -
-

需要注意的是,fat32文件系统不支持硬连接,我们做的工作实际上是在内存里模拟硬连接的过程。在目前的实现里,每个对于文件的访问传入的“文件路径”实际上都是一个虚拟的路径,只是作为KEY存入模拟硬连接的BTreeMap里,映射到它在文件镜像中的实际位置,包括恒等映射。

-
-

由于硬连接的一些特性,这种模拟在某些情境下会出现一些问题。

-

例如,假设A路径是位于硬盘上的A文件的实际路径,B路径则是后创建的一个指向A文件的硬连接,删除A后因为有B存在,实际上只会减少A文件的硬连接数,不会删除实际文件A。这时再创建一个新的A文件时便会报错。

-

针对这个问题,我们采用过的一个解决办法是对每个实际的文件维护一个记录指向它的硬连接的列表,删除实际路径时,弹出出列表首项并将实际文件移动到对应路径,然后从BTreeMap中删除该项,让它成为新的实际路径。

-
-
    -
  1. 实现所需的各类文件系统相关的系统调用。
  2. -
- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\347\275\221\347\273\234\346\250\241\345\235\227-axnet/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\347\275\221\347\273\234\346\250\241\345\235\227-axnet/index.html" deleted file mode 100644 index b851fdc..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\347\275\221\347\273\234\346\250\241\345\235\227-axnet/index.html" +++ /dev/null @@ -1,759 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 网络模块-axnet - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

网络模块-axnet

- -

axnet 提供了对网络设备的驱动与封装。StarryOS 使用了开源的 smoltcp 库作为其网络协议栈。并在 smoltcp 提供的 API 基础上,封装了 TCPSocket 与 UDPSocket 两个套接字类型。

-

Linux syscall 所提供的 Socket API 的实现位于 ulib/socket.rs 中。

-
/// 包装内部的不同协议 Socket
-pub struct Socket {
-    #[allow(dead_code)]
-    domain: Domain,
-    socket_type: SocketType,
-    inner: SocketInner,
-    close_exec: bool,
-    recv_timeout: Option<TimeVal>,
-
-    reuse_addr: bool,
-    dont_route: bool,
-    send_buf_size: usize,
-    recv_buf_size: usize,
-    congestion: String,
-}
-
-

Socket

-

Socket 封装了由 axnet 提供的 TCP/UDP Socket(SocketInner)。并记录了此 Socket 在 Linux Socket API 层具有的其他信息,如 domain(Address Family)、type,以及一些配置信息,如 recv_timeout、close_exec。

-

此 Socket 类型实现了如 bind()、connect()、accept() 等操作,再 syscall 的实际代码中,只需使用这些函数,无需与 axnet 交互。

-

Socket 与其他文件相关的类型相同,实现了 FileExt 与 FileIO trait,使得 Socket 对象可以存储在进程的 FdTable 中。也因如此,read()、write() 等面向文件实现的 syscall 也可用于 socket。

-

SocketOption、TcpSocketOption

-

Linux Socket API 中关于,可以通过 Socket Option 来修改或获取 Socket 的各项选项。对于不同的选项,分别实现了 get() 与 set() 函数,简洁地实现所需功能。

-
#[derive(TryFromPrimitive, Debug)]
-#[repr(usize)]
-#[allow(non_camel_case_types)]
-pub enum SocketOption {
-    SO_REUSEADDR = 2,
-    SO_DONTROUTE = 5,
-    SO_SNDBUF = 7,
-    SO_RCVBUF = 8,
-    SO_KEEPALIVE = 9,
-    SO_RCVTIMEO = 20,
-}
-
- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\350\277\233\347\250\213\346\216\247\345\210\266\346\250\241\345\235\227-axprocess/index.html" "b/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\350\277\233\347\250\213\346\216\247\345\210\266\346\250\241\345\235\227-axprocess/index.html" deleted file mode 100644 index 42bd176..0000000 --- "a/doc/Starry/site/\346\250\241\345\235\227\344\273\213\347\273\215/\350\277\233\347\250\213\346\216\247\345\210\266\346\250\241\345\235\227-axprocess/index.html" +++ /dev/null @@ -1,767 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 进程控制模块-axprocess - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

进程控制模块-axprocess

- -

进程部分是宏内核实现的核心部分,它作为一个资源容器收纳了任务、信号、内存、文件系统等模块的功能,并且进行统筹管理。

-

进程模块的相关功能划分如下

-

avatar

-

进程模块更多是对已有实现模块的一个总结, 因此该部分的额外说明并不会特别多,仅是起一个总结的作用。

-

额外补充如下

-

process

-

process部分实现了进程控制块的主体部分,其进程控制块定义如下:

-
pub struct ProcessInner {
-    /// 父进程的进程号
-    pub parent: u64,
-    /// 子进程
-    pub children: Vec<Arc<Process>>,
-    /// 子任务
-    pub tasks: Vec<AxTaskRef>,
-    /// 地址空间,由于存在地址空间共享,因此设计为Arc类型
-    pub memory_set: Arc<SpinNoIrq<MemorySet>>,
-    /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量
-    pub heap_bottom: usize,
-    /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小
-    pub heap_top: usize,
-    /// 进程状态
-    pub is_zombie: bool,
-    /// 退出状态码
-    pub exit_code: i32,
-    #[cfg(feature = "fs")]
-    pub fd_manager: FdManager,
-    /// 进程工作目录
-    pub cwd: String,
-    #[cfg(feature = "signal")]
-    /// 信号处理模块    
-    /// 第一维代表线程号,第二维代表线程对应的信号处理模块
-    pub signal_module: BTreeMap<u64, SignalModule>,
-
-    /// robust list存储模块
-    /// 用来存储线程对共享变量的使用地址
-    /// 具体使用交给了用户空间
-    pub robust_list: BTreeMap<u64, FutexRobustList>,
-}
-
-

可以看出进程控制块内融合了包括文件、信号、互斥锁、内存地址空间等一系列内容,通过feature条件编译的方式可以方便地对模块进行可插拔编译,符合模块化的内核设计思想。

-

futex

-

在进程部分定义了与互斥锁相关的数据结构FUTEX_WAIT_TASK,其是一个从地址到任务指针的map映射,存储了每一个futex变量对应的正在等待的任务序列。

-

之所以将该数据结构定义在axprocess模块,是因为需要在进程退出时,清空FUTEX_WAIT_TASK中存储的进程Arc指针,从而保证对象能够完整被释放。

-

futex的完整实现在starry/syscall/futex中。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\350\256\276\350\256\241\346\200\235\350\267\257/index.html" "b/doc/Starry/site/\350\256\276\350\256\241\346\200\235\350\267\257/index.html" deleted file mode 100644 index 99abafd..0000000 --- "a/doc/Starry/site/\350\256\276\350\256\241\346\200\235\350\267\257/index.html" +++ /dev/null @@ -1,1027 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - 设计思路 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - -
-
-
- - - -
-
-
- - - -
-
- - - - -

设计思路

- -

模块划分

-

依据模块化内核的设计思想,我们期望我们的内核能够在尽可能保留原有unikernel的基础上同时兼容宏内核功能,因此我们在arceos的基础上新增了如下模块:

-
    -
  • axmem:引入地址空间
  • -
  • axtask/monolithic_task:修改原有task模块,添加了更多任务状态,从而使得任务可以作为线程的形式被进程调度
  • -
  • axsignal:信号模块
  • -
  • axprocess:引入进程概念,支持多进程多线程运行,添加了很多与Linux系统调用相关的内容
  • -
  • starry_libax:Linux系统调用用户库,包装了作为Linux兼容层的众多对外接口。
  • -
-

进程引入

-

为了运行Linux相关的应用,我们需要让不同任务之间存在父子等关系,因此我们引入了进程的概念。在标准的Linux中,进程和线程统一用pthread结构体代替,但我们为了保证原有arceos的任务调度结构不受过大影响,因此选择将进程和线程进行分离,进程保存在独立的结构体Process中。

-

依据模块化的思想,我们可以将进程视为一个容器,存储了各类运行时资源,包括虚存、文件描述符、 -线程、信号等。 -在该种设计理念下,进程仅是对上述资源的一个统一与包装。因此可以通过添加 feature 等方式将进程作为一个可插拔模块,使得内核在宏内核架构与微内核架构中随时进行切换。

-

进程结构设计如下:

-
pub struct ProcessInner {
-    /// 父进程的进程号
-    pub parent: u64,
-    /// 子进程
-    pub children: Vec<Arc<Process>>,
-    /// 子任务
-    pub tasks: Vec<AxTaskRef>,
-    /// 地址空间,由于存在地址空间共享,因此设计为Arc类型
-    pub memory_set: Arc<SpinNoIrq<MemorySet>>,
-    /// 用户堆基址,任何时候堆顶都不能比这个值小,理论上讲是一个常量
-    pub heap_bottom: usize,
-    /// 当前用户堆的堆顶,不能小于基址,不能大于基址加堆的最大大小
-    pub heap_top: usize,
-    /// 进程状态
-    pub is_zombie: bool,
-    /// 退出状态码
-    pub exit_code: i32,
-    /// 文件管理器,存储如文件描述符等内容
-    #[cfg(feature = "fs")]
-    pub fd_manager: FdManager,
-    /// 进程工作目录
-    pub cwd: String,
-    #[cfg(feature = "signal")]
-    /// 信号处理模块    
-    /// 第一维代表线程号,第二维代表线程对应的信号处理模块
-    pub signal_module: BTreeMap<u64, SignalModule>,
-
-    /// robust list存储模块
-    /// 用来存储线程对共享变量的使用地址
-    /// 具体使用交给了用户空间
-    pub robust_list: BTreeMap<u64, FutexRobustList>,
-}
-
-

任务结构如下:

-
/// The inner task structure.
-pub struct TaskInner {
-    id: TaskId,
-    name: String,
-    is_idle: bool,
-    is_init: bool,
-    /// 任务的入口函数,仅在内核态下有效
-    entry: Option<*mut dyn FnOnce()>,
-    state: AtomicU8,
-
-    in_wait_queue: AtomicBool,
-    #[cfg(feature = "irq")]
-    in_timer_list: AtomicBool,
-
-    #[cfg(feature = "preempt")]
-    need_resched: AtomicBool,
-    #[cfg(feature = "preempt")]
-    pub preempt_disable_count: AtomicUsize,
-
-    exit_code: AtomicI32,
-    wait_for_exit: WaitQueue,
-    /// 内核栈,对于unikernel不需要
-    #[cfg(feature = "monolithic")]
-    kstack: Option<TaskStack>,
-
-    ctx: UnsafeCell<TaskContext>,
-
-    #[cfg(feature = "monolithic")]
-    // 对应进程ID
-    process_id: AtomicU64,
-
-    #[cfg(feature = "monolithic")]
-    /// 是否是所属进程下的主线程
-    is_leader: AtomicBool,
-
-    #[cfg(feature = "monolithic")]
-    // 所属页表ID,在宏内核下默认会开启分页,是只读的所以不用原子量
-    page_table_token: usize,
-
-    #[cfg(feature = "monolithic")]
-    /// 初始化的trap上下文
-    pub trap_frame: UnsafeCell<TrapFrame>,
-    // 时间统计
-    #[cfg(feature = "monolithic")]
-    time: UnsafeCell<TimeStat>,
-
-    #[allow(unused)]
-    #[cfg(feature = "monolithic")]
-    /// 子线程初始化的时候,存放tid的地址
-    set_child_tid: AtomicU64,
-
-    #[cfg(feature = "monolithic")]
-    /// 子线程初始化时,将这个地址清空;子线程退出时,触发这里的 futex。
-    /// 在创建时包含 CLONE_CHILD_SETTID 时才非0,但可以被 sys_set_tid_address 修改
-    clear_child_tid: AtomicU64,
-
-    #[cfg(feature = "monolithic")]
-    /// 退出时是否向父进程发送SIG_CHILD
-    pub send_sigchld_when_exit: bool,
-}
-
-

该种设计的优势如下:

-
    -
  • 保留了 ArceOS 的结构,可以较为方便地与其他同学开发结果进行结合
  • -
  • 耦合度低,因此可以使内核较为方便地在不同模式间进行切换
  • -
-

在该种设计架构下,接受外来系统调用时,需要将部分对线程进行操作的系统调用转发给进程。进程收 -到该系统调用之后,再对当前进程下正在运行的线程进行相应的操作。实例为 yield , exit 等。

-

在生成新的任务时,由于是通过Linux的clone调用生成新的任务,因此可以根据clone的参数判断生成的是新的进程还是线程,从而确定线程所属的进程是哪一个,进程与线程之间形成父子关系,而同一进程下的线程形成兄弟关系,从而可以更加方便地进行管理。

-

地址空间引入

-

任务切换

-

引入了进程之后,由于进程是资源容器集合,因此地址空间相关的存储结构也存放在这里,不同进程之间可以共享或者独享地址空间,因此在切换任务时,只需要额外判断当前所属进程的地址空间的token是否发生改变,就可以完成多地址空间的引入。

-

特权级切换

-

目前内核和用户态使用的是同一个地址空间,可以避免trap时更改页表,减少时空损耗。

-

特权级切换

-

在Starry中,各种测例运行在用户态下,从内核态进入到用户态的方式有两个:用户程序初始化进入和trap返回。

-

初始化进入

-

对于用户程序初始化进入部分,即是在原有ArceOS基础上添加了额外的判断:

-

判断的原则如下:若要执行的任务的入口函数在内核态,则直接调用即可。否则需要通过手写汇编代码保存寄存器,以类似trap返回的机制调用sret进入用户态执行对应的函数。

-
extern "C" fn task_entry() {
-    // release the lock that was implicitly held across the reschedule
-    unsafe { crate::RUN_QUEUE.force_unlock() };
-    axhal::arch::enable_irqs();
-    let task: CurrentTask = crate::current();
-    if let Some(entry) = task.entry {
-        if task.get_process_id() == KERNEL_PROCESS_ID {
-            // 对于unikernel,这里是应用程序的入口,由于都在内核态所以可以直接调用函数
-            // 对于宏内核,这是初始调度进程,也在内核态,直接执行即可
-            unsafe { Box::from_raw(entry)() };
-        } else {
-            // 需要通过切换特权级进入到对应的应用程序
-            let kernel_sp = task.get_kernel_stack_top().unwrap();
-
-            let frame_address = task.get_first_trap_frame();
-            // 切换页表已经在switch实现了
-            first_into_user(kernel_sp, frame_address as usize);
-        }
-    }
-    // only for kernel task
-    crate::exit(0);
-}
-
-/// 初始化主进程的trap上下文
-#[no_mangle]
-fn first_into_user(kernel_sp: usize, frame_base: usize) -> ! {
-    let trap_frame_size = core::mem::size_of::<TrapFrame>();
-    let kernel_base = kernel_sp - trap_frame_size;
-    // 在保证将寄存器都存储好之后,再开启中断
-    // 否则此时会因为写入csr寄存器过程中出现中断,导致出现异常
-    axhal::arch::disable_irqs();
-    // 在内核态中,tp寄存器存储的是当前任务的CPU ID
-    // 而当从内核态进入到用户态时,会将tp寄存器的值先存储在内核栈上,即把该任务对应的CPU ID存储在内核栈上
-    // 然后将tp寄存器的值改为对应线程的tls指针的值
-    // 因此在用户态中,tp寄存器存储的值是线程的tls指针的值
-    // 而当从用户态进入到内核态时,会先将内核栈上的值读取到某一个中间寄存器t0中,然后将tp的值存入内核栈
-    // 然后再将t0的值赋给tp,因此此时tp的值是当前任务的CPU ID
-    // 对应实现在axhal/src/arch/riscv/trap.S中
-    unsafe {
-        asm::sfence_vma_all();
-        core::arch::asm!(
-            r"
-            mv      sp, {frame_base}
-            .short  0x2432                      // fld fs0,264(sp)
-            .short  0x24d2                      // fld fs1,272(sp)
-            LDR     gp, sp, 2                   // load user gp and tp
-            LDR     t0, sp, 3
-            mv      t1, {kernel_base}
-            STR     tp, t1, 3                   // save supervisor tp,注意是存储到内核栈上而不是sp中,此时存储的应该是当前运行的CPU的ID
-            mv      tp, t0                      // tp:本来存储的是CPU ID,在这个时候变成了对应线程的TLS 指针
-            csrw    sscratch, {kernel_sp}       // put supervisor sp to scratch
-            LDR     t0, sp, 31
-            LDR     t1, sp, 32
-            csrw    sepc, t0
-            csrw    sstatus, t1
-            POP_GENERAL_REGS
-            LDR     sp, sp, 1
-            sret
-        ",
-            frame_base = in(reg) frame_base,
-            kernel_sp = in(reg) kernel_sp,
-            kernel_base = in(reg) kernel_base,
-        );
-    };
-    core::panic!("already in user mode!")
-}
-
-

trap切换

-

trap切换对应的汇编代码在axhal/src/arch/riscv,值得关注的是其嵌套trap的处理。在第一次进入trap时,是从用户态进入到内核态,此时会将内核栈的地址赋给sp,将用户栈的地址存在内核栈上,并将sscratch清零。若发生内核嵌套trap,则此时sscratch的值为0,与sp交换之后,sp为0,即发生了内核嵌套trap。

-

因此可以通过交换之后sp是否为0来判断是否发生了内核嵌套trap。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git "a/doc/Starry/site/\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263/index.html" "b/doc/Starry/site/\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263/index.html" deleted file mode 100644 index 7b716e4..0000000 --- "a/doc/Starry/site/\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263/index.html" +++ /dev/null @@ -1,938 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - 问题与解决 - Starry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- - -
- -
- - - - - - -
-
- - - -
-
-
- - - - -
-
-
- - - - - - - -
-
- - - - -

问题与解决

- -

操作CSR寄存器时关闭时钟中断

-

由于要运行多个测例,每一个测例都是单独的可执行文件,而当测例量加大时,会经常性出现准备开始运行某个测例的时候卡死或者循环发生内核trap的现象,错误的内容是随机的,可能呈现为store fault、卡死甚至unknown trap等内容。

-

通过gdb调试,定位了第一次发生错误的地址均在下列函数中:

-
#[no_mangle]
-// #[cfg(feature = "user")]
-fn first_into_user(kernel_sp: usize, frame_base: usize) -> ! {
-    let trap_frame_size = core::mem::size_of::<TrapFrame>();
-    let kernel_base = kernel_sp - trap_frame_size;
-    unsafe {
-        asm::sfence_vma_all();
-        core::arch::asm!(
-            r"
-            mv      sp, {frame_base}
-            .short  0x2432                      // fld fs0,264(sp)
-            .short  0x24d2                      // fld fs1,272(sp)
-            LDR     gp, sp, 2                   // load user gp and tp
-            LDR     t0, sp, 3
-            mv      t1, {kernel_base}
-            STR     tp, t1, 3                   // save supervisor tp,注意是存储到内核栈上而不是sp中,此时存储的应该是当前运行的CPU的ID
-            mv      tp, t0                      // tp:本来存储的是CPU ID,在这个时候变成了对应线程的TLS 指针
-            csrw    sscratch, {kernel_sp}       // put supervisor sp to scratch
-            LDR     t0, sp, 31
-            LDR     t1, sp, 32
-            csrw    sepc, t0
-            csrw    sstatus, t1
-            POP_GENERAL_REGS
-            LDR     sp, sp, 1
-            sret
-        ",
-            frame_base = in(reg) frame_base,
-            kernel_sp = in(reg) kernel_sp,
-            kernel_base = in(reg) kernel_base,
-        );
-    };
-    core::panic!("already in user mode!")
-}
-
-

继续定位gdb汇编代码,将错误地址进一步确定为:

-
csrw    sstatus, t1
-
-

当执行这一条汇编代码,会出现不可预测的错误。

-

考虑到sstatus的功能,其可以控制时钟中断、特权级等一系列的内容,通过查阅资料了解到当使用sstatus屏蔽内核中时钟中断时,并非是阻止了中断发出,而是阻止对中断进行处理,一旦内核中时钟中断屏蔽关闭,原先积累的时钟中断会被用来处理。sstatus是控制中断的关键寄存器,查阅资料得知,riscv要求在修改sstatus信息的时候需要保证时钟中断使能关闭,否则会产生不可预料的行为。

-

因此在调用first_into_user函数前需要手动调用axhal::arch::enable_irqs()关闭中断使能。

-

读取长度不足

-

当读取strings.lua测例时,常会有报错:strings.lua:1: unexpected symbol。但其他lua测例运行结果正常且正确。

-

strings.lua内容如下:

-
local str = "Jelly Think"
-
-result = 0
-
--- string.len可以获得字符串的长度
-
-if string.len(str) ~= 11 then
-    result = -1
-end
-
--- string.rep返回字符串重复n次的结果
-
-str = "ab"
-
-if string.rep(str, 2) ~= "abab" then
-    result = -1
-end
-
--- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本
-
-str = "Jelly Think"
-
-if string.lower(str) ~= "jelly think" then
-    result = -1
-end
-
--- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本
-
-if string.upper(str) == "JELLY THINK" then
-    result = -1
-end
-
-return result
-
-

考虑是否是文件编码问题:将strings.lua测例内容复制到其他lua文件,运行对应文件,报错不变。将其他lua文件内容复制到strings.lua,运行strings.lua,结果正常,因此排除了编码问题。

-

再考虑内核是否成功读入文件,输出read系统调用内容,发现read系统调用确实正确读入并返回了文件长度591。

-

考虑到strings.lua测试内容由多个断言形成,考虑逐个断言逐个断言验证,但发现一旦删除了strings.lua的部分内容之后,运行结果就正常了。即当缩短了strings.lua的长度之后,结果正常。

-

考虑输出read系统调用中读入的buf的内容,发现读入的892位buf中,前512位buf被修改为了0,后面的buf仍然正常。而当限制buf长度为512时,此时前512位buf读取结果正常。

-

arceos原先在fat32节点的读取函数定义如下:

-
fn read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {
-    let mut file = self.0.lock();
-    file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient
-    file.read(buf).map_err(as_vfs_err)
-}
-
-

依据上述debug结果,发现starry的文件系统驱动中fat32的块大小定义为512。查询read语义知,每一次实际读取长度不一定等于传入的buf长度,因此不可以直接通过传入buf来实现文件的读入,而需要进行循环判断:

-
n read_at(&self, offset: u64, buf: &mut [u8]) -> VfsResult<usize> {
-    let mut file = self.0.lock();
-    file.seek(SeekFrom::Start(offset)).map_err(as_vfs_err)?; // TODO: more efficient
-    // file.read(buf).map_err(as_vfs_err)
-    let buf_len = buf.len();
-    let mut now_offset = 0;
-    let mut probe = buf.to_vec();
-    while now_offset < buf_len {
-        let ans = file.read(&mut probe).map_err(as_vfs_err);
-        if ans.is_err() {
-            return ans;
-        }
-        let read_len = ans.unwrap();
-
-        if read_len == 0 {
-            break;
-        }
-        buf[now_offset..now_offset + read_len].copy_from_slice(&probe[..read_len]);
-        now_offset += read_len;
-        probe = probe[read_len..].to_vec();
-    }
-    Ok(now_offset)
-}
-
-

依据上述写法,即可实现大文件的读入。

-

文件的链接与初始化

-

fat32文件系统自身不支持符号链接,因此需要在内核中手动维护一个链接映射。但是不同的文件名称字符串可能指向同一个文件, 因此不能单纯地将传入的文件名作为映射的键值。

-

比如我们建立了一个从a.outb.out的链接,此时传入的文件名叫做./a.out,此时它应该被连接到b.out,但在链接中找不到对应程序。

-

为了规范化起见,starry引用了arceos提供的canonicalize函数,将文件名转化为统一格式的绝对路径,并以此建立文件名到链接实际文件的映射。

-

因此从a.outb.out的链接,会被转化为./a.out./b.out的链接,通过规范的字符串使得误判的情况可以被减少。

-

实现busybox、lua、lmbench过程中,需要用到一系列的链接,对应实现在starry_libax/test.rsfs_init函数中。如程序会寻找/lib/tls_get_new-dtv_dso.so,而它会被定向到./tls_get_new-dtv_dso.so文件,这个过程需要我们手动建立链接。

-

另外,busybox等测例也需要我们手动建立一系列的文件系统与文件夹,如dev_fs与ram_fs,其中dev_fs并不允许动态增删文件内容,需要初始化时就确定好。相关的实现在axfs/src/root.rsinit_rootfs函数,需要添加dev/shm、dev/misc等文件夹。

-

多核情况下libc测例结果不可测

-

musl-libc测例中有一个测例为pthread_cancel,主要是测试线程是否可以正常被取消。但这个测例经常会运行失败,即能够成功退出,但是报错并未取消新建的线程。

-

查阅对应的代码如下:

-
static void *start_single(void *arg)
-{
-    pthread_cleanup_push(cleanup1, arg);
-    sleep(3);
-    pthread_cleanup_pop(0);
-    return 0;
-}
-int main() {
-/* Cancellation cleanup handlers */
-    foo[0] = 0;
-    TESTR(r, pthread_create(&td, 0, start_single, foo), "failed to create thread");
-    TESTR(r, pthread_cancel(td), "cancelling");
-    TESTR(r, pthread_join(td, &res), "joining canceled thread");
-    TESTC(res == PTHREAD_CANCELED, "canceled thread exit status");
-    TESTC(foo[0] == 1, "cleanup handler failed to run");
-}
-
-

其测试的原理是在pthread_cleanup_push加入线程取消时调用的处理函数。若线程成功被取消,那么cleanup1函数会被调用,此时会修改f00[0]为1,代表成功取消。

-

但测试时经常报错:cleanup handler failed to run,通过输出f00[0]发现其值仍然为0,即线程取消函数没有被调用。但是输出内核接受到的系统调用以及信号处理流程会发现确实发出并且处理了取消线程的信号。那么问题出在了哪里呢?

-

输出任务调度队列信息发现,主任务在调用了pthread_create之后,并没有被阻塞,反而继续调用了pthread_cancel函数,发出了取消线程信号,之后再被pthread_join函数阻塞。此时才调度到子线程,并且立即进入了信号处理函数的流程,即立即被取消。此时子线程甚至没有进入到start_single函数就被取消了。此时没有注册取消线程函数为cleanup1,因此自然不会修改f00[0]。

-

但是问题在于pthread_create的语义要求本任务会被yield,即子线程应当在创建之后被立即执行。继续debug,输出任务调度列表和对应CPU编号发现,虽然在当前CPU上主任务被yield了,但当前启动了多核,闲置的CPU立即将刚被yield的主任务接管并且继续运行。则此时主任务有概率在子线程开始之前调用cancel函数发出取消信号,从而导致线程取消函数注册失败。

-

将内核改为单核启动之后,问题消失。总结而言,在无法改动测例代码的情况下,跑musl-libc测例应当以单核的形式进行,多核可能会遇到各种奇怪的问题。。

-

lmbench测例的结束

-

运行lmbench测例时发现时,程序总是会访问0x2,0x4,0x6,0x8等地址,导致page fault。gdb进行debug无果,发现程序已经输出了预期输出,之后会直接访问该非法地址。

-

询问往年参加比赛的学长,了解到去年的lmbench会在每个测例结束的时候直接让pc跳到堆栈上,从而触发I fault,通过内核捕获该信号并进行特判,从而手动调用exit结束当前的lmbench测例,进入到下一个lmbench测例。

-

而在今年编译得到的lmbench版本,pc不再跳转到堆栈,而是跳转到低地址如0x6,此时也是要求内核直接做出特判,结束当前任务。

-

查阅riscv规范得知,非法访问内存,内核处理失败之后应当发送SIGSEGV信号到对应线程,从而结束当前任务。因此修改代码如下:

-
#[cfg(feature = "paging")]
-fn handle_page_fault(addr: VirtAddr, flags: MappingFlags, tf: &mut TrapFrame) {
-    use axprocess::handle_page_fault;
-    use axsignal::signal_no::SignalNo;
-    use axtask::current;
-    axprocess::time_stat_from_user_to_kernel();
-    use crate::syscall::signal::{syscall_sigreturn, syscall_tkill};
-    if addr.as_usize() == SIGNAL_RETURN_TRAP {
-        // 说明是信号执行完毕,此时应当执行sig return
-        tf.regs.a0 = syscall_sigreturn() as usize;
-        return;
-    }
-
-    if handle_page_fault(addr, flags).is_err() {
-        // 如果处理失败,则发出sigsegv信号
-        let curr = current().id().as_u64() as isize;
-        axlog::error!("kill task: {}", curr);
-        syscall_tkill(curr, SignalNo::SIGSEGV as isize);
-    }
-    axprocess::time_stat_from_kernel_to_user();
-}
-
-

这种情况不仅可以处理pc跳转到低地址的情况,也可以处理跳转到堆栈的情况,更加地规范化。

- - - - - - -
-
- - -
- -
- - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/doc/figures/Starry.svg b/doc/figures/Starry.svg new file mode 100644 index 0000000..61a35ea --- /dev/null +++ b/doc/figures/Starry.svg @@ -0,0 +1,3 @@ + + +
Application
Application
User lib layer
User lib layer
axstarry
axstarry
axstd
axstd
Kernel Architecture API
Kernel Architecture API
linux_syscall_api
linux_syscall_api
monolithic
monolithic
arceos_posix_api
arceos_posix_api
unikernel
unikernel
arceos_api
arceos_api
Runtime
Runtime
axruntime
axruntime
Module Layer
Module Layer
axprocess
axprocess
axsync
axsync
axtask
axtask
Crate Layer
Crate Layer
axhal
axhal
blk_device
blk_device
axdriver
axdriver
Scheduler
Scheduler
fat32
fat32
ext4
ext4
FileSystem
FileSystem
smoltcp
smoltcp
lwip
lwip
NW Stacks
NW Stacks
net_device
net_device
display_device
display_device
percpu
percpu
OS Primitives Layer
OS Primitives Layer
Platform Layer
Platform Layer
tlsf
tlsf
slab
slab
buddy
buddy
axalloc
axalloc
page
table
page...
spinlock
spinlock
kernel guard
kernel guard
virt-blk
virt-blk
virt-net
virt-net
virt-gpu
virt-gpu
pci
pci
clock
clock
mem_region
mem_region
Hyperivisor
Hyperivisor
kcvitek-sd
kcvitek-sd
cvitek-nic
cvitek-nic
pci
pci
clock
clock
mem_region
mem_region
cv1811H
cv1811H
axconfig
axconfig
dtb
dtb
devfs
devfs
ramfs
ramfs
vfs
vfs
map/munmap
map/munmap
shared_mem
shared_mem
brk
brk
axmem
axmem
fileops
fileops
mount
mount
axfs
axfs
TCP/UDP
TCP/UDP
Loopback
Loopback
ETH0
ETH0
axnet
axnet
fdtable
fdtable
symbol
link
symbol...
fork/exec
fork/exec
signal
signal
axlibc
axlibc
Boot layer
Boot layer
arch_boot
arch_boot
axtrap
axtrap
taskctx
taskctx
Viewer does not support full SVG 1.1
\ No newline at end of file