Loader fixed

This commit is contained in:
Nekotekina 2015-02-17 18:27:15 +03:00
parent 3f3873ceb5
commit 1f2eafc4f2
7 changed files with 107 additions and 87 deletions

View File

@ -680,15 +680,41 @@ bool set_x64_cmp_flags(x64_context* context, size_t d_size, u64 x, u64 y)
size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, size_t d_size, size_t i_size)
{
if ((op == X64OP_MOVS || op == X64OP_STOS) && reg != X64_NOT_SET) // get "full" access size from RCX register
if (op == X64OP_MOVS || op == X64OP_STOS)
{
u64 counter;
if (!get_x64_reg_value(context, reg, 8, i_size, counter))
if (EFLAGS(context) & 0x400 /* direction flag */)
{
return ~0ull;
// skip reservation bound check (TODO)
return 0;
}
return d_size * counter;
if (reg != X64_NOT_SET) // get "full" access size from RCX register
{
u64 counter;
if (!get_x64_reg_value(context, reg, 8, i_size, counter))
{
return -1;
}
return d_size * counter;
}
}
if (op == X64OP_CMPXCHG)
{
// detect whether this instruction can't actually modify memory to avoid breaking reservation;
// this may theoretically cause endless loop, but it shouldn't be a problem if only read_sync() generates such instruction
u64 cmp, exch;
if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch))
{
return -1;
}
if (cmp == exch)
{
// skip reservation bound check
return 0;
}
}
return d_size;
@ -766,23 +792,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
return true;
}
if (op == X64OP_CMPXCHG)
{
// detect whether this instruction can't actually modify memory to avoid breaking reservation;
// this may theoretically cause endless loop, but it shouldn't be a problem if only read_sync() generates such instruction
u64 cmp, exch;
if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch))
{
return false;
}
if (cmp == exch)
{
// this will skip reservation bound check
a_size = 0;
}
}
// check if fault is caused by the reservation
return vm::reservation_query(addr, (u32)a_size, is_writing, [&]() -> bool
{
@ -809,12 +818,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
break;
}
if (d_size > 8)
{
LOG_ERROR(MEMORY, "X64OP_STORE: d_size=%lld", d_size);
return false;
}
u64 reg_value;
if (!get_x64_reg_value(context, reg, d_size, i_size, reg_value))
{
@ -834,7 +837,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
if (vm::get_ptr(addr) != (void*)RDI(context))
{
LOG_ERROR(MEMORY, "X64OP_MOVS error: rdi=0x%llx, addr=0x%x", (u64)RDI(context), addr);
LOG_ERROR(MEMORY, "X64OP_MOVS: rdi=0x%llx, rsi=0x%llx, addr=0x%x", (u64)RDI(context), (u64)RSI(context), addr);
return false;
}
@ -851,7 +854,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
// shift pointers
if (EFLAGS(context) & 0x400 /* direction flag */)
{
// for reversed direction, addr argument should be calculated in different way
LOG_ERROR(MEMORY, "X64OP_MOVS TODO: reversed direction");
return false;
//RSI(context) -= d_size;
@ -890,7 +892,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
if (vm::get_ptr(addr) != (void*)RDI(context))
{
LOG_ERROR(MEMORY, "X64OP_STOS error: rdi=0x%llx, addr=0x%x", (u64)RDI(context), addr);
LOG_ERROR(MEMORY, "X64OP_STOS: rdi=0x%llx, addr=0x%x", (u64)RDI(context), addr);
return false;
}
@ -910,7 +912,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
// shift pointers
if (EFLAGS(context) & 0x400 /* direction flag */)
{
// for reversed direction, addr argument should be calculated in different way
LOG_ERROR(MEMORY, "X64OP_STOS TODO: reversed direction");
return false;
//RDI(context) -= d_size;
@ -939,12 +940,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
}
case X64OP_XCHG:
{
if (d_size != 1 && d_size != 2 && d_size != 4 && d_size != 8)
{
LOG_ERROR(MEMORY, "X64OP_XCHG: d_size=%lld", d_size);
return false;
}
u64 reg_value;
if (!get_x64_reg_value(context, reg, d_size, i_size, reg_value))
{
@ -957,6 +952,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
case 2: reg_value = vm::get_priv_ref<atomic_le_t<u16>>(addr).exchange((u16)reg_value); break;
case 4: reg_value = vm::get_priv_ref<atomic_le_t<u32>>(addr).exchange((u32)reg_value); break;
case 8: reg_value = vm::get_priv_ref<atomic_le_t<u64>>(addr).exchange((u64)reg_value); break;
default: return false;
}
if (!put_x64_reg_value(context, reg, d_size, reg_value))
@ -967,12 +963,6 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
}
case X64OP_CMPXCHG:
{
if (d_size != 1 && d_size != 2 && d_size != 4 && d_size != 8)
{
LOG_ERROR(MEMORY, "X64OP_CMPXCHG: d_size=%lld", d_size);
return false;
}
u64 reg_value, old_value, cmp_value;
if (!get_x64_reg_value(context, reg, d_size, i_size, reg_value) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, cmp_value))
{
@ -985,6 +975,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
case 2: old_value = vm::get_priv_ref<atomic_le_t<u16>>(addr).compare_and_swap((u16)cmp_value, (u16)reg_value); break;
case 4: old_value = vm::get_priv_ref<atomic_le_t<u32>>(addr).compare_and_swap((u32)cmp_value, (u32)reg_value); break;
case 8: old_value = vm::get_priv_ref<atomic_le_t<u64>>(addr).compare_and_swap((u64)cmp_value, (u64)reg_value); break;
default: return false;
}
if (!put_x64_reg_value(context, X64R_RAX, d_size, old_value) || !set_x64_cmp_flags(context, d_size, cmp_value, old_value))

View File

@ -73,7 +73,7 @@ void PPUThread::InitRegs()
//GPR[12] = Emu.GetMallocPageSize();
GPR[13] = ppu_get_tls(GetId()) + 0x7000; // 0x7000 is usually subtracted from r13 to access first TLS element (details are not clear)
LR = Emu.GetCPUThreadExit();
LR = 0;
CTR = PC;
CR.CR = 0x22000082;
VSCR.NJ = 1;

View File

@ -83,7 +83,6 @@ class Emulator
uint m_mode;
u32 m_rsx_callback;
u32 m_cpu_thr_exit;
u32 m_cpu_thr_stop;
std::vector<std::unique_ptr<ModuleInitializer>> m_modules_init;
@ -183,11 +182,6 @@ public:
m_rsx_callback = addr;
}
void SetCPUThreadExit(u32 addr)
{
m_cpu_thr_exit = addr;
}
void SetCPUThreadStop(u32 addr)
{
m_cpu_thr_stop = addr;
@ -202,7 +196,6 @@ public:
u32 GetMallocPageSize() { return m_info.GetProcParam().malloc_pagesize; }
u32 GetRSXCallback() const { return m_rsx_callback; }
u32 GetCPUThreadExit() const { return m_cpu_thr_exit; }
u32 GetCPUThreadStop() const { return m_cpu_thr_stop; }
void CheckStatus();

View File

@ -19,10 +19,16 @@ namespace loader
{
handler::error_code elf32::init(vfsStream& stream)
{
m_ehdr = {};
m_phdrs.clear();
m_shdrs.clear();
error_code res = handler::init(stream);
if (res != ok)
{
return res;
}
m_stream->Read(&m_ehdr, sizeof(ehdr));
@ -52,8 +58,6 @@ namespace loader
if (m_stream->Read(m_phdrs.data(), size) != size)
return broken_file;
}
else
m_phdrs.clear();
if (m_ehdr.data_le.e_shnum)
{
@ -64,8 +68,6 @@ namespace loader
if (m_stream->Read(m_shdrs.data(), size) != size)
return broken_file;
}
else
m_shdrs.clear();
return ok;
}
@ -133,7 +135,7 @@ namespace loader
auto armv7_thr_stop_data = vm::psv::ptr<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4));
armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb)
armv7_thr_stop_data[1] = 0x0001; // index 1
Emu.SetCPUThreadExit(armv7_thr_stop_data.addr());
Emu.SetCPUThreadStop(armv7_thr_stop_data.addr());
u32 entry = 0; // actual entry point (ELFs entry point is ignored)
u32 fnid_addr = 0;

View File

@ -23,10 +23,23 @@ namespace loader
{
handler::error_code elf64::init(vfsStream& stream)
{
m_ehdr = {};
m_sprx_module_info = {};
m_sprx_function_info = {};
m_phdrs.clear();
m_shdrs.clear();
m_sprx_segments_info.clear();
m_sprx_import_info.clear();
m_sprx_export_info.clear();
error_code res = handler::init(stream);
if (res != ok)
{
return res;
}
m_stream->Read(&m_ehdr, sizeof(ehdr));
@ -58,8 +71,6 @@ namespace loader
if (m_stream->Read(m_phdrs.data(), m_ehdr.e_phnum * sizeof(phdr)) != m_ehdr.e_phnum * sizeof(phdr))
return broken_file;
}
else
m_phdrs.clear();
if (m_ehdr.e_shnum)
{
@ -68,8 +79,6 @@ namespace loader
if (m_stream->Read(m_shdrs.data(), m_ehdr.e_shnum * sizeof(shdr)) != m_ehdr.e_shnum * sizeof(shdr))
return broken_file;
}
else
m_shdrs.clear();
if (is_sprx())
{
@ -79,11 +88,6 @@ namespace loader
//m_stream->Seek(handler::get_stream_offset() + m_phdrs[1].p_vaddr.addr());
//m_stream->Read(&m_sprx_function_info, sizeof(sprx_function_info));
}
else
{
m_sprx_import_info.clear();
m_sprx_export_info.clear();
}
return ok;
}
@ -95,6 +99,7 @@ namespace loader
switch ((u32)phdr.p_type)
{
case 0x1: //load
{
if (phdr.p_memsz)
{
sprx_segment_info segment;
@ -186,8 +191,10 @@ namespace loader
}
break;
}
case 0x700000a4: //relocation
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset);
for (uint i = 0; i < phdr.p_filesz; i += sizeof(sys_prx_relocation_info_t))
@ -227,6 +234,7 @@ namespace loader
break;
}
}
}
for (auto &m : info.modules)
@ -264,6 +272,12 @@ namespace loader
//store elf to memory
vm::ps3::init();
error_code res = alloc_memory(0);
if (res != ok)
{
return res;
}
std::vector<u32> start_funcs;
std::vector<u32> stop_funcs;
@ -273,6 +287,7 @@ namespace loader
for (const auto module : lle_dir)
{
elf64 sprx_handler;
vfsFile fsprx(lle_dir.GetPath() + "/" + module->name);
if (fsprx.IsOpened())
@ -286,12 +301,12 @@ namespace loader
if (!load_lib.LoadValue(false))
{
LOG_ERROR(LOADER, "skipped lle library '%s'", sprx_handler.sprx_get_module_name().c_str());
LOG_WARNING(LOADER, "Skipped LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
continue;
}
else
{
LOG_WARNING(LOADER, "loading lle library '%s'", sprx_handler.sprx_get_module_name().c_str());
LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
}
sprx_info info;
@ -332,7 +347,7 @@ namespace loader
}
}
error_code res = load_data(0);
res = load_data(0);
if (res != ok)
return res;
@ -345,18 +360,11 @@ namespace loader
rsx_callback_data[1] = SC(0);
rsx_callback_data[2] = BLR();
auto ppu_thr_exit_data = vm::ptr<u32>::make(Memory.MainMem.AllocAlign(3 * 4));
ppu_thr_exit_data[0] = ADDI(r11, 0, 41);
ppu_thr_exit_data[1] = SC(0);
ppu_thr_exit_data[2] = BLR();
Emu.SetCPUThreadExit(ppu_thr_exit_data.addr());
auto ppu_thr_stop_data = vm::ptr<u32>::make(Memory.MainMem.AllocAlign(2 * 4));
ppu_thr_stop_data[0] = SC(3);
ppu_thr_stop_data[1] = BLR();
Emu.SetCPUThreadStop(ppu_thr_stop_data.addr());
//vm::write64(Memory.PRXMem.AllocAlign(0x10000), 0xDEADBEEFABADCAFE);
/*
//TODO
static const int branch_size = 6 * 4;
@ -395,6 +403,31 @@ namespace loader
return ok;
}
handler::error_code elf64::alloc_memory(u64 offset)
{
for (auto &phdr : m_phdrs)
{
switch (phdr.p_type.value())
{
case 0x00000001: //LOAD
{
if (phdr.p_memsz)
{
if (!vm::alloc(vm::cast(phdr.p_vaddr.addr()), vm::cast(phdr.p_memsz, "phdr.p_memsz"), vm::main))
{
LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%llx) failed", __FUNCTION__, phdr.p_vaddr.addr(), phdr.p_memsz);
return loading_error;
}
}
break;
}
}
}
return ok;
}
handler::error_code elf64::load_data(u64 offset)
{
for (auto &phdr : m_phdrs)
@ -402,16 +435,9 @@ namespace loader
switch (phdr.p_type.value())
{
case 0x00000001: //LOAD
{
if (phdr.p_memsz)
{
if (!vm::alloc(phdr.p_vaddr.addr(), (u32)phdr.p_memsz, vm::main))
{
// addr() has be_t<> type (test)
LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, phdr.p_vaddr.addr(), (u32)phdr.p_memsz);
return loading_error;
}
if (phdr.p_filesz)
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset);
@ -420,15 +446,19 @@ namespace loader
}
}
break;
}
case 0x00000007: //TLS
{
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
{
if (phdr.p_filesz)
{
const sys_process_param& proc_param = *(sys_process_param*)phdr.p_vaddr.get_ptr();
@ -458,8 +488,10 @@ namespace loader
}
}
break;
}
case 0x60000002: //LOOS+2
{
if (phdr.p_filesz)
{
const sys_proc_prx_param& proc_prx_param = *(sys_proc_prx_param*)phdr.p_vaddr.get_ptr();
@ -492,7 +524,7 @@ namespace loader
struct stub_data_t
{
be_t<u32> data[3];
}
}
static const stub_data =
{
be_t<u32>::make(MR(11, 2)),
@ -537,6 +569,7 @@ namespace loader
}
break;
}
}
}
return ok;

View File

@ -156,6 +156,7 @@ namespace loader
error_code init(vfsStream& stream) override;
error_code load() override;
error_code alloc_memory(u64 offset);
error_code load_data(u64 offset);
error_code load_sprx(sprx_info& info);
bool is_sprx() const { return m_ehdr.e_type == 0xffa4; }

View File

@ -19,11 +19,11 @@ namespace loader
return true;
}
LOG_ERROR(LOADER, "loader::load() failed: %s", i->get_error_code().c_str());
LOG_NOTICE(LOADER, "loader::load() failed: %s", i->get_error_code().c_str());
}
else
{
LOG_ERROR(LOADER, "loader::init() failed: %s", i->get_error_code().c_str());
LOG_NOTICE(LOADER, "loader::init() failed: %s", i->get_error_code().c_str());
stream.Seek(i->get_stream_offset());
}
}