1 #include <string>
2 
3 #include "Common/Serialize/Serializer.h"
4 #include "Common/Serialize/SerializeFuncs.h"
5 #include "Core/HLE/HLE.h"
6 #include "Core/HLE/FunctionWrappers.h"
7 #include "Core/HLE/sceKernel.h"
8 #include "Core/HLE/sceKernelHeap.h"
9 #include "Core/HLE/sceKernelMemory.h"
10 #include "Core/Util/BlockAllocator.h"
11 
12 static const u32 KERNEL_HEAP_BLOCK_HEADER_SIZE = 8;
13 static const bool g_fromBottom = false;
14 
15 // This object and the functions here are available for kernel code only, not game code.
16 // This differs from code like sceKernelMutex, which is available for games.
17 // This exists in PPSSPP mainly because certain game patches use these kernel modules.
18 
19 struct KernelHeap : public KernelObject {
20 	int uid = 0;
21 	int partitionId = 0;
22 	u32 size = 0;
23 	int flags = 0;
24 	u32 address = 0;
25 	std::string name;
26 	BlockAllocator alloc;
27 
GetMissingErrorCodeKernelHeap28 	static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_UID; }
GetStaticIDTypeKernelHeap29 	static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_Heap; }
GetIDTypeKernelHeap30 	int GetIDType() const override { return PPSSPP_KERNEL_TMID_Heap; }
GetTypeNameKernelHeap31 	const char *GetTypeName() override { return GetStaticTypeName(); }
GetStaticTypeNameKernelHeap32 	static const char *GetStaticTypeName() { return "Heap"; }
33 
DoStateKernelHeap34 	void DoState(PointerWrap &p) override {
35 		Do(p, uid);
36 		Do(p, partitionId);
37 		Do(p, size);
38 		Do(p, flags);
39 		Do(p, address);
40 		Do(p, name);
41 		Do(p, alloc);
42 	}
43 };
44 
sceKernelCreateHeap(int partitionId,int size,int flags,const char * Name)45 static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) {
46 	u32 allocSize = (size + 3) & ~3;
47 
48 	// TODO: partitionId should probably decide if we allocate from userMemory or kernel or whatever...
49 	u32 addr = userMemory.Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap");
50 	if (addr == (u32)-1) {
51 		ERROR_LOG(HLE, "sceKernelCreateHeap(partitionId=%d): Failed to allocate %d bytes memory", partitionId, size);
52 		return SCE_KERNEL_ERROR_NO_MEMORY;  // Blind guess
53 	}
54 
55 	KernelHeap *heap = new KernelHeap();
56 	SceUID uid = kernelObjects.Create(heap);
57 
58 	heap->partitionId = partitionId;
59 	heap->flags = flags;
60 	heap->name = Name ? Name : "";  // Not sure if this needs validation.
61 	heap->size = allocSize;
62 	heap->address = addr;
63 	heap->alloc.Init(heap->address + 128, heap->size - 128, true);
64 	heap->uid = uid;
65 	return hleLogSuccessInfoX(SCEKERNEL, uid);
66 }
67 
sceKernelAllocHeapMemory(int heapId,int size)68 static int sceKernelAllocHeapMemory(int heapId, int size) {
69 	u32 error;
70 	KernelHeap *heap = kernelObjects.Get<KernelHeap>(heapId, error);
71 	if (heap) {
72 		// There's 8 bytes at the end of every block, reserved.
73 		u32 memSize = KERNEL_HEAP_BLOCK_HEADER_SIZE + size;
74 		u32 addr = heap->alloc.Alloc(memSize, true);
75 		return hleLogSuccessInfoX(SCEKERNEL, addr);
76 	} else {
77 		return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId);
78 	}
79 }
80 
sceKernelDeleteHeap(int heapId)81 static int sceKernelDeleteHeap(int heapId) {
82 	u32 error;
83 	KernelHeap *heap = kernelObjects.Get<KernelHeap>(heapId, error);
84 	if (heap) {
85 		userMemory.Free(heap->address);
86 		kernelObjects.Destroy<KernelHeap>(heap->uid);
87 		return hleLogSuccessInfoX(SCEKERNEL, 0);
88 	} else {
89 		return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId);
90 	}
91 }
92 
sceKernelPartitionTotalFreeMemSize(int partitionId)93 static u32 sceKernelPartitionTotalFreeMemSize(int partitionId) {
94 	ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionTotalFreeMemSize(%d)", partitionId);
95 	//Need more work #13021
96 	///We ignore partitionId for now
97 	return userMemory.GetTotalFreeBytes();
98 }
99 
sceKernelPartitionMaxFreeMemSize(int partitionId)100 static u32 sceKernelPartitionMaxFreeMemSize(int partitionId) {
101 	ERROR_LOG(SCEKERNEL, "UNIMP sceKernelPartitionMaxFreeMemSize(%d)", partitionId);
102 	//Need more work #13021
103 	///We ignore partitionId for now
104 	return userMemory.GetLargestFreeBlockSize();
105 }
106 
SysMemForKernel_536AD5E1()107 static u32 SysMemForKernel_536AD5E1()
108 {
109 	ERROR_LOG(SCEKERNEL, "UNIMP SysMemForKernel_536AD5E1");
110 	return 0;
111 }
112 
113 
114 const HLEFunction SysMemForKernel[] = {
115 	{ 0X636C953B, &WrapI_II<sceKernelAllocHeapMemory>, "sceKernelAllocHeapMemory", 'x', "ii",                                  HLE_KERNEL_SYSCALL },
116 	{ 0XC9805775, &WrapI_I<sceKernelDeleteHeap>,       "sceKernelDeleteHeap",      'i', "i" ,                                  HLE_KERNEL_SYSCALL },
117 	{ 0X1C1FBFE7, &WrapI_IIIC<sceKernelCreateHeap>,    "sceKernelCreateHeap",      'i', "iixs",                                HLE_KERNEL_SYSCALL },
118 	{ 0X237DBD4F, &WrapI_ICIUU<sceKernelAllocPartitionMemory>,     "sceKernelAllocPartitionMemory",         'i', "isixx",      HLE_KERNEL_SYSCALL },
119 	{ 0XB6D61D02, &WrapI_I<sceKernelFreePartitionMemory>,          "sceKernelFreePartitionMemory",          'i', "i",          HLE_KERNEL_SYSCALL },
120 	{ 0X9D9A5BA1, &WrapU_I<sceKernelGetBlockHeadAddr>,             "sceKernelGetBlockHeadAddr",             'x', "i",          HLE_KERNEL_SYSCALL },
121 	{ 0x9697CD32, &WrapU_I<sceKernelPartitionTotalFreeMemSize>,           "sceKernelPartitionTotalFreeMemSize",       'x', "i",HLE_KERNEL_SYSCALL },
122 	{ 0xE6581468, &WrapU_I<sceKernelPartitionMaxFreeMemSize>,             "sceKernelPartitionMaxFreeMemSize",         'x', "i",HLE_KERNEL_SYSCALL },
123 	{ 0X3FC9AE6A, &WrapU_V<sceKernelDevkitVersion>,                "sceKernelDevkitVersion",                'x', ""           ,HLE_KERNEL_SYSCALL },
124 	{ 0x536AD5E1, &WrapU_V<SysMemForKernel_536AD5E1>,       "SysMemForKernel_536AD5E1",      'i', "i"                         ,HLE_KERNEL_SYSCALL },
125 };
126 
Register_SysMemForKernel()127 void Register_SysMemForKernel() {
128 	RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel);
129 }
130