diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp index 961e30591f..a089933124 100644 --- a/rpcs3/Crypto/unself.cpp +++ b/rpcs3/Crypto/unself.cpp @@ -885,12 +885,17 @@ SELFDecrypter::SELFDecrypter(const fs::file& s) { } -bool SELFDecrypter::LoadHeaders(bool isElf32) +bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info) { // Read SCE header. self_f.seek(0); sce_hdr.Load(self_f); + if (out_info) + { + out_info->valid = false; + } + // Check SCE magic. if (!sce_hdr.CheckMagic()) { @@ -905,6 +910,11 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) self_f.seek(self_hdr.se_appinfooff); app_info.Load(self_f); + if (out_info) + { + out_info->app_info = app_info; + } + // Read ELF header. self_f.seek(self_hdr.se_elfoff); @@ -967,8 +977,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) ctrlinfo_arr.clear(); self_f.seek(self_hdr.se_controloff); - u32 i = 0; - while(i < self_hdr.se_controlsize) + for (u64 i = 0; i < self_hdr.se_controlsize;) { ctrlinfo_arr.emplace_back(); ControlInfo &cinfo = ctrlinfo_arr.back(); @@ -976,6 +985,11 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) i += cinfo.size; } + if (out_info) + { + out_info->ctrl_info = ctrlinfo_arr; + } + // Read ELF section headers. if (isElf32) { @@ -1013,6 +1027,11 @@ bool SELFDecrypter::LoadHeaders(bool isElf32) } } + if (out_info) + { + out_info->valid = true; + } + return true; } @@ -1374,8 +1393,13 @@ static bool CheckDebugSelf(fs::file& s) return false; } -extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key) +fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* out_info) { + if (out_info) + { + out_info->valid = false; + } + if (!elf_or_self) { return fs::file{}; @@ -1393,7 +1417,7 @@ extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key) SELFDecrypter self_dec(elf_or_self); // Load the SELF file headers. - if (!self_dec.LoadHeaders(isElf32)) + if (!self_dec.LoadHeaders(isElf32, out_info)) { LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!"); return fs::file{}; @@ -1420,7 +1444,7 @@ extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key) return elf_or_self; } -extern bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key) +bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key) { if (!self) return false; diff --git a/rpcs3/Crypto/unself.h b/rpcs3/Crypto/unself.h index 8032834594..bbf3c70cf5 100644 --- a/rpcs3/Crypto/unself.h +++ b/rpcs3/Crypto/unself.h @@ -343,6 +343,13 @@ struct SelfHeader void Show(){} }; +struct SelfAdditionalInfo +{ + bool valid = false; + std::vector ctrl_info; + AppInfo app_info; +}; + class SCEDecrypter { protected: @@ -413,7 +420,7 @@ class SELFDecrypter public: SELFDecrypter(const fs::file& s); fs::file MakeElf(bool isElf32); - bool LoadHeaders(bool isElf32); + bool LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info = nullptr); void ShowHeaders(bool isElf32); bool LoadMetadata(u8* klic_key); bool DecryptData(); @@ -497,6 +504,6 @@ private: } }; -extern fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr); -extern bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr); -extern std::array get_default_self_klic(); +fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr); +bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr); +std::array get_default_self_klic(); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index ba745113ce..baea8179ca 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -1160,6 +1160,27 @@ void ppu_load_exec(const ppu_exec_object& elf) } } + // Read control flags (0 if doesn't exist) + g_ps3_process_info.ctrl_flags1 = 0; + + if (bool not_found = true) + { + for (const auto& ctrl : g_ps3_process_info.self_info.ctrl_info) + { + if (ctrl.type == 1) + { + if (!std::exchange(not_found, false)) + { + LOG_ERROR(LOADER, "More than one control flags header found! (flags1=0x%x)", + ctrl.control_flags.ctrl_flag1); + break; + } + + g_ps3_process_info.ctrl_flags1 |= ctrl.control_flags.ctrl_flag1; + } + } + } + // Load other programs for (auto& prog : elf.progs) { @@ -1207,7 +1228,8 @@ void ppu_load_exec(const ppu_exec_object& elf) { sdk_version = info.sdk_version; - if (s32 prio = info.primary_prio; prio < 3072 && prio >= 0) + if (s32 prio = info.primary_prio; prio < 3072 + && (prio >= (g_ps3_process_info.debug_or_root() ? 0 : -512))) { primary_prio = prio; } diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 944ec21665..f1b926109d 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -166,7 +166,7 @@ public: u64 rtime{0}; u64 rdata{0}; // Reservation data - atomic_t prio{0}; // Thread priority (0..3071) + atomic_t prio{0}; // Thread priority (0..3071) const u32 stack_size; // Stack size const u32 stack_addr; // Stack address diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 7708887393..4757b89f4f 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -770,7 +770,7 @@ const std::array s_ppu_syscall_table null_func,//BIND_FUNC(sys_ss_individual_info_manager) //868 ROOT / DBG AUTHID null_func,//BIND_FUNC(sys_ss_factory_data_manager) //869 ROOT BIND_FUNC(sys_ss_get_console_id), //870 (0x366) - null_func,//BIND_FUNC(sys_ss_access_control_engine), //871 (0x367) DBG + BIND_FUNC(sys_ss_access_control_engine), //871 (0x367) DBG BIND_FUNC(sys_ss_get_open_psid), //872 (0x368) null_func,//BIND_FUNC(sys_ss_get_cache_of_product_mode), //873 (0x369) null_func,//BIND_FUNC(sys_ss_get_cache_of_flash_ext_flag), //874 (0x36A) @@ -1066,20 +1066,24 @@ void lv2_obj::sleep_unlocked(cpu_thread& thread, u64 timeout) } } -void lv2_obj::awake_unlocked(cpu_thread* cpu, u32 prio) +void lv2_obj::awake_unlocked(cpu_thread* cpu, s32 prio) { // Check thread type AUDIT(!cpu || cpu->id_type() == 1); - if (prio < INT32_MAX) + switch (prio) { - // Priority set - if (static_cast(cpu)->prio.exchange(prio) == prio || !unqueue(g_ppu, cpu)) - { - return; - } + default: + { + // Priority set + if (static_cast(cpu)->prio.exchange(prio) == prio || !unqueue(g_ppu, cpu)) + { + return; + } + + break; } - else if (prio == -4) + case yield_cmd: { // Yield command const u64 start_time = get_guest_system_time(); @@ -1102,6 +1106,11 @@ void lv2_obj::awake_unlocked(cpu_thread* cpu, u32 prio) static_cast(cpu)->start_time = start_time; } + case enqueue_cmd: + { + break; + } + } const auto emplace_thread = [](cpu_thread* const cpu) { diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index bd54a6ec8b..5e4fbf6093 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -7,6 +7,7 @@ #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_event.h" +#include "sys_process.h" #include "sys_mmapper.h" LOG_CHANNEL(sys_ppu_thread); @@ -210,7 +211,7 @@ error_code sys_ppu_thread_set_priority(ppu_thread& ppu, u32 thread_id, s32 prio) { sys_ppu_thread.trace("sys_ppu_thread_set_priority(thread_id=0x%x, prio=%d)", thread_id, prio); - if (prio < 0 || prio > 3071) + if (prio < (g_ps3_process_info.debug_or_root() ? -512 : 0) || prio > 3071) { return CELL_EINVAL; } @@ -219,7 +220,7 @@ error_code sys_ppu_thread_set_priority(ppu_thread& ppu, u32 thread_id, s32 prio) { if (thread.prio != prio) { - lv2_obj::awake(&thread, prio); + lv2_obj::set_priority(thread, prio); } }); @@ -299,7 +300,7 @@ error_code _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr 3071) + if (prio < (g_ps3_process_info.debug_or_root() ? -512 : 0) || prio > 3071) { return CELL_EINVAL; } @@ -359,7 +360,7 @@ error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id) const auto thread = idm::get>(thread_id, [&](ppu_thread& thread) { - lv2_obj::awake(&thread, -2); + lv2_obj::awake(&thread); }); if (!thread) diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 0649bb67d6..7ebf1a4eee 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -25,7 +25,23 @@ #include "sys_fs.h" #include "sys_spu.h" +// Check all flags known to be related to extended permissions (TODO) +// I think anything which has root flags implicitly has debug perm as well +// But I havn't confirmed it. +bool ps3_process_info_t::debug_or_root() const +{ + return (ctrl_flags1 & (0xe << 28)) != 0; +} +bool ps3_process_info_t::has_root_perm() const +{ + return (ctrl_flags1 & (0xc << 28)) != 0; +} + +bool ps3_process_info_t::has_debug_perm() const +{ + return (ctrl_flags1 & (0xa << 28)) != 0; +} LOG_CHANNEL(sys_process); diff --git a/rpcs3/Emu/Cell/lv2/sys_process.h b/rpcs3/Emu/Cell/lv2/sys_process.h index 6c258bdc42..cf6ec469fb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.h +++ b/rpcs3/Emu/Cell/lv2/sys_process.h @@ -1,5 +1,6 @@ #pragma once +#include "Crypto/unself.h" #include "Emu/Memory/vm_ptr.h" // Process Local Object Type @@ -40,6 +41,12 @@ struct ps3_process_info_t { u32 sdk_ver; u32 ppc_seg; + SelfAdditionalInfo self_info; + u32 ctrl_flags1 = 0; + + bool has_root_perm() const; + bool has_debug_perm() const; + bool debug_or_root() const; }; extern ps3_process_info_t g_ps3_process_info; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 48d72d2b4a..1bea099906 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -13,6 +13,7 @@ #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/RawSPUThread.h" #include "sys_interrupt.h" +#include "sys_process.h" #include "sys_mmapper.h" #include "sys_event.h" @@ -409,7 +410,8 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num // TODO: max num value should be affected by sys_spu_initialize() settings - if (attr->nsize > 0x80 || !num || num > 6 || ((prio < 16 || prio > 255) && (attr->type != SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT && attr->type != SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM))) + const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16; + if (attr->nsize > 0x80 || !num || num > 6 || ((prio < min_prio || prio > 255) && (attr->type != SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT && attr->type != SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM))) { return CELL_EINVAL; } @@ -802,11 +804,6 @@ error_code sys_spu_thread_group_set_priority(ppu_thread& ppu, u32 id, s32 priori sys_spu.trace("sys_spu_thread_group_set_priority(id=0x%x, priority=%d)", id, priority); - if (priority < 16 || priority > 255) - { - return CELL_EINVAL; - } - const auto group = idm::get(id); if (!group) @@ -814,6 +811,11 @@ error_code sys_spu_thread_group_set_priority(ppu_thread& ppu, u32 id, s32 priori return CELL_ESRCH; } + if (priority < (g_ps3_process_info.has_root_perm() ? 0 : 16) || priority > 255) + { + return CELL_EINVAL; + } + if (group->type == SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) { return CELL_EINVAL; diff --git a/rpcs3/Emu/Cell/lv2/sys_ss.cpp b/rpcs3/Emu/Cell/lv2/sys_ss.cpp index f8fcf47d8e..844c7ac19a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ss.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ss.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "sys_ss.h" +#include "sys_process.h" #include "Emu/Cell/PPUThread.h" @@ -64,6 +65,52 @@ error_code sys_ss_random_number_generator(u32 arg1, vm::ptr buf, u64 size) return CELL_OK; } +error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3) +{ + sys_ss.todo("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3); + + const u64 authid = g_ps3_process_info.self_info.valid ? + g_ps3_process_info.self_info.app_info.authid : 0; + + switch (pkg_id) + { + case 0x1: + { + if (!g_ps3_process_info.debug_or_root()) + { + return CELL_ENOSYS; + } + + if (!a2) + { + return CELL_ESRCH; + } + + verify(HERE), a2 == process_getpid(); + vm::_ref(vm::cast(a3)) = authid; + break; + } + case 0x2: + { + vm::_ref(vm::cast(a2)) = authid; + break; + } + case 0x3: + { + if (!g_ps3_process_info.debug_or_root()) + { + return CELL_ENOSYS; + } + + break; + } + default: + return 0x8001051du; + } + + return CELL_OK; +} + s32 sys_ss_get_console_id(vm::ptr buf) { sys_ss.todo("sys_ss_get_console_id(buf=*0x%x)", buf); diff --git a/rpcs3/Emu/Cell/lv2/sys_ss.h b/rpcs3/Emu/Cell/lv2/sys_ss.h index 12a0ac1230..3ca032d67d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ss.h +++ b/rpcs3/Emu/Cell/lv2/sys_ss.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Emu/Memory/vm_ptr.h" #include "Emu/Cell/ErrorCodes.h" @@ -10,5 +10,6 @@ struct CellSsOpenPSID }; error_code sys_ss_random_number_generator(u32 arg1, vm::ptr buf, u64 size); +error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3); s32 sys_ss_get_console_id(vm::ptr buf); s32 sys_ss_get_open_psid(vm::ptr ptr); diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index b9d1b32335..16c9fff20c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -65,6 +65,15 @@ struct lv2_obj static const u32 id_step = 0x100; static const u32 id_count = 8192; +private: + enum thread_cmd : s32 + { + yield_cmd = INT32_MIN, + enqueue_cmd, + }; + +public: + // Find and remove the object from the container (deque or vector) template static bool unqueue(std::deque& queue, const E& object) @@ -96,7 +105,7 @@ struct lv2_obj return res; } - u32 prio = -1; + s32 prio = 3071; auto it = queue.cbegin(); for (auto found = it, end = queue.cend(); found != end; found++) @@ -120,7 +129,7 @@ private: static void sleep_unlocked(cpu_thread&, u64 timeout); // Schedule the thread - static void awake_unlocked(cpu_thread*, u32 prio = -1); + static void awake_unlocked(cpu_thread*, s32 prio = enqueue_cmd); public: static void sleep(cpu_thread& cpu, const u64 timeout = 0) @@ -130,7 +139,7 @@ public: g_to_awake.clear(); } - static inline void awake(cpu_thread* const thread, const u32 prio = -1) + static inline void awake(cpu_thread* const thread, s32 prio = enqueue_cmd) { std::lock_guard lock(g_mutex); awake_unlocked(thread, prio); @@ -139,7 +148,13 @@ public: static void yield(cpu_thread& thread) { vm::temporary_unlock(thread); - awake(&thread, -4); + awake(&thread, yield_cmd); + } + + static void set_priority(cpu_thread& thread, s32 prio) + { + verify(HERE), prio + 512u < 3712; + awake(&thread, prio); } static inline void awake_all() diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index bdb4ac77dc..d5e27c3312 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -10,6 +10,7 @@ #include "Emu/Cell/PPUAnalyser.h" #include "Emu/Cell/SPUThread.h" #include "Emu/Cell/RawSPUThread.h" +#include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_memory.h" #include "Emu/Cell/lv2/sys_sync.h" #include "Emu/Cell/lv2/sys_prx.h" @@ -1481,7 +1482,7 @@ void Emulator::Load(const std::string& title_id, bool add_only, bool force_globa elf_file.open(decrypted_path); } // Decrypt SELF - else if ((elf_file = decrypt_self(std::move(elf_file), klic.empty() ? nullptr : klic.data()))) + else if ((elf_file = decrypt_self(std::move(elf_file), klic.empty() ? nullptr : klic.data(), &g_ps3_process_info.self_info))) { if (true) { @@ -1498,6 +1499,10 @@ void Emulator::Load(const std::string& title_id, bool add_only, bool force_globa } } } + else + { + g_ps3_process_info.self_info.valid = false; + } if (!elf_file) {