2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
2014-06-17 17:44:03 +02:00
|
|
|
#include "Utilities/Log.h"
|
2014-08-25 16:56:13 +02:00
|
|
|
#include "Utilities/rFile.h"
|
|
|
|
|
#include "Emu/FS/vfsStream.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "ELF32.h"
|
2014-11-19 15:16:30 +01:00
|
|
|
#include "Emu/Cell/SPUThread.h"
|
|
|
|
|
#include "Emu/ARMv7/ARMv7Thread.h"
|
2014-12-01 17:34:18 +01:00
|
|
|
#include "Emu/ARMv7/PSVFuncList.h"
|
2014-11-19 15:16:30 +01:00
|
|
|
#include "Emu/System.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
namespace loader
|
2014-03-03 05:48:07 +01:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
namespace handlers
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
handler::error_code elf32::init(vfsStream& stream)
|
|
|
|
|
{
|
|
|
|
|
error_code res = handler::init(stream);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (res != ok)
|
|
|
|
|
return res;
|
2013-11-05 19:12:18 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
m_stream->Read(&m_ehdr, sizeof(ehdr));
|
2013-11-09 13:25:12 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (!m_ehdr.check())
|
2013-11-05 19:12:18 +01:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
return bad_file;
|
2013-11-05 19:12:18 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (m_ehdr.data_le.e_phnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_phentsize : m_ehdr.data_be.e_phentsize) != sizeof(phdr))
|
2013-07-12 14:42:17 +02:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
return broken_file;
|
2013-07-12 14:42:17 +02:00
|
|
|
}
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (m_ehdr.data_le.e_shnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_shentsize : m_ehdr.data_be.e_shentsize) != sizeof(shdr))
|
2013-07-12 14:42:17 +02:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
return broken_file;
|
2013-07-12 14:42:17 +02:00
|
|
|
}
|
2013-07-06 01:49:38 +02:00
|
|
|
|
2014-11-21 14:52:01 +01:00
|
|
|
LOG_WARNING(LOADER, "m_ehdr.e_type = 0x%x", (u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_type : m_ehdr.data_be.e_type));
|
2014-11-19 15:16:30 +01:00
|
|
|
|
|
|
|
|
if (m_ehdr.data_le.e_phnum)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum);
|
|
|
|
|
m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_phoff : m_ehdr.data_be.e_phoff));
|
|
|
|
|
size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum) * sizeof(phdr);
|
2014-11-30 23:04:47 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (m_stream->Read(m_phdrs.data(), size) != size)
|
|
|
|
|
return broken_file;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
else
|
|
|
|
|
m_phdrs.clear();
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (m_ehdr.data_le.e_shnum)
|
2013-11-05 19:12:18 +01:00
|
|
|
{
|
2014-11-30 23:04:47 +01:00
|
|
|
m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum);
|
2014-11-19 15:16:30 +01:00
|
|
|
m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff));
|
2014-11-30 23:04:47 +01:00
|
|
|
size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum) * sizeof(phdr);
|
2013-11-05 19:12:18 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (m_stream->Read(m_shdrs.data(), size) != size)
|
|
|
|
|
return broken_file;
|
2013-11-05 19:12:18 +01:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
else
|
|
|
|
|
m_shdrs.clear();
|
2013-11-05 19:12:18 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
return ok;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2013-07-12 14:42:17 +02:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
handler::error_code elf32::load()
|
|
|
|
|
{
|
|
|
|
|
Elf_Machine machine;
|
|
|
|
|
switch (machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine))
|
2013-07-12 14:42:17 +02:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
case MACHINE_MIPS: vm::psp::init(); break;
|
|
|
|
|
case MACHINE_ARM: vm::psv::init(); break;
|
|
|
|
|
case MACHINE_SPU: vm::ps3::init(); break;
|
2013-07-12 14:42:17 +02:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
default:
|
|
|
|
|
return bad_version;
|
2013-07-12 14:42:17 +02:00
|
|
|
}
|
|
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
error_code res = load_data(0);
|
2013-07-12 14:42:17 +02:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
if (res != ok)
|
|
|
|
|
return res;
|
2013-07-12 14:42:17 +02:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
switch (machine)
|
2013-08-03 11:40:03 +02:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
case MACHINE_MIPS: break;
|
2014-11-30 23:04:47 +01:00
|
|
|
case MACHINE_ARM:
|
|
|
|
|
{
|
2014-12-01 17:34:18 +01:00
|
|
|
list_known_psv_modules();
|
|
|
|
|
|
2014-11-30 23:04:47 +01:00
|
|
|
auto armv7_thr_stop_data = vm::psv::ptr<u32>::make(Memory.PSV.RAM.AllocAlign(3 * 4));
|
|
|
|
|
armv7_thr_stop_data[0] = 0xf870; // HACK
|
|
|
|
|
armv7_thr_stop_data[1] = 0x0001; // index 1
|
|
|
|
|
Emu.SetCPUThreadExit(armv7_thr_stop_data.addr());
|
|
|
|
|
|
|
|
|
|
u32 entry = m_ehdr.data_le.e_entry + (u32)Memory.PSV.RAM.GetStartAddr();
|
|
|
|
|
|
|
|
|
|
auto code = vm::psv::ptr<const u32>::make(entry & ~3);
|
|
|
|
|
|
|
|
|
|
// very rough way to find entry point in .sceModuleInfo.rodata
|
|
|
|
|
while (code[0] != 0xffffffffu)
|
|
|
|
|
{
|
|
|
|
|
entry = code[0] + 0x81000000;
|
|
|
|
|
code++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arm7_thread(entry & ~1 /* TODO: Thumb/ARM encoding selection */, "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-11-29 18:41:18 +01:00
|
|
|
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;
|
2013-08-03 11:40:03 +02:00
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
return ok;
|
2013-07-06 01:49:38 +02:00
|
|
|
}
|
2014-11-02 00:19:14 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
handler::error_code elf32::load_data(u32 offset)
|
2014-11-02 00:19:14 +01:00
|
|
|
{
|
2014-11-28 19:56:16 +01:00
|
|
|
Elf_Machine machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine);
|
|
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
for (auto &phdr : m_phdrs)
|
2014-11-02 00:19:14 +01:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
u32 memsz = m_ehdr.is_le() ? phdr.data_le.p_memsz : phdr.data_be.p_memsz;
|
|
|
|
|
u32 filesz = m_ehdr.is_le() ? phdr.data_le.p_filesz : phdr.data_be.p_filesz;
|
|
|
|
|
u32 vaddr = offset + (m_ehdr.is_le() ? phdr.data_le.p_vaddr : phdr.data_be.p_vaddr);
|
|
|
|
|
u32 offset = m_ehdr.is_le() ? phdr.data_le.p_offset : phdr.data_be.p_offset;
|
2014-11-02 00:19:14 +01:00
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
switch (m_ehdr.is_le() ? phdr.data_le.p_type : phdr.data_be.p_type)
|
2014-11-02 00:19:14 +01:00
|
|
|
{
|
2014-11-19 15:16:30 +01:00
|
|
|
case 0x00000001: //LOAD
|
|
|
|
|
if (phdr.data_le.p_memsz)
|
|
|
|
|
{
|
2014-11-30 23:04:47 +01:00
|
|
|
if (machine == MACHINE_ARM && !Memory.PSV.RAM.AllocFixed(vaddr, memsz))
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
|
|
|
|
LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, vaddr, memsz);
|
|
|
|
|
|
|
|
|
|
return loading_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (filesz)
|
|
|
|
|
{
|
|
|
|
|
m_stream->Seek(handler::get_stream_offset() + offset);
|
|
|
|
|
m_stream->Read(vm::get_ptr(vaddr), filesz);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-05 19:53:54 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2014-11-02 00:19:14 +01:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
|
|
|
|
|
return ok;
|
2014-11-02 00:19:14 +01:00
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2014-11-19 15:16:30 +01:00
|
|
|
}
|