SceExcpmgr

SceExcpmgr is a kernel module that sets up exception handling. A version exists in both non-secure and secure worlds. In non-secure world, after the kernel is booted up, the exception handlers pointed to by VBAR all jump into code in this module.

Module
This module exists in both non-secure and secure world. The non-secure world SELF can be found in.

Built-in handlers behaviour
SceExcpmgr is mostly responsible for providing a facility that allows installing exception handlers to other modules. However, it also installs exception handlers by itself.

SceExcpmgr registers an infinite loop as the default exception handler in. For RESET, SVC, RESERVED and IRQ, another infinite loop handler will be installed at priority 7.

SceExcpmgr also installs a priority 7 handler for PABT, DABT and UNDEF. As specified in the Types section, those handlers will panic the kernel if they receive either  or   as their handling code parameter, infinite loop if nested exception count is greater than 1, and call sceKernelSysrootReturnFromExcpToThreadForKernel otherwise.

In addition to this, SceExcpmgr installs a priority 0 handler for PABT, DABT and UNDEF. Those three have a common behaviour: building the, incrementing the nested exception count, clearing some CP14 control registers if needed, loading the   provided by SceSysrootForKernel_118657C6, setting DACR to 0x15450000 (not done in System Software version 0.990.030), zero'ing out   and  , and calling a per-handler callback. The CP14 registers that get zero'ed out are the breakpoint control registers ( - ) if a non-NULL pointer has been provided to SceExcpmgrForKernel_A66DDFA3, and the watchpoint control registers ( - ) if a non-NULL pointer has been provided to SceExcpmgrForKernel_4FF90618.

PABT handler
The PABT handler performs no additional work and merely transfers control to the next exception handler in chain.

UNDEF handler
In System Software version 0.990.030, the UNDEF handler performs no additional work and merely transfers control to the next exception handler in chain.

Since System Software version ?.??, the UNDEF handler will check if the instruction that caused the exception is a, in which case it will be replaced with a   before execution is resumed at the faulting instruction (which is now a  ). Otherwise, control is transferred to the next exception handler in chain. According to the ARM Cortex-A9 TRM, this MCRR instruction is used to program the Preload Engine channels.

DABT handler
The DABT handler is responsible for handling aborts in the Vmaccess routines. If such an exception has not happened, control is transferred to the next exception handler in chain.

Old Vmaccess model
In System Software revision 0.931.010 and earlier, the Vmaccess functions follow this pattern:

If an invalid (user) pointer was provided to this function, a Data Abort would occur on the checked instruction (in this case, ).

When an exception occurs, if the CPU is in ARM mode and  belongs in the old model Vmaccess range, the DABT handler will set   (SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS) in the exception context then resume execution 'three instructions after the faulting one', in the  sled (in modern firmwares, only one instruction is skipped instead of 3). The caller thus see the function failed as it returned an error code (SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS).

In recent firmwares, the old Vmaccess range must be explicitely set via a call to SceExcpmgrForKernel_C45C0D3D instead of being fetched during the call to sceKernelGetVmaccessRange.

New Vmaccess model
Since System Software revision 0.940, this model has been progressively phased out and replaced with a new Vmaccess model.

Under the new model, the Vmaccess functions all begin by loading the address of a function in  but no longer have to follow a specific pattern. When an exception occurs, if the CPU is in ARM mode and the instruction at  is a checked memory access instruction (i.e. one of {,  ,  ,  ,  ,  ,  ,  }), execution is resumed at the address pointed to by. The address loaded in  points to a snippet that cleans the stack if needed then returns SCE_KERNEL_ERROR_INVALID_MEMORY_ACCESS.

Note that if the old and new model ranges overlap, the latter takes priority. This means that exceptions raised from code residing in the overlap will be handled under the new model.

If the DABT or UNDEF handlers return, CP14 registers are restored from either the global variables set previously by SceExcpmgrForKernel_4FF90618 and SceExcpmgrForKernel_A66DDFA3, or interrupted thread's TPIDRPRW->0x18->0xC if the TPIDRPRW is non-NULL. If no breakpoint restore structure has been provided to SceExcpmgrForKernel_A66DDFA3, then watchpoints will not be restored regardless of whether something was provided to SceExcpmgrForKernel_4FF90618 or not.

Non-exported functions
The following table contains offsets (from the base of /segment 0) to non-exported functions whose name is known:

sceKernelRegisterExceptionHandlerForKernel
Temp name was sceExcpmgrRegisterHandlerForKernel.

Installs an exception handler. The exception handler can be ARM code or Thumb code. Allowed  values are from 0 (most important) to 7 (least important), including them. Specifying priority 0 will install the handler directly in VBAR, which means its code will run directly when an exception raises (and as such it needs to build the exception context itself). must be set if the handler function is Thumb code.

The syscall handler in FW 1.50 is SceExcpmgr_func_0x81000E40.

The syscall handler in FW 3.65 is located at offset 0xF40 in SceKernelIntrMgr's  segment.

sceKernelRegisterDefaultExceptionHandlerForKernel
Installs an exception handler for all exceptions. If no exception handler is already installed for an exception, the handler will be installed in the VBAR. must be the same parameter that would be passed to sceKernelRegisterExceptionHandlerForKernel.

sceKernelReleaseExceptionHandlerForKernel
Uninstalls an exception handler.

Pass the same arguments as provided to sceKernelRegisterExceptionHandlerForKernel.

sceKernelInitialHandlerDebugUndefCfuncForKernel
Logs some information about the CPU state and backtrace then returns. Freezes with an infinite loop if currentHandlerIndex is superior to 1.

sceKernelInitialHandlerDebugPabtCfuncForKernel
Logs some information about the CPU state and backtrace then returns. Freezes with an infinite loop if currentHandlerIndex is superior to 1.

sceKernelInitialHandlerDebugDabtCfuncForKernel
Logs some information about the CPU state and backtrace then returns. Freezes with an infinite loop if currentHandlerIndex is superior to 1.

sceKernelPanicHandlerReturnFromNestedExceptionCfuncForKernel
This name is probably incorrect.

SceExcpmgrForKernel_A90AC525
Returns a pointer to the handler previously registered by sceKernelRegisterDefaultExceptionHandlerForKernel.

sceKernelGetExcpStackBottomForKernel
Returns the exception stack bottom for specified CPU core. The stack bottom is the highest address of the stack.

Reimplementation code:

sceKernelGetExcpCBForKernel
This is a guessed name. Temp name was sceKernelGetExcpDataForKernel, sceExcpmgrGetDataForKernel.

Get exception data pointer (for use by handlers).

SceExcpmgrForKernel_3AE9AEE1
Sets a callback function ran by the default UNDEF exception handler before calling the next handler in the chain.

SceExcpmgrForKernel_4FF90618
Called by SceProcessmgr during.

Sets the structure CP14 watchpoint registers will be restored from if TPIDRPRW of thread that raised an exception is NULL (Kernel process). See SceExcpmgr for more information.

SceExcpmgrForKernel_A66DDFA3
Called by SceProcessmgr during.

Sets the structure CP14 breakpoint registers will be restored from if TPIDRPRW of thread that raised an exception is NULL (Kernel process). See SceExcpmgr for more information.

SceExcpmgrForKernel_7ADF11DB
Sets a callback function ran by the default DABT exception handler before trying to handle the exception.

SceExcpmgrForKernel_8D223205
Sets a callback function ran by the default PABT exception handler before calling the next handler in the chain.

SceExcpmgrForKernel_C45C0D3D
Sets the "memory access error area" range. See the built-in handlers behaviour section for more information.

In older firmwares (0.990.030), this range is acquired during the call to SceCpuForKernel_9A3281C0 in SceExcpmgr  instead.

SceExcpmgrForKernel_D464A9A7
Returns the current nested exception count, or 0 if current TPIDRPRW is non-NULL.

SVC
SVC (Supervisor Call), more commonly called Syscalls (system calls), is what allows to interact with non-secure Kernel from usermode.

The SVC interface is defined in non-secure Kernel as:

On return, R1-R3 and R12 are cleared to 0x0 or 0xDEADBEEF to prevent any data leaks. All usermode pointers passed to syscalls are accessed with ARM instructions LDRT and STRT for hardware forced permission checks. Syscalls 0x0 - 0xFF are likely a "fastcall" interface that do not mask interrupts or set the DACR, however currently are no such fastcalls defined. Syscalls 0x100 - 0xFFF are made with IRQ interrupts masked and DACR set to 0xFFFF0000 (to prevent access to certain memory domains). Any other syscall numbers are invalid.

System calls are handled in "system" mode defined in ARMv7 (mode 0b11111).

Usermode exported functions loaded by SceKernelModulemgr are exported as syscalls. The number assigned to the syscall are randomized with respect to each library but not within a library. That means, for example, two functions exported by a library will always be some syscall number apart even though that number will change on each boot.

There is no SVC in secure world because all code in secure world is running as kernel.

SMC
SMC (Secure Monitor Call) is what allows to interact with ARM TrustZone from non-secure kernel.

The SMC interface for making a non-secure kernel call to TrustZone is:

The SMC interface is very similar to the SVC interface. The SMC handler and MVBAR is set up in TrustZone by SceExcpmgrForTZS.

0x0 - 0xFF are fast service calls. 0x100 - 0xFFF are normal service calls ran with IRQs masked.

Secure services are ran in ARM system processor mode (0b11111) in TrustZone.

SMC calls are registered by SceIntrmgrForTZS functions.

Aborts
On development units, data and prefetch aborts can handle  instruction for software breakpoints. SceDebug uses this to handle usermode breakpoints. There is no built-in support for  in kernel code.

SceSysmem uses data aborts with the  and   instructions to implement usermode pointer checking. When LDRT/STRT throws a MMU data exception because of an invalid access and the exception came from SceSysmem or SceSysmem or related functions, the data abort handler will resume execution.

IRQ
IRQs are only handled in non-secure world. An IRQ in secure world is fatal. See SceKernelIntrMgr.

FIQ
FIQs are only handled in secure world because of the bit set in the SCR. Because of this, it is likely that secure devices such as Cmep use FIQs to communicate with the Cortex A9 cores. See SceKernelIntrMgr.