1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-25 12:12:50 +01:00

Merge pull request #989 from Nekotekina/master

Various improvements
This commit is contained in:
B1ackDaemon 2015-02-02 13:39:51 +02:00
commit c267ca2584
34 changed files with 825 additions and 340 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

@ -37,6 +37,25 @@ struct ARMv7Context
};
u32 LR;
union
{
struct
{
u32 reserved0 : 16;
u32 GE : 4;
u32 reserved1 : 4;
u32 dummy : 3;
u32 Q : 1; // Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result
u32 V : 1; // Overflow condition code flag
u32 C : 1; // Carry condition code flag
u32 Z : 1; // Zero condition code flag
u32 N : 1; // Negative condition code flag
};
u32 APSR;
} APSR;
};
struct
@ -45,22 +64,6 @@ struct ARMv7Context
};
};
union
{
struct
{
u32 N : 1; //Negative condition code flag
u32 Z : 1; //Zero condition code flag
u32 C : 1; //Carry condition code flag
u32 V : 1; //Overflow condition code flag
u32 Q : 1; //Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result
u32 dummy : 27;
};
u32 APSR;
} APSR;
union
{
struct
@ -111,9 +114,19 @@ struct ARMv7Context
} ITSTATE;
u32 TLS;
u32 R_ADDR;
u64 R_DATA;
struct perf_counter
{
u32 event;
u32 value;
};
std::array<perf_counter, 6> counters;
void write_gpr(u32 n, u32 value)
{
assert(n < 16);
@ -124,7 +137,7 @@ struct ARMv7Context
}
else
{
write_pc(value & ~1);
write_pc(value);
}
}

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include <unordered_map>
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "ARMv7Thread.h"
#include "ARMv7Interpreter.h"
#include "ARMv7Opcodes.h"
@ -1159,8 +1160,43 @@ 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)
@ -1230,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);
// 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)
{
// replace BLX with "hack" instruction directly, it can help to see where it was called from
vm::psv::write32(addr, instr);
// check if implemented
if (const u32 func = (instr & 0xfff00) >> 4 | (instr & 0xf))
{
// 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
@ -1256,23 +1297,15 @@ 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", g_opct.size());
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 = {};
if (m_ctx.ISET == Thumb)
{
code.code0 = vm::psv::read16(address);
if (auto opcode = g_op2t.data[code.code0])
@ -1299,6 +1332,24 @@ u32 ARMv7Decoder::DecodeMemory(const u32 address)
// return 4;
// }
//}
}
else if (m_ctx.ISET == ARM)
{
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;
}
}
}
else
{
throw "ARMv7Decoder::DecodeMemory() failed (invalid instruction set set)";
}
ARMv7_instrs::UNK(m_ctx, code);
return 4;

View File

@ -191,7 +191,7 @@ namespace ARMv7_instrs
template<typename T> T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow)
{
const T sign_mask = (T)1 << (sizeof(T) - 1);
const T sign_mask = (T)1 << (sizeof(T) * 8 - 1);
T result = x + y;
carry_out = ((x & y) | ((x ^ y) & ~result)) & sign_mask;
@ -280,7 +280,14 @@ namespace ARMv7_instrs
void ARMv7_instrs::UNK(ARMv7Context& context, const ARMv7Code code)
{
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)
@ -316,10 +323,10 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7
switch (type)
{
case T1:
case A1:
case T1: case A1:
case T2: case A2:
{
cond = context.ITSTATE.advance();
cond = type == A1 ? code.data >> 28 : context.ITSTATE.advance();
t = (code.data & 0xf000) >> 12;
cp = (code.data & 0xf00) >> 8;
opc1 = (code.data & 0xe00000) >> 21;
@ -327,8 +334,8 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7
cn = (code.data & 0xf0000) >> 16;
cm = (code.data & 0xf);
reject(cp - 10 < 2, "Advanced SIMD and VFP");
reject(t == 13 && type == T1, "UNPREDICTABLE");
reject(cp - 10 < 2 && (type == T1 || type == A1), "Advanced SIMD and VFP");
reject(t == 13 && (type == T1 || type == T2), "UNPREDICTABLE");
break;
}
default: throw __FUNCTION__;
@ -336,15 +343,19 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7
if (ConditionPassed(context, cond))
{
if (cp == 15 && opc1 == 0 && cn == 13 && cm == 0 && opc2 == 3)
{
LOG_ERROR(ARMv7, "TODO: TLS requested");
// APSR flags are written if t = 15
if (t < 15)
if (t < 15 && cp == 15 && opc1 == 0 && cn == 13 && cm == 0 && opc2 == 3)
{
context.GPR[t] = 0;
return;
// Read CP15 User Read-only Thread ID Register (seems used as TLS address)
if (!context.TLS)
{
throw "TLS not initialized";
}
context.GPR[t] = context.TLS;
return;
}
throw fmt::format("Bad instruction: mrc p%d,%d,r%d,c%d,c%d,%d", cp, opc1, t, cn, cm, opc2);
@ -819,6 +830,7 @@ void ARMv7_instrs::B(ARMv7Context& context, const ARMv7Code code, const ARMv7_en
if (ConditionPassed(context, cond))
{
//LOG_NOTICE(ARMv7, "Branch to 0x%x (cond=0x%x)", context.thread.PC + jump, cond);
context.thread.SetBranch(context.thread.PC + jump);
}
}
@ -971,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);
}
}
@ -1009,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);
}
}
@ -1170,6 +1164,7 @@ void ARMv7_instrs::CMP_REG(ARMv7Context& context, const ARMv7Code code, const AR
}
case T3:
{
cond = context.ITSTATE.advance();
n = (code.data & 0xf0000) >> 16;
m = (code.data & 0xf);
shift_t = DecodeImmShift((code.data & 0x30) >> 4, (code.data & 0x7000) >> 10 | (code.data & 0xc0) >> 6, &shift_n);
@ -1183,13 +1178,17 @@ void ARMv7_instrs::CMP_REG(ARMv7Context& context, const ARMv7Code code, const AR
if (ConditionPassed(context, cond))
{
const u32 m_value = context.read_gpr(m);
const u32 n_value = context.read_gpr(n);
bool carry, overflow;
const u32 shifted = Shift(context.read_gpr(m), shift_t, shift_n, true);
const u32 res = AddWithCarry(context.read_gpr(n), ~shifted, true, carry, overflow);
const u32 shifted = Shift(m_value, shift_t, shift_n, true);
const u32 res = AddWithCarry(n_value, ~shifted, true, carry, overflow);
context.APSR.N = res >> 31;
context.APSR.Z = res == 0;
context.APSR.C = carry;
context.APSR.V = overflow;
//LOG_NOTICE(ARMv7, "CMP: r%d=0x%08x <> r%d=0x%08x, shifted=0x%08x, res=0x%08x", n, n_value, m, m_value, shifted, res);
}
}
@ -1615,11 +1614,60 @@ void ARMv7_instrs::LDRH_REG(ARMv7Context& context, const ARMv7Code code, const A
void ARMv7_instrs::LDRSB_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
{
u32 cond, t, n, imm32;
bool index, add, wback;
switch (type)
{
case T1:
{
cond = context.ITSTATE.advance();
t = (code.data & 0xf000) >> 12;
n = (code.data & 0xf0000) >> 16;
imm32 = (code.data & 0xfff);
index = true;
add = true;
wback = false;
reject(t == 15, "PLI");
reject(n == 15, "LDRSB (literal)");
reject(t == 13, "UNPREDICTABLE");
break;
}
case T2:
{
cond = context.ITSTATE.advance();
t = (code.data & 0xf000) >> 12;
n = (code.data & 0xf0000) >> 16;
imm32 = (code.data & 0xff);
index = (code.data & 0x400);
add = (code.data & 0x200);
wback = (code.data & 0x100);
reject(t == 15 && index && !add && !wback, "PLI");
reject(n == 15, "LDRSB (literal)");
reject(index && add && !wback, "LDRSBT");
reject(!index && !wback, "UNDEFINED");
reject(t == 13 || t == 15 || (wback && n == t), "UNPREDICTABLE");
break;
}
case A1: throw __FUNCTION__;
default: throw __FUNCTION__;
}
if (ConditionPassed(context, cond))
{
const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32;
const u32 addr = index ? offset_addr : context.read_gpr(n);
const s8 value = vm::psv::read8(addr);
context.write_gpr(t, value); // sign-extend
if (wback)
{
context.write_gpr(n, offset_addr);
}
}
}
void ARMv7_instrs::LDRSB_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)

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()
@ -30,6 +31,69 @@ void ARMv7Context::fast_call(u32 addr)
return thread.FastCall(addr);
}
#define TLS_MAX 128
u32 g_armv7_tls_start;
std::array<std::atomic<u32>, TLS_MAX> g_armv7_tls_owners;
void armv7_init_tls()
{
g_armv7_tls_start = Emu.GetTLSMemsz() ? vm::cast(Memory.PSV.RAM.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096)) : 0;
for (auto& v : g_armv7_tls_owners)
{
v.store(0, std::memory_order_relaxed);
}
}
u32 armv7_get_tls(u32 thread)
{
if (!Emu.GetTLSMemsz() || !thread)
{
return 0;
}
for (u32 i = 0; i < TLS_MAX; i++)
{
if (g_armv7_tls_owners[i] == thread)
{
return g_armv7_tls_start + i * Emu.GetTLSMemsz(); // if already initialized, return TLS address
}
}
for (u32 i = 0; i < TLS_MAX; i++)
{
u32 old = 0;
if (g_armv7_tls_owners[i].compare_exchange_strong(old, thread))
{
const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address
memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
memset(vm::get_ptr(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros
return addr;
}
}
throw "Out of TLS memory";
}
void armv7_free_tls(u32 thread)
{
if (!Emu.GetTLSMemsz())
{
return;
}
for (auto& v : g_armv7_tls_owners)
{
u32 old = thread;
if (v.compare_exchange_strong(old, 0))
{
return;
}
}
}
ARMv7Thread::ARMv7Thread()
: CPUThread(CPU_THREAD_ARMv7)
, context(*this)
@ -39,22 +103,39 @@ ARMv7Thread::ARMv7Thread()
{
}
ARMv7Thread::~ARMv7Thread()
{
armv7_free_tls(GetId());
}
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());
context.R_ADDR = 0;
}
void ARMv7Thread::InitStack()
{
if(!m_stack_addr)
if (!m_stack_addr)
{
m_stack_size = 0x10000;
m_stack_addr = (u32)Memory.Alloc(0x10000, 1);
assert(m_stack_size);
m_stack_addr = vm::cast(Memory.Alloc(m_stack_size, 4096));
}
}
void ARMv7Thread::CloseStack()
{
if (m_stack_addr)
{
Memory.Free(m_stack_addr);
m_stack_addr = 0;
}
}
@ -149,7 +230,7 @@ void ARMv7Thread::FastStop()
m_status = Stopped;
}
arm7_thread::arm7_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio)
armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio)
{
thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
@ -160,3 +241,47 @@ arm7_thread::arm7_thread(u32 entry, const std::string& name, u32 stack_size, u32
argc = 0;
}
cpu_thread& armv7_thread::args(std::initializer_list<std::string> values)
{
assert(argc == 0);
if (!values.size())
{
return *this;
}
std::vector<char> argv_data;
u32 argv_size = 0;
for (auto& arg : values)
{
const u32 arg_size = vm::cast(arg.size(), "arg.size()"); // get arg size
for (char c : arg)
{
argv_data.push_back(c); // append characters
}
argv_data.push_back('\0'); // append null terminator
argv_size += arg_size + 1;
argc++;
}
argv = vm::cast(Memory.PSV.RAM.AllocAlign(argv_size, 4096)); // allocate arg list
memcpy(vm::get_ptr(argv), argv_data.data(), argv_size); // copy arg list
return *this;
}
cpu_thread& armv7_thread::run()
{
thread->Run();
// set arguments
static_cast<ARMv7Thread*>(thread)->context.GPR[0] = argc;
static_cast<ARMv7Thread*>(thread)->context.GPR[1] = argv;
return *this;
}

View File

@ -1,28 +1,19 @@
#pragma once
#include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/Memory.h"
#include "ARMv7Context.h"
class ARMv7Thread : public CPUThread
{
public:
ARMv7Context context;
//u32 m_arg;
//u8 m_last_instr_size;
//const char* m_last_instr_name;
ARMv7Thread();
//void update_code(const u32 address)
//{
// code.code0 = vm::psv::read16(address & ~1);
// code.code1 = vm::psv::read16(address + 2 & ~1);
// m_arg = address & 0x1 ? code.code1 << 16 | code.code0 : code.data;
//}
~ARMv7Thread();
public:
virtual void InitRegs();
virtual void InitStack();
virtual void CloseStack();
u32 GetStackArg(u32 pos);
void FastCall(u32 addr);
void FastStop();
@ -41,48 +32,16 @@ protected:
virtual void DoCode();
};
class arm7_thread : cpu_thread
class armv7_thread : cpu_thread
{
static const u32 stack_align = 0x10;
vm::ptr<u64> argv;
u32 argv;
u32 argc;
vm::ptr<u64> envp;
public:
arm7_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0);
armv7_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0);
cpu_thread& args(std::initializer_list<std::string> values) override
{
if (!values.size())
return *this;
cpu_thread& args(std::initializer_list<std::string> values) override;
//assert(argc == 0);
//envp.set(vm::alloc((u32)sizeof(envp), stack_align, vm::main));
//*envp = 0;
//argv.set(vm::alloc(u32(sizeof(argv)* values.size()), stack_align, vm::main));
for (auto &arg : values)
{
//u32 arg_size = align(u32(arg.size() + 1), stack_align);
//u32 arg_addr = vm::alloc(arg_size, stack_align, vm::main);
//std::strcpy(vm::get_ptr<char>(arg_addr), arg.c_str());
//argv[argc++] = arg_addr;
}
return *this;
}
cpu_thread& run() override
{
thread->Run();
//static_cast<ARMv7Thread*>(thread)->GPR[0] = argc;
//static_cast<ARMv7Thread*>(thread)->GPR[1] = argv.addr();
//static_cast<ARMv7Thread*>(thread)->GPR[2] = envp.addr();
return *this;
}
cpu_thread& run() override;
};

View File

@ -42,18 +42,18 @@ s32 sceKernelCreateThread(
s32 cpuAffinityMask,
vm::psv::ptr<const SceKernelThreadOptParam> pOptParam)
{
sceLibKernel.Error("sceKernelCreateThread(pName=0x%x, entry=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=0x%x)",
sceLibKernel.Warning("sceKernelCreateThread(pName=0x%x, entry=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=0x%x)",
pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam);
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;
@ -61,7 +61,7 @@ s32 sceKernelCreateThread(
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pArgBlock)
{
sceLibKernel.Error("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=0x%x)", threadId, argSize, pArgBlock);
sceLibKernel.Warning("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=0x%x)", threadId, argSize, pArgBlock);
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId, CPU_THREAD_ARMv7);
@ -93,7 +93,7 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pAr
s32 sceKernelExitThread(ARMv7Context& context, s32 exitStatus)
{
sceLibKernel.Error("sceKernelExitThread(exitStatus=0x%x)", exitStatus);
sceLibKernel.Warning("sceKernelExitThread(exitStatus=0x%x)", exitStatus);
// exit status is stored in r0
context.thread.Stop();
@ -103,7 +103,7 @@ s32 sceKernelExitThread(ARMv7Context& context, s32 exitStatus)
s32 sceKernelDeleteThread(s32 threadId)
{
sceLibKernel.Error("sceKernelDeleteThread(threadId=0x%x)", threadId);
sceLibKernel.Warning("sceKernelDeleteThread(threadId=0x%x)", threadId);
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId, CPU_THREAD_ARMv7);
@ -125,7 +125,7 @@ s32 sceKernelDeleteThread(s32 threadId)
s32 sceKernelExitDeleteThread(ARMv7Context& context, s32 exitStatus)
{
sceLibKernel.Error("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus);
sceLibKernel.Warning("sceKernelExitDeleteThread(exitStatus=0x%x)", exitStatus);
// exit status is stored in r0
context.thread.Stop();
@ -261,7 +261,7 @@ s32 sceKernelDelayThreadCB(u32 usec)
s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
{
sceLibKernel.Error("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
sceLibKernel.Warning("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId, CPU_THREAD_ARMv7);

View File

@ -16,7 +16,7 @@ namespace sce_libc_func
{
void __cxa_atexit(vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> arg, vm::psv::ptr<void> dso)
{
sceLibc.Error("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso);
sceLibc.Warning("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso);
LV2_LOCK(0);
@ -28,7 +28,7 @@ namespace sce_libc_func
void __aeabi_atexit(vm::psv::ptr<void> arg, vm::psv::ptr<atexit_func_t> func, vm::psv::ptr<void> dso)
{
sceLibc.Error("__aeabi_atexit(arg=0x%x, func=0x%x, dso=0x%x)", arg, func, dso);
sceLibc.Warning("__aeabi_atexit(arg=0x%x, func=0x%x, dso=0x%x)", arg, func, dso);
LV2_LOCK(0);
@ -40,7 +40,7 @@ namespace sce_libc_func
void exit(ARMv7Context& context)
{
sceLibc.Error("exit()");
sceLibc.Warning("exit()");
LV2_LOCK(0);
@ -117,7 +117,7 @@ namespace sce_libc_func
void printf(ARMv7Context& context, vm::psv::ptr<const char> fmt) // va_args...
{
sceLibc.Error("printf(fmt=0x%x)", fmt);
sceLibc.Warning("printf(fmt=0x%x)", fmt);
sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr());
@ -126,7 +126,7 @@ namespace sce_libc_func
void sprintf(ARMv7Context& context, vm::psv::ptr<char> str, vm::psv::ptr<const char> fmt) // va_args...
{
sceLibc.Error("sprintf(str=0x%x, fmt=0x%x)", str, fmt);
sceLibc.Warning("sprintf(str=0x%x, fmt=0x%x)", str, fmt);
sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr());
@ -139,28 +139,28 @@ namespace sce_libc_func
void __cxa_set_dso_handle_main(vm::psv::ptr<void> dso)
{
sceLibc.Error("__cxa_set_dso_handle_main(dso=0x%x)", dso);
sceLibc.Warning("__cxa_set_dso_handle_main(dso=0x%x)", dso);
g_dso = dso;
}
void memcpy(vm::psv::ptr<void> dst, vm::psv::ptr<const void> src, u32 size)
{
sceLibc.Error("memcpy(dst=0x%x, src=0x%x, size=0x%x)", dst, src, size);
sceLibc.Warning("memcpy(dst=0x%x, src=0x%x, size=0x%x)", dst, src, size);
::memcpy(dst.get_ptr(), src.get_ptr(), size);
}
void memset(vm::psv::ptr<void> dst, s32 value, u32 size)
{
sceLibc.Error("memset(dst=0x%x, value=%d, size=0x%x)", dst, value, size);
sceLibc.Warning("memset(dst=0x%x, value=%d, size=0x%x)", dst, value, size);
::memset(dst.get_ptr(), value, size);
}
void _Assert(vm::psv::ptr<const char> text, vm::psv::ptr<const char> func)
{
sceLibc.Error("_Assert(text=0x%x, func=0x%x)", text, func);
sceLibc.Warning("_Assert(text=0x%x, func=0x%x)", text, func);
LOG_ERROR(TTY, "%s : %s\n", func.get_ptr(), text.get_ptr());
Emu.Pause();

View File

@ -8,20 +8,17 @@ namespace sce_libstdcxx_func
{
void __aeabi_unwind_cpp_pr0()
{
sceLibstdcxx.Todo(__FUNCTION__);
Emu.Pause();
throw __FUNCTION__;
}
void __aeabi_unwind_cpp_pr1()
{
sceLibstdcxx.Todo(__FUNCTION__);
Emu.Pause();
throw __FUNCTION__;
}
void __aeabi_unwind_cpp_pr2()
{
sceLibstdcxx.Todo(__FUNCTION__);
Emu.Pause();
throw __FUNCTION__;
}
}

View File

@ -2,48 +2,242 @@
#include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/SysCalls/lv2/sys_time.h"
#define RETURN_ERROR(code) { Emu.Pause(); scePerf.Error("%s() failed: %s", __FUNCTION__, #code); return code; }
extern psv_log_base scePerf;
s32 scePerfArmPmonReset(s32 threadId)
enum
{
scePerf.Todo("scePerfArmPmonReset(threadId=0x%x)", threadId);
// Error Codes
SCE_PERF_ERROR_INVALID_ARGUMENT = 0x80580000,
};
enum : s32
{
// Thread IDs
SCE_PERF_ARM_PMON_THREAD_ID_ALL = -1,
SCE_PERF_ARM_PMON_THREAD_ID_SELF = 0,
};
enum : u32
{
// Counter Numbers
SCE_PERF_ARM_PMON_CYCLE_COUNTER = 31,
SCE_PERF_ARM_PMON_COUNTER_5 = 5,
SCE_PERF_ARM_PMON_COUNTER_4 = 4,
SCE_PERF_ARM_PMON_COUNTER_3 = 3,
SCE_PERF_ARM_PMON_COUNTER_2 = 2,
SCE_PERF_ARM_PMON_COUNTER_1 = 1,
SCE_PERF_ARM_PMON_COUNTER_0 = 0,
// Counter Masks
SCE_PERF_ARM_PMON_COUNTER_MASK_5 = 0x20,
SCE_PERF_ARM_PMON_COUNTER_MASK_4 = 0x10,
SCE_PERF_ARM_PMON_COUNTER_MASK_3 = 0x08,
SCE_PERF_ARM_PMON_COUNTER_MASK_2 = 0x04,
SCE_PERF_ARM_PMON_COUNTER_MASK_1 = 0x02,
SCE_PERF_ARM_PMON_COUNTER_MASK_0 = 0x01,
SCE_PERF_ARM_PMON_COUNTER_MASK_ALL = 0x3f,
};
enum : u8
{
// Performance Counter Events
SCE_PERF_ARM_PMON_SOFT_INCREMENT = 0x00,
SCE_PERF_ARM_PMON_ICACHE_MISS = 0x01,
SCE_PERF_ARM_PMON_ITLB_MISS = 0x02,
SCE_PERF_ARM_PMON_DCACHE_MISS = 0x03,
SCE_PERF_ARM_PMON_DCACHE_ACCESS = 0x04,
SCE_PERF_ARM_PMON_DTLB_MISS = 0x05,
SCE_PERF_ARM_PMON_DATA_READ = 0x06,
SCE_PERF_ARM_PMON_DATA_WRITE = 0x07,
SCE_PERF_ARM_PMON_EXCEPTION_TAKEN = 0x09,
SCE_PERF_ARM_PMON_EXCEPTION_RETURN = 0x0A,
SCE_PERF_ARM_PMON_WRITE_CONTEXTID = 0x0B,
SCE_PERF_ARM_PMON_SOFT_CHANGEPC = 0x0C,
SCE_PERF_ARM_PMON_IMMEDIATE_BRANCH = 0x0D,
SCE_PERF_ARM_PMON_UNALIGNED = 0x0F,
SCE_PERF_ARM_PMON_BRANCH_MISPREDICT = 0x10,
SCE_PERF_ARM_PMON_PREDICT_BRANCH = 0x12,
SCE_PERF_ARM_PMON_COHERENT_LF_MISS = 0x50,
SCE_PERF_ARM_PMON_COHERENT_LF_HIT = 0x51,
SCE_PERF_ARM_PMON_ICACHE_STALL = 0x60,
SCE_PERF_ARM_PMON_DCACHE_STALL = 0x61,
SCE_PERF_ARM_PMON_MAINTLB_STALL = 0x62,
SCE_PERF_ARM_PMON_STREX_PASSED = 0x63,
SCE_PERF_ARM_PMON_STREX_FAILED = 0x64,
SCE_PERF_ARM_PMON_DATA_EVICTION = 0x65,
SCE_PERF_ARM_PMON_ISSUE_NO_DISPATCH = 0x66,
SCE_PERF_ARM_PMON_ISSUE_EMPTY = 0x67,
SCE_PERF_ARM_PMON_INST_RENAME = 0x68,
SCE_PERF_ARM_PMON_PREDICT_FUNC_RET = 0x6E,
SCE_PERF_ARM_PMON_MAIN_PIPE = 0x70,
SCE_PERF_ARM_PMON_SECOND_PIPE = 0x71,
SCE_PERF_ARM_PMON_LS_PIPE = 0x72,
SCE_PERF_ARM_PMON_FPU_RENAME = 0x73,
SCE_PERF_ARM_PMON_PLD_STALL = 0x80,
SCE_PERF_ARM_PMON_WRITE_STALL = 0x81,
SCE_PERF_ARM_PMON_INST_MAINTLB_STALL = 0x82,
SCE_PERF_ARM_PMON_DATA_MAINTLB_STALL = 0x83,
SCE_PERF_ARM_PMON_INST_UTLB_STALL = 0x84,
SCE_PERF_ARM_PMON_DATA_UTLB_STALL = 0x85,
SCE_PERF_ARM_PMON_DMB_STALL = 0x86,
SCE_PERF_ARM_PMON_INTEGER_CLOCK = 0x8A,
SCE_PERF_ARM_PMON_DATAENGINE_CLOCK = 0x8B,
SCE_PERF_ARM_PMON_ISB = 0x90,
SCE_PERF_ARM_PMON_DSB = 0x91,
SCE_PERF_ARM_PMON_DMB = 0x92,
SCE_PERF_ARM_PMON_EXT_INTERRUPT = 0x93,
SCE_PERF_ARM_PMON_PLE_LINE_REQ_COMPLETED = 0xA0,
SCE_PERF_ARM_PMON_PLE_CHANNEL_SKIPPED = 0xA1,
SCE_PERF_ARM_PMON_PLE_FIFO_FLUSH = 0xA2,
SCE_PERF_ARM_PMON_PLE_REQ_COMPLETED = 0xA3,
SCE_PERF_ARM_PMON_PLE_FIFO_OVERFLOW = 0xA4,
SCE_PERF_ARM_PMON_PLE_REQ_PROGRAMMED = 0xA5,
};
s32 scePerfArmPmonReset(ARMv7Context& context, s32 threadId)
{
scePerf.Warning("scePerfArmPmonReset(threadId=0x%x)", threadId);
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
{
throw __FUNCTION__;
}
context.counters = {};
return SCE_OK;
}
s32 scePerfArmPmonSelectEvent(s32 threadId, u32 counter, u8 eventCode)
s32 scePerfArmPmonSelectEvent(ARMv7Context& context, s32 threadId, u32 counter, u8 eventCode)
{
scePerf.Warning("scePerfArmPmonSelectEvent(threadId=0x%x, counter=0x%x, eventCode=0x%x)", threadId, counter, eventCode);
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
{
throw __FUNCTION__;
}
if (counter >= 6)
{
RETURN_ERROR(SCE_PERF_ERROR_INVALID_ARGUMENT);
}
u32 value = 0; // initial value
switch (eventCode)
{
case SCE_PERF_ARM_PMON_SOFT_INCREMENT: break;
case SCE_PERF_ARM_PMON_BRANCH_MISPREDICT:
case SCE_PERF_ARM_PMON_DCACHE_MISS:
case SCE_PERF_ARM_PMON_UNALIGNED:
{
value = 1; // these events will probably never be implemented
break;
}
case SCE_PERF_ARM_PMON_PREDICT_BRANCH:
case SCE_PERF_ARM_PMON_DCACHE_ACCESS:
{
value = 1000; // these events will probably never be implemented
break;
}
default: throw "scePerfArmPmonSelectEvent(): unknown event requested";
}
context.counters[counter].event = eventCode;
context.counters[counter].value = value;
return SCE_OK;
}
s32 scePerfArmPmonStart(s32 threadId)
s32 scePerfArmPmonStart(ARMv7Context& context, s32 threadId)
{
scePerf.Warning("scePerfArmPmonStart(threadId=0x%x)", threadId);
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
{
throw __FUNCTION__;
}
return SCE_OK;
}
s32 scePerfArmPmonStop(s32 threadId)
s32 scePerfArmPmonStop(ARMv7Context& context, s32 threadId)
{
scePerf.Warning("scePerfArmPmonStop(threadId=0x%x)");
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
{
throw __FUNCTION__;
}
return SCE_OK;
}
s32 scePerfArmPmonGetCounterValue(s32 threadId, u32 counter, vm::psv::ptr<u32> pValue)
s32 scePerfArmPmonGetCounterValue(ARMv7Context& context, s32 threadId, u32 counter, vm::psv::ptr<u32> pValue)
{
scePerf.Warning("scePerfArmPmonGetCounterValue(threadId=0x%x, counter=%d, pValue=0x%x)", threadId, counter, pValue);
if (threadId != SCE_PERF_ARM_PMON_THREAD_ID_SELF)
{
throw __FUNCTION__;
}
if (counter >= 6 && counter != SCE_PERF_ARM_PMON_CYCLE_COUNTER)
{
RETURN_ERROR(SCE_PERF_ERROR_INVALID_ARGUMENT);
}
if (counter < 6)
{
*pValue = context.counters[counter].value;
}
else
{
throw "scePerfArmPmonGetCounterValue(): cycle counter requested";
}
return SCE_OK;
}
s32 scePerfArmPmonSoftwareIncrement(u32 mask)
s32 scePerfArmPmonSoftwareIncrement(ARMv7Context& context, u32 mask)
{
throw __FUNCTION__;
scePerf.Warning("scePerfArmPmonSoftwareIncrement(mask=0x%x)", mask);
if (mask > SCE_PERF_ARM_PMON_COUNTER_MASK_ALL)
{
RETURN_ERROR(SCE_PERF_ERROR_INVALID_ARGUMENT);
}
for (u32 i = 0; i < 6; i++, mask >>= 1)
{
if (mask & 1)
{
context.counters[i].value++;
}
}
return SCE_OK;
}
u64 scePerfGetTimebaseValue()
{
throw __FUNCTION__;
scePerf.Warning("scePerfGetTimebaseValue()");
return get_system_time();
}
u32 scePerfGetTimebaseFrequency()
{
throw __FUNCTION__;
scePerf.Warning("scePerfGetTimebaseFrequency()");
return 1;
}
s32 _sceRazorCpuInit(vm::psv::ptr<const void> pBufferBase, u32 bufferSize, u32 numPerfCounters, vm::psv::ptr<vm::psv::ptr<u32>> psceRazorVars)

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

@ -64,17 +64,6 @@ void CPUThread::Reset()
DoReset();
}
void CPUThread::CloseStack()
{
if(m_stack_addr)
{
Memory.StackMem.Free(m_stack_addr);
m_stack_addr = 0;
}
m_stack_size = 0;
}
void CPUThread::SetId(const u32 id)
{
m_id = id;

View File

@ -1,8 +1,7 @@
#pragma once
#include "Utilities/Thread.h"
enum CPUThreadType :unsigned char
enum CPUThreadType : unsigned char
{
CPU_THREAD_PPU,
CPU_THREAD_SPU,
@ -46,10 +45,10 @@ protected:
bool m_trace_call_stack;
public:
virtual void InitRegs()=0;
virtual void InitRegs() = 0;
virtual void InitStack()=0;
virtual void CloseStack();
virtual void InitStack() = 0;
virtual void CloseStack() = 0;
u32 GetStackAddr() const { return m_stack_addr; }
u32 GetStackSize() const { return m_stack_size; }

View File

@ -25,18 +25,3 @@ PPCThread::~PPCThread()
void PPCThread::DoReset()
{
}
void PPCThread::InitStack()
{
if(m_stack_addr) return;
if(m_stack_size == 0) m_stack_size = 0x10000;
m_stack_addr = (u32)Memory.StackMem.AllocAlign(m_stack_size, 0x100);
/*
m_stack_point += m_stack_size - 0x10;
m_stack_point &= -0x10;
vm::write64(m_stack_point, 0);
m_stack_point -= 0x60;
vm::write64(m_stack_point, m_stack_point + 0x60);
*/
}

View File

@ -4,9 +4,6 @@
class PPCThread : public CPUThread
{
public:
virtual void InitRegs()=0;
virtual void InitStack();
virtual std::string GetThreadName() const
{
return fmt::format("%s[0x%08x]", GetFName(), PC);

View File

@ -65,33 +65,8 @@ void PPUThread::InitRegs()
const u32 pc = entry ? vm::read32(entry) : 0;
const u32 rtoc = entry ? vm::read32(entry + 4) : 0;
//ConLog.Write("entry = 0x%x", entry);
//ConLog.Write("rtoc = 0x%x", rtoc);
SetPc(pc);
/*
const s32 thread_num = Emu.GetCPU().GetThreadNumById(GetType(), GetId());
if(thread_num < 0)
{
LOG_ERROR(PPU, "GetThreadNumById failed.");
Emu.Pause();
return;
}
*/
/*
const s32 tls_size = Emu.GetTLSFilesz() * thread_num;
if(tls_size >= Emu.GetTLSMemsz())
{
LOG_ERROR(PPU, "Out of TLS memory.");
Emu.Pause();
return;
}
*/
GPR[1] = align(m_stack_addr + m_stack_size, 0x200) - 0x200;
GPR[2] = rtoc;
//GPR[11] = entry;
@ -105,6 +80,24 @@ void PPUThread::InitRegs()
TB = 0;
}
void PPUThread::InitStack()
{
if (!m_stack_addr)
{
assert(m_stack_size);
m_stack_addr = vm::cast(Memory.StackMem.AllocAlign(m_stack_size, 4096));
}
}
void PPUThread::CloseStack()
{
if (m_stack_addr)
{
Memory.StackMem.Free(m_stack_addr);
m_stack_addr = 0;
}
}
void PPUThread::DoRun()
{
switch(Ini.CPUDecoderMode.GetValue())

View File

@ -799,8 +799,10 @@ public:
}
public:
virtual void InitRegs();
virtual void Task();
virtual void InitRegs() override;
virtual void InitStack() override;
virtual void CloseStack() override;
virtual void Task() override;
u64 GetStackArg(s32 i);
u64 FastCall2(u32 addr, u32 rtoc);
void FastStop();

View File

@ -99,6 +99,19 @@ void SPUThread::InitRegs()
m_event_mask = 0;
m_events = 0;
R_ADDR = 0;
}
void SPUThread::InitStack()
{
m_stack_size = 0x1000; // this value is wrong
m_stack_addr = m_offset + 0x40000 - m_stack_size; // stack is the part of SPU Local Storage
}
void SPUThread::CloseStack()
{
// nothing to do here
}
void SPUThread::DoRun()

View File

@ -568,6 +568,8 @@ public:
public:
virtual void InitRegs();
virtual void InitStack();
virtual void CloseStack();
virtual void Task();
void FastCall(u32 ls_addr);
void FastStop();

View File

@ -131,7 +131,7 @@ void MemoryBase::Init(MemoryType type)
case Memory_PSV:
MemoryBlocks.push_back(PSV.RAM.SetRange(0x81000000, 0x10000000));
MemoryBlocks.push_back(UserMemory = PSV.Userspace.SetRange(0x91000000, 0x10000000));
MemoryBlocks.push_back(UserMemory = PSV.Userspace.SetRange(0x91000000, 0x2F000000));
break;
case Memory_PSP:

View File

@ -2,6 +2,7 @@
#include "Memory.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
namespace vm
{
@ -68,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
@ -167,13 +168,14 @@ namespace vm
u32 stack_push(CPUThread& CPU, u32 size, u32 align_v, u32& old_pos)
{
assert(align_v);
switch (CPU.GetType())
{
case CPU_THREAD_PPU:
{
PPUThread& PPU = static_cast<PPUThread&>(CPU);
assert(align_v);
old_pos = (u32)PPU.GPR[1];
PPU.GPR[1] -= align(size, 8); // room minimal possible size
PPU.GPR[1] &= ~(align_v - 1); // fix stack alignment
@ -199,9 +201,23 @@ namespace vm
case CPU_THREAD_ARMv7:
{
assert(!"stack_push(): ARMv7 not supported");
ARMv7Context& context = static_cast<ARMv7Thread&>(CPU).context;
old_pos = context.SP;
context.SP -= align(size, 4); // room minimal possible size
context.SP &= ~(align_v - 1); // fix stack alignment
if (context.SP < CPU.GetStackAddr())
{
// stack overflow
context.SP = old_pos;
return 0;
}
else
{
return context.SP;
}
}
default:
{
@ -233,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

@ -10,6 +10,8 @@ namespace vm
public:
typedef T type;
static_assert(!std::is_pointer<T>::value, "vm::_ref_base<> error: invalid type (pointer)");
static_assert(!std::is_reference<T>::value, "vm::_ref_base<> error: invalid type (reference)");
typedef typename remove_be_t<T>::type le_type;
typedef typename to_be_t<T>::type be_type;

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

@ -23,12 +23,10 @@
Module *sysPrxForUser = nullptr;
u32 g_tls_size; // size of every thread's storage
u32 g_tls_start; // start of TLS memory area
u32 g_tls_image_addr; // address of TLS initialization area
u32 g_tls_image_size; // size of TLS initialization area
#define TLS_MAX 128
u32 g_tls_start; // start of TLS memory area
const u32 TLS_MAX = 256;
std::array<std::atomic<u32>, TLS_MAX> g_tls_owners;
void sys_initialize_tls()
@ -40,19 +38,21 @@ u32 ppu_get_tls(u32 thread)
{
if (!g_tls_start)
{
g_tls_size = vm::cast(Emu.GetTLSMemsz(), "Emu.GetTLSMemsz"); // (not an address for vm::cast, but fine)
g_tls_start = vm::cast(Memory.Alloc(g_tls_size * TLS_MAX, 4096)); // memory for up to TLS_MAX threads
g_tls_image_addr = vm::cast(Emu.GetTLSAddr(), "Emu.GetTLSAddr");
g_tls_image_size = vm::cast(Emu.GetTLSFilesz(), "Emu.GetTLSFilesz");
g_tls_start = vm::cast(Memory.MainMem.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096)); // memory for up to TLS_MAX threads
sysPrxForUser->Notice("Thread Local Storage initialized (g_tls_start=0x%x, size = 0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x",
g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz());
}
sysPrxForUser->Warning("TLS initialized (g_tls_size=0x%x, g_tls_start=0x%x, g_tls_image_addr=0x%x, g_tls_image_size=0x%x)", g_tls_size, g_tls_start, g_tls_image_addr, g_tls_image_size);
if (!thread)
{
return 0;
}
for (u32 i = 0; i < TLS_MAX; i++)
{
if (g_tls_owners[i] == thread)
{
return g_tls_start + i * g_tls_size; // if already initialized, return TLS address
return g_tls_start + i * Emu.GetTLSMemsz(); // if already initialized, return TLS address
}
}
@ -61,9 +61,9 @@ u32 ppu_get_tls(u32 thread)
u32 old = 0;
if (g_tls_owners[i].compare_exchange_strong(old, thread))
{
const u32 addr = g_tls_start + i * g_tls_size; // get TLS address
memset(vm::get_ptr(addr), 0, g_tls_size); // fill TLS area with zeros
memcpy(vm::get_ptr(addr), vm::get_ptr(g_tls_image_addr), g_tls_image_size); // initialize from TLS image
const u32 addr = g_tls_start + i * Emu.GetTLSMemsz(); // get TLS address
memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
memset(vm::get_ptr(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros
return addr;
}
}
@ -420,10 +420,7 @@ void sysPrxForUser_init(Module *pxThis)
{
sysPrxForUser = pxThis;
g_tls_size = 0;
g_tls_start = 0;
g_tls_image_addr = 0;
g_tls_image_size = 0;
for (auto& v : g_tls_owners)
{
v.store(0, std::memory_order_relaxed);

View File

@ -85,10 +85,10 @@ SPUThread* spu_thread_initialize(std::shared_ptr<SpuGroupInfo>& group, u32 spu_n
sys_spu.Todo("Unsupported SPU Thread options (0x%x)", option);
}
u32 spu_ep = (u32)img.entry_point;
const u32 spu_ep = img.entry_point;
// Copy SPU image:
// TODO: use segment info
u32 spu_offset = (u32)Memory.Alloc(256 * 1024, 4096);
const u32 spu_offset = vm::cast(Memory.MainMem.AllocAlign(256 * 1024, 4096));
memcpy(vm::get_ptr<void>(spu_offset), vm::get_ptr<void>(img.addr), 256 * 1024);
SPUThread& new_thread = static_cast<SPUThread&>(Emu.GetCPU().AddThread(CPU_THREAD_SPU));
@ -218,7 +218,7 @@ s32 sys_spu_thread_group_destroy(u32 id)
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(group_info->list[i]);
if (t)
{
Memory.Free(((SPUThread*)t.get())->GetOffset());
Memory.MainMem.Free(((SPUThread*)t.get())->GetOffset());
Emu.GetCPU().RemoveThread(group_info->list[i]);
}
}

View File

@ -28,9 +28,9 @@ struct VFS;
struct EmuInfo
{
private:
u64 tls_addr;
u64 tls_filesz;
u64 tls_memsz;
u32 tls_addr;
u32 tls_filesz;
u32 tls_memsz;
sys_process_param_info proc_param;
@ -50,16 +50,16 @@ public:
proc_param.primary_prio = be_t<s32>::make(0x50);
}
void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz)
void SetTLSData(u32 addr, u32 filesz, u32 memsz)
{
tls_addr = addr;
tls_filesz = filesz;
tls_memsz = memsz;
}
u64 GetTLSAddr() const { return tls_addr; }
u64 GetTLSFilesz() const { return tls_filesz; }
u64 GetTLSMemsz() const { return tls_memsz; }
u32 GetTLSAddr() const { return tls_addr; }
u32 GetTLSFilesz() const { return tls_filesz; }
u32 GetTLSMemsz() const { return tls_memsz; }
};
class ModuleInitializer
@ -173,7 +173,7 @@ public:
m_modules_init.push_back(std::move(m));
}
void SetTLSData(const u64 addr, const u64 filesz, const u64 memsz)
void SetTLSData(u32 addr, u32 filesz, u32 memsz)
{
m_info.SetTLSData(addr, filesz, memsz);
}
@ -195,9 +195,9 @@ public:
EmuInfo& GetInfo() { return m_info; }
u64 GetTLSAddr() const { return m_info.GetTLSAddr(); }
u64 GetTLSFilesz() const { return m_info.GetTLSFilesz(); }
u64 GetTLSMemsz() const { return m_info.GetTLSMemsz(); }
u32 GetTLSAddr() const { return m_info.GetTLSAddr(); }
u32 GetTLSFilesz() const { return m_info.GetTLSFilesz(); }
u32 GetTLSMemsz() const { return m_info.GetTLSMemsz(); }
u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; }

View File

@ -11,6 +11,8 @@
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/System.h"
extern void armv7_init_tls();
namespace loader
{
namespace handlers
@ -91,6 +93,41 @@ namespace loader
case MACHINE_MIPS: break;
case MACHINE_ARM:
{
struct psv_libc_param_t
{
u32 size; // 0x0000001c
u32 unk1; // 0x00000000
vm::psv::ptr<u32> sceLibcHeapSize;
vm::psv::ptr<u32> sceLibcHeapSizeDefault;
vm::psv::ptr<u32> sceLibcHeapExtendedAlloc;
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
{
u32 size; // 0x00000030
u32 unk1; // 'PSP2'
u32 unk2; // 0x00000005
u32 unk3;
vm::psv::ptr<const char> sceUserMainThreadName;
vm::psv::ptr<s32> sceUserMainThreadPriority;
vm::psv::ptr<u32> sceUserMainThreadStackSize;
vm::psv::ptr<u32> sceUserMainThreadAttribute;
vm::psv::ptr<const char> sceProcessName;
vm::psv::ptr<u32> sce_process_preload_disabled;
vm::psv::ptr<u32> sceUserMainThreadCpuAffinityMask;
vm::psv::ptr<psv_libc_param_t> __sce_libcparam;
};
initialize_psv_modules();
auto armv7_thr_stop_data = vm::psv::ptr<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4));
@ -102,10 +139,11 @@ namespace loader
u32 fnid_addr = 0;
u32 code_start = 0;
u32 code_end = 0;
u32 vnid_addr = 0;
std::unordered_map<u32, u32> vnid_list;
auto proc_param = vm::psv::ptr<psv_process_param_t>::make(0);
for (auto& shdr : m_shdrs)
{
// get secton name
@ -128,24 +166,40 @@ namespace loader
code_start = shdr.data_le.sh_addr;
code_end = shdr.data_le.sh_size + code_start;
}
else if (!strcmp(name.c_str(), ".sceModuleInfo.rodata"))
else if (!strcmp(name.c_str(), ".sceExport.rodata"))
{
LOG_NOTICE(LOADER, ".sceModuleInfo.rodata analysis...");
LOG_NOTICE(LOADER, ".sceExport.rodata analysis...");
auto code = vm::psv::ptr<const u32>::make(shdr.data_le.sh_addr);
auto enid = vm::psv::ptr<const u32>::make(shdr.data_le.sh_addr);
auto edata = vm::psv::ptr<const u32>::make(enid.addr() + shdr.data_le.sh_size / 2);
// very rough way to find the entry point
while (code[0] != 0xffffffffu)
for (u32 j = 0; j < shdr.data_le.sh_size / 8; j++)
{
entry = code[0] + 0x81000000;
code++;
if (code.addr() >= shdr.data_le.sh_addr + shdr.data_le.sh_size)
switch (const u32 nid = enid[j])
{
LOG_ERROR(LOADER, "Unable to find entry point in .sceModuleInfo.rodata");
entry = 0;
case 0x935cd196: // set entry point
{
entry = edata[j];
break;
}
case 0x6c2224ba: // __sce_moduleinfo
{
// currently nothing, but it should theoretically be the root of analysis instead of section name comparison
break;
}
case 0x70fba1e7: // __sce_process_param
{
proc_param.set(edata[j]);
break;
}
default:
{
LOG_ERROR(LOADER, "Unknown export 0x%08x (addr=0x%08x)", nid, edata[j]);
}
}
}
}
else if (!strcmp(name.c_str(), ".sceFNID.rodata"))
@ -183,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
}
@ -235,9 +285,13 @@ namespace loader
}
else if (!strcmp(name.c_str(), ".tbss"))
{
LOG_NOTICE(LOADER, ".tbss analysis");
LOG_NOTICE(LOADER, ".tbss analysis...");
const u32 img_addr = shdr.data_le.sh_addr; // start address of TLS initialization image
const u32 img_size = (&shdr)[1].data_le.sh_addr - img_addr; // calculate its size as the difference between sections
const u32 tls_size = shdr.data_le.sh_size; // full size of TLS
LOG_ERROR(LOADER, "TLS: size=0x%08x", shdr.data_le.sh_size);
LOG_WARNING(LOADER, "TLS: img_addr=0x%08x, img_size=0x%x, tls_size=0x%x", img_addr, img_size, tls_size);
Emu.SetTLSData(img_addr, img_size, tls_size);
}
else if (!strcmp(name.c_str(), ".sceRefs.rodata"))
{
@ -314,9 +368,43 @@ namespace loader
}
}
LOG_NOTICE(LOADER, "__sce_process_param(addr=0x%x) analysis...", proc_param);
if (proc_param->size != 0x30 || proc_param->unk1 != *(u32*)"PSP2" || proc_param->unk2 != 5)
{
LOG_ERROR(LOADER, "__sce_process_param: unexpected data found (size=0x%x, 0x%x, 0x%x, 0x%x)", proc_param->size, proc_param->unk1, proc_param->unk2, proc_param->unk3);
}
LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute);
LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName);
LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask);
auto libc_param = proc_param->__sce_libcparam;
LOG_NOTICE(LOADER, "__sce_libcparam(addr=0x%x) analysis...", libc_param);
if (libc_param->size != 0x1c || libc_param->unk1)
{
LOG_ERROR(LOADER, "__sce_libcparam: unexpected data found (size=0x%x, 0x%x, 0x%x)", libc_param->size, libc_param->unk1, libc_param->unk2);
}
LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize);
LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault);
LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc);
LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc);
armv7_init_tls();
armv7_decoder_initialize(code_start, code_end);
arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run();
const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread";
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? *proc_param->sceUserMainThreadStackSize : 0;
const u32 priority = proc_param->sceUserMainThreadPriority ? *proc_param->sceUserMainThreadPriority : 0;
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;

View File

@ -422,7 +422,10 @@ namespace loader
break;
case 0x00000007: //TLS
Emu.SetTLSData(phdr.p_vaddr.addr(), phdr.p_filesz.value(), phdr.p_memsz.value());
Emu.SetTLSData(
vm::cast(phdr.p_vaddr.addr(), "TLS: phdr.p_vaddr"),
vm::cast(phdr.p_filesz.value(), "TLS: phdr.p_filesz"),
vm::cast(phdr.p_memsz.value(), "TLS: phdr.p_memsz"));
break;
case 0x60000001: //LOOS+1