diff options
Diffstat (limited to 'src/core')
41 files changed, 786 insertions, 478 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 753f55ebe..293d9647b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -490,6 +490,10 @@ add_library(core STATIC | |||
| 490 | hle/service/filesystem/fsp_pr.h | 490 | hle/service/filesystem/fsp_pr.h |
| 491 | hle/service/filesystem/fsp_srv.cpp | 491 | hle/service/filesystem/fsp_srv.cpp |
| 492 | hle/service/filesystem/fsp_srv.h | 492 | hle/service/filesystem/fsp_srv.h |
| 493 | hle/service/filesystem/romfs_controller.cpp | ||
| 494 | hle/service/filesystem/romfs_controller.h | ||
| 495 | hle/service/filesystem/save_data_controller.cpp | ||
| 496 | hle/service/filesystem/save_data_controller.h | ||
| 493 | hle/service/fgm/fgm.cpp | 497 | hle/service/fgm/fgm.cpp |
| 494 | hle/service/fgm/fgm.h | 498 | hle/service/fgm/fgm.h |
| 495 | hle/service/friend/friend.cpp | 499 | hle/service/friend/friend.cpp |
diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp index 47a7a8880..c7285e3a0 100644 --- a/src/core/arm/nce/patcher.cpp +++ b/src/core/arm/nce/patcher.cpp | |||
| @@ -22,14 +22,10 @@ using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters; | |||
| 22 | constexpr size_t MaxRelativeBranch = 128_MiB; | 22 | constexpr size_t MaxRelativeBranch = 128_MiB; |
| 23 | constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32); | 23 | constexpr u32 ModuleCodeIndex = 0x24 / sizeof(u32); |
| 24 | 24 | ||
| 25 | Patcher::Patcher() : c(m_patch_instructions) {} | 25 | Patcher::Patcher() : c(m_patch_instructions) { |
| 26 | 26 | // The first word of the patch section is always a branch to the first instruction of the | |
| 27 | Patcher::~Patcher() = default; | 27 | // module. |
| 28 | 28 | c.dw(0); | |
| 29 | void Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | ||
| 30 | const Kernel::CodeSet::Segment& code) { | ||
| 31 | // Branch to the first instruction of the module. | ||
| 32 | this->BranchToModule(0); | ||
| 33 | 29 | ||
| 34 | // Write save context helper function. | 30 | // Write save context helper function. |
| 35 | c.l(m_save_context); | 31 | c.l(m_save_context); |
| @@ -38,6 +34,25 @@ void Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | |||
| 38 | // Write load context helper function. | 34 | // Write load context helper function. |
| 39 | c.l(m_load_context); | 35 | c.l(m_load_context); |
| 40 | WriteLoadContext(); | 36 | WriteLoadContext(); |
| 37 | } | ||
| 38 | |||
| 39 | Patcher::~Patcher() = default; | ||
| 40 | |||
| 41 | bool Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | ||
| 42 | const Kernel::CodeSet::Segment& code) { | ||
| 43 | // If we have patched modules but cannot reach the new module, then it needs its own patcher. | ||
| 44 | const size_t image_size = program_image.size(); | ||
| 45 | if (total_program_size + image_size > MaxRelativeBranch && total_program_size > 0) { | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | // Add a new module patch to our list | ||
| 50 | modules.emplace_back(); | ||
| 51 | curr_patch = &modules.back(); | ||
| 52 | |||
| 53 | // The first word of the patch section is always a branch to the first instruction of the | ||
| 54 | // module. | ||
| 55 | curr_patch->m_branch_to_module_relocations.push_back({0, 0}); | ||
| 41 | 56 | ||
| 42 | // Retrieve text segment data. | 57 | // Retrieve text segment data. |
| 43 | const auto text = std::span{program_image}.subspan(code.offset, code.size); | 58 | const auto text = std::span{program_image}.subspan(code.offset, code.size); |
| @@ -94,16 +109,17 @@ void Patcher::PatchText(const Kernel::PhysicalMemory& program_image, | |||
| 94 | } | 109 | } |
| 95 | 110 | ||
| 96 | if (auto exclusive = Exclusive{inst}; exclusive.Verify()) { | 111 | if (auto exclusive = Exclusive{inst}; exclusive.Verify()) { |
| 97 | m_exclusives.push_back(i); | 112 | curr_patch->m_exclusives.push_back(i); |
| 98 | } | 113 | } |
| 99 | } | 114 | } |
| 100 | 115 | ||
| 101 | // Determine patching mode for the final relocation step | 116 | // Determine patching mode for the final relocation step |
| 102 | const size_t image_size = program_image.size(); | 117 | total_program_size += image_size; |
| 103 | this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData; | 118 | this->mode = image_size > MaxRelativeBranch ? PatchMode::PreText : PatchMode::PostData; |
| 119 | return true; | ||
| 104 | } | 120 | } |
| 105 | 121 | ||
| 106 | void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | 122 | bool Patcher::RelocateAndCopy(Common::ProcessAddress load_base, |
| 107 | const Kernel::CodeSet::Segment& code, | 123 | const Kernel::CodeSet::Segment& code, |
| 108 | Kernel::PhysicalMemory& program_image, | 124 | Kernel::PhysicalMemory& program_image, |
| 109 | EntryTrampolines* out_trampolines) { | 125 | EntryTrampolines* out_trampolines) { |
| @@ -120,7 +136,7 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 120 | if (mode == PatchMode::PreText) { | 136 | if (mode == PatchMode::PreText) { |
| 121 | rc.B(rel.patch_offset - patch_size - rel.module_offset); | 137 | rc.B(rel.patch_offset - patch_size - rel.module_offset); |
| 122 | } else { | 138 | } else { |
| 123 | rc.B(image_size - rel.module_offset + rel.patch_offset); | 139 | rc.B(total_program_size - rel.module_offset + rel.patch_offset); |
| 124 | } | 140 | } |
| 125 | }; | 141 | }; |
| 126 | 142 | ||
| @@ -129,7 +145,7 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 129 | if (mode == PatchMode::PreText) { | 145 | if (mode == PatchMode::PreText) { |
| 130 | rc.B(patch_size - rel.patch_offset + rel.module_offset); | 146 | rc.B(patch_size - rel.patch_offset + rel.module_offset); |
| 131 | } else { | 147 | } else { |
| 132 | rc.B(rel.module_offset - image_size - rel.patch_offset); | 148 | rc.B(rel.module_offset - total_program_size - rel.patch_offset); |
| 133 | } | 149 | } |
| 134 | }; | 150 | }; |
| 135 | 151 | ||
| @@ -137,7 +153,7 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 137 | if (mode == PatchMode::PreText) { | 153 | if (mode == PatchMode::PreText) { |
| 138 | return GetInteger(load_base) + patch_offset; | 154 | return GetInteger(load_base) + patch_offset; |
| 139 | } else { | 155 | } else { |
| 140 | return GetInteger(load_base) + image_size + patch_offset; | 156 | return GetInteger(load_base) + total_program_size + patch_offset; |
| 141 | } | 157 | } |
| 142 | }; | 158 | }; |
| 143 | 159 | ||
| @@ -150,39 +166,50 @@ void Patcher::RelocateAndCopy(Common::ProcessAddress load_base, | |||
| 150 | }; | 166 | }; |
| 151 | 167 | ||
| 152 | // We are now ready to relocate! | 168 | // We are now ready to relocate! |
| 153 | for (const Relocation& rel : m_branch_to_patch_relocations) { | 169 | auto& patch = modules[m_relocate_module_index++]; |
| 170 | for (const Relocation& rel : patch.m_branch_to_patch_relocations) { | ||
| 154 | ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel); | 171 | ApplyBranchToPatchRelocation(text_words.data() + rel.module_offset / sizeof(u32), rel); |
| 155 | } | 172 | } |
| 156 | for (const Relocation& rel : m_branch_to_module_relocations) { | 173 | for (const Relocation& rel : patch.m_branch_to_module_relocations) { |
| 157 | ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32), | 174 | ApplyBranchToModuleRelocation(m_patch_instructions.data() + rel.patch_offset / sizeof(u32), |
| 158 | rel); | 175 | rel); |
| 159 | } | 176 | } |
| 160 | 177 | ||
| 161 | // Rewrite PC constants and record post trampolines | 178 | // Rewrite PC constants and record post trampolines |
| 162 | for (const Relocation& rel : m_write_module_pc_relocations) { | 179 | for (const Relocation& rel : patch.m_write_module_pc_relocations) { |
| 163 | oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)}; | 180 | oaknut::CodeGenerator rc{m_patch_instructions.data() + rel.patch_offset / sizeof(u32)}; |
| 164 | rc.dx(RebasePc(rel.module_offset)); | 181 | rc.dx(RebasePc(rel.module_offset)); |
| 165 | } | 182 | } |
| 166 | for (const Trampoline& rel : m_trampolines) { | 183 | for (const Trampoline& rel : patch.m_trampolines) { |
| 167 | out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)}); | 184 | out_trampolines->insert({RebasePc(rel.module_offset), RebasePatch(rel.patch_offset)}); |
| 168 | } | 185 | } |
| 169 | 186 | ||
| 170 | // Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not. | 187 | // Cortex-A57 seems to treat all exclusives as ordered, but newer processors do not. |
| 171 | // Convert to ordered to preserve this assumption. | 188 | // Convert to ordered to preserve this assumption. |
| 172 | for (const ModuleTextAddress i : m_exclusives) { | 189 | for (const ModuleTextAddress i : patch.m_exclusives) { |
| 173 | auto exclusive = Exclusive{text_words[i]}; | 190 | auto exclusive = Exclusive{text_words[i]}; |
| 174 | text_words[i] = exclusive.AsOrdered(); | 191 | text_words[i] = exclusive.AsOrdered(); |
| 175 | } | 192 | } |
| 176 | 193 | ||
| 177 | // Copy to program image | 194 | // Remove the patched module size from the total. This is done so total_program_size |
| 178 | if (this->mode == PatchMode::PreText) { | 195 | // always represents the distance from the currently patched module to the patch section. |
| 179 | std::memcpy(program_image.data(), m_patch_instructions.data(), | 196 | total_program_size -= image_size; |
| 180 | m_patch_instructions.size() * sizeof(u32)); | 197 | |
| 181 | } else { | 198 | // Only copy to the program image of the last module |
| 182 | program_image.resize(image_size + patch_size); | 199 | if (m_relocate_module_index == modules.size()) { |
| 183 | std::memcpy(program_image.data() + image_size, m_patch_instructions.data(), | 200 | if (this->mode == PatchMode::PreText) { |
| 184 | m_patch_instructions.size() * sizeof(u32)); | 201 | ASSERT(image_size == total_program_size); |
| 202 | std::memcpy(program_image.data(), m_patch_instructions.data(), | ||
| 203 | m_patch_instructions.size() * sizeof(u32)); | ||
| 204 | } else { | ||
| 205 | program_image.resize(image_size + patch_size); | ||
| 206 | std::memcpy(program_image.data() + image_size, m_patch_instructions.data(), | ||
| 207 | m_patch_instructions.size() * sizeof(u32)); | ||
| 208 | } | ||
| 209 | return true; | ||
| 185 | } | 210 | } |
| 211 | |||
| 212 | return false; | ||
| 186 | } | 213 | } |
| 187 | 214 | ||
| 188 | size_t Patcher::GetSectionSize() const noexcept { | 215 | size_t Patcher::GetSectionSize() const noexcept { |
| @@ -322,7 +349,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id) { | |||
| 322 | 349 | ||
| 323 | // Write the post-SVC trampoline address, which will jump back to the guest after restoring its | 350 | // Write the post-SVC trampoline address, which will jump back to the guest after restoring its |
| 324 | // state. | 351 | // state. |
| 325 | m_trampolines.push_back({c.offset(), module_dest}); | 352 | curr_patch->m_trampolines.push_back({c.offset(), module_dest}); |
| 326 | 353 | ||
| 327 | // Host called this location. Save the return address so we can | 354 | // Host called this location. Save the return address so we can |
| 328 | // unwind the stack properly when jumping back. | 355 | // unwind the stack properly when jumping back. |
diff --git a/src/core/arm/nce/patcher.h b/src/core/arm/nce/patcher.h index c6d1608c1..a44f385e2 100644 --- a/src/core/arm/nce/patcher.h +++ b/src/core/arm/nce/patcher.h | |||
| @@ -31,9 +31,9 @@ public: | |||
| 31 | explicit Patcher(); | 31 | explicit Patcher(); |
| 32 | ~Patcher(); | 32 | ~Patcher(); |
| 33 | 33 | ||
| 34 | void PatchText(const Kernel::PhysicalMemory& program_image, | 34 | bool PatchText(const Kernel::PhysicalMemory& program_image, |
| 35 | const Kernel::CodeSet::Segment& code); | 35 | const Kernel::CodeSet::Segment& code); |
| 36 | void RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, | 36 | bool RelocateAndCopy(Common::ProcessAddress load_base, const Kernel::CodeSet::Segment& code, |
| 37 | Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); | 37 | Kernel::PhysicalMemory& program_image, EntryTrampolines* out_trampolines); |
| 38 | size_t GetSectionSize() const noexcept; | 38 | size_t GetSectionSize() const noexcept; |
| 39 | 39 | ||
| @@ -61,16 +61,16 @@ private: | |||
| 61 | 61 | ||
| 62 | private: | 62 | private: |
| 63 | void BranchToPatch(uintptr_t module_dest) { | 63 | void BranchToPatch(uintptr_t module_dest) { |
| 64 | m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); | 64 | curr_patch->m_branch_to_patch_relocations.push_back({c.offset(), module_dest}); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void BranchToModule(uintptr_t module_dest) { | 67 | void BranchToModule(uintptr_t module_dest) { |
| 68 | m_branch_to_module_relocations.push_back({c.offset(), module_dest}); | 68 | curr_patch->m_branch_to_module_relocations.push_back({c.offset(), module_dest}); |
| 69 | c.dw(0); | 69 | c.dw(0); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | void WriteModulePc(uintptr_t module_dest) { | 72 | void WriteModulePc(uintptr_t module_dest) { |
| 73 | m_write_module_pc_relocations.push_back({c.offset(), module_dest}); | 73 | curr_patch->m_write_module_pc_relocations.push_back({c.offset(), module_dest}); |
| 74 | c.dx(0); | 74 | c.dx(0); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| @@ -84,15 +84,22 @@ private: | |||
| 84 | uintptr_t module_offset; ///< Offset in bytes from the start of the text section. | 84 | uintptr_t module_offset; ///< Offset in bytes from the start of the text section. |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | struct ModulePatch { | ||
| 88 | std::vector<Trampoline> m_trampolines; | ||
| 89 | std::vector<Relocation> m_branch_to_patch_relocations{}; | ||
| 90 | std::vector<Relocation> m_branch_to_module_relocations{}; | ||
| 91 | std::vector<Relocation> m_write_module_pc_relocations{}; | ||
| 92 | std::vector<ModuleTextAddress> m_exclusives{}; | ||
| 93 | }; | ||
| 94 | |||
| 87 | oaknut::VectorCodeGenerator c; | 95 | oaknut::VectorCodeGenerator c; |
| 88 | std::vector<Trampoline> m_trampolines; | ||
| 89 | std::vector<Relocation> m_branch_to_patch_relocations{}; | ||
| 90 | std::vector<Relocation> m_branch_to_module_relocations{}; | ||
| 91 | std::vector<Relocation> m_write_module_pc_relocations{}; | ||
| 92 | std::vector<ModuleTextAddress> m_exclusives{}; | ||
| 93 | oaknut::Label m_save_context{}; | 96 | oaknut::Label m_save_context{}; |
| 94 | oaknut::Label m_load_context{}; | 97 | oaknut::Label m_load_context{}; |
| 95 | PatchMode mode{PatchMode::None}; | 98 | PatchMode mode{PatchMode::None}; |
| 99 | size_t total_program_size{}; | ||
| 100 | size_t m_relocate_module_index{}; | ||
| 101 | std::vector<ModulePatch> modules; | ||
| 102 | ModulePatch* curr_patch; | ||
| 96 | }; | 103 | }; |
| 97 | 104 | ||
| 98 | } // namespace Core::NCE | 105 | } // namespace Core::NCE |
diff --git a/src/core/core.cpp b/src/core/core.cpp index c063f7719..461eea9c8 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -413,6 +413,7 @@ struct System::Impl { | |||
| 413 | kernel.ShutdownCores(); | 413 | kernel.ShutdownCores(); |
| 414 | services.reset(); | 414 | services.reset(); |
| 415 | service_manager.reset(); | 415 | service_manager.reset(); |
| 416 | fs_controller.Reset(); | ||
| 416 | cheat_engine.reset(); | 417 | cheat_engine.reset(); |
| 417 | telemetry_session.reset(); | 418 | telemetry_session.reset(); |
| 418 | time_manager.Shutdown(); | 419 | time_manager.Shutdown(); |
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 0e270eb50..e86aae846 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -114,7 +114,7 @@ public: | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | Kernel::KThread* GetActiveThread() override { | 116 | Kernel::KThread* GetActiveThread() override { |
| 117 | return state->active_thread; | 117 | return state->active_thread.GetPointerUnsafe(); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | private: | 120 | private: |
| @@ -147,11 +147,14 @@ private: | |||
| 147 | 147 | ||
| 148 | std::scoped_lock lk{connection_lock}; | 148 | std::scoped_lock lk{connection_lock}; |
| 149 | 149 | ||
| 150 | // Find the process we are going to debug. | ||
| 151 | SetDebugProcess(); | ||
| 152 | |||
| 150 | // Ensure everything is stopped. | 153 | // Ensure everything is stopped. |
| 151 | PauseEmulation(); | 154 | PauseEmulation(); |
| 152 | 155 | ||
| 153 | // Set up the new frontend. | 156 | // Set up the new frontend. |
| 154 | frontend = std::make_unique<GDBStub>(*this, system); | 157 | frontend = std::make_unique<GDBStub>(*this, system, debug_process.GetPointerUnsafe()); |
| 155 | 158 | ||
| 156 | // Set the new state. This will tear down any existing state. | 159 | // Set the new state. This will tear down any existing state. |
| 157 | state = ConnectionState{ | 160 | state = ConnectionState{ |
| @@ -194,15 +197,20 @@ private: | |||
| 194 | UpdateActiveThread(); | 197 | UpdateActiveThread(); |
| 195 | 198 | ||
| 196 | if (state->info.type == SignalType::Watchpoint) { | 199 | if (state->info.type == SignalType::Watchpoint) { |
| 197 | frontend->Watchpoint(state->active_thread, *state->info.watchpoint); | 200 | frontend->Watchpoint(std::addressof(*state->active_thread), |
| 201 | *state->info.watchpoint); | ||
| 198 | } else { | 202 | } else { |
| 199 | frontend->Stopped(state->active_thread); | 203 | frontend->Stopped(std::addressof(*state->active_thread)); |
| 200 | } | 204 | } |
| 201 | 205 | ||
| 202 | break; | 206 | break; |
| 203 | case SignalType::ShuttingDown: | 207 | case SignalType::ShuttingDown: |
| 204 | frontend->ShuttingDown(); | 208 | frontend->ShuttingDown(); |
| 205 | 209 | ||
| 210 | // Release members. | ||
| 211 | state->active_thread.Reset(nullptr); | ||
| 212 | debug_process.Reset(nullptr); | ||
| 213 | |||
| 206 | // Wait for emulation to shut down gracefully now. | 214 | // Wait for emulation to shut down gracefully now. |
| 207 | state->signal_pipe.close(); | 215 | state->signal_pipe.close(); |
| 208 | state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); | 216 | state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); |
| @@ -222,7 +230,7 @@ private: | |||
| 222 | stopped = true; | 230 | stopped = true; |
| 223 | PauseEmulation(); | 231 | PauseEmulation(); |
| 224 | UpdateActiveThread(); | 232 | UpdateActiveThread(); |
| 225 | frontend->Stopped(state->active_thread); | 233 | frontend->Stopped(state->active_thread.GetPointerUnsafe()); |
| 226 | break; | 234 | break; |
| 227 | } | 235 | } |
| 228 | case DebuggerAction::Continue: | 236 | case DebuggerAction::Continue: |
| @@ -232,7 +240,7 @@ private: | |||
| 232 | MarkResumed([&] { | 240 | MarkResumed([&] { |
| 233 | state->active_thread->SetStepState(Kernel::StepState::StepPending); | 241 | state->active_thread->SetStepState(Kernel::StepState::StepPending); |
| 234 | state->active_thread->Resume(Kernel::SuspendType::Debug); | 242 | state->active_thread->Resume(Kernel::SuspendType::Debug); |
| 235 | ResumeEmulation(state->active_thread); | 243 | ResumeEmulation(state->active_thread.GetPointerUnsafe()); |
| 236 | }); | 244 | }); |
| 237 | break; | 245 | break; |
| 238 | case DebuggerAction::StepThreadLocked: { | 246 | case DebuggerAction::StepThreadLocked: { |
| @@ -255,6 +263,7 @@ private: | |||
| 255 | } | 263 | } |
| 256 | 264 | ||
| 257 | void PauseEmulation() { | 265 | void PauseEmulation() { |
| 266 | Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||
| 258 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | 267 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; |
| 259 | 268 | ||
| 260 | // Put all threads to sleep on next scheduler round. | 269 | // Put all threads to sleep on next scheduler round. |
| @@ -264,6 +273,9 @@ private: | |||
| 264 | } | 273 | } |
| 265 | 274 | ||
| 266 | void ResumeEmulation(Kernel::KThread* except = nullptr) { | 275 | void ResumeEmulation(Kernel::KThread* except = nullptr) { |
| 276 | Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||
| 277 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||
| 278 | |||
| 267 | // Wake up all threads. | 279 | // Wake up all threads. |
| 268 | for (auto& thread : ThreadList()) { | 280 | for (auto& thread : ThreadList()) { |
| 269 | if (std::addressof(thread) == except) { | 281 | if (std::addressof(thread) == except) { |
| @@ -277,15 +289,16 @@ private: | |||
| 277 | 289 | ||
| 278 | template <typename Callback> | 290 | template <typename Callback> |
| 279 | void MarkResumed(Callback&& cb) { | 291 | void MarkResumed(Callback&& cb) { |
| 280 | Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||
| 281 | stopped = false; | 292 | stopped = false; |
| 282 | cb(); | 293 | cb(); |
| 283 | } | 294 | } |
| 284 | 295 | ||
| 285 | void UpdateActiveThread() { | 296 | void UpdateActiveThread() { |
| 297 | Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||
| 298 | |||
| 286 | auto& threads{ThreadList()}; | 299 | auto& threads{ThreadList()}; |
| 287 | for (auto& thread : threads) { | 300 | for (auto& thread : threads) { |
| 288 | if (std::addressof(thread) == state->active_thread) { | 301 | if (std::addressof(thread) == state->active_thread.GetPointerUnsafe()) { |
| 289 | // Thread is still alive, no need to update. | 302 | // Thread is still alive, no need to update. |
| 290 | return; | 303 | return; |
| 291 | } | 304 | } |
| @@ -293,12 +306,18 @@ private: | |||
| 293 | state->active_thread = std::addressof(threads.front()); | 306 | state->active_thread = std::addressof(threads.front()); |
| 294 | } | 307 | } |
| 295 | 308 | ||
| 309 | private: | ||
| 310 | void SetDebugProcess() { | ||
| 311 | debug_process = std::move(system.Kernel().GetProcessList().back()); | ||
| 312 | } | ||
| 313 | |||
| 296 | Kernel::KProcess::ThreadList& ThreadList() { | 314 | Kernel::KProcess::ThreadList& ThreadList() { |
| 297 | return system.ApplicationProcess()->GetThreadList(); | 315 | return debug_process->GetThreadList(); |
| 298 | } | 316 | } |
| 299 | 317 | ||
| 300 | private: | 318 | private: |
| 301 | System& system; | 319 | System& system; |
| 320 | Kernel::KScopedAutoObject<Kernel::KProcess> debug_process; | ||
| 302 | std::unique_ptr<DebuggerFrontend> frontend; | 321 | std::unique_ptr<DebuggerFrontend> frontend; |
| 303 | 322 | ||
| 304 | boost::asio::io_context io_context; | 323 | boost::asio::io_context io_context; |
| @@ -310,7 +329,7 @@ private: | |||
| 310 | boost::process::async_pipe signal_pipe; | 329 | boost::process::async_pipe signal_pipe; |
| 311 | 330 | ||
| 312 | SignalInfo info; | 331 | SignalInfo info; |
| 313 | Kernel::KThread* active_thread; | 332 | Kernel::KScopedAutoObject<Kernel::KThread> active_thread; |
| 314 | std::array<u8, 4096> client_data; | 333 | std::array<u8, 4096> client_data; |
| 315 | bool pipe_data; | 334 | bool pipe_data; |
| 316 | }; | 335 | }; |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 4051ed4af..80091cc7e 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -108,9 +108,9 @@ static std::string EscapeXML(std::string_view data) { | |||
| 108 | return escaped; | 108 | return escaped; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | 111 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_, Kernel::KProcess* debug_process_) |
| 112 | : DebuggerFrontend(backend_), system{system_} { | 112 | : DebuggerFrontend(backend_), system{system_}, debug_process{debug_process_} { |
| 113 | if (system.ApplicationProcess()->Is64Bit()) { | 113 | if (GetProcess()->Is64Bit()) { |
| 114 | arch = std::make_unique<GDBStubA64>(); | 114 | arch = std::make_unique<GDBStubA64>(); |
| 115 | } else { | 115 | } else { |
| 116 | arch = std::make_unique<GDBStubA32>(); | 116 | arch = std::make_unique<GDBStubA32>(); |
| @@ -276,7 +276,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 276 | const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; | 276 | const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; |
| 277 | 277 | ||
| 278 | std::vector<u8> mem(size); | 278 | std::vector<u8> mem(size); |
| 279 | if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) { | 279 | if (GetMemory().ReadBlock(addr, mem.data(), size)) { |
| 280 | // Restore any bytes belonging to replaced instructions. | 280 | // Restore any bytes belonging to replaced instructions. |
| 281 | auto it = replaced_instructions.lower_bound(addr); | 281 | auto it = replaced_instructions.lower_bound(addr); |
| 282 | for (; it != replaced_instructions.end() && it->first < addr + size; it++) { | 282 | for (; it != replaced_instructions.end() && it->first < addr + size; it++) { |
| @@ -310,8 +310,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 310 | const auto mem_substr{std::string_view(command).substr(mem_sep)}; | 310 | const auto mem_substr{std::string_view(command).substr(mem_sep)}; |
| 311 | const auto mem{Common::HexStringToVector(mem_substr, false)}; | 311 | const auto mem{Common::HexStringToVector(mem_substr, false)}; |
| 312 | 312 | ||
| 313 | if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { | 313 | if (GetMemory().WriteBlock(addr, mem.data(), size)) { |
| 314 | Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size); | 314 | Core::InvalidateInstructionCacheRange(GetProcess(), addr, size); |
| 315 | SendReply(GDB_STUB_REPLY_OK); | 315 | SendReply(GDB_STUB_REPLY_OK); |
| 316 | } else { | 316 | } else { |
| 317 | SendReply(GDB_STUB_REPLY_ERR); | 317 | SendReply(GDB_STUB_REPLY_ERR); |
| @@ -353,7 +353,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | |||
| 353 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | 353 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; |
| 354 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | 354 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; |
| 355 | 355 | ||
| 356 | if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { | 356 | if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { |
| 357 | SendReply(GDB_STUB_REPLY_ERR); | 357 | SendReply(GDB_STUB_REPLY_ERR); |
| 358 | return; | 358 | return; |
| 359 | } | 359 | } |
| @@ -362,22 +362,20 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | |||
| 362 | 362 | ||
| 363 | switch (type) { | 363 | switch (type) { |
| 364 | case BreakpointType::Software: | 364 | case BreakpointType::Software: |
| 365 | replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); | 365 | replaced_instructions[addr] = GetMemory().Read32(addr); |
| 366 | system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); | 366 | GetMemory().Write32(addr, arch->BreakpointInstruction()); |
| 367 | Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); | 367 | Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); |
| 368 | success = true; | 368 | success = true; |
| 369 | break; | 369 | break; |
| 370 | case BreakpointType::WriteWatch: | 370 | case BreakpointType::WriteWatch: |
| 371 | success = system.ApplicationProcess()->InsertWatchpoint(addr, size, | 371 | success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); |
| 372 | Kernel::DebugWatchpointType::Write); | ||
| 373 | break; | 372 | break; |
| 374 | case BreakpointType::ReadWatch: | 373 | case BreakpointType::ReadWatch: |
| 375 | success = system.ApplicationProcess()->InsertWatchpoint(addr, size, | 374 | success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); |
| 376 | Kernel::DebugWatchpointType::Read); | ||
| 377 | break; | 375 | break; |
| 378 | case BreakpointType::AccessWatch: | 376 | case BreakpointType::AccessWatch: |
| 379 | success = system.ApplicationProcess()->InsertWatchpoint( | 377 | success = |
| 380 | addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | 378 | GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); |
| 381 | break; | 379 | break; |
| 382 | case BreakpointType::Hardware: | 380 | case BreakpointType::Hardware: |
| 383 | default: | 381 | default: |
| @@ -400,7 +398,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||
| 400 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | 398 | const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; |
| 401 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | 399 | const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; |
| 402 | 400 | ||
| 403 | if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { | 401 | if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { |
| 404 | SendReply(GDB_STUB_REPLY_ERR); | 402 | SendReply(GDB_STUB_REPLY_ERR); |
| 405 | return; | 403 | return; |
| 406 | } | 404 | } |
| @@ -411,24 +409,22 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | |||
| 411 | case BreakpointType::Software: { | 409 | case BreakpointType::Software: { |
| 412 | const auto orig_insn{replaced_instructions.find(addr)}; | 410 | const auto orig_insn{replaced_instructions.find(addr)}; |
| 413 | if (orig_insn != replaced_instructions.end()) { | 411 | if (orig_insn != replaced_instructions.end()) { |
| 414 | system.ApplicationMemory().Write32(addr, orig_insn->second); | 412 | GetMemory().Write32(addr, orig_insn->second); |
| 415 | Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); | 413 | Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); |
| 416 | replaced_instructions.erase(addr); | 414 | replaced_instructions.erase(addr); |
| 417 | success = true; | 415 | success = true; |
| 418 | } | 416 | } |
| 419 | break; | 417 | break; |
| 420 | } | 418 | } |
| 421 | case BreakpointType::WriteWatch: | 419 | case BreakpointType::WriteWatch: |
| 422 | success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, | 420 | success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); |
| 423 | Kernel::DebugWatchpointType::Write); | ||
| 424 | break; | 421 | break; |
| 425 | case BreakpointType::ReadWatch: | 422 | case BreakpointType::ReadWatch: |
| 426 | success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, | 423 | success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); |
| 427 | Kernel::DebugWatchpointType::Read); | ||
| 428 | break; | 424 | break; |
| 429 | case BreakpointType::AccessWatch: | 425 | case BreakpointType::AccessWatch: |
| 430 | success = system.ApplicationProcess()->RemoveWatchpoint( | 426 | success = |
| 431 | addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | 427 | GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); |
| 432 | break; | 428 | break; |
| 433 | case BreakpointType::Hardware: | 429 | case BreakpointType::Hardware: |
| 434 | default: | 430 | default: |
| @@ -466,10 +462,10 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 466 | const auto target_xml{arch->GetTargetXML()}; | 462 | const auto target_xml{arch->GetTargetXML()}; |
| 467 | SendReply(PaginateBuffer(target_xml, command.substr(30))); | 463 | SendReply(PaginateBuffer(target_xml, command.substr(30))); |
| 468 | } else if (command.starts_with("Offsets")) { | 464 | } else if (command.starts_with("Offsets")) { |
| 469 | const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess()); | 465 | const auto main_offset = Core::FindMainModuleEntrypoint(GetProcess()); |
| 470 | SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); | 466 | SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); |
| 471 | } else if (command.starts_with("Xfer:libraries:read::")) { | 467 | } else if (command.starts_with("Xfer:libraries:read::")) { |
| 472 | auto modules = Core::FindModules(system.ApplicationProcess()); | 468 | auto modules = Core::FindModules(GetProcess()); |
| 473 | 469 | ||
| 474 | std::string buffer; | 470 | std::string buffer; |
| 475 | buffer += R"(<?xml version="1.0"?>)"; | 471 | buffer += R"(<?xml version="1.0"?>)"; |
| @@ -483,7 +479,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 483 | SendReply(PaginateBuffer(buffer, command.substr(21))); | 479 | SendReply(PaginateBuffer(buffer, command.substr(21))); |
| 484 | } else if (command.starts_with("fThreadInfo")) { | 480 | } else if (command.starts_with("fThreadInfo")) { |
| 485 | // beginning of list | 481 | // beginning of list |
| 486 | const auto& threads = system.ApplicationProcess()->GetThreadList(); | 482 | const auto& threads = GetProcess()->GetThreadList(); |
| 487 | std::vector<std::string> thread_ids; | 483 | std::vector<std::string> thread_ids; |
| 488 | for (const auto& thread : threads) { | 484 | for (const auto& thread : threads) { |
| 489 | thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); | 485 | thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); |
| @@ -497,7 +493,7 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 497 | buffer += R"(<?xml version="1.0"?>)"; | 493 | buffer += R"(<?xml version="1.0"?>)"; |
| 498 | buffer += "<threads>"; | 494 | buffer += "<threads>"; |
| 499 | 495 | ||
| 500 | const auto& threads = system.ApplicationProcess()->GetThreadList(); | 496 | const auto& threads = GetProcess()->GetThreadList(); |
| 501 | for (const auto& thread : threads) { | 497 | for (const auto& thread : threads) { |
| 502 | auto thread_name{Core::GetThreadName(&thread)}; | 498 | auto thread_name{Core::GetThreadName(&thread)}; |
| 503 | if (!thread_name) { | 499 | if (!thread_name) { |
| @@ -613,7 +609,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||
| 613 | std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; | 609 | std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; |
| 614 | std::string reply; | 610 | std::string reply; |
| 615 | 611 | ||
| 616 | auto* process = system.ApplicationProcess(); | 612 | auto* process = GetProcess(); |
| 617 | auto& page_table = process->GetPageTable(); | 613 | auto& page_table = process->GetPageTable(); |
| 618 | 614 | ||
| 619 | const char* commands = "Commands:\n" | 615 | const char* commands = "Commands:\n" |
| @@ -714,7 +710,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||
| 714 | } | 710 | } |
| 715 | 711 | ||
| 716 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | 712 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { |
| 717 | auto& threads{system.ApplicationProcess()->GetThreadList()}; | 713 | auto& threads{GetProcess()->GetThreadList()}; |
| 718 | for (auto& thread : threads) { | 714 | for (auto& thread : threads) { |
| 719 | if (thread.GetThreadId() == thread_id) { | 715 | if (thread.GetThreadId() == thread_id) { |
| 720 | return std::addressof(thread); | 716 | return std::addressof(thread); |
| @@ -783,4 +779,12 @@ void GDBStub::SendStatus(char status) { | |||
| 783 | backend.WriteToClient(buf); | 779 | backend.WriteToClient(buf); |
| 784 | } | 780 | } |
| 785 | 781 | ||
| 782 | Kernel::KProcess* GDBStub::GetProcess() { | ||
| 783 | return debug_process; | ||
| 784 | } | ||
| 785 | |||
| 786 | Core::Memory::Memory& GDBStub::GetMemory() { | ||
| 787 | return GetProcess()->GetMemory(); | ||
| 788 | } | ||
| 789 | |||
| 786 | } // namespace Core | 790 | } // namespace Core |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 368197920..232dcf49f 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -12,13 +12,22 @@ | |||
| 12 | #include "core/debugger/debugger_interface.h" | 12 | #include "core/debugger/debugger_interface.h" |
| 13 | #include "core/debugger/gdbstub_arch.h" | 13 | #include "core/debugger/gdbstub_arch.h" |
| 14 | 14 | ||
| 15 | namespace Kernel { | ||
| 16 | class KProcess; | ||
| 17 | } | ||
| 18 | |||
| 19 | namespace Core::Memory { | ||
| 20 | class Memory; | ||
| 21 | } | ||
| 22 | |||
| 15 | namespace Core { | 23 | namespace Core { |
| 16 | 24 | ||
| 17 | class System; | 25 | class System; |
| 18 | 26 | ||
| 19 | class GDBStub : public DebuggerFrontend { | 27 | class GDBStub : public DebuggerFrontend { |
| 20 | public: | 28 | public: |
| 21 | explicit GDBStub(DebuggerBackend& backend, Core::System& system); | 29 | explicit GDBStub(DebuggerBackend& backend, Core::System& system, |
| 30 | Kernel::KProcess* debug_process); | ||
| 22 | ~GDBStub() override; | 31 | ~GDBStub() override; |
| 23 | 32 | ||
| 24 | void Connected() override; | 33 | void Connected() override; |
| @@ -42,8 +51,12 @@ private: | |||
| 42 | void SendReply(std::string_view data); | 51 | void SendReply(std::string_view data); |
| 43 | void SendStatus(char status); | 52 | void SendStatus(char status); |
| 44 | 53 | ||
| 54 | Kernel::KProcess* GetProcess(); | ||
| 55 | Core::Memory::Memory& GetMemory(); | ||
| 56 | |||
| 45 | private: | 57 | private: |
| 46 | Core::System& system; | 58 | Core::System& system; |
| 59 | Kernel::KProcess* debug_process; | ||
| 47 | std::unique_ptr<GDBStubArch> arch; | 60 | std::unique_ptr<GDBStubArch> arch; |
| 48 | std::vector<char> current_command; | 61 | std::vector<char> current_command; |
| 49 | std::map<VAddr, u32> replaced_instructions; | 62 | std::map<VAddr, u32> replaced_instructions; |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 12b3bd797..23196cd5f 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -97,8 +97,9 @@ std::string SaveDataAttribute::DebugInfo() const { | |||
| 97 | static_cast<u8>(rank), index); | 97 | static_cast<u8>(rank), index); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_directory_) | 100 | SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, |
| 101 | : dir{std::move(save_directory_)}, system{system_} { | 101 | VirtualDir save_directory_) |
| 102 | : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} { | ||
| 102 | // Delete all temporary storages | 103 | // Delete all temporary storages |
| 103 | // On hardware, it is expected that temporary storage be empty at first use. | 104 | // On hardware, it is expected that temporary storage be empty at first use. |
| 104 | dir->DeleteSubdirectoryRecursive("temp"); | 105 | dir->DeleteSubdirectoryRecursive("temp"); |
| @@ -110,7 +111,7 @@ VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribut | |||
| 110 | PrintSaveDataAttributeWarnings(meta); | 111 | PrintSaveDataAttributeWarnings(meta); |
| 111 | 112 | ||
| 112 | const auto save_directory = | 113 | const auto save_directory = |
| 113 | GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | 114 | GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); |
| 114 | 115 | ||
| 115 | return dir->CreateDirectoryRelative(save_directory); | 116 | return dir->CreateDirectoryRelative(save_directory); |
| 116 | } | 117 | } |
| @@ -118,7 +119,7 @@ VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribut | |||
| 118 | VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { | 119 | VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { |
| 119 | 120 | ||
| 120 | const auto save_directory = | 121 | const auto save_directory = |
| 121 | GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); | 122 | GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); |
| 122 | 123 | ||
| 123 | auto out = dir->GetDirectoryRelative(save_directory); | 124 | auto out = dir->GetDirectoryRelative(save_directory); |
| 124 | 125 | ||
| @@ -147,14 +148,14 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { | |||
| 147 | } | 148 | } |
| 148 | } | 149 | } |
| 149 | 150 | ||
| 150 | std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir, | 151 | std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, |
| 151 | SaveDataSpaceId space, SaveDataType type, u64 title_id, | 152 | SaveDataSpaceId space, SaveDataType type, u64 title_id, |
| 152 | u128 user_id, u64 save_id) { | 153 | u128 user_id, u64 save_id) { |
| 153 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 154 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 154 | // be interpreted as the title id of the current process. | 155 | // be interpreted as the title id of the current process. |
| 155 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { | 156 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { |
| 156 | if (title_id == 0) { | 157 | if (title_id == 0) { |
| 157 | title_id = system.GetApplicationProcessProgramID(); | 158 | title_id = program_id; |
| 158 | } | 159 | } |
| 159 | } | 160 | } |
| 160 | 161 | ||
| @@ -201,7 +202,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future) | |||
| 201 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | 202 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, |
| 202 | u128 user_id) const { | 203 | u128 user_id) const { |
| 203 | const auto path = | 204 | const auto path = |
| 204 | GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | 205 | GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); |
| 205 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); | 206 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); |
| 206 | 207 | ||
| 207 | const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); | 208 | const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); |
| @@ -220,7 +221,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | |||
| 220 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | 221 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, |
| 221 | SaveDataSize new_value) const { | 222 | SaveDataSize new_value) const { |
| 222 | const auto path = | 223 | const auto path = |
| 223 | GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); | 224 | GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); |
| 224 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); | 225 | const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); |
| 225 | 226 | ||
| 226 | const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); | 227 | const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index fd4887e99..30d96928e 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -87,10 +87,13 @@ constexpr const char* GetSaveDataSizeFileName() { | |||
| 87 | return ".yuzu_save_size"; | 87 | return ".yuzu_save_size"; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | using ProgramId = u64; | ||
| 91 | |||
| 90 | /// File system interface to the SaveData archive | 92 | /// File system interface to the SaveData archive |
| 91 | class SaveDataFactory { | 93 | class SaveDataFactory { |
| 92 | public: | 94 | public: |
| 93 | explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_); | 95 | explicit SaveDataFactory(Core::System& system_, ProgramId program_id_, |
| 96 | VirtualDir save_directory_); | ||
| 94 | ~SaveDataFactory(); | 97 | ~SaveDataFactory(); |
| 95 | 98 | ||
| 96 | VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; | 99 | VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; |
| @@ -99,7 +102,7 @@ public: | |||
| 99 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; | 102 | VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; |
| 100 | 103 | ||
| 101 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); | 104 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); |
| 102 | static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, | 105 | static std::string GetFullPath(ProgramId program_id, VirtualDir dir, SaveDataSpaceId space, |
| 103 | SaveDataType type, u64 title_id, u128 user_id, u64 save_id); | 106 | SaveDataType type, u64 title_id, u128 user_id, u64 save_id); |
| 104 | static std::string GetUserGameSaveDataRoot(u128 user_id, bool future); | 107 | static std::string GetUserGameSaveDataRoot(u128 user_id, bool future); |
| 105 | 108 | ||
| @@ -110,8 +113,9 @@ public: | |||
| 110 | void SetAutoCreate(bool state); | 113 | void SetAutoCreate(bool state); |
| 111 | 114 | ||
| 112 | private: | 115 | private: |
| 113 | VirtualDir dir; | ||
| 114 | Core::System& system; | 116 | Core::System& system; |
| 117 | ProgramId program_id; | ||
| 118 | VirtualDir dir; | ||
| 115 | bool auto_create{true}; | 119 | bool auto_create{true}; |
| 116 | }; | 120 | }; |
| 117 | 121 | ||
diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp index 58a1e7216..f08a6e448 100644 --- a/src/core/hle/kernel/k_memory_block_manager.cpp +++ b/src/core/hle/kernel/k_memory_block_manager.cpp | |||
| @@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd, | |||
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, | 30 | void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, |
| 31 | HostUnmapCallback&& host_unmap_callback) { | 31 | BlockCallback&& block_callback) { |
| 32 | // Erase every block until we have none left. | 32 | // Erase every block until we have none left. |
| 33 | auto it = m_memory_block_tree.begin(); | 33 | auto it = m_memory_block_tree.begin(); |
| 34 | while (it != m_memory_block_tree.end()) { | 34 | while (it != m_memory_block_tree.end()) { |
| 35 | KMemoryBlock* block = std::addressof(*it); | 35 | KMemoryBlock* block = std::addressof(*it); |
| 36 | it = m_memory_block_tree.erase(it); | 36 | it = m_memory_block_tree.erase(it); |
| 37 | block_callback(block->GetAddress(), block->GetSize()); | ||
| 37 | slab_manager->Free(block); | 38 | slab_manager->Free(block); |
| 38 | host_unmap_callback(block->GetAddress(), block->GetSize()); | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | ASSERT(m_memory_block_tree.empty()); | 41 | ASSERT(m_memory_block_tree.empty()); |
diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index cb7b6f430..377628504 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h | |||
| @@ -85,11 +85,11 @@ public: | |||
| 85 | public: | 85 | public: |
| 86 | KMemoryBlockManager(); | 86 | KMemoryBlockManager(); |
| 87 | 87 | ||
| 88 | using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>; | 88 | using BlockCallback = std::function<void(Common::ProcessAddress, u64)>; |
| 89 | 89 | ||
| 90 | Result Initialize(KProcessAddress st, KProcessAddress nd, | 90 | Result Initialize(KProcessAddress st, KProcessAddress nd, |
| 91 | KMemoryBlockSlabManager* slab_manager); | 91 | KMemoryBlockSlabManager* slab_manager); |
| 92 | void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback); | 92 | void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback); |
| 93 | 93 | ||
| 94 | iterator end() { | 94 | iterator end() { |
| 95 | return m_memory_block_tree.end(); | 95 | return m_memory_block_tree.end(); |
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 73fbda331..3f0a39d33 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -431,15 +431,43 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool | |||
| 431 | m_memory_block_slab_manager)); | 431 | m_memory_block_slab_manager)); |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | Result KPageTableBase::FinalizeProcess() { | ||
| 435 | // Only process tables should be finalized. | ||
| 436 | ASSERT(!this->IsKernel()); | ||
| 437 | |||
| 438 | // NOTE: Here Nintendo calls an unknown OnFinalize function. | ||
| 439 | // this->OnFinalize(); | ||
| 440 | |||
| 441 | // NOTE: Here Nintendo calls a second unknown OnFinalize function. | ||
| 442 | // this->OnFinalize2(); | ||
| 443 | |||
| 444 | // NOTE: Here Nintendo does a page table walk to discover heap pages to free. | ||
| 445 | // We will use the block manager finalization below to free them. | ||
| 446 | |||
| 447 | R_SUCCEED(); | ||
| 448 | } | ||
| 449 | |||
| 434 | void KPageTableBase::Finalize() { | 450 | void KPageTableBase::Finalize() { |
| 435 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { | 451 | this->FinalizeProcess(); |
| 436 | if (Settings::IsFastmemEnabled()) { | 452 | |
| 453 | auto BlockCallback = [&](KProcessAddress addr, u64 size) { | ||
| 454 | if (m_impl->fastmem_arena) { | ||
| 437 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); | 455 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); |
| 438 | } | 456 | } |
| 457 | |||
| 458 | // Get physical pages. | ||
| 459 | KPageGroup pg(m_kernel, m_block_info_manager); | ||
| 460 | this->MakePageGroup(pg, addr, size / PageSize); | ||
| 461 | |||
| 462 | // Free the pages. | ||
| 463 | pg.CloseAndReset(); | ||
| 439 | }; | 464 | }; |
| 440 | 465 | ||
| 441 | // Finalize memory blocks. | 466 | // Finalize memory blocks. |
| 442 | m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback)); | 467 | { |
| 468 | KScopedLightLock lk(m_general_lock); | ||
| 469 | m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback)); | ||
| 470 | } | ||
| 443 | 471 | ||
| 444 | // Free any unsafe mapped memory. | 472 | // Free any unsafe mapped memory. |
| 445 | if (m_mapped_unsafe_physical_memory) { | 473 | if (m_mapped_unsafe_physical_memory) { |
diff --git a/src/core/hle/kernel/k_page_table_base.h b/src/core/hle/kernel/k_page_table_base.h index 077cafc96..748419f86 100644 --- a/src/core/hle/kernel/k_page_table_base.h +++ b/src/core/hle/kernel/k_page_table_base.h | |||
| @@ -241,6 +241,7 @@ public: | |||
| 241 | KResourceLimit* resource_limit, Core::Memory::Memory& memory, | 241 | KResourceLimit* resource_limit, Core::Memory::Memory& memory, |
| 242 | KProcessAddress aslr_space_start); | 242 | KProcessAddress aslr_space_start); |
| 243 | 243 | ||
| 244 | Result FinalizeProcess(); | ||
| 244 | void Finalize(); | 245 | void Finalize(); |
| 245 | 246 | ||
| 246 | bool IsKernel() const { | 247 | bool IsKernel() const { |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 068e71dff..53735a225 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -171,6 +171,12 @@ void KProcess::Finalize() { | |||
| 171 | m_resource_limit->Close(); | 171 | m_resource_limit->Close(); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | // Clear expensive resources, as the destructor is not called for guest objects. | ||
| 175 | for (auto& interface : m_arm_interfaces) { | ||
| 176 | interface.reset(); | ||
| 177 | } | ||
| 178 | m_exclusive_monitor.reset(); | ||
| 179 | |||
| 174 | // Perform inherited finalization. | 180 | // Perform inherited finalization. |
| 175 | KSynchronizationObject::Finalize(); | 181 | KSynchronizationObject::Finalize(); |
| 176 | } | 182 | } |
| @@ -1233,10 +1239,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { | |||
| 1233 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); | 1239 | ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); |
| 1234 | 1240 | ||
| 1235 | #ifdef HAS_NCE | 1241 | #ifdef HAS_NCE |
| 1236 | if (this->IsApplication() && Settings::IsNceEnabled()) { | 1242 | const auto& patch = code_set.PatchSegment(); |
| 1243 | if (this->IsApplication() && Settings::IsNceEnabled() && patch.size != 0) { | ||
| 1237 | auto& buffer = m_kernel.System().DeviceMemory().buffer; | 1244 | auto& buffer = m_kernel.System().DeviceMemory().buffer; |
| 1238 | const auto& code = code_set.CodeSegment(); | 1245 | const auto& code = code_set.CodeSegment(); |
| 1239 | const auto& patch = code_set.PatchSegment(); | ||
| 1240 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, | 1246 | buffer.Protect(GetInteger(base_addr + code.addr), code.size, |
| 1241 | Common::MemoryPermission::Read | Common::MemoryPermission::Execute); | 1247 | Common::MemoryPermission::Read | Common::MemoryPermission::Execute); |
| 1242 | buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, | 1248 | buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1030f0c12..f3683cdcc 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -112,7 +112,14 @@ struct KernelCore::Impl { | |||
| 112 | old_process->Close(); | 112 | old_process->Close(); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | process_list.clear(); | 115 | { |
| 116 | std::scoped_lock lk{process_list_lock}; | ||
| 117 | for (auto* const process : process_list) { | ||
| 118 | process->Terminate(); | ||
| 119 | process->Close(); | ||
| 120 | } | ||
| 121 | process_list.clear(); | ||
| 122 | } | ||
| 116 | 123 | ||
| 117 | next_object_id = 0; | 124 | next_object_id = 0; |
| 118 | next_kernel_process_id = KProcess::InitialProcessIdMin; | 125 | next_kernel_process_id = KProcess::InitialProcessIdMin; |
| @@ -770,6 +777,7 @@ struct KernelCore::Impl { | |||
| 770 | std::atomic<u64> next_thread_id{1}; | 777 | std::atomic<u64> next_thread_id{1}; |
| 771 | 778 | ||
| 772 | // Lists all processes that exist in the current session. | 779 | // Lists all processes that exist in the current session. |
| 780 | std::mutex process_list_lock; | ||
| 773 | std::vector<KProcess*> process_list; | 781 | std::vector<KProcess*> process_list; |
| 774 | std::atomic<KProcess*> application_process{}; | 782 | std::atomic<KProcess*> application_process{}; |
| 775 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | 783 | std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; |
| @@ -869,9 +877,19 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { | |||
| 869 | } | 877 | } |
| 870 | 878 | ||
| 871 | void KernelCore::AppendNewProcess(KProcess* process) { | 879 | void KernelCore::AppendNewProcess(KProcess* process) { |
| 880 | process->Open(); | ||
| 881 | |||
| 882 | std::scoped_lock lk{impl->process_list_lock}; | ||
| 872 | impl->process_list.push_back(process); | 883 | impl->process_list.push_back(process); |
| 873 | } | 884 | } |
| 874 | 885 | ||
| 886 | void KernelCore::RemoveProcess(KProcess* process) { | ||
| 887 | std::scoped_lock lk{impl->process_list_lock}; | ||
| 888 | if (std::erase(impl->process_list, process)) { | ||
| 889 | process->Close(); | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 875 | void KernelCore::MakeApplicationProcess(KProcess* process) { | 893 | void KernelCore::MakeApplicationProcess(KProcess* process) { |
| 876 | impl->MakeApplicationProcess(process); | 894 | impl->MakeApplicationProcess(process); |
| 877 | } | 895 | } |
| @@ -884,8 +902,15 @@ const KProcess* KernelCore::ApplicationProcess() const { | |||
| 884 | return impl->application_process; | 902 | return impl->application_process; |
| 885 | } | 903 | } |
| 886 | 904 | ||
| 887 | const std::vector<KProcess*>& KernelCore::GetProcessList() const { | 905 | std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() { |
| 888 | return impl->process_list; | 906 | std::list<KScopedAutoObject<KProcess>> processes; |
| 907 | std::scoped_lock lk{impl->process_list_lock}; | ||
| 908 | |||
| 909 | for (auto* const process : impl->process_list) { | ||
| 910 | processes.emplace_back(process); | ||
| 911 | } | ||
| 912 | |||
| 913 | return processes; | ||
| 889 | } | 914 | } |
| 890 | 915 | ||
| 891 | Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { | 916 | Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d4102145..8ea5bed1c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <array> | 6 | #include <array> |
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <list> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include <unordered_map> | 11 | #include <unordered_map> |
| @@ -116,8 +117,9 @@ public: | |||
| 116 | /// Retrieves a shared pointer to the system resource limit instance. | 117 | /// Retrieves a shared pointer to the system resource limit instance. |
| 117 | KResourceLimit* GetSystemResourceLimit(); | 118 | KResourceLimit* GetSystemResourceLimit(); |
| 118 | 119 | ||
| 119 | /// Adds the given shared pointer to an internal list of active processes. | 120 | /// Adds/removes the given pointer to an internal list of active processes. |
| 120 | void AppendNewProcess(KProcess* process); | 121 | void AppendNewProcess(KProcess* process); |
| 122 | void RemoveProcess(KProcess* process); | ||
| 121 | 123 | ||
| 122 | /// Makes the given process the new application process. | 124 | /// Makes the given process the new application process. |
| 123 | void MakeApplicationProcess(KProcess* process); | 125 | void MakeApplicationProcess(KProcess* process); |
| @@ -129,7 +131,7 @@ public: | |||
| 129 | const KProcess* ApplicationProcess() const; | 131 | const KProcess* ApplicationProcess() const; |
| 130 | 132 | ||
| 131 | /// Retrieves the list of processes. | 133 | /// Retrieves the list of processes. |
| 132 | const std::vector<KProcess*>& GetProcessList() const; | 134 | std::list<KScopedAutoObject<KProcess>> GetProcessList(); |
| 133 | 135 | ||
| 134 | /// Gets the sole instance of the global scheduler | 136 | /// Gets the sole instance of the global scheduler |
| 135 | Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); | 137 | Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); |
diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index caa8bee9a..5c3e8829f 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp | |||
| @@ -74,13 +74,15 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | auto& memory = GetCurrentMemory(kernel); | 76 | auto& memory = GetCurrentMemory(kernel); |
| 77 | const auto& process_list = kernel.GetProcessList(); | 77 | auto process_list = kernel.GetProcessList(); |
| 78 | auto it = process_list.begin(); | ||
| 79 | |||
| 78 | const auto num_processes = process_list.size(); | 80 | const auto num_processes = process_list.size(); |
| 79 | const auto copy_amount = | 81 | const auto copy_amount = |
| 80 | std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); | 82 | std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); |
| 81 | 83 | ||
| 82 | for (std::size_t i = 0; i < copy_amount; ++i) { | 84 | for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) { |
| 83 | memory.Write64(out_process_ids, process_list[i]->GetProcessId()); | 85 | memory.Write64(out_process_ids, (*it)->GetProcessId()); |
| 84 | out_process_ids += sizeof(u64); | 86 | out_process_ids += sizeof(u64); |
| 85 | } | 87 | } |
| 86 | 88 | ||
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 5542d6cbc..683f44e27 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -61,9 +61,7 @@ ProfileManager::ProfileManager() { | |||
| 61 | OpenUser(*GetUser(current)); | 61 | OpenUser(*GetUser(current)); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | ProfileManager::~ProfileManager() { | 64 | ProfileManager::~ProfileManager() = default; |
| 65 | WriteUserSaveFile(); | ||
| 66 | } | ||
| 67 | 65 | ||
| 68 | /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the | 66 | /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the |
| 69 | /// internal management of the users profiles | 67 | /// internal management of the users profiles |
| @@ -113,6 +111,8 @@ Result ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& username) | |||
| 113 | return ERROR_USER_ALREADY_EXISTS; | 111 | return ERROR_USER_ALREADY_EXISTS; |
| 114 | } | 112 | } |
| 115 | 113 | ||
| 114 | is_save_needed = true; | ||
| 115 | |||
| 116 | return AddUser({ | 116 | return AddUser({ |
| 117 | .user_uuid = uuid, | 117 | .user_uuid = uuid, |
| 118 | .username = username, | 118 | .username = username, |
| @@ -326,6 +326,9 @@ bool ProfileManager::RemoveUser(UUID uuid) { | |||
| 326 | profiles[*index] = ProfileInfo{}; | 326 | profiles[*index] = ProfileInfo{}; |
| 327 | std::stable_partition(profiles.begin(), profiles.end(), | 327 | std::stable_partition(profiles.begin(), profiles.end(), |
| 328 | [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); | 328 | [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); |
| 329 | |||
| 330 | is_save_needed = true; | ||
| 331 | |||
| 329 | return true; | 332 | return true; |
| 330 | } | 333 | } |
| 331 | 334 | ||
| @@ -340,6 +343,8 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { | |||
| 340 | profile.username = profile_new.username; | 343 | profile.username = profile_new.username; |
| 341 | profile.creation_time = profile_new.timestamp; | 344 | profile.creation_time = profile_new.timestamp; |
| 342 | 345 | ||
| 346 | is_save_needed = true; | ||
| 347 | |||
| 343 | return true; | 348 | return true; |
| 344 | } | 349 | } |
| 345 | 350 | ||
| @@ -348,6 +353,7 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& | |||
| 348 | const auto index = GetUserIndex(uuid); | 353 | const auto index = GetUserIndex(uuid); |
| 349 | if (index.has_value() && SetProfileBase(uuid, profile_new)) { | 354 | if (index.has_value() && SetProfileBase(uuid, profile_new)) { |
| 350 | profiles[*index].data = data_new; | 355 | profiles[*index].data = data_new; |
| 356 | is_save_needed = true; | ||
| 351 | return true; | 357 | return true; |
| 352 | } | 358 | } |
| 353 | 359 | ||
| @@ -391,6 +397,10 @@ void ProfileManager::ParseUserSaveFile() { | |||
| 391 | } | 397 | } |
| 392 | 398 | ||
| 393 | void ProfileManager::WriteUserSaveFile() { | 399 | void ProfileManager::WriteUserSaveFile() { |
| 400 | if (!is_save_needed) { | ||
| 401 | return; | ||
| 402 | } | ||
| 403 | |||
| 394 | ProfileDataRaw raw{}; | 404 | ProfileDataRaw raw{}; |
| 395 | 405 | ||
| 396 | for (std::size_t i = 0; i < MAX_USERS; ++i) { | 406 | for (std::size_t i = 0; i < MAX_USERS; ++i) { |
| @@ -423,7 +433,10 @@ void ProfileManager::WriteUserSaveFile() { | |||
| 423 | if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { | 433 | if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { |
| 424 | LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " | 434 | LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " |
| 425 | "made in current session will be saved."); | 435 | "made in current session will be saved."); |
| 436 | return; | ||
| 426 | } | 437 | } |
| 438 | |||
| 439 | is_save_needed = false; | ||
| 427 | } | 440 | } |
| 428 | 441 | ||
| 429 | }; // namespace Service::Account | 442 | }; // namespace Service::Account |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 900e32200..e21863e64 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -103,6 +103,7 @@ private: | |||
| 103 | std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); | 103 | std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); |
| 104 | bool RemoveProfileAtIndex(std::size_t index); | 104 | bool RemoveProfileAtIndex(std::size_t index); |
| 105 | 105 | ||
| 106 | bool is_save_needed{}; | ||
| 106 | std::array<ProfileInfo, MAX_USERS> profiles{}; | 107 | std::array<ProfileInfo, MAX_USERS> profiles{}; |
| 107 | std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; | 108 | std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; |
| 108 | std::size_t user_count{}; | 109 | std::size_t user_count{}; |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9e05bdafa..a768bdc54 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include "core/hle/service/caps/caps_su.h" | 36 | #include "core/hle/service/caps/caps_su.h" |
| 37 | #include "core/hle/service/caps/caps_types.h" | 37 | #include "core/hle/service/caps/caps_types.h" |
| 38 | #include "core/hle/service/filesystem/filesystem.h" | 38 | #include "core/hle/service/filesystem/filesystem.h" |
| 39 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 39 | #include "core/hle/service/ipc_helpers.h" | 40 | #include "core/hle/service/ipc_helpers.h" |
| 40 | #include "core/hle/service/ns/ns.h" | 41 | #include "core/hle/service/ns/ns.h" |
| 41 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" | 42 | #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" |
| @@ -2178,7 +2179,7 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { | |||
| 2178 | attribute.type = FileSys::SaveDataType::SaveData; | 2179 | attribute.type = FileSys::SaveDataType::SaveData; |
| 2179 | 2180 | ||
| 2180 | FileSys::VirtualDir save_data{}; | 2181 | FileSys::VirtualDir save_data{}; |
| 2181 | const auto res = system.GetFileSystemController().CreateSaveData( | 2182 | const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( |
| 2182 | &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); | 2183 | &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); |
| 2183 | 2184 | ||
| 2184 | IPC::ResponseBuilder rb{ctx, 4}; | 2185 | IPC::ResponseBuilder rb{ctx, 4}; |
| @@ -2353,7 +2354,7 @@ void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { | |||
| 2353 | "new_journal={:016X}", | 2354 | "new_journal={:016X}", |
| 2354 | static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); | 2355 | static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); |
| 2355 | 2356 | ||
| 2356 | system.GetFileSystemController().WriteSaveDataSize( | 2357 | system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( |
| 2357 | type, system.GetApplicationProcessProgramID(), user_id, | 2358 | type, system.GetApplicationProcessProgramID(), user_id, |
| 2358 | {new_normal_size, new_journal_size}); | 2359 | {new_normal_size, new_journal_size}); |
| 2359 | 2360 | ||
| @@ -2378,7 +2379,7 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { | |||
| 2378 | LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], | 2379 | LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], |
| 2379 | user_id[0]); | 2380 | user_id[0]); |
| 2380 | 2381 | ||
| 2381 | const auto size = system.GetFileSystemController().ReadSaveDataSize( | 2382 | const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( |
| 2382 | type, system.GetApplicationProcessProgramID(), user_id); | 2383 | type, system.GetApplicationProcessProgramID(), user_id); |
| 2383 | 2384 | ||
| 2384 | IPC::ResponseBuilder rb{ctx, 6}; | 2385 | IPC::ResponseBuilder rb{ctx, 6}; |
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 56fee4591..de2aa6906 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp | |||
| @@ -18,11 +18,11 @@ using namespace AudioCore::AudioIn; | |||
| 18 | class IAudioIn final : public ServiceFramework<IAudioIn> { | 18 | class IAudioIn final : public ServiceFramework<IAudioIn> { |
| 19 | public: | 19 | public: |
| 20 | explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, | 20 | explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, |
| 21 | const std::string& device_name, const AudioInParameter& in_params, u32 handle, | 21 | const std::string& device_name, const AudioInParameter& in_params, |
| 22 | u64 applet_resource_user_id) | 22 | Kernel::KProcess* handle, u64 applet_resource_user_id) |
| 23 | : ServiceFramework{system_, "IAudioIn"}, | 23 | : ServiceFramework{system_, "IAudioIn"}, |
| 24 | service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, | 24 | service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, |
| 25 | impl{std::make_shared<In>(system_, manager, event, session_id)} { | 25 | process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} { |
| 26 | // clang-format off | 26 | // clang-format off |
| 27 | static const FunctionInfo functions[] = { | 27 | static const FunctionInfo functions[] = { |
| 28 | {0, &IAudioIn::GetAudioInState, "GetAudioInState"}, | 28 | {0, &IAudioIn::GetAudioInState, "GetAudioInState"}, |
| @@ -45,6 +45,8 @@ public: | |||
| 45 | 45 | ||
| 46 | RegisterHandlers(functions); | 46 | RegisterHandlers(functions); |
| 47 | 47 | ||
| 48 | process->Open(); | ||
| 49 | |||
| 48 | if (impl->GetSystem() | 50 | if (impl->GetSystem() |
| 49 | .Initialize(device_name, in_params, handle, applet_resource_user_id) | 51 | .Initialize(device_name, in_params, handle, applet_resource_user_id) |
| 50 | .IsError()) { | 52 | .IsError()) { |
| @@ -55,6 +57,7 @@ public: | |||
| 55 | ~IAudioIn() override { | 57 | ~IAudioIn() override { |
| 56 | impl->Free(); | 58 | impl->Free(); |
| 57 | service_context.CloseEvent(event); | 59 | service_context.CloseEvent(event); |
| 60 | process->Close(); | ||
| 58 | } | 61 | } |
| 59 | 62 | ||
| 60 | [[nodiscard]] std::shared_ptr<In> GetImpl() { | 63 | [[nodiscard]] std::shared_ptr<In> GetImpl() { |
| @@ -196,6 +199,7 @@ private: | |||
| 196 | 199 | ||
| 197 | KernelHelpers::ServiceContext service_context; | 200 | KernelHelpers::ServiceContext service_context; |
| 198 | Kernel::KEvent* event; | 201 | Kernel::KEvent* event; |
| 202 | Kernel::KProcess* process; | ||
| 199 | std::shared_ptr<AudioCore::AudioIn::In> impl; | 203 | std::shared_ptr<AudioCore::AudioIn::In> impl; |
| 200 | Common::ScratchBuffer<u64> released_buffer; | 204 | Common::ScratchBuffer<u64> released_buffer; |
| 201 | }; | 205 | }; |
| @@ -267,6 +271,14 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) { | |||
| 267 | auto device_name = Common::StringFromBuffer(device_name_data); | 271 | auto device_name = Common::StringFromBuffer(device_name_data); |
| 268 | auto handle{ctx.GetCopyHandle(0)}; | 272 | auto handle{ctx.GetCopyHandle(0)}; |
| 269 | 273 | ||
| 274 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||
| 275 | if (process.IsNull()) { | ||
| 276 | LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||
| 277 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 278 | rb.Push(ResultUnknown); | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | |||
| 270 | std::scoped_lock l{impl->mutex}; | 282 | std::scoped_lock l{impl->mutex}; |
| 271 | auto link{impl->LinkToManager()}; | 283 | auto link{impl->LinkToManager()}; |
| 272 | if (link.IsError()) { | 284 | if (link.IsError()) { |
| @@ -287,8 +299,9 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) { | |||
| 287 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, | 299 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, |
| 288 | impl->num_free_sessions); | 300 | impl->num_free_sessions); |
| 289 | 301 | ||
| 290 | auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, | 302 | auto audio_in = |
| 291 | in_params, handle, applet_resource_user_id); | 303 | std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, |
| 304 | process.GetPointerUnsafe(), applet_resource_user_id); | ||
| 292 | impl->sessions[new_session_id] = audio_in->GetImpl(); | 305 | impl->sessions[new_session_id] = audio_in->GetImpl(); |
| 293 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | 306 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
| 294 | 307 | ||
| @@ -318,6 +331,14 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { | |||
| 318 | auto device_name = Common::StringFromBuffer(device_name_data); | 331 | auto device_name = Common::StringFromBuffer(device_name_data); |
| 319 | auto handle{ctx.GetCopyHandle(0)}; | 332 | auto handle{ctx.GetCopyHandle(0)}; |
| 320 | 333 | ||
| 334 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||
| 335 | if (process.IsNull()) { | ||
| 336 | LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||
| 337 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 338 | rb.Push(ResultUnknown); | ||
| 339 | return; | ||
| 340 | } | ||
| 341 | |||
| 321 | std::scoped_lock l{impl->mutex}; | 342 | std::scoped_lock l{impl->mutex}; |
| 322 | auto link{impl->LinkToManager()}; | 343 | auto link{impl->LinkToManager()}; |
| 323 | if (link.IsError()) { | 344 | if (link.IsError()) { |
| @@ -338,8 +359,9 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { | |||
| 338 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, | 359 | LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, |
| 339 | impl->num_free_sessions); | 360 | impl->num_free_sessions); |
| 340 | 361 | ||
| 341 | auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, | 362 | auto audio_in = |
| 342 | in_params, handle, applet_resource_user_id); | 363 | std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, |
| 364 | process.GetPointerUnsafe(), applet_resource_user_id); | ||
| 343 | impl->sessions[new_session_id] = audio_in->GetImpl(); | 365 | impl->sessions[new_session_id] = audio_in->GetImpl(); |
| 344 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; | 366 | impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
| 345 | 367 | ||
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index ca683d72c..8cc7b69f4 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -26,9 +26,10 @@ class IAudioOut final : public ServiceFramework<IAudioOut> { | |||
| 26 | public: | 26 | public: |
| 27 | explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, | 27 | explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, |
| 28 | size_t session_id, const std::string& device_name, | 28 | size_t session_id, const std::string& device_name, |
| 29 | const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) | 29 | const AudioOutParameter& in_params, Kernel::KProcess* handle, |
| 30 | u64 applet_resource_user_id) | ||
| 30 | : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, | 31 | : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, |
| 31 | event{service_context.CreateEvent("AudioOutEvent")}, | 32 | event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, |
| 32 | impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { | 33 | impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { |
| 33 | 34 | ||
| 34 | // clang-format off | 35 | // clang-format off |
| @@ -50,11 +51,14 @@ public: | |||
| 50 | }; | 51 | }; |
| 51 | // clang-format on | 52 | // clang-format on |
| 52 | RegisterHandlers(functions); | 53 | RegisterHandlers(functions); |
| 54 | |||
| 55 | process->Open(); | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | ~IAudioOut() override { | 58 | ~IAudioOut() override { |
| 56 | impl->Free(); | 59 | impl->Free(); |
| 57 | service_context.CloseEvent(event); | 60 | service_context.CloseEvent(event); |
| 61 | process->Close(); | ||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { | 64 | [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { |
| @@ -206,6 +210,7 @@ private: | |||
| 206 | 210 | ||
| 207 | KernelHelpers::ServiceContext service_context; | 211 | KernelHelpers::ServiceContext service_context; |
| 208 | Kernel::KEvent* event; | 212 | Kernel::KEvent* event; |
| 213 | Kernel::KProcess* process; | ||
| 209 | std::shared_ptr<AudioCore::AudioOut::Out> impl; | 214 | std::shared_ptr<AudioCore::AudioOut::Out> impl; |
| 210 | Common::ScratchBuffer<u64> released_buffer; | 215 | Common::ScratchBuffer<u64> released_buffer; |
| 211 | }; | 216 | }; |
| @@ -257,6 +262,14 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) { | |||
| 257 | auto device_name = Common::StringFromBuffer(device_name_data); | 262 | auto device_name = Common::StringFromBuffer(device_name_data); |
| 258 | auto handle{ctx.GetCopyHandle(0)}; | 263 | auto handle{ctx.GetCopyHandle(0)}; |
| 259 | 264 | ||
| 265 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; | ||
| 266 | if (process.IsNull()) { | ||
| 267 | LOG_ERROR(Service_Audio, "Failed to get process handle"); | ||
| 268 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 269 | rb.Push(ResultUnknown); | ||
| 270 | return; | ||
| 271 | } | ||
| 272 | |||
| 260 | auto link{impl->LinkToManager()}; | 273 | auto link{impl->LinkToManager()}; |
| 261 | if (link.IsError()) { | 274 | if (link.IsError()) { |
| 262 | LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); | 275 | LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); |
| @@ -276,10 +289,11 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) { | |||
| 276 | LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, | 289 | LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, |
| 277 | impl->num_free_sessions); | 290 | impl->num_free_sessions); |
| 278 | 291 | ||
| 279 | auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, | 292 | auto audio_out = |
| 280 | in_params, handle, applet_resource_user_id); | 293 | std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params, |
| 281 | result = audio_out->GetImpl()->GetSystem().Initialize(device_name, in_params, handle, | 294 | process.GetPointerUnsafe(), applet_resource_user_id); |
| 282 | applet_resource_user_id); | 295 | result = audio_out->GetImpl()->GetSystem().Initialize( |
| 296 | device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id); | ||
| 283 | if (result.IsError()) { | 297 | if (result.IsError()) { |
| 284 | LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); | 298 | LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); |
| 285 | IPC::ResponseBuilder rb{ctx, 2}; | 299 | IPC::ResponseBuilder rb{ctx, 2}; |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 780f8c74d..ca6d8d607 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -24,15 +24,13 @@ | |||
| 24 | #include "core/hle/service/filesystem/fsp_ldr.h" | 24 | #include "core/hle/service/filesystem/fsp_ldr.h" |
| 25 | #include "core/hle/service/filesystem/fsp_pr.h" | 25 | #include "core/hle/service/filesystem/fsp_pr.h" |
| 26 | #include "core/hle/service/filesystem/fsp_srv.h" | 26 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 27 | #include "core/hle/service/filesystem/romfs_controller.h" | ||
| 28 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 27 | #include "core/hle/service/server_manager.h" | 29 | #include "core/hle/service/server_manager.h" |
| 28 | #include "core/loader/loader.h" | 30 | #include "core/loader/loader.h" |
| 29 | 31 | ||
| 30 | namespace Service::FileSystem { | 32 | namespace Service::FileSystem { |
| 31 | 33 | ||
| 32 | // A default size for normal/journal save data size if application control metadata cannot be found. | ||
| 33 | // This should be large enough to satisfy even the most extreme requirements (~4.2GB) | ||
| 34 | constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; | ||
| 35 | |||
| 36 | static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, | 34 | static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, |
| 37 | std::string_view dir_name_) { | 35 | std::string_view dir_name_) { |
| 38 | std::string dir_name(Common::FS::SanitizePath(dir_name_)); | 36 | std::string dir_name(Common::FS::SanitizePath(dir_name_)); |
| @@ -297,145 +295,65 @@ FileSystemController::FileSystemController(Core::System& system_) : system{syste | |||
| 297 | 295 | ||
| 298 | FileSystemController::~FileSystemController() = default; | 296 | FileSystemController::~FileSystemController() = default; |
| 299 | 297 | ||
| 300 | Result FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) { | 298 | Result FileSystemController::RegisterProcess( |
| 301 | romfs_factory = std::move(factory); | 299 | ProcessId process_id, ProgramId program_id, |
| 302 | LOG_DEBUG(Service_FS, "Registered RomFS"); | 300 | std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) { |
| 303 | return ResultSuccess; | 301 | std::scoped_lock lk{registration_lock}; |
| 304 | } | ||
| 305 | |||
| 306 | Result FileSystemController::RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) { | ||
| 307 | ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data"); | ||
| 308 | save_data_factory = std::move(factory); | ||
| 309 | LOG_DEBUG(Service_FS, "Registered save data"); | ||
| 310 | return ResultSuccess; | ||
| 311 | } | ||
| 312 | 302 | ||
| 313 | Result FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { | 303 | registrations.emplace(process_id, Registration{ |
| 314 | ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC"); | 304 | .program_id = program_id, |
| 315 | sdmc_factory = std::move(factory); | 305 | .romfs_factory = std::move(romfs_factory), |
| 316 | LOG_DEBUG(Service_FS, "Registered SDMC"); | 306 | .save_data_factory = CreateSaveDataFactory(program_id), |
| 317 | return ResultSuccess; | 307 | }); |
| 318 | } | ||
| 319 | 308 | ||
| 320 | Result FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) { | 309 | LOG_DEBUG(Service_FS, "Registered for process {}", process_id); |
| 321 | ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS"); | ||
| 322 | bis_factory = std::move(factory); | ||
| 323 | LOG_DEBUG(Service_FS, "Registered BIS"); | ||
| 324 | return ResultSuccess; | 310 | return ResultSuccess; |
| 325 | } | 311 | } |
| 326 | 312 | ||
| 327 | void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) { | 313 | Result FileSystemController::OpenProcess( |
| 328 | LOG_TRACE(Service_FS, "Setting packed update for romfs"); | 314 | ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller, |
| 329 | 315 | std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) { | |
| 330 | if (romfs_factory == nullptr) | 316 | std::scoped_lock lk{registration_lock}; |
| 331 | return; | ||
| 332 | |||
| 333 | romfs_factory->SetPackedUpdate(std::move(update_raw)); | ||
| 334 | } | ||
| 335 | |||
| 336 | FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const { | ||
| 337 | LOG_TRACE(Service_FS, "Opening RomFS for current process"); | ||
| 338 | |||
| 339 | if (romfs_factory == nullptr) { | ||
| 340 | return nullptr; | ||
| 341 | } | ||
| 342 | |||
| 343 | return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID()); | ||
| 344 | } | ||
| 345 | |||
| 346 | FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id, | ||
| 347 | FileSys::ContentRecordType type) const { | ||
| 348 | LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id); | ||
| 349 | |||
| 350 | if (romfs_factory == nullptr) { | ||
| 351 | return nullptr; | ||
| 352 | } | ||
| 353 | |||
| 354 | return romfs_factory->OpenPatchedRomFS(title_id, type); | ||
| 355 | } | ||
| 356 | |||
| 357 | FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex( | ||
| 358 | u64 title_id, u8 program_index, FileSys::ContentRecordType type) const { | ||
| 359 | LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id, | ||
| 360 | program_index); | ||
| 361 | |||
| 362 | if (romfs_factory == nullptr) { | ||
| 363 | return nullptr; | ||
| 364 | } | ||
| 365 | |||
| 366 | return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); | ||
| 367 | } | ||
| 368 | |||
| 369 | FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 370 | FileSys::ContentRecordType type) const { | ||
| 371 | LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", | ||
| 372 | title_id, storage_id, type); | ||
| 373 | |||
| 374 | if (romfs_factory == nullptr) { | ||
| 375 | return nullptr; | ||
| 376 | } | ||
| 377 | |||
| 378 | return romfs_factory->Open(title_id, storage_id, type); | ||
| 379 | } | ||
| 380 | |||
| 381 | std::shared_ptr<FileSys::NCA> FileSystemController::OpenBaseNca( | ||
| 382 | u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const { | ||
| 383 | return romfs_factory->GetEntry(title_id, storage_id, type); | ||
| 384 | } | ||
| 385 | |||
| 386 | Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data, | ||
| 387 | FileSys::SaveDataSpaceId space, | ||
| 388 | const FileSys::SaveDataAttribute& save_struct) const { | ||
| 389 | LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, | ||
| 390 | save_struct.DebugInfo()); | ||
| 391 | 317 | ||
| 392 | if (save_data_factory == nullptr) { | 318 | const auto it = registrations.find(process_id); |
| 319 | if (it == registrations.end()) { | ||
| 393 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 320 | return FileSys::ERROR_ENTITY_NOT_FOUND; |
| 394 | } | 321 | } |
| 395 | 322 | ||
| 396 | auto save_data = save_data_factory->Create(space, save_struct); | 323 | *out_program_id = it->second.program_id; |
| 397 | if (save_data == nullptr) { | 324 | *out_save_data_controller = |
| 398 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 325 | std::make_shared<SaveDataController>(system, it->second.save_data_factory); |
| 399 | } | 326 | *out_romfs_controller = |
| 400 | 327 | std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id); | |
| 401 | *out_save_data = save_data; | ||
| 402 | return ResultSuccess; | 328 | return ResultSuccess; |
| 403 | } | 329 | } |
| 404 | 330 | ||
| 405 | Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data, | 331 | void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) { |
| 406 | FileSys::SaveDataSpaceId space, | 332 | LOG_TRACE(Service_FS, "Setting packed update for romfs"); |
| 407 | const FileSys::SaveDataAttribute& attribute) const { | ||
| 408 | LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space, | ||
| 409 | attribute.DebugInfo()); | ||
| 410 | |||
| 411 | if (save_data_factory == nullptr) { | ||
| 412 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 413 | } | ||
| 414 | 333 | ||
| 415 | auto save_data = save_data_factory->Open(space, attribute); | 334 | std::scoped_lock lk{registration_lock}; |
| 416 | if (save_data == nullptr) { | 335 | const auto it = registrations.find(process_id); |
| 417 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 336 | if (it == registrations.end()) { |
| 337 | return; | ||
| 418 | } | 338 | } |
| 419 | 339 | ||
| 420 | *out_save_data = save_data; | 340 | it->second.romfs_factory->SetPackedUpdate(std::move(update_raw)); |
| 421 | return ResultSuccess; | ||
| 422 | } | 341 | } |
| 423 | 342 | ||
| 424 | Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | 343 | std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController() { |
| 425 | FileSys::SaveDataSpaceId space) const { | 344 | return std::make_shared<SaveDataController>(system, CreateSaveDataFactory(ProgramId{})); |
| 426 | LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space); | 345 | } |
| 427 | |||
| 428 | if (save_data_factory == nullptr) { | ||
| 429 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 430 | } | ||
| 431 | 346 | ||
| 432 | auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space); | 347 | std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory( |
| 433 | if (save_data_space == nullptr) { | 348 | ProgramId program_id) { |
| 434 | return FileSys::ERROR_ENTITY_NOT_FOUND; | 349 | using YuzuPath = Common::FS::YuzuPath; |
| 435 | } | 350 | const auto rw_mode = FileSys::Mode::ReadWrite; |
| 436 | 351 | ||
| 437 | *out_save_data_space = save_data_space; | 352 | auto vfs = system.GetFilesystem(); |
| 438 | return ResultSuccess; | 353 | const auto nand_directory = |
| 354 | vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); | ||
| 355 | return std::make_shared<FileSys::SaveDataFactory>(system, program_id, | ||
| 356 | std::move(nand_directory)); | ||
| 439 | } | 357 | } |
| 440 | 358 | ||
| 441 | Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { | 359 | Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { |
| @@ -540,48 +458,6 @@ u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const { | |||
| 540 | return 0; | 458 | return 0; |
| 541 | } | 459 | } |
| 542 | 460 | ||
| 543 | FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type, | ||
| 544 | u64 title_id, u128 user_id) const { | ||
| 545 | if (save_data_factory == nullptr) { | ||
| 546 | return {0, 0}; | ||
| 547 | } | ||
| 548 | |||
| 549 | const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id); | ||
| 550 | |||
| 551 | if (value.normal == 0 && value.journal == 0) { | ||
| 552 | FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; | ||
| 553 | |||
| 554 | FileSys::NACP nacp; | ||
| 555 | const auto res = system.GetAppLoader().ReadControlData(nacp); | ||
| 556 | |||
| 557 | if (res != Loader::ResultStatus::Success) { | ||
| 558 | const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(), | ||
| 559 | system.GetFileSystemController(), | ||
| 560 | system.GetContentProvider()}; | ||
| 561 | const auto metadata = pm.GetControlMetadata(); | ||
| 562 | const auto& nacp_unique = metadata.first; | ||
| 563 | |||
| 564 | if (nacp_unique != nullptr) { | ||
| 565 | new_size = {nacp_unique->GetDefaultNormalSaveSize(), | ||
| 566 | nacp_unique->GetDefaultJournalSaveSize()}; | ||
| 567 | } | ||
| 568 | } else { | ||
| 569 | new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()}; | ||
| 570 | } | ||
| 571 | |||
| 572 | WriteSaveDataSize(type, title_id, user_id, new_size); | ||
| 573 | return new_size; | ||
| 574 | } | ||
| 575 | |||
| 576 | return value; | ||
| 577 | } | ||
| 578 | |||
| 579 | void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 580 | FileSys::SaveDataSize new_value) const { | ||
| 581 | if (save_data_factory != nullptr) | ||
| 582 | save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); | ||
| 583 | } | ||
| 584 | |||
| 585 | void FileSystemController::SetGameCard(FileSys::VirtualFile file) { | 461 | void FileSystemController::SetGameCard(FileSys::VirtualFile file) { |
| 586 | gamecard = std::make_unique<FileSys::XCI>(file); | 462 | gamecard = std::make_unique<FileSys::XCI>(file); |
| 587 | const auto dir = gamecard->ConcatenatedPseudoDirectory(); | 463 | const auto dir = gamecard->ConcatenatedPseudoDirectory(); |
| @@ -801,14 +677,9 @@ FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const { | |||
| 801 | return bis_factory->GetBCATDirectory(title_id); | 677 | return bis_factory->GetBCATDirectory(title_id); |
| 802 | } | 678 | } |
| 803 | 679 | ||
| 804 | void FileSystemController::SetAutoSaveDataCreation(bool enable) { | ||
| 805 | save_data_factory->SetAutoCreate(enable); | ||
| 806 | } | ||
| 807 | |||
| 808 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | 680 | void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { |
| 809 | if (overwrite) { | 681 | if (overwrite) { |
| 810 | bis_factory = nullptr; | 682 | bis_factory = nullptr; |
| 811 | save_data_factory = nullptr; | ||
| 812 | sdmc_factory = nullptr; | 683 | sdmc_factory = nullptr; |
| 813 | } | 684 | } |
| 814 | 685 | ||
| @@ -836,11 +707,6 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 836 | bis_factory->GetUserNANDContents()); | 707 | bis_factory->GetUserNANDContents()); |
| 837 | } | 708 | } |
| 838 | 709 | ||
| 839 | if (save_data_factory == nullptr) { | ||
| 840 | save_data_factory = | ||
| 841 | std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory)); | ||
| 842 | } | ||
| 843 | |||
| 844 | if (sdmc_factory == nullptr) { | 710 | if (sdmc_factory == nullptr) { |
| 845 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory), | 711 | sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory), |
| 846 | std::move(sd_load_directory)); | 712 | std::move(sd_load_directory)); |
| @@ -849,12 +715,19 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove | |||
| 849 | } | 715 | } |
| 850 | } | 716 | } |
| 851 | 717 | ||
| 718 | void FileSystemController::Reset() { | ||
| 719 | std::scoped_lock lk{registration_lock}; | ||
| 720 | registrations.clear(); | ||
| 721 | } | ||
| 722 | |||
| 852 | void LoopProcess(Core::System& system) { | 723 | void LoopProcess(Core::System& system) { |
| 853 | auto server_manager = std::make_unique<ServerManager>(system); | 724 | auto server_manager = std::make_unique<ServerManager>(system); |
| 854 | 725 | ||
| 726 | const auto FileSystemProxyFactory = [&] { return std::make_shared<FSP_SRV>(system); }; | ||
| 727 | |||
| 855 | server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system)); | 728 | server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system)); |
| 856 | server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system)); | 729 | server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system)); |
| 857 | server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system)); | 730 | server_manager->RegisterNamedService("fsp-srv", std::move(FileSystemProxyFactory)); |
| 858 | ServerManager::RunServer(std::move(server_manager)); | 731 | ServerManager::RunServer(std::move(server_manager)); |
| 859 | } | 732 | } |
| 860 | 733 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 276d264e1..48f37d289 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -43,6 +43,9 @@ class ServiceManager; | |||
| 43 | 43 | ||
| 44 | namespace FileSystem { | 44 | namespace FileSystem { |
| 45 | 45 | ||
| 46 | class RomFsController; | ||
| 47 | class SaveDataController; | ||
| 48 | |||
| 46 | enum class ContentStorageId : u32 { | 49 | enum class ContentStorageId : u32 { |
| 47 | System, | 50 | System, |
| 48 | User, | 51 | User, |
| @@ -61,32 +64,24 @@ enum class OpenDirectoryMode : u64 { | |||
| 61 | }; | 64 | }; |
| 62 | DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); | 65 | DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); |
| 63 | 66 | ||
| 67 | using ProcessId = u64; | ||
| 68 | using ProgramId = u64; | ||
| 69 | |||
| 64 | class FileSystemController { | 70 | class FileSystemController { |
| 65 | public: | 71 | public: |
| 66 | explicit FileSystemController(Core::System& system_); | 72 | explicit FileSystemController(Core::System& system_); |
| 67 | ~FileSystemController(); | 73 | ~FileSystemController(); |
| 68 | 74 | ||
| 69 | Result RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); | 75 | Result RegisterProcess(ProcessId process_id, ProgramId program_id, |
| 70 | Result RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory); | 76 | std::shared_ptr<FileSys::RomFSFactory>&& factory); |
| 71 | Result RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); | 77 | Result OpenProcess(ProgramId* out_program_id, |
| 72 | Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); | 78 | std::shared_ptr<SaveDataController>* out_save_data_controller, |
| 73 | 79 | std::shared_ptr<RomFsController>* out_romfs_controller, | |
| 74 | void SetPackedUpdate(FileSys::VirtualFile update_raw); | 80 | ProcessId process_id); |
| 75 | FileSys::VirtualFile OpenRomFSCurrentProcess() const; | 81 | void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw); |
| 76 | FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const; | 82 | |
| 77 | FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index, | 83 | std::shared_ptr<SaveDataController> OpenSaveDataController(); |
| 78 | FileSys::ContentRecordType type) const; | 84 | |
| 79 | FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 80 | FileSys::ContentRecordType type) const; | ||
| 81 | std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id, | ||
| 82 | FileSys::ContentRecordType type) const; | ||
| 83 | |||
| 84 | Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 85 | const FileSys::SaveDataAttribute& save_struct) const; | ||
| 86 | Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 87 | const FileSys::SaveDataAttribute& save_struct) const; | ||
| 88 | Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | ||
| 89 | FileSys::SaveDataSpaceId space) const; | ||
| 90 | Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const; | 85 | Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const; |
| 91 | Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition, | 86 | Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition, |
| 92 | FileSys::BisPartitionId id) const; | 87 | FileSys::BisPartitionId id) const; |
| @@ -96,11 +91,6 @@ public: | |||
| 96 | u64 GetFreeSpaceSize(FileSys::StorageId id) const; | 91 | u64 GetFreeSpaceSize(FileSys::StorageId id) const; |
| 97 | u64 GetTotalSpaceSize(FileSys::StorageId id) const; | 92 | u64 GetTotalSpaceSize(FileSys::StorageId id) const; |
| 98 | 93 | ||
| 99 | FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, | ||
| 100 | u128 user_id) const; | ||
| 101 | void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 102 | FileSys::SaveDataSize new_value) const; | ||
| 103 | |||
| 104 | void SetGameCard(FileSys::VirtualFile file); | 94 | void SetGameCard(FileSys::VirtualFile file); |
| 105 | FileSys::XCI* GetGameCard() const; | 95 | FileSys::XCI* GetGameCard() const; |
| 106 | 96 | ||
| @@ -133,15 +123,24 @@ public: | |||
| 133 | 123 | ||
| 134 | FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; | 124 | FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; |
| 135 | 125 | ||
| 136 | void SetAutoSaveDataCreation(bool enable); | ||
| 137 | |||
| 138 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function | 126 | // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function |
| 139 | // above is called. | 127 | // above is called. |
| 140 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); | 128 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); |
| 141 | 129 | ||
| 130 | void Reset(); | ||
| 131 | |||
| 142 | private: | 132 | private: |
| 143 | std::unique_ptr<FileSys::RomFSFactory> romfs_factory; | 133 | std::shared_ptr<FileSys::SaveDataFactory> CreateSaveDataFactory(ProgramId program_id); |
| 144 | std::unique_ptr<FileSys::SaveDataFactory> save_data_factory; | 134 | |
| 135 | struct Registration { | ||
| 136 | ProgramId program_id; | ||
| 137 | std::shared_ptr<FileSys::RomFSFactory> romfs_factory; | ||
| 138 | std::shared_ptr<FileSys::SaveDataFactory> save_data_factory; | ||
| 139 | }; | ||
| 140 | |||
| 141 | std::mutex registration_lock; | ||
| 142 | std::map<ProcessId, Registration> registrations; | ||
| 143 | |||
| 145 | std::unique_ptr<FileSys::SDMCFactory> sdmc_factory; | 144 | std::unique_ptr<FileSys::SDMCFactory> sdmc_factory; |
| 146 | std::unique_ptr<FileSys::BISFactory> bis_factory; | 145 | std::unique_ptr<FileSys::BISFactory> bis_factory; |
| 147 | 146 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 82ecc1b90..a2397bec4 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #include "core/hle/result.h" | 27 | #include "core/hle/result.h" |
| 28 | #include "core/hle/service/filesystem/filesystem.h" | 28 | #include "core/hle/service/filesystem/filesystem.h" |
| 29 | #include "core/hle/service/filesystem/fsp_srv.h" | 29 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 30 | #include "core/hle/service/filesystem/romfs_controller.h" | ||
| 31 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 30 | #include "core/hle/service/hle_ipc.h" | 32 | #include "core/hle/service/hle_ipc.h" |
| 31 | #include "core/hle/service/ipc_helpers.h" | 33 | #include "core/hle/service/ipc_helpers.h" |
| 32 | #include "core/reporter.h" | 34 | #include "core/reporter.h" |
| @@ -577,9 +579,11 @@ private: | |||
| 577 | 579 | ||
| 578 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { | 580 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { |
| 579 | public: | 581 | public: |
| 580 | explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space, | 582 | explicit ISaveDataInfoReader(Core::System& system_, |
| 581 | FileSystemController& fsc_) | 583 | std::shared_ptr<SaveDataController> save_data_controller_, |
| 582 | : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} { | 584 | FileSys::SaveDataSpaceId space) |
| 585 | : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{ | ||
| 586 | save_data_controller_} { | ||
| 583 | static const FunctionInfo functions[] = { | 587 | static const FunctionInfo functions[] = { |
| 584 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, | 588 | {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, |
| 585 | }; | 589 | }; |
| @@ -626,7 +630,7 @@ private: | |||
| 626 | 630 | ||
| 627 | void FindAllSaves(FileSys::SaveDataSpaceId space) { | 631 | void FindAllSaves(FileSys::SaveDataSpaceId space) { |
| 628 | FileSys::VirtualDir save_root{}; | 632 | FileSys::VirtualDir save_root{}; |
| 629 | const auto result = fsc.OpenSaveDataSpace(&save_root, space); | 633 | const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space); |
| 630 | 634 | ||
| 631 | if (result != ResultSuccess || save_root == nullptr) { | 635 | if (result != ResultSuccess || save_root == nullptr) { |
| 632 | LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); | 636 | LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); |
| @@ -723,7 +727,8 @@ private: | |||
| 723 | }; | 727 | }; |
| 724 | static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); | 728 | static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); |
| 725 | 729 | ||
| 726 | FileSystemController& fsc; | 730 | ProcessId process_id = 0; |
| 731 | std::shared_ptr<SaveDataController> save_data_controller; | ||
| 727 | std::vector<SaveDataInfo> info; | 732 | std::vector<SaveDataInfo> info; |
| 728 | u64 next_entry_index = 0; | 733 | u64 next_entry_index = 0; |
| 729 | }; | 734 | }; |
| @@ -863,21 +868,20 @@ FSP_SRV::FSP_SRV(Core::System& system_) | |||
| 863 | if (Settings::values.enable_fs_access_log) { | 868 | if (Settings::values.enable_fs_access_log) { |
| 864 | access_log_mode = AccessLogMode::SdCard; | 869 | access_log_mode = AccessLogMode::SdCard; |
| 865 | } | 870 | } |
| 866 | |||
| 867 | // This should be true on creation | ||
| 868 | fsc.SetAutoSaveDataCreation(true); | ||
| 869 | } | 871 | } |
| 870 | 872 | ||
| 871 | FSP_SRV::~FSP_SRV() = default; | 873 | FSP_SRV::~FSP_SRV() = default; |
| 872 | 874 | ||
| 873 | void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { | 875 | void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { |
| 874 | IPC::RequestParser rp{ctx}; | 876 | current_process_id = ctx.GetPID(); |
| 875 | current_process_id = rp.Pop<u64>(); | ||
| 876 | 877 | ||
| 877 | LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); | 878 | LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); |
| 878 | 879 | ||
| 880 | const auto res = | ||
| 881 | fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); | ||
| 882 | |||
| 879 | IPC::ResponseBuilder rb{ctx, 2}; | 883 | IPC::ResponseBuilder rb{ctx, 2}; |
| 880 | rb.Push(ResultSuccess); | 884 | rb.Push(res); |
| 881 | } | 885 | } |
| 882 | 886 | ||
| 883 | void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { | 887 | void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { |
| @@ -916,7 +920,8 @@ void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { | |||
| 916 | uid[1], uid[0]); | 920 | uid[1], uid[0]); |
| 917 | 921 | ||
| 918 | FileSys::VirtualDir save_data_dir{}; | 922 | FileSys::VirtualDir save_data_dir{}; |
| 919 | fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct); | 923 | save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, |
| 924 | save_struct); | ||
| 920 | 925 | ||
| 921 | IPC::ResponseBuilder rb{ctx, 2}; | 926 | IPC::ResponseBuilder rb{ctx, 2}; |
| 922 | rb.Push(ResultSuccess); | 927 | rb.Push(ResultSuccess); |
| @@ -931,7 +936,8 @@ void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) | |||
| 931 | LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); | 936 | LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); |
| 932 | 937 | ||
| 933 | FileSys::VirtualDir save_data_dir{}; | 938 | FileSys::VirtualDir save_data_dir{}; |
| 934 | fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, save_struct); | 939 | save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, |
| 940 | save_struct); | ||
| 935 | 941 | ||
| 936 | IPC::ResponseBuilder rb{ctx, 2}; | 942 | IPC::ResponseBuilder rb{ctx, 2}; |
| 937 | rb.Push(ResultSuccess); | 943 | rb.Push(ResultSuccess); |
| @@ -950,7 +956,8 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { | |||
| 950 | LOG_INFO(Service_FS, "called."); | 956 | LOG_INFO(Service_FS, "called."); |
| 951 | 957 | ||
| 952 | FileSys::VirtualDir dir{}; | 958 | FileSys::VirtualDir dir{}; |
| 953 | auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute); | 959 | auto result = |
| 960 | save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute); | ||
| 954 | if (result != ResultSuccess) { | 961 | if (result != ResultSuccess) { |
| 955 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 962 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 956 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); | 963 | rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); |
| @@ -1001,7 +1008,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { | |||
| 1001 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1008 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1002 | rb.Push(ResultSuccess); | 1009 | rb.Push(ResultSuccess); |
| 1003 | rb.PushIpcInterface<ISaveDataInfoReader>( | 1010 | rb.PushIpcInterface<ISaveDataInfoReader>( |
| 1004 | std::make_shared<ISaveDataInfoReader>(system, space, fsc)); | 1011 | std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space)); |
| 1005 | } | 1012 | } |
| 1006 | 1013 | ||
| 1007 | void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { | 1014 | void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { |
| @@ -1009,8 +1016,8 @@ void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { | |||
| 1009 | 1016 | ||
| 1010 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1017 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1011 | rb.Push(ResultSuccess); | 1018 | rb.Push(ResultSuccess); |
| 1012 | rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage, | 1019 | rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller, |
| 1013 | fsc); | 1020 | FileSys::SaveDataSpaceId::TemporaryStorage); |
| 1014 | } | 1021 | } |
| 1015 | 1022 | ||
| 1016 | void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { | 1023 | void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { |
| @@ -1050,7 +1057,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { | |||
| 1050 | LOG_DEBUG(Service_FS, "called"); | 1057 | LOG_DEBUG(Service_FS, "called"); |
| 1051 | 1058 | ||
| 1052 | if (!romfs) { | 1059 | if (!romfs) { |
| 1053 | auto current_romfs = fsc.OpenRomFSCurrentProcess(); | 1060 | auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); |
| 1054 | if (!current_romfs) { | 1061 | if (!current_romfs) { |
| 1055 | // TODO (bunnei): Find the right error code to use here | 1062 | // TODO (bunnei): Find the right error code to use here |
| 1056 | LOG_CRITICAL(Service_FS, "no file system interface available!"); | 1063 | LOG_CRITICAL(Service_FS, "no file system interface available!"); |
| @@ -1078,7 +1085,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { | |||
| 1078 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", | 1085 | LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", |
| 1079 | storage_id, unknown, title_id); | 1086 | storage_id, unknown, title_id); |
| 1080 | 1087 | ||
| 1081 | auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); | 1088 | auto data = romfs_controller->OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); |
| 1082 | 1089 | ||
| 1083 | if (!data) { | 1090 | if (!data) { |
| 1084 | const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); | 1091 | const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); |
| @@ -1101,7 +1108,8 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { | |||
| 1101 | 1108 | ||
| 1102 | const FileSys::PatchManager pm{title_id, fsc, content_provider}; | 1109 | const FileSys::PatchManager pm{title_id, fsc, content_provider}; |
| 1103 | 1110 | ||
| 1104 | auto base = fsc.OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data); | 1111 | auto base = |
| 1112 | romfs_controller->OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data); | ||
| 1105 | auto storage = std::make_shared<IStorage>( | 1113 | auto storage = std::make_shared<IStorage>( |
| 1106 | system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); | 1114 | system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); |
| 1107 | 1115 | ||
| @@ -1129,9 +1137,8 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { | |||
| 1129 | 1137 | ||
| 1130 | LOG_DEBUG(Service_FS, "called, program_index={}", program_index); | 1138 | LOG_DEBUG(Service_FS, "called, program_index={}", program_index); |
| 1131 | 1139 | ||
| 1132 | auto patched_romfs = | 1140 | auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( |
| 1133 | fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index, | 1141 | program_id, program_index, FileSys::ContentRecordType::Program); |
| 1134 | FileSys::ContentRecordType::Program); | ||
| 1135 | 1142 | ||
| 1136 | if (!patched_romfs) { | 1143 | if (!patched_romfs) { |
| 1137 | // TODO: Find the right error code to use here | 1144 | // TODO: Find the right error code to use here |
| @@ -1152,7 +1159,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { | |||
| 1152 | void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { | 1159 | void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { |
| 1153 | LOG_DEBUG(Service_FS, "called"); | 1160 | LOG_DEBUG(Service_FS, "called"); |
| 1154 | 1161 | ||
| 1155 | fsc.SetAutoSaveDataCreation(false); | 1162 | save_data_controller->SetAutoCreate(false); |
| 1156 | 1163 | ||
| 1157 | IPC::ResponseBuilder rb{ctx, 2}; | 1164 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1158 | rb.Push(ResultSuccess); | 1165 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 280bc9867..26980af99 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -17,6 +17,9 @@ class FileSystemBackend; | |||
| 17 | 17 | ||
| 18 | namespace Service::FileSystem { | 18 | namespace Service::FileSystem { |
| 19 | 19 | ||
| 20 | class RomFsController; | ||
| 21 | class SaveDataController; | ||
| 22 | |||
| 20 | enum class AccessLogVersion : u32 { | 23 | enum class AccessLogVersion : u32 { |
| 21 | V7_0_0 = 2, | 24 | V7_0_0 = 2, |
| 22 | 25 | ||
| @@ -67,6 +70,9 @@ private: | |||
| 67 | u64 current_process_id = 0; | 70 | u64 current_process_id = 0; |
| 68 | u32 access_log_program_index = 0; | 71 | u32 access_log_program_index = 0; |
| 69 | AccessLogMode access_log_mode = AccessLogMode::None; | 72 | AccessLogMode access_log_mode = AccessLogMode::None; |
| 73 | u64 program_id = 0; | ||
| 74 | std::shared_ptr<SaveDataController> save_data_controller; | ||
| 75 | std::shared_ptr<RomFsController> romfs_controller; | ||
| 70 | }; | 76 | }; |
| 71 | 77 | ||
| 72 | } // namespace Service::FileSystem | 78 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/romfs_controller.cpp b/src/core/hle/service/filesystem/romfs_controller.cpp new file mode 100644 index 000000000..19c9cec72 --- /dev/null +++ b/src/core/hle/service/filesystem/romfs_controller.cpp | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/filesystem/romfs_controller.h" | ||
| 5 | |||
| 6 | namespace Service::FileSystem { | ||
| 7 | |||
| 8 | RomFsController::RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_) | ||
| 9 | : factory{std::move(factory_)}, program_id{program_id_} {} | ||
| 10 | RomFsController::~RomFsController() = default; | ||
| 11 | |||
| 12 | FileSys::VirtualFile RomFsController::OpenRomFSCurrentProcess() { | ||
| 13 | return factory->OpenCurrentProcess(program_id); | ||
| 14 | } | ||
| 15 | |||
| 16 | FileSys::VirtualFile RomFsController::OpenPatchedRomFS(u64 title_id, | ||
| 17 | FileSys::ContentRecordType type) { | ||
| 18 | return factory->OpenPatchedRomFS(title_id, type); | ||
| 19 | } | ||
| 20 | |||
| 21 | FileSys::VirtualFile RomFsController::OpenPatchedRomFSWithProgramIndex( | ||
| 22 | u64 title_id, u8 program_index, FileSys::ContentRecordType type) { | ||
| 23 | return factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); | ||
| 24 | } | ||
| 25 | |||
| 26 | FileSys::VirtualFile RomFsController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 27 | FileSys::ContentRecordType type) { | ||
| 28 | return factory->Open(title_id, storage_id, type); | ||
| 29 | } | ||
| 30 | |||
| 31 | std::shared_ptr<FileSys::NCA> RomFsController::OpenBaseNca(u64 title_id, | ||
| 32 | FileSys::StorageId storage_id, | ||
| 33 | FileSys::ContentRecordType type) { | ||
| 34 | return factory->GetEntry(title_id, storage_id, type); | ||
| 35 | } | ||
| 36 | |||
| 37 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/filesystem/romfs_controller.h b/src/core/hle/service/filesystem/romfs_controller.h new file mode 100644 index 000000000..9a478f71d --- /dev/null +++ b/src/core/hle/service/filesystem/romfs_controller.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/romfs_factory.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | ||
| 9 | |||
| 10 | namespace Service::FileSystem { | ||
| 11 | |||
| 12 | class RomFsController { | ||
| 13 | public: | ||
| 14 | explicit RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_); | ||
| 15 | ~RomFsController(); | ||
| 16 | |||
| 17 | FileSys::VirtualFile OpenRomFSCurrentProcess(); | ||
| 18 | FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type); | ||
| 19 | FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index, | ||
| 20 | FileSys::ContentRecordType type); | ||
| 21 | FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 22 | FileSys::ContentRecordType type); | ||
| 23 | std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id, | ||
| 24 | FileSys::ContentRecordType type); | ||
| 25 | |||
| 26 | private: | ||
| 27 | const std::shared_ptr<FileSys::RomFSFactory> factory; | ||
| 28 | const u64 program_id; | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/filesystem/save_data_controller.cpp b/src/core/hle/service/filesystem/save_data_controller.cpp new file mode 100644 index 000000000..d19b3ea1e --- /dev/null +++ b/src/core/hle/service/filesystem/save_data_controller.cpp | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/core.h" | ||
| 5 | #include "core/file_sys/control_metadata.h" | ||
| 6 | #include "core/file_sys/errors.h" | ||
| 7 | #include "core/file_sys/patch_manager.h" | ||
| 8 | #include "core/hle/service/filesystem/save_data_controller.h" | ||
| 9 | #include "core/loader/loader.h" | ||
| 10 | |||
| 11 | namespace Service::FileSystem { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | // A default size for normal/journal save data size if application control metadata cannot be found. | ||
| 16 | // This should be large enough to satisfy even the most extreme requirements (~4.2GB) | ||
| 17 | constexpr u64 SufficientSaveDataSize = 0xF0000000; | ||
| 18 | |||
| 19 | FileSys::SaveDataSize GetDefaultSaveDataSize(Core::System& system, u64 program_id) { | ||
| 20 | const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), | ||
| 21 | system.GetContentProvider()}; | ||
| 22 | const auto metadata = pm.GetControlMetadata(); | ||
| 23 | const auto& nacp = metadata.first; | ||
| 24 | |||
| 25 | if (nacp != nullptr) { | ||
| 26 | return {nacp->GetDefaultNormalSaveSize(), nacp->GetDefaultJournalSaveSize()}; | ||
| 27 | } | ||
| 28 | |||
| 29 | return {SufficientSaveDataSize, SufficientSaveDataSize}; | ||
| 30 | } | ||
| 31 | |||
| 32 | } // namespace | ||
| 33 | |||
| 34 | SaveDataController::SaveDataController(Core::System& system_, | ||
| 35 | std::shared_ptr<FileSys::SaveDataFactory> factory_) | ||
| 36 | : system{system_}, factory{std::move(factory_)} {} | ||
| 37 | SaveDataController::~SaveDataController() = default; | ||
| 38 | |||
| 39 | Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data, | ||
| 40 | FileSys::SaveDataSpaceId space, | ||
| 41 | const FileSys::SaveDataAttribute& attribute) { | ||
| 42 | LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, | ||
| 43 | attribute.DebugInfo()); | ||
| 44 | |||
| 45 | auto save_data = factory->Create(space, attribute); | ||
| 46 | if (save_data == nullptr) { | ||
| 47 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 48 | } | ||
| 49 | |||
| 50 | *out_save_data = save_data; | ||
| 51 | return ResultSuccess; | ||
| 52 | } | ||
| 53 | |||
| 54 | Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data, | ||
| 55 | FileSys::SaveDataSpaceId space, | ||
| 56 | const FileSys::SaveDataAttribute& attribute) { | ||
| 57 | auto save_data = factory->Open(space, attribute); | ||
| 58 | if (save_data == nullptr) { | ||
| 59 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 60 | } | ||
| 61 | |||
| 62 | *out_save_data = save_data; | ||
| 63 | return ResultSuccess; | ||
| 64 | } | ||
| 65 | |||
| 66 | Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | ||
| 67 | FileSys::SaveDataSpaceId space) { | ||
| 68 | auto save_data_space = factory->GetSaveDataSpaceDirectory(space); | ||
| 69 | if (save_data_space == nullptr) { | ||
| 70 | return FileSys::ERROR_ENTITY_NOT_FOUND; | ||
| 71 | } | ||
| 72 | |||
| 73 | *out_save_data_space = save_data_space; | ||
| 74 | return ResultSuccess; | ||
| 75 | } | ||
| 76 | |||
| 77 | FileSys::SaveDataSize SaveDataController::ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, | ||
| 78 | u128 user_id) { | ||
| 79 | const auto value = factory->ReadSaveDataSize(type, title_id, user_id); | ||
| 80 | |||
| 81 | if (value.normal == 0 && value.journal == 0) { | ||
| 82 | const auto size = GetDefaultSaveDataSize(system, title_id); | ||
| 83 | factory->WriteSaveDataSize(type, title_id, user_id, size); | ||
| 84 | return size; | ||
| 85 | } | ||
| 86 | |||
| 87 | return value; | ||
| 88 | } | ||
| 89 | |||
| 90 | void SaveDataController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 91 | FileSys::SaveDataSize new_value) { | ||
| 92 | factory->WriteSaveDataSize(type, title_id, user_id, new_value); | ||
| 93 | } | ||
| 94 | |||
| 95 | void SaveDataController::SetAutoCreate(bool state) { | ||
| 96 | factory->SetAutoCreate(state); | ||
| 97 | } | ||
| 98 | |||
| 99 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/filesystem/save_data_controller.h b/src/core/hle/service/filesystem/save_data_controller.h new file mode 100644 index 000000000..863188e4c --- /dev/null +++ b/src/core/hle/service/filesystem/save_data_controller.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/file_sys/nca_metadata.h" | ||
| 7 | #include "core/file_sys/savedata_factory.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | ||
| 9 | |||
| 10 | namespace Service::FileSystem { | ||
| 11 | |||
| 12 | class SaveDataController { | ||
| 13 | public: | ||
| 14 | explicit SaveDataController(Core::System& system, | ||
| 15 | std::shared_ptr<FileSys::SaveDataFactory> factory_); | ||
| 16 | ~SaveDataController(); | ||
| 17 | |||
| 18 | Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 19 | const FileSys::SaveDataAttribute& attribute); | ||
| 20 | Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, | ||
| 21 | const FileSys::SaveDataAttribute& attribute); | ||
| 22 | Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, | ||
| 23 | FileSys::SaveDataSpaceId space); | ||
| 24 | |||
| 25 | FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); | ||
| 26 | void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 27 | FileSys::SaveDataSize new_value); | ||
| 28 | void SetAutoCreate(bool state); | ||
| 29 | |||
| 30 | private: | ||
| 31 | Core::System& system; | ||
| 32 | const std::shared_ptr<FileSys::SaveDataFactory> factory; | ||
| 33 | }; | ||
| 34 | |||
| 35 | } // namespace Service::FileSystem | ||
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index 6f1151b03..1254b6d49 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp | |||
| @@ -15,9 +15,10 @@ | |||
| 15 | namespace Service::Glue { | 15 | namespace Service::Glue { |
| 16 | 16 | ||
| 17 | namespace { | 17 | namespace { |
| 18 | std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) { | 18 | std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) { |
| 19 | const auto& list = system.Kernel().GetProcessList(); | 19 | auto list = system.Kernel().GetProcessList(); |
| 20 | const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) { | 20 | |
| 21 | const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) { | ||
| 21 | return process->GetProcessId() == process_id; | 22 | return process->GetProcessId() == process_id; |
| 22 | }); | 23 | }); |
| 23 | 24 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index fc03a0a5f..4ce0a9834 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -22,12 +22,10 @@ void LoopProcess(Core::System& system) { | |||
| 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = | 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = |
| 23 | std::make_shared<HidFirmwareSettings>(); | 23 | std::make_shared<HidFirmwareSettings>(); |
| 24 | 24 | ||
| 25 | // TODO: Remove this hack until this service is emulated properly. | 25 | // TODO: Remove this hack when am is emulated properly. |
| 26 | const auto process_list = system.Kernel().GetProcessList(); | 26 | resource_manager->Initialize(); |
| 27 | if (!process_list.empty()) { | 27 | resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), |
| 28 | resource_manager->Initialize(); | 28 | true); |
| 29 | resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); | ||
| 30 | } | ||
| 31 | 29 | ||
| 32 | server_manager->RegisterNamedService( | 30 | server_manager->RegisterNamedService( |
| 33 | "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); | 31 | "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index d92499f05..b52468e41 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -22,27 +22,26 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1}; | |||
| 22 | 22 | ||
| 23 | constexpr u64 NO_PROCESS_FOUND_PID{0}; | 23 | constexpr u64 NO_PROCESS_FOUND_PID{0}; |
| 24 | 24 | ||
| 25 | std::optional<Kernel::KProcess*> SearchProcessList( | 25 | using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>; |
| 26 | const std::vector<Kernel::KProcess*>& process_list, | 26 | |
| 27 | std::function<bool(Kernel::KProcess*)> predicate) { | 27 | template <typename F> |
| 28 | Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list, | ||
| 29 | F&& predicate) { | ||
| 28 | const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); | 30 | const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); |
| 29 | 31 | ||
| 30 | if (iter == process_list.end()) { | 32 | if (iter == process_list.end()) { |
| 31 | return std::nullopt; | 33 | return nullptr; |
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | return *iter; | 36 | return iter->GetPointerUnsafe(); |
| 35 | } | 37 | } |
| 36 | 38 | ||
| 37 | void GetApplicationPidGeneric(HLERequestContext& ctx, | 39 | void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) { |
| 38 | const std::vector<Kernel::KProcess*>& process_list) { | 40 | auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); }); |
| 39 | const auto process = SearchProcessList(process_list, [](const auto& proc) { | ||
| 40 | return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; | ||
| 41 | }); | ||
| 42 | 41 | ||
| 43 | IPC::ResponseBuilder rb{ctx, 4}; | 42 | IPC::ResponseBuilder rb{ctx, 4}; |
| 44 | rb.Push(ResultSuccess); | 43 | rb.Push(ResultSuccess); |
| 45 | rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID); | 44 | rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId()); |
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | } // Anonymous namespace | 47 | } // Anonymous namespace |
| @@ -80,8 +79,7 @@ private: | |||
| 80 | 79 | ||
| 81 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { | 80 | class DebugMonitor final : public ServiceFramework<DebugMonitor> { |
| 82 | public: | 81 | public: |
| 83 | explicit DebugMonitor(Core::System& system_) | 82 | explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} { |
| 84 | : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} { | ||
| 85 | // clang-format off | 83 | // clang-format off |
| 86 | static const FunctionInfo functions[] = { | 84 | static const FunctionInfo functions[] = { |
| 87 | {0, nullptr, "GetJitDebugProcessIdList"}, | 85 | {0, nullptr, "GetJitDebugProcessIdList"}, |
| @@ -106,12 +104,11 @@ private: | |||
| 106 | 104 | ||
| 107 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | 105 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |
| 108 | 106 | ||
| 109 | const auto process = | 107 | auto list = kernel.GetProcessList(); |
| 110 | SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { | 108 | auto process = SearchProcessList( |
| 111 | return proc->GetProgramId() == program_id; | 109 | list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); |
| 112 | }); | ||
| 113 | 110 | ||
| 114 | if (!process.has_value()) { | 111 | if (process.IsNull()) { |
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 112 | IPC::ResponseBuilder rb{ctx, 2}; |
| 116 | rb.Push(ResultProcessNotFound); | 113 | rb.Push(ResultProcessNotFound); |
| 117 | return; | 114 | return; |
| @@ -119,12 +116,13 @@ private: | |||
| 119 | 116 | ||
| 120 | IPC::ResponseBuilder rb{ctx, 4}; | 117 | IPC::ResponseBuilder rb{ctx, 4}; |
| 121 | rb.Push(ResultSuccess); | 118 | rb.Push(ResultSuccess); |
| 122 | rb.Push((*process)->GetProcessId()); | 119 | rb.Push(process->GetProcessId()); |
| 123 | } | 120 | } |
| 124 | 121 | ||
| 125 | void GetApplicationProcessId(HLERequestContext& ctx) { | 122 | void GetApplicationProcessId(HLERequestContext& ctx) { |
| 126 | LOG_DEBUG(Service_PM, "called"); | 123 | LOG_DEBUG(Service_PM, "called"); |
| 127 | GetApplicationPidGeneric(ctx, kernel.GetProcessList()); | 124 | auto list = kernel.GetProcessList(); |
| 125 | GetApplicationPidGeneric(ctx, list); | ||
| 128 | } | 126 | } |
| 129 | 127 | ||
| 130 | void AtmosphereGetProcessInfo(HLERequestContext& ctx) { | 128 | void AtmosphereGetProcessInfo(HLERequestContext& ctx) { |
| @@ -135,11 +133,10 @@ private: | |||
| 135 | 133 | ||
| 136 | LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); | 134 | LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); |
| 137 | 135 | ||
| 138 | const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) { | 136 | auto list = kernel.GetProcessList(); |
| 139 | return proc->GetProcessId() == pid; | 137 | auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; }); |
| 140 | }); | ||
| 141 | 138 | ||
| 142 | if (!process.has_value()) { | 139 | if (process.IsNull()) { |
| 143 | IPC::ResponseBuilder rb{ctx, 2}; | 140 | IPC::ResponseBuilder rb{ctx, 2}; |
| 144 | rb.Push(ResultProcessNotFound); | 141 | rb.Push(ResultProcessNotFound); |
| 145 | return; | 142 | return; |
| @@ -159,7 +156,7 @@ private: | |||
| 159 | 156 | ||
| 160 | OverrideStatus override_status{}; | 157 | OverrideStatus override_status{}; |
| 161 | ProgramLocation program_location{ | 158 | ProgramLocation program_location{ |
| 162 | .program_id = (*process)->GetProgramId(), | 159 | .program_id = process->GetProgramId(), |
| 163 | .storage_id = 0, | 160 | .storage_id = 0, |
| 164 | }; | 161 | }; |
| 165 | 162 | ||
| @@ -169,14 +166,11 @@ private: | |||
| 169 | rb.PushRaw(program_location); | 166 | rb.PushRaw(program_location); |
| 170 | rb.PushRaw(override_status); | 167 | rb.PushRaw(override_status); |
| 171 | } | 168 | } |
| 172 | |||
| 173 | const Kernel::KernelCore& kernel; | ||
| 174 | }; | 169 | }; |
| 175 | 170 | ||
| 176 | class Info final : public ServiceFramework<Info> { | 171 | class Info final : public ServiceFramework<Info> { |
| 177 | public: | 172 | public: |
| 178 | explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) | 173 | explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} { |
| 179 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { | ||
| 180 | static const FunctionInfo functions[] = { | 174 | static const FunctionInfo functions[] = { |
| 181 | {0, &Info::GetProgramId, "GetProgramId"}, | 175 | {0, &Info::GetProgramId, "GetProgramId"}, |
| 182 | {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, | 176 | {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, |
| @@ -193,11 +187,11 @@ private: | |||
| 193 | 187 | ||
| 194 | LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); | 188 | LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); |
| 195 | 189 | ||
| 196 | const auto process = SearchProcessList(process_list, [process_id](const auto& proc) { | 190 | auto list = kernel.GetProcessList(); |
| 197 | return proc->GetProcessId() == process_id; | 191 | auto process = SearchProcessList( |
| 198 | }); | 192 | list, [process_id](auto& p) { return p->GetProcessId() == process_id; }); |
| 199 | 193 | ||
| 200 | if (!process.has_value()) { | 194 | if (process.IsNull()) { |
| 201 | IPC::ResponseBuilder rb{ctx, 2}; | 195 | IPC::ResponseBuilder rb{ctx, 2}; |
| 202 | rb.Push(ResultProcessNotFound); | 196 | rb.Push(ResultProcessNotFound); |
| 203 | return; | 197 | return; |
| @@ -205,7 +199,7 @@ private: | |||
| 205 | 199 | ||
| 206 | IPC::ResponseBuilder rb{ctx, 4}; | 200 | IPC::ResponseBuilder rb{ctx, 4}; |
| 207 | rb.Push(ResultSuccess); | 201 | rb.Push(ResultSuccess); |
| 208 | rb.Push((*process)->GetProgramId()); | 202 | rb.Push(process->GetProgramId()); |
| 209 | } | 203 | } |
| 210 | 204 | ||
| 211 | void AtmosphereGetProcessId(HLERequestContext& ctx) { | 205 | void AtmosphereGetProcessId(HLERequestContext& ctx) { |
| @@ -214,11 +208,11 @@ private: | |||
| 214 | 208 | ||
| 215 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | 209 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |
| 216 | 210 | ||
| 217 | const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { | 211 | auto list = system.Kernel().GetProcessList(); |
| 218 | return proc->GetProgramId() == program_id; | 212 | auto process = SearchProcessList( |
| 219 | }); | 213 | list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); |
| 220 | 214 | ||
| 221 | if (!process.has_value()) { | 215 | if (process.IsNull()) { |
| 222 | IPC::ResponseBuilder rb{ctx, 2}; | 216 | IPC::ResponseBuilder rb{ctx, 2}; |
| 223 | rb.Push(ResultProcessNotFound); | 217 | rb.Push(ResultProcessNotFound); |
| 224 | return; | 218 | return; |
| @@ -226,16 +220,13 @@ private: | |||
| 226 | 220 | ||
| 227 | IPC::ResponseBuilder rb{ctx, 4}; | 221 | IPC::ResponseBuilder rb{ctx, 4}; |
| 228 | rb.Push(ResultSuccess); | 222 | rb.Push(ResultSuccess); |
| 229 | rb.Push((*process)->GetProcessId()); | 223 | rb.Push(process->GetProcessId()); |
| 230 | } | 224 | } |
| 231 | |||
| 232 | const std::vector<Kernel::KProcess*>& process_list; | ||
| 233 | }; | 225 | }; |
| 234 | 226 | ||
| 235 | class Shell final : public ServiceFramework<Shell> { | 227 | class Shell final : public ServiceFramework<Shell> { |
| 236 | public: | 228 | public: |
| 237 | explicit Shell(Core::System& system_) | 229 | explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} { |
| 238 | : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} { | ||
| 239 | // clang-format off | 230 | // clang-format off |
| 240 | static const FunctionInfo functions[] = { | 231 | static const FunctionInfo functions[] = { |
| 241 | {0, nullptr, "LaunchProgram"}, | 232 | {0, nullptr, "LaunchProgram"}, |
| @@ -257,10 +248,9 @@ public: | |||
| 257 | private: | 248 | private: |
| 258 | void GetApplicationProcessIdForShell(HLERequestContext& ctx) { | 249 | void GetApplicationProcessIdForShell(HLERequestContext& ctx) { |
| 259 | LOG_DEBUG(Service_PM, "called"); | 250 | LOG_DEBUG(Service_PM, "called"); |
| 260 | GetApplicationPidGeneric(ctx, kernel.GetProcessList()); | 251 | auto list = kernel.GetProcessList(); |
| 252 | GetApplicationPidGeneric(ctx, list); | ||
| 261 | } | 253 | } |
| 262 | |||
| 263 | const Kernel::KernelCore& kernel; | ||
| 264 | }; | 254 | }; |
| 265 | 255 | ||
| 266 | void LoopProcess(Core::System& system) { | 256 | void LoopProcess(Core::System& system) { |
| @@ -268,8 +258,7 @@ void LoopProcess(Core::System& system) { | |||
| 268 | 258 | ||
| 269 | server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); | 259 | server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); |
| 270 | server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); | 260 | server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); |
| 271 | server_manager->RegisterNamedService( | 261 | server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system)); |
| 272 | "pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList())); | ||
| 273 | server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); | 262 | server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); |
| 274 | ServerManager::RunServer(std::move(server_manager)); | 263 | ServerManager::RunServer(std::move(server_manager)); |
| 275 | } | 264 | } |
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 15edb23e0..8ef49387d 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp | |||
| @@ -256,8 +256,13 @@ Result ServerManager::WaitAndProcessImpl() { | |||
| 256 | 256 | ||
| 257 | // Wait for a signal. | 257 | // Wait for a signal. |
| 258 | s32 out_index{-1}; | 258 | s32 out_index{-1}; |
| 259 | R_TRY(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), | 259 | R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, |
| 260 | num_objs, -1)); | 260 | wait_objs.data(), num_objs, -1)) { |
| 261 | R_CATCH(Kernel::ResultSessionClosed) { | ||
| 262 | // On session closed, index is updated and we don't want to return an error. | ||
| 263 | } | ||
| 264 | } | ||
| 265 | R_END_TRY_CATCH; | ||
| 261 | ASSERT(out_index >= 0 && out_index < num_objs); | 266 | ASSERT(out_index >= 0 && out_index < num_objs); |
| 262 | 267 | ||
| 263 | // Set the output index. | 268 | // Set the output index. |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index c9f8707b7..9b75c660c 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -19,8 +19,54 @@ | |||
| 19 | #include "core/arm/nce/patcher.h" | 19 | #include "core/arm/nce/patcher.h" |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #ifndef HAS_NCE | ||
| 23 | namespace Core::NCE { | ||
| 24 | class Patcher {}; | ||
| 25 | } // namespace Core::NCE | ||
| 26 | #endif | ||
| 27 | |||
| 22 | namespace Loader { | 28 | namespace Loader { |
| 23 | 29 | ||
| 30 | struct PatchCollection { | ||
| 31 | explicit PatchCollection(bool is_application_) : is_application{is_application_} { | ||
| 32 | module_patcher_indices.fill(-1); | ||
| 33 | patchers.emplace_back(); | ||
| 34 | } | ||
| 35 | |||
| 36 | std::vector<Core::NCE::Patcher>* GetPatchers() { | ||
| 37 | if (is_application && Settings::IsNceEnabled()) { | ||
| 38 | return &patchers; | ||
| 39 | } | ||
| 40 | return nullptr; | ||
| 41 | } | ||
| 42 | |||
| 43 | size_t GetTotalPatchSize() const { | ||
| 44 | size_t total_size{}; | ||
| 45 | #ifdef HAS_NCE | ||
| 46 | for (auto& patcher : patchers) { | ||
| 47 | total_size += patcher.GetSectionSize(); | ||
| 48 | } | ||
| 49 | #endif | ||
| 50 | return total_size; | ||
| 51 | } | ||
| 52 | |||
| 53 | void SaveIndex(size_t module) { | ||
| 54 | module_patcher_indices[module] = static_cast<s32>(patchers.size() - 1); | ||
| 55 | } | ||
| 56 | |||
| 57 | s32 GetIndex(size_t module) const { | ||
| 58 | return module_patcher_indices[module]; | ||
| 59 | } | ||
| 60 | |||
| 61 | s32 GetLastIndex() const { | ||
| 62 | return static_cast<s32>(patchers.size()) - 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | bool is_application; | ||
| 66 | std::vector<Core::NCE::Patcher> patchers; | ||
| 67 | std::array<s32, 13> module_patcher_indices{}; | ||
| 68 | }; | ||
| 69 | |||
| 24 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, | 70 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, |
| 25 | bool override_update_) | 71 | bool override_update_) |
| 26 | : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) { | 72 | : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) { |
| @@ -142,18 +188,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 142 | std::size_t code_size{}; | 188 | std::size_t code_size{}; |
| 143 | 189 | ||
| 144 | // Define an nce patch context for each potential module. | 190 | // Define an nce patch context for each potential module. |
| 145 | #ifdef HAS_NCE | 191 | PatchCollection patch_ctx{is_application}; |
| 146 | std::array<Core::NCE::Patcher, 13> module_patchers; | ||
| 147 | #endif | ||
| 148 | |||
| 149 | const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { | ||
| 150 | #ifdef HAS_NCE | ||
| 151 | if (is_application && Settings::IsNceEnabled()) { | ||
| 152 | return &module_patchers[i]; | ||
| 153 | } | ||
| 154 | #endif | ||
| 155 | return nullptr; | ||
| 156 | }; | ||
| 157 | 192 | ||
| 158 | // Use the NSO module loader to figure out the code layout | 193 | // Use the NSO module loader to figure out the code layout |
| 159 | for (size_t i = 0; i < static_modules.size(); i++) { | 194 | for (size_t i = 0; i < static_modules.size(); i++) { |
| @@ -164,13 +199,14 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 164 | } | 199 | } |
| 165 | 200 | ||
| 166 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 201 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 167 | const auto tentative_next_load_addr = | 202 | const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( |
| 168 | AppLoader_NSO::LoadModule(process, system, *module_file, code_size, | 203 | process, system, *module_file, code_size, should_pass_arguments, false, {}, |
| 169 | should_pass_arguments, false, {}, GetPatcher(i)); | 204 | patch_ctx.GetPatchers(), patch_ctx.GetLastIndex()); |
| 170 | if (!tentative_next_load_addr) { | 205 | if (!tentative_next_load_addr) { |
| 171 | return {ResultStatus::ErrorLoadingNSO, {}}; | 206 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 172 | } | 207 | } |
| 173 | 208 | ||
| 209 | patch_ctx.SaveIndex(i); | ||
| 174 | code_size = *tentative_next_load_addr; | 210 | code_size = *tentative_next_load_addr; |
| 175 | } | 211 | } |
| 176 | 212 | ||
| @@ -184,6 +220,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 184 | return 0; | 220 | return 0; |
| 185 | }(); | 221 | }(); |
| 186 | 222 | ||
| 223 | // Add patch size to the total module size | ||
| 224 | code_size += patch_ctx.GetTotalPatchSize(); | ||
| 225 | |||
| 187 | // Setup the process code layout | 226 | // Setup the process code layout |
| 188 | if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) { | 227 | if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) { |
| 189 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; | 228 | return {ResultStatus::ErrorUnableToParseKernelMetadata, {}}; |
| @@ -204,9 +243,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 204 | 243 | ||
| 205 | const VAddr load_addr{next_load_addr}; | 244 | const VAddr load_addr{next_load_addr}; |
| 206 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; | 245 | const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; |
| 207 | const auto tentative_next_load_addr = | 246 | const auto tentative_next_load_addr = AppLoader_NSO::LoadModule( |
| 208 | AppLoader_NSO::LoadModule(process, system, *module_file, load_addr, | 247 | process, system, *module_file, load_addr, should_pass_arguments, true, pm, |
| 209 | should_pass_arguments, true, pm, GetPatcher(i)); | 248 | patch_ctx.GetPatchers(), patch_ctx.GetIndex(i)); |
| 210 | if (!tentative_next_load_addr) { | 249 | if (!tentative_next_load_addr) { |
| 211 | return {ResultStatus::ErrorLoadingNSO, {}}; | 250 | return {ResultStatus::ErrorLoadingNSO, {}}; |
| 212 | } | 251 | } |
| @@ -216,20 +255,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect | |||
| 216 | LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr); | 255 | LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr); |
| 217 | } | 256 | } |
| 218 | 257 | ||
| 219 | // Find the RomFS by searching for a ".romfs" file in this directory | ||
| 220 | const auto& files = dir->GetFiles(); | ||
| 221 | const auto romfs_iter = | ||
| 222 | std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) { | ||
| 223 | return f->GetName().find(".romfs") != std::string::npos; | ||
| 224 | }); | ||
| 225 | |||
| 226 | // Register the RomFS if a ".romfs" file was found | ||
| 227 | if (romfs_iter != files.end() && *romfs_iter != nullptr) { | ||
| 228 | romfs = *romfs_iter; | ||
| 229 | system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( | ||
| 230 | *this, system.GetContentProvider(), system.GetFileSystemController())); | ||
| 231 | } | ||
| 232 | |||
| 233 | is_loaded = true; | 258 | is_loaded = true; |
| 234 | return {ResultStatus::Success, | 259 | return {ResultStatus::Success, |
| 235 | LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}}; | 260 | LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}}; |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 814407535..2a32b1276 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -74,8 +74,10 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S | |||
| 74 | return load_result; | 74 | return load_result; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( | 77 | system.GetFileSystemController().RegisterProcess( |
| 78 | *this, system.GetContentProvider(), system.GetFileSystemController())); | 78 | process.GetProcessId(), nca->GetTitleId(), |
| 79 | std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(), | ||
| 80 | system.GetFileSystemController())); | ||
| 79 | 81 | ||
| 80 | is_loaded = true; | 82 | is_loaded = true; |
| 81 | return load_result; | 83 | return load_result; |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index e74697cda..f8225d697 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -275,10 +275,12 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S | |||
| 275 | return {ResultStatus::ErrorLoadingNRO, {}}; | 275 | return {ResultStatus::ErrorLoadingNRO, {}}; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | if (romfs != nullptr) { | 278 | u64 program_id{}; |
| 279 | system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( | 279 | ReadProgramId(program_id); |
| 280 | *this, system.GetContentProvider(), system.GetFileSystemController())); | 280 | system.GetFileSystemController().RegisterProcess( |
| 281 | } | 281 | process.GetProcessId(), program_id, |
| 282 | std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(), | ||
| 283 | system.GetFileSystemController())); | ||
| 282 | 284 | ||
| 283 | is_loaded = true; | 285 | is_loaded = true; |
| 284 | return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, | 286 | return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index b053a0d14..583b7e927 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -77,7 +77,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 77 | const FileSys::VfsFile& nso_file, VAddr load_base, | 77 | const FileSys::VfsFile& nso_file, VAddr load_base, |
| 78 | bool should_pass_arguments, bool load_into_process, | 78 | bool should_pass_arguments, bool load_into_process, |
| 79 | std::optional<FileSys::PatchManager> pm, | 79 | std::optional<FileSys::PatchManager> pm, |
| 80 | Core::NCE::Patcher* patch) { | 80 | std::vector<Core::NCE::Patcher>* patches, |
| 81 | s32 patch_index) { | ||
| 81 | if (nso_file.GetSize() < sizeof(NSOHeader)) { | 82 | if (nso_file.GetSize() < sizeof(NSOHeader)) { |
| 82 | return std::nullopt; | 83 | return std::nullopt; |
| 83 | } | 84 | } |
| @@ -94,8 +95,11 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 94 | // Allocate some space at the beginning if we are patching in PreText mode. | 95 | // Allocate some space at the beginning if we are patching in PreText mode. |
| 95 | const size_t module_start = [&]() -> size_t { | 96 | const size_t module_start = [&]() -> size_t { |
| 96 | #ifdef HAS_NCE | 97 | #ifdef HAS_NCE |
| 97 | if (patch && patch->GetPatchMode() == Core::NCE::PatchMode::PreText) { | 98 | if (patches && load_into_process) { |
| 98 | return patch->GetSectionSize(); | 99 | auto* patch = &patches->operator[](patch_index); |
| 100 | if (patch->GetPatchMode() == Core::NCE::PatchMode::PreText) { | ||
| 101 | return patch->GetSectionSize(); | ||
| 102 | } | ||
| 99 | } | 103 | } |
| 100 | #endif | 104 | #endif |
| 101 | return 0; | 105 | return 0; |
| @@ -160,27 +164,24 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core:: | |||
| 160 | #ifdef HAS_NCE | 164 | #ifdef HAS_NCE |
| 161 | // If we are computing the process code layout and using nce backend, patch. | 165 | // If we are computing the process code layout and using nce backend, patch. |
| 162 | const auto& code = codeset.CodeSegment(); | 166 | const auto& code = codeset.CodeSegment(); |
| 163 | if (patch && patch->GetPatchMode() == Core::NCE::PatchMode::None) { | 167 | auto* patch = patches ? &patches->operator[](patch_index) : nullptr; |
| 168 | if (patch && !load_into_process) { | ||
| 164 | // Patch SVCs and MRS calls in the guest code | 169 | // Patch SVCs and MRS calls in the guest code |
| 165 | patch->PatchText(program_image, code); | 170 | while (!patch->PatchText(program_image, code)) { |
| 166 | 171 | patch = &patches->emplace_back(); | |
| 167 | // Add patch section size to the module size. | 172 | } |
| 168 | image_size += static_cast<u32>(patch->GetSectionSize()); | ||
| 169 | } else if (patch) { | 173 | } else if (patch) { |
| 170 | // Relocate code patch and copy to the program_image. | 174 | // Relocate code patch and copy to the program_image. |
| 171 | patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers()); | 175 | if (patch->RelocateAndCopy(load_base, code, program_image, &process.GetPostHandlers())) { |
| 172 | 176 | // Update patch section. | |
| 173 | // Update patch section. | 177 | auto& patch_segment = codeset.PatchSegment(); |
| 174 | auto& patch_segment = codeset.PatchSegment(); | 178 | patch_segment.addr = |
| 175 | patch_segment.addr = | 179 | patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size; |
| 176 | patch->GetPatchMode() == Core::NCE::PatchMode::PreText ? 0 : image_size; | 180 | patch_segment.size = static_cast<u32>(patch->GetSectionSize()); |
| 177 | patch_segment.size = static_cast<u32>(patch->GetSectionSize()); | ||
| 178 | |||
| 179 | // Add patch section size to the module size. In PreText mode image_size | ||
| 180 | // already contains the patch segment as part of module_start. | ||
| 181 | if (patch->GetPatchMode() == Core::NCE::PatchMode::PostData) { | ||
| 182 | image_size += patch_segment.size; | ||
| 183 | } | 181 | } |
| 182 | |||
| 183 | // Refresh image_size to take account the patch section if it was added by RelocateAndCopy | ||
| 184 | image_size = static_cast<u32>(program_image.size()); | ||
| 184 | } | 185 | } |
| 185 | #endif | 186 | #endif |
| 186 | 187 | ||
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 29b86ed4c..6356697e3 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -93,7 +93,8 @@ public: | |||
| 93 | const FileSys::VfsFile& nso_file, VAddr load_base, | 93 | const FileSys::VfsFile& nso_file, VAddr load_base, |
| 94 | bool should_pass_arguments, bool load_into_process, | 94 | bool should_pass_arguments, bool load_into_process, |
| 95 | std::optional<FileSys::PatchManager> pm = {}, | 95 | std::optional<FileSys::PatchManager> pm = {}, |
| 96 | Core::NCE::Patcher* patch = nullptr); | 96 | std::vector<Core::NCE::Patcher>* patches = nullptr, |
| 97 | s32 patch_index = -1); | ||
| 97 | 98 | ||
| 98 | LoadResult Load(Kernel::KProcess& process, Core::System& system) override; | 99 | LoadResult Load(Kernel::KProcess& process, Core::System& system) override; |
| 99 | 100 | ||
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index f4ab75b77..28116ff3a 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -111,7 +111,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S | |||
| 111 | 111 | ||
| 112 | FileSys::VirtualFile update_raw; | 112 | FileSys::VirtualFile update_raw; |
| 113 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { | 113 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { |
| 114 | system.GetFileSystemController().SetPackedUpdate(std::move(update_raw)); | 114 | system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(), |
| 115 | std::move(update_raw)); | ||
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | is_loaded = true; | 118 | is_loaded = true; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 12d72c380..e9abb199a 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -78,7 +78,8 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::S | |||
| 78 | 78 | ||
| 79 | FileSys::VirtualFile update_raw; | 79 | FileSys::VirtualFile update_raw; |
| 80 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { | 80 | if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { |
| 81 | system.GetFileSystemController().SetPackedUpdate(std::move(update_raw)); | 81 | system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(), |
| 82 | std::move(update_raw)); | ||
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | is_loaded = true; | 85 | is_loaded = true; |