Skip to content
Merged
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
2 changes: 2 additions & 0 deletions litebox/src/fs/nine_p/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ impl<Platform: sync::RawSyncPrimitivesProvider, T: transport::Read + transport::
flags: super::OFlags,
mode: super::Mode,
) -> Result<FileFd<Platform, T>, super::errors::OpenError> {
// TODO: we don't support non-blocking, so ignore that flag instead of returning an error
let flags = flags - OFlags::NONBLOCK;
Comment on lines +554 to +555
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our current FS assumes every operation is nonblocking, which does not hold for 9p fs over network. To give the illusion that 9p fs is nonblocking, we use spin loop in the litebox_shim_linux that waits until an operation is done. This is a temporary workaround that makes it work for the SNP runner, in which case it might be fine because the remote 9p server supposes to run locally at VMPL0. We should not use it elsewhere.

let currently_supported_oflags: OFlags = OFlags::RDONLY
| OFlags::WRONLY
| OFlags::RDWR
Expand Down
5 changes: 3 additions & 2 deletions litebox_platform_linux_kernel/src/host/snp/snp-sandbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#define SNP_VMPL_CLONE_REQ 0xd
#define SNP_VMPL_EXECVE_REQ 0xe
#define SNP_VMPL_HANDLE_SIGNAL_REQ 0xf
#define SNP_VMPL_LOAD_FILE_REQ 0x10
#define SNP_VMPL_SEND_INTERRUPT_REQ 0x11
// Do nothing, just return back to VMPL2 for measurement
#define SNP_VMPL_IDLE_REQ 0xff
Expand Down Expand Up @@ -116,7 +115,9 @@ struct vsbox_task {
uint64_t status;
uint64_t alt_stack;
uint64_t robust_list;
unsigned long flags; // task_struct->thread_info->flags in Linux
/// Bitmask of dequeued signals forwarded from VMPL0.
/// Bit (1 << (signo - 1)) is set for each pending signal.
uint64_t pending_signals;
uint64_t mem_map; // VData<MemMAP>
/// Thread ID - the internal kernel "pid"
uint32_t pid;
Expand Down
111 changes: 31 additions & 80 deletions litebox_platform_linux_kernel/src/host/snp/snp_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

//! An implementation of [`HostInterface`] for SNP VMM
use ::alloc::{boxed::Box, ffi::CString, vec::Vec};
use ::alloc::boxed::Box;
use core::{
arch::asm,
cell::{Cell, OnceCell},
Expand Down Expand Up @@ -203,13 +203,16 @@ pub unsafe fn run_thread(
}

fn exit_thread() -> ! {
ACTIVE_THREAD_COUNT.fetch_sub(1, Ordering::Release);

let tls = current().unwrap().tls.cast::<ThreadState>();
if !tls.is_null() {
let tls = unsafe { Box::from_raw(tls) };
drop(tls);
}
// `ACTIVE_THREAD_COUNT` is used in [`all_threads_exited`] to determine when all threads have exited,
// and the network backgroun worker relies on it to know when to stop. So we need to decrement it after
// we drop the TLS because the destructor of the TLS (e.g., 9p fs) still need access to network.
ACTIVE_THREAD_COUNT.fetch_sub(1, Ordering::Release);

let r = HostSnpInterface::syscalls(SyscallN::<1, NR_SYSCALL_EXIT> { args: [0] });
unreachable!("thread has exited: {:?}", r);
}
Expand Down Expand Up @@ -307,7 +310,6 @@ const PHYS_ADDR_MAX: u64 = 0x10_0000_0000u64; // 64GB
const NR_SYSCALL_FUTEX: u32 = 202;
const NR_SYSCALL_READ: u32 = 0;
const NR_SYSCALL_WRITE: u32 = 1;
#[allow(dead_code)]
const NR_SYSCALL_EXIT: u32 = 60;
const NR_SYSCALL_EXIT_GROUP: u32 = 231;
const NR_SYSCALL_CLONE3: u32 = 435;
Expand All @@ -324,14 +326,6 @@ pub struct SyscallN<const N: usize, const ID: u32> {
args: [u64; N],
}

/// Page-aligned buffer for reading file chunks from host
#[repr(C, align(4096))]
struct PageAlignedBuffer([u8; 4096]);

/// Maximum file size that can be loaded (4MB)
/// This is limited by the maximum contiguous memory allocation size.
const MAX_FILE_SIZE: u64 = PAGE_SIZE << bindings::SNP_VMPL_ALLOC_MAX_ORDER;

impl HostSnpInterface {
#[cfg(debug_assertions)]
pub fn dump_stack(rsp: usize, count: usize) {
Expand All @@ -350,45 +344,6 @@ impl HostSnpInterface {
Self::request(&mut req);
}

/// Load a file from host by path
///
/// Note that the maximum file size is limited to 4MB.
pub fn load_file_from_host(path: &str) -> Result<Vec<u8>, Errno> {
const CHUNK_SIZE: usize = 4096;
let mut result = Vec::new();
let mut offset = 0u64;

// Host only accept heap or stack memory with null-terminated string
let path = CString::new(path).map_err(|_| Errno::EINVAL)?;
let mut chunk_buffer = Box::new(PageAlignedBuffer([0u8; CHUNK_SIZE]));
loop {
let bytes_read = Self::load_file(&path, &mut chunk_buffer.0, offset)?;
debug_assert!(bytes_read <= CHUNK_SIZE);

if bytes_read == 0 {
// End of file reached
break;
}

offset += bytes_read as u64;

// Check if file exceeds maximum size
if offset > MAX_FILE_SIZE {
return Err(Errno::EFBIG); // File too large
}

result.extend_from_slice(&chunk_buffer.0[..bytes_read]);

// If we read less than the chunk size, we've reached the end of the file
if bytes_read < CHUNK_SIZE {
break;
}
}

result.shrink_to_fit();
Ok(result)
}

/// [VTL CALL](https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/vsm#vtl-call) via VMMCALL
fn request(arg: &mut bindings::SnpVmplRequestArgs) {
unsafe {
Expand Down Expand Up @@ -421,35 +376,6 @@ impl HostSnpInterface {
Self::parse_result(req.ret).map(|_| ())
}

/// Load a file from host by path
///
/// The host provides files at fixed, predetermined locations identified by path.
///
/// # Parameters
/// - `path`: Path of the file to load
/// - `buffer`: Buffer to store the file content (must be page-aligned, max 4KB)
/// - `offset`: Byte offset in the file to start reading from
///
/// # Returns
/// The number of bytes read on success, or an error
fn load_file(path: &CString, buffer: &mut [u8], offset: u64) -> Result<usize, Errno> {
let path_bytes = path.as_bytes_with_nul();
let mut req = bindings::SnpVmplRequestArgs::new_request(
bindings::SNP_VMPL_LOAD_FILE_REQ,
4, // number of arguments
[
path_bytes.as_ptr() as u64,
buffer.as_mut_ptr() as u64,
buffer.len() as u64,
offset,
0,
0,
],
);
Self::request(&mut req);
Self::parse_result(req.ret)
}

fn parse_result(res: u64) -> Result<usize, Errno> {
const ERESTARTSYS: i64 = 512;
const ERESTARTNOHAND: i64 = 514;
Expand Down Expand Up @@ -658,3 +584,28 @@ impl litebox::platform::CrngProvider for SnpLinuxKernel {
}
}
}

impl litebox::platform::SignalProvider for SnpLinuxKernel {
type Signal = litebox_common_linux::signal::Signal;

fn take_pending_signals(&self, mut f: impl FnMut(Self::Signal)) {
let current = current().unwrap();
let pending_signals: u64;
// SAFETY: `current.pending_signals` is a naturally-aligned `u64` that
// may be written by the host at any time, so we use `xchg` to perform
// an atomic read-and-clear.
unsafe {
asm!(
"xor {tmp}, {tmp}",
"xchg [{addr}], {tmp}",
addr = in(reg) core::ptr::addr_of_mut!(current.pending_signals),
tmp = out(reg) pending_signals,
options(nostack),
);
}
let sigs = litebox_common_linux::signal::SigSet::from_u64(pending_signals);
for sig in sigs {
f(sig);
}
}
}
6 changes: 1 addition & 5 deletions litebox_platform_linux_kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use core::sync::atomic::AtomicU64;
use core::{arch::asm, sync::atomic::AtomicU32};

use litebox::mm::linux::PageRange;
use litebox::platform::Instant as _;
use litebox::platform::RawPointerProvider;
use litebox::platform::page_mgmt::FixedAddressBehavior;
use litebox::platform::{
Expand Down Expand Up @@ -85,9 +84,6 @@ impl<'a, Host: HostInterface> PunchthroughToken for LinuxPunchthroughToken<'a, H
}

impl<Host: HostInterface> Provider for LinuxKernel<Host> {}
impl<Host: HostInterface> litebox::platform::SignalProvider for LinuxKernel<Host> {
type Signal = litebox_common_linux::signal::Signal;
}

// TODO: implement pointer validation to ensure the pointers are in user space.
type UserConstPtr<T> = litebox::platform::common_providers::userspace_pointers::UserConstPtr<
Expand Down Expand Up @@ -155,7 +151,6 @@ pub struct RawMutex<Host: HostInterface> {
unsafe impl<Host: HostInterface> Send for RawMutex<Host> {}
unsafe impl<Host: HostInterface> Sync for RawMutex<Host> {}

/// TODO: common mutex implementation could be moved to a shared crate
impl<Host: HostInterface> litebox::platform::RawMutex for RawMutex<Host> {
const INIT: Self = Self::new();

Expand Down Expand Up @@ -236,6 +231,7 @@ impl<Host: HostInterface> TimeProvider for LinuxKernel<Host> {
}

fn current_time(&self) -> Self::SystemTime {
use litebox::platform::Instant as _;
// Derive the current system time from the monotonic clock elapsed
// since boot, avoiding repeated host calls.
//
Expand Down
2 changes: 1 addition & 1 deletion litebox_platform_linux_userland/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2271,7 +2271,7 @@ fn signal_handler_exit_guest(
guest_context_top = out(reg) guest_context_top,
options(nostack, preserves_flags)
};
Some(guest_context_top.offset(-1))
Some(guest_context_top.sub(1))
}
}

Expand Down
10 changes: 8 additions & 2 deletions litebox_runner_linux_on_windows_userland/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn run(cli_args: CliArgs) -> Result<()> {
let tar_ro = litebox::fs::tar_ro::FileSystem::new(litebox, tar_data.into());
shim_builder.default_fs(in_mem, tar_ro)
};
shim_builder.set_fs(initial_file_system);
let initial_file_system = std::sync::Arc::new(initial_file_system);

shim_builder.set_load_filter(fixup_env);
let shim = shim_builder.build();
Expand Down Expand Up @@ -102,7 +102,13 @@ pub fn run(cli_args: CliArgs) -> Result<()> {
};

let program = shim
.load_program(platform.init_task(), prog_path, argv, envp)
.load_program(
initial_file_system,
platform.init_task(),
prog_path,
argv,
envp,
)
.unwrap();
unsafe {
litebox_platform_windows_userland::run_thread(
Expand Down
8 changes: 4 additions & 4 deletions litebox_runner_linux_on_windows_userland/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use litebox_platform_multiplex::Platform;

pub struct TestLauncher {
platform: &'static Platform,
shim_builder: litebox_shim_linux::LinuxShimBuilder<litebox_shim_linux::DefaultFS>,
shim_builder: litebox_shim_linux::LinuxShimBuilder,
fs: litebox_shim_linux::DefaultFS,
}

Expand Down Expand Up @@ -75,16 +75,16 @@ impl TestLauncher {
self.fs.close(&fd).unwrap();
}

pub fn test_load_exec_common(mut self, executable_path: &str) {
self.shim_builder.set_fs(self.fs);
pub fn test_load_exec_common(self, executable_path: &str) {
let fs = std::sync::Arc::new(self.fs);
let argv = vec![
CString::new(executable_path).unwrap(),
CString::new("hello").unwrap(),
];
let envp = vec![CString::new("PATH=/bin").unwrap()];
let shim = self.shim_builder.build();
let program = shim
.load_program(self.platform.init_task(), executable_path, argv, envp)
.load_program(fs, self.platform.init_task(), executable_path, argv, envp)
.unwrap();
unsafe {
litebox_platform_windows_userland::run_thread(
Expand Down
10 changes: 8 additions & 2 deletions litebox_runner_linux_userland/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ pub fn run(cli_args: CliArgs) -> Result<()> {
)
})?;

shim_builder.set_fs(initial_file_system);
let initial_file_system = std::sync::Arc::new(initial_file_system);

shim_builder.set_load_filter(fixup_env);
let shim = shim_builder.build();
Expand Down Expand Up @@ -414,7 +414,13 @@ pub fn run(cli_args: CliArgs) -> Result<()> {
envp
};

let program = shim.load_program(platform.init_task(), prog_path, argv, envp)?;
let program = shim.load_program(
initial_file_system,
platform.init_task(),
prog_path,
argv,
envp,
)?;

#[cfg(feature = "lock_tracing")]
litebox::sync::start_recording();
Expand Down
8 changes: 4 additions & 4 deletions litebox_runner_linux_userland/tests/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use litebox_platform_multiplex::Platform;

struct TestLauncher {
platform: &'static Platform,
shim_builder: litebox_shim_linux::LinuxShimBuilder<litebox_shim_linux::DefaultFS>,
shim_builder: litebox_shim_linux::LinuxShimBuilder,
fs: litebox_shim_linux::DefaultFS,
}

Expand Down Expand Up @@ -81,7 +81,7 @@ impl TestLauncher {
self.fs.close(&fd).unwrap();
}

fn test_load_exec_common(mut self, executable_path: &str) {
fn test_load_exec_common(self, executable_path: &str) {
let argv = vec![
CString::new(executable_path).unwrap(),
CString::new("hello").unwrap(),
Expand All @@ -90,10 +90,10 @@ impl TestLauncher {
CString::new("PATH=/bin").unwrap(),
CString::new("HOME=/").unwrap(),
];
self.shim_builder.set_fs(self.fs);
let fs = std::sync::Arc::new(self.fs);
let shim = self.shim_builder.build();
let program = shim
.load_program(self.platform.init_task(), executable_path, argv, envp)
.load_program(fs, self.platform.init_task(), executable_path, argv, envp)
.unwrap();
unsafe {
litebox_platform_linux_userland::run_thread(
Expand Down
Loading