mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
PSP2: Fix vitasdk homebrew loading
This commit is contained in:
parent
19d181fa4c
commit
b12a2f7ea5
4 changed files with 566 additions and 48 deletions
|
@ -200,6 +200,15 @@ void AppInfo::Load(const fs::file& f)
|
|||
padding = Read64(f);
|
||||
}
|
||||
|
||||
void AppInfo::LoadLE(const fs::file& f)
|
||||
{
|
||||
authid = Read64LE(f);
|
||||
vendor_id = Read32LE(f);
|
||||
self_type = Read32LE(f);
|
||||
version = Read64(f);
|
||||
padding = Read64(f);
|
||||
}
|
||||
|
||||
void AppInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "AuthID: 0x%llx", authid);
|
||||
|
@ -218,6 +227,16 @@ void SectionInfo::Load(const fs::file& f)
|
|||
encrypted = Read32(f);
|
||||
}
|
||||
|
||||
void SectionInfo::LoadLE(const fs::file& f)
|
||||
{
|
||||
offset = Read64LE(f);
|
||||
size = Read64LE(f);
|
||||
compressed = Read32LE(f);
|
||||
unknown1 = Read32LE(f);
|
||||
unknown2 = Read32LE(f);
|
||||
encrypted = Read32LE(f);
|
||||
}
|
||||
|
||||
void SectionInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Offset: 0x%llx", offset);
|
||||
|
@ -236,6 +255,14 @@ void SCEVersionInfo::Load(const fs::file& f)
|
|||
unknown = Read32(f);
|
||||
}
|
||||
|
||||
void SCEVersionInfo::LoadLE(const fs::file& f)
|
||||
{
|
||||
subheader_type = Read32LE(f);
|
||||
present = Read32LE(f);
|
||||
size = Read32LE(f);
|
||||
unknown = Read32LE(f);
|
||||
}
|
||||
|
||||
void SCEVersionInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Sub-header type: 0x%08x", subheader_type);
|
||||
|
@ -290,6 +317,66 @@ void ControlInfo::Load(const fs::file& f)
|
|||
}
|
||||
}
|
||||
|
||||
void ControlInfo::LoadLE(const fs::file& f)
|
||||
{
|
||||
type = Read32LE(f);
|
||||
size = Read32LE(f);
|
||||
next = Read64LE(f);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
control_flags.ctrl_flag1 = Read32LE(f);
|
||||
control_flags.unknown1 = Read32LE(f);
|
||||
control_flags.unknown2 = Read32LE(f);
|
||||
control_flags.unknown3 = Read32LE(f);
|
||||
control_flags.unknown4 = Read32LE(f);
|
||||
control_flags.unknown5 = Read32LE(f);
|
||||
control_flags.unknown6 = Read32LE(f);
|
||||
control_flags.unknown7 = Read32LE(f);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
if (size == 0x30)
|
||||
{
|
||||
f.read(file_digest_30.digest, 20);
|
||||
file_digest_30.unknown = Read64LE(f);
|
||||
}
|
||||
else if (size == 0x40)
|
||||
{
|
||||
f.read(file_digest_40.digest1, 20);
|
||||
f.read(file_digest_40.digest2, 20);
|
||||
file_digest_40.unknown = Read64LE(f);
|
||||
}
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
npdrm.magic = Read32LE(f);
|
||||
npdrm.unknown1 = Read32LE(f);
|
||||
npdrm.license = Read32LE(f);
|
||||
npdrm.type = Read32LE(f);
|
||||
f.read(npdrm.content_id, 48);
|
||||
f.read(npdrm.digest, 16);
|
||||
f.read(npdrm.invdigest, 16);
|
||||
f.read(npdrm.xordigest, 16);
|
||||
npdrm.unknown2 = Read64LE(f);
|
||||
npdrm.unknown3 = Read64LE(f);
|
||||
}
|
||||
else if (type == 5)
|
||||
{
|
||||
f.read(type5.unk, 0x100);
|
||||
}
|
||||
else if (type == 6)
|
||||
{
|
||||
type6.unknown1 = Read32LE(f);
|
||||
f.read(type6.unk, 0xFC);
|
||||
}
|
||||
else if (type == 7)
|
||||
{
|
||||
f.read(type7.unk, 0x40);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ControlInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", type);
|
||||
|
@ -634,6 +721,19 @@ void SceHeader::Load(const fs::file& f)
|
|||
se_esize = Read64(f);
|
||||
}
|
||||
|
||||
void SceHeader::LoadLE(const fs::file& f)
|
||||
{
|
||||
se_magic = Read32(f);
|
||||
se_hver = Read32LE(f);
|
||||
se_flags = Read16LE(f);
|
||||
se_type = Read16LE(f);
|
||||
se_meta = Read32LE(f);
|
||||
se_hsize = Read64LE(f);
|
||||
se_esize = Read64LE(f);
|
||||
Read64LE(f);
|
||||
Read64LE(f);
|
||||
}
|
||||
|
||||
void SelfHeader::Load(const fs::file& f)
|
||||
{
|
||||
se_htype = Read64(f);
|
||||
|
@ -648,6 +748,11 @@ void SelfHeader::Load(const fs::file& f)
|
|||
pad = Read64(f);
|
||||
}
|
||||
|
||||
void SelfHeader::LoadLE(const fs::file& f)
|
||||
{
|
||||
f.read(this, sizeof(*this));
|
||||
}
|
||||
|
||||
SCEDecrypter::SCEDecrypter(const fs::file& s)
|
||||
: sce_f(s)
|
||||
, data_buf_length(0)
|
||||
|
@ -889,7 +994,13 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
{
|
||||
// Read SCE header.
|
||||
self_f.seek(0);
|
||||
sce_hdr.Load(self_f);
|
||||
sce_hdr.LoadLE(self_f);
|
||||
const bool isVita = sce_hdr.se_hver == 3;
|
||||
|
||||
if (!isVita) {
|
||||
self_f.seek(0);
|
||||
sce_hdr.Load(self_f);
|
||||
}
|
||||
|
||||
// Check SCE magic.
|
||||
if (!sce_hdr.CheckMagic())
|
||||
|
@ -899,11 +1010,18 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
}
|
||||
|
||||
// Read SELF header.
|
||||
self_hdr.Load(self_f);
|
||||
if(!isVita)
|
||||
self_hdr.Load(self_f);
|
||||
else
|
||||
self_hdr.LoadLE(self_f);
|
||||
|
||||
// Read the APP INFO.
|
||||
self_f.seek(self_hdr.se_appinfooff);
|
||||
app_info.Load(self_f);
|
||||
|
||||
if(!isVita)
|
||||
app_info.Load(self_f);
|
||||
else
|
||||
app_info.LoadLE(self_f);
|
||||
|
||||
// Read ELF header.
|
||||
self_f.seek(self_hdr.se_elfoff);
|
||||
|
@ -926,7 +1044,10 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
|
||||
{
|
||||
phdr32_arr.emplace_back();
|
||||
phdr32_arr.back().Load(self_f);
|
||||
if(!isVita)
|
||||
phdr32_arr.back().Load(self_f);
|
||||
else
|
||||
phdr32_arr.back().LoadLE(self_f);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -956,13 +1077,18 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
|
||||
{
|
||||
secinfo_arr.emplace_back();
|
||||
secinfo_arr.back().Load(self_f);
|
||||
if(!isVita)
|
||||
secinfo_arr.back().Load(self_f);
|
||||
else
|
||||
secinfo_arr.back().LoadLE(self_f);
|
||||
}
|
||||
|
||||
// Read SCE version info.
|
||||
self_f.seek(self_hdr.se_sceveroff);
|
||||
scev_info.Load(self_f);
|
||||
|
||||
if(!isVita)
|
||||
scev_info.Load(self_f);
|
||||
else
|
||||
scev_info.LoadLE(self_f);
|
||||
// Read control info.
|
||||
ctrlinfo_arr.clear();
|
||||
self_f.seek(self_hdr.se_controloff);
|
||||
|
@ -972,7 +1098,10 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
{
|
||||
ctrlinfo_arr.emplace_back();
|
||||
ControlInfo &cinfo = ctrlinfo_arr.back();
|
||||
cinfo.Load(self_f);
|
||||
if(!isVita)
|
||||
cinfo.Load(self_f);
|
||||
else
|
||||
cinfo.LoadLE(self_f);
|
||||
i += cinfo.size;
|
||||
}
|
||||
|
||||
|
@ -992,7 +1121,10 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
|
||||
{
|
||||
shdr32_arr.emplace_back();
|
||||
shdr32_arr.back().Load(self_f);
|
||||
if (!isVita)
|
||||
shdr32_arr.back().Load(self_f);
|
||||
else
|
||||
shdr32_arr.back().LoadLE(self_f);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1157,6 +1289,8 @@ bool SELFDecrypter::LoadMetadata(u8* klic_key)
|
|||
memcpy(metadata_iv, keyset.riv, 0x10);
|
||||
|
||||
// Check DEBUG flag.
|
||||
if (sce_hdr.se_flags == 0x00c0)
|
||||
return true;
|
||||
if ((sce_hdr.se_flags & 0x8000) != 0x8000)
|
||||
{
|
||||
// Decrypt the NPDRM layer.
|
||||
|
@ -1219,6 +1353,13 @@ bool SELFDecrypter::DecryptData()
|
|||
}
|
||||
}
|
||||
|
||||
if (meta_hdr.section_count == 0) {
|
||||
for (unsigned int i = 0; i < secinfo_arr.size(); i++)
|
||||
{
|
||||
data_buf_length += secinfo_arr[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate a buffer to store decrypted data.
|
||||
data_buf = std::make_unique<u8[]>(data_buf_length);
|
||||
|
||||
|
@ -1266,6 +1407,15 @@ bool SELFDecrypter::DecryptData()
|
|||
}
|
||||
}
|
||||
|
||||
if (meta_hdr.section_count == 0) {
|
||||
for (unsigned int i = 0; i < secinfo_arr.size(); i++)
|
||||
{
|
||||
self_f.seek(secinfo_arr[i].offset);
|
||||
self_f.read(data_buf.get() + data_buf_offset, secinfo_arr[i].size);
|
||||
data_buf_offset += secinfo_arr[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1288,17 +1438,64 @@ fs::file SELFDecrypter::MakeElf(bool isElf32)
|
|||
WritePhdr(e, phdr32_arr[i]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
|
||||
if (meta_hdr.section_count != 0)
|
||||
{
|
||||
// PHDR type.
|
||||
if (meta_shdr[i].type == 2)
|
||||
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
|
||||
{
|
||||
// Seek to the program header data offset and write the data.
|
||||
e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset);
|
||||
e.write(data_buf.get() + data_buf_offset, meta_shdr[i].data_size);
|
||||
// PHDR type.
|
||||
if (meta_shdr[i].type == 2)
|
||||
{
|
||||
// Seek to the program header data offset and write the data.
|
||||
e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset);
|
||||
e.write(data_buf.get() + data_buf_offset, meta_shdr[i].data_size);
|
||||
|
||||
// Advance the data buffer offset by data size.
|
||||
data_buf_offset += meta_shdr[i].data_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned int i = 0; i < phdr32_arr.size(); i++)
|
||||
{
|
||||
// Decompress if necessary.
|
||||
if (secinfo_arr[i].compressed == 2)
|
||||
{
|
||||
// Store the length in writeable memory space.
|
||||
std::unique_ptr<uLongf> decomp_buf_length(new uLongf);
|
||||
memcpy(decomp_buf_length.get(), &phdr32_arr[i].p_filesz, sizeof(uLongf));
|
||||
/// Create a pointer to a buffer for decompression.
|
||||
std::unique_ptr<u8[]> decomp_buf(new u8[phdr32_arr[i].p_filesz]);
|
||||
|
||||
// Create a buffer separate from data_buf to uncompress.
|
||||
std::unique_ptr<u8[]> zlib_buf(new u8[data_buf_length]);
|
||||
memcpy(zlib_buf.get(), data_buf.get(), data_buf_length);
|
||||
|
||||
// Use zlib uncompress on the new buffer.
|
||||
// decomp_buf_length changes inside the call to uncompress, so it must be a pointer to correct type (in writeable mem space).
|
||||
int rv = uncompress(decomp_buf.get(), decomp_buf_length.get(), zlib_buf.get() + data_buf_offset, data_buf_length);
|
||||
|
||||
// Check for errors (TODO: Probably safe to remove this once these changes have passed testing.)
|
||||
switch (rv)
|
||||
{
|
||||
case Z_MEM_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_MEM_ERROR!"); break;
|
||||
case Z_BUF_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_BUF_ERROR!"); break;
|
||||
case Z_DATA_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_DATA_ERROR!"); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Seek to the program header data offset and write the data.
|
||||
e.seek(phdr32_arr[i].p_offset);
|
||||
e.write(decomp_buf.get(), phdr32_arr[i].p_filesz);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Seek to the program header data offset and write the data.
|
||||
e.seek(phdr32_arr[i].p_offset);
|
||||
e.write(data_buf.get() + data_buf_offset, secinfo_arr[i].size);
|
||||
}
|
||||
|
||||
// Advance the data buffer offset by data size.
|
||||
data_buf_offset += meta_shdr[i].data_size;
|
||||
data_buf_offset += secinfo_arr[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1424,8 +1621,18 @@ static bool IsSelfElf32(const fs::file& f)
|
|||
|
||||
SceHeader hdr;
|
||||
SelfHeader sh;
|
||||
hdr.Load(f);
|
||||
sh.Load(f);
|
||||
|
||||
hdr.LoadLE(f);
|
||||
const bool isVita = hdr.se_hver == 3;
|
||||
|
||||
if (!isVita) {
|
||||
f.seek(0);
|
||||
hdr.Load(f);
|
||||
sh.Load(f);
|
||||
}else{
|
||||
sh.LoadLE(f);
|
||||
}
|
||||
|
||||
|
||||
// Locate the class byte and check it.
|
||||
u8 elf_class[0x8];
|
||||
|
@ -1451,13 +1658,21 @@ static bool CheckDebugSelf(fs::file& s)
|
|||
// Check for DEBUG version.
|
||||
if (key_version == 0x80 || key_version == 0xc0)
|
||||
{
|
||||
LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header...");
|
||||
|
||||
s.seek(0x04);
|
||||
const u16 version = s.read<le_t<u16>>();
|
||||
|
||||
if (version == 3)
|
||||
return false;
|
||||
|
||||
LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header...");
|
||||
|
||||
// Get the real elf offset.
|
||||
s.seek(0x10);
|
||||
|
||||
const u64 realoffset = key_version == 0x80 ? +s.read<be_t<u64>>() : +s.read<le_t<u64>>();
|
||||
// Start at the real elf offset.
|
||||
s.seek(key_version == 0x80 ? +s.read<be_t<u64>>() : +s.read<le_t<u64>>());
|
||||
s.seek(realoffset);
|
||||
|
||||
// Write the real ELF file back.
|
||||
fs::file e = fs::make_stream<std::vector<u8>>();
|
||||
|
|
|
@ -11,6 +11,7 @@ struct AppInfo
|
|||
u64 padding;
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void LoadLE(const fs::file& f);
|
||||
void Show();
|
||||
};
|
||||
|
||||
|
@ -24,6 +25,7 @@ struct SectionInfo
|
|||
u32 encrypted;
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void LoadLE(const fs::file& f);
|
||||
void Show();
|
||||
};
|
||||
|
||||
|
@ -35,6 +37,7 @@ struct SCEVersionInfo
|
|||
u32 unknown;
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void LoadLE(const fs::file& f);
|
||||
void Show();
|
||||
};
|
||||
|
||||
|
@ -92,9 +95,33 @@ struct ControlInfo
|
|||
u64 unknown3;
|
||||
|
||||
} npdrm;
|
||||
|
||||
// type 5 0x110 bytes
|
||||
struct
|
||||
{
|
||||
u32 pad;
|
||||
u8 unk[0x100];
|
||||
} type5;
|
||||
|
||||
// type 6 0x110 bytes
|
||||
struct
|
||||
{
|
||||
u32 pad;
|
||||
u32 unknown1;
|
||||
u8 unk[0xFC];
|
||||
} type6;
|
||||
|
||||
// type 7 0x50 bytes
|
||||
struct
|
||||
{
|
||||
u32 pad;
|
||||
u8 unk[0x40];
|
||||
} type7;
|
||||
|
||||
};
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void LoadLE(const fs::file& f);
|
||||
void Show();
|
||||
};
|
||||
|
||||
|
@ -317,6 +344,7 @@ struct SceHeader
|
|||
u64 se_esize;
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void LoadLE(const fs::file& f);
|
||||
void Show(){}
|
||||
bool CheckMagic() const { return se_magic == 0x53434500; }
|
||||
};
|
||||
|
@ -335,6 +363,7 @@ struct SelfHeader
|
|||
u64 pad;
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void LoadLE(const fs::file& f);
|
||||
void Show(){}
|
||||
};
|
||||
|
||||
|
|
|
@ -201,25 +201,35 @@ struct psv_moduleinfo_t
|
|||
struct psv_libent_t
|
||||
{
|
||||
le_t<u16> size; // ???
|
||||
le_t<u16> unk0;
|
||||
le_t<u16> unk1;
|
||||
le_t<u16> version;
|
||||
le_t<u16> flags;
|
||||
le_t<u16> fcount;
|
||||
le_t<u16> vcount;
|
||||
le_t<u16> unk2;
|
||||
le_t<u32> unk3;
|
||||
le_t<u32> data[1]; // ...
|
||||
le_t<u32> vcount;
|
||||
le_t<u32> unk2;
|
||||
le_t<u32> module_nid;
|
||||
le_t<u32> module_name; /* Pointer to name of this module */
|
||||
le_t<u32> nid_table; /* Pointer to array of 32-bit NIDs to export */
|
||||
le_t<u32> entry_table; /* Pointer to array of data pointers for each NID */
|
||||
};
|
||||
|
||||
struct psv_libstub_t
|
||||
{
|
||||
le_t<u16> size; // 0x2C, 0x34
|
||||
le_t<u16> unk0; // (usually 1, 5 for sceLibKernel)
|
||||
le_t<u16> unk1; // (usually 0)
|
||||
le_t<u16> version; // (usually 1, 5 for sceLibKernel)
|
||||
le_t<u16> flags; // (usually 0)
|
||||
le_t<u16> fcount;
|
||||
le_t<u16> vcount;
|
||||
le_t<u16> unk2;
|
||||
le_t<u32> unk3;
|
||||
le_t<u32> data[1]; // ...
|
||||
le_t<u32> module_nid; /* NID of module to import */
|
||||
le_t<u32> module_name; /* Pointer to name of imported module, for debugging */
|
||||
le_t<u32> reserved2;
|
||||
le_t<u32> func_nid_table; /* Pointer to array of function NIDs to import */
|
||||
le_t<u32> func_entry_table;/* Pointer to array of stub functions to fill */
|
||||
le_t<u32> var_nid_table; /* Pointer to array of variable NIDs to import */
|
||||
le_t<u32> var_entry_table; /* Pointer to array of data pointers to write to */
|
||||
le_t<u32> unk_nid_table;
|
||||
le_t<u32> unk_entry_table;
|
||||
};
|
||||
|
||||
struct psv_libcparam_t
|
||||
|
@ -257,6 +267,48 @@ struct psv_process_param_t
|
|||
vm::lcptr<psv_libcparam_t> sce_libcparam;
|
||||
};
|
||||
|
||||
struct psv_reloc
|
||||
{
|
||||
u32 addr;
|
||||
u32 type;
|
||||
u64 data;
|
||||
};
|
||||
|
||||
/** \name Macros to get SCE reloc values
|
||||
* @{
|
||||
*/
|
||||
#define SCE_RELOC_SHORT_OFFSET(x) (((x).r_opt1 >> 20) | ((x).r_opt2 & 0xFFFFF) << 12)
|
||||
#define SCE_RELOC_SHORT_ADDEND(x) ((x).r_opt2 >> 20)
|
||||
#define SCE_RELOC_LONG_OFFSET(x) ((x).r_offset)
|
||||
#define SCE_RELOC_LONG_ADDEND(x) ((x).r_addend)
|
||||
#define SCE_RELOC_LONG_CODE2(x) (((x).r_type >> 20) & 0xFF)
|
||||
#define SCE_RELOC_LONG_DIST2(x) (((x).r_type >> 28) & 0xF)
|
||||
#define SCE_RELOC_IS_SHORT(x) (((x).r_type) & 0xF)
|
||||
#define SCE_RELOC_CODE(x) (((x).r_type >> 8) & 0xFF)
|
||||
#define SCE_RELOC_SYMSEG(x) (((x).r_type >> 4) & 0xF)
|
||||
#define SCE_RELOC_DATSEG(x) (((x).r_type >> 16) & 0xF)
|
||||
/** @}*/
|
||||
|
||||
/** \name Vita supported relocations
|
||||
* @{
|
||||
*/
|
||||
#define R_ARM_NONE 0
|
||||
#define R_ARM_ABS32 2
|
||||
#define R_ARM_REL32 3
|
||||
#define R_ARM_THM_CALL 10
|
||||
#define R_ARM_CALL 28
|
||||
#define R_ARM_JUMP24 29
|
||||
#define R_ARM_TARGET1 38
|
||||
#define R_ARM_V4BX 40
|
||||
#define R_ARM_TARGET2 41
|
||||
#define R_ARM_PREL31 42
|
||||
#define R_ARM_MOVW_ABS_NC 43
|
||||
#define R_ARM_MOVT_ABS 44
|
||||
#define R_ARM_THM_MOVW_ABS_NC 47
|
||||
#define R_ARM_THM_MOVT_ABS 48
|
||||
/** @}*/
|
||||
|
||||
|
||||
static void arm_patch_refs(u32 refs, u32 addr)
|
||||
{
|
||||
auto ptr = vm::cptr<u32>::make(refs);
|
||||
|
@ -314,27 +366,243 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
u32 tls_fsize{};
|
||||
u32 tls_vsize{};
|
||||
|
||||
for (const auto& prog : elf.progs)
|
||||
std::unique_ptr<u32[]> p_vaddr = std::make_unique<u32[]>(elf.progs.size());
|
||||
|
||||
for (int i = 0; i < elf.progs.size(); i++)
|
||||
{
|
||||
const auto& prog = elf.progs[i];
|
||||
const u32 addr = vm::cast(prog.p_vaddr, HERE);
|
||||
const u32 size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
|
||||
const u32 type = prog.p_type;
|
||||
const u32 flag = prog.p_flags;
|
||||
|
||||
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
|
||||
{
|
||||
if (!vm::falloc(prog.p_vaddr & ~0xfff, prog.p_memsz + (prog.p_vaddr & 0xfff), vm::main))
|
||||
if (!(p_vaddr[i] = vm::alloc(size, vm::main)))
|
||||
{
|
||||
fmt::throw_exception("vm::falloc() failed (addr=0x%x, size=0x%x)", prog.p_vaddr, prog.p_memsz);
|
||||
fmt::throw_exception("vm::alloc() failed (size=0x%x)", size);
|
||||
}
|
||||
|
||||
if (prog.p_paddr)
|
||||
if (elf.header.e_type == elf_type::psv1 && prog.p_paddr)
|
||||
{
|
||||
module_info.set(prog.p_vaddr + (prog.p_paddr - prog.p_offset));
|
||||
module_info.set(start_addr + (prog.p_paddr - prog.p_offset));
|
||||
LOG_NOTICE(LOADER, "Found program with p_paddr=0x%x", prog.p_paddr);
|
||||
}
|
||||
|
||||
if (!start_addr)
|
||||
{
|
||||
start_addr = prog.p_vaddr;
|
||||
start_addr = p_vaddr[i];
|
||||
}
|
||||
|
||||
std::memcpy(vm::base(prog.p_vaddr), prog.bin.data(), prog.p_filesz);
|
||||
std::memcpy(vm::base(p_vaddr[i]), prog.bin.data(), prog.p_filesz);
|
||||
}
|
||||
else if (prog.p_type == 0x60000000) {
|
||||
// Relocation code taken from
|
||||
// https://github.com/yifanlu/UVLoader/blob/master/relocate.c
|
||||
// Relocation information of the SCE_PPURELA segment
|
||||
typedef union sce_reloc
|
||||
{
|
||||
u32 r_type;
|
||||
struct
|
||||
{
|
||||
u32 r_opt1;
|
||||
u32 r_opt2;
|
||||
} r_short;
|
||||
struct
|
||||
{
|
||||
u32 r_type;
|
||||
u32 r_addend;
|
||||
u32 r_offset;
|
||||
} r_long;
|
||||
} sce_reloc_t;
|
||||
|
||||
for (uint i = 0; i < prog.p_filesz; )
|
||||
{
|
||||
const auto& rel = reinterpret_cast<const sce_reloc_t&>(prog.bin[i]);
|
||||
u32 r_offset;
|
||||
u32 r_addend;
|
||||
u8 r_symseg;
|
||||
u8 r_datseg;
|
||||
s32 offset;
|
||||
u32 symval, addend, loc;
|
||||
u32 upper, lower, sign, j1, j2;
|
||||
u32 value;
|
||||
|
||||
if (SCE_RELOC_IS_SHORT(rel))
|
||||
{
|
||||
r_offset = SCE_RELOC_SHORT_OFFSET(rel.r_short);
|
||||
r_addend = SCE_RELOC_SHORT_ADDEND(rel.r_short);
|
||||
LOG_NOTICE(LOADER, "SHORT RELOC %X %X %X", r_offset, r_addend, SCE_RELOC_CODE(rel));
|
||||
i += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_offset = SCE_RELOC_LONG_OFFSET(rel.r_long);
|
||||
r_addend = SCE_RELOC_LONG_ADDEND(rel.r_long);
|
||||
if (SCE_RELOC_LONG_CODE2(rel.r_long))
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Code2 ignored for relocation at %X.", i);
|
||||
}
|
||||
LOG_NOTICE(LOADER, "LONG RELOC %X %X %X", r_offset, r_addend, SCE_RELOC_CODE(rel));
|
||||
i += 12;
|
||||
}
|
||||
|
||||
// get values
|
||||
r_symseg = SCE_RELOC_SYMSEG(rel);
|
||||
r_datseg = SCE_RELOC_DATSEG(rel);
|
||||
symval = r_symseg == 15 ? 0 : p_vaddr[r_symseg];
|
||||
loc = p_vaddr[r_datseg] + r_offset;
|
||||
|
||||
// perform relocation
|
||||
// taken from linux/arch/arm/kernel/module.c of Linux Kernel 4.0
|
||||
switch (SCE_RELOC_CODE(rel))
|
||||
{
|
||||
case R_ARM_V4BX:
|
||||
{
|
||||
/* Preserve Rm and the condition code. Alter
|
||||
* other bits to re-code instruction as
|
||||
* MOV PC,Rm.
|
||||
*/
|
||||
value = vm::_ref<u32>(loc & 0xf000000f) | 0x01a0f000;
|
||||
}
|
||||
break;
|
||||
case R_ARM_ABS32:
|
||||
case R_ARM_TARGET1:
|
||||
{
|
||||
value = r_addend + symval;
|
||||
}
|
||||
break;
|
||||
case R_ARM_REL32:
|
||||
case R_ARM_TARGET2:
|
||||
{
|
||||
value = r_addend + symval - loc;
|
||||
}
|
||||
break;
|
||||
case R_ARM_THM_CALL:
|
||||
{
|
||||
upper = vm::_ref<u16>(loc);
|
||||
lower = vm::_ref<u16>(loc + 2);
|
||||
|
||||
/*
|
||||
* 25 bit signed address range (Thumb-2 BL and B.W
|
||||
* instructions):
|
||||
* S:I1:I2:imm10:imm11:0
|
||||
* where:
|
||||
* S = upper[10] = offset[24]
|
||||
* I1 = ~(J1 ^ S) = offset[23]
|
||||
* I2 = ~(J2 ^ S) = offset[22]
|
||||
* imm10 = upper[9:0] = offset[21:12]
|
||||
* imm11 = lower[10:0] = offset[11:1]
|
||||
* J1 = lower[13]
|
||||
* J2 = lower[11]
|
||||
*/
|
||||
sign = (upper >> 10) & 1;
|
||||
j1 = (lower >> 13) & 1;
|
||||
j2 = (lower >> 11) & 1;
|
||||
offset = r_addend + symval - loc;
|
||||
|
||||
if (offset <= (s32)0xff000000 ||
|
||||
offset >= (s32)0x01000000) {
|
||||
LOG_NOTICE(LOADER, "reloc %x out of range: 0x%08X", i, symval);
|
||||
break;
|
||||
}
|
||||
|
||||
sign = (offset >> 24) & 1;
|
||||
j1 = sign ^ (~(offset >> 23) & 1);
|
||||
j2 = sign ^ (~(offset >> 22) & 1);
|
||||
upper = (u16)((upper & 0xf800) | (sign << 10) |
|
||||
((offset >> 12) & 0x03ff));
|
||||
lower = (u16)((lower & 0xd000) |
|
||||
(j1 << 13) | (j2 << 11) |
|
||||
((offset >> 1) & 0x07ff));
|
||||
|
||||
value = ((u32)lower << 16) | upper;
|
||||
}
|
||||
break;
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
{
|
||||
offset = r_addend + symval - loc;
|
||||
if (offset <= (s32)0xfe000000 ||
|
||||
offset >= (s32)0x02000000) {
|
||||
LOG_NOTICE(LOADER, "reloc %x out of range: 0x%08X", i, symval);
|
||||
break;
|
||||
}
|
||||
|
||||
offset >>= 2;
|
||||
offset &= 0x00ffffff;
|
||||
|
||||
value = vm::_ref<u32>(loc & 0xff000000) | offset;
|
||||
}
|
||||
break;
|
||||
case R_ARM_PREL31:
|
||||
{
|
||||
offset = r_addend + symval - loc;
|
||||
value = offset & 0x7fffffff;
|
||||
}
|
||||
break;
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
case R_ARM_MOVT_ABS:
|
||||
{
|
||||
offset = symval + r_addend;
|
||||
if (SCE_RELOC_CODE(rel) == R_ARM_MOVT_ABS)
|
||||
offset >>= 16;
|
||||
|
||||
value = vm::_ref<u32>(loc);
|
||||
value &= 0xfff0f000;
|
||||
value |= ((offset & 0xf000) << 4) |
|
||||
(offset & 0x0fff);
|
||||
}
|
||||
break;
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
{
|
||||
upper = vm::_ref<u16>(loc);
|
||||
lower = vm::_ref<u16>(loc + 2);
|
||||
|
||||
/*
|
||||
* MOVT/MOVW instructions encoding in Thumb-2:
|
||||
*
|
||||
* i = upper[10]
|
||||
* imm4 = upper[3:0]
|
||||
* imm3 = lower[14:12]
|
||||
* imm8 = lower[7:0]
|
||||
*
|
||||
* imm16 = imm4:i:imm3:imm8
|
||||
*/
|
||||
offset = r_addend + symval;
|
||||
|
||||
if (SCE_RELOC_CODE(rel) == R_ARM_THM_MOVT_ABS)
|
||||
offset >>= 16;
|
||||
|
||||
upper = (u16)((upper & 0xfbf0) |
|
||||
((offset & 0xf000) >> 12) |
|
||||
((offset & 0x0800) >> 1));
|
||||
lower = (u16)((lower & 0x8f00) |
|
||||
((offset & 0x0700) << 4) |
|
||||
(offset & 0x00ff));
|
||||
|
||||
value = ((u32)lower << 16) | upper;
|
||||
}
|
||||
break;
|
||||
case R_ARM_NONE:
|
||||
continue;
|
||||
|
||||
default:
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Unknown relocation code %u at %x", SCE_RELOC_CODE(rel), i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Writing at %X[%d], %X, %X, %d", p_vaddr[r_datseg], r_datseg, r_offset, value, sizeof(value));
|
||||
if ((r_offset + sizeof(value)) > elf.progs[r_datseg].p_filesz)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Relocation overflows segment");
|
||||
continue;
|
||||
}
|
||||
vm::_ref<u32>(p_vaddr[r_datseg]+r_offset) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,7 +620,7 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
tls_fsize = module_info->data[6];
|
||||
tls_vsize = module_info->data[7];
|
||||
}
|
||||
else if (module_info->data[5] == 0xffffffff)
|
||||
else if (module_info->data[5] == 0xffffffff || module_info->data[5] == 0)
|
||||
{
|
||||
tls_faddr = module_info->data[1]; // Guess
|
||||
tls_fsize = module_info->data[2];
|
||||
|
@ -384,14 +652,16 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
else
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Loading libent at *0x%x", libent);
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libent->unk0, libent->unk1);
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libent->version, libent->flags);
|
||||
LOG_NOTICE(LOADER, "** Functions: %u", libent->fcount);
|
||||
LOG_NOTICE(LOADER, "** Variables: %u", libent->vcount);
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libent->unk2, libent->unk3);
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libent->unk2, libent->module_nid);
|
||||
|
||||
const auto export_nids = vm::cptr<u32>::make(libent->data[size == 0x20 ? 2 : 1]);
|
||||
const auto export_data = vm::cptr<u32>::make(libent->data[size == 0x20 ? 3 : 2]);
|
||||
const auto export_nids = vm::cptr<u32>::make(libent->nid_table);
|
||||
const auto export_data = vm::cptr<u32>::make(libent->entry_table);
|
||||
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", export_data, export_nids);
|
||||
|
||||
for (u32 i = 0, count = export_data - export_nids; i < count; i++)
|
||||
{
|
||||
const u32 nid = export_nids[i];
|
||||
|
@ -442,7 +712,7 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
}
|
||||
else
|
||||
{
|
||||
const std::string module_name(vm::_ptr<char>(libstub->data[size == 0x34 ? 1 : 0]));
|
||||
const std::string module_name(vm::_ptr<char>(libstub->module_name));
|
||||
|
||||
LOG_NOTICE(LOADER, "Loading libstub at 0x%x: %s", libstub, module_name);
|
||||
|
||||
|
@ -468,13 +738,13 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
}
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libstub->unk0, libstub->unk1);
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libstub->version, libstub->flags);
|
||||
LOG_NOTICE(LOADER, "** Functions: %u", libstub->fcount);
|
||||
LOG_NOTICE(LOADER, "** Variables: %u", libstub->vcount);
|
||||
LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libstub->unk2, libstub->unk3);
|
||||
|
||||
const auto fnids = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 3 : 1]);
|
||||
const auto fstubs = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 4 : 2]);
|
||||
const auto fnids = vm::cptr<u32>::make(libstub->func_nid_table);
|
||||
const auto fstubs = vm::cptr<u32>::make(libstub->func_entry_table);
|
||||
|
||||
for (u32 j = 0; j < libstub->fcount; j++)
|
||||
{
|
||||
|
@ -517,8 +787,8 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
fstub[0] = 0xe0700090 | arm_code::hack<arm_encoding::A1>::index::insert(index);
|
||||
}
|
||||
|
||||
const auto vnids = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 5 : 3]);
|
||||
const auto vstub = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 6 : 4]);
|
||||
const auto vnids = vm::cptr<u32>::make(libstub->var_nid_table);
|
||||
const auto vstub = vm::cptr<u32>::make(libstub->var_entry_table);
|
||||
|
||||
for (u32 j = 0; j < libstub->vcount; j++)
|
||||
{
|
||||
|
@ -559,6 +829,8 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
|
||||
const auto libc_param = proc_param->sce_libcparam;
|
||||
|
||||
if (libc_param) {
|
||||
|
||||
LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param);
|
||||
|
||||
verify(HERE), libc_param->size >= 0x1c;
|
||||
|
@ -570,6 +842,8 @@ void arm_load_exec(const arm_exec_object& elf)
|
|||
LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc);
|
||||
LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc);
|
||||
|
||||
}
|
||||
|
||||
const auto stop_code = vm::ptr<u32>::make(vm::alloc(3 * 4, vm::main));
|
||||
stop_code[0] = 0xf870; // HACK instruction (Thumb)
|
||||
stop_code[1] = 1; // Predefined function index (HLE return)
|
||||
|
|
|
@ -729,7 +729,7 @@ void Emulator::Load(bool add_only)
|
|||
vm::ps3::init();
|
||||
spu_load_exec(spu_exec);
|
||||
}
|
||||
else if (arm_exec.open(elf_file) == elf_error::ok)
|
||||
else if (arm_exec.open(elf_file, 0, elf_opt::no_sections + elf_opt::no_sections) == elf_error::ok)
|
||||
{
|
||||
// ARMv7 executable
|
||||
g_system = system_type::psv;
|
||||
|
|
Loading…
Add table
Reference in a new issue