mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
_sys_spu_image_import implemented
vm:var<T[]> improved (begin/end) sys_spu_image_import rewritten
This commit is contained in:
parent
dfc970c926
commit
aa5dc5455e
6 changed files with 421 additions and 81 deletions
|
@ -17,7 +17,7 @@
|
|||
|
||||
logs::channel cellSpurs("cellSpurs");
|
||||
|
||||
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img);
|
||||
error_code sys_spu_image_close(vm::ptr<sys_spu_image> img);
|
||||
|
||||
// TODO
|
||||
struct cell_error_t
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Emu/Cell/RawSPUThread.h"
|
||||
#include "Emu/Cell/lv2/sys_spu.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "Loader/ELF.h"
|
||||
#include "sysPrxForUser.h"
|
||||
|
||||
extern logs::channel sysPrxForUser;
|
||||
|
@ -16,6 +17,172 @@ spu_printf_cb_t g_spu_printf_dgcb;
|
|||
spu_printf_cb_t g_spu_printf_atcb;
|
||||
spu_printf_cb_t g_spu_printf_dtcb;
|
||||
|
||||
struct spu_elf_ldr
|
||||
{
|
||||
be_t<u32> _vtable;
|
||||
vm::bptr<void> src;
|
||||
be_t<u32> x8;
|
||||
be_t<u64> ehdr_off;
|
||||
be_t<u64> phdr_off;
|
||||
|
||||
s32 get_ehdr(vm::ptr<elf_ehdr<elf_be, u64>> out)
|
||||
{
|
||||
if (!src)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_vtable == vm::cast(u32{1}))
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
std::memcpy(out.get_ptr(), ehdr.get_ptr(), 0x10); // Not needed?
|
||||
out->e_type = ehdr->e_type;
|
||||
out->e_machine = ehdr->e_machine;
|
||||
out->e_version = ehdr->e_version;
|
||||
out->e_entry = ehdr->e_entry;
|
||||
out->e_phoff = ehdr->e_phoff;
|
||||
out->e_shoff = ehdr->e_shoff;
|
||||
out->e_flags = ehdr->e_flags;
|
||||
out->e_ehsize = ehdr->e_ehsize;
|
||||
out->e_phentsize = ehdr->e_phentsize;
|
||||
out->e_phnum = ehdr->e_phnum;
|
||||
out->e_shentsize = ehdr->e_shentsize;
|
||||
out->e_shnum = ehdr->e_shnum;
|
||||
out->e_shstrndx = ehdr->e_shstrndx;
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u64>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
*out = *ehdr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 get_phdr(vm::ptr<elf_phdr<elf_be, u64>> out, u32 count)
|
||||
{
|
||||
if (!src)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_vtable == vm::cast(u32{1}))
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
vm::ptr<elf_phdr<elf_be, u32>> phdr = vm::cast(src.addr() + (phdr_off ? +phdr_off : +ehdr->e_phoff));
|
||||
|
||||
for (; count; count--, phdr++, out++)
|
||||
{
|
||||
out->p_type = phdr->p_type;
|
||||
out->p_flags = phdr->p_flags;
|
||||
out->p_offset = phdr->p_offset;
|
||||
out->p_vaddr = phdr->p_vaddr;
|
||||
out->p_paddr = phdr->p_paddr;
|
||||
out->p_filesz = phdr->p_filesz;
|
||||
out->p_memsz = phdr->p_memsz;
|
||||
out->p_align = phdr->p_align;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u64>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
vm::ptr<elf_phdr<elf_be, u64>> phdr = vm::cast(src.addr() + (phdr_off ? +phdr_off : +ehdr->e_phoff));
|
||||
|
||||
std::memcpy(out.get_ptr(), phdr.get_ptr(), sizeof(*out) * count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct spu_elf_info
|
||||
{
|
||||
u8 e_class;
|
||||
vm::bptr<spu_elf_ldr> ldr;
|
||||
|
||||
struct sce_hdr
|
||||
{
|
||||
be_t<u32> se_magic;
|
||||
be_t<u32> se_hver;
|
||||
be_t<u16> se_flags;
|
||||
be_t<u16> se_type;
|
||||
be_t<u32> se_meta;
|
||||
be_t<u64> se_hsize;
|
||||
be_t<u64> se_esize;
|
||||
} sce0;
|
||||
|
||||
struct self_hdr
|
||||
{
|
||||
be_t<u64> se_htype;
|
||||
be_t<u64> se_appinfooff;
|
||||
be_t<u64> se_elfoff;
|
||||
be_t<u64> se_phdroff;
|
||||
be_t<u64> se_shdroff;
|
||||
be_t<u64> se_secinfoff;
|
||||
be_t<u64> se_sceveroff;
|
||||
be_t<u64> se_controloff;
|
||||
be_t<u64> se_controlsize;
|
||||
be_t<u64> pad;
|
||||
} self;
|
||||
|
||||
// Doesn't exist there
|
||||
spu_elf_ldr _overlay;
|
||||
|
||||
error_code init(vm::ptr<void> src, s32 arg2 = 0)
|
||||
{
|
||||
if (!src)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
u32 ehdr_off = 0;
|
||||
u32 phdr_off = 0;
|
||||
|
||||
// Check SCE header if found
|
||||
std::memcpy(&sce0, src.get_ptr(), sizeof(sce0));
|
||||
|
||||
if (sce0.se_magic == 0x53434500 /* SCE\0 */)
|
||||
{
|
||||
if (sce0.se_hver != 2 || sce0.se_type != 1 || sce0.se_meta == 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
std::memcpy(&self, src.get_ptr(), sizeof(self));
|
||||
ehdr_off = static_cast<u32>(+self.se_elfoff);
|
||||
phdr_off = static_cast<u32>(+self.se_phdroff);
|
||||
|
||||
if (self.se_htype != 3 || !ehdr_off || !phdr_off)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
// Check ELF header
|
||||
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
|
||||
if (ehdr->e_magic != "\177ELF"_u32 || ehdr->e_data != 2 /* BE */)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
if (ehdr->e_class != 1 && ehdr->e_class != 2)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
e_class = ehdr->e_class;
|
||||
ldr = vm::get_addr(&_overlay);
|
||||
ldr->_vtable = vm::cast(u32{e_class}); // TODO
|
||||
ldr->src = vm::static_ptr_cast<u8>(src);
|
||||
ldr->x8 = arg2;
|
||||
ldr->ehdr_off = ehdr_off;
|
||||
ldr->phdr_off = phdr_off;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
};
|
||||
|
||||
s32 sys_spu_elf_get_information(u32 elf_img, vm::ptr<u32> entry, vm::ptr<s32> nseg)
|
||||
{
|
||||
sysPrxForUser.todo("sys_spu_elf_get_information(elf_img=0x%x, entry=*0x%x, nseg=*0x%x)", elf_img, entry, nseg);
|
||||
|
@ -28,34 +195,116 @@ s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
|
||||
error_code sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type);
|
||||
|
||||
// Load from memory (TODO)
|
||||
img->load(fs::file{vm::base(src), 0 - src});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img);
|
||||
|
||||
if (img->type == SYS_SPU_IMAGE_TYPE_USER)
|
||||
if (type != SYS_SPU_IMAGE_PROTECT && type != SYS_SPU_IMAGE_DIRECT)
|
||||
{
|
||||
//_sys_free(img->segs.addr());
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL)
|
||||
|
||||
// Initialize ELF loader
|
||||
vm::var<spu_elf_info> info(spu_elf_info{});
|
||||
|
||||
if (auto res = info->init(vm::cast(src)))
|
||||
{
|
||||
//return syscall_158(img);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (info->sce0.se_magic == 0x53434500)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load ELF header
|
||||
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
|
||||
|
||||
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load program headers
|
||||
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
|
||||
|
||||
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
if (type == SYS_SPU_IMAGE_PROTECT)
|
||||
{
|
||||
u32 img_size = 0;
|
||||
|
||||
for (const auto& p : phdr)
|
||||
{
|
||||
if (p.p_type != 1 && p.p_type != 4)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
img_size = std::max<u32>(img_size, static_cast<u32>(p.p_offset + p.p_filesz));
|
||||
}
|
||||
|
||||
return _sys_spu_image_import(img, src, img_size, 0);
|
||||
}
|
||||
else if (type == SYS_SPU_IMAGE_DIRECT)
|
||||
{
|
||||
s32 num_segs = sys_spu_image::get_nsegs(phdr);
|
||||
|
||||
if (num_segs < 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
img->nsegs = num_segs;
|
||||
img->entry_point = static_cast<u32>(ehdr->e_entry);
|
||||
|
||||
vm::ptr<sys_spu_segment> segs = vm::cast(vm::alloc(num_segs * sizeof(sys_spu_segment), vm::main));
|
||||
|
||||
if (!segs)
|
||||
{
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
|
||||
if (sys_spu_image::fill(segs, phdr, src) != num_segs)
|
||||
{
|
||||
vm::dealloc(segs.addr());
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
img->type = SYS_SPU_IMAGE_TYPE_USER;
|
||||
img->segs = segs;
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img);
|
||||
|
||||
if (img->type == SYS_SPU_IMAGE_TYPE_USER)
|
||||
{
|
||||
//_sys_free(img->segs.addr());
|
||||
vm::dealloc_verbose_nothrow(img->segs.addr(), vm::main);
|
||||
}
|
||||
else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL)
|
||||
{
|
||||
// Call the syscall
|
||||
return _sys_spu_image_close(img);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
img->free();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -94,7 +343,7 @@ s32 sys_raw_spu_image_load(ppu_thread& ppu, s32 id, vm::ptr<sys_spu_image> img)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_printf_cb_t atcb, spu_printf_cb_t dtcb)
|
||||
error_code _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_printf_cb_t atcb, spu_printf_cb_t dtcb)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_initialize(agcb=*0x%x, dgcb=*0x%x, atcb=*0x%x, dtcb=*0x%x)", agcb, dgcb, atcb, dtcb);
|
||||
|
||||
|
@ -107,7 +356,7 @@ s32 _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_p
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_finalize()
|
||||
error_code _sys_spu_printf_finalize()
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_finalize()");
|
||||
|
||||
|
@ -119,7 +368,7 @@ s32 _sys_spu_printf_finalize()
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
||||
error_code _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_attach_group(group=0x%x)", group);
|
||||
|
||||
|
@ -131,7 +380,7 @@ s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
|||
return g_spu_printf_agcb(ppu, group);
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
||||
error_code _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_detach_group(group=0x%x)", group);
|
||||
|
||||
|
@ -143,7 +392,7 @@ s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
|||
return g_spu_printf_dgcb(ppu, group);
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
||||
error_code _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_attach_thread(thread=0x%x)", thread);
|
||||
|
||||
|
@ -155,7 +404,7 @@ s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
|||
return g_spu_printf_atcb(ppu, thread);
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
|
||||
error_code _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_detach_thread(thread=0x%x)", thread);
|
||||
|
||||
|
|
|
@ -20,20 +20,13 @@ logs::channel sys_spu("sys_spu");
|
|||
|
||||
void sys_spu_image::load(const fs::file& stream)
|
||||
{
|
||||
const spu_exec_object obj{stream};
|
||||
const spu_exec_object obj{stream, 0, elf_opt::no_sections + elf_opt::no_data};
|
||||
|
||||
if (obj != elf_error::ok)
|
||||
{
|
||||
fmt::throw_exception("Failed to load SPU image: %s" HERE, obj.get_error());
|
||||
}
|
||||
|
||||
this->type = SYS_SPU_IMAGE_TYPE_KERNEL;
|
||||
this->entry_point = obj.header.e_entry;
|
||||
this->segs.set(vm::alloc(65 * 4096, vm::main));
|
||||
this->nsegs = 0;
|
||||
|
||||
const u32 addr = this->segs.addr() + 4096;
|
||||
|
||||
for (const auto& shdr : obj.shdrs)
|
||||
{
|
||||
LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags);
|
||||
|
@ -43,37 +36,26 @@ void sys_spu_image::load(const fs::file& stream)
|
|||
{
|
||||
LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
|
||||
|
||||
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
|
||||
{
|
||||
auto& seg = segs[nsegs++];
|
||||
seg.type = prog.p_type;
|
||||
seg.ls = prog.p_vaddr;
|
||||
seg.addr = addr + prog.p_vaddr;
|
||||
seg.size = std::min(prog.p_filesz, prog.p_memsz);
|
||||
std::memcpy(vm::base(seg.addr), prog.bin.data(), seg.size);
|
||||
|
||||
if (prog.p_memsz > prog.p_filesz)
|
||||
{
|
||||
auto& zero = segs[nsegs++];
|
||||
zero.type = SYS_SPU_SEGMENT_TYPE_FILL;
|
||||
zero.ls = prog.p_vaddr + prog.p_filesz;
|
||||
zero.addr = 0;
|
||||
zero.size = prog.p_memsz - seg.size;
|
||||
}
|
||||
}
|
||||
else if (prog.p_type == SYS_SPU_SEGMENT_TYPE_INFO)
|
||||
{
|
||||
auto& seg = segs[nsegs++];
|
||||
seg.type = SYS_SPU_SEGMENT_TYPE_INFO;
|
||||
seg.ls = prog.p_vaddr;
|
||||
seg.addr = 0;
|
||||
seg.size = prog.p_filesz;
|
||||
}
|
||||
else
|
||||
if (prog.p_type != SYS_SPU_SEGMENT_TYPE_COPY && prog.p_type != SYS_SPU_SEGMENT_TYPE_INFO)
|
||||
{
|
||||
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
|
||||
}
|
||||
}
|
||||
|
||||
type = SYS_SPU_IMAGE_TYPE_KERNEL;
|
||||
entry_point = obj.header.e_entry;
|
||||
nsegs = sys_spu_image::get_nsegs(obj.progs);
|
||||
segs = vm::cast(vm::alloc(nsegs * sizeof(sys_spu_segment) + ::size32(stream), vm::main));
|
||||
|
||||
const u32 src = segs.addr() + nsegs * sizeof(sys_spu_segment);
|
||||
|
||||
stream.seek(0);
|
||||
stream.read(vm::base(src), stream.size());
|
||||
|
||||
if (nsegs < 0 || sys_spu_image::fill(segs, obj.progs, src) != nsegs)
|
||||
{
|
||||
fmt::throw_exception("Failed to load SPU segments (%d)" HERE, nsegs);
|
||||
}
|
||||
}
|
||||
|
||||
void sys_spu_image::free()
|
||||
|
@ -100,13 +82,13 @@ void sys_spu_image::deploy(u32 loc)
|
|||
|
||||
fmt::append(dump, "\n\t[%d] t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", i, seg.type, seg.ls, seg.size, seg.addr);
|
||||
|
||||
// Hash big-endian values
|
||||
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
|
||||
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
|
||||
|
||||
// Hash big-endian values
|
||||
if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY)
|
||||
{
|
||||
std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size);
|
||||
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
|
||||
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
|
||||
sha1_update(&sha, vm::g_base_addr + seg.addr, seg.size);
|
||||
}
|
||||
|
@ -118,9 +100,15 @@ void sys_spu_image::deploy(u32 loc)
|
|||
}
|
||||
|
||||
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
|
||||
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
|
||||
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
|
||||
sha1_update(&sha, (uchar*)&seg.addr, sizeof(seg.addr));
|
||||
}
|
||||
else if (seg.type == SYS_SPU_SEGMENT_TYPE_INFO)
|
||||
{
|
||||
const be_t<u32> size = seg.size + 0x14; // Workaround
|
||||
sha1_update(&sha, (uchar*)&size, sizeof(size));
|
||||
}
|
||||
}
|
||||
|
||||
sha1_finish(&sha, sha1_hash);
|
||||
|
@ -182,18 +170,20 @@ error_code sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4)
|
||||
error_code _sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 size, u32 arg4)
|
||||
{
|
||||
sys_spu.todo("_sys_spu_image_import(img=*0x%x, src=*0x%x, arg3=0x%x, arg4=0x%x)", img, src, arg3, arg4);
|
||||
sys_spu.warning("_sys_spu_image_import(img=*0x%x, src=*0x%x, size=0x%x, arg4=0x%x)", img, src, size, arg4);
|
||||
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_import");
|
||||
img->load(fs::file{vm::base(src), size});
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
{
|
||||
sys_spu.todo("_sys_spu_image_close(img=*0x%x)", img);
|
||||
sys_spu.warning("_sys_spu_image_close(img=*0x%x)", img);
|
||||
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_close");
|
||||
vm::dealloc(img->segs.addr(), vm::main);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_raw_spu_image_load(vm::ptr<sys_spu_image> img, u32 ptr, u32 arg3)
|
||||
|
|
|
@ -112,6 +112,74 @@ struct sys_spu_image
|
|||
vm::ps3::bptr<sys_spu_segment> segs;
|
||||
be_t<s32> nsegs;
|
||||
|
||||
template <typename Phdrs>
|
||||
static s32 get_nsegs(const Phdrs& phdrs)
|
||||
{
|
||||
s32 num_segs = 0;
|
||||
|
||||
for (const auto& phdr : phdrs)
|
||||
{
|
||||
if (phdr.p_type != 1 && phdr.p_type != 4)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (phdr.p_type == 1 && phdr.p_filesz != phdr.p_memsz && phdr.p_filesz)
|
||||
{
|
||||
num_segs += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_segs += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return num_segs;
|
||||
}
|
||||
|
||||
template <typename Phdrs>
|
||||
static s32 fill(vm::ps3::ptr<sys_spu_segment> segs, const Phdrs& phdrs, u32 src)
|
||||
{
|
||||
s32 num_segs = 0;
|
||||
|
||||
for (const auto& phdr : phdrs)
|
||||
{
|
||||
if (phdr.p_type == 1)
|
||||
{
|
||||
if (phdr.p_filesz)
|
||||
{
|
||||
auto* seg = &segs[num_segs++];
|
||||
seg->type = SYS_SPU_SEGMENT_TYPE_COPY;
|
||||
seg->ls = static_cast<u32>(phdr.p_vaddr);
|
||||
seg->size = static_cast<u32>(phdr.p_filesz);
|
||||
seg->addr = static_cast<u32>(phdr.p_offset + src);
|
||||
}
|
||||
|
||||
if (phdr.p_memsz > phdr.p_filesz)
|
||||
{
|
||||
auto* seg = &segs[num_segs++];
|
||||
seg->type = SYS_SPU_SEGMENT_TYPE_FILL;
|
||||
seg->ls = static_cast<u32>(phdr.p_vaddr + phdr.p_filesz);
|
||||
seg->size = static_cast<u32>(phdr.p_memsz - phdr.p_filesz);
|
||||
seg->addr = 0;
|
||||
}
|
||||
}
|
||||
else if (phdr.p_type == 4)
|
||||
{
|
||||
auto* seg = &segs[num_segs++];
|
||||
seg->type = SYS_SPU_SEGMENT_TYPE_INFO;
|
||||
seg->size = 0x20;
|
||||
seg->addr = static_cast<u32>(phdr.p_offset + 0x14 + src);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return num_segs;
|
||||
}
|
||||
|
||||
void load(const fs::file& stream);
|
||||
void free();
|
||||
void deploy(u32 loc);
|
||||
|
@ -205,7 +273,7 @@ class ppu_thread;
|
|||
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
|
||||
error_code _sys_spu_image_get_information(vm::ps3::ptr<sys_spu_image> img, u32 ptr1, u32 ptr2);
|
||||
error_code sys_spu_image_open(vm::ps3::ptr<sys_spu_image> img, vm::ps3::cptr<char> path);
|
||||
error_code _sys_spu_image_import(vm::ps3::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4);
|
||||
error_code _sys_spu_image_import(vm::ps3::ptr<sys_spu_image> img, u32 src, u32 size, u32 arg4);
|
||||
error_code _sys_spu_image_close(vm::ps3::ptr<sys_spu_image> img);
|
||||
error_code _sys_raw_spu_image_load(vm::ps3::ptr<sys_spu_image> img, u32 ptr, u32 arg3);
|
||||
error_code sys_spu_thread_initialize(vm::ps3::ptr<u32> thread, u32 group, u32 spu_num, vm::ps3::ptr<sys_spu_image>, vm::ps3::ptr<sys_spu_thread_attribute>, vm::ps3::ptr<sys_spu_thread_argument>);
|
||||
|
|
|
@ -96,6 +96,16 @@ namespace vm
|
|||
{
|
||||
return m_size / SIZE_32(T);
|
||||
}
|
||||
|
||||
auto begin() const
|
||||
{
|
||||
return *this + 0;
|
||||
}
|
||||
|
||||
auto end() const
|
||||
{
|
||||
return *this + get_count();
|
||||
}
|
||||
};
|
||||
|
||||
// LE variable
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../../Utilities/types.h"
|
||||
#include "../../Utilities/File.h"
|
||||
#include "../../Utilities/bit_set.h"
|
||||
|
||||
enum class elf_os : u8
|
||||
{
|
||||
|
@ -133,6 +134,16 @@ struct elf_shdr
|
|||
en_t<sz_t> sh_entsize;
|
||||
};
|
||||
|
||||
// ELF loading options
|
||||
enum class elf_opt : u32
|
||||
{
|
||||
no_programs, // Don't load phdrs, implies no_data
|
||||
no_sections, // Don't load shdrs
|
||||
no_data, // Load phdrs without data
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
||||
// ELF loading error
|
||||
enum class elf_error
|
||||
{
|
||||
|
@ -180,12 +191,12 @@ public:
|
|||
public:
|
||||
elf_object() = default;
|
||||
|
||||
elf_object(const fs::file& stream, u64 offset = 0)
|
||||
elf_object(const fs::file& stream, u64 offset = 0, bs_t<elf_opt> opts = {})
|
||||
{
|
||||
open(stream, offset);
|
||||
open(stream, offset, opts);
|
||||
}
|
||||
|
||||
elf_error open(const fs::file& stream, u64 offset = 0)
|
||||
elf_error open(const fs::file& stream, u64 offset = 0, bs_t<elf_opt> opts = {})
|
||||
{
|
||||
// Check stream
|
||||
if (!stream)
|
||||
|
@ -231,15 +242,23 @@ public:
|
|||
return set_error(elf_error::header_version);
|
||||
|
||||
// Load program headers
|
||||
std::vector<phdr_t> _phdrs(header.e_phnum);
|
||||
stream.seek(offset + header.e_phoff);
|
||||
if (!stream.read(_phdrs))
|
||||
return set_error(elf_error::stream_phdrs);
|
||||
std::vector<phdr_t> _phdrs;
|
||||
|
||||
if (!test(opts, elf_opt::no_programs))
|
||||
{
|
||||
_phdrs.resize(header.e_phnum);
|
||||
stream.seek(offset + header.e_phoff);
|
||||
if (!stream.read(_phdrs))
|
||||
return set_error(elf_error::stream_phdrs);
|
||||
}
|
||||
|
||||
shdrs.resize(header.e_shnum);
|
||||
stream.seek(offset + header.e_shoff);
|
||||
if (!stream.read(shdrs))
|
||||
return set_error(elf_error::stream_shdrs);
|
||||
if (!test(opts, elf_opt::no_sections))
|
||||
{
|
||||
shdrs.resize(header.e_shnum);
|
||||
stream.seek(offset + header.e_shoff);
|
||||
if (!stream.read(shdrs))
|
||||
return set_error(elf_error::stream_shdrs);
|
||||
}
|
||||
|
||||
progs.clear();
|
||||
progs.reserve(_phdrs.size());
|
||||
|
@ -248,10 +267,14 @@ public:
|
|||
progs.emplace_back();
|
||||
|
||||
static_cast<phdr_t&>(progs.back()) = hdr;
|
||||
progs.back().bin.resize(hdr.p_filesz);
|
||||
stream.seek(offset + hdr.p_offset);
|
||||
if (!stream.read(progs.back().bin))
|
||||
return set_error(elf_error::stream_data);
|
||||
|
||||
if (!test(opts, elf_opt::no_data))
|
||||
{
|
||||
progs.back().bin.resize(hdr.p_filesz);
|
||||
stream.seek(offset + hdr.p_offset);
|
||||
if (!stream.read(progs.back().bin))
|
||||
return set_error(elf_error::stream_data);
|
||||
}
|
||||
}
|
||||
|
||||
shdrs.shrink_to_fit();
|
||||
|
|
Loading…
Add table
Reference in a new issue