Make TLS great again

And clean System.h a bit
This commit is contained in:
Nekotekina 2016-07-19 02:33:25 +03:00
parent 6296453ef3
commit fc9fdca3f6
10 changed files with 141 additions and 163 deletions

View File

@ -377,9 +377,9 @@ namespace _spurs
s32 _spurs::get_sdk_version()
{
const s32 version = Emu.GetSDKVersion();
s32 version = -1;
return version == -1 ? 0x465000 : version;
return process_get_sdk_version(process_getpid(), version) || version == -1 ? 0x465000 : version;
}
bool _spurs::is_libprof_loaded()

View File

@ -14,44 +14,44 @@ extern fs::file g_tty;
vm::gvar<s32> sys_prx_version; // ???
#define TLS_SYS 0x30
u32 g_tls_size = 0; // Size of TLS area per thread
u32 g_tls_addr = 0; // Start of TLS memory area
u32 g_tls_max = 0; // Max number of threads
std::unique_ptr<atomic_t<bool>[]> g_tls_map; // I'd like to make it std::vector but it won't work
static u32 s_tls_addr = 0; // TLS image address
static u32 s_tls_file = 0; // TLS image size
static u32 s_tls_zero = 0; // TLS zeroed area size (TLS mem size - TLS image size)
static u32 s_tls_size = 0; // Size of TLS area per thread
static u32 s_tls_area = 0; // Start of TLS memory area
static u32 s_tls_max = 0; // Max number of threads
static std::unique_ptr<atomic_t<bool>[]> s_tls_map; // I'd like to make it std::vector but it won't work
u32 ppu_alloc_tls()
{
for (u32 i = 0; i < g_tls_max; i++)
for (u32 i = 0; i < s_tls_max; i++)
{
if (g_tls_map[i].exchange(true) == false)
if (!s_tls_map[i] && s_tls_map[i].exchange(true) == false)
{
const u32 addr = g_tls_addr + i * g_tls_size; // Calculate TLS address
std::memset(vm::base(addr), 0, TLS_SYS); // Clear system area (TODO)
std::memcpy(vm::base(addr + TLS_SYS), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // Copy TLS image
std::memset(vm::base(addr + TLS_SYS + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // Clear the rest
const u32 addr = s_tls_area + i * s_tls_size; // Calculate TLS address
std::memset(vm::base(addr), 0, 0x30); // Clear system area (TODO)
std::memcpy(vm::base(addr + 0x30), vm::base(s_tls_addr), s_tls_file); // Copy TLS image
std::memset(vm::base(addr + 0x30 + s_tls_file), 0, s_tls_zero); // Clear the rest
return addr;
}
}
sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", g_tls_max);
sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", s_tls_max);
return 0;
}
void ppu_free_tls(u32 addr)
{
// Calculate TLS position
const u32 i = (addr - g_tls_addr) / g_tls_size;
const u32 i = (addr - s_tls_area) / s_tls_size;
if (addr < g_tls_addr || i >= g_tls_max || (addr - g_tls_addr) % g_tls_size)
if (addr < s_tls_area || i >= s_tls_max || (addr - s_tls_area) % s_tls_size)
{
sysPrxForUser.error("ppu_free_tls(0x%x): invalid address", addr);
return;
}
if (g_tls_map[i].exchange(false) == false)
if (s_tls_map[i].exchange(false) == false)
{
sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr);
return;
@ -66,15 +66,18 @@ void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u3
if (ppu.GPR[13] != 0) return;
// Initialize TLS memory
g_tls_size = Emu.GetTLSMemsz() + TLS_SYS;
g_tls_addr = vm::alloc(0x20000, vm::main) + 0x30;
g_tls_max = (0xffd0 / g_tls_size) + (0x10000 / g_tls_size);
g_tls_map = std::make_unique<atomic_t<bool>[]>(g_tls_max);
s_tls_addr = tls_seg_addr;
s_tls_file = tls_seg_size;
s_tls_zero = tls_mem_size - tls_seg_size;
s_tls_size = tls_mem_size + 0x30; // 0x30 is system area size
s_tls_area = vm::alloc(0x20000, vm::main) + 0x30;
s_tls_max = (0xffd0 / s_tls_size) + (0x10000 / s_tls_size);
s_tls_map = std::make_unique<atomic_t<bool>[]>(s_tls_max);
// Allocate TLS for main thread
ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + TLS_SYS;
ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + 0x30;
sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%x)", g_tls_addr - 0x30, g_tls_size, g_tls_max);
sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%x)", s_tls_area - 0x30, s_tls_size, s_tls_max);
// TODO
g_spu_printf_agcb = vm::null;

View File

@ -118,6 +118,8 @@ extern void sys_initialize_tls(PPUThread&, u64, u32, u32, u32);
extern void ppu_initialize(const std::string& name, const std::vector<ppu_function>& set, u32 entry);
extern u32 g_ps3_sdk_version;
// Function lookup table. Not supposed to grow after emulation start.
std::vector<ppu_function_t> g_ppu_function_cache;
@ -946,6 +948,15 @@ void ppu_load_exec(const ppu_exec_object& elf)
// Functions
std::vector<ppu_function> exec_set;
// TLS information
u32 tls_vaddr{0}, tls_fsize{0}, tls_vsize{0};
// Process information
u32 sdk_version = 0x360001;
s32 primary_prio = 0x50;
u32 primary_stacksize = 0x100000;
u32 malloc_pagesize = 0x100000;
// Allocate memory at fixed positions
for (const auto& prog : elf.progs)
{
@ -992,13 +1003,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
case 0x00000007: //TLS
{
const u32 addr = vm::cast(prog.p_vaddr, HERE);
const u32 filesz = fmt::narrow<u32>("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz);
const u32 memsz = fmt::narrow<u32>("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz);
Emu.SetTLSData(addr, filesz, memsz);
LOG_NOTICE(LOADER, "*** TLS segment addr: 0x%08x", Emu.GetTLSAddr());
LOG_NOTICE(LOADER, "*** TLS segment size: 0x%08x", Emu.GetTLSFilesz());
LOG_NOTICE(LOADER, "*** TLS memory size: 0x%08x", Emu.GetTLSMemsz());
tls_vaddr = vm::cast(prog.p_vaddr, HERE);
tls_fsize = fmt::narrow<u32>("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz);
tls_vsize = fmt::narrow<u32>("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz);
break;
}
@ -1025,20 +1032,24 @@ void ppu_load_exec(const ppu_exec_object& elf)
{
LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t));
}
if (info.magic != 0x13bcc5f6)
{
LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic);
}
else
{
sdk_version = info.sdk_version;
primary_prio = info.primary_prio;
primary_stacksize = info.primary_stacksize;
malloc_pagesize = info.malloc_pagesize;
LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version);
LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio);
LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize);
LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize);
LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg);
//LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr);
Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max<u32>(info.primary_stacksize, 0x4000), info.primary_prio);
}
}
break;
@ -1337,16 +1348,19 @@ void ppu_load_exec(const ppu_exec_object& elf)
// Initialize recompiler
ppu_initialize("", exec_set, static_cast<u32>(elf.header.e_entry));
// Set SDK version
g_ps3_sdk_version = sdk_version;
auto ppu = idm::make_ptr<PPUThread>("main_thread");
ppu->pc = entry.addr() & -0x1000;
ppu->stack_size = Emu.GetPrimaryStackSize();
ppu->prio = Emu.GetPrimaryPrio();
ppu->stack_size = std::max<u32>(primary_stacksize, 0x4000);
ppu->prio = primary_prio;
ppu->cpu_init();
ppu->GPR[2] = 0xdeadbeef; // rtoc
ppu->GPR[11] = 0xabadcafe; // OPD ???
ppu->GPR[12] = Emu.GetMallocPageSize();
ppu->GPR[12] = malloc_pagesize;
std::initializer_list<std::string> args = { Emu.GetPath()/*, "-emu"s*/ };
@ -1371,9 +1385,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
// Arguments for sys_initialize_tls()
ppu->GPR[7] = ppu->id;
ppu->GPR[8] = Emu.GetTLSAddr();
ppu->GPR[9] = Emu.GetTLSFilesz();
ppu->GPR[10] = Emu.GetTLSMemsz();
ppu->GPR[8] = tls_vaddr;
ppu->GPR[9] = tls_fsize;
ppu->GPR[10] = tls_vsize;
//ppu->state += cpu_state::interrupt;

View File

@ -25,6 +25,8 @@
logs::channel sys_process("sys_process", logs::level::notice);
u32 g_ps3_sdk_version;
s32 process_getpid()
{
// TODO: get current process id
@ -194,7 +196,7 @@ s32 _sys_process_get_paramsfo(vm::ptr<char> buffer)
s32 process_get_sdk_version(u32 pid, s32& ver)
{
// get correct SDK version for selected pid
ver = Emu.GetSDKVersion();
ver = g_ps3_sdk_version;
return CELL_OK;
}

View File

@ -9,6 +9,7 @@
#include "ARMv7Opcodes.h"
#include "ARMv7Function.h"
#include "ARMv7Module.h"
#include "Modules/sceLibKernel.h"
LOG_CHANNEL(sceAppMgr);
LOG_CHANNEL(sceAppUtil);
@ -71,8 +72,6 @@ LOG_CHANNEL(sceVideodec);
LOG_CHANNEL(sceVoice);
LOG_CHANNEL(sceVoiceQoS);
extern void armv7_init_tls();
extern std::string arm_get_function_name(const std::string& module, u32 fnid);
extern std::string arm_get_variable_name(const std::string& module, u32 vnid);
@ -429,8 +428,6 @@ void arm_load_exec(const arm_exec_object& elf)
LOG_NOTICE(LOADER, "** tls_fsize=0x%x", tls_fsize);
LOG_NOTICE(LOADER, "** tls_vsize=0x%x", tls_vsize);
Emu.SetTLSData(tls_faddr + start_addr, tls_fsize, tls_vsize);
// Process exports
while (libent.addr() < start_addr + module_info->libent_end)
{
@ -635,8 +632,6 @@ void arm_load_exec(const arm_exec_object& elf)
stop_code[1] = 1; // Predefined function index (HLE return)
Emu.SetCPUThreadStop(stop_code.addr());
armv7_init_tls();
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->value() : 256 * 1024;
const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160;
@ -647,6 +642,7 @@ void arm_load_exec(const arm_exec_object& elf)
thread->stack_size = stack_size;
thread->prio = priority;
thread->cpu_init();
thread->TLS = fxm::make_always<arm_tls_manager>(tls_faddr + start_addr, tls_fsize, tls_vsize)->alloc();
// Initialize args
std::vector<char> argv_data;

View File

@ -10,67 +10,6 @@ namespace vm { using namespace psv; }
const arm_decoder<arm_interpreter> s_arm_interpreter;
#define TLS_MAX 128
u32 g_armv7_tls_start;
std::array<atomic_t<u32>, TLS_MAX> g_armv7_tls_owners;
void armv7_init_tls()
{
g_armv7_tls_start = Emu.GetTLSMemsz() ? vm::alloc(Emu.GetTLSMemsz() * TLS_MAX, vm::main) : 0;
for (auto& v : g_armv7_tls_owners)
{
v = 0;
}
}
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++)
{
if (g_armv7_tls_owners[i].compare_and_swap_test(0, thread))
{
const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address
std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
std::memset(vm::base(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros
return addr;
}
}
throw EXCEPTION("Out of TLS memory");
}
void armv7_free_tls(u32 thread)
{
if (!Emu.GetTLSMemsz())
{
return;
}
for (auto& v : g_armv7_tls_owners)
{
if (v.compare_and_swap_test(thread, 0))
{
return;
}
}
}
std::string ARMv7Thread::get_name() const
{
return fmt::format("ARMv7[0x%x] Thread (%s)", id, m_name);
@ -119,7 +58,7 @@ void ARMv7Thread::cpu_init()
PC = PC & ~1; // and fix PC
ITSTATE.IT = 0;
SP = stack_addr + stack_size;
TLS = armv7_get_tls(id);
TLS = 0;
}
extern thread_local std::string(*g_tls_log_prefix)();
@ -174,8 +113,6 @@ void ARMv7Thread::cpu_task_main()
ARMv7Thread::~ARMv7Thread()
{
armv7_free_tls(id);
if (stack_addr)
{
vm::dealloc_verbose_nothrow(stack_addr, vm::main);

View File

@ -15,6 +15,59 @@ logs::channel sceLibKernel("sceLibKernel", logs::level::notice);
extern u64 get_system_time();
arm_tls_manager::arm_tls_manager(u32 vaddr, u32 fsize, u32 vsize)
: vaddr(vaddr)
, fsize(fsize)
, vsize(vsize)
, start(vsize ? vm::alloc(vsize * ::size32(m_map), vm::main) : 0)
{
}
u32 arm_tls_manager::alloc()
{
if (!vsize)
{
return 0;
}
for (u32 i = 0; i < m_map.size(); i++)
{
if (!m_map[i] && m_map[i].exchange(true) == false)
{
const u32 addr = start + i * vsize; // Get TLS address
std::memcpy(vm::base(addr), vm::base(vaddr), fsize); // Initialize from TLS image
std::memset(vm::base(addr + fsize), 0, vsize - fsize); // Fill the rest with zeros
return addr;
}
}
sceLibKernel.error("arm_tls_manager::alloc(): out of TLS memory (max=%zu)", m_map.size());
return 0;
}
void arm_tls_manager::free(u32 addr)
{
if (!addr)
{
return;
}
// Calculate TLS index
const u32 i = (addr - start) / vsize;
if (addr < start || i >= m_map.size() || (addr - start) % vsize)
{
sceLibKernel.error("arm_tls_manager::free(0x%x): invalid address", addr);
return;
}
if (m_map[i].exchange(false) == false)
{
sceLibKernel.error("arm_tls_manager::free(0x%x): deallocation failed", addr);
return;
}
}
s32 sceKernelAllocMemBlock(vm::cptr<char> name, s32 type, u32 vsize, vm::ptr<SceKernelAllocMemBlockOpt> pOpt)
{
throw EXCEPTION("");
@ -46,6 +99,7 @@ arm_error_code sceKernelCreateThread(vm::cptr<char> pName, vm::ptr<SceKernelThre
thread->prio = initPriority;
thread->stack_size = stackSize;
thread->cpu_init();
thread->TLS = fxm::get<arm_tls_manager>()->alloc();
return NOT_AN_ERROR(thread->id);
}
@ -109,6 +163,7 @@ arm_error_code sceKernelDeleteThread(s32 threadId)
// return SCE_KERNEL_ERROR_NOT_DORMANT;
//}
fxm::get<arm_tls_manager>()->free(thread->TLS);
idm::remove<ARMv7Thread>(threadId);
return SCE_OK;
}
@ -120,6 +175,7 @@ arm_error_code sceKernelExitDeleteThread(ARMv7Thread& cpu, s32 exitStatus)
//cpu.state += cpu_state::stop;
// Delete current thread; exit status is stored in r0
fxm::get<arm_tls_manager>()->free(cpu.TLS);
idm::remove<ARMv7Thread>(cpu.id);
return SCE_OK;

View File

@ -3,6 +3,27 @@
#include "Emu/PSP2/ErrorCodes.h"
#include "Emu/PSP2/Modules/Common.h"
// Kernel internal TLS manager (TODO)
class arm_tls_manager
{
std::array<atomic_t<bool>, 128> m_map{};
public:
const u32 vaddr;
const u32 fsize;
const u32 vsize;
const u32 start;
// Initialize from ELF process parameters
arm_tls_manager(u32 vaddr, u32 fsize, u32 vsize);
// Allocate and initialize TLS
u32 alloc();
// Deallocate by address
void free(u32 addr);
};
// Error Codes
enum SceLibKernelError : s32
{

View File

@ -189,7 +189,7 @@ void Emulator::Load()
}
}
ResetInfo();
SetCPUThreadStop(0);
LOG_NOTICE(LOADER, "Path: %s", m_path);

View File

@ -34,25 +34,6 @@ class EmulationStopped {};
class CallbackManager;
struct EmuInfo
{
private:
friend class Emulator;
u32 m_tls_addr = 0;
u32 m_tls_filesz = 0;
u32 m_tls_memsz = 0;
u32 m_sdk_version = 0x360001;
u32 m_malloc_pagesize = 0x100000;
u32 m_primary_stacksize = 0x100000;
s32 m_primary_prio = 0x50;
public:
EmuInfo()
{
}
};
class Emulator final
{
atomic_t<u32> m_status;
@ -66,8 +47,6 @@ class Emulator final
std::unique_ptr<CallbackManager> m_callback_manager;
EmuInfo m_info;
std::string m_path;
std::string m_elf_path;
std::string m_title_id;
@ -133,41 +112,11 @@ public:
return *m_callback_manager;
}
void ResetInfo()
{
m_info = {};
m_cpu_thr_stop = 0;
}
void SetTLSData(u32 addr, u32 filesz, u32 memsz)
{
m_info.m_tls_addr = addr;
m_info.m_tls_filesz = filesz;
m_info.m_tls_memsz = memsz;
}
void SetParams(u32 sdk_ver, u32 malloc_pagesz, u32 stacksz, s32 prio)
{
m_info.m_sdk_version = sdk_ver;
m_info.m_malloc_pagesize = malloc_pagesz;
m_info.m_primary_stacksize = stacksz;
m_info.m_primary_prio = prio;
}
void SetCPUThreadStop(u32 addr)
{
m_cpu_thr_stop = addr;
}
u32 GetTLSAddr() const { return m_info.m_tls_addr; }
u32 GetTLSFilesz() const { return m_info.m_tls_filesz; }
u32 GetTLSMemsz() const { return m_info.m_tls_memsz; }
u32 GetMallocPageSize() { return m_info.m_malloc_pagesize; }
u32 GetSDKVersion() { return m_info.m_sdk_version; }
u32 GetPrimaryStackSize() { return m_info.m_primary_stacksize; }
s32 GetPrimaryPrio() { return m_info.m_primary_prio; }
u32 GetCPUThreadStop() const { return m_cpu_thr_stop; }
bool BootGame(const std::string& path, bool direct = false);