/*---------------------------------------------------------------------------* Copyright (C) Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; namespace CafeX { partial class Program { #region environment variables internal static EnvVar CAFE_ROOT = new EnvVar("CAFE_ROOT"); internal static EnvVar SDIO_BRIDGE_TOOLS = new EnvVar("SDIO_BRIDGE_TOOLS"); internal static EnvVar MION_BRIDGE_TOOLS = new EnvVar("MION_BRIDGE_TOOLS"); internal static EnvVar BRIDGE_CURRENT_NAME = new EnvVar("BRIDGE_CURRENT_NAME"); internal static EnvVar BRIDGE_CURRENT_IP_ADDRESS = new EnvVar("BRIDGE_CURRENT_IP_ADDRESS"); internal static EnvVar PLATFORM = new EnvVar("PLATFORM"); internal static EnvVar CAFESTOP_STATUS = new EnvVar("CAFESTOP_STATUS"); internal static EnvVar CAFERUN_OPTION_SOFT_LAUNCH = new EnvVar("CAFERUN_OPTION_SOFT_LAUNCH"); internal static EnvVar CAFERUN_OPTION_FAST_RELAUNCH = new EnvVar("CAFERUN_OPTION_FAST_RELAUNCH"); internal static EnvVar HOSTSTOP_RVAL = new EnvVar("HOSTSTOP_RVAL"); internal static EnvVar HOSTSTOP_RETRIES = new EnvVar("HOSTSTOP_RETRIES"); internal static EnvVar HOSTSTOP_RESET_OPTION = new EnvVar("HOSTSTOP_RESET_OPTION"); internal static EnvVar CAFE_HARDWARE = new EnvVar("CAFE_HARDWARE"); internal static EnvVar MION_PWR_SEQ = new EnvVar("MION_PWR_SEQ"); internal static EnvVar BRIDGE_TYPE = new EnvVar("BRIDGE_TYPE"); internal static EnvVar TMP = new EnvVar("TMP"); internal static EnvVar SESSION_MANAGER = new EnvVar("SESSION_MANAGER"); internal static EnvVar SESSION_NAME = new EnvVar("SESSION_NAME"); internal static EnvVar SESSION_DEBUG_OUT_PORT = new EnvVar("SESSION_DEBUG_OUT_PORT"); internal static EnvVar SESSION_DEBUG_CONTROL_PORT = new EnvVar("SESSION_DEBUG_CONTROL_PORT"); internal static EnvVar SESSION_HIO_OUT_PORT = new EnvVar("SESSION_HIO_OUT_PORT"); internal static EnvVar SESSION_LAUNCH_CTRL_PORT = new EnvVar("SESSION_LAUNCH_CTRL_PORT"); internal static EnvVar SESSION_NET_MANAGE_PORT = new EnvVar("SESSION_NET_MANAGE_PORT"); internal static EnvVar SESSION_PCFS_SATA_PORT = new EnvVar("SESSION_PCFS_SATA_PORT"); internal static EnvVar SESSION_PATH_PREFIX = new EnvVar("SESSION_PATH_PREFIX"); internal static EnvVar CAFE_DATA_DIR = new EnvVar("CAFE_DATA_DIR"); internal static EnvVar CAFE_CONTENT_DIR = new EnvVar("CAFE_CONTENT_DIR"); internal static EnvVar CAFE_META_DIR = new EnvVar("CAFE_META_DIR"); internal static EnvVar CAFE_SAVE_DIR = new EnvVar("CAFE_SAVE_DIR"); internal static EnvVar CAFE_SLC_DIR = new EnvVar("CAFE_SLC_DIR"); internal static EnvVar CAFE_MLC_DIR = new EnvVar("CAFE_MLC_DIR"); internal static EnvVar CAFE_DATA_TMP = new EnvVar("CAFE_DATA_TMP"); internal static EnvVar LANG = new EnvVar("LANG"); internal static EnvVar QUIET = new EnvVar("QUIET"); internal static EnvVar NO_CONSOLE = new EnvVar("NO_CONSOLE"); internal static EnvVar CAFESTOP_ONLY_IF_FSEMUL = new EnvVar("CAFESTOP_ONLY_IF_FSEMUL"); internal static EnvVar PPC_OS_FLAGS = new EnvVar("PPC_OS_FLAGS"); internal static EnvVar PPC_APP_FLAGS = new EnvVar("PPC_APP_FLAGS"); internal static EnvVar PCFS_SYNC_DATE = new EnvVar("PCFS_SYNC_DATE"); internal static EnvVar MCP_LAUNCH_HINT = new EnvVar("MCP_LAUNCH_HINT"); internal static EnvVar MCP_INFO_OPTION = new EnvVar("MCP_INFO_OPTION"); internal static EnvVar IGNORE_VERSION = new EnvVar("IGNORE_VERSION"); internal static EnvVar DEBUGGER = new EnvVar("DEBUGGER"); internal static EnvVar CAFE_CONSOLE = new EnvVar("CAFE_CONSOLE"); internal static EnvVar CONSOLE = new EnvVar("CONSOLE"); internal static EnvVar CAFE_DEBUG_PORT = new EnvVar("CAFE_DEBUG_PORT"); internal static EnvVar DEBUG_ELF_FILE = new EnvVar("DEBUG_ELF_FILE"); internal static EnvVar CAFERUN_OPTION_SOFT_RESTART = new EnvVar("CAFERUN_OPTION_SOFT_RESTART"); internal static EnvVar CAFE_TEST_SELF_REFRESH = new EnvVar("CAFE_TEST_SELF_REFRESH"); internal static EnvVar CAFERUN_OPTION_MLC_EMU_LAUNCH = new EnvVar("CAFERUN_OPTION_MLC_EMU_LAUNCH"); internal static EnvVar CAFERUN_OPTION_MLC_EMU_TITLEID = new EnvVar("CAFERUN_OPTION_MLC_EMU_TITLEID"); internal static EnvVar CAFERUN_OS_MAJOR_VERSION_LO = new EnvVar("CAFERUN_OS_MAJOR_VERSION_LO"); internal static EnvVar CAFERUN_OS_MAJOR_VERSION = new EnvVar("CAFERUN_OS_MAJOR_VERSION"); internal static EnvVar CAFERUN_COLDBOOT_OS_VERSION = new EnvVar("CAFERUN_COLDBOOT_OS_VERSION"); internal static EnvVar HEARTBEAT_DISABLE = new EnvVar("HEARTBEAT_DISABLE"); internal static EnvVar PCFS_DIR_MAPPING = new EnvVar("PCFS_DIR_MAPPING"); internal static EnvVar MAPDIR_MLC = new EnvVar("MAPDIR_MLC"); internal static EnvVar MAPDIR_SLC = new EnvVar("MAPDIR_SLC"); internal static EnvVar MAPDIR_CODE = new EnvVar("MAPDIR_CODE"); internal static EnvVar MAPDIR_META = new EnvVar("MAPDIR_META"); internal static EnvVar MAPDIR_CONTENT = new EnvVar("MAPDIR_CONTENT"); internal static EnvVar MAPDIR_SAVE = new EnvVar("MAPDIR_SAVE"); internal static EnvVar PCFS_LOG_TIMESTAMP = new EnvVar("PCFS_LOG_TIMESTAMP"); internal static EnvVar PCFS_SRV_LOG_OUTPUT = new EnvVar("PCFS_SRV_LOG_OUTPUT"); internal static EnvVar RUN_FROM_HDD_BANK = new EnvVar("RUN_FROM_HDD_BANK"); internal static EnvVar EJECT_STATE = new EnvVar("EJECT_STATE"); internal static EnvVar BRIDGE_PARAMETERS = new EnvVar("BRIDGE_PARAMETERS"); internal static EnvVar BRIDGE_PARAMETERS_WITH_E = new EnvVar("BRIDGE_PARAMETERS_WITH_E"); internal static EnvVar PCFSSERVER_PARAMETERS = new EnvVar("PCFSSERVER_PARAMETERS"); internal static EnvVar PCFS_OVER_SATA_PORT = new EnvVar("PCFS_OVER_SATA_PORT"); internal static EnvVar PREPHDD_STAT = new EnvVar("PREPHDD_STAT"); internal static EnvVar DISC_EMU_TID = new EnvVar("DISC_EMU_TID"); internal static EnvVar SYSTEM_MODE = new EnvVar("SYSTEM_MODE"); internal static EnvVar RPL_DIRS = new EnvVar("RPL_DIRS"); internal static EnvVar RPL_FILES = new EnvVar("RPL_FILES"); internal static EnvVar CAFERUN_OPTION_NO_DATA_SYNC = new EnvVar("CAFERUN_OPTION_NO_DATA_SYNC"); internal static EnvVar CAFE_BOOT_MODE = new EnvVar("CAFE_BOOT_MODE"); internal static EnvVar CAFERUN_HOSTBRIDGE_VERSION = new EnvVar("CAFERUN_HOSTBRIDGE_VERSION"); internal static EnvVar CAFERUN_FW_VERSION = new EnvVar("CAFERUN_FW_VERSION"); internal static EnvVar CAFE_DEBUG_INIT = new EnvVar("CAFE_DEBUG_INIT"); internal static EnvVar CAFE_DEBUG_PREINIT = new EnvVar("CAFE_DEBUG_PREINIT"); internal static EnvVar CAFE_DEBUG_DONTSTOP = new EnvVar("CAFE_DEBUG_DONTSTOP"); internal static EnvVar CAFE_LAUNCH_DEBUG = new EnvVar("CAFE_LAUNCH_DEBUG"); internal static EnvVar CAFE_SYSLOG_LEVEL = new EnvVar("CAFE_SYSLOG_LEVEL"); internal static EnvVar CAFE_RUN_FORCERESTART = new EnvVar("CAFE_RUN_FORCERESTART"); internal static EnvVar DEBUG_PROC_ID = new EnvVar("DEBUG_PROC_ID"); internal static EnvVar DEBUG_FLAGS = new EnvVar("DEBUG_FLAGS"); internal static EnvVar CATOUTPUT = new EnvVar("CATOUTPUT"); internal static EnvVar CMDOUTPUT = new EnvVar("CMDOUTPUT"); internal static EnvVar CAFE_AUTOTEST = new EnvVar("CAFE_AUTOTEST"); internal static EnvVar YOSHIS_COOKIE = new EnvVar("YOSHIS_COOKIE"); internal static EnvVar CAFERUN_APP_TYPE = new EnvVar("CAFERUN_APP_TYPE"); internal static EnvVar DASH_A_ARGS = new EnvVar("DASH_A_ARGS"); internal static EnvVar ARGS_WITH_BARS = new EnvVar("ARGS_WITH_BARS"); internal static EnvVar DISC_EMU_TYPE = new EnvVar("DISC_EMU_TYPE"); internal static EnvVar APP_XML_FILE = new EnvVar("APP_XML_FILE"); internal static EnvVar USE_PCFS_OVER_SATA = new EnvVar("USE_PCFS_OVER_SATA"); internal static EnvVar CAFERUN_OPTION_CALLED_FROM_CAFEDISCRUN = new EnvVar("CAFERUN_OPTION_CALLED_FROM_CAFEDISCRUN"); internal static EnvVar SYSTEM_XML = new EnvVar("SYSTEM_XML"); //internal static EnvVar TEMP = new EnvVar("TEMP"); internal static EnvVar CAFE_TEMP = new EnvVar("CAFE_TEMP"); internal static EnvVar CAFERUN_WORK_DIR = new EnvVar("CAFERUN_WORK_DIR"); internal static EnvVar SYNCTOOL_SRC = new EnvVar("SYNCTOOL_SRC"); internal static EnvVar SYNCTOOL_DEST = new EnvVar("SYNCTOOL_DEST"); internal static EnvVar SYNCTOOL_CFG = new EnvVar("SYNCTOOL_CFG"); internal static EnvVar SYNCTOOL_LOG = new EnvVar("SYNCTOOL_LOG"); internal static EnvVar CAFE_ELF = new EnvVar("CAFE_ELF"); internal static EnvVar CAFE_ELF_SRC_DIR = new EnvVar("CAFE_ELF_SRC_DIR"); internal static EnvVar CAFE_ELF_DIR = new EnvVar("CAFE_ELF_DIR"); internal static EnvVar CAFE_CODE_DIR = new EnvVar("CAFE_CODE_DIR"); internal static EnvVar COS_XML_FILE = new EnvVar("COS_XML_FILE"); internal static EnvVar META_XML_FILE = new EnvVar("META_XML_FILE"); internal static EnvVar PREV_CAFE_ARGSTR = new EnvVar("PREV_CAFE_ARGSTR"); internal static EnvVar CAFERUN_OS_VERSION_PARTIAL_UNIQUE_ID = new EnvVar("CAFERUN_OS_VERSION_PARTIAL_UNIQUE_ID"); internal static EnvVar PCFS_SRV_LOG_DIR = new EnvVar("PCFS_SRV_LOG_DIR"); internal static EnvVar CMD_RESULT = new EnvVar("CMD_RESULT"); internal static EnvVar CAFERUN_COLDBOOT_OS_VERSION_HI = new EnvVar("CAFERUN_COLDBOOT_OS_VERSION_HI"); internal static EnvVar CAFERUN_COLDBOOT_OS_VERSION_LO = new EnvVar("CAFERUN_COLDBOOT_OS_VERSION_LO"); internal static EnvVar BOOTRUN_WORK_DIR = new EnvVar("BOOTRUN_WORK_DIR"); internal static EnvVar BOOTRUN_USE_RECOVERY_IMAGE = new EnvVar("BOOTRUN_USE_RECOVERY_IMAGE"); internal static EnvVar WUMAD_WORK_DIR = new EnvVar("WUMAD_WORK_DIR"); internal static EnvVar FIRMWARE_FILE = new EnvVar("FIRMWARE_FILE"); internal static EnvVar TOOLCHAIN = new EnvVar("TOOLCHAIN"); internal static EnvVar CAFE_SECURITY = new EnvVar("CAFE_SECURITY"); internal static EnvVar BOOT_DLF_FILE = new EnvVar("BOOT_DLF_FILE"); internal static EnvVar CAFE_WUMAD = new EnvVar("CAFE_WUMAD"); internal static EnvVar CAFEMAKEDLF = new EnvVar("CAFEMAKEDLF"); internal static EnvVar APP_TITLE_ID = new EnvVar("APP_TITLE_ID"); internal static EnvVar APP_GROUP_ID = new EnvVar("APP_GROUP_ID"); internal static EnvVar APP_TITLE_VERSION = new EnvVar("APP_TITLE_VERSION"); internal static EnvVar CAFEDEVRUN_FILE = new EnvVar("CAFEDEVRUN_FILE"); internal static EnvVar CAFEDEVRUN_EXT = new EnvVar("CAFEDEVRUN_EXT"); internal static EnvVar CAFEDEVRUN_NAME = new EnvVar("CAFEDEVRUN_NAME"); internal static EnvVar CAFEDEVRUN_FILENAME = new EnvVar("CAFEDEVRUN_FILENAME"); internal static EnvVar CAFEDEVRUN_DIR = new EnvVar("CAFEDEVRUN_DIR"); internal static EnvVar CAFEDEVRUN_WORK_DIR = new EnvVar("CAFEDEVRUN_WORK_DIR"); internal static EnvVar INCLUDE_SYSTEM_DIR = new EnvVar("INCLUDE_SYSTEM_DIR"); internal static EnvVar CAFE_BASEFILE_PATH = new EnvVar("CAFE_BASEFILE_PATH"); internal static EnvVar DEFAULT_DDF = new EnvVar("DEFAULT_DDF"); internal static EnvVar COMMON_DDF_FILE = new EnvVar("COMMON_DDF_FILE"); internal static EnvVar INDIVIDUAL_DDF_FILE = new EnvVar("INDIVIDUAL_DDF_FILE"); internal static EnvVar FSEMUL_PARAMS = new EnvVar("FSEMUL_PARAMS"); internal static EnvVar BRIDGE_INSTALL_PATH = new EnvVar("BRIDGE_INSTALL_PATH"); internal static EnvVar CAFE_DETACH_FSEMUL = new EnvVar("CAFE_DETACH_FSEMUL"); internal static EnvVar MULTIELF = new EnvVar("MULTIELF"); internal static EnvVar CATTOUCAN_STATUS = new EnvVar("CATTOUCAN_STATUS"); internal static EnvVar MULTI_CONNECT = new EnvVar("MULTI_CONNECT"); internal static EnvVar CAFE_MULTI_INIT = new EnvVar("CAFE_MULTI_INIT"); internal static EnvVar GHS_ROOT = new EnvVar("GHS_ROOT"); internal static EnvVar CAFEON_DISABLE_BGD = new EnvVar("CAFEON_DISABLE_BGD"); internal static EnvVar CAFEON_NOBGD_META = new EnvVar("CAFEON_NOBGD_META"); internal static EnvVar CAFEON_OPTION_NO_DATA_SYNC = new EnvVar("CAFEON_OPTION_NO_DATA_SYNC"); internal static EnvVar AUTOTEST_RUNNING = new EnvVar("AUTOTEST_RUNNING"); internal static EnvVar CAFE_RUN_RUNNING = new EnvVar("CAFE_RUN_RUNNING"); internal static EnvVar CAFERUN_INS = new EnvVar("CAFERUN_INS"); internal static EnvVar CATTOUCAN_TERM = new EnvVar("CATTOUCAN_TERM"); internal static EnvVar OS_VERSION_LO = new EnvVar("OS_VERSION_LO"); internal static EnvVar SDK_VER = new EnvVar("SDK_VER"); internal static EnvVar SDK_MAJ_VER = new EnvVar("SDK_MAJ_VER"); internal static EnvVar SDK_MIN_VER = new EnvVar("SDK_MIN_VER"); internal static EnvVar SDK_MIC_VER = new EnvVar("SDK_MIC_VER"); internal static EnvVar CAFEUPDATE_USE_SYSTEM_UPDATER = new EnvVar("CAFEUPDATE_USE_SYSTEM_UPDATER"); internal static EnvVar CAFEUPDATE_TITLE = new EnvVar("CAFEUPDATE_TITLE"); internal static EnvVar CAFEUPDATE_PACKAGE = new EnvVar("CAFEUPDATE_PACKAGE"); internal static EnvVar CAFEUPDATE_PACKAGE_DEFAULT = new EnvVar("CAFEUPDATE_PACKAGE_DEFAULT"); internal static EnvVar SCRIPT_EXE_TIMESTAMP = new EnvVar("SCRIPT_EXE_TIMESTAMP"); internal static EnvVar LOGDIR = new EnvVar("LOGDIR"); internal static EnvVar _CCRSYSCFG1 = new EnvVar("_CCRSYSCFG1"); internal static EnvVar MONITOR_DEFAULT_TIMEOUT = new EnvVar("MONITOR_DEFAULT_TIMEOUT"); internal static EnvVar COMPORTS_SUPPORT = new EnvVar("COMPORTS_SUPPORT"); internal static EnvVar INITIALIZED_COMPORTS = new EnvVar("INITIALIZED_COMPORTS"); internal static EnvVar MONITOR_FOR_OUTPUT_CALLS = new EnvVar("MONITOR_FOR_OUTPUT_CALLS"); internal static EnvVar MON_RESULT_PASS = new EnvVar("MON_RESULT_PASS"); internal static EnvVar MON_RESULT_TIMEOUT = new EnvVar("MON_RESULT_TIMEOUT"); internal static EnvVar MON_RESULT_UNDEF = new EnvVar("MON_RESULT_UNDEF"); internal static EnvVar MON_RESULT_MANUAL = new EnvVar("MON_RESULT_MANUAL"); internal static EnvVar MON_RESULT_NOLOG = new EnvVar("MON_RESULT_NOLOG"); internal static EnvVar MON_RESULT_FAIL = new EnvVar("MON_RESULT_FAIL"); internal static EnvVar MON_RESULT_EXPECTED_TERM = new EnvVar("MON_RESULT_EXPECTED_TERM"); internal static EnvVar MON_RESULT_EXEC_WIN_APP = new EnvVar("MON_RESULT_EXEC_WIN_APP"); internal static EnvVar MON_RESULT_NOPPC = new EnvVar("MON_RESULT_NOPPC"); internal static EnvVar MON_RESULT_BOOT1 = new EnvVar("MON_RESULT_BOOT1"); internal static EnvVar MON_RESULT_RESTART = new EnvVar("MON_RESULT_RESTART"); internal static EnvVar MON_RESULT_TEST_AS_RPL = new EnvVar("MON_RESULT_TEST_AS_RPL"); internal static EnvVar MON_RESULT_END_OF_RPL_LOADER = new EnvVar("MON_RESULT_END_OF_RPL_LOADER"); internal static EnvVar MON_RESULT_BRIDGE_COLLISION = new EnvVar("MON_RESULT_BRIDGE_COLLISION"); internal static EnvVar MON_RESULT_TEST_DBG_OUT = new EnvVar("MON_RESULT_TEST_DBG_OUT"); internal static EnvVar MON_RESULT_BRIDGE_OFF = new EnvVar("MON_RESULT_BRIDGE_OFF"); internal static EnvVar MON_RESULT_ERROR = new EnvVar("MON_RESULT_ERROR"); internal static EnvVar MON_RESULT_SKIP = new EnvVar("MON_RESULT_SKIP"); internal static EnvVar MON_RESULT_FATAL_ERROR = new EnvVar("MON_RESULT_FATA_ERROR"); internal static EnvVar MON_RESULT_MISSING = new EnvVar("MON_RESULT_MISSING"); internal static EnvVar MON_RESULT_ABORTED = new EnvVar("MON_RESULT_ABORTED"); internal static EnvVar MON_RESULT_KILL_AUTOTEST = new EnvVar("MON_RESULT_KILL_AUTOTEST"); internal static EnvVar SYNCTOOL_RVAL = new EnvVar("SYNCTOOL_RVAL"); internal static EnvVar PATH = new EnvVar("PATH"); internal static EnvVar PCFS_HEADLESS_EMUL = new EnvVar("PCFS_HEADLESS_EMUL"); internal static EnvVar TMP_SUB_DIR = new EnvVar("TMP_SUB_DIR"); internal static EnvVar PCFSSERVERSYNC_RVAL = new EnvVar("PCFSSERVERSYNC_RVAL"); internal static EnvVar CAFE_RUN_DEBUG = new EnvVar("CAFE_RUN_DEBUG"); internal static EnvVar CYGWIN_PATH = new EnvVar("CYGWIN_PATH"); internal static EnvVar CAFEX_STDIN_ENCODING = new EnvVar("CAFEX_STDIN_ENCODING"); internal static EnvVar CAFEX_STDOUT_ENCODING = new EnvVar("CAFEX_STDOUT_ENCODING"); internal static EnvVar CAFE_OUTPUT_ENCODING = new EnvVar("CAFE_OUTPUT_ENCODING"); // CafeX Install internal static EnvVar CAFEINSTALL_USE_SYMLINK = new EnvVar("CAFEINSTALL_USE_SYMLINK"); //disrun in NAND mode internal static EnvVar ALLOW_DISCRUN_IN_SOFTLAUNCH = new EnvVar("ALLOW_DISCRUN_IN_SOFTLAUNCH"); internal static EnvVar BOOTRUN_ELF_OPT = new EnvVar("BOOTRUN_ELF_OPT"); internal static EnvVar BOOTRUN_ELF_VALUE = new EnvVar("BOOTRUN_ELF_VALUE"); internal static EnvVar ELF_NEST_OPT = new EnvVar("ELF_NEST_OPT"); internal static EnvVar ELF_NEST_VALUE = new EnvVar("ELF_NEST_VALUE"); internal static EnvVar SOFT_LAUNCH_CAFE_ELF = new EnvVar("SOFT_LAUNCH_CAFE_ELF"); internal static EnvVar CAFERUN_WUMAD_TITLE_ID = new EnvVar("CAFERUN_WUMAD_TITLE_ID"); // Discrun OS mismatch checking internal static EnvVar SKIP_OS_CHECK = new EnvVar("SKIP_OS_CHECK"); // EXI debug internal static EnvVar USE_EXI_AS_DEBUG_CHANNEL = new EnvVar("USE_EXI_AS_DEBUG_CHANNEL"); // Fast launch internal static EnvVar CAFERUN_OPTION_FASTLAUNCH_RETRIES = new EnvVar("CAFERUN_OPTION_FASTLAUNCH_RETRIES"); internal static EnvVar CAFERUN_OPTION_FASTLAUNCH_TIMEOUT = new EnvVar("CAFERUN_OPTION_FASTLAUNCH_TIMEOUT"); internal static EnvVar CAFERUN_OPTION_FASTLAUNCH_DELAY = new EnvVar("CAFERUN_OPTION_FASTLAUNCH_DELAY"); // KILL RESTART internal static EnvVar CAFERUN_DISABLE_KILL_RESTART = new EnvVar("CAFERUN_DISABLE_KILL_RESTART"); internal static EnvVar CAFERUN_OPTION_KILL_RESTART = new EnvVar("CAFERUN_OPTION_KILL_RESTART"); internal static int g_gArgValue = 0; internal static bool g_KOptionSet = false; //Cafe profiler internal static EnvVar CAFE_PROFILE = new EnvVar("CAFE_PROFILE"); internal static EnvVar USE_SINGLE_CGI = new EnvVar("USE_SINGLE_CGI"); // Mion version checking internal static string MIN_MION_FW_VER = "0.0.14.74"; internal static string MIN_MION_SW_VER = "3.2.6.1"; //For launch command internal static string LAUNCH_DLF_FILE = string.Empty; internal static bool execLaunchCmd = false; //For ECO mode debugging internal static EnvVar ECO_MODE = new EnvVar("ECO_MODE"); //For update/recover testing internal static EnvVar CAFEX_RECOVER_TEST = new EnvVar("CAFEX_RECOVER_TEST"); internal static UInt64 recover_flags = 0x230; //For default caferun / cafediscrun options internal static EnvVar CAFERUN_DEFAULT_OPTIONS = new EnvVar("CAFERUN_DEFAULT_OPTIONS"); //For MIONPS arguments internal const int MIONPS_BOOT_BYTE = 2; internal const int MIONPS_SDK_MAJ_BYTE = 3; internal const int MIONPS_SDK_MIN_BYTE = 4; internal const int MIONPS_SDK_MIC_BYTE = 5; internal const int MIONPS_BOOT_NAND = 1; internal const int MIONPS_BOOT_PCFS = 2; internal const int MIONPS_IMGUPLOAD_BASE_BYTE = 100; #endregion #region GLOBAL INTIALIZATION internal static bool IsBooting = false; internal static bool EjectStateOverride = false; internal const int CAFERUN_RETRY_COUNT = 5; internal const int CAFERUN_LAST_RETRY = (CAFERUN_RETRY_COUNT - 1); internal static char DEFAULT_DELIMITER = '\t'; internal static string SYSCONFIGTOOL_TITLE_ID = "000500101f700500"; internal static bool fAppTypeDefined = false; const int CAFE_ARGSTR_MAX_LENGTH = 4096; const string IOS_CRASHDUMP_TOKEN = "IOS_CRASH_START_PROCESS:"; const string ENV_DISC_EJECT_STATE = "DISC_EJECT_STATE"; const string MIN_EJECT_FW_VER = "0.0.14.78"; const string MIN_EJECT_SW_VER = "3.2.6.5"; internal static CAFEX_ERROR InitialEnvVarSetup() { #if DEBUG Log.WriteLine("InitialEnvVarSetup started."); #endif #region encoding setup //check to see if we are in a cygwin window. // if (CAFE_ROOT.value.Contains("cygdrive") || !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("CYGWIN"))) // CALLED_FROM_CYGWIN = true; //determine the encoding that Cafe is outputting if (!String.IsNullOrEmpty(LANG.value)) { //cygwin uses the format (language)_(territory).(charset)[@modifier] //and we're only interested in the charset int langLoc = LANG.value.IndexOf(".", 0); string lang = null; if (langLoc > -1) { //handle case where LANG may have @ in it (legal in cygwin) int atSignLoc = LANG.value.IndexOf("@", 0); if (langLoc > atSignLoc) lang = LANG.value.Substring(langLoc + 1); else lang = LANG.value.Substring(langLoc + 1, atSignLoc - langLoc); switch (lang) { case "UTF-8": case "utf8": lang = "utf-8"; break; case "SJIS": case "CP932": lang = "shift_jis"; break; case "ASCII": lang = "us-ascii"; break; case "CP1252": lang = "windows-1252"; break; case "CP437": lang = "IBM437"; break; case "CP720": lang = "DOS-270"; break; case "CP737": lang = "ibm737"; break; case "CP775": lang = "ibm775"; break; case "CP850": lang = "ibm850"; break; case "CP852": lang = "ibm852"; break; case "CP855": lang = "IBM855"; break; case "CP857": lang = "ibm857"; break; case "CP858": lang = "IBM00858"; break; case "CP860": lang = "IBM860"; break; case "CP861": lang = "ibm861"; break; case "CP862": lang = "DOS-862"; break; case "CP863": lang = "IBM863"; break; case "CP864": lang = "IBM864"; break; case "CP865": lang = "IBM865"; break; case "CP866": lang = "cp866"; break; case "CP869": lang = "ibm869"; break; case "CP870": lang = "IBM870"; break; case "CP874": case "TIS-620": case "TIS620": lang = "windows-874"; break; case "CP1250": lang = "windows-1250"; break; case "CP1251": lang = "windows-1251"; break; case "CP1253": lang = "windows-1253"; break; case "CP1254": lang = "windows-1254"; break; case "CP1255": lang = "windows-1255"; break; case "CP1256": lang = "windows-1256"; break; case "CP1257": lang = "windows-1257"; break; case "CP1258": lang = "windows-1258"; break; case "ISO-8859-1": lang = "iso-8859-1"; break; case "ISO-8859-2": lang = "iso-8859-2"; break; case "ISO-8859-3": lang = "iso-8859-3"; break; case "ISO-8859-4": lang = "iso-8859-4"; break; case "ISO-8859-5": lang = "iso-8859-5"; break; case "ISO-8859-6": lang = "iso-8859-6"; break; case "ISO-8859-7": lang = "iso-8859-7"; break; case "ISO-8859-8": lang = "iso-8859-8"; break; case "ISO-8859-9": lang = "iso-8859-9"; break; case "ISO-8859-10": lang = "iso-8859-10"; break; case "ISO-8859-11": lang = "iso-8859-11"; break; case "ISO-8859-13": lang = "iso-8859-13"; break; case "ISO-8859-14": lang = "iso-8859-14"; break; case "ISO-8859-15": lang = "iso-8859-15"; break; case "ISO-8859-16": lang = "iso-8859-16"; break; case "Big5": lang = "big5"; break; case "EUCCN": case "euc-CN": case "GB2312": case "GBK": lang = "gb2312"; break; case "EUCJP": case "euc-JP": lang = "EUC-JP"; break; case "EUCKR": case "euc-KR": lang = "ks_c_5601-1987"; break; case "KOI8-R": lang = "koi8-r"; break; case "KOI8-U": lang = "koi8-u"; break; default: Console.WriteLine("cafex: Unknown LANG specified; using UTF-8 encoding for incoming Cafe messages"); lang = null; break; } } else { Console.WriteLine("cafex: Invalid LANG specified; using UTF-8 encoding for incoming Cafe messages"); } CAFE_OUTPUT_ENCODING.value = lang; } #endregion // THESE NEED TO BE SET IN CAFEX_ENV.BAT, BUT FOR NOW ARE HERE CAFE_ROOT.value = PathConverter.Windowsify(CAFE_ROOT.value); if (string.IsNullOrEmpty(CAFE_TEMP.value)) { CAFE_TEMP.value = Path.Combine (CAFE_ROOT.value, "temp"); } CAFE_TEMP.value = PathConverter.Windowsify(CAFE_TEMP.value); GHS_ROOT.value = PathConverter.Windowsify(GHS_ROOT.value); if (string.IsNullOrEmpty(CAFE_HARDWARE.value)) { CAFE_HARDWARE.value = "catdevmp"; } else if (!CAFE_HARDWARE.value.Equals("catdevmp")) { Console.WriteLine("User has already defined CAFE_HARDWARE to '{0}'!", CAFE_HARDWARE.value); Console.WriteLine("Please be aware that anything but 'catdevmp' is not guaranteed to work."); } //CAFE_BOOT_MODE.value = "PCFS"; //CAFE_CONTENT_DIR.value = CAFE_ROOT.value + "\\data\\disc\\content"; //CAFE_SAVE_DIR.value = CAFE_ROOT.value + "\\data\\save"; //CAFE_SLC_DIR.value = CAFE_ROOT.value + "\\data\\slc"; //CAFE_MLC_DIR.value = CAFE_ROOT.value + "\\data\\mlc"; //CAFE_META_DIR.value = CAFE_ROOT.value + "\\data\\disc\\meta"; CAFE_CONTENT_DIR.value = PathConverter.Windowsify(CAFE_CONTENT_DIR.value); CAFE_SAVE_DIR.value = PathConverter.Windowsify(CAFE_SAVE_DIR.value); CAFE_SLC_DIR.value = PathConverter.Windowsify(CAFE_SLC_DIR.value); CAFE_MLC_DIR.value = PathConverter.Windowsify(CAFE_MLC_DIR.value); CAFE_META_DIR.value = PathConverter.Windowsify(CAFE_META_DIR.value); TOOLCHAIN.value = "ghs"; MONITOR_DEFAULT_TIMEOUT.value = "60"; // don't override this setting from environment //CAFE_CONSOLE.value = "cattoucan"; if (string.IsNullOrEmpty(CAFE_CONSOLE.value)) { CAFE_CONSOLE.value = "cattoucan"; } // need to remove this or it will always do pcfs over sata //USE_PCFS_OVER_SATA.value = "1"; if (string.IsNullOrEmpty(CAFE_TEST_SELF_REFRESH.value)) { CAFE_TEST_SELF_REFRESH.value = "0"; } MON_RESULT_UNDEF.value = "-1"; MON_RESULT_TIMEOUT.value = "0"; MON_RESULT_PASS.value = "1"; MON_RESULT_MANUAL.value = "2"; MON_RESULT_NOLOG.value = "3"; MON_RESULT_FAIL.value = "4"; MON_RESULT_EXPECTED_TERM.value = "5"; MON_RESULT_EXEC_WIN_APP.value = "6"; MON_RESULT_NOPPC.value = "7"; MON_RESULT_BOOT1.value = "8"; MON_RESULT_RESTART.value = "9"; MON_RESULT_TEST_AS_RPL.value = "10"; MON_RESULT_END_OF_RPL_LOADER.value = "11"; MON_RESULT_BRIDGE_COLLISION.value = "12"; MON_RESULT_TEST_DBG_OUT.value = "13"; MON_RESULT_BRIDGE_OFF.value = "14"; MON_RESULT_KILL_AUTOTEST.value = "15"; MON_RESULT_ERROR.value = "128"; MON_RESULT_SKIP.value = "129"; MON_RESULT_FATAL_ERROR.value = "255"; MON_RESULT_MISSING.value = "131"; MON_RESULT_ABORTED.value = "132"; ALLOW_DISCRUN_IN_SOFTLAUNCH.value = "0"; SKIP_OS_CHECK.value = "0"; PATH.AddToVar("C:\\cygwin\\bin\\;", ';'); CAFEX_ERROR ret = readSDKFromCafeRoot(null); if (ret != CAFEX_ERROR.OK) { return ret; } #region session setup if (SESSION_MANAGER.value == "1") { if (!File.Exists(MION_BRIDGE_TOOLS.value + "\\SessionManager.dll")) { Console.WriteLine("ERROR: SessionManager.dll not found and multi-CATDEV is enabled!"); Console.WriteLine(" Please install HostBridge version 3.2.2.3+ or disable multi-CATDEV feature."); return CAFEX_ERROR.NO_SESSIONMANAGER_DLL; } string output = string.Empty; SessionManagerUtil.GetSessionInfo(out output); string[] output_array = output.Split(' '); SESSION_NAME.value = output_array[0]; SESSION_DEBUG_OUT_PORT.value = output_array[1]; SESSION_DEBUG_CONTROL_PORT.value = output_array[2]; SESSION_HIO_OUT_PORT.value = output_array[3]; SESSION_LAUNCH_CTRL_PORT.value = output_array[4]; SESSION_NET_MANAGE_PORT.value = output_array[5]; SESSION_PCFS_SATA_PORT.value = output_array[6]; SESSION_PATH_PREFIX.value = SESSION_NAME.value + "_"; CAFE_DATA_DIR.value = CAFE_ROOT.value + "\\" + SESSION_PATH_PREFIX.value + "data"; // If the content or meta location has been changed from the default, we should not touch and use it. // Otherwise, should modify by appending the CAFE_DATA_DIR. string defaultContentDir = Path.Combine(CAFE_ROOT.value, "data\\disc\\content"); string defaultMetaDir = Path.Combine(CAFE_ROOT.value, "data\\disc\\meta"); string defaultSaveDir = Path.Combine(CAFE_DATA_DIR.value, "save"); string defaultSlcDir = Path.Combine(CAFE_DATA_DIR.value, "slc"); string defaultMlcDir = Path.Combine(CAFE_DATA_DIR.value, "mlc"); // typical directories for users to change to something custom if (string.Equals(CAFE_CONTENT_DIR.value, defaultContentDir)) { CAFE_CONTENT_DIR.value = Path.Combine(CAFE_DATA_DIR.value, "disc\\content"); } if (string.Equals(CAFE_META_DIR.value, defaultMetaDir)) { CAFE_META_DIR.value = Path.Combine(CAFE_DATA_DIR.value, "disc\\meta"); } if (string.Equals(CAFE_SAVE_DIR.value, defaultSaveDir)) { CAFE_SAVE_DIR.value = Path.Combine(CAFE_DATA_DIR.value, "save"); } // No idea why users would ever change these next two paths, but we need to support it if (string.Equals(CAFE_SLC_DIR.value, defaultSlcDir)) { CAFE_SLC_DIR.value = Path.Combine(CAFE_DATA_DIR.value, "slc"); } else { Console.WriteLine("WARNING: CAFE_SLC_DIR is set to a non-default path! Cafe may encounter errors!"); Console.WriteLine("default:{0}", defaultSlcDir); Console.WriteLine(" actual:{0}", CAFE_SLC_DIR.value); } if (string.Equals(CAFE_MLC_DIR.value, defaultMlcDir)) { CAFE_MLC_DIR.value = Path.Combine(CAFE_DATA_DIR.value, "mlc"); } else { Console.WriteLine("WARNING: CAFE_MLC_DIR is set to a non-default path! Cafe may encounter errors!"); Console.WriteLine("default:{0}", defaultMlcDir); Console.WriteLine(" actual:{0}", CAFE_MLC_DIR.value); } CAFE_DATA_TMP.value = CAFE_DATA_DIR.value + "\\tmp"; } else { SESSION_NAME.value = ""; SESSION_DEBUG_OUT_PORT.value = "6001"; SESSION_DEBUG_CONTROL_PORT.value = "6002"; SESSION_HIO_OUT_PORT.value = "6003"; SESSION_LAUNCH_CTRL_PORT.value = "6006"; SESSION_NET_MANAGE_PORT.value = "6008"; SESSION_PCFS_SATA_PORT.value = "7500"; SESSION_PATH_PREFIX.value = ""; CAFE_DATA_DIR.value = CAFE_ROOT.value + "\\data"; } #if DEBUG Log.WriteLine("SESSION_NAME = " + SESSION_NAME.value); Log.WriteLine("SESSION_DEBUG_OUT_PORT = " + SESSION_DEBUG_OUT_PORT.value); Log.WriteLine("SESSION_DEBUG_CONTROL_PORT = " + SESSION_DEBUG_CONTROL_PORT.value); Log.WriteLine("SESSION_HIO_OUT_PORT = " + SESSION_HIO_OUT_PORT.value); Log.WriteLine("SESSION_LAUNCH_CTRL_PORT = " + SESSION_LAUNCH_CTRL_PORT.value); Log.WriteLine("SESSION_NET_MANAGE_PORT = " + SESSION_NET_MANAGE_PORT.value); Log.WriteLine("SESSION_PCFS_SATA_PORT = " + SESSION_PCFS_SATA_PORT.value); Log.WriteLine("SESSION_PATH_PREFIX = " + SESSION_PATH_PREFIX.value); Log.WriteLine("CAFE_DATA_DIR = " + CAFE_DATA_DIR.value); Log.WriteLine("CAFE_CONTENT_DIR = " + CAFE_CONTENT_DIR.value); Log.WriteLine("CAFEON_OPTION_NO_DATA_SYNC = " + CAFEON_OPTION_NO_DATA_SYNC.value); Log.WriteLine("CAFERUN_OPTION_NO_DATA_SYNC= " + CAFERUN_OPTION_NO_DATA_SYNC.value); #endif #endregion return CAFEX_ERROR.OK; } #endregion internal static Int64 MCP_MAKE_APP_TYPE(Int64 flags, Int64 id) { return ((flags) | ((id) & ((1<<24) - 1))); } #region SCRIPT FUNCTIONS // Helper function: FindAppType() static string FindAppType( Int64 iTitleID ) { string app_type; // Determine the correct app_type based on the title_id if ((iTitleID == 0x0005001010001000) || (iTitleID == 0x0005001010001100) || (iTitleID == 0x0005001010001200) || (iTitleID == 0x0005001010001300) || (iTitleID == 0x0005001010001400) || (iTitleID == 0x0005001010001500) || (iTitleID == 0x0005001010001600) || (iTitleID == 0x0005001010001700) || (iTitleID == 0x0005001010001800) || (iTitleID == 0x0005001010001900) || (iTitleID == 0x0005001010001A00) || (iTitleID == 0x0005001010001B00) || (iTitleID == 0x0005001010001C00) || (iTitleID == 0x0005001010047000) || (iTitleID == 0x0005001010047100) || (iTitleID == 0x0005001010047200)) // MCP_APP_TYPE_SYSTEM { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28)), 32), 16); } else if ((iTitleID == 0x0005001010004005) || (iTitleID == 0x0005001010004006) || (iTitleID == 0x0005001010004007) || (iTitleID == 0x0005001010004008) || (iTitleID == 0x00050010100040FF) || (iTitleID == 0x0005001010008005) || (iTitleID == 0x0005001010008006) || (iTitleID == 0x0005001010008007) || (iTitleID == 0x0005001010008008) || (iTitleID == 0x000500101000C005) || (iTitleID == 0x000500101000C006) || (iTitleID == 0x000500101000C007) || (iTitleID == 0x000500101000C008) || (iTitleID == 0x000500101000C009)) // MCP_APP_TYPE_OS { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 10), 16); } else if ((iTitleID == 0x0005001010000100)) // MCP_APP_TYPE_BOOT1 { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 9), 16); } else if ((iTitleID == 0x0005001010000200) || (iTitleID == 0x0005001010000300)) // MCP_APP_TYPE_DRH { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 20), 16); } else if ((iTitleID == 0x0005001010000400)) // MCP_APP_TYPE_BT { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 18), 16); } else if ((iTitleID == 0x0005001010004000)) // MCP_APP_TYPE_COMPAT_SYSTEM { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 17), 16); } else if ((iTitleID == 0x0005003010010000) || (iTitleID == 0x0005003010010100) || (iTitleID == 0x0005003010010200) || (iTitleID == 0x0005003010020000) || (iTitleID == 0x0005003010020100) || (iTitleID == 0x0005003010020200)) // MCP_APP_TYPE_HOMEBUTTON { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28) | (1 << 30)), 4), 16); } else if ((iTitleID == 0x0005003010011000) || (iTitleID == 0x0005003010011100) || (iTitleID == 0x0005003010011200) || (iTitleID == 0x0005003010021000) || (iTitleID == 0x0005003010021100) || (iTitleID == 0x0005003010021200)) // MCP_APP_TYPE_ERRORDISPLAY { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28) | (1 << 30)), 5), 16); } else if ((iTitleID == 0x0005003010019000) || (iTitleID == 0x0005003010019100) || (iTitleID == 0x0005003010019200) || (iTitleID == 0x0005003010029000) || (iTitleID == 0x0005003010029100) || (iTitleID == 0x0005003010029200)) // MCP_APP_TYPE_MINIMIIVERSE { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28) | (1 << 30)), 13), 16); } else if ((iTitleID == 0x0005001010040000) || (iTitleID == 0x0005001010040100) || (iTitleID == 0x0005001010040200) || (iTitleID == 0x000500101f700500)) // MCP_APP_TYPE_CAFEMENU { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28)), 1), 16); } else if ((iTitleID == 0x0005001010041000) || (iTitleID == 0x0005001010041100) || (iTitleID == 0x0005001010041200)) // MCP_APP_TYPE_SYSTEM_VERSION { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 21), 16); } else if ((iTitleID == 0x0005001010043000) || (iTitleID == 0x0005001010043100) || (iTitleID == 0x0005001010043200)) // MCP_APP_TYPE_DRC { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 19), 16); } else if ((iTitleID == 0x0005001010044000) || (iTitleID == 0x0005001010044100) || (iTitleID == 0x0005001010044200)) // MCP_APP_TYPE_DRC_LANG { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 28), 26), 16); } else if ((iTitleID == 0x0005001010045000) || (iTitleID == 0x0005001010045100) || (iTitleID == 0x0005001010045200)) // MCP_APP_TYPE_UPDATER { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28)), 11), 16); } else if ((iTitleID == 0x0005001010046000) || (iTitleID == 0x0005001010046100) || (iTitleID == 0x0005001010046200)) // MCP_APP_TYPE_UPDATE_SYSTEM { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 29) | (1 << 28)), 8), 16); } else if ((iTitleID == 0x000500101004B000) || (iTitleID == 0x000500101004B100) || (iTitleID == 0x000500101004B200)) // MCP_APP_TYPE_NETSERV { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28) | (1 << 30)), 22), 16); } else if ((iTitleID == 0x0005001B10059000) || (iTitleID == 0x0005001B10059100) || (iTitleID == 0x0005001B10059200)) // MCP_APP_TYPE_EMANUAL { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 31) | (1 << 28) | (1 << 30)), 3), 16); } else if ((iTitleID == 0x0005001B1005F000)) // MCP_APP_TYPE_DATA_PATCH_MAP { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 27) | (1 << 28)), 35), 16); } else if ((iTitleID == 0x0005001010062000) || (iTitleID == 0x0005001010062100) || (iTitleID == 0x0005001010062200) || (iTitleID == 0x0005001B10063000)) // MCP_APP_TYPE_DATA_WAGONU { app_type = Convert.ToString(MCP_MAKE_APP_TYPE(((1 << 27) | (1 << 28)), 41), 16); } else // If the title ID isn't internal or we don't know the app_type of the title then it gets set as MCP_APP_TYPE_GAME { app_type = Convert.ToString(MCP_MAKE_APP_TYPE((1 << 31), 0), 16); }; app_type = app_type.TrimStart('f'); return app_type; } // Helper function: StartProcessOnCrashdump() static bool StartProcessOnCrashdump(string input) { if (input == null) { throw new ArgumentNullException("input"); } int pos = input.IndexOf(IOS_CRASHDUMP_TOKEN); if (pos >= 0) { #if DEBUG Log.WriteLine(String.Format("Found crash token in '{0}'!", input)); #endif string line = input.Substring(pos + IOS_CRASHDUMP_TOKEN.Length).Trim(); //line = Environment.ExpandEnvironmentVariables(line); string shell; if (FileUtil.RunningFromCygwin) { shell = "cmd.exe"; line = string.Format("/c start bash -c \"{0}\"", Regex.Replace(line, "%([A-Za-z_]\\w+)%", "${$1}")); } else { shell = "cmd.exe"; line = "/c start " + Regex.Replace(line, "\\${?([A-Za-z_]\\w+)}?", "%$1%"); } #if DEBUG Log.WriteLine(String.Format("Starting '{0} {1}'...", shell, line)); #endif ProcessExecutor.DoProcess_DontWait(shell, line); } return true; // don't exit CafeX } #region CafeX Stop //Script function: cafestop static void stop(string[] args, bool checkMionVersion) { #if DEBUG Log.WriteLine("stop started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif bool HARD_STOP = false; if (PcfsTcpOnly) { checkMionVersion = false; HARD_STOP = true; } if (args != null && args.Length > 0) { foreach (string arg in args) { switch (arg.ToLowerInvariant()) { case "-hostonly": // CafeX doesn't let you execute any function if bridge vars are not set, so there is no // reason to check them here again like in BASH. // ----------------------------------------------------------------------------------------- // We want to kill any running processes, but don't want to talk to a (non-existent?) device ToucanReset.Stop(); PCFSServer.Shutdown(); return; case "-hard": // Force hard stop HARD_STOP = true; break; case "-makemine": // Don't do anything with this flag, let it fall through to hoststop() break; case "-h": default: // Display help and return stop_usage(); return; } } } PLATFORM.value = "cafe"; if ((CAFERUN_OPTION_SOFT_LAUNCH.value == "1" || CAFERUN_OPTION_KILL_RESTART.value == "1") && !HARD_STOP) { #if DEBUG Log.WriteLine("(CAFERUN_OPTION_SOFT_LAUNCH.value == 1 || CAFERUN_OPTION_KILL_RESTART.value == 1) && !HARD_STOP -> Doing nothing"); #endif // In autotest or in caferun with CAFERUN_OPTION_SOFTLAUNCH set, cafestop is a no-op CAFESTOP_STATUS.value = "0"; if (USE_SINGLE_CGI.value != "1") { // Explicitly clear the hint if not set to 1 USE_SINGLE_CGI.value = null; } else { Console.WriteLine("cafex {0}: Enabling single pass CGI", command); } } else { #if DEBUG Log.WriteLine("CAFERUN_OPTION_SOFT_LAUNCH.value != 1 -> calling hoststop()"); #endif #if TIMER Log.WriteLine("Hoststop start"); CafeXSetupTime.Report(); #endif if (!PcfsTcpOnly) { hoststop(args, checkMionVersion); } #if TIMER Log.WriteLine("Hoststop end"); CafeXSetupTime.Report(); #endif int ret = PCFSServer.Shutdown(); CAFESTOP_STATUS.value = ret.ToString(); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex stop error: CAFESTOP_STATUS=" + CAFESTOP_STATUS.value); } } static void stop(string[] args) { stop(args, false); } #endregion static CAFEX_ERROR readSDKFromCafeRoot(string sdk_root) { if (string.IsNullOrEmpty(sdk_root)) { sdk_root = CAFE_ROOT.value; } string sdk_ver_file = Path.Combine(sdk_root, "system\\include\\sdk_ver.h"); if (!File.Exists(sdk_ver_file)) { Console.WriteLine("cafex: Unable to find {0}, using OS header file.", sdk_ver_file); sdk_ver_file = Path.Combine(CAFE_ROOT.value, "system\\src\\build\\make\\os_version.mk"); if (!File.Exists(sdk_ver_file)) { Console.WriteLine("cafex: Unable to find OS header file {0}!", sdk_ver_file); return CAFEX_ERROR.RUN_COULDNT_PARSE_SDK_VERSION_HEADER; } else { #if DEBUG Console.WriteLine("cafex: SDK version from {0}.", sdk_ver_file); #endif FileStream fs = new FileStream(sdk_ver_file, FileMode.Open, FileAccess.Read); StreamReader sr = new StreamReader(fs); bool found_line = false; while (!sr.EndOfStream) { string line = sr.ReadLine(); if (line.Contains("SM := ")) SDK_VER.value = line.Substring(25, 1); if (line.Contains("Sm := ")) SDK_VER.value = SDK_VER.value + "." + line.Substring(25, 2); if (line.Contains("Sc := ")) { SDK_VER.value = SDK_VER.value + "." + line.Substring(25, 2); found_line = true; break; } } sr.Close(); if (!found_line) { Console.WriteLine("cafex Error: couldn't determine SDK version!"); return CAFEX_ERROR.RUN_COULDNT_PARSE_SDK_VERSION_HEADER; } } } else { #if DEBUG Console.WriteLine("cafex: SDK version from {0}.", sdk_ver_file); #endif FileStream fs = new FileStream(sdk_ver_file, FileMode.Open, FileAccess.Read); StreamReader sr = new StreamReader(fs); bool found_line = false; while (!sr.EndOfStream) { string line = sr.ReadLine(); if (line.Contains("#define CAFE_OS_SDK_VERSION") && !line.Contains("CAFE_OS_SDK_VERSION_STRING")) { UInt32 maj, min, mic, version; string[] subs = line.Split((string[])null, StringSplitOptions.RemoveEmptyEntries); if (subs.Length < 3) { Console.WriteLine("cafex Error: CAFE_OS_SDK_VERSION not defined in {0}!", sdk_ver_file); break; } if (!UInt32.TryParse(subs[2], out version)) { Console.WriteLine("cafex Error: TryParse on CAFE_OS_SDK_VERSION '{0}' failed!", subs[2]); break; } maj = version / 10000; min = (version % 10000) / 100; mic = version % 100; SDK_VER.value = String.Format("{0}.{1:D2}.{2:D2}", maj, min, mic); found_line = true; break; } } sr.Close(); if (!found_line) { Console.WriteLine("cafex Error: couldn't determine SDK version!"); return CAFEX_ERROR.RUN_COULDNT_PARSE_SDK_VERSION_HEADER; } } return CAFEX_ERROR.OK; } static CAFEX_ERROR readSDKFromMion() { string retVal = mionps.Run(String.Format("{0} {1} {2} {3}",BRIDGE_CURRENT_IP_ADDRESS.value, MIONPS_SDK_MAJ_BYTE,MIONPS_SDK_MIN_BYTE,MIONPS_SDK_MIC_BYTE)).Trim(); if (retVal.Contains("ERROR")) { //some error returned Console.WriteLine("MionPS returned an error."); if (retVal.Contains("5ERROR")) //because mionps is silly { Console.WriteLine("Please ensure that your devkit is turned on and has its Ethernet cable plugged into the front slot."); } return CAFEX_ERROR.MIONPS_ERROR; } char[] delims = {' '}; string[] splitString = retVal.Split(delims); SDK_MAJ_VER.value = splitString[0]; SDK_MIN_VER.value = String.Format("{0:D2}",Convert.ToInt32(splitString[1])); SDK_MIC_VER.value = String.Format("{0:D2}",Convert.ToInt32(splitString[2])); return CAFEX_ERROR.OK; } static void setMionSDKVersion() { char[] delims = { '.', ' ' }; string[] splitString = SDK_VER.value.Split(delims); int sdkmaj = Convert.ToInt32(splitString[0]); int sdkmin = Convert.ToInt32(splitString[1]); int sdkmic = Convert.ToInt32(splitString[2]); string parameters = string.Format("{0} 3 -s {1} 4 -s {2} 5 -s {3}", BRIDGE_CURRENT_IP_ADDRESS.value, sdkmaj, sdkmin, sdkmic); string retVal = mionps.Run(parameters).Trim(); string[] result = retVal.Split(delims); try { int newcatmaj = Convert.ToInt32(result[0]); int newcatmin = Convert.ToInt32(result[1]); int newcatmic = Convert.ToInt32(result[2]); if (sdkmaj != newcatmaj) Console.WriteLine("cafex unable to set the SDK Major version. Mionps returned " + result[0]); if (sdkmin != newcatmin) Console.WriteLine("cafex unable to set the SDK Minor version. Mionps returned " + result[1]); if (sdkmic != newcatmic) Console.WriteLine("cafex unable to set the SDK Micro version. Mionps returned " + result[2]); } catch (Exception) { Console.WriteLine("An error occurred when trying to set the SDK version on the catdev."); Console.WriteLine("Mionps returned: " + retVal); } } static CAFEX_ERROR checkNameFail() { HOSTSTOP_RVAL.value = "1"; return CAFEX_ERROR.CHECKNAME_FAILED; } static CAFEX_ERROR parseVersions(string output, bool checkMionVersion, bool checkSdk) { int res; int end; string sw_ver_str = null; string fw_ver_str = null; // Parse the software version (if not already checked) if (checkMionVersion || sw_ver_flat == 0) { res = output.IndexOf("software:"); if (res < 0) { return checkNameFail(); } end = output.IndexOf('\n', res += 9); if (end < 0) { return checkNameFail(); } sw_ver_str = output.Substring(res, end - res); if (sw_ver_flat == 0) { sw_ver_flat = compute_flat_version(sw_ver_str); } } // Parse the firmware version (if not already checked) if (checkMionVersion || fw_ver_flat == 0) { res = output.IndexOf("firmware:"); if (res < 0) { return checkNameFail(); } end = output.IndexOf('\n', res += 9); if (end < 0) { return checkNameFail(); } fw_ver_str = output.Substring(res, end - res); if (fw_ver_flat == 0) { fw_ver_flat = compute_flat_version(fw_ver_str); } } // Check versions if (checkMionVersion) { int min_fw_ver = compute_flat_version(MIN_MION_FW_VER); int min_sw_ver = compute_flat_version(MIN_MION_SW_VER); if (sw_ver_flat < min_sw_ver || fw_ver_flat < min_fw_ver) { Console.WriteLine("cafex failed: Please install at least HostBridgeSetup_{0}.exe and restart cafex_env.bat", MIN_MION_SW_VER); Console.WriteLine(" Current software version is {0} (need {1})", sw_ver_str, MIN_MION_SW_VER); Console.WriteLine(" Current firmware version is {0} (need {1})", fw_ver_str, MIN_MION_FW_VER); return checkNameFail(); } } // Set SDK versions (if not set) if (checkSdk && (string.IsNullOrEmpty(SDK_MAJ_VER.value) || string.IsNullOrEmpty(SDK_MIN_VER.value) || string.IsNullOrEmpty(SDK_MIC_VER.value))) { res = output.IndexOf("sdk:"); if (res < 0) { return checkNameFail(); } end = output.IndexOf('\n', res += 4); if (end < 0) { return checkNameFail(); } char[] delims = { '.' }; string[] sdk = output.Substring(res, end - res).Split(delims); SDK_MAJ_VER.value = sdk[0]; SDK_MIN_VER.value = sdk[1]; SDK_MIC_VER.value = sdk[2]; } return CAFEX_ERROR.OK; } //Script function: hoststop static CAFEX_ERROR hoststop(string[] args, bool checkMionVersion) { bool bAttemptedSoftwareShutdown = false; bool HARD_STOP = false; if (args != null && args.Length > 0) { if (args[0].ToLowerInvariant() == "-hard") { checkMionVersion = false; HARD_STOP = true; } } #if DEBUG Log.WriteLine("hoststop started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif if (SDIO_BRIDGE_TOOLS.value == null) { if (MION_BRIDGE_TOOLS.value == null) { Console.WriteLine("cafex hoststop failed: Please install the HostBridge and reopen the build environment!"); return CAFEX_ERROR.CHECKNAME_FAILED; } } HOSTSTOP_RVAL.value = "0"; HOSTSTOP_RETRIES.value = "0"; getbridgetype(); HOSTSTOP_RESET_OPTION.value = "-SMCResetHold"; if (BRIDGE_TYPE.value == "Mion") { int res = 0; bool makemine = false; string output = string.Empty; bool singleCGI = USE_SINGLE_CGI.value == "1"; if (!singleCGI) { Environment.SetEnvironmentVariable("CHECK_NAME_STOP", null); } // Set the proper USE_SINGLE_CGI hint if (args != null && args.Length > 0 && args[0] == "-makemine") { ToucanReset.Stop(); makemine = true; if (singleCGI) { Environment.SetEnvironmentVariable("CHECK_NAME_STOP", "2"); } } else if (singleCGI) { Environment.SetEnvironmentVariable("CHECK_NAME_STOP", "1"); } // Check the bridge name res = checkbridgename.CheckName(ref output); if (res != 0) { // Check if error string res = output.IndexOf("ERROR :"); if (res < 0) { output = string.Format("Bridge with the name '{0}' was not found", BRIDGE_CURRENT_NAME.value); } else { // Report error string int end = output.IndexOf('\n', res); if (end < 0) { output = output.Substring(res); } else { output = output.Substring(res, end - res); } } Console.WriteLine("CheckBridgeName: {0}", output); return checkNameFail(); } if (singleCGI) { if (output.Contains("INFO: CGI Reset")) { // Single pass supported firmware if (command != "stop") { Console.WriteLine("cafex {0}: Single pass CGI enabled", command); } if (makemine) { res = output.IndexOf("oldhost:"); if (res < 0) { return checkNameFail(); } int end = output.IndexOf("\n", res += 8); if (end < 0) { return checkNameFail(); } string old = output.Substring(res, (end - 1) - res); res = output.IndexOf("curhost:"); if (res < 0) { return checkNameFail(); } end = output.IndexOf("\n", res += 8); if (end < 0) { return checkNameFail(); } string host = output.Substring(res, (end - 1) - res); Console.WriteLine("cafex {0}: Bridge old owner: [{1}] new owner: [{2}]", command, old, host); } else { ToucanReset.Stop(); } return parseVersions(output, checkMionVersion, true); } // Not supported, clear hint USE_SINGLE_CGI.value = null; // Are we at least using single pass supported hostbridge? res = output.IndexOf("INFO: Display info "); if (res >= 0) { // Check the bridge query version if (output[res + 19] != '(') { return checkNameFail(); } int end = output.IndexOf(')', res += 20); if (end < 0) { return checkNameFail(); } // Parse the versions CAFEX_ERROR err = parseVersions(output, checkMionVersion, int.Parse(output.Substring(res, end - res)) > 1); if (err != CAFEX_ERROR.OK) { return err; } // Only display warning if firmware is out of sync Console.WriteLine("cafex {0}: Disabling single pass CGI, not supported", command); } } /* * Old stop functionality */ if (makemine) { FSEmul.makemine(); } if ((MION_PWR_SEQ.value == "smcreset") && !HARD_STOP) { int mionbutton_ret = MionButton.rsthold(args); HOSTSTOP_RVAL.value = mionbutton_ret.ToString(); } else if ((MION_PWR_SEQ.value == "FOFF1") && !HARD_STOP) { int mionbutton_ret = MionButton.forceOff1(args); HOSTSTOP_RVAL.value = mionbutton_ret.ToString(); } else { string boot_mode_file = Path.Combine(CAFE_TEMP.value, BRIDGE_CURRENT_IP_ADDRESS.value.Replace('.', 'x') + "_" + BRIDGE_CURRENT_NAME.value + "_CAFE_BOOT_MODE"); string OLD_BOOT_MODE = string.Empty; if (File.Exists(boot_mode_file)) { OLD_BOOT_MODE = File.ReadAllText(boot_mode_file); } if (MION_PWR_SEQ.value == "G_SHUTDOWN" && !HARD_STOP && (OLD_BOOT_MODE == CAFE_BOOT_MODE.value)) { int mionbutton_ret = MionButton.init_shutdown_w_FOFF2(args); bAttemptedSoftwareShutdown = true; HOSTSTOP_RVAL.value = mionbutton_ret.ToString(); } else { HOSTSTOP_RVAL.value = "1"; HOSTSTOP_RETRIES.value = "0"; while (HOSTSTOP_RVAL.value != "0" && HexHandler.GetNumberFromString(HOSTSTOP_RETRIES.value) < 4) { if (HexHandler.GetNumberFromString(HOSTSTOP_RETRIES.value) > 0) { Console.WriteLine("WARNING: MionButton powerdown failed with err={0}, will retry shortly, count={1}", HOSTSTOP_RVAL.value, HOSTSTOP_RETRIES.value); Thread.Sleep(new TimeSpan(0, 0, 30)); } int mionbutton_ret = MionButton.forceOff2_off_single_cgi(args); HOSTSTOP_RVAL.value = mionbutton_ret.ToString(); HOSTSTOP_RETRIES.value = (HexHandler.GetNumberFromString(HOSTSTOP_RETRIES.value) + 1).ToString(); } } } if (HOSTSTOP_RVAL.value != "0") { Console.WriteLine("Gathering MION logs via telnet for the mionbutton return of " + HOSTSTOP_RVAL.value + "."); string logfile = TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log"; FileStream fs = new FileStream(logfile, FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.WriteLine("----------------------------------------------------------------"); sw.WriteLine("----- MION telnet debug log @ " + DateTime.Now.ToLocalTime().ToString() + " -----"); sw.WriteLine("----------------------------------------------------------------"); output = string.Empty; int miontelnet_ret = miontelnet.Run(out output); sw.Write(output); sw.Flush(); sw.Close(); Console.WriteLine(" See " + logfile + " for details."); } } else { int toucanreset_ret = ToucanReset.Reset(); HOSTSTOP_RVAL.value = toucanreset_ret.ToString(); } ToucanReset.Stop(); if (HOSTSTOP_RVAL.value == "0") { return CAFEX_ERROR.OK; } if (BRIDGE_TYPE.value == "Mion") { if (bAttemptedSoftwareShutdown && HOSTSTOP_RVAL.value == "1") { Console.WriteLine("cafex hoststop warning: Software shutdown failed."); HOSTSTOP_RVAL.value = "0"; } else { Console.WriteLine("cafex hoststop failed: Could not stop cafe through " + BRIDGE_CURRENT_NAME.value); checkbridgename.CheckName_IPOnly(); } } else { Console.WriteLine("cafex hoststop failed: Could not stop cafe through Toucan."); } return CAFEX_ERROR.CHECKNAME_FAILED; } static CAFEX_ERROR hoststop(string[] args) { return hoststop(args, false); } //Script function: getbridgetype static void getbridgetype() { #if DEBUG Log.WriteLine("getbridgetype started."); #endif BRIDGE_TYPE.value = "Mion"; if (CAFE_HARDWARE.value.Length > 6) { if (CAFE_HARDWARE.value.Substring(6).StartsWith("mp")) { BRIDGE_TYPE.value = "Mion"; } else if (CAFE_HARDWARE.value.Substring(6) == "1" || CAFE_HARDWARE.value.Substring(6) == "2") { BRIDGE_TYPE.value = "Toucan"; } } #if DEBUG Log.WriteLine("BRIDGE_TYPE set to = " + BRIDGE_TYPE.value); #endif } internal enum CafeBootStage { Off, ServerSync, SendingSync1, WaitingForSync1, SendingFlags, SendingSync2, WaitingForSync2, Booted, } static bool trySyncRequest() { if (cattoucan.SendSyncRequest(DEVKIT_HELP_REQUEST_TIMEOUT)) { CMD_RESULT.value = "0"; return true; } CMD_RESULT.value = "1"; return false; } private class CafeBootProgress { public CafeBootStage stage = CafeBootStage.Off; public bool waitForTitle = true; public bool checkPower = true; public int tries = 0; public void checkVDD2() { if (checkPower && mionsig.getVDD2() == 0) { stage = CafeBootStage.Off; } } public bool checkKillRestartSoftlaunch() { waitForTitle = Environment.GetEnvironmentVariable("USE_KILL_RESTART_SOFTLAUNCH") == "1"; return waitForTitle; } public bool Active { get { return stage != CafeBootStage.Off; } } } static bool FastEjectStateSupported() { return (sw_ver_flat >= compute_flat_version(MIN_EJECT_SW_VER)) && (fw_ver_flat >= compute_flat_version(MIN_EJECT_FW_VER)); } static CafeBootStage bootCatDev() { cattoucan.FinishSync(true); List onArguments = new List(); onArguments.Add("-noprompt"); if (!string.IsNullOrEmpty(BRIDGE_PARAMETERS_WITH_E.value)) { onArguments.AddRange(BRIDGE_PARAMETERS_WITH_E.value.Split(' ')); } // discrun support variables onArguments.Add(ELF_NEST_OPT.value); onArguments.Add(ELF_NEST_VALUE.value); string[] noprompt_args = onArguments.ToArray(); EnvVar.BackUpCurrentEnvironment(); // Save and check user input string userProvidedTitleId = CAFERUN_OPTION_MLC_EMU_TITLEID.value; if (!string.IsNullOrEmpty(userProvidedTitleId)) { userProvidedTitleId = userProvidedTitleId.StartsWith("0x") ? userProvidedTitleId.Substring(2).ToLowerInvariant() : userProvidedTitleId.ToLowerInvariant(); // Then assigns to the variable that will be passed in for verification CAFERUN_WUMAD_TITLE_ID.value = userProvidedTitleId; } // Then assigns to the variable that will be passed in for verification CAFERUN_WUMAD_TITLE_ID.value = userProvidedTitleId; IsBooting = true; CafeXReturn ret = on(noprompt_args, true, true); IsBooting = false; if (ret.error != CAFEX_ERROR.OK) { if (CMD_RESULT.value == "0") { CMD_RESULT.value = "1"; } return CafeBootStage.Off; } string wumadRetrievedTitleId = CAFERUN_WUMAD_TITLE_ID.value; EnvVar.RestoreSavedEnvironment(); // If a value returned and it's different, should take it. if (!string.IsNullOrEmpty(wumadRetrievedTitleId) && !wumadRetrievedTitleId.Equals(userProvidedTitleId)) { // This is the auto-discovery action. Reset the wumad title id. CAFERUN_WUMAD_TITLE_ID.value = wumadRetrievedTitleId; } // We are cold booting, disable fast relaunch CAFERUN_OPTION_FAST_RELAUNCH.value = "0"; return CafeBootStage.ServerSync; } static bool tryCafeReboot(bool launch, bool isWumadExecution, CafeBootProgress progress, out CAFEX_ERROR error) { bool coldBootIntoApp = progress.waitForTitle && CAFE_BOOT_MODE.value == "PCFS" && CAFERUN_OPTION_SOFT_LAUNCH.value != "1" && CAFERUN_OPTION_FAST_RELAUNCH.value != "1"; /* Cold booting * don't wait for title to launch * or check power on sync */ progress.waitForTitle = false; progress.checkPower = false; // Cold boot into app if PCFS and not trying to soft or fast launch if (coldBootIntoApp) { error = startBootRun(isWumadExecution, launch, true); if (error != CAFEX_ERROR.OK || !launch) { return false; } progress.tries = CAFERUN_RETRY_COUNT; CMD_RESULT.value = "0"; } else { error = CAFEX_ERROR.OK; // Try to boot into sysconfig if (progress.tries < CAFERUN_LAST_RETRY) { progress.stage = bootCatDev(); if (!progress.Active) { progress.tries = CAFERUN_LAST_RETRY; } } } return true; } static CAFEX_ERROR startBootRun(bool isWumadExecution, bool launch, bool reboot) { if (reboot) { cattoucan.FinishSync(true); hoststop(null, false); } PCFS_SYNC_DATE.value = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-ffff"); string pcfsSync = string.Format("Starting PCFSServer.exe @ sync date [{0}]", PCFS_SYNC_DATE.value); Console.WriteLine(pcfsSync); #if DEBUG Log.WriteLine(pcfsSync); #endif pcfsSync = null; #if TIMER CafeXSetupTime.Report(); #endif CMD_RESULT.value = PCFSServer.Start(PCFSSERVER_PARAMETERS.value, PCFS_DIR_MAPPING.value, PCFS_SRV_LOG_OUTPUT.value).ToString(); Console.WriteLine("PCFSServer has started"); #if DEBUG Log.WriteLine("PCFSServer has started"); #endif #if TIMER CafeXSetupTime.Report(); #endif if(PcfsTcpOnly) { return CAFEX_ERROR.OK; } if (PCFSSERVER_PARAMETERS.value != null) { Console.WriteLine("Waiting for PCFSServer initialization..."); PCFSSERVERSYNC_RVAL.value = PCFSServerSync.wait_sync(PCFS_SYNC_DATE.value).ToString(); if (PCFSSERVERSYNC_RVAL.value != "0") { Console.WriteLine("PCFSServerSync exited with value " + PCFSSERVERSYNC_RVAL.value); return CAFEX_ERROR.RUN_PCFSSERVER_SYNC_FAILED; } Console.WriteLine("PCFSServer initialization complete!"); } else { Console.WriteLine("PCFSServer started without synchronization"); } BOOTRUN_ELF_OPT.value = ""; BOOTRUN_ELF_VALUE.value = ""; if (!string.IsNullOrEmpty(SOFT_LAUNCH_CAFE_ELF.value)) { BOOTRUN_ELF_OPT.value = "-usedlf"; BOOTRUN_ELF_VALUE.value = SOFT_LAUNCH_CAFE_ELF.value; } // Check if this is a wumad execution, so that bootrun can correctly assign the title Id if (isWumadExecution) { if (!string.IsNullOrEmpty(CAFERUN_OPTION_MLC_EMU_TITLEID.value)) { // Saves user input string userProvidedTitleId = CAFERUN_OPTION_MLC_EMU_TITLEID.value.StartsWith("0x") ? CAFERUN_OPTION_MLC_EMU_TITLEID.value.Substring(2).ToLowerInvariant() : CAFERUN_OPTION_MLC_EMU_TITLEID.value.ToLowerInvariant(); // Then assigns to the variable that will be passed in for verification CAFERUN_WUMAD_TITLE_ID.value = userProvidedTitleId; } else { // Ensure there is no title, so autodiscovery can run CAFERUN_WUMAD_TITLE_ID.value = string.Empty; } } if (launch == false) { return CAFEX_ERROR.OK; } #if TIMER Log.WriteLine("Launching bootrun"); CafeXSetupTime.Report(); #endif CAFEX_ERROR bootrun_ret = bootrun(new List() { BOOTRUN_ELF_OPT.value, BOOTRUN_ELF_VALUE.value }, fAppTypeDefined); if (bootrun_ret != CAFEX_ERROR.OK) { return bootrun_ret; } #if TIMER Log.WriteLine("Bootrun end"); CafeXSetupTime.Report(); #endif return CAFEX_ERROR.OK; } static void DefaultEjectState() { if (!EjectStateOverride) { EJECT_STATE.value = "in"; } } static bool CheckEjectState() { if (EJECT_STATE.value != "in" && EJECT_STATE.value != "out") { Console.WriteLine("cafex: Invalid eject state parameter '{0}'! Please specify 'in' or 'out'.", EJECT_STATE.value); return false; } EjectStateOverride = true; return true; } static void ClearEjectState() { EJECT_STATE.value = null; EjectStateOverride = false; } static void SetEjectState() { DefaultEjectState(); if (!string.IsNullOrEmpty(EJECT_STATE.value)) { int returnVal = mionurl.Run(BRIDGE_CURRENT_IP_ADDRESS.value + " /mion/status.cgi operation=eject disc=" + EJECT_STATE.value); if (returnVal != 0) { Console.WriteLine("cafex run: Set disc eject state:'{0}' failed={1}!", EJECT_STATE.value, returnVal); Console.WriteLine(" Continuing execution, ignoring ejectstate"); } else { Console.WriteLine("cafex run: Set disc eject state: '{0}' succeeded.", EJECT_STATE.value); } ClearEjectState(); } // Make sure this is cleared Environment.SetEnvironmentVariable(ENV_DISC_EJECT_STATE, null); } #region CafeX Run //Script function: caferun static CafeXReturn run(string[] args, bool runSetup, bool launch) { CafeXReturn ret = new CafeXReturn(CAFEX_ERROR.UNEXPECTED); //TODO: Spread the love to the other return paths. string TITLEID_INIT = "0xFFFFFFFFFFFFFFFF"; // Check to see if we have default options if (!String.IsNullOrEmpty(CAFERUN_DEFAULT_OPTIONS.value)) { // Warn the user that any default options will get overwritten if matching switches are specified on the command line. Log.WriteLine("*** CAFERUN_DEFAULT_OPTIONS *** Default options detected! Please be aware that any duplicate switches on the command line will overwrite the defaults specified!"); // Split the string into array elements and then create the new args array string[] temp; temp = CAFERUN_DEFAULT_OPTIONS.value.Split(' '); // We need to expand the args array so we can add the new args into it. int newLen = (temp.Length + args.Length); Array.Resize(ref args, newLen); string[] defaultArgs = new string[newLen]; Array.Copy(temp, defaultArgs, temp.Length); Array.Copy(args, 0, defaultArgs, temp.Length, (args.Length - temp.Length)); args = defaultArgs; } #if DEBUG Log.WriteLine("~~~~~~~~~~~~~~~~ START ENV VARIABLES~~~~~~~~~~~~~~~~~~"); IDictionary environmentVariables = Environment.GetEnvironmentVariables(); foreach (DictionaryEntry de in environmentVariables) { Log.WriteLine(string.Format(" {0} = {1}", de.Key, de.Value)); } Log.WriteLine("~~~~~~~~~~~~~~~~ END ENV VARIABLES~~~~~~~~~~~~~~~~~~"); Log.WriteLine(string.Format("**** Current Working Directory = {0} ****", Directory.GetCurrentDirectory())); Log.WriteLine("run started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif #region setup bool isWumadExecution = false; if (runSetup == true) { if (CAFERUN_INS.value == null) { CAFERUN_INS.value = "0"; } // This tells if the current call contains wumad parameters. PLATFORM.value = "cafe"; QUIET.value = "-q"; CAFESTOP_ONLY_IF_FSEMUL.value = "0"; PPC_OS_FLAGS.value = "0"; PPC_APP_FLAGS.value = "0"; PCFS_SYNC_DATE.value = ""; MCP_LAUNCH_HINT.value = ""; MCP_INFO_OPTION.value = ""; if (DEBUGGER.value == null) { DEBUGGER.value = "none"; } if (CAFE_CONSOLE.value == null) { CONSOLE.value = "cattoucan"; } else { CONSOLE.value = CAFE_CONSOLE.value; } if (CAFE_DEBUG_PORT.value == null) { CAFE_DEBUG_PORT.value = "toucan"; } if (DEBUG_ELF_FILE.value == null) { DEBUG_ELF_FILE.value = ""; } CAFERUN_OPTION_SOFT_RESTART.value = "0"; CAFERUN_OPTION_FAST_RELAUNCH.value = "0"; CAFERUN_OPTION_MLC_EMU_LAUNCH.value = "0"; CAFERUN_OPTION_MLC_EMU_TITLEID.value = TITLEID_INIT; string sdk_ver_file = CAFE_ROOT.value + "\\system\\include\\sdk_ver.h"; if (!File.Exists(sdk_ver_file)) { Console.WriteLine("cafex run error: sdk_ver.h does not exist: " + sdk_ver_file); return new CafeXReturn(CAFEX_ERROR.RUN_NO_SDK_VERSION_HEADER); } FileStream fs = new FileStream(CAFE_ROOT.value + "\\system\\include\\sdk_ver.h", FileMode.Open, FileAccess.Read); StreamReader sr = new StreamReader(fs); bool found_line = false; while (!sr.EndOfStream) { string line = sr.ReadLine(); if (line.Contains("00050010")) { int index = line.IndexOf("00050010"); string version = line.Substring(index, 16); CAFERUN_OS_MAJOR_VERSION_LO.value = version.Substring(8, 8); CAFERUN_OS_MAJOR_VERSION.value = version.Substring(14, 2); if (CAFERUN_COLDBOOT_OS_VERSION.value == null) CAFERUN_COLDBOOT_OS_VERSION.value = "0x00050010100040" + CAFERUN_OS_MAJOR_VERSION.value; else CAFERUN_COLDBOOT_OS_VERSION.value = "0x" + CAFERUN_COLDBOOT_OS_VERSION.value; found_line = true; break; } } sr.Close(); if (!found_line) { Console.WriteLine("cafex run error: couldn't find sdk version in sdk_ver.h"); return new CafeXReturn(CAFEX_ERROR.RUN_COULDNT_PARSE_SDK_VERSION_HEADER); } #if DEBUG Log.WriteLine("CAFERUN_COLDBOOT_OS_VERSION set to '{0}' from file {1}\\system\\include\\sdk_ver.h", CAFERUN_COLDBOOT_OS_VERSION.value, CAFE_ROOT.value); #endif HEARTBEAT_DISABLE.value = "0"; PCFS_DIR_MAPPING.value = ""; MAPDIR_MLC.value = ""; MAPDIR_SLC.value = ""; MAPDIR_CODE.value = ""; MAPDIR_META.value = ""; MAPDIR_CONTENT.value = ""; MAPDIR_SAVE.value = ""; PCFS_LOG_TIMESTAMP.value = ""; PCFS_SRV_LOG_OUTPUT.value = ""; RUN_FROM_HDD_BANK.value = ""; BRIDGE_PARAMETERS.value = ""; BRIDGE_PARAMETERS_WITH_E.value = ""; PCFS_OVER_SATA_PORT.value = ""; if (PCFS_HEADLESS_EMUL.value == null) { PCFS_HEADLESS_EMUL.value = "-pcfsenable"; } PREPHDD_STAT.value = ""; DISC_EMU_TID.value = ""; SYSTEM_MODE.value = ""; RPL_DIRS.value = ""; RPL_FILES.value = ""; if (CAFERUN_OPTION_NO_DATA_SYNC.value == null) { CAFERUN_OPTION_NO_DATA_SYNC.value = "0"; } if (command != "on" && command != "setbootmode" && CAFE_BOOT_MODE.value == "NAND" && !PcfsTcpOnly) { CAFERUN_OPTION_SOFT_LAUNCH.value = "1"; } else { CAFERUN_OPTION_SOFT_LAUNCH.value = "0"; } #if DEBUG Log.WriteLine("CAFERUN_OPTION_SOFT_LAUNCH set to " + CAFERUN_OPTION_SOFT_LAUNCH.value); #endif CAFERUN_HOSTBRIDGE_VERSION.value = "unknown"; CAFERUN_FW_VERSION.value = "unknown"; if (CAFE_DEBUG_INIT.value == null) { CAFE_DEBUG_INIT.value = "0"; } if (CAFE_DEBUG_PREINIT.value == null) { CAFE_DEBUG_PREINIT.value = "0"; } if (CAFE_DEBUG_DONTSTOP.value == null) { CAFE_DEBUG_DONTSTOP.value = "0"; } if (CAFE_LAUNCH_DEBUG.value == null) { CAFE_LAUNCH_DEBUG.value = "1"; } if (CAFE_SYSLOG_LEVEL.value == null) { CAFE_SYSLOG_LEVEL.value = "1"; } if (CAFE_RUN_FORCERESTART.value == null) { CAFE_RUN_FORCERESTART.value = "0"; } if (DEBUG_PROC_ID.value == null) { DEBUG_PROC_ID.value = "15"; } if (CAFERUN_OPTION_KILL_RESTART.value == null) { CAFERUN_OPTION_KILL_RESTART.value = "0"; } DEBUG_FLAGS.value = "0"; if (CAFE_DEBUG_INIT.value != "0") { DEBUG_FLAGS.value = "16"; } if (CAFE_DEBUG_DONTSTOP.value != "0") { DEBUG_FLAGS.value = "32"; } if (CAFE_DEBUG_PREINIT.value != "0") { DEBUG_FLAGS.value = "64"; } if (USE_EXI_AS_DEBUG_CHANNEL.value == null || USE_EXI_AS_DEBUG_CHANNEL.value.Equals("0")) { UInt32 dbgFlags = HexHandler.GetNumberFromString(DEBUG_FLAGS.value) | 256; DEBUG_FLAGS.value = dbgFlags.ToString(); } CATOUTPUT.value = "0"; CMDOUTPUT.value = "0"; switch (CONSOLE.value) { case "sdio": { CONSOLE.value = "toucan"; break; } case "cattoucan": { CONSOLE.value = "toucan"; DEBUGGER.value = "cattoucan"; CATOUTPUT.value = "1"; break; } case "cmdtoucan": { CONSOLE.value = "toucan"; DEBUGGER.value = "cattoucan"; CMDOUTPUT.value = "1"; break; } } if (CAFE_AUTOTEST.value == "1") { DEBUGGER.value = "none"; } #if DEBUG Log.WriteLine("CONSOLE = " + CONSOLE.value); Log.WriteLine("DEBUGGER = " + DEBUGGER.value); Log.WriteLine("CATOUTPUT= " + CATOUTPUT.value); Log.WriteLine("CMDOUTPUT= " + CMDOUTPUT.value); #endif } //if (launch == false) //{ // return new CafeXReturn(CAFEX_ERROR.OK); //} #endregion int rpx_index = args.Length; for (int i = 0; i < args.Length; ++i) { if (args[i].ToLowerInvariant().Contains(".rpx") || args[i].ToLowerInvariant().Contains(".elf")) { // Ensure the RPX is not the argument of an option if ( i > 0 && ( args[i - 1].Trim().Equals("-k") || args[i - 1].Trim().Equals("-l") || args[i - 1].ToLowerInvariant().Trim().Equals("-e"))) { // Exceptions: If ELF/RPX is argument of "-k" or "-l". continue; } else { // Default: ELF/RPX found is the one to run. rpx_index = i; break; } } } #if DEBUG Log.WriteLine("Search for RPX index returned index = " + rpx_index.ToString()); #endif #region arguments bool passedArgumentsWithDashA = false; if (!EjectStateOverride && !string.IsNullOrEmpty(EJECT_STATE.value) && !CheckEjectState()) { return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } for (int i = 0; i < rpx_index; ++i) { switch (args[i]) { case "-m": { Console.WriteLine("cafex run failed: memmap not supported"); run_usage(); return new CafeXReturn(CAFEX_ERROR.RUN_MEMMAP_NOT_SUPPORTED); } case "-g": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } uint prev_value = HexHandler.GetNumberFromString(PPC_OS_FLAGS.value); uint arg_value; if (String.IsNullOrEmpty(args[i + 1])) { Console.WriteLine("WARNING: Value after -g is null or empty. Option is ignored."); arg_value = 0; } else { arg_value = HexHandler.GetNumberFromString(args[i + 1]); } uint new_value = prev_value | arg_value; PPC_OS_FLAGS.value = new_value.ToString(); //MULTI sends -g 1 to PPC_OS_FLAGS telling it that debugger is attached //equivalent to ==> -d multi if ((arg_value & 0x1) == 1) { g_gArgValue = 1; } ++i; break; } case "-p": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (String.IsNullOrEmpty(args[i + 1])) { //DEBUG_PROC_ID has a default value of 15, or whatever the user may have set in the env //This is why it's not set here. Console.WriteLine("WARNING: Value for -p is null or empty. Debugger will break in the default process ({0}).", DEBUG_PROC_ID.value); } else { DEBUG_PROC_ID.value = args[i + 1]; } uint debug_flags = HexHandler.GetNumberFromString(DEBUG_FLAGS.value); uint debug_proc_id = HexHandler.GetNumberFromString(DEBUG_PROC_ID.value); if ((debug_flags & 0xf) != 0) { uint new_value = (uint)(debug_flags & ~0xf) | (debug_proc_id & 0xf); DEBUG_FLAGS.value = new_value.ToString(); } ++i; break; } case "-d": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } DEBUGGER.value = args[i + 1]; uint debug_flags = HexHandler.GetNumberFromString(DEBUG_FLAGS.value); uint debug_proc_id = HexHandler.GetNumberFromString(DEBUG_PROC_ID.value); uint new_value = debug_flags | (debug_proc_id & 0xf); DEBUG_FLAGS.value = new_value.ToString(); //CAFE_RUN_FORCERESTART.value = "1"; ++i; break; } case "-k": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } DEBUG_ELF_FILE.value = args[i + 1]; ++i; break; } case "-w": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } uint prev_value = HexHandler.GetNumberFromString(PPC_OS_FLAGS.value); uint arg_value = 0; try { arg_value = HexHandler.GetNumberFromString(args[i + 1]); } catch (FormatException) { Console.WriteLine("cafex : argument for -w option is not a valid number and will be ignored."); } uint new_value = prev_value | arg_value; PPC_OS_FLAGS.value = new_value.ToString(); ++i; break; } case "-a": { if (!ArgumentChecks.ArgumentExists(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } DASH_A_ARGS.value = args[i + 1]; passedArgumentsWithDashA = true; ++i; break; } case "-o": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (String.IsNullOrEmpty(args[i + 1])) { Console.WriteLine("WARNING: value for -o was null or empty, so it will be treated as 0."); CAFERUN_COLDBOOT_OS_VERSION.value = "0x0000000000000000"; } else { CAFERUN_COLDBOOT_OS_VERSION.value = args[i + 1]; } ++i; break; } case "-b": { CAFERUN_COLDBOOT_OS_VERSION.value = "0x00050010100080" + CAFERUN_OS_MAJOR_VERSION.value; break; } case "-C": { CAFERUN_COLDBOOT_OS_VERSION.value = "0x00050010100040FE"; break; } case "-u": { CAFERUN_COLDBOOT_OS_VERSION.value = "0x000500101000C0" + CAFERUN_OS_MAJOR_VERSION.value; break; } case "-n": { uint prev_value = HexHandler.GetNumberFromString(PPC_OS_FLAGS.value); uint new_value = prev_value | 0x02000; PPC_OS_FLAGS.value = new_value.ToString(); break; } case "-i": { uint prev_value = HexHandler.GetNumberFromString(DEBUG_FLAGS.value); uint new_value = prev_value | 16; DEBUG_FLAGS.value = new_value.ToString(); break; } case "-R": { uint prev_value = HexHandler.GetNumberFromString(DEBUG_FLAGS.value); uint new_value = prev_value | 32; DEBUG_FLAGS.value = new_value.ToString(); break; } case "-j": { uint prev_value = HexHandler.GetNumberFromString(DEBUG_FLAGS.value); uint new_value = prev_value | 64; DEBUG_FLAGS.value = new_value.ToString(); break; } case "-q": { CAFE_SYSLOG_LEVEL.value = "0"; break; } case "-v": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } CAFE_SYSLOG_LEVEL.value = args[i + 1]; int sysloglvl = 0; if (int.TryParse(CAFE_SYSLOG_LEVEL.value, out sysloglvl)) { sysloglvl &= 7; CAFE_SYSLOG_LEVEL.value = sysloglvl.ToString(); } else { Console.WriteLine("Unable to convert CAFE_SYSLOG_LEVEL to integer."); return new CafeXReturn(CAFEX_ERROR.SYSLOG_LEVEL_SET_FAILED); } ++i; break; } case "-e": { if (!ArgumentChecks.ArgumentExists(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (args[i + 1].StartsWith("mcp")) { // Split into: [0]: "mcp", [1]: "launch_hint", [2]: {launch_hint_value} List mcp_args = args[i + 1].Split(':').Select(a => a.ToLowerInvariant()).ToList(); if (mcp_args.Count == 3 && mcp_args[1] == "launch_hint") { // Check if launch_hint is valid string[] validLaunchHints = new string[] { "hfiomlc", "hfiodisc", "mlc", "odd", "sddisc", "sdio", "usb" }; if (!validLaunchHints.Contains(mcp_args[2])) { Console.WriteLine("cafex run: \"{0}\" is not a valid launch hint. Valid arguments are: {1}.", mcp_args[2], string.Join(", ", validLaunchHints.ToArray())); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } MCP_LAUNCH_HINT.value = mcp_args[2]; // Check if user wants to launch from somewhere else than the wumad if (isWumadExecution && command != "on" && string.Compare(MCP_LAUNCH_HINT.value, "odd", true) != 0) { Console.WriteLine("WARNING: overriding launch hint for wumad with " + MCP_LAUNCH_HINT.value); } } else { return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } } else if (args[i + 1] == "nopcfs") { Console.WriteLine("cafex run: Emulating PCFS Headless Mode."); PCFS_HEADLESS_EMUL.value = "-pcfsdisable"; } else if (args[i + 1] == "noFFIO") { // This is the designation for PCFSServer to disable Fast File IO Console.WriteLine("cafex run: Disabling PCFS Fast File IO."); PCFSSERVER_PARAMETERS.AddToVar("-noFFIO", ' '); } else if (args[i + 1] == "noCSR") { // This is the designation for PCFSServer to disable cafe from using the combined send+recv in MION Console.WriteLine("cafex run: Disabling MION send/recv support."); PCFSSERVER_PARAMETERS.AddToVar("-noCSR", ' '); } else if (args[i + 1] == "sdioasdbgr") { // make sure to change the port for SDIO from 7977 to 6002 USE_EXI_AS_DEBUG_CHANNEL.value = "0"; } else if (args[i + 1].ToLowerInvariant().StartsWith("ejectstate")) { // Set the MION eject state (in or out) before launching if (args[i + 1].Length < 11) { return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } EJECT_STATE.value = args[i + 1].Substring(11); if (!CheckEjectState()) { return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } } else if (args[i + 1].ToLowerInvariant().StartsWith("wumad")) { if (args[i + 1].Length < 6) { return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } CAFE_WUMAD.value = PathConverter.Windowsify(args[i + 1].Substring(6)); // Check to make sure CAFE_WUMAD.value isn't empty // if(String.IsNullOrEmpty(CAFE_WUMAD.value)) { Console.WriteLine("Invalid WUMAD argument!"); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } BRIDGE_PARAMETERS.AddToVar("-sata", ' '); BRIDGE_PARAMETERS_WITH_E.AddToVar("-e sata", ' '); CAFE_RUN_FORCERESTART.value = "1"; isWumadExecution = true; // Force launching the wumad from ODD (if user didn't specify a launch hint, or cafex on) if (command != "on") { if (string.IsNullOrEmpty(MCP_LAUNCH_HINT.value)) { MCP_LAUNCH_HINT.value = "odd"; } else if (string.Compare(MCP_LAUNCH_HINT.value, "odd", true) != 0) { Console.WriteLine("WARNING: overriding launch hint for wumad with " + MCP_LAUNCH_HINT.value); } } } else if (args[i + 1].ToLowerInvariant().StartsWith("soft_launch_cafe_elf")) { // This is the CAFE_ELF of the top level execution // that invoked this run to power on. This is ued // to create the disk image. CAFERUN_OPTION_CALLED_FROM_CAFEDISCRUN.value = "yes"; SOFT_LAUNCH_CAFE_ELF.value = args[i + 1].Substring(21); } else if (args[i + 1].ToLowerInvariant().StartsWith("eco")) { // eco mode debugging case ECO_MODE.value = "1"; _CCRSYSCFG1.value = "0x20000000"; } else if (args[i + 1] == "sata") { Console.WriteLine("WARNING: The \"sata\" option for -e is deprecated; \"sata\" is used by default."); } else { BRIDGE_PARAMETERS.AddToVar("-" + args[i + 1], ' '); BRIDGE_PARAMETERS_WITH_E.AddToVar("-e " + args[i + 1], ' '); if (args[i + 1].StartsWith("h")) { if (args[i + 1].Length < 2) { return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } RUN_FROM_HDD_BANK.value = args[i + 1].Substring(2); // Check the value of RUN_FROM_HDD_BANK to be sure that it // is a number in the range of 0 - 60 (inclusive) // int hdd_bank = -1; bool result = int.TryParse(RUN_FROM_HDD_BANK.value, out hdd_bank); if (!result) { Console.WriteLine("CafeX: Invalid HDD bank value!"); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } else { // Make sure the number is in range // int MinHDDBankNo = 0; int MaxHDDBankNo = 60; if ( (hdd_bank < MinHDDBankNo) || (hdd_bank > MaxHDDBankNo) ) { Console.WriteLine("CafeX: Invalid HDD bank value!"); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } } } if (args[i + 1].StartsWith("pcfsport")) { string[] pcfsport_arg = args[i + 1].Split(':'); uint port; if (pcfsport_arg.Length == 2 && // Verify argument was passed in the proper format, i.e. pcfsport:12345 uint.TryParse(pcfsport_arg[1], out port) && // Verify port is a number port >= 1 && port <= 65535) // Verify port is within valid port range { PCFS_OVER_SATA_PORT.value = port.ToString(); USE_PCFS_OVER_SATA.value = "1"; } else { Console.WriteLine("cafex run: Invalid PCFS port specified."); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } } if (args[i + 1].StartsWith("sdio")) { // If the Host Bridge does not support this option, remove it // This option was implemented with HB 3.2.4.4 CAFEX_ERROR hostcheckversion_ret = hostcheckversion(); if(hostcheckversion_ret != CAFEX_ERROR.OK) return new CafeXReturn(hostcheckversion_ret); if (sw_ver_flat < compute_flat_version("3.2.4.4")) { BRIDGE_PARAMETERS.RemoveFromVar("-sdio", ' '); BRIDGE_PARAMETERS_WITH_E.RemoveFromVar("-sdio", ' '); } } } ++i; break; } case "-c": { DEBUGGER.value = "cattoucan"; break; } case "-f": { CAFESTOP_ONLY_IF_FSEMUL.value = "1"; break; } case "-s": { CAFERUN_OPTION_SOFT_LAUNCH.value = "1"; break; } case "-y": { CAFERUN_OPTION_FAST_RELAUNCH.value = "1"; if (string.IsNullOrEmpty(CAFERUN_OPTION_FASTLAUNCH_RETRIES.value)) { CAFERUN_OPTION_FASTLAUNCH_RETRIES.value = COSDEBUG_FASTLAUNCH_RETRIES.ToString(); } if (string.IsNullOrEmpty(CAFERUN_OPTION_FASTLAUNCH_TIMEOUT.value)) { CAFERUN_OPTION_FASTLAUNCH_TIMEOUT.value = COSDEBUG_FASTLAUNCH_TIMEOUT.ToString(); } if (string.IsNullOrEmpty(CAFERUN_OPTION_FASTLAUNCH_DELAY.value)) { CAFERUN_OPTION_FASTLAUNCH_DELAY.value = COSDEBUG_FASTLAUNCH_DELAY.ToString(); } break; } case "-r": { CAFERUN_OPTION_SOFT_RESTART.value = "1"; break; } case "-F": { CAFE_RUN_FORCERESTART.value = "1"; break; } case "-K": //Option to execute kill restart { // Set the restart option as a backup CAFERUN_OPTION_SOFT_RESTART.value = "1"; g_KOptionSet = true; break; } case "-L": { IGNORE_VERSION.value = "1"; break; } case "-t": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } try { TitleId titleId = new TitleId(args[i + 1]); CAFERUN_OPTION_MLC_EMU_LAUNCH.value = "1"; CAFERUN_OPTION_MLC_EMU_TITLEID.value = titleId.Value; } catch (ArgumentException ex) { Console.WriteLine("Invalid title ID detected!"); Console.WriteLine(ex.Message); return new CafeXReturn(CAFEX_ERROR.RUN_BAD_TITLE_ID); } ++i; break; } case "-l": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (!args[i + 1].EndsWith(".rpl")) { // CafeX addToVar does not use space as delimiter for the list, so there is no need to replace spaces with "|". RPL_DIRS.AddToVar(args[i + 1], DEFAULT_DELIMITER); } else { // CafeX addToVar does not use space as delimiter for the list, so there is no need to replace spaces with "|". RPL_FILES.AddToVar(args[i + 1], DEFAULT_DELIMITER); } ++i; break; } case "-h": { run_usage(); return new CafeXReturn(CAFEX_ERROR.OK); } case "-H": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (args[i + 1] == "disable") { HEARTBEAT_DISABLE.value = "0x00020000"; } else if (args[i + 1] == "enable") { HEARTBEAT_DISABLE.value = "0"; } else { run_usage(); return new CafeXReturn(CAFEX_ERROR.RUN_BAD_H_ARGUMENT); } ++i; break; } case "-x": { BRIDGE_PARAMETERS.AddToVar("-sata", ' '); break; } case "-z": { if (!Directory.Exists(CAFE_DATA_DIR.value)) { Console.WriteLine("Session data directory is missing and needs to be sync'd!"); Console.WriteLine(" Please re-run without the '-z' option."); return new CafeXReturn(CAFEX_ERROR.RUN_NO_CAFE_DATA_DIR); } CAFERUN_OPTION_NO_DATA_SYNC.value = "1"; break; } case "-A": { Console.WriteLine("*** -A option is deprecated and has no effect. ATFS is now the default file system. ***"); break; } case "-D": { Console.WriteLine("cafex run failed: -D option is deprecated. DVDFS is now unsupported."); run_usage(); return new CafeXReturn(CAFEX_ERROR.RUN_D_OPTION_USED); } case "-M": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } SYSTEM_MODE.value = args[i + 1]; ++i; break; } case "-T": { // Check the apptype to make sure it is valid if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } CAFERUN_APP_TYPE.value = args[i + 1]; // Make sure the value is valid. if (CAFERUN_APP_TYPE.value.StartsWith("0x") || CAFERUN_APP_TYPE.value.StartsWith("0X")) // Check to see if the value is preceded by "0x" { CAFERUN_APP_TYPE.value.Remove(0, 2); // Strip off the "0x" or "0X" because we won't need it } // Now check the length of the value. We will only accept values that are 8 digits in length. if (CAFERUN_APP_TYPE.value.Length != 8) { Console.WriteLine("-T value needs to be an 8 digit hex value"); run_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } // We know that there is no "0x" prefix and that the value is the correct length. // Now we need to check to make sure that it is a hex value between 00000000 - FFFFFFFF try { Convert.ToUInt32(CAFERUN_APP_TYPE.value, 16); } catch ( Exception ) { Console.WriteLine("AppType is not in Hex format"); } fAppTypeDefined = true; ++i; break; } case "-N": { SKIP_OS_CHECK.value = "1"; break; } case "-ignoreQ": { ignore_quiet_mode = true; break; } default: { Console.WriteLine("cafex run failed: invalid option: " + args[i]); run_usage(); return new CafeXReturn(CAFEX_ERROR.RUN_INVALID_OPTION); } } } #endregion #if TIMER CafeXSetupTime.Report(); Log.WriteLine("End of arguments"); #endif // Check if we need to display the HBM warning. See bugzilla 11537 for more details. if (CAFE_BOOT_MODE.value == "PCFS") { // These paths are where HBM is located. if (!File.Exists(Path.Combine(CAFE_MLC_DIR.value, @"sys\title\00050030\1001000A\code\app.xml")) || !File.Exists(Path.Combine(CAFE_MLC_DIR.value, @"sys\title\00050030\1001010A\code\app.xml")) || !File.Exists(Path.Combine(CAFE_MLC_DIR.value, @"sys\title\00050030\1001020A\code\app.xml"))) { Console.WriteLine(string.Concat("WARNING: Some system applications on the system might be missing. ", "If the system fails to boot, please reinstall the SDK to restore the missing system applications and run cafeupdate.")); } } int bankNo = -1; if (command == "discrun" && !(SKIP_OS_CHECK.value == "1") && (!String.IsNullOrEmpty(CAFERUN_OPTION_MLC_EMU_TITLEID.value) && !(CAFERUN_OPTION_MLC_EMU_TITLEID.value == TITLEID_INIT)) && int.TryParse(RUN_FROM_HDD_BANK.value, out bankNo) && !PcfsTcpOnly) { //Check the value on MION to see if we have an OS mismatch when booting from the HDD int mion_os_ver = Convert.ToInt32(mionps.Run(String.Format("{0} {1}", BRIDGE_CURRENT_IP_ADDRESS.value, MIONPS_IMGUPLOAD_BASE_BYTE + bankNo))); // 2 is the DEBUG OS on MION, 1 is NDEBUG, 254 means a non-wumad was uploaded if (mion_os_ver == 254) { Console.WriteLine("Skipping OS check since a non-wumad was uploaded."); } else if (CAFERUN_COLDBOOT_OS_VERSION.value == "0x000500101000800A" && mion_os_ver != 2) { Console.WriteLine("ERROR: Uploaded title's OS version does not match command line arguments!"); Console.WriteLine("ERROR: Please omit \"-b\" on the command line."); Console.WriteLine("If you uploaded the title using a HostBridge prior to 3.2.6.0, please install HostBridge 3.2.6.0 or later, re-upload the image, and try again."); Console.WriteLine("If you want to skip this check, specify \"-N\" on the command line, but be warned that Cafe may return an error!"); return new CafeXReturn(CAFEX_ERROR.UPLOADED_IMAGE_OS_MISMATCH); } else if (CAFERUN_COLDBOOT_OS_VERSION.value == "0x000500101000400A" && mion_os_ver != 1) { Console.WriteLine("ERROR: Uploaded title's OS version does not match command line arguments!"); Console.WriteLine("ERROR: Please specify \"-b\" on the command line."); Console.WriteLine("If you uploaded the title using a HostBridge prior to 3.2.6.0, please install HostBridge 3.2.6.0 or later, re-upload the image, and try again."); Console.WriteLine("If you want to skip this check, specify \"-N\" on the command line, but be warned that Cafe may return an error!"); return new CafeXReturn(CAFEX_ERROR.UPLOADED_IMAGE_OS_MISMATCH); } } //If MULTI is running make sure KILL_RESTART is enabled if (DEBUGGER.value == "multi" && CAFE_LAUNCH_DEBUG.value == "0" && ((CAFERUN_DISABLE_KILL_RESTART.value == null) || (CAFERUN_DISABLE_KILL_RESTART.value == "0")) && ((g_gArgValue == 1) || (CAFERUN_OPTION_SOFT_RESTART.value == "1"))) { CAFERUN_OPTION_KILL_RESTART.value = "1"; } else { CAFERUN_OPTION_KILL_RESTART.value = "0"; } //This is a hack to make sure that killrestart happens from the console instead of multi if (g_KOptionSet) { CAFERUN_OPTION_KILL_RESTART.value = "1"; g_gArgValue = 1; } // Wumad override: if "-e sata" was not provided and "-e wumad" was, sata bridge parameters should be added. if (!string.IsNullOrEmpty(CAFE_WUMAD.value) && (string.IsNullOrEmpty(BRIDGE_PARAMETERS.value) || !BRIDGE_PARAMETERS.value.Contains("-sata")) && (string.IsNullOrEmpty(BRIDGE_PARAMETERS_WITH_E.value) || !BRIDGE_PARAMETERS_WITH_E.value.Contains("-e sata"))) { BRIDGE_PARAMETERS.AddToVar("-sata", ' '); BRIDGE_PARAMETERS_WITH_E.AddToVar("-e sata", ' '); } // Remove arguments before the .rpx string[] new_args = new string[args.Length - rpx_index]; Array.Copy(args, rpx_index, new_args, 0, new_args.Length); args = new_args; //if (args.Length == 0) //{ // Console.WriteLine("cafex run failed: No arguments specified."); // run_usage(); // return new CafeXReturn(CAFEX_ERROR.RUN_NO_ARGUMENTS); //} if (!PcfsTcpOnly) { ret.error = readSDKFromMion(); if (ret.error != CAFEX_ERROR.OK) return ret; //something bad happened in mionps, so abort string catdev_sdk_ver = string.Format("{0}.{1}.{2}", SDK_MAJ_VER.value, SDK_MIN_VER.value, SDK_MIC_VER.value); string sdk_ver = SDK_VER.value; if (catdev_sdk_ver != SDK_VER.value) { Console.WriteLine("The CAT-DEV SDK version is not the same as the SDK you are running."); Console.WriteLine("SDK Version: {0} CAT-DEV SDK Version: {1}", sdk_ver, catdev_sdk_ver); Console.WriteLine("Please run cafeupdate to get in sync."); } if (PCFS_OVER_SATA_PORT.value == null) { if (USE_PCFS_OVER_SATA.value == "1") { PCFS_OVER_SATA_PORT.value = SESSION_PCFS_SATA_PORT.value; BRIDGE_PARAMETERS.AddToVar("-pcfsport:" + SESSION_PCFS_SATA_PORT.value, ' '); Console.WriteLine("cafex run: using PCFS over SATA on port " + PCFS_OVER_SATA_PORT.value); } else { Console.WriteLine("cafex run: not using PCFS over SATA"); } } if (PCFS_OVER_SATA_PORT.value != null) { PCFSSERVER_PARAMETERS.AddToVar("-c " + PCFS_OVER_SATA_PORT.value, ' '); } else { Console.WriteLine("cafex run: PCFS_OVER_SATA_PORT is not set."); } } else { USE_PCFS_OVER_SATA.value = null; PCFSSERVER_PARAMETERS.AddToVar("-l " + PcfsIpEndpoint.Port.ToString(), ' '); PCFSSERVER_PARAMETERS.AddToVar("-i " + PcfsIpEndpoint.Address.ToString(), ' '); //shut down the current running instance because we are going to run a title //that may be different from the previous title, therefore the mappings could be different if (CAFERUN_OPTION_SOFT_LAUNCH.value != "1") { PCFSServer.Shutdown(); } } if (PCFSSERVER_PARAMETERS.value != null) { Console.WriteLine("cafex run: PCFSServer parameters " + PCFSSERVER_PARAMETERS.value); } if (BRIDGE_PARAMETERS.value == null || !BRIDGE_PARAMETERS.value.Contains("-h")) { if (BRIDGE_PARAMETERS.value == null || !BRIDGE_PARAMETERS.value.Contains("-em")) { BRIDGE_PARAMETERS.AddToVar("-em", ' '); } } DISC_EMU_TYPE.value = "hfio"; if (CAFERUN_OPTION_CALLED_FROM_CAFEDISCRUN.value == "yes") { if (RUN_FROM_HDD_BANK.value != null) { DISC_EMU_TYPE.value = "hdd"; Console.WriteLine("cafex run: Will launch HDD bank " + RUN_FROM_HDD_BANK.value); } else if (!string.IsNullOrEmpty(CAFE_WUMAD.value)) { // wumad emulation started from cafediscrun DISC_EMU_TYPE.value = "hdd"; } else if (CAFERUN_OPTION_SOFT_LAUNCH.value == "1") { ALLOW_DISCRUN_IN_SOFTLAUNCH.value = "1"; DISC_EMU_TYPE.value = "blockemu"; BRIDGE_PARAMETERS.AddToVar("-em", ' '); //Tell FSEmul to use block emulation explicitly } else { DISC_EMU_TYPE.value = "blockemu"; if (BRIDGE_PARAMETERS.value == null || !BRIDGE_PARAMETERS.value.Contains("-em")) { BRIDGE_PARAMETERS.AddToVar("-em", ' '); } } } else if (!string.IsNullOrEmpty(CAFE_WUMAD.value)) { // wumad emulation started from caferun DISC_EMU_TYPE.value = "hdd"; } else { // default DISC_EMU_TYPE.value = "hfio"; if (CAFE_BOOT_MODE.value == "NAND") { if (SYSTEM_MODE.value == "test") { Console.WriteLine("cafex run failed: Test mode not supported on NAND."); return new CafeXReturn(CAFEX_ERROR.RUN_TEST_MODE_WITH_NAND_BOOT); } Console.WriteLine("cafex run: Will use NAND file system"); } else { Console.WriteLine("cafex run: Will use PCFS file system emulation"); } if (RUN_FROM_HDD_BANK.value != null) { Console.WriteLine("cafex run: HDD bank " + RUN_FROM_HDD_BANK.value + " will be attached to odd"); } } Console.WriteLine("cafex run: bridge parameters: " + BRIDGE_PARAMETERS.value); // Console.WriteLine("cafex run: bridge parameters with -e: " + BRIDGE_PARAMETERS_WITH_E.value); long os_version = HexHandler.GetLongNumberFromString(CAFERUN_COLDBOOT_OS_VERSION.value); CAFERUN_COLDBOOT_OS_VERSION.value = os_version.ToString("X").PadLeft(16, '0'); if (DEBUGGER.value == "multi" && CAFE_LAUNCH_DEBUG.value == "0" && ((CAFERUN_DISABLE_KILL_RESTART.value == null) || (CAFERUN_DISABLE_KILL_RESTART.value == "0")) && ((g_gArgValue == 1) || (CAFERUN_OPTION_SOFT_RESTART.value == "1"))) { CAFERUN_OPTION_KILL_RESTART.value = "1"; } else { CAFERUN_OPTION_KILL_RESTART.value = "0"; } if(g_KOptionSet) { CAFERUN_OPTION_KILL_RESTART.value = "1"; g_gArgValue = 1; } ret = new CafeXReturn(CAFEX_ERROR.OK); if (!PcfsTcpOnly) { HOSTSTOP_RVAL.value = "0"; Process[] fsEmulProcesses = Process.GetProcessesByName("FSEmul"); if ((CAFESTOP_ONLY_IF_FSEMUL.value == "0" || (fsEmulProcesses != null && fsEmulProcesses.Length > 0)) && CAFERUN_OPTION_KILL_RESTART.value == "0") { stop(null, true); if (HOSTSTOP_RVAL.value != "0") { Console.WriteLine("cafex run failed: Please check the device is connected, powered on, and not in use by another host PC."); return new CafeXReturn(CAFEX_ERROR.RUN_HOSTSTOP_RVAL_NON_ZERO); } } #if TIMER Log.WriteLine("Hostcheckversion start"); CafeXSetupTime.Report(); #endif ret.error = hostcheckversion(); #if TIMER Log.WriteLine("Hostcheckversion end"); CafeXSetupTime.Report(); #endif if (ret.error != CAFEX_ERROR.OK) { return ret; } } if (USE_EXI_AS_DEBUG_CHANNEL.value == null || USE_EXI_AS_DEBUG_CHANNEL.value.Equals("0")) { // use SDIO as debugger. Default is EXI DEBUG_FLAGS.value = (HexHandler.GetLongNumberFromString(DEBUG_FLAGS.value) | 256).ToString(); } uint syslog_level = HexHandler.GetNumberFromString(CAFE_SYSLOG_LEVEL.value); CAFE_SYSLOG_LEVEL.value = (syslog_level & 7).ToString(); PPC_OS_FLAGS.value = (HexHandler.GetNumberFromString(PPC_OS_FLAGS.value) | HexHandler.GetNumberFromString(HEARTBEAT_DISABLE.value) | HexHandler.GetNumberFromString(DEBUG_FLAGS.value) | (syslog_level << 9)).ToString(); PPC_APP_FLAGS.value = ((HexHandler.GetNumberFromString(PPC_OS_FLAGS.value) & 0x00000e70) | ((HexHandler.GetNumberFromString(PPC_OS_FLAGS.value) >> 1) & 0x80) | ((HexHandler.GetNumberFromString(PPC_OS_FLAGS.value) >> 6) & 0x02) | Convert.ToUInt32(((HexHandler.GetNumberFromString(PPC_OS_FLAGS.value) & 0xf) != 0))).ToString(); SYSTEM_XML.value = CAFE_SLC_DIR.value + "\\sys\\config\\system.xml"; if (CAFE_TEMP.value == null) { Console.WriteLine("cafex run failed: CAFE_TEMP environment variable is not set."); return new CafeXReturn(CAFEX_ERROR.RUN_NO_TEMP_VAR); } else { CAFERUN_WORK_DIR.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "caferun"; } create_directory_if_noexist(CAFERUN_WORK_DIR.value); if (SESSION_MANAGER.value == "1") { Console.WriteLine("cafex run: Using CAFE_CONTENT_DIR = " + CAFE_CONTENT_DIR.value); if (CAFERUN_OPTION_NO_DATA_SYNC.value == "0" && CAFERUN_OPTION_SOFT_RESTART.value == "0") { ret.error = syncsession (null); if (CAFEX_ERROR.OK != ret.error) { return ret; } CAFERUN_OPTION_NO_DATA_SYNC.value = "1"; } } if (CAFERUN_OPTION_SOFT_RESTART.value == "0") { create_directory_if_noexist(CAFE_SLC_DIR.value + "\\sys"); create_directory_if_noexist(CAFE_MLC_DIR.value); if (args.Length != 0 && args[0] != null) { if (DISC_EMU_TYPE.value == "hdd") { Console.WriteLine("cafex run: Specified rpx/elf file is used for setting title id from app.xml only"); } CAFE_ELF.value = PathConverter.Windowsify(args[0]); CAFE_ELF.value = PathConverter.Root(CAFE_ELF.value); if (SESSION_MANAGER.value == "1") { if (!File.Exists(CAFE_ELF.value)) { Console.WriteLine("cafex run failed: Cannot find rpx application in " + CAFE_ELF.value); return new CafeXReturn(CAFEX_ERROR.RUN_RPX_DOESNT_EXIST); } TMP_SUB_DIR.value = Path.GetFileNameWithoutExtension(args[0]); string CAFE_DATA_TMP_DOS = CAFE_DATA_TMP.value + "\\" + TMP_SUB_DIR.value; create_directory_if_noexist(CAFE_DATA_TMP_DOS); CAFE_ELF_SRC_DIR.value = Path.GetDirectoryName(CAFE_ELF.value); if (!string.Equals(CAFE_ELF_SRC_DIR.value, CAFE_DATA_TMP_DOS, StringComparison.InvariantCultureIgnoreCase)) { // Don't sync if we are running from the data/tmp folder as this is most-likely // a restart from the Multi debugger. If not, the files are still ok as they were // from a previous sync. // SYNCTOOL_CFG.value = CAFE_ROOT.value + "\\system\\bin\\tool\\synctool.code.xml"; SYNCTOOL_LOG.value = CAFE_DATA_TMP.value + "\\synctool.log"; int SYNCTOOL_RVAL = synctool.sync(SYNCTOOL_CFG.value, CAFE_ELF_SRC_DIR.value, CAFE_DATA_TMP_DOS, SYNCTOOL_LOG.value); if (SYNCTOOL_RVAL != 0) { Console.WriteLine(" : Session data sync FAILED with exit code {0}!", SYNCTOOL_RVAL); Console.WriteLine(" : See {0} for details.", SYNCTOOL_LOG.value); return new CafeXReturn(CAFEX_ERROR.SYNCTOOL_FAILED); } } CAFE_ELF.value = string.Format("{0}\\{1}\\{2}", CAFE_DATA_TMP.value, TMP_SUB_DIR.value, Path.GetFileName(args[0])); } switch (Path.GetExtension(CAFE_ELF.value)) { case ".elf": { DEBUG_ELF_FILE.value = CAFE_ELF.value; string rpx = Path.ChangeExtension(CAFE_ELF.value, "rpx"); if (File.Exists(rpx)) { CAFE_ELF.value = rpx; } break; } case ".rpx": { if (DEBUG_ELF_FILE.value == null) { string elf = Path.ChangeExtension(CAFE_ELF.value, "elf"); if (File.Exists(elf)) { DEBUG_ELF_FILE.value = elf; } } break; } } if (!CAFE_ELF.value.EndsWith(".rpx")) { Console.WriteLine("cafex run failed: Please provide rpx application as first argument after run_options"); run_usage(); return new CafeXReturn(CAFEX_ERROR.RUN_NO_RPX_SPECIFIED); } if (!File.Exists(CAFE_ELF.value)) { Console.WriteLine("cafex run failed: Cannot find rpx application in " + CAFE_ELF.value); return new CafeXReturn(CAFEX_ERROR.RUN_RPX_DOESNT_EXIST); } CAFE_ELF_DIR.value = Path.GetDirectoryName(CAFE_ELF.value); create_directory_if_noexist(CAFE_CONTENT_DIR.value); create_directory_if_noexist(CAFE_META_DIR.value); create_directory_if_noexist(CAFE_SAVE_DIR.value); CAFE_CODE_DIR.value = CAFE_ELF_DIR.value; APP_XML_FILE.value = CAFE_CODE_DIR.value + "\\app.xml"; if (!update_app_xml(APP_XML_FILE.value)) { return new CafeXReturn(CAFEX_ERROR.RUN_UPDATE_APP_XML_FAILED); } COS_XML_FILE.value = CAFE_CODE_DIR.value + "\\cos.xml"; if (!update_cos_xml(COS_XML_FILE.value, PPC_APP_FLAGS.value)) { return new CafeXReturn(CAFEX_ERROR.RUN_UPDATE_COS_XML_FAILED); } META_XML_FILE.value = CAFE_META_DIR.value + "\\meta.xml"; CAFEX_ERROR update_meta_ret = update_meta_xml(META_XML_FILE.value); if (update_meta_ret != CAFEX_ERROR.OK) { return new CafeXReturn(update_meta_ret); } if (!update_arglist(COS_XML_FILE.value, CAFE_ELF.value, args, passedArgumentsWithDashA)) { return new CafeXReturn(CAFEX_ERROR.RUN_UPDATE_ARGLIST_FAILED); } update_boot_logos(CAFE_META_DIR.value); if (RPL_DIRS.value != null) { string[] rpl_dirs = RPL_DIRS.value.Split(DEFAULT_DELIMITER); foreach (string s in rpl_dirs) { string dir = PathConverter.Windowsify(s); string[] contained_files = Directory.GetFiles(dir, "*.rpl"); if (contained_files.Length == 0) { Console.WriteLine("cafex run : WARNING - No files found in directory {0}.", dir); } else { foreach (string origin in contained_files) { string destination = CAFE_CODE_DIR.value + "\\" + Path.GetFileName(origin); Console.WriteLine("cafex run: copy {0} to {1}", origin, destination); File.Copy(origin, destination, true); } } } } if (RPL_FILES.value != null) { string[] rpl_files = RPL_FILES.value.Split(DEFAULT_DELIMITER); foreach (string s in rpl_files) { string file = PathConverter.Windowsify(s); if (File.Exists(file)) { string destination = CAFE_CODE_DIR.value + "\\" + Path.GetFileName(s); Console.WriteLine("cafex run: copy {0} to {1}", file, destination); File.Copy(file, destination, true); } } } } if (CAFERUN_INS.value == "0") { #if DEBUG Log.WriteLine("CAFEX: Writing data to {0}\\previous_launch_info.xml", CAFERUN_WORK_DIR.value); #endif FileStream previous_info_file = new FileStream(CAFERUN_WORK_DIR.value + "\\" + "previous_launch_info.xml", FileMode.Create); StreamWriter writer = new StreamWriter(previous_info_file); writer.WriteLine(""); writer.WriteLine(""); if (!string.IsNullOrEmpty(CAFERUN_OPTION_MLC_EMU_LAUNCH.value) && CAFERUN_OPTION_MLC_EMU_LAUNCH.value == "1") { writer.WriteLine(" " + CAFERUN_OPTION_MLC_EMU_TITLEID.value + ""); } else { writer.WriteLine(" " + CAFE_CODE_DIR.value + ""); writer.WriteLine(" " + DISC_EMU_TYPE.value + ""); writer.WriteLine(" " + RUN_FROM_HDD_BANK.value + ""); writer.WriteLine(" " + DISC_EMU_TID.value + ""); } writer.WriteLine(" " + CAFERUN_COLDBOOT_OS_VERSION.value + ""); writer.WriteLine(" " + CAFERUN_OPTION_FAST_RELAUNCH.value + ""); writer.WriteLine(""); writer.Flush(); writer.Close(); } CAFEX_ERROR updateResult = update_system_xml(SYSTEM_XML.value, PPC_OS_FLAGS.value, SYSTEM_MODE.value, MCP_LAUNCH_HINT.value); if (updateResult != CAFEX_ERROR.OK) { return new CafeXReturn(updateResult); } } else { if (!File.Exists(SYSTEM_XML.value)) { Console.WriteLine("cafex run failed: Please cafex run an rpx application first"); return new CafeXReturn(CAFEX_ERROR.RUN_DASH_R_WITH_NO_PREVIOUS_LAUNCH_INFO); } string prev_info_file = CAFERUN_WORK_DIR.value + "\\" + "previous_launch_info.xml"; CAFERUN_OPTION_FAST_RELAUNCH.value = XmlHandler.GetNodeValue(prev_info_file, "fast_relaunch"); CAFERUN_OPTION_MLC_EMU_TITLEID.value = XmlHandler.GetNodeValue(prev_info_file, "emu_tid"); if (!string.IsNullOrEmpty(CAFERUN_OPTION_MLC_EMU_TITLEID.value)) { CAFERUN_OPTION_MLC_EMU_LAUNCH.value = "1"; CAFERUN_COLDBOOT_OS_VERSION.value = XmlHandler.GetNodeValue(SYSTEM_XML.value, "default_os_id"); } else { CAFE_CODE_DIR.value = XmlHandler.GetNodeValue(prev_info_file, "code_dir"); DISC_EMU_TYPE.value = XmlHandler.GetNodeValue(prev_info_file, "disc_emu"); RUN_FROM_HDD_BANK.value = XmlHandler.GetNodeValue(prev_info_file, "hdd_bank"); DISC_EMU_TID.value = XmlHandler.GetNodeValue(prev_info_file, "disc_emu_tid"); PREV_CAFE_ARGSTR.value = XmlHandler.GetNodeValue(CAFE_CODE_DIR.value + "\\cos.xml", "argstr"); // Check "argstr" length to make sure it is less than 4096. if (!string.IsNullOrEmpty(PREV_CAFE_ARGSTR.value) && PREV_CAFE_ARGSTR.value.Length >= CAFE_ARGSTR_MAX_LENGTH) { Console.WriteLine("cafex run failed: argstr value in cos.xml is greater than or equal to 4096 characters. Please shorten the argstr and retry."); return new CafeXReturn(CAFEX_ERROR.RUN_UPDATE_ARGLIST_FAILED); } CAFE_ELF.value = CAFE_CODE_DIR.value + "\\" + PREV_CAFE_ARGSTR.value.Split(' ')[0]; CAFERUN_COLDBOOT_OS_VERSION.value = XmlHandler.GetNodeValue(prev_info_file, "coldboot_os"); if (string.IsNullOrEmpty(CAFERUN_COLDBOOT_OS_VERSION.value)) { CAFERUN_COLDBOOT_OS_VERSION.value = XmlHandler.GetNodeValue(SYSTEM_XML.value, "default_os_id"); } if (DISC_EMU_TYPE.value != "hdd") { if (!File.Exists(CAFE_ELF.value)) { Console.WriteLine("cafex run failed: Could not find " + CAFE_ELF.value); return new CafeXReturn(CAFEX_ERROR.RUN_DASH_R_CANT_FIND_APPLICATION); } Console.WriteLine("cafex run: Restarting " + CAFE_ELF.value); } } } // Set up the title to be run in Eco mode. If we are not in ECO mode make sure to remove the node from system.xml if (ECO_MODE.value == "1") { string default_title_id; default_title_id = XmlHandler.GetNodeValue(SYSTEM_XML.value, "default_title_id"); if (XmlHandler.NodeExists(SYSTEM_XML.value, "default_eco_title_id")) { XmlHandler.UpdateNodeValue(SYSTEM_XML.value, "default_eco_title_id", default_title_id); } else { XmlHandler.AddNode(SYSTEM_XML.value, "default_eco_title_id", default_title_id, new string[4] { "type", "hexBinary", "length", "8" }); } } else { if (XmlHandler.NodeExists(SYSTEM_XML.value, "default_eco_title_id")) { XmlHandler.RemoveNode(SYSTEM_XML.value, "default_eco_title_id"); } } if (CAFE_BOOT_MODE.value == "PCFS") { string os_directory = string.Format("{0}\\sys\\title\\{1}\\{2}\\code", CAFE_SLC_DIR.value, CAFERUN_COLDBOOT_OS_VERSION.value.Substring(0,8), CAFERUN_COLDBOOT_OS_VERSION.value.Substring(8,8)); if (!Directory.Exists(os_directory)) { Console.WriteLine("cafex run failed: Cannot find OS in " + os_directory); return new CafeXReturn(CAFEX_ERROR.RUN_CANT_FIND_OS_DIRECTORY); } string[] files = Directory.GetFiles(os_directory); bool found_rpl = false; foreach (string s in files) { if (s.EndsWith(".rpl")) { found_rpl = true; break; } } if (!found_rpl) { CAFERUN_OS_VERSION_PARTIAL_UNIQUE_ID.value = (HexHandler.GetLongNumberFromString("0x" + CAFERUN_COLDBOOT_OS_VERSION.value) >> 8 & 0xff).ToString(); uint value = HexHandler.GetNumberFromString(CAFERUN_OS_VERSION_PARTIAL_UNIQUE_ID.value); if (value >= 192) { Console.WriteLine("cafex run failed: Please build FDEBUG os version " + CAFERUN_COLDBOOT_OS_VERSION.value); } else if (value >= 128) { Console.WriteLine("cafex run failed: Please build DEBUG os version " + CAFERUN_COLDBOOT_OS_VERSION.value); Console.WriteLine(" or do not use \"cafex run -b\" to use NDEBUG version"); } else if (value >= 64) { Console.WriteLine("cafex run failed: Please build NDEBUG os version " + CAFERUN_COLDBOOT_OS_VERSION.value); Console.WriteLine(" or use \"cafex run -b\" to use the DEBUG version"); } else if ((HexHandler.GetLongNumberFromString("0x" + CAFERUN_COLDBOOT_OS_VERSION.value) & 0xFF) == 0xFE) { Console.WriteLine("cafex run failed: Please build OS_SECURITY_LEVEL os version " + CAFERUN_COLDBOOT_OS_VERSION.value); } else { Console.WriteLine("cafex run failed: Non-standard titleId for os version " + CAFERUN_COLDBOOT_OS_VERSION.value); } return new CafeXReturn(CAFEX_ERROR.RUN_OS_NOT_PRESENT); } } if (PCFS_SRV_LOG_DIR.value == null) { PCFS_SRV_LOG_OUTPUT.value = "/dev/null"; } else { PCFS_LOG_TIMESTAMP.value = DateTime.Now.ToString("HHmmss"); PCFS_SRV_LOG_OUTPUT.value = string.Format("{0}\\{1}pcfs_{2}.txt", PCFS_SRV_LOG_DIR.value, SESSION_PATH_PREFIX.value, PCFS_LOG_TIMESTAMP.value); PCFS_SRV_LOG_OUTPUT.value = PathConverter.Windowsify(PCFS_SRV_LOG_OUTPUT.value); Console.WriteLine("PCFS output logged to " + PCFS_SRV_LOG_OUTPUT.value); } if (DISC_EMU_TYPE.value == "hdd" || ((!string.IsNullOrEmpty(CAFE_ELF.value)) && CAFE_ELF.value.EndsWith(".rpx"))) { if (DISC_EMU_TYPE.value == "hfio") { MAPDIR_MLC.value = CAFE_MLC_DIR.value + "/"; MAPDIR_SLC.value = CAFE_SLC_DIR.value + "/"; MAPDIR_CODE.value = CAFE_CODE_DIR.value + "/"; MAPDIR_META.value = CAFE_META_DIR.value + "/"; MAPDIR_CONTENT.value = CAFE_CONTENT_DIR.value + "/"; MAPDIR_SAVE.value = CAFE_SAVE_DIR.value + "/"; PCFS_DIR_MAPPING.value = "-m /%MLC_EMU_DIR/ \"" + MAPDIR_MLC.value + "\"" + " -m /%SLC_EMU_DIR/ \"" + MAPDIR_SLC.value + "\"" + " -m /%DISC_EMU_DIR/code/ \"" + MAPDIR_CODE.value + "\"" + " -m /%DISC_EMU_DIR/meta/ \"" + MAPDIR_META.value + "\"" + " -m /%DISC_EMU_DIR/content/ \"" + MAPDIR_CONTENT.value + "\"" + " -m /%DISC_EMU_DIR/save/ \"" + MAPDIR_SAVE.value + "\""; } else { MAPDIR_MLC.value = CAFE_MLC_DIR.value + "/"; MAPDIR_SLC.value = CAFE_SLC_DIR.value + "/"; MAPDIR_SAVE.value = CAFE_SAVE_DIR.value + "/"; PCFS_DIR_MAPPING.value = "-m /%MLC_EMU_DIR/ \"" + MAPDIR_MLC.value + "\"" + " -m /%SLC_EMU_DIR/ \"" + MAPDIR_SLC.value + "\"" + " -m /%SAVE_EMU_DIR/ \"" + MAPDIR_SAVE.value + "\""; } } else if (CAFERUN_OPTION_MLC_EMU_LAUNCH.value == "1") { MAPDIR_MLC.value = CAFE_MLC_DIR.value + "/"; MAPDIR_SLC.value = CAFE_SLC_DIR.value + "/"; PCFS_DIR_MAPPING.value = "-m /%MLC_EMU_DIR/ \"" + MAPDIR_MLC.value + "\"" + " -m /%SLC_EMU_DIR/ \"" + MAPDIR_SLC.value + "\""; } else { MAPDIR_MLC.value = CAFE_MLC_DIR.value + "/"; MAPDIR_SLC.value = CAFE_SLC_DIR.value + "/"; PCFS_DIR_MAPPING.value = "-m /%MLC_EMU_DIR/ \"" + MAPDIR_MLC.value + "\"" + " -m /%SLC_EMU_DIR/ \"" + MAPDIR_SLC.value + "\""; } ELF_NEST_OPT.value=""; ELF_NEST_VALUE.value = ""; if (ALLOW_DISCRUN_IN_SOFTLAUNCH.value == "1") { // the DLF will not be used now - but it has to be made now, // as this is the point where all input environment variables are set correctly // for cafedevrun.sh to run bootrun(new List() {"-makedlf"} , fAppTypeDefined); if (string.IsNullOrEmpty(BRIDGE_PARAMETERS_WITH_E.value) || !BRIDGE_PARAMETERS_WITH_E.value.Contains("soft_launch_cafe_elf")) { if (!string.IsNullOrEmpty(CAFE_ELF.value)) { // we didn't get the ELF name from above. So we must to decide what it is. ELF_NEST_OPT.value = "-e"; ELF_NEST_VALUE.value = "soft_launch_cafe_elf:" + CAFE_ELF.value; // Since there is no way to communicate new DLF contents into an existing FSEmul, // we need a forceful restart for this case - even though it is softlaunch CAFE_RUN_FORCERESTART.value = "1"; } } } // Bug 9826: Watch for magic token from IOS signifying crash if (Environment.GetEnvironmentVariable("CAFERUN_OPTION_IGNORE_CRASH_TOKEN") == null || Environment.GetEnvironmentVariable("CAFERUN_OPTION_IGNORE_CRASH_TOKEN").Trim() != "0") { { Func callback = StartProcessOnCrashdump; cattoucan.AddNotification(IOS_CRASHDUMP_TOKEN, callback); } } CAFERUN_INS.value = "1"; CMD_RESULT.value = "0"; if (CAFERUN_OPTION_SOFT_LAUNCH.value == "1" || (CAFERUN_OPTION_KILL_RESTART.value == "1" && ((CAFERUN_DISABLE_KILL_RESTART.value == null) || (CAFERUN_DISABLE_KILL_RESTART.value == "0")))) { CafeBootProgress progress = new CafeBootProgress(); if (CAFE_RUN_FORCERESTART.value == "1") { Console.WriteLine("**** FORCE REBOOT ****"); g_KOptionSet = false; g_gArgValue = 0; CAFERUN_OPTION_KILL_RESTART.value = "0"; progress.stage = bootCatDev(); CAFERUN_OPTION_SOFT_LAUNCH.value = "1"; } else if (CAFERUN_OPTION_KILL_RESTART.value == "1" && ((CAFERUN_DISABLE_KILL_RESTART.value == null) || (CAFERUN_DISABLE_KILL_RESTART.value == "0")) && ((g_gArgValue == 1) || (CAFERUN_OPTION_SOFT_RESTART.value == "1"))) { //Try executing kill restart operation. //COS restarts the current running application/title if (Program.CAFE_PROFILE.value != null && Program.CAFE_PROFILE.value == "1") { CafeXEventtLog.Instance.WriteToEventLog(562, DateTime.Now, EventStatus.BEGIN, EventProcess.CAFEX, "System is doing KILL RESTART"); } #if TIMER Log.WriteLine("SendKillRestartAndResponse start"); CafeXSetupTime.Report(); #endif g_KOptionSet = cosdebug.SendKillRestartAndResponse(Convert.ToInt32(SESSION_NET_MANAGE_PORT.value), COSDEBUG_KILLRESTART_RETRIES, COSDEBUG_KILLRESTART_TIMEOUT, COSDEBUG_KILLRESTART_DELAY); #if TIMER Log.WriteLine("SendKillRestartAndResponse end"); CafeXSetupTime.Report(); #endif // We're going to cold boot if g_KOptionSet was // set to false, clear these values regardless CAFERUN_OPTION_KILL_RESTART.value = "0"; g_gArgValue = 0; // Check if we don't want to use softlaunch if (!g_KOptionSet && !progress.checkKillRestartSoftlaunch()) { // Boot run if PCFS if (CAFE_BOOT_MODE.value == "PCFS" && CAFERUN_OPTION_SOFT_LAUNCH.value != "1") { ret.error = startBootRun(isWumadExecution, launch, true); if (ret.error != CAFEX_ERROR.OK || !launch) { return ret; } // Causes execution to jump to output g_KOptionSet = true; } else { // Cold boot to sysconfig when in NAND progress.stage = bootCatDev(); progress.waitForTitle = true; } } } else { // Ensure that the K flag is cleared g_KOptionSet = false; CAFERUN_OPTION_KILL_RESTART.value = "0"; if (EjectStateOverride || FastEjectStateSupported()) { SetEjectState(); } } if (CMD_RESULT.value == "0" && !g_KOptionSet) { for (progress.tries = 0; progress.tries < CAFERUN_RETRY_COUNT; ++progress.tries) { switch (progress.stage) { case CafeBootStage.Off: case CafeBootStage.ServerSync: #if DEBUG Log.WriteLine("Iteration #{0} of {1}", progress.tries + 1, CAFERUN_RETRY_COUNT); #endif PCFS_SYNC_DATE.value = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-ffff"); Console.WriteLine("Launching {0} @ sync date [{1}]", Path.GetFileName(CAFE_ELF.value), PCFS_SYNC_DATE.value); #if TIMER CafeXSetupTime.Report(); #endif CMD_RESULT.value = PCFSServerSync.sync(PCFS_SYNC_DATE.value, CAFE_ELF.value, PCFS_DIR_MAPPING.value).ToString(); #if DEBUG Log.WriteLine("PCFSServerSync process returned '{0}' from execution.", CMD_RESULT.value); #endif if (CanAutoLaunchOnCatR()) { return new CafeXReturn(LaunchTitleOnCatR(true)); } else if(PcfsTcpOnly) { Console.WriteLine(); Console.WriteLine("Serial port autolaunch is disabled"); Console.WriteLine("To autolaunch, specify the '-debugport ' option"); Console.WriteLine(); Console.WriteLine("Cycle the power button on your CAT-R and launch from System Config Tool > Title Launcher"); return new CafeXReturn(CAFEX_ERROR.RUN_LAUNCH_FAILED); } #if TIMER Log.WriteLine("PCFSServerSync end"); CafeXSetupTime.Report(); #endif if (CMD_RESULT.value != "0") { // Return error if we already booted if (progress.Active) { ret.error = CAFEX_ERROR.RUN_PCFSSERVER_SYNC_FAILED; } else if (tryCafeReboot(launch, isWumadExecution, progress, out ret.error)) { continue; } return ret; } if (CAFERUN_OPTION_FAST_RELAUNCH.value == "1") { progress.checkPower = false; progress.stage = CafeBootStage.SendingFlags; goto case CafeBootStage.SendingFlags; } cattoucan.BeginBootSync(); progress.stage = CafeBootStage.SendingSync1; goto case CafeBootStage.SendingSync1; case CafeBootStage.SendingSync1: // Try an initial sync request if (!trySyncRequest()) { /* Sending the request failed * Check the power if we did not cold boot */ progress.checkVDD2(); // If we are running, try sending requests if (progress.Active) { int i = 1; for (; i < CAFERUN_RETRY_COUNT; ++i) { if (trySyncRequest()) { // Sending the sync was successful break; } } // Check if not successful if (i > CAFERUN_LAST_RETRY) { // Check if this is the initial check if (!progress.checkPower) { /* This is in a reboot process * break loop and report error */ progress.tries = CAFERUN_RETRY_COUNT; continue; } // Reboot CAT-DEV progress.stage = CafeBootStage.Off; } } // Check if we need to reboot CAT-DEV if (!progress.Active) { if (tryCafeReboot(launch, isWumadExecution, progress, out ret.error)) { continue; } return ret; } } // Sync success, go to next stage progress.checkPower = false; progress.stage = CafeBootStage.WaitingForSync1; goto case CafeBootStage.WaitingForSync1; case CafeBootStage.SendingSync2: if (trySyncRequest()) { progress.stage = CafeBootStage.WaitingForSync2; goto case CafeBootStage.WaitingForSync2; } continue; case CafeBootStage.WaitingForSync1: case CafeBootStage.WaitingForSync2: // Wait for devkit message to respond if (!cattoucan.SyncWithBoot(DEVKIT_HELP_RESPONSE_TIMEOUT)) { CMD_RESULT.value = "1"; continue; } CMD_RESULT.value = "0"; if (progress.stage == CafeBootStage.WaitingForSync2) { cattoucan.FinishSync(!progress.waitForTitle && quiet_mode); progress.stage = CafeBootStage.Booted; break; } progress.stage = CafeBootStage.SendingFlags; goto case CafeBootStage.SendingFlags; case CafeBootStage.SendingFlags: #if DEBUG Log.WriteLine("setting cosflags now."); #endif // Set the COS flags CMD_RESULT.value = set_system_xml_cos_flags(PPC_OS_FLAGS.value).ToString(); if (CMD_RESULT.value == "0") { if (CAFERUN_OPTION_FAST_RELAUNCH.value == "1") { progress.stage = CafeBootStage.Booted; break; } progress.stage = CafeBootStage.SendingSync2; goto case CafeBootStage.SendingSync2; } cattoucan.FinishSync(true); // Return error if we already booted if (progress.Active) { ret.error = CAFEX_ERROR.RUN_UPDATE_SYSTEM_XML_FAILED; } else if (tryCafeReboot(launch, isWumadExecution, progress, out ret.error)) { continue; } return ret; } #if DEBUG Log.WriteLine(command + " trying softlaunch now."); #endif // discrun support. // This is softlaunch, and there is no RPS specified. // try to see if we can get it from the user - in case it applies if (string.IsNullOrEmpty(DISC_EMU_TID.value)) { if (CAFERUN_OPTION_MLC_EMU_LAUNCH.value == "1") { DISC_EMU_TID.value = (!string.IsNullOrEmpty(CAFERUN_OPTION_MLC_EMU_TITLEID.value) && CAFERUN_OPTION_MLC_EMU_TITLEID.value.Length == 16) ? "0x" + CAFERUN_OPTION_MLC_EMU_TITLEID.value : CAFERUN_OPTION_MLC_EMU_TITLEID.value; Console.WriteLine("HDD emulation: using command line TID {0}", DISC_EMU_TID.value); } else if (!string.IsNullOrEmpty(CAFE_WUMAD.value) && !string.IsNullOrEmpty(CAFERUN_WUMAD_TITLE_ID.value)) { // Check if a WUMAD was provided and see if title id is available DISC_EMU_TID.value = CAFERUN_WUMAD_TITLE_ID.value; Console.WriteLine("HDD WUMAD emulation: using command line TID {0}", DISC_EMU_TID.value); } } // still not set despite our attempts? if (string.IsNullOrEmpty(DISC_EMU_TID.value)) { Console.WriteLine("cafex run failed: Unable to determine title ID, and it was not specified in the command line."); return new CafeXReturn(CAFEX_ERROR.RUN_DISCRUN_NAND_UNABLE_TO_FIND_APPLICATION); } // this is to phase in adoption smoothly into autotest, // avoiding any changes to tests other than cafediscrun. // We may disable this check later. if (ALLOW_DISCRUN_IN_SOFTLAUNCH.value == "1") { CMD_RESULT.value = "0"; if (!string.IsNullOrEmpty(SYSTEM_MODE.value)) { if (SYSTEM_MODE.value.ToLowerInvariant().Equals("prod")) { Console.WriteLine("Setting mode to 0"); devkitmsg.sys_mode_prod(); } else if (SYSTEM_MODE.value.ToLowerInvariant().Equals("dev")) { Console.WriteLine("Setting mode to 1"); devkitmsg.sys_mode_dev(); } else if (SYSTEM_MODE.value.ToLowerInvariant().Equals("test")) { Console.WriteLine("Setting mode to 2"); devkitmsg.sys_mode_test(); } } } if (CAFERUN_OPTION_FAST_RELAUNCH.value == "1") { #if false string COSDEBUG_TID_HI = CAFERUN_OPTION_MLC_EMU_TITLEID.value.Substring(2, 8); string COSDEBUG_TID_LO = CAFERUN_OPTION_MLC_EMU_TITLEID.value.Substring(10, 8); cosdebug.launch_retry(Convert.ToInt32(SESSION_NET_MANAGE_PORT.value), COSDEBUG_TID_HI, COSDEBUG_TID_LO, Convert.ToInt32(CAFERUN_OPTION_FASTLAUNCH_RETRIES.value), Convert.ToInt32(CAFERUN_OPTION_FASTLAUNCH_TIMEOUT.value), Convert.ToInt32(CAFERUN_OPTION_FASTLAUNCH_DELAY.value)); if (Program.CAFE_PROFILE.value != null && Program.CAFE_PROFILE.value == "1") { CafeXEventtLog.Instance.WriteToEventLog(562, "[" + DateTime.Now.ToString("HH:mm:ss:fff") + "] [BEGIN] [CafeX]" + " System is doing FAST RELAUNCH"); } if (quiet_mode) { // We need to start cattoucan to get our events and syncronize the launch CATTOUCAN_TERM.value = Nintendo.SDSG.CatToucan.Terms.KI_PIREPARE_TITLE_ASYNC; cattoucan.start(true, true, false); cosdebug.stop_retry(COSDEBUG_FASTLAUNCH_TIMEOUT); } #endif if (cosdebug.try_launch(CAFERUN_OPTION_MLC_EMU_TITLEID.value, 2)) { break; } } else { if (Program.CAFE_PROFILE.value != null && Program.CAFE_PROFILE.value == "1") { CafeXEventtLog.Instance.WriteToEventLog(552, DateTime.Now, EventStatus.BEGIN, EventProcess.CAFEX, "System is doing title soft launch"); } if (progress.waitForTitle) { cattoucan.BeginTitleSoftSync(); } if (MCP_LAUNCH_HINT.value != null) { CMD_RESULT.value = devkitmsg.title_softlaunch_with_hint(CAFERUN_COLDBOOT_OS_VERSION.value, DISC_EMU_TID.value, MCP_LAUNCH_HINT.value, SESSION_LAUNCH_CTRL_PORT.value).ToString(); } else { CMD_RESULT.value = devkitmsg.title_softlaunch(CAFERUN_COLDBOOT_OS_VERSION.value, DISC_EMU_TID.value, SESSION_LAUNCH_CTRL_PORT.value).ToString(); } if (CMD_RESULT.value == "0") { // Break loop if not attempting to synchronize if (!progress.waitForTitle) { break; } // Try sending help messages int i = 0; for (; i < CAFERUN_RETRY_COUNT; ++i) { // Break loop if successfully sent if (devkitmsg.help(DEVKIT_HELP_REQUEST_TIMEOUT) == 0) { break; } } // If it was successful, sync with the title launching keyword if (i < CAFERUN_RETRY_COUNT && cattoucan.SyncWithTitle(Program.KILLRESTART_SOFTLAUNCH_TIMEOUT, false)) { break; } Console.WriteLine("cafex {0}: Timeout waiting for title launch", command); } } if (!progress.waitForTitle) { CMD_RESULT.value = "1"; } else if (!tryCafeReboot(launch, isWumadExecution, progress, out ret.error)) { return ret; } } } if (CMD_RESULT.value != "0") { cattoucan.FinishSync(true); Console.WriteLine("Failed to launch application"); ret.error = CAFEX_ERROR.RUN_LAUNCH_FAILED; return ret; } } else { // Prevent unneeded trips, check if single trip eject is supported if (FastEjectStateSupported()) { DefaultEjectState(); if (!string.IsNullOrEmpty(EJECT_STATE.value)) { Console.WriteLine("cafex run: Setting disc eject state when CAT-DEV boots."); } Environment.SetEnvironmentVariable(ENV_DISC_EJECT_STATE, EJECT_STATE.value); ClearEjectState(); } else if (EjectStateOverride) { SetEjectState(); } if (IsBooting) { cattoucan.BeginMenuSync(); } ret.error = startBootRun(isWumadExecution, launch, false); if (ret.error != CAFEX_ERROR.OK) { cattoucan.FinishSync(true); return ret; } if (CanAutoLaunchOnCatR()) { return new CafeXReturn(LaunchTitleOnCatR(false)); } else if(PcfsTcpOnly) { Console.WriteLine(); Console.WriteLine("Serial port autolaunch is disabled"); Console.WriteLine("To autolaunch, specify the '-debugport ' option"); Console.WriteLine(); Console.WriteLine("Power on your CAT-R and launch from System Config Tool > Title Launcher"); return new CafeXReturn(CAFEX_ERROR.OK); } if (IsBooting) { // We need to make sure system boots successfully cattoucan.SyncWithMenu(); return ret; } } if (!PcfsTcpOnly) { ret = connect_serial_or_debugger(quiet_mode); } else { ret = new CafeXReturn(CAFEX_ERROR.OK); } return ret; } #endregion /// /// Determines if the system is properly configured to launch a title on CAT-R. /// /// True if a launch can be attempted, otherwise false. private static bool CanAutoLaunchOnCatR() { return PcfsTcpOnly && !string.IsNullOrEmpty(DebugSerialPort); } /// /// Attemps to launch a title on the CAT-R. Needs to have -pcfsonly /// and -debugport flags set in CLI. /// /// /// If true, indicates to peform a warm reboot on the system and launch a different title. /// False will wait for sysconfig and launch at that point; generally used during a cold boot. /// /// An error code. private static CAFEX_ERROR LaunchTitleOnCatR(bool slowLaunch) { if (!CanAutoLaunchOnCatR()) { return CAFEX_ERROR.RUN_LAUNCH_FAILED; } var titleId = XmlHandler.GetNodeValue(APP_XML_FILE.value, "title_id"); if (string.IsNullOrEmpty(titleId)) { Console.WriteLine("Title Id not found. Try to launch manually through the System Config Tool."); return CAFEX_ERROR.RUN_TITLE_ID_REQUIRED; } Serial.Device.DisplayOutput = true; if (slowLaunch) { Serial.Device.Start(DebugSerialPort) .LaunchTitleSlow(SYSCONFIGTOOL_TITLE_ID) .WaitForSystemConfigTool() .LaunchTitle(titleId) .WaitForMessage(Serial.Messages.AcpInitialized) .Stop(); } else { Serial.Device.Start(DebugSerialPort) .PrintMessage("Power on your CAT-R") .WaitForSystemConfigTool() .LaunchTitle(titleId) .WaitForMessage(Serial.Messages.AcpInitialized) .Stop(); } return CAFEX_ERROR.OK; } private struct WumadInfo { public bool titleFound; public string titleId; public string appXml; public string cosXml; public string metaXml; } private static CAFEX_ERROR TryGetWumadInfo(string wumadTempDir, ref WumadInfo info) { string[] metaFiles = Directory.GetFiles(wumadTempDir, "*metaxml.bin"); string[] appFiles = Directory.GetFiles(wumadTempDir, "*appxml.bin"); string[] cosFiles = Directory.GetFiles(wumadTempDir, "*cosxml.bin"); // User provided title. string titleId = string.Empty; if (!string.IsNullOrEmpty(CAFERUN_WUMAD_TITLE_ID.value)) { titleId = CAFERUN_WUMAD_TITLE_ID.value.StartsWith("0x") ? CAFERUN_WUMAD_TITLE_ID.value.Substring(2).ToLowerInvariant() : CAFERUN_WUMAD_TITLE_ID.value.ToLowerInvariant(); } info.titleFound = false; if (metaFiles.Length == 1) { // The wumad has only one title string singleTitleId = XmlHandler.GetNodeValue(appFiles[0], "title_id"); if (string.IsNullOrEmpty(titleId) || titleId.Equals("ffffffffffffffff") || titleId.Equals(singleTitleId) ) { // Empty-> auto discovery *OR* // Value-> matches user input info.titleFound = true; info.titleId = singleTitleId; info.metaXml = metaFiles[0]; info.appXml = appFiles[0]; info.cosXml = cosFiles[0]; } else { // We need to respect the title give by the user, // but provide a warning that it didn't match. if (!IsTitleIdReserved(titleId)) { Console.WriteLine("cafex bootrun: WARNING: Unable to find title {0} in the wumad.", titleId); } return CAFEX_ERROR.RUN_BAD_TITLE_ID; } } else { // The wumad has multiple files... need to know the title id if (string.IsNullOrEmpty(titleId) || titleId.Equals("ffffffffffffffff")) { Console.WriteLine("cafex bootrun failed: Multiple titles found in wumad. Either RPX or TitleId is required to select the title to run."); return CAFEX_ERROR.RUN_TITLE_ID_REQUIRED; } // If in NAND/softlaunch mode, we shouldn't validate the title id, since // the user may really want to launch a title there is not inside the wumad. // However, we should alert the user that the title was not found, and also // not search for if we already know it is the sysconfigtool title id. if (!IsTitleIdReserved(titleId)) { // Only looking if it's not a system/reserved titleid. int targetIndex = 0; for (targetIndex = 0; targetIndex < appFiles.Length; ++targetIndex) { string wumadTitle = XmlHandler.GetNodeValue(appFiles[targetIndex], "title_id").ToLowerInvariant(); Console.WriteLine("cafex run : wumad title {0} found and comparing to {1}.", wumadTitle, titleId); if (wumadTitle.Equals(titleId)) { info.titleId = titleId; info.titleFound = true; break; } } if (!info.titleFound) { Console.WriteLine("cafex bootrun: WARNING: Unable to find title {0} in the wumad.", titleId); return CAFEX_ERROR.RUN_BAD_TITLE_ID; } info.metaXml = metaFiles[targetIndex]; info.appXml = appFiles[targetIndex]; info.cosXml = cosFiles[targetIndex]; } } return CAFEX_ERROR.OK; } private static bool IsTitleIdReserved(string fullTitleInHex) { // Reserved range: //0x00000 Through 0x000FF -> 0 <= TID <= 255 //0xF7000 Through 0xF7FFF -> 1011712 <= TID <= 1015807 uint badRangeMaxA = HexHandler.GetNumberFromString("0xff"); uint badRangeMinB = HexHandler.GetNumberFromString("0xf7000"); uint badRangeMaxB = HexHandler.GetNumberFromString("0xf7fff"); if (string.IsNullOrEmpty(fullTitleInHex)) { // Empty title shouldn't be used, so it is reserved! return true; } string titleId = fullTitleInHex.StartsWith("0x") ? fullTitleInHex.Substring(2).ToLowerInvariant() : fullTitleInHex.ToLowerInvariant(); // Need to get the following digits of the title: 000500001XXXXX00 The five "X" hex values represent the Unique Id. string uniqueId = "0x" + titleId.Substring(9, 5); uint uniqueIdValue = HexHandler.GetNumberFromString(uniqueId); if (uniqueIdValue <= badRangeMaxA || (uniqueIdValue >= badRangeMinB && uniqueIdValue <= badRangeMaxB)) { // is reserved return true; } else { // is not reserved return false; } } //Script function: bootrun static CAFEX_ERROR bootrun(List args, bool fAppTypeDefined) { #if DEBUG Log.WriteLine("bootrun started."); #endif int MAKE_DLF_ONLY = 0; int USE_DLF_ONLY = 0; string ELF_FILENAME = CAFE_ELF.value; if (args != null && args.Count > 0) { // Check parameters while (args.Count != 0) { string OPT = args[0]; args.RemoveAt(0); switch(OPT) { case "-makedlf": // It will make the DLF, but won't use it MAKE_DLF_ONLY = 1; break; case "-usedlf": USE_DLF_ONLY = 1; if (args.Count > 0) { ELF_FILENAME = args[0]; args.RemoveAt(0); } break; } } } CAFERUN_COLDBOOT_OS_VERSION_HI.value = CAFERUN_COLDBOOT_OS_VERSION.value.Substring(0, 8); CAFERUN_COLDBOOT_OS_VERSION_LO.value = CAFERUN_COLDBOOT_OS_VERSION.value.Substring(8, 8); if (CAFERUN_OPTION_SOFT_LAUNCH.value == "1" && MAKE_DLF_ONLY == 0) { if (CAFERUN_OPTION_FAST_RELAUNCH.value == "1") { #if false string COSDEBUG_TID_HI = DISC_EMU_TID.value.Substring(0, 8); string COSDEBUG_TID_LO = DISC_EMU_TID.value.Substring(8, 8); cosdebug.launch_retry(Convert.ToInt32(SESSION_NET_MANAGE_PORT.value), COSDEBUG_TID_HI, COSDEBUG_TID_LO, Convert.ToInt32(CAFERUN_OPTION_FASTLAUNCH_RETRIES.value), Convert.ToInt32(CAFERUN_OPTION_FASTLAUNCH_TIMEOUT.value), Convert.ToInt32(CAFERUN_OPTION_FASTLAUNCH_DELAY.value)); if (quiet_mode) { // We need to start cattoucan to get our events and syncronize the launch CATTOUCAN_TERM.value = Nintendo.SDSG.CatToucan.Terms.KI_PIREPARE_TITLE_ASYNC; cattoucan.start(false, false, false); cosdebug.stop_retry(COSDEBUG_FASTLAUNCH_TIMEOUT); } #endif if (!cosdebug.try_launch(DISC_EMU_TID.value, 0)) { return CAFEX_ERROR.TITLE_SYNC_FAILED; } } else { devkitmsg.title_softlaunch(CAFERUN_COLDBOOT_OS_VERSION.value, DISC_EMU_TID.value, SESSION_LAUNCH_CTRL_PORT.value); } } else { if (CAFE_TEMP.value == null) { Console.WriteLine("cafex run failed: CAFE_TEMP environment variable is not set."); return CAFEX_ERROR.BOOTRUN_NO_TEMP_VAR; } else { BOOTRUN_WORK_DIR.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "caferun"; WUMAD_WORK_DIR.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "makewumaddlf"; } initialize_work_directory(BOOTRUN_WORK_DIR.value); //FIRMWARE_FILE.value = CAFE_SLC_DIR.value + "\\sys\\title\\" + CAFERUN_COLDBOOT_OS_VERSION_HI.value + "\\" + CAFERUN_COLDBOOT_OS_VERSION_LO.value + "\\code\\fw.img"; if (!string.IsNullOrEmpty(BOOTRUN_USE_RECOVERY_IMAGE.value) && BOOTRUN_USE_RECOVERY_IMAGE.value == "1") { FIRMWARE_FILE.value = string.Concat(CAFE_ROOT.value, "\\system\\bin\\", TOOLCHAIN.value, "\\", PLATFORM.value, "\\boot\\recovery.img"); } else if (CAFE_SECURITY.value == "off") { FIRMWARE_FILE.value = string.Concat(CAFE_SLC_DIR.value, "\\sys\\title\\", CAFERUN_COLDBOOT_OS_VERSION_HI.value, "\\", CAFERUN_COLDBOOT_OS_VERSION_LO.value, "\\code\\fw.bu.img"); } else { FIRMWARE_FILE.value = string.Concat(CAFE_SLC_DIR.value, "\\sys\\title\\", CAFERUN_COLDBOOT_OS_VERSION_HI.value, "\\", CAFERUN_COLDBOOT_OS_VERSION_LO.value, "\\code\\fw.img"); } BOOT_DLF_FILE.value = BOOTRUN_WORK_DIR.value + "\\ppc_boot.dlf"; CAFEX_ERROR boot1file_ret = make_boot1_system_file(BOOTRUN_WORK_DIR.value + "\\ppc.bsf"); if (boot1file_ret != CAFEX_ERROR.OK) { return boot1file_ret; } string diskid = BOOTRUN_WORK_DIR.value + "\\diskid.bin"; File.Copy(CAFE_ROOT.value + "\\system\\bin\\" + TOOLCHAIN.value + "\\" + PLATFORM.value + "\\boot\\diskid.bin", diskid, true); File.SetAttributes(diskid, FileAttributes.Normal); CAFEX_ERROR bootdlf_ret = make_boot_dlf(diskid + "," + BOOTRUN_WORK_DIR.value + "\\ppc.bsf," + FIRMWARE_FILE.value, BOOT_DLF_FILE.value); if (bootdlf_ret != CAFEX_ERROR.OK) { return bootdlf_ret; } if (DISC_EMU_TYPE.value == "blockemu") { if (!string.IsNullOrEmpty(ELF_FILENAME) && ELF_FILENAME.EndsWith(".rpx")) { if (USE_DLF_ONLY == 0) { CAFEX_ERROR run_ret = devrun(ELF_FILENAME, null, null, null); if (run_ret != CAFEX_ERROR.OK) { return run_ret; } } if (MAKE_DLF_ONLY == 0) { hostrun(BOOT_DLF_FILE.value + " " + Path.ChangeExtension(ELF_FILENAME, ".dlf")); } } } else // HFIO case & HDD case & WUMAD case { if (!string.IsNullOrEmpty(CAFE_WUMAD.value)) { // WUMAD case // Create the DLF from a WUMAD file. string wumadTempName = null; string wumadTempDir = null; string wumadDlfName = null; if (CAFE_WUMAD.value.ToLower().EndsWith("wumad")) { // A WUMAD file was passed instead of a directory. Console.WriteLine("Creating DLF from WUMAD file..."); wumadTempName = Path.GetFileNameWithoutExtension(CAFE_WUMAD.value); wumadTempDir = Path.Combine(WUMAD_WORK_DIR.value, wumadTempName); wumadDlfName = Path.Combine(wumadTempDir, wumadTempName + ".dlf"); } else { // A directory was passed in. wumadTempName = null; wumadTempDir = CAFE_WUMAD.value; wumadDlfName = Path.Combine(WUMAD_WORK_DIR.value, "extractedWumad.dlf"); } if (wumadTempName != null) { wumadTempName = CAFE_WUMAD.value; } Console.WriteLine("wumadName = " + wumadTempName); Console.WriteLine("wumadDir = " + wumadTempDir); Console.WriteLine("wumadDlf = " + wumadDlfName); CAFEX_ERROR wumad_dlf_ret = make_wumad_dlf(wumadTempName, wumadTempDir, wumadDlfName); if (wumad_dlf_ret != CAFEX_ERROR.OK) { return wumad_dlf_ret; } WumadInfo info = new WumadInfo(); CAFEX_ERROR wumadInfoResult = TryGetWumadInfo(wumadTempDir, ref info); // If a title id is required because there are more than one in the wumad // and none was provided, should stop here. if (wumadInfoResult == CAFEX_ERROR.RUN_TITLE_ID_REQUIRED) { return wumadInfoResult; } // We always need to set the titleId, if the function // returned one. This allows the data to be available upstream // in a sequence of calls involving softlaunch. if (info.titleFound) { CAFERUN_WUMAD_TITLE_ID.value = info.titleId; } else { CAFERUN_WUMAD_TITLE_ID.value = string.Empty; } // If no RPX was provided, the xmls not been updated. // This is a valid assumption because the code in caferun // sets all the xmls besed on an RPX provide prior to call // bootrun if (string.IsNullOrEmpty(ELF_FILENAME) && info.titleFound) { // Just in case this directory doesn't exist... if (!Directory.Exists(CAFE_META_DIR.value)) Directory.CreateDirectory(CAFE_META_DIR.value); string contentMetaXml = CAFE_META_DIR.value + "\\meta.xml"; file_copy_retry(info.metaXml, contentMetaXml, true, 3); // Get the title-id, version, app_type, etc from the WUMAD files string title_id = XmlHandler.GetNodeValue(info.appXml, "title_id"); string title_version = XmlHandler.GetNodeValue(info.appXml, "title_version"); string os_version = XmlHandler.GetNodeValue(info.appXml, "os_version"); string app_type = XmlHandler.GetNodeValue(info.appXml, "app_type"); string app_group_id = XmlHandler.GetNodeValue(info.appXml, "group_id"); // Save config to meta.xml XmlHandler.UpdateNodeValue(contentMetaXml, "title_id", title_id); XmlHandler.UpdateNodeValue(contentMetaXml, "group_id", app_group_id); XmlHandler.UpdateNodeValue(contentMetaXml, "title_version", title_version); // Convert the title_id from a string to a number for lookup Int64 iTitleID = Convert.ToInt64(title_id, 16); if (fAppTypeDefined) { app_type = CAFERUN_APP_TYPE.value; } else { //Look up the App Type using the Title ID string calculated_app_type = FindAppType(iTitleID); if (app_type.CompareTo(calculated_app_type) != 0) { Console.WriteLine("WARNING: Calculated AppType does not match what was in APP.XML"); Console.WriteLine("Overwriting with the calculated value for AppType"); } app_type = calculated_app_type; } // Save config to system.xml XmlHandler.UpdateNodeValue(SYSTEM_XML.value, "default_title_id", title_id); XmlHandler.UpdateNodeValue(SYSTEM_XML.value, "default_app_type", app_type); XmlHandler.UpdateNodeValue(SYSTEM_XML.value, "default_os_id", os_version); } // Starts the emulation if (MAKE_DLF_ONLY == 0) { hostrun(BOOT_DLF_FILE.value + " " + wumadDlfName); } } else { // HFIO and HDD cases if (MAKE_DLF_ONLY == 0) { hostrun(BOOT_DLF_FILE.value); } } } } return CAFEX_ERROR.OK; } //Script function: cafedevrun static CAFEX_ERROR devrun(string elf, string MAKE_PATCH, string CAFEMAKEDLF_OPTION, string KIOSK_DEFAULT_DDF) { #if DEBUG Log.WriteLine("devrun started."); #endif APP_TITLE_ID.value = "0000000000000000"; APP_GROUP_ID.value = "00000000"; APP_TITLE_VERSION.value = "0000"; if (elf == null) { Console.WriteLine("cafex cafedevrun failed: image file required!"); return CAFEX_ERROR.CAFEDEVRUN_NO_IMAGE_FILE; } CAFEDEVRUN_FILE.value = elf; CAFEDEVRUN_EXT.value = Path.GetExtension(elf).Remove(0, 1); CAFEDEVRUN_NAME.value = Path.GetDirectoryName(elf) + "\\" + Path.GetFileNameWithoutExtension(elf); CAFEDEVRUN_FILENAME.value = Path.GetFileNameWithoutExtension(elf); CAFEDEVRUN_DIR.value = Path.GetDirectoryName(elf); string GAME_TYPE = null; if (MAKE_PATCH != null && MAKE_PATCH == "1") { GAME_TYPE = "GP"; } else { GAME_TYPE = "GM"; } // Check temporary directory CAFEDEVRUN_WORK_DIR.value = CAFEDEVRUN_NAME.value + "_tmp"; create_directory_if_noexist(CAFEDEVRUN_WORK_DIR.value); if (INCLUDE_SYSTEM_DIR.value == null) { INCLUDE_SYSTEM_DIR.value = "0"; } CAFE_BASEFILE_PATH.value = CAFE_ROOT.value + "\\system\\bin\\tool\\mastering\\resources"; if (string.IsNullOrEmpty(KIOSK_DEFAULT_DDF)) { DEFAULT_DDF.value = CAFE_BASEFILE_PATH.value + "\\default.ddf"; } else { Console.WriteLine("Change default ddf -> " + KIOSK_DEFAULT_DDF); DEFAULT_DDF.value = KIOSK_DEFAULT_DDF; } COMMON_DDF_FILE.value = CAFEDEVRUN_WORK_DIR.value + "\\common.ddf"; string custom_ddf = Path.ChangeExtension(elf, ".ddf"); // Use individual ddf file if exists if (File.Exists(custom_ddf)) { INDIVIDUAL_DDF_FILE.value = custom_ddf; // TODO: Need to replace the game type in the custo_ddf file and save it. } else { INDIVIDUAL_DDF_FILE.value = ""; } APP_XML_FILE.value = CAFEDEVRUN_DIR.value + "\\app.xml"; if (!File.Exists(APP_XML_FILE.value)) { Console.WriteLine("cafex cafedevrun failed: Cannot find " + APP_XML_FILE.value); return CAFEX_ERROR.CAFEDEVRUN_CANT_FIND_APP_XML; } extract_info_from_app_xml(APP_XML_FILE.value); FileStream fs = new FileStream(COMMON_DDF_FILE.value, FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.WriteLine(";"); sw.WriteLine("; " + CAFEDEVRUN_NAME.value + "." + CAFEDEVRUN_EXT.value); sw.WriteLine(";"); sw.WriteLine("[Input]"); sw.WriteLine("DiscHeaderBaseFileName=\"" + CAFE_BASEFILE_PATH.value + "\\discheader_base.bin\""); sw.WriteLine("VolumeHeaderBaseFileName=\"" + CAFE_BASEFILE_PATH.value + "\\volheader_base.bin\""); sw.WriteLine("[Output]"); sw.WriteLine("LayoutFileName=\"" + CAFEDEVRUN_NAME.value + ".dlf\""); sw.WriteLine("OutputDirectory=\"" + CAFEDEVRUN_DIR.value + "\""); sw.WriteLine("AppName=\"" + CAFEDEVRUN_FILENAME.value + "\""); sw.WriteLine("Mode=WU"); sw.WriteLine("[DiscID]"); sw.WriteLine("GameType=" + GAME_TYPE); sw.WriteLine("TitleId=0x" + APP_TITLE_ID.value); sw.WriteLine("GroupId=0x" + APP_GROUP_ID.value); sw.WriteLine("DiskNumber=0"); sw.WriteLine("GameVersion=" + (HexHandler.GetNumberFromString("0x" + APP_TITLE_VERSION.value) / 16).ToString()); sw.WriteLine("[SectionParam]"); sw.WriteLine("\"CONTENT\"=0x" + APP_TITLE_ID.value + ",0x" + APP_GROUP_ID.value + ",0x02"); sw.WriteLine("[PathList]"); sw.WriteLine("CODE_DIR_RPX=\"code\", \"$(CAFE_CODE_DIR)\\" + CAFEDEVRUN_FILENAME.value + ".rpx\""); if (INCLUDE_SYSTEM_DIR.value == "1") { sw.WriteLine("[PathList]"); sw.WriteLine("SYSTEM_DIR=\"sys\", \"$(CAFE_SYSTEM_DIR)\""); } sw.Flush(); sw.Close(); int cafemakedlf_ret = cafemakedlf.make(DEFAULT_DDF.value, COMMON_DDF_FILE.value, INDIVIDUAL_DDF_FILE.value, CAFEMAKEDLF_OPTION); if (cafemakedlf_ret != 0) { return CAFEX_ERROR.CAFEDEVRUN_CAFEMAKEDLF_FAILED; } fs = new FileStream(CAFEDEVRUN_NAME.value + ".dlf", FileMode.Append); sw = new StreamWriter(fs); sw.WriteLine("0x00000005D3A00000,\"\""); sw.Flush(); sw.Close(); return CAFEX_ERROR.OK; } //Script function: hostrun static void hostrun(string arguments) { #if DEBUG Log.WriteLine("hostrun started. Arguments:" + arguments); #endif getbridgetype(); FSEMUL_PARAMS.value = null; if (BRIDGE_TYPE.value == "Toucan") { BRIDGE_INSTALL_PATH.value = SDIO_BRIDGE_TOOLS.value; } else { BRIDGE_INSTALL_PATH.value = MION_BRIDGE_TOOLS.value; } if (BRIDGE_TYPE.value == "Mion") { if (BRIDGE_PARAMETERS.value == null) { FSEMUL_PARAMS.value = "-em -ip " + BRIDGE_CURRENT_IP_ADDRESS.value; } else { FSEMUL_PARAMS.value = BRIDGE_PARAMETERS.value + " -ip " + BRIDGE_CURRENT_IP_ADDRESS.value; } } if (execLaunchCmd && !string.IsNullOrEmpty(LAUNCH_DLF_FILE)) { string[] splitStrings = arguments.Split(' '); int i = 0; arguments = splitStrings[i++] + " " + LAUNCH_DLF_FILE + " "; for (; i < splitStrings.Length; i++) { arguments += splitStrings[i] + " "; } } if (!PcfsTcpOnly) { // Need to figure out what the difference between these two options is in the scripts, and if it is possible to replicate here. if (CAFE_DETACH_FSEMUL.value == null || CAFE_DETACH_FSEMUL.value != "0") { FSEmul.start(arguments, FSEMUL_PARAMS.value); } else { FSEmul.start(arguments, FSEMUL_PARAMS.value); } } // Remeber what the boot mode was when we cold booted the DEVKIT string boot_mode_file = Path.Combine(CAFE_TEMP.value, string.Format("{0}_{1}_CAFE_BOOT_MODE", BRIDGE_CURRENT_IP_ADDRESS.value.Replace('.', 'x'), BRIDGE_CURRENT_NAME.value)); File.WriteAllText(boot_mode_file, CAFE_BOOT_MODE.value); if (Program.CAFE_PROFILE.value != null && Program.CAFE_PROFILE.value == "1") { CafeXEventtLog.Instance.WriteToEventLog(572, DateTime.Now, EventStatus.DISCRETE, EventProcess.CAFEX, "System is going through cold boot"); } } //Script function: cafediscrun static CafeXReturn discrun(string[] args, bool runSetup, bool launch) { #if DEBUG Log.WriteLine("discrun started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif CAFERUN_OPTION_CALLED_FROM_CAFEDISCRUN.value = "yes"; return run(args, runSetup, launch); } //Script function: cafeheadlessrun static CafeXReturn headlessrun(string[] args) { #if DEBUG Log.WriteLine("headlessrun started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif string HLRUN_OUT = Path.Combine(CAFE_TEMP.value, SESSION_PATH_PREFIX.value + "headlessrun"); string HLRUN_TMP = Path.Combine(HLRUN_OUT, "tmp"); bool RUN_DEVMENU = true; // Run Devmenu after upload bool BYPASS_SETUP = false; // Bypass mastering step int TITLE_WAIT = 15; // Time to wait for the title to boot (in seconds) bool DEBUG_FLAG = false; // Use the DEBUG version of the OS int UPLOAD_BANK = 10; // Bank to upload the mastered image to bool NO_SESSION_SYNC = false; // If no session sync was requested (-z) string RPX_PATH = string.Empty; // Path to the RPX file string[] RPX_ARGS = new string[0]; // Arguments to the RPX file CafeXReturn ret = new CafeXReturn(CAFEX_ERROR.OK); // // check_args // for (int i = 0; i < args.Length; ++i) { switch (args[i]) { case "-b": { DEBUG_FLAG = true; break; } case "-h": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (!int.TryParse(args[i + 1], out UPLOAD_BANK)) { Console.WriteLine("Error: '{0}' is not a valid number!", args[i + 1]); headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } ++i; break; } case "-n": { RUN_DEVMENU = false; break; } case "-m": { BYPASS_SETUP = true; break; } case "-w": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (!int.TryParse(args[i + 1], out TITLE_WAIT)) { Console.WriteLine("Error: '{0}' is not a valid number!", args[i + 1]); headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } if (TITLE_WAIT < 0) { Console.WriteLine("Error: Wait time can't be less than zero!"); headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.BAD_ARGUMENT); } ++i; break; } case "-u": { headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.OK); } case "-z": { NO_SESSION_SYNC = true; break; } default: { if (string.IsNullOrEmpty(RPX_PATH) && Path.GetExtension(args[i]).Equals(".rpx", StringComparison.InvariantCultureIgnoreCase)) { RPX_PATH = args[i]; } else { if (i < args.Length) { int start = i; RPX_ARGS = new string[args.Length - 1]; while (i < args.Length) { RPX_ARGS[i - start] = args[i++]; } } i = args.Length; } break; } } } string makecfmaster = getPathToMakeCfMaster(); if (makecfmaster == null) { Console.WriteLine("headlessrun requires makecfmaster.exe but it's not found."); return new CafeXReturn(CAFEX_ERROR.MASTERING_ERROR); } if (string.IsNullOrEmpty(RPX_PATH)) { Console.WriteLine("cafex headlessrun failed: RPX file is missing on command line!"); headlessrun_usage(); return new CafeXReturn(CAFEX_ERROR.RUN_NO_RPX_SPECIFIED); } // // update_bootloader // ret.error = hostcheckversion(); if (ret.error != CAFEX_ERROR.OK) { Console.WriteLine("cafex headlessrun: failed running hostcheckversion."); return ret; } string boot_mode = string.Empty; int hb_ver_flat = compute_flat_version(CAFERUN_HOSTBRIDGE_VERSION.value); if (hb_ver_flat < compute_flat_version("3.2.4.8")) { Console.WriteLine("cafex headlessrun: Using BOOT mode " + CAFE_BOOT_MODE.value); } else { Console.WriteLine("cafex headlessrun: Checking for DUAL bootloader..."); // hostbridge 3.2.5.1 has a problem in mode detection that requires some time after stop // in order to properly detect boot mode try { stop(new string[] { "-hard" }); } catch (Exception e) { Console.WriteLine("cafex recover[warning]: Failure to hard stop the DEVKIT prior to mode detection, error {0}", e.Message); } Thread.Sleep(1000); int boot_mode_detect = FSEmul.boot_mode_detect(BRIDGE_CURRENT_IP_ADDRESS.value, out boot_mode); if (boot_mode_detect != 0) { Console.WriteLine("cafex headlessrun: Unable to determine boot mode!"); return new CafeXReturn(CAFEX_ERROR.BOOTMODEDETECT_FSEMUL_FAILED); } Console.WriteLine("cafex headlessrun: Detected BOOT mode : {0}", boot_mode); } if (boot_mode.Substring(0, 4) != "DUAL") { // Install the DUAL bootlooder ret.error = recover(null); if (ret.error != CAFEX_ERROR.OK) { return ret; } } if (!BYPASS_SETUP) { // // prepare_rpx_for_mastering // CAFE_BOOT_MODE.value = "PCFS"; // Disable the builtin capturing of output string OLD_CAFE_CONSOLE = CAFE_CONSOLE.value; CAFE_CONSOLE.value = "notoucan"; // Run the RPX to create the dependent files needed for mastering List discrun_argsList = new List(); if (DEBUG_FLAG) { discrun_argsList.Add("-b"); } if (NO_SESSION_SYNC) { discrun_argsList.Add("-z"); } discrun_argsList.Add("-e"); discrun_argsList.Add("em"); discrun_argsList.Add("-e"); discrun_argsList.Add("sata"); discrun_argsList.Add(RPX_PATH); discrun_argsList.AddRange(RPX_ARGS); string[] discrun_args = discrun_argsList.ToArray(); Console.WriteLine("cafex headlessrun: calling discrun {0}", string.Join(" ", discrun_args)); ret = discrun(discrun_args, true, true); // Wait for MCP to come up int mon_ret = monitor_for_output("-k", "[+-* DK is ready for console input *-+]", "30", CAFE_TEMP.value, null, true); if (mon_ret == 0) // TODO: This should be from the MON_RESULT enumeration { Console.WriteLine("cafex headlessrun: Master image prep for '{0}' succeeded.", RPX_PATH); } else { Console.WriteLine("cafex headlessrun: Master image prep for '{0}' failed with code {1}!", RPX_PATH, mon_ret); return new CafeXReturn(CAFEX_ERROR.MASTERING_ERROR); } // Give the title time to boot up in case it writes files needed for mastering Console.WriteLine("cafex headlessrun: waiting {0} seconds for title to boot...", TITLE_WAIT); Thread.Sleep(TITLE_WAIT * 1000); CAFE_CONSOLE.value = OLD_CAFE_CONSOLE; stop(null); Thread.Sleep(2000); } // // master_image // // Create the working and temp folders Directory.CreateDirectory(HLRUN_TMP); // Create the master image for the last ran RPX ret.error = makeMaster(new string[] { "-r", RPX_PATH, "-o", Path.Combine(HLRUN_OUT, "title"), "-w", HLRUN_TMP }); if (ret.error == CAFEX_ERROR.OK) { Console.WriteLine("cafex headlessrun: Mastering image for {0} succeeded.", RPX_PATH); } else { Console.WriteLine("cafex headlessrun:Mastering image for $RPX_PATH failed with code {0}!", ret); return ret; } // // upload_image // int imageuploader_ret = ImageUploader.upload(BRIDGE_CURRENT_IP_ADDRESS.value, UPLOAD_BANK, Path.Combine(HLRUN_OUT, "title.wumad")); if (imageuploader_ret == 0) { Console.WriteLine("cafex headlessrun: ImageUpload to bank {0} succeeded.", UPLOAD_BANK); } else { Console.WriteLine("cafex headlessrun: ImageUpload to bank {0} failed with code {0}!", UPLOAD_BANK, imageuploader_ret); return new CafeXReturn(CAFEX_ERROR.IMAGEUPLOADER_FAILED); } // // set_hreader_mode // int mionurl_ret = mionurl.Run(string.Format("{0} /setup.cgi id_27={1} id_32=1 op=0", BRIDGE_CURRENT_IP_ADDRESS.value, UPLOAD_BANK)); if (mionurl_ret == 0) { Console.WriteLine("cafex headlessrun: mionurl succeeded to set HREADER mode."); } else { Console.WriteLine("cafex headlessrun: mionurl failed to set HREADER mode with code {0}!", mionurl_ret); return new CafeXReturn(CAFEX_ERROR.MIONURL_FAILED); } // Reboot MION and wait for completion so Bank and HREADER mode can take effect string miontelnet_output; Console.WriteLine("cafex headlessrun: Rebooting MION..."); int miontelnet_ret = miontelnet.Reboot(out miontelnet_output); Console.WriteLine(miontelnet_output); if (RUN_DEVMENU) { // // run_image // // Change the boot mode TO NAND CAFE_BOOT_MODE.value = "NAND"; string[] discrun_args = new string[DEBUG_FLAG ? 6 : 5]; int discrun_idx = 0; if (DEBUG_FLAG) { discrun_args[discrun_idx++] = "-b"; } discrun_args[discrun_idx++] = "-e"; discrun_args[discrun_idx++] = string.Format("h:{0}", UPLOAD_BANK); discrun_args[discrun_idx++] = "-e"; discrun_args[discrun_idx++] = "nopcfs"; discrun_args[discrun_idx++] = RPX_PATH; Console.WriteLine("cafex headlessrun: calling discrun {0}", string.Join(" ", discrun_args)); return discrun(discrun_args, true, true); } else { Console.WriteLine("cafex headlessrun: completed sucessfully."); } return new CafeXReturn(CAFEX_ERROR.OK); } //Script function: cafeon static CafeXReturn on(string[] args, bool runSetup, bool launch) { #if DEBUG Log.WriteLine("on started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif List argList = new List(); CafeXReturn ret = new CafeXReturn(CAFEX_ERROR.OK); int? verbosityLevel = null; CAFEON_DISABLE_BGD.value = "0"; CAFEON_NOBGD_META.value = ""; BRIDGE_PARAMETERS_WITH_E.value = ""; CAFE_RUN_DEBUG.value = ""; BOOTRUN_USE_RECOVERY_IMAGE.value = ""; CAFEON_OPTION_NO_DATA_SYNC.value = CAFERUN_OPTION_NO_DATA_SYNC.value; if (CAFEON_OPTION_NO_DATA_SYNC.value == null) { CAFEON_OPTION_NO_DATA_SYNC.value = "0"; } if (CAFE_RUN_RUNNING.value == null) { CAFE_RUN_RUNNING.value = "0"; } if (CAFE_RUN_RUNNING.value != "0") { Console.WriteLine("****cafex on: RECURSIVE CALL TO cafex on EXITING***"); ret.error = CAFEX_ERROR.ON_RECURSIVE_CALL; return ret; } CAFE_RUN_RUNNING.value = "1"; if (args != null && args.Length > 0) { for (int i = 0; i < args.Length; ++i) { if (args[i] == "-noprompt") { CATTOUCAN_TERM.value = Nintendo.SDSG.CatToucan.Terms.MENU_SOURCE; } else if (args[i] == "-d") { CAFE_RUN_DEBUG.value = args[i] + " " + args[i + 1]; ++i; } else if (args[i] == "-e") { BRIDGE_PARAMETERS_WITH_E.AddToVar(args[i] + " " + args[i + 1], ' '); ++i; } else if (args[i] == "-nobgd") { CAFEON_DISABLE_BGD.value = "1"; } else if (args[i] == "-nosync") { if (string.IsNullOrEmpty(CAFE_DATA_DIR.value) || !Directory.Exists(CAFE_DATA_DIR.value)) { Console.WriteLine("Session data directory is missing and needs to be sync'd!"); Console.WriteLine(" Please re-run without the '-nosync' option."); ret.error = CAFEX_ERROR.ON_DATA_DIR_MISSING; return ret; } Console.WriteLine("Skipping synchronization of data directory as requested by -nosync switch."); CAFEON_OPTION_NO_DATA_SYNC.value = "1"; } else if (args[i] == "-recover") { _CCRSYSCFG1.value = "0x40000000"; BOOTRUN_USE_RECOVERY_IMAGE.value = "1"; } else if (args[i] == "-h") { on_usage(); ret.error = CAFEX_ERROR.OK; return ret; } else if (args[i] == "-v") { int vArg; if (!Int32.TryParse(args[i + 1], out vArg)) { ret.error = CAFEX_ERROR.BAD_ARGUMENT; return ret; } verbosityLevel = vArg; ++i; } else { // This is an argument that needs to be passed down argList.Add(args[i]); } } } if (CAFEON_DISABLE_BGD.value == "1") { if (!string.IsNullOrEmpty(CAFE_META_DIR.value) && Directory.Exists(CAFE_META_DIR.value)) { CAFEON_NOBGD_META.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "tmp_meta"; Console.WriteLine("Disabling background daemons in tmp dir " + CAFEON_NOBGD_META.value); DirectoryInfo originMetaDiretory = new DirectoryInfo(CAFE_META_DIR.value); FileSystemInfo[] filesToCopy = originMetaDiretory.GetFileSystemInfos(); if (filesToCopy.Length > 0) { create_directory_if_noexist(CAFEON_NOBGD_META.value); string[] meta_files = Directory.GetFiles(CAFE_META_DIR.value); foreach (FileSystemInfo file in filesToCopy) { string fileName = file.FullName; string destinationFileName = CAFEON_NOBGD_META.value + "\\" + Path.GetFileName(fileName); file_copy_retry(fileName, destinationFileName, true, 3); } XmlHandler.UpdateNodeValue(CAFEON_NOBGD_META.value + "\\meta.xml", "bg_daemon_enable", "0"); CAFE_META_DIR.value = CAFEON_NOBGD_META.value; } } } OS_VERSION_LO.value = XmlHandler.GetNodeValue(CAFE_ROOT.value + "\\data\\mlc\\sys\\title\\00050010\\1f700500\\code\\app.xml", "os_version").Substring(8, 6); string total_arglist_with_qs = StringCombiner.MakeDelimitedString(argList.ToArray(), ' ').Replace(' ', '?').Replace("-c?", "-c ").Replace("?-c", " -c"); if (OS_VERSION_LO.value == null) { Console.WriteLine("cafex on error: unable to locate System Config Tool app.xml or file is corrupt"); } else { if (CAFEON_OPTION_NO_DATA_SYNC.value == "0" && SESSION_MANAGER.value == "1") { ret.error = syncsession(null); if (CAFEX_ERROR.OK != ret.error) { return ret; } } XmlHandler.UpdateNodeValue(CAFE_DATA_DIR.value + "\\mlc\\sys\\title\\00050010\\1f700500\\code\\cos.xml", "argstr", "system_config_tool.rpx " + total_arglist_with_qs); // Keep the current command stored, so when run is called it knows it has last been called by 'on' string currentCommand = command; command = "on"; string OS_string = string.Empty; if (OS_VERSION_LO.value == "100040") { // NDEBUG OS OS_string = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\app\\system_config_tool\\base\\NDEBUG\\system_config_tool.rpx"; } else if (OS_VERSION_LO.value == "100080") { // DEBUG OS OS_string = "-b" + DEFAULT_DELIMITER + CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\app\\system_config_tool\\base\\DEBUG\\system_config_tool.rpx"; } string run_args = (!string.IsNullOrEmpty(CAFE_RUN_DEBUG.value) ? CAFE_RUN_DEBUG.value.Replace(' ', DEFAULT_DELIMITER) : string.Empty) + DEFAULT_DELIMITER + (!string.IsNullOrEmpty(BRIDGE_PARAMETERS_WITH_E.value) ? BRIDGE_PARAMETERS_WITH_E.value.Replace(' ', DEFAULT_DELIMITER) : string.Empty) + DEFAULT_DELIMITER + "-e" + DEFAULT_DELIMITER + "mcp:launch_hint:hfiomlc" + DEFAULT_DELIMITER + "-z" + DEFAULT_DELIMITER + "-t" + DEFAULT_DELIMITER + "0x" + SYSCONFIGTOOL_TITLE_ID + DEFAULT_DELIMITER + OS_string; // If user passed in verbosity level, it must be appended to the beginning of the cafex run command, // or else system_config_tool will try to parse it. if (verbosityLevel != null && verbosityLevel.HasValue) { run_args = string.Format("-v{0}{1}{2}{3}", DEFAULT_DELIMITER, verbosityLevel.Value, DEFAULT_DELIMITER, run_args); } if (argList != null) { run_args += DEFAULT_DELIMITER + StringCombiner.MakeDelimitedString(argList.ToArray(), DEFAULT_DELIMITER); } bool fAppTypeBackup = fAppTypeDefined; fAppTypeDefined = false; ret = run(run_args.Split(new char[] { DEFAULT_DELIMITER }, StringSplitOptions.RemoveEmptyEntries), runSetup, launch); fAppTypeDefined = fAppTypeBackup; // Return the current command command = currentCommand; XmlHandler.UpdateNodeValue(CAFE_DATA_DIR.value + "\\mlc\\sys\\title\\00050010\\1f700500\\code\\cos.xml", "argstr", "system_config_tool.rpx"); } return ret; } // Helper function: DUAL bootloader availibility and requirement by SDK static private bool is_DUAL_bootloader_available() { int flat_sdk_ver = compute_flat_version(SDK_VER.value); if (flat_sdk_ver >= compute_flat_version("2.10.01")) { // DUAL bootloader is available starting in SDK 2.10.01 if (Directory.Exists (Path.Combine(CAFE_MLC_DIR.value, "sys\\update\\mixed"))) { // Found the mixed content folder in the MLC return true; } } return false; } static private bool is_DUAL_bootloader_required() { int flat_sdk_ver = compute_flat_version(SDK_VER.value); if (flat_sdk_ver >= compute_flat_version("2.10.11")) { // DUAL bootloader is required starting in SDK 2.10.11 return true; } return false; } // Helper function: Prepares the mixed content folder in the current SDK static private void prepare_mlc_recover_content () { const string sdio_boot1_folder = "zzz-boot1-sdio"; const string dual_boot1_folder = "aaa-boot1-dual"; string MIXED_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "sys\\update\\mixed"); string PCFS_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "sys\\update\\pcfs"); string NAND_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "sys\\update\\nand"); string BL_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "sys\\update\\bootloader"); // Delete the standalone copy of the dual bootloader if (Directory.Exists(BL_DIR)) { FileUtil.DirectoryDelete(BL_DIR, true); } if (!Directory.Exists(MIXED_DIR)) { // Make a standalone copy of the SDIO bootloader since DUAL does not exist FileUtil.DirectoryCopy(Path.Combine(PCFS_DIR, sdio_boot1_folder), Path.Combine(BL_DIR, sdio_boot1_folder), false, false); } else { // Make a standalone copy of the DUAL bootloader FileUtil.DirectoryCopy(Path.Combine(MIXED_DIR, dual_boot1_folder), Path.Combine(BL_DIR, dual_boot1_folder), false, false); // Delete all of the folders except the bootloader in the MLC mixed folder Console.WriteLine("cafex: Cleaning content in '{0}'", MIXED_DIR); foreach (string srcEntry in Directory.GetDirectories(MIXED_DIR)) { string srcName = Path.GetFileName(srcEntry); if (!srcName.Equals(dual_boot1_folder, StringComparison.CurrentCultureIgnoreCase)) { string destEntry = Path.Combine(MIXED_DIR, srcName); FileUtil.DirectoryDelete(srcEntry, true); } } // Delete all of the files in the MLC mixed folder foreach (string srcEntry in Directory.GetFiles(MIXED_DIR)) { #if DEBUG Console.WriteLine("Deleting file '{0}'", srcEntry); #endif FileUtil.FileDelete(srcEntry); } // // Start building the mixed content in dest_dir // Console.WriteLine("cafex: Preparing content in '{0}'", MIXED_DIR); // Copy all of the folders except the bootloader from the src to the dest foreach (string srcEntry in Directory.GetDirectories(NAND_DIR)) { string srcName = Path.GetFileName(srcEntry); if (!srcName.StartsWith("zzz-boot1-")) { string destEntry = Path.Combine(MIXED_DIR, srcName); FileUtil.DirectoryCopy(srcEntry, destEntry, true, false); } } // Copy the files from NAND content in the mixed dir foreach (string srcEntry in Directory.GetFiles(NAND_DIR)) { string srcName = Path.GetFileName(srcEntry); string destEntry = Path.Combine(MIXED_DIR, srcName); #if DEBUG Console.WriteLine("Copying file '{0}' => '{1}'", srcEntry, destEntry); #endif File.Copy(srcEntry, destEntry); } } } // Helper function: Prepares a revert content folder in the current SDK from the reversion SDK. static private void prepare_mlc_revert_content(string REVERT_DIR, string revert_cafe_root, bool use_mixed) { const string sdio_boot1_folder = "zzz-boot1-sdio"; const string dual_boot1_folder = "aaa-boot1-dual"; string PCFS_DIR = Path.Combine(revert_cafe_root, "data\\mlc\\sys\\update\\pcfs"); string NAND_DIR = Path.Combine(revert_cafe_root, "data\\mlc\\sys\\update\\nand"); string MIXED_DIR = Path.Combine(revert_cafe_root, "data\\mlc\\sys\\update\\mixed"); // Delete the standalone copy of the SDIO bootloader if (Directory.Exists(REVERT_DIR)) { FileUtil.DirectoryDelete(REVERT_DIR, true); } if (is_DUAL_bootloader_required()) { use_mixed = true; } Console.WriteLine("cafex: Preparing content in '{0}'", REVERT_DIR); // Copy directories from the NAND content folder (except the bootloader) foreach (string srcEntry in Directory.GetDirectories(NAND_DIR)) { string srcName = Path.GetFileName(srcEntry); if (!srcName.StartsWith("zzz-boot1-")) { string destEntry = Path.Combine(REVERT_DIR, srcName); FileUtil.DirectoryCopy(srcEntry, destEntry, true, false); } } // Copy files from the NAND content folder foreach (string srcEntry in Directory.GetFiles(NAND_DIR)) { string srcName = Path.GetFileName(srcEntry); string destEntry = Path.Combine(REVERT_DIR, srcName); File.Copy(srcEntry, destEntry); } // Copy the bootloader depending of if we using the DUAL bootloader if (!is_DUAL_bootloader_available() || !use_mixed) { // This is reverting to an SDK that doesn't have the DUAL bootloader or // an optional one where we don't want to use it. FileUtil.DirectoryCopy(Path.Combine(PCFS_DIR, sdio_boot1_folder), Path.Combine(REVERT_DIR, sdio_boot1_folder), false, false); } else { // This is reverting to an SDK that requires the DUAL booloader or // an optional one where we do want to use it. FileUtil.DirectoryCopy(Path.Combine(MIXED_DIR, dual_boot1_folder), Path.Combine(REVERT_DIR, dual_boot1_folder), false, false); } } //Script function: cafeupdate static CAFEX_ERROR update(string[] args) { #if DEBUG Log.WriteLine("update started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif CAFEUPDATE_USE_SYSTEM_UPDATER.value = "0"; CAFEUPDATE_TITLE.value = ""; CAFEUPDATE_PACKAGE_DEFAULT.value = "/vol/storage_hfiomlc01/sys/update/pcfs"; CAFEUPDATE_PACKAGE.value = CAFEUPDATE_PACKAGE_DEFAULT.value; bool USE_MIXED_BOOTLOADER = false; bool prod = true; bool reflash = false; bool noreflash = false; bool updateDRC = true; CAFEX_ERROR ret = CAFEX_ERROR.UPDATE_FAILED; if ((recover_flags & RECOVER_COMMAND_MASK) == RECOVER_COMMAND_INIT) { recover_flags = (recover_flags & ~RECOVER_COMMAND_MASK) | RECOVER_COMMAND_UPDATE; } if (is_DUAL_bootloader_required()) { USE_MIXED_BOOTLOADER = true; prod = false; } else //the bootloader isn't available or not required { USE_MIXED_BOOTLOADER = false; prod = true; } for (int i = 0; i < args.Length; ++i) { switch (args[i].ToLowerInvariant()) { case "-u": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return CAFEX_ERROR.BAD_ARGUMENT; } CAFEUPDATE_PACKAGE.value = args[i + 1]; ++i; break; } case "-s": { CAFEUPDATE_USE_SYSTEM_UPDATER.value = "1"; break; } case "-t": { if (!ArgumentChecks.IsArgumentValidSetting(args, i + 1)) { run_usage(); return CAFEX_ERROR.BAD_ARGUMENT; } CAFEUPDATE_TITLE.value = args[i + 1]; ++i; break; } case "-p": { recover_flags = (recover_flags & ~RECOPT_PROD_MASK) | RECOPT_PRODUCTION_DEF; if (!is_DUAL_bootloader_required()) { Console.WriteLine("-p argument not supported on this SDK."); return CAFEX_ERROR.INVALID_OPTION; } if (CAFE_BOOT_MODE.value != "NAND") { Console.WriteLine("Warning: Ignoring '{0}' switch because it is only valid in NAND mode.", args[i]); recover_flags = (recover_flags & ~RECOVER_ENV_BOOT_MASK) | RECOVER_ENV_BOOT_NAND; } else { USE_MIXED_BOOTLOADER = false; prod = true; recover_flags = (recover_flags & ~RECOVER_ENV_BOOT_MASK) | RECOVER_ENV_BOOT_PCFS; //if (!noreflash) //{ // // the -noreflash option was found before the -P // reflash = true; //} } break; } case "-noreflash": { reflash = false; noreflash = true; recover_flags = (recover_flags & ~RECOPT_NOREFLASH_MASK) | RECOPT_NOREFLASH_DEF; break; } case "-reflash": { reflash = true; recover_flags = (recover_flags & ~RECOPT_REFLASH_MASK) | RECOPT_REFLASH_DEF; break; } case "-m": { recover_flags = (recover_flags & ~RECOPT_MIXED_MASK) | RECOPT_MIXED_DEF; //This option was only valid on SDKs 2.10.01-2.10.09 if (is_DUAL_bootloader_available() && !is_DUAL_bootloader_required()) { USE_MIXED_BOOTLOADER = true; prod = false; } else { Console.WriteLine("-M is not supported in this SDK."); return CAFEX_ERROR.INVALID_OPTION; } break; } case "-l": { recover_flags = (recover_flags & ~RECOPT_LEGACY_MASK) | RECOPT_LEGACY_DEF; //This option was only valid on SDKs 2.10.10 and above if (is_DUAL_bootloader_required()) { USE_MIXED_BOOTLOADER = false; prod = true; } else { Console.WriteLine("-L is not supported in this SDK."); return CAFEX_ERROR.INVALID_OPTION; } break; } case "-nodrc": { //don't update the DRC firmware updateDRC = false; break; } case "-h": { update_usage(); return CAFEX_ERROR.OK; } default: { Console.WriteLine("cafex update failed: Invalid argument"); return CAFEX_ERROR.INVALID_OPTION; } } } //I'd really like to check for -M and -L at the same time here, but the old code didn't check that. //So to maintain backcompat, whatever is specified last between -M and -L is what gets used. if (CAFE_BOOT_MODE.value == "NAND") { Console.WriteLine("Unable to perform update when in NAND mode."); Console.WriteLine("Please run \"setbootmode -quick PCFS\" and retry this update."); Console.WriteLine("If updating from SDK 2.09.22 or earlier, please open that SDK's cafe.bat and perform a \"source setbootmode PCFS\", then retry this update."); return CAFEX_ERROR.CANNOT_UPDATE_IN_NAND_MODE; } else { recover_flags = (recover_flags & ~RECOVER_ENV_BOOT_MASK) | RECOVER_ENV_BOOT_PCFS; if (CAFE_SECURITY.value == "off") { Console.WriteLine("Sorry, bringup boot1 update not supported yet"); return CAFEX_ERROR.UPDATE_BRINGUP_BOOT1_UPDATE; } if (CAFEUPDATE_TITLE.value != null) { Console.WriteLine("Installing title " + CAFEUPDATE_TITLE.value + " using System Config Tool..."); CAFEX_ERROR on_ret = on(new string[] { "-c", "install " + CAFEUPDATE_TITLE.value, "-c", "exit" }, true, true).error; if (on_ret != CAFEX_ERROR.OK) { return on_ret; } else { on_ret = readSDKFromMion(); if (on_ret != CAFEX_ERROR.OK) //something bad happened in mionps { return on_ret; } setMionSDKVersion(); } } else { if (CAFEUPDATE_PACKAGE.value == CAFEUPDATE_PACKAGE_DEFAULT.value) { Console.WriteLine("Performing system update using System Config Tool..."); } else { Console.WriteLine("Performing system update using System Config Tool from " + CAFEUPDATE_PACKAGE.value + "..."); } if (CAFEUPDATE_USE_SYSTEM_UPDATER.value == "1") { Console.WriteLine("Using system updater..."); CAFEX_ERROR on_ret = on(new string[] { "-c", "update_launch " + CAFEUPDATE_PACKAGE.value }, true, true).error; if (on_ret != CAFEX_ERROR.OK) { return on_ret; } else { on_ret = readSDKFromMion(); if (on_ret != CAFEX_ERROR.OK) //something bad happened in mionps { return on_ret; } setMionSDKVersion(); } } else { List setbootmode_args = new List(); if (USE_MIXED_BOOTLOADER && !is_DUAL_bootloader_required()) { setbootmode_args.Add("-mixed"); } setbootmode_args.Add("PCFS"); if (noreflash) { setbootmode_args.Add("-noreflash"); } else if (reflash) { setbootmode_args.Add("-reflash"); } ret = setbootmode(setbootmode_args.ToArray()); } } } if (updateDRC && ret == CAFEX_ERROR.OK) { Console.WriteLine("Attempting to update DRC"); //reset some values that on -recover set CAFE_CONSOLE.value = "cattoucan"; CAFE_RUN_RUNNING.value = "0"; _CCRSYSCFG1.value = ""; BOOTRUN_USE_RECOVERY_IMAGE.value = ""; CATTOUCAN_TERM.value = "drc_update end"; ret = on(new string[] {"-c drc_update 1"}, true, true).error; stop(null, true); } return ret; } static CAFEX_ERROR revert(string[] args) { #if DEBUG Log.WriteLine("revert started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif bool reflash = false; bool noreflash = false; string revert_cafe_root = string.Empty; bool use_mixed = false; CAFEX_ERROR ret = CAFEX_ERROR.OK; for (int i = 0; i < args.Length; ++i) { switch (args[i].ToLowerInvariant()) { case "-noreflash": if (reflash) { Console.WriteLine("cafex revert: '-reflash' and '-noreflash' can't be used together!"); return CAFEX_ERROR.INVALID_OPTION; } noreflash = true; break; case "-reflash": if (noreflash) { Console.WriteLine("cafex revert: '-reflash' and '-noreflash' can't be used together!"); return CAFEX_ERROR.INVALID_OPTION; } reflash = true; break; case "-mixed": use_mixed = true; break; case "-h": revert_usage(); return CAFEX_ERROR.OK; default: if (args[i].StartsWith("-") || !string.IsNullOrEmpty(revert_cafe_root)) { Console.WriteLine("cafex revert failed: Invalid argument: '{0}'", args[i]); return CAFEX_ERROR.INVALID_OPTION; } revert_cafe_root = PathConverter.Windowsify(args[i]); break; } } if (string.IsNullOrEmpty(revert_cafe_root)) { Console.WriteLine("cafex revert failed: Missing SDK root to revert to on command line!"); return CAFEX_ERROR.INVALID_OPTION; } if (!Directory.Exists(revert_cafe_root)) { Console.WriteLine("cafex revert failed: Target SDK root folder '{0}' does not exist!", revert_cafe_root); return CAFEX_ERROR.INVALID_OPTION; } // Backup these as we and readSDKFromCafeRoot will modify them string OLD_SDK_VER = SDK_VER.value; // Update the SDK version for teh reversion to that of the target SDK if (CAFEX_ERROR.OK != readSDKFromCafeRoot(revert_cafe_root)) { Console.WriteLine("cafex revert failed: Unable to get SDK version from folder '{0}'!", revert_cafe_root); return CAFEX_ERROR.UPDATE_FAILED; } // Get version as an integer and then make sure we're actually attempting a downgrade, else bail out if (compute_flat_version(SDK_VER.value) > compute_flat_version(OLD_SDK_VER)) { Console.WriteLine("cafex revert failed: Target root \"{0}\" contains a higher SDK version than the current SDK. Please use \"cafex update\" instead.", revert_cafe_root); return CAFEX_ERROR.UPDATE_FAILED; } if (use_mixed && (is_DUAL_bootloader_required() || !is_DUAL_bootloader_available())) { Console.WriteLine("cafex recover failed: -mixed argument not supported by this version of the SDK."); return CAFEX_ERROR.INVALID_OPTION; } if (SESSION_MANAGER.value == "1") { if (string.IsNullOrEmpty(CAFERUN_OPTION_NO_DATA_SYNC.value) || CAFERUN_OPTION_NO_DATA_SYNC.value == "0") { ret = syncsession(null); if (CAFEX_ERROR.OK != ret) { return ret; } CAFERUN_OPTION_NO_DATA_SYNC.value = "1"; } } string REVERT_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "revert"); prepare_mlc_revert_content(REVERT_DIR, revert_cafe_root, use_mixed); List recover_opts = new List(); if (reflash) { recover_opts.Add("-reflash"); } else if (noreflash) { recover_opts.Add("-noreflash"); } recover_opts.Add("-source"); recover_opts.Add("/vol/storage_hfiomlc01/revert"); ret = recover(recover_opts.ToArray()); if (ret == 0) { Console.WriteLine("cafex: DEVKIT reverted to SDK {0}", SDK_VER.value); } // Restore the SDK version in case we are called internally SDK_VER.value = OLD_SDK_VER; return ret; } // remove a directory for clean-up, avoiding any errors from removal static void ForceRemoveDirectory(string dirName) { for (int retry = 0; retry < 3; ++retry) { if (retry > 0) { Thread.Sleep(1000); } try { Directory.Delete(dirName, true); break; // stop retrying } catch (Exception e) { Console.WriteLine("ForceRemoveDirecory: Warning: tried to remove [{0}], got exception [{1}], retry={2}", dirName, e.Message, retry); } } } #region caferecover_flags //Script function: caferecover // //Recover_test number decomposition // Digit order: 0xBA9876543210 // Digit 0: // Digit 1: // Digit 2: // Digit 3: // Digit 4: // Digit 5: // Digit 6: // // Default = 0x02223225 internal static UInt64 RECOVER_SDK_MASK = 0x000000000000000F; internal static UInt64 RECOVER_COMMAND_MASK = 0x00000000000000F0; internal static UInt64 RECOVER_ENV_BOOT_MASK = 0x0000000000000F00; internal static UInt64 RECOPT_REFLASH_MASK = 0x000000000000F000; internal static UInt64 RECOPT_NOREFLASH_MASK = 0x00000000000F0000; internal static UInt64 RECOPT_PROD_MASK = 0x0000000000F00000; internal static UInt64 RECOPT_MIXED_MASK = 0x000000000F000000; internal static UInt64 RECOVER_DETECTED_BOOT_MASK = 0x00000000F0000000; internal static UInt64 RECOPT_QUICK_MASK = 0x0000000F00000000; internal static UInt64 RECOPT_DESIRED_BOOT_MASK = 0x000000F000000000; internal static UInt64 RECOPT_LEGACY_MASK = 0x00000F0000000000; internal static UInt64 RECOPT_BOOTLOADER_MASK = 0x0000F00000000000; internal static uint RECOPT_SDK_NOMIXED = 0x00000000; internal static uint RECOPT_SDK_MIXEDNOTREQ = 0x00000001; internal static uint RECOPT_SDK_MIXEDREQ = 0x00000002; internal static uint RECOVER_COMMAND_RECOVER = 0x00000000; internal static uint RECOVER_COMMAND_SBM = 0x00000010; internal static uint RECOVER_COMMAND_UPDATE = 0x00000020; internal static uint RECOVER_COMMAND_INIT = 0x000000030; internal static uint RECOVER_ENV_BOOT_NAND = 0x00000000; internal static uint RECOVER_ENV_BOOT_PCFS = 0x00000100; internal static uint RECOVER_ENV_BOOT_UNKNOWN = 0x00000200; internal static uint RECOPT_REFLASH_UNDEF = 0x00000000; internal static uint RECOPT_REFLASH_DEF = 0x00001000; internal static uint RECOPT_NOREFLASH_UNDEF = 0x00000000; internal static uint RECOPT_NOREFLASH_DEF = 0x00010000; internal static uint RECOPT_PRODUCTION_UNDEF = 0x00000000; internal static uint RECOPT_PRODUCTION_DEF = 0x00100000; internal static uint RECOPT_MIXED_UNDEF = 0x00000000; internal static uint RECOPT_MIXED_DEF = 0x010000000; internal static uint RECOVER_DETECT_BOOT_NAND = 0x00000000; internal static uint RECOVER_DETECT_BOOT_PCFS = 0x10000000; internal static uint RECOVER_DETECT_BOOT_DUAL = 0x20000000; internal static uint RECOVER_DETECT_BOOT_UNKNOWN = 0x30000000; internal static uint RECOPT_QUICK_UNDEF = 0x00000000; internal static UInt64 RECOPT_QUICK_DEF = 0x0000000100000000; internal static uint RECOPT_DESIRED_BOOT_UNDEF = 0x00000000; internal static UInt64 RECOPT_DESIRED_BOOT_PCFS = 0x0000001000000000; internal static UInt64 RECOPT_DESIRED_BOOT_NAND = 0x0000002000000000; internal static uint RECOPT_LEGACY_UNDEF = 0x00000000; internal static UInt64 RECOPT_LEGACY_DEF = 0x0000010000000000; internal static uint RECOPT_BOOTLOADER_UNDEF = 0x00000000; internal static UInt64 RECOPT_BOOTLOADER_DEF = 0x0000100000000000; #endregion static CAFEX_ERROR recover(string[] args) { #if DEBUG Log.WriteLine("recover started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); Log.WriteLine(String.Format("Recover_flags={0:X12}",recover_flags)); #endif // // Command line processing // bool production_bootloader = false; bool bootloader_only = false; bool mixed_arg = false; bool reflash_arg = false; bool noreflash_arg = false; bool reflash = false; // This sets the default behavior for the recover operation bool noreflash = false; const string DEFAULT_RECOVER_SOURCE = "/vol/storage_hfiomlc01/sys/update/pcfs"; const string MIXED_RECOVER_SOURCE = "/vol/storage_hfiomlc01/sys/update/mixed"; const string NAND_RECOVER_SOURCE = "/vol/storage_hfiomlc01/sys/update/nand"; const string BOOTLOADER_RECOVER_SOURCE = "/vol/storage_hfiomlc01/sys/update/bootloader"; string recover_source = DEFAULT_RECOVER_SOURCE; CAFEX_ERROR ret = CAFEX_ERROR.OK; //TODO: replace all returns with "return ret;" if ((recover_flags & RECOVER_COMMAND_MASK) == RECOVER_COMMAND_INIT) { recover_flags = (recover_flags & ~RECOVER_COMMAND_MASK) | RECOVER_COMMAND_RECOVER; } if (is_DUAL_bootloader_available()) { if (is_DUAL_bootloader_required()) { recover_flags = (recover_flags & ~RECOVER_SDK_MASK) | RECOPT_SDK_MIXEDREQ; } else { recover_flags = (recover_flags & ~RECOVER_SDK_MASK) | RECOPT_SDK_MIXEDNOTREQ; } } else { recover_flags = (recover_flags & ~RECOVER_SDK_MASK) | RECOPT_SDK_NOMIXED; } if (args != null) { for (int i = 0; i < args.Length; ++i) { switch (args[i].ToLowerInvariant()) { case "-production": recover_source = NAND_RECOVER_SOURCE; production_bootloader = true; recover_flags = recover_flags & (~RECOPT_PROD_MASK) | RECOPT_PRODUCTION_DEF; //{ // // the -noreflash option was found before the -production // reflash = true; //} break; case "-bootloader": recover_source = BOOTLOADER_RECOVER_SOURCE; bootloader_only = true; recover_flags = (recover_flags & ~RECOPT_BOOTLOADER_MASK) | RECOPT_BOOTLOADER_DEF; break; case "-source": recover_source = args[++i]; break; case "-noreflash": noreflash_arg = true; reflash = false; noreflash = true; recover_flags = (recover_flags & ~RECOPT_NOREFLASH_MASK) | RECOPT_NOREFLASH_DEF; break; case "-reflash": reflash_arg = true; reflash = true; recover_flags = (recover_flags & ~RECOPT_REFLASH_MASK) | RECOPT_REFLASH_DEF; break; case "-mixed": if (is_DUAL_bootloader_required() || !is_DUAL_bootloader_available()) { Console.WriteLine("cafex recover failed: -mixed argument not supported by this version of the SDK."); return CAFEX_ERROR.INVALID_OPTION; } mixed_arg = true; recover_source = MIXED_RECOVER_SOURCE; recover_flags = recover_flags & ~(RECOPT_MIXED_MASK) | RECOPT_MIXED_DEF; break; case "-h": recover_usage(); return CAFEX_ERROR.OK; default: Console.WriteLine("cafex recover failed: Invalid argument"); return CAFEX_ERROR.INVALID_OPTION; } } } if (production_bootloader && bootloader_only) { Console.WriteLine("cafex recover failed: Invalid arguments: Can't specify both -production and -bootloader options!"); return CAFEX_ERROR.INVALID_OPTION; } if (production_bootloader && mixed_arg) { Console.WriteLine("cafex recover failed: Invalid arguments: Can't specify both -production and -mixed options!"); return CAFEX_ERROR.INVALID_OPTION; } if (mixed_arg && bootloader_only) { Console.WriteLine("WARNING: Ignoring -bootloader option since -mixed was specified"); recover_source = MIXED_RECOVER_SOURCE; } if (reflash_arg && noreflash_arg) { Console.WriteLine("cafex recover failed: Can't specify both -reflash and -noreflash! Please remove one or the other."); return CAFEX_ERROR.INVALID_OPTION; } // can't do -reflash -bootloader, but it seems like the intent is to update the bootloader. // Also, only do this if -mixed isn't specified, since -mixed implies -bootloader, and we could be coming // from production NAND, which would require a reflash. if (bootloader_only && reflash_arg && !mixed_arg) { Console.WriteLine("WARNING: Ignoring reflash/noreflash argument since only bootloader is being updated"); reflash = false; noreflash = true; } // Production bootloader must always reflash unless specified if (production_bootloader && !noreflash_arg) { noreflash = false; reflash = true; } // // Initialization // SCRIPT_EXE_TIMESTAMP.value = DateTime.Now.ToString("MMMdd_yyyy_HHmmss"); LOGDIR.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "caferecover\\" + SCRIPT_EXE_TIMESTAMP.value; Console.WriteLine("cafex recover"); Console.WriteLine("log directory is " + LOGDIR.value); create_directory_if_noexist(LOGDIR.value); string old_boot_mode = CAFE_BOOT_MODE.value; bool skip_update = false; CAFE_CONSOLE.value = "toucan"; FileStream fs = null; TextWriter old_out = null; TextWriter old_err = null; StreamWriter sw = null; CAFEX_ERROR hostcheckversion_ret = hostcheckversion(); if (hostcheckversion_ret != CAFEX_ERROR.OK) { return hostcheckversion_ret; } // Stop the DEVKIT to release any resources it may have locked try { stop(new string[] { "-hard" }); } catch (Exception e) { Console.WriteLine("cafex recover[warning]: Failure to hard stop the DEVKIT prior to mode detection, error {0}", e.Message); } Thread.Sleep(1000); if (CAFEX_RECOVER_TEST.value != "1") { if (SESSION_MANAGER.value == "1") { if (string.IsNullOrEmpty(CAFERUN_OPTION_NO_DATA_SYNC.value) || CAFERUN_OPTION_NO_DATA_SYNC.value == "0") { ret = syncsession(null); if (CAFEX_ERROR.OK != ret) { return ret; } CAFERUN_OPTION_NO_DATA_SYNC.value = "1"; } } // Prepare the mixed and bootloader MLC folders prepare_mlc_recover_content(); } //if the mixed bootloader is required by default for this SDK and we haven't redefined //the default recover source (pcfs) through recover's options, change the source to //the mixed bootloader. if (is_DUAL_bootloader_required() && recover_source == DEFAULT_RECOVER_SOURCE) { if (!Directory.Exists(Path.Combine(CAFE_MLC_DIR.value, "sys\\update\\mixed"))) { Console.WriteLine("cafex recover failed: Required mixed content folder '{0}' is missing!", Path.Combine(CAFE_MLC_DIR.value,"sys\\update\\mixed")); return CAFEX_ERROR.UPDATE_FAILED; } recover_source = MIXED_RECOVER_SOURCE; } // Covers the case where we try to specify reflash when targeting legacy PCFS mode // without breaking setbootmode if (recover_source.EndsWith("pcfs") && reflash_arg) { Console.WriteLine("cafex recover failed: Cannot specify -reflash option with legacy PCFS as target package!"); Console.WriteLine("This is the default package for SDKs 2.10.03 and 2.10.04. Please do not specify -reflash without specifying -mixed or -production"); return CAFEX_ERROR.INVALID_OPTION; } Console.WriteLine("recover source directory is " + recover_source); // // Boot mode detection // string boot_mode; int boot_mode_detect = FSEmul.boot_mode_detect(BRIDGE_CURRENT_IP_ADDRESS.value, out boot_mode); if (boot_mode_detect != 0) { Console.WriteLine("Unable to determine boot mode!"); return CAFEX_ERROR.BOOTMODEDETECT_FSEMUL_FAILED; } Console.WriteLine("Detected BOOT mode : {0}", boot_mode); if( boot_mode.Contains("NAND")) { CAFE_BOOT_MODE.value = "NAND"; recover_flags = (recover_flags & ~RECOVER_DETECTED_BOOT_MASK) | RECOVER_DETECT_BOOT_NAND; if (!noreflash && (!recover_source.EndsWith("pcfs") || recover_source.EndsWith("nand"))) { // Reflash by default unless -noreflash was specified or the recover source // is the legacy PCFS boot reflash = true; } } else { CAFE_BOOT_MODE.value = "PCFS"; if (boot_mode.Contains("DUAL")) { recover_flags = (recover_flags & ~RECOVER_DETECTED_BOOT_MASK) | RECOVER_DETECT_BOOT_DUAL; } else { recover_flags = (recover_flags & ~RECOVER_DETECTED_BOOT_MASK) | RECOVER_DETECT_BOOT_PCFS; } } Console.WriteLine("recover_flags={0:X12}", recover_flags); // // cafex on (using the recovery image if booting in PCFS mode) // if (CAFE_BOOT_MODE.value == "NAND") { Console.WriteLine("Executing cafex on..."); fs = new FileStream(LOGDIR.value + "\\cafeon.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); if (CAFEX_RECOVER_TEST.value != "1") { on(new string[] { "-e", "nomodecheck" }, true, true); } Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafeon_mion.log"); } if (CAFEX_RECOVER_TEST.value != "1") { if (monitor_for_output("-k", Nintendo.SDSG.CatToucan.Terms.MENU_SOURCE, MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex recover: monitor failed waiting for cafeon success message."); return CAFEX_ERROR.RECOVERY_FAILED; } } Console.WriteLine("Executing devkitmsg recover -v..."); devkitmsg.recover(); if (CAFEX_RECOVER_TEST.value != "1") { if (monitor_for_output("-K", "WUD_BCMFWCheck", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex recover: monitor failed waiting for devkitmsg recover success message."); return CAFEX_ERROR.RECOVERY_FAILED; } } Console.WriteLine("Executing devkitmsg 'update /vol/storage_hfiomlc01/sys/update/bootloader' -v..."); devkitmsg.update(BOOTLOADER_RECOVER_SOURCE); if (CAFEX_RECOVER_TEST.value != "1") { if (monitor_for_output("-k", "Update Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex recover: monitor failed waiting for devkitmsg 1st update success message."); return CAFEX_ERROR.RECOVERY_FAILED; } } CAFE_BOOT_MODE.value = "PCFS"; // Change to PCFS for the rest of the update if (bootloader_only) { // We have already updated the bootloader and since we were only // going to update it, skip the rest of update. skip_update = true; } // // cafestop // Console.WriteLine("Executing cafex stop..."); try { stop(new string[] { "-hard" }); } catch (Exception e) { Console.WriteLine("cafex recover[warning]: Failure to hard stop the DEVKIT after bootloader update, error {0}", e.Message); } CAFE_RUN_RUNNING.value = "0"; } if (!skip_update) { Console.WriteLine("Executing cafex on -recover..."); fs = new FileStream(LOGDIR.value + "\\cafeon.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); if(CAFEX_RECOVER_TEST.value != "1") on(new string[] { "-e", "nomodecheck", "-recover" }, true, true); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafeon_mion.log"); } if (CAFEX_RECOVER_TEST.value != "1") { if (monitor_for_output("-K", "WUD_BCMFWCheck", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex recover: monitor failed waiting for devkitmsg recover success message."); return CAFEX_ERROR.RECOVERY_FAILED; } } // Make sure Cafe is ready for commands int syncTry = 0; cattoucan.BeginBootSync(); for (syncTry = 0; syncTry < CAFERUN_RETRY_COUNT; ++syncTry) { if (cattoucan.SendSyncRequest(DEVKIT_HELP_REQUEST_TIMEOUT)) { break; } } for (; syncTry < CAFERUN_RETRY_COUNT; ++syncTry) { if (cattoucan.SyncWithBoot(DEVKIT_HELP_RESPONSE_TIMEOUT)) { break; } } cattoucan.FinishSync(true); if (syncTry >= CAFERUN_RETRY_COUNT) { Console.WriteLine("Failed to sync with device"); return CAFEX_ERROR.RECOVERY_FAILED; } // // Install the bootloader and content // if (reflash) { Console.WriteLine("Executing devkitmsg 'reflash '{0}' -v...", recover_source); devkitmsg.reflash(recover_source); if (CAFEX_RECOVER_TEST.value != "1") { if (monitor_for_output("-k", "System update was successful", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex recover: monitor failed waiting for devkitmsg 1st update success message."); return CAFEX_ERROR.RECOVERY_FAILED; } } else { return CAFEX_ERROR.OK; } } else { Console.WriteLine("Executing devkitmsg 'update {0}' -v...", recover_source); devkitmsg.update(recover_source); if (CAFEX_RECOVER_TEST.value != "1") { if (monitor_for_output("-k", "Update Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex recover: monitor failed waiting for devkitmsg 1st update success message."); return CAFEX_ERROR.RECOVERY_FAILED; } } else { return CAFEX_ERROR.OK; } } // // Enable self-refresh // if (CAFE_TEST_SELF_REFRESH.value == "1") { Console.WriteLine("Executing devkitmsg standby_en 1 -v..."); devkitmsg.standby_en(1); } // Update the DEV-KIT SDK variables to current setMionSDKVersion(); ret = readSDKFromMion(); if (ret != CAFEX_ERROR.OK) //something bad happened in mionps { return ret; } // // cafestop // Console.WriteLine("Executing cafex stop..."); fs = new FileStream(LOGDIR.value + "\\cafestop1.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); stop(null); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafestop1_mion.log"); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex recover: cafestop failure."); return CAFEX_ERROR.RECOVERY_FAILED; } } if (production_bootloader || old_boot_mode == "NAND") { // Update the MION parameter space for NAND boot mode if (mionps.Run(String.Format("{0} {1} -s {2}",BRIDGE_CURRENT_IP_ADDRESS.value,MIONPS_BOOT_BYTE,MIONPS_BOOT_NAND)) != "1") { Console.WriteLine("cafex recover: unable to set NAND boot mode using mionps."); return CAFEX_ERROR.RECOVERY_FAILED; } } else { // Update the MION parameter space for PCFS boot mode if (mionps.Run(String.Format("{0} {1} -s {2}",BRIDGE_CURRENT_IP_ADDRESS.value,MIONPS_BOOT_BYTE,MIONPS_BOOT_PCFS)) != "2") { Console.WriteLine("cafex recover: unable to set PCFS boot mode using mionps."); return CAFEX_ERROR.RECOVERY_FAILED; } } // // Success! // Console.WriteLine("Removing log directory " + LOGDIR.value + "..."); ForceRemoveDirectory(LOGDIR.value); Console.WriteLine("cafex recover complete. Exiting with code 0"); if (production_bootloader && old_boot_mode != "NAND") { Console.WriteLine(); Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); Console.WriteLine("!! !!"); Console.WriteLine("!! Boot Loader/Boot Mode mis-match detected! !!"); Console.WriteLine("!! !!"); Console.WriteLine("!! Please export CAFE_BOOT_MODE=NAND for proper operation! !!"); Console.WriteLine("!! !!"); Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } return CAFEX_ERROR.OK; } //Script function: cafex cleardata static CAFEX_ERROR cleardata(params string[] args) { #if DEBUG Log.WriteLine("cleardata started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif // Handle arguments if (args != null && args.Length > 0) { foreach (string arg in args) { switch (arg.ToLowerInvariant()) { case "-h": cleardata_usage(); return CAFEX_ERROR.OK; default: cleardata_usage(); return CAFEX_ERROR.INVALID_OPTION; } } } // // Initialization // SCRIPT_EXE_TIMESTAMP.value = DateTime.Now.ToString("MMMdd_yyyy_HHmmss"); LOGDIR.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "cleardata\\" + SCRIPT_EXE_TIMESTAMP.value; Console.WriteLine("cafex cleardata"); Console.WriteLine("log directory is " + LOGDIR.value); create_directory_if_noexist(LOGDIR.value); CAFE_CONSOLE.value = "toucan"; FileStream fs = null; TextWriter old_out = null; TextWriter old_err = null; StreamWriter sw = null; // // Boot mode detection // CAFEX_ERROR hostcheckversion_ret = hostcheckversion(); if (hostcheckversion_ret != CAFEX_ERROR.OK) { Console.WriteLine("cafex cleardata: failed running hostcheckversion."); return hostcheckversion_ret; } int hb_ver_flat = compute_flat_version(CAFERUN_HOSTBRIDGE_VERSION.value); if (hb_ver_flat < compute_flat_version("3.2.4.8")) { Console.WriteLine("Error: Clear user data not supported in this version of the HostBridge!"); Console.WriteLine(" Please update your HostBridge to at least version 3.2.4.8 (preferably the latest) and try again."); Console.WriteLine("cafex cleardata failed."); return CAFEX_ERROR.CLEARDATA_FAILED; } else { string boot_mode; // hostbridge 3.2.5.1 has a problem in mode detection that requires some time after stop // in order to properly detect boot mode try { stop(new string[] { "-hard" }); } catch (Exception e) { Console.WriteLine("cafex recover[warning]: Failure to hard stop the DEVKIT prior to mode detection, error {0}", e.Message); } Thread.Sleep(1000); int boot_mode_detect = FSEmul.boot_mode_detect(BRIDGE_CURRENT_IP_ADDRESS.value, out boot_mode); if (boot_mode_detect != 0) { Console.WriteLine("Unable to determine boot mode!"); return CAFEX_ERROR.BOOTMODEDETECT_FSEMUL_FAILED; } Console.WriteLine("Detected BOOT mode : {0}", boot_mode); if (boot_mode == "NAND") { CAFE_BOOT_MODE.value = "NAND"; } else { CAFE_BOOT_MODE.value = "PCFS"; } } if (CAFE_BOOT_MODE.value == "NAND") { stop(null); Console.WriteLine("Error: Can't clear user data in NAND boot mode! Please switch to PCFS boot mode and try again."); Console.WriteLine("cafex cleardata failed."); return CAFEX_ERROR.CLEARDATA_FAILED; } Console.WriteLine("Executing cafex on..."); fs = new FileStream(LOGDIR.value + "\\cafeon.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); // cafeon if (hb_ver_flat < compute_flat_version("3.2.4.1")) { on(null, true, true); } else { on(new string[] { "-e", "nomodecheck" }, true, true); } Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafeon_mion.log"); } if (monitor_for_output("-k", Nintendo.SDSG.CatToucan.Terms.MENU_SOURCE, MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex cleardata: monitor failed waiting for cafeon success message."); return CAFEX_ERROR.CLEARDATA_FAILED; } Console.WriteLine("Executing devkitmsg recover -v..."); devkitmsg.recover(); if (monitor_for_output("-K", "WUD_BCMFWCheck", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex cleardata: monitor failed waiting for devkitmsg recover success message."); return CAFEX_ERROR.CLEARDATA_FAILED; } //clr_usrdata command Console.WriteLine("Executing devkitmsg clr_usrdata -v..."); devkitmsg.clr_usrdata(); if (monitor_for_output("-k", "Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex cleardata: monitor failed waiting for devkitmsg clr_usrdata success message."); return CAFEX_ERROR.CLEARDATA_FAILED; } //cafestop Console.WriteLine("Executing cafex stop..."); fs = new FileStream(LOGDIR.value + "\\cafestop1.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); stop(null); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafestop1_mion.log"); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex cleardata: cafestop failure."); return CAFEX_ERROR.CLEARDATA_FAILED; } //success! Console.WriteLine("Removing log directory " + LOGDIR.value + "..."); ForceRemoveDirectory(LOGDIR.value); Console.WriteLine("cafex cleardata complete. Exiting with code 0"); return CAFEX_ERROR.OK; } //Script function: setbootmode static CAFEX_ERROR setbootmode(string[] args) { #if DEBUG Log.WriteLine("setbootmode started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif CAFEX_ERROR returnValue = CAFEX_ERROR.SETBOOTMODE_FAILED; bool reflash = false; bool noreflash = false; bool mixed = false; bool prod = true; //not having this will break "setbootmode PCFS" in SDKs 2.10.01-2.10.08 bool prod_arg = false; //specifically for the -quick case conditional if ((recover_flags & RECOVER_COMMAND_MASK) == RECOVER_COMMAND_INIT) { recover_flags = (recover_flags & ~RECOVER_COMMAND_MASK) | RECOVER_COMMAND_SBM; } if (is_DUAL_bootloader_required()) { mixed = true; prod = false; } else //the bootloader isn't available or not required { mixed = false; prod = true; } bool quick = false; bool reflash_arg = false; bool noreflash_arg = false; string target = string.Empty; for (int idx = 0; idx < args.Length; idx++) { if (args[idx] == "-noreflash") //uses the update command with devkitmsg { noreflash_arg = true; reflash = false; noreflash = true; recover_flags = (recover_flags & ~RECOPT_NOREFLASH_MASK) | RECOPT_NOREFLASH_DEF; } else if (args[idx] == "-reflash") //uses the reflash command with devkitmsg { reflash_arg = true; noreflash = false; reflash = true; recover_flags = (recover_flags & ~RECOPT_REFLASH_MASK) | RECOPT_REFLASH_DEF; } else if (args[idx] == "-production" || args[idx] == "-P") { mixed = false; prod = true; prod_arg = true; reflash = true; recover_flags = (recover_flags & ~RECOPT_PROD_MASK) | RECOPT_PRODUCTION_DEF; //if (!noreflash) //{ // // the -noreflash option was found before -production // reflash = true; //} } else if (args[idx] == "-quick" || args[idx] == "-Q") { quick = true; recover_flags = (recover_flags & ~RECOPT_QUICK_MASK) | RECOPT_QUICK_DEF; } else if (args[idx] == "-h") { setbootmode_usage(); return CAFEX_ERROR.OK; } //included for backward compatibility. If both mixed and prod are specified, prod will take precedence. else if (args[idx] == "-mixed") { recover_flags = (recover_flags & ~RECOPT_MIXED_MASK) | RECOPT_MIXED_DEF; //This option was only valid on SDKs 2.10.01-2.10.09 if (is_DUAL_bootloader_available() && !is_DUAL_bootloader_required()) { mixed = true; prod = false; } else { Console.WriteLine("-mixed option is not supported on this SDK."); return CAFEX_ERROR.INVALID_OPTION; } } else { if (!string.IsNullOrEmpty(target)) { setbootmode_usage(); return CAFEX_ERROR.INVALID_OPTION; } if (!ArgumentChecks.IsArgumentValidSetting(args, idx)) { setbootmode_usage(); return CAFEX_ERROR.INVALID_OPTION; } if (args[idx] != "NAND" && args[idx] != "PCFS") { Console.WriteLine("cafex setbootmode error: {0} is not a valid boot mode!", args[idx]); setbootmode_usage(); return CAFEX_ERROR.SETBOOTMODE_BAD_MODE; } target = args[idx]; } } if (string.IsNullOrEmpty(target)) { setbootmode_usage(); return CAFEX_ERROR.INVALID_OPTION; } if (reflash_arg && noreflash_arg) { Console.WriteLine("Can't specify both -reflash and -noreflash! Please remove one or the other."); return CAFEX_ERROR.INVALID_OPTION; } string status_str = "FAIL"; if (quick) { if (prod_arg) { Console.WriteLine("cafex setbootmode error: Can't specify both -quick and -production options!"); setbootmode_usage(); return CAFEX_ERROR.BAD_ARGUMENT; } CAFEX_ERROR hostcheckversion_ret = hostcheckversion(); if (hostcheckversion_ret != CAFEX_ERROR.OK) { Console.WriteLine("cafex setbootmode: failed running hostcheckversion."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } int hb_ver_flat = compute_flat_version(CAFERUN_HOSTBRIDGE_VERSION.value); if (hb_ver_flat < compute_flat_version("3.2.4.8")) { Console.WriteLine("cafex setbootmode: This version of the HostBridge doesn't support boot mode detection!."); Console.WriteLine(" Please update to it at least version 3.2.4.8 and try again."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } string boot_mode; // hostbridge 3.2.5.1 has a problem in mode detection that requires some time after stop // in order to properly detect boot mode stop(new string[] { "-hard" }); Thread.Sleep(1000); int boot_mode_detect = FSEmul.boot_mode_detect(BRIDGE_CURRENT_IP_ADDRESS.value, out boot_mode); if (boot_mode_detect != 0) { Console.WriteLine("cafex setbootmode: Error: Unable to determine boot mode!"); return CAFEX_ERROR.BOOTMODEDETECT_FSEMUL_FAILED; } stop(new string[] { "-hard" }); Console.WriteLine("cafex setbootmode: Detected BOOT mode : {0}", boot_mode); if(boot_mode.Contains("PCFS")) { recover_flags = (recover_flags & ~RECOVER_DETECTED_BOOT_MASK) | RECOVER_DETECT_BOOT_PCFS; } else if (boot_mode.Contains("NAND")) { recover_flags = (recover_flags & ~RECOVER_DETECTED_BOOT_MASK) | RECOVER_DETECT_BOOT_NAND; } else if (boot_mode.Contains("DUAL")) { recover_flags = (recover_flags & ~RECOVER_DETECTED_BOOT_MASK) | RECOVER_DETECT_BOOT_DUAL; } if (!boot_mode.StartsWith ("DUAL")) { Console.WriteLine("cafex setbootmode: Error: DUAL bootloader is not installed. Please run cafex recover -bootloader to install."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } if (target == "NAND") { recover_flags = (recover_flags & ~RECOPT_DESIRED_BOOT_MASK) | RECOPT_DESIRED_BOOT_NAND; // Update the MION parameter space for NAND boot mode if (mionps.Run(String.Format("{0} {1} -s {2}",BRIDGE_CURRENT_IP_ADDRESS.value,MIONPS_BOOT_BYTE,MIONPS_BOOT_NAND)) != "1") { Console.WriteLine("cafex unable to set NAND mode using mionps."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } } else { recover_flags = (recover_flags & ~RECOPT_DESIRED_BOOT_MASK) | RECOPT_DESIRED_BOOT_PCFS; // Update the MION parameter space for PCFS boot mode if (mionps.Run(String.Format("{0} {1} -s {2}",BRIDGE_CURRENT_IP_ADDRESS.value,MIONPS_BOOT_BYTE,MIONPS_BOOT_PCFS)) != "2") { Console.WriteLine("cafex unable to set PCFS mode using mionps."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } } if (CAFEX_RECOVER_TEST.value == "1") { Console.WriteLine("recover_flags={0:X12}", recover_flags); Console.WriteLine("devkitmsg_cmd: NA"); } returnValue = CAFEX_ERROR.OK; status_str = "PASS"; } else { switch (target) { case "PCFS": { recover_flags = (recover_flags & ~RECOPT_DESIRED_BOOT_MASK) | RECOPT_DESIRED_BOOT_PCFS; if (prod_arg) { Console.WriteLine("cafex setbootmode: Can't specify -production with the PCFS boot mode!"); return CAFEX_ERROR.SETBOOTMODE_FAILED; } List recover_args = new List(); if (mixed) { Console.WriteLine("Executing cafex recover for mixed PCFS..."); if (!is_DUAL_bootloader_required()) recover_args.Add("-mixed"); } else { Console.WriteLine("Executing cafex recover for legacy PCFS..."); } if (noreflash) { recover_args.Add("-noreflash"); } else if (reflash) { recover_args.Add("-reflash"); } returnValue = recover(recover_args.ToArray()); if (returnValue == CAFEX_ERROR.OK) { // Set the CAT-DEV mode inside mion... if (mionps.Run(String.Format("{0} {1} -s {2}",BRIDGE_CURRENT_IP_ADDRESS.value,MIONPS_BOOT_BYTE,MIONPS_BOOT_PCFS)) != "2") { Console.WriteLine("cafex unable to set mode using mionps."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } CAFE_BOOT_MODE.value = "PCFS"; Console.WriteLine("CAFE_BOOT_MODE=" + CAFE_BOOT_MODE.value); status_str = "PASS"; } break; } case "NAND": { recover_flags = (recover_flags & ~RECOPT_DESIRED_BOOT_MASK) | RECOPT_DESIRED_BOOT_NAND; List recover_args = new List(); if (prod) { Console.WriteLine("Executing cafex recover for production NAND..."); recover_args.Add("-production"); } else { Console.WriteLine("Executing cafex recover for mixed NAND..."); if (!is_DUAL_bootloader_required()) // SDK 2.10.11+ will error if -mixed is specified recover_args.Add("-mixed"); } if (noreflash) { recover_args.Add("-noreflash"); } else if (reflash) { recover_args.Add("-reflash"); } returnValue = recover(recover_args.ToArray()); if (returnValue == CAFEX_ERROR.OK) { // Set the CAT-DEV mode inside mion... if (mionps.Run(String.Format("{0} {1} -s {2}",BRIDGE_CURRENT_IP_ADDRESS.value,MIONPS_BOOT_BYTE,MIONPS_BOOT_NAND)) != "1") { Console.WriteLine("cafex unable to set mode using mionps."); return CAFEX_ERROR.SETBOOTMODE_FAILED; } CAFE_BOOT_MODE.value = "NAND"; Console.WriteLine("CAFE_BOOT_MODE=" + CAFE_BOOT_MODE.value); status_str = "PASS"; } break; } default: { Console.WriteLine("cafex setbootmode error: Invalid boot mode"); status_str = "BAD MODE"; setbootmode_usage(); returnValue = CAFEX_ERROR.SETBOOTMODE_BAD_MODE; break; } } } Console.WriteLine("cafex setbootmode: " + status_str); if (returnValue == CAFEX_ERROR.OK) { returnValue = readSDKFromMion(); if (returnValue != CAFEX_ERROR.OK) { return returnValue; //something bad happened in mionps } setMionSDKVersion(); } return returnValue; } #if false //Script function: cafe_nand2pcfs static int nand2pcfs(int call_mionps) { #if DEBUG Log.WriteLine("nand2pcfs started."); #endif // Initialization SCRIPT_EXE_TIMESTAMP.value = DateTime.Now.ToString("MMMdd_yyyy_HHmmss"); LOGDIR.value = CAFE_ROOT.value + "\\" + SESSION_PATH_PREFIX.value + "cafe_nand2pcfs\\" + SCRIPT_EXE_TIMESTAMP.value; Console.WriteLine("cafe_nand2pcfs"); Console.WriteLine("log directory is " + LOGDIR.value); create_directory_if_noexist(LOGDIR.value); File.Delete(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log"); CAFESTOP_STATUS.value = "0"; _CCRSYSCFG1.value = ""; if (initialize_serial_port_and_directory("cafestop") != 0) return 1; //cafestop Console.WriteLine("Executing cafex stop..."); FileStream fs = new FileStream(LOGDIR.value + "\\cafestop0.txt", FileMode.Create); TextWriter old_out = Console.Out; TextWriter old_err = Console.Error; StreamWriter sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); stop(new string[] {"-hard"}); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafestop0_mion.log"); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex nand2pcfs: cafestop failure."); return 1; } //cafeon CAFEX_ERROR hostcheckversion_ret = hostcheckversion(); if (hostcheckversion_ret != CAFEX_ERROR.OK) { Console.WriteLine("cafex nand2pcfs: failed running hostcheckversion."); return 1; } int hb_ver_flat = compute_flat_version(CAFERUN_HOSTBRIDGE_VERSION.value); Console.WriteLine("Executing cafex on..."); fs = new FileStream(LOGDIR.value + "\\cafeon.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); //quiet_mode = true; // This breaks setbootmode in NAND/softlaunch Console.WriteLine("at on command"); if (hb_ver_flat < compute_flat_version("3.2.4.1")) { on(null, true, true); } else { on(new string[] { "-e", "nomodecheck" }, true, true); } Console.WriteLine("after on command"); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafeon_mion.log"); } if (monitor_for_output("-k", Nintendo.SDSG.CatToucan.Terms.MENU_SOURCE, MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex nand2pcfs: monitor failed waiting for cafeon success message."); return 1; } //recover command Console.WriteLine("Executing devkitmsg recover -v..."); devkitmsg.recover(); if (monitor_for_output("-K", "WUD_BCMFWCheck", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex nand2pcfs: monitor failed waiting for devkitmsg recover success message."); return 1; } //update to PCFS Console.WriteLine("Executing devkitmsg 'update /vol/storage_hfiomlc01/sys/update/pcfs' -v..."); devkitmsg.update_pcfs(); if (monitor_for_output("-k", "Update Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex nand2pcfs: monitor failed waiting for devkitmsg 1st update success message."); return 1; } if (call_mionps == 1) { // Set the CAT-DEV mode inside mion... if (mionps.Run(BRIDGE_CURRENT_IP_ADDRESS.value + " 2 -s 2") != "2") { Console.WriteLine("cafex unable to set mode using mionps."); return 1; } } //clr_usrdata command Console.WriteLine("Executing devkitmsg clr_usrdata -v..."); devkitmsg.clr_usrdata(); if (monitor_for_output("-k", "Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex nand2pcfs: monitor failed waiting for devkitmsg clr_usrdata success message."); return 1; } //enable self-refresh if (CAFE_TEST_SELF_REFRESH.value == "1") { Console.WriteLine("Executing devkitmsg standyby_en 1 -v..."); devkitmsg.standby_en(1); } //cafestop Console.WriteLine("Executing cafex stop..."); fs = new FileStream(LOGDIR.value + "\\cafestop1.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); stop(null); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafestop1_mion.log"); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex nand2pcfs: cafestop failure."); return 1; } //success! Console.WriteLine("Removing log directory " + LOGDIR.value + "..."); ForceRemoveDirectory(LOGDIR.value); Console.WriteLine("cafex nand2pcfs complete. Exiting with code 0"); return 0; } #endif #if false //Script function: cafe_pcfs2nand static int pcfs2nand(int reflash, int call_mionps) { #if DEBUG Log.WriteLine("pcfs2nand started."); #endif // Initialization SCRIPT_EXE_TIMESTAMP.value = DateTime.Now.ToString("MMMdd_yyyy_HHmmss"); LOGDIR.value = CAFE_ROOT.value + "\\" + SESSION_PATH_PREFIX.value + "cafe_pcfs2nand\\" + SCRIPT_EXE_TIMESTAMP.value; Console.WriteLine("cafe_pcfs2nand"); Console.WriteLine("log directory is " + LOGDIR.value); create_directory_if_noexist(LOGDIR.value); File.Delete(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log"); CAFESTOP_STATUS.value = "0"; _CCRSYSCFG1.value = ""; if (initialize_serial_port_and_directory("cafestop") != 0) return 1; //cafestop Console.WriteLine("Executing cafex stop..."); FileStream fs = new FileStream(LOGDIR.value + "\\cafestop0.txt", FileMode.Create); TextWriter old_out = Console.Out; TextWriter old_err = Console.Error; StreamWriter sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); stop(null); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafestop0_mion.log"); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex nand2pcfs: cafestop failure."); return 1; } //cafeon CAFEX_ERROR hostcheckversion_ret = hostcheckversion(); if (hostcheckversion_ret != CAFEX_ERROR.OK) { Console.WriteLine("cafex nand2pcfs: failed running hostcheckversion."); return 1; } int hb_ver_flat = compute_flat_version(CAFERUN_HOSTBRIDGE_VERSION.value); Console.WriteLine("Executing cafex on..."); fs = new FileStream(LOGDIR.value + "\\cafeon.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); //quiet_mode = true; // This breaks setbootmode in NAND/softlaunch Console.WriteLine("at on command"); if (hb_ver_flat < compute_flat_version("3.2.4.1")) { on(null, true, true); } else { on(new string[] { "-e", "nomodecheck" }, true, true); } Console.WriteLine("after on command"); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafeon_mion.log"); } if (monitor_for_output("-k", "source -p -q /vol/content/", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex nand2pcfs: monitor failed waiting for cafeon success message."); return 1; } bool was_pcfs_boot = false; fs = new FileStream(LOGDIR.value + "\\monitor_1.txt", FileMode.Open, FileAccess.Read); StreamReader sr = new StreamReader(fs); string contents = sr.ReadToEnd(); sr.Close(); if (contents.Contains("BOOT1: Loaded firmware image from SDIO.")) { was_pcfs_boot = true; } //recover command Console.WriteLine("Executing devkitmsg recover -v..."); devkitmsg.recover(); if (monitor_for_output("-K", "WUD_BCMFWCheck", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex nand2pcfs: monitor failed waiting for devkitmsg recover success message."); return 1; } // if last boot was NAND, first update BOOT1 to PCFS if (was_pcfs_boot == false) { const string dual_boot1_folder = "aaa-boot1-dual"; string BL_DEST_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "sys\\update\\bootloader"); string MIXED_DEST_DIR = Path.Combine(Program.CAFE_MLC_DIR.value, "sys\\update\\mixed"); Console.WriteLine("cafex pcfs2nand: NAND boot detected, BOOT1 will be updated before updating to NAND"); Console.WriteLine("Executing devkitmsg 'update /vol/storage_hfiomlc01/sys/update/mixed' -v..."); // here we ensure we start from a flexible, configurable system Console.WriteLine("cafex: Checking content in '{0}'", BL_DEST_DIR); // Create the DUAL boot loader only directory if ir does not exist create_directory_if_noexist(BL_DEST_DIR); // Create a junction for the DUAL bootloader in the bootloader dest dir if (!Directory.Exists(Path.Combine(BL_DEST_DIR, dual_boot1_folder))) { #if DEBUG Console.WriteLine("Copying directory '{0}' => '{1}'", Path.Combine(MIXED_DEST_DIR, dual_boot1_folder), Path.Combine(BL_DEST_DIR, dual_boot1_folder)); #endif // // Symbolic links require NTFS which *should* not be a problem for most but // require elevated privledges, which is an issue if the user is not an admin or with UAC. // // We copy the folders instead of linking them as it is relatively fast and more compatible with UAC. // FileUtil.DirectoryCopy(Path.Combine(MIXED_DEST_DIR, dual_boot1_folder), Path.Combine(BL_DEST_DIR, dual_boot1_folder), false); } devkitmsg.update(BOOTLOADER_RECOVER_SOURCE); if (monitor_for_output("-k", "Update Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex pcfs2nand: monitor failed waiting for devkitmsg 1st update success message."); return 1; } } else { Console.WriteLine("cafe_pcfs2nand: PCFS boot detected, no BOOT1 update needed"); } //update command if (reflash == 1) { Console.WriteLine("Executing devkitmsg 'reflash /vol/storage_hfiomlc01/sys/update/nand' -v..."); devkitmsg.update_reflash(); if (monitor_for_output("-k", "MCP: System update was successful", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex pcfs2nand: monitor failed waiting for devkitmsg reflash success message."); return 1; } } else { Console.WriteLine("Executing devkitmsg 'update /vol/storage_hfiomlc01/sys/update/nand' -v..."); devkitmsg.update_nand(); if (monitor_for_output("-k", "Update Done, err 0", MONITOR_DEFAULT_TIMEOUT.value, LOGDIR.value, null, true) != 0) { Console.WriteLine("cafex pcfs2nand: monitor failed waiting for devkitmsg update success message."); return 1; } } if (call_mionps == 1) { // Set the CAT-DEV mode inside mion... if (mionps.Run(BRIDGE_CURRENT_IP_ADDRESS.value + " 2 -s 1") != "1") { Console.WriteLine("cafex unable to set mode using mionps."); return 1; } } // set default boot mode to development devkitmsg.sys_mode_dev(); //cafestop Console.WriteLine("Executing cafex stop..."); fs = new FileStream(LOGDIR.value + "\\cafestop1.txt", FileMode.Create); old_out = Console.Out; old_err = Console.Error; sw = new StreamWriter(fs); Console.SetOut(sw); Console.SetError(sw); stop(null); Console.SetOut(old_out); Console.SetError(old_err); sw.Flush(); sw.Close(); if (File.Exists(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log")) { File.Move(TMP.value + "\\" + SESSION_PATH_PREFIX.value + "cafestop_mion.log", LOGDIR.value + "\\cafestop1_mion.log"); } if (CAFESTOP_STATUS.value != "0") { Console.WriteLine("cafex pcfs2nand: cafestop failure."); return 1; } //success! Console.WriteLine("Removing log directory " + LOGDIR.value + "..."); ForceRemoveDirectory(LOGDIR.value); Console.WriteLine("cafex pcfs2nand complete. Exiting with code 0"); return 0; } #endif //Script function: hostcheckversion static CAFEX_ERROR hostcheckversion() { #if DEBUG Log.WriteLine("hostcheckversion started."); #endif getbridgetype(); string min_fw_ver = string.Empty; string min_sw_ver = string.Empty; if (BRIDGE_TYPE.value == "Mion") { min_fw_ver = MIN_MION_FW_VER; min_sw_ver = MIN_MION_SW_VER; } else { min_sw_ver = "2.9.1.5"; min_fw_ver = "2.8.0.13"; } if (SDIO_BRIDGE_TOOLS.value == null) { if (MION_BRIDGE_TOOLS.value == null) { Console.WriteLine("cafex run failed: Please install HostBridge (version >= " + min_sw_ver + ") and reopen the build environment!"); return CAFEX_ERROR.HOSTCHECKVERSION_NO_HOSTBRIDGE; } } if (fw_ver_flat == 0 || sw_ver_flat == 0) { string fw_ver = string.Empty; string sw_ver = string.Empty; if (BRIDGE_TYPE.value == "Mion") { FSEmul.FW_SW_Version(BRIDGE_CURRENT_IP_ADDRESS.value, out fw_ver, out sw_ver); } else { FSEmul.FW_SW_Version(null, out fw_ver, out sw_ver); } if (fw_ver == string.Empty || sw_ver == string.Empty) { Console.WriteLine("cafex run failed: Cannot check HostBridge version. Please stop the DEVKIT and try again."); return CAFEX_ERROR.HOSTCHECKVERSION_FSEMUL_FAILED; } fw_ver_flat = compute_flat_version(fw_ver); sw_ver_flat = compute_flat_version(sw_ver); CAFERUN_HOSTBRIDGE_VERSION.value = sw_ver; CAFERUN_FW_VERSION.value = fw_ver; } else { CAFERUN_HOSTBRIDGE_VERSION.value = compute_ver_string(sw_ver_flat); CAFERUN_FW_VERSION.value = compute_ver_string(fw_ver_flat); } int min_fw_flat = compute_flat_version(min_fw_ver); int min_sw_flat = compute_flat_version(min_sw_ver); if (sw_ver_flat < min_sw_flat || fw_ver_flat < min_fw_flat) { Console.WriteLine("cafex run failed: Please upgrade the HostBridge to at least version " + min_sw_ver + " and reopen the build environment!"); Console.WriteLine(" Current software version is " + CAFERUN_HOSTBRIDGE_VERSION.value + " (need " + min_sw_ver + ")"); Console.WriteLine(" Current firmware version is " + CAFERUN_FW_VERSION.value + " (need " + min_fw_ver + ")"); return CAFEX_ERROR.HOSTCHECKVERSION_OLD_VERSIONS; } return CAFEX_ERROR.OK; } //Script function: syncsession static CAFEX_ERROR syncsession(string[] args) { #if DEBUG Log.WriteLine("syncsession started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif if (args != null && args.Length > 0) { if (args[0] == "-h") { syncsession_usage(); return CAFEX_ERROR.OK; } else { Console.WriteLine("cafex syncsession failed: Invalid argument"); return CAFEX_ERROR.INVALID_OPTION; } } //if we're not in a multisession this has no effect so display a warning if (SESSION_MANAGER.value != "1") { Console.WriteLine("WARNING: syncsession command has no effect in a single-devkit environment!"); } else { stop(null); SYNCTOOL_SRC.value = PathConverter.Windowsify(Path.Combine(CAFE_ROOT.value, "data")); SYNCTOOL_DEST.value = PathConverter.Windowsify(CAFE_DATA_DIR.value); SYNCTOOL_CFG.value = PathConverter.Windowsify(Path.Combine(CAFE_ROOT.value, "system/bin/tool/synctool.data.xml")); SYNCTOOL_LOG.value = PathConverter.Windowsify(Path.Combine(CAFE_ROOT.value, SESSION_PATH_PREFIX.value + "sync.log")); Console.WriteLine("cafex syncsession: Syncronizing {0} ===> {1}...", SYNCTOOL_SRC.value, SYNCTOOL_DEST.value); int SYNCTOOL_RVAL = synctool.sync(SYNCTOOL_CFG.value, SYNCTOOL_SRC.value, SYNCTOOL_DEST.value, SYNCTOOL_LOG.value); if (SYNCTOOL_RVAL != 0) { Console.WriteLine(" : Session data sync FAILED with exit code {0}!", SYNCTOOL_RVAL); Console.WriteLine(" : See {0} for details.", SYNCTOOL_LOG.value); return CAFEX_ERROR.SYNCTOOL_FAILED; } else { Console.WriteLine(" : Session data sync log at {0}", SYNCTOOL_LOG.value); } } return CAFEX_ERROR.OK; } private static String getPathToMakeCfMaster() { Assembly assembly = Assembly.GetExecutingAssembly(); String path = assembly.Location; String directory = Path.GetDirectoryName(path); String filename = directory + @"\makecfmaster.exe"; if (File.Exists(filename)) return filename; directory = Environment.GetEnvironmentVariable("CAFE_MASTERING_TOOLS"); if (directory != null) { filename = directory + @"\makecfmaster.exe"; if (File.Exists(filename)) { return filename; } } directory = Environment.GetEnvironmentVariable("CAFE_ROOT"); if (directory != null) { filename = directory + @"\system\bin\tool\mastering\makecfmaster.exe"; if (File.Exists(filename)) { return filename; } } return null; } private static void processDataReceived(object sender, DataReceivedEventArgs args) { Console.WriteLine(args.Data); } static CAFEX_ERROR makeMaster(string[] args) { #if DEBUG Log.WriteLine("master started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif Process p = new Process(); p.StartInfo.FileName = getPathToMakeCfMaster(); p.StartInfo.Arguments = "archive " + string.Join(" ", args); p.StartInfo.CreateNoWindow = true; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; try { p.Start(); p.OutputDataReceived += processDataReceived; p.ErrorDataReceived += processDataReceived; p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.WaitForExit(); } catch (Win32Exception e) { Console.Write(e.Message); return CAFEX_ERROR.MASTERING_ERROR; } Int64 returnVal = p.ExitCode; if (returnVal != 0) { Console.WriteLine("MAKE DISC ERROR!!! CODE: {0}", returnVal); CAFEX_ERROR masteringError = (CAFEX_ERROR)returnVal; return masteringError; } return CAFEX_ERROR.OK; } //this function emulates cafediscrun upto creation of //.dlf file. Then it calls cafeon with -c option to launch //the title through system config tool. //Steps: //1. Create dlf file //2. Make sure to append the file to arguments to // FSEmul.exe //3. Call on with -c "launch -p -l . You can get the title // id from app.xml of the title static CAFEX_ERROR launchTitle(string[] args) { CAFEX_ERROR result = CAFEX_ERROR.OK; #if DEBUG Log.WriteLine("makeDownload started."); string argString = null; if (args != null) { foreach (string arg in args) { argString += arg + " "; } } Log.WriteLine("Arguments=" + argString); #endif string rpxPath = string.Empty; StringBuilder launchArgs = null; bool gotRpx = false; execLaunchCmd = true; if (args.Length > 1) { launchArgs = new StringBuilder(); } for (int i = 0; i < args.Length; i++) { string s = args[i]; if (!string.IsNullOrEmpty(s)) { if (!gotRpx && (s.StartsWith("-") || s.CompareTo("help") == 0)) { switch (s) { case "-h": case "-?": case "help": launch_usage(); return CAFEX_ERROR.OK; default: Console.WriteLine("cafex: Invalid parameter."); launch_usage(); return CAFEX_ERROR.MASTERING_ERROR; } } else if (s.Contains(".rpx")) //Must be path to the rpx file { rpxPath = s; gotRpx = true; } else //must be arguments for the rpx { launchArgs.Append(" " + s); } } } if (string.IsNullOrEmpty(rpxPath)) { Console.WriteLine("cafex: Invalid parameter."); launch_usage(); return CAFEX_ERROR.MASTERING_ERROR; } string winrpxPath = PathConverter.Windowsify(rpxPath); winrpxPath = PathConverter.Root(winrpxPath); winrpxPath = Path.GetFullPath(winrpxPath); //string rpxDir = winrpxPath.Substring(0, winrpxPath.LastIndexOf('\\')); //string rpxName = winrpxPath.Substring(winrpxPath.LastIndexOf('\\') + 1); //string rpxDLF = Path.ChangeExtension(winrpxPath, ".dlf"); //string rpxELF = Path.ChangeExtension(winrpxPath, ".elf"); string rpxDir = Path.GetDirectoryName(winrpxPath); string rpxName = Path.GetFileName(winrpxPath); string rpxDLF = Path.ChangeExtension(winrpxPath, ".dlf"); string rpxELF = Path.ChangeExtension(winrpxPath, ".elf"); //Below parameter must be set before we even start anything if (string.IsNullOrEmpty(CAFE_CODE_DIR.value)) { if (string.IsNullOrEmpty(CAFE_ELF_DIR.value)) { CAFE_ELF_DIR.value = rpxDir; } CAFE_CODE_DIR.value = CAFE_ELF_DIR.value; } //Run discrun to enable all the required setup variables //Note that we are only doing initialization and not launching the //application. string[] runArgs = { "-b", winrpxPath }; result = discrun(runArgs, true, false).error; if (result != CAFEX_ERROR.OK) { return result; } //Make sure to remove "0x" from CAFERUN_COLDBOOT_OS_VERSION.value if (CAFERUN_COLDBOOT_OS_VERSION.value.Contains("0x")) { CAFERUN_COLDBOOT_OS_VERSION.value = CAFERUN_COLDBOOT_OS_VERSION.value.Substring(2); } //Make ppc_boot.dlf and fw.img file which is needed to run system config tool result = bootrun(new List { "-makedlf" }, false); if (result != CAFEX_ERROR.OK) { Console.WriteLine("cafex: Failed to run bootrun."); return result; } //Make dlf file and store it in the same directory as the rpx //The dlf generated here will be passed to FSEmul to mounting the title on ODD result = devrun(rpxELF, null, null, null); if (result != CAFEX_ERROR.OK) { Console.WriteLine("cafex: Failed to run devrun."); return result; } if (string.IsNullOrEmpty(BOOT_DLF_FILE.value)) { BOOT_DLF_FILE.value = CAFE_TEMP.value + "\\" + SESSION_PATH_PREFIX.value + "caferun" + "\\ppc_boot.dlf"; } //Make sure SOFT_LUANCH is disabled CAFERUN_OPTION_SOFT_LAUNCH.value = "0"; //call hostrun to launch FSEMUL hostrun(BOOT_DLF_FILE.value + " " + rpxDLF); extract_info_from_app_xml(rpxDir + "\\app.xml"); LAUNCH_DLF_FILE = rpxDLF; string[] onArgs = { "-c launch -p -l 0x" + APP_TITLE_ID.value + ((launchArgs != null) ? launchArgs.ToString():string.Empty) }; on(onArgs, false, true); return CAFEX_ERROR.OK; } #endregion #region CafeX Install static CAFEX_ERROR install(string[] args) { bool helpRequested; string rpxPath; List rplSources; TitleId titleId; int cafeInstallUseSymLink; // Parse arguments passed in CAFEX_ERROR parseErrorCode = CafeXInstall_ParseArgs(args, out helpRequested, out rpxPath, out titleId, out rplSources, out cafeInstallUseSymLink); if (parseErrorCode != CAFEX_ERROR.OK || helpRequested) { install_usage(); return parseErrorCode; } CAFEINSTALL_USE_SYMLINK.value = cafeInstallUseSymLink.ToString(); #if DEBUG Console.WriteLine("CafeX Install arguments parsed:"); Console.WriteLine("rpxFilePath: {0}", rpxPath); Console.WriteLine("titleId: {0}", titleId); for (int i = 0; i < rplSources.Count; i++) { Console.WriteLine("rplSource[{0}] = {1}", i, rplSources[i]); } Console.WriteLine("CAFEINSTALL_USE_SYMLINK.value: {0}", CAFEINSTALL_USE_SYMLINK.value); #endif string titleDir = Path.Combine(CAFE_MLC_DIR.value, Path.Combine(titleId.IsSystemTitle ? "sys" : "usr", string.Format(@"title\{0}\{1}", titleId.HighValue, titleId.LowValue))); string titleCodeDir = Path.Combine(titleDir, "code"); string titleContentsDir = Path.Combine(titleDir, "content"); string appCodeDir = Path.GetDirectoryName(rpxPath); // Remove existing title directory contents Console.WriteLine("Deleting existing contents from {0}", titleContentsDir); FileUtil.DirectoryDelete(titleContentsDir, true); Console.WriteLine("Deleting existing contents from {0}", titleCodeDir); FileUtil.DirectoryDelete(titleCodeDir, true); // Process "code" directory. CafeXInstall_ProcessTitleCode(appCodeDir, titleCodeDir, titleId, rpxPath, rplSources); // Process "metadata" directory. Assumes app.xml exists in the "code" directory. CafeXInstall_ProcessTitleMetadata(appCodeDir, titleDir); // Process "content" directory. Relies on CAFEINSTALL_USE_SYMLINK to determine whether or not a file copy or junction is performed. CafeXInstall_ProcessTitleContent(titleContentsDir); // If we got this far without an exception, we're done! Console.WriteLine("cafex install Done."); return CAFEX_ERROR.OK; } /// /// Parses arguments that are passed to "cafex install". If successful, guarantees that any out parameters will have assigned values, /// else returns the appropriate error code. /// /// Arguments to parse /// Indicates if the help flag was passed in. /// RPX file path. If valid, returns as a Windows-friendly string. /// Title ID. If valid, returns with leading hexadecimal indicator. /// List of explicit RPL files to copy to the title's code directory. /// Flag indicating whether or not symbolic links should be used. /// Appropriate CAFEX_ERROR code (OK if successful). private static CAFEX_ERROR CafeXInstall_ParseArgs(string[] args, out bool helpRequested, out string rpxFilePath, out TitleId titleId, out List rplSources, out int cafeInstallUseSymLink) { CAFEX_ERROR errorCode = CAFEX_ERROR.OK; helpRequested = false; rpxFilePath = string.Empty; titleId = null; rplSources = new List(); cafeInstallUseSymLink = 0; if (args == null || args.Length == 0) { Console.WriteLine("cafex install failed: Insufficient arguments."); return CAFEX_ERROR.BAD_ARGUMENT; } for (int i = 0; i < args.Length; i++) { switch (args[i].ToLowerInvariant()) { case "-l": string path = PathConverter.Windowsify(args[i + 1]); // Make sure we're returning an explicit list of *files* only, not directories. if (File.Exists(path)) { rplSources.Add(path); } else if (Directory.Exists(path)) { // Expand out file paths if we were passed a directory. string[] rplFiles = Directory.GetFiles(path, "*.rpl"); rplSources.AddRange(rplFiles); } else { Console.WriteLine("cafex install failed: RPL path \"{0}\" does not exist.", path); errorCode = CAFEX_ERROR.PATH_DOES_NOT_EXIST; } i++; break; case "-h": helpRequested = true; return CAFEX_ERROR.OK; case "-s": cafeInstallUseSymLink = 1; break; default: TitleId tempTitleId = null; if (Path.GetExtension(args[i]) == ".rpx") { rpxFilePath = PathConverter.Windowsify(args[i]); } else if (TitleId.TryParse(args[i], out tempTitleId)) { titleId = tempTitleId; } else { Console.WriteLine("cafex install failed: Invalid argument: {0}", args[i]); errorCode = CAFEX_ERROR.BAD_ARGUMENT; } break; } } if (string.IsNullOrEmpty(rpxFilePath)) { Console.WriteLine("cafex install failed: Missing RPX file."); errorCode = CAFEX_ERROR.BAD_ARGUMENT; } else if (!File.Exists(rpxFilePath)) { Console.WriteLine("cafex install failed: RPX file \"{0}\" does not exist.", rpxFilePath); errorCode = CAFEX_ERROR.PATH_DOES_NOT_EXIST; } if (titleId == null) { Console.WriteLine("cafex install failed: Missing or invalid title ID."); errorCode = CAFEX_ERROR.BAD_ARGUMENT; } return errorCode; } private static void CafeXInstall_ProcessTitleCode(string appCodeDir, string titleCodeDir, TitleId titleId, string rpxPath, List rplSources) { Console.WriteLine("Installing to {0}", titleCodeDir); // Copy RPX to MLC string rpxFileName = Path.GetFileName(rpxPath); string copyRpxFilePath = Path.Combine(titleCodeDir, rpxFileName); Console.WriteLine(" from {0}", rpxPath); FileUtil.FileCopy(rpxPath, copyRpxFilePath); // If user did not specify specific RPL files, get RPL files from its app code directory if (rplSources.Count == 0) { var rplFiles = Directory.GetFiles(appCodeDir, "*.rpl"); rplSources.AddRange(rplFiles); } // Copy RPL files to MLC foreach (string path in rplSources) { string destinationFile = Path.Combine(titleCodeDir, Path.GetFileName(path)); Console.WriteLine(" from {0}", path); FileUtil.FileCopy(path, destinationFile); } // Copy ramdisk preload list string appCodeDir_preloadTxtPath = Path.Combine(appCodeDir, "preload.txt"); if (File.Exists(appCodeDir_preloadTxtPath)) { FileUtil.FileCopy(appCodeDir_preloadTxtPath, Path.Combine(titleCodeDir, "preload.txt")); } // Process app.xml CafeXInstall_ProcessAppXml(appCodeDir, titleCodeDir, titleId); // Process cos.xml CafeXInstall_ProcessCosXml(appCodeDir, titleCodeDir, rpxFileName); } private static void CafeXInstall_ProcessAppXml(string appCodeDir, string titleCodeDir, TitleId titleId) { string appCodeDir_appXmlPath = Path.Combine(appCodeDir, "app.xml"); string titleCodeDir_appXmlPath = Path.Combine(titleCodeDir, "app.xml"); string appDefaultXmlPath = Path.Combine(CAFE_ROOT.value, @"system\bin\ghs\cafe\boot\app_default.xml"); if (!File.Exists(appCodeDir_appXmlPath)) { Console.WriteLine("cafex install: Generating default app.xml"); FileUtil.FileCopy(appDefaultXmlPath, appCodeDir_appXmlPath); } FileUtil.FileCopy(appCodeDir_appXmlPath, titleCodeDir_appXmlPath); // Update app.xml with title ID XmlHandler.UpdateNodeValue(titleCodeDir_appXmlPath, "title_id", titleId.ValueWithoutPrefix); } private static void CafeXInstall_ProcessCosXml(string appCodeDir, string titleCodeDir, string rpxFileName) { string appCodeDir_cosXmlPath = Path.Combine(appCodeDir, "cos.xml"); string titleCodeDir_cosXmlPath = Path.Combine(titleCodeDir, "cos.xml"); string cosDefaultXmlPath = Path.Combine(CAFE_ROOT.value, @"system\bin\ghs\cafe\boot\cos_default.xml"); if (!File.Exists(appCodeDir_cosXmlPath)) { Console.WriteLine("cafex install: Generating default cos.xml since app-specific xml doesn't exist"); FileUtil.FileCopy(cosDefaultXmlPath, appCodeDir_cosXmlPath); } FileUtil.FileCopy(appCodeDir_cosXmlPath, titleCodeDir_cosXmlPath); // Update cos.xml with RPX filename XmlHandler.UpdateNodeValue(titleCodeDir_cosXmlPath, "argstr", rpxFileName); } private static void CafeXInstall_ProcessTitleMetadata(string appCodeDir, string titleDir) { string titleMetaDir = Path.Combine(titleDir, "meta"); string ownMetaDataPath = Path.Combine(appCodeDir, @"..\meta"); string ownMetaXmlPath = Path.Combine(ownMetaDataPath, "meta.xml"); string titleMetaXmlPath = Path.Combine(titleMetaDir, "meta.xml"); // Copy app's metadata directory if (Directory.Exists(ownMetaDataPath)) { FileUtil.DirectoryCopy(ownMetaDataPath, titleMetaDir, true, true); } // If the app did not have a meta.xml, copy the default meta.xml. if (!File.Exists(ownMetaXmlPath)) { Console.WriteLine("cafex install: Generating default meta.xml since app-specific xml doesn't exist"); string metaDefaultXmlPath = Path.Combine(CAFE_ROOT.value, @"system\bin\ghs\cafe\boot\meta_default.xml"); FileUtil.FileCopy(metaDefaultXmlPath, titleMetaXmlPath); } string titleCodeDir_appXmlPath = Path.Combine(titleDir, @"code\app.xml"); // Get and update title ID string titleId = XmlHandler.GetNodeValue(titleCodeDir_appXmlPath, "title_id"); XmlHandler.UpdateNodeValue(titleMetaXmlPath, "title_id", titleId); // Get and update OS version string discEmuOsVer = XmlHandler.GetNodeValue(titleCodeDir_appXmlPath, "os_version"); XmlHandler.UpdateNodeValue(titleMetaXmlPath, "os_version", discEmuOsVer); // Get and update group ID string groupId = XmlHandler.GetNodeValue(titleCodeDir_appXmlPath, "group_id"); XmlHandler.UpdateNodeValue(titleMetaXmlPath, "group_id", groupId); // Update boot icon/transition data files update_boot_logos(titleMetaDir); } private static void CafeXInstall_ProcessTitleContent(string titleContentsDir) { Console.WriteLine("Installing to {0}", titleContentsDir); Console.WriteLine(" from {0}", CAFE_CONTENT_DIR.value); if (CAFEINSTALL_USE_SYMLINK.value != "1") { FileUtil.DirectoryCopy(CAFE_CONTENT_DIR.value, titleContentsDir, true, false); } else { bool result = NativeMethods.CreateSymbolicLink(titleContentsDir, CAFE_CONTENT_DIR.value, NativeMethods.SYMBOLIC_LINK_FLAG_DIRECTORY); if (!result) { int exitCode = Marshal.GetLastWin32Error(); throw new IOException(string.Format("Failed to create symbolic link. Exit Code = {0}, Symbolic Link = {1}, Target = {2}", exitCode, titleContentsDir, CAFE_CONTENT_DIR.value)); } } } #endregion #region SCRIPT HELPERS static void initialize_work_directory(string directory) { #if DEBUG Log.WriteLine("initialize_work_diretory started."); #endif if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } File.Delete(directory + "\\diskid.bin"); File.Delete(directory + "\\ppc.bsf"); File.Delete(directory + "\\ppc_boot.dlf"); } static CAFEX_ERROR make_boot1_system_file(string bsf_file) { #if DEBUG Log.WriteLine("make_boot1_system_file started."); #endif string flags = "0"; string firmware_filename = Path.GetFileName(FIRMWARE_FILE.value); if (firmware_filename.StartsWith("fw")) { flags = "0x80000000"; } if (makebsf.make(QUIET.value, bsf_file, flags) != 0) { Console.WriteLine("cafex bootrun failed: Cannot generate bsf file."); return CAFEX_ERROR.BOOTRUN_MAKEBSF_FAILED; } return CAFEX_ERROR.OK; } static CAFEX_ERROR make_boot_dlf(string file_list, string output_dlf_file) { #if DEBUG Log.WriteLine("make_boot_dlf started."); #endif string commandResult = string.Empty; if (makedlf.make(QUIET.value, file_list, output_dlf_file, out commandResult) != 0) { Console.WriteLine("cafex bootrun failed: Cannot generate dlf file."); Console.WriteLine("Command output: " + commandResult); return CAFEX_ERROR.BOOTRUN_MAKEDLF_FAILED; } return CAFEX_ERROR.OK; } static CAFEX_ERROR make_wumad_dlf(string wumadFile, string extractionFolder, string output_dlf_file) { #if DEBUG Log.WriteLine("make_wumad_dlf started. Arguments: wumadFile=" + wumadFile + ", extractionFolder=" + extractionFolder + ", output_dlf_file=" + output_dlf_file); #endif if (makewumaddlf.make(wumadFile, extractionFolder, output_dlf_file) != 0) { Console.WriteLine("cafex bootrun failed: Cannot generate dlf file from WUMAD."); return CAFEX_ERROR.BOOTRUN_MAKEDLF_FAILED; } return CAFEX_ERROR.OK; } static void extract_info_from_app_xml(string app_xml_file) { #if DEBUG Log.WriteLine("extract_info_from_app_xml started."); #endif APP_TITLE_ID.value = XmlHandler.GetNodeValue(app_xml_file, "title_id"); APP_GROUP_ID.value = XmlHandler.GetNodeValue(app_xml_file, "group_id"); APP_TITLE_VERSION.value = XmlHandler.GetNodeValue(app_xml_file, "title_version"); Console.WriteLine("App Title ID : " + APP_TITLE_ID.value); Console.WriteLine("App Group ID : " + APP_GROUP_ID.value); Console.WriteLine("App Title Version : " + APP_TITLE_VERSION.value); } static CafeXReturn connect_serial_or_debugger(bool quiet_mode) { #if DEBUG Log.WriteLine("connect_serial_or_debugger started. quiet_mode=" + quiet_mode.ToString() + ", DEBUGGER=" + DEBUGGER.value); #endif switch (DEBUGGER.value) { case "multi": { break; } case "gdb": case "gdbtui": { cattoucan.FinishSync(true); if (FileUtil.RunningFromCygwin && DEBUGGER.value == "gdb") { Console.WriteLine("cafex run error: gdb debugger is not compatible with cafex."); Console.WriteLine("Please disable cafex with \"export USE_CAFEX=0\" and run the command with BASH caferun."); } else { Console.WriteLine("cafex run error: Only Multi debugger supported"); } return new CafeXReturn(CAFEX_ERROR.RUN_NON_MULTI_DEBUGGER); } case "cattoucan": { CafeXReturn ret = new CafeXReturn(CAFEX_ERROR.OK); ret.appExitCode = cattoucan.start(no_console, false); return ret; } case "none": { cattoucan.FinishSync(true); if (CONSOLE.value != "toucan") { CAFE_DEBUG_PORT.value = "toucan"; } return new CafeXReturn(CAFEX_ERROR.OK); } default: { cattoucan.FinishSync(true); Console.WriteLine("cafex run failed: " + DEBUGGER.value + " unsupported debugger."); return new CafeXReturn(CAFEX_ERROR.RUN_BAD_DEBUGGER); } } if (CAFE_DEBUG_PORT.value != "toucan") { cattoucan.FinishSync(true); Console.WriteLine("cafex run failed: Unknown debugger port " + CAFE_DEBUG_PORT.value); return new CafeXReturn(CAFEX_ERROR.RUN_BAD_DEBUGGER_PORT); } #if DEBUG Log.WriteLine("DEBUGGER = multi"); #endif MULTIELF.value = ""; if (DEBUG_ELF_FILE.value != null) { // Make sure the MULTIELF has windows-style path MULTIELF.value = PathConverter.Windowsify(DEBUG_ELF_FILE.value); } CATTOUCAN_STATUS.value = cattoucan.start(no_console, false).ToString(); if (string.IsNullOrEmpty(MULTI_CONNECT.value)) { if (USE_EXI_AS_DEBUG_CHANNEL.value != null && USE_EXI_AS_DEBUG_CHANNEL.value.Equals("1")) { MULTI_CONNECT.value = "\"-connect=cafeserv -iphost " + BRIDGE_CURRENT_IP_ADDRESS.value + " -console_iphost localhost -ipport 7977 -console_ipport " + SESSION_DEBUG_OUT_PORT.value + " -auto_first\""; } else { MULTI_CONNECT.value = "\"-connect=cafeserv -iphost localhost -ipport " + SESSION_DEBUG_CONTROL_PORT.value + " -console_ipport " + SESSION_DEBUG_OUT_PORT.value + " -auto_first\""; } } #if DEBUG Log.WriteLine("MULTI_CONNECT before calling multi = " + MULTI_CONNECT.value); Log.WriteLine("CATTOUCAN_STATUS.value = " + CATTOUCAN_STATUS.value); Log.WriteLine("CAFE_LAUNCH_DEBUG.value = " + CAFE_LAUNCH_DEBUG.value); #endif if (CATTOUCAN_STATUS.value == "42") { if (CAFE_LAUNCH_DEBUG.value == "1") { multi.start(MULTI_CONNECT.value, CAFE_MULTI_INIT.value, MULTIELF.value); } else { Console.WriteLine("Ready to connect from multi"); Console.WriteLine(GHS_ROOT.value + "\\multi.exe -cmd prepare_target " + MULTI_CONNECT.value + " " + CAFE_MULTI_INIT.value + " " + MULTIELF.value); } if (CMDOUTPUT.value == "1") { #if DEBUG Log.WriteLine("CMDOUTPUT = 1 -> calling cattoucan.start..."); #endif cattoucan.start(no_console, false); } } #if DEBUG Log.WriteLine("connect_serial_or_debugger completed."); #endif return new CafeXReturn(CAFEX_ERROR.OK); } static int initialize_serial_port_and_directory(string stop_cmd) { #if DEBUG Log.WriteLine("initialize_serial_port_and_directory started."); #endif if (stop_cmd == null) { Console.WriteLine("\"Usage: Initialize_serial_port_and_directory stop_cmd\", where stop_cmd is cafestop or a bash function call."); return 1; } create_directory_if_noexist(LOGDIR.value); if (stop_cmd == "cafestop") { stop(null); } //trap if (CAFE_CONSOLE.value == "cattoucan") { //trap CAFE_CONSOLE.value = "toucan"; } if (CAFE_CONSOLE.value == "cmdtoucan") { //trap CAFE_CONSOLE.value = "toucan"; } if (CAFE_CONSOLE.value == "catwaikiki") { //trap CAFE_CONSOLE.value = "waikiki"; } #if DEBUG Log.WriteLine("CAFE_CONSOLE=" + CAFE_CONSOLE.value); #endif if (COMPORTS_SUPPORT.value == "-c") { int init_flag = 0; INITIALIZED_COMPORTS.value = ""; for (int COMPORT = 1; COMPORT <= 20; ++COMPORT) { if (cmd.mode(COMPORT) == 0) { Console.WriteLine("Initialized COM" + COMPORT); init_flag = 1; INITIALIZED_COMPORTS.AddToVar("COM" + COMPORT + " ", ' '); } } if (init_flag == 0 && CAFE_CONSOLE.value != "toucan") { Console.WriteLine("ERROR: no serial port is available."); Console.WriteLine("Please close other softwares using serial port,"); Console.WriteLine("such as HyperTerminal."); Console.WriteLine(); Console.WriteLine("This automated test script cannot share the serial port"); Console.WriteLine("with other softwares."); return 1; } } return 0; } static int monitor_for_output(string str_opt, string test_str, string timeout, string log_dir, string file_name, bool printToScreen) { #if DEBUG Log.WriteLine("monitor_for_output started."); #endif create_directory_if_noexist(log_dir); if (MONITOR_FOR_OUTPUT_CALLS.value == null) { MONITOR_FOR_OUTPUT_CALLS.value = "0"; } MONITOR_FOR_OUTPUT_CALLS.value = (HexHandler.GetNumberFromString(MONITOR_FOR_OUTPUT_CALLS.value) + 1).ToString(); string call_no = MONITOR_FOR_OUTPUT_CALLS.value; string mon_rc_file = log_dir + "\\monitor_return_code" + call_no + ".txt"; if (file_name == null) { file_name = "monitor_" + call_no + ".txt"; } string log_file = log_dir + "\\" + file_name; // Write to the log file all the output and print to the screen, if printToScreen is true. FileStream fs = new FileStream(log_file, FileMode.Create); StreamWriter sw = new StreamWriter(fs); DataReceivedEventHandler callback = (sender, e) => { if (e != null && e.Data != null && sw != null) { string outputData = e.Data; if (printToScreen) { Console.WriteLine(outputData); } try { sw.WriteLine(outputData); sw.Flush(); } catch (IOException) { } catch (ObjectDisposedException) { } } }; int retVal = monitor_for_output_redirectionCallback(str_opt, test_str, timeout, callback); sw.Close(); fs = new FileStream(mon_rc_file, FileMode.Create); sw = new StreamWriter(fs); sw.WriteLine(retVal); sw.Flush(); sw.Close(); return retVal; } static int monitor_for_output_redirectionCallback(string str_opt, string test_str, string timeout, DataReceivedEventHandler callback) { #if DEBUG Log.WriteLine("monitor_for_output_redirectionCallback started."); #endif string ret = monitor.start_redirectionCallback(str_opt, test_str, timeout, callback).ToString(); int return_val = evaluate_monitor_return_value(ret); if (return_val == 0) { Console.WriteLine("monitor returned PASS"); } else { return return_val; } return 0; } static int evaluate_monitor_return_value(string mon_rval) { #if DEBUG Log.WriteLine("evaluate_monitor_return_value started."); #endif int return_val = 1; string status_str = string.Empty; if (mon_rval == MON_RESULT_PASS.value) { return_val = 0; } else if (mon_rval == MON_RESULT_TIMEOUT.value) { status_str = "TIMEOUT"; } else if (mon_rval == MON_RESULT_UNDEF.value) { status_str = "UNDEF"; } else if (mon_rval == MON_RESULT_MANUAL.value) { status_str = "MANUAL"; } else if (mon_rval == MON_RESULT_NOLOG.value) { status_str = "NOLOG"; } else if (mon_rval == MON_RESULT_FAIL.value) { status_str = "FAIL"; } else if (mon_rval == MON_RESULT_EXPECTED_TERM.value) { status_str = "EXPECTED_TERM"; } else if (mon_rval == MON_RESULT_EXEC_WIN_APP.value) { status_str = "EXEC_WIN_APP"; } else if (mon_rval == MON_RESULT_NOPPC.value) { status_str = "NOPPC"; } else if (mon_rval == MON_RESULT_BOOT1.value) { status_str = "BOOT1"; } else if (mon_rval == MON_RESULT_RESTART.value) { status_str = "RESTART"; } else if (mon_rval == MON_RESULT_TEST_AS_RPL.value) { status_str = "TEST_AS_RPL"; } else if (mon_rval == MON_RESULT_END_OF_RPL_LOADER.value) { status_str = "END_OF_RPL_LOADER"; } else if (mon_rval == MON_RESULT_BRIDGE_COLLISION.value) { status_str = "BRIDGE_COLLISION"; } else if (mon_rval == MON_RESULT_TEST_DBG_OUT.value) { status_str = "TEST_DBG_OUT"; } else if (mon_rval == MON_RESULT_BRIDGE_OFF.value) { status_str = "BRIDGE_OFF"; } else if (mon_rval == MON_RESULT_ERROR.value) { status_str = "ERROR"; } else if (mon_rval == MON_RESULT_FATAL_ERROR.value) { status_str = "FATAL_ERROR"; } else if (mon_rval == MON_RESULT_MISSING.value) { status_str = "MISSING"; } else if (mon_rval == MON_RESULT_ABORTED.value) { status_str = "ABORTED"; } else { status_str = mon_rval.ToString(); } if (return_val != 0) { Console.WriteLine("monitor returned " + status_str); return return_val; } return 0; } static bool check_xml_version(string file_dest, string file_default, string file_option) { #if DEBUG Log.WriteLine("check_xml_version started."); #endif if (!File.Exists(file_dest)) { Console.WriteLine("cafex run: Copying default config file to " + file_dest); if (!File.Exists(file_default)) { Console.WriteLine("cafex run failed: Cannot find default config file " + file_default); return false; } create_directory_if_noexist(Path.GetDirectoryName(file_dest)); File.Copy(file_default, file_dest, true); File.SetAttributes(file_dest, FileAttributes.Normal); } else { string ver_default = XmlHandler.GetNodeValue(file_default, "version"); string ver_dest = XmlHandler.GetNodeValue(file_dest, "version"); #if DEBUG Log.WriteLine("file_dest: " + file_dest + ", ver_default: " + ver_default + " - ver_dest: " + ver_dest); #endif if (ver_dest == null || ver_default == null) { Console.WriteLine("cafex run failed: Cannot get xml version numbers"); return false; } if (IGNORE_VERSION.value == null) { if (ver_dest != ver_default) { if (file_option == "copy_default_if_mismatch") { Console.WriteLine("cafex run: Config file version mismatch detected: " + ver_dest + " vs. required " + ver_default); Console.WriteLine(" Copying default config file to " + file_dest); if (!File.Exists(file_default)) { Console.WriteLine("cafex run failed: Cannot find default config file " + file_default); return false; } create_directory_if_noexist(Path.GetDirectoryName(file_dest)); File.Copy(file_default, file_dest, true); File.SetAttributes(file_dest, FileAttributes.Normal); } else { Console.WriteLine("cafex run failed: Please update or delete config file: " + file_dest); Console.WriteLine(" Version number mismatch: " + ver_dest + " vs. required " + ver_default); return false; } } } } return true; } static string args_to_bar_sep_list(string[] input) { return StringCombiner.MakeDelimitedString(input, '|'); } static bool exit_if_specials(string[] arglist) { #if DEBUG Log.WriteLine("exit_if_specials started."); #endif if (arglist == null || arglist.Length == 0) { // No args, so it can't contain special characters. return true; } foreach (string s in arglist) { if (s.Contains("?") || s.Contains("+") || s.Contains("<") || s.Contains(">") || s.Contains("|")) { Console.WriteLine("cafex run failed: Unable to parse special character (?+<>|) in arg list."); Console.WriteLine(" arglist: " + s); return false; } } return true; } static bool update_arglist(string file_dest, string cafe_elf, string[] arglist, bool check_DASH_A_ARGS) { #if DEBUG Log.WriteLine("update_arglist started."); #endif string[] arglist_without_rpx = new string[arglist.Length - 1]; Array.Copy(arglist, 1, arglist_without_rpx, 0, arglist_without_rpx.Length); // Check args list if it was passed without the -a option if (!exit_if_specials(arglist_without_rpx)) { return false; } string args_trailing_with_bars = args_to_bar_sep_list(arglist_without_rpx); // Check if args were passed by -a option if (check_DASH_A_ARGS && !string.IsNullOrEmpty(DASH_A_ARGS.value)) { if (!exit_if_specials(new string[] { DASH_A_ARGS.value })) { return false; } ARGS_WITH_BARS.value = DASH_A_ARGS.value.Replace(',', '|'); if (args_trailing_with_bars != string.Empty) { ARGS_WITH_BARS.value = ARGS_WITH_BARS.value + "|" + args_trailing_with_bars; } } else { ARGS_WITH_BARS.value = args_trailing_with_bars; } string args_with_bars_no_quotes = string.Empty; //if (ARGS_WITH_BARS.value != null) //{ // args_with_bars_no_quotes = ARGS_WITH_BARS.value.Replace("\"", "\\\""); //} //else //{ // args_with_bars_no_quotes = ARGS_WITH_BARS.value; //} args_with_bars_no_quotes = ARGS_WITH_BARS.value; string total_arglist = Path.GetFileName(cafe_elf); if (args_with_bars_no_quotes != string.Empty) { total_arglist += "|" + args_with_bars_no_quotes; } string total_arglist_with_qs = total_arglist.Replace(' ', '?'); total_arglist_with_qs = total_arglist_with_qs.Replace('|', ' '); // Check argument length to make sure it is less than 4096. if (!string.IsNullOrEmpty(total_arglist_with_qs) && total_arglist_with_qs.Length >= CAFE_ARGSTR_MAX_LENGTH) { Console.WriteLine("cafex run failed: the length of the filename and its arguments is greater than or equal to 4096 characters. Please shorten and retry."); return false; } // Trim any extra white spaces total_arglist_with_qs = total_arglist_with_qs.Trim(); XmlHandler.UpdateNodeValue(file_dest, "argstr", total_arglist_with_qs); return true; } static CAFEX_ERROR update_system_xml(string file_dest, string cmd_flags, string system_mode, string sys_xml_mcp_launch_hint) { #if DEBUG Log.WriteLine("update_system_xml started."); #endif Int64 iTitleID = 0; string sys_default_xml = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\boot\\system_default.xml"; if (!check_xml_version(file_dest, sys_default_xml, "copy_default_if_mismatch")) { return CAFEX_ERROR.UNEXPECTED; } string old_system_mode_num = XmlHandler.GetNodeValue(file_dest, "dev_mode"); string[] system_mode_name_table = new string[4]; system_mode_name_table[0] = "PROD"; system_mode_name_table[1] = "DEV"; system_mode_name_table[2] = "TEST"; system_mode_name_table[3] = "Unknown"; if (old_system_mode_num != "0" && old_system_mode_num != "1" && old_system_mode_num != "2") { old_system_mode_num = "3"; } string new_system_mode_num = "3"; if (system_mode == "dev") { new_system_mode_num = "1"; } else if (system_mode == "test") { new_system_mode_num = "2"; } else { if (system_mode == "prod") { Console.WriteLine("cafex run Warning: Changing to PROD mode is not supported."); Console.WriteLine(" Please specify '-M dev' or '-M test'."); } else if (system_mode != null) { Console.WriteLine("cafex run Warning: Invalid system mode is specified."); } if (old_system_mode_num != "3") { new_system_mode_num = old_system_mode_num; } else { new_system_mode_num = "1"; Console.WriteLine("cafex run: System mode is broken. Fixing it to DEV"); } } if (CAFE_BOOT_MODE.value == "PCFS") { if (new_system_mode_num != old_system_mode_num) { Console.WriteLine("cafex run: Changing system mode " + system_mode_name_table[HexHandler.GetNumberFromString(old_system_mode_num)] + " to " + system_mode_name_table[HexHandler.GetNumberFromString(new_system_mode_num)]); XmlHandler.UpdateNodeValue(file_dest, "dev_mode", new_system_mode_num); } else { Console.WriteLine("cafex run: Current system mode is " + system_mode_name_table[HexHandler.GetNumberFromString(new_system_mode_num)]); } if (!String.IsNullOrEmpty(CAFE_TEST_SELF_REFRESH.value)) { XmlHandler.UpdateNodeValueByPath(file_dest, "//standby/enable", "1"); } } if (CAFERUN_OPTION_MLC_EMU_LAUNCH.value == "1") { string mlc_emu_tid_hi = CAFERUN_OPTION_MLC_EMU_TITLEID.value.Substring(2, 8); string mlc_emu_tid_lo = CAFERUN_OPTION_MLC_EMU_TITLEID.value.Substring(10, 8); string mlc_emu_title_dir = string.Empty; if (mlc_emu_tid_hi == "00050010") { mlc_emu_title_dir = CAFE_MLC_DIR.value + "\\sys\\title\\" + mlc_emu_tid_hi + "\\" + mlc_emu_tid_lo; } else { mlc_emu_title_dir = CAFE_MLC_DIR.value + "\\usr\\title\\" + mlc_emu_tid_hi + "\\" + mlc_emu_tid_lo; } if (File.Exists(mlc_emu_title_dir + "\\code\\app.xml")) { string mlc_emu_os_version = XmlHandler.GetNodeValue(mlc_emu_title_dir + "\\code\\app.xml", "os_version"); CAFERUN_COLDBOOT_OS_VERSION.value = String.Format("{0:x16}", mlc_emu_os_version); } else { if (DISC_EMU_TYPE.value != "hdd" && ALLOW_DISCRUN_IN_SOFTLAUNCH.value == "0") { Console.WriteLine("cafex run failed: Cannot find title 0x" + mlc_emu_tid_hi + mlc_emu_tid_lo + " on MLC emulation"); Console.WriteLine(" Please cafeinstall before using -t option"); return CAFEX_ERROR.RUN_TITLE_ID_NOT_FOUND_IN_MLC; } } // Convert the title_id from a string to a number for lookup later iTitleID = Convert.ToInt64(mlc_emu_tid_hi + mlc_emu_tid_lo, 16); XmlHandler.UpdateNodeValue(file_dest, "default_title_id", mlc_emu_tid_hi + mlc_emu_tid_lo); } else { if (APP_XML_FILE.value != null) { DISC_EMU_TID.value = XmlHandler.GetNodeValue(APP_XML_FILE.value, "title_id"); // Convert the title_id from a string to a number for lookup later iTitleID = Convert.ToInt64(DISC_EMU_TID.value, 16 ); XmlHandler.UpdateNodeValue(file_dest, "default_title_id", DISC_EMU_TID.value); } else { if (DISC_EMU_TYPE.value == "hdd" && string.IsNullOrEmpty(CAFE_WUMAD.value)) { Console.WriteLine(); Console.WriteLine("-------"); Console.WriteLine("cafex run WARNING: Title ID is not specified."); Console.WriteLine(" Use -t option to specify Title ID of application on HDD."); Console.WriteLine(" Title ID of previously launched app will be used at this time,"); Console.WriteLine(" but launch may fail if it was different from that of application on HDD."); Console.WriteLine("-------"); Console.WriteLine(); } } } if (APP_XML_FILE.value != null) { string disc_emu_app_type = XmlHandler.GetNodeValue(APP_XML_FILE.value, "app_type"); if (fAppTypeDefined) { // AppType override was defined on the command line so use that instead of calculating based on TitleID disc_emu_app_type = CAFERUN_APP_TYPE.value; XmlHandler.UpdateNodeValue(file_dest, "default_app_type", disc_emu_app_type); } else { string calculated_disc_emu_app_type = FindAppType(iTitleID); // Find the app type based on the title ID if (disc_emu_app_type.CompareTo(calculated_disc_emu_app_type) != 0) { Console.WriteLine("WARNING: Calculated AppType does not match what was in APP.XML"); Console.WriteLine("Overwriting with the calculated value for AppType"); } disc_emu_app_type = calculated_disc_emu_app_type; XmlHandler.UpdateNodeValue(file_dest, "default_app_type", disc_emu_app_type); } } else { // There might not be an app.xml but we still want to change the default_app_type with what the user specified with -T if (fAppTypeDefined) { // AppType override was defined on the command line so use that instead of calculating based on TitleID XmlHandler.UpdateNodeValue(file_dest, "default_app_type", CAFERUN_APP_TYPE.value); } else { string calculated_disc_emu_app_type = FindAppType(iTitleID); // Find the app type based on the title ID XmlHandler.UpdateNodeValue(file_dest, "default_app_type", calculated_disc_emu_app_type); } } if (CAFERUN_OPTION_SOFT_RESTART.value == "0") { XmlHandler.UpdateNodeValue(file_dest, "cmdFlags", cmd_flags); } XmlHandler.UpdateNodeValue(file_dest, "default_os_id", CAFERUN_COLDBOOT_OS_VERSION.value); if (sys_xml_mcp_launch_hint != null) { bool node_exists = XmlHandler.NodeExists(file_dest, "default_device_type"); if (!node_exists) { XmlHandler.AddNode(file_dest, "default_device_type", sys_xml_mcp_launch_hint, new string[4] { "type", "string", "length", "16" }); } else { XmlHandler.UpdateNodeValue(file_dest, "default_device_type", sys_xml_mcp_launch_hint); } } else { XmlHandler.RemoveNode(file_dest, "default_device_type"); } return CAFEX_ERROR.OK; } static int set_system_xml_cos_flags(string ppc_os_flags) { #if DEBUG Log.WriteLine("setting cos_flags:" + ppc_os_flags); #endif string file_dest = CAFE_SLC_DIR.value + "\\sys\\config\\system.xml"; int ret = 0; XmlHandler.UpdateNodeValue(file_dest, "cmdFlags", ppc_os_flags); ret = devkitmsg.CosFlags(ppc_os_flags); if (ret != 0) { Console.WriteLine("devkitmsg \"cos_flags " + ppc_os_flags + "\" - failed result = " + ret); } return ret; } static bool update_app_xml(string file_dest) { #if DEBUG Log.WriteLine("update_app_xml started."); #endif string app_default_xml = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\boot\\app_default.xml"; if (!check_xml_version(file_dest, app_default_xml, "")) { return false; } XmlHandler.UpdateNodeValue(file_dest, "os_version", CAFERUN_COLDBOOT_OS_VERSION.value); return true; } static bool update_cos_xml(string file_dest, string cmd_flags) { #if DEBUG Log.WriteLine("update_cos_xml started."); #endif Console.WriteLine("CAFEX: update_cos_xml started, cmd_flags = " + cmd_flags); string cos_default_xml = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\boot\\cos_default.xml"; if (!check_xml_version(file_dest, cos_default_xml, "")) { return false; } //Get original command flags from the xml file string orig_cmd_flags = XmlHandler.GetNodeValue(cos_default_xml, "cmdFlags"); Console.WriteLine("CAFEX: HexHandler.GetNumberFromString(cmd_flags) = " + HexHandler.GetNumberFromString(cmd_flags).ToString()); cmd_flags = (HexHandler.GetNumberFromString(cmd_flags) | (HexHandler.GetNumberFromString(orig_cmd_flags) & ~0xff)).ToString(); Console.WriteLine("CAFEX: change cos.xml cmdFlags to " + cmd_flags); //Compare the command flags passed with the original one. //If the values are different then update the xml node for cmdFlags if (orig_cmd_flags != cmd_flags) { XmlHandler.UpdateNodeValue(file_dest, "cmdFlags", cmd_flags); } return true; } static CAFEX_ERROR update_meta_xml(string file_dest) { #if DEBUG Log.WriteLine("update_meta_xml started on file = " + file_dest); #endif string meta_default_xml = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\boot\\meta_default.xml"; string own_meta_xml; //Since CAFE_CODE_DIR will be modified due to the existence of the session manager, we need to look //at the location of the original rpx to find the custom meta.xml file. if (SESSION_MANAGER.value == "1") { own_meta_xml = Path.Combine(CAFE_ELF_SRC_DIR.value, "..\\meta\\meta.xml"); } else { own_meta_xml = CAFE_CODE_DIR.value + "\\..\\meta\\meta.xml"; } if (CAFERUN_OPTION_MLC_EMU_LAUNCH.value == "0") { if (File.Exists(own_meta_xml)) { string abs_own_meta_xml = Path.GetFullPath(own_meta_xml); string abs_file_dest = Path.GetFullPath(file_dest); if (abs_own_meta_xml != abs_file_dest) { Console.Write("Copy " + own_meta_xml + " to " + file_dest); File.Copy(own_meta_xml, file_dest, true); File.SetAttributes(file_dest, FileAttributes.Normal); } } else { CAFEX_ERROR ret = check_title_id(file_dest, meta_default_xml, APP_XML_FILE.value); if (ret != CAFEX_ERROR.OK) { return ret; } } if (!check_xml_version(file_dest, meta_default_xml, "")) { return CAFEX_ERROR.RUN_UPDATE_META_XML_FAILED; } XmlHandler.UpdateNodeValue(file_dest, "os_version", CAFERUN_COLDBOOT_OS_VERSION.value); Console.WriteLine("Updating title id, group id, title version and app type in " + file_dest + ", based on " + APP_XML_FILE.value + "..."); // get titleId from disc emulation's app.xml DISC_EMU_TID.value = XmlHandler.GetNodeValue(APP_XML_FILE.value, "title_id"); XmlHandler.UpdateNodeValue(file_dest, "title_id", DISC_EMU_TID.value); // get group Id from disc emulation's app.xml string disc_emu_gid = XmlHandler.GetNodeValue(APP_XML_FILE.value, "group_id"); XmlHandler.UpdateNodeValue(file_dest, "group_id", disc_emu_gid); // get title version from disc emulation's app.xml string disc_emu_titlever_hex = XmlHandler.GetNodeValue(APP_XML_FILE.value, "title_version").Trim(); if (!disc_emu_titlever_hex.StartsWith("0x")) { disc_emu_titlever_hex = "0x" + disc_emu_titlever_hex; } uint disc_emu_titlever_decimal = HexHandler.GetNumberFromString(disc_emu_titlever_hex); // insert system default_title_id XmlHandler.UpdateNodeValue(file_dest, "title_version", disc_emu_titlever_decimal.ToString("D5")); } return CAFEX_ERROR.OK; } static void update_boot_logos(string file_dest) { #if DEBUG Log.WriteLine("update_boot_logos started."); #endif string boot_movie_h264 = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\meta\\bootMovie.h264"; string boot_logo_tex_tga = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\meta\\bootLogoTex.tga"; string icon_tex_tga = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\meta\\iconTex.tga"; string boot_tv_tga = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\meta\\bootTvTex.tga"; string boot_drc_tga = CAFE_ROOT.value + "\\system\\bin\\ghs\\cafe\\meta\\bootDrcTex.tga"; string dest_boot_movie_h264 = file_dest + "\\bootMovie.h264"; string dest_boot_logo_tex_tga = file_dest + "\\bootLogoTex.tga"; string dest_icon_tex_tga = file_dest + "\\iconTex.tga"; string dest_boot_tv_tga = file_dest + "\\bootTvTex.tga"; string dest_boot_drc_tga = file_dest + "\\bootDrcTex.tga"; // Copy boot_movie logo_text only if ghs\cafe\meta has a newer timestamp. // This replaces the "cp -u" from the BASH script. bool copyRequired = false; if (!File.Exists(dest_boot_movie_h264)) { // Should copy because it does not exist copyRequired = true; } else { // Check the timestamps if (file_timestamp_compare(boot_movie_h264, dest_boot_movie_h264) > 0) { copyRequired = true; } } if (copyRequired) { file_copy_retry(boot_movie_h264, dest_boot_movie_h264, true, 1); File.SetAttributes(dest_boot_movie_h264, FileAttributes.Normal); } // Copy logo_text only if ghs\cafe\meta has a newer timestamp copyRequired = false; if (!File.Exists(dest_boot_logo_tex_tga)) { // Should copy because it does not exist copyRequired = true; } else { // Check the timestamps if (file_timestamp_compare(boot_logo_tex_tga, dest_boot_logo_tex_tga) > 0) { copyRequired = true; } } if (copyRequired) { file_copy_retry(boot_logo_tex_tga, dest_boot_logo_tex_tga, true, 1); File.SetAttributes(dest_boot_logo_tex_tga, FileAttributes.Normal); } // Applicaion Boot Textures should be copy if files do not exist if (!File.Exists(dest_icon_tex_tga)) { file_copy_retry(icon_tex_tga, dest_icon_tex_tga, true, 1); File.SetAttributes(dest_icon_tex_tga, FileAttributes.Normal); } if (!File.Exists(dest_boot_tv_tga)) { file_copy_retry(boot_tv_tga, dest_boot_tv_tga, true, 1); File.SetAttributes(dest_boot_tv_tga, FileAttributes.Normal); } if (!File.Exists(dest_boot_drc_tga)) { file_copy_retry(boot_drc_tga, dest_boot_drc_tga, true, 1); File.SetAttributes(dest_boot_drc_tga, FileAttributes.Normal); } } static void create_directory_if_noexist(string directory) { #if DEBUG Log.WriteLine("create_directory_if_noexist started."); #endif if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } static int compute_flat_version(string version) { #if DEBUG Log.WriteLine("compute_flat_version started."); #endif string[] numbers = version.Split('.'); int ret = 0; if (numbers.Length > 0) { ret += Convert.ToInt32(numbers[0]) * 1000000; } if (numbers.Length > 1) { ret += Convert.ToInt32(numbers[1]) * 10000; } if (numbers.Length > 2) { ret += Convert.ToInt32(numbers[2]) * 100; } if (numbers.Length > 3) { ret += Convert.ToInt32(numbers[3]); } #if DEBUG Log.WriteLine(string.Format("compute_flat_version: '{0}' => {1}.", version, ret.ToString())); #endif return ret; } static string compute_ver_string(int ver) { string ver_str = (ver % 100).ToString(); if (ver > 100) { ver_str = string.Format("{0}.{1}", (ver / 100) % 100, ver_str); if (ver > 10000) { ver_str = string.Format("{0}.{1}", (ver / 10000) % 100, ver_str); if (ver > 1000000) { ver_str = string.Format("{0}.{1}", (ver / 1000000) % 100, ver_str); } } } return ver_str; } static CAFEX_ERROR check_title_id(string file_dest, string file_default, string file_app) { #if DEBUG Log.WriteLine("check_title_id started. file_dest=" + file_dest + ",file_default=" + file_default + ",file_app=" + file_app); #endif if (!File.Exists(file_dest)) { Console.WriteLine("cafex run: Copying default config file to " + file_dest); if (!File.Exists(file_default)) { Console.WriteLine("cafex run failed: Cannot find default config file " + file_default); return CAFEX_ERROR.RUN_CHECKTITLEID_FAILED; } File.Copy(file_default, file_dest, true); File.SetAttributes(file_dest, FileAttributes.Normal); } else { string titleid_dest = XmlHandler.GetNodeValue(file_dest, "title_id"); string titleid_app = XmlHandler.GetNodeValue(file_app, "title_id"); if (titleid_dest == string.Empty || titleid_app == string.Empty) { Console.WriteLine("cafex run failed: Cannot get title id"); return CAFEX_ERROR.RUN_CHECKTITLEID_FAILED; } if (titleid_dest != titleid_app) { Console.WriteLine("cafex run: Config file title id mismatch detected: " + titleid_dest + " vs. required " + titleid_app); Console.WriteLine(" Copying default config file to " + file_dest); if (!File.Exists(file_default)) { Console.WriteLine("cafex run failed: Cannot find default config file " + file_default); return CAFEX_ERROR.RUN_CHECKTITLEID_FAILED; } File.Copy(file_default, file_dest, true); File.SetAttributes(file_dest, FileAttributes.Normal); } } return CAFEX_ERROR.OK; } /// /// Compares timestamsp between two files. /// /// The first file for comparison. /// The second file for comparison. /// 0 if timestamps are the same, negative if first file is older than the second, and positive if first is newer than the second. static int file_timestamp_compare(string file1, string file2) { if (!File.Exists(file1)) { throw new ArgumentException("file1 = " + file1); } if (!File.Exists(file2)) { throw new ArgumentException("file2 = " + file2); } DateTime file1Time = File.GetLastWriteTime(file1); DateTime file2Time = File.GetLastWriteTime(file2); return DateTime.Compare(file1Time, file2Time); } /// /// Tries to copy a file from source to destination, and if it fails and attempts is greater than one, /// it will wait for 1s and retry. /// /// Source file. /// Destination file. /// Overwrite if destination exists. /// Number of attempts static void file_copy_retry(string sourceFileName, string destFileName, bool overwrite, uint attempts) { try { if (overwrite && File.Exists(destFileName)) { // Force copy by stripping the read-only attribute File.SetAttributes(destFileName, File.GetAttributes(destFileName) & ~FileAttributes.ReadOnly); } File.Copy(sourceFileName, destFileName, overwrite); } catch (IOException) { if (attempts > 1) { --attempts; // Wait a second Thread.Sleep(Program.RETRY_TIMESPAN); // Retry file_copy_retry(sourceFileName, destFileName, overwrite, attempts); } else { // Re-throw if no attempts throw; } } } #endregion #region HELP static void run_usage() { string caller; if (CAFERUN_OPTION_CALLED_FROM_CAFEDISCRUN.value == "yes") { caller = "discrun"; } else { caller = "run"; } Console.WriteLine("Usage: cafex " + caller + " [options] .rpx \"[arg1]\" \"[arg2]\" ... \"[argN]\""); Console.WriteLine(); Console.WriteLine("options:"); Console.WriteLine(" -a a,b... : arguments (comma delimited)"); Console.WriteLine(" -b : use DEBUG OS version"); Console.WriteLine(" -C : use OS_SECURITY_LEVEL OS version"); Console.WriteLine(" -u : use FDEBUG OS version"); Console.WriteLine(" -l : user RPL directory or file to gather for RPX"); Console.WriteLine(); Console.WriteLine(" -d multi : launch multi (GHS UI) on elf file"); Console.WriteLine(" -L : run legacy application independent of xml versions"); Console.WriteLine(" -i : stop debugger in the initialization code"); Console.WriteLine(" -j : stop debugger in the pre-initialization code"); Console.WriteLine(" -R : do not stop in debugger until OSDebug or OSDebugStr call"); Console.WriteLine(" -p : indicate process to debug (defaults to game process)"); Console.WriteLine(" -g : 32-bit flag to pass along to PPC COS"); Console.WriteLine(" -w : 32-bit flag to pass along to PPC COS."); Console.WriteLine(" -k : path to elf file for debugger"); Console.WriteLine(" -x : Enable AHCI/SATA disk access. Deprecated - will soon become default."); Console.WriteLine(" -r : restart last application"); Console.WriteLine(" -s : use soft launch to run"); Console.WriteLine(" -F : force restart (stop and then boot hw)"); Console.WriteLine(" -t : title launch from mlc emulation (tid is hex that starts with 0x)"); Console.WriteLine(" -e : pass op through to FSEmul or MCP (e.g.: -e sata -> FSEmul -sata)"); Console.WriteLine(" -e eco : Set the system to boot in ECO mode"); Console.WriteLine(); Console.WriteLine(" -v : set COS verbose level (0=off 7 == MAX)"); Console.WriteLine(" -q : do not display OS warning or informational messages."); Console.WriteLine(" -z : suppress mirroring the data to the session data directory."); Console.WriteLine(" -K : Use kill restart to restart the application"); Console.WriteLine(" -T : apptype of the title being run (This will override the calculation of apptype)"); Console.WriteLine(); Console.WriteLine(" -h : (help) display options"); } static void headlessrun_usage() { Console.WriteLine("Usage: cafex headlessrun [options] .rpx \"[arg1]\" ... \"[argN]\""); Console.WriteLine(); Console.WriteLine("options:"); Console.WriteLine(" -b : Use DEBUG version of the OS"); Console.WriteLine(" -n : Don't start the title after upload."); Console.WriteLine(" -m : Bypass mastering setup."); Console.WriteLine(" -w