关于移植 ArceOS 以及相关组件化内核到 seL4/reL4 上的思考 #23
Replies: 12 comments 5 replies
-
|
在移植的过程中,目前发现有如下问题
对于第一个问题,我觉得 arceos 上迟早是需要用到堆的,所以倒没有必要修改 srv-gate 中和堆相关的代码。因此我准备先把 axalloc 在 seL4 上的实现做了,在 arceos 可以使用堆相关功能 |
Beta Was this translation helpful? Give feedback.
-
|
目前 arceos 上关于内存分配和管理的设计和 seL4 是冲突的,因此首先考虑解决该问题。主要冲突点如下
针对以上问题,目前做了以下内存相关设计
fn virt_to_phys(&self, vaddr: usize) -> usize {
log::info!("virt_to_phys: vaddr = {:#x}", vaddr);
let vstart = (vaddr / LARGE_PAGE_SIZE) * LARGE_PAGE_SIZE;
if let Some(range) = self.regions.lock().get(&vstart) {
let pstart = range.start;
return pstart + (vaddr - vstart);
}
vaddr
}
fn phys_to_virt(&self, paddr: usize) -> usize {
for (vstart, range) in self.regions.lock().iter() {
if range.contains(&paddr) {
return vstart + (paddr - range.start);
}
}
paddr
}如上所述,arceos 现在内存分为四部分
目前在几乎只改 hal 的情况下,将 arceos 移植到 rel4-linux-kit 框架中使用,但仍有很多细节需要打磨 同时,multi_task 还不知道怎么适配,我会继续看看这块 |
Beta Was this translation helpful? Give feedback.
-
|
相对内存问题,multitask 的问题,我认为更加复杂,主要是以下几点
目前思路有点混乱,所以上面几点写的也没什么逻辑,我预计会先了解下用协程实现的可能性,这是我目前的计划。 |
Beta Was this translation helpful? Give feedback.
-
|
遇到一个新问题,就是 rel4-linux-kit 中的 linkme 段,它们环绕在 percpu 段的周围,导致执行了 percpu 相关操作是,会覆盖这些段,从而报错。 有一个解法是让 percpu 前后留一些空白区域,我目前是 4K 对齐,可以解决。但仍然感觉是临时方案,随时有内存相关的问题。有什么办法可以把这些 linkme 段统一到一起吗,我尝试改了链接脚本,会报错。 |
Beta Was this translation helpful? Give feedback.
-
|
目前已经可以运行 httpclient, httpserver, helloworld 三个例子,基本上只改动了 axhal 和几个底层相关的 crate 改动 commit 如下 目前看起来,如果只是 arceos unikernel 的功能和 feature,适配应该问题都不大。 但是涉及到宏内核的功能,看起来都很复杂,需要好好思考如何设计。 |
Beta Was this translation helpful? Give feedback.
-
|
由于 Arceos 对 hal 和 platform 部分进行了大调整,将 platform 独立出去,因此我同步进行了调整。 调整后,新增了 axplat-aarch64-sel4 crate https://github.com/reL4team2/arceos/tree/croak/sel4_porting/platforms/axplat-aarch64-sel4 现在看起来更加干净了,arceos 中只在 modules/axhal/src/percpu.rs 和 modules/axruntime/src/lib.rs 中做了微小改动,通过 asuser 编译选项打开或者关闭。 改动 commit reL4team2/arceos@f2e29f3#diff-557a9ff9346af8506692e25351145816cb1ca3e3ba51aaf288a37325d920bb9e |
Beta Was this translation helpful? Give feedback.
-
关于中断设计如下:我们的目标是,让 arceos 可以接收注册到 seL4 中的中断,并且可以作相应处理,最好是可以兼容目前的 seL4 配置。按照这个目标,衍生出以下两个问题需要解决
1. arceos 如何接收到中断和在裸机上运行不同,运行在 seL4 上的 arceos 是无法设置中断处理函数,并且由硬件在中断触发的时候跳转到中断处理函数。seL4 的中断机制是内核在触发中断时,向用户态发送对应的 notification。因此需要用户态进程不断轮询该 notification,判断是否有中断产生。 为了减少在 arceos 中的改动,让 arceos 仍然在不知道的情况下跳转到中断处理函数。我们需要另一个进程监听中断,并且让 arceos 跳转到中断处理函数。 1.1 辅助进程监听中断我暂且使用 root-task 作为这个辅助进程,而不是另外创建一个。 在原有的 root-task 轮询监听函数中增加了对应 badge 的监听。目前示例中只监听了 timer 中断,后面应该会改成监听某个高位,这样可以监听所有中断。 上述就可以实现对某个中断的监听。现在 demo 中是默认监听了 timer 中断,后面需要改成注册的方式,修改下现有的 RegisterIRQ IPC 方法即可 1.2 辅助进程处理中断在辅助进程中,主要目的就是让 arceos 跳转到中断处理函数。这里我们可以使用 tcb_write_all_registers syscall,修改 arceos 进程的 pc,实现跳转。由于 arceos 需要知道跳转之前的 pc,因此 root-task 需要把这个值传递给 arceos,暂且是放在 x0 中,但是这样会破坏 arceos 原有上下文,后续考虑使用共享内存或其他方式传递。 上述操作,可以让 arceos 跳转到 trap 处理函数 1.3 TODO总的来说,还有以下细节需要设计
2. Arceos 中如何处理中断2.1 上下文保存和恢复arceos 中最关键的设计是,如何在中断处理函数执行完成后,跳转回到中断之前位置,继续执行。 我们可以参照 trap 进入 kernel 并且退出的过程,分析下不同的点,并做相应改动
明确上述三点不同后,我们就可以针对性的做如下修改了
通过上述设计,arceos 中原本的中断功能设计仍然可用,因为入口和之前一样,还是 irq_handler 2.2 中断 cap 相关设计arceos 中 irq ack 的方式也需要修改,从直接操作 gic,改成操作 sel4 的 irq capability。这部分原理上没什么难度,只需要后续细化设计。 2.3 时钟等一些细节的移植实现在 demo 实现的过程中,发现有一些底层和架构相关的实现需要修改,比如 timer 等等。这部分在后续实现是进行记录。 |
Beta Was this translation helpful? Give feedback.
-
|
根据上次的讨论,做了如下工作
有一个修改值得一说,关于 percpu 变量功能的修改。arceos 中原本是使用 tpidr_el1 寄存器存储 percpu 区域的地址,我之前尝试改成 tpidr_el0 在用户态使用。但是 seL4 中会使用该寄存器指定每个任务的 tls 区域,产生冲突。在不能修改 seL4 的前提下,我只能使用 x28 寄存器,并且在编译选项中,告诉编译器不要使用 x28 寄存器。 关于 thread,目前的做法是,只和父进程共享 vspace,其他的重新创建。在开始任务之前,会从 x8 寄存器传入该线程分配的 ipc buffer 地址,由该线程进行 ipc 的初始化等操作。这些初始化固定操作定义在一个过程宏当中,比如中断处理线程 |
Beta Was this translation helpful? Give feedback.
-
|
最近初步完成了 arceos task 适配 seL4 的工作,和之前提到的 multitask 方案不同,现在每个 arceos task 都是一个 seL4 task,除了共享 vspace,其他能力都是独立的。 具体的 task 创建和回收实现可以参考 https://github.com/reL4team2/arceos/blob/croak/sel4_porting2/platforms/axplat-aarch64-sel4/src/utils/task.rs 按照之前 yjb 的设计,每个 task 创建时,会分配一个固定大小的 untyped 区域,所有能力都从其中分配吗,这样方便回收。 当 arceos 初始化完成后,会产生 main 任务,gc 任务等默认任务,然后主任务会作为 event_handler,监听子任务的 ipc 请求和中断通知,中断注册和管理的实现不用改变,只是把中断监听的功能放到了主进程中。 任务创建、切换、退出都是由主任务执行,因为所有任务创建时产生的能力,都是存储在主任务的 cspace 中。换句话说,只有主任务可以访问所有任务的资源,操作所有任务。 和之前 arceos 保持一样,任何任务都可以创建任务,只是将直接创建,改成了发送 IPC 请求给主任务,由主任务代为创建 调度使用 arceos 原生的调度器,只是在 switch_to 的时候,将切换上下文,改成了通过 IPC 请求切换任务。主任务通过 suspend prev_task,resume next_task 的方式进行任务切换。 退出任务时,同样会发送 IPC 请求,由主任务对任务的 能力 资源进行回收,确保不会出现 untyped 不够,无法分配能力的情况。 这样做的缺点就是,每个任务创建和回收的效率很低,任务间切换效率也很低,但是如果用 seL4 task 的话,这些似乎无法避免。一种解决方案是混合式任务,类似线程和协程。 |
Beta Was this translation helpful? Give feedback.
-
|
关于 tls 段和 linkme 段冲突的问题如下 可以看到,linkme 段是完全跟在 tdata 后面的,和 tbss 段是冲突的。而 arceos 中,会在 tls 初始化的时候,将 tbss 段进行清零,拷贝等操作,就会影响到 linkme 段。 同时 rust-seL4 中的 IPC_BUFFER 地址就是一个 tbss 段的变量,初始化的时候也会设置该变量,会影响 linkme 段 改成下面 链接脚本,可以解决该问题 |
Beta Was this translation helpful? Give feedback.
-
记录下最近在一直多核功能时遇到的一个问题问题描述打开 arceos smp 功能后,发现在进行第一次调度时,会访问一个非法地址,一般是 0 或者 8 这种很小的地址。 第一步,我先通过 log 确认下是在哪几句出错的,定位到下面这句 我首先怀疑是后半段,但是我改成下面后,仍然会报错,所以感觉是前半段 drop 的时候出错了 由于是第一次赋值的时候就出错了,这很奇怪,因为初始化的时候是赋值 Weak::new(),按道理这个值不应该会 drop 失败 进一步,我进行了测试,对 PREV_TASK 进行 upgrade,同样会出错,这样就可以确认是 PREV_TASK 这个值初始化后就有问题 PREV_TASK 是一个 percpu 值,初始化如下 我找到了该值的地址,然后 gdb 中查看了初始化之后该地址的值,发现是 0,看起来没什么问题。然后我查看了 Weak 相关的文档,发现 Weak::new() 产生的值是 -1。 之后就思考为什么初始化的值不对,排查到是因为 elf 文件加载的问题,由于 elf 加载功能实现的时候,忽略了 address 为 0 的段,导致没有复制加载 percpu 段,也就导致初始化值不对。 以上就是我调查该问题的全部过程 |
Beta Was this translation helpful? Give feedback.
-
打开抢占调度后遇到的 panic 问题抢占计数器不对大概两周前,在运行 wait_queue 测例时,将调度策略设置为 rr 或者 cfs 时,发现测例运行失败,在这个断言处检查失败 arceos 中,每个任务中有一个 preempt 计数器,用于记录当前任务被执行 disable_preempt 和 enable_preempt 的次数,前者 +1 后者 -1. 发现在报错时,这个计数器是 1,通过注释可以看出,这个函数执行时,经历了两个锁,也就是 preempt 加了两次,如果是 1,那说明是从 -1 加上来的,这就很不正常了。 接着通过查找,发现第一次出现 -1 是中断中执行 preempt_resched 抢占切换造成的。进一步 debug 发现 backtrace 指向中断处理函数 这儿逻辑也没有问题,就是 drop(guard) 出发的抢占,完全没问题。那这样问题就集中到了 preempt_resched 函数中,首先就怀疑是任务切换时的问题,因为在任务切换前会 lock,也就是对前一个任务 preempt 计数 + 1,切换后对后一个任务 release 也就是 -1,看起来就很容易造成 preempt 计数出现 -1. 分析和 arceos 任务切换的异同,原版 arceos 直接切换上下文,也就是说,原有的控制流被打断,压根不会执行到 drop 的地方,也就不会 -1,而架在 seL4 上的切换本质是通过调用 syscall 切换,执行完不会马上打断中断处理函数,而是会执行完。因此会在切换后,执行锁的 drop,导致对切换后的函数进行 preempt counter -1 的操作,造成问题 目前的解决方案时不允许再中断处理函数中切换任务,由于中断处理函数是在 管理任务 中执行的,如果想在切换时直接打断控制流,似乎只能 suspend 当前任务,但是我找不到一个别的任务可以再次将 管理任务 拉起,因此只能避免在中断中切换任务。 多核时任务刚启动出现抢占计数器不对这个问题是由于初始化流程还未结束,就执行了 idle 任务,进一步开始调度造成的。 根本原因是,在初始化调度器后,直接将 idle 任务在 seL4 中设置为 running 状态,由于 idle 任务优先级低,我认为在初始化流程执行完之前,是不会执行 idle 的。 提前执行的原因是,初始化流程中进行中断初始化时,会注册中断,这是一个 ipc 请求,在初始化任务等待 reply 时,seL4 执行了 idle 任务,然后出错。修改方法就是完成初始化过程后,再启动 idle 任务即可 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
来源于向老师的题目,如何在尽量不侵入的情况下,将 ArceOS 及相关的组件化内核以用户态任务的形式跑在 seL4/reL4 系统上。结合 seL4 系统的安全性和 ArceOS 的组件化开发优势。
1. 思考
这个题目给我的第一反应是,seL4 似乎起到的是 hypervisor 的作用。只不过都往下降了一个特权级。
仔细考虑后,我感觉这个做法可能存在如下优势和劣势
优势
劣势
2. 目标
我计划以 arceos 模块为单位进行修改,最后针对修改的模块看能否兼容 arceos 主仓库。
我目前确认一定会修改的是 axhal 和 axalloc ,其他的还待开发过程中确认。
axhal 和 axalloc 是和硬件资源分配相关的,我的目标就是在其中实现适配 seL4 系统的资源分配和管理功能。
第一阶段目标是用 单核,单任务的配置,把 arceos 的三个例子运行起来,后面待定
Beta Was this translation helpful? Give feedback.
All reactions