Skip to content

Commit

Permalink
kernel/syscall: Implement EXEC
Browse files Browse the repository at this point in the history
Implement the syscall handler for SYS_EXEC. This commit also provides
the ability to specify a new root directory for the process. This is
done because EXEC allows the parent process to specify the root
directory of the new process. New threads automatically inherits its
parent's root directory.

Co-developed-by: Vijay Dhanraj <[email protected]>
Signed-off-by: Peter Fang <[email protected]>
  • Loading branch information
peterfang authored and vijaydhanraj committed Oct 27, 2024
1 parent f2f6522 commit 047d5de
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 13 deletions.
1 change: 1 addition & 0 deletions kernel/src/cpu/idt/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ extern "C" fn ex_handler_system_call(

ctxt.regs.rax = match input {
SYS_EXIT => sys_exit(ctxt.regs.rdi as u32),
SYS_EXEC => sys_exec(ctxt.regs.rdi, ctxt.regs.rsi, ctxt.regs.r8),
SYS_CLOSE => sys_close(ctxt.regs.rdi as u32),
SYS_OPENDIR => sys_opendir(ctxt.regs.rdi),
SYS_READDIR => sys_readdir(ctxt.regs.rdi as u32, ctxt.regs.rsi, ctxt.regs.r8),
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use svsm::cpu::sse::sse_init;
use svsm::debug::gdbstub::svsm_gdbstub::{debug_break, gdbstub_start};
use svsm::debug::stacktrace::print_stack;
use svsm::error::SvsmError;
use svsm::fs::{initialize_fs, populate_ram_fs};
use svsm::fs::{initialize_fs, opendir, populate_ram_fs};
use svsm::fw_cfg::FwCfg;
use svsm::igvm_params::IgvmParams;
use svsm::kernel_region::new_kernel_region;
Expand Down Expand Up @@ -461,7 +461,7 @@ pub extern "C" fn svsm_main() {
#[cfg(test)]
crate::test_main();

match exec_user("/init") {
match exec_user("/init", opendir("/").expect("Failed to find FS root")) {
Ok(_) | Err(SvsmError::Task(TaskError::Terminated)) => (),
Err(e) => log::info!("Failed to launch /init: {e:#?}"),
}
Expand Down
19 changes: 18 additions & 1 deletion kernel/src/syscall/class0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
// Author: Joerg Roedel <[email protected]>

use super::obj::obj_close;
use crate::task::{current_task_terminated, schedule};
use crate::address::VirtAddr;
use crate::cpu::percpu::current_task;
use crate::fs::find_dir;
use crate::mm::guestmem::UserPtr;
use crate::task::{current_task_terminated, exec_user, schedule};
use core::ffi::c_char;
use syscall::SysCallError;

pub fn sys_exit(exit_code: u32) -> ! {
Expand All @@ -17,6 +22,18 @@ pub fn sys_exit(exit_code: u32) -> ! {
unreachable!("schedule() returned in sys_exit()");
}

pub fn sys_exec(file: usize, root: usize, _flags: usize) -> Result<u64, SysCallError> {
let user_file_ptr = UserPtr::<c_char>::new(VirtAddr::from(file));
let user_root_ptr = UserPtr::<c_char>::new(VirtAddr::from(root));

let file_str = user_file_ptr.read_c_string()?;
let root_str = user_root_ptr.read_c_string()?;
let real_root = find_dir(current_task().rootdir(), &root_str)?;
let tid = exec_user(&file_str, real_root)?;

Ok(tid.into())
}

pub fn sys_close(obj_id: u32) -> Result<u64, SysCallError> {
// According to syscall ABI/API spec, close always returns 0 even
// if called with an invalid handle
Expand Down
6 changes: 3 additions & 3 deletions kernel/src/syscall/class1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ extern crate alloc;

use super::obj::{obj_add, obj_get};
use crate::address::VirtAddr;
use crate::fs::{opendir, DirEntry, FileNameArray, FsObj};
use crate::fs::{find_dir, DirEntry, FileNameArray, FsObj};
use crate::mm::guestmem::UserPtr;
use crate::task::current_task;
use alloc::sync::Arc;
use core::ffi::c_char;
use syscall::SysCallError::*;
Expand All @@ -18,8 +19,7 @@ use syscall::{DirEnt, FileType, SysCallError};
pub fn sys_opendir(path: usize) -> Result<u64, SysCallError> {
let user_path_ptr = UserPtr::<c_char>::new(VirtAddr::from(path));
let user_path = user_path_ptr.read_c_string()?;

let dir = opendir(&user_path)?;
let dir = find_dir(current_task().rootdir(), &user_path)?;
let id = obj_add(Arc::new(FsObj::new_dir(&dir)))?;

Ok(u32::from(id).into())
Expand Down
9 changes: 6 additions & 3 deletions kernel/src/task/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
//
// Author: Joerg Roedel <[email protected]>

extern crate alloc;

use crate::address::{Address, VirtAddr};
use crate::error::SvsmError;
use crate::fs::open;
use crate::fs::{open, Directory};
use crate::mm::vm::VMFileMappingFlags;
use crate::mm::USER_MEM_END;
use crate::task::{create_user_task, current_task, schedule, TaskError};
use crate::types::PAGE_SIZE;
use alloc::sync::Arc;
use elf::{Elf64File, Elf64PhdrFlags};

fn convert_elf_phdr_flags(flags: Elf64PhdrFlags) -> VMFileMappingFlags {
Expand All @@ -27,7 +30,7 @@ fn convert_elf_phdr_flags(flags: Elf64PhdrFlags) -> VMFileMappingFlags {
vm_flags
}

pub fn exec_user(binary: &str) -> Result<u32, SvsmError> {
pub fn exec_user(binary: &str, root: Arc<dyn Directory>) -> Result<u32, SvsmError> {
let fh = open(binary)?;
let file_size = fh.size();

Expand All @@ -46,7 +49,7 @@ pub fn exec_user(binary: &str) -> Result<u32, SvsmError> {
let virt_base = alloc_info.range.vaddr_begin;
let entry = elf_bin.get_entry(virt_base);

let task = create_user_task(entry.try_into().unwrap())?;
let task = create_user_task(entry.try_into().unwrap(), root)?;

for seg in elf_bin.image_load_segment_iter(virt_base) {
let virt_start = VirtAddr::from(seg.vaddr_range.vaddr_begin);
Expand Down
8 changes: 6 additions & 2 deletions kernel/src/task/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::cpu::sse::sse_restore_context;
use crate::cpu::sse::sse_save_context;
use crate::cpu::IrqGuard;
use crate::error::SvsmError;
use crate::fs::Directory;
use crate::locking::SpinLock;
use alloc::sync::Arc;
use core::arch::{asm, global_asm};
Expand Down Expand Up @@ -242,9 +243,12 @@ pub fn create_kernel_task(entry: extern "C" fn()) -> Result<TaskPointer, SvsmErr
Ok(task)
}

pub fn create_user_task(user_entry: usize) -> Result<TaskPointer, SvsmError> {
pub fn create_user_task(
user_entry: usize,
root: Arc<dyn Directory>,
) -> Result<TaskPointer, SvsmError> {
let cpu = this_cpu();
let task = Task::create_user(cpu, user_entry)?;
let task = Task::create_user(cpu, user_entry, root)?;
TASKLIST.lock().list().push_back(task.clone());

// Put task on the runqueue of this CPU
Expand Down
17 changes: 15 additions & 2 deletions kernel/src/task/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::cpu::sse::{get_xsave_area_size, sse_restore_context};
use crate::cpu::X86ExceptionContext;
use crate::cpu::{irqs_enable, X86GeneralRegs};
use crate::error::SvsmError;
use crate::fs::FileHandle;
use crate::fs::{opendir, Directory, FileHandle};
use crate::locking::{RWLock, SpinLock};
use crate::mm::pagetable::{PTEntryFlags, PageTable};
use crate::mm::vm::{Mapping, VMFileMappingFlags, VMKernelStack, VMR};
Expand Down Expand Up @@ -141,6 +141,9 @@ pub struct Task {
/// ID of the task
id: u32,

/// Root directory for this task
rootdir: Arc<dyn Directory>,

/// Link to global task list
list_link: LinkedListAtomicLink,

Expand Down Expand Up @@ -217,13 +220,18 @@ impl Task {
cpu: cpu.get_apic_id(),
}),
id: TASK_ID_ALLOCATOR.next_id(),
rootdir: opendir("/")?,
list_link: LinkedListAtomicLink::default(),
runlist_link: LinkedListAtomicLink::default(),
objs: Arc::new(RWLock::new(BTreeMap::new())),
}))
}

pub fn create_user(cpu: &PerCpu, user_entry: usize) -> Result<TaskPointer, SvsmError> {
pub fn create_user(
cpu: &PerCpu,
user_entry: usize,
root: Arc<dyn Directory>,
) -> Result<TaskPointer, SvsmError> {
let mut pgtable = cpu.get_pgtable().clone_shared()?;

cpu.populate_page_table(&mut pgtable);
Expand Down Expand Up @@ -265,6 +273,7 @@ impl Task {
cpu: cpu.get_apic_id(),
}),
id: TASK_ID_ALLOCATOR.next_id(),
rootdir: root,
list_link: LinkedListAtomicLink::default(),
runlist_link: LinkedListAtomicLink::default(),
objs: Arc::new(RWLock::new(BTreeMap::new())),
Expand All @@ -279,6 +288,10 @@ impl Task {
self.id
}

pub fn rootdir(&self) -> Arc<dyn Directory> {
self.rootdir.clone()
}

pub fn set_task_running(&self) {
self.sched_state.lock_write().state = TaskState::RUNNING;
}
Expand Down
1 change: 1 addition & 0 deletions syscall/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const CLASS1: u64 = 1 << 32;

// Syscall number in class0
pub const SYS_EXIT: u64 = CLASS0;
pub const SYS_EXEC: u64 = CLASS0 + 4;
pub const SYS_CLOSE: u64 = CLASS0 + 10;

// Syscall number in class1
Expand Down

0 comments on commit 047d5de

Please sign in to comment.