NSKBL: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
 
(113 intermediate revisions by 3 users not shown)
Line 1: Line 1:
NSBL is a program that performs emmc setup, base kernel module loading, etc. when vita 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 non-secure kernel bootloader contains an embedded and likely stripped version of [[SceSysmem]], [[SceKernelModulemgr]], [[SceSblSmschedProxy]], [[SceExcpmgr]], [[SceKernelIntrMgr]], [[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.


=== How to debug NSBL ===
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!


NSBL reads from sd0: instead, if a read error(?) Occurs in os0: during vita startup.
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).


but, in order to generate os0: read errors, os0: must be damaged in some way, so there must be a way to physically recover vita.
== 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 description is based on System Software version 3.50 and later. Older versions may behave differently. See also [[NSKBL Subroutines]].
 
=== Reset ===
 
The NSKBL 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 1 MiB of the address space (255 page-sized slots - first slot is reserved for NULL page), while larger allocations are randomized in the first 16 MiB (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 memory range is mapped as RWX and seems to be the only RWX mapping in the Non-Secure kernel.
 
After all these mappings are complete, the MMU is turned on along with 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 by this function.
 
After the Sysroot is initialized, <code>sceKernelSysmemStart</code> is called, which initializes the embedded [[SceSysmem]] module. It is at this stage that all the Sysmem object classes are created. Sysroot status is set to 2 then 3 by 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, 16-KiB-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 it used was located in NSKBL <code>.bss</code> section.
 
=== <code>main2</code> ===
 
The <code>main2</code> function 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 the embedded modules are started, Sysroot status is set to 0x10 and the final NSKBL function is called.
 
=== Final function ===
 
The final 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 [[ScePsp2BootConfig|<code>os0:kd/psp2bootconfig.skprx</code>]], links the [[NSKBL#SceKblForKernel|SceKblForKernel library]] to the module, and starts it with <code>SceKernelBootParam</code> address as <code>argp</code>.
 
NSKBL has now handed over control and simply remains resident until it is unmapped by [[SceSysStateMgr]]. See also [[SceKernelModulemgr#sceKernelFinalizeKblForKernel]].
 
== Types ==
 
<source lang="C">
 
typedef struct KBPMemoryRegion {
    SceUIntPtr pbase;
    SceSize psize;
} KBPMemoryRegion;
 
typedef struct KBPMappingInfo {
    char *name;        //<! Name of the mapping
    SceUIntPtr pbase;    //<! Base physical address of the mapping
    SceUIntPtr vbase;    //<! Base virtual address of the mapping
    SceSize psize;    //<! Size of the physical range of the mapping??
    SceSize vsize;    //<! Size of the virtual range of the mapping?? - Usually equal to psize, but may be bigger.
    SceUInt32 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];
    SceUIntPtr ttbcr;
    SceUInt32 dacr;
    SceUInt32 asid;
    SceSize 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
// 0x51030100 on NSKBL
typedef struct SceKernelBootParam { // Size is 0x310-bytes in 3.60-3.65 and 4.00. Layout appears to be identical.
  SSceSize size;                //<! Size of this structure
  SceBool secure;              //<! Is secure state? Always 0 in NSKBL
  SceUInt32 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];
  SceUInt32 SoCInfo;              //<! = *(u32*)PERVASIVE_MISC
  SceUInt32 pmisc_unk4;          //<! = *(u32*)(PERVASIVE_MISC + 4)
  SceUInt32 KermitRevision;      //<! = SoCInfo & 0x1FFFF
  SceUInt32 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.
  SceSysroot *pSysroot;                //<! Pointer to Sysroot structure
  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??
  SceUIDEntryHeapObject *pUIDHeap;      //<! Pointer to SceKernelFixedUIDHeap object
  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)
  SceUInt32 unk2F8[2];
  void *data_0x300;
  void *pPutcharHandler;
  SceUInt32 minimum_log_level;
  SceUInt32 magic;                          //<! 0x7F407C30
} SceKernelBootParam;
 
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
</source>


== Libraries ==
== Libraries ==
Line 19: Line 255:
! Version !! Name !! World !! Visibility !! NID
! Version !! Name !! World !! Visibility !! NID
|-
|-
| 3.60 || [[NSBL#SceKblForKernel|SceKblForKernel]] || Non-secure || Kernel || 0xD0FC2991
| 0.940-3.65 || [[NSKBL#SceKblForKernel|SceKblForKernel]] || Non-secure || Kernel || 0xD0FC2991
|}
|}


== SceKblForKernel ==
== SceKblForKernel ==


=== SceKblForKernel_0x08E9FAEB ===
NOTE: this library is linked directly to <code>psp2bootconfig</code> instead of being registered, and can thus only be imported by this module.
 
=== sceSDrfpStartForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x08E9FAEB
| 0.940-0.990 || 0x230456F3
|-
| 3.60 || not present
|}
|}


In 3.60 this function is at 0x510172BD
=== sceSDbgSdioStartForKernel ===
 
=== SceKblForKernel_0x13A5ABEF ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x13A5ABEF
| 0.940-0.990 || 0x29A8524D
|-
| 3.60 || not present
|}
|}


In 3.60 this function is at 0x510137A9
Requires DIPSW 193.


=== SceKblForKernel_0x161D6FCC ===
<source lang="C">SceInt32 sceSDbgSdioStartForKernel(void);</source>
 
=== sceSDfMgrStartForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x161D6FCC
| 0.940-0.990 || 0xAA8005E4
|-
| 3.60 || not present
|}
|}


In 3.60 this function is at 0x510123DD
=== sceKblPutcharForKernel ===
 
=== SceKblForKernel_0x1DB28F02 ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x1DB28F02
| 0.940-3.60 || 0x08E9FAEB
|}
|}


In 3.60 this function is at 0x510123A1
This is a guessed name.
 
This function is at 0x510172BD in FW 3.60 and at 0x51003BE0 in FW 0.940.040.


=== SceKblForKernel_0x261F2747 ===
<source lang="C">int sceKblPutcharForKernel(void *args, char c);</source>
 
=== sceKernelPrintfForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x261F2747
| 0.940-3.60 || 0x13A5ABEF
|}
|}


Related to initialization?
In FW 3.60 this function is at 0x510137A9.


In 3.60 this function is at 0x51001321
<source lang="C">int sceKernelPrintfForKernel(const char *fmt, ...);</source>


<source lang="C">
=== sceKernelPrintfLevelForKernel ===
{| class="wikitable"
|-
! Version !! NID
|-
| 0.940 || Not present
|-
| 0.990-3.60 || 0x752E7EEC
|}


int SceKblForKernel_0x261F2747(void);
In FW 3.60 this function is at 0x51013841.


</source>
<source lang="C">int sceKernelPrintfLevelForKernel(int level, const char *fmt, ...);</source>


=== SceKblForKernel_0x314AA770 ===
=== sceKernelGetDebugLevelForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x314AA770
| 0.940-3.60 || 0xC011935A
|}
|}


In 3.60 this function is at 0x510124FD
Temp name was sceKblGetMinimumLogLevelForKernel.


=== sceKblIsDEXForKernel ===
In FW 3.60 this function is at 0x51013921.
 
<source lang="C">int sceKernelGetDebugLevelForKernel(void);</source>
 
=== sceKernelGetDebugPutcharForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x5945F065
| 0.940-3.60 || 0x9B868276
|}
|}


In 3.60 this function is at 0x51017159
In FW 3.60 this function is at 0x51013765.


=== sceKblLoadModuleForKernel ===
<source lang="C">void *sceKernelGetDebugPutcharForKernel(void);</source>
 
=== sceKernelSysrootProcessmgrStart2ForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x6D7A1F18
| 0.940-3.60 || 0x161D6FCC
|}
|}


In 3.60 this function is at 0x51001551
In FW 3.60 this function is at 0x510123DD.


<source lang="C">
<source lang="C">int sceKernelSysrootProcessmgrStart2ForKernel(void);</source>


typedef struct SceModuleLoadList {
=== sceKernelSysrootThreadMgrStartAfterProcessForKernel ===
  const char *filename;
{| class="wikitable"
} __attribute__((packed)) SceModuleLoadList;
|-
! Version !! NID
|-
| 0.940-3.60 || 0x1DB28F02
|}


int sceKblLoadModuleForKernel(const SceModuleLoadList *list, SceUID *uid, int count, int some_flag);
In FW 3.60 this function is at 0x510123A1.


</source>
<source lang="C">int sceKernelSysrootThreadMgrStartAfterProcessForKernel(void);</source>


=== SceKblForKernel_0x752E7EEC ===
=== sceKernelSysrootIofilemgrStartForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x752E7EEC
| 0.940-3.60 || 0xC7B77991
|}
|}


In 3.60 this function is at 0x51013841
In FW 3.60 this function is at 0x5101297D.


=== SceKblForKernel_0x79241ACF ===
<source lang="C">int sceKernelSysrootIofilemgrStartForKernel(void);</source>
 
=== sceKernelSysrootCorelockUnlockForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x79241ACF
| 0.940-3.60 || 0x314AA770
|}
|}


Related to initialization?
In FW 3.60 this function is at 0x510124FD.
 
In 3.60 this function is at 0x51001345
 
<source lang="C">


int SceKblForKernel_0x79241ACF(void);
<source lang="C">void sceKernelSysrootCorelockUnlockForKernel(void);</source>


</source>
=== sceKernelSysrootCorelockLockForKernel ===
 
=== SceKblForKernel_0x807B4437 ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x807B4437
| 0.940-3.60 || 0x807B4437
|}
|}


In 3.60 this function is at 0x510124E5
In FW 3.60 this function is at 0x510124E5.


=== sceKblIsVITAForKernel ===
<source lang="C">void sceKernelSysrootCorelockLockForKernel(SceUInt32 core);</source>
 
=== sceKblCpuSuspendIntrForKernel_old ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x838466E9
| 0.940-0.990 || 0x99B2F981
|-
| 3.60 || not present
|}
|}


In 3.60 this function is at 0x51017299
This is a guessed name.


<source lang="C">
On FW 0.940, it calls a routine that simply executes <code>cpsid i</code> then returns 0.


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


</source>
Disables IRQ interrupts by setting the I-bit in the CPSR.


=== sceKblIsCEXForKernel ===
=== sceKblCpuSuspendIntrForKernel_new ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x8A416887
| 0.940-0.990 || Not present
|-
| 3.60 || 0xDDB3A1A8
|}
|}


In 3.60 this function is at 0x510171B5
This is a guessed name. Temp name was sceKblCpuSwitchInterruptsForKernel, sceKblCpuDisableIrqInterruptsForKernel.
 
<source lang="C">


int sceKblIsCEXForKernel(void);
In FW 3.60 this function is at 0x51003554.


</source>
<source lang="C">void sceKblCpuSuspendIntrForKernel_new(void);</source>


=== sceKblIsTestForKernel ===
=== sceSblAimgrIsCEXForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x943E7537
| 0.940-3.60 || 0x8A416887
|}
|}


In 3.60 this function is at 0x5101711D
In FW 3.60 this function is at 0x510171B5.


<source lang="C">
<source lang="C">int sceSblAimgrIsCEXForKernel(void);</source>


int sceKblIsTestForKernel(void);
=== sceSblAimgrIsDiagForKernel ===
 
</source>
 
=== sceKblStartModuleForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x9A92436E
| 0.940-3.60 || 0xC3DDDE15
|}
|}


In 3.60 this function is at 0x51001571
In FW 3.60 this function is at 0x51017175.
 
<source lang="C">
 
int sceKblStartModuleForKernel(SceUID *uid_list, int count, SceSize args, void *argp);


</source>
<source lang="C">int sceSblAimgrIsDiagForKernel(void);</source>


=== SceKblForKernel_0x9B868276 ===
=== sceSblAimgrIsDEXForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x9B868276
| 0.940-0.990 || Not present
|-
| 3.60 || 0x5945F065
|}
|}


return value is ptr?
In FW 3.60 this function is at 0x51017159.


In 3.60 this function is at 0x51013765
<source lang="C">int sceSblAimgrIsDEXForKernel(void);</source>


<source lang="C">
=== sceSblAimgrIsToolForKernel ===
{| class="wikitable"
|-
! Version !! NID
|-
| 0.990 || not present
|-
| 3.60 || 0xB6C9ACF1
|}


int SceKblForKernel_9B868276(void);
In FW 3.60 this function is at 0x51017139.


</source>
<source lang="C">int sceSblAimgrIsToolForKernel(void);</source>


=== SceKblForKernel_0x9F4F3F98 (set some state?) ===
=== sceSblAimgrIsTestForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0x9F4F3F98
| 0.990 || not present
|-
| 3.60 || 0x943E7537
|}
|}


set some state?
In FW 3.60 this function is at 0x5101711D.


In 3.60 this function is at 0x51001561
<source lang="C">int sceSblAimgrIsTestForKernel(void);</source>


<source lang="C">
=== sceSblAimgrIsVITAForKernel ===
{| class="wikitable"
|-
! Version !! NID
|-
| 0.990 || not present
|-
| 3.60 || 0x838466E9
|}


int SceKblForKernel_9F4F3F98(void);
In FW 3.60 this function is at 0x51017299.


</source>
<source lang="C">int sceSblAimgrIsVITAForKernel(void);</source>


=== sceKblIsDolceForKernel ===
=== sceSblAimgrIsDolceForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
| 0.990 || not present
|-
|-
| 3.60 || 0xA7BD4417
| 3.60 || 0xA7BD4417
|}
|}


In 3.60 this function is at 0x510172A1
In FW 3.60 this function is at 0x510172A1.


<source lang="C">
<source lang="C">int sceSblAimgrIsDolceForKernel(void);</source>
 
=== sceSblAimgrIsGenuineDolceForKernel ===
{| class="wikitable"
|-
! Version !! NID
|-
| 0.990 || not present
|-
| 3.60 || 0xB6D00D6D
|}


int sceKblIsDolceForKernel(void);
In FW 3.60 this function is at 0x510171E5.


</source>
<source lang="C">int sceSblAimgrIsGenuineDolceForKernel(void);</source>


=== sceKblGetCpuIdForKernel ===
=== LoadModulesForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xB506A10E
| 0.940-0.990 || 0xFAE33FDD
|-
| 3.60 || not present
|}
|}


In 3.60 this function is at 0x510147C9
Load all modules from the provided list. The list end is marked by an entry with <code>moduleName = NULL</code>.


<source lang="C">
Module GUIDs are populated into the list, so it must be writeable.


int sceKblGetCpuIdForKernel(void);
<source lang="C">SceInt32 LoadModules(SceNskblModuleInfo* module_list);</source>


</source>
=== sceKernelBootLoadModulesForKernel ===
 
=== sceKblIsToolForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xB6C9ACF1
| 0.990 || not present
|-
| 3.60 || 0x6D7A1F18
|}
|}


In 3.60 this function is at 0x51017139
Temp name was sceKblLoadModulesForKernel.
 
<source lang="C">


int sceKblIsToolForKernel(void);
In FW 3.60 this function is at 0x51001551.


</source>
<source lang="C">int sceKernelBootLoadModulesForKernel(const SceNskblModuleInfo2 *pList, SceUID *pUidList, SceUInt32 count, SceBool use_tool_extended_memory);</source>


=== sceKblIsGenuineDolceForKernel ===
=== BootModulesForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xB6D00D6D
| 0.940-0.990 || 0xA7D60F71
|-
| 3.60 || not present
|}
|}


In 3.60 this function is at 0x510171E5
Runs the entrypoint of all modules in provided list. The list end is marked by an entry with <code>moduleId = SCE_UID_INVALID_UID</code>.


<source lang="C">
<source lang="C">
 
// If run_boot_entry is SCE_TRUE, module_start is executed on core 0 then
int sceKblIsGenuineDolceForKernel(void);
// 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);
</source>
</source>


=== SceKblForKernel_0xC011935A ===
=== sceKernelBootBootModulesForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xC011935A
| 0.990 || not present
|-
| 3.60 || 0x9A92436E
|}
|}


get some info?
Temp name was sceKblBootModulesForKernel.
 
In 3.60 this function is at 0x51013921


<source lang="C">
In FW 3.60 this function is at 0x51001571.


int SceKblForKernel_C011935A(void);
<source lang="C">int sceKernelBootBootModulesForKernel(SceUID *pUidList, SceUInt32 count, SceSize args, void *argp);</source>


</source>
=== sceAuthMgrExitForKernel ===
 
=== sceKblIsCEXJpFatForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xC3DDDE15
| 0.990 || not present
|-
| 3.60 || 0x79241ACF
|}
|}


In 3.60 this function is at 0x51017175
Temp name was sceKblAuthMgrCloseForKernel.


<source lang="C">
In FW 3.60 this function is at 0x51001345.


int sceKblIsCEXJpFatForKernel(void);
<source lang="C">int sceAuthMgrExitForKernel(void);</source>


</source>
=== sceKblSetNonSyncModuleStartForKernel ===
 
=== SceKblForKernel_0xC7B77991 ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xC7B77991
| 0.990 || not present
|-
| 3.60 || 0x9F4F3F98
|}
|}


In 3.60 this function is at 0x5101297D
This is a guessed name.


=== sceKblCheckDipswForKernel ===
In FW 3.60 this function is at 0x51001561.
 
<source lang="C">int sceKblSetNonSyncModuleStartForKernel(void);</source>
 
=== sceKernelCpuIdForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xC8F4DE71
| 0.940-3.60 || 0xB506A10E
|}
|}


In 3.60 this function is at 0x51015851
In FW 3.60 this function is at 0x510147C9.


<source lang="C">
<source lang="C">int sceKernelCpuIdForKernel(void);</source>


int sceKblCheckDipswForKernel(int bit);
=== sceKernelCheckDipswForKernel ===
 
</source>
 
=== SceKblForKernel_0xCE94F329 ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xCE94F329
| 0.990-3.60 || 0xC8F4DE71
|}
|}


some qaf function
In FW 3.60 this function is at 0x51015851.


ret = *(uint8_t *)(sysroot + 0x2D) & 1;
<source lang="C">int sceKernelCheckDipswForKernel(int bit);</source>


In 3.60 this function is at 0x51016FD1
=== sceSblQafManagerIsAllowKernelDebugForKernel ===
{| class="wikitable"
|-
! Version !! NID
|-
| 0.940-3.60 || 0xCE94F329
|}


<source lang="C">
In FW 3.60 this function is at 0x51016FD1.


int SceKblForKernel_0xCE94F329(void);
<source lang="C">int sceSblQafManagerIsAllowKernelDebugForKernel(void);</source>
 
</source>


=== SceKblForKernel_0xD3A516D5 ===
=== sceKblGetHardwareFlagsForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
| 0.990 || not present
|-
|-
| 3.60 || 0xD3A516D5
| 3.60 || 0xD3A516D5
|}
|}


get some device info function
This is a guessed name.
 
In 3.60 this function is at 0x510128AD
 
<source lang="C">


typedef struct SceKblSomeSysrootInfo {
In FW 3.60 this function is at 0x510128AD.
uint32_t data[4];
} __attribute__((packed)) SceKblSomeSysrootInfo;


int SceKblForKernel_D3A516D5(SceKblSomeSysrootInfo *some_flag);
These hardware flags are maybe simply the [[KBL_Param#Hardware_Info_2]] like in [[SceSyscon#sceSysconGetHardwareInfo2ForDriver]].


</source>
<source lang="C">int sceKblGetHardwareFlagsForKernel(SceHardwareFlags *pFlags);</source>


=== sceKblCpuSwitchInterruptsForKernel ===
=== sceSdStandaloneInitForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xDDB3A1A8
| 0.940-3.60 || 0xF7AF8690
|}
|}


In 3.60 this function is at 0x51003554
Temp name was sceKblInitDeviceForKernel.


<source lang="C">
Some device init function. On FW 0.940 it initializes and mounts <code>os0:</code> (eMMC) and <code>sd0:</code> (GCSD).


void sceKblCpuSwitchInterruptsForKernel(void);
In FW 3.60 this function is at 0x5100124D.


</source>
<source lang="C">int sceSdStandaloneInitForKernel(void);</source>


=== SceKblForKernel_0xF7AF8690 ===
=== sceSdStandaloneExitForKernel ===
{| class="wikitable"
{| class="wikitable"
|-
|-
! Version !! NID
! Version !! NID
|-
|-
| 3.60 || 0xF7AF8690
| 0.940-3.60 || 0x261F2747
|}
|}


In 3.60 this function is at 0x5100124D
Temp name was sceKblFreeFileSystemCtxForKernel.
 
Cleanup state created by [[NSKBL#sceSdStandaloneInitForKernel|sceSdStandaloneInitForKernel]].
 
In FW 3.60 this function is at 0x51001321.
 
<source lang="C">int sceSdStandaloneExitForKernel(void);</source>


[[Category:Modules]]
[[Category:ARM]]
[[Category:Kernel]]
[[Category:Kernel]]
[[Category:Library]]

Latest revision as of 17:42, 30 March 2024

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 description is based on System Software version 3.50 and later. Older versions may behave differently. See also NSKBL Subroutines.

Reset

The NSKBL 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 1 MiB of the address space (255 page-sized slots - first slot is reserved for NULL page), while larger allocations are randomized in the first 16 MiB (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 memory range is mapped as RWX and seems to be the only RWX mapping in the Non-Secure kernel.

After all these mappings are complete, the MMU is turned on along with 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 by this function.

After the Sysroot is initialized, sceKernelSysmemStart is called, which initializes the embedded SceSysmem module. It is at this stage that all the Sysmem object classes are created. Sysroot status is set to 2 then 3 by 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, 16-KiB-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 it used was located in NSKBL .bss section.

main2

The main2 function 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 the embedded modules are started, Sysroot status is set to 0x10 and the final NSKBL function is called.

Final function

The final 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 os0:kd/psp2bootconfig.skprx, links the SceKblForKernel library to the module, and starts it with SceKernelBootParam address as argp.

NSKBL has now handed over control and simply remains resident until it is unmapped by SceSysStateMgr. See also SceKernelModulemgr#sceKernelFinalizeKblForKernel.

Types


typedef struct KBPMemoryRegion {
    SceUIntPtr pbase;
    SceSize psize;
} KBPMemoryRegion;

typedef struct KBPMappingInfo {
    char *name;         //<! Name of the mapping
    SceUIntPtr pbase;     //<! Base physical address of the mapping
    SceUIntPtr vbase;     //<! Base virtual address of the mapping
    SceSize psize;     //<! Size of the physical range of the mapping??
    SceSize vsize;     //<! Size of the virtual range of the mapping?? - Usually equal to psize, but may be bigger.
    SceUInt32 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];
    SceUIntPtr ttbcr;
    SceUInt32 dacr;
    SceUInt32 asid;
    SceSize 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
// 0x51030100 on NSKBL
typedef struct SceKernelBootParam { // Size is 0x310-bytes in 3.60-3.65 and 4.00. Layout appears to be identical.
   SSceSize size;                 //<! Size of this structure
   SceBool secure;               //<! Is secure state? Always 0 in NSKBL
   SceUInt32 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];
   SceUInt32 SoCInfo;              //<! = *(u32*)PERVASIVE_MISC
   SceUInt32 pmisc_unk4;           //<! = *(u32*)(PERVASIVE_MISC + 4)
   SceUInt32 KermitRevision;       //<! = SoCInfo & 0x1FFFF
   SceUInt32 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.
   SceSysroot *pSysroot;                 //<! Pointer to Sysroot structure
   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??
   SceUIDEntryHeapObject *pUIDHeap;      //<! Pointer to SceKernelFixedUIDHeap object 
   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)
   SceUInt32 unk2F8[2];
   void *data_0x300;
   void *pPutcharHandler;
   SceUInt32 minimum_log_level;
   SceUInt32 magic;                          //<! 0x7F407C30
} SceKernelBootParam;

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.

These hardware flags are maybe simply the KBL_Param#Hardware_Info_2 like in SceSyscon#sceSysconGetHardwareInfo2ForDriver.

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