diff --git a/crates/console/prometeu-firmware/src/firmware/firmware.rs b/crates/console/prometeu-firmware/src/firmware/firmware.rs index 8860f7cc..262e5260 100644 --- a/crates/console/prometeu-firmware/src/firmware/firmware.rs +++ b/crates/console/prometeu-firmware/src/firmware/firmware.rs @@ -181,7 +181,6 @@ mod tests { title: "Broken Cart".into(), app_version: "1.0.0".into(), app_mode: AppMode::Game, - entrypoint: "".into(), capabilities: 0, program: vec![0, 0, 0, 0], assets: AssetsPayloadSource::empty(), @@ -218,7 +217,6 @@ mod tests { title: "Trap Cart".into(), app_version: "1.0.0".into(), app_mode: AppMode::Game, - entrypoint: "".into(), capabilities: caps::GFX, program, assets: AssetsPayloadSource::empty(), diff --git a/crates/console/prometeu-hal/src/cartridge.rs b/crates/console/prometeu-hal/src/cartridge.rs index 5a808c88..c61ae695 100644 --- a/crates/console/prometeu-hal/src/cartridge.rs +++ b/crates/console/prometeu-hal/src/cartridge.rs @@ -22,7 +22,6 @@ pub struct Cartridge { pub title: String, pub app_version: String, pub app_mode: AppMode, - pub entrypoint: String, pub capabilities: CapFlags, pub program: Vec, pub assets: AssetsPayloadSource, @@ -36,7 +35,6 @@ pub struct CartridgeDTO { pub title: String, pub app_version: String, pub app_mode: AppMode, - pub entrypoint: String, pub capabilities: CapFlags, pub program: Vec, pub assets: AssetsPayloadSource, @@ -51,7 +49,6 @@ impl From for Cartridge { title: dto.title, app_version: dto.app_version, app_mode: dto.app_mode, - entrypoint: dto.entrypoint, capabilities: dto.capabilities, program: dto.program, assets: dto.assets, @@ -305,7 +302,6 @@ pub struct CartridgeManifest { pub title: String, pub app_version: String, pub app_mode: AppMode, - pub entrypoint: String, #[serde(default)] pub capabilities: Vec, } diff --git a/crates/console/prometeu-hal/src/cartridge_loader.rs b/crates/console/prometeu-hal/src/cartridge_loader.rs index 70675aaa..9ed03612 100644 --- a/crates/console/prometeu-hal/src/cartridge_loader.rs +++ b/crates/console/prometeu-hal/src/cartridge_loader.rs @@ -85,7 +85,6 @@ impl DirectoryCartridgeLoader { title: manifest.title, app_version: manifest.app_version, app_mode: manifest.app_mode, - entrypoint: manifest.entrypoint, capabilities, program, assets, @@ -277,8 +276,7 @@ mod tests { "app_id": 1001, "title": "Example", "app_version": "1.0.0", - "app_mode": "Game", - "entrypoint": "main" + "app_mode": "Game" }); if let Some(capabilities) = capabilities { diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime.rs b/crates/console/prometeu-system/src/virtual_machine_runtime.rs index 753f0ed6..37935e97 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime.rs @@ -30,7 +30,6 @@ pub struct VirtualMachineRuntime { pub current_cartridge_title: String, pub current_cartridge_app_version: String, pub current_cartridge_app_mode: AppMode, - pub current_entrypoint: String, pub logs_written_this_frame: HashMap, pub telemetry_current: TelemetryFrame, pub telemetry_last: TelemetryFrame, diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/lifecycle.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/lifecycle.rs index b62511b8..84046860 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/lifecycle.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/lifecycle.rs @@ -23,7 +23,6 @@ impl VirtualMachineRuntime { current_cartridge_title: String::new(), current_cartridge_app_version: String::new(), current_cartridge_app_mode: AppMode::Game, - current_entrypoint: String::new(), logs_written_this_frame: HashMap::new(), telemetry_current: TelemetryFrame::default(), telemetry_last: TelemetryFrame::default(), @@ -97,7 +96,6 @@ impl VirtualMachineRuntime { self.current_cartridge_title.clear(); self.current_cartridge_app_version.clear(); self.current_cartridge_app_mode = AppMode::Game; - self.current_entrypoint.clear(); self.logs_written_this_frame.clear(); self.telemetry_current = TelemetryFrame::default(); @@ -122,13 +120,12 @@ impl VirtualMachineRuntime { self.clear_cartridge_state(); vm.set_capabilities(cartridge.capabilities); - match vm.initialize(cartridge.program.clone(), &cartridge.entrypoint) { + match vm.initialize(cartridge.program.clone()) { Ok(_) => { self.current_app_id = cartridge.app_id; self.current_cartridge_title = cartridge.title.clone(); self.current_cartridge_app_version = cartridge.app_version.clone(); self.current_cartridge_app_mode = cartridge.app_mode; - self.current_entrypoint = cartridge.entrypoint.clone(); Ok(()) } Err(e) => { diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs index 44787156..c2a67bcc 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs @@ -59,7 +59,6 @@ fn cartridge_with_program(program: Vec, capabilities: u64) -> Cartridge { title: "Test Cart".into(), app_version: "1.0.0".into(), app_mode: AppMode::Game, - entrypoint: "".into(), capabilities, program, assets: AssetsPayloadSource::empty(), @@ -270,7 +269,6 @@ fn reset_clears_cartridge_scoped_runtime_state() { runtime.current_cartridge_title = "Cart".into(); runtime.current_cartridge_app_version = "1.2.3".into(); runtime.current_cartridge_app_mode = AppMode::System; - runtime.current_entrypoint = "main".into(); runtime.logs_written_this_frame.insert(42, 3); runtime.telemetry_current.frame_index = 8; runtime.telemetry_current.cycles_used = 99; @@ -296,7 +294,6 @@ fn reset_clears_cartridge_scoped_runtime_state() { assert!(runtime.current_cartridge_title.is_empty()); assert!(runtime.current_cartridge_app_version.is_empty()); assert_eq!(runtime.current_cartridge_app_mode, AppMode::Game); - assert!(runtime.current_entrypoint.is_empty()); assert!(runtime.logs_written_this_frame.is_empty()); assert_eq!(runtime.telemetry_current.frame_index, 0); assert_eq!(runtime.telemetry_current.cycles_used, 0); @@ -352,7 +349,6 @@ fn initialize_vm_failure_clears_previous_identity_and_handles() { assert!(runtime.current_cartridge_title.is_empty()); assert!(runtime.current_cartridge_app_version.is_empty()); assert_eq!(runtime.current_cartridge_app_mode, AppMode::Game); - assert!(runtime.current_entrypoint.is_empty()); assert!(runtime.open_files.is_empty()); assert_eq!(runtime.next_handle, 1); assert!(!runtime.paused); @@ -1030,7 +1026,6 @@ fn tick_memcard_slot_roundtrip_for_game_profile() { title: "Memcard Game".into(), app_version: "1.0.0".into(), app_mode: AppMode::Game, - entrypoint: "".into(), capabilities: caps::FS, program, assets: AssetsPayloadSource::empty(), @@ -1070,7 +1065,6 @@ fn tick_memcard_access_is_denied_for_non_game_profile() { title: "System App".into(), app_version: "1.0.0".into(), app_mode: AppMode::System, - entrypoint: "".into(), capabilities: caps::FS, program, assets: AssetsPayloadSource::empty(), diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs index 9d87c06f..61d19946 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs @@ -58,7 +58,7 @@ impl VirtualMachineRuntime { self.begin_logical_frame(signals, hw); if self.needs_prepare_entry_call || vm.call_stack_is_empty() { - vm.prepare_call(&self.current_entrypoint); + vm.prepare_boot_call(); self.needs_prepare_entry_call = false; } diff --git a/crates/console/prometeu-vm/src/virtual_machine.rs b/crates/console/prometeu-vm/src/virtual_machine.rs index 2433385e..3e0ec593 100644 --- a/crates/console/prometeu-vm/src/virtual_machine.rs +++ b/crates/console/prometeu-vm/src/virtual_machine.rs @@ -2598,7 +2598,7 @@ mod tests { #[test] fn test_loader_hardening_invalid_magic() { let mut vm = VirtualMachine::default(); - let res = vm.initialize(vec![0, 0, 0, 0], ""); + let res = vm.initialize(vec![0, 0, 0, 0]); assert_eq!(res, Err(VmInitError::InvalidFormat)); // VM should remain empty assert_eq!(vm.program.rom.len(), 0); @@ -2611,7 +2611,7 @@ mod tests { header[0..4].copy_from_slice(b"PBS\0"); header[4..6].copy_from_slice(&1u16.to_le_bytes()); // version 1 (unsupported) - let res = vm.initialize(header, ""); + let res = vm.initialize(header); assert_eq!(res, Err(VmInitError::UnsupportedFormat)); } @@ -2622,7 +2622,7 @@ mod tests { header[0..4].copy_from_slice(b"PBS\0"); header[8..12].copy_from_slice(&1u32.to_le_bytes()); // 1 section claimed but none provided - let res = vm.initialize(header, ""); + let res = vm.initialize(header); match res { Err(VmInitError::ImageLoadFailed(prometeu_bytecode::LoadError::UnexpectedEof)) => {} _ => panic!("Expected PbsV0LoadFailed(UnexpectedEof), got {:?}", res), @@ -2630,7 +2630,7 @@ mod tests { } #[test] - fn test_loader_hardening_entrypoint_not_found() { + fn test_loader_hardening_boot_protocol_entrypoint_not_found() { let mut vm = VirtualMachine::default(); let header = prometeu_bytecode::model::BytecodeModule { version: 0, @@ -2643,8 +2643,7 @@ mod tests { } .serialize(); - // Try to initialize with numeric entrypoint 10 (out of bounds for empty ROM) - let res = vm.initialize(header, "10"); + let res = vm.initialize(header); assert_eq!(res, Err(VmInitError::EntrypointNotFound)); // VM state should not be updated @@ -2656,22 +2655,27 @@ mod tests { fn test_loader_hardening_successful_init() { let mut vm = VirtualMachine::default(); vm.pc = 123; // Pollution + let code = assemble("HALT").expect("assemble"); let header = prometeu_bytecode::model::BytecodeModule { version: 0, const_pool: vec![], - functions: vec![], - code: vec![], + functions: vec![FunctionMeta { + code_offset: 0, + code_len: code.len() as u32, + ..Default::default() + }], + code, debug_info: None, exports: vec![], syscalls: vec![], } .serialize(); - let res = vm.initialize(header, ""); + let res = vm.initialize(header); assert!(res.is_ok()); assert_eq!(vm.pc, 0); - assert_eq!(vm.program.rom.len(), 0); + assert_eq!(vm.program.rom.len(), 2); assert_eq!(vm.cycles, 0); } @@ -2692,7 +2696,7 @@ mod tests { }], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert!(res.is_ok(), "patched hostcall should initialize"); @@ -2718,7 +2722,7 @@ mod tests { }], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, @@ -2758,7 +2762,7 @@ mod tests { ], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, @@ -2790,7 +2794,7 @@ mod tests { }], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, @@ -2820,7 +2824,7 @@ mod tests { }], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, @@ -2853,7 +2857,7 @@ mod tests { }], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, @@ -2888,7 +2892,7 @@ mod tests { }], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, @@ -2959,7 +2963,7 @@ mod tests { let mut vm = VirtualMachine::default(); vm.set_capabilities(prometeu_hal::syscalls::caps::ALL); let bytes = serialized_single_hostcall_module(syscall); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert!(res.is_ok(), "status-first signature must be accepted: {:?}", res); } } @@ -3015,7 +3019,7 @@ mod tests { let mut vm = VirtualMachine::default(); vm.set_capabilities(prometeu_hal::syscalls::caps::ALL); let bytes = serialized_single_hostcall_module(syscall.clone()); - let err = vm.initialize(bytes, "").expect_err("legacy ABI must be rejected"); + let err = vm.initialize(bytes).expect_err("legacy ABI must be rejected"); match err { VmInitError::LoaderPatchFailed(crate::vm_init_error::LoaderPatchError::ResolveFailed( prometeu_hal::syscalls::DeclaredLoadError::AbiMismatch { @@ -3048,7 +3052,7 @@ mod tests { let mut header = vec![0u8; 32]; header[0..4].copy_from_slice(b"PBS\0"); - let res = vm.initialize(header, ""); + let res = vm.initialize(header); assert_eq!( res, @@ -3080,7 +3084,7 @@ mod tests { ], ); - let res = vm.initialize(bytes, ""); + let res = vm.initialize(bytes); assert_eq!( res, diff --git a/crates/console/prometeu-vm/src/virtual_machine/loader.rs b/crates/console/prometeu-vm/src/virtual_machine/loader.rs index 10f7047b..21f964ba 100644 --- a/crates/console/prometeu-vm/src/virtual_machine/loader.rs +++ b/crates/console/prometeu-vm/src/virtual_machine/loader.rs @@ -68,11 +68,7 @@ fn patch_module_hostcalls( } impl VirtualMachine { - pub fn initialize( - &mut self, - program_bytes: Vec, - entrypoint: &str, - ) -> Result<(), VmInitError> { + pub fn initialize(&mut self, program_bytes: Vec) -> Result<(), VmInitError> { self.program = ProgramImage::default(); self.pc = 0; self.operand_stack.clear(); @@ -113,23 +109,11 @@ impl VirtualMachine { return Err(VmInitError::InvalidFormat); }; - let pc = if entrypoint.is_empty() { - program.functions.first().map(|f| f.code_offset as usize).unwrap_or(0) - } else if let Ok(func_idx) = entrypoint.parse::() { - program - .functions - .get(func_idx) - .map(|f| f.code_offset as usize) - .ok_or(VmInitError::EntrypointNotFound)? - } else if let Some(&func_idx) = program.exports.get(entrypoint) { - program - .functions - .get(func_idx as usize) - .map(|f| f.code_offset as usize) - .ok_or(VmInitError::EntrypointNotFound)? - } else { - return Err(VmInitError::EntrypointNotFound); - }; + let pc = program + .functions + .first() + .map(|f| f.code_offset as usize) + .ok_or(VmInitError::EntrypointNotFound)?; self.program = program; self.pc = pc; @@ -142,6 +126,10 @@ impl VirtualMachine { self.capabilities = caps; } + pub fn prepare_boot_call(&mut self) { + self.prepare_call_by_index(0); + } + pub fn prepare_call(&mut self, entrypoint: &str) { let func_idx = if let Ok(idx) = entrypoint.parse::() { idx @@ -149,6 +137,10 @@ impl VirtualMachine { self.program.exports.get(entrypoint).map(|&idx| idx as usize).ok_or(()).unwrap_or(0) }; + self.prepare_call_by_index(func_idx); + } + + fn prepare_call_by_index(&mut self, func_idx: usize) { let callee = self.program.functions.get(func_idx).cloned().unwrap_or_default(); self.pc = callee.code_offset as usize; self.halted = false; diff --git a/crates/dev/prometeu-layer-tests/tests/verifier_closure_reject.rs b/crates/dev/prometeu-layer-tests/tests/verifier_closure_reject.rs index 36cfc6f0..9d19bb84 100644 --- a/crates/dev/prometeu-layer-tests/tests/verifier_closure_reject.rs +++ b/crates/dev/prometeu-layer-tests/tests/verifier_closure_reject.rs @@ -5,6 +5,6 @@ fn invalid_image_format_is_rejected_before_execution() { // Provide bytes that are not a valid PBS image. The VM must reject it with InvalidFormat. let program_bytes = b"NOT_PBS_IMAGE".to_vec(); let mut vm = VirtualMachine::default(); - let result = vm.initialize(program_bytes, "0"); + let result = vm.initialize(program_bytes); assert!(matches!(result, Err(VmInitError::InvalidFormat))); } diff --git a/crates/tools/pbxgen-stress/src/lib.rs b/crates/tools/pbxgen-stress/src/lib.rs index 948f5146..14bb6bea 100644 --- a/crates/tools/pbxgen-stress/src/lib.rs +++ b/crates/tools/pbxgen-stress/src/lib.rs @@ -93,7 +93,7 @@ pub fn generate() -> Result<()> { if assets_pa_path.exists() { fs::remove_file(&assets_pa_path)?; } - fs::write(out_dir.join("manifest.json"), b"{\n \"magic\": \"PMTU\",\n \"cartridge_version\": 1,\n \"app_id\": 1,\n \"title\": \"Stress Console\",\n \"app_version\": \"0.1.0\",\n \"app_mode\": \"Game\",\n \"entrypoint\": \"main\",\n \"capabilities\": [\"gfx\", \"log\"]\n}\n")?; + fs::write(out_dir.join("manifest.json"), b"{\n \"magic\": \"PMTU\",\n \"cartridge_version\": 1,\n \"app_id\": 1,\n \"title\": \"Stress Console\",\n \"app_version\": \"0.1.0\",\n \"app_mode\": \"Game\",\n \"capabilities\": [\"gfx\", \"log\"]\n}\n")?; Ok(()) }