Merge pull request #90 from gizmo98/patch-2
[libretro-ppsspp.git] / Core / HLE / sceHeap.cpp
blob2667645c3ed98a36011edf43306cc99f86d0c2b5
1 // Copyright (c) 2012- PPSSPP Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18 #include "Common/ChunkFile.h"
19 #include "Core/MemMap.h"
20 #include "Core/Reporting.h"
21 #include "Core/HLE/HLE.h"
22 #include "Core/HLE/FunctionWrappers.h"
23 #include "Core/HLE/sceKernelMemory.h"
24 #include "Core/HLE/sceHeap.h"
25 #include "Core/Util/BlockAllocator.h"
26 #include <map>
28 struct Heap {
29 Heap():alloc(4) {}
31 u32 size;
32 u32 address;
33 bool fromtop;
34 BlockAllocator alloc;
36 void DoState (PointerWrap &p) {
37 p.Do(size);
38 p.Do(address);
39 p.Do(fromtop);
40 p.Do(alloc);
44 std::map<u32,Heap*> heapList;
46 static Heap *getHeap(u32 addr) {
47 auto found = heapList.find(addr);
48 if (found == heapList.end()) {
49 return NULL;
51 return found->second;
54 void __HeapDoState(PointerWrap &p) {
55 auto s = p.Section("sceHeap", 1, 2);
56 if (!s)
57 return;
59 if (s >= 2) {
60 p.Do(heapList);
64 enum SceHeapAttr {
65 PSP_HEAP_ATTR_HIGHMEM = 0x4000,
66 PSP_HEAP_ATTR_EXT = 0x8000,
69 void __HeapInit() {
70 heapList.clear();
73 static int sceHeapReallocHeapMemory(u32 heapAddr, u32 memPtr, int memSize) {
74 ERROR_LOG_REPORT(HLE,"UNIMPL sceHeapReallocHeapMemory(%08x, %08x, %08x)", heapAddr, memPtr, memSize);
75 return 0;
78 static int sceHeapReallocHeapMemoryWithOption(u32 heapPtr, u32 memPtr, int memSize, u32 paramsPtr) {
79 ERROR_LOG_REPORT(HLE,"UNIMPL sceHeapReallocHeapMemoryWithOption(%08x, %08x, %08x, %08x)", heapPtr, memPtr, memSize, paramsPtr);
80 return 0;
83 static int sceHeapFreeHeapMemory(u32 heapAddr, u32 memAddr) {
84 Heap *heap = getHeap(heapAddr);
85 if (!heap) {
86 ERROR_LOG(HLE, "sceHeapFreeHeapMemory(%08x, %08x): invalid heap", heapAddr, memAddr);
87 return SCE_KERNEL_ERROR_INVALID_ID;
90 DEBUG_LOG(HLE, "sceHeapFreeHeapMemory(%08x, %08x)", heapAddr, memAddr);
91 // An invalid address will crash the PSP, but 0 is always returns success.
92 if (memAddr == 0) {
93 return 0;
96 if (!heap->alloc.FreeExact(memAddr)) {
97 return SCE_KERNEL_ERROR_INVALID_POINTER;
99 return 0;
102 static int sceHeapGetMallinfo(u32 heapAddr, u32 infoPtr) {
103 ERROR_LOG_REPORT(HLE,"UNIMPL sceHeapGetMallinfo(%08x, %08x)", heapAddr, infoPtr);
104 return 0;
107 static u32 sceHeapAllocHeapMemoryWithOption(u32 heapAddr, u32 memSize, u32 paramsPtr) {
108 Heap *heap = getHeap(heapAddr);
109 u32 grain = 4;
110 if (!heap) {
111 ERROR_LOG(HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid heap", heapAddr, memSize, paramsPtr);
112 return 0;
115 // 0 is ignored.
116 if (paramsPtr != 0) {
117 u32 size = Memory::Read_U32(paramsPtr);
118 if (size < 8) {
119 ERROR_LOG(HLE, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid param size", heapAddr, memSize, paramsPtr);
120 return 0;
122 if (size > 8) {
123 WARN_LOG_REPORT(HLE, "sceHeapAllocHeapMemoryWithOption(): unexpected param size %d", size);
125 grain = Memory::Read_U32(paramsPtr + 4);
128 DEBUG_LOG(HLE,"sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x)", heapAddr, memSize, paramsPtr);
129 // There's 8 bytes at the end of every block, reserved.
130 memSize += 8;
131 u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true);
132 return addr;
135 static int sceHeapGetTotalFreeSize(u32 heapAddr) {
136 Heap *heap = getHeap(heapAddr);
137 if (!heap) {
138 ERROR_LOG(HLE, "sceHeapGetTotalFreeSize(%08x): invalid heap", heapAddr);
139 return SCE_KERNEL_ERROR_INVALID_ID;
142 DEBUG_LOG(HLE, "sceHeapGetTotalFreeSize(%08x)", heapAddr);
143 u32 free = heap->alloc.GetTotalFreeBytes();
144 if (free >= 8) {
145 // Every allocation requires an extra 8 bytes.
146 free -= 8;
148 return free;
151 static int sceHeapIsAllocatedHeapMemory(u32 heapPtr, u32 memPtr) {
152 if (!Memory::IsValidAddress(memPtr)) {
153 ERROR_LOG(HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x): invalid address", heapPtr, memPtr);
154 return SCE_KERNEL_ERROR_INVALID_POINTER;
157 DEBUG_LOG(HLE, "sceHeapIsAllocatedHeapMemory(%08x, %08x)", heapPtr, memPtr);
158 Heap *heap = getHeap(heapPtr);
159 // An invalid heap is fine, it's not a member of this heap one way or another.
160 // Only an exact address matches. Off by one crashes, and off by 4 says no.
161 if (heap && heap->alloc.GetBlockStartFromAddress(memPtr) == memPtr) {
162 return 1;
164 return 0;
167 static int sceHeapDeleteHeap(u32 heapAddr) {
168 Heap *heap = getHeap(heapAddr);
169 if (!heap) {
170 ERROR_LOG(HLE, "sceHeapDeleteHeap(%08x): invalid heap", heapAddr);
171 return SCE_KERNEL_ERROR_INVALID_ID;
174 DEBUG_LOG(HLE, "sceHeapDeleteHeap(%08x)", heapAddr);
175 heapList.erase(heapAddr);
176 delete heap;
177 return 0;
180 static int sceHeapCreateHeap(const char* name, u32 heapSize, int attr, u32 paramsPtr) {
181 if (paramsPtr != 0) {
182 u32 size = Memory::Read_U32(paramsPtr);
183 WARN_LOG_REPORT(HLE, "sceHeapCreateHeap(): unsupported options parameter, size = %d", size);
185 if (name == NULL) {
186 WARN_LOG_REPORT(HLE, "sceHeapCreateHeap(): name is NULL");
187 return 0;
189 int allocSize = (heapSize + 3) & ~3;
191 Heap *heap = new Heap;
192 heap->size = allocSize;
193 heap->fromtop = (attr & PSP_HEAP_ATTR_HIGHMEM) != 0;
194 u32 addr = userMemory.Alloc(heap->size, heap->fromtop, "Heap");
195 if (addr == (u32)-1) {
196 ERROR_LOG(HLE, "sceHeapCreateHeap(): Failed to allocate %i bytes memory", allocSize);
197 delete heap;
198 return 0;
200 heap->address = addr;
202 // Some of the heap is reseved by the implementation (the first 128 bytes, and 8 after each block.)
203 heap->alloc.Init(heap->address + 128, heap->size - 128);
204 heapList[heap->address] = heap;
205 DEBUG_LOG(HLE, "%08x=sceHeapCreateHeap(%s, %08x, %08x, %08x)", heap->address, name, heapSize, attr, paramsPtr);
206 return heap->address;
209 static u32 sceHeapAllocHeapMemory(u32 heapAddr, u32 memSize) {
210 Heap *heap = getHeap(heapAddr);
211 if (!heap) {
212 ERROR_LOG(HLE, "sceHeapAllocHeapMemory(%08x, %08x): invalid heap", heapAddr, memSize);
213 // Yes, not 0 (returns a pointer), but an error code. Strange.
214 return SCE_KERNEL_ERROR_INVALID_ID;
217 DEBUG_LOG(HLE, "sceHeapAllocHeapMemory(%08x, %08x)", heapAddr, memSize);
218 // There's 8 bytes at the end of every block, reserved.
219 memSize += 8;
220 // Always goes down, regardless of whether the heap is high or low.
221 u32 addr = heap->alloc.Alloc(memSize, true);
222 return addr;
226 static const HLEFunction sceHeap[] =
228 {0X0E875980, &WrapI_UUI<sceHeapReallocHeapMemory>, "sceHeapReallocHeapMemory", 'i', "xxi" },
229 {0X1C84B58D, &WrapI_UUIU<sceHeapReallocHeapMemoryWithOption>, "sceHeapReallocHeapMemoryWithOption", 'i', "xxix"},
230 {0X2ABADC63, &WrapI_UU<sceHeapFreeHeapMemory>, "sceHeapFreeHeapMemory", 'i', "xx" },
231 {0X2A0C2009, &WrapI_UU<sceHeapGetMallinfo>, "sceHeapGetMallinfo", 'i', "xx" },
232 {0X2B7299D8, &WrapU_UUU<sceHeapAllocHeapMemoryWithOption>, "sceHeapAllocHeapMemoryWithOption", 'x', "xxx" },
233 {0X4929B40D, &WrapI_U<sceHeapGetTotalFreeSize>, "sceHeapGetTotalFreeSize", 'i', "x" },
234 {0X7012BBDD, &WrapI_UU<sceHeapIsAllocatedHeapMemory>, "sceHeapIsAllocatedHeapMemory", 'i', "xx" },
235 {0X70210B73, &WrapI_U<sceHeapDeleteHeap>, "sceHeapDeleteHeap", 'i', "x" },
236 {0X7DE281C2, &WrapI_CUIU<sceHeapCreateHeap>, "sceHeapCreateHeap", 'i', "sxix"},
237 {0XA8E102A0, &WrapU_UU<sceHeapAllocHeapMemory>, "sceHeapAllocHeapMemory", 'x', "xx" },
240 void Register_sceHeap()
242 RegisterModule("sceHeap", ARRAY_SIZE(sceHeap), sceHeap);