This commit is contained in:
Nekotekina 2016-05-13 13:17:26 +03:00
parent 5c52521a0a
commit 38c444cfa1
133 changed files with 767 additions and 478 deletions

View File

@ -1 +0,0 @@
#pragma once

View File

@ -99,8 +99,8 @@ static const char* fmt_reg(u32 reg)
static std::string fmt_shift(u32 type, u32 amount)
{
Expects(type != arm_code::SRType_RRX || amount == 1);
Expects(amount <= 32);
EXPECTS(type != arm_code::SRType_RRX || amount == 1);
EXPECTS(amount <= 32);
if (amount)
{

View File

@ -669,7 +669,7 @@ void arm_interpreter::LDM(ARMv7Thread& cpu, const u32 op, const u32 cond)
if (ConditionPassed(cpu, cond))
{
vm::ptr<u32> memory(cpu.read_gpr(n), vm::addr);
vm::ptr<u32> memory(vm::cast(cpu.read_gpr(n)));
for (u32 i = 0; i < 16; i++)
{
@ -1384,7 +1384,7 @@ void arm_interpreter::PUSH(ARMv7Thread& cpu, const u32 op, const u32 cond)
if (ConditionPassed(cpu, cond))
{
vm::ptr<u32> memory(cpu.SP, vm::addr);
vm::ptr<u32> memory(vm::cast(cpu.SP));
for (u32 i = 15; ~i; i--)
{

View File

@ -48,46 +48,46 @@ struct arm_interpreter
static u32 LSL_C(u32 x, s32 shift, bool& carry_out)
{
Expects(shift > 0);
EXPECTS(shift > 0);
carry_out = shift <= 32 ? (x & (1 << (32 - shift))) != 0 : false;
return shift < 32 ? x << shift : 0;
}
static u32 LSL_(u32 x, s32 shift)
{
Expects(shift >= 0);
EXPECTS(shift >= 0);
return shift < 32 ? x << shift : 0;
}
static u32 LSR_C(u32 x, s32 shift, bool& carry_out)
{
Expects(shift > 0);
EXPECTS(shift > 0);
carry_out = shift <= 32 ? (x & (1 << (shift - 1))) != 0 : false;
return shift < 32 ? x >> shift : 0;
}
static u32 LSR_(u32 x, s32 shift)
{
Expects(shift >= 0);
EXPECTS(shift >= 0);
return shift < 32 ? x >> shift : 0;
}
static s32 ASR_C(s32 x, s32 shift, bool& carry_out)
{
Expects(shift > 0);
EXPECTS(shift > 0);
carry_out = shift <= 32 ? (x & (1 << (shift - 1))) != 0 : x < 0;
return shift < 32 ? x >> shift : x >> 31;
}
static s32 ASR_(s32 x, s32 shift)
{
Expects(shift >= 0);
EXPECTS(shift >= 0);
return shift < 32 ? x >> shift : x >> 31;
}
static u32 ROR_C(u32 x, s32 shift, bool& carry_out)
{
Expects(shift);
EXPECTS(shift);
const u32 result = x >> shift | x << (32 - shift);
carry_out = (result >> 31) != 0;
return result;
@ -111,7 +111,7 @@ struct arm_interpreter
static u32 Shift_C(u32 value, u32 type, s32 amount, bool carry_in, bool& carry_out)
{
Expects(type != arm_code::SRType_RRX || amount == 1);
EXPECTS(type != arm_code::SRType_RRX || amount == 1);
if (amount)
{

View File

@ -1,4 +1,5 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Loader/ELF.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
@ -9,6 +10,67 @@
#include "ARMv7Function.h"
#include "ARMv7Module.h"
LOG_CHANNEL(sceAppMgr);
LOG_CHANNEL(sceAppUtil);
LOG_CHANNEL(sceAudio);
LOG_CHANNEL(sceAudiodec);
LOG_CHANNEL(sceAudioenc);
LOG_CHANNEL(sceAudioIn);
LOG_CHANNEL(sceCamera);
LOG_CHANNEL(sceCodecEngine);
LOG_CHANNEL(sceCommonDialog);
LOG_CHANNEL(sceCtrl);
LOG_CHANNEL(sceDbg);
LOG_CHANNEL(sceDeci4p);
LOG_CHANNEL(sceDeflt);
LOG_CHANNEL(sceDisplay);
LOG_CHANNEL(sceFiber);
LOG_CHANNEL(sceFios);
LOG_CHANNEL(sceFpu);
LOG_CHANNEL(sceGxm);
LOG_CHANNEL(sceHttp);
LOG_CHANNEL(sceIme);
LOG_CHANNEL(sceJpeg);
LOG_CHANNEL(sceJpegEnc);
LOG_CHANNEL(sceLibc);
LOG_CHANNEL(sceLibKernel);
LOG_CHANNEL(sceLibm);
LOG_CHANNEL(sceLibstdcxx);
LOG_CHANNEL(sceLibXml);
LOG_CHANNEL(sceLiveArea);
LOG_CHANNEL(sceLocation);
LOG_CHANNEL(sceMd5);
LOG_CHANNEL(sceMotion);
LOG_CHANNEL(sceMt19937);
LOG_CHANNEL(sceNet);
LOG_CHANNEL(sceNetCtl);
LOG_CHANNEL(sceNgs);
LOG_CHANNEL(sceNpBasic);
LOG_CHANNEL(sceNpCommon);
LOG_CHANNEL(sceNpManager);
LOG_CHANNEL(sceNpMatching);
LOG_CHANNEL(sceNpScore);
LOG_CHANNEL(sceNpUtility);
LOG_CHANNEL(scePerf);
LOG_CHANNEL(scePgf);
LOG_CHANNEL(scePhotoExport);
LOG_CHANNEL(sceRazorCapture);
LOG_CHANNEL(sceRtc);
LOG_CHANNEL(sceSas);
LOG_CHANNEL(sceScreenShot);
LOG_CHANNEL(sceSfmt);
LOG_CHANNEL(sceSha);
LOG_CHANNEL(sceSqlite);
LOG_CHANNEL(sceSsl);
LOG_CHANNEL(sceSulpha);
LOG_CHANNEL(sceSysmodule);
LOG_CHANNEL(sceSystemGesture);
LOG_CHANNEL(sceTouch);
LOG_CHANNEL(sceUlt);
LOG_CHANNEL(sceVideodec);
LOG_CHANNEL(sceVoice);
LOG_CHANNEL(sceVoiceQoS);
extern void armv7_init_tls();
extern std::string arm_get_function_name(const std::string& module, u32 fnid);
@ -29,18 +91,18 @@ extern void arm_execute_function(ARMv7Thread& cpu, u32 index)
{
func(cpu);
}
catch (const std::exception&)
{
LOG_ERROR(ARMv7, "Function '%s' aborted", cpu.last_function);
cpu.last_function = previous_function;
throw;
}
catch (EmulationStopped)
{
LOG_WARNING(ARMv7, "Function '%s' aborted", cpu.last_function);
cpu.last_function = previous_function;
throw;
}
catch (...)
{
LOG_ERROR(ARMv7, "Function '%s' aborted", cpu.last_function);
cpu.last_function = previous_function;
throw;
}
LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", cpu.last_function, cpu.GPR[0]);
cpu.last_function = previous_function;
@ -411,7 +473,7 @@ void arm_exec_loader::load() const
case 0x6c2224ba: // __sce_moduleinfo
{
ASSERT(addr == module_info.addr());
VERIFY(addr == module_info.addr());
break;
}
@ -546,8 +608,8 @@ void arm_exec_loader::load() const
LOG_NOTICE(LOADER, "__sce_process_param(*0x%x) analysis...", proc_param);
ASSERT(proc_param->size >= sizeof(psv_process_param_t));
ASSERT(proc_param->ver == "PSP2"_u32);
VERIFY(proc_param->size >= sizeof(psv_process_param_t));
VERIFY(proc_param->ver == "PSP2"_u32);
LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", proc_param->size, proc_param->ver, proc_param->unk0, proc_param->unk1);
@ -563,7 +625,7 @@ void arm_exec_loader::load() const
LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param);
ASSERT(libc_param->size >= 0x1c);
VERIFY(libc_param->size >= 0x1c);
LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", libc_param->size, libc_param->unk0, libc_param->unk1, libc_param->unk2);

View File

@ -1,6 +1,5 @@
#pragma once
#include "Utilities/Config.h"
#include "ARMv7Function.h"
#include "ARMv7Callback.h"
#include "ErrorCodes.h"
@ -167,37 +166,3 @@ public:
#define REG_FNID(module, nid, func, ...) arm_module_manager::register_static_function<decltype(&func), &func>(#module, #func, BIND_FUNC(func), nid, {__VA_ARGS__})
#define REG_VNID(module, nid, var, ...) arm_module_manager::register_static_variable<decltype(var), &var>(#module, #var, nid, {__VA_ARGS__})
struct SceDateTime
{
le_t<u16> year;
le_t<u16> month;
le_t<u16> day;
le_t<u16> hour;
le_t<u16> minute;
le_t<u16> second;
le_t<u32> microsecond;
};
struct SceFVector3
{
le_t<f32> x, y, z;
};
struct SceFQuaternion
{
le_t<f32> x, y, z, w;
};
union SceUMatrix4
{
struct
{
le_t<f32> f[4][4];
};
struct
{
le_t<s32> i[4][4];
};
};

View File

@ -129,7 +129,7 @@ public:
std::array<perf_counter, 6> counters{};
u32 PC = 0;
s32 prio = 0;
u32 prio = -1;
u32 stack_addr = 0;
u32 stack_size = 0;
@ -155,7 +155,7 @@ public:
void write_gpr(u32 n, u32 value, u32 size)
{
Expects(n < 16);
EXPECTS(n < 16);
if (n < 15)
{
@ -169,7 +169,7 @@ public:
u32 read_gpr(u32 n)
{
Expects(n < 16);
EXPECTS(n < 16);
if (n < 15)
{
@ -242,7 +242,7 @@ struct arm_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
static inline vm::_ptr_base<T, AT> from(const u32 reg)
{
return{ arm_gpr_cast_impl<AT>::from(reg), vm::addr };
return vm::cast(arm_gpr_cast_impl<AT>::from(reg));
}
};
@ -256,7 +256,7 @@ struct arm_gpr_cast_impl<vm::_ref_base<T, AT>, void>
static inline vm::_ref_base<T, AT> from(const u32 reg)
{
return{ arm_gpr_cast_impl<AT>::from(reg), vm::addr };
return vm::cast(arm_gpr_cast_impl<AT>::from(reg));
}
};

View File

@ -179,9 +179,12 @@ struct arm_error_code
{
}
// Helper
enum class not_an_error : s32 {};
// Silence any error
constexpr arm_error_code(s32 value, const std::nothrow_t&)
: value(value)
constexpr arm_error_code(not_an_error value)
: value(static_cast<s32>(value))
{
}
@ -193,7 +196,7 @@ struct arm_error_code
};
// Helper macro for silencing possible error checks on returning arm_error_code values
#define NOT_AN_ERROR(value) { static_cast<s32>(value), std::nothrow }
#define NOT_AN_ERROR(...) static_cast<arm_error_code::not_an_error>(static_cast<s32>(__VA_ARGS__))
template<typename T, typename>
struct arm_gpr_cast_impl;

View File

@ -0,0 +1,38 @@
#pragma once
#include "Utilities/types.h"
#include "Utilities/BEType.h"
struct SceDateTime
{
le_t<u16> year;
le_t<u16> month;
le_t<u16> day;
le_t<u16> hour;
le_t<u16> minute;
le_t<u16> second;
le_t<u32> microsecond;
};
struct SceFVector3
{
le_t<f32> x, y, z;
};
struct SceFQuaternion
{
le_t<f32> x, y, z, w;
};
union SceUMatrix4
{
struct
{
le_t<f32> f[4][4];
};
struct
{
le_t<s32> i[4][4];
};
};

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceAppMgr.h"
LOG_CHANNEL(sceAppMgr);
logs::channel sceAppMgr("sceAppMgr", logs::level::notice);
s32 sceAppMgrReceiveEventNum(vm::ptr<s32> eventNum)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceAppUtil.h"
LOG_CHANNEL(sceAppUtil);
logs::channel sceAppUtil("sceAppUtil", logs::level::notice);
s32 sceAppUtilInit(vm::cptr<SceAppUtilInitParam> initParam, vm::ptr<SceAppUtilBootParam> bootParam)
{

View File

@ -1,5 +1,7 @@
#pragma once
#include "Common.h"
struct SceAppUtilInitParam
{
le_t<u32> workBufSize;

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceAudio.h"
LOG_CHANNEL(sceAudio);
logs::channel sceAudio("sceAudio", logs::level::notice);
s32 sceAudioOutOpenPort(s32 portType, s32 len, s32 freq, s32 param)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceAudioIn.h"
LOG_CHANNEL(sceAudioIn);
logs::channel sceAudioIn("sceAudioIn", logs::level::notice);
s32 sceAudioInOpenPort(s32 portType, s32 grain, s32 freq, s32 param)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceAudiodec.h"
LOG_CHANNEL(sceAudiodec);
logs::channel sceAudiodec("sceAudiodec", logs::level::notice);
s32 sceAudiodecInitLibrary(u32 codecType, vm::ptr<SceAudiodecInitParam> pInitParam)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceAudioenc.h"
LOG_CHANNEL(sceAudioenc);
logs::channel sceAudioenc("sceAudioenc", logs::level::notice);
s32 sceAudioencInitLibrary(u32 codecType, vm::ptr<SceAudioencInitParam> pInitParam)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceCamera.h"
LOG_CHANNEL(sceCamera);
logs::channel sceCamera("sceCamera", logs::level::notice);
s32 sceCameraOpen(s32 devnum, vm::ptr<SceCameraInfo> pInfo)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceCodecEngine.h"
LOG_CHANNEL(sceCodecEngine);
logs::channel sceCodecEngine("sceCodecEngine", logs::level::notice);
s32 sceCodecEnginePmonStart()
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceCommonDialog.h"
LOG_CHANNEL(sceCommonDialog);
logs::channel sceCommonDialog("sceCommonDialog", logs::level::notice);
s32 sceCommonDialogUpdate(vm::cptr<SceCommonDialogUpdateParam> updateParam)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceCtrl.h"
LOG_CHANNEL(sceCtrl);
logs::channel sceCtrl("sceCtrl", logs::level::notice);
s32 sceCtrlSetSamplingMode(u32 uiMode)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceDbg.h"
LOG_CHANNEL(sceDbg);
logs::channel sceDbg("sceDbg", logs::level::notice);
s32 sceDbgSetMinimumLogLevel(s32 minimumLogLevel)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceDeci4p.h"
LOG_CHANNEL(sceDeci4p);
logs::channel sceDeci4p("sceDeci4p", logs::level::notice);
s32 sceKernelDeci4pOpen(vm::cptr<char> protoname, u32 protonum, u32 bufsize)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceDeflt.h"
LOG_CHANNEL(sceDeflt);
logs::channel sceDeflt("sceDeflt", logs::level::notice);
s32 sceGzipIsValid(vm::cptr<void> pSrcGzip)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceDisplay.h"
LOG_CHANNEL(sceDisplay);
logs::channel sceDisplay("sceDisplay", logs::level::notice);
s32 sceDisplayGetRefreshRate(vm::ptr<float> pFps)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceFiber.h"
LOG_CHANNEL(sceFiber);
logs::channel sceFiber("sceFiber", logs::level::notice);
s32 _sceFiberInitializeImpl(vm::ptr<SceFiber> fiber, vm::cptr<char> name, vm::ptr<SceFiberEntry> entry, u32 argOnInitialize, vm::ptr<void> addrContext, u32 sizeContext, vm::cptr<SceFiberOptParam> optParam, u32 buildVersion)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceFios.h"
LOG_CHANNEL(sceFios);
logs::channel sceFios("sceFios", logs::level::notice);
s32 sceFiosInitialize(vm::cptr<SceFiosParams> pParameters)
{

View File

@ -1,5 +1,7 @@
#pragma once
#include "Common.h"
using SceFiosOpCallback = s32(vm::ptr<void> pContext, s32 op, u8 event, s32 err);
using SceFiosVprintfCallback = s32(vm::cptr<char> fmt, arm_va_args_t ap /* va_list */);
using SceFiosMemcpyCallback = vm::ptr<void>(vm::ptr<void> dst, vm::cptr<void> src, u32 len);

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceFpu.h"
LOG_CHANNEL(sceFpu);
logs::channel sceFpu("sceFpu", logs::level::notice);
float sceFpuSinf(float x)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceGxm.h"
LOG_CHANNEL(sceGxm);
logs::channel sceGxm("sceGxm", logs::level::notice);
s32 sceGxmInitialize(vm::cptr<SceGxmInitializeParams> params)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceHttp.h"
LOG_CHANNEL(sceHttp);
logs::channel sceHttp("sceHttp", logs::level::notice);
s32 sceHttpInit(u32 poolSize)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceIme.h"
LOG_CHANNEL(sceIme);
logs::channel sceIme("sceIme", logs::level::notice);
s32 sceImeOpen(vm::ptr<SceImeParam> param)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceJpeg.h"
LOG_CHANNEL(sceJpeg);
logs::channel sceJpeg("sceJpeg", logs::level::notice);
s32 sceJpegInitMJpeg(s32 maxSplitDecoder)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceJpegEnc.h"
LOG_CHANNEL(sceJpegEnc);
logs::channel sceJpegEnc("sceJpegEnc", logs::level::notice);
s32 sceJpegEncoderGetContextSize()
{

View File

@ -1,18 +1,20 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/IPC.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceLibKernel.h"
#include "Utilities/StrUtil.h"
#include "Utilities/lockless.h"
LOG_CHANNEL(sceLibKernel);
#include <algorithm>
logs::channel sceLibKernel("sceLibKernel", logs::level::notice);
extern u64 get_system_time();
extern std::condition_variable& get_current_thread_cv();
s32 sceKernelAllocMemBlock(vm::cptr<char> name, s32 type, u32 vsize, vm::ptr<SceKernelAllocMemBlockOpt> pOpt)
{
throw EXCEPTION("");
@ -75,7 +77,7 @@ arm_error_code sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr<void> pA
thread->GPR[1] = pos;
thread->state -= cpu_state::stop;
thread->lock_notify();
(*thread)->lock_notify();
return SCE_OK;
}
@ -207,19 +209,6 @@ s32 sceKernelGetSystemInfo(vm::ptr<SceKernelSystemInfo> pInfo)
throw EXCEPTION("");
}
arm_error_code sceKernelGetThreadmgrUIDClass(s32 uid)
{
sceLibKernel.error("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid);
if (idm::check<ARMv7Thread>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_THREAD;
if (idm::check<psv_semaphore_t>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_SEMA;
if (idm::check<psv_event_flag_t>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG;
if (idm::check<psv_mutex_t>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX;
if (idm::check<psv_cond_t>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_COND;
return SCE_KERNEL_ERROR_INVALID_UID;
}
s32 sceKernelChangeThreadVfpException(s32 clearMask, s32 setMask)
{
sceLibKernel.todo("sceKernelChangeThreadVfpException(clearMask=0x%x, setMask=0x%x)", clearMask, setMask);
@ -263,12 +252,7 @@ arm_error_code sceKernelWaitThreadEnd(s32 threadId, vm::ptr<s32> pExitStatus, vm
{
}
while (!(thread->state & cpu_state::exit))
{
CHECK_EMU_STATUS;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
(*thread)->join();
if (pExitStatus)
{
@ -374,20 +358,352 @@ s32 sceKernelWaitMultipleEventsCB(vm::ptr<SceKernelWaitEvent> pWaitEventList, s3
throw EXCEPTION("");
}
// Event flag functions
struct psp2_event_flag final
{
struct alignas(8) ctrl_t
{
u32 waiters;
u32 pattern;
};
atomic_t<ctrl_t> ctrl; // Sync variable
atomic_t<u64> wait_ctr{}; // FIFO ordering helper
using ipc = ipc_manager<psp2_event_flag, std::string>;
const std::string name; // IPC/Debug Name
atomic_t<u32> ipc_ref{1}; // IPC Ref Count
const u32 attr;
const u32 init;
psp2_event_flag(std::string&& name, u32 attr, u32 pattern)
: ctrl({0, pattern})
, name(std::move(name))
, attr(attr)
, init(pattern)
{
}
static inline bool pat_test(u32 current, u32 pattern, u32 mode)
{
const u32 or_mask = mode & SCE_KERNEL_EVF_WAITMODE_OR ? pattern : 0;
const u32 and_mask = mode & SCE_KERNEL_EVF_WAITMODE_OR ? 0 : pattern;
return (current & or_mask) != 0 && (current & and_mask) == and_mask;
}
// Get mask for bitwise AND for bit clear operation
static inline u32 pat_clear(u32 pattern, u32 mode)
{
return
mode & SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL ? 0 :
mode & SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT ? ~pattern : ~0;
}
// Commands
enum class task : u32
{
null = 0,
wait,
poll,
set,
clear,
cancel,
destroy,
signal,
};
struct alignas(8) cmd_t
{
task type;
u32 arg;
};
// Enqueue a command and try to execute all pending commands. Commands are executed sequentially.
// Returns true if the command has been completed immediately. Its status is unknown otherwise.
bool exec(task type, u32 arg)
{
// Acquire position in the queue
const u32 push_pos = m_workload.push_begin();
// Make the command
cmd_t cmd{type, arg};
u32 pos = m_workload.peek();
// Check optimistic case
if (UNLIKELY(pos != push_pos))
{
// Write the command
m_workload[push_pos] = cmd;
pos = m_workload.peek(); // ???
// Try to acquire a command
cmd = m_workload[pos].exchange({task::null});
}
while (true)
{
switch (cmd.type)
{
case task::null:
{
// Return immediately if can't process a command. Possible reasons:
// 1) The command has not yet been written
// 2) The command has already been acquired
return push_pos < pos;
}
case task::wait: op_wait(cmd.arg); break;
case task::poll: op_poll(cmd.arg); break;
case task::set: op_set(cmd.arg); break;
case task::clear: op_clear(cmd.arg); break;
case task::cancel: op_stop(vm::cast(cmd.arg), SCE_KERNEL_ERROR_WAIT_CANCEL); break;
case task::destroy: op_stop(vm::cast(cmd.arg), SCE_KERNEL_ERROR_WAIT_DELETE); break;
case task::signal:
{
idm::get<ARMv7Thread>(cmd.arg, [&](u32, ARMv7Thread& cpu)
{
cpu.state += cpu_state::signal;
cpu->lock_notify();
});
break;
}
default: ASSUME(0);
}
// Get next position
pos = m_workload.pop_end();
// Exit after the cleanup
if (LIKELY(!pos)) return true;
// Get next command
cmd = m_workload[pos].exchange({task::null});
}
}
// Enqueue a command and ensure its completion.
void sync(ARMv7Thread& cpu, task type, u32 arg)
{
if (UNLIKELY(!exec(type, arg)))
{
if (!exec(task::signal, cpu.id))
{
thread_lock{cpu}, thread_ctrl::wait(WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal)));
}
else
{
cpu.state -= cpu_state::signal;
}
}
}
private:
lf_fifo<atomic_t<cmd_t>, 16> m_workload;
// Check condition
void op_wait(u32 thread_id)
{
idm::get<ARMv7Thread>(thread_id, [&](u32, ARMv7Thread& cpu)
{
const u32 pattern = ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state) -> u32
{
const u32 pat = state.pattern;
if (pat_test(pat, cpu.GPR[1], cpu.GPR[0]))
{
state.pattern &= pat_clear(cpu.GPR[1], cpu.GPR[0]);
state.waiters -= attr & SCE_KERNEL_ATTR_MULTI ? 1 : cpu.id;
return pat;
}
return 0;
});
if (pattern)
{
cpu.GPR[0] = SCE_OK;
cpu.GPR[1] = pattern;
cpu.state += cpu_state::signal;
cpu->lock_notify();
}
else
{
cpu.owner = this;
cpu.GPR_D[1] = ++wait_ctr;
}
});
}
// Check condition
void op_poll(u32 thread_id)
{
idm::get<ARMv7Thread>(thread_id, [&](u32, ARMv7Thread& cpu)
{
cpu.GPR[1] = ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state) -> u32
{
const u32 pat = state.pattern;
if (pat_test(pat, cpu.GPR[1], cpu.GPR[0]))
{
state.pattern &= pat_clear(cpu.GPR[1], cpu.GPR[0]);
return pat;
}
return 0;
});
});
}
// Set pattern bits and wake up threads
void op_set(u32 pattern)
{
const auto new_state = ctrl.op_fetch([&](psp2_event_flag::ctrl_t& state)
{
state.pattern |= pattern;
});
if (new_state.waiters)
{
std::vector<std::reference_wrapper<ARMv7Thread>> threads;
// Check and lock appropriate threads
if (attr & SCE_KERNEL_ATTR_MULTI)
{
threads.reserve(new_state.waiters);
idm::select<ARMv7Thread>([&](u32 id, ARMv7Thread& cpu)
{
if (cpu->lock_if(WRAP_EXPR(cpu.owner == this && pat_test(new_state.pattern, cpu.GPR[1], cpu.GPR[0]))))
{
threads.emplace_back(cpu);
}
});
// Sort the thread list using appropriate scheduling policy
std::sort(threads.begin(), threads.end(), [&](const ARMv7Thread& cpu1, const ARMv7Thread& cpu2)
{
if (attr & SCE_KERNEL_ATTR_TH_PRIO && cpu1.prio != cpu2.prio)
{
return cpu1.prio < cpu2.prio;
}
else
{
return cpu1.GPR_D[1] < cpu2.GPR_D[1];
}
});
}
else
{
idm::get<ARMv7Thread>(new_state.waiters, [&](u32 id, ARMv7Thread& cpu)
{
if (cpu->lock_if(WRAP_EXPR(cpu.owner == this && pat_test(new_state.pattern, cpu.GPR[1], cpu.GPR[0]))))
{
threads.emplace_back(cpu);
}
});
}
// Wake up threads
for (ARMv7Thread& cpu : threads)
{
const u32 old_pattern = ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state) -> u32
{
const u32 pat = state.pattern;
if (pat_test(pat, cpu.GPR[1], cpu.GPR[0]))
{
state.pattern &= pat_clear(cpu.GPR[1], cpu.GPR[0]);
state.waiters -= attr & SCE_KERNEL_ATTR_MULTI ? 1 : cpu.id;
return pat;
}
return 0;
});
if (old_pattern)
{
cpu.GPR[0] = SCE_OK;
cpu.GPR[1] = old_pattern;
cpu.state += cpu_state::signal;
cpu.owner = nullptr;
cpu->unlock();
cpu->notify();
}
else
{
cpu->unlock();
}
}
}
}
// Clear pattern bits (bitwise AND)
void op_clear(u32 pattern)
{
ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state)
{
state.pattern &= pattern;
});
}
// Wake up all threads
void op_stop(vm::ptr<u32> ptr, s32 error)
{
s32 result = 0;
const u32 pattern = ptr ? ptr->value() : ctrl.load().pattern;
idm::select<ARMv7Thread>([&](u32, ARMv7Thread& cpu)
{
if (cpu->lock_if(WRAP_EXPR(cpu.owner == this)))
{
cpu.GPR[0] = error;
cpu.GPR[1] = pattern;
cpu.state += cpu_state::signal;
cpu.owner = nullptr;
cpu->unlock();
cpu->notify();
result++;
}
});
if (ptr)
{
*ptr = result;
}
ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state)
{
state.pattern = pattern;
state.waiters = attr & SCE_KERNEL_ATTR_MULTI ? state.waiters - result : 0;
});
}
};
template<> DECLARE(psp2_event_flag::ipc::g_ipc) {};
arm_error_code sceKernelCreateEventFlag(vm::cptr<char> pName, u32 attr, u32 initPattern, vm::cptr<SceKernelEventFlagOptParam> pOptParam)
{
sceLibKernel.error("sceKernelCreateEventFlag(pName=*0x%x, attr=0x%x, initPattern=0x%x, pOptParam=*0x%x)", pName, attr, initPattern, pOptParam);
return NOT_AN_ERROR(idm::make<psv_event_flag_t>(pName.get_ptr(), attr, initPattern));
// Create EVF
auto evf = std::make_shared<psp2_event_flag>(pName.get_ptr(), attr, initPattern);
// Try to register IPC name, only if not empty string (TODO)
if (evf->name.empty() || !psp2_event_flag::ipc::add(evf->name, WRAP_EXPR(evf))) evf->ipc_ref = 0;
// Register ID
return NOT_AN_ERROR(idm::import_existing(evf));
}
arm_error_code sceKernelDeleteEventFlag(s32 evfId)
{
sceLibKernel.error("sceKernelDeleteEventFlag(evfId=0x%x)", evfId);
const auto evf = idm::withdraw<psv_event_flag_t>(evfId);
const auto evf = idm::withdraw<psp2_event_flag>(evfId);
if (!evf)
{
@ -395,9 +711,15 @@ arm_error_code sceKernelDeleteEventFlag(s32 evfId)
}
// Unregister IPC name
if (evf->ref.atomic_op(ipc_ref_try_unregister))
if (evf->ipc_ref.fetch_op([](u32& ref) { if (ref) ref--; }))
{
evf->destroy();
psp2_event_flag::ipc::remove(evf->name);
}
// Finalize the last reference
if (!evf->ipc_ref)
{
evf->exec(psp2_event_flag::task::destroy, 0);
}
return SCE_OK;
@ -407,35 +729,32 @@ arm_error_code sceKernelOpenEventFlag(vm::cptr<char> pName)
{
sceLibKernel.error("sceKernelOpenEventFlag(pName=*0x%x)", pName);
// For now, go through all objects to find the name
for (const auto& data : idm::get_map<psv_event_flag_t>())
{
const auto& evf = data.second;
const auto evf = psp2_event_flag::ipc::get(pName.get_ptr());
if (evf->name == pName.get_ptr() && evf->ref.atomic_op(ipc_ref_try_inc))
{
return NOT_AN_ERROR(idm::import_existing(evf));
}
// Try to add IPC reference
if (!evf || !evf->ipc_ref.fetch_op([](u32& ref) { if (ref) ref++; }))
{
return SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME;
}
return SCE_KERNEL_ERROR_UID_CANNOT_FIND_BY_NAME;
return NOT_AN_ERROR(idm::import_existing(evf));
}
arm_error_code sceKernelCloseEventFlag(s32 evfId)
{
sceLibKernel.error("sceKernelCloseEventFlag(evfId=0x%x)", evfId);
const auto evf = idm::withdraw<psv_event_flag_t>(evfId);
const auto evf = idm::withdraw<psp2_event_flag>(evfId);
if (!evf)
if (!evf || !evf->ipc_ref)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
// Decrement IPC ref
if (evf->ref.atomic_op(ipc_ref_try_dec))
// Remove one IPC reference
if (!evf->ipc_ref.op_fetch([](u32& ref) { if (ref) ref--; }))
{
evf->destroy();
evf->exec(psp2_event_flag::task::destroy, 0);
}
return SCE_OK;
@ -448,52 +767,64 @@ arm_error_code sceKernelWaitEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPatter
const u64 start_time = pTimeout ? get_system_time() : 0;
const u32 timeout = pTimeout ? pTimeout->value() : 0;
const auto evf = idm::get<psv_event_flag_t>(evfId);
const auto evf = idm::get<psp2_event_flag>(evfId);
if (!evf)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
std::unique_lock<std::mutex> lock(evf->mutex);
const u32 result = evf->pattern.fetch_op(event_flag_try_poll, bitPattern, waitMode);
if (event_flag_test(result, bitPattern, waitMode))
// First chance
const auto state = evf->ctrl.fetch_op([&](psp2_event_flag::ctrl_t& state)
{
if (pResultPat) *pResultPat = result;
if (!state.waiters && psp2_event_flag::pat_test(state.pattern, bitPattern, waitMode))
{
state.pattern &= psp2_event_flag::pat_clear(bitPattern, waitMode);
}
else if (evf->attr & SCE_KERNEL_ATTR_MULTI)
{
state.waiters++;
}
else if (!state.waiters)
{
state.waiters = cpu.id;
}
});
if (state.waiters && !(evf->attr & SCE_KERNEL_ATTR_MULTI))
{
return SCE_KERNEL_ERROR_EVF_MULTI;
}
if (!state.waiters && psp2_event_flag::pat_test(state.pattern, bitPattern, waitMode))
{
if (pResultPat) *pResultPat = state.pattern;
return SCE_OK;
}
// fixup register values for external use
// Set register values for external use
cpu.GPR[0] = waitMode;
cpu.GPR[1] = bitPattern;
cpu.GPR[2] = waitMode;
// add waiter; attributes are ignored in current implementation
sleep_entry<cpu_thread> waiter(evf->sq, cpu);
while (!cpu.state.test_and_reset(cpu_state::signal))
// Second chance
if (evf->exec(psp2_event_flag::task::wait, cpu.id) && cpu.state.test_and_reset(cpu_state::signal))
{
CHECK_EMU_STATUS;
if (pResultPat) *pResultPat = cpu.GPR[1];
return SCE_OK;
}
if (pTimeout)
cpu_thread_lock entry(cpu);
if (!thread_ctrl::wait(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal))))
{
// Timeout cleanup
cpu.owner = nullptr;
cpu.GPR[0] = SCE_KERNEL_ERROR_WAIT_TIMEOUT;
cpu.GPR[1] = evf->ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state)
{
const u64 passed = get_system_time() - start_time;
if (passed >= timeout)
{
cpu.GPR[0] = SCE_KERNEL_ERROR_WAIT_TIMEOUT;
cpu.GPR[1] = evf->pattern;
break;
}
get_current_thread_cv().wait_for(lock, std::chrono::microseconds(timeout - passed));
}
else
{
get_current_thread_cv().wait(lock);
}
state.waiters -= evf->attr & SCE_KERNEL_ATTR_MULTI ? 1 : cpu.id;
return state.pattern;
});
}
if (pResultPat) *pResultPat = cpu.GPR[1];
@ -509,73 +840,63 @@ arm_error_code sceKernelWaitEventFlagCB(ARMv7Thread& cpu, s32 evfId, u32 bitPatt
return sceKernelWaitEventFlag(cpu, evfId, bitPattern, waitMode, pResultPat, pTimeout);
}
arm_error_code sceKernelPollEventFlag(s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr<u32> pResultPat)
arm_error_code sceKernelPollEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPattern, u32 waitMode, vm::ptr<u32> pResultPat)
{
sceLibKernel.error("sceKernelPollEventFlag(evfId=0x%x, bitPattern=0x%x, waitMode=0x%x, pResultPat=*0x%x)", evfId, bitPattern, waitMode, pResultPat);
const auto evf = idm::get<psv_event_flag_t>(evfId);
const auto evf = idm::get<psp2_event_flag>(evfId);
if (!evf)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
std::lock_guard<std::mutex> lock(evf->mutex);
const u32 result = evf->pattern.fetch_op(event_flag_try_poll, bitPattern, waitMode);
if (!event_flag_test(result, bitPattern, waitMode))
// First chance
const auto state = evf->ctrl.fetch_op([&](psp2_event_flag::ctrl_t& state)
{
return SCE_KERNEL_ERROR_EVENT_COND;
if (!state.waiters && psp2_event_flag::pat_test(state.pattern, bitPattern, waitMode))
{
state.pattern &= psp2_event_flag::pat_clear(bitPattern, waitMode);
}
});
if (psp2_event_flag::pat_test(state.pattern, bitPattern, waitMode))
{
if (!state.waiters)
{
*pResultPat = state.pattern;
return SCE_OK;
}
cpu.GPR[0] = waitMode;
cpu.GPR[1] = bitPattern;
evf->sync(cpu, psp2_event_flag::task::poll, cpu.id);
if (cpu.GPR[1])
{
*pResultPat = cpu.GPR[1];
return SCE_OK;
}
}
*pResultPat = result;
return SCE_OK;
return NOT_AN_ERROR(SCE_KERNEL_ERROR_EVENT_COND);
}
arm_error_code sceKernelSetEventFlag(s32 evfId, u32 bitPattern)
{
sceLibKernel.error("sceKernelSetEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern);
const auto evf = idm::get<psv_event_flag_t>(evfId);
const auto evf = idm::get<psp2_event_flag>(evfId);
if (!evf)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
std::lock_guard<std::mutex> lock(evf->mutex);
evf->pattern |= bitPattern;
auto pred = [&](cpu_thread* thread) -> bool
if (!evf->exec(psp2_event_flag::task::set, bitPattern))
{
auto& cpu = static_cast<ARMv7Thread&>(*thread);
// load pattern and mode from registers
const u32 pattern = cpu.GPR[1];
const u32 mode = cpu.GPR[2];
// check specific pattern
const u32 result = evf->pattern.fetch_op(event_flag_try_poll, pattern, mode);
if (event_flag_test(result, pattern, mode))
{
// save pattern
cpu.GPR[0] = SCE_OK;
cpu.GPR[1] = result;
thread->state += cpu_state::signal;
thread->notify();
return true;
}
return false;
};
// check all waiters; protocol is ignored in current implementation
evf->sq.erase(std::remove_if(evf->sq.begin(), evf->sq.end(), pred), evf->sq.end());
}
return SCE_OK;
}
@ -584,45 +905,34 @@ arm_error_code sceKernelClearEventFlag(s32 evfId, u32 bitPattern)
{
sceLibKernel.error("sceKernelClearEventFlag(evfId=0x%x, bitPattern=0x%x)", evfId, bitPattern);
const auto evf = idm::get<psv_event_flag_t>(evfId);
const auto evf = idm::get<psp2_event_flag>(evfId);
if (!evf)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
std::lock_guard<std::mutex> lock(evf->mutex);
evf->pattern &= ~bitPattern;
if (!evf->exec(psp2_event_flag::task::clear, bitPattern))
{
}
return SCE_OK;
}
arm_error_code sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr<s32> pNumWaitThreads)
arm_error_code sceKernelCancelEventFlag(ARMv7Thread& cpu, s32 evfId, u32 setPattern, vm::ptr<s32> pNumWaitThreads)
{
sceLibKernel.error("sceKernelCancelEventFlag(evfId=0x%x, setPattern=0x%x, pNumWaitThreads=*0x%x)", evfId, setPattern, pNumWaitThreads);
const auto evf = idm::get<psv_event_flag_t>(evfId);
const auto evf = idm::get<psp2_event_flag>(evfId);
if (!evf)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
std::lock_guard<std::mutex> lock(evf->mutex);
*pNumWaitThreads = setPattern;
for (auto& thread : evf->sq)
{
static_cast<ARMv7Thread&>(*thread).GPR[0] = SCE_KERNEL_ERROR_WAIT_CANCEL;
static_cast<ARMv7Thread&>(*thread).GPR[1] = setPattern;
thread->state += cpu_state::signal;
thread->notify();
}
*pNumWaitThreads = static_cast<u32>(evf->sq.size());
evf->pattern = setPattern;
evf->sq.clear();
evf->sync(cpu, psp2_event_flag::task::cancel, pNumWaitThreads.addr());
return SCE_OK;
}
@ -631,15 +941,13 @@ arm_error_code sceKernelGetEventFlagInfo(s32 evfId, vm::ptr<SceKernelEventFlagIn
{
sceLibKernel.error("sceKernelGetEventFlagInfo(evfId=0x%x, pInfo=*0x%x)", evfId, pInfo);
const auto evf = idm::get<psv_event_flag_t>(evfId);
const auto evf = idm::get<psp2_event_flag>(evfId);
if (!evf)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
std::lock_guard<std::mutex> lock(evf->mutex);
pInfo->size = SIZE_32(SceKernelEventFlagInfo);
pInfo->evfId = evfId;
@ -647,8 +955,11 @@ arm_error_code sceKernelGetEventFlagInfo(s32 evfId, vm::ptr<SceKernelEventFlagIn
pInfo->attr = evf->attr;
pInfo->initPattern = evf->init;
pInfo->currentPattern = evf->pattern;
pInfo->numWaitThreads = static_cast<u32>(evf->sq.size());
const auto state = evf->ctrl.load();
pInfo->currentPattern = state.pattern;
pInfo->numWaitThreads = evf->attr & SCE_KERNEL_ATTR_MULTI ? state.waiters : state.waiters != 0;
return SCE_OK;
}
@ -659,14 +970,14 @@ arm_error_code sceKernelCreateSema(vm::cptr<char> pName, u32 attr, s32 initCount
{
sceLibKernel.error("sceKernelCreateSema(pName=*0x%x, attr=0x%x, initCount=%d, maxCount=%d, pOptParam=*0x%x)", pName, attr, initCount, maxCount, pOptParam);
return NOT_AN_ERROR(idm::make<psv_semaphore_t>(pName.get_ptr(), attr, initCount, maxCount));
return NOT_AN_ERROR(idm::make<psp2_semaphore>(pName.get_ptr(), attr, initCount, maxCount));
}
arm_error_code sceKernelDeleteSema(s32 semaId)
{
sceLibKernel.error("sceKernelDeleteSema(semaId=0x%x)", semaId);
const auto sema = idm::withdraw<psv_semaphore_t>(semaId);
const auto sema = idm::withdraw<psp2_semaphore>(semaId);
if (!sema)
{
@ -692,7 +1003,7 @@ arm_error_code sceKernelWaitSema(s32 semaId, s32 needCount, vm::ptr<u32> pTimeou
{
sceLibKernel.error("sceKernelWaitSema(semaId=0x%x, needCount=%d, pTimeout=*0x%x)", semaId, needCount, pTimeout);
const auto sema = idm::get<psv_semaphore_t>(semaId);
const auto sema = idm::get<psp2_semaphore>(semaId);
if (!sema)
{
@ -735,14 +1046,14 @@ arm_error_code sceKernelCreateMutex(vm::cptr<char> pName, u32 attr, s32 initCoun
{
sceLibKernel.error("sceKernelCreateMutex(pName=*0x%x, attr=0x%x, initCount=%d, pOptParam=*0x%x)", pName, attr, initCount, pOptParam);
return NOT_AN_ERROR(idm::make<psv_mutex_t>(pName.get_ptr(), attr, initCount));
return NOT_AN_ERROR(idm::make<psp2_mutex>(pName.get_ptr(), attr, initCount));
}
arm_error_code sceKernelDeleteMutex(s32 mutexId)
{
sceLibKernel.error("sceKernelDeleteMutex(mutexId=0x%x)", mutexId);
const auto mutex = idm::withdraw<psv_mutex_t>(mutexId);
const auto mutex = idm::withdraw<psp2_mutex>(mutexId);
if (!mutex)
{
@ -842,21 +1153,21 @@ arm_error_code sceKernelCreateCond(vm::cptr<char> pName, u32 attr, s32 mutexId,
{
sceLibKernel.error("sceKernelCreateCond(pName=*0x%x, attr=0x%x, mutexId=0x%x, pOptParam=*0x%x)", pName, attr, mutexId, pOptParam);
const auto mutex = idm::get<psv_mutex_t>(mutexId);
const auto mutex = idm::get<psp2_mutex>(mutexId);
if (!mutex)
{
return SCE_KERNEL_ERROR_INVALID_UID;
}
return NOT_AN_ERROR(idm::make<psv_cond_t>(pName.get_ptr(), attr, mutex));
return NOT_AN_ERROR(idm::make<psp2_cond>(pName.get_ptr(), attr, mutex));
}
arm_error_code sceKernelDeleteCond(s32 condId)
{
sceLibKernel.error("sceKernelDeleteCond(condId=0x%x)", condId);
const auto cond = idm::withdraw<psv_cond_t>(condId);
const auto cond = idm::withdraw<psp2_cond>(condId);
if (!cond)
{
@ -1121,6 +1432,19 @@ s32 sceKernelGetRWLockInfo(s32 rwLockId, vm::ptr<SceKernelRWLockInfo> pInfo)
throw EXCEPTION("");
}
arm_error_code sceKernelGetThreadmgrUIDClass(s32 uid)
{
sceLibKernel.error("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid);
if (idm::check<ARMv7Thread>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_THREAD;
if (idm::check<psp2_semaphore>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_SEMA;
if (idm::check<psp2_event_flag>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG;
if (idm::check<psp2_mutex>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX;
if (idm::check<psp2_cond>(uid)) return SCE_KERNEL_THREADMGR_UID_CLASS_COND;
return SCE_KERNEL_ERROR_INVALID_UID;
}
// IO/File functions
s32 sceIoRemove(vm::cptr<char> filename)

View File

@ -1,10 +1,9 @@
#pragma once
#include "Utilities/SleepQueue.h"
#include "Emu/ARMv7/ErrorCodes.h"
#include "Emu/PSP2/ErrorCodes.h"
#include "Emu/PSP2/Modules/Common.h"
// Error Codes
enum SceLibKernelError : s32
{
SCE_KERNEL_ERROR_ERROR = ERROR_CODE(0x80020001),
@ -99,6 +98,7 @@ enum SceLibKernelError : s32
SCE_KERNEL_ERROR_ILLEGAL_SELF_HEADER = ERROR_CODE(0x80025002),
};
// Error Codes
enum SceLibKernelError0 : s32
{
SCE_KERNEL_ERROR_EXCPMGR_ERROR = ERROR_CODE(0x80027000),
@ -204,6 +204,7 @@ enum SceLibKernelError0 : s32
SCE_KERNEL_ERROR_RW_LOCK_FAILED_TO_UNLOCK = ERROR_CODE(0x80028046),
};
// Error Codes
enum SceLibKernelError1 : s32
{
SCE_KERNEL_ERROR_PROCESSMGR_ERROR = ERROR_CODE(0x80029000),
@ -535,7 +536,8 @@ inline const char* arm_error_code::print(SceLibKernelError1 error)
return nullptr;
}
enum psv_object_class_t : u32
// PSP2 UID Class
enum : u32
{
SCE_KERNEL_UID_CLASS_PROCESS = 0,
SCE_KERNEL_THREADMGR_UID_CLASS_THREAD = 1,
@ -589,6 +591,15 @@ struct SceKernelAllocMemBlockOpt
// Thread Manager definitions (threads)
enum
{
SCE_KERNEL_ATTR_TH_FIFO = 0,
SCE_KERNEL_ATTR_TH_PRIO = 0x2000,
SCE_KERNEL_ATTR_SINGLE = 0, // Event Flag only
SCE_KERNEL_ATTR_MULTI = 0x1000, // Event Flag only
};
using SceKernelThreadEntry = s32(u32 argSize, vm::ptr<void> pArgBlock);
struct SceKernelThreadOptParam
@ -727,78 +738,6 @@ struct SceKernelEventFlagInfo
le_t<s32> numWaitThreads;
};
struct psv_event_flag_t
{
const std::string name; // IPC Name
atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter
const u32 attr; // Event Flag Attributes
const u32 init; // Event Flag Init Pattern
atomic_t<u32> pattern; // Event Flag Pattern
std::mutex mutex;
sleep_queue<cpu_thread> sq;
psv_event_flag_t(const char* name, u32 attr, u32 pattern)
: name(name)
, attr(attr)
, init(pattern)
, pattern(pattern)
{
}
// Wakeup all waiters to return SCE_KERNEL_ERROR_WAIT_DELETE
void destroy()
{
std::lock_guard<std::mutex> lock(mutex);
const u32 pattern = this->pattern;
for (auto& thread : sq)
{
static_cast<ARMv7Thread&>(*thread).GPR[0] = SCE_KERNEL_ERROR_WAIT_DELETE;
static_cast<ARMv7Thread&>(*thread).GPR[1] = pattern;
thread->state += cpu_state::signal;
thread->notify();
}
}
};
inline bool event_flag_test(u32 value, u32 pattern, u32 mode)
{
if (mode & SCE_KERNEL_EVF_WAITMODE_OR)
{
return (value & pattern) != 0;
}
else
{
return (value & pattern) == pattern;
}
}
inline void event_flag_try_poll(u32& value, u32 pattern, u32 mode)
{
if (mode & ~7 || (mode & 6) == 6)
{
throw EXCEPTION("Unknown mode (0x%x)", mode);
}
if (event_flag_test(value, pattern, mode))
{
if (mode & SCE_KERNEL_EVF_WAITMODE_CLEAR_ALL)
{
value = 0;
}
else if (mode & SCE_KERNEL_EVF_WAITMODE_CLEAR_PAT)
{
value &= ~pattern;
}
}
}
// Thread Manager definitions (semaphores)
struct SceKernelSemaOptParam
@ -818,18 +757,18 @@ struct SceKernelSemaInfo
le_t<s32> numWaitThreads;
};
struct psv_semaphore_t
struct psp2_semaphore
{
const std::string name; // IPC Name
atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter
atomic_t<u32> ref{}; // IPC Ref Counter
const u32 attr;
const s32 max;
atomic_t<s32> count;
psv_semaphore_t(const char* name, u32 attr, s32 count, s32 max)
psp2_semaphore(const char* name, u32 attr, s32 count, s32 max)
: name(name)
, attr(attr)
, max(max)
@ -858,17 +797,17 @@ struct SceKernelMutexInfo
le_t<s32> numWaitThreads;
};
struct psv_mutex_t
struct psp2_mutex
{
const std::string name; // IPC Name
atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter
atomic_t<u32> ref{}; // IPC Ref Counter
const u32 attr;
atomic_t<s32> count;
psv_mutex_t(const char* name, u32 attr, s32 count)
psp2_mutex(const char* name, u32 attr, s32 count)
: name(name)
, attr(attr)
, count(count)
@ -918,17 +857,17 @@ struct SceKernelCondInfo
le_t<u32> numWaitThreads;
};
struct psv_cond_t
struct psp2_cond
{
const std::string name; // IPC Name
atomic_t<u32> ref{ 0x80000000 }; // IPC Ref Counter
atomic_t<u32> ref{}; // IPC Ref Counter
const u32 attr;
const std::shared_ptr<psv_mutex_t> mutex;
const std::shared_ptr<psp2_mutex> mutex;
psv_cond_t(const char* name, u32 attr, const std::shared_ptr<psv_mutex_t>& mutex)
psp2_cond(const char* name, u32 attr, const std::shared_ptr<psp2_mutex>& mutex)
: name(name)
, attr(attr)
, mutex(mutex)
@ -1022,47 +961,3 @@ struct SceIoDirent
vm::lptr<void> d_private;
le_t<s32> dummy;
};
// Module
// Aux
inline bool ipc_ref_try_dec(u32& ref)
{
if (ref & 0x7fffffff)
{
// return true if the last reference is removed and object must be deleted
return !--ref;
}
else
{
throw EXCEPTION("Unexpected IPC Ref value (0x%x)", ref);
}
}
inline bool ipc_ref_try_inc(u32& ref)
{
if (ref & 0x80000000)
{
if (!++ref)
{
throw EXCEPTION("IPC Ref overflow");
}
return true;
}
return false;
}
inline bool ipc_ref_try_unregister(u32& ref)
{
if (ref & 0x80000000)
{
ref &= ~0x80000000;
// return true if object must be deleted
return !ref;
}
throw EXCEPTION("Unexpected IPC Ref value (0x%x)", ref);
}

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceLibXml.h"
LOG_CHANNEL(sceLibXml);
logs::channel sceLibXml("sceLibXml", logs::level::notice);
#define REG_FUNC(nid, name) REG_FNID(SceLibXml, nid, name)

View File

@ -1,12 +1,14 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/ARMv7Callback.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Thread.h"
#include "Emu/PSP2/ARMv7Callback.h"
#include "sceLibc.h"
LOG_CHANNEL(sceLibc);
#include <thread>
logs::channel sceLibc("sceLibc", logs::level::notice);
extern fs::file g_tty;
@ -15,8 +17,6 @@ vm::ptr<void> g_dso;
std::vector<std::function<void(ARMv7Thread&)>> g_atexit;
std::mutex g_atexit_mutex;
std::string arm_fmt(ARMv7Thread& cpu, vm::cptr<char> fmt, u32 g_count)
{
std::string result;
@ -132,7 +132,7 @@ std::string arm_fmt(ARMv7Thread& cpu, vm::cptr<char> fmt, u32 g_count)
case 's':
{
// string
const vm::cptr<char> string{ cpu.get_next_gpr_arg(g_count), vm::addr };
const vm::cptr<char> string = vm::cast(cpu.get_next_gpr_arg(g_count));
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
@ -157,8 +157,6 @@ namespace sce_libc_func
{
sceLibc.warning("__cxa_atexit(func=*0x%x, arg=*0x%x, dso=*0x%x)", func, arg, dso);
std::lock_guard<std::mutex> lock(g_atexit_mutex);
g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Thread& cpu)
{
func(cpu, arg);
@ -169,8 +167,6 @@ namespace sce_libc_func
{
sceLibc.warning("__aeabi_atexit(arg=*0x%x, func=*0x%x, dso=*0x%x)", arg, func, dso);
std::lock_guard<std::mutex> lock(g_atexit_mutex);
g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Thread& cpu)
{
func(cpu, arg);
@ -181,8 +177,6 @@ namespace sce_libc_func
{
sceLibc.warning("exit()");
std::lock_guard<std::mutex> lock(g_atexit_mutex);
CHECK_EMU_STATUS;
for (auto& func : decltype(g_atexit)(std::move(g_atexit)))

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceLibm.h"
LOG_CHANNEL(sceLibm);
logs::channel sceLibm("sceLibm", logs::level::notice);
namespace sce_libm_func
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceLibstdcxx.h"
LOG_CHANNEL(sceLibstdcxx);
logs::channel sceLibstdcxx("sceLibstdcxx", logs::level::notice);
namespace sce_libstdcxx_func
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceLiveArea.h"
LOG_CHANNEL(sceLiveArea);
logs::channel sceLiveArea("sceLiveArea", logs::level::notice);
s32 sceLiveAreaResourceReplaceAll(vm::cptr<char> dirpath)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceLocation.h"
LOG_CHANNEL(sceLocation);
logs::channel sceLocation("sceLocation", logs::level::notice);
s32 sceLocationOpen(vm::ptr<u8> handle, SceLocationLocationMethod lmethod, SceLocationHeadingMethod hmethod)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceMd5.h"
LOG_CHANNEL(sceMd5);
logs::channel sceMd5("sceMd5", logs::level::notice);
s32 sceMd5Digest(vm::cptr<void> plain, u32 len, vm::ptr<u8> digest)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceMotion.h"
LOG_CHANNEL(sceMotion);
logs::channel sceMotion("sceMotion", logs::level::notice);
s32 sceMotionGetState(vm::ptr<SceMotionState> motionState)
{

View File

@ -1,5 +1,7 @@
#pragma once
#include "Common.h"
struct SceMotionState
{
le_t<u32> timestamp;

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceMt19937.h"
LOG_CHANNEL(sceMt19937);
logs::channel sceMt19937("sceMt19937", logs::level::notice);
s32 sceMt19937Init(vm::ptr<SceMt19937Context> pCtx, u32 seed)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNet.h"
LOG_CHANNEL(sceNet);
logs::channel sceNet("sceNet", logs::level::notice);
s32 sceNetSetDnsInfo(vm::ptr<SceNetDnsInfo> info, s32 flags)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNetCtl.h"
LOG_CHANNEL(sceNetCtl);
logs::channel sceNetCtl("sceNetCtl", logs::level::notice);
s32 sceNetCtlInit()
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNgs.h"
LOG_CHANNEL(sceNgs);
logs::channel sceNgs("sceNgs", logs::level::notice);
s32 sceNgsSystemGetRequiredMemorySize(vm::cptr<SceNgsSystemInitParams> pSynthParams, vm::ptr<u32> pnSize)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNpBasic.h"
LOG_CHANNEL(sceNpBasic);
logs::channel sceNpBasic("sceNpBasic", logs::level::notice);
s32 sceNpBasicInit(vm::ptr<void> opt)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNpCommon.h"
LOG_CHANNEL(sceNpCommon);
logs::channel sceNpCommon("sceNpCommon", logs::level::notice);
s32 sceNpAuthInit()
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNpManager.h"
LOG_CHANNEL(sceNpManager);
logs::channel sceNpManager("sceNpManager", logs::level::notice);
s32 sceNpInit(vm::cptr<SceNpCommunicationConfig> commConf, vm::ptr<SceNpOptParam> opt)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNpMatching.h"
LOG_CHANNEL(sceNpMatching);
logs::channel sceNpMatching("sceNpMatching", logs::level::notice);
// Functions

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNpScore.h"
LOG_CHANNEL(sceNpScore);
logs::channel sceNpScore("sceNpScore", logs::level::notice);
s32 sceNpScoreInit(s32 threadPriority, s32 cpuAffinityMask, vm::ptr<void> option)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "sceNpUtility.h"
LOG_CHANNEL(sceNpUtility);
logs::channel sceNpUtility("sceNpUtility", logs::level::notice);
s32 sceNpLookupInit(s32 usesAsync, s32 threadPriority, s32 cpuAffinityMask, vm::ptr<void> option)
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "scePerf.h"
LOG_CHANNEL(scePerf);
logs::channel scePerf("scePerf", logs::level::notice);
extern u64 get_system_time();
@ -12,7 +12,7 @@ arm_error_code scePerfArmPmonReset(ARMv7Thread& cpu, s32 threadId)
{
scePerf.warning("scePerfArmPmonReset(threadId=0x%x)", threadId);
ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
VERIFY(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
cpu.counters = {};
@ -23,7 +23,7 @@ arm_error_code scePerfArmPmonSelectEvent(ARMv7Thread& cpu, s32 threadId, u32 cou
{
scePerf.warning("scePerfArmPmonSelectEvent(threadId=0x%x, counter=0x%x, eventCode=0x%x)", threadId, counter, eventCode);
ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
VERIFY(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
if (counter >= 6)
{
@ -72,7 +72,7 @@ arm_error_code scePerfArmPmonStart(ARMv7Thread& cpu, s32 threadId)
{
scePerf.warning("scePerfArmPmonStart(threadId=0x%x)", threadId);
ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
VERIFY(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
return SCE_OK;
}
@ -81,7 +81,7 @@ arm_error_code scePerfArmPmonStop(ARMv7Thread& cpu, s32 threadId)
{
scePerf.warning("scePerfArmPmonStop(threadId=0x%x)");
ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
VERIFY(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
return SCE_OK;
}
@ -90,7 +90,7 @@ arm_error_code scePerfArmPmonGetCounterValue(ARMv7Thread& cpu, s32 threadId, u32
{
scePerf.warning("scePerfArmPmonGetCounterValue(threadId=0x%x, counter=%d, pValue=*0x%x)", threadId, counter, pValue);
ASSERT(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
VERIFY(threadId == SCE_PERF_ARM_PMON_THREAD_ID_SELF);
if (counter >= 6 && counter != SCE_PERF_ARM_PMON_CYCLE_COUNTER)
{

View File

@ -1,6 +1,6 @@
#pragma once
#include "Emu/ARMv7/ErrorCodes.h"
#include "Emu/PSP2/ErrorCodes.h"
enum ScePerfError : s32
{

View File

@ -1,10 +1,10 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/ARMv7/ARMv7Module.h"
#include "Emu/PSP2/ARMv7Module.h"
#include "scePgf.h"
LOG_CHANNEL(scePgf);
logs::channel scePgf("scePgf", logs::level::notice);
#define REG_FUNC(nid, name) REG_FNID(ScePgf, nid, name)

Some files were not shown because too many files have changed in this diff Show More