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