Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement object management #456

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions kernel/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::mm::alloc::AllocError;
use crate::sev::ghcb::GhcbError;
use crate::sev::msr_protocol::GhcbMsrError;
use crate::sev::SevSnpError;
use crate::syscall::ObjError;
use crate::task::TaskError;
use elf::ElfError;

Expand Down Expand Up @@ -83,6 +84,8 @@ pub enum SvsmError {
Acpi,
/// Errors from the filesystem.
FileSystem(FsError),
/// Obj related error
Obj(ObjError),
/// Task management errors,
Task(TaskError),
/// Errors from #VC handler
Expand All @@ -104,3 +107,9 @@ impl From<ApicError> for SvsmError {
Self::Apic(err)
}
}

impl From<ObjError> for SvsmError {
fn from(err: ObjError) -> Self {
Self::Obj(err)
}
}
2 changes: 2 additions & 0 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
// Author: Joerg Roedel <jroedel@suse.de>

mod handlers;
mod obj;

pub use handlers::*;
pub use obj::{Obj, ObjError, ObjHandle};
113 changes: 113 additions & 0 deletions kernel/src/syscall/obj.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2024 Intel Corporation.
//
// Author: Chuanxiao Dong <chuanxiao.dong@intel.com>

extern crate alloc;

use crate::cpu::percpu::current_task;
use crate::error::SvsmError;
use alloc::sync::Arc;

#[derive(Clone, Copy, Debug)]
pub enum ObjError {
InvalidHandle,
NotFound,
}

/// An object represents the type of resource like file, VM, vCPU in the
/// COCONUT-SVSM kernel which can be accessible by the user mode. The Obj
/// trait is defined for such type of resource, which can be used to define
/// the common functionalities of the objects. With the trait bounds of Send
/// and Sync, the objects implementing Obj trait could be sent to another
/// thread and shared between threads safely.
pub trait Obj: Send + Sync + core::fmt::Debug {}

/// ObjHandle is a unique identifier for an object in the current process.
/// An ObjHandle can be converted to a u32 id which can be used by the user
/// mode to access this object. The passed id from the user mode by syscalls
/// can be converted to an `ObjHandle`, which is used to access the object in
/// the COCONUT-SVSM kernel.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct ObjHandle(u32);

impl ObjHandle {
pub fn new(id: u32) -> Self {
Self(id)
}
}

impl From<u32> for ObjHandle {
#[inline]
fn from(id: u32) -> Self {
Self(id)
}
}

impl From<ObjHandle> for u32 {
#[inline]
fn from(obj_handle: ObjHandle) -> Self {
obj_handle.0
}
}

/// Add an object to the current process and assigns it an `ObjHandle`.
///
/// # Arguments
///
/// * `obj` - An `Arc<dyn Obj>` representing the object to be added.
///
/// # Returns
///
/// * `Result<ObjHandle, SvsmError>` - Returns the object handle of the
/// added object if successful, or an `SvsmError` on failure.
///
/// # Errors
///
/// This function will return an error if adding the object to the
/// current task fails.
#[allow(dead_code)]
pub fn obj_add(obj: Arc<dyn Obj>) -> Result<ObjHandle, SvsmError> {
current_task().add_obj(obj)
}

/// Closes an object identified by its ObjHandle.
///
/// # Arguments
///
/// * `id` - The ObjHandle for the object to be closed.
///
/// # Returns
///
/// * `Result<Arc<dyn Obj>>, SvsmError>` - Returns the `Arc<dyn Obj>`
/// on success, or an `SvsmError` on failure.
///
/// # Errors
///
/// This function will return an error if removing the object from the
/// current task fails.
#[allow(dead_code)]
pub fn obj_close(id: ObjHandle) -> Result<Arc<dyn Obj>, SvsmError> {
current_task().remove_obj(id)
}

/// Retrieves an object by its ObjHandle.
///
/// # Arguments
///
/// * `id` - The ObjHandle for the object to be retrieved.
///
/// # Returns
///
/// * `Result<Arc<dyn Obj>>, SvsmError>` - Returns the `Arc<dyn Obj>` on
/// success, or an `SvsmError` on failure.
///
/// # Errors
///
/// This function will return an error if retrieving the object from the
/// current task fails.
#[allow(dead_code)]
pub fn obj_get(id: ObjHandle) -> Result<Arc<dyn Obj>, SvsmError> {
current_task().get_obj(id)
}
88 changes: 88 additions & 0 deletions kernel/src/task/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

extern crate alloc;

use alloc::collections::btree_map::BTreeMap;
use alloc::sync::Arc;
use core::fmt;
use core::mem::size_of;
Expand All @@ -27,6 +28,7 @@ use crate::mm::{
mappings::create_anon_mapping, mappings::create_file_mapping, VMMappingGuard,
SVSM_PERTASK_BASE, SVSM_PERTASK_END, SVSM_PERTASK_STACK_BASE, USER_MEM_END, USER_MEM_START,
};
use crate::syscall::{Obj, ObjError, ObjHandle};
use crate::types::{SVSM_USER_CS, SVSM_USER_DS};
use crate::utils::MemoryRegion;
use intrusive_collections::{intrusive_adapter, LinkedListAtomicLink};
Expand Down Expand Up @@ -139,6 +141,9 @@ pub struct Task {

/// Link to scheduler run queue
runlist_link: LinkedListAtomicLink,

/// Objects shared among threads within the same process
objs: Arc<RWLock<BTreeMap<ObjHandle, Arc<dyn Obj>>>>,
}

// SAFETY: Send + Sync is required for Arc<Task> to implement Send. All members
Expand Down Expand Up @@ -206,6 +211,7 @@ impl Task {
id: TASK_ID_ALLOCATOR.next_id(),
list_link: LinkedListAtomicLink::default(),
runlist_link: LinkedListAtomicLink::default(),
objs: Arc::new(RWLock::new(BTreeMap::new())),
}))
}

Expand Down Expand Up @@ -249,6 +255,7 @@ impl Task {
id: TASK_ID_ALLOCATOR.next_id(),
list_link: LinkedListAtomicLink::default(),
runlist_link: LinkedListAtomicLink::default(),
objs: Arc::new(RWLock::new(BTreeMap::new())),
}))
}

Expand Down Expand Up @@ -475,6 +482,87 @@ impl Task {
self.vm_user_range.as_ref().unwrap().remove(addr)?;
Ok(())
}

/// Adds an object to the current task.
///
/// # Arguments
///
/// * `obj` - The object to be added.
///
/// # Returns
///
/// * `Result<ObjHandle, SvsmError>` - Returns the object handle for the object
/// to be added if successful, or an `SvsmError` on failure.
///
/// # Errors
///
/// This function will return an error if allocating the object handle fails.
pub fn add_obj(&self, obj: Arc<dyn Obj>) -> Result<ObjHandle, SvsmError> {
let mut objs = self.objs.lock_write();
let last_key = objs
.keys()
.last()
.map_or(Some(0), |k| u32::from(*k).checked_add(1))
.ok_or(SvsmError::from(ObjError::InvalidHandle))?;
let id = ObjHandle::new(if last_key != objs.len() as u32 {
objs.keys()
.enumerate()
.find(|(i, &key)| *i as u32 != u32::from(key))
.unwrap()
.0 as u32
} else {
last_key
});

objs.insert(id, obj);

Ok(id)
}

/// Removes an object from the current task.
///
/// # Arguments
///
/// * `id` - The ObjHandle for the object to be removed.
///
/// # Returns
///
/// * `Result<Arc<dyn Obj>>, SvsmError>` - Returns the removed `Arc<dyn Obj>`
/// on success, or an `SvsmError` on failure.
///
/// # Errors
///
/// This function will return an error if the object handle id does not
/// exist in the current task.
pub fn remove_obj(&self, id: ObjHandle) -> Result<Arc<dyn Obj>, SvsmError> {
self.objs
.lock_write()
.remove(&id)
.ok_or(ObjError::NotFound.into())
}

/// Retrieves an object from the current task.
///
/// # Arguments
///
/// * `id` - The ObjHandle for the object to be retrieved.
///
/// # Returns
///
/// * `Result<Arc<dyn Obj>>, SvsmError>` - Returns the `Arc<dyn Obj>` on
/// success, or an `SvsmError` on failure.
///
/// # Errors
///
/// This function will return an error if the object handle id does not exist
/// in the current task.
pub fn get_obj(&self, id: ObjHandle) -> Result<Arc<dyn Obj>, SvsmError> {
self.objs
.lock_read()
.get(&id)
.cloned()
.ok_or(ObjError::NotFound.into())
}
}

pub fn is_task_fault(vaddr: VirtAddr) -> bool {
Expand Down
2 changes: 2 additions & 0 deletions syscall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@
#![no_std]

mod numbers;
mod obj;

pub use numbers::*;
pub use obj::*;
29 changes: 29 additions & 0 deletions syscall/src/obj.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2024 Intel Corporation.
//
// Author: Chuanxiao Dong <chuanxiao.dong@intel.com>

/// The object is exposed to the user mode via the object-opening related
/// syscalls, which returns the id of the object created by the COCONUT-SVSM
/// kernel. The user mode can make use this id to access the corresponding
/// object via other syscalls. From the user mode's point of view, an
/// ObjHanle is defined to wrap a u32 which is the value returned by an
/// object-opening syscall. This u32 value can be used as the input for the
/// syscalls to access the corresponding kernel object.
#[derive(Debug)]
pub struct ObjHandle(u32);

impl ObjHandle {
#[allow(dead_code)]
pub(crate) fn new(id: u32) -> Self {
Self(id)
}
}

impl From<&ObjHandle> for u32 {
#[inline]
fn from(obj_handle: &ObjHandle) -> Self {
obj_handle.0
}
}
Loading