mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 12:05:23 +00:00
Partial commit: Modules
This commit is contained in:
parent
2553e45d76
commit
7e30a0f464
46 changed files with 1021 additions and 2710 deletions
654
rpcs3/Emu/Cell/Modules/libmixer.cpp
Normal file
654
rpcs3/Emu/Cell/Modules/libmixer.cpp
Normal 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);
|
||||
});
|
|
@ -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);
|
||||
});
|
|
@ -51,5 +51,3 @@ struct CellSnd3RequestQueueCtx
|
|||
vm::bptr<void> rearQueue;
|
||||
be_t<u32> rearQueueSize;
|
||||
};
|
||||
|
||||
extern Module<> libsnd3;
|
|
@ -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);
|
||||
});
|
|
@ -17,5 +17,3 @@ struct CellSoundSynth2EffectAttr
|
|||
be_t<u16> delay;
|
||||
be_t<u16> feedback;
|
||||
};
|
||||
|
||||
extern Module<> libsynth2;
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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;
|
||||
rXmlDocument doc;
|
||||
Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user
|
||||
// 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;
|
||||
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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < TLS_MAX; i++)
|
||||
{
|
||||
if (g_tls_owners[i] == thread)
|
||||
if (g_tls_map[i].exchange(true) == false)
|
||||
{
|
||||
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)
|
||||
// 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)
|
||||
{
|
||||
u32 old = thread;
|
||||
if (v.compare_exchange_strong(old, 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
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);
|
|
@ -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;
|
|
@ -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
|
||||
{
|
|
@ -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();
|
24
rpcs3/Emu/Cell/Modules/sys_libc.cpp
Normal file
24
rpcs3/Emu/Cell/Modules/sys_libc.cpp
Normal 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);
|
||||
});
|
|
@ -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 },
|
||||
);
|
||||
});
|
|
@ -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);
|
|
@ -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; }
|
||||
|
|
@ -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;
|
||||
|
|
@ -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)
|
|
@ -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;
|
||||
|
|
@ -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()
|
||||
{
|
|
@ -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);
|
|
@ -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)
|
||||
// ...
|
||||
|
||||
// Deallocate TLS
|
||||
ppu_free_tls(vm::cast(ppu.GPR[13], HERE) - 0x7030);
|
||||
|
||||
if (ppu.hle_code == 0xaff080a4)
|
||||
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
|
|
@ -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()
|
||||
{
|
|
@ -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)
|
||||
{
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Add table
Reference in a new issue