Partial commit: Modules

This commit is contained in:
Nekotekina 2016-03-21 22:42:14 +03:00
parent 2553e45d76
commit 7e30a0f464
46 changed files with 1021 additions and 2710 deletions

View File

@ -0,0 +1,654 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "cellAudio.h"
#include "libmixer.h"
LOG_CHANNEL(libmixer);
// TODO: use fxm
SurMixerConfig g_surmx;
std::vector<SSPlayer> g_ssp;
s32 cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr<float> addr, u32 samples)
{
libmixer.trace("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d)", aan_handle, aan_port, offset, addr, samples);
u32 type = aan_port >> 16;
u32 port = aan_port & 0xffff;
switch (type)
{
case CELL_SURMIXER_CHSTRIP_TYPE1A:
if (port >= g_surmx.ch_strips_1) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE2A:
if (port >= g_surmx.ch_strips_2) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE6A:
if (port >= g_surmx.ch_strips_6) type = 0; break;
case CELL_SURMIXER_CHSTRIP_TYPE8A:
if (port >= g_surmx.ch_strips_8) type = 0; break;
default:
type = 0; break;
}
if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0)
{
libmixer.error("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d): invalid parameters", aan_handle, aan_port, offset, addr, samples);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (type == CELL_SURMIXER_CHSTRIP_TYPE1A)
{
// mono upmixing
for (u32 i = 0; i < samples; i++)
{
const float center = addr[i];
g_surmx.mixdata[i * 8 + 0] += center;
g_surmx.mixdata[i * 8 + 1] += center;
}
}
else if (type == CELL_SURMIXER_CHSTRIP_TYPE2A)
{
// stereo upmixing
for (u32 i = 0; i < samples; i++)
{
const float left = addr[i * 2 + 0];
const float right = addr[i * 2 + 1];
g_surmx.mixdata[i * 8 + 0] += left;
g_surmx.mixdata[i * 8 + 1] += right;
}
}
else if (type == CELL_SURMIXER_CHSTRIP_TYPE6A)
{
// 5.1 upmixing
for (u32 i = 0; i < samples; i++)
{
const float left = addr[i * 6 + 0];
const float right = addr[i * 6 + 1];
const float center = addr[i * 6 + 2];
const float low_freq = addr[i * 6 + 3];
const float rear_left = addr[i * 6 + 4];
const float rear_right = addr[i * 6 + 5];
g_surmx.mixdata[i * 8 + 0] += left;
g_surmx.mixdata[i * 8 + 1] += right;
g_surmx.mixdata[i * 8 + 2] += center;
g_surmx.mixdata[i * 8 + 3] += low_freq;
g_surmx.mixdata[i * 8 + 4] += rear_left;
g_surmx.mixdata[i * 8 + 5] += rear_right;
}
}
else if (type == CELL_SURMIXER_CHSTRIP_TYPE8A)
{
// 7.1
for (u32 i = 0; i < samples * 8; i++)
{
g_surmx.mixdata[i] += addr[i];
}
}
return CELL_OK;
}
s32 cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo)
{
libmixer.warning("cellAANConnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)",
receive, receivePortNo, source, sourcePortNo);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (source >= g_ssp.size() || !g_ssp[source].m_created)
{
libmixer.error("cellAANConnect(): invalid source (%d)", source);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
g_ssp[source].m_connected = true;
return CELL_OK;
}
s32 cellAANDisconnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo)
{
libmixer.warning("cellAANDisconnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)",
receive, receivePortNo, source, sourcePortNo);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (source >= g_ssp.size() || !g_ssp[source].m_created)
{
libmixer.error("cellAANDisconnect(): invalid source (%d)", source);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
g_ssp[source].m_connected = false;
return CELL_OK;
}
s32 cellSSPlayerCreate(vm::ptr<u32> handle, vm::ptr<CellSSPlayerConfig> config)
{
libmixer.warning("cellSSPlayerCreate(handle=*0x%x, config=*0x%x)", handle, config);
if (config->outputMode != 0 || config->channels - 1 >= 2)
{
libmixer.error("cellSSPlayerCreate(config.outputMode=%d, config.channels=%d): invalid parameters", config->outputMode, config->channels);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
std::lock_guard<std::mutex> lock(g_surmx.mutex);
SSPlayer p;
p.m_created = true;
p.m_connected = false;
p.m_active = false;
p.m_channels = config->channels;
g_ssp.push_back(p);
*handle = (u32)g_ssp.size() - 1;
return CELL_OK;
}
s32 cellSSPlayerRemove(u32 handle)
{
libmixer.warning("cellSSPlayerRemove(handle=0x%x)", handle);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (handle >= g_ssp.size() || !g_ssp[handle].m_created)
{
libmixer.error("cellSSPlayerRemove(): SSPlayer not found (%d)", handle);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
g_ssp[handle].m_active = false;
g_ssp[handle].m_created = false;
g_ssp[handle].m_connected = false;
return CELL_OK;
}
s32 cellSSPlayerSetWave(u32 handle, vm::ptr<CellSSPlayerWaveParam> waveInfo, vm::ptr<CellSSPlayerCommonParam> commonInfo)
{
libmixer.warning("cellSSPlayerSetWave(handle=0x%x, waveInfo=*0x%x, commonInfo=*0x%x)", handle, waveInfo, commonInfo);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (handle >= g_ssp.size() || !g_ssp[handle].m_created)
{
libmixer.error("cellSSPlayerSetWave(): SSPlayer not found (%d)", handle);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
// TODO: check parameters
g_ssp[handle].m_addr = waveInfo->addr;
g_ssp[handle].m_samples = waveInfo->samples;
g_ssp[handle].m_loop_start = waveInfo->loopStartOffset - 1;
g_ssp[handle].m_loop_mode = commonInfo ? (u32)commonInfo->loopMode : CELL_SSPLAYER_ONESHOT;
g_ssp[handle].m_position = waveInfo->startOffset - 1;
return CELL_OK;
}
s32 cellSSPlayerPlay(u32 handle, vm::ptr<CellSSPlayerRuntimeInfo> info)
{
libmixer.warning("cellSSPlayerPlay(handle=0x%x, info=*0x%x)", handle, info);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (handle >= g_ssp.size() || !g_ssp[handle].m_created)
{
libmixer.error("cellSSPlayerPlay(): SSPlayer not found (%d)", handle);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
// TODO: check parameters
g_ssp[handle].m_active = true;
g_ssp[handle].m_level = info->level;
g_ssp[handle].m_speed = info->speed;
g_ssp[handle].m_x = info->position.x;
g_ssp[handle].m_y = info->position.y;
g_ssp[handle].m_z = info->position.z;
return CELL_OK;
}
s32 cellSSPlayerStop(u32 handle, u32 mode)
{
libmixer.warning("cellSSPlayerStop(handle=0x%x, mode=0x%x)", handle, mode);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (handle >= g_ssp.size() || !g_ssp[handle].m_created)
{
libmixer.error("cellSSPlayerStop(): SSPlayer not found (%d)", handle);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
// TODO: transition to stop state
g_ssp[handle].m_active = false;
return CELL_OK;
}
s32 cellSSPlayerSetParam(u32 handle, vm::ptr<CellSSPlayerRuntimeInfo> info)
{
libmixer.warning("cellSSPlayerSetParam(handle=0x%x, info=*0x%x)", handle, info);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (handle >= g_ssp.size() || !g_ssp[handle].m_created)
{
libmixer.error("cellSSPlayerSetParam(): SSPlayer not found (%d)", handle);
return CELL_LIBMIXER_ERROR_INVALID_PARAMATER;
}
// TODO: check parameters
g_ssp[handle].m_level = info->level;
g_ssp[handle].m_speed = info->speed;
g_ssp[handle].m_x = info->position.x;
g_ssp[handle].m_y = info->position.y;
g_ssp[handle].m_z = info->position.z;
return CELL_OK;
}
s32 cellSSPlayerGetState(u32 handle)
{
libmixer.warning("cellSSPlayerGetState(handle=0x%x)", handle);
std::lock_guard<std::mutex> lock(g_surmx.mutex);
if (handle >= g_ssp.size() || !g_ssp[handle].m_created)
{
libmixer.warning("cellSSPlayerGetState(): SSPlayer not found (%d)", handle);
return CELL_SSPLAYER_STATE_ERROR;
}
if (g_ssp[handle].m_active)
{
return CELL_SSPLAYER_STATE_ON;
}
return CELL_SSPLAYER_STATE_OFF;
}
s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
{
libmixer.warning("cellSurMixerCreate(config=*0x%x)", config);
const auto g_audio = fxm::get<audio_config>();
const auto port = g_audio->open_port();
if (!port)
{
return CELL_LIBMIXER_ERROR_FULL;
}
g_surmx.audio_port = port->number;
g_surmx.priority = config->priority;
g_surmx.ch_strips_1 = config->chStrips1;
g_surmx.ch_strips_2 = config->chStrips2;
g_surmx.ch_strips_6 = config->chStrips6;
g_surmx.ch_strips_8 = config->chStrips8;
port->channel = 8;
port->block = 16;
port->attr = 0;
port->size = port->channel * port->block * AUDIO_SAMPLES * sizeof(float);
port->tag = 0;
port->level = 1.0f;
port->level_set.store({ 1.0f, 0.0f });
libmixer.warning("*** audio port opened (port=%d)", g_surmx.audio_port);
g_surmx.mixcount = 0;
g_surmx.cb = vm::null;
g_ssp.clear();
libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8);
const auto ppu = idm::make_ptr<PPUThread>("Surmixer Thread");
ppu->prio = 1001;
ppu->stack_size = 0x10000;
ppu->custom_task = [g_audio](PPUThread& ppu)
{
audio_port& port = g_audio->ports[g_surmx.audio_port];
while (port.state != audio_port_state::closed)
{
CHECK_EMU_STATUS;
if (g_surmx.mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
if (port.state == audio_port_state::started)
{
//u64 stamp0 = get_system_time();
memset(g_surmx.mixdata, 0, sizeof(g_surmx.mixdata));
if (g_surmx.cb)
{
g_surmx.cb(ppu, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256);
}
//u64 stamp1 = get_system_time();
{
std::lock_guard<std::mutex> lock(g_surmx.mutex);
for (auto& p : g_ssp) if (p.m_active && p.m_created)
{
auto v = vm::ptrl<s16>::make(p.m_addr); // 16-bit LE audio data
float left = 0.0f;
float right = 0.0f;
float speed = fabs(p.m_speed);
float fpos = 0.0f;
for (s32 i = 0; i < 256; i++) if (p.m_active)
{
u32 pos = p.m_position;
s32 pos_inc = 0;
if (p.m_speed > 0.0f) // select direction
{
pos_inc = 1;
}
else if (p.m_speed < 0.0f)
{
pos_inc = -1;
}
s32 shift = i - (int)fpos; // change playback speed (simple and rough)
if (shift > 0)
{
// slow playback
pos_inc = 0; // duplicate one sample at this time
fpos += 1.0f;
fpos += speed;
}
else if (shift < 0)
{
// fast playback
i--; // mix two sample into one at this time
fpos -= 1.0f;
}
else
{
fpos += speed;
}
p.m_position += (u32)pos_inc;
if (p.m_channels == 1) // get mono data
{
left = right = (float)v[pos] / 0x8000 * p.m_level;
}
else if (p.m_channels == 2) // get stereo data
{
left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level;
right = (float)v[pos * 2 + 1] / 0x8000 * p.m_level;
}
if (p.m_connected) // mix
{
// TODO: m_x, m_y, m_z ignored
g_surmx.mixdata[i * 8 + 0] += left;
g_surmx.mixdata[i * 8 + 1] += right;
}
if ((p.m_position == p.m_samples && p.m_speed > 0.0f) ||
(p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop
{
if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON)
{
p.m_position = p.m_loop_start;
}
else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT)
{
p.m_position -= (u32)pos_inc; // restore position
}
else // oneshot
{
p.m_active = false;
p.m_position = p.m_loop_start; // TODO: check value
}
}
}
}
}
//u64 stamp2 = get_system_time();
auto buf = vm::_ptr<f32>(port.addr.addr() + (g_surmx.mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float));
for (auto& mixdata : g_surmx.mixdata)
{
// reverse byte order
*buf++ = mixdata;
}
//u64 stamp3 = get_system_time();
//ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2);
}
g_surmx.mixcount++;
}
idm::remove<PPUThread>(ppu.id);
};
ppu->cpu_init();
ppu->state -= cpu_state::stop;
ppu->safe_notify();
return CELL_OK;
}
s32 cellSurMixerGetAANHandle(vm::ptr<u32> handle)
{
libmixer.warning("cellSurMixerGetAANHandle(handle=*0x%x) -> %d", handle, 0x11111111);
*handle = 0x11111111;
return CELL_OK;
}
s32 cellSurMixerChStripGetAANPortNo(vm::ptr<u32> port, u32 type, u32 index)
{
libmixer.warning("cellSurMixerChStripGetAANPortNo(port=*0x%x, type=0x%x, index=0x%x) -> 0x%x", port, type, index, (type << 16) | index);
*port = (type << 16) | index;
return CELL_OK;
}
s32 cellSurMixerSetNotifyCallback(vm::ptr<CellSurMixerNotifyCallbackFunction> func, vm::ptr<void> arg)
{
libmixer.warning("cellSurMixerSetNotifyCallback(func=*0x%x, arg=*0x%x)", func, arg);
if (g_surmx.cb)
{
throw EXCEPTION("Callback already set");
}
g_surmx.cb = func;
g_surmx.cb_arg = arg;
return CELL_OK;
}
s32 cellSurMixerRemoveNotifyCallback(vm::ptr<CellSurMixerNotifyCallbackFunction> func)
{
libmixer.warning("cellSurMixerRemoveNotifyCallback(func=*0x%x)", func);
if (g_surmx.cb != func)
{
throw EXCEPTION("Callback not set");
}
g_surmx.cb = vm::null;
return CELL_OK;
}
s32 cellSurMixerStart()
{
libmixer.warning("cellSurMixerStart()");
const auto g_audio = fxm::get<audio_config>();
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
{
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
}
g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::opened, audio_port_state::started);
return CELL_OK;
}
s32 cellSurMixerSetParameter(u32 param, float value)
{
libmixer.todo("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value);
return CELL_OK;
}
s32 cellSurMixerFinalize()
{
libmixer.warning("cellSurMixerFinalize()");
const auto g_audio = fxm::get<audio_config>();
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
{
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
}
g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::opened, audio_port_state::closed);
return CELL_OK;
}
s32 cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr<float> addr, u32 samples)
{
if (busNo < 8 && samples == 256 && offset == 0)
{
libmixer.trace("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples);
}
else
{
libmixer.todo("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples);
return CELL_OK;
}
std::lock_guard<std::mutex> lock(g_surmx.mutex);
for (u32 i = 0; i < samples; i++)
{
// reverse byte order and mix
g_surmx.mixdata[i * 8 + busNo] += addr[i];
}
return CELL_OK;
}
s32 cellSurMixerChStripSetParameter(u32 type, u32 index, vm::ptr<CellSurMixerChStripParam> param)
{
libmixer.todo("cellSurMixerChStripSetParameter(type=%d, index=%d, param=*0x%x)", type, index, param);
return CELL_OK;
}
s32 cellSurMixerPause(u32 type)
{
libmixer.warning("cellSurMixerPause(type=%d)", type);
const auto g_audio = fxm::get<audio_config>();
if (g_surmx.audio_port >= AUDIO_PORT_COUNT)
{
return CELL_LIBMIXER_ERROR_NOT_INITIALIZED;
}
g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::started, audio_port_state::opened);
return CELL_OK;
}
s32 cellSurMixerGetCurrentBlockTag(vm::ptr<u64> tag)
{
libmixer.trace("cellSurMixerGetCurrentBlockTag(tag=*0x%x)", tag);
*tag = g_surmx.mixcount;
return CELL_OK;
}
s32 cellSurMixerGetTimestamp(u64 tag, vm::ptr<u64> stamp)
{
libmixer.trace("cellSurMixerGetTimestamp(tag=0x%llx, stamp=*0x%x)", tag, stamp);
const auto g_audio = fxm::get<audio_config>();
*stamp = g_audio->start_time + (tag) * 256000000 / 48000; // ???
return CELL_OK;
}
void cellSurMixerBeep(u32 arg)
{
libmixer.todo("cellSurMixerBeep(arg=%d)", arg);
return;
}
f32 cellSurMixerUtilGetLevelFromDB(f32 dB)
{
libmixer.todo("cellSurMixerUtilGetLevelFromDB(dB=%f)", dB);
throw EXCEPTION("TODO");
}
f32 cellSurMixerUtilGetLevelFromDBIndex(s32 index)
{
libmixer.todo("cellSurMixerUtilGetLevelFromDBIndex(index=%d)", index);
throw EXCEPTION("TODO");
}
f32 cellSurMixerUtilNoteToRatio(u8 refNote, u8 note)
{
libmixer.todo("cellSurMixerUtilNoteToRatio(refNote=%d, note=%d)", refNote, note);
throw EXCEPTION("TODO");
}
DECLARE(ppu_module_manager::libmixer)("libmixer", []()
{
REG_FUNC(libmixer, cellAANAddData);
REG_FUNC(libmixer, cellAANConnect);
REG_FUNC(libmixer, cellAANDisconnect);
REG_FUNC(libmixer, cellSurMixerCreate);
REG_FUNC(libmixer, cellSurMixerGetAANHandle);
REG_FUNC(libmixer, cellSurMixerChStripGetAANPortNo);
REG_FUNC(libmixer, cellSurMixerSetNotifyCallback);
REG_FUNC(libmixer, cellSurMixerRemoveNotifyCallback);
REG_FUNC(libmixer, cellSurMixerStart);
REG_FUNC(libmixer, cellSurMixerSetParameter);
REG_FUNC(libmixer, cellSurMixerFinalize);
REG_FUNC(libmixer, cellSurMixerSurBusAddData);
REG_FUNC(libmixer, cellSurMixerChStripSetParameter);
REG_FUNC(libmixer, cellSurMixerPause);
REG_FUNC(libmixer, cellSurMixerGetCurrentBlockTag);
REG_FUNC(libmixer, cellSurMixerGetTimestamp);
REG_FUNC(libmixer, cellSurMixerBeep);
REG_FUNC(libmixer, cellSSPlayerCreate);
REG_FUNC(libmixer, cellSSPlayerRemove);
REG_FUNC(libmixer, cellSSPlayerSetWave);
REG_FUNC(libmixer, cellSSPlayerPlay);
REG_FUNC(libmixer, cellSSPlayerStop);
REG_FUNC(libmixer, cellSSPlayerSetParam);
REG_FUNC(libmixer, cellSSPlayerGetState);
REG_FUNC(libmixer, cellSurMixerUtilGetLevelFromDB);
REG_FUNC(libmixer, cellSurMixerUtilGetLevelFromDBIndex);
REG_FUNC(libmixer, cellSurMixerUtilNoteToRatio);
});

View File

@ -1,9 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "libsnd3.h"
LOG_CHANNEL(libsnd3);
s32 cellSnd3Init(u32 maxVoice, u32 samples, vm::ptr<CellSnd3RequestQueueCtx> queue)
{
UNIMPLEMENTED_FUNC(libsnd3);
@ -290,56 +291,56 @@ s32 cellSnd3SMFGetKeyOnID(u32 smfID, u32 midiChannel, vm::ptr<u32> keyOnID)
}
Module<> libsnd3("libsnd3", []()
DECLARE(ppu_module_manager::libsnd3)("libsnd3", []()
{
REG_SUB(libsnd3,, cellSnd3Init);
REG_SUB(libsnd3,, cellSnd3Exit);
REG_SUB(libsnd3,, cellSnd3Note2Pitch);
REG_SUB(libsnd3,, cellSnd3Pitch2Note);
REG_SUB(libsnd3,, cellSnd3SetOutputMode);
REG_SUB(libsnd3,, cellSnd3Synthesis);
REG_SUB(libsnd3,, cellSnd3SynthesisEx);
REG_SUB(libsnd3,, cellSnd3BindSoundData);
REG_SUB(libsnd3,, cellSnd3UnbindSoundData);
REG_SUB(libsnd3,, cellSnd3NoteOnByTone);
REG_SUB(libsnd3,, cellSnd3KeyOnByTone);
REG_SUB(libsnd3,, cellSnd3VoiceNoteOnByTone);
REG_SUB(libsnd3,, cellSnd3VoiceKeyOnByTone);
REG_SUB(libsnd3,, cellSnd3VoiceSetReserveMode);
REG_SUB(libsnd3,, cellSnd3VoiceSetSustainHold);
REG_SUB(libsnd3,, cellSnd3VoiceKeyOff);
REG_SUB(libsnd3,, cellSnd3VoiceSetPitch);
REG_SUB(libsnd3,, cellSnd3VoiceSetVelocity);
REG_SUB(libsnd3,, cellSnd3VoiceSetPanpot);
REG_SUB(libsnd3,, cellSnd3VoiceSetPanpotEx);
REG_SUB(libsnd3,, cellSnd3VoiceSetPitchBend);
REG_SUB(libsnd3,, cellSnd3VoiceAllKeyOff);
REG_SUB(libsnd3,, cellSnd3VoiceGetEnvelope);
REG_SUB(libsnd3,, cellSnd3VoiceGetStatus);
REG_SUB(libsnd3,, cellSnd3KeyOffByID);
REG_SUB(libsnd3,, cellSnd3GetVoice);
REG_SUB(libsnd3,, cellSnd3GetVoiceByID);
REG_SUB(libsnd3,, cellSnd3NoteOn);
REG_SUB(libsnd3,, cellSnd3NoteOff);
REG_SUB(libsnd3,, cellSnd3SetSustainHold);
REG_SUB(libsnd3,, cellSnd3SetEffectType);
REG_SUB(libsnd3,, cellSnd3SMFBind);
REG_SUB(libsnd3,, cellSnd3SMFUnbind);
REG_SUB(libsnd3,, cellSnd3SMFPlay);
REG_SUB(libsnd3,, cellSnd3SMFPlayEx);
REG_SUB(libsnd3,, cellSnd3SMFPause);
REG_SUB(libsnd3,, cellSnd3SMFResume);
REG_SUB(libsnd3,, cellSnd3SMFStop);
REG_SUB(libsnd3,, cellSnd3SMFAddTempo);
REG_SUB(libsnd3,, cellSnd3SMFGetTempo);
REG_SUB(libsnd3,, cellSnd3SMFSetPlayVelocity);
REG_SUB(libsnd3,, cellSnd3SMFGetPlayVelocity);
REG_SUB(libsnd3,, cellSnd3SMFSetPlayPanpot);
REG_SUB(libsnd3,, cellSnd3SMFSetPlayPanpotEx);
REG_SUB(libsnd3,, cellSnd3SMFGetPlayPanpot);
REG_SUB(libsnd3,, cellSnd3SMFGetPlayPanpotEx);
REG_SUB(libsnd3,, cellSnd3SMFGetPlayStatus);
REG_SUB(libsnd3,, cellSnd3SMFSetPlayChannel);
REG_SUB(libsnd3,, cellSnd3SMFGetPlayChannel);
REG_SUB(libsnd3,, cellSnd3SMFGetKeyOnID);
REG_FUNC(libsnd3, cellSnd3Init);
REG_FUNC(libsnd3, cellSnd3Exit);
REG_FUNC(libsnd3, cellSnd3Note2Pitch);
REG_FUNC(libsnd3, cellSnd3Pitch2Note);
REG_FUNC(libsnd3, cellSnd3SetOutputMode);
REG_FUNC(libsnd3, cellSnd3Synthesis);
REG_FUNC(libsnd3, cellSnd3SynthesisEx);
REG_FUNC(libsnd3, cellSnd3BindSoundData);
REG_FUNC(libsnd3, cellSnd3UnbindSoundData);
REG_FUNC(libsnd3, cellSnd3NoteOnByTone);
REG_FUNC(libsnd3, cellSnd3KeyOnByTone);
REG_FUNC(libsnd3, cellSnd3VoiceNoteOnByTone);
REG_FUNC(libsnd3, cellSnd3VoiceKeyOnByTone);
REG_FUNC(libsnd3, cellSnd3VoiceSetReserveMode);
REG_FUNC(libsnd3, cellSnd3VoiceSetSustainHold);
REG_FUNC(libsnd3, cellSnd3VoiceKeyOff);
REG_FUNC(libsnd3, cellSnd3VoiceSetPitch);
REG_FUNC(libsnd3, cellSnd3VoiceSetVelocity);
REG_FUNC(libsnd3, cellSnd3VoiceSetPanpot);
REG_FUNC(libsnd3, cellSnd3VoiceSetPanpotEx);
REG_FUNC(libsnd3, cellSnd3VoiceSetPitchBend);
REG_FUNC(libsnd3, cellSnd3VoiceAllKeyOff);
REG_FUNC(libsnd3, cellSnd3VoiceGetEnvelope);
REG_FUNC(libsnd3, cellSnd3VoiceGetStatus);
REG_FUNC(libsnd3, cellSnd3KeyOffByID);
REG_FUNC(libsnd3, cellSnd3GetVoice);
REG_FUNC(libsnd3, cellSnd3GetVoiceByID);
REG_FUNC(libsnd3, cellSnd3NoteOn);
REG_FUNC(libsnd3, cellSnd3NoteOff);
REG_FUNC(libsnd3, cellSnd3SetSustainHold);
REG_FUNC(libsnd3, cellSnd3SetEffectType);
REG_FUNC(libsnd3, cellSnd3SMFBind);
REG_FUNC(libsnd3, cellSnd3SMFUnbind);
REG_FUNC(libsnd3, cellSnd3SMFPlay);
REG_FUNC(libsnd3, cellSnd3SMFPlayEx);
REG_FUNC(libsnd3, cellSnd3SMFPause);
REG_FUNC(libsnd3, cellSnd3SMFResume);
REG_FUNC(libsnd3, cellSnd3SMFStop);
REG_FUNC(libsnd3, cellSnd3SMFAddTempo);
REG_FUNC(libsnd3, cellSnd3SMFGetTempo);
REG_FUNC(libsnd3, cellSnd3SMFSetPlayVelocity);
REG_FUNC(libsnd3, cellSnd3SMFGetPlayVelocity);
REG_FUNC(libsnd3, cellSnd3SMFSetPlayPanpot);
REG_FUNC(libsnd3, cellSnd3SMFSetPlayPanpotEx);
REG_FUNC(libsnd3, cellSnd3SMFGetPlayPanpot);
REG_FUNC(libsnd3, cellSnd3SMFGetPlayPanpotEx);
REG_FUNC(libsnd3, cellSnd3SMFGetPlayStatus);
REG_FUNC(libsnd3, cellSnd3SMFSetPlayChannel);
REG_FUNC(libsnd3, cellSnd3SMFGetPlayChannel);
REG_FUNC(libsnd3, cellSnd3SMFGetKeyOnID);
});

View File

@ -51,5 +51,3 @@ struct CellSnd3RequestQueueCtx
vm::bptr<void> rearQueue;
be_t<u32> rearQueueSize;
};
extern Module<> libsnd3;

View File

@ -1,9 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "libsynth2.h"
LOG_CHANNEL(libsynth2);
s32 cellSoundSynth2Config(s16 param, s32 value)
{
libsynth2.todo("cellSoundSynth2Config(param=%d, value=%d)", param, value);
@ -104,23 +105,23 @@ u16 cellSoundSynth2Pitch2Note(u16 center_note, u16 center_fine, u16 pitch)
}
Module<> libsynth2("libsynth2", []()
DECLARE(ppu_module_manager::libsynth2)("libsynth2", []()
{
REG_SUB(libsynth2,, cellSoundSynth2Config);
REG_SUB(libsynth2,, cellSoundSynth2Init);
REG_SUB(libsynth2,, cellSoundSynth2Exit);
REG_SUB(libsynth2,, cellSoundSynth2SetParam);
REG_SUB(libsynth2,, cellSoundSynth2GetParam);
REG_SUB(libsynth2,, cellSoundSynth2SetSwitch);
REG_SUB(libsynth2,, cellSoundSynth2GetSwitch);
REG_SUB(libsynth2,, cellSoundSynth2SetAddr);
REG_SUB(libsynth2,, cellSoundSynth2GetAddr);
REG_SUB(libsynth2,, cellSoundSynth2SetEffectAttr);
REG_SUB(libsynth2,, cellSoundSynth2SetEffectMode);
REG_SUB(libsynth2,, cellSoundSynth2SetCoreAttr);
REG_SUB(libsynth2,, cellSoundSynth2Generate);
REG_SUB(libsynth2,, cellSoundSynth2VoiceTrans);
REG_SUB(libsynth2,, cellSoundSynth2VoiceTransStatus);
REG_SUB(libsynth2,, cellSoundSynth2Note2Pitch);
REG_SUB(libsynth2,, cellSoundSynth2Pitch2Note);
REG_FUNC(libsynth2, cellSoundSynth2Config);
REG_FUNC(libsynth2, cellSoundSynth2Init);
REG_FUNC(libsynth2, cellSoundSynth2Exit);
REG_FUNC(libsynth2, cellSoundSynth2SetParam);
REG_FUNC(libsynth2, cellSoundSynth2GetParam);
REG_FUNC(libsynth2, cellSoundSynth2SetSwitch);
REG_FUNC(libsynth2, cellSoundSynth2GetSwitch);
REG_FUNC(libsynth2, cellSoundSynth2SetAddr);
REG_FUNC(libsynth2, cellSoundSynth2GetAddr);
REG_FUNC(libsynth2, cellSoundSynth2SetEffectAttr);
REG_FUNC(libsynth2, cellSoundSynth2SetEffectMode);
REG_FUNC(libsynth2, cellSoundSynth2SetCoreAttr);
REG_FUNC(libsynth2, cellSoundSynth2Generate);
REG_FUNC(libsynth2, cellSoundSynth2VoiceTrans);
REG_FUNC(libsynth2, cellSoundSynth2VoiceTransStatus);
REG_FUNC(libsynth2, cellSoundSynth2Note2Pitch);
REG_FUNC(libsynth2, cellSoundSynth2Pitch2Note);
});

View File

@ -17,5 +17,3 @@ struct CellSoundSynth2EffectAttr
be_t<u16> delay;
be_t<u16> feedback;
};
extern Module<> libsynth2;

View File

@ -1,16 +1,12 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/lv2/sys_process.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/FS/VFS.h"
#include "Emu/FS/vfsDir.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "Crypto/unedat.h"
#include "sceNp.h"
extern Module<> sceNp;
LOG_CHANNEL(sceNp);
s32 sceNpInit(u32 poolsize, vm::ptr<void> poolptr)
{
@ -42,9 +38,11 @@ s32 sceNpTerm()
s32 npDrmIsAvailable(u32 k_licensee_addr, vm::cptr<char> drm_path)
{
if (!Emu.GetVFS().ExistsFile(drm_path.get_ptr()))
const std::string& enc_drm_path = drm_path.get_ptr();
if (!fs::is_file(vfs::get(enc_drm_path)))
{
sceNp.warning("npDrmIsAvailable(): '%s' not found", drm_path.get_ptr());
sceNp.warning("npDrmIsAvailable(): '%s' not found", enc_drm_path);
return CELL_ENOENT;
}
@ -60,49 +58,40 @@ s32 npDrmIsAvailable(u32 k_licensee_addr, vm::cptr<char> drm_path)
}
}
sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", drm_path.get_ptr());
sceNp.warning("npDrmIsAvailable(): Using k_licensee 0x%s", k_licensee_str.c_str());
sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", enc_drm_path);
sceNp.warning("npDrmIsAvailable(): Using k_licensee 0x%s", k_licensee_str);
// Set the necessary file paths.
std::string drm_file_name = fmt::AfterLast(drm_path.get_ptr(), '/');
const std::string& drm_file_name = enc_drm_path.substr(enc_drm_path.find_last_of('/') + 1);
// TODO: Make more explicit what this actually does (currently it copies "XXXXXXXX" from drm_path (== "/dev_hdd0/game/XXXXXXXXX/*" assumed)
std::string titleID(&drm_path[15], 9);
const std::string& drm_file_dir = enc_drm_path.substr(15);
const std::string& title_id = drm_file_dir.substr(0, drm_file_dir.find_first_of('/'));
// TODO: These shouldn't use current dir
std::string enc_drm_path = drm_path.get_ptr();
std::string dec_drm_path = "/dev_hdd1/cache/" + drm_file_name;
std::string pf_str("00000001"); // TODO: Allow multiple profiles. Use default for now.
std::string rap_path("/dev_hdd0/home/" + pf_str + "/exdata/");
const std::string& dec_drm_path = "/dev_hdd1/cache/" + drm_file_name;
std::string rap_lpath = vfs::get("/dev_hdd0/home/00000001/exdata/"); // TODO: Allow multiple profiles. Use default for now.
// Search for a compatible RAP file.
for (const auto entry : vfsDir(rap_path))
for (const auto& entry : fs::dir(rap_lpath))
{
if (entry->name.find(titleID) != std::string::npos)
if (entry.name.find(title_id) != -1)
{
rap_path += entry->name;
rap_lpath += entry.name;
break;
}
}
if (rap_path.back() == '/')
if (rap_lpath.back() == '/')
{
sceNp.warning("npDrmIsAvailable(): Can't find RAP file for '%s' (titleID='%s')", drm_path.get_ptr(), titleID);
rap_path.clear();
sceNp.warning("npDrmIsAvailable(): Can't find RAP file for %s", enc_drm_path);
rap_lpath.clear();
}
// Decrypt this EDAT using the supplied k_licensee and matching RAP file.
std::string enc_drm_path_local, dec_drm_path_local, rap_path_local;
const std::string& enc_drm_path_local = vfs::get(enc_drm_path);
const std::string& dec_drm_path_local = vfs::get(dec_drm_path);
Emu.GetVFS().GetDevice(enc_drm_path, enc_drm_path_local);
Emu.GetVFS().GetDevice(dec_drm_path, dec_drm_path_local);
if (rap_path.size())
{
Emu.GetVFS().GetDevice(rap_path, rap_path_local);
}
if (DecryptEDAT(enc_drm_path_local, dec_drm_path_local, 8, rap_path_local, k_licensee, false) >= 0)
if (DecryptEDAT(enc_drm_path_local, dec_drm_path_local, 8, rap_lpath, k_licensee, false) >= 0)
{
// If decryption succeeds, replace the encrypted file with it.
fs::remove_file(enc_drm_path_local);
@ -1526,7 +1515,7 @@ s32 _Z32_sce_np_sysutil_cxml_prepare_docPN16sysutil_cxmlutil11FixedMemoryERN4cxm
}
Module<> sceNp("sceNp", []()
DECLARE(ppu_module_manager::sceNp)("sceNp", []()
{
REG_FUNC(sceNp, sceNpInit);
REG_FUNC(sceNp, sceNpTerm);

View File

@ -1,11 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sceNp.h"
#include "sceNp2.h"
extern Module<> sceNp2;
LOG_CHANNEL(sceNp2);
s32 sceNp2Init(u32 poolsize, vm::ptr<void> poolptr)
{
@ -384,7 +383,7 @@ s32 sceNpMatching2RegisterRoomMessageCallback()
}
Module<> sceNp2("sceNp2", []()
DECLARE(ppu_module_manager::sceNp2)("sceNp2", []()
{
REG_FUNC(sceNp2, sceNpMatching2DestroyContext);
REG_FUNC(sceNp2, sceNpMatching2LeaveLobby);

View File

@ -1,12 +1,11 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sceNp.h"
#include "sceNpClans.h"
extern Module<> sceNpClans;
LOG_CHANNEL(sceNpClans);
s32 sceNpClansInit(vm::ptr<SceNpCommunicationId> commId, vm::ptr<SceNpCommunicationPassphrase> passphrase, vm::ptr<void> pool, vm::ptr<u32> poolSize, u32 flags)
{
@ -255,7 +254,7 @@ s32 sceNpClansRemoveChallenge()
return CELL_OK;
}
Module<> sceNpClans("sceNpClans", []()
DECLARE(ppu_module_manager::sceNpClans)("sceNpClans", []()
{
REG_FUNC(sceNpClans, sceNpClansInit);
REG_FUNC(sceNpClans, sceNpClansTerm);

View File

@ -1,10 +1,9 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sceNpCommerce2.h"
extern Module<> sceNpCommerce2;
LOG_CHANNEL(sceNpCommerce2);
s32 sceNpCommerce2ExecuteStoreBrowse()
{
@ -315,7 +314,7 @@ s32 sceNpCommerce2DoServiceListFinishAsync()
throw EXCEPTION("");
}
Module<> sceNpCommerce2("sceNpCommerce2", []()
DECLARE(ppu_module_manager::sceNpCommerce2)("sceNpCommerce2", []()
{
REG_FUNC(sceNpCommerce2, sceNpCommerce2ExecuteStoreBrowse);
REG_FUNC(sceNpCommerce2, sceNpCommerce2GetStoreBrowseUserdata);

View File

@ -1,9 +1,9 @@
#include "stdafx.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sceNpSns.h"
extern Module<> sceNpSns;
LOG_CHANNEL(sceNpSns);
s32 sceNpSnsFbInit(vm::ptr<const SceNpSnsFbInitParams> params)
{
@ -66,7 +66,7 @@ s32 sceNpSnsFbLoadThrottle()
}
Module<> sceNpSns("sceNpSns", []()
DECLARE(ppu_module_manager::sceNpSns)("sceNpSns", []()
{
REG_FUNC(sceNpSns, sceNpSnsFbInit);
REG_FUNC(sceNpSns, sceNpSnsFbTerm);

View File

@ -1,33 +1,29 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "Utilities/rXml.h"
#include "Loader/TRP.h"
#include "Loader/TROPUSR.h"
#include "Emu/FS/VFS.h"
#include "Emu/FS/vfsDir.h"
#include "Emu/FS/vfsFileBase.h"
#include "sceNp.h"
#include "sceNpTrophy.h"
extern Module<> sceNpTrophy;
LOG_CHANNEL(sceNpTrophy);
struct trophy_context_t
{
const u32 id = idm::get_last_id();
const u32 id{};
std::string trp_name;
std::unique_ptr<vfsStream> trp_stream;
fs::file trp_stream;
std::unique_ptr<TROPUSRLoader> tropusr;
};
struct trophy_handle_t
{
const u32 id = idm::get_last_id();
const u32 id{};
};
// Functions
@ -103,10 +99,10 @@ s32 sceNpTrophyCreateContext(vm::ptr<u32> context, vm::cptr<SceNpCommunicationId
std::string name = fmt::format("%s_%02d", commId->data, commId->num);
// open trophy pack file
std::unique_ptr<vfsStream> stream(Emu.GetVFS().OpenFile("/app_home/../TROPDIR/" + name + "/TROPHY.TRP", fom::read));
fs::file stream(vfs::get("/app_home/../TROPDIR/" + name + "/TROPHY.TRP"));
// check if exists and opened
if (!stream || !stream->IsOpened())
if (!stream)
{
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
}
@ -158,7 +154,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr<
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
}
TRPLoader trp(*ctxt->trp_stream);
TRPLoader trp(ctxt->trp_stream);
if (!trp.LoadHeader())
{
sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE");
@ -169,7 +165,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr<
const size_t kTargetBufferLength = 31;
char target[kTargetBufferLength + 1];
target[kTargetBufferLength] = 0;
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", rpcs3::config.system.language.value()));
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", /*rpcs3::config.system.language.value()*/0));
if (trp.ContainsEntry(target))
{
@ -191,7 +187,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr<
for (s32 i = 0; i <= 18; i++)
{
strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i));
if (i != rpcs3::config.system.language.value())
if (i != /*rpcs3::config.system.language.value()*/0)
{
trp.RemoveEntry(target);
}
@ -237,7 +233,7 @@ s32 sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr<u64> reqspa
}
// TODO: This is not accurate. It's just an approximation of the real value
*reqspace = ctxt->trp_stream->GetSize();
*reqspace = ctxt->trp_stream.size();
return CELL_OK;
}
@ -267,9 +263,12 @@ s32 sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptr<SceNpTrophyGameDetai
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
}
std::string path;
// TODO: Get the path of the current user
const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM");
// TODO: rXmlDocument can open only real file
ASSERT(!fs::get_virtual_device(path));
rXmlDocument doc;
Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user
doc.Load(path);
std::string titleName;
@ -394,9 +393,12 @@ s32 sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceN
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE;
}
std::string path;
// TODO: Get the path of the current user
const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM");
// TODO: rXmlDocument can open only real file
ASSERT(!fs::get_virtual_device(path));
rXmlDocument doc;
Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user
doc.Load(path);
std::string name;
@ -455,7 +457,7 @@ s32 sceNpTrophyGetTrophyIcon(u32 context, u32 handle, s32 trophyId, vm::ptr<void
}
Module<> sceNpTrophy("sceNpTrophy", []()
DECLARE(ppu_module_manager::sceNpTrophy)("sceNpTrophy", []()
{
REG_FUNC(sceNpTrophy, sceNpTrophyGetGameProgress);
REG_FUNC(sceNpTrophy, sceNpTrophyRegisterContext);

View File

@ -1,11 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sceNp.h"
#include "sceNpTus.h"
extern Module<> sceNpTus;
LOG_CHANNEL(sceNpTus);
s32 sceNpTusInit()
{
@ -333,7 +332,7 @@ s32 sceNpTusDeleteMultiSlotDataVUserAsync()
return CELL_OK;
}
Module<> sceNpTus("sceNpTus", []()
DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
{
REG_FUNC(sceNpTus, sceNpTusInit);
REG_FUNC(sceNpTus, sceNpTusTerm);

View File

@ -1,11 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sceNp.h"
#include "sceNpUtil.h"
extern Module<> sceNpUtil;
LOG_CHANNEL(sceNpUtil);
s32 sceNpUtilBandwidthTestInitStart(u32 prio, size_t stack)
{
@ -31,7 +30,7 @@ s32 sceNpUtilBandwidthTestAbort()
return CELL_OK;
}
Module<> sceNpUtil("sceNpUtil", []()
DECLARE(ppu_module_manager::sceNpUtil)("sceNpUtil", []()
{
REG_FUNC(sceNpUtil, sceNpUtilBandwidthTestInitStart);
REG_FUNC(sceNpUtil, sceNpUtilBandwidthTestShutdown);

View File

@ -1,80 +1,84 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/SysCalls/lv2/sys_interrupt.h"
#include "Emu/SysCalls/lv2/sys_process.h"
#include "Emu/Cell/lv2/sys_interrupt.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
LOG_CHANNEL(sysPrxForUser);
extern u64 get_system_time();
#define TLS_MAX 128
vm::gvar<s32> sys_prx_version; // ???
#define TLS_SYS 0x30
u32 g_tls_start; // start of TLS memory area
u32 g_tls_size;
u32 g_tls_size = 0; // Size of TLS area per thread
u32 g_tls_addr = 0; // Start of TLS memory area
u32 g_tls_max = 0; // Max number of threads
std::array<std::atomic<u32>, TLS_MAX> g_tls_owners;
std::unique_ptr<atomic_t<bool>[]> g_tls_map; // I'd like to make it std::vector but it won't work
void sys_initialize_tls()
u32 ppu_alloc_tls()
{
sysPrxForUser.trace("sys_initialize_tls()");
}
u32 ppu_get_tls(u32 thread)
{
if (!g_tls_start)
for (u32 i = 0; i < g_tls_max; i++)
{
g_tls_size = Emu.GetTLSMemsz() + TLS_SYS;
g_tls_start = vm::alloc(g_tls_size * TLS_MAX, vm::main); // memory for up to TLS_MAX threads
LOG_NOTICE(MEMORY, "Thread Local Storage initialized (g_tls_start=0x%x, user_size=0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x",
g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz());
}
if (!thread)
if (g_tls_map[i].exchange(true) == false)
{
return 0;
}
for (u32 i = 0; i < TLS_MAX; i++)
{
if (g_tls_owners[i] == thread)
{
return g_tls_start + i * g_tls_size + TLS_SYS; // if already initialized, return TLS address
}
}
for (u32 i = 0; i < TLS_MAX; i++)
{
u32 old = 0;
if (g_tls_owners[i].compare_exchange_strong(old, thread))
{
const u32 addr = g_tls_start + i * g_tls_size + TLS_SYS; // get TLS address
std::memset(vm::base(addr - TLS_SYS), 0, TLS_SYS); // initialize system area with zeros
std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
std::memset(vm::base(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros
const u32 addr = g_tls_addr + i * g_tls_size; // Calculate TLS address
std::memset(vm::base(addr), 0, TLS_SYS); // Clear system area (TODO)
std::memcpy(vm::base(addr + TLS_SYS), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // Copy TLS image
std::memset(vm::base(addr + TLS_SYS + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // Clear the rest
return addr;
}
}
throw EXCEPTION("Out of TLS memory");
sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", g_tls_max);
return 0;
}
void ppu_free_tls(u32 thread)
void ppu_free_tls(u32 addr)
{
for (auto& v : g_tls_owners)
{
u32 old = thread;
if (v.compare_exchange_strong(old, 0))
// Calculate TLS position
const u32 i = (addr - g_tls_addr) / g_tls_size;
if (addr < g_tls_addr || i >= g_tls_max || (addr - g_tls_addr) % g_tls_size)
{
sysPrxForUser.error("ppu_free_tls(0x%x): invalid address", addr);
return;
}
}
LOG_ERROR(MEMORY, "TLS deallocation failed (thread=0x%x)", thread);
if (g_tls_map[i].exchange(false) == false)
{
sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr);
return;
}
}
void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size)
{
sysPrxForUser.notice("sys_initialize_tls(thread_id=0x%llx, addr=*0x%x, size=0x%x, mem_size=0x%x)", main_thread_id, tls_seg_addr, tls_seg_size, tls_mem_size);
// Uninitialized TLS expected.
if (ppu.GPR[13] != 0) return;
// Initialize TLS memory
g_tls_size = Emu.GetTLSMemsz() + TLS_SYS;
g_tls_addr = vm::alloc(0x20000, vm::main) + 0x30;
g_tls_max = (0xffd0 / g_tls_size) + (0x10000 / g_tls_size);
g_tls_map = std::make_unique<atomic_t<bool>[]>(g_tls_max);
// Allocate TLS for main thread
ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + TLS_SYS;
sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%zu)", g_tls_addr - 0x30, g_tls_size, g_tls_max);
// TODO
g_spu_printf_agcb = vm::null;
g_spu_printf_dgcb = vm::null;
g_spu_printf_atcb = vm::null;
g_spu_printf_dtcb = vm::null;
}
s64 sys_time_get_system_time()
@ -86,21 +90,32 @@ s64 sys_time_get_system_time()
s64 _sys_process_atexitspawn()
{
sysPrxForUser.trace("_sys_process_atexitspawn()");
sysPrxForUser.todo("_sys_process_atexitspawn()");
return CELL_OK;
}
s64 _sys_process_at_Exitspawn()
{
sysPrxForUser.trace("_sys_process_at_Exitspawn");
sysPrxForUser.todo("_sys_process_at_Exitspawn");
return CELL_OK;
}
s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih)
{
sysPrxForUser.todo("sys_interrupt_thread_disestablish(ih=0x%x)", ih);
sysPrxForUser.notice("sys_interrupt_thread_disestablish(ih=0x%x)", ih);
return _sys_interrupt_thread_disestablish(ppu, ih, vm::var<u64>{});
vm::var<u64> r13;
// Call the syscall
if (s32 res = _sys_interrupt_thread_disestablish(ppu, ih, r13))
{
return res;
}
// Deallocate TLS
ppu_free_tls(vm::cast(*r13, HERE) - 0x7030);
return CELL_OK;
}
s32 sys_process_is_stack(u32 p)
@ -166,20 +181,8 @@ extern void sysPrxForUser_sys_spu_init();
extern void sysPrxForUser_sys_game_init();
extern void sysPrxForUser_sys_libc_init();
Module<> sysPrxForUser("sysPrxForUser", []()
DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []()
{
g_tls_start = 0;
for (auto& v : g_tls_owners)
{
v = 0;
}
// Setup random number generator
srand(time(NULL));
//REG_VARIABLE(sysPrxForUser, sys_prx_version); // 0x7df066cf
sysPrxForUser_sys_lwmutex_init();
sysPrxForUser_sys_lwcond_init();
sysPrxForUser_sys_ppu_thread_init();
@ -192,6 +195,8 @@ Module<> sysPrxForUser("sysPrxForUser", []()
sysPrxForUser_sys_game_init();
sysPrxForUser_sys_libc_init();
REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf
REG_FUNC(sysPrxForUser, sys_initialize_tls);
REG_FUNC(sysPrxForUser, sys_time_get_system_time);

View File

@ -1,12 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/FS/VFS.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
void sys_game_process_exitspawn(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
{
@ -70,18 +68,11 @@ void sys_game_process_exitspawn(vm::cptr<char> path, u32 argv_addr, u32 envp_add
Emu.Pause();
sysPrxForUser.success("Process finished");
Emu.CallAfter([=]()
Emu.CallAfter([=, path = vfs::get(_path)]()
{
Emu.Stop();
std::string real_path;
Emu.GetVFS().GetDevice(_path.c_str(), real_path);
Emu.BootGame(real_path, true);
Emu.BootGame(path, true);
});
return;
}
void sys_game_process_exitspawn2(vm::cptr<char> path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags)
@ -146,15 +137,10 @@ void sys_game_process_exitspawn2(vm::cptr<char> path, u32 argv_addr, u32 envp_ad
Emu.Pause();
sysPrxForUser.success("Process finished");
Emu.CallAfter([=]()
Emu.CallAfter([=, path = vfs::get(_path)]()
{
Emu.Stop();
std::string real_path;
Emu.GetVFS().GetDevice(_path.c_str(), real_path);
Emu.BootGame(real_path, true);
Emu.BootGame(path, true);
});
return;

View File

@ -1,12 +1,11 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
struct HeapInfo
{

View File

@ -1,7 +1,7 @@
#include "stdafx.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
extern Module<> sys_io;
LOG_CHANNEL(sys_io);
extern void cellPad_init();
extern void cellKb_init();
@ -39,7 +39,7 @@ s32 sys_config_unregister_service()
}
Module<> sys_io("sys_io", []()
DECLARE(ppu_module_manager::sys_io)("sys_io", []()
{
cellPad_init();
cellKb_init();

View File

@ -0,0 +1,24 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/PPUOpcodes.h"
LOG_CHANNEL(sys_libc);
namespace sys_libc_func
{
void memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
{
sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size);
::memcpy(dst.get_ptr(), src.get_ptr(), size);
}
}
// Define macro for namespace
#define REG_FUNC_(name) REG_FNID(sys_libc, ppu_generate_id(#name), sys_libc_func::name)
DECLARE(ppu_module_manager::sys_libc)("sys_libc", []()
{
REG_FUNC_(memcpy);
});

View File

@ -1,12 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUInstrTable.h"
#include "Emu/Cell/PPUModule.h"
extern Module<> sys_libc;
extern _log::channel sysPrxForUser;
std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_count, u32 v_count)
// TODO
static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count)
{
std::string result;
@ -33,7 +31,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
if (*fmt == '*')
{
fmt++;
return context.get_next_gpr_arg(g_count, f_count, v_count);
return context.get_next_arg(g_count);
}
while (*fmt - '0' < 10)
@ -57,7 +55,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
if (*++fmt == '*')
{
fmt++;
return context.get_next_gpr_arg(g_count, f_count, v_count);
return context.get_next_arg(g_count);
}
while (*fmt - '0' < 10)
@ -81,7 +79,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
case 'i':
{
// signed decimal
const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
const s64 value = context.get_next_arg(g_count);
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
@ -92,7 +90,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
case 'X':
{
// hexadecimal
const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
const u64 value = context.get_next_arg(g_count);
if (plus_sign || minus_sign || space_sign || prec) break;
@ -101,7 +99,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
result += cf == 'x' ? "0x" : "0X";
}
const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::toupper(fmt::to_hex(value));
const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value));
if (hex.length() >= width)
{
@ -120,7 +118,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
case 's':
{
// string
auto string = vm::cptr<char, u64>::make(context.get_next_gpr_arg(g_count, f_count, v_count));
auto string = vm::cptr<char, u64>::make(context.get_next_arg(g_count));
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
@ -130,7 +128,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
case 'u':
{
// unsigned decimal
const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
const u64 value = context.get_next_arg(g_count);
if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break;
@ -149,18 +147,6 @@ std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count, u32 f_c
return result;
}
namespace sys_libc_func
{
void memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
{
sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size);
::memcpy(dst.get_ptr(), src.get_ptr(), size);
}
}
extern Module<> sysPrxForUser;
vm::ptr<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size)
{
sysPrxForUser.trace("_sys_memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size);
@ -328,7 +314,7 @@ s32 _sys_snprintf(PPUThread& ppu, vm::ptr<char> dst, u32 count, vm::cptr<char> f
{
sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=*0x%x, ...)", dst, count, fmt);
std::string result = ps3_fmt(ppu, fmt, va_args.g_count, va_args.f_count, va_args.v_count);
std::string result = ps3_fmt(ppu, fmt, va_args.count);
sysPrxForUser.warning("*** '%s' -> '%s'", fmt.get_ptr(), result);
@ -350,7 +336,7 @@ s32 _sys_printf(PPUThread& ppu, vm::cptr<char> fmt, ppu_va_args_t va_args)
{
sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt);
_log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.g_count, va_args.f_count, va_args.v_count));
_log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.count));
return CELL_OK;
}
@ -414,19 +400,3 @@ void sysPrxForUser_sys_libc_init()
REG_FUNC(sysPrxForUser, _sys_qsort);
}
Module<> sys_libc("sys_libc", []()
{
using namespace PPU_instr;
REG_SUB(sys_libc, sys_libc_func, memcpy,
SP_I(CMPLDI(cr7, r5, 7)),
SP_I(CLRLDI(r3, r3, 32)),
SP_I(CLRLDI(r4, r4, 32)),
SP_I(MR(r11, r3)),
SP_I(BGT(cr7, XXX & 0xff)),
SP_I(CMPDI(r5, 0)),
OPT_SP_I(MR(r9, r3)),
{ SPET_MASKED_OPCODE, 0x4d820020, 0xffffffff },
);
});

View File

@ -1,12 +1,11 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sys_lv2dbg.h"
extern Module<> sys_lv2dbg;
LOG_CHANNEL(sys_lv2dbg);
s32 sys_dbg_read_ppu_thread_context(u64 id, vm::ptr<sys_dbg_ppu_thread_context_t> ppu_context)
{
@ -190,7 +189,7 @@ s32 sys_dbg_set_mask_to_ppu_exception_handler(u64 mask, u64 flags)
throw EXCEPTION("");
}
Module<> sys_lv2dbg("sys_lv2dbg", []
DECLARE(ppu_module_manager::sys_lv2dbg)("sys_lv2dbg", []
{
REG_FUNC(sys_lv2dbg, sys_dbg_read_ppu_thread_context);
REG_FUNC(sys_lv2dbg, sys_dbg_read_spu_thread_context);

View File

@ -1,13 +1,13 @@
#pragma once
#include "Emu/SysCalls/lv2/sys_mutex.h"
#include "Emu/SysCalls/lv2/sys_cond.h"
#include "Emu/SysCalls/lv2/sys_rwlock.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/SysCalls/lv2/sys_semaphore.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h"
#include "Emu/Cell/lv2/sys_mutex.h"
#include "Emu/Cell/lv2/sys_cond.h"
#include "Emu/Cell/lv2/sys_rwlock.h"
#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/Cell/lv2/sys_semaphore.h"
#include "Emu/Cell/lv2/sys_lwmutex.h"
#include "Emu/Cell/lv2/sys_lwcond.h"
#include "Emu/Cell/lv2/sys_event_flag.h"
namespace vm { using namespace ps3; }

View File

@ -1,15 +1,13 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/SysCalls/lv2/sys_sync.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/Cell/lv2/sys_lwmutex.h"
#include "Emu/Cell/lv2/sys_lwcond.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
{
@ -47,7 +45,7 @@ s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond)
//return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2);
}
if (lwmutex->vars.owner.load() == ppu.get_id())
if (lwmutex->vars.owner.load() == ppu.id)
{
// if owns the mutex
lwmutex->all_info++;
@ -105,7 +103,7 @@ s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond)
//return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2);
}
if (lwmutex->vars.owner.load() == ppu.get_id())
if (lwmutex->vars.owner.load() == ppu.id)
{
// if owns the mutex, call the syscall
const s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
@ -162,7 +160,7 @@ s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_t
//return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2);
}
if (lwmutex->vars.owner.load() == ppu.get_id())
if (lwmutex->vars.owner.load() == ppu.id)
{
// if owns the mutex
lwmutex->all_info++;
@ -212,7 +210,7 @@ s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
{
sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout);
const be_t<u32> tid = ppu.get_id();
const be_t<u32> tid = ppu.id;
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;

View File

@ -2,13 +2,12 @@
#include "Emu/Memory/Memory.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/SysCalls/lv2/sys_sync.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/Cell/lv2/sys_lwmutex.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
{
@ -45,7 +44,7 @@ s32 sys_lwmutex_destroy(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
sysPrxForUser.trace("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex);
// check to prevent recursive locking in the next call
if (lwmutex->vars.owner.load() == ppu.get_id())
if (lwmutex->vars.owner.load() == ppu.id)
{
return CELL_EBUSY;
}
@ -75,7 +74,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout
{
sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout);
const be_t<u32> tid = ppu.get_id();
const be_t<u32> tid = ppu.id;
// try to lock lightweight mutex
const be_t<u32> old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid);
@ -169,7 +168,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
{
sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex);
const be_t<u32> tid = ppu.get_id();
const be_t<u32> tid = ppu.id;
// try to lock lightweight mutex
const be_t<u32> old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid);
@ -236,7 +235,7 @@ s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
{
sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex);
const be_t<u32> tid = ppu.get_id();
const be_t<u32> tid = ppu.id;
// check owner
if (lwmutex->vars.owner.load() != tid)

View File

@ -1,12 +1,11 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
using sys_mempool_t = u32;

View File

@ -1,12 +1,11 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/SysCalls/lv2/sys_mmapper.h"
#include "Emu/Cell/lv2/sys_mmapper.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
void sysPrxForUser_sys_mmapper_init()
{

View File

@ -1,6 +1,5 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sys_net.h"
@ -9,7 +8,6 @@
#define _WIN32_WINNT 0x0601
#include <winsock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/types.h>
#include <sys/socket.h>
@ -18,7 +16,7 @@
#include <unistd.h>
#endif
extern Module<> libnet;
LOG_CHANNEL(libnet);
// We map host sockets to sequential IDs to return as FDs because syscalls using
// socketselect(), etc. expect socket FDs to be under 1024.
@ -622,10 +620,10 @@ namespace sys_net
}
}
// define additional macro for specific namespace
#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &libnet, #name, BIND_FUNC(sys_net::name)))
// Define macro for namespace
#define REG_FUNC_(name) REG_FNID(sys_net, ppu_generate_id(#name), sys_net::name)
Module<> libnet("sys_net", []()
DECLARE(ppu_module_manager::libnet)("sys_net", []()
{
REG_FUNC_(accept);
REG_FUNC_(bind);

View File

@ -1,28 +1,35 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/SysCalls/lv2/sys_ppu_thread.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
extern u32 ppu_alloc_tls();
extern void ppu_free_tls(u32 addr);
s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname)
{
sysPrxForUser.warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)", thread_id, entry, arg, prio, stacksize, flags, threadname);
sysPrxForUser.warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)",
thread_id, entry, arg, prio, stacksize, flags, threadname);
// (allocate TLS)
// (return CELL_ENOMEM if failed)
// ...
// Allocate TLS
const u32 tls_addr = ppu_alloc_tls();
// call the syscall
if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, 0 }), arg, 0, prio, stacksize, flags, threadname))
if (!tls_addr)
{
return CELL_ENOMEM;
}
// Call the syscall
if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname))
{
return res;
}
// run the thread
// Run the thread
return flags & SYS_PPU_THREAD_CREATE_INTERRUPT ? CELL_OK : sys_ppu_thread_start(static_cast<u32>(*thread_id));
}
@ -30,7 +37,7 @@ s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr<u64> thread_id)
{
sysPrxForUser.trace("sys_ppu_thread_get_id(thread_id=*0x%x)", thread_id);
*thread_id = ppu.get_id();
*thread_id = ppu.id;
return CELL_OK;
}
@ -40,13 +47,15 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val)
sysPrxForUser.trace("sys_ppu_thread_exit(val=0x%llx)", val);
// (call registered atexit functions)
// (deallocate TLS)
// ...
if (ppu.hle_code == 0xaff080a4)
// Deallocate TLS
ppu_free_tls(vm::cast(ppu.GPR[13], HERE) - 0x7030);
if (ppu.GPR[3] == val && !ppu.custom_task)
{
// Change sys_ppu_thread_exit code to the syscall code
ppu.hle_code = ~41;
// Change sys_ppu_thread_exit code to the syscall code (hack)
ppu.GPR[11] = 41;
}
// Call the syscall

View File

@ -1,12 +1,11 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/SysCalls/lv2/sys_prx.h"
#include "Emu/Cell/lv2/sys_prx.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
s64 sys_prx_exitspawn_with_level()
{

View File

@ -1,11 +1,10 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
void sys_spinlock_initialize(vm::ptr<atomic_be_t<u32>> lock)
{

View File

@ -1,15 +1,13 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/RawSPUThread.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/FS/vfsFile.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Crypto/unself.h"
#include "sysPrxForUser.h"
extern Module<> sysPrxForUser;
extern _log::channel sysPrxForUser;
extern u64 get_system_time();
@ -30,17 +28,38 @@ s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32
return CELL_OK;
}
s32 sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
s32 sys_spu_image_import(vm::ptr<sys_spu_image_t> img, u32 src, u32 type)
{
sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type);
return spu_image_import(*img, src, type);
u32 entry, offset = LoadSpuImage(fs::file(vm::base(src), 0 - src), entry);
img->type = SYS_SPU_IMAGE_TYPE_USER;
img->entry_point = entry;
img->segs.set(offset); // TODO: writing actual segment info
img->nsegs = 1; // wrong value
return CELL_OK;
}
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img)
s32 sys_spu_image_close(vm::ptr<sys_spu_image_t> img)
{
sysPrxForUser.todo("sys_spu_image_close(img=*0x%x)", img);
sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img);
if (img->type == SYS_SPU_IMAGE_TYPE_USER)
{
//_sys_free(img->segs.addr());
}
else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL)
{
//return syscall_158(img);
}
else
{
return CELL_EINVAL;
}
ASSERT(vm::dealloc(img->segs.addr(), vm::main)); // Current rough implementation
return CELL_OK;
}
@ -49,10 +68,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=*0x%x, entry=*0x%x)", id, path, entry);
sysPrxForUser.warning("*** path = '%s'", path.get_ptr());
vfsFile f(path.get_ptr());
if (!f.IsOpened())
const fs::file f(vfs::get(path.get_ptr()));
if (!f)
{
sysPrxForUser.error("sys_raw_spu_load error: '%s' not found!", path.get_ptr());
sysPrxForUser.error("sys_raw_spu_load() error: '%s' not found!", path.get_ptr());
return CELL_ENOENT;
}
@ -61,12 +80,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
if (hdr.CheckMagic())
{
sysPrxForUser.error("sys_raw_spu_load error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr());
Emu.Pause();
return CELL_ENOENT;
throw fmt::exception("sys_raw_spu_load() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr());
}
f.Seek(0);
f.seek(0);
u32 _entry;
LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
@ -76,7 +93,7 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
return CELL_OK;
}
s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr<sys_spu_image> img)
s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr<sys_spu_image_t> img)
{
sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img);
@ -84,7 +101,7 @@ s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr<sys_spu_image> img)
const auto stamp0 = get_system_time();
std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::base(img->addr), 256 * 1024);
std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), img->segs.get_ptr(), 256 * 1024);
const auto stamp1 = get_system_time();
@ -173,11 +190,6 @@ s32 _sys_spu_printf_detach_thread(PPUThread& ppu, u32 thread)
void sysPrxForUser_sys_spu_init()
{
g_spu_printf_agcb = vm::null;
g_spu_printf_dgcb = vm::null;
g_spu_printf_atcb = vm::null;
g_spu_printf_dtcb = vm::null;
REG_FUNC(sysPrxForUser, sys_spu_elf_get_information);
REG_FUNC(sysPrxForUser, sys_spu_elf_get_segments);
REG_FUNC(sysPrxForUser, sys_spu_image_import);

View File

@ -1,343 +0,0 @@
#include "stdafx.h"
#include "Modules.h"
#include "ModuleManager.h"
extern Module<> cellAdec;
extern Module<> cellAtrac;
extern Module<> cellAtracMulti;
extern Module<> cellAudio;
extern Module<> cellAvconfExt;
extern Module<> cellBGDL;
extern Module<> cellCamera;
extern Module<> cellCelp8Enc;
extern Module<> cellCelpEnc;
extern Module<> cellDaisy;
extern Module<> cellDmux;
extern Module<> cellFiber;
extern Module<> cellFont;
extern Module<> cellFontFT;
extern Module<> cellFs;
extern Module<> cellGame;
extern Module<> cellGameExec;
extern Module<> cellGcmSys;
extern Module<> cellGem;
extern Module<> cellGifDec;
extern Module<> cellHttp;
extern Module<> cellHttps;
extern Module<> cellHttpUtil;
extern Module<> cellImeJp;
extern Module<> cellJpgDec;
extern Module<> cellJpgEnc;
extern Module<> cellKey2char;
extern Module<> cellL10n;
extern Module<> cellMic;
extern Module<> cellMusic;
extern Module<> cellMusicDecode;
extern Module<> cellMusicExport;
extern Module<> cellNetCtl;
extern Module<> cellOskDialog;
extern Module<> cellOvis;
extern Module<> cellPamf;
extern Module<> cellPhotoDecode;
extern Module<> cellPhotoExport;
extern Module<> cellPhotoImportUtil;
extern Module<> cellPngDec;
extern Module<> cellPngEnc;
extern Module<> cellPrint;
extern Module<> cellRec;
extern Module<> cellRemotePlay;
extern Module<> cellResc;
extern Module<> cellRtc;
extern Module<> cellRudp;
extern Module<> cellSail;
extern Module<> cellSailRec;
extern Module<> cellSaveData;
extern Module<> cellMinisSaveData;
extern Module<> cellScreenshot;
extern Module<> cellSearch;
extern Module<> cellSheap;
extern Module<> cellSpudll;
extern Module<> cellSpurs;
extern Module<> cellSpursJq;
extern Module<> cellSsl;
extern Module<> cellSubdisplay;
extern Module<> cellSync;
extern Module<struct Sync2Instance> cellSync2;
extern Module<> cellSysconf;
extern Module<> cellSysmodule;
extern Module<> cellSysutil;
extern Module<> cellSysutilAp;
extern Module<> cellSysutilAvc;
extern Module<> cellSysutilAvc2;
extern Module<> cellSysutilMisc;
extern Module<> cellUsbd;
extern Module<> cellUsbPspcm;
extern Module<> cellUserInfo;
extern Module<> cellVdec;
extern Module<> cellVideoExport;
extern Module<> cellVideoUpload;
extern Module<> cellVoice;
extern Module<> cellVpost;
extern Module<> libmixer;
extern Module<> libsnd3;
extern Module<> libsynth2;
extern Module<> sceNp;
extern Module<> sceNp2;
extern Module<> sceNpClans;
extern Module<> sceNpCommerce2;
extern Module<> sceNpSns;
extern Module<> sceNpTrophy;
extern Module<> sceNpTus;
extern Module<> sceNpUtil;
extern Module<> sys_io;
extern Module<> libnet;
extern Module<> sysPrxForUser;
extern Module<> sys_libc;
extern Module<> sys_lv2dbg;
struct ModuleInfo
{
const s32 id; // -1 if the module doesn't have corresponding CELL_SYSMODULE_* id
const char* const name;
Module<>* const module;
explicit operator bool() const
{
return module != nullptr;
}
operator Module<>*() const
{
return module;
}
Module<>* operator ->() const
{
return module;
}
}
const g_module_list[] =
{
{ 0x0000, "sys_net", &libnet },
{ 0x0001, "cellHttp", &cellHttp },
{ 0x0002, "cellHttpUtil", &cellHttpUtil },
{ 0x0003, "cellSsl", &cellSsl },
{ 0x0004, "cellHttps", &cellHttps },
{ 0x0005, "libvdec", &cellVdec },
{ 0x0006, "cellAdec", &cellAdec },
{ 0x0007, "cellDmux", &cellDmux },
{ 0x0008, "cellVpost", &cellVpost },
{ 0x0009, "cellRtc", &cellRtc },
{ 0x000a, "cellSpurs", &cellSpurs },
{ 0x000b, "cellOvis", &cellOvis },
{ 0x000c, "cellSheap", &cellSheap },
{ 0x000d, "cellSync", &cellSync },
{ 0x000e, "sys_fs", &cellFs },
{ 0x000f, "cellJpgDec", &cellJpgDec },
{ 0x0010, "cellGcmSys", &cellGcmSys },
{ 0x0011, "cellAudio", &cellAudio },
{ 0x0012, "cellPamf", &cellPamf },
{ 0x0013, "cellAtrac", &cellAtrac },
{ 0x0014, "cellNetCtl", &cellNetCtl },
{ 0x0015, "cellSysutil", &cellSysutil },
{ 0x0016, "sceNp", &sceNp },
{ 0x0017, "sys_io", &sys_io },
{ 0x0018, "cellPngDec", &cellPngDec },
{ 0x0019, "cellFont", &cellFont },
{ 0x001a, "cellFontFT", &cellFontFT },
{ 0x001b, "cell_FreeType2", nullptr },
{ 0x001c, "cellUsbd", &cellUsbd },
{ 0x001d, "cellSail", &cellSail },
{ 0x001e, "cellL10n", &cellL10n },
{ 0x001f, "cellResc", &cellResc },
{ 0x0020, "cellDaisy", &cellDaisy },
{ 0x0021, "cellKey2char", &cellKey2char },
{ 0x0022, "cellMic", &cellMic },
{ 0x0023, "cellCamera", &cellCamera },
{ 0x0024, "cellVdecMpeg2", nullptr },
{ 0x0025, "cellVdecAvc", nullptr },
{ 0x0026, "cellAdecLpcm", nullptr },
{ 0x0027, "cellAdecAc3", nullptr },
{ 0x0028, "cellAdecAtx", nullptr },
{ 0x0029, "cellAdecAt3", nullptr },
{ 0x002a, "cellDmuxPamf", nullptr },
{ 0x002b, "?", nullptr },
{ 0x002c, "?", nullptr },
{ 0x002d, "?", nullptr },
{ 0x002e, "sys_lv2dbg", &sys_lv2dbg },
{ 0x002f, "cellSysutilAvcExt", &cellSysutilAvc },
{ 0x0030, "cellUsbPspcm", &cellUsbPspcm },
{ 0x0031, "cellSysutilAvconfExt", &cellAvconfExt },
{ 0x0032, "cellUserInfo", &cellUserInfo },
{ 0x0033, "cellSaveData", &cellSaveData },
{ 0x0034, "cellSubDisplay", &cellSubdisplay },
{ 0x0035, "cellRec", &cellRec },
{ 0x0036, "cellVideoExportUtility", &cellVideoExport },
{ 0x0037, "cellGameExec", &cellGameExec },
{ 0x0038, "sceNp2", &sceNp2 },
{ 0x0039, "cellSysutilAp", &cellSysutilAp },
{ 0x003a, "sceNpClans", &sceNpClans },
{ 0x003b, "cellOskExtUtility", &cellOskDialog },
{ 0x003c, "cellVdecDivx", nullptr },
{ 0x003d, "cellJpgEnc", &cellJpgEnc },
{ 0x003e, "cellGame", &cellGame },
{ 0x003f, "cellBGDLUtility", &cellBGDL },
{ 0x0040, "cell_FreeType2", nullptr },
{ 0x0041, "cellVideoUpload", &cellVideoUpload },
{ 0x0042, "cellSysconfExtUtility", &cellSysconf },
{ 0x0043, "cellFiber", &cellFiber },
{ 0x0044, "sceNpCommerce2", &sceNpCommerce2 },
{ 0x0045, "sceNpTus", &sceNpTus },
{ 0x0046, "cellVoice", &cellVoice },
{ 0x0047, "cellAdecCelp8", nullptr },
{ 0x0048, "cellCelp8Enc", &cellCelp8Enc },
{ 0x0049, "cellSysutilMisc", &cellSysutilMisc },
{ 0x004a, "cellMusicUtility", &cellMusic }, // 2
{ 0x004e, "cellScreenShotUtility", &cellScreenshot },
{ 0x004f, "cellMusicDecodeUtility", &cellMusicDecode },
{ 0x0050, "cellSpursJq", &cellSpursJq },
{ 0x0052, "cellPngEnc", &cellPngEnc },
{ 0x0053, "cellMusicDecodeUtility", &cellMusicDecode }, // 2
{ 0x0055, "cellSync2", &cellSync2 },
{ 0x0056, "sceNpUtil", &sceNpUtil },
{ 0x0057, "cellRudp", &cellRudp },
{ 0x0059, "sceNpSns", &sceNpSns },
{ 0x005a, "libgem", &cellGem },
{ 0xf00a, "cellCelpEnc", &cellCelpEnc },
{ 0xf010, "cellGifDec", &cellGifDec },
{ 0xf019, "cellAdecCelp", nullptr },
{ 0xf01b, "cellAdecM2bc", nullptr },
{ 0xf01d, "cellAdecM4aac", nullptr },
{ 0xf01e, "cellAdecMp3", nullptr },
{ 0xf023, "cellImeJpUtility", &cellImeJp },
{ 0xf028, "cellMusicUtility", &cellMusic },
{ 0xf029, "cellPhotoUtility", &cellPhotoExport },
{ 0xf02a, "cellPrintUtility", &cellPrint },
{ 0xf02b, "cellPhotoImportUtil", &cellPhotoImportUtil },
{ 0xf02c, "cellMusicExportUtility", &cellMusicExport },
{ 0xf02e, "cellPhotoDecodeUtil", &cellPhotoDecode },
{ 0xf02f, "cellSearchUtility", &cellSearch },
{ 0xf030, "cellSysutilAvc2", &cellSysutilAvc2 },
{ 0xf034, "cellSailRec", &cellSailRec },
{ 0xf035, "sceNpTrophy", &sceNpTrophy },
{ 0xf053, "cellAdecAt3multi", nullptr },
{ 0xf054, "cellAtracMulti", &cellAtracMulti },
{ -1, "cellSysmodule", &cellSysmodule },
{ -1, "libmixer", &libmixer },
{ -1, "sysPrxForUser", &sysPrxForUser },
{ -1, "sys_libc", &sys_libc },
{ -1, "cellMinisSaveData", &cellMinisSaveData },
{ -1, "cellSpudll", &cellSpudll },
{ -1, "cellRemotePlay", &cellRemotePlay },
{ -1, "libsnd3", &libsnd3 },
{ -1, "libsynth2", &libsynth2 },
};
void ModuleManager::Init()
{
if (m_init)
{
Close();
}
clear_ppu_functions();
std::unordered_set<Module<>*> processed;
for (auto& module : g_module_list)
{
if (module && processed.emplace(module).second)
{
module->Init();
}
}
m_init = true;
}
ModuleManager::ModuleManager()
{
}
ModuleManager::~ModuleManager()
{
Close();
}
void ModuleManager::Close()
{
if (!m_init)
{
return;
}
std::unordered_set<Module<>*> processed;
for (auto& module : g_module_list)
{
if (module && module->on_stop && processed.emplace(module).second)
{
module->on_stop();
}
}
m_init = false;
}
void ModuleManager::Alloc()
{
if (!m_init)
{
return;
}
std::unordered_set<Module<>*> processed;
for (auto& module : g_module_list)
{
if (module && module->on_alloc && processed.emplace(module).second)
{
module->on_alloc();
}
}
}
Module<>* ModuleManager::GetModuleByName(const char* name)
{
for (auto& module : g_module_list)
{
if (!strcmp(name, module.name))
{
return module;
}
}
return nullptr;
}
Module<>* ModuleManager::GetModuleById(u16 id)
{
for (auto& module : g_module_list)
{
if (module.id == id)
{
return module;
}
}
return nullptr;
}
bool ModuleManager::CheckModuleId(u16 id)
{
for (auto& module : g_module_list)
{
if (module.id == id)
{
return true;
}
}
return false;
}

View File

@ -1,20 +0,0 @@
#pragma once
template<typename T> class Module;
class ModuleManager
{
bool m_init = false;
public:
ModuleManager();
~ModuleManager();
void Init();
void Close();
void Alloc();
static Module<void>* GetModuleByName(const char* name);
static Module<void>* GetModuleById(u16 id);
static bool CheckModuleId(u16 id);
};

View File

@ -1,576 +0,0 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Crypto/sha1.h"
#include "ModuleManager.h"
#include "Emu/Cell/PPUInstrTable.h"
std::vector<ModuleFunc> g_ppu_func_list;
std::vector<StaticFunc> g_ppu_func_subs;
std::vector<ModuleVariable> g_ps3_var_list;
u32 add_ppu_func(ModuleFunc func)
{
if (g_ppu_func_list.empty())
{
// prevent relocations if the array growths, must be sizeof(ModuleFunc) * 0x8000 ~~ about 1 MB of memory
g_ppu_func_list.reserve(0x8000);
}
for (auto& f : g_ppu_func_list)
{
if (f.id == func.id)
{
// if NIDs overlap or if the same function is added twice
throw EXCEPTION("FNID already exists: 0x%08x (%s)", f.id, f.name);
}
}
g_ppu_func_list.emplace_back(std::move(func));
return (u32)g_ppu_func_list.size() - 1;
}
void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)())
{
if (g_ps3_var_list.empty())
{
g_ps3_var_list.reserve(0x4000); // as g_ppu_func_list
}
for (auto& v : g_ps3_var_list)
{
if (v.id == nid)
{
throw EXCEPTION("VNID already exists: 0x%08x (%s)", nid, name);
}
}
g_ps3_var_list.emplace_back(ModuleVariable{ nid, module, name, addr });
}
ModuleVariable* get_variable_by_nid(u32 nid)
{
for (auto& v : g_ps3_var_list)
{
if (v.id == nid)
{
return &v;
}
}
return nullptr;
}
u32 add_ppu_func_sub(StaticFunc func)
{
g_ppu_func_subs.emplace_back(func);
return func.index;
}
u32 add_ppu_func_sub(const std::initializer_list<SearchPatternEntry>& ops, const char* name, Module<>* module, ppu_func_caller func)
{
StaticFunc sf;
sf.index = add_ppu_func(ModuleFunc(get_function_id(name), 0, module, name, func));
sf.name = name;
sf.found = 0;
sf.ops = ops;
return add_ppu_func_sub(std::move(sf));
}
ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index)
{
for (auto& f : g_ppu_func_list)
{
if (f.id == nid)
{
if (out_index)
{
*out_index = (u32)(&f - g_ppu_func_list.data());
}
return &f;
}
}
return nullptr;
}
ModuleFunc* get_ppu_func_by_index(u32 index)
{
index &= ~EIF_FLAGS;
if (index >= g_ppu_func_list.size())
{
return nullptr;
}
return &g_ppu_func_list[index];
}
void execute_ppu_func_by_index(PPUThread& ppu, u32 index)
{
if (auto func = get_ppu_func_by_index(index))
{
// save RTOC if necessary
if (index & EIF_SAVE_RTOC)
{
vm::write64(VM_CAST(ppu.GPR[1] + 0x28), ppu.GPR[2]);
}
// save old syscall/NID value
const auto last_code = ppu.hle_code;
// branch directly to the LLE function
if (index & EIF_USE_BRANCH)
{
// for example, FastCall2 can't work with functions which do user level context switch
if (last_code)
{
throw EXCEPTION("This function cannot be called from the callback: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
if (!func->lle_func)
{
throw EXCEPTION("LLE function not set: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
if (func->flags & MFF_FORCED_HLE)
{
throw EXCEPTION("Forced HLE enabled: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
}
LOG_TRACE(HLE, "Branch to LLE function: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
if (index & EIF_PERFORM_BLR)
{
throw EXCEPTION("TODO: Branch with link: %s (0x%llx)", get_ps3_function_name(func->id), func->id);
// CPU.LR = CPU.PC + 4;
}
const auto data = vm::_ptr<u32>(func->lle_func.addr());
ppu.PC = data[0] - 4;
ppu.GPR[2] = data[1]; // set rtoc
return;
}
// change current syscall/NID value
ppu.hle_code = func->id;
if (func->lle_func && !(func->flags & MFF_FORCED_HLE))
{
// call LLE function if available
const auto data = vm::_ptr<u32>(func->lle_func.addr());
const u32 pc = data[0];
const u32 rtoc = data[1];
LOG_TRACE(HLE, "LLE function called: %s", get_ps3_function_name(func->id));
ppu.fast_call(pc, rtoc);
LOG_TRACE(HLE, "LLE function finished: %s -> 0x%llx", get_ps3_function_name(func->id), ppu.GPR[3]);
}
else if (func->func)
{
LOG_TRACE(HLE, "HLE function called: %s", get_ps3_function_name(func->id));
func->func(ppu);
LOG_TRACE(HLE, "HLE function finished: %s -> 0x%llx", get_ps3_function_name(func->id), ppu.GPR[3]);
}
else
{
LOG_TODO(HLE, "Unimplemented function: %s -> CELL_OK", get_ps3_function_name(func->id));
ppu.GPR[3] = 0;
}
if (index & EIF_PERFORM_BLR)
{
// return if necessary
ppu.PC = VM_CAST(ppu.LR & ~3) - 4;
}
// execute module-specific error check
if ((s64)ppu.GPR[3] < 0 && func->module && func->module->on_error)
{
func->module->on_error(ppu.GPR[3], func);
}
ppu.hle_code = last_code;
}
else
{
throw EXCEPTION("Invalid function index (0x%x)", index);
}
}
void clear_ppu_functions()
{
g_ppu_func_list.clear();
g_ppu_func_subs.clear();
g_ps3_var_list.clear();
}
u32 get_function_id(const char* name)
{
const char* suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; // Symbol name suffix
u8 output[20];
// Compute SHA-1 hash
sha1_context ctx;
sha1_starts(&ctx);
sha1_update(&ctx, (const u8*)name, strlen(name));
sha1_update(&ctx, (const u8*)suffix, strlen(suffix));
sha1_finish(&ctx, output);
return (u32&)output[0];
}
void hook_ppu_func(vm::ptr<u32> base, u32 pos, u32 size)
{
using namespace PPU_instr;
for (auto& sub : g_ppu_func_subs)
{
bool found = sub.ops.size() != 0;
for (u32 k = pos, x = 0; x + 1 <= sub.ops.size(); k++, x++)
{
if (k >= size)
{
found = false;
break;
}
// skip NOP
if (base[k] == 0x60000000)
{
x--;
continue;
}
const be_t<u32> data = sub.ops[x].data;
const be_t<u32> mask = sub.ops[x].mask;
const bool match = (base[k] & mask) == data;
switch (sub.ops[x].type)
{
case SPET_MASKED_OPCODE:
{
// masked pattern
if (!match)
{
found = false;
}
break;
}
case SPET_OPTIONAL_MASKED_OPCODE:
{
// optional masked pattern
if (!match)
{
k--;
}
break;
}
case SPET_LABEL:
{
const u32 addr = (base + k--).addr();
const u32 lnum = data;
const auto label = sub.labels.find(lnum);
if (label == sub.labels.end()) // register the label
{
sub.labels[lnum] = addr;
}
else if (label->second != addr) // or check registered label
{
found = false;
}
break;
}
case SPET_BRANCH_TO_LABEL:
{
if (!match)
{
found = false;
break;
}
const auto addr = (base[k] & 2 ? 0 : (base + k).addr()) + ((s32)base[k] << cntlz32(mask) >> (cntlz32(mask) + 2));
const auto lnum = sub.ops[x].num;
const auto label = sub.labels.find(lnum);
if (label == sub.labels.end()) // register the label
{
sub.labels[lnum] = addr;
}
else if (label->second != addr) // or check registered label
{
found = false;
}
break;
}
//case SPET_BRANCH_TO_FUNC:
//{
// if (!match)
// {
// found = false;
// break;
// }
// const auto addr = (base[k] & 2 ? 0 : (base + k).addr()) + ((s32)base[k] << cntlz32(mask) >> (cntlz32(mask) + 2));
// const auto nid = sub.ops[x].num;
// // TODO: recursive call
//}
default:
{
throw EXCEPTION("Unknown search pattern type (%d)", sub.ops[x].type);
}
}
if (!found)
{
break;
}
}
if (found)
{
LOG_SUCCESS(LOADER, "Function '%s' hooked (addr=*0x%x)", sub.name, base + pos);
sub.found++;
base[pos] = HACK(sub.index | EIF_PERFORM_BLR);
}
if (sub.labels.size())
{
sub.labels.clear();
}
}
}
void hook_ppu_funcs(vm::ptr<u32> base, u32 size)
{
using namespace PPU_instr;
// TODO: optimize search
for (u32 i = 0; i < size; i++)
{
// skip NOP
if (base[i] == 0x60000000)
{
continue;
}
hook_ppu_func(base, i, size);
}
// check functions
for (u32 i = 0; i < g_ppu_func_subs.size(); i++)
{
if (g_ppu_func_subs[i].found > 1)
{
LOG_ERROR(LOADER, "Function '%s' hooked %u times", g_ppu_func_subs[i].found);
}
}
}
bool patch_ppu_import(u32 addr, u32 index)
{
const auto data = vm::cptr<u32>::make(addr);
using namespace PPU_instr;
if (index >= g_ppu_func_list.size())
{
return false;
}
const u32 imm = (g_ppu_func_list[index].flags & MFF_NO_RETURN) && !(g_ppu_func_list[index].flags & MFF_FORCED_HLE)
? index | EIF_USE_BRANCH
: index | EIF_PERFORM_BLR;
// check different patterns:
if (vm::check_addr(addr, 32) &&
(data[0] & 0xffff0000) == LI_(r12, 0) &&
(data[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(data[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
data[3] == STD(r2, r1, 0x28) &&
data[4] == LWZ(r0, r12, 0) &&
data[5] == LWZ(r2, r12, 4) &&
data[6] == MTCTR(r0) &&
data[7] == BCTR())
{
vm::write32(addr, HACK(imm | EIF_SAVE_RTOC));
return true;
}
if (vm::check_addr(addr, 12) &&
(data[0] & 0xffff0000) == LI_(r0, 0) &&
(data[1] & 0xffff0000) == ORIS(r0, r0, 0) &&
(data[2] & 0xfc000003) == B(0, 0, 0))
{
const auto sub = vm::cptr<u32>::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2));
if (vm::check_addr(sub.addr(), 60) &&
sub[0x0] == STDU(r1, r1, -0x80) &&
sub[0x1] == STD(r2, r1, 0x70) &&
sub[0x2] == MR(r2, r0) &&
sub[0x3] == MFLR(r0) &&
sub[0x4] == STD(r0, r1, 0x90) &&
sub[0x5] == LWZ(r2, r2, 0) &&
sub[0x6] == LWZ(r0, r2, 0) &&
sub[0x7] == LWZ(r2, r2, 4) &&
sub[0x8] == MTCTR(r0) &&
sub[0x9] == BCTRL() &&
sub[0xa] == LD(r2, r1, 0x70) &&
sub[0xb] == ADDI(r1, r1, 0x80) &&
sub[0xc] == LD(r0, r1, 0x10) &&
sub[0xd] == MTLR(r0) &&
sub[0xe] == BLR())
{
vm::write32(addr, HACK(imm));
return true;
}
}
if (vm::check_addr(addr, 64) &&
data[0x0] == MFLR(r0) &&
data[0x1] == STD(r0, r1, 0x10) &&
data[0x2] == STDU(r1, r1, -0x80) &&
data[0x3] == STD(r2, r1, 0x70) &&
(data[0x4] & 0xffff0000) == LI_(r2, 0) &&
(data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) &&
data[0x6] == LWZ(r2, r2, 0) &&
data[0x7] == LWZ(r0, r2, 0) &&
data[0x8] == LWZ(r2, r2, 4) &&
data[0x9] == MTCTR(r0) &&
data[0xa] == BCTRL() &&
data[0xb] == LD(r2, r1, 0x70) &&
data[0xc] == ADDI(r1, r1, 0x80) &&
data[0xd] == LD(r0, r1, 0x10) &&
data[0xe] == MTLR(r0) &&
data[0xf] == BLR())
{
vm::write32(addr, HACK(imm));
return true;
}
if (vm::check_addr(addr, 64) &&
data[0x0] == MFLR(r0) &&
data[0x1] == STD(r0, r1, 0x10) &&
data[0x2] == STDU(r1, r1, -0x80) &&
data[0x3] == STD(r2, r1, 0x70) &&
(data[0x4] & 0xffff0000) == LIS(r12, 0) &&
(data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) &&
data[0x6] == LWZ(r0, r12, 0) &&
data[0x7] == LWZ(r2, r12, 4) &&
data[0x8] == MTCTR(r0) &&
data[0x9] == BCTRL() &&
data[0xa] == LD(r2, r1, 0x70) &&
data[0xb] == ADDI(r1, r1, 0x80) &&
data[0xc] == LD(r0, r1, 0x10) &&
data[0xd] == MTLR(r0) &&
data[0xe] == BLR())
{
vm::write32(addr, HACK(imm));
return true;
}
if (vm::check_addr(addr, 56) &&
(data[0x0] & 0xffff0000) == LI_(r12, 0) &&
(data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) &&
(data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) &&
data[0x3] == STD(r2, r1, 0x28) &&
data[0x4] == MFLR(r0) &&
data[0x5] == STD(r0, r1, 0x20) &&
data[0x6] == LWZ(r0, r12, 0) &&
data[0x7] == LWZ(r2, r12, 4) &&
data[0x8] == MTCTR(r0) &&
data[0x9] == BCTRL() &&
data[0xa] == LD(r0, r1, 0x20) &&
data[0xb] == MTLR(r0) &&
data[0xc] == LD(r2, r1, 0x28) &&
data[0xd] == BLR())
{
vm::write32(addr, HACK(imm));
return true;
}
//vm::write32(addr, HACK(imm));
return false;
}
Module<>::Module(const std::string& name, void(*init)())
: _log::channel(name, _log::level::notice)
, m_is_loaded(false)
, m_init(init)
{
}
Module<>::~Module()
{
}
void Module<>::Init()
{
on_load = nullptr;
on_unload = nullptr;
on_stop = nullptr;
on_error = nullptr;
m_init();
}
void Module<>::Load()
{
if (IsLoaded())
{
return;
}
if (on_load)
{
on_load();
}
SetLoaded(true);
}
void Module<>::Unload()
{
if (!IsLoaded())
{
return;
}
if (on_unload)
{
on_unload();
}
SetLoaded(false);
}
void Module<>::SetLoaded(bool loaded)
{
m_is_loaded = loaded;
}
bool Module<>::IsLoaded() const
{
return m_is_loaded;
}

View File

@ -1,185 +0,0 @@
#pragma once
#include "Emu/SysCalls/SC_FUNC.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "ErrorCodes.h"
namespace vm { using namespace ps3; }
template<typename T = void> class Module;
struct ModuleFunc
{
u32 id;
u32 flags;
Module<>* module;
const char* name;
ppu_func_caller func;
vm::ptr<void()> lle_func;
ModuleFunc()
{
}
ModuleFunc(u32 id, u32 flags, Module<>* module, const char* name, ppu_func_caller func, vm::ptr<void()> lle_func = vm::null)
: id(id)
, flags(flags)
, module(module)
, name(name)
, func(func)
, lle_func(lle_func)
{
}
};
struct ModuleVariable
{
u32 id;
Module<>* module;
const char* name;
u32(*retrieve_addr)();
};
enum : u32
{
SPET_MASKED_OPCODE,
SPET_OPTIONAL_MASKED_OPCODE,
SPET_LABEL,
SPET_BRANCH_TO_LABEL,
SPET_BRANCH_TO_FUNC,
};
struct SearchPatternEntry
{
u32 type;
be_t<u32> data;
be_t<u32> mask;
u32 num; // supplement info
};
struct StaticFunc
{
u32 index;
const char* name;
std::vector<SearchPatternEntry> ops;
u32 found;
std::unordered_map<u32, u32> labels;
};
template<> class Module<void> : public _log::channel
{
friend class ModuleManager;
bool m_is_loaded;
void(*m_init)();
protected:
std::function<void()> on_alloc;
public:
Module(const std::string& name, void(*init)());
Module(const Module&) = delete; // Delete copy/move constructors and copy/move operators
~Module();
std::function<void()> on_load;
std::function<void()> on_unload;
std::function<void()> on_stop;
std::function<void(s64 value, ModuleFunc* func)> on_error;
void Init();
void Load();
void Unload();
void SetLoaded(bool loaded = true);
bool IsLoaded() const;
};
// Module<> with an instance of specified type in PS3 memory
template<typename T> class Module : public Module<void>
{
u32 m_addr;
public:
Module(const char* name, void(*init)())
: Module<void>(name, init)
{
on_alloc = [this]
{
static_assert(std::is_trivially_destructible<T>::value, "Module<> instance must be trivially destructible");
//static_assert(std::is_trivially_copy_assignable<T>::value, "Module<> instance must be trivially copy-assignable");
// Allocate module instance and call the default constructor
#include "restore_new.h"
new(vm::base(m_addr = vm::alloc(sizeof(T), vm::main))) T();
#include "define_new_memleakdetect.h"
};
}
T* operator ->() const
{
return vm::_ptr<T>(m_addr);
}
};
u32 add_ppu_func(ModuleFunc func);
void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)());
ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index = nullptr);
ModuleFunc* get_ppu_func_by_index(u32 index);
ModuleVariable* get_variable_by_nid(u32 nid);
void execute_ppu_func_by_index(PPUThread& ppu, u32 id);
extern std::string get_ps3_function_name(u64 fid);
void clear_ppu_functions();
u32 get_function_id(const char* name);
u32 add_ppu_func_sub(StaticFunc sf);
u32 add_ppu_func_sub(const std::initializer_list<SearchPatternEntry>& ops, const char* name, Module<>* module, ppu_func_caller func);
void hook_ppu_funcs(vm::ptr<u32> base, u32 size);
bool patch_ppu_import(u32 addr, u32 index);
// Variable associated with registered HLE function
template<typename T, T Func> struct ppu_func_by_func { static u32 index; };
template<typename T, T Func> u32 ppu_func_by_func<T, Func>::index = 0xffffffffu;
template<typename T, T Func, typename... Args, typename RT = std::result_of_t<T(Args...)>> inline RT call_ppu_func(PPUThread& ppu, Args&&... args)
{
const auto mfunc = get_ppu_func_by_index(ppu_func_by_func<T, Func>::index);
if (mfunc && mfunc->lle_func && (mfunc->flags & MFF_FORCED_HLE) == 0 && (mfunc->flags & MFF_NO_RETURN) == 0)
{
const u32 pc = vm::read32(mfunc->lle_func.addr());
const u32 rtoc = vm::read32(mfunc->lle_func.addr() + 4);
return cb_call<RT, Args...>(ppu, pc, rtoc, std::forward<Args>(args)...);
}
else
{
return Func(std::forward<Args>(args)...);
}
}
// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise
#define CALL_FUNC(ppu, func, ...) call_ppu_func<decltype(&func), &func>(ppu, __VA_ARGS__)
#define REG_FNID(module, nid, func, ...) (ppu_func_by_func<decltype(&func), &func>::index = add_ppu_func(ModuleFunc(nid, { __VA_ARGS__ }, &module, #func, BIND_FUNC(func))))
#define REG_FUNC(module, func, ...) REG_FNID(module, get_function_id(#func), func, __VA_ARGS__)
#define REG_VNID(module, nid, var) add_variable(nid, &module, #var, []{ return vm::get_addr(&module->var); })
#define REG_VARIABLE(module, var) REG_VNID(module, get_function_id(#var), var)
#define REG_SUB(module, ns, name, ...) add_ppu_func_sub({ __VA_ARGS__ }, #name, &module, BIND_FUNC(ns::name))
#define SP_OP(type, op, sup) []() { s32 XXX = 0; SearchPatternEntry res = { (type), (op), 0, (sup) }; XXX = -1; res.mask = (op) ^ ~res.data; return res; }()
#define SP_I(op) SP_OP(SPET_MASKED_OPCODE, op, 0)
#define OPT_SP_I(op) SP_OP(SPET_OPTIONAL_MASKED_OPCODE, op, 0)
#define SET_LABEL(label) { SPET_LABEL, (label) }
#define SP_LABEL_BR(op, label) SP_OP(SPET_BRANCH_TO_LABEL, op, label)
#define SP_CALL(op, name) SP_OP(SPET_BRANCH_TO_FUNC, op, get_function_id(#name))
#define UNIMPLEMENTED_FUNC(module) module.todo("%s", __FUNCTION__)

File diff suppressed because it is too large Load Diff