由于大部分测试需要使用 busybox,为了避免多次解析 elf、从零创建地址空间等问题,我们采用了类似于加载initproc的方法。
具体而言,我们将 busybox 预加载到内核中,并保存 load_elf 获取的信息。每次执行busybox时,我们直接使用保存的 load_elf 信息,并通过写时拷贝来创建所需的 busybox 进程的地址空间,更快速地创建 busybox 进程从而实现更高效的测试。
// kernel/src/task/initproc/mod.rs
pub static ref BUSYBOX: RwLock<Busybox> = RwLock::new({
extern "C" {
fn busybox_entry();
fn busybox_tail();
}
let entry = busybox_entry as usize;
let tail = busybox_tail as usize;
let siz = tail - entry;
let busybox = unsafe { core::slice::from_raw_parts(entry as *const u8, siz) };
let path = AbsolutePath::from_str("/busybox0");
let inode = fs::open(path, OpenFlags::O_CREATE, CreateMode::empty()).expect("busybox0 create failed");
inode.write_all(&busybox.to_owned());
let bb = Arc::new(TaskControlBlock::new(inode.clone()));
inode.delete();
Busybox {
inner: bb,
}
});
pub static mut ONCE_BB_ENTRY: usize = 0;
pub static mut ONCE_BB_AUX: Vec<AuxEntry> = Vec::new();
pub struct Busybox {
inner: Arc<TaskControlBlock>,
}
impl Busybox {
pub fn elf_entry_point(&self) -> usize {
unsafe { ONCE_BB_ENTRY }
}
pub fn aux(&self) -> Vec<AuxEntry> {
unsafe { ONCE_BB_AUX.clone() }
}
pub fn memory_set(&self) -> MemorySet {
let mut write = self.inner.memory_set.write();
MemorySet::from_copy_on_write(&mut write)
}
}