Skip to content

Commit

Permalink
Merge pull request #525 from joergroedel/user-fixes
Browse files Browse the repository at this point in the history
User -Mode Update
  • Loading branch information
joergroedel authored Dec 2, 2024
2 parents 2c1be77 + 3ba293f commit 51cb549
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 22 deletions.
5 changes: 3 additions & 2 deletions elf/src/program_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ impl Elf64Phdr {
return Err(ElfError::InvalidSegmentSize);
}

if self.p_align != 0 {
if self.p_align > 1 {
if !self.p_align.is_power_of_two() {
return Err(ElfError::InvalidAddressAlignment);
}
if self.p_vaddr & (self.p_align - 1) != 0 {

if self.p_vaddr % self.p_align != self.p_offset % self.p_align {
return Err(ElfError::UnalignedSegmentAddress);
}
}
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/cpu/smp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::error::SvsmError;
use crate::platform::SvsmPlatform;
use crate::platform::SVSM_PLATFORM;
use crate::requests::{request_loop, request_processing_main};
use crate::task::{create_kernel_task, schedule_init};
use crate::task::{schedule_init, start_kernel_task};
use crate::utils::immut_after_init::immut_after_init_set_multithreaded;

fn start_cpu(platform: &dyn SvsmPlatform, apic_id: u32) -> Result<(), SvsmError> {
Expand Down Expand Up @@ -68,7 +68,7 @@ fn start_ap() {

#[no_mangle]
pub extern "C" fn ap_request_loop() {
create_kernel_task(request_processing_main).expect("Failed to launch request processing task");
start_kernel_task(request_processing_main).expect("Failed to launch request processing task");
request_loop();
panic!("Returned from request_loop!");
}
4 changes: 2 additions & 2 deletions kernel/src/svsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use svsm::sev::utils::{rmp_adjust, RMPFlags};
use svsm::sev::{secrets_page, secrets_page_mut};
use svsm::svsm_paging::{init_page_table, invalidate_early_boot_memory};
use svsm::task::exec_user;
use svsm::task::{create_kernel_task, schedule_init};
use svsm::task::{schedule_init, start_kernel_task};
use svsm::types::{PageSize, GUEST_VMPL, PAGE_SIZE};
use svsm::utils::{immut_after_init::ImmutAfterInitCell, zero_mem_region};
#[cfg(all(feature = "vtpm", not(test)))]
Expand Down Expand Up @@ -462,7 +462,7 @@ pub extern "C" fn svsm_main() {
}
}

create_kernel_task(request_processing_main).expect("Failed to launch request processing task");
start_kernel_task(request_processing_main).expect("Failed to launch request processing task");

#[cfg(test)]
crate::test_main();
Expand Down
35 changes: 29 additions & 6 deletions kernel/src/task/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use crate::error::SvsmError;
use crate::fs::open;
use crate::mm::vm::VMFileMappingFlags;
use crate::mm::USER_MEM_END;
use crate::task::{create_user_task, current_task, schedule};
use crate::task::{create_user_task, current_task, finish_user_task, schedule};
use crate::types::PAGE_SIZE;
use crate::utils::align_up;
use elf::{Elf64File, Elf64PhdrFlags};

fn convert_elf_phdr_flags(flags: Elf64PhdrFlags) -> VMFileMappingFlags {
Expand All @@ -27,6 +28,15 @@ fn convert_elf_phdr_flags(flags: Elf64PhdrFlags) -> VMFileMappingFlags {
vm_flags
}

/// Loads and executes an ELF binary in user-mode.
///
/// # Arguments
///
/// * binary: Path to file in the file-system
///
/// # Returns
///
/// `()` on success, [`SvsmError`] on failure.
pub fn exec_user(binary: &str) -> Result<(), SvsmError> {
let fh = open(binary)?;
let file_size = fh.size();
Expand All @@ -53,14 +63,26 @@ pub fn exec_user(binary: &str) -> Result<(), SvsmError> {
let virt_end = VirtAddr::from(seg.vaddr_range.vaddr_end).align_up(PAGE_SIZE);
let file_offset = seg.file_range.offset_begin;
let len = virt_end - virt_start;
let file_size = seg.file_range.offset_end - seg.file_range.offset_begin;
let flags = convert_elf_phdr_flags(seg.flags);

if !virt_start.is_aligned(PAGE_SIZE) {
return Err(SvsmError::Mem);
}

if file_offset > 0 {
task.mmap_user(virt_start, Some(&fh), file_offset, len, flags)?;
if file_size > len {
return Err(SvsmError::Elf(elf::ElfError::InvalidFileRange));
}

// Handle unaligned VirtAddr and Offset
let start_aligned = virt_start.page_align();
let offset = file_offset - virt_start.page_offset();
let size = file_size + virt_start.page_offset();
task.mmap_user(start_aligned, Some(&fh), offset, size, flags)?;

let size_aligned = align_up(size, PAGE_SIZE);
if size_aligned < len {
let start_anon = start_aligned.const_add(size_aligned);
let remaining_len = len - size_aligned;
task.mmap_user(start_anon, None, 0, remaining_len, flags)?;
}
} else {
task.mmap_user(virt_start, None, 0, len, flags)?;
}
Expand All @@ -75,6 +97,7 @@ pub fn exec_user(binary: &str) -> Result<(), SvsmError> {
let stack_addr = USER_MEM_END - user_stack_size;
task.mmap_user(stack_addr, None, 0, user_stack_size, stack_flags)?;

finish_user_task(task);
schedule();

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ mod tasks;
mod waiting;

pub use schedule::{
create_kernel_task, create_user_task, current_task, current_task_terminated, is_current_task,
schedule, schedule_init, schedule_task, terminate, RunQueue, TASKLIST,
create_user_task, current_task, current_task_terminated, finish_user_task, is_current_task,
schedule, schedule_init, schedule_task, start_kernel_task, terminate, RunQueue, TASKLIST,
};

pub use tasks::{
Expand Down
38 changes: 33 additions & 5 deletions kernel/src/task/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,17 @@ impl TaskList {

pub static TASKLIST: SpinLock<TaskList> = SpinLock::new(TaskList::new());

pub fn create_kernel_task(entry: extern "C" fn()) -> Result<TaskPointer, SvsmError> {
/// Creates, initializes and starts a new kernel task. Note that the task has
/// already started to run before this function returns.
///
/// # Arguments
///
/// * entry: The function to run as the new tasks main function
///
/// # Returns
///
/// A new instance of [`TaskPointer`] on success, [`SvsmError`] on failure.
pub fn start_kernel_task(entry: extern "C" fn()) -> Result<TaskPointer, SvsmError> {
let cpu = this_cpu();
let task = Task::create(cpu, entry)?;
TASKLIST.lock().list().push_back(task.clone());
Expand All @@ -245,15 +255,33 @@ pub fn create_kernel_task(entry: extern "C" fn()) -> Result<TaskPointer, SvsmErr
Ok(task)
}

/// Creates and initializes the kernel state of a new user task. The task is
/// not added to the TASKLIST or run-queue yet.
///
/// # Arguments
///
/// * user_entry: The user-space entry point.
///
/// # Returns
///
/// A new instance of [`TaskPointer`] on success, [`SvsmError`] on failure.
pub fn create_user_task(user_entry: usize) -> Result<TaskPointer, SvsmError> {
let cpu = this_cpu();
let task = Task::create_user(cpu, user_entry)?;
Task::create_user(cpu, user_entry)
}

/// Finished user-space task creation by putting the task on the global
/// TASKLIST and adding it to the run-queue.
///
/// # Arguments
///
/// * task: Pointer to user task
pub fn finish_user_task(task: TaskPointer) {
// Add task to global TASKLIST
TASKLIST.lock().list().push_back(task.clone());

// Put task on the runqueue of this CPU
cpu.runqueue().lock_write().handle_task(task.clone());

Ok(task)
this_cpu().runqueue().lock_write().handle_task(task);
}

pub fn current_task() -> TaskPointer {
Expand Down
6 changes: 3 additions & 3 deletions kernel/src/task/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ extern "C" fn task_exit() {

#[cfg(test)]
mod tests {
use crate::task::create_kernel_task;
use crate::task::start_kernel_task;
use core::arch::asm;
use core::arch::global_asm;

Expand Down Expand Up @@ -792,7 +792,7 @@ mod tests {
#[test]
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
fn test_fpu_context_switch() {
create_kernel_task(task1).expect("Failed to launch request processing task");
start_kernel_task(task1).expect("Failed to launch request processing task");
}

extern "C" fn task1() {
Expand All @@ -801,7 +801,7 @@ mod tests {
asm!("call test_fpu", options(att_syntax));
}

create_kernel_task(task2).expect("Failed to launch request processing task");
start_kernel_task(task2).expect("Failed to launch request processing task");

unsafe {
asm!("call check_fpu", out("rax") ret, options(att_syntax));
Expand Down

0 comments on commit 51cb549

Please sign in to comment.