diff --git a/CMakeLists.txt b/CMakeLists.txt
index b5d256c21095..50cd7b535643 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1590,6 +1590,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceKernelAlarm.h
Core/HLE/sceKernelEventFlag.cpp
Core/HLE/sceKernelEventFlag.h
+ Core/HLE/sceKernelHeap.cpp
+ Core/HLE/sceKernelHeap.h
Core/HLE/sceKernelInterrupt.cpp
Core/HLE/sceKernelInterrupt.h
Core/HLE/sceKernelMbx.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 1c422c1593ef..5b675bd729d9 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -371,6 +371,7 @@
+
@@ -899,6 +900,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 19698164c259..c95b6aa41fd4 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -740,6 +740,9 @@
HW
+
+ HLE\Kernel
+
@@ -1373,10 +1376,13 @@
HW
+
+ HLE\Kernel
+
-
\ No newline at end of file
+
diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h
index 39599d408fde..01124ea15735 100644
--- a/Core/HLE/FunctionWrappers.h
+++ b/Core/HLE/FunctionWrappers.h
@@ -134,6 +134,11 @@ template void WrapI_CIIIII
RETURN(retval);
}
+template void WrapI_IIIC() {
+ u32 retval = func(PARAM(0), PARAM(1), PARAM(2), Memory::GetCharPointer(PARAM(3)));
+ RETURN(retval);
+}
+
// Hm, do so many params get passed in registers?
template void WrapI_IIIIIIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp
index c62a564b7fa9..b4f0636f7709 100644
--- a/Core/HLE/HLETables.cpp
+++ b/Core/HLE/HLETables.cpp
@@ -40,6 +40,7 @@
#include "sceJpeg.h"
#include "sceKernel.h"
#include "sceKernelEventFlag.h"
+#include "sceKernelHeap.h"
#include "sceKernelMemory.h"
#include "sceKernelInterrupt.h"
#include "sceKernelModule.h"
diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp
index ad571355ef15..520295f2d929 100644
--- a/Core/HLE/sceKernel.cpp
+++ b/Core/HLE/sceKernel.cpp
@@ -50,6 +50,7 @@
#include "sceJpeg.h"
#include "sceKernel.h"
#include "sceKernelAlarm.h"
+#include "sceKernelHeap.h"
#include "sceKernelInterrupt.h"
#include "sceKernelThread.h"
#include "sceKernelMemory.h"
diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h
index fa5928584bba..96e94cb76002 100644
--- a/Core/HLE/sceKernel.h
+++ b/Core/HLE/sceKernel.h
@@ -340,6 +340,7 @@ enum TMIDPurpose
PPSSPP_KERNEL_TMID_PMB = 0x100002,
PPSSPP_KERNEL_TMID_File = 0x100003,
PPSSPP_KERNEL_TMID_DirList = 0x100004,
+ PPSSPP_KERNEL_TMID_Heap = 0x100005,
};
typedef int SceUID;
diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp
new file mode 100644
index 000000000000..7b99eca18479
--- /dev/null
+++ b/Core/HLE/sceKernelHeap.cpp
@@ -0,0 +1,94 @@
+#include
+
+#include "Common/ChunkFile.h"
+#include "Core/HLE/HLE.h"
+#include "Core/HLE/FunctionWrappers.h"
+#include "Core/HLE/sceKernel.h"
+#include "Core/HLE/sceKernelHeap.h"
+#include "Core/HLE/sceKernelMemory.h"
+#include "Core/Util/BlockAllocator.h"
+
+static const u32 HEAP_BLOCK_HEADER_SIZE = 8;
+static const bool g_fromBottom = false;
+
+struct Heap : public KernelObject {
+ int uid = 0;
+ int partitionId = 0;
+ u32 size = 0;
+ int flags = 0;
+ u32 address = 0;
+ std::string name;
+ BlockAllocator alloc;
+
+ static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_UID; }
+ static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_Heap; }
+ int GetIDType() const override { return PPSSPP_KERNEL_TMID_Heap; }
+
+ void DoState(PointerWrap &p) override {
+ p.Do(uid);
+ p.Do(partitionId);
+ p.Do(size);
+ p.Do(flags);
+ p.Do(address);
+ p.Do(name);
+ p.Do(alloc);
+ }
+};
+
+static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) {
+ u32 allocSize = (size + 3) & ~3;
+
+ // TODO: partitionId should probably decide if we allocate from userMemory or kernel or whatever...
+ u32 addr = userMemory.Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap");
+ if (addr == (u32)-1) {
+ ERROR_LOG(HLE, "sceKernelCreateHeap(partitionId=%d): Failed to allocate %d bytes memory", partitionId, size);
+ return SCE_KERNEL_ERROR_NO_MEMORY; // Blind guess
+ }
+
+ Heap *heap = new Heap();
+ SceUID uid = kernelObjects.Create(heap);
+
+ heap->partitionId = partitionId;
+ heap->flags = flags;
+ heap->name = Name ? Name : ""; // Not sure if this needs validation.
+ heap->size = allocSize;
+ heap->address = addr;
+ heap->alloc.Init(heap->address + 128, heap->size - 128);
+ heap->uid = uid;
+ return hleLogSuccessInfoX(SCEKERNEL, uid);
+}
+
+static int sceKernelAllocHeapMemory(int heapId, int size) {
+ u32 error;
+ Heap *heap = kernelObjects.Get(heapId, error);
+ if (heap) {
+ // There's 8 bytes at the end of every block, reserved.
+ u32 memSize = HEAP_BLOCK_HEADER_SIZE + size;
+ u32 addr = heap->alloc.Alloc(memSize, true);
+ return hleLogSuccessInfoX(SCEKERNEL, addr);
+ } else {
+ return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId);
+ }
+}
+
+static int sceKernelDeleteHeap(int heapId) {
+ u32 error;
+ Heap *heap = kernelObjects.Get(heapId, error);
+ if (heap) {
+ userMemory.Free(heap->address);
+ kernelObjects.Destroy(heap->uid);
+ return hleLogSuccessInfoX(SCEKERNEL, 0);
+ } else {
+ return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId);
+ }
+}
+
+const HLEFunction SysMemForKernel[] = {
+ { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'x', "ii" },
+ { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'i', "i" },
+ { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'i', "iixs" },
+};
+
+void Register_SysMemForKernel() {
+ RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel);
+}
diff --git a/Core/HLE/sceKernelHeap.h b/Core/HLE/sceKernelHeap.h
new file mode 100644
index 000000000000..1279c7496232
--- /dev/null
+++ b/Core/HLE/sceKernelHeap.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void Register_SysMemForKernel();
diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp
index 46e53753979c..40cccaa03d9b 100644
--- a/Core/HLE/sceKernelMemory.cpp
+++ b/Core/HLE/sceKernelMemory.cpp
@@ -2287,16 +2287,6 @@ const HLEFunction SysMemUserForUser[] = {
{0XD8DE5C1E, &WrapU_V, "SysMemUserForUser_D8DE5C1E", 'x', "" },
};
-const HLEFunction SysMemForKernel[] = {
- {0x636C953B, nullptr, "SysMemForKernel_636c953b", '?', "" },
- {0xC9805775, nullptr, "SysMemForKernel_c9805775", '?', "" },
- {0x1C1FBFE7, nullptr, "SysMemForKernel_1c1fbfe7", '?', "" },
-};
-
-void Register_SysMemForKernel() {
- RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel);
-}
-
void Register_SysMemUserForUser() {
RegisterModule("SysMemUserForUser", ARRAY_SIZE(SysMemUserForUser), SysMemUserForUser);
}
diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h
index 2396792436e9..dce6df77e04a 100644
--- a/Core/HLE/sceKernelMemory.h
+++ b/Core/HLE/sceKernelMemory.h
@@ -66,5 +66,4 @@ int sceKernelGetTlsAddr(SceUID uid);
int sceKernelFreeTlspl(SceUID uid);
int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr);
-void Register_SysMemForKernel();
void Register_SysMemUserForUser();
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 814930607bfc..0bbac0c46e94 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -466,6 +466,7 @@
+
@@ -678,6 +679,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index 07d1e0937168..7afcc97e719d 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -368,6 +368,9 @@
HLE
+
+ HLE
+
HLE
@@ -968,6 +971,9 @@
HLE
+
+ HLE
+
HLE
@@ -1298,4 +1304,4 @@
HW
-
\ No newline at end of file
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index d334324cf82d..6f23ada75f0f 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -360,6 +360,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/HLE/sceKernel.cpp \
$(SRC)/Core/HLE/sceKernelAlarm.cpp \
$(SRC)/Core/HLE/sceKernelEventFlag.cpp \
+ $(SRC)/Core/HLE/sceKernelHeap.cpp \
$(SRC)/Core/HLE/sceKernelInterrupt.cpp \
$(SRC)/Core/HLE/sceKernelMemory.cpp \
$(SRC)/Core/HLE/sceKernelModule.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index d909df3ada36..b1fd51bdb670 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -389,6 +389,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \
$(COREDIR)/HLE/sceKernel.cpp \
$(COREDIR)/HLE/sceKernelAlarm.cpp \
$(COREDIR)/HLE/sceKernelEventFlag.cpp \
+ $(COREDIR)/HLE/sceKernelHeap.cpp \
$(COREDIR)/HLE/sceKernelInterrupt.cpp \
$(COREDIR)/HLE/sceKernelMbx.cpp \
$(COREDIR)/HLE/sceKernelMemory.cpp \