SceSysmem is a kernel module that acts as the heart of the kernel. It exports multiple libraries for different functionalities (one of the few modules that do so). SceSysmem is the first module that is loaded in the kernel load sequence and its libraries are imported by almost all other modules. See Memory for more details on the memory subsystem.
Module
This module exists in both non-secure and secure world. The non-secure world SELF can be found in os0:kd/sysmem.skprx
. It also can be found in the Boot Image.
Known NIDs
Version |
Name |
World |
Privilege |
NID
|
1.69 |
SceSysmem |
Non-secure |
Kernel |
0xB93950C6
|
1.69 |
SceSysmem |
Secure |
Kernel |
0x502BE0E5
|
Libraries
This module only exports kernel libraries.
Known NIDs
Memory Block Type
The type
parameter indicates what kind of memory to allocate. Here is a mapping of type
flags to ARM MMU flags. Higher bits are used for other options including where to allocate from. Not all flag values are valid, there is a table of valid types in the kernel. You cannot, for example, allocate RWX memory.
Mask |
Value |
Description
|
0x10000 |
0x10000 |
Global. nG bit NOT set
|
0xFF00 |
0x800 |
B bit set. Sharable device memory.
|
0xFF00 |
0x2000 |
TEX[2] and TEX[0] bit set. Outer cache Write-back, Write-Allocate. Inner cache non-cachable.
|
0xFF00 |
0x4000 |
TEX[2] and B bit set. Outer cache non-cachable. Inner cache Write-back, Write-Allocate
|
0xFF00 |
0x8000 |
TEX[0] bit set. S bit unset. Outer and inner non-cachable. Not sharable.
|
0xFF00 |
0xD000 |
TEX[0] bit set. C,B bits set. Outer and inner Write-back, Write-Allocate.
|
0xFF |
0x4 |
AP[2:0] = 5 , XN=1 . Privileged RO, User NA.
|
0xFF |
0x5 |
AP[2:0] = 5 . Privileged RX, User NA.
|
0xFF |
0x6 |
AP[2:0] = 1 , XN=1 . Privileged RW, User NA.
|
0xFF |
0x7 |
AP[2:0] = 1 . Privileged RWX, User NA. (Never used)
|
0xFF |
0x50 |
AP[2:0] = 7 . Privileged RX, User RX.
|
0xFF |
0x60 |
AP[2:0] = 3 , XN=1 . Privileged RW, User RW.
|
0xFF |
0x40 |
AP[2:0] = 7 , XN=1 . Privileged RO, User RO.
|
SceSysmemForKernel
sceKernelAllocMemBlockForKernel
Version
|
NID
|
1.69 (non-secure)
|
0xC94850C9
|
1.69 (secure)
|
0x402EB970
|
struct SceKernelAllocMemKernelBlockOpt
{
uint32_t size; // 0x34
uint32_t unk;
uint32_t attr;
uint32_t unk2;
uint32_t paddr;
uint32_t align;
uint32_t unk3[3];
uint32_t processid;
uint32_t unk4[3];
};
int sceKernelAllocMemBlockForKernel(const char *name, int32_t type, uint32_t vsize, struct SceKernelAllocMemKernelBlockOpt *pOpt);
The interface is the same as the user version of this call, however more types can be specified and more options are in the pOpt argument.
To allocate a kernel RW block of memory, specify type = 0x6020D006
.
To allocate a block of memory with a specific physical address, specify type = 0x20100206
, pOpt->attr = 2
, and pOpt->paddr = physical address
.
To allocate a block of memory that is kernel executable, specify type = 0x1020D005
.
To allocate a block of memory inside the CDRAM, specify type = 0x40404006
.
Unrestricted Write for Process
Unrestricted memcpy to the virtual address space for process pid
. Both dst
and src
must be in the address space of pid
but src
must also be accessible in the address space of the caller. This is normally used for resolving stubs in module loads.
Version
|
NID
|
1.69 (non-secure)
|
0x30931572
|
int unrestricted_memcpy_for_pid(int pid, void *dst, void *src, size_t len);
SceSysmemForDriver
sceKernelMemcpyKernelToUser
Version
|
NID
|
1.69 (non-secure)
|
0x6D88EF8A
|
int sceKernelMemcpyKernelToUser(uint32_t uaddr, const void *kaddr, uint32_t len);
sceKernelMemcpyUserToKernel
Version
|
NID
|
1.69 (non-secure)
|
0xBC996A7A
|
int sceKernelMemcpyUserToKernel(void *kaddr, uint32_t uaddr, uint32_t len);
sceKernelMemcpyUserToKernelForPid
Version
|
NID
|
3.60 (non-secure)
|
0x605275F8
|
int sceKernelMemcpyUserToKernelForPid(int pid, void *kaddr, uint32_t uaddr, uint32_t len);
Same as above, but copies from the specified process.
strncpyKernelToUser
Version
|
NID
|
1.69 (non-secure)
|
0x80BD6FEB
|
int strncpyKernelToUser(uint32_t uaddr, const void *kaddr, uint32_t maxlen);
strncpyUserToKernel
Version
|
NID
|
1.69 (non-secure)
|
0xDB3EC244
|
int strncpyUserToKernel(void *kaddr, uint32_t uaddr, uint32_t maxlen);
strnlenUserSrc
Version
|
NID
|
1.69 (non-secure)
|
0xB429D419
|
int strnlenUserSrc(uint32_t uaddr, uint32_t maxlen);
get_paddr
Version
|
NID
|
1.69 (non-secure)
|
0x8D160E65
|
1.69 (secure)
|
0x1DEADF6C
|
int get_paddr(void *vaddr, void **result);
This will write the physical address for a virtual address vaddr
to memory pointed to by result
. Returns <0 on error, values >=0 indicate success.
get paddr list
Version
|
NID
|
1.69 (non-secure)
|
0xE68BEEBD
|
struct addr_pair
{
uint32_t addr;
uint32_t length;
};
struct paddr_list_req
{
uint32_t size; // 0x14
uint32_t output_buffer_size;
uint32_t unk;
uint32_t ret_count;
struct addr_pair *output_buffer;
};
input.addr = vaddr;
input.length = length;
int get_paddr_list(struct addr_pair *input, struct paddr_list_req *req);
This function takes in two parameters: an array of length 2 specifying the virtual address and the size of the block of memory and a request information. The function will write into output_buffer
an array of addr_pair
that encompasses the block of memory specified in the input. req->ret_count
will contain the number of entries written. If output_buffer
is null, it will just write the count.
sceKernelGetMemBlockBaseForDriver
Version
|
NID
|
1.69 (non-secure)
|
0xA841EDDA
|
int sceKernelGetMemBlockBaseForDriver(int blkid, void **base);
sceKernelFindMemBlockByAddrForDriver
Version
|
NID
|
1.69 (non-secure)
|
0x8A1742F6
|
int sceKernelFindMemBlockByAddrForDriver(void *base, int);
Remap Block
Version
|
NID
|
1.69 (non-secure)
|
0xDFE2C8CB
|
int sysmem_remap(int blkid, int type);
This is used to remap RW memory as RX. To do this, first allocate a memory block of type 0x1020D006
. After you are done writing, call this with type
set to 0x1020D006
.
Create Heap Pool
Version
|
NID
|
1.69 (non-secure)
|
0x9328E0E8
|
typedef struct {
int size; // 28
int flags; // usually 0x1
int unk;
int unk;
int block_type;
int unk;
int unk;
} pool_arg_t;
int heap_pool_create(const char *name, int size, pool_arg_t *opt); // opt can be NULL
The heap pool is thread safe.
Destroy Heap Pool
Version
|
NID
|
1.69 (non-secure)
|
0xD6437637
|
int heap_pool_destroy(int pool_uid);
Alloc from Heap Pool
Version
|
NID
|
1.69 (non-secure)
|
0x7B4CB60A
|
void *heap_pool_malloc(int pool_uid);
Free from Heap Pool
Version
|
NID
|
1.69 (non-secure)
|
0x3EBCE343
|
int heap_pool_free(int pool_uid, void *ptr);
Map User to Kernel
Version
|
NID
|
1.69 (non-secure)
|
0x7D4F8B5F
|
Permission is either "1" for read only, no execute or "2"/"3" for read write, no execute. Type is either 0, 1, or 17 and affects the block type. 0 is default. This will allocate kernel memory starting at kernel_page. To get the same memory as the user pointer, add the kernel_offset. kernel_size is how much is allocated.
int map_user_to_kernel(int permission, int type, void *user_buf, int size, void **kernel_page, int *kernel_size, int *kernel_offset);
Switch TTB to PID
Changes the TTBR to point to the tables for a given PID.
Version
|
NID
|
1.69 (non-secure)
|
0x6F2ACDAE
|
3.60 (non-secure)
|
N/A
|
int switch_ttb(int pid);
Write to RO for PID
Version
|
NID
|
1.69 (non-secure)
|
0x571D2739
|
int write_to_ro(int pid, void *dst, const void *src, int size);
Write to RX for PID
Same as write to RO but does a cache flush.
Version
|
NID
|
1.69 (non-secure)
|
0x30931572
|
int write_to_rx(int pid, void *dst, const void *src, int size);
Find Int for PID
Looks for an integer in user space.
Version
|
NID
|
1.69 (non-secure)
|
0x8334454F
|
int find_int(int pid, void *haystack, int needle, int size);
strnlen for PID
Version
|
NID
|
1.69 (non-secure)
|
0x9929EB07
|
int user_strnlen(int pid, char *ptr, int size);
strncpy for PID
Version
|
NID
|
1.69 (non-secure)
|
0x75AAF178
|
int user_strncpy(int pid, char *dst, const char *kern_src, int size);
memcpyk2u unchecked for PID
Version
|
NID
|
1.69 (non-secure)
|
0xFED82F2D
|
int user_memcpyk2u(int pid, void *dst, const void *kern_src, int size);
memcpyk2u checked for PID
This will not crash on invalid user pointers, but instead return error.
Version
|
NID
|
1.69 (non-secure)
|
0x6B825479
|
int user_safe_memcpyk2u(int pid, void *dst, const void *kern_src, int size);
memcpyu2u for PID
Version
|
NID
|
1.69 (non-secure)
|
0x8E086C33
|
int user_memcpyu2u(int pid, void *dst, const void *src, int size);
SceSysmem
The SceSysmem library is responsible for both low-level and high-level memory management. There are functions for allocating raw blocks of memory (similar to Linux sbrk
) as well as functions for maintaining a heap-like structure (similar to malloc
) for kernel, however SceLibKernel implements a proper heap and that is used for user code.
sceKernelGetMemBlockInfoByRange
Version |
NID
|
1.69 |
0x6F3DB4
|
sceKernelSyncVMDomain
Version |
NID
|
1.69 |
0x19D2A81A
|
sceKernelRemapMemBlock
Version |
NID
|
1.69 |
0x3B29E0F5
|
sceKernelGetMemBlockInfoByAddr
Version |
NID
|
1.69 |
0x4010AD65
|
sceKernelMapMemBlock
Version |
NID
|
1.69 |
0x7B763A21
|
sceKernelGetSubbudgetInfo
Version |
NID
|
1.69 |
0x832B4A65
|
sceKernelGetFreeMemorySize
Version |
NID
|
1.69 |
0x87CC580B
|
sceKernelOpenMemBlock
Version |
NID
|
1.69 |
0x8EB8DFBB
|
sceKernelOpenVMDomain
Version |
NID
|
1.69 |
0x9CA3EB2B
|
sceKernelFindMemBlockByAddr
Version |
NID
|
1.69 |
0xA33B99D1
|
sceKernelFreeMemBlock
Version |
NID
|
1.69 |
0xA91E15EE
|
sceKernelCloseMemBlock
Version |
NID
|
1.69 |
0xB680E3A0
|
sceKernelGetMemBlockBase
Version |
NID
|
1.69 |
0xB8EF5818
|
sceKernelAllocMemBlock
Version |
NID
|
1.69 |
0xB9D5EBDE
|
sceKernelPartialMapMemBlock
Version |
NID
|
1.69 |
0xC0A59868
|
sceKernelPartialUnmapMemBlock
Version |
NID
|
1.69 |
0xCA99929B
|
sceKernelCloseVMDomain
Version |
NID
|
1.69 |
0xD6CA56CA
|
sceKernelAllocMemBlockForVM
Version |
NID
|
1.69 |
0xE2D7E137
|
sceKernelUnmapMemBlock
Version |
NID
|
1.69 |
0xEE30D976
|
SceDipsw
SceCpu
This library provides wrapper for much ARM CP15 co-processor access as well as low level support of spinlocks and other synchronization primitives.
SceSysclib
The C standard library for use in the kernel only. (User code have SceLibKernel, which confusingly is user-only code). Include standard string functions (no insecure variants like strcpy
).
strcmp
Version
|
NID
|
1.69 (non-secure)
|
0x0B33BC43
|
strncmp
Version
|
NID
|
1.69 (non-secure)
|
0x12cee649
|
strstr
Version
|
NID
|
1.69 (non-secure)
|
0x1304A69D
|
rshift
Version
|
NID
|
1.69 (non-secure)
|
0x1D89F6C0
|
memcpy
Version
|
NID
|
1.69 (non-secure)
|
0x40c88316
|
strchr
Version
|
NID
|
1.69 (non-secure)
|
0x38463759
|
memset2
Version
|
NID
|
1.69 (non-secure)
|
0x502B000D
|
memmove
On 1.69, this seems to be implemented incorrectly.
Version
|
NID
|
1.69 (non-secure)
|
0x6CC9C1A1
|
strrchr
Version
|
NID
|
1.69 (non-secure)
|
0x7F0E0835
|
strncat
Version
|
NID
|
1.69 (non-secure)
|
0xA1D1C32C
|
strtol
Version
|
NID
|
1.69 (non-secure)
|
0xAB77C5AA
|
snprintf
Version
|
NID
|
1.69 (non-secure)
|
0xAE7A8981
|
sceKernelStackCheckFail
Version
|
NID
|
1.69 (non-secure)
|
0xb997493d
|
strnlen
Version
|
NID
|
1.69 (non-secure)
|
0xCD4BD884
|
strlen
Version
|
NID
|
1.69 (non-secure)
|
0xCFC6A9AC
|
memcmp
Version
|
NID
|
1.69 (non-secure)
|
0xF939E83D
|
SceDipsw
sceKernelCheckDipsw
Version |
NID
|
1.69 |
0x1C783FB2
|
sceKernelClearDipsw
Version |
NID
|
1.69 |
0x800EDCC1
|
sceKernelSetDipsw
Version |
NID
|
1.69 |
0x817053D4
|
SceDipswForDriver
SceUartForKernel
SceCpu
sceKernelCpuId
Version |
NID
|
1.69 |
0x2704CFEE
|
SceCpuForKernel
Unrestricted Write for Kernel
Unrestricted memcpy by first setting the DACR
register to 0xFFFFFFFF
and then doing a memcpy.
Version
|
NID
|
1.69
|
0x8C683DEC
|
int unrestricted_memcpy_for_kernel(void *dst, void *src, size_t len);
SceCpuForDriver
SceCpuForDriver_BF82DEB2_lock
Version |
NID
|
1.60 |
0xBF82DEB2
|
int SceCpuForDriver_BF82DEB2_lock(int *addr);
SceCpuForDriver_D6ED0C46_unlock
Version |
NID
|
1.60 |
0xD6ED0C46
|
int SceCpuForDriver_D6ED0C46_unlock(int *addr);
These two functions implement a simple mutual exclusive access on a resource addr using LDREX/STREX.
SceCpuForDriver_D32ACE9E_lock_int
Version |
NID
|
3.35 |
0xD32ACE9E
|
int SceCpuForDriver_D32ACE9E_lock_int(int *addr);
SceCpuForDriver_7BB9D5DF_unlock_int
Version |
NID
|
3.35 |
0x7BB9D5DF
|
void SceCpuForDriver_7BB9D5DF_unlock_int(int *addr, int prev_state);
Same as the pair above, but while mutex is held, interrupts are disabled. Used like this:
int prev_state = SceCpuForDriver_D32ACE9E_lock_int(mutex);
// do work
SceCpuForDriver_7BB9D5DF_unlock_int(mutex, prev_state);
SceCpuForDriver_4C38CE4D_lock_int_2
Version |
NID
|
3.35 |
0x4C38CE4D
|
SceCpuForDriver_9EC91017_unlock_int_2
Version |
NID
|
3.35 |
0x9EC91017
|
Same as the pair above, but stores 0x80000000 as the addr value instead of LR.
SceCpuForDriver_821FC0EE_disable_irq
Version |
NID
|
1.60 |
0x821FC0EE
|
int SceCpuForDriver_821FC0EE_disable_irq(void);
Disables irq (but not fiq) and returns previous interrupt bit status (so either 0 or 0x80).
SceCpuForDriver_F5BAD43B_restore_irq
Version |
NID
|
1.60 |
0xF5BAD43B
|
void SceCpuForDriver_F5BAD43B_restore_irq(int previous_state);
Restores previous irq state, pass either 0 or 0x80.
SceSysclibForKernel
SceSysclibForDriver
__aeabi_uidiv
Version |
NID
|
3.35 |
0xA9FF1205
|
__aeabi_uidivmod
Version |
NID
|
3.35 |
0xA46CB7DE
|
memcpy
Version |
NID
|
1.60 |
0x40C88316
|
memset
Version |
NID
|
1.60 |
0x0AB9BF5C
|
strchr
Version |
NID
|
3.35 |
0x38463759
|
strncmp
Version |
NID
|
1.60 |
0x12CEE649
|
SceSysrootForKernel
SceKernelUtilsForDriver
Crypto utilities
AES Init
This sets up the AES engine. ctx
is a 960 byte buffer (int 1.69). blocksize
and keysize
is the security in bits. 128/196/256 are supported values.
Version |
NID
|
1.69 |
0xF12B6451
|
int aes_init(void *ctx, int blocksize, int keysize, const char *key);
AES Encrypt
Encrypt with AES. There are two functions that are the same on 1.69.
Version |
NID
|
1.69 |
0xC2A61770
|
1.69 |
0x302947B6
|
int aes_encrypt(void *ctx, const char *src, char *dst);
AES Decrypt
Decrypt with AES.
Version |
NID
|
1.69 |
0xD8678061
|
int aes_decrypt(void *ctx, const char *src, char *dst);
SceZlibForDriver
zlib compression library.
Firmware |
zlib version
|
1.60 |
1.2.5
|
inflate
Version |
NID
|
1.60 |
0xE4F34A68
|
deflate
Version |
NID
|
1.60 |
0xE859D60F
|
deflateReset
Version |
NID
|
1.60 |
0x68CFEA45
|
crc32
Version |
NID
|
1.60 |
0xE0CE06C0
|
adler32
Version |
NID
|
1.60 |
0x98619620
|
inflateSetDictionary
Version |
NID
|
1.60 |
0x7B16DBD6
|
SceKernelSuspendForDriver
Libraries can register callbacks for handling suspend/resume related events.
Register Callback
Version |
NID
|
1.69 |
0x04C05D10
|
typedef struct {
uint32_t size; // 24
uint32_t unk1;
uint32_t unk2;
uint32_t unk3;
uint32_t unk4;
uint32_t unk5;
} suspend_args_t;
typedef int (*suspend_callback_t)(int resume, int eventid, suspend_args_t *args, void *opt);
int suspend_register_callback(const char *name, suspend_callback_t *callback_func, void *opt);
Registers a function for handling suspend/resume. resume
is 0 if we are currently suspending and 1 if we are currently resuming. opt
is passed from the registration. Registration
adds an entry to a linked list and returns the block id for the new entry.
Unregister
Version |
NID
|
1.69 |
0xDD61D621
|
int suspend_unregister(int id);
Call with the id returned from suspend_register_callback
to remove the entry from the linked list and free the memory.
Make Callback
Version |
NID
|
1.69 |
0xD4622EA8
|
int suspend_make_callback(int resume, int eventid, suspend_args_t *args, int stop_on_error);
This will go through the linked list and call each callback. If stop_on_error
is set, then the first callback that returns a negative value will stop the call chain and return the block id of the callback that broke the chain. Otherwise, this function will invoke each callback and return zero.
Reset auto-suspend timer
Version |
NID
|
3.61 |
0xE0489831
|
int reset_autosuspend_timer(int unk);
SceQafMgrForDriver
Provides many device permission checks including Vita model checks, running app privilege checks, and so on.
ScePmMgrForDriver
SceSblAIMgrForDriver
SceProcEventForDriver
SceSysrootForDriver