diff --git a/Cargo.lock b/Cargo.lock index 9770b25e7..6b14556a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1352,6 +1352,7 @@ dependencies = [ "hyperlight-testing", "log", "spin 0.10.0", + "thiserror 2.0.16", "tracing", ] @@ -1412,11 +1413,23 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-macro", "hyperlight-guest-tracing", + "linkme", "log", "spin 0.10.0", ] +[[package]] +name = "hyperlight-guest-macro" +version = "0.9.0" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "hyperlight-guest-tracing" version = "0.9.0" @@ -1888,6 +1901,26 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linkme" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b1703c00b2a6a70738920544aa51652532cacddfec2e162d2e29eae01e665c" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index d5f9a4092..e8374879c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "src/hyperlight_testing", "fuzz", "src/hyperlight_guest_bin", + "src/hyperlight_guest_macro", "src/hyperlight_component_util", "src/hyperlight_component_macro", "src/trace_dump", @@ -41,6 +42,7 @@ hyperlight-common = { path = "src/hyperlight_common", version = "0.9.0", default hyperlight-host = { path = "src/hyperlight_host", version = "0.9.0", default-features = false } hyperlight-guest = { path = "src/hyperlight_guest", version = "0.9.0", default-features = false } hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.9.0", default-features = false } +hyperlight-guest-macro = { path = "src/hyperlight_guest_macro", version = "0.9.0", default-features = false } hyperlight-testing = { path = "src/hyperlight_testing", default-features = false } hyperlight-guest-tracing = { path = "src/hyperlight_guest_tracing", version = "0.9.0", default-features = false } hyperlight-guest-tracing-macro = { path = "src/hyperlight_guest_tracing_macro", version = "0.9.0", default-features = false } diff --git a/src/hyperlight_common/Cargo.toml b/src/hyperlight_common/Cargo.toml index b74dbb023..b487690fd 100644 --- a/src/hyperlight_common/Cargo.toml +++ b/src/hyperlight_common/Cargo.toml @@ -21,14 +21,16 @@ log = "0.4.27" tracing = { version = "0.1.41", optional = true } arbitrary = {version = "1.4.2", optional = true, features = ["derive"]} spin = "0.10.0" +thiserror = { version = "2.0.16", default-features = false } [features] default = ["tracing"] +tracing = ["dep:tracing"] fuzzing = ["dep:arbitrary"] trace_guest = [] unwind_guest = [] mem_profile = [] -std = [] +std = ["thiserror/std", "log/std", "tracing/std"] [dev-dependencies] hyperlight-testing = { workspace = true } diff --git a/src/hyperlight_common/src/func/error.rs b/src/hyperlight_common/src/func/error.rs new file mode 100644 index 000000000..26883a7c7 --- /dev/null +++ b/src/hyperlight_common/src/func/error.rs @@ -0,0 +1,45 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use alloc::string::String; + +use thiserror::Error; + +use crate::func::{ParameterValue, ReturnValue}; + +/// The error type for Hyperlight operations +#[derive(Error, Debug)] +pub enum Error { + /// Failed to get value from parameter value + #[error("Failed To Convert Parameter Value {0:?} to {1:?}")] + ParameterValueConversionFailure(ParameterValue, &'static str), + + /// Failed to get value from return value + #[error("Failed To Convert Return Value {0:?} to {1:?}")] + ReturnValueConversionFailure(ReturnValue, &'static str), + + /// A function was called with an incorrect number of arguments + #[error("The number of arguments to the function is wrong: got {0:?} expected {1:?}")] + UnexpectedNoOfArguments(usize, usize), + + /// The parameter value type is unexpected + #[error("The parameter value type is unexpected got {0:?} expected {1:?}")] + UnexpectedParameterValueType(ParameterValue, String), + + /// The return value type is unexpected + #[error("The return value type is unexpected got {0:?} expected {1:?}")] + UnexpectedReturnValueType(ReturnValue, String), +} diff --git a/src/hyperlight_common/src/func/functions.rs b/src/hyperlight_common/src/func/functions.rs new file mode 100644 index 000000000..a663ef2f6 --- /dev/null +++ b/src/hyperlight_common/src/func/functions.rs @@ -0,0 +1,40 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use super::utils::for_each_tuple; +use super::{Error, ParameterTuple, ResultType, SupportedReturnType}; + +pub trait Function> { + fn call(&self, args: Args) -> Result; +} + +macro_rules! impl_function { + ([$N:expr] ($($p:ident: $P:ident),*)) => { + impl Function for F + where + F: Fn($($P),*) -> R, + ($($P,)*): ParameterTuple, + R: ResultType, + E: From + core::fmt::Debug, + { + fn call(&self, ($($p,)*): ($($P,)*)) -> Result { + (self)($($p),*).into_result() + } + } + }; +} + +for_each_tuple!(impl_function); diff --git a/src/hyperlight_common/src/func/mod.rs b/src/hyperlight_common/src/func/mod.rs new file mode 100644 index 000000000..5556f6fe7 --- /dev/null +++ b/src/hyperlight_common/src/func/mod.rs @@ -0,0 +1,49 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/// Error types related to function support +pub(crate) mod error; +/// Definitions and functionality to enable guest-to-host function calling, +/// also called "host functions" +/// +/// This module includes functionality to do the following +/// +/// - Define several prototypes for what a host function must look like, +/// including the number of arguments (arity) they can have, supported argument +/// types, and supported return types +/// - Registering host functions to be callable by the guest +/// - Dynamically dispatching a call from the guest to the appropriate +/// host function +pub(crate) mod functions; +/// Definitions and functionality for supported parameter types +pub(crate) mod param_type; +/// Definitions and functionality for supported return types +pub(crate) mod ret_type; + +pub use error::Error; +/// Re-export for `HostFunction` trait +pub use functions::Function; +pub use param_type::{ParameterTuple, SupportedParameterType}; +pub use ret_type::{ResultType, SupportedReturnType}; + +/// Re-export for `ParameterValue` enum +pub use crate::flatbuffer_wrappers::function_types::ParameterValue; +/// Re-export for `ReturnType` enum +pub use crate::flatbuffer_wrappers::function_types::ReturnType; +/// Re-export for `ReturnType` enum +pub use crate::flatbuffer_wrappers::function_types::ReturnValue; + +mod utils; diff --git a/src/hyperlight_host/src/func/param_type.rs b/src/hyperlight_common/src/func/param_type.rs similarity index 72% rename from src/hyperlight_host/src/func/param_type.rs rename to src/hyperlight_common/src/func/param_type.rs index b86a89d33..b4db004d8 100644 --- a/src/hyperlight_host/src/func/param_type.rs +++ b/src/hyperlight_common/src/func/param_type.rs @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterType, ParameterValue}; -use tracing::{Span, instrument}; +use alloc::string::String; +use alloc::vec; +use alloc::vec::Vec; +use super::error::Error; use super::utils::for_each_tuple; -use crate::HyperlightError::{ParameterValueConversionFailure, UnexpectedNoOfArguments}; -use crate::{Result, log_then_return}; +use crate::flatbuffer_wrappers::function_types::{ParameterType, ParameterValue}; /// This is a marker trait that is used to indicate that a type is a /// valid Hyperlight parameter type. @@ -34,7 +35,7 @@ pub trait SupportedParameterType: Sized + Clone + Send + Sync + 'static { /// `SupportedParameterType` fn into_value(self) -> ParameterValue; /// Get the actual inner value of this `SupportedParameterType` - fn from_value(value: ParameterValue) -> Result; + fn from_value(value: ParameterValue) -> Result; } // We can then implement these traits for each type that Hyperlight supports as a parameter or return type @@ -57,21 +58,17 @@ macro_rules! impl_supported_param_type { impl SupportedParameterType for $type { const TYPE: ParameterType = ParameterType::$enum; - #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn into_value(self) -> ParameterValue { ParameterValue::$enum(self) } - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn from_value(value: ParameterValue) -> Result { + fn from_value(value: ParameterValue) -> Result { match value { ParameterValue::$enum(i) => Ok(i), - other => { - log_then_return!(ParameterValueConversionFailure( - other.clone(), - stringify!($type) - )); - } + other => Err(Error::ParameterValueConversionFailure( + other.clone(), + stringify!($type), + )), } } } @@ -93,7 +90,7 @@ pub trait ParameterTuple: Sized + Clone + Send + Sync + 'static { fn into_value(self) -> Vec; /// Get the actual inner value of this `SupportedParameterType` - fn from_value(value: Vec) -> Result; + fn from_value(value: Vec) -> Result; } impl ParameterTuple for T { @@ -101,18 +98,14 @@ impl ParameterTuple for T { const TYPE: &[ParameterType] = &[T::TYPE]; - #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn into_value(self) -> Vec { vec![self.into_value()] } - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn from_value(value: Vec) -> Result { + fn from_value(value: Vec) -> Result { match <[ParameterValue; 1]>::try_from(value) { Ok([val]) => Ok(T::from_value(val)?), - Err(value) => { - log_then_return!(UnexpectedNoOfArguments(value.len(), 1)); - } + Err(value) => Err(Error::UnexpectedNoOfArguments(value.len(), 1)), } } } @@ -126,17 +119,15 @@ macro_rules! impl_param_tuple { $($param::TYPE),* ]; - #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn into_value(self) -> Vec { let ($($name,)*) = self; vec![$($name.into_value()),*] } - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn from_value(value: Vec) -> Result { + fn from_value(value: Vec) -> Result { match <[ParameterValue; $N]>::try_from(value) { Ok([$($name,)*]) => Ok(($($param::from_value($name)?,)*)), - Err(value) => { log_then_return!(UnexpectedNoOfArguments(value.len(), $N)); } + Err(value) => Err(Error::UnexpectedNoOfArguments(value.len(), $N)) } } } diff --git a/src/hyperlight_host/src/func/ret_type.rs b/src/hyperlight_common/src/func/ret_type.rs similarity index 60% rename from src/hyperlight_host/src/func/ret_type.rs rename to src/hyperlight_common/src/func/ret_type.rs index 89fe1481f..9534b51be 100644 --- a/src/hyperlight_host/src/func/ret_type.rs +++ b/src/hyperlight_common/src/func/ret_type.rs @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -use hyperlight_common::flatbuffer_wrappers::function_types::{ReturnType, ReturnValue}; -use tracing::{Span, instrument}; +use alloc::string::String; +use alloc::vec::Vec; -use crate::HyperlightError::ReturnValueConversionFailure; -use crate::{Result, log_then_return}; +use super::error::Error; +use crate::flatbuffer_wrappers::function_types::{ReturnType, ReturnValue}; /// This is a marker trait that is used to indicate that a type is a valid Hyperlight return type. pub trait SupportedReturnType: Sized + Clone + Send + Sync + 'static { @@ -29,16 +29,7 @@ pub trait SupportedReturnType: Sized + Clone + Send + Sync + 'static { fn into_value(self) -> ReturnValue; /// Gets the inner value of the supported return type - fn from_value(value: ReturnValue) -> Result; -} - -/// A trait to handle either a [`SupportedReturnType`] or a [`Result`] -pub trait ResultType { - /// The return type of the supported return value - type ReturnType: SupportedReturnType; - - /// Convert the return type into a `Result` - fn into_result(self) -> Result; + fn from_value(value: ReturnValue) -> Result; } macro_rules! for_each_return_type { @@ -61,43 +52,65 @@ macro_rules! impl_supported_return_type { impl SupportedReturnType for $type { const TYPE: ReturnType = ReturnType::$enum; - #[instrument(skip_all, parent = Span::current(), level= "Trace")] fn into_value(self) -> ReturnValue { ReturnValue::$enum(self) } - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn from_value(value: ReturnValue) -> Result { + fn from_value(value: ReturnValue) -> Result { match value { ReturnValue::$enum(i) => Ok(i), - other => { - log_then_return!(ReturnValueConversionFailure( - other.clone(), - stringify!($type) - )); - } + other => Err(Error::ReturnValueConversionFailure( + other.clone(), + stringify!($type), + )), } } } + }; +} - impl ResultType for $type { - type ReturnType = $type; +/// A trait to handle either a [`SupportedReturnType`] or a [`Result`] +pub trait ResultType { + /// The return type of the supported return value + type ReturnType: SupportedReturnType; - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn into_result(self) -> Result { - Ok(self) - } - } + /// Convert the return type into a `Result` + fn into_result(self) -> Result; - impl ResultType for Result<$type> { - type ReturnType = $type; + /// Convert a result into this type, panicking if needed + fn from_result(res: Result) -> Self; +} - #[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")] - fn into_result(self) -> Result { - self - } - } - }; +impl ResultType for T +where + T: SupportedReturnType, + E: core::fmt::Debug, +{ + type ReturnType = T; + + fn into_result(self) -> Result { + Ok(self) + } + + fn from_result(res: Result) -> Self { + res.unwrap() + } +} + +impl ResultType for Result +where + T: SupportedReturnType, + E: core::fmt::Debug, +{ + type ReturnType = T; + + fn into_result(self) -> Result { + self + } + + fn from_result(res: Result) -> Self { + res + } } for_each_return_type!(impl_supported_return_type); diff --git a/src/hyperlight_host/src/func/utils.rs b/src/hyperlight_common/src/func/utils.rs similarity index 98% rename from src/hyperlight_host/src/func/utils.rs rename to src/hyperlight_common/src/func/utils.rs index 6e92ca041..e7132aef5 100644 --- a/src/hyperlight_host/src/func/utils.rs +++ b/src/hyperlight_common/src/func/utils.rs @@ -31,6 +31,8 @@ limitations under the License. /// /// for_each_tuple!(my_macro); /// ``` +#[doc(hidden)] +#[macro_export] macro_rules! for_each_tuple { (@ $macro:ident diff --git a/src/hyperlight_common/src/lib.rs b/src/hyperlight_common/src/lib.rs index e22cf6417..eda7fa33c 100644 --- a/src/hyperlight_common/src/lib.rs +++ b/src/hyperlight_common/src/lib.rs @@ -42,3 +42,6 @@ pub mod outb; /// cbindgen:ignore pub mod resource; + +/// cbindgen:ignore +pub mod func; diff --git a/src/hyperlight_guest/Cargo.toml b/src/hyperlight_guest/Cargo.toml index ecc516241..12abb2151 100644 --- a/src/hyperlight_guest/Cargo.toml +++ b/src/hyperlight_guest/Cargo.toml @@ -14,7 +14,7 @@ Provides only the essential building blocks for interacting with the host enviro [dependencies] anyhow = { version = "1.0.99", default-features = false } serde_json = { version = "1.0", default-features = false, features = ["alloc"] } -hyperlight-common = { workspace = true } +hyperlight-common = { workspace = true, default-features = false } hyperlight-guest-tracing = { workspace = true, default-features = false } flatbuffers = { version= "25.2.10", default-features = false } diff --git a/src/hyperlight_guest/src/error.rs b/src/hyperlight_guest/src/error.rs index db7e01924..733a1c2d9 100644 --- a/src/hyperlight_guest/src/error.rs +++ b/src/hyperlight_guest/src/error.rs @@ -15,9 +15,10 @@ limitations under the License. */ use alloc::format; -use alloc::string::String; +use alloc::string::{String, ToString as _}; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; +use hyperlight_common::func::Error as FuncError; use {anyhow, serde_json}; pub type Result = core::result::Result; @@ -51,3 +52,30 @@ impl From for HyperlightGuestError { } } } + +impl From for HyperlightGuestError { + fn from(e: FuncError) -> Self { + match e { + FuncError::ParameterValueConversionFailure(..) => HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + e.to_string(), + ), + FuncError::ReturnValueConversionFailure(..) => HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + e.to_string(), + ), + FuncError::UnexpectedNoOfArguments(..) => HyperlightGuestError::new( + ErrorCode::GuestFunctionIncorrecNoOfParameters, + e.to_string(), + ), + FuncError::UnexpectedParameterValueType(..) => HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + e.to_string(), + ), + FuncError::UnexpectedReturnValueType(..) => HyperlightGuestError::new( + ErrorCode::GuestFunctionParameterTypeMismatch, + e.to_string(), + ), + } + } +} diff --git a/src/hyperlight_guest_bin/Cargo.toml b/src/hyperlight_guest_bin/Cargo.toml index c21d00c91..93245d36b 100644 --- a/src/hyperlight_guest_bin/Cargo.toml +++ b/src/hyperlight_guest_bin/Cargo.toml @@ -19,13 +19,18 @@ libc = [] # compile musl libc printf = [ "libc" ] # compile printf trace_guest = ["hyperlight-common/trace_guest", "hyperlight-guest/trace_guest", "hyperlight-guest-tracing/trace"] mem_profile = ["hyperlight-common/unwind_guest","hyperlight-common/mem_profile"] +# Not enabled by default as with rustc < 1.89, linkme requires the +# -znostart-stop-gc linker flag. Fixed in rustc 1.89+. +macros = ["dep:hyperlight-guest-macro", "dep:linkme"] [dependencies] hyperlight-guest = { workspace = true, default-features = false } hyperlight-common = { workspace = true, default-features = false } hyperlight-guest-tracing = { workspace = true, default-features = false } +hyperlight-guest-macro = { workspace = true, default-features = false, optional = true } buddy_system_allocator = "0.11.0" log = { version = "0.4", default-features = false } +linkme = { version = "0.3.33", optional = true } spin = "0.10.0" [lints] diff --git a/src/hyperlight_guest_bin/src/guest_function/definition.rs b/src/hyperlight_guest_bin/src/guest_function/definition.rs index a60ca2e14..a173d5e01 100644 --- a/src/hyperlight_guest_bin/src/guest_function/definition.rs +++ b/src/hyperlight_guest_bin/src/guest_function/definition.rs @@ -18,8 +18,14 @@ use alloc::format; use alloc::string::String; use alloc::vec::Vec; +use hyperlight_common::flatbuffer_wrappers::function_call::FunctionCall; use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterType, ReturnType}; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; +use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result; +use hyperlight_common::for_each_tuple; +use hyperlight_common::func::{ + Function, ParameterTuple, ResultType, ReturnValue, SupportedReturnType, +}; use hyperlight_guest::error::{HyperlightGuestError, Result}; /// The definition of a function exposed from the guest to the host @@ -35,6 +41,101 @@ pub struct GuestFunctionDefinition { pub function_pointer: usize, } +/// Trait for functions that can be converted to a `fn(&FunctionCall) -> Result>` +#[doc(hidden)] +pub trait IntoGuestFunction +where + Self: Function, + Self: Copy + 'static, + Output: SupportedReturnType, + Args: ParameterTuple, +{ + #[doc(hidden)] + const ASSERT_ZERO_SIZED: (); + + /// Convert the function into a `fn(&FunctionCall) -> Result>` + fn into_guest_function(self) -> fn(&FunctionCall) -> Result>; +} + +/// Trait for functions that can be converted to a `GuestFunctionDefinition` +pub trait AsGuestFunctionDefinition +where + Self: Function, + Self: IntoGuestFunction, + Output: SupportedReturnType, + Args: ParameterTuple, +{ + /// Get the `GuestFunctionDefinition` for this function + fn as_guest_function_definition(&self, name: impl Into) -> GuestFunctionDefinition; +} + +fn into_flatbuffer_result(value: ReturnValue) -> Vec { + match value { + ReturnValue::Void(()) => get_flatbuffer_result(()), + ReturnValue::Int(i) => get_flatbuffer_result(i), + ReturnValue::UInt(u) => get_flatbuffer_result(u), + ReturnValue::Long(l) => get_flatbuffer_result(l), + ReturnValue::ULong(ul) => get_flatbuffer_result(ul), + ReturnValue::Float(f) => get_flatbuffer_result(f), + ReturnValue::Double(d) => get_flatbuffer_result(d), + ReturnValue::Bool(b) => get_flatbuffer_result(b), + ReturnValue::String(s) => get_flatbuffer_result(s.as_str()), + ReturnValue::VecBytes(v) => get_flatbuffer_result(v.as_slice()), + } +} + +macro_rules! impl_host_function { + ([$N:expr] ($($p:ident: $P:ident),*)) => { + impl IntoGuestFunction for F + where + F: Fn($($P),*) -> R, + F: Function, + F: Copy + 'static, // Copy implies that F has no Drop impl + ($($P,)*): ParameterTuple, + R: ResultType, + { + #[doc(hidden)] + const ASSERT_ZERO_SIZED: () = const { + assert!(core::mem::size_of::() == 0) + }; + + fn into_guest_function(self) -> fn(&FunctionCall) -> Result> { + |fc: &FunctionCall| { + // SAFETY: This is safe because of the safety comment on the function. + let this = unsafe { core::mem::zeroed::() }; + let params = fc.parameters.clone().unwrap_or_default(); + let params = <($($P,)*) as ParameterTuple>::from_value(params)?; + let result = Function::::call(&this, params)?; + Ok(into_flatbuffer_result(result.into_value())) + } + } + } + }; +} + +impl AsGuestFunctionDefinition for F +where + F: IntoGuestFunction, + Args: ParameterTuple, + Output: SupportedReturnType, +{ + fn as_guest_function_definition(&self, name: impl Into) -> GuestFunctionDefinition { + let parameter_types = Args::TYPE.to_vec(); + let return_type = Output::TYPE; + let function_pointer = self.into_guest_function(); + let function_pointer = function_pointer as usize; + + GuestFunctionDefinition { + function_name: name.into(), + parameter_types, + return_type, + function_pointer, + } + } +} + +for_each_tuple!(impl_host_function); + impl GuestFunctionDefinition { /// Create a new `GuestFunctionDefinition`. pub fn new( @@ -51,6 +152,19 @@ impl GuestFunctionDefinition { } } + /// Create a new `GuestFunctionDefinition` from a function that implements + /// `AsGuestFunctionDefinition`. + pub fn from_fn( + function_name: String, + function: impl AsGuestFunctionDefinition, + ) -> Self + where + Args: ParameterTuple, + Output: SupportedReturnType, + { + function.as_guest_function_definition(function_name) + } + /// Verify that `self` has same signature as the provided `parameter_types`. pub fn verify_parameters(&self, parameter_types: &[ParameterType]) -> Result<()> { // Verify that the function does not have more than `MAX_PARAMETERS` parameters. diff --git a/src/hyperlight_guest_bin/src/guest_function/register.rs b/src/hyperlight_guest_bin/src/guest_function/register.rs index e68ed6440..ec64bda2e 100644 --- a/src/hyperlight_guest_bin/src/guest_function/register.rs +++ b/src/hyperlight_guest_bin/src/guest_function/register.rs @@ -17,8 +17,11 @@ limitations under the License. use alloc::collections::BTreeMap; use alloc::string::String; +use hyperlight_common::func::{ParameterTuple, SupportedReturnType}; + use super::definition::GuestFunctionDefinition; use crate::REGISTERED_GUEST_FUNCTIONS; +use crate::guest_function::definition::AsGuestFunctionDefinition; /// Represents the functions that the guest exposes to the host. #[derive(Debug, Default, Clone)] @@ -47,6 +50,18 @@ impl GuestFunctionRegister { .insert(guest_function.function_name.clone(), guest_function) } + pub fn register_fn( + &mut self, + name: impl Into, + f: impl AsGuestFunctionDefinition, + ) where + Args: ParameterTuple, + Output: SupportedReturnType, + { + let gfd = f.as_guest_function_definition(name); + self.register(gfd); + } + /// Gets a `GuestFunctionDefinition` by its `name` field. pub fn get(&self, function_name: &str) -> Option<&GuestFunctionDefinition> { self.guest_functions.get(function_name) @@ -62,3 +77,19 @@ pub fn register_function(function_definition: GuestFunctionDefinition) { gfd.register(function_definition); } } + +pub fn register_fn( + name: impl Into, + f: impl AsGuestFunctionDefinition, +) where + Args: ParameterTuple, + Output: SupportedReturnType, +{ + unsafe { + // This is currently safe, because we are single threaded, but we + // should find a better way to do this, see issue #808 + #[allow(static_mut_refs)] + let gfd = &mut REGISTERED_GUEST_FUNCTIONS; + gfd.register_fn(name, f); + } +} diff --git a/src/hyperlight_guest_bin/src/host_comm.rs b/src/hyperlight_guest_bin/src/host_comm.rs index ab0b3d46a..1fc327526 100644 --- a/src/hyperlight_guest_bin/src/host_comm.rs +++ b/src/hyperlight_guest_bin/src/host_comm.rs @@ -26,6 +26,7 @@ use hyperlight_common::flatbuffer_wrappers::function_types::{ use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::flatbuffer_wrappers::host_function_details::HostFunctionDetails; use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result; +use hyperlight_common::func::{ParameterTuple, SupportedReturnType}; use hyperlight_guest::error::{HyperlightGuestError, Result}; const BUFFER_SIZE: usize = 1000; @@ -45,6 +46,13 @@ where handle.call_host_function::(function_name, parameters, return_type) } +pub fn call_host(function_name: impl AsRef, args: impl ParameterTuple) -> Result +where + T: SupportedReturnType + TryFrom, +{ + call_host_function::(function_name.as_ref(), Some(args.into_value()), T::TYPE) +} + pub fn call_host_function_without_returning_result( function_name: &str, parameters: Option>, diff --git a/src/hyperlight_guest_bin/src/lib.rs b/src/hyperlight_guest_bin/src/lib.rs index 27918ad3f..f5d9f4e91 100644 --- a/src/hyperlight_guest_bin/src/lib.rs +++ b/src/hyperlight_guest_bin/src/lib.rs @@ -206,6 +206,11 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve .expect("Invalid log level"); init_logger(max_log_level); + #[cfg(feature = "macros")] + for registration in __private::GUEST_FUNCTION_INIT { + registration(); + } + trace!("hyperlight_main", hyperlight_main(); ); @@ -214,3 +219,17 @@ pub extern "C" fn entrypoint(peb_address: u64, seed: u64, ops: u64, max_log_leve halt(); } + +#[cfg(feature = "macros")] +#[doc(hidden)] +pub mod __private { + pub use hyperlight_common::func::ResultType; + pub use hyperlight_guest::error::HyperlightGuestError; + pub use linkme; + + #[linkme::distributed_slice] + pub static GUEST_FUNCTION_INIT: [fn()]; +} + +#[cfg(feature = "macros")] +pub use hyperlight_guest_macro::{guest_function, host_function}; diff --git a/src/hyperlight_guest_macro/Cargo.toml b/src/hyperlight_guest_macro/Cargo.toml new file mode 100644 index 000000000..d3a7b5cfc --- /dev/null +++ b/src/hyperlight_guest_macro/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "hyperlight-guest-macro" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +readme.workspace = true +description = """ +Macros for registering guest and host functions on hyperlight guests binaries. +""" + +[dependencies] +syn = { version = "2", features = ["full"] } +quote = "1" +proc-macro2 = "1.0" +proc-macro-crate = "3.3.0" + +[lib] +proc-macro = true + +[lints] +workspace = true diff --git a/src/hyperlight_guest_macro/src/lib.rs b/src/hyperlight_guest_macro/src/lib.rs new file mode 100644 index 000000000..1ee238319 --- /dev/null +++ b/src/hyperlight_guest_macro/src/lib.rs @@ -0,0 +1,204 @@ +/* +Copyright 2025 The Hyperlight Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +use proc_macro::TokenStream; +use proc_macro_crate::{FoundCrate, crate_name}; +use quote::quote; +use syn::parse::{Error, Parse, ParseStream, Result}; +use syn::spanned::Spanned as _; +use syn::{ForeignItemFn, ItemFn, LitStr, Pat, parse_macro_input}; + +enum NameArg { + None, + Name(LitStr), +} + +impl Parse for NameArg { + fn parse(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(NameArg::None); + } + let name: LitStr = input.parse()?; + if !input.is_empty() { + return Err(Error::new(input.span(), "expected a single identifier")); + } + Ok(NameArg::Name(name)) + } +} + +#[proc_macro_attribute] +pub fn guest_function(attr: TokenStream, item: TokenStream) -> TokenStream { + let crate_name = + crate_name("hyperlight-guest-bin").expect("hyperlight-guest-bin must be a dependency"); + let crate_name = match crate_name { + FoundCrate::Itself => quote! {crate}, + FoundCrate::Name(name) => { + let ident = syn::Ident::new(&name, proc_macro2::Span::call_site()); + quote! {::#ident} + } + }; + + let fn_declaration = parse_macro_input!(item as ItemFn); + + let ident = fn_declaration.sig.ident.clone(); + + let exported_name = match parse_macro_input!(attr as NameArg) { + NameArg::None => quote! { stringify!(#ident) }, + NameArg::Name(name) => quote! { #name }, + }; + + if let Some(syn::FnArg::Receiver(arg)) = fn_declaration.sig.inputs.first() { + return Error::new( + arg.span(), + "Receiver (self) argument is not allowed in guest functions", + ) + .to_compile_error() + .into(); + } + + if fn_declaration.sig.asyncness.is_some() { + return Error::new( + fn_declaration.sig.asyncness.span(), + "Async functions are not allowed in guest functions", + ) + .to_compile_error() + .into(); + } + + let output = quote! { + #fn_declaration + + const _: () = { + #[#crate_name::__private::linkme::distributed_slice(#crate_name::__private::GUEST_FUNCTION_INIT)] + #[linkme(crate = #crate_name::__private::linkme)] + static REGISTRATION: fn() = || { + hyperlight_guest_bin::guest_function::register::register_fn(#exported_name, #ident); + }; + }; + }; + + output.into() +} + +#[proc_macro_attribute] +pub fn host_function(attr: TokenStream, item: TokenStream) -> TokenStream { + let crate_name = + crate_name("hyperlight-guest-bin").expect("hyperlight-guest-bin must be a dependency"); + let crate_name = match crate_name { + FoundCrate::Itself => quote! {crate}, + FoundCrate::Name(name) => { + let ident = syn::Ident::new(&name, proc_macro2::Span::call_site()); + quote! {::#ident} + } + }; + + let fn_declaration = parse_macro_input!(item as ForeignItemFn); + + let ForeignItemFn { + attrs, + vis, + sig, + semi_token: _, + } = fn_declaration; + + let ident = sig.ident.clone(); + + let exported_name = match parse_macro_input!(attr as NameArg) { + NameArg::None => quote! { stringify!(#ident) }, + NameArg::Name(name) => quote! { #name }, + }; + + let mut args = vec![]; + for arg in sig.inputs.iter() { + match arg { + syn::FnArg::Receiver(_) => { + return Error::new( + arg.span(), + "Receiver (self) argument is not allowed in guest functions", + ) + .to_compile_error() + .into(); + } + syn::FnArg::Typed(arg) => { + let Pat::Ident(pat) = *arg.pat.clone() else { + return Error::new( + arg.span(), + "Only named arguments are allowed in host functions", + ) + .to_compile_error() + .into(); + }; + + if pat.attrs.len() > 0 { + return Error::new( + arg.span(), + "Attributes are not allowed on host function arguments", + ) + .to_compile_error() + .into(); + } + + if pat.by_ref.is_some() { + return Error::new( + arg.span(), + "By-ref arguments are not allowed in host functions", + ) + .to_compile_error() + .into(); + } + + if pat.mutability.is_some() { + return Error::new( + arg.span(), + "Mutable arguments are not allowed in host functions", + ) + .to_compile_error() + .into(); + } + + if pat.subpat.is_some() { + return Error::new( + arg.span(), + "Sub-patterns are not allowed in host functions", + ) + .to_compile_error() + .into(); + } + + let ident = pat.ident.clone(); + + args.push(quote! { #ident }); + } + } + } + + let ret: proc_macro2::TokenStream = match &sig.output { + syn::ReturnType::Default => quote! { quote! { () } }, + syn::ReturnType::Type(_, ty) => { + quote! { #ty } + } + }; + + let output = quote! { + #(#attrs)* #vis #sig { + use #crate_name::__private::{ResultType, HyperlightGuestError}; + use #crate_name::host_comm::call_host; + <#ret as ResultType>::from_result(call_host(#exported_name, (#(#args,)*))) + } + }; + + output.into() +} diff --git a/src/hyperlight_host/src/func/host_functions.rs b/src/hyperlight_host/src/func/host_functions.rs index 3944b0703..5347d371a 100644 --- a/src/hyperlight_host/src/func/host_functions.rs +++ b/src/hyperlight_host/src/func/host_functions.rs @@ -17,12 +17,13 @@ limitations under the License. use std::sync::{Arc, Mutex}; use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue}; +use hyperlight_common::for_each_tuple; +use hyperlight_common::func::{Error as FuncError, Function, ResultType}; -use super::utils::for_each_tuple; -use super::{ParameterTuple, ResultType, SupportedReturnType}; +use super::{ParameterTuple, SupportedReturnType}; use crate::sandbox::host_funcs::FunctionEntry; use crate::sandbox::{ExtraAllowedSyscall, UninitializedSandbox}; -use crate::{Result, new_error}; +use crate::{HyperlightError, Result, new_error}; /// A sandbox on which (primitive) host functions can be registered /// @@ -118,7 +119,7 @@ where // Use Arc in here instead of Box because it's useful in tests and // presumably in other places to be able to clone a HostFunction and // use it across different sandboxes. - func: Arc Result + Send + Sync + 'static>, + func: Arc + Send + Sync + 'static>, } pub(crate) struct TypeErasedHostFunction { @@ -132,7 +133,7 @@ where { /// Call the host function with the given arguments. pub fn call(&self, args: Args) -> Result { - (self.func)(args) + self.func.call(args) } } @@ -142,6 +143,28 @@ impl TypeErasedHostFunction { } } +impl From for HyperlightError { + fn from(e: FuncError) -> Self { + match e { + FuncError::ParameterValueConversionFailure(from, to) => { + HyperlightError::ParameterValueConversionFailure(from, to) + } + FuncError::ReturnValueConversionFailure(from, to) => { + HyperlightError::ReturnValueConversionFailure(from, to) + } + FuncError::UnexpectedNoOfArguments(got, expected) => { + HyperlightError::UnexpectedNoOfArguments(got, expected) + } + FuncError::UnexpectedParameterValueType(got, expected) => { + HyperlightError::UnexpectedParameterValueType(got, expected) + } + FuncError::UnexpectedReturnValueType(got, expected) => { + HyperlightError::UnexpectedReturnValueType(got, expected) + } + } + } +} + impl From> for TypeErasedHostFunction where Args: ParameterTuple, @@ -164,26 +187,22 @@ macro_rules! impl_host_function { // like we do in the case of a `FnMut`. // However, we can't implement `IntoHostFunction` for `Fn` and `FnMut` // because `FnMut` is a supertrait of `Fn`. - */ + */ impl From for HostFunction where F: FnMut($($P),*) -> R + Send + 'static, ($($P,)*): ParameterTuple, - R: ResultType, + R: ResultType, { - fn from(mut func: F) -> HostFunction { - let func = move |($($p,)*): ($($P,)*)| -> Result { - func($($p),*).into_result() - }; + fn from(func: F) -> HostFunction { let func = Mutex::new(func); - HostFunction { - func: Arc::new(move |args: ($($P,)*)| { - func.try_lock() - .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))? - (args) - }) - } + let func = move |$($p: $P,)*| { + let mut func = func.lock().map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?; + (func)($($p),*).into_result() + }; + let func = Arc::new(func); + HostFunction { func } } } }; diff --git a/src/hyperlight_host/src/func/mod.rs b/src/hyperlight_host/src/func/mod.rs index 57b69dbc4..3ac62ab47 100644 --- a/src/hyperlight_host/src/func/mod.rs +++ b/src/hyperlight_host/src/func/mod.rs @@ -28,10 +28,6 @@ pub(crate) mod guest_err; /// - Dynamically dispatching a call from the guest to the appropriate /// host function pub(crate) mod host_functions; -/// Definitions and functionality for supported parameter types -pub(crate) mod param_type; -/// Definitions and functionality for supported return types -pub(crate) mod ret_type; /// Re-export for `HostFunction` trait pub use host_functions::{HostFunction, Registerable}; @@ -39,9 +35,8 @@ pub use host_functions::{HostFunction, Registerable}; pub use hyperlight_common::flatbuffer_wrappers::function_types::ParameterValue; /// Re-export for `ReturnType` enum pub use hyperlight_common::flatbuffer_wrappers::function_types::ReturnType; -/// Re-export for `ReturnType` enum +/// Re-export for `ReturnValue` enum pub use hyperlight_common::flatbuffer_wrappers::function_types::ReturnValue; -pub use param_type::{ParameterTuple, SupportedParameterType}; -pub use ret_type::{ResultType, SupportedReturnType}; - -mod utils; +pub use hyperlight_common::func::{ + ParameterTuple, ResultType, SupportedParameterType, SupportedReturnType, +}; diff --git a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs index 82a920158..1b2aaf8f1 100644 --- a/src/hyperlight_host/src/sandbox/initialized_multi_use.rs +++ b/src/hyperlight_host/src/sandbox/initialized_multi_use.rs @@ -296,7 +296,8 @@ impl MultiUseSandbox { Output::TYPE, args.into_value(), ); - Output::from_value(ret?) + let ret = Output::from_value(ret?)?; + Ok(ret) }) } diff --git a/src/tests/rust_guests/simpleguest/.cargo/config.toml b/src/tests/rust_guests/simpleguest/.cargo/config.toml index 037201bc1..0dd88f142 100644 --- a/src/tests/rust_guests/simpleguest/.cargo/config.toml +++ b/src/tests/rust_guests/simpleguest/.cargo/config.toml @@ -3,10 +3,9 @@ target = "x86_64-unknown-none" [target.x86_64-unknown-none] rustflags = [ - "-C", - "code-model=small", - "-C", - "link-args=-e entrypoint", + "-Ccode-model=small", + "-Clink-args=-e entrypoint", + "-Clink-arg=-znostart-stop-gc", ] linker = "rust-lld" diff --git a/src/tests/rust_guests/simpleguest/Cargo.lock b/src/tests/rust_guests/simpleguest/Cargo.lock index 1900d8955..a884624d5 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.lock +++ b/src/tests/rust_guests/simpleguest/Cargo.lock @@ -44,6 +44,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "flatbuffers" version = "25.2.10" @@ -60,6 +66,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + [[package]] name = "hyperlight-common" version = "0.9.0" @@ -68,6 +80,7 @@ dependencies = [ "flatbuffers", "log", "spin 0.10.0", + "thiserror", ] [[package]] @@ -91,11 +104,23 @@ dependencies = [ "glob", "hyperlight-common", "hyperlight-guest", + "hyperlight-guest-macro", "hyperlight-guest-tracing", + "linkme", "log", "spin 0.10.0", ] +[[package]] +name = "hyperlight-guest-macro" +version = "0.9.0" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "hyperlight-guest-tracing" version = "0.9.0" @@ -114,12 +139,42 @@ dependencies = [ "syn", ] +[[package]] +name = "indexmap" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "linkme" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b1703c00b2a6a70738920544aa51652532cacddfec2e162d2e29eae01e665c" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "lock_api" version = "0.4.13" @@ -142,6 +197,15 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -265,8 +329,54 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] diff --git a/src/tests/rust_guests/simpleguest/Cargo.toml b/src/tests/rust_guests/simpleguest/Cargo.toml index 34925b9fc..f977814bc 100644 --- a/src/tests/rust_guests/simpleguest/Cargo.toml +++ b/src/tests/rust_guests/simpleguest/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] hyperlight-guest = { path = "../../../hyperlight_guest" } -hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin" } +hyperlight-guest-bin = { path = "../../../hyperlight_guest_bin", features = ["macros"] } hyperlight-common = { path = "../../../hyperlight_common", default-features = false } hyperlight-guest-tracing = { path = "../../../hyperlight_guest_tracing" } log = {version = "0.4", default-features = false } diff --git a/src/tests/rust_guests/simpleguest/src/main.rs b/src/tests/rust_guests/simpleguest/src/main.rs index c3b17ad58..6c08a811a 100644 --- a/src/tests/rust_guests/simpleguest/src/main.rs +++ b/src/tests/rust_guests/simpleguest/src/main.rs @@ -26,7 +26,7 @@ const MAX_BUFFER_SIZE: usize = 1024; extern crate alloc; use alloc::boxed::Box; -use alloc::string::ToString; +use alloc::string::{String, ToString}; use alloc::vec::Vec; use alloc::{format, vec}; use core::ffi::c_char; @@ -34,442 +34,247 @@ use core::hint::black_box; use core::ptr::write_volatile; use hyperlight_common::flatbuffer_wrappers::function_call::{FunctionCall, FunctionCallType}; -use hyperlight_common::flatbuffer_wrappers::function_types::{ - ParameterType, ParameterValue, ReturnType, -}; +use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnType}; use hyperlight_common::flatbuffer_wrappers::guest_error::ErrorCode; use hyperlight_common::flatbuffer_wrappers::guest_log_level::LogLevel; use hyperlight_common::flatbuffer_wrappers::util::get_flatbuffer_result; use hyperlight_common::mem::PAGE_SIZE; use hyperlight_guest::error::{HyperlightGuestError, Result}; use hyperlight_guest::exit::{abort_with_code, abort_with_code_and_message}; -use hyperlight_guest_bin::guest_function::definition::GuestFunctionDefinition; -use hyperlight_guest_bin::guest_function::register::register_function; use hyperlight_guest_bin::host_comm::{ - call_host_function, call_host_function_without_returning_result, read_n_bytes_from_user_memory, + call_host, call_host_function, call_host_function_without_returning_result, + read_n_bytes_from_user_memory, }; use hyperlight_guest_bin::memory::malloc; -use hyperlight_guest_bin::{MIN_STACK_ADDRESS, guest_logger}; +use hyperlight_guest_bin::{MIN_STACK_ADDRESS, guest_function, guest_logger, host_function}; use log::{LevelFilter, error}; extern crate hyperlight_guest; static mut BIGARRAY: [i32; 1024 * 1024] = [0; 1024 * 1024]; +#[host_function("HostPrint")] +fn host_print(message: String) -> Result; + +#[host_function("MakeGetpidSyscall")] +fn make_getpid_syscall() -> Result; + +#[host_function("HostAdd")] +fn host_add(a: i32, b: i32) -> Result; + +#[guest_function("SetStatic")] #[hyperlight_guest_tracing::trace_function] -fn set_static(_: &FunctionCall) -> Result> { +fn set_static() -> i32 { + #[allow(static_mut_refs)] unsafe { - #[allow(static_mut_refs)] for val in BIGARRAY.iter_mut() { *val = 1; } - #[allow(static_mut_refs)] - Ok(get_flatbuffer_result(BIGARRAY.len() as i32)) + BIGARRAY.len() as i32 } } +#[guest_function("EchoDouble")] #[hyperlight_guest_tracing::trace_function] -fn echo_double(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Double(value) = function_call.parameters.clone().unwrap()[0].clone() { - Ok(get_flatbuffer_result(value)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to echo_double".to_string(), - )) - } +fn echo_double(value: f64) -> f64 { + value } +#[guest_function("EchoFloat")] #[hyperlight_guest_tracing::trace_function] -fn echo_float(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Float(value) = function_call.parameters.clone().unwrap()[0].clone() { - Ok(get_flatbuffer_result(value)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to echo_float".to_string(), - )) - } +fn echo_float(value: f32) -> f32 { + value } +#[guest_function("PrintUsingPrintf")] #[hyperlight_guest_tracing::trace_function] -fn print_output(message: &str) -> Result> { - let res = call_host_function::( - "HostPrint", - Some(Vec::from(&[ParameterValue::String(message.to_string())])), - ReturnType::Int, - )?; - - Ok(get_flatbuffer_result(res)) +fn simple_print_output(message: String) -> Result { + host_print(message) } +#[guest_function("PrintOutput")] #[hyperlight_guest_tracing::trace_function] -fn simple_print_output(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to simple_print_output".to_string(), - )) - } +fn print_output(message: String) -> Result { + host_print(message) } +#[guest_function("SetByteArrayToZero")] #[hyperlight_guest_tracing::trace_function] -fn set_byte_array_to_zero(function_call: &FunctionCall) -> Result> { - if let ParameterValue::VecBytes(mut vec) = function_call.parameters.clone().unwrap()[0].clone() - { - vec.fill(0); - Ok(get_flatbuffer_result(&*vec)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to set_byte_array_to_zero".to_string(), - )) - } +fn set_byte_array_to_zero(mut vec: Vec) -> Vec { + vec.fill(0); + vec } +#[guest_function("PrintTwoArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_two_args(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::String(arg1), ParameterValue::Int(arg2)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let message = format!("Message: arg1:{} arg2:{}.", arg1, arg2); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_two_args".to_string(), - )) - } +fn print_two_args(arg1: String, arg2: i32) -> Result { + let message = format!("Message: arg1:{arg1} arg2:{arg2}."); + host_print(message) } +#[guest_function("PrintThreeArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_three_args(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::String(arg1), ParameterValue::Int(arg2), ParameterValue::Long(arg3)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - ) { - let message = format!("Message: arg1:{} arg2:{} arg3:{}.", arg1, arg2, arg3); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_three_args".to_string(), - )) - } +fn print_three_args(arg1: String, arg2: i32, arg3: i64) -> Result { + let message = format!("Message: arg1:{arg1} arg2:{arg2} arg3:{arg3}."); + host_print(message) } +#[guest_function("PrintFourArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_four_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{}.", - arg1, arg2, arg3, arg4 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_four_args".to_string(), - )) - } +fn print_four_args(arg1: String, arg2: i32, arg3: i64, arg4: String) -> Result { + let message = format!("Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4}."); + host_print(message) } +#[guest_function("PrintFiveArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_five_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{}.", - arg1, arg2, arg3, arg4, arg5 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_five_args".to_string(), - )) - } +fn print_five_args(arg1: String, arg2: i32, arg3: i64, arg4: String, arg5: String) -> Result { + let message = format!("Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5}."); + host_print(message) } +#[guest_function("PrintSixArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_six_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ParameterValue::Bool(arg6), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - function_call.parameters.clone().unwrap()[5].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{} arg6:{}.", - arg1, arg2, arg3, arg4, arg5, arg6 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_six_args".to_string(), - )) - } +fn print_six_args( + arg1: String, + arg2: i32, + arg3: i64, + arg4: String, + arg5: String, + arg6: bool, +) -> Result { + let message = format!( + "Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5} arg6:{arg6}." + ); + host_print(message) } +#[guest_function("PrintSevenArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_seven_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ParameterValue::Bool(arg6), - ParameterValue::Bool(arg7), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - function_call.parameters.clone().unwrap()[5].clone(), - function_call.parameters.clone().unwrap()[6].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{} arg6:{} arg7:{}.", - arg1, arg2, arg3, arg4, arg5, arg6, arg7 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_seven_args".to_string(), - )) - } +fn print_seven_args( + arg1: String, + arg2: i32, + arg3: i64, + arg4: String, + arg5: String, + arg6: bool, + arg7: bool, +) -> Result { + let message = format!( + "Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5} arg6:{arg6} arg7:{arg7}." + ); + host_print(message) } +#[guest_function("PrintEightArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_eight_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ParameterValue::Bool(arg6), - ParameterValue::Bool(arg7), - ParameterValue::UInt(arg8), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - function_call.parameters.clone().unwrap()[5].clone(), - function_call.parameters.clone().unwrap()[6].clone(), - function_call.parameters.clone().unwrap()[7].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{} arg6:{} arg7:{} arg8:{}.", - arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_eight_args".to_string(), - )) - } +fn print_eight_args( + arg1: String, + arg2: i32, + arg3: i64, + arg4: String, + arg5: String, + arg6: bool, + arg7: bool, + arg8: u32, +) -> Result { + let message = format!( + "Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5} arg6:{arg6} arg7:{arg7} arg8:{arg8}." + ); + host_print(message) } +#[guest_function("PrintNineArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_nine_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ParameterValue::Bool(arg6), - ParameterValue::Bool(arg7), - ParameterValue::UInt(arg8), - ParameterValue::ULong(arg9), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - function_call.parameters.clone().unwrap()[5].clone(), - function_call.parameters.clone().unwrap()[6].clone(), - function_call.parameters.clone().unwrap()[7].clone(), - function_call.parameters.clone().unwrap()[8].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{} arg6:{} arg7:{} arg8:{} arg9:{}.", - arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_nine_args".to_string(), - )) - } +fn print_nine_args( + arg1: String, + arg2: i32, + arg3: i64, + arg4: String, + arg5: String, + arg6: bool, + arg7: bool, + arg8: u32, + arg9: u64, +) -> Result { + let message = format!( + "Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5} arg6:{arg6} arg7:{arg7} arg8:{arg8} arg9:{arg9}." + ); + host_print(message) } +#[guest_function("PrintTenArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_ten_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ParameterValue::Bool(arg6), - ParameterValue::Bool(arg7), - ParameterValue::UInt(arg8), - ParameterValue::ULong(arg9), - ParameterValue::Int(arg10), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - function_call.parameters.clone().unwrap()[5].clone(), - function_call.parameters.clone().unwrap()[6].clone(), - function_call.parameters.clone().unwrap()[7].clone(), - function_call.parameters.clone().unwrap()[8].clone(), - function_call.parameters.clone().unwrap()[9].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{} arg6:{} arg7:{} arg8:{} arg9:{} arg10:{}.", - arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_ten_args".to_string(), - )) - } +fn print_ten_args( + arg1: String, + arg2: i32, + arg3: i64, + arg4: String, + arg5: String, + arg6: bool, + arg7: bool, + arg8: u32, + arg9: u64, + arg10: i32, +) -> Result { + let message = format!( + "Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5} arg6:{arg6} arg7:{arg7} arg8:{arg8} arg9:{arg9} arg10:{arg10:.3}." + ); + host_print(message) } +#[guest_function("PrintElevenArgs")] #[hyperlight_guest_tracing::trace_function] -fn print_eleven_args(function_call: &FunctionCall) -> Result> { - if let ( - ParameterValue::String(arg1), - ParameterValue::Int(arg2), - ParameterValue::Long(arg3), - ParameterValue::String(arg4), - ParameterValue::String(arg5), - ParameterValue::Bool(arg6), - ParameterValue::Bool(arg7), - ParameterValue::UInt(arg8), - ParameterValue::ULong(arg9), - ParameterValue::Int(arg10), - ParameterValue::Float(arg11), - ) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - function_call.parameters.clone().unwrap()[2].clone(), - function_call.parameters.clone().unwrap()[3].clone(), - function_call.parameters.clone().unwrap()[4].clone(), - function_call.parameters.clone().unwrap()[5].clone(), - function_call.parameters.clone().unwrap()[6].clone(), - function_call.parameters.clone().unwrap()[7].clone(), - function_call.parameters.clone().unwrap()[8].clone(), - function_call.parameters.clone().unwrap()[9].clone(), - function_call.parameters.clone().unwrap()[10].clone(), - ) { - let message = format!( - "Message: arg1:{} arg2:{} arg3:{} arg4:{} arg5:{} arg6:{} arg7:{} arg8:{} arg9:{} arg10:{} arg11:{:.3}.", - arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 - ); - print_output(&message) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to print_eleven_args".to_string(), - )) - } +fn print_eleven_args( + arg1: String, + arg2: i32, + arg3: i64, + arg4: String, + arg5: String, + arg6: bool, + arg7: bool, + arg8: u32, + arg9: u64, + arg10: i32, + arg11: f32, +) -> Result { + let message = format!( + "Message: arg1:{arg1} arg2:{arg2} arg3:{arg3} arg4:{arg4} arg5:{arg5} arg6:{arg6} arg7:{arg7} arg8:{arg8} arg9:{arg9} arg10:{arg10} arg11:{arg11:.3}." + ); + host_print(message) } +#[guest_function("BufferOverrun")] #[hyperlight_guest_tracing::trace_function] -fn buffer_overrun(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { - let c_str = value.as_str(); - - let mut buffer: [u8; 17] = [0; 17]; - let length = c_str.len(); - - let copy_length = length.min(buffer.len()); - buffer[..copy_length].copy_from_slice(&c_str.as_bytes()[..copy_length]); - - let result = (17i32).saturating_sub(length as i32); +fn buffer_overrun(value: String) -> i32 { + let c_str = value.as_str(); - Ok(get_flatbuffer_result(result)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to buffer_overrun".to_string(), - )) - } + let mut buffer: [u8; 17] = [0; 17]; + let length = c_str.len(); + + let copy_length = length.min(buffer.len()); + buffer[..copy_length].copy_from_slice(&c_str.as_bytes()[..copy_length]); + + (17i32).saturating_sub(length as i32) } +#[guest_function("InfiniteRecursion")] #[allow(unconditional_recursion)] #[hyperlight_guest_tracing::trace_function] -fn infinite_recursion(_a: &FunctionCall) -> Result> { +fn infinite_recursion() { // blackbox is needed so something //is written to the stack in release mode, //to trigger guard page violation let param = black_box(5); black_box(param); - infinite_recursion(_a) + infinite_recursion(); } +#[guest_function("StackOverflow")] #[hyperlight_guest_tracing::trace_function] -fn stack_overflow(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { - loop_stack_overflow(i); - Ok(get_flatbuffer_result(i)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to stack_overflow".to_string(), - )) - } +fn stack_overflow(i: i32) -> i32 { + loop_stack_overflow(i); + i } // This function will allocate i * (8KiB + 1B) on the stack #[hyperlight_guest_tracing::trace_function] @@ -480,155 +285,121 @@ fn loop_stack_overflow(i: i32) { } } +#[guest_function("LargeVar")] #[hyperlight_guest_tracing::trace_function] -fn large_var(_: &FunctionCall) -> Result> { +fn large_var() -> i32 { let _buffer = black_box([0u8; (DEFAULT_GUEST_STACK_SIZE + 1) as usize]); - Ok(get_flatbuffer_result(DEFAULT_GUEST_STACK_SIZE + 1)) + DEFAULT_GUEST_STACK_SIZE + 1 } +#[guest_function("SmallVar")] #[hyperlight_guest_tracing::trace_function] -fn small_var(_: &FunctionCall) -> Result> { +fn small_var() -> i32 { let _buffer = black_box([0u8; 1024]); - Ok(get_flatbuffer_result(1024)) + 1024 } +#[guest_function("CallMalloc")] #[hyperlight_guest_tracing::trace_function] -fn call_malloc(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { - // will panic if OOM, and we need blackbox to avoid optimizing away this test - let buffer = Vec::::with_capacity(size as usize); - black_box(buffer); - Ok(get_flatbuffer_result(size)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to call_malloc".to_string(), - )) - } +fn call_malloc(size: i32) -> i32 { + // will panic if OOM, and we need blackbox to avoid optimizing away this test + let buffer = Vec::::with_capacity(size as usize); + black_box(buffer); + size } +#[guest_function("MallocAndFree")] #[hyperlight_guest_tracing::trace_function] -fn malloc_and_free(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Int(size) = function_call.parameters.clone().unwrap()[0].clone() { - let alloc_length = if size < DEFAULT_GUEST_STACK_SIZE { - size - } else { - size.min(MAX_BUFFER_SIZE as i32) - }; - let allocated_buffer = vec![0; alloc_length as usize]; - drop(allocated_buffer); - - Ok(get_flatbuffer_result(size)) +fn malloc_and_free(size: i32) -> i32 { + let alloc_length = if size < DEFAULT_GUEST_STACK_SIZE { + size } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to malloc_and_free".to_string(), - )) - } + size.min(MAX_BUFFER_SIZE as i32) + }; + let allocated_buffer = vec![0; alloc_length as usize]; + drop(allocated_buffer); + size } +#[guest_function("Echo")] #[hyperlight_guest_tracing::trace_function] -fn echo(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(value) = function_call.parameters.clone().unwrap()[0].clone() { - Ok(get_flatbuffer_result(&*value)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to echo".to_string(), - )) - } +fn echo(value: String) -> String { + value } +#[guest_function("GetSizePrefixedBuffer")] #[hyperlight_guest_tracing::trace_function] -fn get_size_prefixed_buffer(function_call: &FunctionCall) -> Result> { - if let ParameterValue::VecBytes(data) = function_call.parameters.clone().unwrap()[0].clone() { - Ok(get_flatbuffer_result(&*data)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to get_size_prefixed_buffer".to_string(), - )) - } +fn get_size_prefixed_buffer(data: Vec) -> Vec { + data } +#[guest_function("Spin")] #[expect( clippy::empty_loop, reason = "This function is used to keep the CPU busy" )] -fn spin(_: &FunctionCall) -> Result> { +fn spin() { loop { // Keep the CPU 100% busy forever } - - #[allow(unreachable_code)] - Ok(get_flatbuffer_result(())) } +#[guest_function("GuestAbortWithCode")] #[hyperlight_guest_tracing::trace_function] -fn test_abort(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { - abort_with_code(&[code as u8]); - } - Ok(get_flatbuffer_result(())) +fn test_abort(code: i32) { + abort_with_code(&[code as u8]); } +#[guest_function("GuestAbortWithMessage")] #[hyperlight_guest_tracing::trace_function] -fn test_abort_with_code_and_message(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::Int(code), ParameterValue::String(message)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - unsafe { - abort_with_code_and_message(&[code as u8], message.as_ptr() as *const c_char); - } +fn test_abort_with_code_and_message(code: i32, message: String) { + unsafe { + abort_with_code_and_message(&[code as u8], message.as_ptr() as *const c_char); } - Ok(get_flatbuffer_result(())) } +#[guest_function("guest_panic")] #[hyperlight_guest_tracing::trace_function] -fn test_guest_panic(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(message) = function_call.parameters.clone().unwrap()[0].clone() { - panic!("{}", message); - } - Ok(get_flatbuffer_result(())) +fn test_guest_panic(message: String) { + panic!("{message}"); } +#[guest_function("test_write_raw_ptr")] #[hyperlight_guest_tracing::trace_function] -fn test_write_raw_ptr(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Long(offset) = function_call.parameters.clone().unwrap()[0].clone() { - let min_stack_addr = unsafe { MIN_STACK_ADDRESS }; - let page_guard_start = min_stack_addr - PAGE_SIZE; - let addr = { - let abs = u64::try_from(offset.abs()) - .map_err(|_| error!("Invalid offset")) - .unwrap(); - if offset.is_negative() { - page_guard_start - abs - } else { - page_guard_start + abs - } - }; - unsafe { - // print_output(format!("writing to {:#x}\n", addr).as_str()).unwrap(); - write_volatile(addr as *mut u8, 0u8); +fn test_write_raw_ptr(offset: i64) -> String { + let min_stack_addr = unsafe { MIN_STACK_ADDRESS }; + let page_guard_start = min_stack_addr - PAGE_SIZE; + let addr = { + let abs = u64::try_from(offset.abs()) + .map_err(|_| error!("Invalid offset")) + .unwrap(); + if offset.is_negative() { + page_guard_start - abs + } else { + page_guard_start + abs } - return Ok(get_flatbuffer_result("success")); + }; + unsafe { + // print_output(format!("writing to {:#x}\n", addr).as_str()).unwrap(); + write_volatile(addr as *mut u8, 0u8); } - Ok(get_flatbuffer_result("fail")) + "success".into() } +#[guest_function("ExecuteOnStack")] #[hyperlight_guest_tracing::trace_function] -fn execute_on_stack(_function_call: &FunctionCall) -> Result> { +fn execute_on_stack() -> String { unsafe { let mut noop: u8 = 0x90; let stack_fn: fn() = core::mem::transmute(&mut noop as *mut u8); stack_fn(); }; - Ok(get_flatbuffer_result("fail")) + "fail".into() } +#[guest_function("ExecuteOnHeap")] #[hyperlight_guest_tracing::trace_function] -fn execute_on_heap(_function_call: &FunctionCall) -> Result> { +fn execute_on_heap() -> String { unsafe { // NO-OP followed by RET let heap_memory = Box::new([0x90u8, 0xC3]); @@ -637,85 +408,54 @@ fn execute_on_heap(_function_call: &FunctionCall) -> Result> { black_box(heap_fn); // avoid optimization when running in release mode } // will only reach this point if heap is executable - Ok(get_flatbuffer_result("fail")) + "fail".into() } +#[guest_function("TestMalloc")] #[hyperlight_guest_tracing::trace_function] -fn test_rust_malloc(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Int(code) = function_call.parameters.clone().unwrap()[0].clone() { - let ptr = unsafe { malloc(code as usize) }; - Ok(get_flatbuffer_result(ptr as i32)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to test_rust_malloc".to_string(), - )) - } +fn test_rust_malloc(code: i32) -> i32 { + let ptr = unsafe { malloc(code as usize) }; + ptr as i32 } +#[guest_function("LogMessage")] #[hyperlight_guest_tracing::trace_function] -fn log_message(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::String(message), ParameterValue::Int(level)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let level = LevelFilter::iter().nth(level as usize).unwrap().to_level(); - - match level { - Some(level) => log::log!(level, "{}", &message), - None => { - // was passed LevelFilter::Off, do nothing - } - } - Ok(get_flatbuffer_result(())) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to log_message".to_string(), - )) +fn log_message(message: String, level: i32) { + let level = LevelFilter::iter().nth(level as usize).unwrap().to_level(); + + if let Some(level) = level { + log::log!(level, "{message}"); } } +#[guest_function("TriggerException")] #[hyperlight_guest_tracing::trace_function] -fn trigger_exception(_: &FunctionCall) -> Result> { +fn trigger_exception() { unsafe { core::arch::asm!("ud2"); } // trigger an undefined instruction exception - Ok(get_flatbuffer_result(())) } static mut COUNTER: i32 = 0; +#[guest_function("AddToStatic")] #[hyperlight_guest_tracing::trace_function] -fn add_to_static(function_call: &FunctionCall) -> Result> { - if let ParameterValue::Int(i) = function_call.parameters.clone().unwrap()[0].clone() { - let res = unsafe { - COUNTER += i; - COUNTER - }; - Ok(get_flatbuffer_result(res)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to add_to_static".to_string(), - )) +fn add_to_static(i: i32) -> i32 { + unsafe { + COUNTER += i; + COUNTER } } +#[guest_function("GetStatic")] #[hyperlight_guest_tracing::trace_function] -fn get_static(function_call: &FunctionCall) -> Result> { - if function_call.parameters.is_none() { - Ok(get_flatbuffer_result(unsafe { COUNTER })) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to get_static".to_string(), - )) - } +fn get_static() -> i32 { + unsafe { COUNTER } } +#[guest_function("AddToStaticAndFail")] #[hyperlight_guest_tracing::trace_function] -fn add_to_static_and_fail(_: &FunctionCall) -> Result> { +fn add_to_static_and_fail() -> Result { unsafe { COUNTER += 10; }; @@ -725,648 +465,104 @@ fn add_to_static_and_fail(_: &FunctionCall) -> Result> { )) } +#[guest_function("24K_in_8K_out")] #[hyperlight_guest_tracing::trace_function] -fn twenty_four_k_in_eight_k_out(function_call: &FunctionCall) -> Result> { - if let ParameterValue::VecBytes(input) = &function_call.parameters.as_ref().unwrap()[0] { - assert!(input.len() == 24 * 1024, "Input must be 24K bytes"); - Ok(get_flatbuffer_result(&input[..8 * 1024])) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to 24K_in_8K_out".to_string(), - )) - } +fn twenty_four_k_in_eight_k_out(input: Vec) -> Vec { + assert!(input.len() == 24 * 1024, "Input must be 24K bytes"); + input[..8 * 1024].to_vec() } +#[guest_function("ViolateSeccompFilters")] #[hyperlight_guest_tracing::trace_function] -fn violate_seccomp_filters(function_call: &FunctionCall) -> Result> { - if function_call.parameters.is_none() { - let res = call_host_function::("MakeGetpidSyscall", None, ReturnType::ULong)?; - - Ok(get_flatbuffer_result(res)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to violate_seccomp_filters".to_string(), - )) - } +fn violate_seccomp_filters() -> Result { + make_getpid_syscall() } +#[guest_function("CallGivenParamlessHostFuncThatReturnsI64")] #[hyperlight_guest_tracing::trace_function] -fn call_given_paramless_hostfunc_that_returns_i64(function_call: &FunctionCall) -> Result> { - if let ParameterValue::String(hostfuncname) = - function_call.parameters.clone().unwrap()[0].clone() - { - let res = call_host_function::(&hostfuncname, None, ReturnType::Long)?; - - Ok(get_flatbuffer_result(res)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to test_rust_malloc".to_string(), - )) - } +fn call_given_paramless_hostfunc_that_returns_i64(hostfuncname: String) -> Result { + call_host::(&hostfuncname, ()) } +#[guest_function("Add")] #[hyperlight_guest_tracing::trace_function] -fn add(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::Int(a), ParameterValue::Int(b)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let res = call_host_function::( - "HostAdd", - Some(Vec::from(&[ParameterValue::Int(a), ParameterValue::Int(b)])), - ReturnType::Int, - )?; - Ok(get_flatbuffer_result(res)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to add".to_string(), - )) - } +fn add(a: i32, b: i32) -> Result { + host_add(a, b) } // Does nothing, but used for testing large parameters +#[guest_function("LargeParameters")] #[hyperlight_guest_tracing::trace_function] -fn large_parameters(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::VecBytes(v), ParameterValue::String(s)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - black_box((v, s)); - Ok(get_flatbuffer_result(())) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to large_parameters".to_string(), - )) - } +fn large_parameters(v: Vec, s: String) { + black_box((v, s)); } +#[guest_function("ReadFromUserMemory")] #[hyperlight_guest_tracing::trace_function] -fn read_from_user_memory(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::ULong(num), ParameterValue::VecBytes(expected)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let bytes = read_n_bytes_from_user_memory(num).expect("Failed to read from user memory"); - - // verify that the user memory contains the expected data - if bytes != expected { - error!("User memory does not contain the expected data"); - return Err(HyperlightGuestError::new( - ErrorCode::GuestError, - "User memory does not contain the expected data".to_string(), - )); - } +fn read_from_user_memory(num: u64, expected: Vec) -> Result> { + let bytes = read_n_bytes_from_user_memory(num).expect("Failed to read from user memory"); - Ok(get_flatbuffer_result(&*bytes)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to read_from_user_memory".to_string(), - )) + // verify that the user memory contains the expected data + if bytes != expected { + error!("User memory does not contain the expected data"); + return Err(HyperlightGuestError::new( + ErrorCode::GuestError, + "User memory does not contain the expected data".to_string(), + )); } + + Ok(bytes) } +#[guest_function("ReadMappedBuffer")] #[hyperlight_guest_tracing::trace_function] -fn read_mapped_buffer(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let base = base as usize as *const u8; - let len = len as usize; +fn read_mapped_buffer(base: u64, len: u64) -> Vec { + let base = base as usize as *const u8; + let len = len as usize; - unsafe { - hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) - }; + unsafe { hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) }; - let data = unsafe { core::slice::from_raw_parts(base, len) }; + let data = unsafe { core::slice::from_raw_parts(base, len) }; - Ok(get_flatbuffer_result(data)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to read_mapped_buffer".to_string(), - )) - } + data.to_vec() } +#[guest_function("WriteMappedBuffer")] #[hyperlight_guest_tracing::trace_function] -fn write_mapped_buffer(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let base = base as usize as *mut u8; - let len = len as usize; +fn write_mapped_buffer(base: u64, len: u64) -> bool { + let base = base as usize as *mut u8; + let len = len as usize; - unsafe { - hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) - }; + unsafe { hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) }; - let data = unsafe { core::slice::from_raw_parts_mut(base, len) }; + let data = unsafe { core::slice::from_raw_parts_mut(base, len) }; - // should fail - data[0] = 0x42; + // should fail + data[0] = 0x42; - // should never reach this - Ok(get_flatbuffer_result(true)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to read_mapped_buffer".to_string(), - )) - } + // should never reach this + true } #[hyperlight_guest_tracing::trace_function] -fn exec_mapped_buffer(function_call: &FunctionCall) -> Result> { - if let (ParameterValue::ULong(base), ParameterValue::ULong(len)) = ( - function_call.parameters.clone().unwrap()[0].clone(), - function_call.parameters.clone().unwrap()[1].clone(), - ) { - let base = base as usize as *mut u8; - let len = len as usize; +fn exec_mapped_buffer(base: u64, len: u64) -> bool { + let base = base as usize as *mut u8; + let len = len as usize; - unsafe { - hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) - }; + unsafe { hyperlight_guest_bin::paging::map_region(base as _, base as _, len as u64 + 4096) }; - let data = unsafe { core::slice::from_raw_parts(base, len) }; + let data = unsafe { core::slice::from_raw_parts(base, len) }; - // Should be safe as long as data is something like a NOOP followed by a RET - let func: fn() = unsafe { core::mem::transmute(data.as_ptr()) }; - func(); + // Should be safe as long as data is something like a NOOP followed by a RET + let func: fn() = unsafe { core::mem::transmute(data.as_ptr()) }; + func(); - Ok(get_flatbuffer_result(true)) - } else { - Err(HyperlightGuestError::new( - ErrorCode::GuestFunctionParameterTypeMismatch, - "Invalid parameters passed to read_mapped_buffer".to_string(), - )) - } + true } #[no_mangle] #[hyperlight_guest_tracing::trace_function] -pub extern "C" fn hyperlight_main() { - let twenty_four_k_in_def = GuestFunctionDefinition::new( - "24K_in_8K_out".to_string(), - Vec::from(&[ParameterType::VecBytes]), - ReturnType::VecBytes, - twenty_four_k_in_eight_k_out as usize, - ); - register_function(twenty_four_k_in_def); - - let read_from_user_memory_def = GuestFunctionDefinition::new( - "ReadFromUserMemory".to_string(), - Vec::from(&[ParameterType::ULong, ParameterType::VecBytes]), - ReturnType::VecBytes, - read_from_user_memory as usize, - ); - - register_function(read_from_user_memory_def); - - let read_mapped_buffer_def = GuestFunctionDefinition::new( - "ReadMappedBuffer".to_string(), - Vec::from(&[ParameterType::ULong, ParameterType::ULong]), - ReturnType::VecBytes, - read_mapped_buffer as usize, - ); - - register_function(read_mapped_buffer_def); - - let write_mapped_buffer_def = GuestFunctionDefinition::new( - "WriteMappedBuffer".to_string(), - Vec::from(&[ParameterType::ULong, ParameterType::ULong]), - ReturnType::Bool, - write_mapped_buffer as usize, - ); - - register_function(write_mapped_buffer_def); - - let exec_mapped_buffer_def = GuestFunctionDefinition::new( - "ExecMappedBuffer".to_string(), - Vec::from(&[ParameterType::ULong, ParameterType::ULong]), - ReturnType::Bool, - exec_mapped_buffer as usize, - ); - - register_function(exec_mapped_buffer_def); - - let set_static_def = GuestFunctionDefinition::new( - "SetStatic".to_string(), - Vec::new(), - ReturnType::Int, - set_static as usize, - ); - - register_function(set_static_def); - - let simple_print_output_def = GuestFunctionDefinition::new( - "PrintOutput".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - simple_print_output as usize, - ); - register_function(simple_print_output_def); - - let print_using_printf_def = GuestFunctionDefinition::new( - "PrintUsingPrintf".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - simple_print_output as usize, // alias to simple_print_output for now - ); - register_function(print_using_printf_def); - - let stack_overflow_def = GuestFunctionDefinition::new( - "StackOverflow".to_string(), - Vec::from(&[ParameterType::Int]), - ReturnType::Int, - stack_overflow as usize, - ); - register_function(stack_overflow_def); - - let buffer_overrun_def = GuestFunctionDefinition::new( - "BufferOverrun".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Int, - buffer_overrun as usize, - ); - register_function(buffer_overrun_def); - - let large_var_def = GuestFunctionDefinition::new( - "LargeVar".to_string(), - Vec::new(), - ReturnType::Int, - large_var as usize, - ); - register_function(large_var_def); - - let small_var_def = GuestFunctionDefinition::new( - "SmallVar".to_string(), - Vec::new(), - ReturnType::Int, - small_var as usize, - ); - register_function(small_var_def); - - let call_malloc_def = GuestFunctionDefinition::new( - "CallMalloc".to_string(), - Vec::from(&[ParameterType::Int]), - ReturnType::Int, - call_malloc as usize, - ); - register_function(call_malloc_def); - - let malloc_and_free_def = GuestFunctionDefinition::new( - "MallocAndFree".to_string(), - Vec::from(&[ParameterType::Int]), - ReturnType::Int, - malloc_and_free as usize, - ); - register_function(malloc_and_free_def); - - let print_two_args_def = GuestFunctionDefinition::new( - "PrintTwoArgs".to_string(), - Vec::from(&[ParameterType::String, ParameterType::Int]), - ReturnType::Int, - print_two_args as usize, - ); - register_function(print_two_args_def); - - let print_three_args_def = GuestFunctionDefinition::new( - "PrintThreeArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ]), - ReturnType::Int, - print_three_args as usize, - ); - register_function(print_three_args_def); - - let print_four_args_def = GuestFunctionDefinition::new( - "PrintFourArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ]), - ReturnType::Int, - print_four_args as usize, - ); - register_function(print_four_args_def); - - let print_five_args_def = GuestFunctionDefinition::new( - "PrintFiveArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ]), - ReturnType::Int, - print_five_args as usize, - ); - register_function(print_five_args_def); - - let print_six_args_def = GuestFunctionDefinition::new( - "PrintSixArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ParameterType::Bool, - ]), - ReturnType::Int, - print_six_args as usize, - ); - register_function(print_six_args_def); - - let print_seven_args_def = GuestFunctionDefinition::new( - "PrintSevenArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ParameterType::Bool, - ParameterType::Bool, - ]), - ReturnType::Int, - print_seven_args as usize, - ); - register_function(print_seven_args_def); - - let print_eight_args_def = GuestFunctionDefinition::new( - "PrintEightArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ParameterType::Bool, - ParameterType::Bool, - ParameterType::UInt, - ]), - ReturnType::Int, - print_eight_args as usize, - ); - register_function(print_eight_args_def); - - let print_nine_args_def = GuestFunctionDefinition::new( - "PrintNineArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ParameterType::Bool, - ParameterType::Bool, - ParameterType::UInt, - ParameterType::ULong, - ]), - ReturnType::Int, - print_nine_args as usize, - ); - register_function(print_nine_args_def); - - let print_ten_args_def = GuestFunctionDefinition::new( - "PrintTenArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ParameterType::Bool, - ParameterType::Bool, - ParameterType::UInt, - ParameterType::ULong, - ParameterType::Int, - ]), - ReturnType::Int, - print_ten_args as usize, - ); - register_function(print_ten_args_def); - - let print_eleven_args_def = GuestFunctionDefinition::new( - "PrintElevenArgs".to_string(), - Vec::from(&[ - ParameterType::String, - ParameterType::Int, - ParameterType::Long, - ParameterType::String, - ParameterType::String, - ParameterType::Bool, - ParameterType::Bool, - ParameterType::UInt, - ParameterType::ULong, - ParameterType::Int, - ParameterType::Float, - ]), - ReturnType::Int, - print_eleven_args as usize, - ); - register_function(print_eleven_args_def); - - let set_byte_array_to_zero_def = GuestFunctionDefinition::new( - "SetByteArrayToZero".to_string(), - Vec::from(&[ParameterType::VecBytes]), - ReturnType::VecBytes, - set_byte_array_to_zero as usize, - ); - register_function(set_byte_array_to_zero_def); - - let echo_def = GuestFunctionDefinition::new( - "Echo".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::String, - echo as usize, - ); - register_function(echo_def); - - let get_size_prefixed_buffer_def = GuestFunctionDefinition::new( - "GetSizePrefixedBuffer".to_string(), - Vec::from(&[ParameterType::VecBytes]), - ReturnType::Int, - get_size_prefixed_buffer as usize, - ); - register_function(get_size_prefixed_buffer_def); - - let spin_def = GuestFunctionDefinition::new( - "Spin".to_string(), - Vec::new(), - ReturnType::Int, - spin as usize, - ); - register_function(spin_def); - - let abort_def = GuestFunctionDefinition::new( - "GuestAbortWithCode".to_string(), - Vec::from(&[ParameterType::Int]), - ReturnType::Void, - test_abort as usize, - ); - register_function(abort_def); - - let abort_with_code_message_def = GuestFunctionDefinition::new( - "GuestAbortWithMessage".to_string(), - Vec::from(&[ParameterType::Int, ParameterType::String]), - ReturnType::Void, - test_abort_with_code_and_message as usize, - ); - register_function(abort_with_code_message_def); - - let guest_panic_def = GuestFunctionDefinition::new( - "guest_panic".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Void, - test_guest_panic as usize, - ); - register_function(guest_panic_def); - - let rust_malloc_def = GuestFunctionDefinition::new( - "TestMalloc".to_string(), - Vec::from(&[ParameterType::Int]), - ReturnType::Int, - test_rust_malloc as usize, - ); - register_function(rust_malloc_def); - - let log_message_def = GuestFunctionDefinition::new( - "LogMessage".to_string(), - Vec::from(&[ParameterType::String, ParameterType::Int]), - ReturnType::Void, - log_message as usize, - ); - register_function(log_message_def); - - let infinite_recursion_def = GuestFunctionDefinition::new( - "InfiniteRecursion".to_string(), - Vec::new(), - ReturnType::Void, - infinite_recursion as usize, - ); - register_function(infinite_recursion_def); - - let test_write_raw_ptr_def = GuestFunctionDefinition::new( - "test_write_raw_ptr".to_string(), - Vec::from(&[ParameterType::Long]), - ReturnType::String, - test_write_raw_ptr as usize, - ); - register_function(test_write_raw_ptr_def); - - let execute_on_stack_def = GuestFunctionDefinition::new( - "ExecuteOnStack".to_string(), - Vec::new(), - ReturnType::String, - execute_on_stack as usize, - ); - register_function(execute_on_stack_def); - - let execute_on_heap_def = GuestFunctionDefinition::new( - "ExecuteOnHeap".to_string(), - Vec::new(), - ReturnType::String, - execute_on_heap as usize, - ); - register_function(execute_on_heap_def); - - let add_to_static_def = GuestFunctionDefinition::new( - "AddToStatic".to_string(), - Vec::from(&[ParameterType::Int]), - ReturnType::Int, - add_to_static as usize, - ); - register_function(add_to_static_def); - - let get_static_def = GuestFunctionDefinition::new( - "GetStatic".to_string(), - Vec::new(), - ReturnType::Int, - get_static as usize, - ); - register_function(get_static_def); - - let add_to_static_and_fail_def = GuestFunctionDefinition::new( - "AddToStaticAndFail".to_string(), - Vec::new(), - ReturnType::Int, - add_to_static_and_fail as usize, - ); - register_function(add_to_static_and_fail_def); - - let violate_seccomp_filters_def = GuestFunctionDefinition::new( - "ViolateSeccompFilters".to_string(), - Vec::new(), - ReturnType::ULong, - violate_seccomp_filters as usize, - ); - register_function(violate_seccomp_filters_def); - - let echo_float_def = GuestFunctionDefinition::new( - "EchoFloat".to_string(), - Vec::from(&[ParameterType::Float]), - ReturnType::Float, - echo_float as usize, - ); - register_function(echo_float_def); - - let echo_double_def = GuestFunctionDefinition::new( - "EchoDouble".to_string(), - Vec::from(&[ParameterType::Double]), - ReturnType::Double, - echo_double as usize, - ); - register_function(echo_double_def); - - let add_def = GuestFunctionDefinition::new( - "Add".to_string(), - Vec::from(&[ParameterType::Int, ParameterType::Int]), - ReturnType::Int, - add as usize, - ); - register_function(add_def); - - let trigger_exception_def = GuestFunctionDefinition::new( - "TriggerException".to_string(), - Vec::new(), - ReturnType::Void, - trigger_exception as usize, - ); - register_function(trigger_exception_def); - - let large_parameters_def = GuestFunctionDefinition::new( - "LargeParameters".to_string(), - Vec::from(&[ParameterType::VecBytes, ParameterType::String]), - ReturnType::Void, - large_parameters as usize, - ); - register_function(large_parameters_def); - - let call_given_hostfunc_def = GuestFunctionDefinition::new( - "CallGivenParamlessHostFuncThatReturnsI64".to_string(), - Vec::from(&[ParameterType::String]), - ReturnType::Long, - call_given_paramless_hostfunc_that_returns_i64 as usize, - ); - register_function(call_given_hostfunc_def); -} +pub extern "C" fn hyperlight_main() {} #[no_mangle] #[hyperlight_guest_tracing::trace_function]