mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 22:11:26 +12:00
TLS for ARMv7 threads
This commit is contained in:
parent
12d1f8202d
commit
61a5459ccb
9 changed files with 115 additions and 64 deletions
|
@ -111,6 +111,8 @@ struct ARMv7Context
|
||||||
|
|
||||||
} ITSTATE;
|
} ITSTATE;
|
||||||
|
|
||||||
|
u32 TLS;
|
||||||
|
|
||||||
u32 R_ADDR;
|
u32 R_ADDR;
|
||||||
u64 R_DATA;
|
u64 R_DATA;
|
||||||
|
|
||||||
|
|
|
@ -336,15 +336,17 @@ void ARMv7_instrs::MRC_(ARMv7Context& context, const ARMv7Code code, const ARMv7
|
||||||
|
|
||||||
if (ConditionPassed(context, cond))
|
if (ConditionPassed(context, cond))
|
||||||
{
|
{
|
||||||
if (cp == 15 && opc1 == 0 && cn == 13 && cm == 0 && opc2 == 3)
|
// APSR flags are written if t = 15
|
||||||
{
|
|
||||||
LOG_ERROR(ARMv7, "TODO: TLS requested");
|
|
||||||
|
|
||||||
if (t < 15)
|
if (t < 15 && cp == 15 && opc1 == 0 && cn == 13 && cm == 0 && opc2 == 3)
|
||||||
|
{
|
||||||
|
if (!context.TLS)
|
||||||
{
|
{
|
||||||
context.GPR[t] = 0;
|
throw "TLS not initialized";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
throw fmt::format("Bad instruction: mrc p%d,%d,r%d,c%d,c%d,%d", cp, opc1, t, cn, cm, opc2);
|
||||||
|
|
|
@ -30,6 +30,69 @@ void ARMv7Context::fast_call(u32 addr)
|
||||||
return thread.FastCall(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())
|
||||||
|
{
|
||||||
|
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
|
||||||
|
memset(vm::get_ptr(addr), 0, Emu.GetTLSMemsz()); // fill TLS area with zeros
|
||||||
|
memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
|
||||||
|
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()
|
ARMv7Thread::ARMv7Thread()
|
||||||
: CPUThread(CPU_THREAD_ARMv7)
|
: CPUThread(CPU_THREAD_ARMv7)
|
||||||
, context(*this)
|
, context(*this)
|
||||||
|
@ -39,6 +102,11 @@ ARMv7Thread::ARMv7Thread()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARMv7Thread::~ARMv7Thread()
|
||||||
|
{
|
||||||
|
armv7_free_tls(GetId());
|
||||||
|
}
|
||||||
|
|
||||||
void ARMv7Thread::InitRegs()
|
void ARMv7Thread::InitRegs()
|
||||||
{
|
{
|
||||||
memset(context.GPR, 0, sizeof(context.GPR[0]) * 15);
|
memset(context.GPR, 0, sizeof(context.GPR[0]) * 15);
|
||||||
|
@ -47,6 +115,7 @@ void ARMv7Thread::InitRegs()
|
||||||
context.ISET = Thumb;
|
context.ISET = Thumb;
|
||||||
context.ITSTATE.IT = 0;
|
context.ITSTATE.IT = 0;
|
||||||
context.SP = m_stack_addr + m_stack_size;
|
context.SP = m_stack_addr + m_stack_size;
|
||||||
|
context.TLS = armv7_get_tls(GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMv7Thread::InitStack()
|
void ARMv7Thread::InitStack()
|
||||||
|
|
|
@ -12,6 +12,7 @@ public:
|
||||||
//const char* m_last_instr_name;
|
//const char* m_last_instr_name;
|
||||||
|
|
||||||
ARMv7Thread();
|
ARMv7Thread();
|
||||||
|
~ARMv7Thread();
|
||||||
|
|
||||||
//void update_code(const u32 address)
|
//void update_code(const u32 address)
|
||||||
//{
|
//{
|
||||||
|
|
|
@ -55,7 +55,7 @@ void PPUThread::DoReset()
|
||||||
XER.XER = 0;
|
XER.XER = 0;
|
||||||
FPSCR.FPSCR = 0;
|
FPSCR.FPSCR = 0;
|
||||||
VSCR.VSCR = 0;
|
VSCR.VSCR = 0;
|
||||||
VRSAVE = 0;
|
VRSAVE = 0;
|
||||||
|
|
||||||
cycle = 0;
|
cycle = 0;
|
||||||
}
|
}
|
||||||
|
@ -65,33 +65,8 @@ void PPUThread::InitRegs()
|
||||||
const u32 pc = entry ? vm::read32(entry) : 0;
|
const u32 pc = entry ? vm::read32(entry) : 0;
|
||||||
const u32 rtoc = entry ? vm::read32(entry + 4) : 0;
|
const u32 rtoc = entry ? vm::read32(entry + 4) : 0;
|
||||||
|
|
||||||
//ConLog.Write("entry = 0x%x", entry);
|
|
||||||
//ConLog.Write("rtoc = 0x%x", rtoc);
|
|
||||||
|
|
||||||
SetPc(pc);
|
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[1] = align(m_stack_addr + m_stack_size, 0x200) - 0x200;
|
||||||
GPR[2] = rtoc;
|
GPR[2] = rtoc;
|
||||||
//GPR[11] = entry;
|
//GPR[11] = entry;
|
||||||
|
|
|
@ -23,12 +23,10 @@
|
||||||
|
|
||||||
Module *sysPrxForUser = nullptr;
|
Module *sysPrxForUser = nullptr;
|
||||||
|
|
||||||
u32 g_tls_size; // size of every thread's storage
|
#define TLS_MAX 128
|
||||||
u32 g_tls_start; // start of TLS memory area
|
|
||||||
u32 g_tls_image_addr; // address of TLS initialization area
|
u32 g_tls_start; // start of TLS memory area
|
||||||
u32 g_tls_image_size; // size of TLS initialization area
|
|
||||||
|
|
||||||
const u32 TLS_MAX = 256;
|
|
||||||
std::array<std::atomic<u32>, TLS_MAX> g_tls_owners;
|
std::array<std::atomic<u32>, TLS_MAX> g_tls_owners;
|
||||||
|
|
||||||
void sys_initialize_tls()
|
void sys_initialize_tls()
|
||||||
|
@ -40,19 +38,16 @@ u32 ppu_get_tls(u32 thread)
|
||||||
{
|
{
|
||||||
if (!g_tls_start)
|
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.MainMem.AllocAlign(Emu.GetTLSMemsz() * TLS_MAX, 4096)); // memory for up to TLS_MAX threads
|
||||||
g_tls_start = vm::cast(Memory.Alloc(g_tls_size * 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_image_addr = vm::cast(Emu.GetTLSAddr(), "Emu.GetTLSAddr");
|
g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz());
|
||||||
g_tls_image_size = vm::cast(Emu.GetTLSFilesz(), "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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < TLS_MAX; i++)
|
for (u32 i = 0; i < TLS_MAX; i++)
|
||||||
{
|
{
|
||||||
if (g_tls_owners[i] == thread)
|
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 +56,9 @@ u32 ppu_get_tls(u32 thread)
|
||||||
u32 old = 0;
|
u32 old = 0;
|
||||||
if (g_tls_owners[i].compare_exchange_strong(old, thread))
|
if (g_tls_owners[i].compare_exchange_strong(old, thread))
|
||||||
{
|
{
|
||||||
const u32 addr = g_tls_start + i * g_tls_size; // get TLS address
|
const u32 addr = g_tls_start + i * Emu.GetTLSMemsz(); // get TLS address
|
||||||
memset(vm::get_ptr(addr), 0, g_tls_size); // fill TLS area with zeros
|
memset(vm::get_ptr(addr), 0, Emu.GetTLSMemsz()); // 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
|
memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,10 +415,7 @@ void sysPrxForUser_init(Module *pxThis)
|
||||||
{
|
{
|
||||||
sysPrxForUser = pxThis;
|
sysPrxForUser = pxThis;
|
||||||
|
|
||||||
g_tls_size = 0;
|
|
||||||
g_tls_start = 0;
|
g_tls_start = 0;
|
||||||
g_tls_image_addr = 0;
|
|
||||||
g_tls_image_size = 0;
|
|
||||||
for (auto& v : g_tls_owners)
|
for (auto& v : g_tls_owners)
|
||||||
{
|
{
|
||||||
v.store(0, std::memory_order_relaxed);
|
v.store(0, std::memory_order_relaxed);
|
||||||
|
|
|
@ -28,9 +28,9 @@ struct VFS;
|
||||||
struct EmuInfo
|
struct EmuInfo
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
u64 tls_addr;
|
u32 tls_addr;
|
||||||
u64 tls_filesz;
|
u32 tls_filesz;
|
||||||
u64 tls_memsz;
|
u32 tls_memsz;
|
||||||
|
|
||||||
sys_process_param_info proc_param;
|
sys_process_param_info proc_param;
|
||||||
|
|
||||||
|
@ -50,16 +50,16 @@ public:
|
||||||
proc_param.primary_prio = be_t<s32>::make(0x50);
|
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_addr = addr;
|
||||||
tls_filesz = filesz;
|
tls_filesz = filesz;
|
||||||
tls_memsz = memsz;
|
tls_memsz = memsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetTLSAddr() const { return tls_addr; }
|
u32 GetTLSAddr() const { return tls_addr; }
|
||||||
u64 GetTLSFilesz() const { return tls_filesz; }
|
u32 GetTLSFilesz() const { return tls_filesz; }
|
||||||
u64 GetTLSMemsz() const { return tls_memsz; }
|
u32 GetTLSMemsz() const { return tls_memsz; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModuleInitializer
|
class ModuleInitializer
|
||||||
|
@ -173,7 +173,7 @@ public:
|
||||||
m_modules_init.push_back(std::move(m));
|
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);
|
m_info.SetTLSData(addr, filesz, memsz);
|
||||||
}
|
}
|
||||||
|
@ -195,9 +195,9 @@ public:
|
||||||
|
|
||||||
EmuInfo& GetInfo() { return m_info; }
|
EmuInfo& GetInfo() { return m_info; }
|
||||||
|
|
||||||
u64 GetTLSAddr() const { return m_info.GetTLSAddr(); }
|
u32 GetTLSAddr() const { return m_info.GetTLSAddr(); }
|
||||||
u64 GetTLSFilesz() const { return m_info.GetTLSFilesz(); }
|
u32 GetTLSFilesz() const { return m_info.GetTLSFilesz(); }
|
||||||
u64 GetTLSMemsz() const { return m_info.GetTLSMemsz(); }
|
u32 GetTLSMemsz() const { return m_info.GetTLSMemsz(); }
|
||||||
|
|
||||||
u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; }
|
u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; }
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "Emu/ARMv7/PSVFuncList.h"
|
#include "Emu/ARMv7/PSVFuncList.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
|
||||||
|
extern void armv7_init_tls();
|
||||||
|
|
||||||
namespace loader
|
namespace loader
|
||||||
{
|
{
|
||||||
namespace handlers
|
namespace handlers
|
||||||
|
@ -235,9 +237,13 @@ namespace loader
|
||||||
}
|
}
|
||||||
else if (!strcmp(name.c_str(), ".tbss"))
|
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"))
|
else if (!strcmp(name.c_str(), ".sceRefs.rodata"))
|
||||||
{
|
{
|
||||||
|
@ -314,6 +320,7 @@ namespace loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
armv7_init_tls();
|
||||||
armv7_decoder_initialize(code_start, code_end);
|
armv7_decoder_initialize(code_start, code_end);
|
||||||
|
|
||||||
arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run();
|
arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run();
|
||||||
|
|
|
@ -422,7 +422,10 @@ namespace loader
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x00000007: //TLS
|
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;
|
break;
|
||||||
|
|
||||||
case 0x60000001: //LOOS+1
|
case 0x60000001: //LOOS+1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue