146 lines
4.9 KiB
Rust

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<CertificationConfig>) -> 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<dyn FsBackend>) {
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)
}
}
}
}