ARMv7: ARM encoding introduced; bugfixes

This commit is contained in:
Nekotekina 2015-02-02 12:14:49 +03:00
parent dab80497bb
commit 23c7028b2a
16 changed files with 161 additions and 109 deletions

View File

@ -14,6 +14,12 @@
#define __noinline __attribute__((noinline))
#endif
#ifdef _WIN32
#define __safebuffers __declspec(safebuffers)
#else
#define __safebuffers
#endif
template<size_t size>
void strcpy_trunc(char(&dst)[size], const std::string& src)
{

View File

@ -132,5 +132,5 @@ void log_message(Log::LogType type, Log::LogSeverity sev, std::string text);
template<typename... Targs>
__noinline void log_message(Log::LogType type, Log::LogSeverity sev, const char* fmt, Targs... args)
{
log_message(type, sev, fmt::detail::format(fmt, strlen(fmt), fmt::do_unveil(args)...));
log_message(type, sev, fmt::detail::format(fmt, fmt::do_unveil(args)...));
}

View File

@ -144,8 +144,9 @@ size_t fmt::detail::get_fmt_precision(const char* fmt, size_t len)
return 1;
}
std::string fmt::detail::format(const char* fmt, size_t len)
std::string fmt::detail::format(const char* fmt)
{
const size_t len = strlen(fmt);
const size_t fmt_start = get_fmt_start(fmt, len);
if (fmt_start != len)
{

View File

@ -429,16 +429,17 @@ namespace fmt
}
};
std::string format(const char* fmt, size_t len); // terminator
std::string format(const char* fmt); // terminator
template<typename T, typename... Args>
std::string format(const char* fmt, size_t len, const T& arg, Args... args)
std::string format(const char* fmt, const T& arg, Args... args)
{
const size_t len = strlen(fmt);
const size_t fmt_start = get_fmt_start(fmt, len);
const size_t fmt_len = get_fmt_len(fmt + fmt_start, len - fmt_start);
const size_t fmt_end = fmt_start + fmt_len;
return std::string(fmt, fmt_start) + get_fmt<T>::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, len - fmt_end, args...);
return std::string(fmt, fmt_start) + get_fmt<T>::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, args...);
}
};
@ -551,9 +552,9 @@ namespace fmt
Other features are not supported.
*/
template<typename... Args>
__forceinline std::string format(const char* fmt, Args... args)
__forceinline __safebuffers std::string format(const char* fmt, Args... args)
{
return detail::format(fmt, strlen(fmt), do_unveil(args)...);
return detail::format(fmt, do_unveil(args)...);
}
//convert a wxString to a std::string encoded in utf8

View File

@ -137,7 +137,7 @@ struct ARMv7Context
}
else
{
write_pc(value & ~1);
write_pc(value);
}
}

View File

@ -1159,9 +1159,44 @@ struct ARMv7_op4t_table_t
}
}
}
const ARMv7_opcode_t* HACK()
{
for (auto& opcode : table)
{
if (opcode->func == ARMv7_instrs::HACK)
{
return opcode;
}
}
throw "HACK instruction not found";
}
} g_op4t;
struct ARMv7_op4arm_table_t
{
std::vector<const ARMv7_opcode_t*> table;
ARMv7_op4arm_table_t()
{
for (auto& opcode : ARMv7_opcode_table)
{
if (opcode.type >= A1)
{
if (opcode.code & ~opcode.mask)
{
LOG_ERROR(GENERAL, "%s: wrong opcode mask (mask=0x%08x, code=0x%08x)", opcode.name, opcode.mask, opcode.code);
}
table.push_back(&opcode);
}
}
}
} g_op4arm;
std::unordered_map<u32, const ARMv7_opcode_t*> g_opct;
void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
@ -1231,16 +1266,21 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
const u32 i2 = (code.data >> 11) & 0x1 ^ s ^ 1;
const u32 target = (addr + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (code.data & 0x3ff0000) >> 4 | (code.data & 0x7ff) << 1);
// possibly a call to imported function:
if (target >= end_addr && ((target - end_addr) % 16) == 0 && vm::psv::read16(target) == 0xf870)
{
const u32 instr = vm::psv::read32(target);
const u32 instr = vm::psv::read32(target);
// check if not "unimplemented"
if (instr >> 16)
// possibly a call to imported function:
if (target >= end_addr && ((target - end_addr) % 16) == 0 && (instr & 0xfff000f0) == 0xe0700090)
{
// check if implemented
if (const u32 func = (instr & 0xfff00) >> 4 | (instr & 0xf))
{
// replace BLX with "hack" instruction directly, it can help to see where it was called from
vm::psv::write32(addr, instr);
// replace BLX with "HACK" instruction directly (in Thumb form), it can help to see where it was called from
vm::psv::write32(addr, 0xf870 | func << 16);
g_opct[0xf8700000 | func] = g_op4t.HACK();
}
else
{
// leave as is if unimplemented
}
}
else
@ -1257,50 +1297,60 @@ void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump)
addr += found->length;
}
while (vm::psv::read16(addr) == 0xf870)
{
g_opct[0xf8700000 | vm::psv::read16(addr + 2)] = g_op4t.table[0];
addr += 16;
}
LOG_NOTICE(ARMv7, "armv7_decoder_initialize() finished, g_opct.size() = %lld", (u64)g_opct.size());
}
u32 ARMv7Decoder::DecodeMemory(const u32 address)
{
if (address & 0x1)
{
throw "ARMv7Decoder::DecodeMemory() failed (something is wrong with instruction set)";
}
ARMv7Code code = {};
code.code0 = vm::psv::read16(address);
if (auto opcode = g_op2t.data[code.code0])
if (m_ctx.ISET == Thumb)
{
(*opcode->func)(m_ctx, code, opcode->type);
return 2;
code.code0 = vm::psv::read16(address);
if (auto opcode = g_op2t.data[code.code0])
{
(*opcode->func)(m_ctx, code, opcode->type);
return 2;
}
code.code1 = code.code0;
code.code0 = vm::psv::read16(address + 2);
auto op = g_opct.find(code.data);
if (op != g_opct.end())
{
(*op->second->func)(m_ctx, code, op->second->type);
return 4;
}
//for (auto opcode : g_op4t.table)
//{
// if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data)))
// {
// (*opcode->func)(m_ctx, code, opcode->type);
// return 4;
// }
//}
}
code.code1 = code.code0;
code.code0 = vm::psv::read16(address + 2);
auto op = g_opct.find(code.data);
if (op != g_opct.end())
else if (m_ctx.ISET == ARM)
{
(*op->second->func)(m_ctx, code, op->second->type);
return 4;
code.data = vm::psv::read32(address);
for (auto opcode : g_op4arm.table)
{
if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data)))
{
(*opcode->func)(m_ctx, code, opcode->type);
return 4;
}
}
}
//for (auto opcode : g_op4t.table)
//{
// if ((code.data & opcode->mask) == opcode->code && (!opcode->skip || !opcode->skip(code.data)))
// {
// (*opcode->func)(m_ctx, code, opcode->type);
// return 4;
// }
//}
else
{
throw "ARMv7Decoder::DecodeMemory() failed (invalid instruction set set)";
}
ARMv7_instrs::UNK(m_ctx, code);
return 4;

View File

@ -280,7 +280,14 @@ namespace ARMv7_instrs
void ARMv7_instrs::UNK(ARMv7Context& context, const ARMv7Code code)
{
throw fmt::format("Unknown/illegal opcode: 0x%04x 0x%04x", code.code1, code.code0);
if (context.ISET == Thumb)
{
throw fmt::format("Unknown/illegal opcode: 0x%04x 0x%04x", code.code1, code.code0);
}
else
{
throw fmt::format("Unknown/illegal opcode: 0x%08x", code.data);
}
}
void ARMv7_instrs::HACK(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
@ -976,16 +983,7 @@ void ARMv7_instrs::BLX(ARMv7Context& context, const ARMv7Code code, const ARMv7_
if (ConditionPassed(context, cond))
{
context.LR = newLR;
if (target & 1)
{
context.ISET = Thumb;
context.thread.SetBranch(target & ~1);
}
else
{
context.ISET = ARM;
context.thread.SetBranch(target);
}
context.write_pc(target);
}
}
@ -1014,16 +1012,7 @@ void ARMv7_instrs::BX(ARMv7Context& context, const ARMv7Code code, const ARMv7_e
if (ConditionPassed(context, cond))
{
if (target & 1)
{
context.ISET = Thumb;
context.thread.SetBranch(target & ~1);
}
else
{
context.ISET = ARM;
context.thread.SetBranch(target);
}
context.write_pc(target);
}
}

View File

@ -12,7 +12,8 @@
void ARMv7Context::write_pc(u32 value)
{
thread.SetBranch(value);
ISET = value & 1 ? Thumb : ARM;
thread.SetBranch(value & ~1);
}
u32 ARMv7Context::read_pc()
@ -109,10 +110,11 @@ ARMv7Thread::~ARMv7Thread()
void ARMv7Thread::InitRegs()
{
memset(context.GPR, 0, sizeof(context.GPR[0]) * 15);
memset(context.GPR, 0, sizeof(context.GPR));
context.APSR.APSR = 0;
context.IPSR.IPSR = 0;
//context.ISET = Thumb;
context.ISET = PC & 1 ? Thumb : ARM; // select instruction set
context.thread.SetPc(PC & ~1); // and fix PC
context.ITSTATE.IT = 0;
context.SP = m_stack_addr + m_stack_size;
context.TLS = armv7_get_tls(GetId());

View File

@ -48,12 +48,12 @@ s32 sceKernelCreateThread(
ARMv7Thread& new_thread = static_cast<ARMv7Thread&>(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7));
const auto id = new_thread.GetId();
new_thread.SetEntry(entry.addr() ^ 1);
new_thread.SetEntry(entry.addr());
new_thread.SetPrio(initPriority);
new_thread.SetStackSize(stackSize);
new_thread.SetName(pName.get_ptr());
sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id -> 0x%x", pName.get_ptr(), entry, id);
sceLibKernel.Warning("*** New ARMv7 Thread [%s] (entry=0x%x): id -> 0x%x", pName.get_ptr(), entry, id);
new_thread.Run();
return id;

View File

@ -59,7 +59,7 @@ s32 sceRtcCheckValid(vm::psv::ptr<const SceDateTime> pTime)
throw __FUNCTION__;
}
s32 sceRtcSetTime_t(vm::psv::ptr<SceDateTime> pTime, time_t iTime)
s32 sceRtcSetTime_t(vm::psv::ptr<SceDateTime> pTime, u32 iTime)
{
throw __FUNCTION__;
}
@ -69,7 +69,7 @@ s32 sceRtcSetTime64_t(vm::psv::ptr<SceDateTime> pTime, u64 ullTime)
throw __FUNCTION__;
}
s32 sceRtcGetTime_t(vm::psv::ptr<const SceDateTime> pTime, vm::psv::ptr<time_t> piTime)
s32 sceRtcGetTime_t(vm::psv::ptr<const SceDateTime> pTime, vm::psv::ptr<u32> piTime)
{
throw __FUNCTION__;
}

View File

@ -69,7 +69,7 @@ namespace vm
void error(const u64 addr, const char* func)
{
throw fmt::format("%s(): invalid address 0x%llx", func, addr);
throw fmt::format("%s(): failed to cast 0x%llx (too big value)", func, addr);
}
namespace ps3
@ -249,7 +249,10 @@ namespace vm
case CPU_THREAD_ARMv7:
{
assert(!"stack_pop(): ARMv7 not supported");
ARMv7Context& context = static_cast<ARMv7Thread&>(CPU).context;
assert(context.SP == addr);
context.SP = old_pos;
return;
}

View File

@ -17,9 +17,9 @@ class LogBase
void LogOutput(LogType type, const std::string& text) const;
template<typename... Targs>
__noinline void LogPrepare(LogType type, const char* fmt, size_t len, Targs... args) const
__noinline void LogPrepare(LogType type, const char* fmt, Targs... args) const
{
LogOutput(type, fmt::detail::format(fmt, len, args...));
LogOutput(type, fmt::detail::format(fmt, args...));
}
public:
@ -38,7 +38,7 @@ public:
template<typename... Targs>
__forceinline void Notice(const char* fmt, Targs... args) const
{
LogPrepare(LogNotice, fmt, strlen(fmt), fmt::do_unveil(args)...);
LogPrepare(LogNotice, fmt, fmt::do_unveil(args)...);
}
template<typename... Targs>
@ -53,25 +53,25 @@ public:
template<typename... Targs>
__forceinline void Success(const char* fmt, Targs... args) const
{
LogPrepare(LogSuccess, fmt, strlen(fmt), fmt::do_unveil(args)...);
LogPrepare(LogSuccess, fmt, fmt::do_unveil(args)...);
}
template<typename... Targs>
__forceinline void Warning(const char* fmt, Targs... args) const
{
LogPrepare(LogWarning, fmt, strlen(fmt), fmt::do_unveil(args)...);
LogPrepare(LogWarning, fmt, fmt::do_unveil(args)...);
}
template<typename... Targs>
__forceinline void Error(const char* fmt, Targs... args) const
{
LogPrepare(LogError, fmt, strlen(fmt), fmt::do_unveil(args)...);
LogPrepare(LogError, fmt, fmt::do_unveil(args)...);
}
template<typename... Targs>
__forceinline void Todo(const char* fmt, Targs... args) const
{
LogPrepare(LogTodo, fmt, strlen(fmt), fmt::do_unveil(args)...);
LogPrepare(LogTodo, fmt, fmt::do_unveil(args)...);
}
};

View File

@ -372,7 +372,7 @@ s32 cellSaveDataListSave2(
for (u32 i=0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
*dirList[i].reserved = {};
memset(dirList[i].reserved, 0, sizeof(dirList[i].reserved));
}
funcList(result, listGet, listSet);
@ -464,7 +464,7 @@ s32 cellSaveDataListLoad2(
for (u32 i=0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
*dirList[i].reserved = {};
memset(dirList[i].reserved, 0, sizeof(dirList[i].reserved));
}
funcList(result, listGet, listSet);
@ -553,7 +553,7 @@ s32 cellSaveDataFixedSave2(
for (u32 i = 0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
*dirList[i].reserved = {};
memset(dirList[i].reserved, 0, sizeof(dirList[i].reserved));
}
funcFixed(result, listGet, fixedSet);
if (result->result < 0) {
@ -629,7 +629,7 @@ s32 cellSaveDataFixedLoad2(
for (u32 i = 0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
*dirList[i].reserved = {};
memset(dirList[i].reserved, 0, sizeof(dirList[i].reserved));
}
funcFixed(result, listGet, fixedSet);
if (result->result < 0) {
@ -826,7 +826,7 @@ s32 cellSaveDataListAutoSave(
//for (u32 i = 0; i<saveEntries.size(); i++) {
// strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName.c_str());
// strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam.c_str());
// *dirList[i].reserved = {};
// memset(dirList[i].reserved, 0, sizeof(dirList[i].reserved));
//}
//funcFixed(result, listGet, fixedSet);
@ -909,7 +909,7 @@ s32 cellSaveDataListAutoLoad(
//for (u32 i = 0; i<saveEntries.size(); i++) {
// strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
// strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
// *dirList[i].reserved = {};
// memset(dirList[i].reserved, 0, sizeof(dirList[i].reserved));
//}
//funcFixed(result, listGet, fixedSet);

View File

@ -850,8 +850,8 @@ void syncLFQueueInit(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u8> buffer, u32 siz
queue->m_depth = depth;
queue->m_buffer = buffer;
queue->m_direction = direction;
*queue->m_hs1 = {};
*queue->m_hs2 = {};
memset(queue->m_hs1, 0, sizeof(queue->m_hs1));
memset(queue->m_hs2, 0, sizeof(queue->m_hs2));
queue->m_eaSignal = eaSignal;
if (direction == CELL_SYNC_QUEUE_ANY2ANY)

View File

@ -217,6 +217,7 @@ int cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfiguration
videoOut, config.addr(), option.addr());
if (option) *option = {};
*config = {};
switch(videoOut)
{
@ -224,13 +225,11 @@ int cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfiguration
config->resolutionId = Emu.GetGSManager().GetInfo().mode.resolutionId;
config->format = Emu.GetGSManager().GetInfo().mode.format;
config->aspect = Emu.GetGSManager().GetInfo().mode.aspect;
*config->reserved = {};
config->pitch = Emu.GetGSManager().GetInfo().mode.pitch;
return CELL_VIDEO_OUT_SUCCEEDED;
case CELL_VIDEO_OUT_SECONDARY:
*config = {}; // ???
return CELL_VIDEO_OUT_SUCCEEDED;
}
@ -478,22 +477,25 @@ int cellAudioOutGetState(u32 audioOut, u32 deviceIndex, vm::ptr<CellAudioOutStat
{
cellSysutil->Warning("cellAudioOutGetState(audioOut=0x%x, deviceIndex=0x%x, state_addr=0x%x)", audioOut, deviceIndex, state.addr());
*state = {};
switch(audioOut)
{
case CELL_AUDIO_OUT_PRIMARY:
state->state = Emu.GetAudioManager().GetState();
state->encoder = Emu.GetAudioManager().GetInfo().mode.encoder;
*state->reserved = {};
state->downMixer = Emu.GetAudioManager().GetInfo().mode.downMixer;
state->soundMode.type = Emu.GetAudioManager().GetInfo().mode.type;
state->soundMode.channel = Emu.GetAudioManager().GetInfo().mode.channel;
state->soundMode.fs = Emu.GetAudioManager().GetInfo().mode.fs;
state->soundMode.reserved = 0;
state->soundMode.layout = Emu.GetAudioManager().GetInfo().mode.layout;
return CELL_AUDIO_OUT_SUCCEEDED;
case CELL_AUDIO_OUT_SECONDARY:
*state = { CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED };
state->state = CELL_AUDIO_OUT_OUTPUT_STATE_DISABLED;
return CELL_AUDIO_OUT_SUCCEEDED;
}
@ -534,19 +536,18 @@ int cellAudioOutGetConfiguration(u32 audioOut, vm::ptr<CellAudioOutConfiguration
cellSysutil->Warning("cellAudioOutGetConfiguration(audioOut=%d, config_addr=0x%x, option_addr=0x%x)", audioOut, config.addr(), option.addr());
if (option) *option = {};
*config = {};
switch(audioOut)
{
case CELL_AUDIO_OUT_PRIMARY:
config->channel = Emu.GetAudioManager().GetInfo().mode.channel;
config->encoder = Emu.GetAudioManager().GetInfo().mode.encoder;
*config->reserved = {};
config->downMixer = Emu.GetAudioManager().GetInfo().mode.downMixer;
return CELL_AUDIO_OUT_SUCCEEDED;
case CELL_AUDIO_OUT_SECONDARY:
*config = {};
return CELL_AUDIO_OUT_SUCCEEDED;
}

View File

@ -104,6 +104,10 @@ namespace loader
vm::psv::ptr<u32> sceLibcHeapDelayedAlloc;
u32 unk2;
u32 unk3;
vm::psv::ptr<u32> __sce_libcmallocreplace;
vm::psv::ptr<u32> __sce_libcnewreplace;
};
struct psv_process_param_t
@ -233,18 +237,14 @@ namespace loader
LOG_NOTICE(LOADER, "Imported function %s (nid=0x%08x, addr=0x%x)", func->name, nid, addr);
}
// writing Thumb code (temporarily, because it should be ARM)
vm::psv::write16(addr + 0, 0xf870); // HACK instruction (Thumb)
vm::psv::write16(addr + 2, (u16)get_psv_func_index(func)); // function index
vm::psv::write16(addr + 4, 0x4770); // BX LR
vm::psv::write16(addr + 6, 0); // null
const u32 code = get_psv_func_index(func);
vm::psv::write32(addr + 0, 0xe0700090 | (code & 0xfff0) << 4 | (code & 0xf)); // HACK instruction (ARM)
}
else
{
LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr);
vm::psv::write16(addr + 0, 0xf870); // HACK instruction (Thumb)
vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub)
vm::psv::write32(addr + 0, 0xe0700090); // HACK instruction (ARM), unimplemented stub (code 0)
vm::psv::write32(addr + 4, nid); // nid
}
@ -404,8 +404,7 @@ namespace loader
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 0;
const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 0;
/* TODO: Thumb/ARM encoding selection */
armv7_thread(entry & ~1, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run();
armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run();
break;
}
case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break;