diff --git a/Cargo.toml b/Cargo.toml index 56c0260..4a3911c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "crates/vm", "aTester", ] +resolver = "3" [profile.release] panic = "abort" diff --git a/Makefile b/Makefile index f26a250..b43d7e4 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,11 @@ KERNEL_OUT_DIR := crates/bootloader/bin KERNEL_BINS := $(shell awk '/\[\[bin\]\]/{inbin=1;next} inbin && /name =/{gsub(/"/,"",$$3); print $$3; inbin=0}' $(KERNEL_MANIFEST)) KERNEL_TEST_BINS := $(filter-out kernel,$(KERNEL_BINS)) -all: clean examples test utils summary +all: clean examples test atests utils summary .PHONY: run_examples .PHONY: kernel +.PHONY: atests kernel: @echo "=== Building kernel ELF ===" @@ -48,6 +49,9 @@ test: generate_abis cd crates/examples && cargo test -- --nocapture @echo "=== Tests complete ===" +atests: + cargo test -p a_tests -- --nocapture + generate_abis: @echo "=== Generating ABIs ===" cd crates/examples && $(MAKE) abi diff --git a/aTester/tests/examples.rs b/aTester/tests/examples.rs index 9a610cf..b761de2 100644 --- a/aTester/tests/examples.rs +++ b/aTester/tests/examples.rs @@ -71,16 +71,19 @@ fn examples_tests() { let cases = all_example_cases() .expect("failed to build example bundles") .into_iter() - .map(|case| TestCase { - name: case.name.to_string(), - kind: TestKind::Smoke, - elf: target_dir.join("kernel.elf"), - options: RunOptions { - timeout_ms: None, - vm_memory_size: None, - verbose: false, - input: vec![case.bundle.encode(), state_bytes.clone()], - }, + .map(|case| { + println!("Running example: {} - {}", case.name, case.description); + TestCase { + name: case.name.to_string(), + kind: TestKind::Smoke, + elf: target_dir.join("kernel.elf"), + options: RunOptions { + timeout_ms: None, + vm_memory_size: None, + verbose: false, + input: vec![case.bundle.encode(), state_bytes.clone()], + }, + } }) .collect::>(); diff --git a/crates/clibc/src/allocator.rs b/crates/clibc/src/allocator.rs index 59e54ff..ef57ef9 100644 --- a/crates/clibc/src/allocator.rs +++ b/crates/clibc/src/allocator.rs @@ -1,10 +1,6 @@ extern crate alloc; use alloc::alloc::{GlobalAlloc, Layout}; -// System call numbers for memory allocation -const SYSCALL_ALLOC: u32 = 7; -const SYSCALL_DEALLOC: u32 = 8; - /// VM Global Allocator /// /// This allocator uses system calls to request memory from the VM host. @@ -73,4 +69,3 @@ unsafe fn syscall_dealloc(ptr: *mut u8, size: usize) { alloc::alloc::dealloc(ptr, layout); } } - diff --git a/crates/clibc/src/lib.rs b/crates/clibc/src/lib.rs index e16de65..a4d67a6 100644 --- a/crates/clibc/src/lib.rs +++ b/crates/clibc/src/lib.rs @@ -31,7 +31,6 @@ pub use storage_map::StorageKey; // Events pub mod event; -pub use event::*; // Logging macros pub mod log; diff --git a/crates/clibc/src/router.rs b/crates/clibc/src/router.rs index c939503..3e0ed21 100644 --- a/crates/clibc/src/router.rs +++ b/crates/clibc/src/router.rs @@ -1,7 +1,6 @@ use types::result::Result; use types::address::Address; use types::{O}; -use crate::logf; /// Represents a function call with a selector (function ID) and arguments. /// This is the core data structure for routing function calls in our VM. @@ -204,4 +203,4 @@ pub fn route<'a>( } last_result -} \ No newline at end of file +} diff --git a/crates/compiler/src/abi_codegen.rs b/crates/compiler/src/abi_codegen.rs index 62725ba..7810e1e 100644 --- a/crates/compiler/src/abi_codegen.rs +++ b/crates/compiler/src/abi_codegen.rs @@ -255,78 +255,6 @@ impl AbiCodeGenerator { } } - /// Generate code to encode an argument - fn generate_argument_encoding(&self, name: &str, param_type: &ParamType) -> String { - match param_type { - ParamType::Address => { - format!(" args.extend({}.0.to_vec());\n", name) - } - ParamType::Uint(8) => { - format!(" args.push({});\n", name) - } - ParamType::Uint(16) => { - format!(" args.extend({}.to_le_bytes());\n", name) - } - ParamType::Uint(32) => { - format!(" args.extend({}.to_le_bytes());\n", name) - } - ParamType::Uint(64) => { - format!(" args.extend({}.to_le_bytes());\n", name) - } - ParamType::Uint(128) => { - format!(" args.extend({}.to_le_bytes());\n", name) - } - ParamType::Bool => { - format!(" args.push(if {} {{ 1 }} else {{ 0 }});\n", name) - } - ParamType::String => { - format!(" args.extend({}.as_bytes());\n", name) - } - ParamType::Bytes => { - format!(" args.extend({});\n", name) - } - _ => { - format!(" // TODO: Encode {}\n", name) - } - } - } - - /// Generate code to encode an argument for direct calls - fn generate_argument_encoding_direct(&self, name: &str, param_type: &ParamType) -> String { - match param_type { - ParamType::Address => { - format!(" data.extend({}.0.to_vec());\n", name) - } - ParamType::Uint(8) => { - format!(" data.push({});\n", name) - } - ParamType::Uint(16) => { - format!(" data.extend({}.to_le_bytes());\n", name) - } - ParamType::Uint(32) => { - format!(" data.extend({}.to_le_bytes());\n", name) - } - ParamType::Uint(64) => { - format!(" data.extend({}.to_le_bytes());\n", name) - } - ParamType::Uint(128) => { - format!(" data.extend({}.to_le_bytes());\n", name) - } - ParamType::Bool => { - format!(" data.push(if {} {{ 1 }} else {{ 0 }});\n", name) - } - ParamType::String => { - format!(" data.extend({}.as_bytes());\n", name) - } - ParamType::Bytes => { - format!(" data.extend({});\n", name) - } - _ => { - format!(" // TODO: Encode {}\n", name) - } - } - } - /// Generate Rust client code from an ABI file pub fn from_abi_file>(abi_path: P, contract_name: String) -> std::io::Result { let abi_json = fs::read_to_string(abi_path)?; diff --git a/crates/compiler/src/abi_generator.rs b/crates/compiler/src/abi_generator.rs index 10ccd93..5a6438f 100644 --- a/crates/compiler/src/abi_generator.rs +++ b/crates/compiler/src/abi_generator.rs @@ -241,56 +241,12 @@ impl AbiGenerator { functions } - /// Parse a selector pattern like "0x01 => function_name(call.args)" or "0x01 => { function_name(caller, call.args); }" - fn parse_selector_pattern<'a>(&self, line: &'a str) -> Option<(u8, &'a str)> { - let parts: Vec<&str> = line.split("=>").collect(); - if parts.len() != 2 { - return None; - } - - let selector_str = parts[0].trim(); - let function_part = parts[1].trim(); - - // Extract selector - if !selector_str.starts_with("0x") { - return None; - } - - let selector = u8::from_str_radix(&selector_str[2..], 16).ok()?; - - // Extract function name - handle both patterns: - // 1. "function_name(call.args)" - // 2. "{ function_name(caller, call.args); }" - let function_name = if function_part.starts_with('{') { - // Pattern 2: extract from inside braces - let inner = function_part.trim_start_matches('{').trim_end_matches('}'); - // Look for function call pattern: function_name(...) - if let Some(start) = inner.find('(') { - inner[..start].trim() - } else { - return None; - } - } else { - // Pattern 1: extract directly - if let Some(start) = function_part.find('(') { - function_part[..start].trim() - } else { - return None; - } - }; - - // Skip empty function names - if function_name.is_empty() { - return None; - } - - Some((selector, function_name)) - } - /// Find function definition and create FunctionAbi fn find_function_definition(&self, lines: &[&str], start_line: usize, function_name: &str) -> Option { // Look for function definition pattern: fn function_name(...) - for i in 0..lines.len() { + let forward = start_line..lines.len(); + let backward = 0..start_line; + for i in forward.chain(backward) { let trimmed = lines[i].trim(); if trimmed.starts_with("fn ") && trimmed.contains(function_name) { // Extract function signature @@ -299,7 +255,7 @@ impl AbiGenerator { } } } - + None } diff --git a/crates/compiler/src/bin/avm32.rs b/crates/compiler/src/bin/avm32.rs index b643fbb..481b2f6 100644 --- a/crates/compiler/src/bin/avm32.rs +++ b/crates/compiler/src/bin/avm32.rs @@ -70,7 +70,7 @@ fn main() { } } -fn cmd_build(mut args: Vec, paths: &Paths) -> Result<(), String> { +fn cmd_build(args: Vec, paths: &Paths) -> Result<(), String> { let mut bin: Option = None; let mut features: Option = None; let mut release = true; @@ -211,7 +211,7 @@ fn cmd_build(mut args: Vec, paths: &Paths) -> Result<(), String> { Ok(()) } -fn cmd_abi(mut args: Vec, paths: &Paths) -> Result<(), String> { +fn cmd_abi(args: Vec, paths: &Paths) -> Result<(), String> { let mut bin: Option = None; let mut src: Option = None; let mut out: Option = None; @@ -284,7 +284,7 @@ fn cmd_abi(mut args: Vec, paths: &Paths) -> Result<(), String> { Ok(()) } -fn cmd_client(mut args: Vec, _paths: &Paths) -> Result<(), String> { +fn cmd_client(args: Vec, _paths: &Paths) -> Result<(), String> { let mut abi_path: Option = None; let mut out: Option = None; let mut contract: Option = None; @@ -342,7 +342,7 @@ fn cmd_client(mut args: Vec, _paths: &Paths) -> Result<(), String> { Ok(()) } -fn cmd_all(mut args: Vec, paths: &Paths) -> Result<(), String> { +fn cmd_all(args: Vec, paths: &Paths) -> Result<(), String> { let mut bin: Option = None; let mut out_dir: Option = None; let mut cargo_cmd: Option = None; diff --git a/crates/examples/Cargo.toml b/crates/examples/Cargo.toml index fed7b87..938f0b2 100644 --- a/crates/examples/Cargo.toml +++ b/crates/examples/Cargo.toml @@ -12,12 +12,6 @@ k256 = { version = "0.13", default-features = false, features = ["arithmetic", " default = [] binaries = [] # Enable this feature to build RISC-V binaries -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" - # Note: These binaries are designed for RISC-V target and will cause linking errors # when building for host architecture during tests. Use --features binaries to build them. [[bin]] diff --git a/crates/examples/src/allocator_demo.rs b/crates/examples/src/allocator_demo.rs index 78ab601..be7b08f 100644 --- a/crates/examples/src/allocator_demo.rs +++ b/crates/examples/src/allocator_demo.rs @@ -7,8 +7,8 @@ use clibc::{ DataParser, entrypoint, require, types::address::Address, types::result::Result, vm_panic, }; -/// Guest program that demonstrates heap allocation using VM syscalls entrypoint!(main); +/// Guest program that demonstrates heap allocation using VM syscalls fn main(program: Address, _caller: Address, data: &[u8]) -> Result { let _ = program; // Need to import alloc types after entrypoint macro includes the allocator diff --git a/crates/examples/src/erc20.rs b/crates/examples/src/erc20.rs index c63ce68..fd610bc 100644 --- a/crates/examples/src/erc20.rs +++ b/crates/examples/src/erc20.rs @@ -3,7 +3,7 @@ extern crate clibc; use clibc::{ - DataParser, Map, StorageKey, entrypoint, event, fire_event, log, logf, persist_struct, + DataParser, Map, StorageKey, entrypoint, event, fire_event, logf, persist_struct, require, router::route, types::{address::Address, o::O, result::Result}, vm_panic, }; @@ -47,7 +47,7 @@ impl StorageKey for AllowanceKey { } unsafe fn main_entry(program: Address, caller: Address, data: &[u8]) -> Result { - route(data, program, caller, |to, from, call| { + route(data, program, caller, |_to, _from, call| { match call.selector { 0x01 => { init(&program, caller, call.args); @@ -89,7 +89,7 @@ unsafe fn main_entry(program: Address, caller: Address, data: &[u8]) -> Result { fn init(program: &Address, caller: Address, args: &[u8]) { logf!("init called"); let mut meta = match Metadata::load(program) { - O::Some(m) => vm_panic(b"already initialized"), + O::Some(_) => vm_panic(b"already initialized"), O::None => Metadata { total_supply: 0, decimals: 0, diff --git a/crates/examples/src/multi_func.rs b/crates/examples/src/multi_func.rs index 4d8fe4f..1ed0515 100644 --- a/crates/examples/src/multi_func.rs +++ b/crates/examples/src/multi_func.rs @@ -26,7 +26,7 @@ use clibc::{DataParser, entrypoint, require, types::result::Result, vm_panic}; fn my_vm_entry(program: Address, _caller: Address, data: &[u8]) -> Result { // EDUCATIONAL: Use the router to handle multiple function calls // The router decodes the input data and calls the appropriate function - route(data, program, _caller, |to, from, call| { + route(data, program, _caller, |_to, _from, call| { match call.selector { 0x01 => compare(call.args), // Function selector 0x01 = compare function 0x02 => other(call.args), // Function selector 0x02 = other function diff --git a/crates/examples/src/storage.rs b/crates/examples/src/storage.rs index 53b62c2..1cce2a6 100644 --- a/crates/examples/src/storage.rs +++ b/crates/examples/src/storage.rs @@ -37,8 +37,8 @@ fn my_vm_entry(program: Address, _caller: Address, _data: &[u8]) -> Result { // ... change local copy ... user.level = 5; user.id = 40001; - - // ... later ... + require(user.level == 5, b"user local level must be 5"); + require(user.id == 40001, b"user local id must be 40001"); let reloaded_user = User::load(&program).expect("user not found"); require(reloaded_user.level == 4, b"user level must be 4"); @@ -60,8 +60,11 @@ fn my_vm_entry(program: Address, _caller: Address, _data: &[u8]) -> Result { // ... change local copy ... config.retries = 15; config.timeout_ms = 103000; - - // ... later ... + require(config.retries == 15, b"config local retries must be 15"); + require( + config.timeout_ms == 103000, + b"config local timeout_ms must be 103000", + ); let reloaded_config = Config::load(&program).expect("config not found"); require(reloaded_config.retries == 13, b"config retries must be 13"); diff --git a/crates/kernel/src/bundle/mod.rs b/crates/kernel/src/bundle/mod.rs index fbb2a45..79537d0 100644 --- a/crates/kernel/src/bundle/mod.rs +++ b/crates/kernel/src/bundle/mod.rs @@ -94,7 +94,6 @@ fn execute_transaction(tx: &Transaction) -> bool { transfer(tx); true } - _ => panic!("unsupported transaction type"), } } diff --git a/crates/kernel/src/global.rs b/crates/kernel/src/global.rs index 379d796..58a1f33 100644 --- a/crates/kernel/src/global.rs +++ b/crates/kernel/src/global.rs @@ -201,7 +201,7 @@ pub static ROOT_PPN: Global = Global::new(0); /// Page allocator backing store. pub static PAGE_ALLOC: Global> = Global::new(None); /// Kernel heap allocator instance. -pub static KERNEL_HEAP: Global = Global::new(BumpAllocator::empty()); +pub(crate) static KERNEL_HEAP: Global = Global::new(BumpAllocator::empty()); const fn align_up(val: usize, align: usize) -> usize { (val + (align - 1)) & !(align - 1) diff --git a/crates/kernel/src/init.rs b/crates/kernel/src/init.rs index 0e6b31c..9fc0d0f 100644 --- a/crates/kernel/src/init.rs +++ b/crates/kernel/src/init.rs @@ -1,20 +1,18 @@ -use core::{cmp, slice}; +use core::slice; use clibc::{log, logf}; use state::State; -use kernel::global::{CURRENT_TASK, KERNEL_TASK_SLOT, STATE, TASKS}; -use kernel::{BootInfo, Task, trap}; +use kernel::global::STATE; +use kernel::{BootInfo, trap}; use kernel::memory::{heap, page_allocator}; /// Initialize kernel state from the bootloader handoff and optional state blob. pub fn init_kernel(state_ptr: *const u8, state_len: usize, boot_info_ptr: *const BootInfo) { let boot_info = unsafe { boot_info_ptr.as_ref() }; - if let Some(info) = init_boot_info(boot_info) { - unsafe { - page_allocator::init(info); - heap::init(info.heap_ptr, info.va_base, info.va_len); - } + if let Some(info) = crate::init_boot::init_boot_info(boot_info) { + page_allocator::init(info); + heap::init(info.heap_ptr, info.va_base, info.va_len); trap::init_trap_vector(info.kstack_top); init_state(state_ptr, state_len); } else { @@ -40,38 +38,3 @@ fn init_state(state_ptr: *const u8, state_len: usize) { } } } - -pub(crate) fn init_boot_info(boot_info: Option<&BootInfo>) -> Option<&BootInfo> { - logf!( - "init_boot_info: boot_info_ptr=0x%x", - boot_info - .map(|info| info as *const BootInfo as usize as u32) - .unwrap_or(0) - ); - if let Some(info) = boot_info { - let task = Task::kernel( - info.root_ppn, - info.heap_ptr, - info.va_base, - info.va_len, - ); - unsafe { - let tasks_slot = TASKS.get_mut(); - if tasks_slot.set_at(KERNEL_TASK_SLOT, task).is_err() { - log!("kernel task slot unavailable; kernel task not recorded"); - } - *CURRENT_TASK.get_mut() = KERNEL_TASK_SLOT; - } - logf!( - "boot_info: root_ppn=0x%x kstack_top=0x%x heap_ptr=0x%x mem_size=%d", - info.root_ppn, - info.kstack_top, - info.heap_ptr, - info.memory_size - ); - Some(info) - } else { - log!("boot_info missing; kernel task not initialized"); - None - } -} diff --git a/crates/kernel/src/init_boot.rs b/crates/kernel/src/init_boot.rs new file mode 100644 index 0000000..051a69d --- /dev/null +++ b/crates/kernel/src/init_boot.rs @@ -0,0 +1,39 @@ +use clibc::{log, logf}; + +use kernel::global::{CURRENT_TASK, KERNEL_TASK_SLOT, TASKS}; +use kernel::{BootInfo, Task}; + +pub(crate) fn init_boot_info(boot_info: Option<&BootInfo>) -> Option<&BootInfo> { + logf!( + "init_boot_info: boot_info_ptr=0x%x", + boot_info + .map(|info| info as *const BootInfo as usize as u32) + .unwrap_or(0) + ); + if let Some(info) = boot_info { + let task = Task::kernel( + info.root_ppn, + info.heap_ptr, + info.va_base, + info.va_len, + ); + unsafe { + let tasks_slot = TASKS.get_mut(); + if tasks_slot.set_at(KERNEL_TASK_SLOT, task).is_err() { + log!("kernel task slot unavailable; kernel task not recorded"); + } + *CURRENT_TASK.get_mut() = KERNEL_TASK_SLOT; + } + logf!( + "boot_info: root_ppn=0x%x kstack_top=0x%x heap_ptr=0x%x mem_size=%d", + info.root_ppn, + info.kstack_top, + info.heap_ptr, + info.memory_size + ); + Some(info) + } else { + log!("boot_info missing; kernel task not initialized"); + None + } +} diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index c084723..fded424 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -1,5 +1,4 @@ #![no_std] -#![feature(naked_functions)] #![feature(alloc_error_handler)] pub use types::boot::BootInfo; diff --git a/crates/kernel/src/main.rs b/crates/kernel/src/main.rs index b0b82c1..e6ee4ce 100644 --- a/crates/kernel/src/main.rs +++ b/crates/kernel/src/main.rs @@ -5,9 +5,10 @@ extern crate alloc; use core::slice; use kernel::BootInfo; -use clibc::{log, logf}; +use clibc::log; mod init; +mod init_boot; mod bundle; use crate::bundle::{decode_bundle, process_bundle}; use crate::init::init_kernel; diff --git a/crates/kernel/src/memory/heap.rs b/crates/kernel/src/memory/heap.rs index ad68dc2..bbec2f4 100644 --- a/crates/kernel/src/memory/heap.rs +++ b/crates/kernel/src/memory/heap.rs @@ -1,4 +1,3 @@ -use crate::global::Global; use core::alloc::{GlobalAlloc, Layout}; use core::ptr; diff --git a/crates/kernel/src/memory/tests/heap_edge_test.rs b/crates/kernel/src/memory/tests/heap_edge_test.rs index 7c7c529..ecdd4f9 100644 --- a/crates/kernel/src/memory/tests/heap_edge_test.rs +++ b/crates/kernel/src/memory/tests/heap_edge_test.rs @@ -8,6 +8,8 @@ use kernel::memory::heap; #[path = "../../tests/results.rs"] mod results; +#[path = "../../tests/fail.rs"] +mod fail; #[path = "../../tests/utils.rs"] mod utils; @@ -24,10 +26,10 @@ pub extern "C" fn _start( let _input = unsafe { core::slice::from_raw_parts(input_ptr, input_len) }; if let Err(code) = test_invalid_layouts() { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_monotonic_bump_and_data() { - utils::fail(code); + fail::fail(code); } log!("kernel heap edge test done"); diff --git a/crates/kernel/src/memory/tests/mem_alloc_test.rs b/crates/kernel/src/memory/tests/mem_alloc_test.rs index eb6b8c7..9ea96fa 100644 --- a/crates/kernel/src/memory/tests/mem_alloc_test.rs +++ b/crates/kernel/src/memory/tests/mem_alloc_test.rs @@ -10,6 +10,8 @@ use kernel::memory::{heap, page_allocator}; #[path = "../../tests/results.rs"] mod results; +#[path = "../../tests/fail.rs"] +mod fail; #[path = "../../tests/utils.rs"] mod utils; @@ -26,16 +28,16 @@ pub extern "C" fn _start( let _input = unsafe { core::slice::from_raw_parts(input_ptr, input_len) }; if let Err(code) = test_heap_alignment() { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_heap_exhaustion(info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_page_allocator_roots() { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_heap_too_large() { - utils::fail(code); + fail::fail(code); } utils::pass(); diff --git a/crates/kernel/src/memory/tests/mem_map_edge_test.rs b/crates/kernel/src/memory/tests/mem_map_edge_test.rs index e2c3486..69ce22e 100644 --- a/crates/kernel/src/memory/tests/mem_map_edge_test.rs +++ b/crates/kernel/src/memory/tests/mem_map_edge_test.rs @@ -11,6 +11,8 @@ use kernel::memory::page_allocator::{self, PagePerms}; #[path = "../../tests/results.rs"] mod results; +#[path = "../../tests/fail.rs"] +mod fail; #[path = "../../tests/utils.rs"] mod utils; @@ -31,32 +33,32 @@ pub extern "C" fn _start( let user_root = page_allocator::alloc_root().unwrap_or(0); if user_root == 0 { - utils::fail(1); + fail::fail(1); } if let Err(code) = test_unaligned_map_and_translate(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_cross_l1_boundary(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_multiple_l2_tables(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_zero_len_map_no_effect(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_map_to_physical_alignment_and_alias(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_mirror_gap_behavior(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_copy_user_atomic(user_root, info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_remap_override_perms(user_root, info) { - utils::fail(code); + fail::fail(code); } log!("kernel mem map edge test done"); diff --git a/crates/kernel/src/memory/tests/mem_map_test.rs b/crates/kernel/src/memory/tests/mem_map_test.rs index 45e5bf1..b3dce7b 100644 --- a/crates/kernel/src/memory/tests/mem_map_test.rs +++ b/crates/kernel/src/memory/tests/mem_map_test.rs @@ -10,6 +10,8 @@ use kernel::memory::page_allocator::{self, PagePerms}; #[path = "../../tests/results.rs"] mod results; +#[path = "../../tests/fail.rs"] +mod fail; #[path = "../../tests/utils.rs"] mod utils; @@ -27,34 +29,34 @@ pub extern "C" fn _start( let user_root = page_allocator::alloc_root().unwrap_or(0); if user_root == 0 { - utils::fail(1); + fail::fail(1); } let (va_start, len) = pick_user_range(info); if let Err(code) = test_user_map(user_root, va_start, len) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_read_only_mapping(user_root, info, va_start, len) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_exec_mapping(user_root, info, va_start, len) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_kernel_sees_different_phys_before_mirror(user_root, va_start) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_mirror(user_root, va_start, len) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_translate(user_root, va_start) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_copy_peek(user_root, va_start) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_user_cannot_translate_kernel_only(user_root, info) { - utils::fail(code); + fail::fail(code); } log!("kernel mem map test done"); diff --git a/crates/kernel/src/memory/tests/page_alloc_test.rs b/crates/kernel/src/memory/tests/page_alloc_test.rs index de7a80f..fe78fff 100644 --- a/crates/kernel/src/memory/tests/page_alloc_test.rs +++ b/crates/kernel/src/memory/tests/page_alloc_test.rs @@ -8,6 +8,8 @@ use kernel::memory::page_allocator; #[path = "../../tests/results.rs"] mod results; +#[path = "../../tests/fail.rs"] +mod fail; #[path = "../../tests/utils.rs"] mod utils; @@ -24,10 +26,10 @@ pub extern "C" fn _start( let _input = unsafe { core::slice::from_raw_parts(input_ptr, input_len) }; if let Err(code) = test_alloc_root_zeroed(info) { - utils::fail(code); + fail::fail(code); } if let Err(code) = test_bump_allocator_behavior() { - utils::fail(code); + fail::fail(code); } log!("kernel page allocator test done"); diff --git a/crates/kernel/src/syscall/mod.rs b/crates/kernel/src/syscall/mod.rs index 4398c88..7b2ecf0 100644 --- a/crates/kernel/src/syscall/mod.rs +++ b/crates/kernel/src/syscall/mod.rs @@ -21,7 +21,6 @@ use call_program::sys_call_program; use fire_event::sys_fire_event; use panic::sys_panic; use storage::{sys_storage_get, sys_storage_set}; -pub(crate) use panic::sys_panic_with_message; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum CallerMode { diff --git a/crates/kernel/src/task/prep.rs b/crates/kernel/src/task/prep.rs index e8906cd..bd6dca1 100644 --- a/crates/kernel/src/task/prep.rs +++ b/crates/kernel/src/task/prep.rs @@ -1,7 +1,7 @@ use crate::{AddressSpace, Task}; use crate::global::{ - CALL_ARGS_PAGE_BASE, CODE_SIZE_LIMIT, CURRENT_TASK, FROM_PTR_ADDR, HEAP_START_ADDR, - INPUT_BASE_ADDR, MAX_INPUT_LEN, RO_DATA_SIZE_LIMIT, TO_PTR_ADDR, + CALL_ARGS_PAGE_BASE, CURRENT_TASK, FROM_PTR_ADDR, HEAP_START_ADDR, INPUT_BASE_ADDR, + MAX_INPUT_LEN, TO_PTR_ADDR, }; use crate::memory::page_allocator as mmu; use clibc::{log, logf}; @@ -64,23 +64,6 @@ pub fn prep_program_task( if entry_off as usize >= code.len() { panic!("launch_program: invalid entry offset"); } - if code.len() >= entry_off as usize + 8 { - let head = u32::from_le_bytes([ - code[entry_off as usize], - code[entry_off as usize + 1], - code[entry_off as usize + 2], - code[entry_off as usize + 3], - ]); - let head2 = u32::from_le_bytes([ - code[entry_off as usize + 4], - code[entry_off as usize + 5], - code[entry_off as usize + 6], - code[entry_off as usize + 7], - ]); - } - let nz_count = code.iter().filter(|&&b| b != 0).count(); - let local_first_nz = code.iter().position(|&b| b != 0).unwrap_or(code.len()); - if !mmu::copy(root_ppn, PROGRAM_VA_BASE, code) { logf!("launch_program: failed to copy code into root=0x%x", root_ppn); return None; diff --git a/crates/kernel/src/tests/fail.rs b/crates/kernel/src/tests/fail.rs new file mode 100644 index 0000000..1f7bd2e --- /dev/null +++ b/crates/kernel/src/tests/fail.rs @@ -0,0 +1,6 @@ +use crate::{results, utils}; + +pub fn fail(code: u32) -> ! { + unsafe { results::write_results(results::TestResults { status: 1, detail: code }) }; + utils::halt(); +} diff --git a/crates/kernel/src/tests/results.rs b/crates/kernel/src/tests/results.rs index c013666..90176ac 100644 --- a/crates/kernel/src/tests/results.rs +++ b/crates/kernel/src/tests/results.rs @@ -12,13 +12,6 @@ impl TestResults { detail, } } - - pub const fn fail(detail: u32) -> Self { - Self { - status: 1, - detail, - } - } } pub unsafe fn write_results(results: TestResults) { diff --git a/crates/kernel/src/tests/utils.rs b/crates/kernel/src/tests/utils.rs index cd8534b..61fddaa 100644 --- a/crates/kernel/src/tests/utils.rs +++ b/crates/kernel/src/tests/utils.rs @@ -3,16 +3,14 @@ use kernel::memory::{heap, page_allocator}; use kernel::{trap, BootInfo}; use crate::results; -#[path = "../init.rs"] -mod init; +#[path = "../init_boot.rs"] +mod init_boot; pub fn init_test_kernel(boot_info_ptr: *const BootInfo) -> BootInfo { let boot_info = unsafe { boot_info_ptr.as_ref() }; - if let Some(info) = init::init_boot_info(boot_info) { - unsafe { - page_allocator::init(info); - heap::init(info.heap_ptr, info.va_base, info.va_len); - } + if let Some(info) = init_boot::init_boot_info(boot_info) { + page_allocator::init(info); + heap::init(info.heap_ptr, info.va_base, info.va_len); trap::init_trap_vector(info.kstack_top); let info_copy = *info; log!("kernel initialized"); @@ -27,11 +25,6 @@ pub fn pass() -> ! { halt(); } -pub fn fail(code: u32) -> ! { - unsafe { results::write_results(results::TestResults::fail(code)) }; - halt(); -} - #[inline(never)] pub fn halt() -> ! { unsafe { core::arch::asm!("ebreak") }; diff --git a/crates/kernel/src/trap/mod.rs b/crates/kernel/src/trap/mod.rs index ffa5b0c..31ab61d 100644 --- a/crates/kernel/src/trap/mod.rs +++ b/crates/kernel/src/trap/mod.rs @@ -37,6 +37,12 @@ const REG_A7: usize = 17; const REG_SP: usize = 2; const REG_PC: usize = 32; +#[repr(C)] +pub struct TrapReturn { + sp: u32, + kind: u32, +} + /// Install the kernel trap vector and set up the kernel stack for traps. pub fn init_trap_vector(kstack_top: u32) { // Seed sscratch with the kernel stack top so trap entry can swap sp with @@ -110,7 +116,7 @@ unsafe extern "C" fn return_from_trap() -> ! { /// laid out as: /// regs[0..32] = x0..x31, regs[32] = pc. #[unsafe(no_mangle)] -pub extern "C" fn handle_trap(saved: *mut u32) -> (u32, u32) { +pub extern "C" fn handle_trap(saved: *mut u32) -> TrapReturn { let regs = unsafe { core::slice::from_raw_parts_mut(saved, TRAP_FRAME_WORDS) }; let scause = read_scause(); let stval = read_stval(); @@ -230,7 +236,10 @@ pub extern "C" fn handle_trap(saved: *mut u32) -> (u32, u32) { } _ => log!("unhandled trap"), } - (return_sp, return_kind) + TrapReturn { + sp: return_sp, + kind: return_kind, + } } #[unsafe(no_mangle)] @@ -256,13 +265,6 @@ fn read_scause() -> usize { value } -#[inline(always)] -fn read_satp() -> u32 { - let value: u32; - unsafe { asm!("csrr {0}, satp", out(reg) value); } - value -} - #[inline(always)] fn read_sstatus() -> u32 { let value: u32; diff --git a/crates/state/src/state.rs b/crates/state/src/state.rs index c2adcb5..92f909e 100644 --- a/crates/state/src/state.rs +++ b/crates/state/src/state.rs @@ -1,5 +1,5 @@ use alloc::collections::BTreeMap; -use alloc::string::{String, ToString}; +use alloc::string::ToString; use alloc::vec::Vec; use crate::Account; use types::address::Address; diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 2a17123..894f7a1 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -4,3 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] + +[features] +std = [] diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 178b01b..11a6168 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -13,7 +13,6 @@ pub mod o; pub use o::*; // Allow `$crate::O` in macros pub mod primitives; -pub use primitives::*; pub mod transaction; pub use transaction::*; diff --git a/crates/vm/src/cpu.rs b/crates/vm/src/cpu.rs index e0efe5f..973e410 100644 --- a/crates/vm/src/cpu.rs +++ b/crates/vm/src/cpu.rs @@ -442,8 +442,8 @@ impl CPU { /// DEBUGGING: This function provides detailed information about what /// went wrong, including the hex dump of the invalid bytes. /// - /// RETURN VALUE: Returns false to halt execution on invalid instructions - fn unknown_instruction(&mut self, memory: Memory) -> bool { + /// RETURN VALUE: This method always panics and never returns. + fn unknown_instruction(&mut self, memory: Memory) -> ! { // EDUCATIONAL: Try to read the invalid instruction bytes for debugging if let Some(slice_ref) = memory.mem_slice(VirtualAddress(self.pc), VirtualAddress(self.pc.wrapping_add(4))) { @@ -464,7 +464,6 @@ impl CPU { self.pc ); } - false } /// Fetches and decodes the next instruction from memory. diff --git a/crates/vm/src/decoder.rs b/crates/vm/src/decoder.rs index 6d5ecd6..dca4855 100644 --- a/crates/vm/src/decoder.rs +++ b/crates/vm/src/decoder.rs @@ -497,7 +497,7 @@ pub fn decode_compressed(hword: u16) -> Option { // C.LUI expands into lui rd, nzimm[17:12] // The 6-bit nzimm is used as imm[17:12] of the 20-bit LUI immediate // Sign-extend bit 17 (nzimm[17]) into all higher bits [31:18] - let signed_nzimm = (((nzimm as i32) << 26) >> 26); + let signed_nzimm = ((nzimm as i32) << 26) >> 26; Some(Instruction::Lui { rd, imm: signed_nzimm}) } else { diff --git a/crates/vm/src/exe.rs b/crates/vm/src/exe.rs index 2b326d5..e22dc78 100644 --- a/crates/vm/src/exe.rs +++ b/crates/vm/src/exe.rs @@ -1378,7 +1378,6 @@ impl CPU { } // 1 = failure } } - _ => todo!("unhandled instruction"), } true } diff --git a/crates/vm/tests/spec_runner.rs b/crates/vm/tests/spec_runner.rs index 980e97d..4621327 100644 --- a/crates/vm/tests/spec_runner.rs +++ b/crates/vm/tests/spec_runner.rs @@ -235,7 +235,7 @@ fn run_category_tests(test_dir: &str, category: &str) -> Result<(usize, usize, u println!("Found {} {} test files to run ({} skipped)", test_files.len(), category, skipped_count); let mut passed_count = 0; - let mut failed_count = 0; + let failed_count = 0; for (i, elf_path) in test_files.iter().enumerate() { let test_name = std::path::Path::new(elf_path) @@ -248,7 +248,6 @@ fn run_category_tests(test_dir: &str, category: &str) -> Result<(usize, usize, u if let Err(e) = run_single_test(elf_path) { println!("❌ FAILED - {}", e); - failed_count += 1; return Err(e); } else { println!("✅ PASSED");