diff options
Diffstat (limited to 'src')
80 files changed, 1102 insertions, 575 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 521b19ff7..6f0ff953a 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -79,7 +79,7 @@ u32 AudioRenderer::GetMixBufferCount() const { | |||
| 79 | return worker_params.mix_buffer_count; | 79 | return worker_params.mix_buffer_count; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | u32 AudioRenderer::GetState() const { | 82 | Stream::State AudioRenderer::GetStreamState() const { |
| 83 | return stream->GetState(); | 83 | return stream->GetState(); |
| 84 | } | 84 | } |
| 85 | 85 | ||
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index be923ee65..dfef89e1d 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h | |||
| @@ -170,7 +170,7 @@ public: | |||
| 170 | u32 GetSampleRate() const; | 170 | u32 GetSampleRate() const; |
| 171 | u32 GetSampleCount() const; | 171 | u32 GetSampleCount() const; |
| 172 | u32 GetMixBufferCount() const; | 172 | u32 GetMixBufferCount() const; |
| 173 | u32 GetState() const; | 173 | Stream::State GetStreamState() const; |
| 174 | 174 | ||
| 175 | private: | 175 | private: |
| 176 | class VoiceState; | 176 | class VoiceState; |
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index ee4aa98af..742a5e0a0 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -53,8 +53,8 @@ void Stream::Stop() { | |||
| 53 | ASSERT_MSG(false, "Unimplemented"); | 53 | ASSERT_MSG(false, "Unimplemented"); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | u32 Stream::GetState() const { | 56 | Stream::State Stream::GetState() const { |
| 57 | return static_cast<u32>(state); | 57 | return state; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { | 60 | s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { |
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 43eca74e1..aebfeb51d 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h | |||
| @@ -33,6 +33,12 @@ public: | |||
| 33 | Multi51Channel16, | 33 | Multi51Channel16, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | /// Current state of the stream | ||
| 37 | enum class State { | ||
| 38 | Stopped, | ||
| 39 | Playing, | ||
| 40 | }; | ||
| 41 | |||
| 36 | /// Callback function type, used to change guest state on a buffer being released | 42 | /// Callback function type, used to change guest state on a buffer being released |
| 37 | using ReleaseCallback = std::function<void()>; | 43 | using ReleaseCallback = std::function<void()>; |
| 38 | 44 | ||
| @@ -73,15 +79,9 @@ public: | |||
| 73 | u32 GetNumChannels() const; | 79 | u32 GetNumChannels() const; |
| 74 | 80 | ||
| 75 | /// Get the state | 81 | /// Get the state |
| 76 | u32 GetState() const; | 82 | State GetState() const; |
| 77 | 83 | ||
| 78 | private: | 84 | private: |
| 79 | /// Current state of the stream | ||
| 80 | enum class State { | ||
| 81 | Stopped, | ||
| 82 | Playing, | ||
| 83 | }; | ||
| 84 | |||
| 85 | /// Plays the next queued buffer in the audio stream, starting playback if necessary | 85 | /// Plays the next queued buffer in the audio stream, starting playback if necessary |
| 86 | void PlayNextBuffer(); | 86 | void PlayNextBuffer(); |
| 87 | 87 | ||
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 16d528994..59da33f30 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -22,10 +22,16 @@ public: | |||
| 22 | std::array<u64, 31> cpu_registers; | 22 | std::array<u64, 31> cpu_registers; |
| 23 | u64 sp; | 23 | u64 sp; |
| 24 | u64 pc; | 24 | u64 pc; |
| 25 | u64 pstate; | 25 | u32 pstate; |
| 26 | std::array<u8, 4> padding; | ||
| 26 | std::array<u128, 32> vector_registers; | 27 | std::array<u128, 32> vector_registers; |
| 27 | u64 fpcr; | 28 | u32 fpcr; |
| 29 | u32 fpsr; | ||
| 30 | u64 tpidr; | ||
| 28 | }; | 31 | }; |
| 32 | // Internally within the kernel, it expects the AArch64 version of the | ||
| 33 | // thread context to be 800 bytes in size. | ||
| 34 | static_assert(sizeof(ThreadContext) == 0x320); | ||
| 29 | 35 | ||
| 30 | /// Runs the CPU until an event happens | 36 | /// Runs the CPU until an event happens |
| 31 | virtual void Run() = 0; | 37 | virtual void Run() = 0; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 7be5a38de..05cc84458 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -129,7 +129,8 @@ public: | |||
| 129 | }; | 129 | }; |
| 130 | 130 | ||
| 131 | std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { | 131 | std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { |
| 132 | auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data(); | 132 | auto& current_process = Core::CurrentProcess(); |
| 133 | auto** const page_table = current_process->VMManager().page_table.pointers.data(); | ||
| 133 | 134 | ||
| 134 | Dynarmic::A64::UserConfig config; | 135 | Dynarmic::A64::UserConfig config; |
| 135 | 136 | ||
| @@ -138,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { | |||
| 138 | 139 | ||
| 139 | // Memory | 140 | // Memory |
| 140 | config.page_table = reinterpret_cast<void**>(page_table); | 141 | config.page_table = reinterpret_cast<void**>(page_table); |
| 141 | config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS; | 142 | config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth(); |
| 142 | config.silently_mirror_page_table = false; | 143 | config.silently_mirror_page_table = false; |
| 143 | 144 | ||
| 144 | // Multi-process state | 145 | // Multi-process state |
| @@ -174,7 +175,7 @@ ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, | |||
| 174 | std::size_t core_index) | 175 | std::size_t core_index) |
| 175 | : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, | 176 | : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, |
| 176 | exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { | 177 | exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { |
| 177 | ThreadContext ctx; | 178 | ThreadContext ctx{}; |
| 178 | inner_unicorn.SaveContext(ctx); | 179 | inner_unicorn.SaveContext(ctx); |
| 179 | PageTableChanged(); | 180 | PageTableChanged(); |
| 180 | LoadContext(ctx); | 181 | LoadContext(ctx); |
| @@ -246,15 +247,19 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) { | |||
| 246 | ctx.pstate = jit->GetPstate(); | 247 | ctx.pstate = jit->GetPstate(); |
| 247 | ctx.vector_registers = jit->GetVectors(); | 248 | ctx.vector_registers = jit->GetVectors(); |
| 248 | ctx.fpcr = jit->GetFpcr(); | 249 | ctx.fpcr = jit->GetFpcr(); |
| 250 | ctx.fpsr = jit->GetFpsr(); | ||
| 251 | ctx.tpidr = cb->tpidr_el0; | ||
| 249 | } | 252 | } |
| 250 | 253 | ||
| 251 | void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { | 254 | void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { |
| 252 | jit->SetRegisters(ctx.cpu_registers); | 255 | jit->SetRegisters(ctx.cpu_registers); |
| 253 | jit->SetSP(ctx.sp); | 256 | jit->SetSP(ctx.sp); |
| 254 | jit->SetPC(ctx.pc); | 257 | jit->SetPC(ctx.pc); |
| 255 | jit->SetPstate(static_cast<u32>(ctx.pstate)); | 258 | jit->SetPstate(ctx.pstate); |
| 256 | jit->SetVectors(ctx.vector_registers); | 259 | jit->SetVectors(ctx.vector_registers); |
| 257 | jit->SetFpcr(static_cast<u32>(ctx.fpcr)); | 260 | jit->SetFpcr(ctx.fpcr); |
| 261 | jit->SetFpsr(ctx.fpsr); | ||
| 262 | SetTPIDR_EL0(ctx.tpidr); | ||
| 258 | } | 263 | } |
| 259 | 264 | ||
| 260 | void ARM_Dynarmic::PrepareReschedule() { | 265 | void ARM_Dynarmic::PrepareReschedule() { |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 50f0a42fb..b6acfb3e4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -64,7 +64,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 64 | if (concat.empty()) | 64 | if (concat.empty()) |
| 65 | return nullptr; | 65 | return nullptr; |
| 66 | 66 | ||
| 67 | return FileSys::ConcatenateFiles(concat, dir->GetName()); | 67 | return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName()); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | return vfs->OpenFile(path, FileSys::Mode::Read); | 70 | return vfs->OpenFile(path, FileSys::Mode::Read); |
| @@ -202,7 +202,7 @@ struct System::Impl { | |||
| 202 | return init_result; | 202 | return init_result; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | const Loader::ResultStatus load_result{app_loader->Load(kernel.CurrentProcess())}; | 205 | const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())}; |
| 206 | if (load_result != Loader::ResultStatus::Success) { | 206 | if (load_result != Loader::ResultStatus::Success) { |
| 207 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); | 207 | LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); |
| 208 | Shutdown(); | 208 | Shutdown(); |
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 21568ad50..265f8ed9c 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp | |||
| @@ -55,16 +55,16 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, | |||
| 55 | 55 | ||
| 56 | if (Settings::values.use_cpu_jit) { | 56 | if (Settings::values.use_cpu_jit) { |
| 57 | #ifdef ARCHITECTURE_x86_64 | 57 | #ifdef ARCHITECTURE_x86_64 |
| 58 | arm_interface = std::make_shared<ARM_Dynarmic>(exclusive_monitor, core_index); | 58 | arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index); |
| 59 | #else | 59 | #else |
| 60 | arm_interface = std::make_shared<ARM_Unicorn>(); | 60 | arm_interface = std::make_unique<ARM_Unicorn>(); |
| 61 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | 61 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); |
| 62 | #endif | 62 | #endif |
| 63 | } else { | 63 | } else { |
| 64 | arm_interface = std::make_shared<ARM_Unicorn>(); | 64 | arm_interface = std::make_unique<ARM_Unicorn>(); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get()); | 67 | scheduler = std::make_shared<Kernel::Scheduler>(*arm_interface); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | Cpu::~Cpu() = default; | 70 | Cpu::~Cpu() = default; |
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index 685532965..ee7e04abc 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h | |||
| @@ -76,7 +76,7 @@ public: | |||
| 76 | private: | 76 | private: |
| 77 | void Reschedule(); | 77 | void Reschedule(); |
| 78 | 78 | ||
| 79 | std::shared_ptr<ARM_Interface> arm_interface; | 79 | std::unique_ptr<ARM_Interface> arm_interface; |
| 80 | std::shared_ptr<CpuBarrier> cpu_barrier; | 80 | std::shared_ptr<CpuBarrier> cpu_barrier; |
| 81 | std::shared_ptr<Kernel::Scheduler> scheduler; | 81 | std::shared_ptr<Kernel::Scheduler> scheduler; |
| 82 | 82 | ||
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index 21fc3d796..2a913ce82 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <cstring> | 25 | #include <cstring> |
| 26 | #include "common/alignment.h" | ||
| 26 | #include "common/assert.h" | 27 | #include "common/assert.h" |
| 27 | #include "core/file_sys/fsmitm_romfsbuild.h" | 28 | #include "core/file_sys/fsmitm_romfsbuild.h" |
| 28 | #include "core/file_sys/vfs.h" | 29 | #include "core/file_sys/vfs.h" |
| @@ -73,7 +74,7 @@ static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size | |||
| 73 | struct RomFSBuildFileContext; | 74 | struct RomFSBuildFileContext; |
| 74 | 75 | ||
| 75 | struct RomFSBuildDirectoryContext { | 76 | struct RomFSBuildDirectoryContext { |
| 76 | std::string path = ""; | 77 | std::string path; |
| 77 | u32 cur_path_ofs = 0; | 78 | u32 cur_path_ofs = 0; |
| 78 | u32 path_len = 0; | 79 | u32 path_len = 0; |
| 79 | u32 entry_offset = 0; | 80 | u32 entry_offset = 0; |
| @@ -84,7 +85,7 @@ struct RomFSBuildDirectoryContext { | |||
| 84 | }; | 85 | }; |
| 85 | 86 | ||
| 86 | struct RomFSBuildFileContext { | 87 | struct RomFSBuildFileContext { |
| 87 | std::string path = ""; | 88 | std::string path; |
| 88 | u32 cur_path_ofs = 0; | 89 | u32 cur_path_ofs = 0; |
| 89 | u32 path_len = 0; | 90 | u32 path_len = 0; |
| 90 | u32 entry_offset = 0; | 91 | u32 entry_offset = 0; |
| @@ -92,12 +93,10 @@ struct RomFSBuildFileContext { | |||
| 92 | u64 size = 0; | 93 | u64 size = 0; |
| 93 | std::shared_ptr<RomFSBuildDirectoryContext> parent; | 94 | std::shared_ptr<RomFSBuildDirectoryContext> parent; |
| 94 | std::shared_ptr<RomFSBuildFileContext> sibling; | 95 | std::shared_ptr<RomFSBuildFileContext> sibling; |
| 95 | VirtualFile source = nullptr; | 96 | VirtualFile source; |
| 96 | |||
| 97 | RomFSBuildFileContext() : path(""), cur_path_ofs(0), path_len(0) {} | ||
| 98 | }; | 97 | }; |
| 99 | 98 | ||
| 100 | static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t path_len) { | 99 | static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) { |
| 101 | u32 hash = parent ^ 123456789; | 100 | u32 hash = parent ^ 123456789; |
| 102 | for (u32 i = 0; i < path_len; i++) { | 101 | for (u32 i = 0; i < path_len; i++) { |
| 103 | hash = (hash >> 5) | (hash << 27); | 102 | hash = (hash >> 5) | (hash << 27); |
| @@ -107,13 +106,16 @@ static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t | |||
| 107 | return hash; | 106 | return hash; |
| 108 | } | 107 | } |
| 109 | 108 | ||
| 110 | static u32 romfs_get_hash_table_count(u32 num_entries) { | 109 | static u64 romfs_get_hash_table_count(u64 num_entries) { |
| 111 | if (num_entries < 3) { | 110 | if (num_entries < 3) { |
| 112 | return 3; | 111 | return 3; |
| 113 | } else if (num_entries < 19) { | 112 | } |
| 113 | |||
| 114 | if (num_entries < 19) { | ||
| 114 | return num_entries | 1; | 115 | return num_entries | 1; |
| 115 | } | 116 | } |
| 116 | u32 count = num_entries; | 117 | |
| 118 | u64 count = num_entries; | ||
| 117 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || | 119 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || |
| 118 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { | 120 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { |
| 119 | count++; | 121 | count++; |
| @@ -139,7 +141,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, | |||
| 139 | const auto child = std::make_shared<RomFSBuildDirectoryContext>(); | 141 | const auto child = std::make_shared<RomFSBuildDirectoryContext>(); |
| 140 | // Set child's path. | 142 | // Set child's path. |
| 141 | child->cur_path_ofs = parent->path_len + 1; | 143 | child->cur_path_ofs = parent->path_len + 1; |
| 142 | child->path_len = child->cur_path_ofs + kv.first.size(); | 144 | child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); |
| 143 | child->path = parent->path + "/" + kv.first; | 145 | child->path = parent->path + "/" + kv.first; |
| 144 | 146 | ||
| 145 | // Sanity check on path_len | 147 | // Sanity check on path_len |
| @@ -152,7 +154,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, | |||
| 152 | const auto child = std::make_shared<RomFSBuildFileContext>(); | 154 | const auto child = std::make_shared<RomFSBuildFileContext>(); |
| 153 | // Set child's path. | 155 | // Set child's path. |
| 154 | child->cur_path_ofs = parent->path_len + 1; | 156 | child->cur_path_ofs = parent->path_len + 1; |
| 155 | child->path_len = child->cur_path_ofs + kv.first.size(); | 157 | child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); |
| 156 | child->path = parent->path + "/" + kv.first; | 158 | child->path = parent->path + "/" + kv.first; |
| 157 | 159 | ||
| 158 | // Sanity check on path_len | 160 | // Sanity check on path_len |
| @@ -181,7 +183,7 @@ bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> | |||
| 181 | // Add a new directory. | 183 | // Add a new directory. |
| 182 | num_dirs++; | 184 | num_dirs++; |
| 183 | dir_table_size += | 185 | dir_table_size += |
| 184 | sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3); | 186 | sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); |
| 185 | dir_ctx->parent = parent_dir_ctx; | 187 | dir_ctx->parent = parent_dir_ctx; |
| 186 | directories.emplace(dir_ctx->path, dir_ctx); | 188 | directories.emplace(dir_ctx->path, dir_ctx); |
| 187 | 189 | ||
| @@ -199,7 +201,7 @@ bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> pare | |||
| 199 | // Add a new file. | 201 | // Add a new file. |
| 200 | num_files++; | 202 | num_files++; |
| 201 | file_table_size += | 203 | file_table_size += |
| 202 | sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3); | 204 | sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); |
| 203 | file_ctx->parent = parent_dir_ctx; | 205 | file_ctx->parent = parent_dir_ctx; |
| 204 | files.emplace(file_ctx->path, file_ctx); | 206 | files.emplace(file_ctx->path, file_ctx); |
| 205 | 207 | ||
| @@ -219,8 +221,8 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_)) | |||
| 219 | RomFSBuildContext::~RomFSBuildContext() = default; | 221 | RomFSBuildContext::~RomFSBuildContext() = default; |
| 220 | 222 | ||
| 221 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { | 223 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { |
| 222 | const auto dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); | 224 | const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); |
| 223 | const auto file_hash_table_entry_count = romfs_get_hash_table_count(num_files); | 225 | const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); |
| 224 | dir_hash_table_size = 4 * dir_hash_table_entry_count; | 226 | dir_hash_table_size = 4 * dir_hash_table_entry_count; |
| 225 | file_hash_table_size = 4 * file_hash_table_entry_count; | 227 | file_hash_table_size = 4 * file_hash_table_entry_count; |
| 226 | 228 | ||
| @@ -233,12 +235,6 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 233 | std::vector<u8> dir_table(dir_table_size); | 235 | std::vector<u8> dir_table(dir_table_size); |
| 234 | std::vector<u8> file_table(file_table_size); | 236 | std::vector<u8> file_table(file_table_size); |
| 235 | 237 | ||
| 236 | // Clear out hash tables. | ||
| 237 | for (u32 i = 0; i < dir_hash_table_entry_count; i++) | ||
| 238 | dir_hash_table[i] = ROMFS_ENTRY_EMPTY; | ||
| 239 | for (u32 i = 0; i < file_hash_table_entry_count; i++) | ||
| 240 | file_hash_table[i] = ROMFS_ENTRY_EMPTY; | ||
| 241 | |||
| 242 | std::shared_ptr<RomFSBuildFileContext> cur_file; | 238 | std::shared_ptr<RomFSBuildFileContext> cur_file; |
| 243 | 239 | ||
| 244 | // Determine file offsets. | 240 | // Determine file offsets. |
| @@ -246,12 +242,12 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 246 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; | 242 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; |
| 247 | for (const auto& it : files) { | 243 | for (const auto& it : files) { |
| 248 | cur_file = it.second; | 244 | cur_file = it.second; |
| 249 | file_partition_size = (file_partition_size + 0xFULL) & ~0xFULL; | 245 | file_partition_size = Common::AlignUp(file_partition_size, 16); |
| 250 | cur_file->offset = file_partition_size; | 246 | cur_file->offset = file_partition_size; |
| 251 | file_partition_size += cur_file->size; | 247 | file_partition_size += cur_file->size; |
| 252 | cur_file->entry_offset = entry_offset; | 248 | cur_file->entry_offset = entry_offset; |
| 253 | entry_offset += | 249 | entry_offset += sizeof(RomFSFileEntry) + |
| 254 | sizeof(RomFSFileEntry) + ((cur_file->path_len - cur_file->cur_path_ofs + 3) & ~3); | 250 | Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4); |
| 255 | prev_file = cur_file; | 251 | prev_file = cur_file; |
| 256 | } | 252 | } |
| 257 | // Assign deferred parent/sibling ownership. | 253 | // Assign deferred parent/sibling ownership. |
| @@ -268,8 +264,8 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 268 | for (const auto& it : directories) { | 264 | for (const auto& it : directories) { |
| 269 | cur_dir = it.second; | 265 | cur_dir = it.second; |
| 270 | cur_dir->entry_offset = entry_offset; | 266 | cur_dir->entry_offset = entry_offset; |
| 271 | entry_offset += | 267 | entry_offset += sizeof(RomFSDirectoryEntry) + |
| 272 | sizeof(RomFSDirectoryEntry) + ((cur_dir->path_len - cur_dir->cur_path_ofs + 3) & ~3); | 268 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4); |
| 273 | } | 269 | } |
| 274 | // Assign deferred parent/sibling ownership. | 270 | // Assign deferred parent/sibling ownership. |
| 275 | for (auto it = directories.rbegin(); it->second != root; ++it) { | 271 | for (auto it = directories.rbegin(); it->second != root; ++it) { |
| @@ -302,7 +298,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 302 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source); | 298 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source); |
| 303 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); | 299 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); |
| 304 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, | 300 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, |
| 305 | (cur_entry.name_size + 3) & ~3); | 301 | Common::AlignUp(cur_entry.name_size, 4)); |
| 306 | std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), | 302 | std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), |
| 307 | cur_file->path.data() + cur_file->cur_path_ofs, name_size); | 303 | cur_file->path.data() + cur_file->cur_path_ofs, name_size); |
| 308 | } | 304 | } |
| @@ -329,10 +325,8 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 329 | 325 | ||
| 330 | std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry, | 326 | std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry, |
| 331 | sizeof(RomFSDirectoryEntry)); | 327 | sizeof(RomFSDirectoryEntry)); |
| 332 | std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry, | ||
| 333 | sizeof(RomFSDirectoryEntry)); | ||
| 334 | std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0, | 328 | std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0, |
| 335 | (cur_entry.name_size + 3) & ~3); | 329 | Common::AlignUp(cur_entry.name_size, 4)); |
| 336 | std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), | 330 | std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), |
| 337 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); | 331 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); |
| 338 | } | 332 | } |
| @@ -344,18 +338,18 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 344 | header.dir_hash_table_size = dir_hash_table_size; | 338 | header.dir_hash_table_size = dir_hash_table_size; |
| 345 | header.dir_table_size = dir_table_size; | 339 | header.dir_table_size = dir_table_size; |
| 346 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; | 340 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; |
| 347 | header.dir_hash_table_ofs = (header.file_partition_ofs + file_partition_size + 3ULL) & ~3ULL; | 341 | header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); |
| 348 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; | 342 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; |
| 349 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; | 343 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; |
| 350 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; | 344 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; |
| 351 | 345 | ||
| 352 | std::vector<u8> header_data(sizeof(RomFSHeader)); | 346 | std::vector<u8> header_data(sizeof(RomFSHeader)); |
| 353 | std::memcpy(header_data.data(), &header, header_data.size()); | 347 | std::memcpy(header_data.data(), &header, header_data.size()); |
| 354 | out.emplace(0, std::make_shared<VectorVfsFile>(header_data)); | 348 | out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data))); |
| 355 | 349 | ||
| 356 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + | 350 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + |
| 357 | dir_table_size); | 351 | dir_table_size); |
| 358 | auto index = 0; | 352 | std::size_t index = 0; |
| 359 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); | 353 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); |
| 360 | index += dir_hash_table.size() * sizeof(u32); | 354 | index += dir_hash_table.size() * sizeof(u32); |
| 361 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); | 355 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); |
| @@ -364,7 +358,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 364 | file_hash_table.size() * sizeof(u32)); | 358 | file_hash_table.size() * sizeof(u32)); |
| 365 | index += file_hash_table.size() * sizeof(u32); | 359 | index += file_hash_table.size() * sizeof(u32); |
| 366 | std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); | 360 | std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); |
| 367 | out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(metadata)); | 361 | out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata))); |
| 368 | 362 | ||
| 369 | return out; | 363 | return out; |
| 370 | } | 364 | } |
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index af3f9a78f..4b3b5e665 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -70,38 +70,40 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 70 | 70 | ||
| 71 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { | 71 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { |
| 72 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | 72 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); |
| 73 | if (type == ContentRecordType::Program && load_dir != nullptr && load_dir->GetSize() > 0) { | 73 | if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) { |
| 74 | auto extracted = ExtractRomFS(romfs); | 74 | return; |
| 75 | 75 | } | |
| 76 | if (extracted != nullptr) { | ||
| 77 | auto patch_dirs = load_dir->GetSubdirectories(); | ||
| 78 | std::sort(patch_dirs.begin(), patch_dirs.end(), | ||
| 79 | [](const VirtualDir& l, const VirtualDir& r) { | ||
| 80 | return l->GetName() < r->GetName(); | ||
| 81 | }); | ||
| 82 | |||
| 83 | std::vector<VirtualDir> layers; | ||
| 84 | layers.reserve(patch_dirs.size() + 1); | ||
| 85 | for (const auto& subdir : patch_dirs) { | ||
| 86 | auto romfs_dir = subdir->GetSubdirectory("romfs"); | ||
| 87 | if (romfs_dir != nullptr) | ||
| 88 | layers.push_back(std::move(romfs_dir)); | ||
| 89 | } | ||
| 90 | 76 | ||
| 91 | layers.push_back(std::move(extracted)); | 77 | auto extracted = ExtractRomFS(romfs); |
| 78 | if (extracted == nullptr) { | ||
| 79 | return; | ||
| 80 | } | ||
| 92 | 81 | ||
| 93 | const auto layered = LayerDirectories(layers); | 82 | auto patch_dirs = load_dir->GetSubdirectories(); |
| 83 | std::sort(patch_dirs.begin(), patch_dirs.end(), | ||
| 84 | [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); | ||
| 94 | 85 | ||
| 95 | if (layered != nullptr) { | 86 | std::vector<VirtualDir> layers; |
| 96 | auto packed = CreateRomFS(layered); | 87 | layers.reserve(patch_dirs.size() + 1); |
| 88 | for (const auto& subdir : patch_dirs) { | ||
| 89 | auto romfs_dir = subdir->GetSubdirectory("romfs"); | ||
| 90 | if (romfs_dir != nullptr) | ||
| 91 | layers.push_back(std::move(romfs_dir)); | ||
| 92 | } | ||
| 93 | layers.push_back(std::move(extracted)); | ||
| 97 | 94 | ||
| 98 | if (packed != nullptr) { | 95 | auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers)); |
| 99 | LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); | 96 | if (layered == nullptr) { |
| 100 | romfs = std::move(packed); | 97 | return; |
| 101 | } | 98 | } |
| 102 | } | 99 | |
| 103 | } | 100 | auto packed = CreateRomFS(std::move(layered)); |
| 101 | if (packed == nullptr) { | ||
| 102 | return; | ||
| 104 | } | 103 | } |
| 104 | |||
| 105 | LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); | ||
| 106 | romfs = std::move(packed); | ||
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, | 109 | VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, |
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 02319ce0f..8903ed1d3 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp | |||
| @@ -83,10 +83,12 @@ void ProgramMetadata::Print() const { | |||
| 83 | 83 | ||
| 84 | auto address_space = "Unknown"; | 84 | auto address_space = "Unknown"; |
| 85 | switch (npdm_header.address_space_type) { | 85 | switch (npdm_header.address_space_type) { |
| 86 | case ProgramAddressSpaceType::Is64Bit: | 86 | case ProgramAddressSpaceType::Is36Bit: |
| 87 | case ProgramAddressSpaceType::Is39Bit: | ||
| 87 | address_space = "64-bit"; | 88 | address_space = "64-bit"; |
| 88 | break; | 89 | break; |
| 89 | case ProgramAddressSpaceType::Is32Bit: | 90 | case ProgramAddressSpaceType::Is32Bit: |
| 91 | case ProgramAddressSpaceType::Is32BitNoMap: | ||
| 90 | address_space = "32-bit"; | 92 | address_space = "32-bit"; |
| 91 | break; | 93 | break; |
| 92 | } | 94 | } |
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 1143e36c4..e4470d6f0 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h | |||
| @@ -17,8 +17,10 @@ enum class ResultStatus : u16; | |||
| 17 | namespace FileSys { | 17 | namespace FileSys { |
| 18 | 18 | ||
| 19 | enum class ProgramAddressSpaceType : u8 { | 19 | enum class ProgramAddressSpaceType : u8 { |
| 20 | Is64Bit = 1, | 20 | Is32Bit = 0, |
| 21 | Is32Bit = 2, | 21 | Is36Bit = 1, |
| 22 | Is32BitNoMap = 2, | ||
| 23 | Is39Bit = 3, | ||
| 22 | }; | 24 | }; |
| 23 | 25 | ||
| 24 | enum class ProgramFilePermission : u64 { | 26 | enum class ProgramFilePermission : u64 { |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 653ef2e7b..e9b040689 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -125,7 +125,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | |||
| 125 | if (concat.empty()) | 125 | if (concat.empty()) |
| 126 | return nullptr; | 126 | return nullptr; |
| 127 | 127 | ||
| 128 | file = FileSys::ConcatenateFiles(concat, concat.front()->GetName()); | 128 | file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | return file; | 131 | return file; |
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 205284a4d..5910f7046 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -134,7 +134,7 @@ VirtualFile CreateRomFS(VirtualDir dir) { | |||
| 134 | return nullptr; | 134 | return nullptr; |
| 135 | 135 | ||
| 136 | RomFSBuildContext ctx{dir}; | 136 | RomFSBuildContext ctx{dir}; |
| 137 | return ConcatenateFiles<0>(ctx.Build(), dir->GetName()); | 137 | return ConcatenatedVfsFile::MakeConcatenatedFile(0, ctx.Build(), dir->GetName()); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | } // namespace FileSys | 140 | } // namespace FileSys |
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 3d1a3685e..d027a8d59 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -34,7 +34,7 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { | |||
| 34 | if (!updatable) | 34 | if (!updatable) |
| 35 | return MakeResult<VirtualFile>(file); | 35 | return MakeResult<VirtualFile>(file); |
| 36 | 36 | ||
| 37 | const PatchManager patch_manager(Core::CurrentProcess()->program_id); | 37 | const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID()); |
| 38 | return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); | 38 | return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); |
| 39 | } | 39 | } |
| 40 | 40 | ||
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 9b2c51bbd..47f2ab9e0 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -81,7 +81,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ | |||
| 81 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 81 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 82 | // be interpreted as the title id of the current process. | 82 | // be interpreted as the title id of the current process. |
| 83 | if (type == SaveDataType::SaveData && title_id == 0) | 83 | if (type == SaveDataType::SaveData && title_id == 0) |
| 84 | title_id = Core::CurrentProcess()->program_id; | 84 | title_id = Core::CurrentProcess()->GetTitleID(); |
| 85 | 85 | ||
| 86 | std::string out; | 86 | std::string out; |
| 87 | 87 | ||
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 5fbea1739..bfe50da73 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -463,14 +463,14 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t | |||
| 463 | return true; | 463 | return true; |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size) { | 466 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size) { |
| 467 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | 467 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) |
| 468 | return false; | 468 | return false; |
| 469 | if (!dest->Resize(src->GetSize())) | 469 | if (!dest->Resize(src->GetSize())) |
| 470 | return false; | 470 | return false; |
| 471 | 471 | ||
| 472 | std::vector<u8> temp(std::min(block_size, src->GetSize())); | 472 | std::vector<u8> temp(std::min(block_size, src->GetSize())); |
| 473 | for (size_t i = 0; i < src->GetSize(); i += block_size) { | 473 | for (std::size_t i = 0; i < src->GetSize(); i += block_size) { |
| 474 | const auto read = std::min(block_size, src->GetSize() - i); | 474 | const auto read = std::min(block_size, src->GetSize() - i); |
| 475 | const auto block = src->Read(temp.data(), read, i); | 475 | const auto block = src->Read(temp.data(), read, i); |
| 476 | 476 | ||
| @@ -481,7 +481,7 @@ bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_si | |||
| 481 | return true; | 481 | return true; |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size) { | 484 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size) { |
| 485 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | 485 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) |
| 486 | return false; | 486 | return false; |
| 487 | 487 | ||
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index cea4aa8b8..270291631 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h | |||
| @@ -315,18 +315,19 @@ public: | |||
| 315 | bool Rename(std::string_view name) override; | 315 | bool Rename(std::string_view name) override; |
| 316 | }; | 316 | }; |
| 317 | 317 | ||
| 318 | // Compare the two files, byte-for-byte, in increments specificed by block_size | 318 | // Compare the two files, byte-for-byte, in increments specified by block_size |
| 319 | bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x1000); | 319 | bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, |
| 320 | std::size_t block_size = 0x1000); | ||
| 320 | 321 | ||
| 321 | // A method that copies the raw data between two different implementations of VirtualFile. If you | 322 | // A method that copies the raw data between two different implementations of VirtualFile. If you |
| 322 | // are using the same implementation, it is probably better to use the Copy method in the parent | 323 | // are using the same implementation, it is probably better to use the Copy method in the parent |
| 323 | // directory of src/dest. | 324 | // directory of src/dest. |
| 324 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000); | 325 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size = 0x1000); |
| 325 | 326 | ||
| 326 | // A method that performs a similar function to VfsRawCopy above, but instead copies entire | 327 | // A method that performs a similar function to VfsRawCopy above, but instead copies entire |
| 327 | // directories. It suffers the same performance penalties as above and an implementation-specific | 328 | // directories. It suffers the same performance penalties as above and an implementation-specific |
| 328 | // Copy should always be preferred. | 329 | // Copy should always be preferred. |
| 329 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000); | 330 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size = 0x1000); |
| 330 | 331 | ||
| 331 | // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not | 332 | // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not |
| 332 | // it attempts to create it and returns the new dir or nullptr on failure. | 333 | // it attempts to create it and returns the new dir or nullptr on failure. |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index d9f9911da..16d801c0c 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "core/file_sys/vfs_concat.h" | 9 | #include "core/file_sys/vfs_concat.h" |
| 10 | #include "core/file_sys/vfs_static.h" | ||
| 10 | 11 | ||
| 11 | namespace FileSys { | 12 | namespace FileSys { |
| 12 | 13 | ||
| @@ -22,15 +23,6 @@ static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& m | |||
| 22 | return map.begin()->first == 0; | 23 | return map.begin()->first == 0; |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { | ||
| 26 | if (files.empty()) | ||
| 27 | return nullptr; | ||
| 28 | if (files.size() == 1) | ||
| 29 | return files[0]; | ||
| 30 | |||
| 31 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 32 | } | ||
| 33 | |||
| 34 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) | 26 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) |
| 35 | : name(std::move(name)) { | 27 | : name(std::move(name)) { |
| 36 | std::size_t next_offset = 0; | 28 | std::size_t next_offset = 0; |
| @@ -47,6 +39,41 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std: | |||
| 47 | 39 | ||
| 48 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; | 40 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; |
| 49 | 41 | ||
| 42 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files, | ||
| 43 | std::string name) { | ||
| 44 | if (files.empty()) | ||
| 45 | return nullptr; | ||
| 46 | if (files.size() == 1) | ||
| 47 | return files[0]; | ||
| 48 | |||
| 49 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 50 | } | ||
| 51 | |||
| 52 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, | ||
| 53 | std::map<u64, VirtualFile> files, | ||
| 54 | std::string name) { | ||
| 55 | if (files.empty()) | ||
| 56 | return nullptr; | ||
| 57 | if (files.size() == 1) | ||
| 58 | return files.begin()->second; | ||
| 59 | |||
| 60 | const auto last_valid = --files.end(); | ||
| 61 | for (auto iter = files.begin(); iter != last_valid;) { | ||
| 62 | const auto old = iter++; | ||
| 63 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 64 | files.emplace(old->first + old->second->GetSize(), | ||
| 65 | std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first - | ||
| 66 | old->second->GetSize())); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | // Ensure the map starts at offset 0 (start of file), otherwise pad to fill. | ||
| 71 | if (files.begin()->first != 0) | ||
| 72 | files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first)); | ||
| 73 | |||
| 74 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 75 | } | ||
| 76 | |||
| 50 | std::string ConcatenatedVfsFile::GetName() const { | 77 | std::string ConcatenatedVfsFile::GetName() const { |
| 51 | if (files.empty()) | 78 | if (files.empty()) |
| 52 | return ""; | 79 | return ""; |
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index 76211d38a..c90f9d5d1 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -7,26 +7,27 @@ | |||
| 7 | #include <map> | 7 | #include <map> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string_view> | 9 | #include <string_view> |
| 10 | #include <boost/container/flat_map.hpp> | ||
| 11 | #include "core/file_sys/vfs.h" | 10 | #include "core/file_sys/vfs.h" |
| 12 | #include "core/file_sys/vfs_static.h" | ||
| 13 | 11 | ||
| 14 | namespace FileSys { | 12 | namespace FileSys { |
| 15 | 13 | ||
| 16 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently | 14 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently |
| 17 | // read-only. | 15 | // read-only. |
| 18 | class ConcatenatedVfsFile : public VfsFile { | 16 | class ConcatenatedVfsFile : public VfsFile { |
| 19 | friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); | ||
| 20 | |||
| 21 | template <u8 filler_byte> | ||
| 22 | friend VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name); | ||
| 23 | |||
| 24 | ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); | 17 | ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); |
| 25 | ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); | 18 | ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); |
| 26 | 19 | ||
| 27 | public: | 20 | public: |
| 28 | ~ConcatenatedVfsFile() override; | 21 | ~ConcatenatedVfsFile() override; |
| 29 | 22 | ||
| 23 | /// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | ||
| 24 | static VirtualFile MakeConcatenatedFile(std::vector<VirtualFile> files, std::string name); | ||
| 25 | |||
| 26 | /// Convenience function that turns a map of offsets to files into a concatenated file, filling | ||
| 27 | /// gaps with a given filler byte. | ||
| 28 | static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files, | ||
| 29 | std::string name); | ||
| 30 | |||
| 30 | std::string GetName() const override; | 31 | std::string GetName() const override; |
| 31 | std::size_t GetSize() const override; | 32 | std::size_t GetSize() const override; |
| 32 | bool Resize(std::size_t new_size) override; | 33 | bool Resize(std::size_t new_size) override; |
| @@ -43,33 +44,4 @@ private: | |||
| 43 | std::string name; | 44 | std::string name; |
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | // Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | ||
| 47 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); | ||
| 48 | |||
| 49 | // Convenience function that turns a map of offsets to files into a concatenated file, filling gaps | ||
| 50 | // with template parameter. | ||
| 51 | template <u8 filler_byte> | ||
| 52 | VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name) { | ||
| 53 | if (files.empty()) | ||
| 54 | return nullptr; | ||
| 55 | if (files.size() == 1) | ||
| 56 | return files.begin()->second; | ||
| 57 | |||
| 58 | const auto last_valid = --files.end(); | ||
| 59 | for (auto iter = files.begin(); iter != last_valid;) { | ||
| 60 | const auto old = iter++; | ||
| 61 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 62 | files.emplace(old->first + old->second->GetSize(), | ||
| 63 | std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first - | ||
| 64 | old->second->GetSize())); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | // Ensure the map starts at offset 0 (start of file), otherwise pad to fill. | ||
| 69 | if (files.begin()->first != 0) | ||
| 70 | files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first)); | ||
| 71 | |||
| 72 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 73 | } | ||
| 74 | |||
| 75 | } // namespace FileSys | 47 | } // namespace FileSys |
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index 45563d7ae..bfee01725 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp | |||
| @@ -8,7 +8,13 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) { | 11 | LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) |
| 12 | : dirs(std::move(dirs)), name(std::move(name)) {} | ||
| 13 | |||
| 14 | LayeredVfsDirectory::~LayeredVfsDirectory() = default; | ||
| 15 | |||
| 16 | VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dirs, | ||
| 17 | std::string name) { | ||
| 12 | if (dirs.empty()) | 18 | if (dirs.empty()) |
| 13 | return nullptr; | 19 | return nullptr; |
| 14 | if (dirs.size() == 1) | 20 | if (dirs.size() == 1) |
| @@ -17,11 +23,6 @@ VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) { | |||
| 17 | return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); | 23 | return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); |
| 18 | } | 24 | } |
| 19 | 25 | ||
| 20 | LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) | ||
| 21 | : dirs(std::move(dirs)), name(std::move(name)) {} | ||
| 22 | |||
| 23 | LayeredVfsDirectory::~LayeredVfsDirectory() = default; | ||
| 24 | |||
| 25 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { | 26 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { |
| 26 | for (const auto& layer : dirs) { | 27 | for (const auto& layer : dirs) { |
| 27 | const auto file = layer->GetFileRelative(path); | 28 | const auto file = layer->GetFileRelative(path); |
| @@ -41,7 +42,7 @@ std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative( | |||
| 41 | out.push_back(std::move(dir)); | 42 | out.push_back(std::move(dir)); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | return LayerDirectories(std::move(out)); | 45 | return MakeLayeredDirectory(std::move(out)); |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { | 48 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { |
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h index 4f6e341ab..d85310f57 100644 --- a/src/core/file_sys/vfs_layered.h +++ b/src/core/file_sys/vfs_layered.h | |||
| @@ -9,20 +9,18 @@ | |||
| 9 | 9 | ||
| 10 | namespace FileSys { | 10 | namespace FileSys { |
| 11 | 11 | ||
| 12 | // Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. | ||
| 13 | VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name = ""); | ||
| 14 | |||
| 15 | // Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first | 12 | // Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first |
| 16 | // one and falling back to the one after. The highest priority directory (overwrites all others) | 13 | // one and falling back to the one after. The highest priority directory (overwrites all others) |
| 17 | // should be element 0 in the dirs vector. | 14 | // should be element 0 in the dirs vector. |
| 18 | class LayeredVfsDirectory : public VfsDirectory { | 15 | class LayeredVfsDirectory : public VfsDirectory { |
| 19 | friend VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name); | ||
| 20 | |||
| 21 | LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); | 16 | LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); |
| 22 | 17 | ||
| 23 | public: | 18 | public: |
| 24 | ~LayeredVfsDirectory() override; | 19 | ~LayeredVfsDirectory() override; |
| 25 | 20 | ||
| 21 | /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. | ||
| 22 | static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = ""); | ||
| 23 | |||
| 26 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; | 24 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; |
| 27 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; | 25 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; |
| 28 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; | 26 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; |
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h index 4dd47ffcc..44fab51d1 100644 --- a/src/core/file_sys/vfs_static.h +++ b/src/core/file_sys/vfs_static.h | |||
| @@ -12,21 +12,21 @@ | |||
| 12 | 12 | ||
| 13 | namespace FileSys { | 13 | namespace FileSys { |
| 14 | 14 | ||
| 15 | template <u8 value> | ||
| 16 | class StaticVfsFile : public VfsFile { | 15 | class StaticVfsFile : public VfsFile { |
| 17 | public: | 16 | public: |
| 18 | explicit StaticVfsFile(size_t size = 0, std::string name = "", VirtualDir parent = nullptr) | 17 | explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "", |
| 19 | : size(size), name(std::move(name)), parent(std::move(parent)) {} | 18 | VirtualDir parent = nullptr) |
| 19 | : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {} | ||
| 20 | 20 | ||
| 21 | std::string GetName() const override { | 21 | std::string GetName() const override { |
| 22 | return name; | 22 | return name; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | size_t GetSize() const override { | 25 | std::size_t GetSize() const override { |
| 26 | return size; | 26 | return size; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | bool Resize(size_t new_size) override { | 29 | bool Resize(std::size_t new_size) override { |
| 30 | size = new_size; | 30 | size = new_size; |
| 31 | return true; | 31 | return true; |
| 32 | } | 32 | } |
| @@ -43,23 +43,23 @@ public: | |||
| 43 | return true; | 43 | return true; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | size_t Read(u8* data, size_t length, size_t offset) const override { | 46 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override { |
| 47 | const auto read = std::min(length, size - offset); | 47 | const auto read = std::min(length, size - offset); |
| 48 | std::fill(data, data + read, value); | 48 | std::fill(data, data + read, value); |
| 49 | return read; | 49 | return read; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | size_t Write(const u8* data, size_t length, size_t offset) override { | 52 | std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override { |
| 53 | return 0; | 53 | return 0; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | boost::optional<u8> ReadByte(size_t offset) const override { | 56 | boost::optional<u8> ReadByte(std::size_t offset) const override { |
| 57 | if (offset < size) | 57 | if (offset < size) |
| 58 | return value; | 58 | return value; |
| 59 | return boost::none; | 59 | return boost::none; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | std::vector<u8> ReadBytes(size_t length, size_t offset) const override { | 62 | std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override { |
| 63 | const auto read = std::min(length, size - offset); | 63 | const auto read = std::min(length, size - offset); |
| 64 | return std::vector<u8>(read, value); | 64 | return std::vector<u8>(read, value); |
| 65 | } | 65 | } |
| @@ -70,7 +70,8 @@ public: | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | private: | 72 | private: |
| 73 | size_t size; | 73 | u8 value; |
| 74 | std::size_t size; | ||
| 74 | std::string name; | 75 | std::string name; |
| 75 | VirtualDir parent; | 76 | VirtualDir parent; |
| 76 | }; | 77 | }; |
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index 7033e2c88..389c7e003 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace FileSys { | 10 | namespace FileSys { |
| 11 | VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) | 11 | VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) |
| 12 | : data(std::move(initial_data)), name(std::move(name)), parent(std::move(parent)) {} | 12 | : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {} |
| 13 | 13 | ||
| 14 | VectorVfsFile::~VectorVfsFile() = default; | 14 | VectorVfsFile::~VectorVfsFile() = default; |
| 15 | 15 | ||
| @@ -38,13 +38,13 @@ bool VectorVfsFile::IsReadable() const { | |||
| 38 | return true; | 38 | return true; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | size_t VectorVfsFile::Read(u8* data_, size_t length, size_t offset) const { | 41 | std::size_t VectorVfsFile::Read(u8* data_, std::size_t length, std::size_t offset) const { |
| 42 | const auto read = std::min(length, data.size() - offset); | 42 | const auto read = std::min(length, data.size() - offset); |
| 43 | std::memcpy(data_, data.data() + offset, read); | 43 | std::memcpy(data_, data.data() + offset, read); |
| 44 | return read; | 44 | return read; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | size_t VectorVfsFile::Write(const u8* data_, size_t length, size_t offset) { | 47 | std::size_t VectorVfsFile::Write(const u8* data_, std::size_t length, std::size_t offset) { |
| 48 | if (offset + length > data.size()) | 48 | if (offset + length > data.size()) |
| 49 | data.resize(offset + length); | 49 | data.resize(offset + length); |
| 50 | const auto write = std::min(length, data.size() - offset); | 50 | const auto write = std::min(length, data.size() - offset); |
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index 115c3ae95..48a414c98 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h | |||
| @@ -16,13 +16,13 @@ public: | |||
| 16 | ~VectorVfsFile() override; | 16 | ~VectorVfsFile() override; |
| 17 | 17 | ||
| 18 | std::string GetName() const override; | 18 | std::string GetName() const override; |
| 19 | size_t GetSize() const override; | 19 | std::size_t GetSize() const override; |
| 20 | bool Resize(size_t new_size) override; | 20 | bool Resize(std::size_t new_size) override; |
| 21 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 21 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; |
| 22 | bool IsWritable() const override; | 22 | bool IsWritable() const override; |
| 23 | bool IsReadable() const override; | 23 | bool IsReadable() const override; |
| 24 | size_t Read(u8* data, size_t length, size_t offset) const override; | 24 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; |
| 25 | size_t Write(const u8* data, size_t length, size_t offset) override; | 25 | std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; |
| 26 | bool Rename(std::string_view name) override; | 26 | bool Rename(std::string_view name) override; |
| 27 | 27 | ||
| 28 | virtual void Assign(std::vector<u8> new_data); | 28 | virtual void Assign(std::vector<u8> new_data); |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 0ecdd9f82..5bc947010 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -37,7 +37,9 @@ | |||
| 37 | #include "core/core.h" | 37 | #include "core/core.h" |
| 38 | #include "core/core_cpu.h" | 38 | #include "core/core_cpu.h" |
| 39 | #include "core/gdbstub/gdbstub.h" | 39 | #include "core/gdbstub/gdbstub.h" |
| 40 | #include "core/hle/kernel/process.h" | ||
| 40 | #include "core/hle/kernel/scheduler.h" | 41 | #include "core/hle/kernel/scheduler.h" |
| 42 | #include "core/hle/kernel/vm_manager.h" | ||
| 41 | #include "core/loader/loader.h" | 43 | #include "core/loader/loader.h" |
| 42 | #include "core/memory.h" | 44 | #include "core/memory.h" |
| 43 | 45 | ||
| @@ -248,7 +250,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) | |||
| 248 | } else if (id == PC_REGISTER) { | 250 | } else if (id == PC_REGISTER) { |
| 249 | thread->context.pc = val; | 251 | thread->context.pc = val; |
| 250 | } else if (id == PSTATE_REGISTER) { | 252 | } else if (id == PSTATE_REGISTER) { |
| 251 | thread->context.pstate = val; | 253 | thread->context.pstate = static_cast<u32>(val); |
| 252 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { | 254 | } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { |
| 253 | thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; | 255 | thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; |
| 254 | } | 256 | } |
| @@ -585,7 +587,8 @@ static void HandleQuery() { | |||
| 585 | strlen("Xfer:features:read:target.xml:")) == 0) { | 587 | strlen("Xfer:features:read:target.xml:")) == 0) { |
| 586 | SendReply(target_xml); | 588 | SendReply(target_xml); |
| 587 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { | 589 | } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { |
| 588 | std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); | 590 | const VAddr base_address = Core::CurrentProcess()->VMManager().GetCodeRegionBaseAddress(); |
| 591 | std::string buffer = fmt::format("TextSeg={:0x}", base_address); | ||
| 589 | SendReply(buffer.c_str()); | 592 | SendReply(buffer.c_str()); |
| 590 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | 593 | } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { |
| 591 | std::string val = "m"; | 594 | std::string val = "m"; |
| @@ -893,11 +896,11 @@ static void ReadMemory() { | |||
| 893 | static u8 reply[GDB_BUFFER_SIZE - 4]; | 896 | static u8 reply[GDB_BUFFER_SIZE - 4]; |
| 894 | 897 | ||
| 895 | auto start_offset = command_buffer + 1; | 898 | auto start_offset = command_buffer + 1; |
| 896 | auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); | 899 | const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); |
| 897 | VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); | 900 | const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); |
| 898 | 901 | ||
| 899 | start_offset = addr_pos + 1; | 902 | start_offset = addr_pos + 1; |
| 900 | u64 len = | 903 | const u64 len = |
| 901 | HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); | 904 | HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); |
| 902 | 905 | ||
| 903 | LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); | 906 | LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); |
| @@ -906,7 +909,9 @@ static void ReadMemory() { | |||
| 906 | SendReply("E01"); | 909 | SendReply("E01"); |
| 907 | } | 910 | } |
| 908 | 911 | ||
| 909 | if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { | 912 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); |
| 913 | if (addr < vm_manager.GetCodeRegionBaseAddress() || | ||
| 914 | addr >= vm_manager.GetMapRegionEndAddress()) { | ||
| 910 | return SendReply("E00"); | 915 | return SendReply("E00"); |
| 911 | } | 916 | } |
| 912 | 917 | ||
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 8c2be2681..e5fa67ae8 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h | |||
| @@ -31,6 +31,7 @@ enum { | |||
| 31 | TooLarge = 119, | 31 | TooLarge = 119, |
| 32 | InvalidEnumValue = 120, | 32 | InvalidEnumValue = 120, |
| 33 | NoSuchEntry = 121, | 33 | NoSuchEntry = 121, |
| 34 | AlreadyRegistered = 122, | ||
| 34 | InvalidState = 125, | 35 | InvalidState = 125, |
| 35 | ResourceLimitExceeded = 132, | 36 | ResourceLimitExceeded = 132, |
| 36 | }; | 37 | }; |
| @@ -58,6 +59,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, | |||
| 58 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); | 59 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); |
| 59 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); | 60 | constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); |
| 60 | constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); | 61 | constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); |
| 62 | constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered); | ||
| 61 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); | 63 | constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); |
| 62 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, | 64 | constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, |
| 63 | ErrCodes::InvalidThreadPriority); | 65 | ErrCodes::InvalidThreadPriority); |
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index b054cbf7d..9eb72315c 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <utility> | ||
| 10 | 9 | ||
| 11 | #include <boost/smart_ptr/intrusive_ptr.hpp> | 10 | #include <boost/smart_ptr/intrusive_ptr.hpp> |
| 12 | 11 | ||
| @@ -97,7 +96,7 @@ using SharedPtr = boost::intrusive_ptr<T>; | |||
| 97 | template <typename T> | 96 | template <typename T> |
| 98 | inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { | 97 | inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { |
| 99 | if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { | 98 | if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { |
| 100 | return boost::static_pointer_cast<T>(std::move(object)); | 99 | return boost::static_pointer_cast<T>(object); |
| 101 | } | 100 | } |
| 102 | return nullptr; | 101 | return nullptr; |
| 103 | } | 102 | } |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 121f741fd..dc9fc8470 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/file_sys/program_metadata.h" | ||
| 11 | #include "core/hle/kernel/errors.h" | 12 | #include "core/hle/kernel/errors.h" |
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| @@ -34,14 +35,22 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { | |||
| 34 | process->name = std::move(name); | 35 | process->name = std::move(name); |
| 35 | process->flags.raw = 0; | 36 | process->flags.raw = 0; |
| 36 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | 37 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); |
| 38 | process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); | ||
| 37 | process->status = ProcessStatus::Created; | 39 | process->status = ProcessStatus::Created; |
| 38 | process->program_id = 0; | 40 | process->program_id = 0; |
| 39 | process->process_id = kernel.CreateNewProcessID(); | 41 | process->process_id = kernel.CreateNewProcessID(); |
| 42 | process->svc_access_mask.set(); | ||
| 40 | 43 | ||
| 41 | kernel.AppendNewProcess(process); | 44 | kernel.AppendNewProcess(process); |
| 42 | return process; | 45 | return process; |
| 43 | } | 46 | } |
| 44 | 47 | ||
| 48 | void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { | ||
| 49 | program_id = metadata.GetTitleID(); | ||
| 50 | is_64bit_process = metadata.Is64BitProgram(); | ||
| 51 | vm_manager.Reset(metadata.GetAddressSpaceType()); | ||
| 52 | } | ||
| 53 | |||
| 45 | void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { | 54 | void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { |
| 46 | for (std::size_t i = 0; i < len; ++i) { | 55 | for (std::size_t i = 0; i < len; ++i) { |
| 47 | u32 descriptor = kernel_caps[i]; | 56 | u32 descriptor = kernel_caps[i]; |
| @@ -119,7 +128,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | |||
| 119 | // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part | 128 | // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part |
| 120 | // of the user address space. | 129 | // of the user address space. |
| 121 | vm_manager | 130 | vm_manager |
| 122 | .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size, | 131 | .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size, |
| 123 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, | 132 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, |
| 124 | MemoryState::Mapped) | 133 | MemoryState::Mapped) |
| 125 | .Unwrap(); | 134 | .Unwrap(); |
| @@ -185,6 +194,7 @@ static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot( | |||
| 185 | 194 | ||
| 186 | VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { | 195 | VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { |
| 187 | auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); | 196 | auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); |
| 197 | const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress(); | ||
| 188 | 198 | ||
| 189 | if (needs_allocation) { | 199 | if (needs_allocation) { |
| 190 | tls_slots.emplace_back(0); // The page is completely available at the start | 200 | tls_slots.emplace_back(0); // The page is completely available at the start |
| @@ -197,18 +207,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { | |||
| 197 | 207 | ||
| 198 | vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); | 208 | vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); |
| 199 | 209 | ||
| 200 | vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, | 210 | vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0, |
| 201 | tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal); | 211 | Memory::PAGE_SIZE, MemoryState::ThreadLocal); |
| 202 | } | 212 | } |
| 203 | 213 | ||
| 204 | tls_slots[available_page].set(available_slot); | 214 | tls_slots[available_page].set(available_slot); |
| 205 | 215 | ||
| 206 | return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + | 216 | return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; |
| 207 | available_slot * Memory::TLS_ENTRY_SIZE; | ||
| 208 | } | 217 | } |
| 209 | 218 | ||
| 210 | void Process::FreeTLSSlot(VAddr tls_address) { | 219 | void Process::FreeTLSSlot(VAddr tls_address) { |
| 211 | const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR; | 220 | const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress(); |
| 212 | const VAddr tls_page = tls_base / Memory::PAGE_SIZE; | 221 | const VAddr tls_page = tls_base / Memory::PAGE_SIZE; |
| 213 | const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | 222 | const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; |
| 214 | 223 | ||
| @@ -232,8 +241,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { | |||
| 232 | } | 241 | } |
| 233 | 242 | ||
| 234 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { | 243 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { |
| 235 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || | 244 | if (target < vm_manager.GetHeapRegionBaseAddress() || |
| 236 | target + size < target) { | 245 | target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { |
| 237 | return ERR_INVALID_ADDRESS; | 246 | return ERR_INVALID_ADDRESS; |
| 238 | } | 247 | } |
| 239 | 248 | ||
| @@ -268,8 +277,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per | |||
| 268 | } | 277 | } |
| 269 | 278 | ||
| 270 | ResultCode Process::HeapFree(VAddr target, u32 size) { | 279 | ResultCode Process::HeapFree(VAddr target, u32 size) { |
| 271 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || | 280 | if (target < vm_manager.GetHeapRegionBaseAddress() || |
| 272 | target + size < target) { | 281 | target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { |
| 273 | return ERR_INVALID_ADDRESS; | 282 | return ERR_INVALID_ADDRESS; |
| 274 | } | 283 | } |
| 275 | 284 | ||
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 04d74e572..590e0c73d 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -17,6 +17,10 @@ | |||
| 17 | #include "core/hle/kernel/thread.h" | 17 | #include "core/hle/kernel/thread.h" |
| 18 | #include "core/hle/kernel/vm_manager.h" | 18 | #include "core/hle/kernel/vm_manager.h" |
| 19 | 19 | ||
| 20 | namespace FileSys { | ||
| 21 | class ProgramMetadata; | ||
| 22 | } | ||
| 23 | |||
| 20 | namespace Kernel { | 24 | namespace Kernel { |
| 21 | 25 | ||
| 22 | class KernelCore; | 26 | class KernelCore; |
| @@ -131,6 +135,16 @@ public: | |||
| 131 | return HANDLE_TYPE; | 135 | return HANDLE_TYPE; |
| 132 | } | 136 | } |
| 133 | 137 | ||
| 138 | /// Gets a reference to the process' memory manager. | ||
| 139 | Kernel::VMManager& VMManager() { | ||
| 140 | return vm_manager; | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Gets a const reference to the process' memory manager. | ||
| 144 | const Kernel::VMManager& VMManager() const { | ||
| 145 | return vm_manager; | ||
| 146 | } | ||
| 147 | |||
| 134 | /// Gets the current status of the process | 148 | /// Gets the current status of the process |
| 135 | ProcessStatus GetStatus() const { | 149 | ProcessStatus GetStatus() const { |
| 136 | return status; | 150 | return status; |
| @@ -141,29 +155,52 @@ public: | |||
| 141 | return process_id; | 155 | return process_id; |
| 142 | } | 156 | } |
| 143 | 157 | ||
| 144 | /// Title ID corresponding to the process | 158 | /// Gets the title ID corresponding to this process. |
| 145 | u64 program_id; | 159 | u64 GetTitleID() const { |
| 160 | return program_id; | ||
| 161 | } | ||
| 146 | 162 | ||
| 147 | /// Resource limit descriptor for this process | 163 | /// Gets the resource limit descriptor for this process |
| 148 | SharedPtr<ResourceLimit> resource_limit; | 164 | ResourceLimit& GetResourceLimit() { |
| 165 | return *resource_limit; | ||
| 166 | } | ||
| 149 | 167 | ||
| 150 | /// The process may only call SVCs which have the corresponding bit set. | 168 | /// Gets the resource limit descriptor for this process |
| 151 | std::bitset<0x80> svc_access_mask; | 169 | const ResourceLimit& GetResourceLimit() const { |
| 152 | /// Maximum size of the handle table for the process. | 170 | return *resource_limit; |
| 153 | unsigned int handle_table_size = 0x200; | 171 | } |
| 154 | /// Special memory ranges mapped into this processes address space. This is used to give | 172 | |
| 155 | /// processes access to specific I/O regions and device memory. | 173 | /// Gets the default CPU ID for this process |
| 156 | boost::container::static_vector<AddressMapping, 8> address_mappings; | 174 | u8 GetDefaultProcessorID() const { |
| 157 | ProcessFlags flags; | 175 | return ideal_processor; |
| 158 | /// Kernel compatibility version for this process | 176 | } |
| 159 | u16 kernel_version = 0; | 177 | |
| 160 | /// The default CPU for this process, threads are scheduled on this cpu by default. | 178 | /// Gets the bitmask of allowed CPUs that this process' threads can run on. |
| 161 | u8 ideal_processor = 0; | 179 | u32 GetAllowedProcessorMask() const { |
| 162 | /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse | 180 | return allowed_processor_mask; |
| 163 | /// this value from the process header. | 181 | } |
| 164 | u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; | 182 | |
| 165 | u32 allowed_thread_priority_mask = 0xFFFFFFFF; | 183 | /// Gets the bitmask of allowed thread priorities. |
| 166 | u32 is_virtual_address_memory_enabled = 0; | 184 | u32 GetAllowedThreadPriorityMask() const { |
| 185 | return allowed_thread_priority_mask; | ||
| 186 | } | ||
| 187 | |||
| 188 | u32 IsVirtualMemoryEnabled() const { | ||
| 189 | return is_virtual_address_memory_enabled; | ||
| 190 | } | ||
| 191 | |||
| 192 | /// Whether this process is an AArch64 or AArch32 process. | ||
| 193 | bool Is64BitProcess() const { | ||
| 194 | return is_64bit_process; | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * Loads process-specifics configuration info with metadata provided | ||
| 199 | * by an executable. | ||
| 200 | * | ||
| 201 | * @param metadata The provided metadata to load process specific info. | ||
| 202 | */ | ||
| 203 | void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); | ||
| 167 | 204 | ||
| 168 | /** | 205 | /** |
| 169 | * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them | 206 | * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them |
| @@ -200,18 +237,43 @@ public: | |||
| 200 | 237 | ||
| 201 | ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); | 238 | ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); |
| 202 | 239 | ||
| 203 | VMManager vm_manager; | ||
| 204 | |||
| 205 | private: | 240 | private: |
| 206 | explicit Process(KernelCore& kernel); | 241 | explicit Process(KernelCore& kernel); |
| 207 | ~Process() override; | 242 | ~Process() override; |
| 208 | 243 | ||
| 244 | /// Memory manager for this process. | ||
| 245 | Kernel::VMManager vm_manager; | ||
| 246 | |||
| 209 | /// Current status of the process | 247 | /// Current status of the process |
| 210 | ProcessStatus status; | 248 | ProcessStatus status; |
| 211 | 249 | ||
| 212 | /// The ID of this process | 250 | /// The ID of this process |
| 213 | u32 process_id = 0; | 251 | u32 process_id = 0; |
| 214 | 252 | ||
| 253 | /// Title ID corresponding to the process | ||
| 254 | u64 program_id; | ||
| 255 | |||
| 256 | /// Resource limit descriptor for this process | ||
| 257 | SharedPtr<ResourceLimit> resource_limit; | ||
| 258 | |||
| 259 | /// The process may only call SVCs which have the corresponding bit set. | ||
| 260 | std::bitset<0x80> svc_access_mask; | ||
| 261 | /// Maximum size of the handle table for the process. | ||
| 262 | u32 handle_table_size = 0x200; | ||
| 263 | /// Special memory ranges mapped into this processes address space. This is used to give | ||
| 264 | /// processes access to specific I/O regions and device memory. | ||
| 265 | boost::container::static_vector<AddressMapping, 8> address_mappings; | ||
| 266 | ProcessFlags flags; | ||
| 267 | /// Kernel compatibility version for this process | ||
| 268 | u16 kernel_version = 0; | ||
| 269 | /// The default CPU for this process, threads are scheduled on this cpu by default. | ||
| 270 | u8 ideal_processor = 0; | ||
| 271 | /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse | ||
| 272 | /// this value from the process header. | ||
| 273 | u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; | ||
| 274 | u32 allowed_thread_priority_mask = 0xFFFFFFFF; | ||
| 275 | u32 is_virtual_address_memory_enabled = 0; | ||
| 276 | |||
| 215 | // Memory used to back the allocations in the regular heap. A single vector is used to cover | 277 | // Memory used to back the allocations in the regular heap. A single vector is used to cover |
| 216 | // the entire virtual address space extents that bound the allocations, including any holes. | 278 | // the entire virtual address space extents that bound the allocations, including any holes. |
| 217 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous | 279 | // This makes deallocation and reallocation of holes fast and keeps process memory contiguous |
| @@ -230,6 +292,11 @@ private: | |||
| 230 | /// This vector will grow as more pages are allocated for new threads. | 292 | /// This vector will grow as more pages are allocated for new threads. |
| 231 | std::vector<std::bitset<8>> tls_slots; | 293 | std::vector<std::bitset<8>> tls_slots; |
| 232 | 294 | ||
| 295 | /// Whether or not this process is AArch64, or AArch32. | ||
| 296 | /// By default, we currently assume this is true, unless otherwise | ||
| 297 | /// specified by metadata provided to the process during loading. | ||
| 298 | bool is_64bit_process = true; | ||
| 299 | |||
| 233 | std::string name; | 300 | std::string name; |
| 234 | }; | 301 | }; |
| 235 | 302 | ||
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 69c812f16..1e82cfffb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -17,7 +17,7 @@ namespace Kernel { | |||
| 17 | 17 | ||
| 18 | std::mutex Scheduler::scheduler_mutex; | 18 | std::mutex Scheduler::scheduler_mutex; |
| 19 | 19 | ||
| 20 | Scheduler::Scheduler(Core::ARM_Interface* cpu_core) : cpu_core(cpu_core) {} | 20 | Scheduler::Scheduler(Core::ARM_Interface& cpu_core) : cpu_core(cpu_core) {} |
| 21 | 21 | ||
| 22 | Scheduler::~Scheduler() { | 22 | Scheduler::~Scheduler() { |
| 23 | for (auto& thread : thread_list) { | 23 | for (auto& thread : thread_list) { |
| @@ -59,9 +59,9 @@ void Scheduler::SwitchContext(Thread* new_thread) { | |||
| 59 | // Save context for previous thread | 59 | // Save context for previous thread |
| 60 | if (previous_thread) { | 60 | if (previous_thread) { |
| 61 | previous_thread->last_running_ticks = CoreTiming::GetTicks(); | 61 | previous_thread->last_running_ticks = CoreTiming::GetTicks(); |
| 62 | cpu_core->SaveContext(previous_thread->context); | 62 | cpu_core.SaveContext(previous_thread->context); |
| 63 | // Save the TPIDR_EL0 system register in case it was modified. | 63 | // Save the TPIDR_EL0 system register in case it was modified. |
| 64 | previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0(); | 64 | previous_thread->tpidr_el0 = cpu_core.GetTPIDR_EL0(); |
| 65 | 65 | ||
| 66 | if (previous_thread->status == ThreadStatus::Running) { | 66 | if (previous_thread->status == ThreadStatus::Running) { |
| 67 | // This is only the case when a reschedule is triggered without the current thread | 67 | // This is only the case when a reschedule is triggered without the current thread |
| @@ -88,13 +88,13 @@ void Scheduler::SwitchContext(Thread* new_thread) { | |||
| 88 | 88 | ||
| 89 | if (previous_process != current_thread->owner_process) { | 89 | if (previous_process != current_thread->owner_process) { |
| 90 | Core::CurrentProcess() = current_thread->owner_process; | 90 | Core::CurrentProcess() = current_thread->owner_process; |
| 91 | SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); | 91 | SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | cpu_core->LoadContext(new_thread->context); | 94 | cpu_core.LoadContext(new_thread->context); |
| 95 | cpu_core->SetTlsAddress(new_thread->GetTLSAddress()); | 95 | cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); |
| 96 | cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); | 96 | cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); |
| 97 | cpu_core->ClearExclusiveState(); | 97 | cpu_core.ClearExclusiveState(); |
| 98 | } else { | 98 | } else { |
| 99 | current_thread = nullptr; | 99 | current_thread = nullptr; |
| 100 | // Note: We do not reset the current process and current page table when idling because | 100 | // Note: We do not reset the current process and current page table when idling because |
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 744990c9b..2c94641ec 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h | |||
| @@ -19,7 +19,7 @@ namespace Kernel { | |||
| 19 | 19 | ||
| 20 | class Scheduler final { | 20 | class Scheduler final { |
| 21 | public: | 21 | public: |
| 22 | explicit Scheduler(Core::ARM_Interface* cpu_core); | 22 | explicit Scheduler(Core::ARM_Interface& cpu_core); |
| 23 | ~Scheduler(); | 23 | ~Scheduler(); |
| 24 | 24 | ||
| 25 | /// Returns whether there are any threads that are ready to run. | 25 | /// Returns whether there are any threads that are ready to run. |
| @@ -72,7 +72,7 @@ private: | |||
| 72 | 72 | ||
| 73 | SharedPtr<Thread> current_thread = nullptr; | 73 | SharedPtr<Thread> current_thread = nullptr; |
| 74 | 74 | ||
| 75 | Core::ARM_Interface* cpu_core; | 75 | Core::ARM_Interface& cpu_core; |
| 76 | 76 | ||
| 77 | static std::mutex scheduler_mutex; | 77 | static std::mutex scheduler_mutex; |
| 78 | }; | 78 | }; |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index abb1d09cd..d061e6155 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hle/kernel/errors.h" | 10 | #include "core/hle/kernel/errors.h" |
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/shared_memory.h" | 12 | #include "core/hle/kernel/shared_memory.h" |
| 12 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| 13 | 14 | ||
| @@ -34,11 +35,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce | |||
| 34 | 35 | ||
| 35 | // Refresh the address mappings for the current process. | 36 | // Refresh the address mappings for the current process. |
| 36 | if (Core::CurrentProcess() != nullptr) { | 37 | if (Core::CurrentProcess() != nullptr) { |
| 37 | Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings( | 38 | Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings( |
| 38 | shared_memory->backing_block.get()); | 39 | shared_memory->backing_block.get()); |
| 39 | } | 40 | } |
| 40 | } else { | 41 | } else { |
| 41 | auto& vm_manager = shared_memory->owner_process->vm_manager; | 42 | auto& vm_manager = shared_memory->owner_process->VMManager(); |
| 42 | 43 | ||
| 43 | // The memory is already available and mapped in the owner process. | 44 | // The memory is already available and mapped in the owner process. |
| 44 | auto vma = vm_manager.FindVMA(address); | 45 | auto vma = vm_manager.FindVMA(address); |
| @@ -71,7 +72,8 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet( | |||
| 71 | shared_memory->other_permissions = other_permissions; | 72 | shared_memory->other_permissions = other_permissions; |
| 72 | shared_memory->backing_block = std::move(heap_block); | 73 | shared_memory->backing_block = std::move(heap_block); |
| 73 | shared_memory->backing_block_offset = offset; | 74 | shared_memory->backing_block_offset = offset; |
| 74 | shared_memory->base_address = Memory::HEAP_VADDR + offset; | 75 | shared_memory->base_address = |
| 76 | kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset; | ||
| 75 | 77 | ||
| 76 | return shared_memory; | 78 | return shared_memory; |
| 77 | } | 79 | } |
| @@ -105,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 105 | VAddr target_address = address; | 107 | VAddr target_address = address; |
| 106 | 108 | ||
| 107 | // Map the memory block into the target process | 109 | // Map the memory block into the target process |
| 108 | auto result = target_process->vm_manager.MapMemoryBlock( | 110 | auto result = target_process->VMManager().MapMemoryBlock( |
| 109 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | 111 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); |
| 110 | if (result.Failed()) { | 112 | if (result.Failed()) { |
| 111 | LOG_ERROR( | 113 | LOG_ERROR( |
| @@ -115,14 +117,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 115 | return result.Code(); | 117 | return result.Code(); |
| 116 | } | 118 | } |
| 117 | 119 | ||
| 118 | return target_process->vm_manager.ReprotectRange(target_address, size, | 120 | return target_process->VMManager().ReprotectRange(target_address, size, |
| 119 | ConvertPermissions(permissions)); | 121 | ConvertPermissions(permissions)); |
| 120 | } | 122 | } |
| 121 | 123 | ||
| 122 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { | 124 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { |
| 123 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not | 125 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not |
| 124 | // mapped to a SharedMemory. | 126 | // mapped to a SharedMemory. |
| 125 | return target_process->vm_manager.UnmapRange(address, size); | 127 | return target_process->VMManager().UnmapRange(address, size); |
| 126 | } | 128 | } |
| 127 | 129 | ||
| 128 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | 130 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c9d212a4c..1cdaa740a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -51,8 +51,9 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | |||
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | auto& process = *Core::CurrentProcess(); | 53 | auto& process = *Core::CurrentProcess(); |
| 54 | const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress(); | ||
| 54 | CASCADE_RESULT(*heap_addr, | 55 | CASCADE_RESULT(*heap_addr, |
| 55 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); | 56 | process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite)); |
| 56 | return RESULT_SUCCESS; | 57 | return RESULT_SUCCESS; |
| 57 | } | 58 | } |
| 58 | 59 | ||
| @@ -325,26 +326,27 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 325 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, | 326 | LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, |
| 326 | info_sub_id, handle); | 327 | info_sub_id, handle); |
| 327 | 328 | ||
| 328 | const auto& vm_manager = Core::CurrentProcess()->vm_manager; | 329 | const auto& current_process = Core::CurrentProcess(); |
| 330 | const auto& vm_manager = current_process->VMManager(); | ||
| 329 | 331 | ||
| 330 | switch (static_cast<GetInfoType>(info_id)) { | 332 | switch (static_cast<GetInfoType>(info_id)) { |
| 331 | case GetInfoType::AllowedCpuIdBitmask: | 333 | case GetInfoType::AllowedCpuIdBitmask: |
| 332 | *result = Core::CurrentProcess()->allowed_processor_mask; | 334 | *result = current_process->GetAllowedProcessorMask(); |
| 333 | break; | 335 | break; |
| 334 | case GetInfoType::AllowedThreadPrioBitmask: | 336 | case GetInfoType::AllowedThreadPrioBitmask: |
| 335 | *result = Core::CurrentProcess()->allowed_thread_priority_mask; | 337 | *result = current_process->GetAllowedThreadPriorityMask(); |
| 336 | break; | 338 | break; |
| 337 | case GetInfoType::MapRegionBaseAddr: | 339 | case GetInfoType::MapRegionBaseAddr: |
| 338 | *result = Memory::MAP_REGION_VADDR; | 340 | *result = vm_manager.GetMapRegionBaseAddress(); |
| 339 | break; | 341 | break; |
| 340 | case GetInfoType::MapRegionSize: | 342 | case GetInfoType::MapRegionSize: |
| 341 | *result = Memory::MAP_REGION_SIZE; | 343 | *result = vm_manager.GetMapRegionSize(); |
| 342 | break; | 344 | break; |
| 343 | case GetInfoType::HeapRegionBaseAddr: | 345 | case GetInfoType::HeapRegionBaseAddr: |
| 344 | *result = Memory::HEAP_VADDR; | 346 | *result = vm_manager.GetHeapRegionBaseAddress(); |
| 345 | break; | 347 | break; |
| 346 | case GetInfoType::HeapRegionSize: | 348 | case GetInfoType::HeapRegionSize: |
| 347 | *result = Memory::HEAP_SIZE; | 349 | *result = vm_manager.GetHeapRegionSize(); |
| 348 | break; | 350 | break; |
| 349 | case GetInfoType::TotalMemoryUsage: | 351 | case GetInfoType::TotalMemoryUsage: |
| 350 | *result = vm_manager.GetTotalMemoryUsage(); | 352 | *result = vm_manager.GetTotalMemoryUsage(); |
| @@ -359,22 +361,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 359 | *result = 0; | 361 | *result = 0; |
| 360 | break; | 362 | break; |
| 361 | case GetInfoType::AddressSpaceBaseAddr: | 363 | case GetInfoType::AddressSpaceBaseAddr: |
| 362 | *result = vm_manager.GetAddressSpaceBaseAddr(); | 364 | *result = vm_manager.GetCodeRegionBaseAddress(); |
| 363 | break; | 365 | break; |
| 364 | case GetInfoType::AddressSpaceSize: | 366 | case GetInfoType::AddressSpaceSize: { |
| 365 | *result = vm_manager.GetAddressSpaceSize(); | 367 | const u64 width = vm_manager.GetAddressSpaceWidth(); |
| 368 | |||
| 369 | switch (width) { | ||
| 370 | case 32: | ||
| 371 | *result = 0xFFE00000; | ||
| 372 | break; | ||
| 373 | case 36: | ||
| 374 | *result = 0xFF8000000; | ||
| 375 | break; | ||
| 376 | case 39: | ||
| 377 | *result = 0x7FF8000000; | ||
| 378 | break; | ||
| 379 | } | ||
| 366 | break; | 380 | break; |
| 381 | } | ||
| 367 | case GetInfoType::NewMapRegionBaseAddr: | 382 | case GetInfoType::NewMapRegionBaseAddr: |
| 368 | *result = Memory::NEW_MAP_REGION_VADDR; | 383 | *result = vm_manager.GetNewMapRegionBaseAddress(); |
| 369 | break; | 384 | break; |
| 370 | case GetInfoType::NewMapRegionSize: | 385 | case GetInfoType::NewMapRegionSize: |
| 371 | *result = Memory::NEW_MAP_REGION_SIZE; | 386 | *result = vm_manager.GetNewMapRegionSize(); |
| 372 | break; | 387 | break; |
| 373 | case GetInfoType::IsVirtualAddressMemoryEnabled: | 388 | case GetInfoType::IsVirtualAddressMemoryEnabled: |
| 374 | *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; | 389 | *result = current_process->IsVirtualMemoryEnabled(); |
| 375 | break; | 390 | break; |
| 376 | case GetInfoType::TitleId: | 391 | case GetInfoType::TitleId: |
| 377 | *result = Core::CurrentProcess()->program_id; | 392 | *result = current_process->GetTitleID(); |
| 378 | break; | 393 | break; |
| 379 | case GetInfoType::PrivilegedProcessId: | 394 | case GetInfoType::PrivilegedProcessId: |
| 380 | LOG_WARNING(Kernel_SVC, | 395 | LOG_WARNING(Kernel_SVC, |
| @@ -400,8 +415,36 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) { | |||
| 400 | } | 415 | } |
| 401 | 416 | ||
| 402 | /// Gets the thread context | 417 | /// Gets the thread context |
| 403 | static ResultCode GetThreadContext(Handle handle, VAddr addr) { | 418 | static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { |
| 404 | LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); | 419 | LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); |
| 420 | |||
| 421 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 422 | const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle); | ||
| 423 | if (!thread) { | ||
| 424 | return ERR_INVALID_HANDLE; | ||
| 425 | } | ||
| 426 | |||
| 427 | const auto current_process = Core::CurrentProcess(); | ||
| 428 | if (thread->owner_process != current_process) { | ||
| 429 | return ERR_INVALID_HANDLE; | ||
| 430 | } | ||
| 431 | |||
| 432 | if (thread == GetCurrentThread()) { | ||
| 433 | return ERR_ALREADY_REGISTERED; | ||
| 434 | } | ||
| 435 | |||
| 436 | Core::ARM_Interface::ThreadContext ctx = thread->context; | ||
| 437 | // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. | ||
| 438 | ctx.pstate &= 0xFF0FFE20; | ||
| 439 | |||
| 440 | // If 64-bit, we can just write the context registers directly and we're good. | ||
| 441 | // However, if 32-bit, we have to ensure some registers are zeroed out. | ||
| 442 | if (!current_process->Is64BitProcess()) { | ||
| 443 | std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0); | ||
| 444 | std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); | ||
| 445 | } | ||
| 446 | |||
| 447 | Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); | ||
| 405 | return RESULT_SUCCESS; | 448 | return RESULT_SUCCESS; |
| 406 | } | 449 | } |
| 407 | 450 | ||
| @@ -429,8 +472,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | |||
| 429 | 472 | ||
| 430 | // Note: The kernel uses the current process's resource limit instead of | 473 | // Note: The kernel uses the current process's resource limit instead of |
| 431 | // the one from the thread owner's resource limit. | 474 | // the one from the thread owner's resource limit. |
| 432 | SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; | 475 | const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); |
| 433 | if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { | 476 | if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { |
| 434 | return ERR_NOT_AUTHORIZED; | 477 | return ERR_NOT_AUTHORIZED; |
| 435 | } | 478 | } |
| 436 | 479 | ||
| @@ -504,9 +547,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i | |||
| 504 | if (!process) { | 547 | if (!process) { |
| 505 | return ERR_INVALID_HANDLE; | 548 | return ERR_INVALID_HANDLE; |
| 506 | } | 549 | } |
| 507 | auto vma = process->vm_manager.FindVMA(addr); | 550 | auto vma = process->VMManager().FindVMA(addr); |
| 508 | memory_info->attributes = 0; | 551 | memory_info->attributes = 0; |
| 509 | if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) { | 552 | if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) { |
| 510 | memory_info->base_address = 0; | 553 | memory_info->base_address = 0; |
| 511 | memory_info->permission = static_cast<u32>(VMAPermission::None); | 554 | memory_info->permission = static_cast<u32>(VMAPermission::None); |
| 512 | memory_info->size = 0; | 555 | memory_info->size = 0; |
| @@ -553,14 +596,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 553 | return ERR_INVALID_THREAD_PRIORITY; | 596 | return ERR_INVALID_THREAD_PRIORITY; |
| 554 | } | 597 | } |
| 555 | 598 | ||
| 556 | SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; | 599 | const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); |
| 557 | if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { | 600 | if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { |
| 558 | return ERR_NOT_AUTHORIZED; | 601 | return ERR_NOT_AUTHORIZED; |
| 559 | } | 602 | } |
| 560 | 603 | ||
| 561 | if (processor_id == THREADPROCESSORID_DEFAULT) { | 604 | if (processor_id == THREADPROCESSORID_DEFAULT) { |
| 562 | // Set the target CPU to the one specified in the process' exheader. | 605 | // Set the target CPU to the one specified in the process' exheader. |
| 563 | processor_id = Core::CurrentProcess()->ideal_processor; | 606 | processor_id = Core::CurrentProcess()->GetDefaultProcessorID(); |
| 564 | ASSERT(processor_id != THREADPROCESSORID_DEFAULT); | 607 | ASSERT(processor_id != THREADPROCESSORID_DEFAULT); |
| 565 | } | 608 | } |
| 566 | 609 | ||
| @@ -887,10 +930,10 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 887 | } | 930 | } |
| 888 | 931 | ||
| 889 | if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) { | 932 | if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) { |
| 890 | ASSERT(thread->owner_process->ideal_processor != | 933 | ASSERT(thread->owner_process->GetDefaultProcessorID() != |
| 891 | static_cast<u8>(THREADPROCESSORID_DEFAULT)); | 934 | static_cast<u8>(THREADPROCESSORID_DEFAULT)); |
| 892 | // Set the target CPU to the one specified in the process' exheader. | 935 | // Set the target CPU to the one specified in the process' exheader. |
| 893 | core = thread->owner_process->ideal_processor; | 936 | core = thread->owner_process->GetDefaultProcessorID(); |
| 894 | mask = 1ull << core; | 937 | mask = 1ull << core; |
| 895 | } | 938 | } |
| 896 | 939 | ||
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index fea9ba5ea..22712e64f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -64,6 +64,11 @@ void SvcWrap() { | |||
| 64 | FuncReturn(func(Param(0), (s32)Param(1)).raw); | 64 | FuncReturn(func(Param(0), (s32)Param(1)).raw); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | template <ResultCode func(u64, u32)> | ||
| 68 | void SvcWrap() { | ||
| 69 | FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw); | ||
| 70 | } | ||
| 71 | |||
| 67 | template <ResultCode func(u64*, u64)> | 72 | template <ResultCode func(u64*, u64)> |
| 68 | void SvcWrap() { | 73 | void SvcWrap() { |
| 69 | u64 param_1 = 0; | 74 | u64 param_1 = 0; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 315f65338..b5c16cfbb 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -259,11 +259,12 @@ void Thread::BoostPriority(u32 priority) { | |||
| 259 | SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, | 259 | SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, |
| 260 | Process& owner_process) { | 260 | Process& owner_process) { |
| 261 | // Setup page table so we can write to memory | 261 | // Setup page table so we can write to memory |
| 262 | SetCurrentPageTable(&owner_process.vm_manager.page_table); | 262 | SetCurrentPageTable(&owner_process.VMManager().page_table); |
| 263 | 263 | ||
| 264 | // Initialize new "main" thread | 264 | // Initialize new "main" thread |
| 265 | const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); | ||
| 265 | auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, | 266 | auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, |
| 266 | Memory::STACK_AREA_VADDR_END, &owner_process); | 267 | stack_top, &owner_process); |
| 267 | 268 | ||
| 268 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); | 269 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); |
| 269 | 270 | ||
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 608cbd57b..e412309fd 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/arm/arm_interface.h" | 10 | #include "core/arm/arm_interface.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/file_sys/program_metadata.h" | ||
| 12 | #include "core/hle/kernel/errors.h" | 13 | #include "core/hle/kernel/errors.h" |
| 13 | #include "core/hle/kernel/vm_manager.h" | 14 | #include "core/hle/kernel/vm_manager.h" |
| 14 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| @@ -54,30 +55,32 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { | |||
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | VMManager::VMManager() { | 57 | VMManager::VMManager() { |
| 57 | Reset(); | 58 | // Default to assuming a 39-bit address space. This way we have a sane |
| 59 | // starting point with executables that don't provide metadata. | ||
| 60 | Reset(FileSys::ProgramAddressSpaceType::Is39Bit); | ||
| 58 | } | 61 | } |
| 59 | 62 | ||
| 60 | VMManager::~VMManager() { | 63 | VMManager::~VMManager() { |
| 61 | Reset(); | 64 | Reset(FileSys::ProgramAddressSpaceType::Is39Bit); |
| 62 | } | 65 | } |
| 63 | 66 | ||
| 64 | void VMManager::Reset() { | 67 | void VMManager::Reset(FileSys::ProgramAddressSpaceType type) { |
| 65 | vma_map.clear(); | 68 | Clear(); |
| 69 | |||
| 70 | InitializeMemoryRegionRanges(type); | ||
| 71 | |||
| 72 | page_table.Resize(address_space_width); | ||
| 66 | 73 | ||
| 67 | // Initialize the map with a single free region covering the entire managed space. | 74 | // Initialize the map with a single free region covering the entire managed space. |
| 68 | VirtualMemoryArea initial_vma; | 75 | VirtualMemoryArea initial_vma; |
| 69 | initial_vma.size = MAX_ADDRESS; | 76 | initial_vma.size = address_space_end; |
| 70 | vma_map.emplace(initial_vma.base, initial_vma); | 77 | vma_map.emplace(initial_vma.base, initial_vma); |
| 71 | 78 | ||
| 72 | page_table.pointers.fill(nullptr); | ||
| 73 | page_table.special_regions.clear(); | ||
| 74 | page_table.attributes.fill(Memory::PageType::Unmapped); | ||
| 75 | |||
| 76 | UpdatePageTableForVMA(initial_vma); | 79 | UpdatePageTableForVMA(initial_vma); |
| 77 | } | 80 | } |
| 78 | 81 | ||
| 79 | VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { | 82 | VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { |
| 80 | if (target >= MAX_ADDRESS) { | 83 | if (target >= address_space_end) { |
| 81 | return vma_map.end(); | 84 | return vma_map.end(); |
| 82 | } else { | 85 | } else { |
| 83 | return std::prev(vma_map.upper_bound(target)); | 86 | return std::prev(vma_map.upper_bound(target)); |
| @@ -291,7 +294,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) { | |||
| 291 | 294 | ||
| 292 | const VAddr target_end = target + size; | 295 | const VAddr target_end = target + size; |
| 293 | ASSERT(target_end >= target); | 296 | ASSERT(target_end >= target); |
| 294 | ASSERT(target_end <= MAX_ADDRESS); | 297 | ASSERT(target_end <= address_space_end); |
| 295 | ASSERT(size > 0); | 298 | ASSERT(size > 0); |
| 296 | 299 | ||
| 297 | VMAIter begin_vma = StripIterConstness(FindVMA(target)); | 300 | VMAIter begin_vma = StripIterConstness(FindVMA(target)); |
| @@ -382,6 +385,85 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | |||
| 382 | } | 385 | } |
| 383 | } | 386 | } |
| 384 | 387 | ||
| 388 | void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) { | ||
| 389 | u64 map_region_size = 0; | ||
| 390 | u64 heap_region_size = 0; | ||
| 391 | u64 new_map_region_size = 0; | ||
| 392 | u64 tls_io_region_size = 0; | ||
| 393 | |||
| 394 | switch (type) { | ||
| 395 | case FileSys::ProgramAddressSpaceType::Is32Bit: | ||
| 396 | address_space_width = 32; | ||
| 397 | code_region_base = 0x200000; | ||
| 398 | code_region_end = code_region_base + 0x3FE00000; | ||
| 399 | map_region_size = 0x40000000; | ||
| 400 | heap_region_size = 0x40000000; | ||
| 401 | break; | ||
| 402 | case FileSys::ProgramAddressSpaceType::Is36Bit: | ||
| 403 | address_space_width = 36; | ||
| 404 | code_region_base = 0x8000000; | ||
| 405 | code_region_end = code_region_base + 0x78000000; | ||
| 406 | map_region_size = 0x180000000; | ||
| 407 | heap_region_size = 0x180000000; | ||
| 408 | break; | ||
| 409 | case FileSys::ProgramAddressSpaceType::Is32BitNoMap: | ||
| 410 | address_space_width = 32; | ||
| 411 | code_region_base = 0x200000; | ||
| 412 | code_region_end = code_region_base + 0x3FE00000; | ||
| 413 | map_region_size = 0; | ||
| 414 | heap_region_size = 0x80000000; | ||
| 415 | break; | ||
| 416 | case FileSys::ProgramAddressSpaceType::Is39Bit: | ||
| 417 | address_space_width = 39; | ||
| 418 | code_region_base = 0x8000000; | ||
| 419 | code_region_end = code_region_base + 0x80000000; | ||
| 420 | map_region_size = 0x1000000000; | ||
| 421 | heap_region_size = 0x180000000; | ||
| 422 | new_map_region_size = 0x80000000; | ||
| 423 | tls_io_region_size = 0x1000000000; | ||
| 424 | break; | ||
| 425 | default: | ||
| 426 | UNREACHABLE_MSG("Invalid address space type specified: {}", static_cast<u32>(type)); | ||
| 427 | return; | ||
| 428 | } | ||
| 429 | |||
| 430 | address_space_base = 0; | ||
| 431 | address_space_end = 1ULL << address_space_width; | ||
| 432 | |||
| 433 | map_region_base = code_region_end; | ||
| 434 | map_region_end = map_region_base + map_region_size; | ||
| 435 | |||
| 436 | heap_region_base = map_region_end; | ||
| 437 | heap_region_end = heap_region_base + heap_region_size; | ||
| 438 | |||
| 439 | new_map_region_base = heap_region_end; | ||
| 440 | new_map_region_end = new_map_region_base + new_map_region_size; | ||
| 441 | |||
| 442 | tls_io_region_base = new_map_region_end; | ||
| 443 | tls_io_region_end = tls_io_region_base + tls_io_region_size; | ||
| 444 | |||
| 445 | if (new_map_region_size == 0) { | ||
| 446 | new_map_region_base = address_space_base; | ||
| 447 | new_map_region_end = address_space_end; | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | void VMManager::Clear() { | ||
| 452 | ClearVMAMap(); | ||
| 453 | ClearPageTable(); | ||
| 454 | } | ||
| 455 | |||
| 456 | void VMManager::ClearVMAMap() { | ||
| 457 | vma_map.clear(); | ||
| 458 | } | ||
| 459 | |||
| 460 | void VMManager::ClearPageTable() { | ||
| 461 | std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr); | ||
| 462 | page_table.special_regions.clear(); | ||
| 463 | std::fill(page_table.attributes.begin(), page_table.attributes.end(), | ||
| 464 | Memory::PageType::Unmapped); | ||
| 465 | } | ||
| 466 | |||
| 385 | u64 VMManager::GetTotalMemoryUsage() const { | 467 | u64 VMManager::GetTotalMemoryUsage() const { |
| 386 | LOG_WARNING(Kernel, "(STUBBED) called"); | 468 | LOG_WARNING(Kernel, "(STUBBED) called"); |
| 387 | return 0xF8000000; | 469 | return 0xF8000000; |
| @@ -392,14 +474,80 @@ u64 VMManager::GetTotalHeapUsage() const { | |||
| 392 | return 0x0; | 474 | return 0x0; |
| 393 | } | 475 | } |
| 394 | 476 | ||
| 395 | VAddr VMManager::GetAddressSpaceBaseAddr() const { | 477 | VAddr VMManager::GetAddressSpaceBaseAddress() const { |
| 396 | LOG_WARNING(Kernel, "(STUBBED) called"); | 478 | return address_space_base; |
| 397 | return 0x8000000; | 479 | } |
| 480 | |||
| 481 | VAddr VMManager::GetAddressSpaceEndAddress() const { | ||
| 482 | return address_space_end; | ||
| 398 | } | 483 | } |
| 399 | 484 | ||
| 400 | u64 VMManager::GetAddressSpaceSize() const { | 485 | u64 VMManager::GetAddressSpaceSize() const { |
| 401 | LOG_WARNING(Kernel, "(STUBBED) called"); | 486 | return address_space_end - address_space_base; |
| 402 | return MAX_ADDRESS; | 487 | } |
| 488 | |||
| 489 | u64 VMManager::GetAddressSpaceWidth() const { | ||
| 490 | return address_space_width; | ||
| 491 | } | ||
| 492 | |||
| 493 | VAddr VMManager::GetCodeRegionBaseAddress() const { | ||
| 494 | return code_region_base; | ||
| 495 | } | ||
| 496 | |||
| 497 | VAddr VMManager::GetCodeRegionEndAddress() const { | ||
| 498 | return code_region_end; | ||
| 499 | } | ||
| 500 | |||
| 501 | u64 VMManager::GetCodeRegionSize() const { | ||
| 502 | return code_region_end - code_region_base; | ||
| 503 | } | ||
| 504 | |||
| 505 | VAddr VMManager::GetHeapRegionBaseAddress() const { | ||
| 506 | return heap_region_base; | ||
| 507 | } | ||
| 508 | |||
| 509 | VAddr VMManager::GetHeapRegionEndAddress() const { | ||
| 510 | return heap_region_end; | ||
| 511 | } | ||
| 512 | |||
| 513 | u64 VMManager::GetHeapRegionSize() const { | ||
| 514 | return heap_region_end - heap_region_base; | ||
| 515 | } | ||
| 516 | |||
| 517 | VAddr VMManager::GetMapRegionBaseAddress() const { | ||
| 518 | return map_region_base; | ||
| 519 | } | ||
| 520 | |||
| 521 | VAddr VMManager::GetMapRegionEndAddress() const { | ||
| 522 | return map_region_end; | ||
| 523 | } | ||
| 524 | |||
| 525 | u64 VMManager::GetMapRegionSize() const { | ||
| 526 | return map_region_end - map_region_base; | ||
| 527 | } | ||
| 528 | |||
| 529 | VAddr VMManager::GetNewMapRegionBaseAddress() const { | ||
| 530 | return new_map_region_base; | ||
| 531 | } | ||
| 532 | |||
| 533 | VAddr VMManager::GetNewMapRegionEndAddress() const { | ||
| 534 | return new_map_region_end; | ||
| 535 | } | ||
| 536 | |||
| 537 | u64 VMManager::GetNewMapRegionSize() const { | ||
| 538 | return new_map_region_end - new_map_region_base; | ||
| 539 | } | ||
| 540 | |||
| 541 | VAddr VMManager::GetTLSIORegionBaseAddress() const { | ||
| 542 | return tls_io_region_base; | ||
| 543 | } | ||
| 544 | |||
| 545 | VAddr VMManager::GetTLSIORegionEndAddress() const { | ||
| 546 | return tls_io_region_end; | ||
| 547 | } | ||
| 548 | |||
| 549 | u64 VMManager::GetTLSIORegionSize() const { | ||
| 550 | return tls_io_region_end - tls_io_region_base; | ||
| 403 | } | 551 | } |
| 404 | 552 | ||
| 405 | } // namespace Kernel | 553 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index de75036c0..015559a64 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -12,6 +12,10 @@ | |||
| 12 | #include "core/memory.h" | 12 | #include "core/memory.h" |
| 13 | #include "core/memory_hook.h" | 13 | #include "core/memory_hook.h" |
| 14 | 14 | ||
| 15 | namespace FileSys { | ||
| 16 | enum class ProgramAddressSpaceType : u8; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace Kernel { | 19 | namespace Kernel { |
| 16 | 20 | ||
| 17 | enum class VMAType : u8 { | 21 | enum class VMAType : u8 { |
| @@ -111,12 +115,6 @@ struct VirtualMemoryArea { | |||
| 111 | class VMManager final { | 115 | class VMManager final { |
| 112 | public: | 116 | public: |
| 113 | /** | 117 | /** |
| 114 | * The maximum amount of address space managed by the kernel. | ||
| 115 | * @todo This was selected arbitrarily, and should be verified for Switch OS. | ||
| 116 | */ | ||
| 117 | static constexpr VAddr MAX_ADDRESS{0x1000000000ULL}; | ||
| 118 | |||
| 119 | /** | ||
| 120 | * A map covering the entirety of the managed address space, keyed by the `base` field of each | 118 | * A map covering the entirety of the managed address space, keyed by the `base` field of each |
| 121 | * VMA. It must always be modified by splitting or merging VMAs, so that the invariant | 119 | * VMA. It must always be modified by splitting or merging VMAs, so that the invariant |
| 122 | * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be | 120 | * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be |
| @@ -130,7 +128,7 @@ public: | |||
| 130 | ~VMManager(); | 128 | ~VMManager(); |
| 131 | 129 | ||
| 132 | /// Clears the address space map, re-initializing with a single free area. | 130 | /// Clears the address space map, re-initializing with a single free area. |
| 133 | void Reset(); | 131 | void Reset(FileSys::ProgramAddressSpaceType type); |
| 134 | 132 | ||
| 135 | /// Finds the VMA in which the given address is included in, or `vma_map.end()`. | 133 | /// Finds the VMA in which the given address is included in, or `vma_map.end()`. |
| 136 | VMAHandle FindVMA(VAddr target) const; | 134 | VMAHandle FindVMA(VAddr target) const; |
| @@ -195,12 +193,63 @@ public: | |||
| 195 | /// Gets the total heap usage, used by svcGetInfo | 193 | /// Gets the total heap usage, used by svcGetInfo |
| 196 | u64 GetTotalHeapUsage() const; | 194 | u64 GetTotalHeapUsage() const; |
| 197 | 195 | ||
| 198 | /// Gets the total address space base address, used by svcGetInfo | 196 | /// Gets the address space base address |
| 199 | VAddr GetAddressSpaceBaseAddr() const; | 197 | VAddr GetAddressSpaceBaseAddress() const; |
| 200 | 198 | ||
| 201 | /// Gets the total address space address size, used by svcGetInfo | 199 | /// Gets the address space end address |
| 200 | VAddr GetAddressSpaceEndAddress() const; | ||
| 201 | |||
| 202 | /// Gets the total address space address size in bytes | ||
| 202 | u64 GetAddressSpaceSize() const; | 203 | u64 GetAddressSpaceSize() const; |
| 203 | 204 | ||
| 205 | /// Gets the address space width in bits. | ||
| 206 | u64 GetAddressSpaceWidth() const; | ||
| 207 | |||
| 208 | /// Gets the base address of the code region. | ||
| 209 | VAddr GetCodeRegionBaseAddress() const; | ||
| 210 | |||
| 211 | /// Gets the end address of the code region. | ||
| 212 | VAddr GetCodeRegionEndAddress() const; | ||
| 213 | |||
| 214 | /// Gets the total size of the code region in bytes. | ||
| 215 | u64 GetCodeRegionSize() const; | ||
| 216 | |||
| 217 | /// Gets the base address of the heap region. | ||
| 218 | VAddr GetHeapRegionBaseAddress() const; | ||
| 219 | |||
| 220 | /// Gets the end address of the heap region; | ||
| 221 | VAddr GetHeapRegionEndAddress() const; | ||
| 222 | |||
| 223 | /// Gets the total size of the heap region in bytes. | ||
| 224 | u64 GetHeapRegionSize() const; | ||
| 225 | |||
| 226 | /// Gets the base address of the map region. | ||
| 227 | VAddr GetMapRegionBaseAddress() const; | ||
| 228 | |||
| 229 | /// Gets the end address of the map region. | ||
| 230 | VAddr GetMapRegionEndAddress() const; | ||
| 231 | |||
| 232 | /// Gets the total size of the map region in bytes. | ||
| 233 | u64 GetMapRegionSize() const; | ||
| 234 | |||
| 235 | /// Gets the base address of the new map region. | ||
| 236 | VAddr GetNewMapRegionBaseAddress() const; | ||
| 237 | |||
| 238 | /// Gets the end address of the new map region. | ||
| 239 | VAddr GetNewMapRegionEndAddress() const; | ||
| 240 | |||
| 241 | /// Gets the total size of the new map region in bytes. | ||
| 242 | u64 GetNewMapRegionSize() const; | ||
| 243 | |||
| 244 | /// Gets the base address of the TLS IO region. | ||
| 245 | VAddr GetTLSIORegionBaseAddress() const; | ||
| 246 | |||
| 247 | /// Gets the end address of the TLS IO region. | ||
| 248 | VAddr GetTLSIORegionEndAddress() const; | ||
| 249 | |||
| 250 | /// Gets the total size of the TLS IO region in bytes. | ||
| 251 | u64 GetTLSIORegionSize() const; | ||
| 252 | |||
| 204 | /// Each VMManager has its own page table, which is set as the main one when the owning process | 253 | /// Each VMManager has its own page table, which is set as the main one when the owning process |
| 205 | /// is scheduled. | 254 | /// is scheduled. |
| 206 | Memory::PageTable page_table; | 255 | Memory::PageTable page_table; |
| @@ -240,5 +289,36 @@ private: | |||
| 240 | 289 | ||
| 241 | /// Updates the pages corresponding to this VMA so they match the VMA's attributes. | 290 | /// Updates the pages corresponding to this VMA so they match the VMA's attributes. |
| 242 | void UpdatePageTableForVMA(const VirtualMemoryArea& vma); | 291 | void UpdatePageTableForVMA(const VirtualMemoryArea& vma); |
| 292 | |||
| 293 | /// Initializes memory region ranges to adhere to a given address space type. | ||
| 294 | void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type); | ||
| 295 | |||
| 296 | /// Clears the underlying map and page table. | ||
| 297 | void Clear(); | ||
| 298 | |||
| 299 | /// Clears out the VMA map, unmapping any previously mapped ranges. | ||
| 300 | void ClearVMAMap(); | ||
| 301 | |||
| 302 | /// Clears out the page table | ||
| 303 | void ClearPageTable(); | ||
| 304 | |||
| 305 | u32 address_space_width = 0; | ||
| 306 | VAddr address_space_base = 0; | ||
| 307 | VAddr address_space_end = 0; | ||
| 308 | |||
| 309 | VAddr code_region_base = 0; | ||
| 310 | VAddr code_region_end = 0; | ||
| 311 | |||
| 312 | VAddr heap_region_base = 0; | ||
| 313 | VAddr heap_region_end = 0; | ||
| 314 | |||
| 315 | VAddr map_region_base = 0; | ||
| 316 | VAddr map_region_end = 0; | ||
| 317 | |||
| 318 | VAddr new_map_region_base = 0; | ||
| 319 | VAddr new_map_region_end = 0; | ||
| 320 | |||
| 321 | VAddr tls_io_region_base = 0; | ||
| 322 | VAddr tls_io_region_end = 0; | ||
| 243 | }; | 323 | }; |
| 244 | } // namespace Kernel | 324 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 0bd97133c..f4367ee28 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h | |||
| @@ -69,7 +69,7 @@ private: | |||
| 69 | template <> | 69 | template <> |
| 70 | inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { | 70 | inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { |
| 71 | if (object != nullptr && object->IsWaitable()) { | 71 | if (object != nullptr && object->IsWaitable()) { |
| 72 | return boost::static_pointer_cast<WaitObject>(std::move(object)); | 72 | return boost::static_pointer_cast<WaitObject>(object); |
| 73 | } | 73 | } |
| 74 | return nullptr; | 74 | return nullptr; |
| 75 | } | 75 | } |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 80ed4b152..6073f4ecd 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/alignment.h" | 10 | #include "common/alignment.h" |
| 11 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "core/core.h" | ||
| 13 | #include "core/hle/ipc_helpers.h" | 14 | #include "core/hle/ipc_helpers.h" |
| 14 | #include "core/hle/kernel/event.h" | 15 | #include "core/hle/kernel/event.h" |
| 15 | #include "core/hle/kernel/hle_ipc.h" | 16 | #include "core/hle/kernel/hle_ipc.h" |
| @@ -65,7 +66,7 @@ private: | |||
| 65 | void GetAudioRendererState(Kernel::HLERequestContext& ctx) { | 66 | void GetAudioRendererState(Kernel::HLERequestContext& ctx) { |
| 66 | IPC::ResponseBuilder rb{ctx, 3}; | 67 | IPC::ResponseBuilder rb{ctx, 3}; |
| 67 | rb.Push(RESULT_SUCCESS); | 68 | rb.Push(RESULT_SUCCESS); |
| 68 | rb.Push<u32>(renderer->GetState()); | 69 | rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); |
| 69 | LOG_DEBUG(Service_Audio, "called"); | 70 | LOG_DEBUG(Service_Audio, "called"); |
| 70 | } | 71 | } |
| 71 | 72 | ||
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 6de7edf9e..2f15ac2a6 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp | |||
| @@ -6,11 +6,11 @@ | |||
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include <ctime> | 7 | #include <ctime> |
| 8 | #include <fmt/time.h> | 8 | #include <fmt/time.h> |
| 9 | #include "common/common_paths.h" | ||
| 10 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 11 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 12 | #include "common/scm_rev.h" | 11 | #include "common/scm_rev.h" |
| 13 | #include "common/swap.h" | 12 | #include "common/swap.h" |
| 13 | #include "core/core.h" | ||
| 14 | #include "core/hle/ipc_helpers.h" | 14 | #include "core/hle/ipc_helpers.h" |
| 15 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 16 | #include "core/hle/service/fatal/fatal.h" | 16 | #include "core/hle/service/fatal/fatal.h" |
| @@ -51,7 +51,7 @@ enum class FatalType : u32 { | |||
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { | 53 | static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { |
| 54 | const auto title_id = Core::CurrentProcess()->program_id; | 54 | const auto title_id = Core::CurrentProcess()->GetTitleID(); |
| 55 | std::string crash_report = | 55 | std::string crash_report = |
| 56 | fmt::format("Yuzu {}-{} crash report\n" | 56 | fmt::format("Yuzu {}-{} crash report\n" |
| 57 | "Title ID: {:016x}\n" | 57 | "Title ID: {:016x}\n" |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index f8d2127d9..8c07a05c2 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | 7 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/event.h" | 8 | #include "core/hle/kernel/event.h" |
| 8 | #include "core/hle/service/hid/hid.h" | 9 | #include "core/hle/service/hid/hid.h" |
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index c1737defa..261ad539c 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <chrono> | 5 | #include <chrono> |
| 6 | #include <ctime> | 6 | #include <ctime> |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 8 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 9 | #include "core/hle/service/nim/nim.h" | 10 | #include "core/hle/service/nim/nim.h" |
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 1069d103f..4b2f758a8 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -317,9 +317,9 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | |||
| 317 | 317 | ||
| 318 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | 318 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { |
| 319 | // Map backing memory for the font data | 319 | // Map backing memory for the font data |
| 320 | Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, | 320 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, |
| 321 | SHARED_FONT_MEM_SIZE, | 321 | SHARED_FONT_MEM_SIZE, |
| 322 | Kernel::MemoryState::Shared); | 322 | Kernel::MemoryState::Shared); |
| 323 | 323 | ||
| 324 | // Create shared font memory object | 324 | // Create shared font memory object |
| 325 | auto& kernel = Core::System::GetInstance().Kernel(); | 325 | auto& kernel = Core::System::GetInstance().Kernel(); |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index cdf328a26..98f6e4111 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -2,8 +2,11 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/assert.h" | ||
| 5 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 6 | #include "core/hle/ipc_helpers.h" | 7 | #include "core/hle/ipc_helpers.h" |
| 8 | #include "core/hle/kernel/client_session.h" | ||
| 9 | #include "core/hle/kernel/server_session.h" | ||
| 7 | #include "core/hle/kernel/session.h" | 10 | #include "core/hle/kernel/session.h" |
| 8 | #include "core/hle/service/sm/controller.h" | 11 | #include "core/hle/service/sm/controller.h" |
| 9 | 12 | ||
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 2ee60f1ec..bbc02abcc 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -612,7 +612,7 @@ public: | |||
| 612 | {3000, nullptr, "ListDisplayModes"}, | 612 | {3000, nullptr, "ListDisplayModes"}, |
| 613 | {3001, nullptr, "ListDisplayRgbRanges"}, | 613 | {3001, nullptr, "ListDisplayRgbRanges"}, |
| 614 | {3002, nullptr, "ListDisplayContentTypes"}, | 614 | {3002, nullptr, "ListDisplayContentTypes"}, |
| 615 | {3200, nullptr, "GetDisplayMode"}, | 615 | {3200, &ISystemDisplayService::GetDisplayMode, "GetDisplayMode"}, |
| 616 | {3201, nullptr, "SetDisplayMode"}, | 616 | {3201, nullptr, "SetDisplayMode"}, |
| 617 | {3202, nullptr, "GetDisplayUnderscan"}, | 617 | {3202, nullptr, "GetDisplayUnderscan"}, |
| 618 | {3203, nullptr, "SetDisplayUnderscan"}, | 618 | {3203, nullptr, "SetDisplayUnderscan"}, |
| @@ -663,6 +663,24 @@ private: | |||
| 663 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, | 663 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, |
| 664 | visibility); | 664 | visibility); |
| 665 | } | 665 | } |
| 666 | |||
| 667 | void GetDisplayMode(Kernel::HLERequestContext& ctx) { | ||
| 668 | IPC::ResponseBuilder rb{ctx, 6}; | ||
| 669 | rb.Push(RESULT_SUCCESS); | ||
| 670 | |||
| 671 | if (Settings::values.use_docked_mode) { | ||
| 672 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); | ||
| 673 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); | ||
| 674 | } else { | ||
| 675 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); | ||
| 676 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); | ||
| 677 | } | ||
| 678 | |||
| 679 | rb.PushRaw<float>(60.0f); | ||
| 680 | rb.Push<u32>(0); | ||
| 681 | |||
| 682 | LOG_DEBUG(Service_VI, "called"); | ||
| 683 | } | ||
| 666 | }; | 684 | }; |
| 667 | 685 | ||
| 668 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 686 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 2b8f78136..c1824b9c3 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -14,11 +14,9 @@ | |||
| 14 | #include "core/gdbstub/gdbstub.h" | 14 | #include "core/gdbstub/gdbstub.h" |
| 15 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/process.h" | 16 | #include "core/hle/kernel/process.h" |
| 17 | #include "core/hle/kernel/resource_limit.h" | ||
| 18 | #include "core/hle/service/filesystem/filesystem.h" | 17 | #include "core/hle/service/filesystem/filesystem.h" |
| 19 | #include "core/loader/deconstructed_rom_directory.h" | 18 | #include "core/loader/deconstructed_rom_directory.h" |
| 20 | #include "core/loader/nso.h" | 19 | #include "core/loader/nso.h" |
| 21 | #include "core/memory.h" | ||
| 22 | 20 | ||
| 23 | namespace Loader { | 21 | namespace Loader { |
| 24 | 22 | ||
| @@ -88,8 +86,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua | |||
| 88 | return FileType::Error; | 86 | return FileType::Error; |
| 89 | } | 87 | } |
| 90 | 88 | ||
| 91 | ResultStatus AppLoader_DeconstructedRomDirectory::Load( | 89 | ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) { |
| 92 | Kernel::SharedPtr<Kernel::Process>& process) { | ||
| 93 | if (is_loaded) { | 90 | if (is_loaded) { |
| 94 | return ResultStatus::ErrorAlreadyLoaded; | 91 | return ResultStatus::ErrorAlreadyLoaded; |
| 95 | } | 92 | } |
| @@ -127,12 +124,16 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 127 | metadata.Print(); | 124 | metadata.Print(); |
| 128 | 125 | ||
| 129 | const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; | 126 | const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; |
| 130 | if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { | 127 | if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit || |
| 128 | arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { | ||
| 131 | return ResultStatus::Error32BitISA; | 129 | return ResultStatus::Error32BitISA; |
| 132 | } | 130 | } |
| 133 | 131 | ||
| 132 | process.LoadFromMetadata(metadata); | ||
| 133 | |||
| 134 | // Load NSO modules | 134 | // Load NSO modules |
| 135 | VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; | 135 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 136 | VAddr next_load_addr = base_address; | ||
| 136 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", | 137 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", |
| 137 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { | 138 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { |
| 138 | const FileSys::VirtualFile module_file = dir->GetFile(module); | 139 | const FileSys::VirtualFile module_file = dir->GetFile(module); |
| @@ -145,13 +146,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 145 | } | 146 | } |
| 146 | } | 147 | } |
| 147 | 148 | ||
| 148 | auto& kernel = Core::System::GetInstance().Kernel(); | 149 | process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); |
| 149 | process->program_id = metadata.GetTitleID(); | ||
| 150 | process->svc_access_mask.set(); | ||
| 151 | process->resource_limit = | ||
| 152 | kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 153 | process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), | ||
| 154 | metadata.GetMainThreadStackSize()); | ||
| 155 | 150 | ||
| 156 | // Find the RomFS by searching for a ".romfs" file in this directory | 151 | // Find the RomFS by searching for a ".romfs" file in this directory |
| 157 | const auto& files = dir->GetFiles(); | 152 | const auto& files = dir->GetFiles(); |
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 8a0dc1b1e..d109ed2b5 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/file_sys/program_metadata.h" | 9 | #include "core/file_sys/program_metadata.h" |
| 10 | #include "core/hle/kernel/object.h" | ||
| 11 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 12 | 11 | ||
| 13 | namespace Loader { | 12 | namespace Loader { |
| @@ -38,7 +37,7 @@ public: | |||
| 38 | return IdentifyType(file); | 37 | return IdentifyType(file); |
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 40 | ResultStatus Load(Kernel::Process& process) override; |
| 42 | 41 | ||
| 43 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 42 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 44 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 43 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 0e2af20b4..e67b49fc9 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/kernel/resource_limit.h" | 15 | #include "core/hle/kernel/vm_manager.h" |
| 16 | #include "core/loader/elf.h" | 16 | #include "core/loader/elf.h" |
| 17 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 18 | 18 | ||
| @@ -189,7 +189,7 @@ private: | |||
| 189 | 189 | ||
| 190 | u32* sectionAddrs; | 190 | u32* sectionAddrs; |
| 191 | bool relocate; | 191 | bool relocate; |
| 192 | u32 entryPoint; | 192 | VAddr entryPoint; |
| 193 | 193 | ||
| 194 | public: | 194 | public: |
| 195 | explicit ElfReader(void* ptr); | 195 | explicit ElfReader(void* ptr); |
| @@ -205,13 +205,13 @@ public: | |||
| 205 | ElfMachine GetMachine() const { | 205 | ElfMachine GetMachine() const { |
| 206 | return (ElfMachine)(header->e_machine); | 206 | return (ElfMachine)(header->e_machine); |
| 207 | } | 207 | } |
| 208 | u32 GetEntryPoint() const { | 208 | VAddr GetEntryPoint() const { |
| 209 | return entryPoint; | 209 | return entryPoint; |
| 210 | } | 210 | } |
| 211 | u32 GetFlags() const { | 211 | u32 GetFlags() const { |
| 212 | return (u32)(header->e_flags); | 212 | return (u32)(header->e_flags); |
| 213 | } | 213 | } |
| 214 | SharedPtr<CodeSet> LoadInto(u32 vaddr); | 214 | SharedPtr<CodeSet> LoadInto(VAddr vaddr); |
| 215 | 215 | ||
| 216 | int GetNumSegments() const { | 216 | int GetNumSegments() const { |
| 217 | return (int)(header->e_phnum); | 217 | return (int)(header->e_phnum); |
| @@ -274,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const { | |||
| 274 | return nullptr; | 274 | return nullptr; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | 277 | SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) { |
| 278 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); | 278 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); |
| 279 | 279 | ||
| 280 | // Should we relocate? | 280 | // Should we relocate? |
| @@ -289,11 +289,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 289 | LOG_DEBUG(Loader, "{} segments:", header->e_phnum); | 289 | LOG_DEBUG(Loader, "{} segments:", header->e_phnum); |
| 290 | 290 | ||
| 291 | // First pass : Get the bits into RAM | 291 | // First pass : Get the bits into RAM |
| 292 | u32 base_addr = relocate ? vaddr : 0; | 292 | const VAddr base_addr = relocate ? vaddr : 0; |
| 293 | 293 | ||
| 294 | u32 total_image_size = 0; | 294 | u64 total_image_size = 0; |
| 295 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | 295 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 296 | Elf32_Phdr* p = &segments[i]; | 296 | const Elf32_Phdr* p = &segments[i]; |
| 297 | if (p->p_type == PT_LOAD) { | 297 | if (p->p_type == PT_LOAD) { |
| 298 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; | 298 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; |
| 299 | } | 299 | } |
| @@ -306,7 +306,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 306 | SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, ""); | 306 | SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, ""); |
| 307 | 307 | ||
| 308 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | 308 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 309 | Elf32_Phdr* p = &segments[i]; | 309 | const Elf32_Phdr* p = &segments[i]; |
| 310 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, | 310 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, |
| 311 | p->p_vaddr, p->p_filesz, p->p_memsz); | 311 | p->p_vaddr, p->p_filesz, p->p_memsz); |
| 312 | 312 | ||
| @@ -333,8 +333,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 333 | continue; | 333 | continue; |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | u32 segment_addr = base_addr + p->p_vaddr; | 336 | const VAddr segment_addr = base_addr + p->p_vaddr; |
| 337 | u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; | 337 | const u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; |
| 338 | 338 | ||
| 339 | codeset_segment->offset = current_image_position; | 339 | codeset_segment->offset = current_image_position; |
| 340 | codeset_segment->addr = segment_addr; | 340 | codeset_segment->addr = segment_addr; |
| @@ -387,7 +387,7 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 387 | return FileType::Error; | 387 | return FileType::Error; |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 390 | ResultStatus AppLoader_ELF::Load(Kernel::Process& process) { |
| 391 | if (is_loaded) | 391 | if (is_loaded) |
| 392 | return ResultStatus::ErrorAlreadyLoaded; | 392 | return ResultStatus::ErrorAlreadyLoaded; |
| 393 | 393 | ||
| @@ -395,19 +395,13 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 395 | if (buffer.size() != file->GetSize()) | 395 | if (buffer.size() != file->GetSize()) |
| 396 | return ResultStatus::ErrorIncorrectELFFileSize; | 396 | return ResultStatus::ErrorIncorrectELFFileSize; |
| 397 | 397 | ||
| 398 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); | ||
| 398 | ElfReader elf_reader(&buffer[0]); | 399 | ElfReader elf_reader(&buffer[0]); |
| 399 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); | 400 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address); |
| 400 | codeset->name = file->GetName(); | 401 | codeset->name = file->GetName(); |
| 401 | 402 | ||
| 402 | process->LoadModule(codeset, codeset->entrypoint); | 403 | process.LoadModule(codeset, codeset->entrypoint); |
| 403 | process->svc_access_mask.set(); | 404 | process.Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); |
| 404 | |||
| 405 | // Attach the default resource limit (APPLICATION) to the process | ||
| 406 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 407 | process->resource_limit = | ||
| 408 | kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 409 | |||
| 410 | process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); | ||
| 411 | 405 | ||
| 412 | is_loaded = true; | 406 | is_loaded = true; |
| 413 | return ResultStatus::Success; | 407 | return ResultStatus::Success; |
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h index b8fb982d0..6af76441c 100644 --- a/src/core/loader/elf.h +++ b/src/core/loader/elf.h | |||
| @@ -8,9 +8,6 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/loader/loader.h" | 9 | #include "core/loader/loader.h" |
| 10 | 10 | ||
| 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 12 | // Loader namespace | ||
| 13 | |||
| 14 | namespace Loader { | 11 | namespace Loader { |
| 15 | 12 | ||
| 16 | /// Loads an ELF/AXF file | 13 | /// Loads an ELF/AXF file |
| @@ -29,7 +26,7 @@ public: | |||
| 29 | return IdentifyType(file); | 26 | return IdentifyType(file); |
| 30 | } | 27 | } |
| 31 | 28 | ||
| 32 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 29 | ResultStatus Load(Kernel::Process& process) override; |
| 33 | }; | 30 | }; |
| 34 | 31 | ||
| 35 | } // namespace Loader | 32 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 843c4bb91..20e66109b 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <boost/optional.hpp> | 12 | #include <boost/optional.hpp> |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "core/file_sys/vfs.h" | 14 | #include "core/file_sys/vfs.h" |
| 15 | #include "core/hle/kernel/object.h" | ||
| 16 | 15 | ||
| 17 | namespace Kernel { | 16 | namespace Kernel { |
| 18 | struct AddressMapping; | 17 | struct AddressMapping; |
| @@ -136,7 +135,7 @@ public: | |||
| 136 | * @param process The newly created process. | 135 | * @param process The newly created process. |
| 137 | * @return The status result of the operation. | 136 | * @return The status result of the operation. |
| 138 | */ | 137 | */ |
| 139 | virtual ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) = 0; | 138 | virtual ResultStatus Load(Kernel::Process& process) = 0; |
| 140 | 139 | ||
| 141 | /** | 140 | /** |
| 142 | * Loads the system mode that this application needs. | 141 | * Loads the system mode that this application needs. |
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index 5d4380684..073fb9d2f 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp | |||
| @@ -41,7 +41,7 @@ FileType AppLoader_NAX::GetFileType() { | |||
| 41 | return IdentifyTypeImpl(*nax); | 41 | return IdentifyTypeImpl(*nax); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 44 | ResultStatus AppLoader_NAX::Load(Kernel::Process& process) { |
| 45 | if (is_loaded) { | 45 | if (is_loaded) { |
| 46 | return ResultStatus::ErrorAlreadyLoaded; | 46 | return ResultStatus::ErrorAlreadyLoaded; |
| 47 | } | 47 | } |
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index 56605fe45..fc3c01876 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h | |||
| @@ -33,7 +33,7 @@ public: | |||
| 33 | 33 | ||
| 34 | FileType GetFileType() override; | 34 | FileType GetFileType() override; |
| 35 | 35 | ||
| 36 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 36 | ResultStatus Load(Kernel::Process& process) override; |
| 37 | 37 | ||
| 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 39 | ResultStatus ReadProgramId(u64& out_program_id) override; | 39 | ResultStatus ReadProgramId(u64& out_program_id) override; |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 6aaffae59..7e1b0d84f 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -30,7 +30,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 30 | return FileType::Error; | 30 | return FileType::Error; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 33 | ResultStatus AppLoader_NCA::Load(Kernel::Process& process) { |
| 34 | if (is_loaded) { | 34 | if (is_loaded) { |
| 35 | return ResultStatus::ErrorAlreadyLoaded; | 35 | return ResultStatus::ErrorAlreadyLoaded; |
| 36 | } | 36 | } |
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 10be197c4..95d9b73a1 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/file_sys/vfs.h" | 8 | #include "core/file_sys/vfs.h" |
| 9 | #include "core/hle/kernel/object.h" | ||
| 10 | #include "core/loader/loader.h" | 9 | #include "core/loader/loader.h" |
| 11 | 10 | ||
| 12 | namespace FileSys { | 11 | namespace FileSys { |
| @@ -34,7 +33,7 @@ public: | |||
| 34 | return IdentifyType(file); | 33 | return IdentifyType(file); |
| 35 | } | 34 | } |
| 36 | 35 | ||
| 37 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 36 | ResultStatus Load(Kernel::Process& process) override; |
| 38 | 37 | ||
| 39 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 38 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 40 | u64 ReadRomFSIVFCOffset() const override; | 39 | u64 ReadRomFSIVFCOffset() const override; |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index c49ec34ab..c10f826a4 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | #include "core/gdbstub/gdbstub.h" | 16 | #include "core/gdbstub/gdbstub.h" |
| 17 | #include "core/hle/kernel/kernel.h" | 17 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/process.h" | 18 | #include "core/hle/kernel/process.h" |
| 19 | #include "core/hle/kernel/resource_limit.h" | 19 | #include "core/hle/kernel/vm_manager.h" |
| 20 | #include "core/loader/nro.h" | 20 | #include "core/loader/nro.h" |
| 21 | #include "core/memory.h" | 21 | #include "core/memory.h" |
| 22 | 22 | ||
| @@ -175,23 +175,19 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) { | |||
| 175 | return true; | 175 | return true; |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 178 | ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { |
| 179 | if (is_loaded) { | 179 | if (is_loaded) { |
| 180 | return ResultStatus::ErrorAlreadyLoaded; | 180 | return ResultStatus::ErrorAlreadyLoaded; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | // Load NRO | 183 | // Load NRO |
| 184 | static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; | 184 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 185 | 185 | ||
| 186 | if (!LoadNro(file, base_addr)) { | 186 | if (!LoadNro(file, base_address)) { |
| 187 | return ResultStatus::ErrorLoadingNRO; | 187 | return ResultStatus::ErrorLoadingNRO; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | auto& kernel = Core::System::GetInstance().Kernel(); | 190 | process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); |
| 191 | process->svc_access_mask.set(); | ||
| 192 | process->resource_limit = | ||
| 193 | kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 194 | process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); | ||
| 195 | 191 | ||
| 196 | is_loaded = true; | 192 | is_loaded = true; |
| 197 | return ResultStatus::Success; | 193 | return ResultStatus::Success; |
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 96d2de305..04b46119a 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/hle/kernel/object.h" | ||
| 10 | #include "core/loader/linker.h" | 9 | #include "core/loader/linker.h" |
| 11 | #include "core/loader/loader.h" | 10 | #include "core/loader/loader.h" |
| 12 | 11 | ||
| @@ -33,7 +32,7 @@ public: | |||
| 33 | return IdentifyType(file); | 32 | return IdentifyType(file); |
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 35 | ResultStatus Load(Kernel::Process& process) override; |
| 37 | 36 | ||
| 38 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 37 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 39 | ResultStatus ReadProgramId(u64& out_program_id) override; | 38 | ResultStatus ReadProgramId(u64& out_program_id) override; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 78a4438c4..cbe2a3e53 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #include "core/gdbstub/gdbstub.h" | 13 | #include "core/gdbstub/gdbstub.h" |
| 14 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 16 | #include "core/hle/kernel/resource_limit.h" | 16 | #include "core/hle/kernel/vm_manager.h" |
| 17 | #include "core/loader/nso.h" | 17 | #include "core/loader/nso.h" |
| 18 | #include "core/memory.h" | 18 | #include "core/memory.h" |
| 19 | 19 | ||
| @@ -153,21 +153,17 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) { | |||
| 153 | return load_base + image_size; | 153 | return load_base + image_size; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 156 | ResultStatus AppLoader_NSO::Load(Kernel::Process& process) { |
| 157 | if (is_loaded) { | 157 | if (is_loaded) { |
| 158 | return ResultStatus::ErrorAlreadyLoaded; | 158 | return ResultStatus::ErrorAlreadyLoaded; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | // Load module | 161 | // Load module |
| 162 | LoadModule(file, Memory::PROCESS_IMAGE_VADDR); | 162 | const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); |
| 163 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); | 163 | LoadModule(file, base_address); |
| 164 | LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); | ||
| 164 | 165 | ||
| 165 | auto& kernel = Core::System::GetInstance().Kernel(); | 166 | process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); |
| 166 | process->svc_access_mask.set(); | ||
| 167 | process->resource_limit = | ||
| 168 | kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); | ||
| 169 | process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT, | ||
| 170 | Memory::DEFAULT_STACK_SIZE); | ||
| 171 | 167 | ||
| 172 | is_loaded = true; | 168 | is_loaded = true; |
| 173 | return ResultStatus::Success; | 169 | return ResultStatus::Success; |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index aaeb1f2a9..7f142405b 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -4,9 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 9 | #include "core/hle/kernel/object.h" | ||
| 10 | #include "core/loader/linker.h" | 8 | #include "core/loader/linker.h" |
| 11 | #include "core/loader/loader.h" | 9 | #include "core/loader/loader.h" |
| 12 | 10 | ||
| @@ -30,7 +28,7 @@ public: | |||
| 30 | 28 | ||
| 31 | static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base); | 29 | static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base); |
| 32 | 30 | ||
| 33 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 31 | ResultStatus Load(Kernel::Process& process) override; |
| 34 | }; | 32 | }; |
| 35 | 33 | ||
| 36 | } // namespace Loader | 34 | } // namespace Loader |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 291a9876d..b7ba77ef4 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | #include "core/file_sys/control_metadata.h" | 10 | #include "core/file_sys/control_metadata.h" |
| 11 | #include "core/file_sys/nca_metadata.h" | 11 | #include "core/file_sys/nca_metadata.h" |
| 12 | #include "core/file_sys/patch_manager.h" | 12 | #include "core/file_sys/patch_manager.h" |
| 13 | #include "core/file_sys/registered_cache.h" | ||
| 14 | #include "core/file_sys/romfs.h" | ||
| 15 | #include "core/file_sys/submission_package.h" | 13 | #include "core/file_sys/submission_package.h" |
| 16 | #include "core/hle/kernel/process.h" | 14 | #include "core/hle/kernel/process.h" |
| 17 | #include "core/loader/deconstructed_rom_directory.h" | 15 | #include "core/loader/deconstructed_rom_directory.h" |
| @@ -62,7 +60,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 62 | return FileType::Error; | 60 | return FileType::Error; |
| 63 | } | 61 | } |
| 64 | 62 | ||
| 65 | ResultStatus AppLoader_NSP::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 63 | ResultStatus AppLoader_NSP::Load(Kernel::Process& process) { |
| 66 | if (is_loaded) { | 64 | if (is_loaded) { |
| 67 | return ResultStatus::ErrorAlreadyLoaded; | 65 | return ResultStatus::ErrorAlreadyLoaded; |
| 68 | } | 66 | } |
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 7ef810499..eac9b819a 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -35,7 +35,7 @@ public: | |||
| 35 | return IdentifyType(file); | 35 | return IdentifyType(file); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 38 | ResultStatus Load(Kernel::Process& process) override; |
| 39 | 39 | ||
| 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 41 | ResultStatus ReadProgramId(u64& out_program_id) override; | 41 | ResultStatus ReadProgramId(u64& out_program_id) override; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 16509229f..eda67a8c8 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -9,8 +9,6 @@ | |||
| 9 | #include "core/file_sys/content_archive.h" | 9 | #include "core/file_sys/content_archive.h" |
| 10 | #include "core/file_sys/control_metadata.h" | 10 | #include "core/file_sys/control_metadata.h" |
| 11 | #include "core/file_sys/patch_manager.h" | 11 | #include "core/file_sys/patch_manager.h" |
| 12 | #include "core/file_sys/romfs.h" | ||
| 13 | #include "core/file_sys/submission_package.h" | ||
| 14 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/loader/nca.h" | 13 | #include "core/loader/nca.h" |
| 16 | #include "core/loader/xci.h" | 14 | #include "core/loader/xci.h" |
| @@ -46,7 +44,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { | |||
| 46 | return FileType::Error; | 44 | return FileType::Error; |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) { | 47 | ResultStatus AppLoader_XCI::Load(Kernel::Process& process) { |
| 50 | if (is_loaded) { | 48 | if (is_loaded) { |
| 51 | return ResultStatus::ErrorAlreadyLoaded; | 49 | return ResultStatus::ErrorAlreadyLoaded; |
| 52 | } | 50 | } |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index cc4287e17..17e47b658 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -35,7 +35,7 @@ public: | |||
| 35 | return IdentifyType(file); | 35 | return IdentifyType(file); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 38 | ResultStatus Load(Kernel::Process& process) override; |
| 39 | 39 | ||
| 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 40 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 41 | ResultStatus ReadProgramId(u64& out_program_id) override; | 41 | ResultStatus ReadProgramId(u64& out_program_id) override; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 316b46820..014298ed6 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | ||
| 7 | #include <cstring> | 6 | #include <cstring> |
| 8 | #include <utility> | 7 | #include <utility> |
| 9 | 8 | ||
| @@ -15,11 +14,11 @@ | |||
| 15 | #include "core/arm/arm_interface.h" | 14 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/core.h" | 15 | #include "core/core.h" |
| 17 | #include "core/hle/kernel/process.h" | 16 | #include "core/hle/kernel/process.h" |
| 17 | #include "core/hle/kernel/vm_manager.h" | ||
| 18 | #include "core/hle/lock.h" | 18 | #include "core/hle/lock.h" |
| 19 | #include "core/memory.h" | 19 | #include "core/memory.h" |
| 20 | #include "core/memory_setup.h" | 20 | #include "core/memory_setup.h" |
| 21 | #include "video_core/renderer_base.h" | 21 | #include "video_core/renderer_base.h" |
| 22 | #include "video_core/video_core.h" | ||
| 23 | 22 | ||
| 24 | namespace Memory { | 23 | namespace Memory { |
| 25 | 24 | ||
| @@ -41,6 +40,21 @@ PageTable* GetCurrentPageTable() { | |||
| 41 | return current_page_table; | 40 | return current_page_table; |
| 42 | } | 41 | } |
| 43 | 42 | ||
| 43 | PageTable::PageTable() = default; | ||
| 44 | |||
| 45 | PageTable::PageTable(std::size_t address_space_width_in_bits) { | ||
| 46 | Resize(address_space_width_in_bits); | ||
| 47 | } | ||
| 48 | |||
| 49 | PageTable::~PageTable() = default; | ||
| 50 | |||
| 51 | void PageTable::Resize(std::size_t address_space_width_in_bits) { | ||
| 52 | const std::size_t num_page_table_entries = 1ULL << (address_space_width_in_bits - PAGE_BITS); | ||
| 53 | |||
| 54 | pointers.resize(num_page_table_entries); | ||
| 55 | attributes.resize(num_page_table_entries); | ||
| 56 | } | ||
| 57 | |||
| 44 | static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { | 58 | static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { |
| 45 | LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, | 59 | LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, |
| 46 | (base + size) * PAGE_SIZE); | 60 | (base + size) * PAGE_SIZE); |
| @@ -50,7 +64,7 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa | |||
| 50 | 64 | ||
| 51 | VAddr end = base + size; | 65 | VAddr end = base + size; |
| 52 | while (base != end) { | 66 | while (base != end) { |
| 53 | ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:016X}", base); | 67 | ASSERT_MSG(base < page_table.pointers.size(), "out of range mapping at {:016X}", base); |
| 54 | 68 | ||
| 55 | page_table.attributes[base] = type; | 69 | page_table.attributes[base] = type; |
| 56 | page_table.pointers[base] = memory; | 70 | page_table.pointers[base] = memory; |
| @@ -105,7 +119,7 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin | |||
| 105 | static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { | 119 | static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { |
| 106 | u8* direct_pointer = nullptr; | 120 | u8* direct_pointer = nullptr; |
| 107 | 121 | ||
| 108 | auto& vm_manager = process.vm_manager; | 122 | auto& vm_manager = process.VMManager(); |
| 109 | 123 | ||
| 110 | auto it = vm_manager.FindVMA(vaddr); | 124 | auto it = vm_manager.FindVMA(vaddr); |
| 111 | ASSERT(it != vm_manager.vma_map.end()); | 125 | ASSERT(it != vm_manager.vma_map.end()); |
| @@ -200,7 +214,7 @@ void Write(const VAddr vaddr, const T data) { | |||
| 200 | } | 214 | } |
| 201 | 215 | ||
| 202 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | 216 | bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { |
| 203 | auto& page_table = process.vm_manager.page_table; | 217 | const auto& page_table = process.VMManager().page_table; |
| 204 | 218 | ||
| 205 | const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; | 219 | const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; |
| 206 | if (page_pointer) | 220 | if (page_pointer) |
| @@ -323,7 +337,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { | |||
| 323 | return; | 337 | return; |
| 324 | } | 338 | } |
| 325 | 339 | ||
| 326 | VAddr end = start + size; | 340 | const VAddr end = start + size; |
| 327 | 341 | ||
| 328 | const auto CheckRegion = [&](VAddr region_start, VAddr region_end) { | 342 | const auto CheckRegion = [&](VAddr region_start, VAddr region_end) { |
| 329 | if (start >= region_end || end <= region_start) { | 343 | if (start >= region_end || end <= region_start) { |
| @@ -333,7 +347,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { | |||
| 333 | 347 | ||
| 334 | const VAddr overlap_start = std::max(start, region_start); | 348 | const VAddr overlap_start = std::max(start, region_start); |
| 335 | const VAddr overlap_end = std::min(end, region_end); | 349 | const VAddr overlap_end = std::min(end, region_end); |
| 336 | const u64 overlap_size = overlap_end - overlap_start; | 350 | const VAddr overlap_size = overlap_end - overlap_start; |
| 337 | 351 | ||
| 338 | auto& rasterizer = system_instance.Renderer().Rasterizer(); | 352 | auto& rasterizer = system_instance.Renderer().Rasterizer(); |
| 339 | switch (mode) { | 353 | switch (mode) { |
| @@ -349,8 +363,10 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { | |||
| 349 | } | 363 | } |
| 350 | }; | 364 | }; |
| 351 | 365 | ||
| 352 | CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END); | 366 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); |
| 353 | CheckRegion(HEAP_VADDR, HEAP_VADDR_END); | 367 | |
| 368 | CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress()); | ||
| 369 | CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress()); | ||
| 354 | } | 370 | } |
| 355 | 371 | ||
| 356 | u8 Read8(const VAddr addr) { | 372 | u8 Read8(const VAddr addr) { |
| @@ -371,7 +387,7 @@ u64 Read64(const VAddr addr) { | |||
| 371 | 387 | ||
| 372 | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, | 388 | void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, |
| 373 | const std::size_t size) { | 389 | const std::size_t size) { |
| 374 | auto& page_table = process.vm_manager.page_table; | 390 | const auto& page_table = process.VMManager().page_table; |
| 375 | 391 | ||
| 376 | std::size_t remaining_size = size; | 392 | std::size_t remaining_size = size; |
| 377 | std::size_t page_index = src_addr >> PAGE_BITS; | 393 | std::size_t page_index = src_addr >> PAGE_BITS; |
| @@ -436,7 +452,7 @@ void Write64(const VAddr addr, const u64 data) { | |||
| 436 | 452 | ||
| 437 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, | 453 | void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, |
| 438 | const std::size_t size) { | 454 | const std::size_t size) { |
| 439 | auto& page_table = process.vm_manager.page_table; | 455 | const auto& page_table = process.VMManager().page_table; |
| 440 | std::size_t remaining_size = size; | 456 | std::size_t remaining_size = size; |
| 441 | std::size_t page_index = dest_addr >> PAGE_BITS; | 457 | std::size_t page_index = dest_addr >> PAGE_BITS; |
| 442 | std::size_t page_offset = dest_addr & PAGE_MASK; | 458 | std::size_t page_offset = dest_addr & PAGE_MASK; |
| @@ -482,7 +498,7 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t | |||
| 482 | } | 498 | } |
| 483 | 499 | ||
| 484 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { | 500 | void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { |
| 485 | auto& page_table = process.vm_manager.page_table; | 501 | const auto& page_table = process.VMManager().page_table; |
| 486 | std::size_t remaining_size = size; | 502 | std::size_t remaining_size = size; |
| 487 | std::size_t page_index = dest_addr >> PAGE_BITS; | 503 | std::size_t page_index = dest_addr >> PAGE_BITS; |
| 488 | std::size_t page_offset = dest_addr & PAGE_MASK; | 504 | std::size_t page_offset = dest_addr & PAGE_MASK; |
| @@ -524,7 +540,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std: | |||
| 524 | 540 | ||
| 525 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, | 541 | void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, |
| 526 | const std::size_t size) { | 542 | const std::size_t size) { |
| 527 | auto& page_table = process.vm_manager.page_table; | 543 | const auto& page_table = process.VMManager().page_table; |
| 528 | std::size_t remaining_size = size; | 544 | std::size_t remaining_size = size; |
| 529 | std::size_t page_index = src_addr >> PAGE_BITS; | 545 | std::size_t page_index = src_addr >> PAGE_BITS; |
| 530 | std::size_t page_offset = src_addr & PAGE_MASK; | 546 | std::size_t page_offset = src_addr & PAGE_MASK; |
diff --git a/src/core/memory.h b/src/core/memory.h index 2a27c0251..1acf5ce8c 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -4,10 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include <cstddef> | 7 | #include <cstddef> |
| 9 | #include <string> | 8 | #include <string> |
| 10 | #include <tuple> | 9 | #include <tuple> |
| 10 | #include <vector> | ||
| 11 | #include <boost/icl/interval_map.hpp> | 11 | #include <boost/icl/interval_map.hpp> |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "core/memory_hook.h" | 13 | #include "core/memory_hook.h" |
| @@ -23,10 +23,8 @@ namespace Memory { | |||
| 23 | * be mapped. | 23 | * be mapped. |
| 24 | */ | 24 | */ |
| 25 | constexpr std::size_t PAGE_BITS = 12; | 25 | constexpr std::size_t PAGE_BITS = 12; |
| 26 | constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; | 26 | constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS; |
| 27 | constexpr u64 PAGE_MASK = PAGE_SIZE - 1; | 27 | constexpr u64 PAGE_MASK = PAGE_SIZE - 1; |
| 28 | constexpr std::size_t ADDRESS_SPACE_BITS = 36; | ||
| 29 | constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS); | ||
| 30 | 28 | ||
| 31 | enum class PageType : u8 { | 29 | enum class PageType : u8 { |
| 32 | /// Page is unmapped and should cause an access error. | 30 | /// Page is unmapped and should cause an access error. |
| @@ -62,32 +60,39 @@ struct SpecialRegion { | |||
| 62 | * mimics the way a real CPU page table works. | 60 | * mimics the way a real CPU page table works. |
| 63 | */ | 61 | */ |
| 64 | struct PageTable { | 62 | struct PageTable { |
| 63 | explicit PageTable(); | ||
| 64 | explicit PageTable(std::size_t address_space_width_in_bits); | ||
| 65 | ~PageTable(); | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Resizes the page table to be able to accomodate enough pages within | ||
| 69 | * a given address space. | ||
| 70 | * | ||
| 71 | * @param address_space_width_in_bits The address size width in bits. | ||
| 72 | */ | ||
| 73 | void Resize(std::size_t address_space_width_in_bits); | ||
| 74 | |||
| 65 | /** | 75 | /** |
| 66 | * Array of memory pointers backing each page. An entry can only be non-null if the | 76 | * Vector of memory pointers backing each page. An entry can only be non-null if the |
| 67 | * corresponding entry in the `attributes` array is of type `Memory`. | 77 | * corresponding entry in the `attributes` vector is of type `Memory`. |
| 68 | */ | 78 | */ |
| 69 | std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers; | 79 | std::vector<u8*> pointers; |
| 70 | 80 | ||
| 71 | /** | 81 | /** |
| 72 | * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of | 82 | * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is |
| 73 | * type `Special`. | 83 | * of type `Special`. |
| 74 | */ | 84 | */ |
| 75 | boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions; | 85 | boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions; |
| 76 | 86 | ||
| 77 | /** | 87 | /** |
| 78 | * Array of fine grained page attributes. If it is set to any value other than `Memory`, then | 88 | * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then |
| 79 | * the corresponding entry in `pointers` MUST be set to null. | 89 | * the corresponding entry in `pointers` MUST be set to null. |
| 80 | */ | 90 | */ |
| 81 | std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; | 91 | std::vector<PageType> attributes; |
| 82 | }; | 92 | }; |
| 83 | 93 | ||
| 84 | /// Virtual user-space memory regions | 94 | /// Virtual user-space memory regions |
| 85 | enum : VAddr { | 95 | enum : VAddr { |
| 86 | /// Where the application text, data and bss reside. | ||
| 87 | PROCESS_IMAGE_VADDR = 0x08000000, | ||
| 88 | PROCESS_IMAGE_MAX_SIZE = 0x08000000, | ||
| 89 | PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, | ||
| 90 | |||
| 91 | /// Read-only page containing kernel and system configuration values. | 96 | /// Read-only page containing kernel and system configuration values. |
| 92 | CONFIG_MEMORY_VADDR = 0x1FF80000, | 97 | CONFIG_MEMORY_VADDR = 0x1FF80000, |
| 93 | CONFIG_MEMORY_SIZE = 0x00001000, | 98 | CONFIG_MEMORY_SIZE = 0x00001000, |
| @@ -98,36 +103,12 @@ enum : VAddr { | |||
| 98 | SHARED_PAGE_SIZE = 0x00001000, | 103 | SHARED_PAGE_SIZE = 0x00001000, |
| 99 | SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, | 104 | SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, |
| 100 | 105 | ||
| 101 | /// Area where TLS (Thread-Local Storage) buffers are allocated. | 106 | /// TLS (Thread-Local Storage) related. |
| 102 | TLS_AREA_VADDR = 0x40000000, | ||
| 103 | TLS_ENTRY_SIZE = 0x200, | 107 | TLS_ENTRY_SIZE = 0x200, |
| 104 | TLS_AREA_SIZE = 0x10000000, | ||
| 105 | TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, | ||
| 106 | 108 | ||
| 107 | /// Application stack | 109 | /// Application stack |
| 108 | STACK_AREA_VADDR = TLS_AREA_VADDR_END, | ||
| 109 | STACK_AREA_SIZE = 0x10000000, | ||
| 110 | STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE, | ||
| 111 | DEFAULT_STACK_SIZE = 0x100000, | 110 | DEFAULT_STACK_SIZE = 0x100000, |
| 112 | 111 | ||
| 113 | /// Application heap | ||
| 114 | /// Size is confirmed to be a static value on fw 3.0.0 | ||
| 115 | HEAP_VADDR = 0x108000000, | ||
| 116 | HEAP_SIZE = 0x180000000, | ||
| 117 | HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, | ||
| 118 | |||
| 119 | /// New map region | ||
| 120 | /// Size is confirmed to be a static value on fw 3.0.0 | ||
| 121 | NEW_MAP_REGION_VADDR = HEAP_VADDR_END, | ||
| 122 | NEW_MAP_REGION_SIZE = 0x80000000, | ||
| 123 | NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE, | ||
| 124 | |||
| 125 | /// Map region | ||
| 126 | /// Size is confirmed to be a static value on fw 3.0.0 | ||
| 127 | MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, | ||
| 128 | MAP_REGION_SIZE = 0x1000000000, | ||
| 129 | MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, | ||
| 130 | |||
| 131 | /// Kernel Virtual Address Range | 112 | /// Kernel Virtual Address Range |
| 132 | KERNEL_REGION_VADDR = 0xFFFFFF8000000000, | 113 | KERNEL_REGION_VADDR = 0xFFFFFF8000000000, |
| 133 | KERNEL_REGION_SIZE = 0x7FFFE00000, | 114 | KERNEL_REGION_SIZE = 0x7FFFE00000, |
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 7c69fc26e..c0a57e71f 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | |||
| 5 | #include "core/core.h" | 7 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/process.h" | 8 | #include "core/hle/kernel/process.h" |
| 7 | #include "core/memory.h" | 9 | #include "core/memory.h" |
| @@ -14,11 +16,12 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) | |||
| 14 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { | 16 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { |
| 15 | 17 | ||
| 16 | Core::CurrentProcess() = Kernel::Process::Create(kernel, ""); | 18 | Core::CurrentProcess() = Kernel::Process::Create(kernel, ""); |
| 17 | page_table = &Core::CurrentProcess()->vm_manager.page_table; | 19 | page_table = &Core::CurrentProcess()->VMManager().page_table; |
| 18 | 20 | ||
| 19 | page_table->pointers.fill(nullptr); | 21 | std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); |
| 20 | page_table->special_regions.clear(); | 22 | page_table->special_regions.clear(); |
| 21 | page_table->attributes.fill(Memory::PageType::Unmapped); | 23 | std::fill(page_table->attributes.begin(), page_table->attributes.end(), |
| 24 | Memory::PageType::Unmapped); | ||
| 22 | 25 | ||
| 23 | Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); | 26 | Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); |
| 24 | Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); | 27 | Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index b81b0723d..9f5581045 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -41,6 +41,7 @@ public: | |||
| 41 | static constexpr std::size_t NumCBData = 16; | 41 | static constexpr std::size_t NumCBData = 16; |
| 42 | static constexpr std::size_t NumVertexArrays = 32; | 42 | static constexpr std::size_t NumVertexArrays = 32; |
| 43 | static constexpr std::size_t NumVertexAttributes = 32; | 43 | static constexpr std::size_t NumVertexAttributes = 32; |
| 44 | static constexpr std::size_t NumTextureSamplers = 32; | ||
| 44 | static constexpr std::size_t MaxShaderProgram = 6; | 45 | static constexpr std::size_t MaxShaderProgram = 6; |
| 45 | static constexpr std::size_t MaxShaderStage = 5; | 46 | static constexpr std::size_t MaxShaderStage = 5; |
| 46 | // Maximum number of const buffers per shader stage. | 47 | // Maximum number of const buffers per shader stage. |
| @@ -461,7 +462,11 @@ public: | |||
| 461 | u32 entry; | 462 | u32 entry; |
| 462 | } macros; | 463 | } macros; |
| 463 | 464 | ||
| 464 | INSERT_PADDING_WORDS(0x1B8); | 465 | INSERT_PADDING_WORDS(0x189); |
| 466 | |||
| 467 | u32 tfb_enabled; | ||
| 468 | |||
| 469 | INSERT_PADDING_WORDS(0x2E); | ||
| 465 | 470 | ||
| 466 | RenderTargetConfig rt[NumRenderTargets]; | 471 | RenderTargetConfig rt[NumRenderTargets]; |
| 467 | 472 | ||
| @@ -594,7 +599,9 @@ public: | |||
| 594 | 599 | ||
| 595 | u32 depth_write_enabled; | 600 | u32 depth_write_enabled; |
| 596 | 601 | ||
| 597 | INSERT_PADDING_WORDS(0x7); | 602 | u32 alpha_test_enabled; |
| 603 | |||
| 604 | INSERT_PADDING_WORDS(0x6); | ||
| 598 | 605 | ||
| 599 | u32 d3d_cull_mode; | 606 | u32 d3d_cull_mode; |
| 600 | 607 | ||
| @@ -635,7 +642,11 @@ public: | |||
| 635 | 642 | ||
| 636 | u32 vb_element_base; | 643 | u32 vb_element_base; |
| 637 | 644 | ||
| 638 | INSERT_PADDING_WORDS(0x40); | 645 | INSERT_PADDING_WORDS(0x38); |
| 646 | |||
| 647 | float point_size; | ||
| 648 | |||
| 649 | INSERT_PADDING_WORDS(0x7); | ||
| 639 | 650 | ||
| 640 | u32 zeta_enable; | 651 | u32 zeta_enable; |
| 641 | 652 | ||
| @@ -977,6 +988,7 @@ private: | |||
| 977 | "Field " #field_name " has invalid position") | 988 | "Field " #field_name " has invalid position") |
| 978 | 989 | ||
| 979 | ASSERT_REG_POSITION(macros, 0x45); | 990 | ASSERT_REG_POSITION(macros, 0x45); |
| 991 | ASSERT_REG_POSITION(tfb_enabled, 0x1D1); | ||
| 980 | ASSERT_REG_POSITION(rt, 0x200); | 992 | ASSERT_REG_POSITION(rt, 0x200); |
| 981 | ASSERT_REG_POSITION(viewport_transform[0], 0x280); | 993 | ASSERT_REG_POSITION(viewport_transform[0], 0x280); |
| 982 | ASSERT_REG_POSITION(viewport, 0x300); | 994 | ASSERT_REG_POSITION(viewport, 0x300); |
| @@ -996,6 +1008,7 @@ ASSERT_REG_POSITION(zeta_height, 0x48b); | |||
| 996 | ASSERT_REG_POSITION(depth_test_enable, 0x4B3); | 1008 | ASSERT_REG_POSITION(depth_test_enable, 0x4B3); |
| 997 | ASSERT_REG_POSITION(independent_blend_enable, 0x4B9); | 1009 | ASSERT_REG_POSITION(independent_blend_enable, 0x4B9); |
| 998 | ASSERT_REG_POSITION(depth_write_enabled, 0x4BA); | 1010 | ASSERT_REG_POSITION(depth_write_enabled, 0x4BA); |
| 1011 | ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); | ||
| 999 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); | 1012 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); |
| 1000 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); | 1013 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); |
| 1001 | ASSERT_REG_POSITION(blend, 0x4CF); | 1014 | ASSERT_REG_POSITION(blend, 0x4CF); |
| @@ -1009,6 +1022,7 @@ ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6); | |||
| 1009 | ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); | 1022 | ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); |
| 1010 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); | 1023 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); |
| 1011 | ASSERT_REG_POSITION(vb_element_base, 0x50D); | 1024 | ASSERT_REG_POSITION(vb_element_base, 0x50D); |
| 1025 | ASSERT_REG_POSITION(point_size, 0x546); | ||
| 1012 | ASSERT_REG_POSITION(zeta_enable, 0x54E); | 1026 | ASSERT_REG_POSITION(zeta_enable, 0x54E); |
| 1013 | ASSERT_REG_POSITION(tsc, 0x557); | 1027 | ASSERT_REG_POSITION(tsc, 0x557); |
| 1014 | ASSERT_REG_POSITION(tic, 0x55D); | 1028 | ASSERT_REG_POSITION(tic, 0x55D); |
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp index e4e5f9e5e..59e28b22d 100644 --- a/src/video_core/engines/maxwell_compute.cpp +++ b/src/video_core/engines/maxwell_compute.cpp | |||
| @@ -2,12 +2,29 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/core.h" | ||
| 5 | #include "video_core/engines/maxwell_compute.h" | 7 | #include "video_core/engines/maxwell_compute.h" |
| 6 | 8 | ||
| 7 | namespace Tegra { | 9 | namespace Tegra { |
| 8 | namespace Engines { | 10 | namespace Engines { |
| 9 | 11 | ||
| 10 | void MaxwellCompute::WriteReg(u32 method, u32 value) {} | 12 | void MaxwellCompute::WriteReg(u32 method, u32 value) { |
| 13 | ASSERT_MSG(method < Regs::NUM_REGS, | ||
| 14 | "Invalid MaxwellCompute register, increase the size of the Regs structure"); | ||
| 15 | |||
| 16 | regs.reg_array[method] = value; | ||
| 17 | |||
| 18 | switch (method) { | ||
| 19 | case MAXWELL_COMPUTE_REG_INDEX(compute): { | ||
| 20 | LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); | ||
| 21 | UNREACHABLE(); | ||
| 22 | break; | ||
| 23 | } | ||
| 24 | default: | ||
| 25 | break; | ||
| 26 | } | ||
| 27 | } | ||
| 11 | 28 | ||
| 12 | } // namespace Engines | 29 | } // namespace Engines |
| 13 | } // namespace Tegra | 30 | } // namespace Tegra |
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/maxwell_compute.h index 2b3e4ced6..6ea934fb9 100644 --- a/src/video_core/engines/maxwell_compute.h +++ b/src/video_core/engines/maxwell_compute.h | |||
| @@ -4,17 +4,53 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/bit_field.h" | ||
| 10 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 8 | 12 | ||
| 9 | namespace Tegra::Engines { | 13 | namespace Tegra::Engines { |
| 10 | 14 | ||
| 15 | #define MAXWELL_COMPUTE_REG_INDEX(field_name) \ | ||
| 16 | (offsetof(Tegra::Engines::MaxwellCompute::Regs, field_name) / sizeof(u32)) | ||
| 17 | |||
| 11 | class MaxwellCompute final { | 18 | class MaxwellCompute final { |
| 12 | public: | 19 | public: |
| 13 | MaxwellCompute() = default; | 20 | MaxwellCompute() = default; |
| 14 | ~MaxwellCompute() = default; | 21 | ~MaxwellCompute() = default; |
| 15 | 22 | ||
| 23 | struct Regs { | ||
| 24 | static constexpr std::size_t NUM_REGS = 0xCF8; | ||
| 25 | |||
| 26 | union { | ||
| 27 | struct { | ||
| 28 | INSERT_PADDING_WORDS(0x281); | ||
| 29 | |||
| 30 | union { | ||
| 31 | u32 compute_end; | ||
| 32 | BitField<0, 1, u32> unknown; | ||
| 33 | } compute; | ||
| 34 | |||
| 35 | INSERT_PADDING_WORDS(0xA76); | ||
| 36 | }; | ||
| 37 | std::array<u32, NUM_REGS> reg_array; | ||
| 38 | }; | ||
| 39 | } regs{}; | ||
| 40 | |||
| 41 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), | ||
| 42 | "MaxwellCompute Regs has wrong size"); | ||
| 43 | |||
| 16 | /// Write the value to the register identified by method. | 44 | /// Write the value to the register identified by method. |
| 17 | void WriteReg(u32 method, u32 value); | 45 | void WriteReg(u32 method, u32 value); |
| 18 | }; | 46 | }; |
| 19 | 47 | ||
| 48 | #define ASSERT_REG_POSITION(field_name, position) \ | ||
| 49 | static_assert(offsetof(MaxwellCompute::Regs, field_name) == position * 4, \ | ||
| 50 | "Field " #field_name " has invalid position") | ||
| 51 | |||
| 52 | ASSERT_REG_POSITION(compute, 0x281); | ||
| 53 | |||
| 54 | #undef ASSERT_REG_POSITION | ||
| 55 | |||
| 20 | } // namespace Tegra::Engines | 56 | } // namespace Tegra::Engines |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 70fb54507..1fcd13f04 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -450,6 +450,9 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 450 | SyncBlendState(); | 450 | SyncBlendState(); |
| 451 | SyncLogicOpState(); | 451 | SyncLogicOpState(); |
| 452 | SyncCullMode(); | 452 | SyncCullMode(); |
| 453 | SyncAlphaTest(); | ||
| 454 | SyncTransformFeedback(); | ||
| 455 | SyncPointState(); | ||
| 453 | 456 | ||
| 454 | // TODO(bunnei): Sync framebuffer_scale uniform here | 457 | // TODO(bunnei): Sync framebuffer_scale uniform here |
| 455 | // TODO(bunnei): Sync scissorbox uniform(s) here | 458 | // TODO(bunnei): Sync scissorbox uniform(s) here |
| @@ -883,4 +886,30 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||
| 883 | state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); | 886 | state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); |
| 884 | } | 887 | } |
| 885 | 888 | ||
| 889 | void RasterizerOpenGL::SyncAlphaTest() { | ||
| 890 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 891 | |||
| 892 | // TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be | ||
| 893 | // implemented with a test+discard in fragment shaders. | ||
| 894 | if (regs.alpha_test_enabled != 0) { | ||
| 895 | LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented"); | ||
| 896 | UNREACHABLE(); | ||
| 897 | } | ||
| 898 | } | ||
| 899 | |||
| 900 | void RasterizerOpenGL::SyncTransformFeedback() { | ||
| 901 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 902 | |||
| 903 | if (regs.tfb_enabled != 0) { | ||
| 904 | LOG_CRITICAL(Render_OpenGL, "Transform feedbacks are not implemented"); | ||
| 905 | UNREACHABLE(); | ||
| 906 | } | ||
| 907 | } | ||
| 908 | |||
| 909 | void RasterizerOpenGL::SyncPointState() { | ||
| 910 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 911 | |||
| 912 | state.point.size = regs.point_size; | ||
| 913 | } | ||
| 914 | |||
| 886 | } // namespace OpenGL | 915 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index bf9560bdc..4c8ecbd1c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -158,6 +158,15 @@ private: | |||
| 158 | /// Syncs the LogicOp state to match the guest state | 158 | /// Syncs the LogicOp state to match the guest state |
| 159 | void SyncLogicOpState(); | 159 | void SyncLogicOpState(); |
| 160 | 160 | ||
| 161 | /// Syncs the alpha test state to match the guest state | ||
| 162 | void SyncAlphaTest(); | ||
| 163 | |||
| 164 | /// Syncs the transform feedback state to match the guest state | ||
| 165 | void SyncTransformFeedback(); | ||
| 166 | |||
| 167 | /// Syncs the point state to match the guest state | ||
| 168 | void SyncPointState(); | ||
| 169 | |||
| 161 | bool has_ARB_direct_state_access = false; | 170 | bool has_ARB_direct_state_access = false; |
| 162 | bool has_ARB_multi_bind = false; | 171 | bool has_ARB_multi_bind = false; |
| 163 | bool has_ARB_separate_shader_objects = false; | 172 | bool has_ARB_separate_shader_objects = false; |
| @@ -178,7 +187,7 @@ private: | |||
| 178 | OGLVertexArray> | 187 | OGLVertexArray> |
| 179 | vertex_array_cache; | 188 | vertex_array_cache; |
| 180 | 189 | ||
| 181 | std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; | 190 | std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers; |
| 182 | 191 | ||
| 183 | static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; | 192 | static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; |
| 184 | OGLBufferCache buffer_cache; | 193 | OGLBufferCache buffer_cache; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index b86cd96e8..3de15ba9b 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -11,9 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | namespace OpenGL::GLShader { | 12 | namespace OpenGL::GLShader { |
| 13 | 13 | ||
| 14 | /// Number of OpenGL texture samplers that can be used in the fragment shader | ||
| 15 | static constexpr std::size_t NumTextureSamplers = 32; | ||
| 16 | |||
| 17 | using Tegra::Engines::Maxwell3D; | 14 | using Tegra::Engines::Maxwell3D; |
| 18 | 15 | ||
| 19 | /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned | 16 | /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index e5173e20a..1fe26a2a9 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -79,6 +79,8 @@ OpenGLState::OpenGLState() { | |||
| 79 | viewport.height = 0; | 79 | viewport.height = 0; |
| 80 | 80 | ||
| 81 | clip_distance = {}; | 81 | clip_distance = {}; |
| 82 | |||
| 83 | point.size = 1; | ||
| 82 | } | 84 | } |
| 83 | 85 | ||
| 84 | void OpenGLState::Apply() const { | 86 | void OpenGLState::Apply() const { |
| @@ -205,9 +207,6 @@ void OpenGLState::Apply() const { | |||
| 205 | glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); | 207 | glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); |
| 206 | glBindTexture(texture_unit.target, texture_unit.texture); | 208 | glBindTexture(texture_unit.target, texture_unit.texture); |
| 207 | } | 209 | } |
| 208 | if (texture_unit.sampler != cur_state_texture_unit.sampler) { | ||
| 209 | glBindSampler(static_cast<GLuint>(i), texture_unit.sampler); | ||
| 210 | } | ||
| 211 | // Update the texture swizzle | 210 | // Update the texture swizzle |
| 212 | if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r || | 211 | if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r || |
| 213 | texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g || | 212 | texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g || |
| @@ -219,6 +218,27 @@ void OpenGLState::Apply() const { | |||
| 219 | } | 218 | } |
| 220 | } | 219 | } |
| 221 | 220 | ||
| 221 | // Samplers | ||
| 222 | { | ||
| 223 | bool has_delta{}; | ||
| 224 | std::size_t first{}, last{}; | ||
| 225 | std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers; | ||
| 226 | for (std::size_t i = 0; i < std::size(samplers); ++i) { | ||
| 227 | samplers[i] = texture_units[i].sampler; | ||
| 228 | if (samplers[i] != cur_state.texture_units[i].sampler) { | ||
| 229 | if (!has_delta) { | ||
| 230 | first = i; | ||
| 231 | has_delta = true; | ||
| 232 | } | ||
| 233 | last = i; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | if (has_delta) { | ||
| 237 | glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1), | ||
| 238 | samplers.data()); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 222 | // Framebuffer | 242 | // Framebuffer |
| 223 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { | 243 | if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { |
| 224 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); | 244 | glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); |
| @@ -283,6 +303,11 @@ void OpenGLState::Apply() const { | |||
| 283 | } | 303 | } |
| 284 | } | 304 | } |
| 285 | 305 | ||
| 306 | // Point | ||
| 307 | if (point.size != cur_state.point.size) { | ||
| 308 | glPointSize(point.size); | ||
| 309 | } | ||
| 310 | |||
| 286 | cur_state = *this; | 311 | cur_state = *this; |
| 287 | } | 312 | } |
| 288 | 313 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 9a93029d8..dc21a2ee3 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <glad/glad.h> | 8 | #include <glad/glad.h> |
| 9 | #include "video_core/engines/maxwell_3d.h" | ||
| 9 | 10 | ||
| 10 | namespace OpenGL { | 11 | namespace OpenGL { |
| 11 | 12 | ||
| @@ -114,7 +115,7 @@ public: | |||
| 114 | target = GL_TEXTURE_2D; | 115 | target = GL_TEXTURE_2D; |
| 115 | } | 116 | } |
| 116 | }; | 117 | }; |
| 117 | std::array<TextureUnit, 32> texture_units; | 118 | std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units; |
| 118 | 119 | ||
| 119 | struct { | 120 | struct { |
| 120 | GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING | 121 | GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING |
| @@ -141,6 +142,10 @@ public: | |||
| 141 | GLsizei height; | 142 | GLsizei height; |
| 142 | } viewport; | 143 | } viewport; |
| 143 | 144 | ||
| 145 | struct { | ||
| 146 | float size; // GL_POINT_SIZE | ||
| 147 | } point; | ||
| 148 | |||
| 144 | std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE | 149 | std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE |
| 145 | 150 | ||
| 146 | OpenGLState(); | 151 | OpenGLState(); |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 20ba6d4f6..3d5476e5d 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -13,47 +13,20 @@ | |||
| 13 | namespace Tegra::Texture { | 13 | namespace Tegra::Texture { |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | * This table represents the internal swizzle of a gob, | ||
| 17 | * in format 16 bytes x 2 sector packing. | ||
| 16 | * Calculates the offset of an (x, y) position within a swizzled texture. | 18 | * Calculates the offset of an (x, y) position within a swizzled texture. |
| 17 | * Taken from the Tegra X1 TRM. | 19 | * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188 |
| 18 | */ | 20 | */ |
| 19 | static u32 GetSwizzleOffset(u32 x, u32 y, u32 image_width, u32 bytes_per_pixel, u32 block_height) { | 21 | template <std::size_t N, std::size_t M, u32 Align> |
| 20 | // Round up to the next gob | ||
| 21 | const u32 image_width_in_gobs{(image_width * bytes_per_pixel + 63) / 64}; | ||
| 22 | |||
| 23 | u32 GOB_address = 0 + (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs + | ||
| 24 | (x * bytes_per_pixel / 64) * 512 * block_height + | ||
| 25 | (y % (8 * block_height) / 8) * 512; | ||
| 26 | x *= bytes_per_pixel; | ||
| 27 | u32 address = GOB_address + ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 + | ||
| 28 | (y % 2) * 16 + (x % 16); | ||
| 29 | |||
| 30 | return address; | ||
| 31 | } | ||
| 32 | |||
| 33 | void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, | ||
| 34 | u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) { | ||
| 35 | u8* data_ptrs[2]; | ||
| 36 | for (unsigned y = 0; y < height; ++y) { | ||
| 37 | for (unsigned x = 0; x < width; ++x) { | ||
| 38 | u32 swizzle_offset = GetSwizzleOffset(x, y, width, bytes_per_pixel, block_height); | ||
| 39 | u32 pixel_index = (x + y * width) * out_bytes_per_pixel; | ||
| 40 | |||
| 41 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; | ||
| 42 | data_ptrs[!unswizzle] = &unswizzled_data[pixel_index]; | ||
| 43 | |||
| 44 | std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | template <std::size_t N, std::size_t M> | ||
| 50 | struct alignas(64) SwizzleTable { | 22 | struct alignas(64) SwizzleTable { |
| 23 | static_assert(M * Align == 64, "Swizzle Table does not align to GOB"); | ||
| 51 | constexpr SwizzleTable() { | 24 | constexpr SwizzleTable() { |
| 52 | for (u32 y = 0; y < N; ++y) { | 25 | for (u32 y = 0; y < N; ++y) { |
| 53 | for (u32 x = 0; x < M; ++x) { | 26 | for (u32 x = 0; x < M; ++x) { |
| 54 | const u32 x2 = x * 16; | 27 | const u32 x2 = x * Align; |
| 55 | values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 + | 28 | values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 + |
| 56 | ((x2 % 32) / 16) * 32 + (y % 2) * 16); | 29 | ((x2 % 32) / 16) * 32 + (y % 2) * 16 + (x2 % 16)); |
| 57 | } | 30 | } |
| 58 | } | 31 | } |
| 59 | } | 32 | } |
| @@ -63,24 +36,60 @@ struct alignas(64) SwizzleTable { | |||
| 63 | std::array<std::array<u16, M>, N> values{}; | 36 | std::array<std::array<u16, M>, N> values{}; |
| 64 | }; | 37 | }; |
| 65 | 38 | ||
| 66 | constexpr auto swizzle_table = SwizzleTable<8, 4>(); | 39 | constexpr auto legacy_swizzle_table = SwizzleTable<8, 64, 1>(); |
| 40 | constexpr auto fast_swizzle_table = SwizzleTable<8, 4, 16>(); | ||
| 67 | 41 | ||
| 68 | void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_data, | 42 | static void LegacySwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, |
| 69 | u8* unswizzled_data, bool unswizzle, u32 block_height) { | 43 | u8* swizzled_data, u8* unswizzled_data, bool unswizzle, |
| 44 | u32 block_height) { | ||
| 45 | std::array<u8*, 2> data_ptrs; | ||
| 46 | const std::size_t stride = width * bytes_per_pixel; | ||
| 47 | const std::size_t gobs_in_x = 64; | ||
| 48 | const std::size_t gobs_in_y = 8; | ||
| 49 | const std::size_t gobs_size = gobs_in_x * gobs_in_y; | ||
| 50 | const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x}; | ||
| 51 | for (std::size_t y = 0; y < height; ++y) { | ||
| 52 | const std::size_t gob_y_address = | ||
| 53 | (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs + | ||
| 54 | (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size; | ||
| 55 | const auto& table = legacy_swizzle_table[y % gobs_in_y]; | ||
| 56 | for (std::size_t x = 0; x < width; ++x) { | ||
| 57 | const std::size_t gob_address = | ||
| 58 | gob_y_address + (x * bytes_per_pixel / gobs_in_x) * gobs_size * block_height; | ||
| 59 | const std::size_t x2 = x * bytes_per_pixel; | ||
| 60 | const std::size_t swizzle_offset = gob_address + table[x2 % gobs_in_x]; | ||
| 61 | const std::size_t pixel_index = (x + y * width) * out_bytes_per_pixel; | ||
| 62 | |||
| 63 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; | ||
| 64 | data_ptrs[!unswizzle] = unswizzled_data + pixel_index; | ||
| 65 | |||
| 66 | std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | static void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, | ||
| 72 | u8* swizzled_data, u8* unswizzled_data, bool unswizzle, | ||
| 73 | u32 block_height) { | ||
| 70 | std::array<u8*, 2> data_ptrs; | 74 | std::array<u8*, 2> data_ptrs; |
| 71 | const std::size_t stride{width * bytes_per_pixel}; | 75 | const std::size_t stride{width * bytes_per_pixel}; |
| 72 | const std::size_t image_width_in_gobs{(stride + 63) / 64}; | 76 | const std::size_t gobs_in_x = 64; |
| 77 | const std::size_t gobs_in_y = 8; | ||
| 78 | const std::size_t gobs_size = gobs_in_x * gobs_in_y; | ||
| 79 | const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x}; | ||
| 73 | const std::size_t copy_size{16}; | 80 | const std::size_t copy_size{16}; |
| 74 | for (std::size_t y = 0; y < height; ++y) { | 81 | for (std::size_t y = 0; y < height; ++y) { |
| 75 | const std::size_t initial_gob = | 82 | const std::size_t initial_gob = |
| 76 | (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs + | 83 | (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs + |
| 77 | (y % (8 * block_height) / 8) * 512; | 84 | (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size; |
| 78 | const std::size_t pixel_base{y * width * bytes_per_pixel}; | 85 | const std::size_t pixel_base{y * width * out_bytes_per_pixel}; |
| 79 | const auto& table = swizzle_table[y % 8]; | 86 | const auto& table = fast_swizzle_table[y % gobs_in_y]; |
| 80 | for (std::size_t xb = 0; xb < stride; xb += copy_size) { | 87 | for (std::size_t xb = 0; xb < stride; xb += copy_size) { |
| 81 | const std::size_t gob_address{initial_gob + (xb / 64) * 512 * block_height}; | 88 | const std::size_t gob_address{initial_gob + |
| 89 | (xb / gobs_in_x) * gobs_size * block_height}; | ||
| 82 | const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]}; | 90 | const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]}; |
| 83 | const std::size_t pixel_index{xb + pixel_base}; | 91 | const std::size_t out_x = xb * out_bytes_per_pixel / bytes_per_pixel; |
| 92 | const std::size_t pixel_index{out_x + pixel_base}; | ||
| 84 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; | 93 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; |
| 85 | data_ptrs[!unswizzle] = unswizzled_data + pixel_index; | 94 | data_ptrs[!unswizzle] = unswizzled_data + pixel_index; |
| 86 | std::memcpy(data_ptrs[0], data_ptrs[1], copy_size); | 95 | std::memcpy(data_ptrs[0], data_ptrs[1], copy_size); |
| @@ -88,6 +97,17 @@ void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_da | |||
| 88 | } | 97 | } |
| 89 | } | 98 | } |
| 90 | 99 | ||
| 100 | void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel, | ||
| 101 | u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) { | ||
| 102 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) { | ||
| 103 | FastSwizzleData(width, height, bytes_per_pixel, out_bytes_per_pixel, swizzled_data, | ||
| 104 | unswizzled_data, unswizzle, block_height); | ||
| 105 | } else { | ||
| 106 | LegacySwizzleData(width, height, bytes_per_pixel, out_bytes_per_pixel, swizzled_data, | ||
| 107 | unswizzled_data, unswizzle, block_height); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 91 | u32 BytesPerPixel(TextureFormat format) { | 111 | u32 BytesPerPixel(TextureFormat format) { |
| 92 | switch (format) { | 112 | switch (format) { |
| 93 | case TextureFormat::DXT1: | 113 | case TextureFormat::DXT1: |
| @@ -134,13 +154,8 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 134 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, | 154 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, |
| 135 | u32 height, u32 block_height) { | 155 | u32 height, u32 block_height) { |
| 136 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); | 156 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); |
| 137 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) { | 157 | CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, |
| 138 | FastSwizzleData(width / tile_size, height / tile_size, bytes_per_pixel, | 158 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); |
| 139 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); | ||
| 140 | } else { | ||
| 141 | CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, | ||
| 142 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); | ||
| 143 | } | ||
| 144 | return unswizzled_data; | 159 | return unswizzled_data; |
| 145 | } | 160 | } |
| 146 | 161 | ||
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 991ae10cd..67890455a 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -26,10 +26,10 @@ | |||
| 26 | #include "yuzu/main.h" | 26 | #include "yuzu/main.h" |
| 27 | #include "yuzu/ui_settings.h" | 27 | #include "yuzu/ui_settings.h" |
| 28 | 28 | ||
| 29 | GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {} | 29 | GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {} |
| 30 | 30 | ||
| 31 | // EventFilter in order to process systemkeys while editing the searchfield | 31 | // EventFilter in order to process systemkeys while editing the searchfield |
| 32 | bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) { | 32 | bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) { |
| 33 | // If it isn't a KeyRelease event then continue with standard event processing | 33 | // If it isn't a KeyRelease event then continue with standard event processing |
| 34 | if (event->type() != QEvent::KeyRelease) | 34 | if (event->type() != QEvent::KeyRelease) |
| 35 | return QObject::eventFilter(obj, event); | 35 | return QObject::eventFilter(obj, event); |
| @@ -88,21 +88,21 @@ bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* e | |||
| 88 | return QObject::eventFilter(obj, event); | 88 | return QObject::eventFilter(obj, event); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | void GameList::SearchField::setFilterResult(int visible, int total) { | 91 | void GameListSearchField::setFilterResult(int visible, int total) { |
| 92 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); | 92 | label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | void GameList::SearchField::clear() { | 95 | void GameListSearchField::clear() { |
| 96 | edit_filter->setText(""); | 96 | edit_filter->setText(""); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | void GameList::SearchField::setFocus() { | 99 | void GameListSearchField::setFocus() { |
| 100 | if (edit_filter->isVisible()) { | 100 | if (edit_filter->isVisible()) { |
| 101 | edit_filter->setFocus(); | 101 | edit_filter->setFocus(); |
| 102 | } | 102 | } |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} { | 105 | GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { |
| 106 | KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent); | 106 | KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent); |
| 107 | layout_filter = new QHBoxLayout; | 107 | layout_filter = new QHBoxLayout; |
| 108 | layout_filter->setMargin(8); | 108 | layout_filter->setMargin(8); |
| @@ -202,7 +202,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent) | |||
| 202 | this->main_window = parent; | 202 | this->main_window = parent; |
| 203 | layout = new QVBoxLayout; | 203 | layout = new QVBoxLayout; |
| 204 | tree_view = new QTreeView; | 204 | tree_view = new QTreeView; |
| 205 | search_field = new SearchField(this); | 205 | search_field = new GameListSearchField(this); |
| 206 | item_model = new QStandardItemModel(tree_view); | 206 | item_model = new QStandardItemModel(tree_view); |
| 207 | tree_view->setModel(item_model); | 207 | tree_view->setModel(item_model); |
| 208 | 208 | ||
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 3bf51870e..05e115e19 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "yuzu/compatibility_list.h" | 22 | #include "yuzu/compatibility_list.h" |
| 23 | 23 | ||
| 24 | class GameListWorker; | 24 | class GameListWorker; |
| 25 | class GameListSearchField; | ||
| 25 | class GMainWindow; | 26 | class GMainWindow; |
| 26 | 27 | ||
| 27 | namespace FileSys { | 28 | namespace FileSys { |
| @@ -46,33 +47,6 @@ public: | |||
| 46 | COLUMN_COUNT, // Number of columns | 47 | COLUMN_COUNT, // Number of columns |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | class SearchField : public QWidget { | ||
| 50 | public: | ||
| 51 | void setFilterResult(int visible, int total); | ||
| 52 | void clear(); | ||
| 53 | void setFocus(); | ||
| 54 | explicit SearchField(GameList* parent = nullptr); | ||
| 55 | |||
| 56 | private: | ||
| 57 | class KeyReleaseEater : public QObject { | ||
| 58 | public: | ||
| 59 | explicit KeyReleaseEater(GameList* gamelist); | ||
| 60 | |||
| 61 | private: | ||
| 62 | GameList* gamelist = nullptr; | ||
| 63 | QString edit_filter_text_old; | ||
| 64 | |||
| 65 | protected: | ||
| 66 | bool eventFilter(QObject* obj, QEvent* event) override; | ||
| 67 | }; | ||
| 68 | QHBoxLayout* layout_filter = nullptr; | ||
| 69 | QTreeView* tree_view = nullptr; | ||
| 70 | QLabel* label_filter = nullptr; | ||
| 71 | QLineEdit* edit_filter = nullptr; | ||
| 72 | QLabel* label_filter_result = nullptr; | ||
| 73 | QToolButton* button_filter_close = nullptr; | ||
| 74 | }; | ||
| 75 | |||
| 76 | explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, GMainWindow* parent = nullptr); | 50 | explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, GMainWindow* parent = nullptr); |
| 77 | ~GameList() override; | 51 | ~GameList() override; |
| 78 | 52 | ||
| @@ -110,7 +84,7 @@ private: | |||
| 110 | void RefreshGameDirectory(); | 84 | void RefreshGameDirectory(); |
| 111 | 85 | ||
| 112 | std::shared_ptr<FileSys::VfsFilesystem> vfs; | 86 | std::shared_ptr<FileSys::VfsFilesystem> vfs; |
| 113 | SearchField* search_field; | 87 | GameListSearchField* search_field; |
| 114 | GMainWindow* main_window = nullptr; | 88 | GMainWindow* main_window = nullptr; |
| 115 | QVBoxLayout* layout = nullptr; | 89 | QVBoxLayout* layout = nullptr; |
| 116 | QTreeView* tree_view = nullptr; | 90 | QTreeView* tree_view = nullptr; |
| @@ -118,6 +92,8 @@ private: | |||
| 118 | GameListWorker* current_worker = nullptr; | 92 | GameListWorker* current_worker = nullptr; |
| 119 | QFileSystemWatcher* watcher = nullptr; | 93 | QFileSystemWatcher* watcher = nullptr; |
| 120 | CompatibilityList compatibility_list; | 94 | CompatibilityList compatibility_list; |
| 95 | |||
| 96 | friend class GameListSearchField; | ||
| 121 | }; | 97 | }; |
| 122 | 98 | ||
| 123 | Q_DECLARE_METATYPE(GameListOpenTarget); | 99 | Q_DECLARE_METATYPE(GameListOpenTarget); |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index cee109730..3db0e90da 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <QObject> | 16 | #include <QObject> |
| 17 | #include <QStandardItem> | 17 | #include <QStandardItem> |
| 18 | #include <QString> | 18 | #include <QString> |
| 19 | #include <QWidget> | ||
| 19 | 20 | ||
| 20 | #include "common/common_types.h" | 21 | #include "common/common_types.h" |
| 21 | #include "common/logging/log.h" | 22 | #include "common/logging/log.h" |
| @@ -176,3 +177,42 @@ public: | |||
| 176 | return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong(); | 177 | return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong(); |
| 177 | } | 178 | } |
| 178 | }; | 179 | }; |
| 180 | |||
| 181 | class GameList; | ||
| 182 | class QHBoxLayout; | ||
| 183 | class QTreeView; | ||
| 184 | class QLabel; | ||
| 185 | class QLineEdit; | ||
| 186 | class QToolButton; | ||
| 187 | |||
| 188 | class GameListSearchField : public QWidget { | ||
| 189 | Q_OBJECT | ||
| 190 | |||
| 191 | public: | ||
| 192 | explicit GameListSearchField(GameList* parent = nullptr); | ||
| 193 | |||
| 194 | void setFilterResult(int visible, int total); | ||
| 195 | |||
| 196 | void clear(); | ||
| 197 | void setFocus(); | ||
| 198 | |||
| 199 | private: | ||
| 200 | class KeyReleaseEater : public QObject { | ||
| 201 | public: | ||
| 202 | explicit KeyReleaseEater(GameList* gamelist); | ||
| 203 | |||
| 204 | private: | ||
| 205 | GameList* gamelist = nullptr; | ||
| 206 | QString edit_filter_text_old; | ||
| 207 | |||
| 208 | protected: | ||
| 209 | // EventFilter in order to process systemkeys while editing the searchfield | ||
| 210 | bool eventFilter(QObject* obj, QEvent* event) override; | ||
| 211 | }; | ||
| 212 | QHBoxLayout* layout_filter = nullptr; | ||
| 213 | QTreeView* tree_view = nullptr; | ||
| 214 | QLabel* label_filter = nullptr; | ||
| 215 | QLineEdit* edit_filter = nullptr; | ||
| 216 | QLabel* label_filter_result = nullptr; | ||
| 217 | QToolButton* button_filter_close = nullptr; | ||
| 218 | }; | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index cb37796fa..27015d02c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -622,9 +622,9 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 622 | std::string title_name; | 622 | std::string title_name; |
| 623 | const auto res = Core::System::GetInstance().GetGameName(title_name); | 623 | const auto res = Core::System::GetInstance().GetGameName(title_name); |
| 624 | if (res != Loader::ResultStatus::Success) { | 624 | if (res != Loader::ResultStatus::Success) { |
| 625 | const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id; | 625 | const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| 626 | 626 | ||
| 627 | const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); | 627 | const auto [nacp, icon_file] = FileSys::PatchManager(title_id).GetControlMetadata(); |
| 628 | if (nacp != nullptr) | 628 | if (nacp != nullptr) |
| 629 | title_name = nacp->GetApplicationName(); | 629 | title_name = nacp->GetApplicationName(); |
| 630 | 630 | ||
| @@ -756,11 +756,51 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | |||
| 756 | QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); | 756 | QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); |
| 757 | } | 757 | } |
| 758 | 758 | ||
| 759 | static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) { | ||
| 760 | std::size_t out = 0; | ||
| 761 | |||
| 762 | for (const auto& subdir : dir->GetSubdirectories()) { | ||
| 763 | out += 1 + CalculateRomFSEntrySize(subdir, full); | ||
| 764 | } | ||
| 765 | |||
| 766 | return out + (full ? dir->GetFiles().size() : 0); | ||
| 767 | } | ||
| 768 | |||
| 769 | static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src, | ||
| 770 | const FileSys::VirtualDir& dest, std::size_t block_size, bool full) { | ||
| 771 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 772 | return false; | ||
| 773 | if (dialog.wasCanceled()) | ||
| 774 | return false; | ||
| 775 | |||
| 776 | if (full) { | ||
| 777 | for (const auto& file : src->GetFiles()) { | ||
| 778 | const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); | ||
| 779 | if (!FileSys::VfsRawCopy(file, out, block_size)) | ||
| 780 | return false; | ||
| 781 | dialog.setValue(dialog.value() + 1); | ||
| 782 | if (dialog.wasCanceled()) | ||
| 783 | return false; | ||
| 784 | } | ||
| 785 | } | ||
| 786 | |||
| 787 | for (const auto& dir : src->GetSubdirectories()) { | ||
| 788 | const auto out = dest->CreateSubdirectory(dir->GetName()); | ||
| 789 | if (!RomFSRawCopy(dialog, dir, out, block_size, full)) | ||
| 790 | return false; | ||
| 791 | dialog.setValue(dialog.value() + 1); | ||
| 792 | if (dialog.wasCanceled()) | ||
| 793 | return false; | ||
| 794 | } | ||
| 795 | |||
| 796 | return true; | ||
| 797 | } | ||
| 798 | |||
| 759 | void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { | 799 | void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { |
| 760 | const auto path = fmt::format("{}{:016X}/romfs", | 800 | const auto path = fmt::format("{}{:016X}/romfs", |
| 761 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id); | 801 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id); |
| 762 | 802 | ||
| 763 | auto failed = [this, &path]() { | 803 | const auto failed = [this, &path] { |
| 764 | QMessageBox::warning(this, tr("RomFS Extraction Failed!"), | 804 | QMessageBox::warning(this, tr("RomFS Extraction Failed!"), |
| 765 | tr("There was an error copying the RomFS files or the user " | 805 | tr("There was an error copying the RomFS files or the user " |
| 766 | "cancelled the operation.")); | 806 | "cancelled the operation.")); |
| @@ -808,53 +848,13 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 808 | failed(); | 848 | failed(); |
| 809 | 849 | ||
| 810 | const auto full = res == "Full"; | 850 | const auto full = res == "Full"; |
| 811 | 851 | const auto entry_size = CalculateRomFSEntrySize(extracted, full); | |
| 812 | const static std::function<size_t(const FileSys::VirtualDir&, bool)> calculate_entry_size = | ||
| 813 | [](const FileSys::VirtualDir& dir, bool full) { | ||
| 814 | size_t out = 0; | ||
| 815 | for (const auto& subdir : dir->GetSubdirectories()) | ||
| 816 | out += 1 + calculate_entry_size(subdir, full); | ||
| 817 | return out + full ? dir->GetFiles().size() : 0; | ||
| 818 | }; | ||
| 819 | const auto entry_size = calculate_entry_size(extracted, full); | ||
| 820 | 852 | ||
| 821 | QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); | 853 | QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); |
| 822 | progress.setWindowModality(Qt::WindowModal); | 854 | progress.setWindowModality(Qt::WindowModal); |
| 823 | progress.setMinimumDuration(100); | 855 | progress.setMinimumDuration(100); |
| 824 | 856 | ||
| 825 | const static std::function<bool(QProgressDialog&, const FileSys::VirtualDir&, | 857 | if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) { |
| 826 | const FileSys::VirtualDir&, size_t, bool)> | ||
| 827 | qt_raw_copy = [](QProgressDialog& dialog, const FileSys::VirtualDir& src, | ||
| 828 | const FileSys::VirtualDir& dest, size_t block_size, bool full) { | ||
| 829 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 830 | return false; | ||
| 831 | if (dialog.wasCanceled()) | ||
| 832 | return false; | ||
| 833 | |||
| 834 | if (full) { | ||
| 835 | for (const auto& file : src->GetFiles()) { | ||
| 836 | const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); | ||
| 837 | if (!FileSys::VfsRawCopy(file, out, block_size)) | ||
| 838 | return false; | ||
| 839 | dialog.setValue(dialog.value() + 1); | ||
| 840 | if (dialog.wasCanceled()) | ||
| 841 | return false; | ||
| 842 | } | ||
| 843 | } | ||
| 844 | |||
| 845 | for (const auto& dir : src->GetSubdirectories()) { | ||
| 846 | const auto out = dest->CreateSubdirectory(dir->GetName()); | ||
| 847 | if (!qt_raw_copy(dialog, dir, out, block_size, full)) | ||
| 848 | return false; | ||
| 849 | dialog.setValue(dialog.value() + 1); | ||
| 850 | if (dialog.wasCanceled()) | ||
| 851 | return false; | ||
| 852 | } | ||
| 853 | |||
| 854 | return true; | ||
| 855 | }; | ||
| 856 | |||
| 857 | if (qt_raw_copy(progress, extracted, out, 0x400000, full)) { | ||
| 858 | progress.close(); | 858 | progress.close(); |
| 859 | QMessageBox::information(this, tr("RomFS Extraction Succeeded!"), | 859 | QMessageBox::information(this, tr("RomFS Extraction Succeeded!"), |
| 860 | tr("The operation completed successfully.")); | 860 | tr("The operation completed successfully.")); |
| @@ -931,7 +931,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 931 | } | 931 | } |
| 932 | 932 | ||
| 933 | const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, | 933 | const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, |
| 934 | const FileSys::VirtualFile& dest, size_t block_size) { | 934 | const FileSys::VirtualFile& dest, std::size_t block_size) { |
| 935 | if (src == nullptr || dest == nullptr) | 935 | if (src == nullptr || dest == nullptr) |
| 936 | return false; | 936 | return false; |
| 937 | if (!dest->Resize(src->GetSize())) | 937 | if (!dest->Resize(src->GetSize())) |