NSKBL: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
(Add details description of NSKBL and its role in the boot process, and SceKernelBootParam)
Line 1: Line 1:
Non-Secure Kernel Boot Loader (NSKBL) is a Non-Secure world program that performs eMMC setup, base kernel modules loading, etc. during PSVita boot.
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 ==
== Module ==


The NSKBL contains subroutines that are stripped versions of the non-secure kernel ones found in [[SceSysmem]], [[SceKernelModulemgr]], [[SceSblSmschedProxy]], [[SceExcpmgr]], [[SceKernelIntrMgr]], [[SceSblAuthMgr]], [[SceProcessmgr]] (maybe), [[SceSdif]], [[SceIofilemgr]] (simple version?), and some other core drivers.
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]]
** <code>iofilemgr_if</code> serves as a thin wrapper around [[SceSdif]] for compatibility
*** Only <code>sceIoOpen</code>, <code>sceIoLseek</code>, <code>sceIoRead</code> and <code>sceIoClose</code> 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).


== Notes ==
== Notes ==
Line 14: Line 30:


This error can occur if the file is fragmented.
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 <code>0x51000000</code>, is the first instruction executed in Non-Secure state, with the MMU turned off.
It jumps to a small ASM function that disables interrupts (<code>cpsid if</code>), clears exclusive access requests (<code>clrex</code>), invalidates all caches, sets up stacks for all processors modes, and calls <code>boot</code>.
=== <code>boot</code> ===
This function is responsible for turning on the MMU. It partially initializes the <code>SceKernelBootParam</code>, copies the [[KBL Param]] from <code>0x40200100</code> (where it was placed by [[SKBL]]) and prints the <code>Starting PSP2 Kernel Boot Loader (Non-secure)</code> message.
The <code>SceKernelBootParam</code> 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 <code>0x51000000</code>-<code>0x51FFFFFF</code> 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 <code>SCTLR</code>. At this point, <code>boot</code> is done and <code>sceKblMain</code> is called.
=== <code>sceKblMain</code> ===
This function runs with the MMU enabled and receives a partially filled-in <code>SceKernelBootParam</code> from <code>boot()</code>.
This function begins with a call to <code>sceKernelSysrootStart</code> which initializes the Sysroot structure. The slack space after the structure in the <code>SceSysroot</code> mapping (which is 16KiB-sized) is turned into a "heap" as part of this process. Memory allocation needs are serviced from this space using <code>sceKernelSysrootAlloc</code> (at this point, there are no other kernel heaps available). Sysroot status is set to 1 in this function.
After the Sysroot is initialized, <code>sceKernelSysmemStart</code> is called, which initializes the embedded [[SceSysmem|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 <code>SceKernelBootStackCoreX</code> memory blocks are allocated, and execution is transfered to <code>main2</code> after switching the stack pointer to these memblocks (up until now, the stack we were using was located in the NSKBL <code>.bss</code> section).
=== <code>main2</code> ===
This functions receives a filled-up <code>SceKernelBootParam</code> from <code>sceKblMain()</code>.
After setting the Sysroot status to 4, the remaining embedded modules are started (in order: <code>sceKernelModulemgrStart()</code>, [[SceExcpmgr]] start, <code>sceKernelIntrMgrStart</code>, <code>sceSblAuthMgrStart()</code> 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 <code>SceKernelBootParam</code> as <code>main2</code>.
It first calls [[NSKBL#sceSdStandaloneInitForKernel|sceSdStandaloneInit]] then loads and caches the <code>gcauthmgr</code>, <code>rmauth</code> and <code>encdec_w_portability</code> security modules.
After this, it loads the [[ScePsp2BootConfig|<code>os0:kd/psp2bootconfig.skprx</code>]], links the [[NSKBL#SceKblForKernel|NSKBL library]] to the module, and starts it with the <code>SceKernelBootParam*</code> as <code>argp</code>.
NSKBL has now handed over control and simply remains resident until it is unmapped by [[SceSysStateMgr]].


== Types ==
== Types ==


<source lang="C">
<source lang="C">
typedef struct KBPMemoryRegion {
    unsigned pbase;
    unsigned psize;
} KBPMemoryRegion;
typedef struct KBPMappingInfo {
    char* name;        //<! Name of the mapping
    unsigned pbase;    //<! Base physical address of the mapping
    unsigned vbase;    //<! Base virtual address of the mapping
    unsigned psize;    //<! Size of the physical range of the mapping??
    unsigned vsize;    //<! Size of the virtual range of the mapping?? - Usually equal to psize, but may be bigger.
    unsigned extraHigh; //<! Sometimes used as extraHigh for some memblock allocations? Exact meaning unknown.
    //psize + extraHigh must always be equal to vsize
} KBPMappingInfo;
typedef struct KBPBootStackInfo {
    unsigned unk0[2];
    unsigned ttbcr;
    unsigned dacr;
    unsigned asid;
    unsigned size;
    SceUID blkId;      //<! UID of the stack's memblock
    void* stackBottom; //<! = memblock.vbase + size
} KBPBootStackInfo;
//This structure is passed as argp of modules like sysmem.skprx, etc
typedef struct SceKernelBootParam { // Size is 0x310 in 3.60-3.65 and 4.00. Layout appears to be identical.
  unsigned size;                //<! Size of this structure
  unsigned secure;              //<! Is secure state? Always 0 in NSKBL
  unsigned num_memory;          //<! Number of filled elements in the next field
  KBPMemoryRegion memory[4];    //<! Physical memory ranges usable by NSKBL and kernel
  SceKblParam *pKblParam;        //<! Pointer to KBL Param
  unsigned unk30[5];
  unsigned SoCInfo;              //<! = *(u32*)PERVASIVE_MISC
  unsigned pmisc_unk4;          //<! = *(u32*)(PERVASIVE_MISC + 4)
  unsigned KermitRevision;      //<! = SoCInfo & 0x1FFFF
  unsigned hwDependent[2];      //<! Depends on pKBLParam->hardwareInfo
  KBPMappingInfo ttbr0;          //<! "SceKernelTTBR0", ASLR vbase, psize 0x4000
  unsigned ttbr0_maxAddress;    //<! Maximal address covered by TTBR0
  unsigned sizeTTBR0Address;    //<! Size of the address space covered by TTBR0
  KBPMappingInfo ttbr1;          //<! "SceKernelTTBR1", ASLR vbase, psize 0x4000
  unsigned sizeTTBR1Address;    //<! Size of the address space covered by TTBR1
  void *L2PT000_mapbase;        //<! First vaddr mapped by "SceKernelL2PageTable000"
  KPBMappingInfo reset;          //<! "SceKernelReset", vbase 0, psize 0x1000, extraHigh 0x3000
  KBPMappingInfo excpEntry;      //<! "SceKernelExceptionEntry", ASLR vbase, psize 0x1000, extraHigh 0x1000
  KBPMappingInfo l2pt000;        //<! "SceKernelL2PageTable000", ASLR vbase, psize 0x1000, extraHigh 0x1000
  KBPMappingInfo l2vector;      //<! "SceKernelL2Vector", ASLR vbase, psize 0x4000, extraHigh 0x4000
  KBPMappingInfo sysroot;        //<! "SceSysroot", ASLR vbase, psize 0x4000
  KBPMappingInfo fh32b;          //<! "SceKernelFixedHeap32B", ASLR vbase, psize 0x10000
  KBPMappingInfo fh48b;          //<! "SceKernelFixedHeap48B", ASLR vbase, psize 0x10000
  KBPMappingInfo fh64b;          //<! "SceKernelFixedHeap64B", ASLR vbase, psize 0x10000
  KBPMappingInfo fhUIDEntry;    //<! "SceKernelFixedHeapUIDEntry", ASLR vbase, psize 0x10000
  KBPMappingInfo fhL2Object;    //<! "SceKernelFixedHeapForL2Object", ASLR vbase, psize 0x1000, extraHigh 0x1000
  KBPMappingInfo unk188;        //<! Unused? NOTE: ASLR vbase = randomize in 255 slots, MegaASLR vbase = randomize in 15 slots
  KBPMappingInfo phypage;        //<! "SceKernelPhyPageTable", MegaASLR vbase, psize 0x80000
  KBPMappingInfo phypageHigh;    //<! "SceKernelPhyPageTableHigh", MegaASLR vbase, psize 0x80000, pbase 0x77F00000
  KBPMappingInfo bootkernimg;    //<! "SceBootKernelImage", vbase=pbase=0x51000000, psize 0x1000000, extraHigh 0x1000000
  KBPMappingInfo hwreg;          //<! Unnamed. vbase=pbase=0xE0000000, psize 0x8000000
  SceCorelockContext *pCorelock;
  KBPBootStackInfo bootCpu[4];  //<! bootCpu[X] corresponds to CPUX's info. Stack is pivoted to this when calling main2.
  unsigned unk288;                      //<! Related to L2PageTable000? Always 0.
  void *pL2PageTable000;                //<! Base address of the L2PageTable000
  void *resetVector;                    //<! Goes into VBAR. = excpEntry.vbase + 0x100
  SceKernelPhyMemPart *phyMemPartKD;    //<! "SceKernelPhyMemPartKD"
  SceKernelPhyMemPart *phyMemPartTool;  //<! "SceKernelPhyMemPartTool". May be NULL
  PhyPage *pPageKernelReset;            //<! PhyPage object describing the pages backing SceKernelReset
  PhyPage *pPageL2PageTable000;        //<! PhyPage object describing the pages backing SceKernelL2PageTable000
  PhyPage *pPageSysroot;                //<! PhyPage object describing the pages backing SceSysroot
  PhyPage *pPageTTBR0;                  //<! PhyPage object describing the pages backing SceKernelTTBR0
  PhyPage *pPageTTBR1;                  //<! PhyPage object describing the pages backing SceKernelTTBR1
  PhyPage *pPageL2Vector;              //<! PhyPage object describing the pages backing SceKernelL2Vector
  PhyPage *pPagePhypage;                //<! PhyPage object describing the pages backing SceKernelPhyPageTable
  PhyPage *pPagePhypageHigh;            //<! PhyPage object describing the pages backing SceKernelPhyPageTableHigh
  PhyPage *pPageBootKernelImage;        //<! PhyPage object describing the pages backing SceBootKernelImage????
  PhyPage *pPageFixedHeap32B;          //<! PhyPage object describing the pages backing SceKernelFixedHeap32B
  PhyPage *pPageFixedHeap48B;          //<! PhyPage object describing the pages backing SceKernelFixedHeap48B
  PhyPage *pPageFixedHeap64B;          //<! PhyPage object describing the pages backing SceKernelFixedHeap64B
  PhyPage *pPageFixedHeapForL2Object;  //<! PhyPage object describing the pages backing SceKernelFixedHeapForL2Object
  SceUIDFixedHeapObject *pFixedHeap32B;
  SceUIDFixedHeapObject *pFixedHeap48B;
  SceUIDFixedHeapObject *pFixedHeap64B;
  SceUIDFixedHeapObject *pFixedHeapForL2Object;
  PhyPage *pPageUIDHeap;                //<! PhyPage object describing the pages backing SceKernelFixedUIDHeap??
  L2PageTableObject *pL2PT000Object;    //<! L2PageTableObject for SceKernelL2PageTable000
  L2PageTableObject *pPhyPageTblL2PTO;  //<! L2PageTableObject for table used to map the PhyPageTable (located @ SceKernelL2PageTable000.pbase + 0x400)
  SceUIDPartitionObject *pPartitionKernel; //<! Object of "SceKernelRoot" partition
  SceUID uidPartitionKernel;              //<! UID of object above (0x10009)
  unsigned unk2F8[5];
  unsigned magic;                          //<! 0x7F407C30
};
typedef struct SceNskblModuleInfo { // size is 0xC on FWs 0.940-0.990
typedef struct SceNskblModuleInfo { // size is 0xC on FWs 0.940-0.990
     char* filename;    // Raw SKPRX file name (e.g. "sysmem.skprx"). Modules are loaded either from os0:kd/ or host0:module/.
     char* filename;    // Raw SKPRX file name (e.g. "sysmem.skprx"). Modules are loaded either from os0:kd/ or host0:module/.
Line 102: Line 247:


== SceKblForKernel ==
== SceKblForKernel ==
NOTE: this library is linked directly to <code>psp2bootconfig</code> instead of being registered, and can thus only be imported by this module.


=== sceSDrfpStartForKernel ===
=== sceSDrfpStartForKernel ===

Revision as of 22:47, 13 January 2023

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:

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).

Notes

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 0x51000000, is the first instruction executed in Non-Secure state, with the MMU turned off. It jumps to a small ASM function that disables interrupts (cpsid if), clears exclusive access requests (clrex), invalidates all caches, sets up stacks for all processors modes, and calls boot.

boot

This function is responsible for turning on the MMU. It partially initializes the SceKernelBootParam, copies the KBL Param from 0x40200100 (where it was placed by SKBL) and prints the Starting PSP2 Kernel Boot Loader (Non-secure) message.

The SceKernelBootParam 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 0x51000000-0x51FFFFFF 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 SCTLR. At this point, boot is done and sceKblMain is called.

sceKblMain

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

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

After the Sysroot is initialized, sceKernelSysmemStart 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 SceKernelBootStackCoreX memory blocks are allocated, and execution is transfered to main2 after switching the stack pointer to these memblocks (up until now, the stack we were using was located in the NSKBL .bss section).

main2

This functions receives a filled-up SceKernelBootParam from sceKblMain().

After setting the Sysroot status to 4, the remaining embedded modules are started (in order: sceKernelModulemgrStart(), SceExcpmgr start, sceKernelIntrMgrStart, sceSblAuthMgrStart() 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 SceKernelBootParam as main2.

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

After this, it loads the os0:kd/psp2bootconfig.skprx, links the NSKBL library to the module, and starts it with the SceKernelBootParam* as argp.

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

Types


typedef struct KBPMemoryRegion {
    unsigned pbase;
    unsigned psize;
} KBPMemoryRegion;

typedef struct KBPMappingInfo {
    char* name;         //<! Name of the mapping
    unsigned pbase;     //<! Base physical address of the mapping
    unsigned vbase;     //<! Base virtual address of the mapping
    unsigned psize;     //<! Size of the physical range of the mapping??
    unsigned vsize;     //<! Size of the virtual range of the mapping?? - Usually equal to psize, but may be bigger.
    unsigned extraHigh; //<! Sometimes used as extraHigh for some memblock allocations? Exact meaning unknown.
    //psize + extraHigh must always be equal to vsize
} KBPMappingInfo;

typedef struct KBPBootStackInfo {
    unsigned unk0[2];
    unsigned ttbcr;
    unsigned dacr;
    unsigned asid;
    unsigned size;
    SceUID blkId;      //<! UID of the stack's memblock
    void* stackBottom; //<! = memblock.vbase + size 
} KBPBootStackInfo;

//This structure is passed as argp of modules like sysmem.skprx, etc
typedef struct SceKernelBootParam { // Size is 0x310 in 3.60-3.65 and 4.00. Layout appears to be identical.
   unsigned size;                 //<! Size of this structure
   unsigned secure;               //<! Is secure state? Always 0 in NSKBL
   unsigned num_memory;           //<! Number of filled elements in the next field
   KBPMemoryRegion memory[4];     //<! Physical memory ranges usable by NSKBL and kernel
   SceKblParam *pKblParam;        //<! Pointer to KBL Param
   unsigned unk30[5];
   unsigned SoCInfo;              //<! = *(u32*)PERVASIVE_MISC
   unsigned pmisc_unk4;           //<! = *(u32*)(PERVASIVE_MISC + 4)
   unsigned KermitRevision;       //<! = SoCInfo & 0x1FFFF
   unsigned hwDependent[2];       //<! Depends on pKBLParam->hardwareInfo
   KBPMappingInfo ttbr0;          //<! "SceKernelTTBR0", ASLR vbase, psize 0x4000
   unsigned ttbr0_maxAddress;     //<! Maximal address covered by TTBR0
   unsigned sizeTTBR0Address;     //<! Size of the address space covered by TTBR0
   KBPMappingInfo ttbr1;          //<! "SceKernelTTBR1", ASLR vbase, psize 0x4000
   unsigned sizeTTBR1Address;     //<! Size of the address space covered by TTBR1
   void *L2PT000_mapbase;         //<! First vaddr mapped by "SceKernelL2PageTable000"
   KPBMappingInfo reset;          //<! "SceKernelReset", vbase 0, psize 0x1000, extraHigh 0x3000
   KBPMappingInfo excpEntry;      //<! "SceKernelExceptionEntry", ASLR vbase, psize 0x1000, extraHigh 0x1000
   KBPMappingInfo l2pt000;        //<! "SceKernelL2PageTable000", ASLR vbase, psize 0x1000, extraHigh 0x1000
   KBPMappingInfo l2vector;       //<! "SceKernelL2Vector", ASLR vbase, psize 0x4000, extraHigh 0x4000
   KBPMappingInfo sysroot;        //<! "SceSysroot", ASLR vbase, psize 0x4000
   KBPMappingInfo fh32b;          //<! "SceKernelFixedHeap32B", ASLR vbase, psize 0x10000
   KBPMappingInfo fh48b;          //<! "SceKernelFixedHeap48B", ASLR vbase, psize 0x10000
   KBPMappingInfo fh64b;          //<! "SceKernelFixedHeap64B", ASLR vbase, psize 0x10000
   KBPMappingInfo fhUIDEntry;     //<! "SceKernelFixedHeapUIDEntry", ASLR vbase, psize 0x10000
   KBPMappingInfo fhL2Object;     //<! "SceKernelFixedHeapForL2Object", ASLR vbase, psize 0x1000, extraHigh 0x1000
   KBPMappingInfo unk188;         //<! Unused? NOTE: ASLR vbase = randomize in 255 slots, MegaASLR vbase = randomize in 15 slots
   KBPMappingInfo phypage;        //<! "SceKernelPhyPageTable", MegaASLR vbase, psize 0x80000
   KBPMappingInfo phypageHigh;    //<! "SceKernelPhyPageTableHigh", MegaASLR vbase, psize 0x80000, pbase 0x77F00000
   KBPMappingInfo bootkernimg;    //<! "SceBootKernelImage", vbase=pbase=0x51000000, psize 0x1000000, extraHigh 0x1000000
   KBPMappingInfo hwreg;          //<! Unnamed. vbase=pbase=0xE0000000, psize 0x8000000
   SceCorelockContext *pCorelock;
   KBPBootStackInfo bootCpu[4];   //<! bootCpu[X] corresponds to CPUX's info. Stack is pivoted to this when calling main2.
   unsigned unk288;                      //<! Related to L2PageTable000? Always 0.
   void *pL2PageTable000;                //<! Base address of the L2PageTable000
   void *resetVector;                    //<! Goes into VBAR. = excpEntry.vbase + 0x100
   SceKernelPhyMemPart *phyMemPartKD;    //<! "SceKernelPhyMemPartKD"
   SceKernelPhyMemPart *phyMemPartTool;  //<! "SceKernelPhyMemPartTool". May be NULL
   PhyPage *pPageKernelReset;            //<! PhyPage object describing the pages backing SceKernelReset
   PhyPage *pPageL2PageTable000;         //<! PhyPage object describing the pages backing SceKernelL2PageTable000
   PhyPage *pPageSysroot;                //<! PhyPage object describing the pages backing SceSysroot
   PhyPage *pPageTTBR0;                  //<! PhyPage object describing the pages backing SceKernelTTBR0
   PhyPage *pPageTTBR1;                  //<! PhyPage object describing the pages backing SceKernelTTBR1
   PhyPage *pPageL2Vector;               //<! PhyPage object describing the pages backing SceKernelL2Vector
   PhyPage *pPagePhypage;                //<! PhyPage object describing the pages backing SceKernelPhyPageTable
   PhyPage *pPagePhypageHigh;            //<! PhyPage object describing the pages backing SceKernelPhyPageTableHigh
   PhyPage *pPageBootKernelImage;        //<! PhyPage object describing the pages backing SceBootKernelImage????
   PhyPage *pPageFixedHeap32B;           //<! PhyPage object describing the pages backing SceKernelFixedHeap32B
   PhyPage *pPageFixedHeap48B;           //<! PhyPage object describing the pages backing SceKernelFixedHeap48B
   PhyPage *pPageFixedHeap64B;           //<! PhyPage object describing the pages backing SceKernelFixedHeap64B
   PhyPage *pPageFixedHeapForL2Object;   //<! PhyPage object describing the pages backing SceKernelFixedHeapForL2Object
   SceUIDFixedHeapObject *pFixedHeap32B;
   SceUIDFixedHeapObject *pFixedHeap48B;
   SceUIDFixedHeapObject *pFixedHeap64B;
   SceUIDFixedHeapObject *pFixedHeapForL2Object;
   PhyPage *pPageUIDHeap;                //<! PhyPage object describing the pages backing SceKernelFixedUIDHeap??
   L2PageTableObject *pL2PT000Object;    //<! L2PageTableObject for SceKernelL2PageTable000
   L2PageTableObject *pPhyPageTblL2PTO;  //<! L2PageTableObject for table used to map the PhyPageTable (located @ SceKernelL2PageTable000.pbase + 0x400)
   SceUIDPartitionObject *pPartitionKernel; //<! Object of "SceKernelRoot" partition
   SceUID uidPartitionKernel;               //<! UID of object above (0x10009)
   unsigned unk2F8[5];
   unsigned magic;                          //<! 0x7F407C30
};

typedef struct SceNskblModuleInfo { // size is 0xC on FWs 0.940-0.990
    char* filename;    // Raw SKPRX file name (e.g. "sysmem.skprx"). Modules are loaded either from os0:kd/ or host0:module/.
    SceUID moduleId;     // SCE_UID_INVALID_UID. It gets filled when loading.
    SceUInt32 loadFlags; // Passed as flags to sceKernelLoadModule.
} __attribute__((packed)) SceNskblModuleInfo;

typedef struct SceNskblModuleInfo2 { // size is 4 on FW 3.60
    const char* filename;
} __attribute__((packed)) SceNskblModuleInfo2;

typedef struct SceHardwareFlags { // size is 0x10 on FW 3.60
    uint32_t data[4];
} __attribute__((packed)) SceHardwareFlags;

/* Many pointers are NSKBL heap relationships */
typedef struct SceNskblSysrootInfo { // size is at least 0xC8 on FW 3.60
	SceUID unk_0x00; // maybe some PID. ex: 0x10089
	int unk_0x04;
	void *unk_0x08;
	void *unk_0x0C;
	void *unk_0x10;
	void *unk_0x14;
	void *unk_0x18;
	void *unk_0x1C;
	void *unk_0x20;
	void *unk_0x24;
	void *unk_0x28;
	void *unk_0x2C;
	SceUID unk_0x30; // maybe some PID. ex: 0x1000B
	const void *unk_0x34; // mapped paddr in vaddr
	const void *unk_0x38; // mapped paddr in vaddr
	void *unk_0x3C;
	int unk_0x40; // ex: 0x80000000
	int unk_0x44; // ex: 0x20000000
	void *unk_0x48;
	void *unk_0x4C;
	void *unk_0x50;
	void *unk_0x54;
	void *unk_0x58;
	void *unk_0x5C;
	void *unk_0x60;
	void *unk_0x64;
	void *unk_0x68;
	void *unk_0x6C;
	void *unk_0x70;
	void *unk_0x74;
	void *unk_0x78;
	void *unk_0x7C;
	void *unk_0x80;
	void *unk_0x84;
	void *unk_0x88;
	void *unk_0x8C;
	void *unk_0x90;
	void *unk_0x94;
	void *unk_0x98;
	SceUInt32 magic; // 0x 19442EA8
	int unk_0xA0; // ex: 0x1000
	int unk_0xA4; // ex: 0x1000
	int unk_0xA8; // ex: 0x40000
	int unk_0xAC; // ex: 0x200000
	int unk_0xB0; // ex: 7
	int unk_0xB4;
	int unk_0xB8; // ex: 0x80
	sysroot_t *pSysroot;
	void *unk_0xC0;
	void *unk_0xC4;
	// more...?
} SceNskblSysrootInfo; // 3.60

SceNskblSysrootInfo *nskbl_sysroot_info = (SceNskblSysrootInfo *)(0x51000000 + 0x138980); // 3.60

Libraries

Known NIDs

Version Name World Visibility NID
0.940-3.65 SceKblForKernel Non-secure Kernel 0xD0FC2991

SceKblForKernel

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

sceSDrfpStartForKernel

Version NID
0.940-0.990 0x230456F3
3.60 not present

sceSDbgSdioStartForKernel

Version NID
0.940-0.990 0x29A8524D
3.60 not present

Requires DIPSW 193.

SceInt32 sceSDbgSdioStartForKernel(void);

sceSDfMgrStartForKernel

Version NID
0.940-0.990 0xAA8005E4
3.60 not present

sceKblPutcharForKernel

Version NID
0.940-3.60 0x08E9FAEB

This is a guessed name.

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

int sceKblPutcharForKernel(void *args, char c);

sceKernelPrintfForKernel

Version NID
0.940-3.60 0x13A5ABEF

In FW 3.60 this function is at 0x510137A9.

int sceKernelPrintfForKernel(const char *fmt, ...);

sceKernelPrintfLevelForKernel

Version NID
0.940 Not present
0.990-3.60 0x752E7EEC

In FW 3.60 this function is at 0x51013841.

int sceKernelPrintfLevelForKernel(int level, const char *fmt, ...);

sceKernelGetDebugLevelForKernel

Version NID
0.940-3.60 0xC011935A

Temp name was sceKblGetMinimumLogLevelForKernel.

In FW 3.60 this function is at 0x51013921.

int sceKernelGetDebugLevelForKernel(void);

sceKernelGetDebugPutcharForKernel

Version NID
0.940-3.60 0x9B868276

In FW 3.60 this function is at 0x51013765.

void *sceKernelGetDebugPutcharForKernel(void);

sceKernelSysrootProcessmgrStart2ForKernel

Version NID
0.940-3.60 0x161D6FCC

In FW 3.60 this function is at 0x510123DD.

int sceKernelSysrootProcessmgrStart2ForKernel(void);

sceKernelSysrootThreadMgrStartAfterProcessForKernel

Version NID
0.940-3.60 0x1DB28F02

In FW 3.60 this function is at 0x510123A1.

int sceKernelSysrootThreadMgrStartAfterProcessForKernel(void);

sceKernelSysrootIofilemgrStartForKernel

Version NID
0.940-3.60 0xC7B77991

In FW 3.60 this function is at 0x5101297D.

int sceKernelSysrootIofilemgrStartForKernel(void);

sceKernelSysrootCorelockUnlockForKernel

Version NID
0.940-3.60 0x314AA770

In FW 3.60 this function is at 0x510124FD.

void sceKernelSysrootCorelockUnlockForKernel(void);

sceKernelSysrootCorelockLockForKernel

Version NID
0.940-3.60 0x807B4437

In FW 3.60 this function is at 0x510124E5.

void sceKernelSysrootCorelockLockForKernel(SceUInt32 core);

sceKblCpuSuspendIntrForKernel_old

Version NID
0.940-0.990 0x99B2F981
3.60 not present

This is a guessed name.

On FW 0.940, it calls a routine that simply executes cpsid i 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

Version NID
0.940-0.990 Not present
3.60 0xDDB3A1A8

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

In FW 3.60 this function is at 0x51003554.

void sceKblCpuSuspendIntrForKernel_new(void);

sceSblAimgrIsCEXForKernel

Version NID
0.940-3.60 0x8A416887

In FW 3.60 this function is at 0x510171B5.

int sceSblAimgrIsCEXForKernel(void);

sceSblAimgrIsDiagForKernel

Version NID
0.940-3.60 0xC3DDDE15

In FW 3.60 this function is at 0x51017175.

int sceSblAimgrIsDiagForKernel(void);

sceSblAimgrIsDEXForKernel

Version NID
0.940-0.990 Not present
3.60 0x5945F065

In FW 3.60 this function is at 0x51017159.

int sceSblAimgrIsDEXForKernel(void);

sceSblAimgrIsToolForKernel

Version NID
0.990 not present
3.60 0xB6C9ACF1

In FW 3.60 this function is at 0x51017139.

int sceSblAimgrIsToolForKernel(void);

sceSblAimgrIsTestForKernel

Version NID
0.990 not present
3.60 0x943E7537

In FW 3.60 this function is at 0x5101711D.

int sceSblAimgrIsTestForKernel(void);

sceSblAimgrIsVITAForKernel

Version NID
0.990 not present
3.60 0x838466E9

In FW 3.60 this function is at 0x51017299.

int sceSblAimgrIsVITAForKernel(void);

sceSblAimgrIsDolceForKernel

Version NID
0.990 not present
3.60 0xA7BD4417

In FW 3.60 this function is at 0x510172A1.

int sceSblAimgrIsDolceForKernel(void);

sceSblAimgrIsGenuineDolceForKernel

Version NID
0.990 not present
3.60 0xB6D00D6D

In FW 3.60 this function is at 0x510171E5.

int sceSblAimgrIsGenuineDolceForKernel(void);

LoadModulesForKernel

Version NID
0.940-0.990 0xFAE33FDD
3.60 not present

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

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

SceInt32 LoadModules(SceNskblModuleInfo* module_list);

sceKernelBootLoadModulesForKernel

Version NID
0.990 not present
3.60 0x6D7A1F18

Temp name was sceKblLoadModulesForKernel.

In FW 3.60 this function is at 0x51001551.

int sceKernelBootLoadModulesForKernel(const SceNskblModuleInfo2 *pList, SceUID *pUidList, SceUInt32 count, SceBool use_tool_extended_memory);

BootModulesForKernel

Version NID
0.940-0.990 0xA7D60F71
3.60 not present

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

// If run_boot_entry is SCE_TRUE, module_start is executed on core 0 then
// module_bootstart is executed on all cores. Otherwise, module_start is executed on all cores and
// module_bootstart is not executed.
SceInt32 BootModules(SceNskblModuleInfo* module_list, SceSize args, const void* argp, SceBool run_boot_entry);

sceKernelBootBootModulesForKernel

Version NID
0.990 not present
3.60 0x9A92436E

Temp name was sceKblBootModulesForKernel.

In FW 3.60 this function is at 0x51001571.

int sceKernelBootBootModulesForKernel(SceUID *pUidList, SceUInt32 count, SceSize args, void *argp);

sceAuthMgrExitForKernel

Version NID
0.990 not present
3.60 0x79241ACF

Temp name was sceKblAuthMgrCloseForKernel.

In FW 3.60 this function is at 0x51001345.

int sceAuthMgrExitForKernel(void);

sceKblSetNonSyncModuleStartForKernel

Version NID
0.990 not present
3.60 0x9F4F3F98

This is a guessed name.

In FW 3.60 this function is at 0x51001561.

int sceKblSetNonSyncModuleStartForKernel(void);

sceKernelCpuIdForKernel

Version NID
0.940-3.60 0xB506A10E

In FW 3.60 this function is at 0x510147C9.

int sceKernelCpuIdForKernel(void);

sceKernelCheckDipswForKernel

Version NID
0.990-3.60 0xC8F4DE71

In FW 3.60 this function is at 0x51015851.

int sceKernelCheckDipswForKernel(int bit);

sceSblQafManagerIsAllowKernelDebugForKernel

Version NID
0.940-3.60 0xCE94F329

In FW 3.60 this function is at 0x51016FD1.

int sceSblQafManagerIsAllowKernelDebugForKernel(void);

sceKblGetHardwareFlagsForKernel

Version NID
0.990 not present
3.60 0xD3A516D5

This is a guessed name.

In FW 3.60 this function is at 0x510128AD.

int sceKblGetHardwareFlagsForKernel(SceHardwareFlags *pFlags);

sceSdStandaloneInitForKernel

Version NID
0.940-3.60 0xF7AF8690

Temp name was sceKblInitDeviceForKernel.

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

In FW 3.60 this function is at 0x5100124D.

int sceSdStandaloneInitForKernel(void);

sceSdStandaloneExitForKernel

Version NID
0.940-3.60 0x261F2747

Temp name was sceKblFreeFileSystemCtxForKernel.

Cleanup state created by sceSdStandaloneInitForKernel.

In FW 3.60 this function is at 0x51001321.

int sceSdStandaloneExitForKernel(void);