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"
36 void DoState (PointerWrap
&p
) {
44 std::map
<u32
,Heap
*> heapList
;
46 static Heap
*getHeap(u32 addr
) {
47 auto found
= heapList
.find(addr
);
48 if (found
== heapList
.end()) {
54 void __HeapDoState(PointerWrap
&p
) {
55 auto s
= p
.Section("sceHeap", 1, 2);
65 PSP_HEAP_ATTR_HIGHMEM
= 0x4000,
66 PSP_HEAP_ATTR_EXT
= 0x8000,
73 static int sceHeapReallocHeapMemory(u32 heapAddr
, u32 memPtr
, int memSize
) {
74 ERROR_LOG_REPORT(HLE
,"UNIMPL sceHeapReallocHeapMemory(%08x, %08x, %08x)", heapAddr
, memPtr
, memSize
);
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
);
83 static int sceHeapFreeHeapMemory(u32 heapAddr
, u32 memAddr
) {
84 Heap
*heap
= getHeap(heapAddr
);
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.
96 if (!heap
->alloc
.FreeExact(memAddr
)) {
97 return SCE_KERNEL_ERROR_INVALID_POINTER
;
102 static int sceHeapGetMallinfo(u32 heapAddr
, u32 infoPtr
) {
103 ERROR_LOG_REPORT(HLE
,"UNIMPL sceHeapGetMallinfo(%08x, %08x)", heapAddr
, infoPtr
);
107 static u32
sceHeapAllocHeapMemoryWithOption(u32 heapAddr
, u32 memSize
, u32 paramsPtr
) {
108 Heap
*heap
= getHeap(heapAddr
);
111 ERROR_LOG(HLE
, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid heap", heapAddr
, memSize
, paramsPtr
);
116 if (paramsPtr
!= 0) {
117 u32 size
= Memory::Read_U32(paramsPtr
);
119 ERROR_LOG(HLE
, "sceHeapAllocHeapMemoryWithOption(%08x, %08x, %08x): invalid param size", heapAddr
, memSize
, paramsPtr
);
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.
131 u32 addr
= heap
->alloc
.AllocAligned(memSize
, grain
, grain
, true);
135 static int sceHeapGetTotalFreeSize(u32 heapAddr
) {
136 Heap
*heap
= getHeap(heapAddr
);
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();
145 // Every allocation requires an extra 8 bytes.
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
) {
167 static int sceHeapDeleteHeap(u32 heapAddr
) {
168 Heap
*heap
= getHeap(heapAddr
);
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
);
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
);
186 WARN_LOG_REPORT(HLE
, "sceHeapCreateHeap(): name is NULL");
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
);
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
);
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.
220 // Always goes down, regardless of whether the heap is high or low.
221 u32 addr
= heap
->alloc
.Alloc(memSize
, true);
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
);