#![no_std]
#![feature(allocator_api)]
#![feature(const_fn)]
extern crate psp2_sys;
mod utils;
use core::alloc::Alloc;
use core::alloc::AllocErr;
use core::alloc::Layout;
use core::cell::UnsafeCell;
use core::cmp::max;
use core::mem::size_of;
use core::ptr::NonNull;
use psp2_sys::kernel::sysmem::sceKernelAllocMemBlock;
use psp2_sys::kernel::sysmem::sceKernelFindMemBlockByAddr;
use psp2_sys::kernel::sysmem::sceKernelFreeMemBlock;
use psp2_sys::kernel::sysmem::sceKernelGetMemBlockBase;
use psp2_sys::kernel::sysmem::sceKernelGetMemBlockInfoByAddr;
use psp2_sys::kernel::sysmem::SceKernelAllocMemBlockOpt;
use psp2_sys::kernel::sysmem::SceKernelMemBlockInfo;
use psp2_sys::kernel::sysmem::SceKernelMemBlockType::SCE_KERNEL_MEMBLOCK_TYPE_USER_RW;
use psp2_sys::kernel::sysmem::SceKernelMemoryAccessType::SCE_KERNEL_MEMORY_ACCESS_R;
use psp2_sys::kernel::sysmem::SceKernelMemoryAccessType::SCE_KERNEL_MEMORY_ACCESS_W;
use psp2_sys::kernel::sysmem::SceKernelMemoryAccessType::SCE_KERNEL_MEMORY_ACCESS_X;
use psp2_sys::kernel::threadmgr::sceKernelCreateMutex;
use psp2_sys::kernel::threadmgr::sceKernelLockMutex;
use psp2_sys::kernel::threadmgr::sceKernelUnlockMutex;
use psp2_sys::types::SceUID;
use psp2_sys::void;
pub struct Vitallocator {
block_count: usize,
}
impl Default for Vitallocator {
fn default() -> Self {
Vitallocator::new()
}
}
impl Vitallocator {
pub const fn new() -> Self {
Vitallocator { block_count: 0 }
}
}
unsafe impl Alloc for Vitallocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
let mut options = SceKernelAllocMemBlockOpt {
size: size_of::<SceKernelAllocMemBlockOpt>() as u32,
attr: SCE_KERNEL_MEMORY_ACCESS_R as u32,
alignment: layout.align() as u32,
uidBaseBlock: 0,
strBaseBlockName: ::core::ptr::null(),
flags: 0,
reserved: [0; 10],
};
let mut basep: *mut void = ::core::ptr::null_mut::<u8>() as *mut _;
let mut name: [u8; 18] = *b"__rust_0x00000000\0";
utils::write_hex(self.block_count, &mut name[9..16]);
let uid: SceUID = sceKernelAllocMemBlock(
(&name).as_ptr(),
SCE_KERNEL_MEMBLOCK_TYPE_USER_RW,
max(layout.size() as i32, 4096),
&mut options as *mut _,
);
if uid < 0 {
return Err(AllocErr);
}
self.block_count = self.block_count.wrapping_add(1);
if sceKernelGetMemBlockBase(uid, &mut basep as *mut *mut void) < 0 {
sceKernelFreeMemBlock(uid); return Err(AllocErr);
}
NonNull::new(basep as *mut _).ok_or(AllocErr)
}
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
let mut info: SceKernelMemBlockInfo = ::core::mem::uninitialized();
sceKernelGetMemBlockInfoByAddr(ptr.as_ptr() as *mut void, (&mut info) as *mut _);
let uid = sceKernelFindMemBlockByAddr(ptr.as_ptr() as *mut void, info.size);
sceKernelFreeMemBlock(uid);
}
}