From c4a9c874d197a42ed99a520c6b0a3834fec7c282 Mon Sep 17 00:00:00 2001
From: Hykem <hykem@hotmail.com>
Date: Sat, 15 Mar 2014 19:45:43 +0000
Subject: [PATCH] Improved FRES and FRSQRTE results (tested with ppu_fpu).

Implemented and improved several SC_Memory syscalls.

Started working in sceNp module.
---
 rpcs3/Emu/Cell/PPUInterpreter.h              |  60 +--
 rpcs3/Emu/SysCalls/Modules/sceNp.cpp         |  34 ++
 rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp |   2 +
 rpcs3/Emu/SysCalls/SysCalls.cpp              |  29 +-
 rpcs3/Emu/SysCalls/SysCalls.h                |  19 +-
 rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp         | 513 ++++++++++++++-----
 rpcs3/Emu/SysCalls/lv2/SC_Memory.h           | 120 +++--
 7 files changed, 517 insertions(+), 260 deletions(-)

diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h
index 5ebb8a36f4..4baa3ec1bf 100644
--- a/rpcs3/Emu/Cell/PPUInterpreter.h
+++ b/rpcs3/Emu/Cell/PPUInterpreter.h
@@ -3404,62 +3404,11 @@ private:
 	}
 	void FRES(u32 frd, u32 frb, bool rc)
 	{
-		double res;
-
-#ifdef _MSC_VER
-		if(_fpclass(CPU.FPR[frb]) >= _FPCLASS_NZ)
-#else
-		if(_fpclass(CPU.FPR[frb]) == FP_ZERO || std::signbit(CPU.FPR[frb]) == 0)
-#endif
-		{
-			res = static_cast<float>(1.0 / CPU.FPR[frb]);
-			if(FPRdouble::IsINF(res) && CPU.FPR[frb] != 0.0)
-			{
-				if(res > 0.0)
-				{
-					(u64&)res = 0x47EFFFFFE0000000ULL;
-				}
-				else
-				{
-					(u64&)res = 0xC7EFFFFFE0000000ULL;
-				}
-			}
-		}
-		else
-		{
-			u64 v = CPU.FPR[frb];
-
-			if(v == 0ULL)
-			{
-				v = 0x7FF0000000000000ULL;
-			}
-			else if(v == 0x8000000000000000ULL)
-			{
-				v = 0xFFF0000000000000ULL;
-			}
-			else if(FPRdouble::IsNaN(CPU.FPR[frb]))
-			{
-				v = 0x7FF8000000000000ULL;
-			}
-			else if(CPU.FPR[frb] < 0.0)
-			{
-				v = 0x8000000000000000ULL;
-			}
-			else
-			{
-				v = 0ULL;
-			}
-
-			res = (double&)v;
-		}
-
 		if(CPU.FPR[frb] == 0.0)
 		{
 			CPU.SetFPSCRException(FPSCR_ZX);
 		}
-
-		CPU.FPR[frd] = res;
-
+		CPU.FPR[frd] = static_cast<float>(1.0 / CPU.FPR[frb]);
 		if(rc) UNK("fres.");//CPU.UpdateCR1(CPU.FPR[frd]);
 	}
 	void FMULS(u32 frd, u32 fra, u32 frc, bool rc)
@@ -3790,7 +3739,12 @@ private:
 	}
 	void FRSQRTE(u32 frd, u32 frb, bool rc)
 	{
-		CPU.FPR[frd] = 1.0f / (float)sqrt(CPU.FPR[frb]);
+		if(CPU.FPR[frb] == 0.0)
+		{
+			CPU.SetFPSCRException(FPSCR_ZX);
+		}
+		CPU.FPR[frd] = static_cast<float>(1.0 / sqrt(CPU.FPR[frb]));
+		if(rc) UNK("frsqrte.");//CPU.UpdateCR1(CPU.FPR[frd]);
 	}
 	void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc)
 	{
diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp
index 3732beb5f1..e024f0712e 100644
--- a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp
@@ -7,6 +7,37 @@
 void sceNp_init();
 Module sceNp(0x0016, sceNp_init);
 
+int sceNpInit(u32 mem_size, u32 mem_addr)
+{
+	sceNp.Log("sceNpInit(mem_size=0x%x, mem_addr=0x%x)", mem_size, mem_addr);
+	return CELL_OK;
+}
+
+int sceNpTerm()
+{
+	sceNp.Log("sceNpTerm");
+	return CELL_OK;
+}
+
+int sceNpDrmIsAvailable(u32 k_licensee_addr, u32 drm_path_addr)
+{
+	sceNp.Warning("sceNpDrmIsAvailable(k_licensee_addr=0x%x, drm_path_addr=0x%x)", k_licensee_addr, drm_path_addr);
+
+	wxString k_licensee_str;
+	wxString drm_path = Memory.ReadString(drm_path_addr);
+	u8 k_licensee[0x10];
+	for(int i = 0; i < 0x10; i++)
+	{
+		k_licensee[i] = Memory.Read8(k_licensee_addr + i);
+		k_licensee_str += wxString::Format("%02x", k_licensee[i]);
+	}
+
+	sceNp.Warning("sceNpDrmIsAvailable: Found DRM license file at %s", drm_path.c_str());
+	sceNp.Warning("sceNpDrmIsAvailable: Using k_licensee 0x%s", k_licensee_str);
+
+	return CELL_OK;
+}
+
 int sceNpManagerGetStatus(mem32_t status)
 {
 	sceNp.Log("sceNpManagerGetStatus(status_addr=0x%x)", status.GetAddr());
@@ -22,5 +53,8 @@ int sceNpManagerGetStatus(mem32_t status)
 
 void sceNp_init()
 {
+	sceNp.AddFunc(0xbd28fdbf, sceNpInit);
+	sceNp.AddFunc(0x4885aa18, sceNpTerm);
+	sceNp.AddFunc(0xad218faf, sceNpDrmIsAvailable);
 	sceNp.AddFunc(0xa7bff757, sceNpManagerGetStatus);
 }
diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp
index 945e925063..ca91624905 100644
--- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp
+++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp
@@ -167,7 +167,9 @@ void sysPrxForUser_init()
 	sysPrxForUser.AddFunc(0x44265c08, _sys_heap_memalign);
 
 	sysPrxForUser.AddFunc(0xb257540b, sys_mmapper_allocate_memory);
+	sysPrxForUser.AddFunc(0x70258515, sys_mmapper_allocate_memory_from_container);
 	sysPrxForUser.AddFunc(0xdc578057, sys_mmapper_map_memory);
+	sysPrxForUser.AddFunc(0x4643ba6e, sys_mmapper_unmap_memory);
 	sysPrxForUser.AddFunc(0x409ad939, sys_mmapper_free_memory);
 
 	sysPrxForUser.AddFunc(0x1ed454ce, sys_spu_elf_get_information);
diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp
index aad96f9329..f6903a3115 100644
--- a/rpcs3/Emu/SysCalls/SysCalls.cpp
+++ b/rpcs3/Emu/SysCalls/SysCalls.cpp
@@ -148,13 +148,28 @@ static func_caller* sc_table[1024] =
 	bind_func(sys_vm_get_statistics),                       //312 (0x138)
 	null_func, null_func, //314
 	null_func, null_func, null_func, null_func, null_func, //319
-	null_func, null_func, null_func, null_func, bind_func(sys_memory_container_create), //324
-	bind_func(sys_memory_container_destroy), null_func, null_func, null_func, null_func, //329
-	bind_func(sys_mmapper_allocate_address), null_func, null_func, null_func, null_func, //334
-	null_func, null_func, null_func, null_func, null_func, //339
-	null_func, bind_func(sys_memory_container_create), bind_func(sys_memory_container_destroy), null_func, null_func, //344
-	null_func, null_func, null_func, bind_func(sys_memory_allocate), bind_func(sys_memory_free), //349
-	null_func, bind_func(sys_memory_get_page_attribute), bind_func(sys_memory_get_user_memory_size), null_func, null_func, //354
+	null_func, null_func, null_func, null_func, //323
+	bind_func(sys_memory_container_create),                 //324
+	bind_func(sys_memory_container_destroy),                //325
+	bind_func(sys_mmapper_allocate_fixed_address),          //326
+	bind_func(sys_mmapper_enable_page_fault_notification),  //327
+	null_func, null_func, //329
+	bind_func(sys_mmapper_allocate_address),                //330
+	bind_func(sys_mmapper_free_address),                    //331
+	null_func, null_func, null_func, null_func, //335
+	bind_func(sys_mmapper_change_address_access_right),     //336
+	bind_func(sys_mmapper_search_and_map),                  //337
+	null_func, null_func, null_func, //340
+	bind_func(sys_memory_container_create),                 //341
+	bind_func(sys_memory_container_destroy),                //342
+	bind_func(sys_memory_container_get_size),				//343
+	null_func, null_func, null_func, null_func, //347
+	bind_func(sys_memory_allocate),							//348
+	bind_func(sys_memory_free),								//349
+	bind_func(sys_memory_allocate_from_container),			//350
+	bind_func(sys_memory_get_page_attribute),				//351
+	bind_func(sys_memory_get_user_memory_size),				//352
+	null_func, null_func, //354
 	null_func, null_func, null_func, null_func, null_func, //359
 	null_func, null_func, null_func, null_func, null_func, //364
 	null_func, null_func, null_func, null_func, null_func, //369
diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h
index 0b06490c51..64c6646f1b 100644
--- a/rpcs3/Emu/SysCalls/SysCalls.h
+++ b/rpcs3/Emu/SysCalls/SysCalls.h
@@ -223,16 +223,25 @@ extern void sys_ppu_thread_once(u32 once_ctrl_addr, u32 entry);
 extern int sys_ppu_thread_get_id(const u32 id_addr);
 
 //memory
+extern int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr);
+extern int sys_memory_allocate_from_container(u32 size, u32 cid, u32 flags, u32 alloc_addr_addr);
+extern int sys_memory_free(u32 start_addr);
+extern int sys_memory_get_page_attribute(u32 addr, mem_ptr_t<sys_page_attr_t> attr);
+extern int sys_memory_get_user_memory_size(u32 mem_info_addr);
 extern int sys_memory_container_create(mem32_t cid, u32 yield_size);
 extern int sys_memory_container_destroy(u32 cid);
-extern int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr);
-extern int sys_memory_free(u32 start_addr);
-extern int sys_memory_get_user_memory_size(u32 mem_info_addr);
-extern int sys_memory_get_page_attribute(u32 addr, mem_ptr_t<sys_page_attr_t> a);
+extern int sys_memory_container_get_size(u32 mem_info_addr, u32 cid);
 extern int sys_mmapper_allocate_address(u32 size, u64 flags, u32 alignment, u32 alloc_addr);
+extern int sys_mmapper_allocate_fixed_address();
 extern int sys_mmapper_allocate_memory(u32 size, u64 flags, mem32_t mem_id);
-extern int sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags);
+extern int sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, mem32_t mem_id);
+extern int sys_mmapper_change_address_access_right(u32 start_addr, u64 flags);
+extern int sys_mmapper_free_address(u32 start_addr);
 extern int sys_mmapper_free_memory(u32 mem_id);
+extern int sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags);
+extern int sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, u32 alloc_addr);
+extern int sys_mmapper_unmap_memory(u32 start_addr, u32 mem_id_addr);
+extern int sys_mmapper_enable_page_fault_notification(u32 start_addr, u32 q_id);
 
 //vm
 extern int sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 addr);
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp
index 5c4f5b9761..09e297ab27 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Memory.cpp
@@ -3,50 +3,13 @@
 #include "SC_Memory.h"
 
 SysCallBase sc_mem("memory");
-
-int sys_memory_container_create(mem32_t cid, u32 yield_size)
-{
-	sc_mem.Warning("sys_memory_container_create(cid_addr=0x%x, yield_size=0x%x)", cid.GetAddr(), yield_size);
-
-	if (!cid.IsGood())
-	{
-		return CELL_EFAULT;
-	}
-
-	yield_size &= ~0xfffff; //round down to 1 MB granularity
-
-	u64 addr = Memory.Alloc(yield_size, 0x100000); //1 MB alignment
-
-	if(!addr)
-	{
-		return CELL_ENOMEM;
-	}
-
-	cid = sc_mem.GetNewId(new MemoryContainerInfo(addr, yield_size));
-	sc_mem.Warning("*** memory_container created(addr=0x%llx): id = %d", addr, cid.GetValue());
-	return CELL_OK;
-}
-
-int sys_memory_container_destroy(u32 cid)
-{
-	sc_mem.Warning("sys_memory_container_destroy(cid=%d)", cid);
-
-	MemoryContainerInfo* ct;
-
-	if(!sc_mem.CheckId(cid, ct))
-	{
-		return CELL_ESRCH;
-	}
-
-	Memory.Free(ct->addr);
-	Emu.GetIdManager().RemoveID(cid);
-	return CELL_OK;
-}
+std::map<u32, u32> mmapper_info_map;
 
 int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
 {
-	//0x30000100;
 	sc_mem.Log("sys_memory_allocate(size=0x%x, flags=0x%x)", size, flags);
+	
+	// Check page size.
 	u32 addr;
 	switch(flags)
 	{
@@ -63,119 +26,64 @@ int sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
 	default: return CELL_EINVAL;
 	}
 
-	if(!addr) return CELL_ENOMEM;
+	if(!addr)
+		return CELL_ENOMEM;
+	
+	// Write back the start address of the allocated area.
 	sc_mem.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", addr, size);
 	Memory.Write32(alloc_addr_addr, addr);
 
 	return CELL_OK;
 }
 
+int sys_memory_allocate_from_container(u32 size, u32 cid, u32 flags, u32 alloc_addr_addr)
+{
+	sc_mem.Log("sys_memory_allocate_from_container(size=0x%x, cid=0x%x, flags=0x%x)", size, cid, flags);
+
+	// Check if this container ID is valid.
+	MemoryContainerInfo* ct;
+	if(!sc_mem.CheckId(cid, ct))
+		return CELL_ESRCH;
+	
+	// Check page size.
+	switch(flags)
+	{
+	case SYS_MEMORY_PAGE_SIZE_1M:
+		if(size & 0xfffff) return CELL_EALIGN;
+		ct->addr = Memory.Alloc(size, 0x100000);
+	break;
+
+	case SYS_MEMORY_PAGE_SIZE_64K:
+		if(size & 0xffff) return CELL_EALIGN;
+		ct->addr = Memory.Alloc(size, 0x10000);
+	break;
+
+	default: return CELL_EINVAL;
+	}
+
+	// Store the address and size in the container.
+	if(!ct->addr)
+		return CELL_ENOMEM;
+	ct->size = size;
+
+	// Write back the start address of the allocated area.
+	sc_mem.Log("Memory allocated! [addr: 0x%x, size: 0x%x]", ct->addr, ct->size);
+	Memory.Write32(alloc_addr_addr, ct->addr);
+
+	return CELL_OK;
+}
+
 int sys_memory_free(u32 start_addr)
 {
 	sc_mem.Log("sys_memory_free(start_addr=0x%x)", start_addr);
 
-	if(!Memory.Free(start_addr)) return CELL_EFAULT;
+	// Release the allocated memory.
+	if(!Memory.Free(start_addr))
+		return CELL_EFAULT;
 
 	return CELL_OK;
 }
 
-int sys_mmapper_allocate_address(u32 size, u64 flags, u32 alignment, u32 alloc_addr)
-{
-	sc_mem.Warning("sys_mmapper_allocate_address(size=0x%x, flags=0x%llx, alignment=0x%x, alloc_addr=0x%x)", size, flags, alignment, alloc_addr);
-
-	if(!Memory.IsGoodAddr(alloc_addr)) return CELL_EFAULT;
-
-	if(!alignment)
-		alignment = 1;
-
-	u32 addr;
-
-	switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
-	{
-	default:
-	case SYS_MEMORY_PAGE_SIZE_1M:
-		if(Memory.AlignAddr(size, alignment) & 0xfffff) return CELL_EALIGN;
-		addr = Memory.Alloc(size, 0x100000);
-	break;
-
-	case SYS_MEMORY_PAGE_SIZE_64K:
-		if(Memory.AlignAddr(size, alignment) & 0xffff) return CELL_EALIGN;
-		addr = Memory.Alloc(size, 0x10000);
-	break;
-	}
-
-	Memory.Write32(alloc_addr, addr);
-
-	return CELL_OK;
-}
-
-int sys_mmapper_allocate_memory(u32 size, u64 flags, mem32_t mem_id)
-{
-	sc_mem.Warning("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id_addr=0x%x)", size, flags, mem_id.GetAddr());
-
-	if(!mem_id.IsGood()) return CELL_EFAULT;
-
-	u32 addr;
-	switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
-	{
-	case SYS_MEMORY_PAGE_SIZE_1M:
-		if(size & 0xfffff) return CELL_EALIGN;
-		addr = Memory.Alloc(size, 0x100000);
-	break;
-
-	case SYS_MEMORY_PAGE_SIZE_64K:
-		if(size & 0xffff) return CELL_EALIGN;
-		addr = Memory.Alloc(size, 0x10000);
-	break;
-
-	default:
-		return CELL_EINVAL;
-	}
-
-	if(!addr)
-		return CELL_ENOMEM;
-
-	mem_id = sc_mem.GetNewId(new mmapper_info(addr, size, flags));
-
-	return CELL_OK;
-}
-
-int sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags)
-{
-	sc_mem.Warning("sys_mmapper_map_memory(start_addr=0x%x, mem_id=0x%x, flags=0x%llx)", start_addr, mem_id, flags);
-
-	mmapper_info* info;
-	if(!sc_mem.CheckId(mem_id, info)) return CELL_ESRCH;
-
-	if(!Memory.Map(start_addr, info->addr, info->size))
-	{
-		sc_mem.Error("sys_mmapper_map_memory failed!");
-	}
-
-	return CELL_OK;
-}
-
-int sys_mmapper_free_memory(u32 mem_id)
-{
-	sc_mem.Warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id);
-
-	mmapper_info* info;
-	if(!sc_mem.CheckId(mem_id, info)) return CELL_ESRCH;
-
-	Memory.Free(info->addr);
-	return CELL_OK;
-}
-
-int sys_memory_get_user_memory_size(u32 mem_info_addr)
-{
-	sc_mem.Warning("sys_memory_get_user_memory_size(mem_info_addr=0x%x)", mem_info_addr);
-	sys_memory_info info;
-	info.total_user_memory = re(Memory.GetUserMemTotalSize());
-	info.available_user_memory = re(Memory.GetUserMemAvailSize());
-	Memory.WriteData(mem_info_addr, info);
-	return CELL_OK;
-}
-
 int sys_memory_get_page_attribute(u32 addr, mem_ptr_t<sys_page_attr_t> attr)
 {
 	sc_mem.Warning("sys_memory_get_page_attribute(addr=0x%x, attr_addr=0x%x)", addr, attr.GetAddr());
@@ -183,10 +91,335 @@ int sys_memory_get_page_attribute(u32 addr, mem_ptr_t<sys_page_attr_t> attr)
 	if (!attr.IsGood())
 		return CELL_EFAULT;
 
+	// TODO: Implement per thread page attribute setting.
 	attr->attribute = 0;
 	attr->page_size = 0;
 	attr->access_right = 0;
 	attr->pad = 0;
 
 	return CELL_OK;
-}
\ No newline at end of file
+}
+
+int sys_memory_get_user_memory_size(u32 mem_info_addr)
+{
+	sc_mem.Warning("sys_memory_get_user_memory_size(mem_info_addr=0x%x)", mem_info_addr);
+	
+	// Fetch the user memory available.
+	sys_memory_info info;
+	info.total_user_memory = re(Memory.GetUserMemTotalSize());
+	info.available_user_memory = re(Memory.GetUserMemAvailSize());
+	
+	Memory.WriteData(mem_info_addr, info);
+	
+	return CELL_OK;
+}
+
+int sys_memory_container_create(mem32_t cid, u32 yield_size)
+{
+	sc_mem.Warning("sys_memory_container_create(cid_addr=0x%x, yield_size=0x%x)", cid.GetAddr(), yield_size);
+
+	if (!cid.IsGood())
+		return CELL_EFAULT;
+
+	yield_size &= ~0xfffff; //round down to 1 MB granularity
+	u64 addr = Memory.Alloc(yield_size, 0x100000); //1 MB alignment
+
+	if(!addr)
+		return CELL_ENOMEM;
+
+	// Wrap the allocated memory in a memory container.
+	MemoryContainerInfo *ct = new MemoryContainerInfo(addr, yield_size);
+	cid = sc_mem.GetNewId(ct);
+
+	sc_mem.Warning("*** memory_container created(addr=0x%llx): id = %d", addr, cid.GetValue());
+
+	return CELL_OK;
+}
+
+int sys_memory_container_destroy(u32 cid)
+{
+	sc_mem.Warning("sys_memory_container_destroy(cid=%d)", cid);
+
+	// Check if this container ID is valid.
+	MemoryContainerInfo* ct;
+	if(!sc_mem.CheckId(cid, ct))
+		return CELL_ESRCH;
+
+	// Release the allocated memory and remove the ID.
+	Memory.Free(ct->addr);
+	Emu.GetIdManager().RemoveID(cid);
+
+	return CELL_OK;
+}
+
+int sys_memory_container_get_size(u32 mem_info_addr, u32 cid)
+{
+	sc_mem.Warning("sys_memory_container_get_size(mem_info_addr=0x%x, cid=%d)", mem_info_addr, cid);
+
+	// Check if this container ID is valid.
+	MemoryContainerInfo* ct;
+	if(!sc_mem.CheckId(cid, ct))
+		return CELL_ESRCH;
+
+	// HACK: Return all memory.
+	sys_memory_info info;
+	info.total_user_memory = re(ct->size);
+	info.available_user_memory = re(ct->size);
+	
+	Memory.WriteData(mem_info_addr, info);
+
+	return CELL_OK;
+}
+
+int sys_mmapper_allocate_address(u32 size, u64 flags, u32 alignment, u32 alloc_addr)
+{
+	sc_mem.Warning("sys_mmapper_allocate_address(size=0x%x, flags=0x%llx, alignment=0x%x, alloc_addr=0x%x)", 
+		size, flags, alignment, alloc_addr);
+
+	if(!Memory.IsGoodAddr(alloc_addr))
+		return CELL_EFAULT;
+
+	// Check for valid alignment.
+	if(alignment > 0x80000000)
+		return CELL_EALIGN;
+
+	// Check page size.
+	u32 addr;
+	switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
+	{
+	default:
+	case SYS_MEMORY_PAGE_SIZE_1M:
+		if(Memory.AlignAddr(size, alignment) & 0xfffff)
+			return CELL_EALIGN;
+		addr = Memory.Alloc(size, 0x100000);
+	break;
+
+	case SYS_MEMORY_PAGE_SIZE_64K:
+		if(Memory.AlignAddr(size, alignment) & 0xffff)
+			return CELL_EALIGN;
+		addr = Memory.Alloc(size, 0x10000);
+	break;
+	}
+
+	// Write back the start address of the allocated area.
+	Memory.Write32(alloc_addr, addr);
+
+	return CELL_OK;
+}
+
+int sys_mmapper_allocate_fixed_address()
+{
+	sc_mem.Warning("sys_mmapper_allocate_fixed_address");
+
+	// Allocate a fixed size from user memory.
+	if (!Memory.Alloc(SYS_MMAPPER_FIXED_SIZE, 0x100000))
+		return CELL_EEXIST;
+	
+	return CELL_OK;
+}
+
+int sys_mmapper_allocate_memory(u32 size, u64 flags, mem32_t mem_id)
+{
+	sc_mem.Warning("sys_mmapper_allocate_memory(size=0x%x, flags=0x%llx, mem_id_addr=0x%x)", size, flags, mem_id.GetAddr());
+
+	if(!mem_id.IsGood())
+		return CELL_EFAULT;
+
+	// Check page granularity.
+	u32 addr;
+	switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
+	{
+	case SYS_MEMORY_PAGE_SIZE_1M:
+		if(size & 0xfffff)
+			return CELL_EALIGN;
+		addr = Memory.Alloc(size, 0x100000);
+	break;
+
+	case SYS_MEMORY_PAGE_SIZE_64K:
+		if(size & 0xffff)
+			return CELL_EALIGN;
+		addr = Memory.Alloc(size, 0x10000);
+	break;
+
+	default:
+		return CELL_EINVAL;
+	}
+
+	if(!addr)
+		return CELL_ENOMEM;
+
+	// Generate a new mem ID.
+	mem_id = sc_mem.GetNewId(new mmapper_info(addr, size, flags));
+
+	return CELL_OK;
+}
+
+int sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, mem32_t mem_id)
+{
+	sc_mem.Warning("sys_mmapper_allocate_memory_from_container(size=0x%x, cid=%d, flags=0x%llx, mem_id_addr=0x%x)", 
+		size, cid, flags, mem_id.GetAddr());
+
+	if(!mem_id.IsGood())
+		return CELL_EFAULT;
+
+	// Check if this container ID is valid.
+	MemoryContainerInfo* ct;
+	if(!sc_mem.CheckId(cid, ct))
+		return CELL_ESRCH;
+
+	// Check page granularity.
+	switch(flags & (SYS_MEMORY_PAGE_SIZE_1M | SYS_MEMORY_PAGE_SIZE_64K))
+	{
+	case SYS_MEMORY_PAGE_SIZE_1M:
+		if(size & 0xfffff)
+			return CELL_EALIGN;
+		ct->addr = Memory.Alloc(size, 0x100000);
+	break;
+
+	case SYS_MEMORY_PAGE_SIZE_64K:
+		if(size & 0xffff)
+			return CELL_EALIGN;
+		ct->addr = Memory.Alloc(size, 0x10000);
+	break;
+
+	default:
+		return CELL_EINVAL;
+	}
+
+	if(!ct->addr)
+		return CELL_ENOMEM;
+	ct->size = size;
+
+	// Generate a new mem ID.
+	mem_id = sc_mem.GetNewId(new mmapper_info(ct->addr, ct->size, flags));
+
+	return CELL_OK;
+}
+
+int sys_mmapper_change_address_access_right(u32 start_addr, u64 flags)
+{
+	sc_mem.Warning("sys_mmapper_change_address_access_right(start_addr=0x%x, flags=0x%llx)", start_addr, flags);
+
+	if (!Memory.IsGoodAddr(start_addr))
+		return CELL_EINVAL;
+
+	// TODO
+
+	return CELL_OK;
+}
+
+int sys_mmapper_free_address(u32 start_addr)
+{
+	sc_mem.Warning("sys_mmapper_free_address(start_addr=0x%x)", start_addr);
+
+	if(!Memory.IsGoodAddr(start_addr))
+		return CELL_EINVAL;
+	
+	// Free the address.
+	Memory.Free(start_addr);
+	return CELL_OK;
+}
+
+int sys_mmapper_free_memory(u32 mem_id)
+{
+	sc_mem.Warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id);
+
+	// Check if this mem ID is valid.
+	mmapper_info* info;
+	if(!sc_mem.CheckId(mem_id, info))
+		return CELL_ESRCH;
+
+	// Release the allocated memory and remove the ID.
+	Memory.Free(info->addr);
+	Emu.GetIdManager().RemoveID(mem_id);
+
+	return CELL_OK;
+}
+
+int sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags)
+{
+	sc_mem.Warning("sys_mmapper_map_memory(start_addr=0x%x, mem_id=0x%x, flags=0x%llx)", start_addr, mem_id, flags);
+
+	// Check if this mem ID is valid.
+	mmapper_info* info;
+	if(!sc_mem.CheckId(mem_id, info))
+		return CELL_ESRCH;
+
+	// Map the memory into the process address.
+	if(!Memory.Map(start_addr, info->addr, info->size))
+		sc_mem.Error("sys_mmapper_map_memory failed!");
+
+	// Keep track of mapped addresses.
+	mmapper_info_map[mem_id] = start_addr;
+
+	return CELL_OK;
+}
+
+int sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, u32 alloc_addr)
+{
+	sc_mem.Warning("sys_mmapper_search_and_map(start_addr=0x%x, mem_id=0x%x, flags=0x%llx, alloc_addr=0x%x)",
+		start_addr, mem_id, flags, alloc_addr);
+
+	if(!Memory.IsGoodAddr(alloc_addr))
+		return CELL_EFAULT;
+
+	// Check if this mem ID is valid.
+	mmapper_info* info;
+	if(!sc_mem.CheckId(mem_id, info))
+		return CELL_ESRCH;
+	
+	// Search for a mappable address.
+	u32 addr;
+	bool found;
+	for (int i = 0; i < SYS_MMAPPER_FIXED_SIZE; i += 0x100000)
+	{
+		addr = start_addr + i;
+		found = Memory.Map(addr, info->addr, info->size);
+		if(found)
+		{
+			sc_mem.Warning("Found and mapped address 0x%x", addr);
+			break;
+		}
+	}
+
+	// Check if the address is valid.
+	if (!Memory.IsGoodAddr(addr) || !found)
+		return CELL_ENOMEM;
+	
+	// Write back the start address of the allocated area.
+	Memory.Write32(alloc_addr, addr);
+
+	// Keep track of mapped addresses.
+	mmapper_info_map[mem_id] = addr;
+
+	return CELL_OK;
+}
+
+int sys_mmapper_unmap_memory(u32 start_addr, u32 mem_id_addr)
+{
+	sc_mem.Warning("sys_mmapper_unmap_memory(start_addr=0x%x, mem_id_addr=0x%x)", start_addr, mem_id_addr);
+
+	if (!Memory.IsGoodAddr(start_addr))
+		return CELL_EINVAL;
+
+	if (!Memory.IsGoodAddr(mem_id_addr))
+		return CELL_EFAULT;
+
+	// Write back the mem ID of the unmapped area.
+	u32 mem_id = mmapper_info_map.find(start_addr)->first;
+	Memory.Write32(mem_id_addr, mem_id);
+
+	return CELL_OK;
+}
+
+int sys_mmapper_enable_page_fault_notification(u32 start_addr, u32 q_id)
+{
+	sc_mem.Warning("sys_mmapper_enable_page_fault_notification(start_addr=0x%x, q_id=0x%x)", start_addr, q_id);
+
+	if (!Memory.IsGoodAddr(start_addr))
+		return CELL_EINVAL;
+
+	// TODO
+
+	return CELL_OK;
+}
diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Memory.h b/rpcs3/Emu/SysCalls/lv2/SC_Memory.h
index 3f6b7e0dd4..5a09b05016 100644
--- a/rpcs3/Emu/SysCalls/lv2/SC_Memory.h
+++ b/rpcs3/Emu/SysCalls/lv2/SC_Memory.h
@@ -1,53 +1,71 @@
-#pragma once
-
-#define SYS_MEMORY_CONTAINER_ID_INVALID		0xFFFFFFFF
+#pragma once
+
+#define SYS_MEMORY_CONTAINER_ID_INVALID		0xFFFFFFFF
+#define SYS_MEMORY_ACCESS_RIGHT_NONE		0x00000000000000F0ULL
+#define SYS_MEMORY_ACCESS_RIGHT_PPU_THREAD  0x0000000000000008ULL
+#define SYS_MEMORY_ACCESS_RIGHT_HANDLER     0x0000000000000004ULL
+#define SYS_MEMORY_ACCESS_RIGHT_SPU_THREAD  0x0000000000000002ULL
+#define SYS_MEMORY_ACCESS_RIGHT_SPU_RAW		0x0000000000000001ULL
+#define SYS_MEMORY_ATTR_READ_ONLY			0x0000000000080000ULL
+#define SYS_MEMORY_ATTR_READ_WRITE			0x0000000000040000ULL
+#define SYS_MMAPPER_FIXED_ADDR				0xB0000000
+#define SYS_MMAPPER_FIXED_SIZE				0x10000000
 #define SYS_VM_TEST_INVALID                 0x0000ULL
 #define SYS_VM_TEST_UNUSED                  0x0001ULL
 #define SYS_VM_TEST_ALLOCATED               0x0002ULL
-#define SYS_VM_TEST_STORED                  0x0004ULL
-
-enum
-{
-	SYS_MEMORY_PAGE_SIZE_1M = 0x400,
-	SYS_MEMORY_PAGE_SIZE_64K = 0x200,
-};
-
-struct MemoryContainerInfo
-{
-	u64 addr;
-	u32 size;
-
-	MemoryContainerInfo(u64 addr, u32 size)
-		: addr(addr)
-		, size(size)
-	{
-	}
-};
-
-struct mmapper_info
-{
-	u64 addr;
-	u32 size;
-	u32 flags;
-
-	mmapper_info(u64 _addr, u32 _size, u32 _flags)
-		: addr(_addr)
-		, size(_size)
-		, flags(_flags)
-	{
-	}
-
-	mmapper_info()
-	{
-	}
-};
-
-struct sys_memory_info
-{
-	u32 total_user_memory;
-	u32 available_user_memory;
-};
-
+#define SYS_VM_TEST_STORED                  0x0004ULL
+
+enum
+{
+	SYS_MEMORY_PAGE_SIZE_1M = 0x400,
+	SYS_MEMORY_PAGE_SIZE_64K = 0x200,
+};
+
+struct sys_memory_info
+{
+	u32 total_user_memory;
+	u32 available_user_memory;
+};
+
+
+struct sys_page_attr_t
+{
+	u64 attribute;
+	u64 access_right;
+	u32 page_size;
+	u32 pad;
+};
+
+struct MemoryContainerInfo
+{
+	u64 addr;
+	u32 size;
+
+	MemoryContainerInfo(u64 addr, u32 size)
+		: addr(addr)
+		, size(size)
+	{
+	}
+};
+
+struct mmapper_info
+{
+	u64 addr;
+	u32 size;
+	u32 flags;
+
+	mmapper_info(u64 _addr, u32 _size, u32 _flags)
+		: addr(_addr)
+		, size(_size)
+		, flags(_flags)
+	{
+	}
+
+	mmapper_info()
+	{
+	}
+};
+
 struct sys_vm_statistics {
 	u64 vm_crash_ppu;
 	u64 vm_crash_spu;
@@ -56,12 +74,4 @@ struct sys_vm_statistics {
 	u32 physical_mem_size;
 	u32 physical_mem_used;
 	u64 timestamp;
-};
-
-struct sys_page_attr_t
-{
-	u64 attribute;
-	u64 access_right;
-	u32 page_size;
-	u32 pad;
 };
\ No newline at end of file