diff --git a/Cargo.toml b/Cargo.toml
index 2319a78d..e56de447 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,6 +44,8 @@ ksync = { path = "core/ksync" }
ktask = { path = "core/ktask" }
watchdog = { path = "io/watchdog" }
kcpu = { path = "arch/kcpu" }
+karch = { path = "arch/karch" }
+
# x-kernel Crates
alloc-engine = { path = "mm/alloc-engine" }
@@ -128,7 +130,6 @@ net = { path = "drivers/net" }
pci = { path = "drivers/pci" }
vsock = { path = "drivers/vsock" }
virtio = { path = "drivers/virtio" }
-virtio-drivers = { version = "0.12.0", default-features = false }
aarch64-pmuv3 = { path = "drivers/aarch64-pmuv3" }
fatfs = { path = "fs/fatfs", default-features = false }
rsext4 = { path = "fs/rsext4", default-features = false }
@@ -144,3 +145,4 @@ kbuild_config = { path = "util/kbuild_config" }
kconfig-gen = { path = "xtask/kconfig-gen" }
smoltcp = { version = "0.12.0", package = "x-smoltcp", default-features = false }
+virtio-drivers = { version = "0.7.4", default-features = false }
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 00000000..4bda5e9d
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,69 @@
+#!/usr/bin/env groovy
+
+pipeline {
+ agent {
+ docker {
+ image 'yeanwang/x-kernel-builder:v1.0'
+ args '-v /var/run/docker.sock:/var/run/docker.sock --privileged -u root:root' }
+ }
+
+ environment {
+ CI = 'true'
+ TEST_HARNESS_REPO = 'https://gitee.com/openkylin/starry-test-harness'
+ TEST_HARNESS_BRANCH = 'master'
+ }
+
+ stages {
+ stage('Parallel Architecture Verification') {
+ failFast true
+ parallel {
+ stage('Architecture: aarch64') {
+ steps {
+ script { executeBuildAndTest('aarch64') }
+ }
+ }
+ stage('Architecture: x86_64') {
+ steps {
+ script { executeBuildAndTest('x86_64') }
+ }
+ }
+ }
+ }
+ }
+
+ post {
+ always {
+ archiveArtifacts artifacts: '**/artifacts/**/*', allowEmptyArchive: true
+ archiveArtifacts artifacts: '**/logs/**/*', allowEmptyArchive: true
+ cleanWs()
+ }
+ success {
+ updateGiteeCommitStatus state: 'success', context: 'ci/jenkins'
+ }
+ unsuccessful {
+ updateGiteeCommitStatus state: 'failed', context: 'ci/jenkins'
+ }
+ }
+}
+
+def executeBuildAndTest(arch) {
+ ws("${WORKSPACE}/${arch}") {
+ echo "Verifying architecture: ${arch}"
+
+ checkout scm
+ sh "git config --global --add safe.directory ${pwd()}"
+ dir('test-harness') {
+ git branch: "${env.TEST_HARNESS_BRANCH}",
+ url: "${env.TEST_HARNESS_REPO}",
+ credentialsId: 'gitee-my-token'
+
+ sh "git config --global --add safe.directory ${pwd()}"
+ }
+
+ dir('test-harness') {
+ withEnv(["XKERNEL_ROOT=${pwd()}/..", "ARCH=${arch}"]) {
+ sh "make ci-test run"
+ }
+ }
+ }
+}
diff --git a/Makefile b/Makefile
index c7f2943f..ef14d133 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,8 @@
# Enable unstable features
export RUSTC_BOOTSTRAP := 1
export DWARF := y
+export DISK_IMG ?= $(PWD)/disk.img
+XCONF = env RUSTFLAGS= CARGO_ENCODED_RUSTFLAGS= cargo run --manifest-path xtask/xconfig/Cargo.toml --bin xconf --
V ?=
LTO ?=
@@ -94,6 +96,9 @@ GDB ?= gdb
OUT_DIR ?= $(PWD)
LD_SCRIPT ?= $(abspath $(TARGET_DIR)/$(TARGET)/$(MODE)/linker_$(PLAT_NAME).lds)
+# Generate Rust const definitions from .config
+CONFIG_RS := $(TARGET_DIR)/kbuild/config.rs
+
APP_NAME := xkernel
OUT_ELF := $(OUT_DIR)/$(APP_NAME)_$(PLAT_NAME).elf
OUT_BIN := $(patsubst %.elf,%.bin,$(OUT_ELF))
@@ -116,14 +121,14 @@ else ifeq ($(PLAT_NAME), aarch64-bsta1000b)
include scripts/make/bsta1000b-fada.mk
endif
-ROOTFS_URL = https://github.com/Starry-OS/rootfs/releases/download/20250917
+ROOTFS_URL = https://gitee.com/openkylin/x-kernel-image/releases/download/20260302/
ROOTFS_IMG = rootfs-$(ARCH).img
endif # end of IS_BUILD
menuconfig:
- @xconf menuconfig -k Kconfig -s .
+ @$(XCONF) menuconfig -k Kconfig -s .
@if [ -f .config ]; then \
echo "✅ Configuration saved to .config"; \
else \
@@ -142,11 +147,11 @@ teefs:
$(MAKE) -C tee_apps ARCH=$(ARCH)
defconfig:
- @xconf saveconfig -o .config -k Kconfig -s .
+ @$(XCONF) saveconfig -o .config -k Kconfig -s .
@echo "✅ Default configuration saved to .config"
saveconfig:
- @xconf saveconfig -o .config -k Kconfig -s .
+ @$(XCONF) saveconfig -o .config -k Kconfig -s .
oldconfig:
@if [ ! -f .config ]; then \
@@ -154,15 +159,20 @@ oldconfig:
echo "Please run 'make defconfig' or 'make menuconfig' first."; \
exit 1; \
fi
- @xconf oldconfig -c .config -k Kconfig -s .
+ @$(XCONF) oldconfig -c .config -k Kconfig -s .
-# Generate const definitions before build
-gen-const: .config
+
+# 只在 .config 更新时才生成
+$(CONFIG_RS): .config
@echo "📝 Generating Rust const definitions from .config..."
- @xconf gen-const
+ @$(XCONF) gen-const
@echo "✅ Generated config.rs"
-build: gen-const $(OUT_DIR) $(FINAL_IMG)
+
+# Generate const definitions before build
+gen-const: $(CONFIG_RS)
+
+build: $(CONFIG_RS) $(OUT_DIR) $(FINAL_IMG)
disasm:
$(OBJDUMP) $(OUT_ELF) | less
@@ -180,7 +190,7 @@ debug: build
-ex 'continue' \
-ex 'disp /16i $$pc'
-clippy: gen-const
+clippy: $(CONFIG_RS)
ifeq ($(origin ARCH), command line)
$(call cargo_clippy,--target $(TARGET))
else
@@ -221,6 +231,8 @@ distclean: clean
clean_c::
rm -rf $(app-objs)
+# Note: gen-const is kept as PHONY to allow manual invocation,
+# but the actual dependency is on $(CONFIG_RS) which is file-based
.PHONY: all defconfig oldconfig menuconfig saveconfig gen-const \
build disasm run justrun debug \
clippy doc doc_check_missing fmt fmt_c unittest unittest_no_fail_fast \
diff --git a/api/kapi/src/tee/README.md b/api/kapi/src/tee/README.md
new file mode 100644
index 00000000..e8f16f7e
--- /dev/null
+++ b/api/kapi/src/tee/README.md
@@ -0,0 +1,7 @@
+# tee
+
+rust implement for tee core
+
+## arch
+
+hygon_csv_bindings.rs is auto generated by repo https://gitee.com/kylinyubo/rust-csv-guest-module-tools.
diff --git a/api/kapi/src/tee/arch/mod.rs b/api/kapi/src/tee/arch/mod.rs
index 832557ef..2fe50193 100644
--- a/api/kapi/src/tee/arch/mod.rs
+++ b/api/kapi/src/tee/arch/mod.rs
@@ -1,2 +1,6 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(target_arch = "x86_64")]
pub mod x86_64;
diff --git a/api/kapi/src/tee/arch/x86_64/hygon_csv.rs b/api/kapi/src/tee/arch/x86_64/hygon_csv.rs
index bf3406ec..f59b4e4d 100644
--- a/api/kapi/src/tee/arch/x86_64/hygon_csv.rs
+++ b/api/kapi/src/tee/arch/x86_64/hygon_csv.rs
@@ -93,7 +93,7 @@ pub fn get_huk_key(huk_key: &mut [u8]) -> TeeResult {
let salt = "Hygon CSV Sealing Key";
Hkdf::hkdf(MdType::SM3, &salt.as_bytes(), sealing_key, &[], huk_key)
.map_err(|_| TEE_ERROR_BAD_PARAMETERS)?;
- warn!("get_huk_key: huk_key: {:?}", slice_fmt(huk_key));
+ // warn!("get_huk_key: huk_key: {:?}", slice_fmt(huk_key));
Ok(())
}
diff --git a/api/kapi/src/tee/arch/x86_64/hygon_csv_bindings.rs b/api/kapi/src/tee/arch/x86_64/hygon_csv_bindings.rs
index 4d19dc4f..a97c2099 100644
--- a/api/kapi/src/tee/arch/x86_64/hygon_csv_bindings.rs
+++ b/api/kapi/src/tee/arch/x86_64/hygon_csv_bindings.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
// automatically generated by rust-bindgen 0.69.5
#[repr(C)]
diff --git a/api/kapi/src/tee/arch/x86_64/mod.rs b/api/kapi/src/tee/arch/x86_64/mod.rs
index 48398ccb..3707c056 100644
--- a/api/kapi/src/tee/arch/x86_64/mod.rs
+++ b/api/kapi/src/tee/arch/x86_64/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(feature = "x86_csv")]
pub mod hygon_csv;
#[cfg(feature = "x86_csv")]
diff --git a/api/kapi/src/tee/crypto_temp/aes_ecb.rs b/api/kapi/src/tee/crypto_temp/aes_ecb.rs
deleted file mode 100644
index 1b457906..00000000
--- a/api/kapi/src/tee/crypto_temp/aes_ecb.rs
+++ /dev/null
@@ -1,220 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-use alloc::boxed::Box;
-
-use mbedtls_sys_auto::{
- AES_DECRYPT, AES_ENCRYPT, aes_context, aes_crypt_ecb, aes_free, aes_init, aes_setkey_dec,
- aes_setkey_enc,
-};
-use tee_raw_sys::{TEE_ERROR_BAD_PARAMETERS, TEE_ERROR_BAD_STATE, TEE_OperationMode};
-
-use super::crypto_hash_temp::{CryptoCipherCtx, CryptoCipherOps};
-use crate::tee::{TeeResult, common::array, utee_defines::TEE_AES_BLOCK_SIZE, utils::slice_fmt};
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct MbedAesEcbCtx {
- mbed_mode: i32,
- aes_ctx: aes_context,
-}
-
-fn mbed_aes_ecb_init(
- ctx: &mut MbedAesEcbCtx,
- mode: TEE_OperationMode,
- key1: Option<&[u8]>,
- _key2: Option<&[u8]>,
- _iv: Option<&[u8]>,
-) -> TeeResult {
- tee_debug!("mbed_aes_ecb_init: mode: {:?}, key1: {:?}", mode, key1);
- let (key1_ptr, key1_len) = array::get_const_ptr_and_len(key1);
-
- unsafe { aes_init(&mut ctx.aes_ctx) };
-
- let mbed_res = match mode {
- TEE_OperationMode::TEE_MODE_ENCRYPT => {
- ctx.mbed_mode = AES_ENCRYPT;
- unsafe { aes_setkey_enc(&mut ctx.aes_ctx, key1_ptr, key1_len as u32 * 8) }
- }
- TEE_OperationMode::TEE_MODE_DECRYPT => {
- ctx.mbed_mode = AES_DECRYPT;
- unsafe { aes_setkey_dec(&mut ctx.aes_ctx, key1_ptr, key1_len as u32 * 8) }
- }
- _ => {
- return Err(TEE_ERROR_BAD_PARAMETERS);
- }
- };
-
- if mbed_res != 0 {
- return Err(TEE_ERROR_BAD_STATE);
- }
-
- Ok(())
-}
-
-fn mbed_aes_ecb_update(
- ctx: &mut MbedAesEcbCtx,
- _last_block: bool,
- data: Option<&[u8]>,
- dst: Option<&mut [u8]>,
-) -> TeeResult {
- let (data_ptr, data_len) = array::get_const_ptr_and_len(data);
- let (dst_ptr, _dst_len) = array::get_mut_ptr_and_len(dst);
-
- if data_len % TEE_AES_BLOCK_SIZE != 0 {
- return Err(TEE_ERROR_BAD_PARAMETERS);
- }
-
- tee_debug!(
- "mbed_aes_ecb_update: mode: {:?}, data_len: {:?}, dst_len: {:?}",
- ctx.mbed_mode,
- data_len,
- _dst_len
- );
-
- // AES ECB processes one block (16 bytes) at a time
- let num_blocks = data_len / TEE_AES_BLOCK_SIZE;
- for i in 0..num_blocks {
- let input_block = unsafe { data_ptr.add(i * TEE_AES_BLOCK_SIZE) };
- let output_block = unsafe { dst_ptr.add(i * TEE_AES_BLOCK_SIZE) };
-
- let mbed_res =
- unsafe { aes_crypt_ecb(&mut ctx.aes_ctx, ctx.mbed_mode, input_block, output_block) };
-
- if mbed_res != 0 {
- return Err(TEE_ERROR_BAD_STATE);
- }
- }
-
- Ok(())
-}
-
-fn mbed_aes_ecb_final(ctx: &mut MbedAesEcbCtx) {
- unsafe { aes_free(&mut ctx.aes_ctx as *mut aes_context) };
-}
-
-// optee_os, the context is allocated by function crypto_aes_ecb_alloc_ctx, so need free it manually.
-// in libmbedtls, the context is owned by Box with function alloc_cipher_ctx, freed automatically
-// when it goes out of scope.
-// So this function is a no-op in this case.
-fn mbed_aes_ecb_free_ctx(_ctx: &mut MbedAesEcbCtx) {}
-
-fn mbed_aes_ecb_copy_state(dst_ctx: &mut MbedAesEcbCtx, src_ctx: &MbedAesEcbCtx) {
- dst_ctx.mbed_mode = src_ctx.mbed_mode;
- dst_ctx.aes_ctx = src_ctx.aes_ctx;
-}
-
-impl CryptoCipherOps for MbedAesEcbCtx {
- fn init(
- &mut self,
- mode: TEE_OperationMode,
- key1: Option<&[u8]>,
- key2: Option<&[u8]>,
- iv: Option<&[u8]>,
- ) -> TeeResult {
- mbed_aes_ecb_init(self, mode, key1, key2, iv)
- }
-
- fn update(
- &mut self,
- last_block: bool,
- data: Option<&[u8]>,
- dst: Option<&mut [u8]>,
- ) -> TeeResult {
- mbed_aes_ecb_update(self, last_block, data, dst)
- }
-
- fn finalize(&mut self) {
- mbed_aes_ecb_final(self)
- }
-
- fn free_ctx(&mut self) {
- mbed_aes_ecb_free_ctx(self)
- }
-
- fn copy_state(&self, dst_ctx: &mut MbedAesEcbCtx) {
- mbed_aes_ecb_copy_state(dst_ctx, self);
- }
-}
-
-impl CryptoCipherCtx for MbedAesEcbCtx {
- type Context = MbedAesEcbCtx;
-
- fn alloc_cipher_ctx() -> Result, TeeResult> {
- let ctx = MbedAesEcbCtx {
- mbed_mode: 0,
- aes_ctx: aes_context::default(),
- };
-
- Ok(Box::new(ctx))
- }
-}
-
-#[cfg(feature = "tee_test")]
-pub mod tests_aes_ecb {
- use hashbrown::hash_map::Keys;
- use unittest::{
- test_fn, test_framework::TestDescriptor, test_framework_basic::TestResult, tests_name,
- };
-
- use super::*;
- use crate::tee::utils::random_bytes;
-
- test_fn! {
- using TestResult;
-
- fn test_tee_aes_ecb_init_update_final() {
- // test encrypt
- let plaintext = [1u8; 16];
- let Key = [2u8; 16];
- let mut ciphertext = [0u8; 16];
- let mut ctx = MbedAesEcbCtx::alloc_cipher_ctx().expect("Failed to allocate AES ECB context");
- let _ = ctx.init(TEE_OperationMode::TEE_MODE_ENCRYPT, Some(&Key), None, None).expect("Failed to initialize AES ECB context");
- let _ = ctx.update(true, Some(&plaintext), Some(&mut ciphertext)).expect("Failed to update AES ECB context");
- ctx.finalize();
- tee_debug!("ciphertext: {:?}", slice_fmt(&ciphertext));
- // test decrypt
- let mut decrypted_text = [0u8; 16];
- let _ = ctx.init(TEE_OperationMode::TEE_MODE_DECRYPT, Some(&Key), None, None).expect("Failed to initialize AES ECB context");
- let _ = ctx.update(true, Some(&ciphertext), Some(&mut decrypted_text)).expect("Failed to update AES ECB context");
- ctx.finalize();
- tee_debug!("decrypted_text: {:?}", slice_fmt(&decrypted_text));
- assert_eq!(decrypted_text, plaintext);
- }
- }
-
- test_fn! {
- using TestResult;
-
- fn test_tee_aes_ecb_init_update_final_long() {
- // test encrypt
- let mut plaintext = [1u8; 256];
- // randomize the plaintext, using randChacha
- random_bytes(&mut plaintext);
-
- let Key = [2u8; 16];
- let mut ciphertext = [0u8; 256];
- let mut ctx = MbedAesEcbCtx::alloc_cipher_ctx().expect("Failed to allocate AES ECB context");
- let _ = ctx.init(TEE_OperationMode::TEE_MODE_ENCRYPT, Some(&Key), None, None).expect("Failed to initialize AES ECB context");
- let _ = ctx.update(true, Some(&plaintext), Some(&mut ciphertext)).expect("Failed to update AES ECB context");
- ctx.finalize();
- // tee_debug!("ciphertext: {:?}", slice_fmt(&ciphertext));
- // test decrypt
- let mut decrypted_text = [0u8; 256];
- let _ = ctx.init(TEE_OperationMode::TEE_MODE_DECRYPT, Some(&Key), None, None).expect("Failed to initialize AES ECB context");
- let _ = ctx.update(true, Some(&ciphertext), Some(&mut decrypted_text)).expect("Failed to update AES ECB context");
- ctx.finalize();
- tee_debug!("decrypted_text: {:?}", slice_fmt(&decrypted_text));
- assert_eq!(decrypted_text, plaintext);
- }
- }
-
- tests_name! {
- TEST_TEE_AES_ECB;
- //------------------------
- aes_ecb;
- test_tee_aes_ecb_init_update_final,
- test_tee_aes_ecb_init_update_final_long,
- }
-}
diff --git a/api/kapi/src/tee/crypto_temp/crypto_hash_temp.rs b/api/kapi/src/tee/crypto_temp/crypto_hash_temp.rs
deleted file mode 100644
index 2cd03d8e..00000000
--- a/api/kapi/src/tee/crypto_temp/crypto_hash_temp.rs
+++ /dev/null
@@ -1,259 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-use alloc::boxed::Box;
-
-use mbedtls::hash::{Md, Type};
-use tee_raw_sys::{
- TEE_ALG_AES_ECB_NOPAD, TEE_ALG_HMAC_MD5, TEE_ALG_HMAC_SHA1, TEE_ALG_HMAC_SHA256,
- TEE_ALG_HMAC_SHA512, TEE_ALG_HMAC_SM3, TEE_ALG_MD5, TEE_ALG_SHA256, TEE_ALG_SHA512,
- TEE_ALG_SM3, TEE_ALG_SM4_ECB_NOPAD, TEE_ERROR_BAD_PARAMETERS, TEE_ERROR_BAD_STATE,
- TEE_ERROR_NOT_IMPLEMENTED, TEE_OperationMode,
-};
-
-use crate::tee::{
- TeeResult,
- crypto_temp::{aes_ecb::MbedAesEcbCtx, sm4_ecb::MbedSm4EcbCtx},
- utee_defines::TeeAlg,
-};
-
-pub trait HashOps {
- fn init(&mut self, key: &[u8]) -> TeeResult;
- fn update(&mut self, data: &[u8]) -> TeeResult;
- fn finalize(&mut self, digest: &mut [u8]) -> TeeResult;
- fn free_ctx(&mut self);
- fn copy_state(&self, dst_ctx: &mut dyn HashOps) -> TeeResult;
-}
-
-// 添加MacAlgorithmTrait trait
-pub trait MacAlgorithmTrait {
- type Context: HashOps + 'static;
-
- fn alloc_hash() -> Result;
-}
-
-pub trait HashAlgorithm {
- type Ops: HashOps + 'static;
-
- fn get_ops() -> &'static Self::Ops;
- // fn get_md_type() -> mbedtls_md_type_t;
-}
-
-pub struct MbedCtx;
-
-// 具体的MAC算法实现
-// HMAC-SHA256
-#[allow(dead_code)]
-pub struct HmacSha256 {
- inner: MbedCtx,
-}
-#[allow(dead_code)]
-pub struct HmacSha512 {
- inner: MbedCtx,
-}
-
-impl HashOps for HmacSha256 {
- fn init(&mut self, _key: &[u8]) -> TeeResult {
- debug!("HashOps with HmacSha256");
- Ok(())
- }
-
- fn update(&mut self, _data: &[u8]) -> TeeResult {
- Ok(())
- }
-
- fn finalize(&mut self, _digest: &mut [u8]) -> TeeResult {
- Ok(())
- }
-
- fn free_ctx(&mut self) {
- // 这里应该释放资源,但返回类型是()
- }
-
- fn copy_state(&self, _dst_ctx: &mut dyn HashOps) -> TeeResult {
- Ok(())
- }
-}
-
-// 为HmacSha256实现MacAlgorithmTrait
-impl MacAlgorithmTrait for HmacSha256 {
- type Context = HmacSha256;
-
- fn alloc_hash() -> Result {
- Ok(HmacSha256 { inner: MbedCtx })
- }
-}
-
-impl HashOps for HmacSha512 {
- fn init(&mut self, _key: &[u8]) -> TeeResult {
- Ok(())
- }
-
- fn update(&mut self, _data: &[u8]) -> TeeResult {
- Ok(())
- }
-
- fn finalize(&mut self, _digest: &mut [u8]) -> TeeResult {
- Ok(())
- }
-
- fn free_ctx(&mut self) {
- // 这里应该释放资源,但返回类型是()
- }
-
- fn copy_state(&self, _dst_ctx: &mut dyn HashOps) -> TeeResult {
- Ok(())
- }
-}
-
-// 为HmacSha512实现MacAlgorithmTrait
-impl MacAlgorithmTrait for HmacSha512 {
- type Context = HmacSha512;
-
- fn alloc_hash() -> Result {
- Ok(HmacSha512 { inner: MbedCtx })
- }
-}
-
-// 工厂方法:根据hash_id生成不同的HMAC实例
-pub fn crypto_mac_alloc_ctx(algorithm: TeeAlg) -> Result, TeeResult> {
- match algorithm {
- TEE_ALG_HMAC_SHA256 => {
- let ctx: HmacSha256 = HmacSha256::alloc_hash()?;
- Ok(Box::new(ctx))
- }
- TEE_ALG_HMAC_SHA512 => {
- let ctx = HmacSha512::alloc_hash()?;
- Ok(Box::new(ctx))
- }
- _ => Err(Err(TEE_ERROR_BAD_PARAMETERS)),
- }
-}
-
-pub trait CryptoCipherOps {
- fn init(
- &mut self,
- mode: TEE_OperationMode,
- key1: Option<&[u8]>,
- key2: Option<&[u8]>,
- iv: Option<&[u8]>,
- ) -> TeeResult;
- fn update(
- &mut self,
- last_block: bool,
- data: Option<&[u8]>,
- dst: Option<&mut [u8]>,
- ) -> TeeResult;
- fn finalize(&mut self);
- fn free_ctx(&mut self);
- fn copy_state(&self, dst_ctx: &mut MbedAesEcbCtx);
-}
-
-pub trait CryptoCipherCtx {
- type Context;
-
- fn alloc_cipher_ctx() -> Result, TeeResult>;
-}
-pub trait CryptoHashOps {
- fn init(&mut self) -> TeeResult;
- fn update(&mut self, data: Option<&[u8]>) -> TeeResult;
- fn finalize(&mut self, digest: Option<&mut [u8]>) -> TeeResult;
- fn free_ctx(&mut self);
- fn copy_state(&self, dst_ctx: &mut Self);
-}
-
-// pub fn crypto_mac_alloc_ctx() -> Result {
-// A::alloc_ctx()
-// }
-
-/// Convert TeeAlg to mbedtls::hash::Type
-/// This is a helper function instead of TryFrom implementation due to Rust's orphan rule
-fn tee_alg_to_hash_type(value: TeeAlg) -> Result {
- match value {
- TEE_ALG_MD5 => Ok(Type::Md5),
- TEE_ALG_SHA256 => Ok(Type::Sha256),
- TEE_ALG_SHA512 => Ok(Type::Sha512),
- TEE_ALG_SM3 => Ok(Type::SM3),
- _ => Err(TEE_ERROR_NOT_IMPLEMENTED),
- }
-}
-
-/// Convert TeeAlg to mbedtls::hash::Type
-/// This is a helper function instead of TryFrom implementation due to Rust's orphan rule
-pub fn tee_alg_to_hmac_type(value: TeeAlg) -> TeeResult {
- match value {
- TEE_ALG_HMAC_MD5 => Ok(Type::Md5),
- TEE_ALG_HMAC_SHA1 => Ok(Type::Sha1),
- TEE_ALG_HMAC_SHA256 => Ok(Type::Sha256),
- TEE_ALG_HMAC_SHA512 => Ok(Type::Sha512),
- TEE_ALG_HMAC_SM3 => Ok(Type::SM3),
- _ => Err(TEE_ERROR_NOT_IMPLEMENTED),
- }
-}
-
-pub fn crypto_cipher_alloc_ctx(algo: TeeAlg) -> Result, TeeResult> {
- match algo {
- TEE_ALG_AES_ECB_NOPAD => {
- let ctx: MbedAesEcbCtx = *MbedAesEcbCtx::alloc_cipher_ctx()?;
- Ok(Box::new(ctx))
- }
- TEE_ALG_SM4_ECB_NOPAD => {
- let ctx: MbedSm4EcbCtx = *MbedSm4EcbCtx::alloc_cipher_ctx()?;
- Ok(Box::new(ctx))
- }
- _ => Err(Err(TEE_ERROR_NOT_IMPLEMENTED)),
- }
-}
-
-pub fn crypto_hash_free_ctx(ctx: &mut H)
-where
- H: CryptoHashOps,
-{
- ctx.free_ctx();
-}
-
-// pub fn crypto_hash_copy_state(src: &H, dst: &mut H)
-// where
-// H: CryptoHashOps,
-// {
-// src.copy_state(dst)
-// }
-
-// pub fn crypto_hash_alloc_ctx(t : Type) -> Result {
-// let mut md = Md::new(t).map_err(|e| TeeResultCode::ErrorBadState)?;
-//
-// Ok(md)
-// }
-
-pub fn crypto_hash_alloc_ctx(alg: TeeAlg) -> TeeResult {
- let t = tee_alg_to_hash_type(alg)?;
- let md = Md::new(t).map_err(|_| TEE_ERROR_BAD_STATE)?;
-
- Ok(md)
-}
-
-pub fn crypto_hash_init(_md: &mut Md) -> TeeResult {
- // initialized in Md.new
- Ok(())
-}
-
-pub fn crypto_hash_update(md: &mut Md, data: &[u8]) -> TeeResult {
- tee_debug!(
- "crypto_hash_update: data length: {:?}, data: {:X?}",
- data.len(),
- hex::encode(data)
- );
- md.update(data).map_err(|_| TEE_ERROR_BAD_STATE)?;
- Ok(())
-}
-
-pub fn crypto_hash_final(md: Md, digest: &mut [u8]) -> TeeResult {
- tee_debug!(
- "crypto_hash_final: digest length: {:?}, digest: {:X?}",
- digest.len(),
- hex::encode(&digest)
- );
- md.finish(digest).map_err(|_| TEE_ERROR_BAD_STATE)?;
- Ok(())
-}
diff --git a/api/kapi/src/tee/crypto_temp/hash.rs b/api/kapi/src/tee/crypto_temp/hash.rs
deleted file mode 100644
index 129ce6ae..00000000
--- a/api/kapi/src/tee/crypto_temp/hash.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-use tee_raw_sys::{TEE_ERROR_BAD_PARAMETERS, TEE_ERROR_BAD_STATE};
-
-use super::crypto_hash_temp::CryptoHashOps;
-use crate::tee::{TeeResult, common::array, utee_defines::TEE_MAX_HASH_SIZE};
-//--------------------from rust-mbedtls bindings.rs --------------------
-#[allow(non_camel_case_types)]
-pub struct md_info_t {}
-#[allow(dead_code)]
-#[allow(non_camel_case_types)]
-pub struct md_context_t<'a> {
- md_info: &'a md_info_t,
-}
-#[allow(dead_code)]
-pub fn md_starts(_ctx: *mut md_context_t) -> i32 {
- 0
-}
-#[allow(dead_code)]
-pub fn md_update(_ctx: *mut md_context_t, _input: *const u8, _ilen: usize) -> u32 {
- 0
-}
-#[allow(dead_code)]
-pub fn md_get_size(_md_info: *const md_info_t) -> u8 {
- 32 // 假设返回 SHA-256 的大小
-}
-#[allow(dead_code)]
-pub fn md_finish(_ctx: *mut md_context_t, _output: *mut u8) -> i32 {
- 0
-}
-#[allow(dead_code)]
-pub fn md_free(_ctx: *mut md_context_t) {}
-#[allow(dead_code)]
-pub fn md_clone(_dst: *mut md_context_t, _src: *const md_context_t) -> i32 {
- 0
-}
-
-//-------------------- end rust-mbedtls bindings.rs --------------------
-#[allow(dead_code)]
-pub struct MbedHashCtx<'a> {
- md_context: md_context_t<'a>,
-}
-
-impl CryptoHashOps for MbedHashCtx<'_> {
- fn init(&mut self) -> TeeResult {
- if md_starts(&mut self.md_context) != 0 {
- Err(TEE_ERROR_BAD_STATE)
- } else {
- Ok(())
- }
- }
-
- fn update(&mut self, buf: Option<&[u8]>) -> TeeResult {
- let (buf_ptr, buf_len) = array::get_const_ptr_and_len(buf);
-
- if md_update(&mut self.md_context, buf_ptr, buf_len) != 0 {
- Err(TEE_ERROR_BAD_STATE)
- } else {
- Ok(())
- }
- }
-
- fn finalize(&mut self, digest: Option<&mut [u8]>) -> TeeResult {
- let hash_size = md_get_size(self.md_context.md_info) as usize;
- let mut block_digest = [0u8; TEE_MAX_HASH_SIZE]; // 内部的临时哈希缓冲区
-
- if hash_size > block_digest.len() {
- return Err(TEE_ERROR_BAD_STATE);
- }
-
- match digest {
- Some(user_buf) => {
- let target_ptr = if user_buf.len() >= hash_size {
- user_buf.as_mut_ptr()
- } else {
- block_digest.as_mut_ptr()
- };
-
- if md_finish(&mut self.md_context, target_ptr) != 0 {
- return Err(TEE_ERROR_BAD_STATE);
- }
-
- if user_buf.len() < hash_size {
- let copy_len = user_buf.len();
- user_buf[..copy_len].copy_from_slice(&block_digest[..copy_len]);
- }
- }
- None => {
- return Err(TEE_ERROR_BAD_PARAMETERS);
- }
- }
-
- Ok(())
- }
-
- fn free_ctx(&mut self) {
- md_free(&mut self.md_context);
- }
-
- fn copy_state(&self, dst_ctx: &mut Self) {
- if md_clone(&mut dst_ctx.md_context, &self.md_context) != 0 {
- // TODO panic
- }
- }
-}
diff --git a/api/kapi/src/tee/crypto_temp/mod.rs b/api/kapi/src/tee/crypto_temp/mod.rs
deleted file mode 100644
index 195723b3..00000000
--- a/api/kapi/src/tee/crypto_temp/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-// NOTE: !!!Temporary file for crypto operations.!!!
-// !!! DO NOT ADD NEW FUNCTIONS TO THIS FILE !!!
-// TODO: Remove this file after the crypto module are implemented.
-
-pub mod aes_ecb;
-pub mod crypto_hash_temp;
-pub mod hash;
-pub mod sm4_ecb;
diff --git a/api/kapi/src/tee/crypto_temp/sm4_ecb.rs b/api/kapi/src/tee/crypto_temp/sm4_ecb.rs
deleted file mode 100644
index 01aacd27..00000000
--- a/api/kapi/src/tee/crypto_temp/sm4_ecb.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-use alloc::boxed::Box;
-
-use mbedtls_sys_auto::{
- sm4_context, sm4_crypt_ecb, sm4_free, sm4_init, sm4_setkey_dec, sm4_setkey_enc,
-};
-use tee_raw_sys::{TEE_ERROR_BAD_PARAMETERS, TEE_ERROR_BAD_STATE, TEE_OperationMode};
-
-use super::crypto_hash_temp::{CryptoCipherCtx, CryptoCipherOps};
-use crate::tee::{
- TeeResult, common::array, crypto_temp::aes_ecb::MbedAesEcbCtx, utee_defines::TEE_SM4_BLOCK_SIZE,
-};
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-pub struct MbedSm4EcbCtx {
- mbed_mode: i32, // 1 for encrypt, 0 for decrypt
- sm4_ctx: sm4_context,
-}
-
-fn mbed_sm4_ecb_init(
- ctx: &mut MbedSm4EcbCtx,
- mode: TEE_OperationMode,
- key1: Option<&[u8]>,
- _key2: Option<&[u8]>,
- _iv: Option<&[u8]>,
-) -> TeeResult {
- tee_debug!("mbed_sm4_ecb_init: mode: {:?}, key1: {:?}", mode, key1);
- let (key1_ptr, key1_len) = array::get_const_ptr_and_len(key1);
-
- // if key1_len != 16 {
- // return Err(TEE_ERROR_BAD_PARAMETERS);
- // }
-
- unsafe { sm4_init(&mut ctx.sm4_ctx) };
-
- let mbed_res = match mode {
- TEE_OperationMode::TEE_MODE_ENCRYPT => {
- ctx.mbed_mode = 1; // SM4_ENCRYPT
- unsafe { sm4_setkey_enc(&mut ctx.sm4_ctx, key1_ptr, 128) }
- }
- TEE_OperationMode::TEE_MODE_DECRYPT => {
- ctx.mbed_mode = 0; // SM4_DECRYPT
- unsafe { sm4_setkey_dec(&mut ctx.sm4_ctx, key1_ptr, 128) }
- }
- _ => {
- return Err(TEE_ERROR_BAD_PARAMETERS);
- }
- };
-
- if mbed_res != 0 {
- return Err(TEE_ERROR_BAD_STATE);
- }
-
- Ok(())
-}
-
-fn mbed_sm4_ecb_update(
- ctx: &mut MbedSm4EcbCtx,
- _last_block: bool,
- data: Option<&[u8]>,
- dst: Option<&mut [u8]>,
-) -> TeeResult {
- let (data_ptr, data_len) = array::get_const_ptr_and_len(data);
- let (dst_ptr, _dst_len) = array::get_mut_ptr_and_len(dst);
-
- if data_len % TEE_SM4_BLOCK_SIZE != 0 {
- return Err(TEE_ERROR_BAD_PARAMETERS);
- }
-
- tee_debug!(
- "mbed_sm4_ecb_update: mode: {:?}, data_len: {:?}, dst_len: {:?}",
- ctx.mbed_mode,
- data_len,
- _dst_len
- );
-
- // SM4 ECB processes one block (16 bytes) at a time
- let num_blocks = data_len / TEE_SM4_BLOCK_SIZE;
- for i in 0..num_blocks {
- let input_block = unsafe { data_ptr.add(i * TEE_SM4_BLOCK_SIZE) };
- let output_block = unsafe { dst_ptr.add(i * TEE_SM4_BLOCK_SIZE) };
-
- let mbed_res =
- unsafe { sm4_crypt_ecb(&mut ctx.sm4_ctx, ctx.mbed_mode, input_block, output_block) };
-
- if mbed_res != 0 {
- return Err(TEE_ERROR_BAD_STATE);
- }
- }
-
- Ok(())
-}
-
-fn mbed_sm4_ecb_final(ctx: &mut MbedSm4EcbCtx) {
- unsafe { sm4_free(&mut ctx.sm4_ctx as *mut sm4_context) };
-}
-
-fn mbed_sm4_ecb_free_ctx(_ctx: &mut MbedSm4EcbCtx) {}
-
-fn mbed_sm4_ecb_copy_state(dst_ctx: &mut MbedSm4EcbCtx, src_ctx: &MbedSm4EcbCtx) {
- dst_ctx.mbed_mode = src_ctx.mbed_mode;
- dst_ctx.sm4_ctx = src_ctx.sm4_ctx;
-}
-
-impl CryptoCipherOps for MbedSm4EcbCtx {
- fn init(
- &mut self,
- mode: TEE_OperationMode,
- key1: Option<&[u8]>,
- key2: Option<&[u8]>,
- iv: Option<&[u8]>,
- ) -> TeeResult {
- mbed_sm4_ecb_init(self, mode, key1, key2, iv).inspect_err(|e| {
- error!("mbed_sm4_ecb_init failed: {:X?}", e);
- })
- }
-
- fn update(
- &mut self,
- last_block: bool,
- data: Option<&[u8]>,
- dst: Option<&mut [u8]>,
- ) -> TeeResult {
- mbed_sm4_ecb_update(self, last_block, data, dst)
- }
-
- fn finalize(&mut self) {
- mbed_sm4_ecb_final(self)
- }
-
- fn free_ctx(&mut self) {
- mbed_sm4_ecb_free_ctx(self)
- }
-
- fn copy_state(&self, _dst_ctx: &mut MbedAesEcbCtx) {
- // TODO: SM4 copy_state not implemented yet
- // This is a placeholder implementation
- }
-}
-
-impl CryptoCipherCtx for MbedSm4EcbCtx {
- type Context = MbedSm4EcbCtx;
-
- fn alloc_cipher_ctx() -> Result, TeeResult> {
- let ctx = MbedSm4EcbCtx {
- mbed_mode: 0,
- sm4_ctx: sm4_context::default(),
- };
-
- Ok(Box::new(ctx))
- }
-}
diff --git a/api/kapi/src/tee/fs_htree.rs b/api/kapi/src/tee/fs_htree.rs
index d72071a1..c04997cf 100644
--- a/api/kapi/src/tee/fs_htree.rs
+++ b/api/kapi/src/tee/fs_htree.rs
@@ -10,15 +10,16 @@ use cfg_if::cfg_if;
use mbedtls::{
cipher::{Authenticated, Cipher, CipherData, Decryption, Encryption, Fresh, Operation, raw},
error::HiError::PemAllocFailed,
- hash::Md,
+ hash::{Md, Type},
};
use memoffset::offset_of;
use subtle::ConstantTimeEq;
use tee_raw_sys::{
- TEE_ALG_AES_ECB_NOPAD, TEE_ALG_AES_GCM, TEE_ALG_HMAC_SHA256, TEE_ALG_HMAC_SM3, TEE_ALG_SHA256,
- TEE_ALG_SM3, TEE_ALG_SM4_ECB_NOPAD, TEE_ALG_SM4_GCM, TEE_ERROR_BAD_PARAMETERS,
- TEE_ERROR_CORRUPT_OBJECT, TEE_ERROR_GENERIC, TEE_ERROR_MAC_INVALID, TEE_ERROR_NOT_SUPPORTED,
- TEE_ERROR_SECURITY, TEE_ERROR_SHORT_BUFFER, TEE_OperationMode, TEE_UUID,
+ TEE_ALG_AES_ECB_NOPAD, TEE_ALG_AES_GCM, TEE_ALG_HMAC_SHA256, TEE_ALG_HMAC_SM3, TEE_ALG_MD5,
+ TEE_ALG_SHA256, TEE_ALG_SHA512, TEE_ALG_SM3, TEE_ALG_SM4_ECB_NOPAD, TEE_ALG_SM4_GCM,
+ TEE_ERROR_BAD_PARAMETERS, TEE_ERROR_BAD_STATE, TEE_ERROR_CORRUPT_OBJECT, TEE_ERROR_GENERIC,
+ TEE_ERROR_MAC_INVALID, TEE_ERROR_NOT_IMPLEMENTED, TEE_ERROR_NOT_SUPPORTED, TEE_ERROR_SECURITY,
+ TEE_ERROR_SHORT_BUFFER, TEE_OperationMode, TEE_UUID,
};
use super::utee_defines::{
@@ -27,9 +28,6 @@ use super::utee_defines::{
use crate::tee::{
TeeResult,
common::file_ops::FileVariant,
- crypto_temp::crypto_hash_temp::{
- crypto_hash_alloc_ctx, crypto_hash_final, crypto_hash_init, crypto_hash_update,
- },
rng_software::crypto_rng_read,
tee_fs_key_manager::{TEE_FS_KM_FEK_SIZE, tee_fs_fek_crypt},
tee_ree_fs::{BLOCK_SIZE, TeeFsFdAux, TeeFsHtreeStorageOps},
@@ -308,6 +306,48 @@ impl Debug for TeeFsHtree {
}
}
+fn tee_alg_to_hash_type(value: TeeAlg) -> Result {
+ match value {
+ TEE_ALG_MD5 => Ok(Type::Md5),
+ TEE_ALG_SHA256 => Ok(Type::Sha256),
+ TEE_ALG_SHA512 => Ok(Type::Sha512),
+ TEE_ALG_SM3 => Ok(Type::SM3),
+ _ => Err(TEE_ERROR_NOT_IMPLEMENTED),
+ }
+}
+
+fn crypto_hash_alloc_ctx(alg: TeeAlg) -> TeeResult {
+ let t = tee_alg_to_hash_type(alg)?;
+ let md = Md::new(t).map_err(|_| TEE_ERROR_BAD_STATE)?;
+
+ Ok(md)
+}
+
+fn crypto_hash_init(_md: &mut Md) -> TeeResult {
+ // initialized in Md.new
+ Ok(())
+}
+
+fn crypto_hash_update(md: &mut Md, data: &[u8]) -> TeeResult {
+ tee_debug!(
+ "crypto_hash_update: data length: {:?}, data: {:X?}",
+ data.len(),
+ hex::encode(data)
+ );
+ md.update(data).map_err(|_| TEE_ERROR_BAD_STATE)?;
+ Ok(())
+}
+
+fn crypto_hash_final(md: Md, digest: &mut [u8]) -> TeeResult {
+ tee_debug!(
+ "crypto_hash_final: digest length: {:?}, digest: {:X?}",
+ digest.len(),
+ hex::encode(&digest)
+ );
+ md.finish(digest).map_err(|_| TEE_ERROR_BAD_STATE)?;
+ Ok(())
+}
+
/// read the data from the storage
///
/// # Arguments
diff --git a/api/kapi/src/tee/mod.rs b/api/kapi/src/tee/mod.rs
index 923d68e9..951d4c35 100644
--- a/api/kapi/src/tee/mod.rs
+++ b/api/kapi/src/tee/mod.rs
@@ -58,7 +58,6 @@ mod bitstring;
mod common;
mod config;
mod crypto;
-mod crypto_temp;
mod fs_dirfile;
mod fs_htree;
#[cfg(feature = "tee_test")]
diff --git a/api/kapi/src/tee/tee_fs_key_manager.rs b/api/kapi/src/tee/tee_fs_key_manager.rs
index 149cbb62..918a9ff6 100644
--- a/api/kapi/src/tee/tee_fs_key_manager.rs
+++ b/api/kapi/src/tee/tee_fs_key_manager.rs
@@ -8,7 +8,12 @@ use core::mem::size_of;
use cfg_if::cfg_if;
use ksync::Mutex;
use lazy_static::lazy_static;
-use mbedtls::hash;
+use mbedtls::{
+ cipher,
+ cipher::raw::{Cipher, CipherId, CipherMode, Operation},
+ hash,
+ hash::Type,
+};
use static_assertions::const_assert;
use tee_raw_sys::{
TEE_ALG_AES_ECB_NOPAD, TEE_ALG_HMAC_SHA256, TEE_ALG_HMAC_SM3, TEE_ALG_SM4_ECB_NOPAD,
@@ -21,11 +26,7 @@ use super::{
huk_subkey::{HUK_SUBKEY_MAX_LEN, HukSubkeyUsage, huk_subkey_derive},
otp_stubs::{TeeHwUniqueKey, tee_otp_get_hw_unique_key},
utee_defines::{TEE_SHA256_HASH_SIZE, TEE_SM3_HASH_SIZE, TeeAlg},
-};
-use crate::tee::crypto_temp::{
- aes_ecb::MbedAesEcbCtx,
- crypto_hash_temp::{CryptoCipherCtx, CryptoCipherOps, tee_alg_to_hmac_type},
- sm4_ecb::MbedSm4EcbCtx,
+ utils::slice_fmt,
};
const TEE_FS_KM_CHIP_ID_LENGTH: usize = 32;
@@ -82,17 +83,58 @@ lazy_static! {
static ref TEE_FS_SSK: Mutex = Mutex::new(init_ssk());
}
-pub fn crypto_cipher_alloc_ctx(algo: TeeAlg) -> Result, TeeResult> {
- match algo {
- TEE_ALG_AES_ECB_NOPAD => {
- let ctx: MbedAesEcbCtx = *MbedAesEcbCtx::alloc_cipher_ctx()?;
- Ok(Box::new(ctx))
- }
- TEE_ALG_SM4_ECB_NOPAD => {
- let ctx: MbedSm4EcbCtx = *MbedSm4EcbCtx::alloc_cipher_ctx()?;
- Ok(Box::new(ctx))
- }
- _ => Err(Err(TEE_ERROR_NOT_IMPLEMENTED)),
+pub fn crypto_cipher_ecb_nopad(
+ algo: TeeAlg,
+ mode: TEE_OperationMode,
+ key: &[u8],
+ input: &[u8],
+ output: &mut [u8],
+) -> TeeResult {
+ debug_assert!(key.len() >= 16);
+
+ let (cipher_id, key_bytes) = match algo {
+ TEE_ALG_AES_ECB_NOPAD => (CipherId::Aes, key.len()),
+ TEE_ALG_SM4_ECB_NOPAD => (CipherId::SM4, 16),
+ _ => return Err(TEE_ERROR_NOT_IMPLEMENTED),
+ };
+
+ // 根据模式确定操作类型
+ let operation = match mode {
+ TEE_OperationMode::TEE_MODE_ENCRYPT => Operation::Encrypt,
+ TEE_OperationMode::TEE_MODE_DECRYPT => Operation::Decrypt,
+ _ => return Err(TEE_ERROR_BAD_PARAMETERS),
+ };
+
+ // 使用 raw 接口创建 Cipher 实例
+ let mut cipher_ctx = Cipher::setup(cipher_id, CipherMode::ECB, (key_bytes * 8) as u32)
+ .map_err(|_| TEE_ERROR_BAD_PARAMETERS)?;
+
+ // 设置密钥
+ cipher_ctx
+ .set_key(operation, &key[..key_bytes])
+ .map_err(|_| TEE_ERROR_BAD_PARAMETERS)?;
+
+ // 根据模式执行加密或解密
+ let _len = match mode {
+ TEE_OperationMode::TEE_MODE_ENCRYPT => cipher_ctx.encrypt(input, output),
+ TEE_OperationMode::TEE_MODE_DECRYPT => cipher_ctx.decrypt(input, output),
+ _ => return Err(TEE_ERROR_BAD_PARAMETERS),
+ }
+ .map_err(|_| TEE_ERROR_BAD_PARAMETERS)?;
+
+ Ok(())
+}
+
+/// Convert TeeAlg to mbedtls::hash::Type
+/// This is a helper function instead of TryFrom implementation due to Rust's orphan rule
+fn tee_alg_to_hmac_type(value: TeeAlg) -> TeeResult {
+ match value {
+ TEE_ALG_HMAC_MD5 => Ok(Type::Md5),
+ TEE_ALG_HMAC_SHA1 => Ok(Type::Sha1),
+ TEE_ALG_HMAC_SHA256 => Ok(Type::Sha256),
+ TEE_ALG_HMAC_SHA512 => Ok(Type::Sha512),
+ TEE_ALG_HMAC_SM3 => Ok(Type::SM3),
+ _ => Err(TEE_ERROR_NOT_IMPLEMENTED),
}
}
@@ -171,27 +213,78 @@ pub fn tee_fs_fek_crypt(
let dummy = [0u8, 1];
do_hmac(&mut tsk, ssk_key_slice, &dummy)?;
}
- match crypto_cipher_alloc_ctx(TEE_FS_KM_ENC_FEK_ALG) {
- Ok(mut ctx) => {
- ctx.init(mode, Some(&tsk), None, None).inspect_err(|_| {
- error!("tee_fs_fek_crypt: ctx.init failed");
- })?;
- ctx.update(true, Some(in_key_slice), Some(&mut dst_key))
- .inspect_err(|_| {
- error!("tee_fs_fek_crypt: ctx.update failed");
- })?;
- ctx.finalize();
- if let Some(out_key) = out_key {
- out_key.copy_from_slice(&dst_key);
- tee_debug!(
- "tee_fs_fek_crypt: in_key: {:?}, out_key: {:?}",
- hex::encode(in_key_slice),
- hex::encode(out_key)
- );
- }
- }
- Err(e) => return e,
- };
+
+ // 使用 crypto_cipher_ecb_nopad 函数进行加密或解密
+ crypto_cipher_ecb_nopad(
+ TEE_FS_KM_ENC_FEK_ALG,
+ mode,
+ &tsk,
+ in_key_slice,
+ &mut dst_key,
+ )
+ .inspect_err(|e| {
+ error!("tee_fs_fek_crypt: crypto_cipher_ecb_nopad failed: {:X?}", e);
+ })?;
+
+ if let Some(out_key) = out_key {
+ out_key.copy_from_slice(&dst_key);
+ tee_debug!(
+ "tee_fs_fek_crypt: in_key: {:?}, out_key: {:?}",
+ hex::encode(in_key_slice),
+ hex::encode(out_key)
+ );
+ }
Ok(())
}
+
+#[cfg(feature = "tee_test")]
+pub mod tests_tee_fs_key_manager {
+ use unittest::{
+ test_fn, test_framework::TestDescriptor, test_framework_basic::TestResult, tests_name,
+ };
+
+ use super::*;
+ use crate::tee::utils::slice_fmt;
+
+ test_fn! {
+ using TestResult;
+
+ fn test_crypto_cipher_encrypt() {
+ // aes encrypt
+ let algo = TEE_ALG_AES_ECB_NOPAD;
+ let key = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10];
+ let plain = [0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20];
+ let mut cipher = [0u8; 16];
+ let result = crypto_cipher_ecb_nopad(algo, TEE_OperationMode::TEE_MODE_ENCRYPT, &key, &plain, &mut cipher);
+ tee_debug!("test_crypto_cipher_encrypt: key: {:?}, plain: {:?}, cipher: {:?}", slice_fmt(&key), slice_fmt(&plain), slice_fmt(&cipher));
+ assert!(result.is_ok());
+ assert_eq!("D721A0F194231822F398706DD1FFF2B7", hex::encode_upper(&cipher));
+
+ // aes decrypt
+ let mut decrypted = [0u8; 16];
+ let result = crypto_cipher_ecb_nopad(algo, TEE_OperationMode::TEE_MODE_DECRYPT, &key, &cipher, &mut decrypted);
+ assert!(result.is_ok());
+ assert_eq!(plain, decrypted);
+
+ // sm4 encrypt
+ let algo = TEE_ALG_SM4_ECB_NOPAD;
+ let result = crypto_cipher_ecb_nopad(algo, TEE_OperationMode::TEE_MODE_ENCRYPT, &key, &plain, &mut cipher);
+ tee_debug!("test_crypto_cipher_encrypt: key: {:?}, plain: {:?}, cipher: {:?}", slice_fmt(&key), slice_fmt(&plain), slice_fmt(&cipher));
+ assert!(result.is_ok());
+ assert_eq!("4329A6241E39AD7A9A404A814A7EDD32", hex::encode_upper(&cipher));
+
+ // sm4 decrypt
+ let result = crypto_cipher_ecb_nopad(algo, TEE_OperationMode::TEE_MODE_DECRYPT, &key, &cipher, &mut decrypted);
+ assert!(result.is_ok());
+ assert_eq!(plain, decrypted);
+ }
+ }
+
+ tests_name! {
+ TEST_TEE_FS_KEY_MANAGER;
+ tee_fs_key_manager;
+ //------------------------
+ test_crypto_cipher_encrypt,
+ }
+}
diff --git a/api/kapi/src/tee/tee_svc_cryp2.rs b/api/kapi/src/tee/tee_svc_cryp2.rs
index c5e23b14..412b82d4 100644
--- a/api/kapi/src/tee/tee_svc_cryp2.rs
+++ b/api/kapi/src/tee/tee_svc_cryp2.rs
@@ -1078,7 +1078,7 @@ pub fn syscall_authenc_init(
_arg5: usize,
) -> TeeResult {
let nonce_ptr = arg1 as *const u8;
- let nonce_len = arg2 as usize;
+ let nonce_len = arg2;
let nonce_slice = unsafe { core::slice::from_raw_parts(nonce_ptr, nonce_len) };
let nonce = bb_memdup_user(nonce_slice)?;
@@ -1107,7 +1107,7 @@ pub fn tee_cryp_authenc_update_aad(id: u32, aad: &[u8]) -> TeeResult {
pub fn syscall_authenc_update_aad(arg0: usize, arg1: usize, arg2: usize) -> TeeResult {
let aad_ptr = arg1 as *const u8;
- let aad_len = arg2 as usize;
+ let aad_len = arg2;
let aad_slice = unsafe { core::slice::from_raw_parts(aad_ptr, aad_len) };
let aad = bb_memdup_user(aad_slice)?;
@@ -1164,7 +1164,7 @@ pub fn syscall_authenc_enc_final(
arg6: usize,
) -> TeeResult {
let src_ptr = arg1 as *const u8;
- let src_len = arg2 as usize;
+ let src_len = arg2;
// 输入的dst_len长度应该为缓冲区长度,最后函数返回值为实际长度
let dst_ptr = arg3 as *mut u8;
@@ -1244,7 +1244,7 @@ pub fn syscall_authenc_dec_final(
arg6: usize,
) -> TeeResult {
let src_ptr = arg1 as *const u8;
- let src_len = arg2 as usize;
+ let src_len = arg2;
// 输入的dst_len长度应该为缓冲区长度,最后函数返回值为实际长度
let dst_ptr = arg3 as *mut u8;
@@ -1267,7 +1267,7 @@ pub fn syscall_authenc_dec_final(
let mut dst = bb_memdup_user(dst_slice)?;
let tag_ptr = arg5 as *const u8;
- let mut tag_len = arg6 as usize;
+ let mut tag_len = arg6;
if tag_ptr.is_null() || tag_len == 0 {
return Err(TEE_ERROR_BAD_PARAMETERS);
@@ -1380,7 +1380,7 @@ pub fn syscall_asymm_operate(
arg6: usize,
) -> TeeResult {
let src_ptr = arg3 as *const u8;
- let src_len = arg4 as usize;
+ let src_len = arg4;
// 输入的dst_len长度应该为缓冲区长度,最后函数返回值为实际长度
let dst_ptr = arg5 as *mut u8;
@@ -1460,10 +1460,10 @@ pub fn syscall_asymm_verify(
arg6: usize,
) -> TeeResult {
let data_ptr = arg3 as *const u8;
- let data_len = arg4 as usize;
+ let data_len = arg4;
let sig_ptr = arg5 as *mut u8;
- let mut sig_len = arg6 as usize;
+ let mut sig_len = arg6;
let data = if data_ptr.is_null() || data_len == 0 {
return Err(TEE_ERROR_BAD_PARAMETERS);
@@ -1478,7 +1478,7 @@ pub fn syscall_asymm_verify(
let sig_slice = unsafe { core::slice::from_raw_parts_mut(sig_ptr, sig_len) };
let mut sig = bb_memdup_user(sig_slice)?;
- tee_cryp_asymm_verify(arg0 as _, &data, &mut sig)?;
+ tee_cryp_asymm_verify(arg0 as _, &data, &sig)?;
// Copy to user
unsafe { copy_to_user(sig_slice, &sig, sig_len * size_of::())? };
diff --git a/api/kapi/src/tee/test_unit_test.rs b/api/kapi/src/tee/test_unit_test.rs
index 93d15156..7299a0f5 100644
--- a/api/kapi/src/tee/test_unit_test.rs
+++ b/api/kapi/src/tee/test_unit_test.rs
@@ -15,14 +15,14 @@ use crate::tee::arch::x86_64::hygon_csv::tests_hygon_csv_get_sealing_key::TEST_H
use crate::tee::{
bitstring::tests_bitstring::TEST_BITSTRING, common::file_ops::tests_file_ops::TEST_FILE_OPS,
crypto::crypto_impl::tests_tee_crypto_impl::TEST_TEE_CRYPTO_IMPL,
- crypto_temp::aes_ecb::tests_aes_ecb::TEST_TEE_AES_ECB,
fs_dirfile::tests_tee_fs_dirfile::TEST_TEE_FS_DIRFILE, fs_htree::tests_fs_htree::TEST_FS_HTREE,
fs_htree_tests::tests_fs_htree_tests::TEST_FS_HTREE_TESTS,
huk_subkey::tests_huk_subkey::TEST_HUK_SUBKEY_DERIVE,
libmbedtls::bignum::tests_tee_bignum::TEST_TEE_BIGNUM,
- rng_software::tests_rng_software::TEST_RNG_SOFTWARE, tee_misc::tests_tee_misc::TEST_TEE_MISC,
- tee_obj::tests_tee_obj::TEST_TEE_OBJ, tee_pobj::tests_tee_pobj::TEST_TEE_POBJ,
- tee_ree_fs::tests_tee_ree_fs::TEST_TEE_REE_FS,
+ rng_software::tests_rng_software::TEST_RNG_SOFTWARE,
+ tee_fs_key_manager::tests_tee_fs_key_manager::TEST_TEE_FS_KEY_MANAGER,
+ tee_misc::tests_tee_misc::TEST_TEE_MISC, tee_obj::tests_tee_obj::TEST_TEE_OBJ,
+ tee_pobj::tests_tee_pobj::TEST_TEE_POBJ, tee_ree_fs::tests_tee_ree_fs::TEST_TEE_REE_FS,
tee_session::tests_tee_session::TEST_TEE_SESSION,
tee_svc_cryp::tests_tee_svc_cryp::TEST_TEE_SVC_CRYP, tee_svc_cryp2::tests_cryp::TEST_TEE_CRYP,
tee_svc_storage::tests_tee_svc_storage::TEST_TEE_SVC_STORAGE,
@@ -55,8 +55,8 @@ pub fn tee_unit_test() {
TEST_FS_HTREE_TESTS,
TEST_RNG_SOFTWARE,
TEST_TEE_CRYPTO_IMPL,
- TEST_TEE_AES_ECB,
TEST_TEE_CRYP,
+ TEST_TEE_FS_KEY_MANAGER,
]
);
#[cfg(all(target_arch = "x86_64", feature = "x86_csv", feature = "tee_test"))]
diff --git a/arch/karch/Cargo.toml b/arch/karch/Cargo.toml
new file mode 100644
index 00000000..e98c5b45
--- /dev/null
+++ b/arch/karch/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "karch"
+description = "Lightweight architecture-specific low-level operations (TLB flush, cache maintenance, CPU halt, interrupt management, thread pointer access)"
+version.workspace = true
+edition.workspace = true
+authors.workspace = true
+license.workspace = true
+homepage.workspace = true
+repository.workspace = true
+
+[features]
+default = []
+arm-el2 = []
+
+[dependencies]
+cfg-if = "1.0"
+memaddr = { workspace = true }
+
+[target.'cfg(target_arch = "x86_64")'.dependencies]
+x86 = "0.52"
+x86_64 = { workspace = true }
+
+[target.'cfg(target_arch = "aarch64")'.dependencies]
+aarch64-cpu = "10.0"
+
+[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
+riscv = "0.14"
+
+[target.'cfg(target_arch = "loongarch64")'.dependencies]
+loongArch64 = "0.2.4"
+
+[package.metadata.docs.rs]
+all-features = true
+targets = [
+ "x86_64-unknown-none",
+ "aarch64-unknown-none-softfloat",
+ "riscv64gc-unknown-none-elf",
+ "loongarch64-unknown-none-softfloat",
+]
diff --git a/arch/karch/README.md b/arch/karch/README.md
new file mode 100644
index 00000000..f16afce0
--- /dev/null
+++ b/arch/karch/README.md
@@ -0,0 +1,46 @@
+# karch
+
+Lightweight architecture-specific low-level operations for the x-kernel project.
+
+This crate provides a uniform API across all supported architectures (AArch64, x86_64, RISC-V, LoongArch64, ARM) for:
+
+- **TLB flush**: `flush_tlb(vaddr: Option)`
+- **Cache maintenance** (AArch64): `flush_icache_all()`, `flush_dcache_line(vaddr)`
+- **CPU control**: `stop_cpu()`, `await_interrupts()`
+- **Local interrupt management**:
+ - `enable_local_irq()`, `disable_local_irq()`, `local_irq_enabled()`
+ - `save_irq_and_disable() -> usize` — atomically save interrupt state and disable local interrupts
+ - `restore_irq(flags: usize)` — restore previously saved interrupt state
+- **Thread pointer (TLS)**: `read_thread_pointer()`, `write_thread_pointer(val)`
+- **FP/SIMD enable** (AArch64, LoongArch64): `enable_fp()`
+- **LSX extension** (LoongArch64): `enable_lsx()`
+- **MMU / Page table root**:
+ - `read_kernel_page_table() -> PhysAddr`
+ - `read_user_page_table() -> PhysAddr`
+ - `unsafe fn write_kernel_page_table(root_paddr: PhysAddr)`
+ - `unsafe fn write_user_page_table(root_paddr: PhysAddr)`
+- **Trap / exception vector** (AArch64, RISC-V, LoongArch64):
+ - `unsafe fn write_trap_vector_base(addr: usize)`
+- **Hypercall** (x86_64): `fn hypercall(nr: u64, a0: u64, a1: u64) -> i64`
+- **Page walk controller** (LoongArch64): `unsafe fn write_pwc(pwcl: u32, pwch: u32)`
+
+## Deprecated names
+
+The following names are deprecated and will be removed in a future release. Use the replacements shown:
+
+| Deprecated | Replacement |
+|---|---|
+| `enable_irq()` | `enable_local_irq()` |
+| `disable_irq()` | `disable_local_irq()` |
+| `irq_enabled()` | `local_irq_enabled()` |
+
+## Design
+
+`karch` is intentionally kept lightweight: it only depends on `memaddr`, `cfg-if`, and
+architecture-specific register libraries (`aarch64-cpu`, `x86`/`x86_64`, `riscv`,
+`loongArch64`). It has **no** OS-level dependencies, making it suitable as a low-level
+building block for other crates.
+
+## Features
+
+- `arm-el2`: Enable AArch64 EL2 (hypervisor) variants of TLB flush, page table root, and trap vector operations.
diff --git a/arch/karch/src/aarch64/cache.rs b/arch/karch/src/aarch64/cache.rs
new file mode 100644
index 00000000..1427e119
--- /dev/null
+++ b/arch/karch/src/aarch64/cache.rs
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Cache maintenance operations for AArch64.
+
+use core::arch::asm;
+
+use memaddr::VirtAddr;
+
+/// Flushes the entire instruction cache.
+#[inline]
+pub fn flush_icache_all() {
+ unsafe { asm!("ic iallu; dsb sy; isb") };
+}
+
+/// Flushes the data cache line at the given virtual address.
+///
+/// Uses the `DC IVAC` instruction (Data Cache Invalidate by Virtual Address to
+/// Point of Coherency). The cache line size is implementation-defined; 64 bytes
+/// is typical for AArch64 but may vary across CPU implementations.
+#[inline]
+pub fn flush_dcache_line(vaddr: VirtAddr) {
+ unsafe { asm!("dc ivac, {0:x}; dsb sy; isb", in(reg) vaddr.as_usize()) };
+}
diff --git a/arch/karch/src/aarch64/cpu.rs b/arch/karch/src/aarch64/cpu.rs
new file mode 100644
index 00000000..a015cc8d
--- /dev/null
+++ b/arch/karch/src/aarch64/cpu.rs
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! CPU control operations for AArch64.
+
+use super::irq::disable_local_irq;
+
+/// Halt the current CPU.
+///
+/// Disables interrupts then executes WFI. Since interrupts are disabled,
+/// this should stop execution until reset.
+#[inline]
+pub fn stop_cpu() {
+ disable_local_irq();
+ aarch64_cpu::asm::wfi();
+}
+
+/// Relaxes the current CPU and waits for interrupts.
+///
+/// It must be called with interrupts enabled, otherwise it will never return.
+#[inline]
+pub fn await_interrupts() {
+ aarch64_cpu::asm::wfi();
+}
diff --git a/arch/karch/src/aarch64/fp.rs b/arch/karch/src/aarch64/fp.rs
new file mode 100644
index 00000000..28bb09ca
--- /dev/null
+++ b/arch/karch/src/aarch64/fp.rs
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Floating-point/SIMD operations for AArch64.
+
+use aarch64_cpu::{
+ asm::barrier,
+ registers::{CPACR_EL1, Writeable},
+};
+
+/// Enable FP/SIMD instructions by setting the `FPEN` field in `CPACR_EL1`.
+#[inline]
+pub fn enable_fp() {
+ CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
+ barrier::isb(barrier::SY);
+}
diff --git a/arch/karch/src/aarch64/irq.rs b/arch/karch/src/aarch64/irq.rs
new file mode 100644
index 00000000..d4bdb2ac
--- /dev/null
+++ b/arch/karch/src/aarch64/irq.rs
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Interrupt control operations for AArch64.
+
+use core::arch::asm;
+
+use aarch64_cpu::registers::{DAIF, Readable, Writeable};
+
+/// Allows the current CPU to respond to interrupts (clears DAIF.I).
+#[inline]
+pub fn enable_local_irq() {
+ DAIF.write(DAIF::I::Unmasked);
+}
+
+/// Makes the current CPU ignore interrupts (sets DAIF.I).
+#[inline]
+pub fn disable_local_irq() {
+ DAIF.write(DAIF::I::Masked);
+}
+
+/// Returns whether the current CPU is allowed to respond to interrupts.
+#[inline]
+pub fn local_irq_enabled() -> bool {
+ !DAIF.is_set(DAIF::I)
+}
+
+/// Deprecated: use [`enable_local_irq`] instead.
+#[deprecated(note = "Use `enable_local_irq` instead")]
+#[inline]
+pub fn enable_irq() {
+ enable_local_irq()
+}
+
+/// Deprecated: use [`disable_local_irq`] instead.
+#[deprecated(note = "Use `disable_local_irq` instead")]
+#[inline]
+pub fn disable_irq() {
+ disable_local_irq()
+}
+
+/// Deprecated: use [`local_irq_enabled`] instead.
+#[deprecated(note = "Use `local_irq_enabled` instead")]
+#[inline]
+pub fn irq_enabled() -> bool {
+ local_irq_enabled()
+}
+
+/// Saves the current local interrupt state and disables interrupts atomically.
+///
+/// Returns the saved DAIF register value. Pass it to [`restore_irq`] to
+/// restore the previous interrupt state.
+#[inline]
+pub fn save_irq_and_disable() -> usize {
+ let flags: usize;
+ unsafe {
+ asm!("mrs {}, daif", out(reg) flags, options(nomem, nostack, preserves_flags));
+ asm!("msr daifset, #2", options(nomem, nostack));
+ }
+ flags
+}
+
+/// Restores local interrupt state from a value previously returned by
+/// [`save_irq_and_disable`].
+#[inline]
+pub fn restore_irq(flags: usize) {
+ unsafe {
+ asm!("msr daif, {}", in(reg) flags, options(nomem, nostack));
+ }
+}
diff --git a/arch/karch/src/aarch64/mmu.rs b/arch/karch/src/aarch64/mmu.rs
new file mode 100644
index 00000000..ff075984
--- /dev/null
+++ b/arch/karch/src/aarch64/mmu.rs
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! MMU/page table operations for AArch64.
+
+use aarch64_cpu::registers::{Readable, TTBR0_EL1, TTBR1_EL1, Writeable};
+use memaddr::PhysAddr;
+
+/// Reads the current page table root register for kernel space.
+///
+/// When the `arm-el2` feature is enabled, reads `TTBR0_EL2`; otherwise
+/// reads `TTBR1_EL1`.
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_kernel_page_table() -> PhysAddr {
+ let pt_root_reg: usize;
+
+ #[cfg(not(feature = "arm-el2"))]
+ {
+ pt_root_reg = TTBR1_EL1.get() as usize;
+ }
+
+ #[cfg(feature = "arm-el2")]
+ {
+ use aarch64_cpu::registers::TTBR0_EL2;
+ pt_root_reg = TTBR0_EL2.get() as usize;
+ }
+
+ PhysAddr::from(pt_root_reg)
+}
+
+/// Reads the current page table root register for user space (`TTBR0_EL1`).
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_user_page_table() -> PhysAddr {
+ let val = TTBR0_EL1.get();
+ PhysAddr::from(val as usize)
+}
+
+/// Writes the register to update the current page table root for kernel space.
+///
+/// When the `arm-el2` feature is enabled, writes `TTBR0_EL2`; otherwise
+/// writes `TTBR1_EL1`.
+///
+/// Note that the TLB is **NOT** flushed after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
+ #[cfg(not(feature = "arm-el2"))]
+ {
+ TTBR1_EL1.set(root_paddr.as_usize() as _);
+ }
+
+ #[cfg(feature = "arm-el2")]
+ {
+ use aarch64_cpu::registers::TTBR0_EL2;
+ TTBR0_EL2.set(root_paddr.as_usize() as _);
+ }
+}
+
+/// Writes the register to update the current page table root for user space
+/// (`TTBR0_EL1`).
+///
+/// Note that the TLB is **NOT** flushed after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
+ TTBR0_EL1.set(root_paddr.as_usize() as _);
+}
diff --git a/arch/karch/src/aarch64/mod.rs b/arch/karch/src/aarch64/mod.rs
new file mode 100644
index 00000000..1500ac7f
--- /dev/null
+++ b/arch/karch/src/aarch64/mod.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! AArch64 low-level architecture operations.
+
+mod cache;
+mod cpu;
+mod fp;
+mod irq;
+mod mmu;
+mod tlb;
+mod tls;
+mod trap;
+
+pub use cache::{flush_dcache_line, flush_icache_all};
+pub use cpu::{await_interrupts, stop_cpu};
+pub use fp::enable_fp;
+#[allow(deprecated)]
+pub use irq::{
+ disable_irq, disable_local_irq, enable_irq, enable_local_irq, irq_enabled, local_irq_enabled,
+ restore_irq, save_irq_and_disable,
+};
+pub use mmu::{
+ read_kernel_page_table, read_user_page_table, write_kernel_page_table, write_user_page_table,
+};
+pub use tlb::flush_tlb;
+pub use tls::{read_thread_pointer, write_thread_pointer};
+pub use trap::write_trap_vector_base;
diff --git a/arch/karch/src/aarch64/tlb.rs b/arch/karch/src/aarch64/tlb.rs
new file mode 100644
index 00000000..1c4f42be
--- /dev/null
+++ b/arch/karch/src/aarch64/tlb.rs
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! TLB maintenance operations for AArch64.
+
+use core::arch::asm;
+
+use memaddr::VirtAddr;
+
+/// Flushes the TLB.
+///
+/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
+/// entry that maps the given virtual address.
+#[inline]
+pub fn flush_tlb(vaddr: Option) {
+ if let Some(vaddr) = vaddr {
+ const VA_MASK: usize = (1 << 44) - 1; // VA[55:12] => bits[43:0]
+ let operand = (vaddr.as_usize() >> 12) & VA_MASK;
+
+ #[cfg(not(feature = "arm-el2"))]
+ unsafe {
+ // TLB Invalidate by VA, All ASID, EL1, Inner Shareable
+ asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) operand)
+ }
+ #[cfg(feature = "arm-el2")]
+ unsafe {
+ // TLB Invalidate by VA, EL2, Inner Shareable
+ asm!("tlbi vae2is, {}; dsb sy; isb", in(reg) operand)
+ }
+ } else {
+ // flush the entire TLB
+ #[cfg(not(feature = "arm-el2"))]
+ unsafe {
+ // TLB Invalidate by VMID, All at stage 1, EL1
+ asm!("dsb sy; isb; tlbi vmalle1; dsb sy; isb")
+ }
+ #[cfg(feature = "arm-el2")]
+ unsafe {
+ // TLB Invalidate All, EL2
+ asm!("tlbi alle2; dsb sy; isb")
+ }
+ }
+}
diff --git a/arch/karch/src/aarch64/tls.rs b/arch/karch/src/aarch64/tls.rs
new file mode 100644
index 00000000..3338ba52
--- /dev/null
+++ b/arch/karch/src/aarch64/tls.rs
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Thread-local storage operations for AArch64.
+
+use aarch64_cpu::registers::{Readable, TPIDR_EL0, Writeable};
+
+/// Reads the thread pointer of the current CPU (`TPIDR_EL0`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+#[inline]
+pub fn read_thread_pointer() -> usize {
+ TPIDR_EL0.get() as usize
+}
+
+/// Writes the thread pointer of the current CPU (`TPIDR_EL0`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the current CPU states.
+#[inline]
+pub unsafe fn write_thread_pointer(val: usize) {
+ TPIDR_EL0.set(val as _)
+}
diff --git a/arch/karch/src/aarch64/trap.rs b/arch/karch/src/aarch64/trap.rs
new file mode 100644
index 00000000..d1dbca68
--- /dev/null
+++ b/arch/karch/src/aarch64/trap.rs
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Exception/trap vector operations for AArch64.
+
+use aarch64_cpu::registers::Writeable;
+
+/// Writes the exception vector base address register (`VBAR_EL1` or `VBAR_EL2`).
+///
+/// When the `arm-el2` feature is enabled, writes `VBAR_EL2`; otherwise
+/// writes `VBAR_EL1`.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the exception handling behavior of the
+/// current CPU.
+#[inline]
+pub unsafe fn write_trap_vector_base(addr: usize) {
+ #[cfg(not(feature = "arm-el2"))]
+ {
+ use aarch64_cpu::registers::VBAR_EL1;
+ VBAR_EL1.set(addr as _);
+ }
+ #[cfg(feature = "arm-el2")]
+ {
+ use aarch64_cpu::registers::VBAR_EL2;
+ VBAR_EL2.set(addr as _);
+ }
+}
diff --git a/arch/karch/src/arm/irq.rs b/arch/karch/src/arm/irq.rs
new file mode 100644
index 00000000..95b6cd62
--- /dev/null
+++ b/arch/karch/src/arm/irq.rs
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Interrupt control operations for ARM.
+
+use core::arch::asm;
+
+/// Interrupt Disable bit (bit 7) in CPSR.
+const IRQ_DISABLE_BIT: usize = 1 << 7;
+
+/// Saves the current local interrupt state and disables interrupts atomically.
+///
+/// Returns the saved CPSR value with the IRQ disable bit. Pass it to
+/// [`restore_irq`] to restore the previous interrupt state.
+#[inline]
+pub fn save_irq_and_disable() -> usize {
+ let flags: usize;
+ unsafe {
+ asm!(
+ "mrs {0}, cpsr",
+ "cpsid i",
+ out(reg) flags,
+ options(nomem, nostack, preserves_flags)
+ );
+ }
+ flags & IRQ_DISABLE_BIT
+}
+
+/// Restores local interrupt state from a value previously returned by
+/// [`save_irq_and_disable`].
+///
+/// In ARM CPSR, bit 7 = 0 means IRQs enabled, bit 7 = 1 means IRQs disabled.
+/// If the saved flags had bit 7 clear (IRQs were enabled), re-enable them.
+#[inline]
+pub fn restore_irq(flags: usize) {
+ if flags & IRQ_DISABLE_BIT == 0 {
+ // IRQ_DISABLE_BIT was clear in saved flags → IRQs were enabled before; re-enable them.
+ unsafe {
+ asm!("cpsie i", options(nomem, nostack));
+ }
+ }
+ // If IRQ_DISABLE_BIT was set → IRQs were already disabled; leave them disabled.
+}
diff --git a/arch/karch/src/arm/mod.rs b/arch/karch/src/arm/mod.rs
new file mode 100644
index 00000000..eca897f0
--- /dev/null
+++ b/arch/karch/src/arm/mod.rs
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! ARM low-level architecture operations.
+
+mod irq;
+
+pub use irq::{restore_irq, save_irq_and_disable};
diff --git a/arch/karch/src/lib.rs b/arch/karch/src/lib.rs
new file mode 100644
index 00000000..b18d8544
--- /dev/null
+++ b/arch/karch/src/lib.rs
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Lightweight architecture-specific low-level operations.
+//!
+//! This crate provides a uniform API across all supported architectures for
+//! TLB flush, cache maintenance, CPU halt, interrupt management, thread pointer
+//! access, and FP/SIMD enable operations.
+#![doc = include_str!("../README.md")]
+#![no_std]
+
+cfg_if::cfg_if! {
+ if #[cfg(target_arch = "x86_64")] {
+ mod x86_64;
+ pub use self::x86_64::*;
+ } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
+ mod riscv;
+ pub use self::riscv::*;
+ } else if #[cfg(target_arch = "aarch64")] {
+ mod aarch64;
+ pub use self::aarch64::*;
+ } else if #[cfg(target_arch = "loongarch64")] {
+ mod loongarch64;
+ pub use self::loongarch64::*;
+ } else if #[cfg(target_arch = "arm")] {
+ mod arm;
+ pub use self::arm::*;
+ }
+}
diff --git a/arch/karch/src/loongarch64/cpu.rs b/arch/karch/src/loongarch64/cpu.rs
new file mode 100644
index 00000000..700ffa80
--- /dev/null
+++ b/arch/karch/src/loongarch64/cpu.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! CPU control operations for LoongArch64.
+
+use super::irq::disable_local_irq;
+
+/// Halt the current CPU.
+#[inline]
+pub fn stop_cpu() {
+ disable_local_irq();
+ unsafe { loongArch64::asm::idle() }
+}
+
+/// Relaxes the current CPU and waits for interrupts.
+///
+/// It must be called with interrupts enabled, otherwise it will never return.
+#[inline]
+pub fn await_interrupts() {
+ unsafe { loongArch64::asm::idle() }
+}
diff --git a/arch/karch/src/loongarch64/fp.rs b/arch/karch/src/loongarch64/fp.rs
new file mode 100644
index 00000000..dc614866
--- /dev/null
+++ b/arch/karch/src/loongarch64/fp.rs
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Floating-point/SIMD operations for LoongArch64.
+
+/// Enables floating-point instructions by setting `EUEN.FPE`.
+///
+/// - `EUEN`:
+#[inline]
+pub fn enable_fp() {
+ loongArch64::register::euen::set_fpe(true);
+}
+
+/// Enables LSX extension by setting `EUEN.LSX`.
+///
+/// - `EUEN`:
+#[inline]
+pub fn enable_lsx() {
+ loongArch64::register::euen::set_sxe(true);
+}
diff --git a/arch/karch/src/loongarch64/irq.rs b/arch/karch/src/loongarch64/irq.rs
new file mode 100644
index 00000000..26dd3fe1
--- /dev/null
+++ b/arch/karch/src/loongarch64/irq.rs
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Interrupt control operations for LoongArch64.
+
+use core::arch::asm;
+
+use loongArch64::register::crmd;
+
+/// Allows the current CPU to respond to interrupts.
+#[inline]
+pub fn enable_local_irq() {
+ crmd::set_ie(true)
+}
+
+/// Makes the current CPU ignore interrupts.
+#[inline]
+pub fn disable_local_irq() {
+ crmd::set_ie(false)
+}
+
+/// Returns whether the current CPU is allowed to respond to interrupts.
+#[inline]
+pub fn local_irq_enabled() -> bool {
+ crmd::read().ie()
+}
+
+/// Deprecated: use [`enable_local_irq`] instead.
+#[deprecated(note = "Use `enable_local_irq` instead")]
+#[inline]
+pub fn enable_irq() {
+ enable_local_irq()
+}
+
+/// Deprecated: use [`disable_local_irq`] instead.
+#[deprecated(note = "Use `disable_local_irq` instead")]
+#[inline]
+pub fn disable_irq() {
+ disable_local_irq()
+}
+
+/// Deprecated: use [`local_irq_enabled`] instead.
+#[deprecated(note = "Use `local_irq_enabled` instead")]
+#[inline]
+pub fn irq_enabled() -> bool {
+ local_irq_enabled()
+}
+
+/// Saves the current local interrupt state and disables interrupts atomically.
+///
+/// Returns the saved CRMD value with the IE bit. Pass it to [`restore_irq`]
+/// to restore the previous interrupt state.
+#[inline]
+pub fn save_irq_and_disable() -> usize {
+ /// Interrupt Enable bit mask in CRMD.
+ const IE_MASK: usize = 1 << 2;
+ let mut flags: usize = 0;
+ // csrxchg atomically reads CRMD and clears the IE bit
+ unsafe { asm!("csrxchg {}, {}, 0x0", inout(reg) flags, in(reg) IE_MASK) };
+ flags & IE_MASK
+}
+
+/// Restores local interrupt state from a value previously returned by
+/// [`save_irq_and_disable`].
+#[inline]
+pub fn restore_irq(flags: usize) {
+ /// Interrupt Enable bit mask in CRMD.
+ const IE_MASK: usize = 1 << 2;
+ // csrxchg atomically restores the IE bit
+ unsafe { asm!("csrxchg {}, {}, 0x0", in(reg) flags, in(reg) IE_MASK) };
+}
diff --git a/arch/karch/src/loongarch64/mmu.rs b/arch/karch/src/loongarch64/mmu.rs
new file mode 100644
index 00000000..03eebdf8
--- /dev/null
+++ b/arch/karch/src/loongarch64/mmu.rs
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! MMU/page table operations for LoongArch64.
+
+use core::arch::asm;
+
+use loongArch64::register::{pgdh, pgdl};
+use memaddr::PhysAddr;
+
+/// Reads the current page table root register for user space (`PGDL`).
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_user_page_table() -> PhysAddr {
+ PhysAddr::from(pgdl::read().base())
+}
+
+/// Reads the current page table root register for kernel space (`PGDH`).
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_kernel_page_table() -> PhysAddr {
+ PhysAddr::from(pgdh::read().base())
+}
+
+/// Writes the register to update the current page table root for user space
+/// (`PGDL`).
+///
+/// Note that the TLB is **NOT** flushed after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
+ pgdl::set_base(root_paddr.as_usize() as _);
+}
+
+/// Writes the register to update the current page table root for kernel space
+/// (`PGDH`).
+///
+/// Note that the TLB is **NOT** flushed after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
+ pgdh::set_base(root_paddr.as_usize());
+}
+
+/// Writes the Page Walk Controller registers (`PWCL` and `PWCH`).
+///
+/// The CSR numbers are inlined as numeric constants:
+/// - `PWCL` = CSR 0x1c (lower-half page walk controller)
+/// - `PWCH` = CSR 0x1d (higher-half page walk controller)
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the page walk configuration such as
+/// levels and starting bits.
+///
+/// - `PWCL` (CSR 0x1c):
+/// - `PWCH` (CSR 0x1d):
+#[inline]
+pub unsafe fn write_pwc(pwcl: u32, pwch: u32) {
+ unsafe {
+ asm!(
+ "csrwr {}, 0x1c",
+ "csrwr {}, 0x1d",
+ in(reg) pwcl,
+ in(reg) pwch
+ )
+ }
+}
diff --git a/arch/karch/src/loongarch64/mod.rs b/arch/karch/src/loongarch64/mod.rs
new file mode 100644
index 00000000..9dcc0234
--- /dev/null
+++ b/arch/karch/src/loongarch64/mod.rs
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! LoongArch64 low-level architecture operations.
+
+mod cpu;
+mod fp;
+mod irq;
+mod mmu;
+mod tlb;
+mod tls;
+mod trap;
+
+pub use cpu::{await_interrupts, stop_cpu};
+pub use fp::{enable_fp, enable_lsx};
+#[allow(deprecated)]
+pub use irq::{
+ disable_irq, disable_local_irq, enable_irq, enable_local_irq, irq_enabled, local_irq_enabled,
+ restore_irq, save_irq_and_disable,
+};
+pub use mmu::{
+ read_kernel_page_table, read_user_page_table, write_kernel_page_table, write_pwc,
+ write_user_page_table,
+};
+pub use tlb::flush_tlb;
+pub use tls::{read_thread_pointer, write_thread_pointer};
+pub use trap::write_trap_vector_base;
diff --git a/arch/karch/src/loongarch64/tlb.rs b/arch/karch/src/loongarch64/tlb.rs
new file mode 100644
index 00000000..5363d5f3
--- /dev/null
+++ b/arch/karch/src/loongarch64/tlb.rs
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! TLB maintenance operations for LoongArch64.
+
+use core::arch::asm;
+
+use memaddr::VirtAddr;
+
+/// Flushes the TLB.
+///
+/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
+/// entry that maps the given virtual address.
+#[inline]
+pub fn flush_tlb(vaddr: Option) {
+ unsafe {
+ if let Some(vaddr) = vaddr {
+ //
+ //
+ // Only after all previous load/store access operations are completely
+ // executed, the DBAR 0 instruction can be executed; and only after the
+ // execution of DBAR 0 is completed, all subsequent load/store access
+ // operations can be executed.
+ //
+ //
+ //
+ // formats: invtlb op, asid, addr
+ //
+ // op 0x5: Clear all page table entries with G=0 and ASID equal to the
+ // register specified ASID, and VA equal to the register specified VA.
+ //
+ // When the operation indicated by op does not require an ASID, the
+ // general register rj should be set to r0.
+ asm!("dbar 0; invtlb 0x05, $r0, {reg}", reg = in(reg) vaddr.as_usize());
+ } else {
+ // op 0x0: Clear all page table entries
+ asm!("dbar 0; invtlb 0x00, $r0, $r0");
+ }
+ }
+}
diff --git a/arch/karch/src/loongarch64/tls.rs b/arch/karch/src/loongarch64/tls.rs
new file mode 100644
index 00000000..d3799bf5
--- /dev/null
+++ b/arch/karch/src/loongarch64/tls.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Thread-local storage operations for LoongArch64.
+
+use core::arch::asm;
+
+/// Reads the thread pointer of the current CPU (`$tp`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+#[inline]
+pub fn read_thread_pointer() -> usize {
+ let tp;
+ unsafe { asm!("move {}, $tp", out(reg) tp) };
+ tp
+}
+
+/// Writes the thread pointer of the current CPU (`$tp`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the CPU states.
+#[inline]
+pub unsafe fn write_thread_pointer(val: usize) {
+ unsafe { asm!("move $tp, {}", in(reg) val) }
+}
diff --git a/arch/karch/src/loongarch64/trap.rs b/arch/karch/src/loongarch64/trap.rs
new file mode 100644
index 00000000..97847b28
--- /dev/null
+++ b/arch/karch/src/loongarch64/trap.rs
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Exception/trap vector operations for LoongArch64.
+
+use loongArch64::register::{ecfg, eentry};
+
+/// Writes the Exception Entry Base Address register (`EENTRY`).
+///
+/// It also sets the Exception Configuration register (`ECFG`) to `VS=0`.
+///
+/// - ECFG:
+/// - EENTRY:
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the exception handling behavior of the
+/// current CPU.
+#[inline]
+pub unsafe fn write_trap_vector_base(addr: usize) {
+ ecfg::set_vs(0);
+ eentry::set_eentry(addr);
+}
diff --git a/arch/karch/src/riscv/cpu.rs b/arch/karch/src/riscv/cpu.rs
new file mode 100644
index 00000000..b76c16fb
--- /dev/null
+++ b/arch/karch/src/riscv/cpu.rs
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! CPU control operations for RISC-V.
+
+use super::irq::disable_local_irq;
+
+/// Halt the current CPU.
+#[inline]
+pub fn stop_cpu() {
+ disable_local_irq();
+ riscv::asm::wfi(); // should never return
+}
+
+/// Relaxes the current CPU and waits for interrupts.
+///
+/// It must be called with interrupts enabled, otherwise it will never return.
+#[inline]
+pub fn await_interrupts() {
+ riscv::asm::wfi()
+}
diff --git a/arch/karch/src/riscv/irq.rs b/arch/karch/src/riscv/irq.rs
new file mode 100644
index 00000000..2d9d13b0
--- /dev/null
+++ b/arch/karch/src/riscv/irq.rs
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Interrupt control operations for RISC-V.
+
+use riscv::register::sstatus;
+
+/// Allows the current CPU to respond to interrupts.
+#[inline]
+pub fn enable_local_irq() {
+ unsafe { sstatus::set_sie() }
+}
+
+/// Makes the current CPU ignore interrupts.
+#[inline]
+pub fn disable_local_irq() {
+ unsafe { sstatus::clear_sie() }
+}
+
+/// Returns whether the current CPU is allowed to respond to interrupts.
+#[inline]
+pub fn local_irq_enabled() -> bool {
+ sstatus::read().sie()
+}
+
+/// Deprecated: use [`enable_local_irq`] instead.
+#[deprecated(note = "Use `enable_local_irq` instead")]
+#[inline]
+pub fn enable_irq() {
+ enable_local_irq()
+}
+
+/// Deprecated: use [`disable_local_irq`] instead.
+#[deprecated(note = "Use `disable_local_irq` instead")]
+#[inline]
+pub fn disable_irq() {
+ disable_local_irq()
+}
+
+/// Deprecated: use [`local_irq_enabled`] instead.
+#[deprecated(note = "Use `local_irq_enabled` instead")]
+#[inline]
+pub fn irq_enabled() -> bool {
+ local_irq_enabled()
+}
+
+/// Saves the current local interrupt state and disables interrupts atomically.
+///
+/// Returns the saved sstatus value with the SIE bit. Pass it to
+/// [`restore_irq`] to restore the previous interrupt state.
+#[inline]
+pub fn save_irq_and_disable() -> usize {
+ /// Supervisor Interrupt Enable bit in sstatus.
+ const SIE_BIT: usize = 1 << 1;
+ let flags: usize;
+ // csrrc: atomically clear the SIE bit and return the old sstatus value
+ unsafe { core::arch::asm!("csrrc {}, sstatus, {}", out(reg) flags, const SIE_BIT) };
+ flags & SIE_BIT
+}
+
+/// Restores local interrupt state from a value previously returned by
+/// [`save_irq_and_disable`].
+#[inline]
+pub fn restore_irq(flags: usize) {
+ // csrrs: set the bits from `flags` back into sstatus
+ unsafe { core::arch::asm!("csrrs x0, sstatus, {}", in(reg) flags) };
+}
diff --git a/arch/karch/src/riscv/mmu.rs b/arch/karch/src/riscv/mmu.rs
new file mode 100644
index 00000000..e7447ff9
--- /dev/null
+++ b/arch/karch/src/riscv/mmu.rs
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! MMU/page table operations for RISC-V.
+
+use memaddr::PhysAddr;
+use riscv::register::satp;
+
+/// Reads the current page table root register for user space (`satp`).
+///
+/// RISC-V does not have a separate page table root register for user and
+/// kernel space, so this operation is the same as [`read_kernel_page_table`].
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_user_page_table() -> PhysAddr {
+ PhysAddr::from(satp::read().ppn() << 12)
+}
+
+/// Reads the current page table root register for kernel space (`satp`).
+///
+/// RISC-V does not have a separate page table root register for user and
+/// kernel space, so this operation is the same as [`read_user_page_table`].
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_kernel_page_table() -> PhysAddr {
+ read_user_page_table()
+}
+
+/// Writes the register to update the current page table root for user space
+/// (`satp`).
+///
+/// RISC-V does not have a separate page table root register for user
+/// and kernel space, so this operation is the same as [`write_kernel_page_table`].
+///
+/// Note that the TLB is **NOT** flushed after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
+ unsafe { satp::set(satp::Mode::Sv39, 0, root_paddr.as_usize() >> 12) };
+}
+
+/// Writes the register to update the current page table root for kernel space
+/// (`satp`).
+///
+/// RISC-V does not have a separate page table root register for user
+/// and kernel space, so this operation is the same as [`write_user_page_table`].
+///
+/// Note that the TLB is **NOT** flushed after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
+ unsafe { write_user_page_table(root_paddr) };
+}
diff --git a/arch/karch/src/riscv/mod.rs b/arch/karch/src/riscv/mod.rs
new file mode 100644
index 00000000..78ab8655
--- /dev/null
+++ b/arch/karch/src/riscv/mod.rs
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! RISC-V low-level architecture operations.
+
+mod cpu;
+mod irq;
+mod mmu;
+mod tlb;
+mod tls;
+mod trap;
+
+pub use cpu::{await_interrupts, stop_cpu};
+#[allow(deprecated)]
+pub use irq::{
+ disable_irq, disable_local_irq, enable_irq, enable_local_irq, irq_enabled, local_irq_enabled,
+ restore_irq, save_irq_and_disable,
+};
+pub use mmu::{
+ read_kernel_page_table, read_user_page_table, write_kernel_page_table, write_user_page_table,
+};
+pub use tlb::flush_tlb;
+pub use tls::{read_thread_pointer, write_thread_pointer};
+pub use trap::write_trap_vector_base;
diff --git a/arch/karch/src/riscv/tlb.rs b/arch/karch/src/riscv/tlb.rs
new file mode 100644
index 00000000..0f7e0e79
--- /dev/null
+++ b/arch/karch/src/riscv/tlb.rs
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! TLB maintenance operations for RISC-V.
+
+use memaddr::VirtAddr;
+use riscv::asm;
+
+/// Flushes the TLB.
+///
+/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
+/// entry that maps the given virtual address.
+#[inline]
+pub fn flush_tlb(vaddr: Option) {
+ if let Some(vaddr) = vaddr {
+ asm::sfence_vma(0, vaddr.as_usize())
+ } else {
+ asm::sfence_vma_all();
+ }
+}
diff --git a/arch/karch/src/riscv/tls.rs b/arch/karch/src/riscv/tls.rs
new file mode 100644
index 00000000..c75f27c2
--- /dev/null
+++ b/arch/karch/src/riscv/tls.rs
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Thread-local storage operations for RISC-V.
+
+/// Reads the thread pointer of the current CPU (`tp`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+#[inline]
+pub fn read_thread_pointer() -> usize {
+ let tp;
+ unsafe { core::arch::asm!("mv {}, tp", out(reg) tp) };
+ tp
+}
+
+/// Writes the thread pointer of the current CPU (`tp`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the CPU states.
+#[inline]
+pub unsafe fn write_thread_pointer(val: usize) {
+ unsafe { core::arch::asm!("mv tp, {}", in(reg) val) }
+}
diff --git a/arch/karch/src/riscv/trap.rs b/arch/karch/src/riscv/trap.rs
new file mode 100644
index 00000000..c71e6bde
--- /dev/null
+++ b/arch/karch/src/riscv/trap.rs
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Exception/trap vector operations for RISC-V.
+
+use riscv::register::stvec;
+
+/// Writes the Supervisor Trap Vector Base Address register (`stvec`).
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the exception handling behavior of the
+/// current CPU.
+#[inline]
+pub unsafe fn write_trap_vector_base(addr: usize) {
+ let mut reg = stvec::read();
+ reg.set_address(addr);
+ reg.set_trap_mode(stvec::TrapMode::Direct);
+ unsafe { stvec::write(reg) }
+}
diff --git a/arch/karch/src/x86_64/cpu.rs b/arch/karch/src/x86_64/cpu.rs
new file mode 100644
index 00000000..a7da5b25
--- /dev/null
+++ b/arch/karch/src/x86_64/cpu.rs
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! CPU control operations for x86_64.
+
+use core::arch::asm;
+
+use super::irq::disable_local_irq;
+
+/// Halt the current CPU.
+#[inline]
+pub fn stop_cpu() {
+ disable_local_irq();
+ await_interrupts(); // should never return
+}
+
+/// Relaxes the current CPU and waits for interrupts.
+///
+/// It must be called with interrupts enabled, otherwise it will never return.
+#[inline]
+pub fn await_interrupts() {
+ if cfg!(target_os = "none") {
+ unsafe { asm!("hlt") }
+ } else {
+ core::hint::spin_loop()
+ }
+}
diff --git a/arch/karch/src/x86_64/hypercall.rs b/arch/karch/src/x86_64/hypercall.rs
new file mode 100644
index 00000000..6a2fa3a7
--- /dev/null
+++ b/arch/karch/src/x86_64/hypercall.rs
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Hypervisor call operations for x86_64.
+
+use core::arch::asm;
+
+/// Performs a hypercall to the hypervisor using the `vmmcall` instruction.
+///
+/// This is used on AMD/Hygon platforms for KVM hypercalls.
+/// For Intel platforms, `vmcall` would be used instead.
+///
+/// # Arguments
+/// * `nr` - Hypercall number (passed in RAX)
+/// * `a0` - First argument (passed in RBX)
+/// * `a1` - Second argument (passed in RCX)
+///
+/// # Returns
+/// The return value from the hypervisor (from RAX).
+#[inline]
+pub fn hypercall(nr: u64, a0: u64, a1: u64) -> i64 {
+ let ret: i64;
+ unsafe {
+ // Note: rbx is reserved by LLVM, so we need to save/restore it manually
+ asm!(
+ "push rbx",
+ "mov rbx, {a0}",
+ "vmmcall",
+ "pop rbx",
+ a0 = in(reg) a0,
+ inout("rax") nr => ret,
+ in("rcx") a1,
+ options()
+ );
+ }
+ ret
+}
diff --git a/arch/karch/src/x86_64/irq.rs b/arch/karch/src/x86_64/irq.rs
new file mode 100644
index 00000000..893403a6
--- /dev/null
+++ b/arch/karch/src/x86_64/irq.rs
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Interrupt control operations for x86_64.
+
+use core::arch::asm;
+
+use x86_64::instructions::interrupts;
+
+/// Allows the current CPU to respond to interrupts.
+#[inline]
+pub fn enable_local_irq() {
+ #[cfg(target_os = "none")]
+ interrupts::enable()
+}
+
+/// Makes the current CPU ignore interrupts.
+#[inline]
+pub fn disable_local_irq() {
+ #[cfg(target_os = "none")]
+ interrupts::disable()
+}
+
+/// Returns whether the current CPU is allowed to respond to interrupts.
+#[inline]
+pub fn local_irq_enabled() -> bool {
+ interrupts::are_enabled()
+}
+
+/// Deprecated: use [`enable_local_irq`] instead.
+#[deprecated(note = "Use `enable_local_irq` instead")]
+#[inline]
+pub fn enable_irq() {
+ enable_local_irq()
+}
+
+/// Deprecated: use [`disable_local_irq`] instead.
+#[deprecated(note = "Use `disable_local_irq` instead")]
+#[inline]
+pub fn disable_irq() {
+ disable_local_irq()
+}
+
+/// Deprecated: use [`local_irq_enabled`] instead.
+#[deprecated(note = "Use `local_irq_enabled` instead")]
+#[inline]
+pub fn irq_enabled() -> bool {
+ local_irq_enabled()
+}
+
+/// Saves the current local interrupt state and disables interrupts atomically.
+///
+/// Returns the saved EFLAGS value with the IF bit. Pass it to [`restore_irq`]
+/// to restore the previous interrupt state.
+#[inline]
+pub fn save_irq_and_disable() -> usize {
+ #[cfg(target_os = "none")]
+ {
+ /// Interrupt Enable Flag (IF).
+ const IF_BIT: usize = 1 << 9;
+ let flags: usize;
+ unsafe { asm!("pushf; pop {}; cli", out(reg) flags) };
+ flags & IF_BIT
+ }
+ #[cfg(not(target_os = "none"))]
+ 0
+}
+
+/// Restores local interrupt state from a value previously returned by
+/// [`save_irq_and_disable`].
+#[inline]
+pub fn restore_irq(flags: usize) {
+ #[cfg(target_os = "none")]
+ {
+ if flags != 0 {
+ unsafe { asm!("sti") };
+ } else {
+ unsafe { asm!("cli") };
+ }
+ }
+ #[cfg(not(target_os = "none"))]
+ let _ = flags;
+}
diff --git a/arch/karch/src/x86_64/mmu.rs b/arch/karch/src/x86_64/mmu.rs
new file mode 100644
index 00000000..8acf639e
--- /dev/null
+++ b/arch/karch/src/x86_64/mmu.rs
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! MMU/page table operations for x86_64.
+
+use memaddr::{MemoryAddr, PhysAddr};
+use x86::controlregs;
+
+/// Reads the current page table root register for user space (`CR3`).
+///
+/// x86_64 does not have a separate page table root register for user and
+/// kernel space, so this operation is the same as [`read_kernel_page_table`].
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_user_page_table() -> PhysAddr {
+ PhysAddr::from(unsafe { controlregs::cr3() } as usize).align_down_4k()
+}
+
+/// Reads the current page table root register for kernel space (`CR3`).
+///
+/// x86_64 does not have a separate page table root register for user and
+/// kernel space, so this operation is the same as [`read_user_page_table`].
+///
+/// Returns the physical address of the page table root.
+#[inline]
+pub fn read_kernel_page_table() -> PhysAddr {
+ read_user_page_table()
+}
+
+/// Writes the register to update the current page table root for user space
+/// (`CR3`).
+///
+/// x86_64 does not have a separate page table root register for user
+/// and kernel space, so this operation is the same as [`write_kernel_page_table`].
+///
+/// Note that the TLB will be **flushed** after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
+ unsafe { controlregs::cr3_write(root_paddr.as_usize() as _) }
+}
+
+/// Writes the register to update the current page table root for kernel space
+/// (`CR3`).
+///
+/// x86_64 does not have a separate page table root register for user
+/// and kernel space, so this operation is the same as [`write_user_page_table`].
+///
+/// Note that the TLB will be **flushed** after this operation.
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the virtual memory address space.
+#[inline]
+pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
+ unsafe { write_user_page_table(root_paddr) }
+}
diff --git a/arch/karch/src/x86_64/mod.rs b/arch/karch/src/x86_64/mod.rs
new file mode 100644
index 00000000..03ca60ff
--- /dev/null
+++ b/arch/karch/src/x86_64/mod.rs
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! x86_64 low-level architecture operations.
+
+mod cpu;
+mod hypercall;
+mod irq;
+mod mmu;
+mod tlb;
+mod tls;
+
+pub use cpu::{await_interrupts, stop_cpu};
+pub use hypercall::hypercall;
+#[allow(deprecated)]
+pub use irq::{
+ disable_irq, disable_local_irq, enable_irq, enable_local_irq, irq_enabled, local_irq_enabled,
+ restore_irq, save_irq_and_disable,
+};
+pub use mmu::{
+ read_kernel_page_table, read_user_page_table, write_kernel_page_table, write_user_page_table,
+};
+pub use tlb::flush_tlb;
+pub use tls::{read_thread_pointer, write_thread_pointer};
diff --git a/arch/karch/src/x86_64/tlb.rs b/arch/karch/src/x86_64/tlb.rs
new file mode 100644
index 00000000..f86ff31a
--- /dev/null
+++ b/arch/karch/src/x86_64/tlb.rs
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! TLB maintenance operations for x86_64.
+
+use memaddr::VirtAddr;
+use x86::tlb;
+
+/// Flushes the TLB.
+///
+/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
+/// entry that maps the given virtual address.
+#[inline]
+pub fn flush_tlb(vaddr: Option) {
+ if let Some(vaddr) = vaddr {
+ unsafe { tlb::flush(vaddr.into()) }
+ } else {
+ unsafe { tlb::flush_all() }
+ }
+}
diff --git a/arch/karch/src/x86_64/tls.rs b/arch/karch/src/x86_64/tls.rs
new file mode 100644
index 00000000..24e644b6
--- /dev/null
+++ b/arch/karch/src/x86_64/tls.rs
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
+//! Thread-local storage operations for x86_64.
+
+use x86::msr;
+
+/// Reads the thread pointer of the current CPU (`FS_BASE`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+#[inline]
+pub fn read_thread_pointer() -> usize {
+ unsafe { msr::rdmsr(msr::IA32_FS_BASE) as usize }
+}
+
+/// Writes the thread pointer of the current CPU (`FS_BASE`).
+///
+/// It is used to implement TLS (Thread Local Storage).
+///
+/// # Safety
+///
+/// This function is unsafe as it changes the CPU states.
+#[inline]
+pub unsafe fn write_thread_pointer(val: usize) {
+ unsafe { msr::wrmsr(msr::IA32_FS_BASE, val as u64) }
+}
diff --git a/arch/kcpu/Cargo.toml b/arch/kcpu/Cargo.toml
index 845d58f5..33f5b6f3 100644
--- a/arch/kcpu/Cargo.toml
+++ b/arch/kcpu/Cargo.toml
@@ -13,10 +13,11 @@ default = []
fp-simd = []
tls = []
uspace = []
-arm-el2 = []
+arm-el2 = ["karch/arm-el2"]
[dependencies]
backtrace = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
linkme = "0.3"
log = "0.4"
diff --git a/arch/kcpu/src/aarch64/boot.rs b/arch/kcpu/src/aarch64/boot.rs
index 6e2b7a3e..27ef3973 100644
--- a/arch/kcpu/src/aarch64/boot.rs
+++ b/arch/kcpu/src/aarch64/boot.rs
@@ -91,7 +91,7 @@ pub unsafe fn init_mmu(root_paddr: PhysAddr) {
TTBR1_EL1.set(root_paddr);
// Flush the entire TLB
- crate::instrs::flush_tlb(None);
+ karch::flush_tlb(None);
// Enable the MMU and turn on I-cache and D-cache
SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable);
@@ -111,7 +111,7 @@ pub fn init_trap() {
fn exception_vector_base();
}
unsafe {
- crate::instrs::write_exception_vector_base(exception_vector_base as *const () as usize);
- crate::instrs::write_user_page_table(0.into());
+ karch::write_trap_vector_base(exception_vector_base as *const () as usize);
+ karch::write_user_page_table(0.into());
}
}
diff --git a/arch/kcpu/src/aarch64/ctx.rs b/arch/kcpu/src/aarch64/ctx.rs
index 4a0618f9..949f4be5 100644
--- a/arch/kcpu/src/aarch64/ctx.rs
+++ b/arch/kcpu/src/aarch64/ctx.rs
@@ -253,8 +253,8 @@ impl TaskContext {
pub fn switch_to(&mut self, next_ctx: &Self) {
#[cfg(feature = "tls")]
{
- self.tpidr_el0 = crate::instrs::read_thread_pointer() as _;
- unsafe { crate::instrs::write_thread_pointer(next_ctx.tpidr_el0 as _) };
+ self.tpidr_el0 = karch::read_thread_pointer() as _;
+ unsafe { karch::write_thread_pointer(next_ctx.tpidr_el0 as _) };
}
#[cfg(feature = "fp-simd")]
{
@@ -263,8 +263,8 @@ impl TaskContext {
}
#[cfg(feature = "uspace")]
if self.ttbr0_el1 != next_ctx.ttbr0_el1 {
- unsafe { crate::instrs::write_user_page_table(next_ctx.ttbr0_el1) };
- crate::instrs::flush_tlb(None); // currently flush the entire TLB
+ unsafe { karch::write_user_page_table(next_ctx.ttbr0_el1) };
+ karch::flush_tlb(None); // currently flush the entire TLB
}
unsafe { context_switch(self, next_ctx) }
}
diff --git a/arch/kcpu/src/aarch64/instrs.rs b/arch/kcpu/src/aarch64/instrs.rs
index 13b16965..1caf938d 100644
--- a/arch/kcpu/src/aarch64/instrs.rs
+++ b/arch/kcpu/src/aarch64/instrs.rs
@@ -4,193 +4,6 @@
//! Wrapper functions for assembly instructions.
-use core::arch::asm;
-
-use aarch64_cpu::{asm::barrier, registers::*};
-pub use kplat::interrupts::{disable_local, enable_local, is_enabled};
-use memaddr::{PhysAddr, VirtAddr};
-
-/// Halt the current CPU.
-#[inline]
-pub fn stop_cpu() {
- disable_local();
- // Execute WFI (Wait For Interrupt) instruction
- // Since interrupts are disabled, this should stop execution until reset
- aarch64_cpu::asm::wfi();
-}
-
-/// Relaxes the current CPU and waits for interrupts.
-///
-/// It must be called with interrupts enabled, otherwise it will never return.
-#[inline]
-pub fn await_interrupts() {
- aarch64_cpu::asm::wfi();
-}
-
-/// Reads the current page table root register for kernel space (`TTBR1_EL1`).
-///
-/// When the "arm-el2" feature is enabled,
-/// TTBR0_EL2 is dedicated to the Hypervisor's Stage-2 page table base address.
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn kernel_pt_root() -> PhysAddr {
- let pt_root_reg: usize;
-
- #[cfg(not(feature = "arm-el2"))]
- {
- pt_root_reg = TTBR1_EL1.get() as usize;
- }
-
- #[cfg(feature = "arm-el2")]
- {
- pt_root_reg = TTBR0_EL2.get() as usize;
- }
-
- pa!(pt_root_reg)
-}
-
-/// Reads the current page table root register for user space (`TTBR0_EL1`).
-///
-/// When the "arm-el2" feature is enabled, for user-mode programs,
-/// virtualization is completely transparent to them, so there is no need to modify
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn user_pt_root() -> PhysAddr {
- let val = TTBR0_EL1.get();
- pa!(val as usize)
-}
-
-/// Writes the register to update the current page table root for kernel space
-/// (`TTBR1_EL1`).
-///
-/// When the "arm-el2" feature is enabled,
-/// TTBR0_EL2 is dedicated to the Hypervisor's Stage-2 page table base address.
-///
-/// Note that the TLB is **NOT** flushed after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-#[inline]
-pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
- #[cfg(not(feature = "arm-el2"))]
- {
- // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff)
- TTBR1_EL1.set(root_paddr.as_usize() as _);
- }
-
- #[cfg(feature = "arm-el2")]
- {
- // kernel space page table at EL2 use TTBR0_EL2 (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff)
- TTBR0_EL2.set(root_paddr.as_usize() as _);
- }
-}
-
-/// Writes the register to update the current page table root for user space
-/// (`TTBR1_EL0`).
-/// When the "arm-el2" feature is enabled, for user-mode programs,
-/// virtualization is completely transparent to them, so there is no need to modify
-///
-/// Note that the TLB is **NOT** flushed after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-#[inline]
-pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
- TTBR0_EL1.set(root_paddr.as_usize() as _);
-}
-
-/// Flushes the TLB.
-///
-/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
-/// entry that maps the given virtual address.
-#[inline]
-pub fn flush_tlb(vaddr: Option) {
- if let Some(vaddr) = vaddr {
- const VA_MASK: usize = (1 << 44) - 1; // VA[55:12] => bits[43:0]
- let operand = (vaddr.as_usize() >> 12) & VA_MASK;
-
- #[cfg(not(feature = "arm-el2"))]
- unsafe {
- // TLB Invalidate by VA, All ASID, EL1, Inner Shareable
- asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) operand)
- }
- #[cfg(feature = "arm-el2")]
- unsafe {
- // TLB Invalidate by VA, EL2, Inner Shareable
- asm!("tlbi vae2is, {}; dsb sy; isb", in(reg) operand)
- }
- } else {
- // flush the entire TLB
- #[cfg(not(feature = "arm-el2"))]
- unsafe {
- // TLB Invalidate by VMID, All at stage 1, EL1
- asm!("dsb sy; isb; tlbi vmalle1; dsb sy; isb")
- }
- #[cfg(feature = "arm-el2")]
- unsafe {
- // TLB Invalidate All, EL2
- asm!("tlbi alle2; dsb sy; isb")
- }
- }
-}
-
-/// Flushes the entire instruction cache.
-#[inline]
-pub fn flush_icache_all() {
- unsafe { asm!("ic iallu; dsb sy; isb") };
-}
-
-/// Flushes the data cache line (64 bytes) at the given virtual address
-#[inline]
-pub fn flush_dcache_line(vaddr: VirtAddr) {
- unsafe { asm!("dc ivac, {0:x}; dsb sy; isb", in(reg) vaddr.as_usize()) };
-}
-
-/// Writes exception vector base address register (`VBAR_EL1`).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the exception handling behavior of the
-/// current CPU.
-#[inline]
-pub unsafe fn write_exception_vector_base(vbar: usize) {
- #[cfg(not(feature = "arm-el2"))]
- VBAR_EL1.set(vbar as _);
- #[cfg(feature = "arm-el2")]
- VBAR_EL2.set(vbar as _);
-}
-
-/// Reads the thread pointer of the current CPU (`TPIDR_EL0`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-#[inline]
-pub fn read_thread_pointer() -> usize {
- TPIDR_EL0.get() as usize
-}
-
-/// Writes the thread pointer of the current CPU (`TPIDR_EL0`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the current CPU states.
-#[inline]
-pub unsafe fn write_thread_pointer(tpidr_el0: usize) {
- TPIDR_EL0.set(tpidr_el0 as _)
-}
-
-/// Enable FP/SIMD instructions by setting the `FPEN` field in `CPACR_EL1`.
-#[inline]
-pub fn enable_fp() {
- CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
- barrier::isb(barrier::SY);
-}
-
#[cfg(feature = "uspace")]
core::arch::global_asm!(include_str!("copy_user.S"));
diff --git a/arch/kcpu/src/aarch64/userspace.rs b/arch/kcpu/src/aarch64/userspace.rs
index 59caecea..3d4745ca 100644
--- a/arch/kcpu/src/aarch64/userspace.rs
+++ b/arch/kcpu/src/aarch64/userspace.rs
@@ -85,7 +85,7 @@ impl UserContext {
unsafe fn enter_user(uctx: &mut UserContext) -> ArchTrap;
}
- crate::instrs::disable_local(); // updated module reference from asm -> instrs
+ karch::disable_local_irq(); // updated module reference from asm -> instrs
let trap_kind = unsafe { enter_user(self) };
let ret = match trap_kind {
@@ -125,7 +125,7 @@ impl UserContext {
}
};
- crate::instrs::enable_local();
+ karch::enable_local_irq();
ret
}
}
diff --git a/arch/kcpu/src/loongarch64/boot.rs b/arch/kcpu/src/loongarch64/boot.rs
index 6b1c0533..8724146d 100644
--- a/arch/kcpu/src/loongarch64/boot.rs
+++ b/arch/kcpu/src/loongarch64/boot.rs
@@ -30,11 +30,11 @@ pub fn init_mmu(root_paddr: PhysAddr, phys_virt_offset: usize) {
// Configure page table walking
unsafe {
- crate::instrs::write_pwc(LA64MetaData::PWCL_VALUE, LA64MetaData::PWCH_VALUE);
- crate::instrs::write_kernel_page_table(root_paddr);
- crate::instrs::write_user_page_table(pa!(0));
+ karch::write_pwc(LA64MetaData::PWCL_VALUE, LA64MetaData::PWCH_VALUE);
+ karch::write_kernel_page_table(root_paddr);
+ karch::write_user_page_table(pa!(0));
}
- crate::instrs::flush_tlb(None);
+ karch::flush_tlb(None);
// Enable mapped address translation mode
crmd::set_pg(true);
@@ -51,6 +51,6 @@ pub fn init_trap() {
fn exception_entry_base();
}
core::arch::asm!(include_asm_macros!(), "csrwr $r0, KSAVE_KSP");
- crate::instrs::write_exception_entry_base(exception_entry_base as usize);
+ karch::write_trap_vector_base(exception_entry_base as usize);
}
}
diff --git a/arch/kcpu/src/loongarch64/ctx.rs b/arch/kcpu/src/loongarch64/ctx.rs
index 9a7594cf..549454d7 100644
--- a/arch/kcpu/src/loongarch64/ctx.rs
+++ b/arch/kcpu/src/loongarch64/ctx.rs
@@ -301,14 +301,14 @@ impl TaskContext {
pub fn switch_to(&mut self, next_ctx: &Self) {
#[cfg(feature = "tls")]
{
- self.tp = crate::instrs::read_thread_pointer();
- unsafe { crate::instrs::write_thread_pointer(next_ctx.tp) };
+ self.tp = karch::read_thread_pointer();
+ unsafe { karch::write_thread_pointer(next_ctx.tp) };
}
#[cfg(feature = "uspace")]
{
if self.pgdl != next_ctx.pgdl {
- unsafe { crate::instrs::write_user_page_table(pa!(next_ctx.pgdl)) };
- crate::instrs::flush_tlb(None); // currently flush the entire TLB
+ unsafe { karch::write_user_page_table(pa!(next_ctx.pgdl)) };
+ karch::flush_tlb(None); // currently flush the entire TLB
}
}
#[cfg(feature = "fp-simd")]
diff --git a/arch/kcpu/src/loongarch64/instrs.rs b/arch/kcpu/src/loongarch64/instrs.rs
index 6a8e0aca..6821423d 100644
--- a/arch/kcpu/src/loongarch64/instrs.rs
+++ b/arch/kcpu/src/loongarch64/instrs.rs
@@ -4,190 +4,11 @@
//! Wrapper functions for assembly instructions.
-use core::arch::asm;
-
-use loongArch64::register::{crmd, ecfg, eentry, pgdh, pgdl};
-use memaddr::{PhysAddr, VirtAddr};
-
-/// Allows the current CPU to respond to interrupts.
-#[inline]
-pub fn enable_local() {
- crmd::set_ie(true)
-}
-
-/// Makes the current CPU to ignore interrupts.
-#[inline]
-pub fn disable_local() {
- crmd::set_ie(false)
-}
-
-/// Returns whether the current CPU is allowed to respond to interrupts.
-#[inline]
-pub fn is_enabled() -> bool {
- crmd::read().ie()
-}
-
-/// Relaxes the current CPU and waits for interrupts.
-///
-/// It must be called with interrupts enabled, otherwise it will never return.
-#[inline]
-pub fn await_interrupts() {
- unsafe { loongArch64::asm::idle() }
-}
-
-/// Halt the current CPU.
-#[inline]
-pub fn stop_cpu() {
- disable_local();
- unsafe { loongArch64::asm::idle() }
-}
-
-/// Reads the current page table root register for user space (`PGDL`).
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn read_user_page_table() -> PhysAddr {
- PhysAddr::from(pgdl::read().base())
-}
-
-/// Reads the current page table root register for kernel space (`PGDH`).
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn read_kernel_page_table() -> PhysAddr {
- PhysAddr::from(pgdh::read().base())
-}
-
-/// Writes the register to update the current page table root for user space
-/// (`PGDL`).
-///
-/// Note that the TLB is **NOT** flushed after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
- pgdl::set_base(root_paddr.as_usize() as _);
-}
-
-/// Writes the register to update the current page table root for kernel space
-/// (`PGDH`).
-///
-/// Note that the TLB is **NOT** flushed after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
- pgdh::set_base(root_paddr.as_usize());
-}
-
-/// Flushes the TLB.
-///
-/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
-/// entry that maps the given virtual address.
-#[inline]
-pub fn flush_tlb(vaddr: Option) {
- unsafe {
- if let Some(vaddr) = vaddr {
- //
- //
- // Only after all previous load/store access operations are completely
- // executed, the DBAR 0 instruction can be executed; and only after the
- // execution of DBAR 0 is completed, all subsequent load/store access
- // operations can be executed.
- //
- //
- //
- // formats: invtlb op, asid, addr
- //
- // op 0x5: Clear all page table entries with G=0 and ASID equal to the
- // register specified ASID, and VA equal to the register specified VA.
- //
- // When the operation indicated by op does not require an ASID, the
- // general register rj should be set to r0.
- asm!("dbar 0; invtlb 0x05, $r0, {reg}", reg = in(reg) vaddr.as_usize());
- } else {
- // op 0x0: Clear all page table entries
- asm!("dbar 0; invtlb 0x00, $r0, $r0");
- }
- }
-}
-
-/// Writes the Exception Entry Base Address register (`EENTRY`).
-///
-/// It also set the Exception Configuration register (`ECFG`) to `VS=0`.
-///
-/// - ECFG:
-/// - EENTRY:
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the exception handling behavior of the
-/// current CPU.
+/// Deprecated: use [`karch::write_trap_vector_base`] instead.
+#[deprecated(note = "Use `karch::write_trap_vector_base` instead")]
#[inline]
pub unsafe fn write_exception_entry_base(eentry: usize) {
- ecfg::set_vs(0);
- eentry::set_eentry(eentry);
-}
-
-/// Writes the Page Walk Controller registers (`PWCL` and `PWCH`).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the page walk configuration such as
-/// levels and starting bits.
-///
-/// - `PWCL`:
-/// - `PWCH`:
-#[inline]
-pub unsafe fn write_pwc(pwcl: u32, pwch: u32) {
- unsafe {
- asm!(
- include_asm_macros!(),
- "csrwr {}, LA_CSR_PWCL",
- "csrwr {}, LA_CSR_PWCH",
- in(reg) pwcl,
- in(reg) pwch
- )
- }
-}
-
-/// Reads the thread pointer of the current CPU (`$tp`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-#[inline]
-pub fn read_thread_pointer() -> usize {
- let tp;
- unsafe { asm!("move {}, $tp", out(reg) tp) };
- tp
-}
-
-/// Writes the thread pointer of the current CPU (`$tp`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the CPU states.
-#[inline]
-pub unsafe fn write_thread_pointer(tp: usize) {
- unsafe { asm!("move $tp, {}", in(reg) tp) }
-}
-
-/// Enables floating-point instructions by setting `EUEN.FPE`.
-///
-/// - `EUEN`:
-#[inline]
-pub fn enable_fp() {
- loongArch64::register::euen::set_fpe(true);
-}
-
-/// Enables LSX extension by setting `EUEN.LSX`.
-///
-/// - `EUEN`:
-pub fn enable_lsx() {
- loongArch64::register::euen::set_sxe(true);
+ unsafe { karch::write_trap_vector_base(eentry) }
}
#[cfg(feature = "uspace")]
diff --git a/arch/kcpu/src/loongarch64/userspace.rs b/arch/kcpu/src/loongarch64/userspace.rs
index 2d0ad397..d5ed15d8 100644
--- a/arch/kcpu/src/loongarch64/userspace.rs
+++ b/arch/kcpu/src/loongarch64/userspace.rs
@@ -45,7 +45,7 @@ impl UserContext {
fn enter_user(uctx: &mut UserContext);
}
- crate::instrs::disable_local();
+ karch::disable_local_irq();
unsafe { enter_user(self) };
let estat = estat::read();
@@ -78,7 +78,7 @@ impl UserContext {
_ => ReturnReason::Unknown,
};
- crate::instrs::enable_local();
+ karch::enable_local_irq();
ret
}
}
diff --git a/arch/kcpu/src/riscv/boot.rs b/arch/kcpu/src/riscv/boot.rs
index 64c4bf88..c77768ab 100644
--- a/arch/kcpu/src/riscv/boot.rs
+++ b/arch/kcpu/src/riscv/boot.rs
@@ -16,6 +16,6 @@ pub fn init_trap() {
unsafe {
#[cfg(feature = "uspace")]
riscv::register::sstatus::set_sum();
- crate::instrs::write_trap_vector_base(trap_vector_base as *const () as usize);
+ karch::write_trap_vector_base(trap_vector_base as *const () as usize);
}
}
diff --git a/arch/kcpu/src/riscv/ctx.rs b/arch/kcpu/src/riscv/ctx.rs
index 902f9e62..a5160958 100644
--- a/arch/kcpu/src/riscv/ctx.rs
+++ b/arch/kcpu/src/riscv/ctx.rs
@@ -353,7 +353,7 @@ impl TaskContext {
pub fn new() -> Self {
Self {
#[cfg(feature = "uspace")]
- satp: crate::instrs::read_kernel_page_table(),
+ satp: karch::read_kernel_page_table(),
..Default::default()
}
}
@@ -382,13 +382,13 @@ impl TaskContext {
pub fn switch_to(&mut self, next_ctx: &Self) {
#[cfg(feature = "tls")]
{
- self.tp = crate::instrs::read_thread_pointer();
- unsafe { crate::instrs::write_thread_pointer(next_ctx.tp) };
+ self.tp = karch::read_thread_pointer();
+ unsafe { karch::write_thread_pointer(next_ctx.tp) };
}
#[cfg(feature = "uspace")]
if self.satp != next_ctx.satp {
- unsafe { crate::instrs::write_user_page_table(next_ctx.satp) };
- crate::instrs::flush_tlb(None); // currently flush the entire TLB
+ unsafe { karch::write_user_page_table(next_ctx.satp) };
+ karch::flush_tlb(None); // currently flush the entire TLB
}
#[cfg(feature = "fp-simd")]
{
diff --git a/arch/kcpu/src/riscv/instrs.rs b/arch/kcpu/src/riscv/instrs.rs
index f1d0ca07..b4df8292 100644
--- a/arch/kcpu/src/riscv/instrs.rs
+++ b/arch/kcpu/src/riscv/instrs.rs
@@ -4,148 +4,6 @@
//! Wrapper functions for assembly instructions.
-use memaddr::{PhysAddr, VirtAddr};
-use riscv::{
- asm,
- register::{satp, sstatus, stvec},
-};
-
-/// Allows the current CPU to respond to interrupts.
-#[inline]
-pub fn enable_local() {
- unsafe { sstatus::set_sie() }
-}
-
-/// Makes the current CPU to ignore interrupts.
-#[inline]
-pub fn disable_local() {
- unsafe { sstatus::clear_sie() }
-}
-
-/// Returns whether the current CPU is allowed to respond to interrupts.
-#[inline]
-pub fn is_enabled() -> bool {
- sstatus::read().sie()
-}
-
-/// Relaxes the current CPU and waits for interrupts.
-///
-/// It must be called with interrupts enabled, otherwise it will never return.
-#[inline]
-pub fn await_interrupts() {
- riscv::asm::wfi()
-}
-
-/// Halt the current CPU.
-#[inline]
-pub fn stop_cpu() {
- disable_local();
- riscv::asm::wfi() // should never return
-}
-
-/// Reads the current page table root register for user space (`satp`).
-///
-/// RISC-V does not have a separate page table root register for user and
-/// kernel space, so this operation is the same as [`read_kernel_page_table`].
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn read_user_page_table() -> PhysAddr {
- pa!(satp::read().ppn() << 12)
-}
-
-/// Reads the current page table root register for kernel space (`satp`).
-///
-/// RISC-V does not have a separate page table root register for user and
-/// kernel space, so this operation is the same as [`read_user_page_table`].
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn read_kernel_page_table() -> PhysAddr {
- read_user_page_table()
-}
-
-/// Writes the register to update the current page table root for user space
-/// (`satp`).
-///
-/// RISC-V does not have a separate page table root register for user
-/// and kernel space, so this operation is the same as [`write_kernel_page_table`].
-///
-/// Note that the TLB is **NOT** flushed after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-#[inline]
-pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
- unsafe { satp::set(satp::Mode::Sv39, 0, root_paddr.as_usize() >> 12) };
-}
-
-/// Writes the register to update the current page table root for user space
-/// (`satp`).
-///
-/// RISC-V does not have a separate page table root register for user
-/// and kernel space, so this operation is the same as [`write_user_page_table`].
-///
-/// Note that the TLB is **NOT** flushed after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-#[inline]
-pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
- unsafe { write_user_page_table(root_paddr) };
-}
-
-/// Flushes the TLB.
-///
-/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
-/// entry that maps the given virtual address.
-#[inline]
-pub fn flush_tlb(vaddr: Option) {
- if let Some(vaddr) = vaddr {
- asm::sfence_vma(0, vaddr.as_usize())
- } else {
- asm::sfence_vma_all();
- }
-}
-
-/// Writes the Supervisor Trap Vector Base Address register (`stvec`).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the exception handling behavior of the
-/// current CPU.
-#[inline]
-pub unsafe fn write_trap_vector_base(stvec: usize) {
- let mut reg = stvec::read();
- reg.set_address(stvec);
- reg.set_trap_mode(stvec::TrapMode::Direct);
- unsafe { stvec::write(reg) }
-}
-
-/// Reads the thread pointer of the current CPU (`tp`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-#[inline]
-pub fn read_thread_pointer() -> usize {
- let tp;
- unsafe { core::arch::asm!("mv {}, tp", out(reg) tp) };
- tp
-}
-
-/// Writes the thread pointer of the current CPU (`tp`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the CPU states.
-#[inline]
-pub unsafe fn write_thread_pointer(tp: usize) {
- unsafe { core::arch::asm!("mv tp, {}", in(reg) tp) }
-}
-
#[cfg(feature = "uspace")]
core::arch::global_asm!(include_asm_macros!(), include_str!("copy_user.S"));
diff --git a/arch/kcpu/src/riscv/userspace.rs b/arch/kcpu/src/riscv/userspace.rs
index fba3d23c..34379a24 100644
--- a/arch/kcpu/src/riscv/userspace.rs
+++ b/arch/kcpu/src/riscv/userspace.rs
@@ -57,7 +57,7 @@ impl UserContext {
fn enter_user(uctx: &mut UserContext);
}
- crate::instrs::disable_local();
+ karch::disable_local_irq();
unsafe { enter_user(self) };
let scause = scause::read();
@@ -89,7 +89,7 @@ impl UserContext {
ReturnReason::Unknown
};
- crate::instrs::enable_local();
+ karch::enable_local_irq();
ret
}
}
diff --git a/arch/kcpu/src/x86_64/ctx.rs b/arch/kcpu/src/x86_64/ctx.rs
index 13288527..3ece55c6 100644
--- a/arch/kcpu/src/x86_64/ctx.rs
+++ b/arch/kcpu/src/x86_64/ctx.rs
@@ -299,7 +299,7 @@ impl TaskContext {
rsp: 0,
fs_base: 0,
#[cfg(feature = "uspace")]
- cr3: crate::instrs::read_kernel_page_table(),
+ cr3: karch::read_kernel_page_table(),
#[cfg(feature = "fp-simd")]
ext_state: ExtendedState::default(),
}
@@ -348,13 +348,13 @@ impl TaskContext {
}
#[cfg(feature = "tls")]
unsafe {
- self.fs_base = crate::instrs::read_thread_pointer();
- crate::instrs::write_thread_pointer(next_ctx.fs_base);
+ self.fs_base = karch::read_thread_pointer();
+ karch::write_thread_pointer(next_ctx.fs_base);
}
#[cfg(feature = "uspace")]
unsafe {
if next_ctx.cr3 != self.cr3 {
- crate::instrs::write_user_page_table(next_ctx.cr3);
+ karch::write_user_page_table(next_ctx.cr3);
// writing to CR3 has flushed the TLB
}
}
diff --git a/arch/kcpu/src/x86_64/instrs.rs b/arch/kcpu/src/x86_64/instrs.rs
index 3fa38d4f..4aa3ec2e 100644
--- a/arch/kcpu/src/x86_64/instrs.rs
+++ b/arch/kcpu/src/x86_64/instrs.rs
@@ -4,146 +4,6 @@
//! Wrapper functions for assembly instructions.
-use core::arch::asm;
-
-use memaddr::{MemoryAddr, PhysAddr, VirtAddr};
-use x86::{controlregs, msr, tlb};
-use x86_64::instructions::interrupts;
-
-/// Allows the current CPU to respond to interrupts.
-#[inline]
-pub fn enable_local() {
- #[cfg(not(target_os = "none"))]
- {
- warn!("enable_local: not implemented");
- }
- #[cfg(target_os = "none")]
- interrupts::enable()
-}
-
-/// Makes the current CPU to ignore interrupts.
-#[inline]
-pub fn disable_local() {
- #[cfg(not(target_os = "none"))]
- {
- warn!("disable_local: not implemented");
- }
- #[cfg(target_os = "none")]
- interrupts::disable()
-}
-
-/// Returns whether the current CPU is allowed to respond to interrupts.
-#[inline]
-pub fn is_enabled() -> bool {
- interrupts::are_enabled()
-}
-
-/// Relaxes the current CPU and waits for interrupts.
-///
-/// It must be called with interrupts enabled, otherwise it will never return.
-#[inline]
-pub fn await_interrupts() {
- if cfg!(target_os = "none") {
- unsafe { asm!("hlt") }
- } else {
- core::hint::spin_loop()
- }
-}
-
-/// Halt the current CPU.
-#[inline]
-pub fn stop_cpu() {
- disable_local();
- await_interrupts(); // should never return
-}
-
-/// Reads the current page table root register for user space (`CR3`).
-///
-/// x86_64 does not have a separate page table root register for user and
-/// kernel space, so this operation is the same as [`read_kernel_page_table`].
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn read_user_page_table() -> PhysAddr {
- pa!(unsafe { controlregs::cr3() } as usize).align_down_4k()
-}
-
-/// Reads the current page table root register for kernel space (`CR3`).
-///
-/// x86_64 does not have a separate page table root register for user and
-/// kernel space, so this operation is the same as [`read_user_page_table`].
-///
-/// Returns the physical address of the page table root.
-#[inline]
-pub fn read_kernel_page_table() -> PhysAddr {
- read_user_page_table()
-}
-
-/// Writes the register to update the current page table root for user space
-/// (`CR3`).
-///
-/// x86_64 does not have a separate page table root register for user
-/// and kernel space, so this operation is the same as [`write_kernel_page_table`].
-///
-/// Note that the TLB will be **flushed** after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-#[inline]
-pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
- unsafe { controlregs::cr3_write(root_paddr.as_usize() as _) }
-}
-
-/// Writes the register to update the current page table root for kernel space
-/// (`CR3`).
-///
-/// x86_64 does not have a separate page table root register for user
-/// and kernel space, so this operation is the same as [`write_user_page_table`].
-///
-/// Note that the TLB will be **flushed** after this operation.
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the virtual memory address space.
-#[inline]
-pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
- unsafe { write_user_page_table(root_paddr) }
-}
-
-/// Flushes the TLB.
-///
-/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
-/// entry that maps the given virtual address.
-#[inline]
-pub fn flush_tlb(vaddr: Option) {
- if let Some(vaddr) = vaddr {
- unsafe { tlb::flush(vaddr.into()) }
- } else {
- unsafe { tlb::flush_all() }
- }
-}
-
-/// Reads the thread pointer of the current CPU (`FS_BASE`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-#[inline]
-pub fn read_thread_pointer() -> usize {
- unsafe { msr::rdmsr(msr::IA32_FS_BASE) as usize }
-}
-
-/// Writes the thread pointer of the current CPU (`FS_BASE`).
-///
-/// It is used to implement TLS (Thread Local Storage).
-///
-/// # Safety
-///
-/// This function is unsafe as it changes the CPU states.
-#[inline]
-pub unsafe fn write_thread_pointer(fs_base: usize) {
- unsafe { msr::wrmsr(msr::IA32_FS_BASE, fs_base as u64) }
-}
-
#[cfg(feature = "uspace")]
core::arch::global_asm!(include_str!("copy_user.S"));
@@ -160,34 +20,3 @@ unsafe extern "C" {
/// while a value > 0 indicates failure.
pub fn user_copy(dst: *mut u8, src: *const u8, size: usize) -> usize;
}
-
-/// Performs a hypercall to the hypervisor using the `vmmcall` instruction.
-///
-/// This is used on AMD/Hygon platforms for KVM hypercalls.
-/// For Intel platforms, `vmcall` would be used instead.
-///
-/// # Arguments
-/// * `nr` - Hypercall number (passed in RAX)
-/// * `a0` - First argument (passed in RBX)
-/// * `a1` - Second argument (passed in RCX)
-///
-/// # Returns
-/// The return value from the hypervisor (from RAX).
-#[inline]
-pub fn hypercall(nr: u64, a0: u64, a1: u64) -> i64 {
- let ret: i64;
- unsafe {
- // Note: rbx is reserved by LLVM, so we need to save/restore it manually
- core::arch::asm!(
- "push rbx",
- "mov rbx, {a0}",
- "vmmcall",
- "pop rbx",
- a0 = in(reg) a0,
- inout("rax") nr => ret,
- in("rcx") a1,
- options()
- );
- }
- ret
-}
diff --git a/arch/kcpu/src/x86_64/mod.rs b/arch/kcpu/src/x86_64/mod.rs
index cac20ab4..3e26f0a3 100644
--- a/arch/kcpu/src/x86_64/mod.rs
+++ b/arch/kcpu/src/x86_64/mod.rs
@@ -10,7 +10,7 @@ mod idt;
pub mod instrs;
pub use instrs as asm;
-pub use instrs::hypercall;
+pub use karch::hypercall;
pub mod boot;
mod excp;
diff --git a/arch/kcpu/src/x86_64/userspace.rs b/arch/kcpu/src/x86_64/userspace.rs
index 4c9a8f43..6caf6676 100644
--- a/arch/kcpu/src/x86_64/userspace.rs
+++ b/arch/kcpu/src/x86_64/userspace.rs
@@ -18,7 +18,6 @@ use x86_64::{
use super::{
TrapFrame,
- asm::{read_thread_pointer, write_thread_pointer},
excp::{IRQ_VECTOR_END, IRQ_VECTOR_START, LEGACY_SYSCALL_VECTOR, err_code_to_flags},
gdt,
};
@@ -79,17 +78,17 @@ impl UserContext {
assert_eq!(self.cs, gdt::UCODE64.0 as _);
assert_eq!(self.ss, gdt::UDATA.0 as _);
- crate::instrs::disable_local();
+ karch::disable_local_irq();
- let kernel_fs_base = read_thread_pointer();
- unsafe { write_thread_pointer(self.fs_base as _) };
+ let kernel_fs_base = karch::read_thread_pointer();
+ unsafe { karch::write_thread_pointer(self.fs_base as _) };
KernelGsBase::write(x86_64::VirtAddr::new_truncate(self.gs_base));
unsafe { enter_user(self) };
self.gs_base = KernelGsBase::read().as_u64();
- self.fs_base = read_thread_pointer() as _;
- unsafe { write_thread_pointer(kernel_fs_base) };
+ self.fs_base = karch::read_thread_pointer() as _;
+ unsafe { karch::write_thread_pointer(kernel_fs_base) };
let cr2 = Cr2::read().unwrap().as_u64() as usize;
let vector = self.vector as u8;
@@ -112,7 +111,7 @@ impl UserContext {
}),
};
- crate::instrs::enable_local();
+ karch::enable_local_irq();
ret
}
}
diff --git a/arch/khal/src/dummy.rs b/arch/khal/src/dummy.rs
index 5cf697ab..91c9b763 100644
--- a/arch/khal/src/dummy.rs
+++ b/arch/khal/src/dummy.rs
@@ -142,18 +142,4 @@ impl IntrManager for DummyIrq {
fn notify_cpu(_irq: usize, _target: TargetCpu) {}
fn set_prio(_irq: usize, _priority: u8) {}
-
- fn save_disable() -> usize {
- 0
- }
-
- fn restore(_flag: usize) {}
-
- fn enable_local() {}
-
- fn disable_local() {}
-
- fn is_enabled() -> bool {
- false
- }
}
diff --git a/arch/khal/src/irq.rs b/arch/khal/src/irq.rs
index 2c1926b1..c15bb961 100644
--- a/arch/khal/src/irq.rs
+++ b/arch/khal/src/irq.rs
@@ -12,8 +12,7 @@ use kcpu::excp::{IRQ, register_trap_handler};
#[cfg(feature = "ipi")]
pub use kplat::interrupts::{TargetCpu, notify_cpu};
pub use kplat::interrupts::{
- dispatch_irq, enable, reg_handler as register, restore, save_disable, set_prio,
- unreg_handler as unregister,
+ dispatch_irq, enable, reg_handler as register, set_prio, unreg_handler as unregister,
};
static IRQ_HOOK: AtomicUsize = AtomicUsize::new(0);
diff --git a/core/kernel_elf_parser/src/auxv.rs b/core/kernel_elf_parser/src/auxv.rs
index cff6c854..48f178da 100644
--- a/core/kernel_elf_parser/src/auxv.rs
+++ b/core/kernel_elf_parser/src/auxv.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use zerocopy::{Immutable, IntoBytes};
/// Represents the type of an auxiliary vector entry.
diff --git a/core/kernel_elf_parser/src/info.rs b/core/kernel_elf_parser/src/info.rs
index 8710390a..28c7685f 100644
--- a/core/kernel_elf_parser/src/info.rs
+++ b/core/kernel_elf_parser/src/info.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! ELF information parsed from the ELF file
use alloc::vec::Vec;
diff --git a/core/kernel_elf_parser/src/lib.rs b/core/kernel_elf_parser/src/lib.rs
index 425eafb6..d8dc4b4a 100644
--- a/core/kernel_elf_parser/src/lib.rs
+++ b/core/kernel_elf_parser/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#![cfg_attr(not(test), no_std)]
#![doc = include_str!("../README.md")]
diff --git a/core/kernel_elf_parser/src/user_stack.rs b/core/kernel_elf_parser/src/user_stack.rs
index b59715e8..545084ba 100644
--- a/core/kernel_elf_parser/src/user_stack.rs
+++ b/core/kernel_elf_parser/src/user_stack.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Initialize the user stack for the application
//!
//! The structure of the user stack is described in the following figure:
diff --git a/core/kernel_elf_parser/tests/test_dynamic.rs b/core/kernel_elf_parser/tests/test_dynamic.rs
index b5754296..cc764533 100644
--- a/core/kernel_elf_parser/tests/test_dynamic.rs
+++ b/core/kernel_elf_parser/tests/test_dynamic.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[test]
fn test_elf_parser() {
let elf_bytes = include_bytes!("ld-linux-x86-64.so.2");
diff --git a/core/kernel_elf_parser/tests/test_static.rs b/core/kernel_elf_parser/tests/test_static.rs
index af01ed59..cc065293 100644
--- a/core/kernel_elf_parser/tests/test_static.rs
+++ b/core/kernel_elf_parser/tests/test_static.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use kernel_elf_parser::ELFParser;
#[test]
diff --git a/core/kpoll/src/tests.rs b/core/kpoll/src/tests.rs
index d0131c1e..3f429b48 100644
--- a/core/kpoll/src/tests.rs
+++ b/core/kpoll/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for kpoll using the unittest framework.
#![cfg(unittest)]
diff --git a/core/ksync/src/tests.rs b/core/ksync/src/tests.rs
index bc6fa006..81cf3cbf 100644
--- a/core/ksync/src/tests.rs
+++ b/core/ksync/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for ksync using the unittest framework.
#![cfg(unittest)]
diff --git a/core/ktask/Cargo.toml b/core/ktask/Cargo.toml
index df8279d6..fb75553f 100644
--- a/core/ktask/Cargo.toml
+++ b/core/ktask/Cargo.toml
@@ -46,3 +46,4 @@ memaddr = { workspace = true }
percpu = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
+karch = { workspace = true }
diff --git a/core/ktask/src/api.rs b/core/ktask/src/api.rs
index 6ee7d198..58ddcf22 100644
--- a/core/ktask/src/api.rs
+++ b/core/ktask/src/api.rs
@@ -67,14 +67,6 @@ impl kspin::KernelGuardIf for KernelGuardIfImpl {
curr.enable_preempt(true);
}
}
-
- fn save_disable() -> usize {
- khal::irq::save_disable()
- }
-
- fn restore(flags: usize) {
- khal::irq::restore(flags);
- }
}
/// Gets the current task, or returns [`None`] if the current task is not
@@ -242,7 +234,7 @@ pub fn run_idle() -> ! {
loop {
yield_now();
trace!("idle task: waiting for IRQs...");
- khal::asm::await_interrupts();
+ karch::await_interrupts();
}
}
diff --git a/core/ktask/src/run_queue.rs b/core/ktask/src/run_queue.rs
index f344841d..13ddb245 100644
--- a/core/ktask/src/run_queue.rs
+++ b/core/ktask/src/run_queue.rs
@@ -521,7 +521,7 @@ impl RunQueue {
fn switch_to(&mut self, prev_task: CurrentTask, next_task: KtaskRef) {
// Make sure that IRQs are disabled by kernel guard or other means.
assert!(
- !khal::asm::is_enabled(),
+ !karch::local_irq_enabled(),
"IRQs must be disabled during scheduling"
);
trace!(
diff --git a/core/ktask/src/task.rs b/core/ktask/src/task.rs
index 4ad6a845..672846b6 100644
--- a/core/ktask/src/task.rs
+++ b/core/ktask/src/task.rs
@@ -693,7 +693,7 @@ extern "C" fn task_entry() -> ! {
crate::run_queue::clear_prev_task_on_cpu();
}
// Enable irq (if feature "irq" is enabled) before running the task entry function.
- khal::asm::enable_local();
+ karch::enable_local_irq();
let task = crate::current();
if let Some(entry) = task.entry.take() {
entry()
diff --git a/core/ktypes/src/lazy.rs b/core/ktypes/src/lazy.rs
index 94083e98..7b4d4b87 100644
--- a/core/ktypes/src/lazy.rs
+++ b/core/ktypes/src/lazy.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Synchronization primitives for lazy evaluation.
//!
//! Implementation adapted from the `SyncLazy` type of the standard library. See:
diff --git a/core/slab_allocator/src/lib.rs b/core/slab_allocator/src/lib.rs
index 1d89c68d..82110ddf 100644
--- a/core/slab_allocator/src/lib.rs
+++ b/core/slab_allocator/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Slab allocator for `no_std` systems. It uses multiple slabs with blocks of
//! different sizes and a [buddy_system_allocator] for blocks larger than 4096
//! bytes.
diff --git a/core/slab_allocator/src/slab.rs b/core/slab_allocator/src/slab.rs
index 428c4e46..46302c41 100644
--- a/core/slab_allocator/src/slab.rs
+++ b/core/slab_allocator/src/slab.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use alloc::alloc::{AllocError, Layout};
use super::SET_SIZE;
diff --git a/core/slab_allocator/src/tests.rs b/core/slab_allocator/src/tests.rs
index e99c6b9f..ad7dd3ea 100644
--- a/core/slab_allocator/src/tests.rs
+++ b/core/slab_allocator/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use alloc::alloc::Layout;
use core::mem::{align_of, size_of};
diff --git a/drivers/aarch64-pmuv3/src/lib.rs b/drivers/aarch64-pmuv3/src/lib.rs
index cda2f75f..55eeb0e8 100644
--- a/drivers/aarch64-pmuv3/src/lib.rs
+++ b/drivers/aarch64-pmuv3/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#![no_std]
pub mod pmuv3;
diff --git a/drivers/aarch64-pmuv3/src/pmuv3.rs b/drivers/aarch64-pmuv3/src/pmuv3.rs
index 1533157d..f4e225fc 100644
--- a/drivers/aarch64-pmuv3/src/pmuv3.rs
+++ b/drivers/aarch64-pmuv3/src/pmuv3.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! PMU Counter Configuration Module
use core::sync::atomic::{AtomicBool, Ordering};
diff --git a/drivers/aarch64-pmuv3/src/regs/macros.rs b/drivers/aarch64-pmuv3/src/regs/macros.rs
index 2d8a2627..04f3e4fe 100644
--- a/drivers/aarch64-pmuv3/src/regs/macros.rs
+++ b/drivers/aarch64-pmuv3/src/regs/macros.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
// Move to ARM register from system coprocessor register.
// MRS Xd, sysreg "Xd = sysreg"
#[macro_export]
diff --git a/drivers/aarch64-pmuv3/src/regs/mod.rs b/drivers/aarch64-pmuv3/src/regs/mod.rs
index 744c29ba..115a548d 100644
--- a/drivers/aarch64-pmuv3/src/regs/mod.rs
+++ b/drivers/aarch64-pmuv3/src/regs/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[macro_use]
pub mod macros;
diff --git a/drivers/aarch64-pmuv3/src/regs/pmccfiltr_el0.rs b/drivers/aarch64-pmuv3/src/regs/pmccfiltr_el0.rs
index 5d08086a..61fafb18 100644
--- a/drivers/aarch64-pmuv3/src/regs/pmccfiltr_el0.rs
+++ b/drivers/aarch64-pmuv3/src/regs/pmccfiltr_el0.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields,
diff --git a/drivers/aarch64-pmuv3/src/regs/pmcr_el0.rs b/drivers/aarch64-pmuv3/src/regs/pmcr_el0.rs
index bcb905b7..8ed93dfa 100644
--- a/drivers/aarch64-pmuv3/src/regs/pmcr_el0.rs
+++ b/drivers/aarch64-pmuv3/src/regs/pmcr_el0.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields,
diff --git a/drivers/aarch64-pmuv3/src/regs/pmuserenr_el0.rs b/drivers/aarch64-pmuv3/src/regs/pmuserenr_el0.rs
index 81678928..46a82bf2 100644
--- a/drivers/aarch64-pmuv3/src/regs/pmuserenr_el0.rs
+++ b/drivers/aarch64-pmuv3/src/regs/pmuserenr_el0.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields,
diff --git a/drivers/aarch64-pmuv3/src/regs/regs.rs b/drivers/aarch64-pmuv3/src/regs/regs.rs
index 467f69f8..50d6492c 100644
--- a/drivers/aarch64-pmuv3/src/regs/regs.rs
+++ b/drivers/aarch64-pmuv3/src/regs/regs.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use crate::define_pmu_register;
// define_pmu_register!(pmccfiltr_el0, PMCCFILTR_EL0, "PMCCFILTR_EL0");
define_pmu_register!(pmccntr_el0, PMCCNTR_EL0, "PMCCNTR_EL0");
diff --git a/drivers/display/src/tests.rs b/drivers/display/src/tests.rs
index 3b0992fb..adb50736 100644
--- a/drivers/display/src/tests.rs
+++ b/drivers/display/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for display drivers using the unittest framework.
#![cfg(unittest)]
diff --git a/drivers/kdriver/src/bus/pci.rs b/drivers/kdriver/src/bus/pci.rs
index 05929a69..6fa71c3f 100644
--- a/drivers/kdriver/src/bus/pci.rs
+++ b/drivers/kdriver/src/bus/pci.rs
@@ -5,8 +5,7 @@
//! PCI bus probing and BAR configuration.
use khal::mem::p2v;
use pci::{
- BarInfo, Cam, Command, ConfigurationAccess, DeviceFunction, HeaderType, MemoryBarType, MmioCam,
- PciRangeAllocator, PciRoot,
+ BarInfo, Cam, Command, DeviceFunction, HeaderType, MemoryBarType, PciRangeAllocator, PciRoot,
};
use crate::{AllDevices, prelude::*};
@@ -14,20 +13,14 @@ use crate::{AllDevices, prelude::*};
const PCI_BAR_NUM: u8 = 6;
/// Configure PCI BARs and enable the device.
-fn config_pci_device(
- root: &mut PciRoot,
+fn config_pci_device(
+ root: &mut PciRoot,
bdf: DeviceFunction,
allocator: &mut Option,
) -> DriverResult {
let mut bar = 0;
while bar < PCI_BAR_NUM {
- let info = match root.bar_info(bdf, bar).unwrap() {
- Some(info) => info,
- None => {
- bar += 1;
- continue;
- }
- };
+ let info = root.bar_info(bdf, bar).unwrap();
if let BarInfo::Memory {
address_type,
address,
@@ -51,14 +44,7 @@ fn config_pci_device(
}
// read the BAR info again after assignment.
- let info = match root.bar_info(bdf, bar).unwrap() {
- Some(info) => info,
- None => {
- bar += 1;
- continue;
- }
- };
- let takes_two = info.takes_two_entries();
+ let info = root.bar_info(bdf, bar).unwrap();
match info {
BarInfo::IO { address, size } => {
if address > 0 && size > 0 {
@@ -76,7 +62,7 @@ fn config_pci_device(
" BAR {}: MEM [{:#x}, {:#x}){}{}",
bar,
address,
- address + size,
+ address + size as u64,
if address_type == MemoryBarType::Width64 {
" 64bit"
} else {
@@ -89,7 +75,7 @@ fn config_pci_device(
}
bar += 1;
- if takes_two {
+ if info.takes_two_entries() {
bar += 1;
}
}
@@ -110,13 +96,11 @@ impl AllDevices {
let mut root = {
#[cfg(feature = "pci-mmio")]
{
- let cam = unsafe { MmioCam::new(base_vaddr.as_mut_ptr(), Cam::MmioCam) };
- PciRoot::new(cam)
+ unsafe { PciRoot::new(base_vaddr.as_mut_ptr(), Cam::MmioCam) }
}
#[cfg(not(feature = "pci-mmio"))]
{
- let cam = unsafe { MmioCam::new(base_vaddr.as_mut_ptr(), Cam::Ecam) };
- PciRoot::new(cam)
+ unsafe { PciRoot::new(base_vaddr.as_mut_ptr(), Cam::Ecam) }
}
};
diff --git a/drivers/kdriver/src/drivers.rs b/drivers/kdriver/src/drivers.rs
index ab85a393..50118379 100644
--- a/drivers/kdriver/src/drivers.rs
+++ b/drivers/kdriver/src/drivers.rs
@@ -8,7 +8,7 @@
use driver_base::DeviceKind;
#[cfg(feature = "bus-pci")]
-use pci::{ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, PciRoot};
+use pci::{DeviceFunction, DeviceFunctionInfo, PciRoot};
pub use super::dummy::*;
use crate::DeviceEnum;
@@ -30,8 +30,8 @@ pub trait DriverProbe {
#[cfg(bus = "pci")]
/// Probe a PCI device described by BDF and device info.
- fn probe_pci(
- _root: &mut PciRoot,
+ fn probe_pci(
+ _root: &mut PciRoot,
_bdf: DeviceFunction,
_dev_info: &DeviceFunctionInfo,
) -> Option {
@@ -171,8 +171,8 @@ cfg_if::cfg_if! {
register_net_driver!(IxgbeDriver, net::ixgbe::IxgbeNic);
impl DriverProbe for IxgbeDriver {
#[cfg(bus = "pci")]
- fn probe_pci(
- root: &mut pci::PciRoot,
+ fn probe_pci(
+ root: &mut pci::PciRoot,
bdf: pci::DeviceFunction,
dev_info: &pci::DeviceFunctionInfo,
) -> Option {
diff --git a/drivers/kdriver/src/virtio.rs b/drivers/kdriver/src/virtio.rs
index 66a31c5b..ef4e181d 100644
--- a/drivers/kdriver/src/virtio.rs
+++ b/drivers/kdriver/src/virtio.rs
@@ -16,10 +16,10 @@ use crate::{DeviceEnum, drivers::DriverProbe};
cfg_if! {
if #[cfg(bus = "pci")] {
- use pci::{ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, PciRoot};
+ use pci::{PciRoot, DeviceFunction, DeviceFunctionInfo};
type VirtIoTransport = virtio::PciTransport;
} else if #[cfg(bus = "mmio")] {
- type VirtIoTransport = virtio::MmioTransport<'static>;
+ type VirtIoTransport = virtio::MmioTransport;
}
}
@@ -139,8 +139,8 @@ impl DriverProbe for VirtIoDriver {
}
#[cfg(bus = "pci")]
- fn probe_pci(
- root: &mut PciRoot,
+ fn probe_pci(
+ root: &mut PciRoot,
bdf: DeviceFunction,
dev_info: &DeviceFunctionInfo,
) -> Option {
@@ -157,7 +157,7 @@ impl DriverProbe for VirtIoDriver {
}
if let Some((ty, transport, irq)) =
- virtio::probe_pci_device::(root, bdf, dev_info)
+ virtio::probe_pci_device::(root, bdf, dev_info)
&& ty == D::DEVICE_TYPE
{
match D::try_new(transport, Some(irq)) {
@@ -214,7 +214,7 @@ unsafe impl VirtIoHal for VirtIoHalImpl {
let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
let dma_info = kdma::DMAInfo {
cpu_addr: vaddr,
- bus_addr: kdma::DmaBusAddress::new(paddr),
+ bus_addr: kdma::DmaBusAddress::new(paddr as u64),
};
unsafe { kdma::deallocate_dma_memory(dma_info, layout) };
#[cfg(feature = "crosvm")]
@@ -226,8 +226,7 @@ unsafe impl VirtIoHal for VirtIoHalImpl {
#[inline]
unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull {
- let paddr_usize = paddr as usize;
- NonNull::new(p2v(paddr_usize.into()).as_mut_ptr()).unwrap()
+ NonNull::new(p2v(paddr.into()).as_mut_ptr()).unwrap()
}
#[allow(unused_variables)]
@@ -277,8 +276,7 @@ unsafe impl VirtIoHal for VirtIoHalImpl {
#[cfg(not(any(feature = "crosvm", feature = "sev")))]
{
let vaddr = buffer.as_ptr() as *mut u8 as usize;
- let paddr_usize: usize = khal::mem::v2p(vaddr.into()).into();
- paddr_usize as PhysAddr
+ khal::mem::v2p(vaddr.into()).into()
}
}
@@ -298,8 +296,7 @@ unsafe impl VirtIoHal for VirtIoHalImpl {
// If data flows from device to driver, copy back from shared buffer
if direction != BufferDirection::DriverToDevice {
- let paddr_usize = paddr as usize;
- let shared_ptr = p2v(paddr_usize.into()).as_ptr();
+ let shared_ptr = p2v(paddr.into()).as_ptr();
unsafe {
core::ptr::copy_nonoverlapping(shared_ptr, buffer.as_ptr() as *mut u8, len);
}
@@ -317,10 +314,7 @@ unsafe impl VirtIoHal for VirtIoHalImpl {
// Free the bounce buffer via kdma
let layout = Layout::from_size_align(aligned_size, PAGE_SIZE).unwrap();
let dma_info = kdma::DMAInfo {
- cpu_addr: {
- let paddr_usize = paddr as usize;
- NonNull::new(p2v(paddr_usize.into()).as_mut_ptr()).unwrap()
- },
+ cpu_addr: NonNull::new(p2v(paddr.into()).as_mut_ptr()).unwrap(),
bus_addr: kdma::DmaBusAddress::new(paddr as u64),
};
unsafe { kdma::deallocate_dma_memory(dma_info, layout) };
diff --git a/drivers/net/Cargo.toml b/drivers/net/Cargo.toml
index 00217f64..2b548132 100644
--- a/drivers/net/Cargo.toml
+++ b/drivers/net/Cargo.toml
@@ -19,5 +19,5 @@ driver_base = { workspace = true }
# fxmac_rs = { git = "https://github.com/elliott10/fxmac_rs.git", rev = "0dbc3916", optional = true }
# ixgbe-driver = { git = "https://github.com/KuangjuX/ixgbe-driver.git", rev = "8e5eb74", optional = true }
log = { workspace = true }
-spin = "0.9"
+ksync = { workspace = true }
unittest = { workspace = true }
diff --git a/drivers/net/src/net_buf.rs b/drivers/net/src/net_buf.rs
index 8db1bacb..8fa3410e 100644
--- a/drivers/net/src/net_buf.rs
+++ b/drivers/net/src/net_buf.rs
@@ -6,7 +6,7 @@
use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
use core::ptr::NonNull;
-use spin::Mutex;
+use ksync::Mutex;
use crate::{DriverError, DriverResult};
diff --git a/drivers/pci/Cargo.toml b/drivers/pci/Cargo.toml
index 73d2caf7..2c85df34 100644
--- a/drivers/pci/Cargo.toml
+++ b/drivers/pci/Cargo.toml
@@ -12,5 +12,4 @@ repository.workspace = true
categories.workspace = true
[dependencies]
-virtio-drivers.workspace = true
-kbuild_config.workspace = true
+virtio-drivers = { workspace = true }
diff --git a/drivers/pci/src/lib.rs b/drivers/pci/src/lib.rs
index 100d7f08..177c0c4b 100644
--- a/drivers/pci/src/lib.rs
+++ b/drivers/pci/src/lib.rs
@@ -13,8 +13,8 @@
#![no_std]
pub use virtio_drivers::transport::pci::bus::{
- BarInfo, Cam, CapabilityInfo, Command, ConfigurationAccess, DeviceFunction, DeviceFunctionInfo,
- HeaderType, MemoryBarType, MmioCam, PciError, PciRoot, Status,
+ BarInfo, Cam, CapabilityInfo, Command, DeviceFunction, DeviceFunctionInfo, HeaderType,
+ MemoryBarType, PciError, PciRoot, Status,
};
/// Used to allocate MMIO regions for PCI BARs.
diff --git a/drivers/virtio/Cargo.toml b/drivers/virtio/Cargo.toml
index 5a0c66a6..7fb60303 100644
--- a/drivers/virtio/Cargo.toml
+++ b/drivers/virtio/Cargo.toml
@@ -27,6 +27,5 @@ input = { workspace = true, optional = true }
net = { workspace = true, optional = true }
vsock = { workspace = true, optional = true }
log = { workspace = true }
-virtio-drivers.workspace = true
+virtio-drivers = { workspace = true }
unittest = { workspace = true }
-zerocopy = "0.8"
diff --git a/drivers/virtio/src/input.rs b/drivers/virtio/src/input.rs
index 08ba4663..92203285 100644
--- a/drivers/virtio/src/input.rs
+++ b/drivers/virtio/src/input.rs
@@ -75,8 +75,7 @@ impl InputDriverOps for VirtIoInputDev {
fn get_event_bits(&mut self, ty: EventType, out: &mut [u8]) -> DriverResult {
let read = self
.inner
- .query_config_select(InputConfigSelect::EvBits, ty as u8, out)
- .map_err(as_driver_error)?;
+ .query_config_select(InputConfigSelect::EvBits, ty as u8, out);
Ok(read != 0)
}
diff --git a/drivers/virtio/src/lib.rs b/drivers/virtio/src/lib.rs
index fa0b6e4c..9ae77335 100644
--- a/drivers/virtio/src/lib.rs
+++ b/drivers/virtio/src/lib.rs
@@ -56,7 +56,7 @@ pub use virtio_drivers::{
},
};
-use self::pci::{ConfigurationAccess, DeviceFunction, DeviceFunctionInfo, PciRoot};
+use self::pci::{DeviceFunction, DeviceFunctionInfo, PciRoot};
#[cfg(feature = "socket")]
pub use self::socket::VirtIoSocketDev;
@@ -66,14 +66,14 @@ pub use self::socket::VirtIoSocketDev;
/// for later operations. Otherwise, returns [`None`].
pub fn probe_mmio_device(
reg_base: *mut u8,
- reg_size: usize,
-) -> Option<(DeviceKind, MmioTransport<'static>)> {
+ _reg_size: usize,
+) -> Option<(DeviceKind, MmioTransport)> {
use core::ptr::NonNull;
use virtio_drivers::transport::mmio::VirtIOHeader;
let header = NonNull::new(reg_base as *mut VirtIOHeader).unwrap();
- let transport = unsafe { MmioTransport::new(header, reg_size) }.ok()?;
+ let transport = unsafe { MmioTransport::new(header) }.ok()?;
let dev_kind = as_device_kind(transport.device_type())?;
Some((dev_kind, transport))
}
@@ -82,8 +82,8 @@ pub fn probe_mmio_device(
///
/// If the device is recognized, returns the device type and a transport object
/// for later operations. Otherwise, returns [`None`].
-pub fn probe_pci_device(
- root: &mut PciRoot,
+pub fn probe_pci_device(
+ root: &mut PciRoot,
bdf: DeviceFunction,
dev_info: &DeviceFunctionInfo,
) -> Option<(DeviceKind, PciTransport, usize)> {
@@ -99,7 +99,7 @@ pub fn probe_pci_device(
const PCI_IRQ_BASE: usize = 0x23;
let dev_kind = virtio_device_type(dev_info).and_then(as_device_kind)?;
- let transport = PciTransport::new::(root, bdf).ok()?;
+ let transport = PciTransport::new::(root, bdf).ok()?;
let irq = PCI_IRQ_BASE + (bdf.device & 3) as usize;
Some((dev_kind, transport, irq))
}
@@ -137,7 +137,9 @@ pub(crate) const fn as_driver_error(e: virtio_drivers::Error) -> DriverError {
OutputBufferTooShort(_) | BufferTooShort | BufferTooLong(..) => {
DriverError::InvalidInput
}
- UnexpectedDataInPacket | PeerSocketShutdown => DriverError::Io,
+ UnexpectedDataInPacket | PeerSocketShutdown | NoResponseReceived | ConnectionFailed => {
+ DriverError::Io
+ }
InsufficientBufferSpaceInPeer => DriverError::WouldBlock,
RecycledWrongBuffer => DriverError::BadState,
},
diff --git a/drivers/virtio/src/mock_virtio.rs b/drivers/virtio/src/mock_virtio.rs
index aab9d2c2..f8465be6 100644
--- a/drivers/virtio/src/mock_virtio.rs
+++ b/drivers/virtio/src/mock_virtio.rs
@@ -1,10 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use core::{cell::RefCell, ptr::NonNull};
use virtio_drivers::{
- BufferDirection, Error, Hal, PhysAddr, Result,
- transport::{DeviceStatus, DeviceType, InterruptStatus, Transport},
+ BufferDirection, Hal, PhysAddr, Result,
+ transport::{DeviceStatus, DeviceType, Transport},
};
-use zerocopy::{FromBytes, Immutable, IntoBytes};
extern crate alloc;
use alloc::alloc::{Layout, alloc, dealloc};
@@ -20,7 +23,7 @@ unsafe impl Hal for MockHal {
panic!("MockHal: dma_alloc failed");
}
unsafe { ptr.write_bytes(0, pages * 4096) }; // Zero memory
- (ptr as PhysAddr, NonNull::new(ptr).unwrap())
+ (ptr as usize, NonNull::new(ptr).unwrap())
}
unsafe fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull, pages: usize) -> i32 {
@@ -111,50 +114,14 @@ impl Transport for MockTransport {
false
}
- fn ack_interrupt(&mut self) -> InterruptStatus {
- InterruptStatus::empty()
- }
-
- fn read_config_generation(&self) -> u32 {
- 0
+ fn ack_interrupt(&mut self) -> bool {
+ false
}
- fn read_config_space(&self, offset: usize) -> Result {
- let size = core::mem::size_of::();
- let config = self.config_space.borrow();
- if offset
- .checked_add(size)
- .is_none_or(|end| end > config.len())
- {
- return Err(Error::ConfigSpaceTooSmall);
- }
-
- let mut value = core::mem::MaybeUninit::::uninit();
+ fn config_space(&self) -> Result> {
unsafe {
- core::ptr::copy_nonoverlapping(
- config.as_ptr().add(offset),
- value.as_mut_ptr() as *mut u8,
- size,
- );
- Ok(value.assume_init())
- }
- }
-
- fn write_config_space(
- &mut self,
- offset: usize,
- value: T,
- ) -> Result<()> {
- let bytes = value.as_bytes();
- let mut config = self.config_space.borrow_mut();
- if offset
- .checked_add(bytes.len())
- .is_none_or(|end| end > config.len())
- {
- return Err(Error::ConfigSpaceTooSmall);
+ let ptr = self.config_space.borrow_mut().as_mut_ptr() as *mut T;
+ Ok(NonNull::new_unchecked(ptr))
}
-
- config[offset..offset + bytes.len()].copy_from_slice(bytes);
- Ok(())
}
}
diff --git a/fs/fatfs/src/boot_sector.rs b/fs/fatfs/src/boot_sector.rs
index f41a3157..d5f1e6d2 100644
--- a/fs/fatfs/src/boot_sector.rs
+++ b/fs/fatfs/src/boot_sector.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use core::slice;
use crate::{
diff --git a/fs/fatfs/src/dir.rs b/fs/fatfs/src/dir.rs
index 1e5f9a67..80809a83 100644
--- a/fs/fatfs/src/dir.rs
+++ b/fs/fatfs/src/dir.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(all(not(feature = "std"), feature = "alloc", feature = "lfn"))]
use alloc::vec::Vec;
#[cfg(feature = "lfn")]
diff --git a/fs/fatfs/src/dir_entry.rs b/fs/fatfs/src/dir_entry.rs
index 9bb1fb5c..4f8d6bb7 100644
--- a/fs/fatfs/src/dir_entry.rs
+++ b/fs/fatfs/src/dir_entry.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::String;
#[cfg(not(feature = "unicode"))]
diff --git a/fs/fatfs/src/error.rs b/fs/fatfs/src/error.rs
index ab2c4119..0749d034 100644
--- a/fs/fatfs/src/error.rs
+++ b/fs/fatfs/src/error.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
/// Error enum with all errors that can be returned by functions from this crate
///
/// Generic parameter `T` is a type of external error returned by the user provided storage
diff --git a/fs/fatfs/src/file.rs b/fs/fatfs/src/file.rs
index 0ddbe88f..d2ae76fb 100644
--- a/fs/fatfs/src/file.rs
+++ b/fs/fatfs/src/file.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use core::convert::TryFrom;
use crate::{
diff --git a/fs/fatfs/src/fs.rs b/fs/fatfs/src/fs.rs
index cb677c51..b5d87c5e 100644
--- a/fs/fatfs/src/fs.rs
+++ b/fs/fatfs/src/fs.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::String;
use core::{
diff --git a/fs/fatfs/src/io.rs b/fs/fatfs/src/io.rs
index 7e873700..b4bfe853 100644
--- a/fs/fatfs/src/io.rs
+++ b/fs/fatfs/src/io.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use crate::error::IoError;
/// Provides IO error as an associated type.
diff --git a/fs/fatfs/src/lib.rs b/fs/fatfs/src/lib.rs
index df68299b..4ec9374f 100644
--- a/fs/fatfs/src/lib.rs
+++ b/fs/fatfs/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! A FAT filesystem library implemented in Rust.
//!
//! # Usage
diff --git a/fs/fatfs/src/log_macros.rs b/fs/fatfs/src/log_macros.rs
index 36a195dc..5cb9eb48 100644
--- a/fs/fatfs/src/log_macros.rs
+++ b/fs/fatfs/src/log_macros.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! This module offers a convenient way to enable only a subset of logging levels
//! for just this `fatfs` crate only without changing the logging levels
//! of other crates in a given project.
diff --git a/fs/fatfs/src/table.rs b/fs/fatfs/src/table.rs
index abd345f4..eeed24f5 100644
--- a/fs/fatfs/src/table.rs
+++ b/fs/fatfs/src/table.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use core::{borrow::BorrowMut, marker::PhantomData};
use crate::{
diff --git a/fs/fatfs/src/time.rs b/fs/fatfs/src/time.rs
index daa72a20..259d935f 100644
--- a/fs/fatfs/src/time.rs
+++ b/fs/fatfs/src/time.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(feature = "chrono")]
use core::convert::TryFrom;
use core::fmt::Debug;
diff --git a/fs/fs-ng-vfs/src/test_path.rs b/fs/fs-ng-vfs/src/test_path.rs
index eef065a6..56ac6b1f 100644
--- a/fs/fs-ng-vfs/src/test_path.rs
+++ b/fs/fs-ng-vfs/src/test_path.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for Path and PathBuf.
#![cfg(unittest)]
diff --git a/fs/fs-ng-vfs/src/test_types.rs b/fs/fs-ng-vfs/src/test_types.rs
index a40d0f74..556fd1cb 100644
--- a/fs/fs-ng-vfs/src/test_types.rs
+++ b/fs/fs-ng-vfs/src/test_types.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#![cfg(unittest)]
use unittest::{assert_eq, def_test};
diff --git a/fs/kfs/src/fs/ext4/lwext4/fs.rs b/fs/kfs/src/fs/ext4/lwext4/fs.rs
index 5d1e5ecc..d6eefb53 100644
--- a/fs/kfs/src/fs/ext4/lwext4/fs.rs
+++ b/fs/kfs/src/fs/ext4/lwext4/fs.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use alloc::sync::Arc;
use core::cell::OnceCell;
diff --git a/fs/kfs/src/fs/ext4/lwext4/inode.rs b/fs/kfs/src/fs/ext4/lwext4/inode.rs
index d701a2c2..84a2fed3 100644
--- a/fs/kfs/src/fs/ext4/lwext4/inode.rs
+++ b/fs/kfs/src/fs/ext4/lwext4/inode.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use alloc::{borrow::ToOwned, string::String, sync::Arc};
use core::{any::Any, task::Context};
diff --git a/fs/kfs/src/fs/ext4/lwext4/mod.rs b/fs/kfs/src/fs/ext4/lwext4/mod.rs
index 26c6fd34..a5986b37 100644
--- a/fs/kfs/src/fs/ext4/lwext4/mod.rs
+++ b/fs/kfs/src/fs/ext4/lwext4/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
mod fs;
mod inode;
mod util;
diff --git a/fs/kfs/src/fs/ext4/lwext4/util.rs b/fs/kfs/src/fs/ext4/lwext4/util.rs
index d6806f81..0f5cb541 100644
--- a/fs/kfs/src/fs/ext4/lwext4/util.rs
+++ b/fs/kfs/src/fs/ext4/lwext4/util.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use fs_ng_vfs::{NodeType, VfsError};
use kerrno::LinuxError;
use lwext4_rust::{Ext4Error, InodeType, SystemHal};
diff --git a/fs/kfs/src/fs/ext4/mod.rs b/fs/kfs/src/fs/ext4/mod.rs
index 0e02f325..40edad9e 100644
--- a/fs/kfs/src/fs/ext4/mod.rs
+++ b/fs/kfs/src/fs/ext4/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(feature = "ext4-rsext4")]
mod rsext4;
diff --git a/fs/kfs/src/test_path_resolver.rs b/fs/kfs/src/test_path_resolver.rs
index 9bdf7e0b..e5886fab 100644
--- a/fs/kfs/src/test_path_resolver.rs
+++ b/fs/kfs/src/test_path_resolver.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for PathResolver.
#![cfg(unittest)]
diff --git a/fs/kfs/src/test_working_context.rs b/fs/kfs/src/test_working_context.rs
index 962f4cb7..0ae90bed 100644
--- a/fs/kfs/src/test_working_context.rs
+++ b/fs/kfs/src/test_working_context.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for WorkingContext.
#![cfg(unittest)]
diff --git a/fs/rsext4/src/api.rs b/fs/rsext4/src/api.rs
index 593bddfb..01ffe5c7 100644
--- a/fs/rsext4/src/api.rs
+++ b/fs/rsext4/src/api.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # ext4 API
//!
//! 提供 ext4 文件系统的高级 API 接口,包括文件系统挂载、文件操作等功能。
diff --git a/fs/rsext4/src/bitmap.rs b/fs/rsext4/src/bitmap.rs
index 72e42641..343b5934 100644
--- a/fs/rsext4/src/bitmap.rs
+++ b/fs/rsext4/src/bitmap.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 位图操作模块
//!
//! 提供对块和inode位图的操作,用于跟踪块和inode的分配状态。
diff --git a/fs/rsext4/src/bitmap_cache.rs b/fs/rsext4/src/bitmap_cache.rs
index e03066db..d1cec8f8 100644
--- a/fs/rsext4/src/bitmap_cache.rs
+++ b/fs/rsext4/src/bitmap_cache.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! 位图缓存模块
use alloc::{collections::BTreeMap, vec::Vec};
diff --git a/fs/rsext4/src/blockdev.rs b/fs/rsext4/src/blockdev.rs
index 1daa2412..870bd378 100644
--- a/fs/rsext4/src/blockdev.rs
+++ b/fs/rsext4/src/blockdev.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 块设备实现
//!
//! 定义了块设备的抽象接口和实现,为文件系统提供底层存储支持
diff --git a/fs/rsext4/src/blockgroup_description.rs b/fs/rsext4/src/blockgroup_description.rs
index 882ff2bb..1193c8ec 100644
--- a/fs/rsext4/src/blockgroup_description.rs
+++ b/fs/rsext4/src/blockgroup_description.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 块组描述符模块
//!
//! 定义了 ext4 文件系统的块组描述符结构和相关操作。
diff --git a/fs/rsext4/src/bmalloc.rs b/fs/rsext4/src/bmalloc.rs
index b5e7c8b7..782d5a4e 100644
--- a/fs/rsext4/src/bmalloc.rs
+++ b/fs/rsext4/src/bmalloc.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! 位图分配器模块
use crate::{bitmap::*, blockgroup_description::*, superblock::*};
diff --git a/fs/rsext4/src/config.rs b/fs/rsext4/src/config.rs
index e82071f6..de2299f6 100644
--- a/fs/rsext4/src/config.rs
+++ b/fs/rsext4/src/config.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 配置常量定义
//!
//! 定义了 ext4 文件系统实现中使用的各种配置常量,包括块大小、
diff --git a/fs/rsext4/src/datablock_cache.rs b/fs/rsext4/src/datablock_cache.rs
index 4cb471f0..65097320 100644
--- a/fs/rsext4/src/datablock_cache.rs
+++ b/fs/rsext4/src/datablock_cache.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! 数据块缓存模块
//!
//! 提供文件和目录数据块的缓存管理,支持延迟写回和LRU淘汰
diff --git a/fs/rsext4/src/dir.rs b/fs/rsext4/src/dir.rs
index 72a80af6..5ae903dc 100644
--- a/fs/rsext4/src/dir.rs
+++ b/fs/rsext4/src/dir.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 目录操作模块
//!
//! 提供对 ext4 文件系统中目录的创建、删除、遍历等操作功能。
diff --git a/fs/rsext4/src/disknode.rs b/fs/rsext4/src/disknode.rs
index aac26f37..88588715 100644
--- a/fs/rsext4/src/disknode.rs
+++ b/fs/rsext4/src/disknode.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 磁盘节点模块
//!
//! 定义了 ext4 文件系统的 inode 结构和相关操作。
diff --git a/fs/rsext4/src/endian.rs b/fs/rsext4/src/endian.rs
index ee85cfb3..58e76d7a 100644
--- a/fs/rsext4/src/endian.rs
+++ b/fs/rsext4/src/endian.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 字节序转换辅助模块
//!
//! Ext4 磁盘格式使用小端序(Little Endian)
diff --git a/fs/rsext4/src/entries.rs b/fs/rsext4/src/entries.rs
index b742ec41..69a79847 100644
--- a/fs/rsext4/src/entries.rs
+++ b/fs/rsext4/src/entries.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 目录条目模块
//!
//! 定义了 ext4 文件系统中目录条目的数据结构和操作。
diff --git a/fs/rsext4/src/error.rs b/fs/rsext4/src/error.rs
index 06956b5f..4bbbbcc2 100644
--- a/fs/rsext4/src/error.rs
+++ b/fs/rsext4/src/error.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 错误处理模块
//!
//! 定义了 rsext4 库中使用的所有错误类型,提供清晰的错误信息以便调试和处理
diff --git a/fs/rsext4/src/ext4.rs b/fs/rsext4/src/ext4.rs
index 4a45de6f..337014de 100644
--- a/fs/rsext4/src/ext4.rs
+++ b/fs/rsext4/src/ext4.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # Ext4 文件系统主调用入口
//!
//! 提供 ext4 文件系统的核心实现,包括文件系统挂载、卸载、文件操作等高层接口。
diff --git a/fs/rsext4/src/extents_tree.rs b/fs/rsext4/src/extents_tree.rs
index e9e2add5..8be3cee3 100644
--- a/fs/rsext4/src/extents_tree.rs
+++ b/fs/rsext4/src/extents_tree.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # Extents 树模块
//!
//! 实现 ext4 文件系统的 extents 功能,用于高效管理文件的连续块分配。
diff --git a/fs/rsext4/src/file.rs b/fs/rsext4/src/file.rs
index e60d7a92..235517c6 100644
--- a/fs/rsext4/src/file.rs
+++ b/fs/rsext4/src/file.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 文件操作模块
//!
//! 提供对 ext4 文件系统中文件的读写、创建、删除等操作功能。
diff --git a/fs/rsext4/src/hashtree.rs b/fs/rsext4/src/hashtree.rs
index 1e9d9d3e..470e983a 100644
--- a/fs/rsext4/src/hashtree.rs
+++ b/fs/rsext4/src/hashtree.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 目录条目 HashTree 实现
//!
//! 提供基于哈希树的目录查找功能,替代线性搜索以提高大型目录的性能
diff --git a/fs/rsext4/src/inodetable_cache.rs b/fs/rsext4/src/inodetable_cache.rs
index 5788c288..4cc26566 100644
--- a/fs/rsext4/src/inodetable_cache.rs
+++ b/fs/rsext4/src/inodetable_cache.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Inode表缓存模块
//!
//! 提供inode结构的缓存管理,支持延迟写回和LRU淘汰
diff --git a/fs/rsext4/src/jbd2/jbd2.rs b/fs/rsext4/src/jbd2/jbd2.rs
index d4883052..8d0d9a93 100644
--- a/fs/rsext4/src/jbd2/jbd2.rs
+++ b/fs/rsext4/src/jbd2/jbd2.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # JBD2 日志系统实现
//!
//! 实现了 ext4 文件系统的日志功能,确保事务的原子性和一致性。
diff --git a/fs/rsext4/src/jbd2/jbdstruct.rs b/fs/rsext4/src/jbd2/jbdstruct.rs
index 3d5edb9a..9104a509 100644
--- a/fs/rsext4/src/jbd2/jbdstruct.rs
+++ b/fs/rsext4/src/jbd2/jbdstruct.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # JBD2 数据结构定义
//!
//! 定义了 JBD2 日志系统使用的各种数据结构。
diff --git a/fs/rsext4/src/jbd2/mod.rs b/fs/rsext4/src/jbd2/mod.rs
index 28572694..132e6119 100644
--- a/fs/rsext4/src/jbd2/mod.rs
+++ b/fs/rsext4/src/jbd2/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # JBD2 日志系统模块
//!
//! 提供 ext4 文件系统的日志功能,确保文件系统的一致性和可靠性。
diff --git a/fs/rsext4/src/lib.rs b/fs/rsext4/src/lib.rs
index ec2053bb..123537e1 100644
--- a/fs/rsext4/src/lib.rs
+++ b/fs/rsext4/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # ext4_backend
//!
//! ext4 文件系统的核心实现模块,提供对 ext4 文件系统的底层操作支持。
diff --git a/fs/rsext4/src/loopfile.rs b/fs/rsext4/src/loopfile.rs
index 6cde2bfe..c1a637dc 100644
--- a/fs/rsext4/src/loopfile.rs
+++ b/fs/rsext4/src/loopfile.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 文件遍历和操作模块
//!
//! 提供文件内容读取、块解析等功能。
diff --git a/fs/rsext4/src/superblock.rs b/fs/rsext4/src/superblock.rs
index cb82f7c0..8a7a8d9b 100644
--- a/fs/rsext4/src/superblock.rs
+++ b/fs/rsext4/src/superblock.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 超级块实现模块
//!
//! 定义了 ext4 文件系统的超级块结构,包含文件系统的基本元数据和参数。
diff --git a/fs/rsext4/src/tool.rs b/fs/rsext4/src/tool.rs
index 2010ca27..3e6dd7ed 100644
--- a/fs/rsext4/src/tool.rs
+++ b/fs/rsext4/src/tool.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! # 工具函数模块
//!
//! 提供各种辅助函数,如 UUID 生成等。
diff --git a/init/kruntime/Cargo.toml b/init/kruntime/Cargo.toml
index 71e82037..0d5f24af 100644
--- a/init/kruntime/Cargo.toml
+++ b/init/kruntime/Cargo.toml
@@ -54,3 +54,4 @@ kinit_setup.workspace = true
indoc = "2"
percpu.workspace = true
kbuild_config = { workspace = true }
+karch = { workspace = true }
diff --git a/init/kruntime/src/lib.rs b/init/kruntime/src/lib.rs
index 67151deb..88bc9658 100644
--- a/init/kruntime/src/lib.rs
+++ b/init/kruntime/src/lib.rs
@@ -320,5 +320,5 @@ fn init_interrupt() {
});
// Enable IRQs before starting app
- khal::asm::enable_local();
+ karch::enable_local_irq();
}
diff --git a/init/kruntime/src/mp.rs b/init/kruntime/src/mp.rs
index a20b2a0d..6e0c1f8d 100644
--- a/init/kruntime/src/mp.rs
+++ b/init/kruntime/src/mp.rs
@@ -66,7 +66,7 @@ pub fn rust_main_secondary(cpu_id: usize) -> ! {
#[cfg(feature = "pmu")]
khal::irq::enable(kbuild_config::PMU_IRQ, true);
- khal::asm::enable_local();
+ karch::enable_local_irq();
#[cfg(feature = "watchdog")]
watchdog::init_secondary();
diff --git a/io/kio/src/test_cursor.rs b/io/kio/src/test_cursor.rs
index 476da5aa..f9a0c7d3 100644
--- a/io/kio/src/test_cursor.rs
+++ b/io/kio/src/test_cursor.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for Cursor.
#![cfg(unittest)]
diff --git a/io/kio/src/test_iobuf.rs b/io/kio/src/test_iobuf.rs
index e122abad..53d7c047 100644
--- a/io/kio/src/test_iobuf.rs
+++ b/io/kio/src/test_iobuf.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for IoBuf and IoBufMut.
#![cfg(unittest)]
diff --git a/io/kio/src/test_seek.rs b/io/kio/src/test_seek.rs
index d019f70d..37a56a05 100644
--- a/io/kio/src/test_seek.rs
+++ b/io/kio/src/test_seek.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for Seek operations.
#![cfg(unittest)]
diff --git a/mm/memspace/Cargo.toml b/mm/memspace/Cargo.toml
index 36d5aa31..6060ad99 100644
--- a/mm/memspace/Cargo.toml
+++ b/mm/memspace/Cargo.toml
@@ -28,3 +28,4 @@ memset = { workspace = true }
page_table = { workspace = true, optional = true }
unittest.workspace = true
kbuild_config = { workspace = true }
+karch = { workspace = true }
diff --git a/mm/memspace/src/lib.rs b/mm/memspace/src/lib.rs
index 5d570a86..ccb41a51 100644
--- a/mm/memspace/src/lib.rs
+++ b/mm/memspace/src/lib.rs
@@ -106,16 +106,16 @@ pub fn init_memory_management() {
debug!("root: {:?}", root);
}
}
- unsafe { khal::asm::write_kernel_page_table(root) };
+ unsafe { karch::write_kernel_page_table(root) };
// flush all TLB
- khal::asm::flush_tlb(None);
+ karch::flush_tlb(None);
}
/// Initializes kernel paging for secondary CPUs.
pub fn init_memory_management_secondary() {
- unsafe { khal::asm::write_kernel_page_table(kernel_page_table_root()) };
+ unsafe { karch::write_kernel_page_table(kernel_page_table_root()) };
// flush all TLB
- khal::asm::flush_tlb(None);
+ karch::flush_tlb(None);
}
#[cfg(unittest)]
diff --git a/mm/page_table/Cargo.toml b/mm/page_table/Cargo.toml
index cf9264db..00176e89 100644
--- a/mm/page_table/Cargo.toml
+++ b/mm/page_table/Cargo.toml
@@ -20,18 +20,8 @@ bitmaps = { version = "3.2", default-features = false, optional = true }
log = "0.4"
memaddr = { workspace = true }
kerrno = { workspace = true, optional = true }
+karch = { workspace = true }
unittest.workspace = true
[target.'cfg(target_arch = "x86_64")'.dependencies]
x86_64 = { workspace = true }
-
-[target.'cfg(target_arch = "aarch64")'.dependencies]
-aarch64-cpu = "10.0"
-
-[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
-riscv = "0.14"
-
-[target.'cfg(target_arch = "loongarch64")'.dependencies]
-loongArch64 = "0.2.4"
-aarch64-cpu = "9.4"
-tock-registers = "0.9"
diff --git a/mm/page_table/src/arch/aarch64.rs b/mm/page_table/src/arch/aarch64.rs
index d766e3f4..67eb2cfc 100644
--- a/mm/page_table/src/arch/aarch64.rs
+++ b/mm/page_table/src/arch/aarch64.rs
@@ -2,7 +2,7 @@
// Copyright 2025 KylinSoft Co., Ltd.
// See LICENSES for license details.
-use core::{arch::asm, fmt};
+use core::fmt;
use memaddr::{PhysAddr, VirtAddr};
@@ -226,14 +226,7 @@ impl PagingMetaData for A64PagingMetaData {
#[inline]
fn flush_tlb(vaddr: Option) {
- unsafe {
- if let Some(vaddr) = vaddr {
- const VA_MASK: usize = (1 << 44) - 1;
- asm!("dsb ishst; tlbi vaae1is, {}; dsb ish; isb", in(reg) ((vaddr.as_usize() >> 12) & VA_MASK))
- } else {
- asm!("dsb ishst; tlbi vmalle1is; dsb ish; isb")
- }
- }
+ karch::flush_tlb(vaddr);
}
}
diff --git a/mm/page_table/src/arch/loongarch64.rs b/mm/page_table/src/arch/loongarch64.rs
index 5c155b9e..5dcc9884 100644
--- a/mm/page_table/src/arch/loongarch64.rs
+++ b/mm/page_table/src/arch/loongarch64.rs
@@ -2,7 +2,7 @@
// Copyright 2025 KylinSoft Co., Ltd.
// See LICENSES for license details.
-use core::{arch::asm, fmt};
+use core::fmt;
use memaddr::{PhysAddr, VirtAddr};
@@ -177,15 +177,7 @@ impl PagingMetaData for LA64MetaData {
const VA_MAX_BITS: usize = 48;
fn flush_tlb(vaddr: Option) {
- if let Some(vaddr) = vaddr {
- unsafe {
- asm!("invtlb 0x01, $r0, {}", in(reg) vaddr.as_usize());
- }
- } else {
- unsafe {
- asm!("invtlb 0x00, $r0, $r0");
- }
- }
+ karch::flush_tlb(vaddr);
}
}
diff --git a/mm/page_table/src/arch/riscv.rs b/mm/page_table/src/arch/riscv.rs
index 145a2152..40e1e1f6 100644
--- a/mm/page_table/src/arch/riscv.rs
+++ b/mm/page_table/src/arch/riscv.rs
@@ -146,11 +146,7 @@ pub trait SvVirtAddr: memaddr::MemoryAddr + Send + Sync {
impl SvVirtAddr for VirtAddr {
#[inline]
fn flush_tlb(vaddr: Option) {
- if let Some(vaddr) = vaddr {
- riscv::asm::sfence_vma(0, vaddr.as_usize());
- } else {
- riscv::asm::sfence_vma_all();
- }
+ karch::flush_tlb(vaddr);
}
}
diff --git a/mm/page_table/src/arch/x86_64.rs b/mm/page_table/src/arch/x86_64.rs
index 42a4ca10..08a909aa 100644
--- a/mm/page_table/src/arch/x86_64.rs
+++ b/mm/page_table/src/arch/x86_64.rs
@@ -187,11 +187,7 @@ impl PagingMetaData for X64PagingMetaData {
#[inline]
fn flush_tlb(vaddr: Option) {
- if let Some(vaddr) = vaddr {
- x86_64::instructions::tlb::flush(x86_64::VirtAddr::new(vaddr.as_usize() as u64));
- } else {
- x86_64::instructions::tlb::flush_all();
- }
+ karch::flush_tlb(vaddr);
}
}
diff --git a/net/knet/src/test_options.rs b/net/knet/src/test_options.rs
index e28948db..16e85531 100644
--- a/net/knet/src/test_options.rs
+++ b/net/knet/src/test_options.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for socket options.
#![cfg(unittest)]
diff --git a/net/knet/src/test_state.rs b/net/knet/src/test_state.rs
index 23142622..618c89e5 100644
--- a/net/knet/src/test_state.rs
+++ b/net/knet/src/test_state.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for socket state management.
#![cfg(unittest)]
diff --git a/platforms/aarch64-crosvm-virt/Cargo.toml b/platforms/aarch64-crosvm-virt/Cargo.toml
index 5f3cf026..c01d1783 100644
--- a/platforms/aarch64-crosvm-virt/Cargo.toml
+++ b/platforms/aarch64-crosvm-virt/Cargo.toml
@@ -19,14 +19,15 @@ page_table = { workspace = true }
kspin = "0.1"
dw_apb_uart = "0.1"
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
aarch64-peripherals = { workspace = true, default-features = false, features = ["gicv3"] }
aarch64-cpu = "10.0"
rs_fdtree = { workspace = true }
-spin = "0.9"
lazyinit = "0.2"
arm-gic.workspace = true
kbuild_config = { workspace = true }
+ktypes = { workspace = true }
[package.metadata.docs.rs]
targets = ["aarch64-unknown-none"]
diff --git a/platforms/aarch64-crosvm-virt/src/boot.rs b/platforms/aarch64-crosvm-virt/src/boot.rs
index 2b3558b5..5a47edf2 100644
--- a/platforms/aarch64-crosvm-virt/src/boot.rs
+++ b/platforms/aarch64-crosvm-virt/src/boot.rs
@@ -61,7 +61,7 @@ extern "C" fn kernel_main_test() {
/// Enable FP/SIMD usage if supported by build features.
unsafe fn enable_fp() {
#[cfg(feature = "fp-simd")]
- kcpu::instrs::enable_fp();
+ karch::enable_fp();
}
#[unsafe(naked)]
#[unsafe(no_mangle)]
diff --git a/platforms/aarch64-crosvm-virt/src/fdt.rs b/platforms/aarch64-crosvm-virt/src/fdt.rs
index 671d3a3a..e8481fe9 100644
--- a/platforms/aarch64-crosvm-virt/src/fdt.rs
+++ b/platforms/aarch64-crosvm-virt/src/fdt.rs
@@ -4,9 +4,9 @@
//! Device tree parsing helpers for the platform.
use kplat::memory::{VirtAddr, p2v, pa};
+use ktypes::Once;
use log::*;
use rs_fdtree::{InterruptController, LinuxFdt};
-use spin::Once;
pub static FDT: Once = Once::new();
/// Parse and cache the FDT pointed to by the bootloader.
pub(crate) fn init_fdt(fdt_paddr: VirtAddr) {
diff --git a/platforms/aarch64-crosvm-virt/src/gicv3.rs b/platforms/aarch64-crosvm-virt/src/gicv3.rs
index 1570a5f2..fdc73904 100644
--- a/platforms/aarch64-crosvm-virt/src/gicv3.rs
+++ b/platforms/aarch64-crosvm-virt/src/gicv3.rs
@@ -3,10 +3,7 @@
// See LICENSES for license details.
//! GICv3 initialization and IRQ routing helpers.
-use core::{
- arch::asm,
- sync::atomic::{AtomicBool, Ordering},
-};
+use core::sync::atomic::{AtomicBool, Ordering};
use aarch64_cpu::registers::*;
use arm_gic::gicv3::*;
@@ -228,29 +225,6 @@ pub fn dispatch_irq_irq(_unused: usize) -> Option {
}
Some(irq)
}
-#[inline]
-pub fn enable_local() {
- unsafe { asm!("msr daifclr, #2") };
-}
-#[inline]
-pub fn disable_local() {
- unsafe { asm!("msr daifset, #2") };
-}
-#[inline]
-pub fn is_enabled() -> bool {
- !DAIF.matches_all(DAIF::I::Masked)
-}
-#[inline]
-pub fn save_disable() -> usize {
- let flags: usize;
- unsafe { asm!("mrs {}, daif", out(reg) flags) };
- disable_local();
- flags
-}
-#[inline]
-pub fn restore(flags: usize) {
- unsafe { asm!("msr daif, {}", in(reg) flags) };
-}
#[macro_export]
macro_rules! irq_if_impl {
($name:ident) => {
@@ -280,26 +254,6 @@ macro_rules! irq_if_impl {
fn set_prio(_irq: usize, _priority: u8) {
todo!()
}
-
- fn save_disable() -> usize {
- $crate::gicv3::save_disable()
- }
-
- fn restore(flag: usize) {
- $crate::gicv3::restore(flag);
- }
-
- fn enable_local() {
- $crate::gicv3::enable_local();
- }
-
- fn disable_local() {
- $crate::gicv3::disable_local();
- }
-
- fn is_enabled() -> bool {
- $crate::gicv3::is_enabled()
- }
}
};
}
diff --git a/platforms/aarch64-crosvm-virt/src/mem.rs b/platforms/aarch64-crosvm-virt/src/mem.rs
index e79bfd29..04269f31 100644
--- a/platforms/aarch64-crosvm-virt/src/mem.rs
+++ b/platforms/aarch64-crosvm-virt/src/mem.rs
@@ -7,8 +7,8 @@ use core::sync::atomic::{AtomicUsize, Ordering};
use kbuild_config::{MMIO_RANGES, PHYS_MEM_BASE, PHYS_MEM_SIZE, PHYS_VIRT_OFFSET};
use kplat::memory::{HwMemory, MemRange, PhysAddr, VirtAddr, pa, va};
+use ktypes::Once;
use rs_fdtree::LinuxFdt;
-use spin::Once;
const FDT_MEM_SIZE: usize = 0x20_0000;
static FDT_MEM_BASE: AtomicUsize = AtomicUsize::new(0);
diff --git a/platforms/aarch64-crosvm-virt/src/psci.rs b/platforms/aarch64-crosvm-virt/src/psci.rs
index 5d92e078..1208fdae 100644
--- a/platforms/aarch64-crosvm-virt/src/psci.rs
+++ b/platforms/aarch64-crosvm-virt/src/psci.rs
@@ -4,7 +4,7 @@
//! PSCI wrappers and KVM guard-granule helpers.
use kplat::psci::PsciOp;
-use spin::Once;
+use ktypes::Once;
use crate::serial::{boot_print_str, boot_print_usize};
pub static GUARD_GRANULE: Once = Once::new();
diff --git a/platforms/aarch64-peripherals/Cargo.toml b/platforms/aarch64-peripherals/Cargo.toml
index ec4a2e8d..8b92f390 100644
--- a/platforms/aarch64-peripherals/Cargo.toml
+++ b/platforms/aarch64-peripherals/Cargo.toml
@@ -29,6 +29,7 @@ arm-gic-driver = "0.15"
uart_16550 = "0.4"
arm_pl031 = "0.2"
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
aarch64-pmuv3 = { workspace = true, optional = true }
percpu = { workspace = true }
diff --git a/platforms/aarch64-peripherals/src/gic.rs b/platforms/aarch64-peripherals/src/gic.rs
index 8e9612c1..5b2aacb2 100644
--- a/platforms/aarch64-peripherals/src/gic.rs
+++ b/platforms/aarch64-peripherals/src/gic.rs
@@ -3,11 +3,11 @@
// See LICENSES for license details.
//! GIC interrupt controller integration for AArch64 platforms.
+#[cfg(feature = "pmr")]
use core::arch::asm;
#[cfg(feature = "pmr")]
use core::sync::atomic::{AtomicBool, Ordering};
-use aarch64_cpu::registers::{DAIF, Readable};
#[cfg(all(feature = "gicv2", not(feature = "gicv3")))]
use arm_gic_driver::v2::*;
#[cfg(feature = "gicv3")]
@@ -244,82 +244,6 @@ pub fn notify_cpu(interrupt_id: usize, target: TargetCpu) {
}
}
}
-/// Enable local IRQ handling.
-#[cfg(not(feature = "pmr"))]
-#[inline]
-pub fn enable_local() {
- unsafe { asm!("msr daifclr, #2") };
-}
-/// Disable local IRQ handling.
-#[cfg(not(feature = "pmr"))]
-#[inline]
-pub fn disable_local() {
- unsafe { asm!("msr daifset, #2") };
-}
-/// Test whether local IRQs are enabled.
-#[cfg(not(feature = "pmr"))]
-#[inline]
-pub fn is_enabled() -> bool {
- !DAIF.matches_all(DAIF::I::Masked)
-}
-/// Save flags and disable local IRQ handling.
-#[cfg(not(feature = "pmr"))]
-#[inline]
-pub fn save_disable() -> usize {
- let flags: usize;
- unsafe { asm!("mrs {}, daif", out(reg) flags) };
- disable_local();
- flags
-}
-/// Restore local IRQ flags previously saved.
-#[cfg(not(feature = "pmr"))]
-#[inline]
-pub fn restore(flags: usize) {
- unsafe { asm!("msr daif, {}", in(reg) flags) };
-}
-/// Enable local IRQ handling with PMR unmasking.
-#[cfg(feature = "pmr")]
-#[inline]
-pub fn enable_local() {
- set_prio_mask(0xff);
- unsafe { asm!("msr daifclr, #2") };
-}
-/// Disable local IRQ handling while keeping PMR state.
-#[cfg(feature = "pmr")]
-#[inline]
-pub fn disable_local() {
- open_high_priority_irq_mode();
-}
-/// Test whether local IRQs are enabled given PMR state.
-#[cfg(feature = "pmr")]
-#[inline]
-pub fn is_enabled() -> bool {
- !DAIF.matches_all(DAIF::I::Masked) && get_priority_mask() > 0xa0
-}
-/// Save PMR/flags and disable local IRQ handling.
-#[cfg(feature = "pmr")]
-#[inline]
-pub fn save_disable() -> usize {
- if is_gic_initialized() {
- let pmr = get_priority_mask();
- set_prio_mask(0x80);
- pmr as usize
- } else {
- let flags: usize;
- unsafe { asm!("mrs {}, daif; msr daifset, #2", out(reg) flags) };
- flags
- }
-}
-/// Restore PMR/flags previously saved.
-#[cfg(feature = "pmr")]
-#[inline]
-pub fn restore(flags: usize) {
- if is_gic_initialized() {
- set_prio_mask(flags as u8);
- } else {
- unsafe { asm!("msr daif, {}", in(reg) flags) };
- }
-}
/// Implement `kplat::interrupts::IntrManager` using this GIC backend.
#[allow(clippy::crate_in_macro_def)]
#[macro_export]
@@ -352,26 +276,6 @@ macro_rules! irq_if_impl {
fn set_prio(irq: usize, priority: u8) {
$crate::gic::set_prio(irq, priority);
}
-
- fn save_disable() -> usize {
- $crate::gic::save_disable()
- }
-
- fn restore(flag: usize) {
- $crate::gic::restore(flag);
- }
-
- fn enable_local() {
- $crate::gic::enable_local();
- }
-
- fn disable_local() {
- $crate::gic::disable_local();
- }
-
- fn is_enabled() -> bool {
- $crate::gic::is_enabled()
- }
}
};
}
diff --git a/platforms/aarch64-peripherals/src/psci.rs b/platforms/aarch64-peripherals/src/psci.rs
index abe8cae6..60d108cd 100644
--- a/platforms/aarch64-peripherals/src/psci.rs
+++ b/platforms/aarch64-peripherals/src/psci.rs
@@ -99,7 +99,7 @@ pub fn shutdown() -> ! {
psci_call(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0).ok();
warn!("It should shutdown!");
loop {
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
}
}
/// Power on a target CPU with the given entry point and argument.
diff --git a/platforms/aarch64-qemu-virt/Cargo.toml b/platforms/aarch64-qemu-virt/Cargo.toml
index c1b8ceb4..e5b13ce0 100644
--- a/platforms/aarch64-qemu-virt/Cargo.toml
+++ b/platforms/aarch64-qemu-virt/Cargo.toml
@@ -20,6 +20,7 @@ log = "0.4"
page_table = { workspace = true }
aarch64-peripherals = { workspace = true, default-features = false, features = ["gicv2"]}
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
diff --git a/platforms/aarch64-qemu-virt/src/boot.rs b/platforms/aarch64-qemu-virt/src/boot.rs
index 828298ba..d3dacd3b 100644
--- a/platforms/aarch64-qemu-virt/src/boot.rs
+++ b/platforms/aarch64-qemu-virt/src/boot.rs
@@ -32,7 +32,7 @@ unsafe fn init_boot_page_table() {
}
unsafe fn enable_fp() {
#[cfg(feature = "fp-simd")]
- kcpu::instrs::enable_fp();
+ karch::enable_fp();
}
#[unsafe(naked)]
#[unsafe(no_mangle)]
diff --git a/platforms/aarch64-raspi/Cargo.toml b/platforms/aarch64-raspi/Cargo.toml
index 24740f46..8c7f393b 100644
--- a/platforms/aarch64-raspi/Cargo.toml
+++ b/platforms/aarch64-raspi/Cargo.toml
@@ -19,6 +19,7 @@ aarch64-cpu = "10.0"
page_table = { workspace = true }
aarch64-peripherals = { version = "0.3.0", path = "../kplat-aarch64-peripherals" }
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
diff --git a/platforms/aarch64-raspi/src/boot.rs b/platforms/aarch64-raspi/src/boot.rs
index bf02c59f..f4fbede8 100644
--- a/platforms/aarch64-raspi/src/boot.rs
+++ b/platforms/aarch64-raspi/src/boot.rs
@@ -39,7 +39,7 @@ unsafe fn init_boot_page_table() {
}
unsafe fn enable_fp() {
#[cfg(feature = "fp-simd")]
- kcpu::instrs::enable_fp();
+ karch::enable_fp();
}
/// Primary CPU entry point from the boot loader.
#[unsafe(naked)]
diff --git a/platforms/aarch64-raspi/src/mp.rs b/platforms/aarch64-raspi/src/mp.rs
index 72465c78..e8d7c3f9 100644
--- a/platforms/aarch64-raspi/src/mp.rs
+++ b/platforms/aarch64-raspi/src/mp.rs
@@ -24,10 +24,10 @@ pub fn start_secondary_cpu(cpu_id: usize, stack_top: PhysAddr) {
let entry_paddr = v2p(va!(modify_stack_and_start as usize)).as_usize();
let stack_top_ptr = &raw mut SECONDARY_STACK_TOP;
unsafe { stack_top_ptr.write_volatile(stack_top.as_usize()) };
- kcpu::instrs::flush_dcache_line(va!(stack_top_ptr as usize));
+ karch::flush_dcache_line(va!(stack_top_ptr as usize));
let spintable_vaddr = p2v(CPU_SPIN_TABLE[cpu_id]);
let release_ptr = spintable_vaddr.as_mut_ptr() as *mut usize;
unsafe { release_ptr.write_volatile(entry_paddr) };
- kcpu::instrs::flush_dcache_line(spintable_vaddr);
+ karch::flush_dcache_line(spintable_vaddr);
aarch64_cpu::asm::sev();
}
diff --git a/platforms/aarch64-raspi/src/power.rs b/platforms/aarch64-raspi/src/power.rs
index b8fbb7d5..b948d56a 100644
--- a/platforms/aarch64-raspi/src/power.rs
+++ b/platforms/aarch64-raspi/src/power.rs
@@ -14,7 +14,7 @@ impl SysCtrl for PowerImpl {
fn shutdown() -> ! {
log::info!("Shutting down...");
loop {
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
}
}
}
diff --git a/platforms/kplat/src/interrupts.rs b/platforms/kplat/src/interrupts.rs
index 2605b170..221217b8 100644
--- a/platforms/kplat/src/interrupts.rs
+++ b/platforms/kplat/src/interrupts.rs
@@ -35,16 +35,4 @@ pub trait IntrManager {
fn notify_cpu(id: usize, target: TargetCpu);
/// Sets the priority for the given interrupt.
fn set_prio(id: usize, prio: u8);
-
- /// Saves and disables local interrupt state.
- fn save_disable() -> usize;
- /// Restores local interrupt state saved by `save_disable`.
- fn restore(flags: usize);
-
- /// Enables local interrupts on the current CPU.
- fn enable_local();
- /// Disables local interrupts on the current CPU.
- fn disable_local();
- /// Returns whether local interrupts are enabled.
- fn is_enabled() -> bool;
}
diff --git a/platforms/loongarch64-qemu-virt/Cargo.toml b/platforms/loongarch64-qemu-virt/Cargo.toml
index d0fa07e3..52f07db8 100644
--- a/platforms/loongarch64-qemu-virt/Cargo.toml
+++ b/platforms/loongarch64-qemu-virt/Cargo.toml
@@ -20,6 +20,7 @@ lazyinit = "0.2"
log = "0.4"
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
diff --git a/platforms/loongarch64-qemu-virt/src/boot.rs b/platforms/loongarch64-qemu-virt/src/boot.rs
index 562df8f0..5bc5a680 100644
--- a/platforms/loongarch64-qemu-virt/src/boot.rs
+++ b/platforms/loongarch64-qemu-virt/src/boot.rs
@@ -46,8 +46,8 @@ unsafe fn init_boot_page_table() {
fn enable_fp_simd() {
#[cfg(feature = "fp-simd")]
{
- kcpu::instrs::enable_fp();
- kcpu::instrs::enable_lsx();
+ karch::enable_fp();
+ karch::enable_lsx();
}
}
fn init_mmu() {
diff --git a/platforms/loongarch64-qemu-virt/src/irq.rs b/platforms/loongarch64-qemu-virt/src/irq.rs
index faa5ef80..62c6b04f 100644
--- a/platforms/loongarch64-qemu-virt/src/irq.rs
+++ b/platforms/loongarch64-qemu-virt/src/irq.rs
@@ -114,24 +114,4 @@ impl IntrManager for IntrManagerImpl {
fn set_prio(irq: usize, priority: u8) {
todo!()
}
-
- fn save_disable() -> usize {
- todo!()
- }
-
- fn restore(flag: usize) {
- todo!()
- }
-
- fn enable_local() {
- todo!()
- }
-
- fn disable_local() {
- todo!()
- }
-
- fn is_enabled() -> bool {
- todo!()
- }
}
diff --git a/platforms/loongarch64-qemu-virt/src/power.rs b/platforms/loongarch64-qemu-virt/src/power.rs
index 9c447046..11a2ca00 100644
--- a/platforms/loongarch64-qemu-virt/src/power.rs
+++ b/platforms/loongarch64-qemu-virt/src/power.rs
@@ -20,10 +20,10 @@ impl SysCtrl for PowerImpl {
let halt_addr = p2v(pa!(GED_PADDR)).as_mut_ptr();
info!("Shutting down...");
unsafe { halt_addr.write_volatile(0x34) };
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
warn!("It should shutdown!");
loop {
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
}
}
}
diff --git a/platforms/riscv64-qemu-virt/Cargo.toml b/platforms/riscv64-qemu-virt/Cargo.toml
index 4b7db09a..346e45d1 100644
--- a/platforms/riscv64-qemu-virt/Cargo.toml
+++ b/platforms/riscv64-qemu-virt/Cargo.toml
@@ -20,6 +20,7 @@ log = "0.4"
percpu = { workspace = true }
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
diff --git a/platforms/riscv64-qemu-virt/src/boot.rs b/platforms/riscv64-qemu-virt/src/boot.rs
index 3f19a0c6..6d7dd080 100644
--- a/platforms/riscv64-qemu-virt/src/boot.rs
+++ b/platforms/riscv64-qemu-virt/src/boot.rs
@@ -20,8 +20,8 @@ unsafe fn init_boot_page_table() {
}
unsafe fn init_mmu() {
unsafe {
- kcpu::instrs::write_kernel_page_table(pa!(&raw const BOOT_PT_SV39 as usize));
- kcpu::instrs::flush_tlb(None);
+ karch::write_kernel_page_table(pa!(&raw const BOOT_PT_SV39 as usize));
+ karch::flush_tlb(None);
}
}
#[unsafe(naked)]
diff --git a/platforms/riscv64-qemu-virt/src/irq.rs b/platforms/riscv64-qemu-virt/src/irq.rs
index 21cad78d..ff50379d 100644
--- a/platforms/riscv64-qemu-virt/src/irq.rs
+++ b/platforms/riscv64-qemu-virt/src/irq.rs
@@ -214,24 +214,4 @@ impl IntrManager for IntrManagerImpl {
fn set_prio(_irq: usize, _priority: u8) {
todo!()
}
-
- fn save_disable() -> usize {
- todo!()
- }
-
- fn restore(_flag: usize) {
- todo!()
- }
-
- fn enable_local() {
- todo!()
- }
-
- fn disable_local() {
- todo!()
- }
-
- fn is_enabled() -> bool {
- todo!()
- }
}
diff --git a/platforms/riscv64-qemu-virt/src/power.rs b/platforms/riscv64-qemu-virt/src/power.rs
index f3742d20..14714031 100644
--- a/platforms/riscv64-qemu-virt/src/power.rs
+++ b/platforms/riscv64-qemu-virt/src/power.rs
@@ -22,7 +22,7 @@ impl SysCtrl for PowerImpl {
sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason);
warn!("It should shutdown!");
loop {
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
}
}
}
diff --git a/platforms/x86-csv/Cargo.toml b/platforms/x86-csv/Cargo.toml
index c87944ed..55316d4b 100644
--- a/platforms/x86-csv/Cargo.toml
+++ b/platforms/x86-csv/Cargo.toml
@@ -23,6 +23,7 @@ int_ratio = "0.1"
percpu = { workspace = true }
heapless = "0.9"
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
diff --git a/platforms/x86-csv/src/apic.rs b/platforms/x86-csv/src/apic.rs
index 480615f8..1e6ffbb8 100644
--- a/platforms/x86-csv/src/apic.rs
+++ b/platforms/x86-csv/src/apic.rs
@@ -144,25 +144,5 @@ mod irq_impl {
fn set_prio(_irq: usize, _priority: u8) {
todo!()
}
-
- fn save_disable() -> usize {
- todo!()
- }
-
- fn restore(_flag: usize) {
- todo!()
- }
-
- fn enable_local() {
- todo!()
- }
-
- fn disable_local() {
- todo!()
- }
-
- fn is_enabled() -> bool {
- todo!()
- }
}
}
diff --git a/platforms/x86-csv/src/power.rs b/platforms/x86-csv/src/power.rs
index ac10a0b7..d0f19e0b 100644
--- a/platforms/x86-csv/src/power.rs
+++ b/platforms/x86-csv/src/power.rs
@@ -23,10 +23,10 @@ impl SysCtrl for PowerImpl {
} else {
unsafe { PortWriteOnly::new(0x604).write(0x2000u16) };
}
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
warn!("It should shutdown!");
loop {
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
}
}
}
diff --git a/platforms/x86_64-qemu-virt/Cargo.toml b/platforms/x86_64-qemu-virt/Cargo.toml
index c1933c06..755eb0c4 100644
--- a/platforms/x86_64-qemu-virt/Cargo.toml
+++ b/platforms/x86_64-qemu-virt/Cargo.toml
@@ -23,6 +23,7 @@ int_ratio = "0.1"
percpu = { workspace = true }
heapless = "0.9"
kcpu = { workspace = true }
+karch = { workspace = true }
kplat = { workspace = true }
kbuild_config = { workspace = true }
diff --git a/platforms/x86_64-qemu-virt/src/apic.rs b/platforms/x86_64-qemu-virt/src/apic.rs
index 17165ea5..6e427723 100644
--- a/platforms/x86_64-qemu-virt/src/apic.rs
+++ b/platforms/x86_64-qemu-virt/src/apic.rs
@@ -153,25 +153,5 @@ mod irq_impl {
fn set_prio(_irq: usize, _priority: u8) {
todo!()
}
-
- fn save_disable() -> usize {
- todo!()
- }
-
- fn restore(_flag: usize) {
- todo!()
- }
-
- fn enable_local() {
- todo!()
- }
-
- fn disable_local() {
- todo!()
- }
-
- fn is_enabled() -> bool {
- todo!()
- }
}
}
diff --git a/platforms/x86_64-qemu-virt/src/power.rs b/platforms/x86_64-qemu-virt/src/power.rs
index 1f1660b3..fb31090a 100644
--- a/platforms/x86_64-qemu-virt/src/power.rs
+++ b/platforms/x86_64-qemu-virt/src/power.rs
@@ -25,10 +25,10 @@ impl SysCtrl for PowerImpl {
} else {
unsafe { PortWriteOnly::new(0x604).write(0x2000u16) };
}
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
warn!("It should shutdown!");
loop {
- kcpu::instrs::stop_cpu();
+ karch::stop_cpu();
}
}
}
diff --git a/process/kprocess/src/tests.rs b/process/kprocess/src/tests.rs
index 5bdaf1e2..722f8957 100644
--- a/process/kprocess/src/tests.rs
+++ b/process/kprocess/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for kprocess
#![cfg(unittest)]
diff --git a/process/ksignal/src/tests.rs b/process/ksignal/src/tests.rs
index 0fe7d2e4..52df8094 100644
--- a/process/ksignal/src/tests.rs
+++ b/process/ksignal/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for ksignal
#![cfg(unittest)]
diff --git a/process/osvm/src/tests.rs b/process/osvm/src/tests.rs
index 0543e373..37decc69 100644
--- a/process/osvm/src/tests.rs
+++ b/process/osvm/src/tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Unit tests for osvm
#![cfg(unittest)]
diff --git a/scripts/check_header.py b/scripts/check_header.py
new file mode 100644
index 00000000..def31543
--- /dev/null
+++ b/scripts/check_header.py
@@ -0,0 +1,61 @@
+import os
+
+EXPECTED_HEADER = """// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details."""
+
+def check_rs_file_headers(root_dir="."):
+ """
+ 检查指定目录下的所有 .rs 文件是否包含预期的文件头。
+ 返回一个缺失文件头的文件路径列表。
+ """
+ missing_headers_list = []
+
+ for root, dirs, files in os.walk(root_dir):
+ # 忽略 target 目录以加快搜索速度
+ if 'target' in dirs:
+ dirs.remove('target')
+
+ for file in files:
+ if file.endswith(".rs"):
+ file_path = os.path.join(root, file)
+ try:
+ with open(file_path, 'r', encoding='utf-8') as f:
+ # 读取文件的前几行(假设头信息在前 10 行内),以避免读取整个大文件
+ lines = [f.readline() for _ in range(10)]
+ content_head = "".join(lines)
+
+ if EXPECTED_HEADER not in content_head:
+ missing_headers_list.append(file_path)
+ except Exception as e:
+ print(f"无法读取文件 {file_path}: {e}")
+
+ return missing_headers_list
+
+def add_missing_headers(missing_list):
+ """
+ 为缺失文件头的文件添加版权头信息。
+ """
+ if not missing_list:
+ print("🎉 恭喜!所有的 .rs 文件都包含了指定的版权头信息。")
+ return
+
+ print(f"⚠️ 发现 {len(missing_list)} 个 .rs 文件缺失指定的版权头信息,正在添加...")
+ print("-" * 50)
+ for path in missing_list:
+ try:
+ with open(path, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ with open(path, 'w', encoding='utf-8') as f:
+ f.write(EXPECTED_HEADER + "\n\n" + content)
+ print(f"已添加: {path}")
+ except Exception as e:
+ print(f"❌ 无法处理文件 {path}: {e}")
+ print("-" * 50)
+ print("✅ 处理完成!")
+
+if __name__ == "__main__":
+ # 指定项目根目录运行,默认为当前目录 '.'
+ missing_files = check_rs_file_headers(".")
+ add_missing_headers(missing_files)
\ No newline at end of file
diff --git a/scripts/make/deps.mk b/scripts/make/deps.mk
index 5cadd336..51524788 100644
--- a/scripts/make/deps.mk
+++ b/scripts/make/deps.mk
@@ -1,11 +1,5 @@
# Necessary dependencies for the build system
-# Tool to generate xconfig
-ifeq ($(shell xconfig --version 2>/dev/null),)
- $(info Installing xconfig...)
- $(shell cargo install --path xtask/xconfig)
-endif
-
# Cargo binutils
ifeq ($(shell cargo install --list | grep cargo-binutils),)
$(info Installing cargo-binutils...)
diff --git a/sync/kspin/Cargo.toml b/sync/kspin/Cargo.toml
index cb5c8c22..ff0f9b31 100644
--- a/sync/kspin/Cargo.toml
+++ b/sync/kspin/Cargo.toml
@@ -18,4 +18,5 @@ default = []
[dependencies]
cfg-if = { workspace = true }
crate_interface = {workspace = true}
+karch = { workspace = true }
unittest.workspace = true
diff --git a/sync/kspin/README.md b/sync/kspin/README.md
index a1467428..a26ffd81 100644
--- a/sync/kspin/README.md
+++ b/sync/kspin/README.md
@@ -129,14 +129,6 @@ impl KernelGuardIf for MyKernelGuard {
fn disable_preempt() {
// Your implementation
}
-
- fn local_irq_save_and_disable() -> usize {
- 0 // Your implementation
- }
-
- fn local_irq_restore(flags: usize) {
- // Your implementation
- }
}
```
diff --git a/sync/kspin/src/guard/arch/aarch64.rs b/sync/kspin/src/guard/arch/aarch64.rs
deleted file mode 100644
index 819f1c20..00000000
--- a/sync/kspin/src/guard/arch/aarch64.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-/// Save IRQ state and disable local interrupts.
-#[inline]
-pub fn save_disable() -> usize {
- crate_interface::call_interface!(crate::guard::KernelGuardIf::save_disable)
-}
-
-/// Restore local interrupt state from saved flags.
-#[inline]
-pub fn restore(flags: usize) {
- crate_interface::call_interface!(crate::guard::KernelGuardIf::restore(flags))
-}
diff --git a/sync/kspin/src/guard/arch/arm.rs b/sync/kspin/src/guard/arch/arm.rs
deleted file mode 100644
index 1a574b0d..00000000
--- a/sync/kspin/src/guard/arch/arm.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-//! ARM IRQ save/restore helpers.
-use core::arch::asm;
-
-/// Bit 7: IRQ disable bit in CPSR
-const IRQ_DISABLE_BIT: usize = 1 << 7;
-
-/// Save CPSR and disable IRQs.
-#[inline]
-pub fn save_disable() -> usize {
- let flags: usize;
- unsafe {
- // Save CPSR and disable IRQs by setting the I bit
- asm!(
- "mrs {0}, cpsr",
- "cpsid i",
- out(reg) flags,
- options(nomem, nostack, preserves_flags)
- );
- }
- flags & IRQ_DISABLE_BIT
-}
-
-/// Restore IRQ state according to saved CPSR flags.
-#[inline]
-pub fn restore(flags: usize) {
- if flags & IRQ_DISABLE_BIT == 0 {
- // IRQs were enabled before, re-enable them
- unsafe {
- asm!("cpsie i", options(nomem, nostack));
- }
- }
-}
diff --git a/sync/kspin/src/guard/arch/loongarch64.rs b/sync/kspin/src/guard/arch/loongarch64.rs
deleted file mode 100644
index ecfca2db..00000000
--- a/sync/kspin/src/guard/arch/loongarch64.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-//! LoongArch64 IRQ save/restore helpers.
-use core::arch::asm;
-
-const IE_MASK: usize = 1 << 2;
-
-/// Save IE and disable interrupts.
-#[inline]
-pub fn save_disable() -> usize {
- let mut flags: usize = 0;
- // clear the `IE` bit, and return the old CSR
- unsafe { asm!("csrxchg {}, {}, 0x0", inout(reg) flags, in(reg) IE_MASK) };
- flags & IE_MASK
-}
-
-/// Restore IE according to saved flags.
-#[inline]
-pub fn restore(flags: usize) {
- // restore the `IE` bit
- unsafe { asm!("csrxchg {}, {}, 0x0", in(reg) flags, in(reg) IE_MASK) };
-}
diff --git a/sync/kspin/src/guard/arch/mod.rs b/sync/kspin/src/guard/arch/mod.rs
index a175a3d5..3956b0e6 100644
--- a/sync/kspin/src/guard/arch/mod.rs
+++ b/sync/kspin/src/guard/arch/mod.rs
@@ -3,23 +3,19 @@
// See LICENSES for license details.
//! Architecture-specific IRQ save/restore helpers.
-#![cfg_attr(not(target_os = "none"), allow(dead_code, unused_imports))]
+//!
+//! Delegates to [`karch`] for a unified implementation across all supported
+//! architectures.
+#![cfg_attr(not(target_os = "none"), allow(dead_code))]
-cfg_if::cfg_if! {
- if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
- mod x86;
- pub use self::x86::*;
- } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
- mod riscv;
- pub use self::riscv::*;
- } else if #[cfg(target_arch = "aarch64")] {
- mod aarch64;
- pub use self::aarch64::*;
- } else if #[cfg(target_arch = "loongarch64")] {
- mod loongarch64;
- pub use self::loongarch64::*;
- } else if #[cfg(target_arch = "arm")] {
- mod arm;
- pub use self::arm::*;
- }
+/// Saves and disables local interrupts, returning the saved state.
+#[inline]
+pub fn save_disable() -> usize {
+ karch::save_irq_and_disable()
+}
+
+/// Restores local interrupt state from the saved flags.
+#[inline]
+pub fn restore(flags: usize) {
+ karch::restore_irq(flags)
}
diff --git a/sync/kspin/src/guard/arch/riscv.rs b/sync/kspin/src/guard/arch/riscv.rs
deleted file mode 100644
index ef2faf84..00000000
--- a/sync/kspin/src/guard/arch/riscv.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-//! RISC-V IRQ save/restore helpers.
-use core::arch::asm;
-
-/// Bit 1: Supervisor Interrupt Enable
-const SIE_BIT: usize = 1 << 1;
-
-/// Save SIE and disable interrupts.
-#[inline]
-pub fn save_disable() -> usize {
- let flags: usize;
- // clear the `SIE` bit, and return the old CSR
- unsafe { asm!("csrrc {}, sstatus, {}", out(reg) flags, const SIE_BIT) };
- flags & SIE_BIT
-}
-
-/// Restore SIE according to saved flags.
-#[inline]
-pub fn restore(flags: usize) {
- // restore the `SIE` bit
- unsafe { asm!("csrrs x0, sstatus, {}", in(reg) flags) };
-}
diff --git a/sync/kspin/src/guard/arch/x86.rs b/sync/kspin/src/guard/arch/x86.rs
deleted file mode 100644
index 312a3b24..00000000
--- a/sync/kspin/src/guard/arch/x86.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// Copyright 2025 KylinSoft Co., Ltd.
-// See LICENSES for license details.
-
-//! x86/x86_64 IRQ save/restore helpers.
-use core::arch::asm;
-
-/// Interrupt Enable Flag (IF)
-const IF_BIT: usize = 1 << 9;
-
-/// Save IF and disable interrupts.
-#[inline]
-pub fn save_disable() -> usize {
- let flags: usize;
- unsafe { asm!("pushf; pop {}; cli", out(reg) flags) };
- flags & IF_BIT
-}
-
-/// Restore IF according to saved flags.
-#[inline]
-pub fn restore(flags: usize) {
- if flags != 0 {
- unsafe { asm!("sti") };
- } else {
- unsafe { asm!("cli") };
- }
-}
diff --git a/sync/kspin/src/guard/mod.rs b/sync/kspin/src/guard/mod.rs
index 5e0b25ca..762b3b40 100644
--- a/sync/kspin/src/guard/mod.rs
+++ b/sync/kspin/src/guard/mod.rs
@@ -15,12 +15,6 @@ pub trait KernelGuardIf {
/// Disable kernel preemption.
fn disable_preempt();
-
- /// Save and disable local interrupts, returning saved flags.
- fn save_disable() -> usize;
-
- /// Restore local interrupts from saved flags.
- fn restore(flags: usize);
}
/// Base trait for all guard types.
diff --git a/sync/kspin/src/lib.rs b/sync/kspin/src/lib.rs
index 2f63aef4..1c3acd97 100644
--- a/sync/kspin/src/lib.rs
+++ b/sync/kspin/src/lib.rs
@@ -81,15 +81,6 @@
//! fn disable_preempt() {
//! // Your implementation
//! }
-//!
-//! fn save_disable() -> usize {
-//! // Your implementation
-//! 0
-//! }
-//!
-//! fn restore(flags: usize) {
-//! // Your implementation
-//! }
//! }
//! ```
diff --git a/tee_apps/sh/src/main.rs b/tee_apps/sh/src/main.rs
index 24850a02..592b5cd0 100644
--- a/tee_apps/sh/src/main.rs
+++ b/tee_apps/sh/src/main.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::process::{Child, Command, Stdio};
fn spawn_app(path: &str) -> Option {
diff --git a/tee_apps/tee_app1/src/main.rs b/tee_apps/tee_app1/src/main.rs
index 373b8f01..1788a928 100644
--- a/tee_apps/tee_app1/src/main.rs
+++ b/tee_apps/tee_app1/src/main.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
fn main() {
println!("Hello, tee_app1!");
let mut count = 0u64;
diff --git a/tee_apps/tee_app2/src/main.rs b/tee_apps/tee_app2/src/main.rs
index bdcbd026..ccda0b56 100644
--- a/tee_apps/tee_app2/src/main.rs
+++ b/tee_apps/tee_app2/src/main.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
fn main() {
println!("Hello, tee_app2!");
let mut count = 0u64;
diff --git a/util/kbuild_config/build.rs b/util/kbuild_config/build.rs
index 1a629cf9..2994c04c 100644
--- a/util/kbuild_config/build.rs
+++ b/util/kbuild_config/build.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{env, fs, path::Path};
fn main() {
diff --git a/util/kbuild_config/src/lib.rs b/util/kbuild_config/src/lib.rs
index b292f19b..142973bd 100644
--- a/util/kbuild_config/src/lib.rs
+++ b/util/kbuild_config/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
// Auto-generated kbuild configuration module
//
// This module provides access to configuration constants from .config file
diff --git a/xtask/crate_rootfs/src/args.rs b/xtask/crate_rootfs/src/args.rs
index 8789e7a9..6755ca18 100644
--- a/xtask/crate_rootfs/src/args.rs
+++ b/xtask/crate_rootfs/src/args.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use clap::Parser;
diff --git a/xtask/crate_rootfs/src/blockdev.rs b/xtask/crate_rootfs/src/blockdev.rs
index 5305b5ec..f7ae6460 100644
--- a/xtask/crate_rootfs/src/blockdev.rs
+++ b/xtask/crate_rootfs/src/blockdev.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{
fs::File,
io::{Read, Seek, SeekFrom, Write},
diff --git a/xtask/crate_rootfs/src/main.rs b/xtask/crate_rootfs/src/main.rs
index c607195f..1cb633c8 100644
--- a/xtask/crate_rootfs/src/main.rs
+++ b/xtask/crate_rootfs/src/main.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
mod args;
mod blockdev;
mod rootfs;
diff --git a/xtask/crate_rootfs/src/rootfs.rs b/xtask/crate_rootfs/src/rootfs.rs
index 90be4ff0..7a580e4d 100644
--- a/xtask/crate_rootfs/src/rootfs.rs
+++ b/xtask/crate_rootfs/src/rootfs.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{
fs::{File, OpenOptions},
io::Read,
diff --git a/xtask/crate_rootfs/src/util.rs b/xtask/crate_rootfs/src/util.rs
index 03665d37..79f5d1b1 100644
--- a/xtask/crate_rootfs/src/util.rs
+++ b/xtask/crate_rootfs/src/util.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::Path;
/// Align up to the next multiple of `align`.
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index b9543968..cdea0691 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
fn main() {
println!("Hello, xtask!");
}
\ No newline at end of file
diff --git a/xtask/xconfig/Cargo.toml b/xtask/xconfig/Cargo.toml
index 40ce2acc..74c19b6a 100644
--- a/xtask/xconfig/Cargo.toml
+++ b/xtask/xconfig/Cargo.toml
@@ -34,11 +34,3 @@ path = "src/main.rs"
[[bench]]
name = "parser_bench"
harness = false
-
-[profile.release]
-opt-level = 3
-lto = true
-codegen-units = 1
-
-[profile.bench]
-inherits = "release"
diff --git a/xtask/xconfig/benches/parser_bench.rs b/xtask/xconfig/benches/parser_bench.rs
index 21d11d1a..200ad84c 100644
--- a/xtask/xconfig/benches/parser_bench.rs
+++ b/xtask/xconfig/benches/parser_bench.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
diff --git a/xtask/xconfig/src/cli/commands.rs b/xtask/xconfig/src/cli/commands.rs
index 7d306d59..ef832790 100644
--- a/xtask/xconfig/src/cli/commands.rs
+++ b/xtask/xconfig/src/cli/commands.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use clap::{Parser as ClapParser, Subcommand};
diff --git a/xtask/xconfig/src/cli/defconfig.rs b/xtask/xconfig/src/cli/defconfig.rs
index b790a7c4..72fd4bd4 100644
--- a/xtask/xconfig/src/cli/defconfig.rs
+++ b/xtask/xconfig/src/cli/defconfig.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use crate::error::Result;
diff --git a/xtask/xconfig/src/cli/gen_const.rs b/xtask/xconfig/src/cli/gen_const.rs
index 3baa438c..d22c5bae 100644
--- a/xtask/xconfig/src/cli/gen_const.rs
+++ b/xtask/xconfig/src/cli/gen_const.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{
collections::HashMap,
fs,
diff --git a/xtask/xconfig/src/cli/menuconfig.rs b/xtask/xconfig/src/cli/menuconfig.rs
index fbeb43fa..b630572e 100644
--- a/xtask/xconfig/src/cli/menuconfig.rs
+++ b/xtask/xconfig/src/cli/menuconfig.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{io, path::PathBuf};
use crossterm::{
diff --git a/xtask/xconfig/src/cli/mod.rs b/xtask/xconfig/src/cli/mod.rs
index 6b521ae2..1bf6ef76 100644
--- a/xtask/xconfig/src/cli/mod.rs
+++ b/xtask/xconfig/src/cli/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod commands;
pub mod defconfig;
pub mod gen_const;
diff --git a/xtask/xconfig/src/cli/oldconfig.rs b/xtask/xconfig/src/cli/oldconfig.rs
index ce379f04..0c9ef8da 100644
--- a/xtask/xconfig/src/cli/oldconfig.rs
+++ b/xtask/xconfig/src/cli/oldconfig.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use crate::{
diff --git a/xtask/xconfig/src/cli/saveconfig.rs b/xtask/xconfig/src/cli/saveconfig.rs
index 0802fe0d..160916a7 100644
--- a/xtask/xconfig/src/cli/saveconfig.rs
+++ b/xtask/xconfig/src/cli/saveconfig.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use crate::{
diff --git a/xtask/xconfig/src/config/generator.rs b/xtask/xconfig/src/config/generator.rs
index 47bec42f..bd0e8dda 100644
--- a/xtask/xconfig/src/config/generator.rs
+++ b/xtask/xconfig/src/config/generator.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{collections::HashMap, fs::File, io::Write, path::Path};
use crate::{
diff --git a/xtask/xconfig/src/config/mod.rs b/xtask/xconfig/src/config/mod.rs
index ddac4425..aeb11bf8 100644
--- a/xtask/xconfig/src/config/mod.rs
+++ b/xtask/xconfig/src/config/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod generator;
pub mod oldconfig;
pub mod reader;
diff --git a/xtask/xconfig/src/config/oldconfig.rs b/xtask/xconfig/src/config/oldconfig.rs
index 6111d993..4e672c06 100644
--- a/xtask/xconfig/src/config/oldconfig.rs
+++ b/xtask/xconfig/src/config/oldconfig.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{collections::HashSet, path::Path};
use crate::{
diff --git a/xtask/xconfig/src/config/reader.rs b/xtask/xconfig/src/config/reader.rs
index 44933e71..fcdc2ce4 100644
--- a/xtask/xconfig/src/config/reader.rs
+++ b/xtask/xconfig/src/config/reader.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{collections::HashMap, fs, path::Path};
use crate::error::Result;
diff --git a/xtask/xconfig/src/config/writer.rs b/xtask/xconfig/src/config/writer.rs
index 1cde8cc9..f9f54fb1 100644
--- a/xtask/xconfig/src/config/writer.rs
+++ b/xtask/xconfig/src/config/writer.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{fs::File, io::Write, path::Path};
use crate::{error::Result, kconfig::SymbolTable};
diff --git a/xtask/xconfig/src/error.rs b/xtask/xconfig/src/error.rs
index dae5a3bf..8245e368 100644
--- a/xtask/xconfig/src/error.rs
+++ b/xtask/xconfig/src/error.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use thiserror::Error;
diff --git a/xtask/xconfig/src/kconfig/ast.rs b/xtask/xconfig/src/kconfig/ast.rs
index 8781f715..8f9ab4a5 100644
--- a/xtask/xconfig/src/kconfig/ast.rs
+++ b/xtask/xconfig/src/kconfig/ast.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq)]
diff --git a/xtask/xconfig/src/kconfig/expr.rs b/xtask/xconfig/src/kconfig/expr.rs
index 0e45751f..439853e1 100644
--- a/xtask/xconfig/src/kconfig/expr.rs
+++ b/xtask/xconfig/src/kconfig/expr.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use crate::{
error::{KconfigError, Result},
kconfig::{ast::Expr, shell_expr::evaluate_shell_expr, symbol::SymbolTable},
diff --git a/xtask/xconfig/src/kconfig/lexer.rs b/xtask/xconfig/src/kconfig/lexer.rs
index 785f15d1..1158fa65 100644
--- a/xtask/xconfig/src/kconfig/lexer.rs
+++ b/xtask/xconfig/src/kconfig/lexer.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use crate::error::{KconfigError, Result};
diff --git a/xtask/xconfig/src/kconfig/mod.rs b/xtask/xconfig/src/kconfig/mod.rs
index e322f26b..93224572 100644
--- a/xtask/xconfig/src/kconfig/mod.rs
+++ b/xtask/xconfig/src/kconfig/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod ast;
pub mod expr;
pub mod lexer;
diff --git a/xtask/xconfig/src/kconfig/parser.rs b/xtask/xconfig/src/kconfig/parser.rs
index 1051ef41..0b50d2d0 100644
--- a/xtask/xconfig/src/kconfig/parser.rs
+++ b/xtask/xconfig/src/kconfig/parser.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{
collections::HashSet,
fs,
diff --git a/xtask/xconfig/src/kconfig/shell_expr.rs b/xtask/xconfig/src/kconfig/shell_expr.rs
index 145660ad..649998c2 100644
--- a/xtask/xconfig/src/kconfig/shell_expr.rs
+++ b/xtask/xconfig/src/kconfig/shell_expr.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use crate::{
error::{KconfigError, Result},
kconfig::symbol::SymbolTable,
diff --git a/xtask/xconfig/src/kconfig/symbol.rs b/xtask/xconfig/src/kconfig/symbol.rs
index c038a0e1..ddcb3ddf 100644
--- a/xtask/xconfig/src/kconfig/symbol.rs
+++ b/xtask/xconfig/src/kconfig/symbol.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::collections::HashMap;
use crate::kconfig::ast::SymbolType;
diff --git a/xtask/xconfig/src/lib.rs b/xtask/xconfig/src/lib.rs
index e2c707ef..b3638585 100644
--- a/xtask/xconfig/src/lib.rs
+++ b/xtask/xconfig/src/lib.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod cli;
pub mod config;
pub mod error;
diff --git a/xtask/xconfig/src/log.rs b/xtask/xconfig/src/log.rs
index c293b7d1..93fe4eda 100644
--- a/xtask/xconfig/src/log.rs
+++ b/xtask/xconfig/src/log.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[cfg(unix)]
use std::os::unix::fs::OpenOptionsExt;
use std::sync::OnceLock;
diff --git a/xtask/xconfig/src/main.rs b/xtask/xconfig/src/main.rs
index 02ea0cbd..468d9c69 100644
--- a/xtask/xconfig/src/main.rs
+++ b/xtask/xconfig/src/main.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use xconfig::cli::run_cli;
fn main() {
diff --git a/xtask/xconfig/src/ui/app.rs b/xtask/xconfig/src/ui/app.rs
index feeac043..a1a84165 100644
--- a/xtask/xconfig/src/ui/app.rs
+++ b/xtask/xconfig/src/ui/app.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{io::Write, time::Duration};
use crossterm::event::{self, Event, KeyCode, KeyEvent};
diff --git a/xtask/xconfig/src/ui/dependency_resolver.rs b/xtask/xconfig/src/ui/dependency_resolver.rs
index 7aef3e86..f1c6fa3b 100644
--- a/xtask/xconfig/src/ui/dependency_resolver.rs
+++ b/xtask/xconfig/src/ui/dependency_resolver.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::collections::HashMap;
use crate::kconfig::{
diff --git a/xtask/xconfig/src/ui/events/handler.rs b/xtask/xconfig/src/ui/events/handler.rs
index c7b34a96..683571e2 100644
--- a/xtask/xconfig/src/ui/events/handler.rs
+++ b/xtask/xconfig/src/ui/events/handler.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventResult {
Continue,
diff --git a/xtask/xconfig/src/ui/events/mod.rs b/xtask/xconfig/src/ui/events/mod.rs
index 4bc7dc7f..fb7ced11 100644
--- a/xtask/xconfig/src/ui/events/mod.rs
+++ b/xtask/xconfig/src/ui/events/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod handler;
pub use handler::{EventHandler, EventResult};
diff --git a/xtask/xconfig/src/ui/mod.rs b/xtask/xconfig/src/ui/mod.rs
index 4d9e6cda..8eee578b 100644
--- a/xtask/xconfig/src/ui/mod.rs
+++ b/xtask/xconfig/src/ui/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod app;
pub mod dependency_resolver;
pub mod events;
diff --git a/xtask/xconfig/src/ui/rendering/mod.rs b/xtask/xconfig/src/ui/rendering/mod.rs
index 3104c3fe..2760024b 100644
--- a/xtask/xconfig/src/ui/rendering/mod.rs
+++ b/xtask/xconfig/src/ui/rendering/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod theme;
pub use theme::Theme;
diff --git a/xtask/xconfig/src/ui/rendering/theme.rs b/xtask/xconfig/src/ui/rendering/theme.rs
index cc6399f6..ad177444 100644
--- a/xtask/xconfig/src/ui/rendering/theme.rs
+++ b/xtask/xconfig/src/ui/rendering/theme.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use ratatui::style::{Color, Modifier, Style};
#[derive(Debug, Clone)]
diff --git a/xtask/xconfig/src/ui/state/mod.rs b/xtask/xconfig/src/ui/state/mod.rs
index 921375c9..ce5f7007 100644
--- a/xtask/xconfig/src/ui/state/mod.rs
+++ b/xtask/xconfig/src/ui/state/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::{collections::HashMap, io::Write};
use crate::{
diff --git a/xtask/xconfig/src/ui/utils/fuzzy_search.rs b/xtask/xconfig/src/ui/utils/fuzzy_search.rs
index 520c7a99..517f155d 100644
--- a/xtask/xconfig/src/ui/utils/fuzzy_search.rs
+++ b/xtask/xconfig/src/ui/utils/fuzzy_search.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use crate::ui::state::MenuItem;
pub struct FuzzySearcher {
diff --git a/xtask/xconfig/src/ui/utils/mod.rs b/xtask/xconfig/src/ui/utils/mod.rs
index 9a85027e..a666f9b7 100644
--- a/xtask/xconfig/src/ui/utils/mod.rs
+++ b/xtask/xconfig/src/ui/utils/mod.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
pub mod fuzzy_search;
pub use fuzzy_search::{FuzzySearcher, SearchResult};
diff --git a/xtask/xconfig/tests/arch_config_bugs_test.rs b/xtask/xconfig/tests/arch_config_bugs_test.rs
index d68230f7..6cca3d9b 100644
--- a/xtask/xconfig/tests/arch_config_bugs_test.rs
+++ b/xtask/xconfig/tests/arch_config_bugs_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
/// Tests for Bug 1: ARCH config value is incorrect when loading defconfig with ARCH_X86_64=y
/// Tests for Bug 2: Cross-architecture configuration pollution from defconfig
use std::fs;
diff --git a/xtask/xconfig/tests/choice_defaults_test.rs b/xtask/xconfig/tests/choice_defaults_test.rs
index e7fd9300..0a8ab5d8 100644
--- a/xtask/xconfig/tests/choice_defaults_test.rs
+++ b/xtask/xconfig/tests/choice_defaults_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/choice_mutual_exclusion_test.rs b/xtask/xconfig/tests/choice_mutual_exclusion_test.rs
index 2638d5b6..bafe5ce9 100644
--- a/xtask/xconfig/tests/choice_mutual_exclusion_test.rs
+++ b/xtask/xconfig/tests/choice_mutual_exclusion_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::io::Write;
use tempfile::NamedTempFile;
diff --git a/xtask/xconfig/tests/config_tests.rs b/xtask/xconfig/tests/config_tests.rs
index e77e9a45..4d07b3f2 100644
--- a/xtask/xconfig/tests/config_tests.rs
+++ b/xtask/xconfig/tests/config_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/dependency_display_test.rs b/xtask/xconfig/tests/dependency_display_test.rs
index 3d41603d..48d15262 100644
--- a/xtask/xconfig/tests/dependency_display_test.rs
+++ b/xtask/xconfig/tests/dependency_display_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::{kconfig::Parser, ui::state::ConfigState};
diff --git a/xtask/xconfig/tests/dependency_not_operator_test.rs b/xtask/xconfig/tests/dependency_not_operator_test.rs
index 7d582b5c..b7247803 100644
--- a/xtask/xconfig/tests/dependency_not_operator_test.rs
+++ b/xtask/xconfig/tests/dependency_not_operator_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::{
diff --git a/xtask/xconfig/tests/dependency_tests.rs b/xtask/xconfig/tests/dependency_tests.rs
index aa65baf0..70a2fabb 100644
--- a/xtask/xconfig/tests/dependency_tests.rs
+++ b/xtask/xconfig/tests/dependency_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::{
diff --git a/xtask/xconfig/tests/end_to_end_range_test.rs b/xtask/xconfig/tests/end_to_end_range_test.rs
index b333df83..16d54d13 100644
--- a/xtask/xconfig/tests/end_to_end_range_test.rs
+++ b/xtask/xconfig/tests/end_to_end_range_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/if_block_test.rs b/xtask/xconfig/tests/if_block_test.rs
index e363ac54..d24e4bfa 100644
--- a/xtask/xconfig/tests/if_block_test.rs
+++ b/xtask/xconfig/tests/if_block_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/integration_tests.rs b/xtask/xconfig/tests/integration_tests.rs
index eb9bcf22..1a5adec5 100644
--- a/xtask/xconfig/tests/integration_tests.rs
+++ b/xtask/xconfig/tests/integration_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/lexer_tests.rs b/xtask/xconfig/tests/lexer_tests.rs
index ce4e43d4..ca7fa2d1 100644
--- a/xtask/xconfig/tests/lexer_tests.rs
+++ b/xtask/xconfig/tests/lexer_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::kconfig::{Lexer, Token};
diff --git a/xtask/xconfig/tests/menu_navigation_test.rs b/xtask/xconfig/tests/menu_navigation_test.rs
index 83fb3b40..64158f24 100644
--- a/xtask/xconfig/tests/menu_navigation_test.rs
+++ b/xtask/xconfig/tests/menu_navigation_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::{
diff --git a/xtask/xconfig/tests/menuconfig_defaults_test.rs b/xtask/xconfig/tests/menuconfig_defaults_test.rs
index a414fa14..7a1b2334 100644
--- a/xtask/xconfig/tests/menuconfig_defaults_test.rs
+++ b/xtask/xconfig/tests/menuconfig_defaults_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use xconfig::{
config::ConfigReader,
kconfig::{SymbolTable, SymbolType},
diff --git a/xtask/xconfig/tests/menuconfig_ghost_filter_test.rs b/xtask/xconfig/tests/menuconfig_ghost_filter_test.rs
index 1b9b8159..261e4460 100644
--- a/xtask/xconfig/tests/menuconfig_ghost_filter_test.rs
+++ b/xtask/xconfig/tests/menuconfig_ghost_filter_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Tests for ghost config filtering in menuconfig
//!
//! Verifies that configs with unsatisfied dependencies are cleared when loading .config
diff --git a/xtask/xconfig/tests/parser_tests.rs b/xtask/xconfig/tests/parser_tests.rs
index baf4138d..dc43a192 100644
--- a/xtask/xconfig/tests/parser_tests.rs
+++ b/xtask/xconfig/tests/parser_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::kconfig::Parser;
diff --git a/xtask/xconfig/tests/range_array_tests.rs b/xtask/xconfig/tests/range_array_tests.rs
index 2abf114e..d13a747b 100644
--- a/xtask/xconfig/tests/range_array_tests.rs
+++ b/xtask/xconfig/tests/range_array_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::kconfig::{
diff --git a/xtask/xconfig/tests/range_test.rs b/xtask/xconfig/tests/range_test.rs
index a2246fbc..5ac3b29d 100644
--- a/xtask/xconfig/tests/range_test.rs
+++ b/xtask/xconfig/tests/range_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/search_navigation_test.rs b/xtask/xconfig/tests/search_navigation_test.rs
index 4f5bd9eb..7a14ca16 100644
--- a/xtask/xconfig/tests/search_navigation_test.rs
+++ b/xtask/xconfig/tests/search_navigation_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::{kconfig::Parser, ui::app::MenuConfigApp};
diff --git a/xtask/xconfig/tests/source_tests.rs b/xtask/xconfig/tests/source_tests.rs
index 405f7fc7..5b2e57d2 100644
--- a/xtask/xconfig/tests/source_tests.rs
+++ b/xtask/xconfig/tests/source_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::kconfig::Parser;
diff --git a/xtask/xconfig/tests/stable_ordering_test.rs b/xtask/xconfig/tests/stable_ordering_test.rs
index f989e23d..bef65357 100644
--- a/xtask/xconfig/tests/stable_ordering_test.rs
+++ b/xtask/xconfig/tests/stable_ordering_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;
diff --git a/xtask/xconfig/tests/ui_checkbox_sync_test.rs b/xtask/xconfig/tests/ui_checkbox_sync_test.rs
index dbe2122e..caf5a324 100644
--- a/xtask/xconfig/tests/ui_checkbox_sync_test.rs
+++ b/xtask/xconfig/tests/ui_checkbox_sync_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
//! Tests for checkbox state synchronization in MenuConfigApp
//!
//! # Testing Limitations
diff --git a/xtask/xconfig/tests/ui_tests.rs b/xtask/xconfig/tests/ui_tests.rs
index d8559a77..bbb87dfd 100644
--- a/xtask/xconfig/tests/ui_tests.rs
+++ b/xtask/xconfig/tests/ui_tests.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::path::PathBuf;
use xconfig::{
diff --git a/xtask/xconfig/tests/visibility_filtering_test.rs b/xtask/xconfig/tests/visibility_filtering_test.rs
index 3cd7a35e..4a8e2dcb 100644
--- a/xtask/xconfig/tests/visibility_filtering_test.rs
+++ b/xtask/xconfig/tests/visibility_filtering_test.rs
@@ -1,3 +1,7 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2025 KylinSoft Co., Ltd.
+// See LICENSES for license details.
+
use std::fs;
use tempfile::TempDir;