diff --git a/src/kernel/src/args.rs b/src/kernel/src/args.rs new file mode 100644 index 00000000..3ee4d6ee --- /dev/null +++ b/src/kernel/src/args.rs @@ -0,0 +1,93 @@ +use crate::idps::ConsoleId; +use clap::{command, value_parser, Arg, ArgAction}; +use serde::Deserialize; +use std::io::Read; +use std::path::PathBuf; + +/// Kernel arguments loaded from either `.kernel-debug` or command line arguments. +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +pub struct Args { + pub system: PathBuf, + pub game: PathBuf, + pub debug_dump: Option, + #[serde(default)] + pub clear_debug_dump: bool, + #[serde(default)] + pub pro: bool, + #[serde(default)] + pub idps: ConsoleId, +} + +impl Args { + pub fn from_file(file: impl Read) -> Result { + serde_yaml::from_reader(file) + } + + pub fn from_command_line() -> Self { + // Parse. + let args = command!() + .arg( + Arg::new("pro") + .help("Enable PS4 Pro mode (AKA Neo mode)") + .long("pro") + .alias("neo") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("idps") + .help("IDPS to use (AKA Console ID)") + .long("idps") + .value_name("IDPS") + .value_parser(value_parser!(ConsoleId)), + ) + .arg( + Arg::new("debug_dump") + .help("Path to a directory to write debug information") + .long("debug-dump") + .value_name("PATH") + .value_parser(value_parser!(PathBuf)), + ) + .arg( + Arg::new("clear_debug_dump") + .help("Clear all previous files in the debug dump directory") + .long("clear-debug-dump") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("system") + .help("Path to a directory contains PS4 firmware to use") + .value_name("SYSTEM") + .value_parser(value_parser!(PathBuf)) + .required(true), + ) + .arg( + Arg::new("game") + .help("Path to an installed PS4 game to use") + .value_name("GAME") + .value_parser(value_parser!(PathBuf)) + .required(true), + ) + .get_matches(); + + // Process. + let system = args.get_one::("system").unwrap().clone(); + let game = args.get_one::("game").unwrap().clone(); + let debug_dump = args.get_one("debug_dump").cloned(); + let clear_debug_dump = args.get_flag("clear_debug_dump"); + let pro = args.get_flag("pro"); + let idps = args + .get_one::("idps") + .cloned() + .unwrap_or_default(); + + Self { + system, + game, + debug_dump, + clear_debug_dump, + pro, + idps, + } + } +} diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index 5b678e64..9a8ace63 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -1,9 +1,10 @@ use crate::arch::MachDep; +use crate::args::Args; use crate::budget::{Budget, BudgetManager, ProcType}; use crate::dev::{ - CameraInitError, CameraManager, DceManager, DebugManager, DebugManagerInitError, - DipswInitError, DipswManager, DmemContainer, GcInitError, GcManager, HmdManager, RngInitError, - RngManager, SblSrvManager, TtyManager, TtyManagerInitError, + CameraInitError, CameraManager, DceInitError, DceManager, DebugManager, DebugManagerInitError, + DipswInitError, DipswManager, DmemContainer, GcInitError, GcManager, HmdInitError, HmdManager, + RngInitError, RngManager, SblSrvInitError, SblSrvManager, TtyManager, TtyManagerInitError, }; use crate::dmem::{DmemManager, DmemManagerInitError}; use crate::ee::native::NativeEngine; @@ -11,7 +12,6 @@ use crate::ee::EntryArg; use crate::errno::EEXIST; use crate::fs::{Fs, FsInitError, MkdirError, MountError, MountFlags, MountOpts, VPath, VPathBuf}; use crate::hv::Hypervisor; -use crate::idps::ConsoleId; use crate::kqueue::KernelQueueManager; use crate::log::{print, LOGGER}; use crate::namedobj::NamedObjManager; @@ -28,12 +28,9 @@ use crate::sysctl::Sysctl; use crate::time::TimeManager; use crate::ucred::{AuthAttrs, AuthCaps, AuthInfo, AuthPaid, Gid, Ucred, Uid}; use crate::umtx::UmtxManager; -use clap::Parser; -use dev::{DceInitError, HmdInitError, SblSrvInitError}; use llt::{OsThread, SpawnError}; use macros::vpath; use param::Param; -use serde::Deserialize; use std::error::Error; use std::fs::{create_dir_all, remove_dir_all, File}; use std::io::Write; @@ -45,6 +42,7 @@ use sysinfo::{MemoryRefreshKind, System}; use thiserror::Error; mod arch; +mod args; mod arnd; mod budget; mod dev; @@ -87,7 +85,7 @@ fn main() -> ExitCode { } }; - match serde_yaml::from_reader(file) { + match Args::from_file(file) { Ok(v) => v, Err(e) => { eprintln!("Failed to parse {}: {}.", path.display(), e); @@ -95,7 +93,7 @@ fn main() -> ExitCode { } } } else { - Args::parse() + Args::from_command_line() }; // Run the kernel. @@ -581,32 +579,6 @@ fn join_thread(thr: OsThread) -> Result<(), std::io::Error> { Ok(()) } -#[derive(Parser, Deserialize)] -#[command(about)] -#[serde(rename_all = "kebab-case")] -struct Args { - #[arg(long)] - system: PathBuf, - - #[arg(long)] - game: PathBuf, - - #[arg(long)] - debug_dump: Option, - - #[arg(long)] - #[serde(default)] - clear_debug_dump: bool, - - #[arg(long)] - #[serde(default)] - pro: bool, - - #[arg(long)] - #[serde(default)] - idps: ConsoleId, -} - #[derive(Debug, Error)] enum DiscordPresenceError { #[error("failed to create Discord IPC")] diff --git a/src/main_window.cpp b/src/main_window.cpp index 7efd786a..2ce1d2f3 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -392,10 +392,10 @@ void MainWindow::startGame(const QModelIndex &index) // Setup kernel arguments. QStringList args; - args << "--system" << readSystemDirectorySetting(); - args << "--game" << game->directory(); args << "--debug-dump" << kernelDebugDump(); args << "--clear-debug-dump"; + args << readSystemDirectorySetting(); + args << game->directory(); // Setup environment variable. auto env = QProcessEnvironment::systemEnvironment();