diff --git a/Cargo.toml b/Cargo.toml
index 0d07ce45b086db7545ed1ad84b9e5dbf8ab3d891..c23dbfd09ee9e88b22b034bb54707559d0057873 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -114,6 +114,7 @@ strum = { version = "0.27", default-features = false, features = ["derive"] }
x86_64 = { version = "0.15.2", features = ["instructions"] }
# Tee Crates
+ tee_kernel = { path = "tee/tee_kernel" }
tee_raw_sys = { path = "tee/tee_raw_sys" }
mbedtls = { version = "0.13", package = "mbedtls-smx", default-features = false, features = [
"no_std_deps",
@@ -144,6 +145,7 @@ klogger = { path = "util/klogger" }
backtrace = { path = "util/backtrace" }
kerrno = { path = "util/kerrno" }
unittest = { path = "util/unittest" }
+unittest_support = { path = "util/unittest_support" }
kbuild_config = { path = "util/kbuild_config" }
kconfig-gen = { path = "xtask/kconfig-gen" }
diff --git a/Makefile b/Makefile
index 7cf87fa103e4367cda64406e0eb0fc38b333bc66..6937705944e622e325426d6202aa164ccef29288 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,7 @@ doc_check_missing:
$(call cargo_doc)
fmt:
- cargo +nightly fmt --all
+ cargo +nightly-2026-03-08 fmt --all
unittest:
$(call unit_test)
diff --git a/api/kapi/Cargo.toml b/api/kapi/Cargo.toml
index 2e480d2fcb4bcc0284fbe647fd23b25c278b9115..f97dde7750688f4650948c0e5035a248082f4503 100644
--- a/api/kapi/Cargo.toml
+++ b/api/kapi/Cargo.toml
@@ -21,27 +21,17 @@ dice = [
"dep:mbedtls",
]
tee = [
- "linux_sysno/tee",
- "kalloc/tee",
- "dep:tee_raw_sys",
- "dep:bincode",
- "dep:uuid",
- "dep:hex",
- "dep:rand_chacha",
- "dep:mbedtls",
- "dep:mbedtls-sys-auto",
- "tee_ss_smx",
+ "dep:tee_kernel",
]
-tee_cfg_memtag = []
-tee_ss_smx = []
sev = ["dep:kcpu"]
-x86_csv = ["dep:kcpu"]
+x86_csv = ["tee_kernel/x86_csv"]
[dependencies]
kbuild_config = { workspace = true }
kalloc.workspace = true
backtrace.workspace = true
unittest = { workspace = true }
+unittest_support.workspace = true
rust-dice = { workspace = true, optional = true }
mbedtls = { workspace = true, optional = true }
mbedtls-sys-auto = { workspace = true, optional = true }
@@ -95,16 +85,8 @@ ksignal.workspace = true
osvm.workspace = true
linux_sysno.workspace = true
zerocopy = { version = "0.8.26", features = ["derive"] }
+tee_kernel = { workspace = true, optional = true }
-bincode = { version = "2.0.1", default-features = false, optional = true, features = [
- "alloc",
- "derive",
-] }
-tee_raw_sys = { workspace = true, optional = true }
-uuid = { version = "0.8", default-features = false, optional = true }
-hex = { version = "0.4", default-features = false, optional = true, features = [
- "alloc",
-] }
cty = "0.2"
kcore.workspace = true
diff --git a/api/kapi/src/lib.rs b/api/kapi/src/lib.rs
index da3d102210ececa302513e3588db8af0cd62dbee..d89f3a5f717be70e67dee79cbe520651b98eb143 100644
--- a/api/kapi/src/lib.rs
+++ b/api/kapi/src/lib.rs
@@ -23,11 +23,14 @@ pub mod socket;
pub mod syscall;
pub mod task;
#[cfg(feature = "tee")]
-pub mod tee;
+pub use tee_kernel::tee;
pub mod terminal;
pub mod time;
+
+#[cfg(unittest)]
+mod unittest_task;
#[cfg(unittest)]
-pub mod unittest_task;
+pub use unittest_task::{register_unittest_runtime, run_with_test_user_thread};
pub mod vfs;
/// Initializes VFS, /proc/interrupts accounting, and alarm task.
diff --git a/api/kapi/src/syscall/mod.rs b/api/kapi/src/syscall/mod.rs
index 759461fd803ed9c451f3b7f8b475d510e00733cc..6d3f66b49e5c927e834cb5935a88ffd27b19339b 100644
--- a/api/kapi/src/syscall/mod.rs
+++ b/api/kapi/src/syscall/mod.rs
@@ -651,7 +651,7 @@ pub fn dispatch_irq_syscall(uctx: &mut UserContext) {
_ => {
#[cfg(feature = "tee")]
{
- use tee_raw_sys::TEE_SUCCESS;
+ use tee_kernel::TEE_SUCCESS;
use crate::tee::dispatch_irq_tee_syscall;
diff --git a/api/kapi/src/task.rs b/api/kapi/src/task.rs
index 010c6b099537cc44d92e761b82c38e78f72877fb..477a93ae80a1a9cc14db5c3a505130880092b389 100644
--- a/api/kapi/src/task.rs
+++ b/api/kapi/src/task.rs
@@ -24,10 +24,6 @@ use ktask::{TaskInner, current};
use linux_raw_sys::general::ROBUST_LIST_LIMIT;
use osvm::{VirtMutPtr, VirtPtr};
-#[cfg(unittest)]
-pub use crate::unittest_task::{
- TestUserArray, TestUserBuffer, TestUserValue, run_with_test_user_thread,
-};
use crate::{
signal::{check_signals, unblock_next_signal},
syscall::dispatch_irq_syscall,
diff --git a/api/kapi/src/unittest_task.rs b/api/kapi/src/unittest_task.rs
index 7701f35c02eb74147a61a7895d47aa8c26ab06cf..5f07ed68fde98fdade8003c1ca5358d39504629d 100644
--- a/api/kapi/src/unittest_task.rs
+++ b/api/kapi/src/unittest_task.rs
@@ -2,32 +2,23 @@
// Copyright 2025 KylinSoft Co., Ltd.
// See LICENSES for license details.
-//! Unittest-only helpers for installing a simulated user thread and mapped user buffers.
+//! Unittest-only helpers for installing a simulated user thread runtime.
#![cfg(unittest)]
-use alloc::{string::ToString, sync::Arc, vec, vec::Vec};
-use core::{
- marker::PhantomData,
- mem::{MaybeUninit, size_of, transmute},
- ops::{Deref, DerefMut},
- sync::atomic::{AtomicU32, AtomicUsize, Ordering},
-};
+use alloc::{string::ToString, sync::Arc, vec};
+use core::sync::atomic::{AtomicU32, Ordering};
-use kcore::task::{AsThread, ProcessData, Thread};
-use kerrno::{KError, KResult};
-use khal::{mem::v2p, paging::MappingFlags};
+use kcore::task::{ProcessData, Thread};
+use kerrno::KResult;
use kprocess::Pid;
use ksignal::api::SignalActions;
use ksync::{Mutex, spin::SpinNoIrq};
use ktask::{KTaskExt, TaskExt, current};
-use memaddr::{PAGE_SIZE_4K, PhysAddr, VirtAddr};
-use osvm::{read_vm_mem, write_vm_mem};
+use memaddr::PhysAddr;
use unittest::{TestDescriptor, TestResult};
static NEXT_TEST_PROCESS_ID: AtomicU32 = AtomicU32::new(0x7000_0000);
-static NEXT_TEST_USER_ADDR: AtomicUsize = AtomicUsize::new(kcore::config::USER_HEAP_BASE);
-
fn alloc_test_process_id() -> Pid {
NEXT_TEST_PROCESS_ID.fetch_add(1, Ordering::Relaxed)
}
@@ -149,245 +140,3 @@ pub fn register_unittest_runtime() {
run_with_test_user_thread(test, init_unittest_thread)
});
}
-
-#[macro_export]
-macro_rules! __unittest_user_vec {
- ($value:expr; $len:expr) => {{
- $crate::unittest_task::TestUserArray::from_array([$value; $len]).unwrap()
- }};
- ($($value:expr),+ $(,)?) => {{
- $crate::unittest_task::TestUserArray::from_array([$($value),+]).unwrap()
- }};
-}
-
-pub use crate::__unittest_user_vec as user_vec;
-
-pub struct TestUserBuffer {
- aspace: Arc>,
- user_addr: usize,
- mapped_size: usize,
- kernel_va: usize,
- num_pages: usize,
- len: usize,
-}
-
-impl TestUserBuffer {
- pub fn new(len: usize) -> KResult {
- let current_task = current();
- let thread = current_task.try_as_thread().ok_or(KError::BadState)?;
- let aspace = thread.proc_data.aspace.clone();
- let mapped_size = len.max(1).next_multiple_of(PAGE_SIZE_4K);
- let num_pages = mapped_size / PAGE_SIZE_4K;
- let kernel_va = kalloc::global_allocator()
- .alloc_pages(num_pages, PAGE_SIZE_4K, kalloc::UsageKind::VirtMem)
- .map_err(|_| KError::NoMemory)?;
-
- unsafe {
- core::ptr::write_bytes(kernel_va as *mut u8, 0, mapped_size);
- }
-
- let user_addr = NEXT_TEST_USER_ADDR.fetch_add(mapped_size, Ordering::Relaxed);
- aspace
- .lock()
- .map_linear(
- VirtAddr::from_usize(user_addr),
- v2p(VirtAddr::from_usize(kernel_va)),
- mapped_size,
- MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER,
- )
- .map_err(|_| {
- kalloc::global_allocator().dealloc_pages(
- kernel_va,
- num_pages,
- kalloc::UsageKind::VirtMem,
- );
- KError::NoMemory
- })?;
-
- Ok(Self {
- aspace,
- user_addr,
- mapped_size,
- kernel_va,
- num_pages,
- len,
- })
- }
-
- pub fn write_bytes(&self, data: &[u8]) -> KResult {
- if data.len() > self.len {
- return Err(KError::InvalidInput);
- }
- write_vm_mem(self.user_addr as *mut u8, data).map_err(Into::into)
- }
-
- pub fn read_bytes(&self, len: usize) -> KResult> {
- if len > self.len {
- return Err(KError::InvalidInput);
- }
- let mut out = vec![0u8; len];
- read_vm_mem(self.user_addr as *const u8, unsafe {
- transmute::<&mut [u8], &mut [MaybeUninit]>(&mut out[..])
- })
- .map_err(KError::from)?;
- Ok(out)
- }
-
- pub fn write_u64(&self, value: u64) -> KResult {
- write_vm_mem(self.user_addr as *mut u64, core::slice::from_ref(&value)).map_err(Into::into)
- }
-
- pub fn read_u64(&self) -> KResult {
- let mut out = 0u64;
- let out_slice = unsafe {
- core::slice::from_raw_parts_mut((&mut out as *mut u64).cast::>(), 1)
- };
- read_vm_mem(self.user_addr as *const u64, out_slice).map_err(KError::from)?;
- Ok(out)
- }
-
- pub fn len(&self) -> usize {
- self.len
- }
-
- pub fn as_user_ptr(&self) -> *mut T {
- assert!(size_of::() <= self.len);
- self.user_addr as *mut T
- }
-
- pub fn as_user_slice(&mut self, len: usize) -> &mut [u8] {
- assert!(len <= self.len);
- unsafe { core::slice::from_raw_parts_mut(self.user_addr as *mut u8, len) }
- }
-
- pub fn as_user_ref(&mut self) -> &mut T {
- assert!(core::mem::size_of::() <= self.len);
- unsafe { &mut *(self.user_addr as *mut T) }
- }
-}
-
-pub struct TestUserValue {
- buffer: TestUserBuffer,
- _marker: PhantomData,
-}
-
-impl TestUserValue {
- pub fn new() -> KResult {
- Ok(Self {
- buffer: TestUserBuffer::new(size_of::())?,
- _marker: PhantomData,
- })
- }
-
- pub fn from_value(value: T) -> KResult
- where
- T: Copy,
- {
- let mut user_value = Self::new()?;
- user_value.write(value);
- Ok(user_value)
- }
-
- pub fn as_user_ref(&mut self) -> &mut T {
- self.buffer.as_user_ref::()
- }
-
- pub fn as_user_ptr(&self) -> *mut T {
- self.buffer.as_user_ptr::()
- }
-
- pub fn write(&mut self, value: T)
- where
- T: Copy,
- {
- *self.as_user_ref() = value;
- }
-
- pub fn read(&self) -> T
- where
- T: Copy,
- {
- unsafe { self.as_user_ptr().read() }
- }
-}
-
-pub struct TestUserArray {
- buffer: TestUserBuffer,
- _marker: PhantomData,
-}
-
-impl TestUserArray {
- pub fn new() -> KResult {
- Ok(Self {
- buffer: TestUserBuffer::new(size_of::<[T; N]>())?,
- _marker: PhantomData,
- })
- }
-
- pub fn from_array(value: [T; N]) -> KResult
- where
- T: Copy,
- {
- let mut user_array = Self::new()?;
- user_array.write(value);
- Ok(user_array)
- }
-
- pub fn len(&self) -> usize {
- N
- }
-
- pub fn as_user_slice(&mut self) -> &mut [T] {
- unsafe { core::slice::from_raw_parts_mut(self.as_user_ptr(), N) }
- }
-
- pub fn as_user_ref(&mut self) -> &mut [T; N] {
- unsafe { &mut *(self.as_user_ptr() as *mut [T; N]) }
- }
-
- pub fn as_user_ptr(&self) -> *mut T {
- self.buffer.as_user_ptr::()
- }
-
- pub fn write(&mut self, value: [T; N])
- where
- T: Copy,
- {
- self.as_user_slice().copy_from_slice(&value);
- }
-
- pub fn read(&self) -> [T; N]
- where
- T: Copy,
- {
- unsafe { (self.as_user_ptr() as *const [T; N]).read() }
- }
-}
-
-impl Deref for TestUserArray {
- type Target = [T];
-
- fn deref(&self) -> &Self::Target {
- unsafe { core::slice::from_raw_parts(self.as_user_ptr(), N) }
- }
-}
-
-impl DerefMut for TestUserArray {
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.as_user_slice()
- }
-}
-
-impl Drop for TestUserBuffer {
- fn drop(&mut self) {
- let _ = self
- .aspace
- .lock()
- .unmap(VirtAddr::from_usize(self.user_addr), self.mapped_size);
- kalloc::global_allocator().dealloc_pages(
- self.kernel_va,
- self.num_pages,
- kalloc::UsageKind::VirtMem,
- );
- }
-}
diff --git a/entry/src/main.rs b/entry/src/main.rs
index 70ad099f72f7cd66c0bfc47a9d5ee1538d5e5093..d5fc1659363009aad5e8641418c4225033b5f81a 100644
--- a/entry/src/main.rs
+++ b/entry/src/main.rs
@@ -53,7 +53,7 @@ fn main() {
#[unsafe(no_mangle)]
fn main() {
kapi::init();
- kapi::unittest_task::register_unittest_runtime();
+ kapi::register_unittest_runtime();
{
let cx = kfs::FS_CONTEXT.lock();
diff --git a/tee/tee_kernel/Cargo.toml b/tee/tee_kernel/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7710305badf73cf6354a399268cc7c14d629ca1d
--- /dev/null
+++ b/tee/tee_kernel/Cargo.toml
@@ -0,0 +1,77 @@
+[package]
+name = "tee_kernel"
+description = "TEE support crate extracted from kapi for X-Kernel"
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+documentation.workspace = true
+
+[features]
+default = ["linux_sysno/tee", "kalloc/tee", "tee_ss_smx"]
+tee_cfg_memtag = []
+tee_ss_smx = []
+x86_csv = ["dep:kcpu"]
+
+[dependencies]
+kalloc.workspace = true
+unittest.workspace = true
+unittest_support.workspace = true
+rust-dice = { workspace = true, optional = true }
+mbedtls = { workspace = true }
+mbedtls-sys-auto = { workspace = true }
+ktypes.workspace = true
+kcpu = { workspace = true, optional = true }
+kerrno.workspace = true
+kfeat.workspace = true
+fs-ng-vfs.workspace = true
+kfs.workspace = true
+khal.workspace = true
+karch.workspace = true
+kio.workspace = true
+klogger.workspace = true
+memspace.workspace = true
+knet.workspace = true
+kpoll.workspace = true
+ksync.workspace = true
+ktask.workspace = true
+bitflags.workspace = true
+bytemuck.workspace = true
+cfg-if.workspace = true
+chrono = { version = "0.4.41", default-features = false }
+hashbrown = { workspace = true }
+lazy_static = { workspace = true }
+linux-raw-sys = { workspace = true, features = ["ioctl", "loop_device"] }
+memaddr.workspace = true
+osvm.workspace = true
+kprocess.workspace = true
+linux_sysno.workspace = true
+zerocopy = { version = "0.8.26", features = ["derive"] }
+bincode = { version = "2.0.1", default-features = false, features = ["alloc", "derive"] }
+tee_raw_sys = { workspace = true }
+uuid = { version = "0.8", default-features = false }
+hex = { version = "0.4", default-features = false, features = ["alloc"] }
+cty = "0.2"
+kcore.workspace = true
+subtle = { version = "2", default-features = false }
+static_assertions = "1.1.0"
+memoffset = { version = "0.9", default-features = false }
+flatten_objects = "0.2.4"
+rand_chacha = { version = "0.3", default-features = false }
+scope-local = { workspace = true }
+slab = { workspace = true }
+rand = { version = "0.9.1", default-features = false, features = [
+ "alloc",
+ "small_rng",
+] }
+
+[target.'cfg(target_arch = "x86_64")'.dependencies]
+x86 = "0.52"
+
+[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
+riscv = "0.14"
+
+# [dev-dependencies]
+# kapi = { path = "../../api/kapi" }
diff --git a/tee/tee_kernel/src/file.rs b/tee/tee_kernel/src/file.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4ddeccf1f8d8d6de0ae83edd3571832070863da2
--- /dev/null
+++ b/tee/tee_kernel/src/file.rs
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+use core::ffi::c_int;
+
+use fs_ng_vfs::{Location, Metadata};
+use kerrno::{KError, KResult};
+use kfs::{FS_CONTEXT, FsContext};
+use linux_raw_sys::general::{AT_FDCWD, AT_SYMLINK_NOFOLLOW};
+
+pub fn with_fs(dirfd: c_int, f: impl FnOnce(&mut FsContext) -> KResult) -> KResult {
+ if dirfd != AT_FDCWD {
+ return Err(KError::InvalidInput);
+ }
+
+ let mut fs = FS_CONTEXT.lock();
+ f(&mut fs)
+}
+
+pub enum ResolveAtResult {
+ File(Location),
+}
+
+impl ResolveAtResult {
+ pub fn stat(&self) -> KResult {
+ match self {
+ Self::File(file) => file.metadata(),
+ }
+ }
+}
+
+pub fn resolve_at(dirfd: c_int, path: Option<&str>, flags: u32) -> KResult {
+ let path = path
+ .filter(|path| !path.is_empty())
+ .ok_or(KError::NotFound)?;
+
+ with_fs(dirfd, |fs| {
+ if flags & AT_SYMLINK_NOFOLLOW != 0 {
+ fs.resolve_no_follow(path)
+ } else {
+ fs.resolve(path)
+ }
+ .map(ResolveAtResult::File)
+ })
+}
diff --git a/tee/tee_kernel/src/lib.rs b/tee/tee_kernel/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..695589b7da2286ef24de55fd31e17e9852e1a80a
--- /dev/null
+++ b/tee/tee_kernel/src/lib.rs
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+#![no_std]
+#![allow(missing_docs)]
+
+#[macro_use]
+extern crate klogger;
+
+extern crate alloc;
+
+pub mod file;
+pub mod mm;
+pub mod tee;
+pub use tee_raw_sys::TEE_SUCCESS;
+#[cfg(unittest)]
+pub use unittest_support::{TestUserArray, TestUserBuffer, TestUserValue, user_vec};
diff --git a/tee/tee_kernel/src/mm.rs b/tee/tee_kernel/src/mm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9cde27277aff28530e451e683f61796aa6dcb60f
--- /dev/null
+++ b/tee/tee_kernel/src/mm.rs
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+use alloc::string::String;
+use core::ffi::c_char;
+
+use kerrno::{KError, KResult};
+use osvm::{load_vec, load_vec_until_null};
+
+pub fn vm_load_string(ptr: *const c_char) -> KResult {
+ #[allow(clippy::unnecessary_cast)]
+ let bytes = load_vec_until_null(ptr as *const u8)?;
+ String::from_utf8(bytes).map_err(|_| KError::IllegalBytes)
+}
+
+pub fn vm_load_string_with_len(ptr: *const c_char, len: usize) -> KResult {
+ #[allow(clippy::unnecessary_cast)]
+ let bytes = load_vec(ptr as *const u8, len)?;
+ String::from_utf8(bytes).map_err(|_| KError::IllegalBytes)
+}
diff --git a/api/kapi/src/tee/README.md b/tee/tee_kernel/src/tee/README.md
similarity index 100%
rename from api/kapi/src/tee/README.md
rename to tee/tee_kernel/src/tee/README.md
diff --git a/api/kapi/src/tee/arch/mod.rs b/tee/tee_kernel/src/tee/arch/mod.rs
similarity index 100%
rename from api/kapi/src/tee/arch/mod.rs
rename to tee/tee_kernel/src/tee/arch/mod.rs
diff --git a/api/kapi/src/tee/arch/x86_64/hygon_csv.rs b/tee/tee_kernel/src/tee/arch/x86_64/hygon_csv.rs
similarity index 100%
rename from api/kapi/src/tee/arch/x86_64/hygon_csv.rs
rename to tee/tee_kernel/src/tee/arch/x86_64/hygon_csv.rs
diff --git a/api/kapi/src/tee/arch/x86_64/hygon_csv_bindings.rs b/tee/tee_kernel/src/tee/arch/x86_64/hygon_csv_bindings.rs
similarity index 100%
rename from api/kapi/src/tee/arch/x86_64/hygon_csv_bindings.rs
rename to tee/tee_kernel/src/tee/arch/x86_64/hygon_csv_bindings.rs
diff --git a/api/kapi/src/tee/arch/x86_64/mod.rs b/tee/tee_kernel/src/tee/arch/x86_64/mod.rs
similarity index 100%
rename from api/kapi/src/tee/arch/x86_64/mod.rs
rename to tee/tee_kernel/src/tee/arch/x86_64/mod.rs
diff --git a/api/kapi/src/tee/bitstring.rs b/tee/tee_kernel/src/tee/bitstring.rs
similarity index 100%
rename from api/kapi/src/tee/bitstring.rs
rename to tee/tee_kernel/src/tee/bitstring.rs
diff --git a/api/kapi/src/tee/common/array.rs b/tee/tee_kernel/src/tee/common/array.rs
similarity index 100%
rename from api/kapi/src/tee/common/array.rs
rename to tee/tee_kernel/src/tee/common/array.rs
diff --git a/api/kapi/src/tee/common/file_ops.rs b/tee/tee_kernel/src/tee/common/file_ops.rs
similarity index 100%
rename from api/kapi/src/tee/common/file_ops.rs
rename to tee/tee_kernel/src/tee/common/file_ops.rs
diff --git a/api/kapi/src/tee/common/mod.rs b/tee/tee_kernel/src/tee/common/mod.rs
similarity index 100%
rename from api/kapi/src/tee/common/mod.rs
rename to tee/tee_kernel/src/tee/common/mod.rs
diff --git a/api/kapi/src/tee/config.rs b/tee/tee_kernel/src/tee/config.rs
similarity index 100%
rename from api/kapi/src/tee/config.rs
rename to tee/tee_kernel/src/tee/config.rs
diff --git a/api/kapi/src/tee/crypto/crypto.rs b/tee/tee_kernel/src/tee/crypto/crypto.rs
similarity index 100%
rename from api/kapi/src/tee/crypto/crypto.rs
rename to tee/tee_kernel/src/tee/crypto/crypto.rs
diff --git a/api/kapi/src/tee/crypto/crypto_impl.rs b/tee/tee_kernel/src/tee/crypto/crypto_impl.rs
similarity index 100%
rename from api/kapi/src/tee/crypto/crypto_impl.rs
rename to tee/tee_kernel/src/tee/crypto/crypto_impl.rs
diff --git a/api/kapi/src/tee/crypto/mod.rs b/tee/tee_kernel/src/tee/crypto/mod.rs
similarity index 100%
rename from api/kapi/src/tee/crypto/mod.rs
rename to tee/tee_kernel/src/tee/crypto/mod.rs
diff --git a/api/kapi/src/tee/crypto/sm3_hash.rs b/tee/tee_kernel/src/tee/crypto/sm3_hash.rs
similarity index 100%
rename from api/kapi/src/tee/crypto/sm3_hash.rs
rename to tee/tee_kernel/src/tee/crypto/sm3_hash.rs
diff --git a/api/kapi/src/tee/crypto/sm3_hmac.rs b/tee/tee_kernel/src/tee/crypto/sm3_hmac.rs
similarity index 100%
rename from api/kapi/src/tee/crypto/sm3_hmac.rs
rename to tee/tee_kernel/src/tee/crypto/sm3_hmac.rs
diff --git a/api/kapi/src/tee/fs_dirfile.rs b/tee/tee_kernel/src/tee/fs_dirfile.rs
similarity index 100%
rename from api/kapi/src/tee/fs_dirfile.rs
rename to tee/tee_kernel/src/tee/fs_dirfile.rs
diff --git a/api/kapi/src/tee/fs_htree.rs b/tee/tee_kernel/src/tee/fs_htree.rs
similarity index 100%
rename from api/kapi/src/tee/fs_htree.rs
rename to tee/tee_kernel/src/tee/fs_htree.rs
diff --git a/api/kapi/src/tee/fs_htree_tests.rs b/tee/tee_kernel/src/tee/fs_htree_tests.rs
similarity index 100%
rename from api/kapi/src/tee/fs_htree_tests.rs
rename to tee/tee_kernel/src/tee/fs_htree_tests.rs
diff --git a/api/kapi/src/tee/huk_subkey.rs b/tee/tee_kernel/src/tee/huk_subkey.rs
similarity index 100%
rename from api/kapi/src/tee/huk_subkey.rs
rename to tee/tee_kernel/src/tee/huk_subkey.rs
diff --git a/api/kapi/src/tee/libmbedtls/bignum.rs b/tee/tee_kernel/src/tee/libmbedtls/bignum.rs
similarity index 100%
rename from api/kapi/src/tee/libmbedtls/bignum.rs
rename to tee/tee_kernel/src/tee/libmbedtls/bignum.rs
diff --git a/api/kapi/src/tee/libmbedtls/ecc.rs b/tee/tee_kernel/src/tee/libmbedtls/ecc.rs
similarity index 100%
rename from api/kapi/src/tee/libmbedtls/ecc.rs
rename to tee/tee_kernel/src/tee/libmbedtls/ecc.rs
diff --git a/api/kapi/src/tee/libmbedtls/mod.rs b/tee/tee_kernel/src/tee/libmbedtls/mod.rs
similarity index 100%
rename from api/kapi/src/tee/libmbedtls/mod.rs
rename to tee/tee_kernel/src/tee/libmbedtls/mod.rs
diff --git a/api/kapi/src/tee/libmbedtls/rsa.rs b/tee/tee_kernel/src/tee/libmbedtls/rsa.rs
similarity index 100%
rename from api/kapi/src/tee/libmbedtls/rsa.rs
rename to tee/tee_kernel/src/tee/libmbedtls/rsa.rs
diff --git a/api/kapi/src/tee/libutee/mod.rs b/tee/tee_kernel/src/tee/libutee/mod.rs
similarity index 100%
rename from api/kapi/src/tee/libutee/mod.rs
rename to tee/tee_kernel/src/tee/libutee/mod.rs
diff --git a/api/kapi/src/tee/libutee/tee_api_objects.rs b/tee/tee_kernel/src/tee/libutee/tee_api_objects.rs
similarity index 100%
rename from api/kapi/src/tee/libutee/tee_api_objects.rs
rename to tee/tee_kernel/src/tee/libutee/tee_api_objects.rs
diff --git a/api/kapi/src/tee/libutee/utee_defines.rs b/tee/tee_kernel/src/tee/libutee/utee_defines.rs
similarity index 99%
rename from api/kapi/src/tee/libutee/utee_defines.rs
rename to tee/tee_kernel/src/tee/libutee/utee_defines.rs
index 9b80b8e3fafedc5a09e1319e0dcb9a58b5ee2557..a984f63a6f4bb67bf1b11a67c2f7b2f7a9e2e476 100644
--- a/api/kapi/src/tee/libutee/utee_defines.rs
+++ b/tee/tee_kernel/src/tee/libutee/utee_defines.rs
@@ -4,7 +4,6 @@
use tee_raw_sys::*;
-#[cfg(feature = "tee")]
use crate::tee::{
TEE_ALG_DES3_CMAC, TEE_ALG_RSAES_PKCS1_OAEP_MGF1_MD5, TEE_ALG_RSASSA_PKCS1_PSS_MGF1_MD5,
TEE_ALG_RSASSA_PKCS1_V1_5, TEE_ALG_SHAKE128, TEE_ALG_SHAKE256, TEE_ALG_SM4_XTS, TEE_ALG_X448,
diff --git a/api/kapi/src/tee/macros.rs b/tee/tee_kernel/src/tee/macros.rs
similarity index 100%
rename from api/kapi/src/tee/macros.rs
rename to tee/tee_kernel/src/tee/macros.rs
diff --git a/api/kapi/src/tee/memtag.rs b/tee/tee_kernel/src/tee/memtag.rs
similarity index 100%
rename from api/kapi/src/tee/memtag.rs
rename to tee/tee_kernel/src/tee/memtag.rs
diff --git a/api/kapi/src/tee/mod.rs b/tee/tee_kernel/src/tee/mod.rs
similarity index 100%
rename from api/kapi/src/tee/mod.rs
rename to tee/tee_kernel/src/tee/mod.rs
diff --git a/api/kapi/src/tee/otp_stubs.rs b/tee/tee_kernel/src/tee/otp_stubs.rs
similarity index 100%
rename from api/kapi/src/tee/otp_stubs.rs
rename to tee/tee_kernel/src/tee/otp_stubs.rs
diff --git a/api/kapi/src/tee/protocal.rs b/tee/tee_kernel/src/tee/protocal.rs
similarity index 100%
rename from api/kapi/src/tee/protocal.rs
rename to tee/tee_kernel/src/tee/protocal.rs
diff --git a/api/kapi/src/tee/ree_fs_rpc.rs b/tee/tee_kernel/src/tee/ree_fs_rpc.rs
similarity index 100%
rename from api/kapi/src/tee/ree_fs_rpc.rs
rename to tee/tee_kernel/src/tee/ree_fs_rpc.rs
diff --git a/api/kapi/src/tee/rng_software.rs b/tee/tee_kernel/src/tee/rng_software.rs
similarity index 100%
rename from api/kapi/src/tee/rng_software.rs
rename to tee/tee_kernel/src/tee/rng_software.rs
diff --git a/api/kapi/src/tee/tee_api_defines_extensions.rs b/tee/tee_kernel/src/tee/tee_api_defines_extensions.rs
similarity index 100%
rename from api/kapi/src/tee/tee_api_defines_extensions.rs
rename to tee/tee_kernel/src/tee/tee_api_defines_extensions.rs
diff --git a/api/kapi/src/tee/tee_cancel.rs b/tee/tee_kernel/src/tee/tee_cancel.rs
similarity index 100%
rename from api/kapi/src/tee/tee_cancel.rs
rename to tee/tee_kernel/src/tee/tee_cancel.rs
diff --git a/api/kapi/src/tee/tee_fs.rs b/tee/tee_kernel/src/tee/tee_fs.rs
similarity index 100%
rename from api/kapi/src/tee/tee_fs.rs
rename to tee/tee_kernel/src/tee/tee_fs.rs
diff --git a/api/kapi/src/tee/tee_fs_key_manager.rs b/tee/tee_kernel/src/tee/tee_fs_key_manager.rs
similarity index 100%
rename from api/kapi/src/tee/tee_fs_key_manager.rs
rename to tee/tee_kernel/src/tee/tee_fs_key_manager.rs
diff --git a/api/kapi/src/tee/tee_generic.rs b/tee/tee_kernel/src/tee/tee_generic.rs
similarity index 100%
rename from api/kapi/src/tee/tee_generic.rs
rename to tee/tee_kernel/src/tee/tee_generic.rs
diff --git a/api/kapi/src/tee/tee_inter_ta.rs b/tee/tee_kernel/src/tee/tee_inter_ta.rs
similarity index 100%
rename from api/kapi/src/tee/tee_inter_ta.rs
rename to tee/tee_kernel/src/tee/tee_inter_ta.rs
diff --git a/api/kapi/src/tee/tee_misc.rs b/tee/tee_kernel/src/tee/tee_misc.rs
similarity index 100%
rename from api/kapi/src/tee/tee_misc.rs
rename to tee/tee_kernel/src/tee/tee_misc.rs
diff --git a/api/kapi/src/tee/tee_obj.rs b/tee/tee_kernel/src/tee/tee_obj.rs
similarity index 100%
rename from api/kapi/src/tee/tee_obj.rs
rename to tee/tee_kernel/src/tee/tee_obj.rs
diff --git a/api/kapi/src/tee/tee_pobj.rs b/tee/tee_kernel/src/tee/tee_pobj.rs
similarity index 100%
rename from api/kapi/src/tee/tee_pobj.rs
rename to tee/tee_kernel/src/tee/tee_pobj.rs
diff --git a/api/kapi/src/tee/tee_property.rs b/tee/tee_kernel/src/tee/tee_property.rs
similarity index 100%
rename from api/kapi/src/tee/tee_property.rs
rename to tee/tee_kernel/src/tee/tee_property.rs
diff --git a/api/kapi/src/tee/tee_ree_fs.rs b/tee/tee_kernel/src/tee/tee_ree_fs.rs
similarity index 100%
rename from api/kapi/src/tee/tee_ree_fs.rs
rename to tee/tee_kernel/src/tee/tee_ree_fs.rs
diff --git a/api/kapi/src/tee/tee_session.rs b/tee/tee_kernel/src/tee/tee_session.rs
similarity index 100%
rename from api/kapi/src/tee/tee_session.rs
rename to tee/tee_kernel/src/tee/tee_session.rs
diff --git a/api/kapi/src/tee/tee_svc_cryp.rs b/tee/tee_kernel/src/tee/tee_svc_cryp.rs
similarity index 99%
rename from api/kapi/src/tee/tee_svc_cryp.rs
rename to tee/tee_kernel/src/tee/tee_svc_cryp.rs
index 48ddc3367e8ccc43c020ebf0ba59e49f76a6213d..b66176417dd99d8d8b0329a3dd294ac8f185f4c7 100644
--- a/api/kapi/src/tee/tee_svc_cryp.rs
+++ b/tee/tee_kernel/src/tee/tee_svc_cryp.rs
@@ -2810,7 +2810,7 @@ pub mod tests_tee_svc_cryp {
use zerocopy::IntoBytes;
use super::*;
- use crate::unittest_task::TestUserValue;
+ use crate::TestUserValue;
#[unittest::def_test]
fn test_tee_svc_cryp_utils() {
@@ -2874,7 +2874,7 @@ pub mod tests_tee_svc_cryp {
#[unittest::def_test(custom)]
fn test_op_attr_secret_value_from_user() {
// 测试基础数据
- let mut user_key = crate::unittest_task::user_vec![0xAAu8; 16];
+ let mut user_key = crate::user_vec![0xAAu8; 16];
let mut secret_wrapper = tee_cryp_obj_secret_wrapper::new(32);
// 从用户空间导入密钥
@@ -2886,7 +2886,7 @@ pub mod tests_tee_svc_cryp {
assert_eq!(&secret_wrapper.data()[..16], &user_key.read());
// 测试长度超出分配大小的情况
- let mut long_user_key = crate::unittest_task::user_vec![0xBBu8; 40];
+ let mut long_user_key = crate::user_vec![0xBBu8; 40];
let result =
op_attr_secret_value_from_user(&mut secret_wrapper, long_user_key.as_user_slice());
assert_eq!(result.err(), Some(TEE_ERROR_SHORT_BUFFER));
@@ -2911,7 +2911,7 @@ pub mod tests_tee_svc_cryp {
assert_eq!(size.read(), 16);
// 第二次调用,提供足够大的 buffer
- let mut user_buffer = crate::unittest_task::user_vec![0u8; 32];
+ let mut user_buffer = crate::user_vec![0u8; 32];
size.write(32);
let result = op_attr_secret_value_to_user(
&secret_wrapper,
@@ -3013,7 +3013,7 @@ pub mod tests_tee_svc_cryp {
attr[..4].copy_from_slice(value_bytes);
let mut size = TestUserValue::::from_value(8).unwrap();
- let mut user_buffer = crate::unittest_task::user_vec![0u8; 8];
+ let mut user_buffer = crate::user_vec![0u8; 8];
let result = op_attr_value_to_user(&attr, user_buffer.as_user_slice(), size.as_user_ref());
assert!(result.is_ok());
@@ -3090,14 +3090,14 @@ pub mod tests_tee_svc_cryp {
};
{
let mut attr_ref = CryptoAttrRef::U32(&mut value);
- let mut value_bytes_user = crate::unittest_task::user_vec![0u8; 8];
+ let mut value_bytes_user = crate::user_vec![0u8; 8];
value_bytes_user.copy_from_slice(value_bytes);
let result = attr_ref.update_from_user(value_bytes_user.as_user_slice());
assert!(result.is_ok());
}
assert_eq!(value, 0x11223344);
- let mut buffer = crate::unittest_task::user_vec![0u8; 8];
+ let mut buffer = crate::user_vec![0u8; 8];
let mut size = TestUserValue::::from_value(8).unwrap();
{
let attr_ref = CryptoAttrRef::U32(&mut value);
@@ -3112,7 +3112,7 @@ pub mod tests_tee_svc_cryp {
fn test_cryptoattrref_bignum() {
// test CryptoAttrRef::BigNum
let bn = BigNum::new(0x11223344).unwrap();
- let mut buffer = crate::unittest_task::user_vec![0u8; 4];
+ let mut buffer = crate::user_vec![0u8; 4];
let mut size = TestUserValue::::from_value(4).unwrap();
let result = bn.to_user(buffer.as_user_slice(), size.as_user_ref());
assert!(result.is_ok());
@@ -3134,7 +3134,7 @@ pub mod tests_tee_svc_cryp {
// 1. test tee_cryp_obj_secret_wrapper to user
// - test to_user
- let mut buffer = crate::unittest_task::user_vec![0u8; 16];
+ let mut buffer = crate::user_vec![0u8; 16];
let mut size = TestUserValue::::from_value(16).unwrap();
let result = secret.to_user(buffer.as_user_slice(), size.as_user_ref());
assert!(result.is_ok());
@@ -3263,8 +3263,8 @@ pub mod tests_tee_svc_cryp {
// Helper function to test RSA keypair generation and verification
fn test_rsa_keypair(key_size: usize, e: u64) -> TestResult {
let mut e_bytes: [u8; 8] = [0; 8];
- let mut usr_params = crate::unittest_task::user_vec![utee_attribute::default(); 1];
- let mut usr_exp = crate::unittest_task::user_vec![0u8; 8];
+ let mut usr_params = crate::user_vec![utee_attribute::default(); 1];
+ let mut usr_exp = crate::user_vec![0u8; 8];
let (usr_params, param_count) = {
if e == 0 {
@@ -3402,14 +3402,14 @@ pub mod tests_tee_svc_cryp {
};
let mut attrs: [TEE_Attribute; 2] = [tee_attr_value; 2];
- let mut usr_attrs = crate::unittest_task::user_vec![utee_attribute::default(); 2];
+ let mut usr_attrs = crate::user_vec![utee_attribute::default(); 2];
// index 0 is value attribute
usr_attrs[0].attribute_id = TEE_ATTR_FLAG_VALUE;
usr_attrs[0].a = 0x11223344_u64;
usr_attrs[0].b = 0x55667788_u64;
// index 1 is memref attribute
// allocate memory for memref
- let mem = crate::unittest_task::user_vec![0xAAu8; 16];
+ let mem = crate::user_vec![0xAAu8; 16];
let mem_ptr = mem.as_user_ptr() as *mut c_void;
usr_attrs[1].attribute_id &= !TEE_ATTR_FLAG_VALUE;
usr_attrs[1].a = mem_ptr as u64;
diff --git a/api/kapi/src/tee/tee_svc_cryp2.rs b/tee/tee_kernel/src/tee/tee_svc_cryp2.rs
similarity index 99%
rename from api/kapi/src/tee/tee_svc_cryp2.rs
rename to tee/tee_kernel/src/tee/tee_svc_cryp2.rs
index 6f3fb01c592aafd0785d637eda099a58046b2ff1..ac5a495bbdeef4a80f2d1f2d00774ec0fb8f883f 100644
--- a/api/kapi/src/tee/tee_svc_cryp2.rs
+++ b/tee/tee_kernel/src/tee/tee_svc_cryp2.rs
@@ -1491,10 +1491,10 @@ pub mod tests_cryp {
use super::*;
use crate::{
+ TestUserValue,
tee::tee_svc_cryp::{
syscall_cryp_obj_alloc, syscall_cryp_obj_copy, syscall_obj_generate_key,
},
- unittest_task::TestUserValue,
};
#[unittest::def_test(custom)]
diff --git a/api/kapi/src/tee/tee_svc_storage.rs b/tee/tee_kernel/src/tee/tee_svc_storage.rs
similarity index 99%
rename from api/kapi/src/tee/tee_svc_storage.rs
rename to tee/tee_kernel/src/tee/tee_svc_storage.rs
index 8887c3427332eb8cc1d8ed8ef46e6f2edf137f11..ccc8c0b58b6f219c49d3feb373b005262debbb06 100644
--- a/api/kapi/src/tee/tee_svc_storage.rs
+++ b/tee/tee_kernel/src/tee/tee_svc_storage.rs
@@ -1419,7 +1419,7 @@ pub mod tests_tee_svc_storage {
use unittest::{assert, assert_eq};
use super::*;
- use crate::unittest_task::{TestUserBuffer, TestUserValue};
+ use crate::{TestUserBuffer, TestUserValue};
const TEE_DIRNAME_BUFFER_REQUIRED_LEN: usize = tee_b2hs_hsbuf_size(TEE_UUID_HEX_LEN) + 1;
diff --git a/api/kapi/src/tee/tee_ta_manager.rs b/tee/tee_kernel/src/tee/tee_ta_manager.rs
similarity index 100%
rename from api/kapi/src/tee/tee_ta_manager.rs
rename to tee/tee_kernel/src/tee/tee_ta_manager.rs
diff --git a/api/kapi/src/tee/tee_time.rs b/tee/tee_kernel/src/tee/tee_time.rs
similarity index 100%
rename from api/kapi/src/tee/tee_time.rs
rename to tee/tee_kernel/src/tee/tee_time.rs
diff --git a/api/kapi/src/tee/types_ext.rs b/tee/tee_kernel/src/tee/types_ext.rs
similarity index 100%
rename from api/kapi/src/tee/types_ext.rs
rename to tee/tee_kernel/src/tee/types_ext.rs
diff --git a/api/kapi/src/tee/user_access.rs b/tee/tee_kernel/src/tee/user_access.rs
similarity index 99%
rename from api/kapi/src/tee/user_access.rs
rename to tee/tee_kernel/src/tee/user_access.rs
index d7be05ed137794a246863ca5f578bab054527d8c..fec26368ec299419bb0a008c7c6fba648c5fe1e0 100644
--- a/api/kapi/src/tee/user_access.rs
+++ b/tee/tee_kernel/src/tee/user_access.rs
@@ -167,7 +167,7 @@ pub mod tests_user_access {
use unittest::{assert, assert_eq};
use super::*;
- use crate::unittest_task::{TestUserBuffer, TestUserValue};
+ use crate::{TestUserBuffer, TestUserValue};
fn user_buffer_from_bytes(bytes: &[u8]) -> TestUserBuffer {
let buffer = TestUserBuffer::new(bytes.len()).unwrap();
diff --git a/api/kapi/src/tee/user_ta.rs b/tee/tee_kernel/src/tee/user_ta.rs
similarity index 100%
rename from api/kapi/src/tee/user_ta.rs
rename to tee/tee_kernel/src/tee/user_ta.rs
diff --git a/api/kapi/src/tee/utee_defines.rs b/tee/tee_kernel/src/tee/utee_defines.rs
similarity index 100%
rename from api/kapi/src/tee/utee_defines.rs
rename to tee/tee_kernel/src/tee/utee_defines.rs
diff --git a/api/kapi/src/tee/utils.rs b/tee/tee_kernel/src/tee/utils.rs
similarity index 100%
rename from api/kapi/src/tee/utils.rs
rename to tee/tee_kernel/src/tee/utils.rs
diff --git a/api/kapi/src/tee/uuid.rs b/tee/tee_kernel/src/tee/uuid.rs
similarity index 100%
rename from api/kapi/src/tee/uuid.rs
rename to tee/tee_kernel/src/tee/uuid.rs
diff --git a/api/kapi/src/tee/vm.rs b/tee/tee_kernel/src/tee/vm.rs
similarity index 100%
rename from api/kapi/src/tee/vm.rs
rename to tee/tee_kernel/src/tee/vm.rs
diff --git a/util/unittest_support/Cargo.toml b/util/unittest_support/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..47089e5953c9818be32eb2bf835d82fb58e8bf27
--- /dev/null
+++ b/util/unittest_support/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "unittest_support"
+description = "Shared unittest user-memory helpers for X-Kernel crates"
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+documentation.workspace = true
+
+[dependencies]
+kalloc.workspace = true
+kcore.workspace = true
+kerrno.workspace = true
+khal.workspace = true
+ksync.workspace = true
+ktask.workspace = true
+memaddr.workspace = true
+memspace.workspace = true
+osvm.workspace = true
\ No newline at end of file
diff --git a/util/unittest_support/src/lib.rs b/util/unittest_support/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..82425aac4d317239716b2d69bcf6c1c833d0528b
--- /dev/null
+++ b/util/unittest_support/src/lib.rs
@@ -0,0 +1,264 @@
+#![no_std]
+#![allow(missing_docs)]
+
+extern crate alloc;
+
+use alloc::{sync::Arc, vec, vec::Vec};
+use core::{
+ marker::PhantomData,
+ mem::{MaybeUninit, size_of, transmute},
+ ops::{Deref, DerefMut},
+ sync::atomic::{AtomicUsize, Ordering},
+};
+
+use kcore::task::AsThread;
+use kerrno::{KError, KResult};
+use khal::{mem::v2p, paging::MappingFlags};
+use ksync::Mutex;
+use ktask::current;
+use memaddr::{PAGE_SIZE_4K, VirtAddr};
+use osvm::{read_vm_mem, write_vm_mem};
+
+static NEXT_TEST_USER_ADDR: AtomicUsize = AtomicUsize::new(kcore::config::USER_HEAP_BASE);
+
+#[macro_export]
+macro_rules! __unittest_support_user_vec {
+ ($value:expr; $len:expr) => {{
+ $crate::TestUserArray::from_array([$value; $len]).unwrap()
+ }};
+ ($($value:expr),+ $(,)?) => {{
+ $crate::TestUserArray::from_array([$($value),+]).unwrap()
+ }};
+}
+
+pub use crate::__unittest_support_user_vec as user_vec;
+
+pub struct TestUserBuffer {
+ aspace: Arc>,
+ user_addr: usize,
+ mapped_size: usize,
+ kernel_va: usize,
+ num_pages: usize,
+ len: usize,
+}
+
+impl TestUserBuffer {
+ pub fn new(len: usize) -> KResult {
+ let current_task = current();
+ let thread = current_task.try_as_thread().ok_or(KError::BadState)?;
+ let aspace = thread.proc_data.aspace.clone();
+ let mapped_size = len.max(1).next_multiple_of(PAGE_SIZE_4K);
+ let num_pages = mapped_size / PAGE_SIZE_4K;
+ let kernel_va = kalloc::global_allocator()
+ .alloc_pages(num_pages, PAGE_SIZE_4K, kalloc::UsageKind::VirtMem)
+ .map_err(|_| KError::NoMemory)?;
+
+ unsafe {
+ core::ptr::write_bytes(kernel_va as *mut u8, 0, mapped_size);
+ }
+
+ let user_addr = NEXT_TEST_USER_ADDR.fetch_add(mapped_size, Ordering::Relaxed);
+ aspace
+ .lock()
+ .map_linear(
+ VirtAddr::from_usize(user_addr),
+ v2p(VirtAddr::from_usize(kernel_va)),
+ mapped_size,
+ MappingFlags::READ | MappingFlags::WRITE | MappingFlags::USER,
+ )
+ .map_err(|_| {
+ kalloc::global_allocator().dealloc_pages(
+ kernel_va,
+ num_pages,
+ kalloc::UsageKind::VirtMem,
+ );
+ KError::NoMemory
+ })?;
+
+ Ok(Self {
+ aspace,
+ user_addr,
+ mapped_size,
+ kernel_va,
+ num_pages,
+ len,
+ })
+ }
+
+ pub fn write_bytes(&self, data: &[u8]) -> KResult {
+ if data.len() > self.len {
+ return Err(KError::InvalidInput);
+ }
+ write_vm_mem(self.user_addr as *mut u8, data).map_err(Into::into)
+ }
+
+ pub fn read_bytes(&self, len: usize) -> KResult> {
+ if len > self.len {
+ return Err(KError::InvalidInput);
+ }
+ let mut out = vec![0u8; len];
+ read_vm_mem(self.user_addr as *const u8, unsafe {
+ transmute::<&mut [u8], &mut [MaybeUninit]>(&mut out[..])
+ })
+ .map_err(KError::from)?;
+ Ok(out)
+ }
+
+ pub fn write_u64(&self, value: u64) -> KResult {
+ write_vm_mem(self.user_addr as *mut u64, core::slice::from_ref(&value)).map_err(Into::into)
+ }
+
+ pub fn read_u64(&self) -> KResult {
+ let mut out = 0u64;
+ let out_slice = unsafe {
+ core::slice::from_raw_parts_mut((&mut out as *mut u64).cast::>(), 1)
+ };
+ read_vm_mem(self.user_addr as *const u64, out_slice).map_err(KError::from)?;
+ Ok(out)
+ }
+
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ pub fn as_user_ptr(&self) -> *mut T {
+ assert!(size_of::() <= self.len);
+ self.user_addr as *mut T
+ }
+
+ pub fn as_user_slice(&mut self, len: usize) -> &mut [u8] {
+ assert!(len <= self.len);
+ unsafe { core::slice::from_raw_parts_mut(self.user_addr as *mut u8, len) }
+ }
+
+ pub fn as_user_ref(&mut self) -> &mut T {
+ assert!(size_of::() <= self.len);
+ unsafe { &mut *(self.user_addr as *mut T) }
+ }
+}
+
+pub struct TestUserValue {
+ buffer: TestUserBuffer,
+ _marker: PhantomData,
+}
+
+impl TestUserValue {
+ pub fn new() -> KResult {
+ Ok(Self {
+ buffer: TestUserBuffer::new(size_of::())?,
+ _marker: PhantomData,
+ })
+ }
+
+ pub fn from_value(value: T) -> KResult
+ where
+ T: Copy,
+ {
+ let mut user_value = Self::new()?;
+ user_value.write(value);
+ Ok(user_value)
+ }
+
+ pub fn as_user_ref(&mut self) -> &mut T {
+ self.buffer.as_user_ref::()
+ }
+
+ pub fn as_user_ptr(&self) -> *mut T {
+ self.buffer.as_user_ptr::()
+ }
+
+ pub fn write(&mut self, value: T)
+ where
+ T: Copy,
+ {
+ *self.as_user_ref() = value;
+ }
+
+ pub fn read(&self) -> T
+ where
+ T: Copy,
+ {
+ unsafe { self.as_user_ptr().read() }
+ }
+}
+
+pub struct TestUserArray {
+ buffer: TestUserBuffer,
+ _marker: PhantomData,
+}
+
+impl TestUserArray {
+ pub fn new() -> KResult {
+ Ok(Self {
+ buffer: TestUserBuffer::new(size_of::<[T; N]>())?,
+ _marker: PhantomData,
+ })
+ }
+
+ pub fn from_array(value: [T; N]) -> KResult
+ where
+ T: Copy,
+ {
+ let mut user_array = Self::new()?;
+ user_array.write(value);
+ Ok(user_array)
+ }
+
+ pub fn len(&self) -> usize {
+ N
+ }
+
+ pub fn as_user_slice(&mut self) -> &mut [T] {
+ unsafe { core::slice::from_raw_parts_mut(self.as_user_ptr(), N) }
+ }
+
+ pub fn as_user_ref(&mut self) -> &mut [T; N] {
+ unsafe { &mut *(self.as_user_ptr() as *mut [T; N]) }
+ }
+
+ pub fn as_user_ptr(&self) -> *mut T {
+ self.buffer.as_user_ptr::()
+ }
+
+ pub fn write(&mut self, value: [T; N])
+ where
+ T: Copy,
+ {
+ self.as_user_slice().copy_from_slice(&value);
+ }
+
+ pub fn read(&self) -> [T; N]
+ where
+ T: Copy,
+ {
+ unsafe { (self.as_user_ptr() as *const [T; N]).read() }
+ }
+}
+
+impl Deref for TestUserArray {
+ type Target = [T];
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { core::slice::from_raw_parts(self.as_user_ptr(), N) }
+ }
+}
+
+impl DerefMut for TestUserArray {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.as_user_slice()
+ }
+}
+
+impl Drop for TestUserBuffer {
+ fn drop(&mut self) {
+ let _ = self
+ .aspace
+ .lock()
+ .unmap(VirtAddr::from_usize(self.user_addr), self.mapped_size);
+ kalloc::global_allocator().dealloc_pages(
+ self.kernel_va,
+ self.num_pages,
+ kalloc::UsageKind::VirtMem,
+ );
+ }
+}