SceSysStateMgr

From Vita Development Wiki
Revision as of 09:44, 19 January 2023 by CreepNT (talk | contribs) (→‎ifmodel: Correct name of the function)
Jump to navigation Jump to search

This module initializes part of the kernel, then loads and parses System Configuration script which is responsible for loading the rest of the kernel and spawning the Shell.

See also Boot Sequence (SceSysStateMgr)

Module

This module only exists in Non-Secure world.

The SELF can be found at os0:kd/sysstatemgr.skprx.

Version World Privilege
0.931-3.60 Non-secure Kernel

Libraries

This module doesn't export any library.

System Configuration script

The bulk of SceSysStateMgr consists of loading, parsing, and executing so-called System Configuration scripts.

Scripts can exist in two forms: encrypted modules that get loaded and expose a callback to get the plaintext (once decrypted) script, or a plain UTF-8 text file. Every line of the script contains one command or a comment. Each command performs an action (load module, ...) or changes the parser's state (change directory, load bootfs, ...). Scripts are parsed in their entirety before being executed.

The maximum blob size is 0x8000 bytes, and each command consumes a ~16 bytes fixed overhead + 1 byte per argument byte. This gives a rough estimation of a maximum of around 1000 commands per script.

Script locations

SceSysStateMgr will attempt to parse configuration scripts from different locations, depending on the firmware and the console's QA flags.

Unlike what could be expected, the script file's extension is not taken into account to determine whether or not the configuration is loaded as a module or a plaintext file. Script is loaded as a module if the file's first four bytes are SCE\0 (SELF magic), and plaintext otherwise, if QA flags allow it (SceQafMgrForDriver_883E9465() returns true).

The following tables provides all locations a script is attempted to be loaded from in the order of the attempts.

Script locations for firmware 2.10-3.60
Path Condition
host0:psp2config.skprx SceQafMgrForDriver_082A4FC2() returns non-0
sd0:psp2config.skprx MANUFACTURING_MODE predicate is true
ux0:psp2config.skprx MANUFACTURING_MODE predicate is true
os0:psp2config_vita.skprx sceSblAIMgrIsDolce returns 0
os0:psp2config_dolce.skprx sceSblAIMgrIsDolce returns non-0
Script locations for firmware 1.00-2.06
Path Condition
host0:psp2config.skprx SceQafMgrForDriver_082A4FC2() returns non-0
sd0:psp2config.skprx MANUFACTURING_MODE predicate is true
ux0:psp2config.skprx MANUFACTURING_MODE predicate is true
os0:psp2config.skprx Always
Script locations for firmware 0.995-0.996
Path Condition
The following applies if SceSysStateMgr is started with args=1.
sd0:psp2-config.txt DIP switch 0xE0 is enabled
host0:psp2config.skprx DIP switch 0xE0 is disabled
host0:psp2-config.txt Always
The following applies if SceSysStateMgr is started with args=0. (always?)
host0:psp2config.skprx SceQafMgrForDriver_082A4FC2() returns non-0
host0:psp2-config.skarx SceQafMgrForDriver_082A4FC2() returns non-0
sd0:psp2config.skprx MANUFACTURING_MODE predicate is true
sd0:psp2-config.skarx MANUFACTURING_MODE predicate is true
ux0:psp2config.skprx MANUFACTURING_MODE predicate is true
os0:psp2config.skprx Always
os0:psp2-config.skarx Always
Script locations for firmware 0.931-0.990
Path Condition
The following applies if SceSysStateMgr is started with args=1.
sd0:psp2-config.txt DIP switch 0xE0 is enabled
host0:psp2config.skprx DIP switch 0xE0 is disabled
host0:psp2-config.txt Always
The following applies if SceSysStateMgr is started with args=0. (always?)
host0:psp2config.skprx SceQafMgrForDriver_082A4FC2() returns non-0
host0:psp2-config.skarx SceQafMgrForDriver_082A4FC2() returns non-0
sd0:psp2config.skprx MANUFACTURING_MODE predicate is true
sd0:psp2-config.skarx MANUFACTURING_MODE predicate is true
os0:psp2config.skprx Always
os0:psp2-config.skarx Always

Processing flow

Scripts are processed in two steps:

  1. Parsing: Every line of the script is read and split by whitespace. Each line is transformed into a corresponding instruction for the execution engine and saved into a data blob. Invalid scripts cause an early abort here and never reach the next pass.
  2. Execution: The data blob created in step 1 is handed over to a sort of virtual machine that reads it and executes the code corresponding to the instructions specified in it.

Syntax

  • \r(0xD) is ignored
  • \xFF, if present, marks the end of the file
  • \n ends a line
  • \t/\f/ (respectively 0x9, 0xC and 0x20) are considered as whitespace

Syntax of a line (Convention: {x} is ignored, [x] is optional, <x> is mandatory):

  {whitespace}[prefix]{whitespace}<command / keyword>{whitespace}[argumentBlock]<newline>
  
  [argumentBlock]:
   <argument>{whitespace}[argumentBlock]

Up to 7 arguments can be passed to a command if the prefix is not whitespace-separated from it, 6 otherwise. Additional arguments are ignored.

Example commands:

  # Example
     #      with more spaces
  -load os0:kd/codec.skprx
  & echo ohayo

Prefixes

The first non-ignored character of a command is checked to be among one of those, and affects the behaviour of the command.

#

Comment. Rest of the line is ignored and can contain anything.

-

Ignore error. If an error happens while executing command, continue executing the script anyways.

If this prefix isn't present, when an error happens, execution of the script is aborted, no other script is attempted to be executed ?and kernel panics?.

&

Not supported '&' option

Commands

The set of commands available and their behaviour can slightly vary between firmware.

All path parameters can refer to either an absolute or relative path. Relative pathes are canonicalized by appending the provided path to the current directory (see cd), while absolute pathes are used raw.

A path is treated as absolutes if it begins with one of the following strings: /,\, sd0:, host0:, os0:, vs0:, ur0:, ud0: and ux0: (ux0: is not considered as a drive before firmware 0.995).

sd0: and ux0: are only allowed if external storage access is allowed.

If DIP switch 0xFC is enabled and SceQafMgrForDriver_082A4FC2() returns true, all pathes except those starting with host0: are attempted from host0:module/ first. For example, load os0:kd/test.skprx would try to load host0:module/test.skprx then, if it failed, try to load os0:kd/test.skprx.

For module related commands, the provided path is "canonicalized" before being used. The same canonical path used when loading must be used for all commands. Since canonicalization for relative pathes involves the current directory, the following script is invalid:

  cd sd0:kd/
  # Module canonical path is "sd0:kd/test.skprx"
  loadonly test.skprx
  cd os0:kd/
  # Module canonical path is "os0:kd/test.skprx" - has not been loaded, so this fails!
  start test.skprx

load

Load and start module (sceKernelLoadStartModule()).

The module path ends at the first whitespace. Same logic applies to other load-like commands.

Syntax:

  load <module path> [arguments]

Example:

  load sd0:module.skprx this args param1
  # -> loads sd0:module.skprx and pass "sd0:module.skprx this args param1" to argp.
  # Whitespace hazard demonstration
  load sd0:kernel modules/test module.skprx
  # -> loads "sd0:kernel", not "sd0:kernel modules/test module.skprx"!

tload

Same as load, but module is loaded in TOOL memory instead. Requires DIP switch 0xD2.

sload

Performs a load if SceSysrootForDriver_930B1342() & 0x40 (Show Mode).

Added between firmware 1.50 and 1.691.

unload

Stop and unload a module (sceKernelStopUnloadModule()).

Syntax:

  unload <module path> [?arguments?]

Example:

  unload sd0:module.skprx

loadonly

Load a module without starting it (sceKernelLoadModule()).

Syntax:

  loadonly <module path>

Example:

  loadonly sd0:module.skprx

start

Start a loaded module (sceKernelStartModule()).

Syntax:

  start <module path> [?arguments?]

Example:

  start sd0:module.skprx

stop

Stop a module (sceKernelStopModule()).

Syntax:

  stop <module path> [?arguments?]

Example:

  stop sd0:module.skprx

unloadonly

Unload a module (sceKernelUnloadModule).

Syntax:

  unloadonly <module path>

Example:

  unloadonly sd0:module.skprx

spawn

Create and start a new process, using specified module as its main module. This command is subject to rpath redirection.

Syntax:

  spawn <module path> [?arguments?]

Example:

  if SAFE_MODE
  spawn os0:ue/safemode.self
  end
  endif

wait

Wait until a spawn'ed process finished.

Syntax:

  wait <module path>

Example:

  spawn sd0:example.self
  wait sd0:example.self

spawnwait

Combined spawn+wait not subject to rpath redirection.

Syntax:

  spawnwait <module path> [?arguments?]

Example:

  if MANUFACTURING_MODE
     - spawnwait sd0:psp2diag.self
     - spawnwait ux0:psp2diag.self
  endif

appspawn

Spawn an application process using sceKernelSysrootAppMgrSpawnProcess(). This command is subject to rpath and Shell path redirection.

Syntax:

  appspawn <executable path> [budget ID]

Budget ID must be one of the following:

ID string Budget ID Notes
GAME_BUDGET_ID 0x1000000 0x1010001 in 0.931
SHELL_BUDGET_ID 0x4000000 0x4020102 in 0.931

If none is specified, GAME_BUDGET_ID is used.

Examples:

  - appspawn vs0:vsh/shell/shell.self SHELL_BUDGET_ID
  - appspawn sd0:game.self GAME_BUDGET_ID
  # Same effect as above
  - appspawn sd0:game.self

kill

Kill a process. This command is dummy and doesn't have any effect.

sleep

Sleep for a certain duration. This command is dummy and doesn't have any effect.

echo

Write to stdout (using sceKernelPrintf).

Syntax:

  echo [data]

Example:

  # Write "Hello world!" to stdout.
  echo Hello world!

loadconfig

Load and parse another configuration file. The configuration file must be either a module or a plaintext file (latter is only allowed depending on the system's QA flags). The configuration file is fully executed before this command returns.

This command can be executed by the loaded configuration files, but the maximum number of nested calls is 4 (or 5?) - further nested calls are ignored. For example, assuming file cfgX.txt loads file cfg(X+1).txt, only files 0-4 are executed, and cfg5.txt is skipped. Nested call overflow is not considered an error; the files are simply skipped but the command succeeds.

Note that the configuration is loaded under its own independent context; for example, it cannot unload a module that the configuration executing the loadconfig has load'ed.

Syntax:

  loadconfig <configuration path>

Example:

  - loadconfig sd0:boot_config_second.txt

include

Alias of loadconfig.

cd

Change directory. Sets the current directory.

Syntax:

  cd <directory>

Example:

  cd sd0:kd/
  load module.skprx
  # loads sd0:kd/module.skprx

The default working directory is the same as where the bootconfig is located.

setenv

Sets an environement variable. Seems unused.

Syntax:

  setenv <name> <value>

Example:

  setenv OHAYO_PATH sd0:ohayo

setmodfile

Alias of setenv.

umount_bootfs

Unmount bootfs. os0:kd/bootimage.skprx is mounted as bootfs before scripts execute since firmware 0.996 (except if External Boot mode (SceSysrootForKernel_89D19090()) is active on firmwares >= 3.00).

Added in firmware 1.80.

Syntax:

   umount_bootfs

Special commands

Those commands affect the script's execution flow instead of invoking callbacks with side effects.

Special commands cannot fail and do not support prefixing. For example, -if MANUFACTURING_MODE is a syntax error.

ifmodel

Conditional code block start. Execute code in block if predicate is true.

Syntax:

  ifmodel <predicate name>

Example:

  ifmodel MANUFACTURING_MODE
     # Code executes only if MANUFACTURING_MODE evaluates to true
     echo Running in manufacturing mode!
  endif

Nested ifmodel/ifnmodel blocks are supported, maximum depth is 32.

Every ifmodel block must end with a corresponding endif.

predicate name is a string provided to the function ConfReaderUtilsEvalCond which finds a callback function whose return value is considered as the value of the predicate (i.e. false if the function returns 0, true if the function returns 1). Specifying the name of a non-existent predicate is a syntax error.

The following table contains the name of all supported predicates along with the code of the associated callback function:

Available predicates list
Firmware Name Predicate code Notes
0.931-3.60 0 return 0; Always false.
0.931-3.60 1 return 1; Always true.
0.931-3.60 MANUFACTURING_MODE return sceKernelSysrootIsManufacturingModeForKernel();
0.940-3.60 EXTERNAL_BOOT_MODE return sceKernelSysrootIsExternalBootModeForKernel();
0.931-0.945 UPDATE_MODE
return (sceKernelSysrootGetKblParam()->bootFlags[0] != 0xFF);
0.990-3.60 UPDATE_MODE return sceKernelSysrootIsUpdateModeForKernel(); Identical to 0.931 but moved to a Sysroot function
0.990-0.995 USB_ENUM_WAKEUP return ((sceKernelSysrootGetErnieWakeupFactor() & 0x7F) == 0xF);
0.996-3.60 USB_ENUM_WAKEUP return sceKernelSysrootIsUsbEnumWakeupForKernel(); Identical to 0.990 but code was moved to a Sysroot function
0.940-3.60 DEVELOPMENT_MODE return sceSblACMgrIsDevelopmentMode();
0.931-0.945 SAFE_MODE
SceKblParam* pKbl = sceKernelSysrootGetKblParam();
return ((pKbl->wakeupFactor & 0x7F) == 0xB) && ((pKbl->bootControlsInfo >> 8 & 0xFF) == 0xA9); //R+SELECT+X+O
0.990-3.60 SAFE_MODE return sceKernelSysrootIsSafeModeForKernel(); Routine is similar to 0.931 check
0.931-3.60 UD0_EXIST
SceIoStat stat;
return (sceIoGetstat("ud0:", &stat) == SCE_OK);
0.931-3.01 DEMO_MODE
SceIoStat stat;
if (!SceQafMgrForDriver_CAD47130() || sceIoGetstat("vs0:vsh/shell/shell_mini.self", &stat) >= 0)
  return false;
return (sceIoGetstat("vs0:vsh/shell/shell_gamebudget.self", &stat) == SCE_OK);
0.931-1.69 KERMIT_REV_ES1_X return (sceKernelSysrootGetKermitRevision() & 0xF0) == 0x10);
0.931-1.69 KERMIT_REV_ES2_X return (sceKernelSysrootGetKermitRevision() & 0xF0) == 0x20);
0.940-1.69 KERMIT_REV_ES3_X return (sceKernelSysrootGetKermitRevision() & 0xF0) == 0x30);
0.990-1.69 KERMIT_REV_ES4_X return (sceKernelSysrootGetKermitRevision() & 0xF0) == 0x40);
1.80-3.01 KERMIT_REV_ES4_X Same as KERMIT10_REV_ES4_X
1.80-3.01 KERMIT10_REV_ES4_X return (sceKernelSysrootGetKermitRevision() & 0x1FFF0) == 0x40); Change due to new Kermit revision encoding
1.80-3.01 KERMIT15_REV_ES1_X return (sceKernelSysrootGetKermitRevision() & 0x1FFF0) == 0x110);
3.10-3.60 AU_CODEC_IC_CONEXANT
uint32_t hwFlag[4];
SceSysrootForDriver_46E72428(&hwFlag); // sceKernelSysrootGetHardwareFlagsForDriver
return ((hwFlag[0] & 0x40) != 0);
Related to SceCodec IC. Probably superseded KERMITxx_REV_ESx_X variables
2.10-3.60 BSOD_REBOOT return sceKernelSysrootIsBsodRebootForKernel();

if

Alias of ifmodel.

ifnmodel

Conditional code block start. Execute code in block if predicate is false. See ifmodel.

Syntax:

  ifnmodel <predicate>

Example:

  ifnmodel USB_ENUM_WAKEUP
     # Code executes only if USB_ENUM_WAKEUP evaluates to false
     echo Not wakeup due to USB enum!
   endif

Every ifnmodel block must end with a corresponding endif.

else

Mark the beginning of a failed predicate conditional block. Must reside between a if[n]model and the corresponding endif.

Syntax:

  else

Example:

  if USB_ENUM_WAKEUP
  load os0:kd/enum_wakeup.skprx
  else
  echo No USB enum wakeup!
  endif

endif

Marks the end of a conditional block.

Syntax:

  endif

Example:

  if USB_ENUM_WAKEUP
  load os0:kd/enum_wakeup.skprx
  endif

repeat

Start of a repetition block. Commands in a repetition block are repeated multiple times.

Syntax:

  repeat <count>

count is the number of times the code block will be executed, and must be a decimal number.

Example:

  repeat 3
  echo Something
  endrepeat
  # prints the following:
  #
  # Something
  # Something
  # Something

endrepeat

End of a repetition block. Must appear after a repeat command.

Syntax:

  endrepeat

end

Stop the script execution and return success.

Syntax:

  end
  if SAFE_MODE
  spawn os0:ue/safemode.self
  end
  endif
  echo Not in Safe Mode!

Remote Path file

SceSysStateMgr attempts to read a Remote Path file at host0:psp2config.rpath. This is only done if either SceQafMgrForDriver_B99770A13() or SceQafMgrForDriver_082A4FC2() return true. The rpath file applies to all configuration scripts.

The file's syntax is similar to System Configuration scripts.

This file can be used for two purposes: override the Shell file, and override application spawn path.

If a line starts with set_shell_filename [path], path is used when appspawn'ing any application with executable name shell.self. See appspawn. If path is empty, Shell loading override is disabled (i.e. the requested file is loaded).

This only affects the appspawn command.

Otherwise, if a line doesn't start with a # (i.e. not a comment), it is stored as a remote path for application spawning. Up to 4 such pathes can be specified, all those past the 4th one are ignored.

This only affects the spawn and appspawn commands.

When attempting to load file os0:path/to/module.skprx, the following files are attempted to be loaded in order:

  1. "Remote path" (host0:module/ prefix i.e. host0:module/module.skprx) if allowed by QAF and DIP switches
  2. "Remote Rpath" (e.g. os0:tk/module.skprx if rpath was os0:tk/) if a rpath file is present and allowed
  3. "Canonical path" (absolute path if specified, otherwise built from current directory)

Example psp2config.rpath file:

  # Load development Shell from PC
  set_shell_filename host0:dev_shell.self
  
  # Allow test app spawn from PC
  host0:test_app/

With this file, the following behaviour is observed:

appspawn vs0:vsh/shell/shell.self:

  1. Attempt to load host0:dev_shell.self
  2. Attempt to load host0:test_app/dev_shell.self

Note how the original Shell path is completly ignored.

spawn os0:kd/test_exec.self

  1. Attempt to load host0:module/test_exec.self if allowed by QAF
  2. Attempt to load host0:test_app/test_exec.self
  3. Attempt to load os0:kd/test_exec.self