use super::*; use crate::CrashReport; use crate::fs::FsBackend; use prometeu_hal::cartridge::Cartridge; use prometeu_hal::log::{LogLevel, LogSource}; impl VirtualMachineRuntime { pub fn new(cap_config: Option) -> Self { let boot_time = Instant::now(); let log_service = LogService::new(4096); let atomic_telemetry = Arc::new(AtomicTelemetry::new(Arc::clone(&log_service.logs_count))); let mut os = Self { tick_index: 0, logical_frame_index: 0, logical_frame_active: false, logical_frame_remaining_cycles: 0, last_frame_cpu_time_us: 0, fs: VirtualFS::new(), fs_state: FsState::Unmounted, memcard: MemcardService::new(), open_files: HashMap::new(), next_handle: 1, log_service, current_app_id: 0, current_cartridge_title: String::new(), current_cartridge_app_version: String::new(), current_cartridge_app_mode: AppMode::Game, logs_written_this_frame: HashMap::new(), atomic_telemetry, last_crash_report: None, certifier: Certifier::new(cap_config.unwrap_or_default()), paused: false, debug_step_request: false, inspection_active: false, needs_prepare_entry_call: false, boot_time, }; os.log(LogLevel::Info, LogSource::Pos, 0, "PrometeuOS starting...".to_string()); os } pub fn log(&mut self, level: LogLevel, source: LogSource, tag: u16, msg: String) { let ts_ms = self.boot_time.elapsed().as_millis() as u64; let frame = self.logical_frame_index; self.log_service.log(ts_ms, frame, level, source, tag, msg); } pub fn mount_fs(&mut self, backend: Box) { self.log(LogLevel::Info, LogSource::Fs, 0, "Attempting to mount filesystem".to_string()); match self.fs.mount(backend) { Ok(_) => { self.fs_state = FsState::Mounted; self.log( LogLevel::Info, LogSource::Fs, 0, "Filesystem mounted successfully".to_string(), ); } Err(e) => { let err_msg = format!("Failed to mount filesystem: {:?}", e); self.log(LogLevel::Error, LogSource::Fs, 0, err_msg); self.fs_state = FsState::Error(e); } } } pub fn unmount_fs(&mut self) { self.fs.unmount(); self.fs_state = FsState::Unmounted; } pub(crate) fn update_fs(&mut self) { if self.fs_state == FsState::Mounted && !self.fs.is_healthy() { self.log( LogLevel::Error, LogSource::Fs, 0, "Filesystem became unhealthy, unmounting".to_string(), ); self.unmount_fs(); } } pub(crate) fn clear_cartridge_state(&mut self) { self.logical_frame_index = 0; self.logical_frame_active = false; self.logical_frame_remaining_cycles = 0; self.last_frame_cpu_time_us = 0; self.open_files.clear(); self.next_handle = 1; self.memcard.clear_all_staging(); self.current_app_id = 0; self.current_cartridge_title.clear(); self.current_cartridge_app_version.clear(); self.current_cartridge_app_mode = AppMode::Game; self.logs_written_this_frame.clear(); self.last_crash_report = None; self.paused = false; self.debug_step_request = false; self.inspection_active = false; self.needs_prepare_entry_call = false; } pub fn reset(&mut self, vm: &mut VirtualMachine) { *vm = VirtualMachine::default(); self.clear_cartridge_state(); } pub fn initialize_vm( &mut self, vm: &mut VirtualMachine, cartridge: &Cartridge, ) -> Result<(), CrashReport> { self.clear_cartridge_state(); vm.set_capabilities(cartridge.capabilities); 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; Ok(()) } Err(e) => { let report = CrashReport::VmInit { error: e }; self.last_crash_report = Some(report.clone()); self.log( LogLevel::Error, LogSource::Vm, report.log_tag(), format!("Failed to initialize VM: {}", report), ); Err(report) } } } }