146 lines
4.9 KiB
Rust
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)
|
|
}
|
|
}
|
|
}
|
|
}
|