mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-25 12:12:50 +01:00
commit
c267ca2584
@ -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)
|
||||
{
|
||||
|
@ -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)...));
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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__;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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__;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user