NSKBL

The Non-Secure Kernel Boot Loader (NSKBL) is the first program that runs on ARM cores in Non-Secure state. As its name indicate, it has the role of initializing the Non-Secure state environment and loading the kernel from storage.

Module
NSKBL is made of stripped down versions of some Non-Secure kernel modules along with code using all these functions to prepare the non-secure environment and load the next stage.

Reduced versions of the following modules are embedded in NSKBL:
 * SceSysmem
 * SceKernelModulemgr
 * SceExcpmgr
 * SceKernelIntrMgr
 * SceSblAuthMgr
 * SceSblSmschedProxy
 * SceLowio (only parts of the Pervasive submodule)
 * SceSdif
 * serves as a thin wrapper around SceSdif for compatibility
 * Only,  ,   and   are provided
 * This is just a wrapper. SceIofilemgr is not included in NSKBL!

It is very likely that the embedded modules in NSKBL are built from the same source tree as the Non-Secure kernel modules. This can be inferred from debugging information contained in some modules (line numbers in NSKBL and module equivalent match).

How to debug NSKBL
NSKBL supports sd0: for debugging. pKblParam->boot_type_indicator_1 = 0x40000 is required.

sceIoOpen(?) error code 0x803FF007
This error can occur if the file is fragmented.

NSKBL walk through
This section aims to provide an overview of the tasks performed by NSKBL. This is based on late firmwares (3.60+) NSKBL; older firmwares may behave differently.

Reset
The reset vector, located at, is the first instruction executed in Non-Secure state, with the MMU turned off. It jumps to a small ASM function that disables interrupts, clears exclusive access requests , invalidates all caches, sets up stacks for all processors modes, and calls.

This function is responsible for turning on the MMU. It partially initializes the, copies the KBL Param from   (where it was placed by SKBL) and prints the   message.

The  initialization includes allocating physical and virtual pages for things like page tables, TTBR, fixed heaps, Sysroot, PhyPageTable, etc. The virtual address for the smaller mappings is randomized in the first 1MiB of the address space (255 page-sized slots - first slot is reserved for NULL page), while larger allocations are randomized in the first 16MiB (15 section-sized slots - slot 0 is reserved for the small ASLR mappings). A few mappings are exempted from randomization, like the identity mapping of -  where NSKBL resides (this range is mapped as RWX, which is probably the only RWX mapping in the Non-Secure kernel).

After all these mappings are complete, the MMU is turned on along with the caches, branch predictor, and a few other things via the. At this point,  is done and   is called.

This function runs with the MMU enabled and receives a partially filled-in  from.

This function begins with a call to  which initializes the Sysroot structure. The slack space after the structure in the  mapping (which is 16KiB-sized) is turned into a "heap" as part of this process. Memory allocation needs are serviced from this space using  (at this point, there are no other kernel heaps available). Sysroot status is set to 1 in this function.

After the Sysroot is initialized,  is called, which initializes the embedded Sysmem module. It's at this stage that all the Sysmem object classes are created. Sysroot status is set to 2 then 3 in this function. Kernel heaps are available after the Sysroot status is set to 3 (i.e. when this function returns).

Now that Sysmem is initialized, 16KiB-sized  memory blocks are allocated, and execution is transfered to   after switching the stack pointer to these memblocks (up until now, the stack we were using was located in the NSKBL   section).

This functions receives a filled-up  from.

After setting the Sysroot status to 4, the remaining embedded modules are started (in order:, SceExcpmgr start,  ,   and SceSblSmschedProxy start). Once starting the embedded modules is done, Sysroot status is set to 0x10 and the final NSKBL function is called.

Final function
This function receives the same  as.

It first calls sceSdStandaloneInit then loads and caches the,   and   security modules.

After this, it loads the, links the NSKBL library to the module, and starts it with the   as.

NSKBL has now handed over control and simply remains resident until it is unmapped by SceSysStateMgr.

SceKblForKernel
NOTE: this library is linked directly to  instead of being registered, and can thus only be imported by this module.

sceSDbgSdioStartForKernel
Requires DIPSW 193.

sceKblPutcharForKernel
This is a guessed name.

This function is at 0x510172BD in FW 3.60 and at 0x51003BE0 in FW 0.940.040.

sceKernelPrintfForKernel
In FW 3.60 this function is at 0x510137A9.

sceKernelPrintfLevelForKernel
In FW 3.60 this function is at 0x51013841.

sceKernelGetDebugLevelForKernel
Temp name was sceKblGetMinimumLogLevelForKernel.

In FW 3.60 this function is at 0x51013921.

sceKernelGetDebugPutcharForKernel
In FW 3.60 this function is at 0x51013765.

sceKernelSysrootProcessmgrStart2ForKernel
In FW 3.60 this function is at 0x510123DD.

sceKernelSysrootThreadMgrStartAfterProcessForKernel
In FW 3.60 this function is at 0x510123A1.

sceKernelSysrootIofilemgrStartForKernel
In FW 3.60 this function is at 0x5101297D.

sceKernelSysrootCorelockUnlockForKernel
In FW 3.60 this function is at 0x510124FD.

sceKernelSysrootCorelockLockForKernel
In FW 3.60 this function is at 0x510124E5.

sceKblCpuSuspendIntrForKernel_old
This is a guessed name.

On FW 0.940, it calls a routine that simply executes  then returns 0.

CPSID i ; Disable all interrupts except NMI (set PRIMASK)

Disables IRQ interrupts by setting the I-bit in the CPSR.

sceKblCpuSuspendIntrForKernel_new
This is a guessed name. Temp name was sceKblCpuSwitchInterruptsForKernel, sceKblCpuDisableIrqInterruptsForKernel.

In FW 3.60 this function is at 0x51003554.

sceSblAimgrIsCEXForKernel
In FW 3.60 this function is at 0x510171B5.

sceSblAimgrIsDiagForKernel
In FW 3.60 this function is at 0x51017175.

sceSblAimgrIsDEXForKernel
In FW 3.60 this function is at 0x51017159.

sceSblAimgrIsToolForKernel
In FW 3.60 this function is at 0x51017139.

sceSblAimgrIsTestForKernel
In FW 3.60 this function is at 0x5101711D.

sceSblAimgrIsVITAForKernel
In FW 3.60 this function is at 0x51017299.

sceSblAimgrIsDolceForKernel
In FW 3.60 this function is at 0x510172A1.

sceSblAimgrIsGenuineDolceForKernel
In FW 3.60 this function is at 0x510171E5.

LoadModulesForKernel
Load all modules from the provided list. The list end is marked by an entry with.

Module GUIDs are populated into the list, so it must be writeable.

sceKernelBootLoadModulesForKernel
Temp name was sceKblLoadModulesForKernel.

In FW 3.60 this function is at 0x51001551.

BootModulesForKernel
Runs the entrypoint of all modules in provided list. The list end is marked by an entry with.

sceKernelBootBootModulesForKernel
Temp name was sceKblBootModulesForKernel.

In FW 3.60 this function is at 0x51001571.

sceAuthMgrExitForKernel
Temp name was sceKblAuthMgrCloseForKernel.

In FW 3.60 this function is at 0x51001345.

sceKblSetNonSyncModuleStartForKernel
This is a guessed name.

In FW 3.60 this function is at 0x51001561.

sceKernelCpuIdForKernel
In FW 3.60 this function is at 0x510147C9.

sceKernelCheckDipswForKernel
In FW 3.60 this function is at 0x51015851.

sceSblQafManagerIsAllowKernelDebugForKernel
In FW 3.60 this function is at 0x51016FD1.

sceKblGetHardwareFlagsForKernel
This is a guessed name.

In FW 3.60 this function is at 0x510128AD.

sceSdStandaloneInitForKernel
Temp name was sceKblInitDeviceForKernel.

Some device init function. On FW 0.940 it initializes and mounts  (eMMC) and   (GCSD).

In FW 3.60 this function is at 0x5100124D.

sceSdStandaloneExitForKernel
Temp name was sceKblFreeFileSystemCtxForKernel.

Cleanup state created by sceSdStandaloneInitForKernel.

In FW 3.60 this function is at 0x51001321.