diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index c2d430fe10..db038bc368 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -1343,10 +1343,13 @@ static fs::file CheckDebugSelf(const fs::file& s) fs::file e = fs::make_stream>(); // Copy the data. - char buf[2048]; - while (const u64 size = s.read(buf, 2048)) + std::vector buf(std::min(s.size(), 4096)); + + usz read_pos = 0; + while (const u64 size = s.read_at(read_pos, buf.data(), buf.size())) { - e.write(buf, size); + e.write(buf.data(), size); + read_pos += size; } return e; @@ -1412,6 +1415,23 @@ fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key, SelfAddit // Make a new ELF file from this SELF. return self_dec.MakeElf(isElf32); } + else if (Emu.GetBoot().ends_with(".elf") || Emu.GetBoot().ends_with(".ELF")) + { + // Write the file back if the main executable is not signed + fs::file e = fs::make_stream>(); + + // Copy the data. + std::vector buf(std::min(elf_or_self.size(), 4096)); + + usz read_pos = 0; + while (const u64 size = elf_or_self.read_at(read_pos, buf.data(), buf.size())) + { + e.write(buf.data(), size); + read_pos += size; + } + + return e; + } return {}; } diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index e5c00fab9d..8d4db2bc91 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -373,7 +373,7 @@ const std::array, 1024> g_ppu_sysc uns_func, uns_func, uns_func, uns_func, uns_func, //255-259 UNS - NULL_FUNC(sys_spu_image_open_by_fd), //260 (0x104) + BIND_SYSC(sys_spu_image_open_by_fd), //260 (0x104) uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, //261-269 UNS uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, uns_func, //270-279 UNS diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 9cc12678b9..77fbcb8505 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -66,13 +66,14 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -void sys_spu_image::load(const fs::file& stream) +bool sys_spu_image::load(const fs::file& 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", obj.get_error()); + sys_spu.error("Failed to load SPU image: %s", obj.get_error()); + return false; } for (const auto& shdr : obj.shdrs) @@ -94,7 +95,7 @@ void sys_spu_image::load(const fs::file& stream) const s32 nsegs = sys_spu_image::get_nsegs(obj.progs); const u32 mem_size = nsegs * sizeof(sys_spu_segment) + ::size32(stream); - const vm::ptr segs = vm::cast(vm::reserve_map(vm::user64km 0, 0x10000000)->alloc(mem_size)); + const vm::ptr segs = vm::cast(vm::reserve_map(vm::user64k, 0, 0x10000000)->alloc(mem_size)); //const u32 entry = obj.header.e_entry; @@ -116,6 +117,7 @@ void sys_spu_image::load(const fs::file& stream) this->segs = vm::null; vm::page_protect(segs.addr(), utils::align(mem_size, 4096), 0, 0, vm::page_writable); + return true; } void sys_spu_image::free() const @@ -517,28 +519,52 @@ error_code sys_spu_image_open(ppu_thread& ppu, vm::ptr img, vm::c u128 klic = g_fxo->get().last_key(); - fs::file elf_file; + const fs::file elf_file = decrypt_self(file, reinterpret_cast(&klic)); - // Check for SELF header - u32 file_type = umax; - file.read_at(0, &file_type, sizeof(file_type)); - - if (file_type == "SCE\0"_u32) - { - elf_file = decrypt_self(file, reinterpret_cast(&klic)); - } - else - { - elf_file = std::move(file); - } - - if (!elf_file) + if (!elf_file || !img->load(elf_file)) { sys_spu.error("sys_spu_image_open(): file %s is illegal for SPU image!", path); return {CELL_ENOEXEC, path}; } - img->load(elf_file); + return CELL_OK; +} + +error_code sys_spu_image_open_by_fd(ppu_thread& ppu, vm::ptr img, s32 fd, s64 offset) +{ + ppu.state += cpu_flag::wait; + + sys_spu.warning("sys_spu_image_open_by_fd(img=*0x%x, fd=%d, offset=0x%x)", img, fd, offset); + + const auto file = idm::get_unlocked(fd); + + if (!file) + { + return CELL_EBADF; + } + + if (offset < 0) + { + return CELL_ENOEXEC; + } + + std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + + u128 klic = g_fxo->get().last_key(); + + const fs::file elf_file = decrypt_self(lv2_file::make_view(file, offset), reinterpret_cast(&klic)); + + if (!img->load(elf_file)) + { + sys_spu.error("sys_spu_image_open(): file %s is illegal for SPU image!", file->name.data()); + return {CELL_ENOEXEC, file->name.data()}; + } + return CELL_OK; } @@ -570,7 +596,7 @@ error_code _sys_spu_image_close(ppu_thread& ppu, vm::ptr img) return CELL_ESRCH; } - ensure(vm::dealloc(handle->segs.addr(), vm::main)); + ensure(vm::dealloc(handle->segs.addr(), vm::user64k)); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index c1f6c31bb5..06e21e067b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -225,7 +225,7 @@ struct sys_spu_image return num_segs; } - void load(const fs::file& stream); + bool load(const fs::file& stream); void free() const; static void deploy(u8* loc, std::span segs, bool is_verbose = true); }; @@ -354,6 +354,7 @@ class ppu_thread; error_code sys_spu_initialize(ppu_thread&, u32 max_usable_spu, u32 max_raw_spu); error_code _sys_spu_image_get_information(ppu_thread&, vm::ptr img, vm::ptr entry_point, vm::ptr nsegs); error_code sys_spu_image_open(ppu_thread&, vm::ptr img, vm::cptr path); +error_code sys_spu_image_open_by_fd(ppu_thread&, vm::ptr img, s32 fd, s64 offset); error_code _sys_spu_image_import(ppu_thread&, vm::ptr img, u32 src, u32 size, u32 arg4); error_code _sys_spu_image_close(ppu_thread&, vm::ptr img); error_code _sys_spu_image_get_segments(ppu_thread&, vm::ptr img, vm::ptr segments, s32 nseg);