diff options
Diffstat (limited to 'src')
119 files changed, 3270 insertions, 1017 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 2bbc5bb16..7f3ae1a4e 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -35,11 +35,14 @@ namespace Log { | |||
| 35 | SUB(Service, ACC) \ | 35 | SUB(Service, ACC) \ |
| 36 | SUB(Service, Audio) \ | 36 | SUB(Service, Audio) \ |
| 37 | SUB(Service, AM) \ | 37 | SUB(Service, AM) \ |
| 38 | SUB(Service, AOC) \ | ||
| 38 | SUB(Service, APM) \ | 39 | SUB(Service, APM) \ |
| 40 | SUB(Service, Friend) \ | ||
| 39 | SUB(Service, FS) \ | 41 | SUB(Service, FS) \ |
| 40 | SUB(Service, HID) \ | 42 | SUB(Service, HID) \ |
| 41 | SUB(Service, LM) \ | 43 | SUB(Service, LM) \ |
| 42 | SUB(Service, NIFM) \ | 44 | SUB(Service, NIFM) \ |
| 45 | SUB(Service, NS) \ | ||
| 43 | SUB(Service, NVDRV) \ | 46 | SUB(Service, NVDRV) \ |
| 44 | SUB(Service, PCTL) \ | 47 | SUB(Service, PCTL) \ |
| 45 | SUB(Service, SET) \ | 48 | SUB(Service, SET) \ |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 0d79b8498..3cf13fcb0 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -51,12 +51,15 @@ enum class Class : ClassType { | |||
| 51 | /// should have its own subclass. | 51 | /// should have its own subclass. |
| 52 | Service_ACC, ///< The ACC (Accounts) service | 52 | Service_ACC, ///< The ACC (Accounts) service |
| 53 | Service_AM, ///< The AM (Applet manager) service | 53 | Service_AM, ///< The AM (Applet manager) service |
| 54 | Service_AOC, ///< The AOC (AddOn Content) service | ||
| 54 | Service_APM, ///< The APM (Performance) service | 55 | Service_APM, ///< The APM (Performance) service |
| 55 | Service_Audio, ///< The Audio (Audio control) service | 56 | Service_Audio, ///< The Audio (Audio control) service |
| 57 | Service_Friend, ///< The friend service | ||
| 56 | Service_FS, ///< The FS (Filesystem) service | 58 | Service_FS, ///< The FS (Filesystem) service |
| 57 | Service_HID, ///< The HID (Human interface device) service | 59 | Service_HID, ///< The HID (Human interface device) service |
| 58 | Service_LM, ///< The LM (Logger) service | 60 | Service_LM, ///< The LM (Logger) service |
| 59 | Service_NIFM, ///< The NIFM (Network interface) service | 61 | Service_NIFM, ///< The NIFM (Network interface) service |
| 62 | Service_NS, ///< The NS services | ||
| 60 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service | 63 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service |
| 61 | Service_PCTL, ///< The PCTL (Parental control) service | 64 | Service_PCTL, ///< The PCTL (Parental control) service |
| 62 | Service_SET, ///< The SET (Settings) service | 65 | Service_SET, ///< The SET (Settings) service |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index fc6cb67c7..faaa50e4d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -7,15 +7,21 @@ add_library(core STATIC | |||
| 7 | core_timing.cpp | 7 | core_timing.cpp |
| 8 | core_timing.h | 8 | core_timing.h |
| 9 | file_sys/directory.h | 9 | file_sys/directory.h |
| 10 | file_sys/disk_filesystem.cpp | ||
| 11 | file_sys/disk_filesystem.h | ||
| 10 | file_sys/errors.h | 12 | file_sys/errors.h |
| 11 | file_sys/filesystem.cpp | 13 | file_sys/filesystem.cpp |
| 12 | file_sys/filesystem.h | 14 | file_sys/filesystem.h |
| 13 | file_sys/path_parser.cpp | 15 | file_sys/path_parser.cpp |
| 14 | file_sys/path_parser.h | 16 | file_sys/path_parser.h |
| 17 | file_sys/program_metadata.cpp | ||
| 18 | file_sys/program_metadata.h | ||
| 15 | file_sys/romfs_factory.cpp | 19 | file_sys/romfs_factory.cpp |
| 16 | file_sys/romfs_factory.h | 20 | file_sys/romfs_factory.h |
| 17 | file_sys/romfs_filesystem.cpp | 21 | file_sys/romfs_filesystem.cpp |
| 18 | file_sys/romfs_filesystem.h | 22 | file_sys/romfs_filesystem.h |
| 23 | file_sys/savedata_factory.cpp | ||
| 24 | file_sys/savedata_factory.h | ||
| 19 | file_sys/storage.h | 25 | file_sys/storage.h |
| 20 | frontend/emu_window.cpp | 26 | frontend/emu_window.cpp |
| 21 | frontend/emu_window.h | 27 | frontend/emu_window.h |
| @@ -28,8 +34,6 @@ add_library(core STATIC | |||
| 28 | hle/config_mem.h | 34 | hle/config_mem.h |
| 29 | hle/ipc.h | 35 | hle/ipc.h |
| 30 | hle/ipc_helpers.h | 36 | hle/ipc_helpers.h |
| 31 | hle/kernel/address_arbiter.cpp | ||
| 32 | hle/kernel/address_arbiter.h | ||
| 33 | hle/kernel/client_port.cpp | 37 | hle/kernel/client_port.cpp |
| 34 | hle/kernel/client_port.h | 38 | hle/kernel/client_port.h |
| 35 | hle/kernel/client_session.cpp | 39 | hle/kernel/client_session.cpp |
| @@ -55,6 +59,8 @@ add_library(core STATIC | |||
| 55 | hle/kernel/process.h | 59 | hle/kernel/process.h |
| 56 | hle/kernel/resource_limit.cpp | 60 | hle/kernel/resource_limit.cpp |
| 57 | hle/kernel/resource_limit.h | 61 | hle/kernel/resource_limit.h |
| 62 | hle/kernel/scheduler.cpp | ||
| 63 | hle/kernel/scheduler.h | ||
| 58 | hle/kernel/server_port.cpp | 64 | hle/kernel/server_port.cpp |
| 59 | hle/kernel/server_port.h | 65 | hle/kernel/server_port.h |
| 60 | hle/kernel/server_session.cpp | 66 | hle/kernel/server_session.cpp |
| @@ -112,6 +118,10 @@ add_library(core STATIC | |||
| 112 | hle/service/filesystem/filesystem.h | 118 | hle/service/filesystem/filesystem.h |
| 113 | hle/service/filesystem/fsp_srv.cpp | 119 | hle/service/filesystem/fsp_srv.cpp |
| 114 | hle/service/filesystem/fsp_srv.h | 120 | hle/service/filesystem/fsp_srv.h |
| 121 | hle/service/friend/friend.cpp | ||
| 122 | hle/service/friend/friend.h | ||
| 123 | hle/service/friend/friend_a.cpp | ||
| 124 | hle/service/friend/friend_a.h | ||
| 115 | hle/service/hid/hid.cpp | 125 | hle/service/hid/hid.cpp |
| 116 | hle/service/hid/hid.h | 126 | hle/service/hid/hid.h |
| 117 | hle/service/lm/lm.cpp | 127 | hle/service/lm/lm.cpp |
| @@ -124,6 +134,10 @@ add_library(core STATIC | |||
| 124 | hle/service/nifm/nifm_s.h | 134 | hle/service/nifm/nifm_s.h |
| 125 | hle/service/nifm/nifm_u.cpp | 135 | hle/service/nifm/nifm_u.cpp |
| 126 | hle/service/nifm/nifm_u.h | 136 | hle/service/nifm/nifm_u.h |
| 137 | hle/service/ns/ns.cpp | ||
| 138 | hle/service/ns/ns.h | ||
| 139 | hle/service/ns/pl_u.cpp | ||
| 140 | hle/service/ns/pl_u.h | ||
| 127 | hle/service/nvdrv/devices/nvdevice.h | 141 | hle/service/nvdrv/devices/nvdevice.h |
| 128 | hle/service/nvdrv/devices/nvdisp_disp0.cpp | 142 | hle/service/nvdrv/devices/nvdisp_disp0.cpp |
| 129 | hle/service/nvdrv/devices/nvdisp_disp0.h | 143 | hle/service/nvdrv/devices/nvdisp_disp0.h |
| @@ -155,6 +169,14 @@ add_library(core STATIC | |||
| 155 | hle/service/service.h | 169 | hle/service/service.h |
| 156 | hle/service/set/set.cpp | 170 | hle/service/set/set.cpp |
| 157 | hle/service/set/set.h | 171 | hle/service/set/set.h |
| 172 | hle/service/set/set_cal.cpp | ||
| 173 | hle/service/set/set_cal.h | ||
| 174 | hle/service/set/set_fd.cpp | ||
| 175 | hle/service/set/set_fd.h | ||
| 176 | hle/service/set/set_sys.cpp | ||
| 177 | hle/service/set/set_sys.h | ||
| 178 | hle/service/set/settings.cpp | ||
| 179 | hle/service/set/settings.h | ||
| 158 | hle/service/sm/controller.cpp | 180 | hle/service/sm/controller.cpp |
| 159 | hle/service/sm/controller.h | 181 | hle/service/sm/controller.h |
| 160 | hle/service/sm/sm.cpp | 182 | hle/service/sm/sm.cpp |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 9f2224b78..32ff3c345 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -31,8 +31,12 @@ public: | |||
| 31 | /// Step CPU by one instruction | 31 | /// Step CPU by one instruction |
| 32 | virtual void Step() = 0; | 32 | virtual void Step() = 0; |
| 33 | 33 | ||
| 34 | /// Maps a backing memory region for the CPU | ||
| 34 | virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, | 35 | virtual void MapBackingMemory(VAddr address, size_t size, u8* memory, |
| 35 | Kernel::VMAPermission perms) {} | 36 | Kernel::VMAPermission perms) = 0; |
| 37 | |||
| 38 | /// Unmaps a region of memory that was previously mapped using MapBackingMemory | ||
| 39 | virtual void UnmapMemory(VAddr address, size_t size) = 0; | ||
| 36 | 40 | ||
| 37 | /// Clear all instruction cache | 41 | /// Clear all instruction cache |
| 38 | virtual void ClearInstructionCache() = 0; | 42 | virtual void ClearInstructionCache() = 0; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index a64ce9551..7d83f9717 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -6,7 +6,9 @@ | |||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <dynarmic/A64/a64.h> | 7 | #include <dynarmic/A64/a64.h> |
| 8 | #include <dynarmic/A64/config.h> | 8 | #include <dynarmic/A64/config.h> |
| 9 | #include "common/logging/log.h" | ||
| 9 | #include "core/arm/dynarmic/arm_dynarmic.h" | 10 | #include "core/arm/dynarmic/arm_dynarmic.h" |
| 11 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | 12 | #include "core/core_timing.h" |
| 11 | #include "core/hle/kernel/memory.h" | 13 | #include "core/hle/kernel/memory.h" |
| 12 | #include "core/hle/kernel/svc.h" | 14 | #include "core/hle/kernel/svc.h" |
| @@ -53,6 +55,9 @@ public: | |||
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | void InterpreterFallback(u64 pc, size_t num_instructions) override { | 57 | void InterpreterFallback(u64 pc, size_t num_instructions) override { |
| 58 | LOG_INFO(Core_ARM, "Unicorn fallback @ 0x%" PRIx64 " for %zu instructions (instr = %08x)", | ||
| 59 | pc, num_instructions, MemoryReadCode(pc)); | ||
| 60 | |||
| 56 | ARM_Interface::ThreadContext ctx; | 61 | ARM_Interface::ThreadContext ctx; |
| 57 | parent.SaveContext(ctx); | 62 | parent.SaveContext(ctx); |
| 58 | parent.inner_unicorn.LoadContext(ctx); | 63 | parent.inner_unicorn.LoadContext(ctx); |
| @@ -63,8 +68,17 @@ public: | |||
| 63 | } | 68 | } |
| 64 | 69 | ||
| 65 | void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { | 70 | void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { |
| 66 | ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")", | 71 | switch (exception) { |
| 67 | static_cast<size_t>(exception), pc); | 72 | case Dynarmic::A64::Exception::WaitForInterrupt: |
| 73 | case Dynarmic::A64::Exception::WaitForEvent: | ||
| 74 | case Dynarmic::A64::Exception::SendEvent: | ||
| 75 | case Dynarmic::A64::Exception::SendEventLocal: | ||
| 76 | case Dynarmic::A64::Exception::Yield: | ||
| 77 | return; | ||
| 78 | default: | ||
| 79 | ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")", | ||
| 80 | static_cast<size_t>(exception), pc); | ||
| 81 | } | ||
| 68 | } | 82 | } |
| 69 | 83 | ||
| 70 | void CallSVC(u32 swi) override { | 84 | void CallSVC(u32 swi) override { |
| @@ -81,23 +95,30 @@ public: | |||
| 81 | u64 GetTicksRemaining() override { | 95 | u64 GetTicksRemaining() override { |
| 82 | return ticks_remaining; | 96 | return ticks_remaining; |
| 83 | } | 97 | } |
| 98 | u64 GetCNTPCT() override { | ||
| 99 | return CoreTiming::GetTicks(); | ||
| 100 | } | ||
| 84 | 101 | ||
| 85 | ARM_Dynarmic& parent; | 102 | ARM_Dynarmic& parent; |
| 86 | size_t ticks_remaining = 0; | 103 | size_t ticks_remaining = 0; |
| 87 | size_t num_interpreted_instructions = 0; | 104 | size_t num_interpreted_instructions = 0; |
| 88 | u64 tpidrro_el0 = 0; | 105 | u64 tpidrro_el0 = 0; |
| 106 | u64 tpidr_el0 = 0; | ||
| 89 | }; | 107 | }; |
| 90 | 108 | ||
| 91 | std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) { | 109 | std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) { |
| 92 | const auto page_table = Kernel::g_current_process->vm_manager.page_table.pointers.data(); | 110 | const auto page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data(); |
| 93 | 111 | ||
| 94 | Dynarmic::A64::UserConfig config; | 112 | Dynarmic::A64::UserConfig config; |
| 95 | config.callbacks = cb.get(); | 113 | config.callbacks = cb.get(); |
| 96 | config.tpidrro_el0 = &cb->tpidrro_el0; | 114 | config.tpidrro_el0 = &cb->tpidrro_el0; |
| 115 | config.tpidr_el0 = &cb->tpidr_el0; | ||
| 97 | config.dczid_el0 = 4; | 116 | config.dczid_el0 = 4; |
| 117 | config.ctr_el0 = 0x8444c004; | ||
| 98 | config.page_table = reinterpret_cast<void**>(page_table); | 118 | config.page_table = reinterpret_cast<void**>(page_table); |
| 99 | config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS; | 119 | config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS; |
| 100 | config.silently_mirror_page_table = false; | 120 | config.silently_mirror_page_table = false; |
| 121 | |||
| 101 | return std::make_unique<Dynarmic::A64::Jit>(config); | 122 | return std::make_unique<Dynarmic::A64::Jit>(config); |
| 102 | } | 123 | } |
| 103 | 124 | ||
| @@ -126,6 +147,10 @@ void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory, | |||
| 126 | inner_unicorn.MapBackingMemory(address, size, memory, perms); | 147 | inner_unicorn.MapBackingMemory(address, size, memory, perms); |
| 127 | } | 148 | } |
| 128 | 149 | ||
| 150 | void ARM_Dynarmic::UnmapMemory(u64 address, size_t size) { | ||
| 151 | inner_unicorn.UnmapMemory(address, size); | ||
| 152 | } | ||
| 153 | |||
| 129 | void ARM_Dynarmic::SetPC(u64 pc) { | 154 | void ARM_Dynarmic::SetPC(u64 pc) { |
| 130 | jit->SetPC(pc); | 155 | jit->SetPC(pc); |
| 131 | } | 156 | } |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index a436ddd0f..128669d01 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h | |||
| @@ -19,7 +19,7 @@ public: | |||
| 19 | 19 | ||
| 20 | void MapBackingMemory(VAddr address, size_t size, u8* memory, | 20 | void MapBackingMemory(VAddr address, size_t size, u8* memory, |
| 21 | Kernel::VMAPermission perms) override; | 21 | Kernel::VMAPermission perms) override; |
| 22 | 22 | void UnmapMemory(u64 address, size_t size) override; | |
| 23 | void SetPC(u64 pc) override; | 23 | void SetPC(u64 pc) override; |
| 24 | u64 GetPC() const override; | 24 | u64 GetPC() const override; |
| 25 | u64 GetReg(int index) const override; | 25 | u64 GetReg(int index) const override; |
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 7542ed46a..bd98cb160 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp | |||
| @@ -53,7 +53,8 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si | |||
| 53 | void* user_data) { | 53 | void* user_data) { |
| 54 | ARM_Interface::ThreadContext ctx{}; | 54 | ARM_Interface::ThreadContext ctx{}; |
| 55 | Core::CPU().SaveContext(ctx); | 55 | Core::CPU().SaveContext(ctx); |
| 56 | ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x%llx", addr); | 56 | ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x%llx, pc=0x%llx, lr=0x%llx", addr, |
| 57 | ctx.pc, ctx.cpu_registers[30]); | ||
| 57 | return {}; | 58 | return {}; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| @@ -77,6 +78,10 @@ void ARM_Unicorn::MapBackingMemory(VAddr address, size_t size, u8* memory, | |||
| 77 | CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory)); | 78 | CHECKED(uc_mem_map_ptr(uc, address, size, static_cast<u32>(perms), memory)); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 81 | void ARM_Unicorn::UnmapMemory(VAddr address, size_t size) { | ||
| 82 | CHECKED(uc_mem_unmap(uc, address, size)); | ||
| 83 | } | ||
| 84 | |||
| 80 | void ARM_Unicorn::SetPC(u64 pc) { | 85 | void ARM_Unicorn::SetPC(u64 pc) { |
| 81 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc)); | 86 | CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc)); |
| 82 | } | 87 | } |
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index a2841c564..b99b58e4c 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h | |||
| @@ -14,6 +14,7 @@ public: | |||
| 14 | ~ARM_Unicorn(); | 14 | ~ARM_Unicorn(); |
| 15 | void MapBackingMemory(VAddr address, size_t size, u8* memory, | 15 | void MapBackingMemory(VAddr address, size_t size, u8* memory, |
| 16 | Kernel::VMAPermission perms) override; | 16 | Kernel::VMAPermission perms) override; |
| 17 | void UnmapMemory(VAddr address, size_t size) override; | ||
| 17 | void SetPC(u64 pc) override; | 18 | void SetPC(u64 pc) override; |
| 18 | u64 GetPC() const override; | 19 | u64 GetPC() const override; |
| 19 | u64 GetReg(int index) const override; | 20 | u64 GetReg(int index) const override; |
diff --git a/src/core/core.cpp b/src/core/core.cpp index a42cb48eb..183c5109c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -104,7 +104,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file | |||
| 104 | return init_result; | 104 | return init_result; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | const Loader::ResultStatus load_result{app_loader->Load(Kernel::g_current_process)}; | 107 | const Loader::ResultStatus load_result{app_loader->Load(current_process)}; |
| 108 | if (Loader::ResultStatus::Success != load_result) { | 108 | if (Loader::ResultStatus::Success != load_result) { |
| 109 | LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result); | 109 | LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result); |
| 110 | System::Shutdown(); | 110 | System::Shutdown(); |
| @@ -137,22 +137,26 @@ void System::Reschedule() { | |||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | reschedule_pending = false; | 139 | reschedule_pending = false; |
| 140 | Kernel::Reschedule(); | 140 | Core::System::GetInstance().Scheduler().Reschedule(); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | 143 | System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { |
| 144 | LOG_DEBUG(HW_Memory, "initialized OK"); | 144 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 145 | 145 | ||
| 146 | CoreTiming::Init(); | ||
| 147 | |||
| 148 | current_process = Kernel::Process::Create("main"); | ||
| 149 | |||
| 146 | switch (Settings::values.cpu_core) { | 150 | switch (Settings::values.cpu_core) { |
| 147 | case Settings::CpuCore::Unicorn: | 151 | case Settings::CpuCore::Unicorn: |
| 148 | cpu_core = std::make_unique<ARM_Unicorn>(); | 152 | cpu_core = std::make_shared<ARM_Unicorn>(); |
| 149 | break; | 153 | break; |
| 150 | case Settings::CpuCore::Dynarmic: | 154 | case Settings::CpuCore::Dynarmic: |
| 151 | default: | 155 | default: |
| 152 | #ifdef ARCHITECTURE_x86_64 | 156 | #ifdef ARCHITECTURE_x86_64 |
| 153 | cpu_core = std::make_unique<ARM_Dynarmic>(); | 157 | cpu_core = std::make_shared<ARM_Dynarmic>(); |
| 154 | #else | 158 | #else |
| 155 | cpu_core = std::make_unique<ARM_Unicorn>(); | 159 | cpu_core = std::make_shared<ARM_Unicorn>(); |
| 156 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | 160 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); |
| 157 | #endif | 161 | #endif |
| 158 | break; | 162 | break; |
| @@ -162,9 +166,9 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | |||
| 162 | 166 | ||
| 163 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 167 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
| 164 | 168 | ||
| 165 | CoreTiming::Init(); | ||
| 166 | HW::Init(); | 169 | HW::Init(); |
| 167 | Kernel::Init(system_mode); | 170 | Kernel::Init(system_mode); |
| 171 | scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get()); | ||
| 168 | Service::Init(); | 172 | Service::Init(); |
| 169 | GDBStub::Init(); | 173 | GDBStub::Init(); |
| 170 | 174 | ||
| @@ -192,15 +196,18 @@ void System::Shutdown() { | |||
| 192 | perf_results.frametime * 1000.0); | 196 | perf_results.frametime * 1000.0); |
| 193 | 197 | ||
| 194 | // Shutdown emulation session | 198 | // Shutdown emulation session |
| 195 | GDBStub::Shutdown(); | ||
| 196 | VideoCore::Shutdown(); | 199 | VideoCore::Shutdown(); |
| 200 | GDBStub::Shutdown(); | ||
| 197 | Service::Shutdown(); | 201 | Service::Shutdown(); |
| 202 | scheduler = nullptr; | ||
| 198 | Kernel::Shutdown(); | 203 | Kernel::Shutdown(); |
| 199 | HW::Shutdown(); | 204 | HW::Shutdown(); |
| 200 | CoreTiming::Shutdown(); | 205 | telemetry_session = nullptr; |
| 206 | gpu_core = nullptr; | ||
| 201 | cpu_core = nullptr; | 207 | cpu_core = nullptr; |
| 208 | CoreTiming::Shutdown(); | ||
| 209 | |||
| 202 | app_loader = nullptr; | 210 | app_loader = nullptr; |
| 203 | telemetry_session = nullptr; | ||
| 204 | 211 | ||
| 205 | LOG_DEBUG(Core, "Shutdown OK"); | 212 | LOG_DEBUG(Core, "Shutdown OK"); |
| 206 | } | 213 | } |
diff --git a/src/core/core.h b/src/core/core.h index 2d15ebe34..552c8f5ee 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/scheduler.h" | ||
| 10 | #include "core/loader/loader.h" | 12 | #include "core/loader/loader.h" |
| 11 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| 12 | #include "core/perf_stats.h" | 14 | #include "core/perf_stats.h" |
| @@ -107,6 +109,14 @@ public: | |||
| 107 | return *gpu_core; | 109 | return *gpu_core; |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 112 | Kernel::Scheduler& Scheduler() { | ||
| 113 | return *scheduler; | ||
| 114 | } | ||
| 115 | |||
| 116 | Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { | ||
| 117 | return current_process; | ||
| 118 | } | ||
| 119 | |||
| 110 | PerfStats perf_stats; | 120 | PerfStats perf_stats; |
| 111 | FrameLimiter frame_limiter; | 121 | FrameLimiter frame_limiter; |
| 112 | 122 | ||
| @@ -140,11 +150,12 @@ private: | |||
| 140 | /// AppLoader used to load the current executing application | 150 | /// AppLoader used to load the current executing application |
| 141 | std::unique_ptr<Loader::AppLoader> app_loader; | 151 | std::unique_ptr<Loader::AppLoader> app_loader; |
| 142 | 152 | ||
| 143 | ///< ARM11 CPU core | 153 | std::shared_ptr<ARM_Interface> cpu_core; |
| 144 | std::unique_ptr<ARM_Interface> cpu_core; | 154 | std::unique_ptr<Kernel::Scheduler> scheduler; |
| 145 | |||
| 146 | std::unique_ptr<Tegra::GPU> gpu_core; | 155 | std::unique_ptr<Tegra::GPU> gpu_core; |
| 147 | 156 | ||
| 157 | Kernel::SharedPtr<Kernel::Process> current_process; | ||
| 158 | |||
| 148 | /// When true, signals that a reschedule should happen | 159 | /// When true, signals that a reschedule should happen |
| 149 | bool reschedule_pending{}; | 160 | bool reschedule_pending{}; |
| 150 | 161 | ||
| @@ -165,4 +176,8 @@ inline TelemetrySession& Telemetry() { | |||
| 165 | return System::GetInstance().TelemetrySession(); | 176 | return System::GetInstance().TelemetrySession(); |
| 166 | } | 177 | } |
| 167 | 178 | ||
| 179 | inline Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { | ||
| 180 | return System::GetInstance().CurrentProcess(); | ||
| 181 | } | ||
| 182 | |||
| 168 | } // namespace Core | 183 | } // namespace Core |
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp new file mode 100644 index 000000000..22b17ba04 --- /dev/null +++ b/src/core/file_sys/disk_filesystem.cpp | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <memory> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/file_sys/disk_filesystem.h" | ||
| 10 | #include "core/file_sys/errors.h" | ||
| 11 | |||
| 12 | namespace FileSys { | ||
| 13 | |||
| 14 | std::string Disk_FileSystem::GetName() const { | ||
| 15 | return "Disk"; | ||
| 16 | } | ||
| 17 | |||
| 18 | ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path, | ||
| 19 | Mode mode) const { | ||
| 20 | ASSERT_MSG(mode == Mode::Read || mode == Mode::Write, "Other file modes are not supported"); | ||
| 21 | |||
| 22 | std::string full_path = base_directory + path; | ||
| 23 | auto file = std::make_shared<FileUtil::IOFile>(full_path, mode == Mode::Read ? "rb" : "wb"); | ||
| 24 | |||
| 25 | if (!file->IsOpen()) { | ||
| 26 | return ERROR_PATH_NOT_FOUND; | ||
| 27 | } | ||
| 28 | |||
| 29 | return MakeResult<std::unique_ptr<StorageBackend>>( | ||
| 30 | std::make_unique<Disk_Storage>(std::move(file))); | ||
| 31 | } | ||
| 32 | |||
| 33 | ResultCode Disk_FileSystem::DeleteFile(const Path& path) const { | ||
| 34 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 35 | // TODO(bunnei): Use correct error code | ||
| 36 | return ResultCode(-1); | ||
| 37 | } | ||
| 38 | |||
| 39 | ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const { | ||
| 40 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 41 | // TODO(wwylele): Use correct error code | ||
| 42 | return ResultCode(-1); | ||
| 43 | } | ||
| 44 | |||
| 45 | ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const { | ||
| 46 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 47 | // TODO(wwylele): Use correct error code | ||
| 48 | return ResultCode(-1); | ||
| 49 | } | ||
| 50 | |||
| 51 | ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const { | ||
| 52 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 53 | // TODO(wwylele): Use correct error code | ||
| 54 | return ResultCode(-1); | ||
| 55 | } | ||
| 56 | |||
| 57 | ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const { | ||
| 58 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 59 | |||
| 60 | std::string full_path = base_directory + path; | ||
| 61 | if (size == 0) { | ||
| 62 | FileUtil::CreateEmptyFile(full_path); | ||
| 63 | return RESULT_SUCCESS; | ||
| 64 | } | ||
| 65 | |||
| 66 | FileUtil::IOFile file(full_path, "wb"); | ||
| 67 | // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) | ||
| 68 | // We do this by seeking to the right size, then writing a single null byte. | ||
| 69 | if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) { | ||
| 70 | return RESULT_SUCCESS; | ||
| 71 | } | ||
| 72 | |||
| 73 | LOG_ERROR(Service_FS, "Too large file"); | ||
| 74 | // TODO(Subv): Find out the correct error code | ||
| 75 | return ResultCode(-1); | ||
| 76 | } | ||
| 77 | |||
| 78 | ResultCode Disk_FileSystem::CreateDirectory(const Path& path) const { | ||
| 79 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 80 | // TODO(wwylele): Use correct error code | ||
| 81 | return ResultCode(-1); | ||
| 82 | } | ||
| 83 | |||
| 84 | ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { | ||
| 85 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 86 | // TODO(wwylele): Use correct error code | ||
| 87 | return ResultCode(-1); | ||
| 88 | } | ||
| 89 | |||
| 90 | ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory( | ||
| 91 | const Path& path) const { | ||
| 92 | return MakeResult<std::unique_ptr<DirectoryBackend>>(std::make_unique<Disk_Directory>()); | ||
| 93 | } | ||
| 94 | |||
| 95 | u64 Disk_FileSystem::GetFreeSpaceSize() const { | ||
| 96 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& path) const { | ||
| 101 | std::string full_path = base_directory + path; | ||
| 102 | if (!FileUtil::Exists(full_path)) { | ||
| 103 | return ERROR_PATH_NOT_FOUND; | ||
| 104 | } | ||
| 105 | |||
| 106 | // TODO(Subv): Find out the EntryType values | ||
| 107 | UNIMPLEMENTED_MSG("Unimplemented GetEntryType"); | ||
| 108 | } | ||
| 109 | |||
| 110 | ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { | ||
| 111 | LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); | ||
| 112 | file->Seek(offset, SEEK_SET); | ||
| 113 | return MakeResult<size_t>(file->ReadBytes(buffer, length)); | ||
| 114 | } | ||
| 115 | |||
| 116 | ResultVal<size_t> Disk_Storage::Write(const u64 offset, const size_t length, const bool flush, | ||
| 117 | const u8* buffer) const { | ||
| 118 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 119 | file->Seek(offset, SEEK_SET); | ||
| 120 | size_t written = file->WriteBytes(buffer, length); | ||
| 121 | if (flush) { | ||
| 122 | file->Flush(); | ||
| 123 | } | ||
| 124 | return MakeResult<size_t>(written); | ||
| 125 | } | ||
| 126 | |||
| 127 | u64 Disk_Storage::GetSize() const { | ||
| 128 | return file->GetSize(); | ||
| 129 | } | ||
| 130 | |||
| 131 | bool Disk_Storage::SetSize(const u64 size) const { | ||
| 132 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 133 | return false; | ||
| 134 | } | ||
| 135 | |||
| 136 | u32 Disk_Directory::Read(const u32 count, Entry* entries) { | ||
| 137 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | bool Disk_Directory::Close() const { | ||
| 142 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 143 | return true; | ||
| 144 | } | ||
| 145 | |||
| 146 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/disk_filesystem.h b/src/core/file_sys/disk_filesystem.h new file mode 100644 index 000000000..53767b949 --- /dev/null +++ b/src/core/file_sys/disk_filesystem.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <memory> | ||
| 9 | #include <string> | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/file_util.h" | ||
| 12 | #include "core/file_sys/directory.h" | ||
| 13 | #include "core/file_sys/filesystem.h" | ||
| 14 | #include "core/file_sys/storage.h" | ||
| 15 | #include "core/hle/result.h" | ||
| 16 | |||
| 17 | namespace FileSys { | ||
| 18 | |||
| 19 | class Disk_FileSystem : public FileSystemBackend { | ||
| 20 | public: | ||
| 21 | explicit Disk_FileSystem(std::string base_directory) | ||
| 22 | : base_directory(std::move(base_directory)) {} | ||
| 23 | |||
| 24 | std::string GetName() const override; | ||
| 25 | |||
| 26 | ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path, | ||
| 27 | Mode mode) const override; | ||
| 28 | ResultCode DeleteFile(const Path& path) const override; | ||
| 29 | ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; | ||
| 30 | ResultCode DeleteDirectory(const Path& path) const override; | ||
| 31 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; | ||
| 32 | ResultCode CreateFile(const std::string& path, u64 size) const override; | ||
| 33 | ResultCode CreateDirectory(const Path& path) const override; | ||
| 34 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | ||
| 35 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; | ||
| 36 | u64 GetFreeSpaceSize() const override; | ||
| 37 | ResultVal<EntryType> GetEntryType(const std::string& path) const override; | ||
| 38 | |||
| 39 | protected: | ||
| 40 | std::string base_directory; | ||
| 41 | }; | ||
| 42 | |||
| 43 | class Disk_Storage : public StorageBackend { | ||
| 44 | public: | ||
| 45 | Disk_Storage(std::shared_ptr<FileUtil::IOFile> file) : file(std::move(file)) {} | ||
| 46 | |||
| 47 | ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override; | ||
| 48 | ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; | ||
| 49 | u64 GetSize() const override; | ||
| 50 | bool SetSize(u64 size) const override; | ||
| 51 | bool Close() const override { | ||
| 52 | return false; | ||
| 53 | } | ||
| 54 | void Flush() const override {} | ||
| 55 | |||
| 56 | private: | ||
| 57 | std::shared_ptr<FileUtil::IOFile> file; | ||
| 58 | }; | ||
| 59 | |||
| 60 | class Disk_Directory : public DirectoryBackend { | ||
| 61 | public: | ||
| 62 | u32 Read(const u32 count, Entry* entries) override; | ||
| 63 | bool Close() const override; | ||
| 64 | }; | ||
| 65 | |||
| 66 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index be3224ef8..0ed7d2a0c 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h | |||
| @@ -10,36 +10,17 @@ namespace FileSys { | |||
| 10 | 10 | ||
| 11 | namespace ErrCodes { | 11 | namespace ErrCodes { |
| 12 | enum { | 12 | enum { |
| 13 | RomFSNotFound = 100, | 13 | NotFound = 1, |
| 14 | ArchiveNotMounted = 101, | ||
| 15 | FileNotFound = 112, | ||
| 16 | PathNotFound = 113, | ||
| 17 | GameCardNotInserted = 141, | ||
| 18 | NotFound = 120, | ||
| 19 | FileAlreadyExists = 180, | ||
| 20 | DirectoryAlreadyExists = 185, | ||
| 21 | AlreadyExists = 190, | ||
| 22 | InvalidOpenFlags = 230, | ||
| 23 | DirectoryNotEmpty = 240, | ||
| 24 | NotAFile = 250, | ||
| 25 | NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive | ||
| 26 | ExeFSSectionNotFound = 567, | ||
| 27 | CommandNotAllowed = 630, | ||
| 28 | InvalidReadFlag = 700, | ||
| 29 | InvalidPath = 702, | ||
| 30 | WriteBeyondEnd = 705, | ||
| 31 | UnsupportedOpenFlags = 760, | ||
| 32 | IncorrectExeFSReadSize = 761, | ||
| 33 | UnexpectedFileOrDirectory = 770, | ||
| 34 | }; | 14 | }; |
| 35 | } | 15 | } |
| 36 | 16 | ||
| 17 | constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound); | ||
| 18 | |||
| 37 | // TODO(bunnei): Replace these with correct errors for Switch OS | 19 | // TODO(bunnei): Replace these with correct errors for Switch OS |
| 38 | constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1)); | 20 | constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1)); |
| 39 | constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1)); | 21 | constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1)); |
| 40 | constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1)); | 22 | constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1)); |
| 41 | constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1)); | 23 | constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1)); |
| 42 | constexpr ResultCode ERROR_PATH_NOT_FOUND(ResultCode(-1)); | ||
| 43 | constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1)); | 24 | constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1)); |
| 44 | constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1)); | 25 | constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1)); |
| 45 | constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ResultCode(-1)); | 26 | constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ResultCode(-1)); |
diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index 02705506b..94ad2abf2 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h | |||
| @@ -27,11 +27,14 @@ enum LowPathType : u32 { | |||
| 27 | Wchar = 4, | 27 | Wchar = 4, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | union Mode { | 30 | enum EntryType : u32 { |
| 31 | u32 hex; | 31 | Directory = 0, |
| 32 | BitField<0, 1, u32> read_flag; | 32 | File = 1, |
| 33 | BitField<1, 1, u32> write_flag; | 33 | }; |
| 34 | BitField<2, 1, u32> create_flag; | 34 | |
| 35 | enum class Mode : u32 { | ||
| 36 | Read = 1, | ||
| 37 | Write = 2, | ||
| 35 | }; | 38 | }; |
| 36 | 39 | ||
| 37 | class Path { | 40 | class Path { |
| @@ -86,7 +89,7 @@ public: | |||
| 86 | * @param size The size of the new file, filled with zeroes | 89 | * @param size The size of the new file, filled with zeroes |
| 87 | * @return Result of the operation | 90 | * @return Result of the operation |
| 88 | */ | 91 | */ |
| 89 | virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; | 92 | virtual ResultCode CreateFile(const std::string& path, u64 size) const = 0; |
| 90 | 93 | ||
| 91 | /** | 94 | /** |
| 92 | * Delete a file specified by its path | 95 | * Delete a file specified by its path |
| @@ -138,8 +141,8 @@ public: | |||
| 138 | * @param mode Mode to open the file with | 141 | * @param mode Mode to open the file with |
| 139 | * @return Opened file, or error code | 142 | * @return Opened file, or error code |
| 140 | */ | 143 | */ |
| 141 | virtual ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const Path& path, | 144 | virtual ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path, |
| 142 | const Mode& mode) const = 0; | 145 | Mode mode) const = 0; |
| 143 | 146 | ||
| 144 | /** | 147 | /** |
| 145 | * Open a directory specified by its path | 148 | * Open a directory specified by its path |
| @@ -153,6 +156,12 @@ public: | |||
| 153 | * @return The number of free bytes in the archive | 156 | * @return The number of free bytes in the archive |
| 154 | */ | 157 | */ |
| 155 | virtual u64 GetFreeSpaceSize() const = 0; | 158 | virtual u64 GetFreeSpaceSize() const = 0; |
| 159 | |||
| 160 | /** | ||
| 161 | * Get the type of the specified path | ||
| 162 | * @return The type of the specified path or error code | ||
| 163 | */ | ||
| 164 | virtual ResultVal<EntryType> GetEntryType(const std::string& path) const = 0; | ||
| 156 | }; | 165 | }; |
| 157 | 166 | ||
| 158 | class FileSystemFactory : NonCopyable { | 167 | class FileSystemFactory : NonCopyable { |
| @@ -174,10 +183,9 @@ public: | |||
| 174 | /** | 183 | /** |
| 175 | * Deletes the archive contents and then re-creates the base folder | 184 | * Deletes the archive contents and then re-creates the base folder |
| 176 | * @param path Path to the archive | 185 | * @param path Path to the archive |
| 177 | * @param format_info Format information for the new archive | ||
| 178 | * @return ResultCode of the operation, 0 on success | 186 | * @return ResultCode of the operation, 0 on success |
| 179 | */ | 187 | */ |
| 180 | virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0; | 188 | virtual ResultCode Format(const Path& path) = 0; |
| 181 | 189 | ||
| 182 | /** | 190 | /** |
| 183 | * Retrieves the format info about the archive with the specified path | 191 | * Retrieves the format info about the archive with the specified path |
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp new file mode 100644 index 000000000..a6dcebcc3 --- /dev/null +++ b/src/core/file_sys/program_metadata.cpp | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cinttypes> | ||
| 6 | #include "common/file_util.h" | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/file_sys/program_metadata.h" | ||
| 9 | #include "core/loader/loader.h" | ||
| 10 | |||
| 11 | namespace FileSys { | ||
| 12 | |||
| 13 | Loader::ResultStatus ProgramMetadata::Load(const std::string& file_path) { | ||
| 14 | FileUtil::IOFile file(file_path, "rb"); | ||
| 15 | if (!file.IsOpen()) | ||
| 16 | return Loader::ResultStatus::Error; | ||
| 17 | |||
| 18 | std::vector<u8> file_data(file.GetSize()); | ||
| 19 | |||
| 20 | if (!file.ReadBytes(file_data.data(), file_data.size())) | ||
| 21 | return Loader::ResultStatus::Error; | ||
| 22 | |||
| 23 | Loader::ResultStatus result = Load(file_data); | ||
| 24 | if (result != Loader::ResultStatus::Success) | ||
| 25 | LOG_ERROR(Service_FS, "Failed to load NPDM from file %s!", file_path.c_str()); | ||
| 26 | |||
| 27 | return result; | ||
| 28 | } | ||
| 29 | |||
| 30 | Loader::ResultStatus ProgramMetadata::Load(const std::vector<u8> file_data, size_t offset) { | ||
| 31 | size_t total_size = static_cast<size_t>(file_data.size() - offset); | ||
| 32 | if (total_size < sizeof(Header)) | ||
| 33 | return Loader::ResultStatus::Error; | ||
| 34 | |||
| 35 | size_t header_offset = offset; | ||
| 36 | memcpy(&npdm_header, &file_data[offset], sizeof(Header)); | ||
| 37 | |||
| 38 | size_t aci_offset = header_offset + npdm_header.aci_offset; | ||
| 39 | size_t acid_offset = header_offset + npdm_header.acid_offset; | ||
| 40 | memcpy(&aci_header, &file_data[aci_offset], sizeof(AciHeader)); | ||
| 41 | memcpy(&acid_header, &file_data[acid_offset], sizeof(AcidHeader)); | ||
| 42 | |||
| 43 | size_t fac_offset = acid_offset + acid_header.fac_offset; | ||
| 44 | size_t fah_offset = aci_offset + aci_header.fah_offset; | ||
| 45 | memcpy(&acid_file_access, &file_data[fac_offset], sizeof(FileAccessControl)); | ||
| 46 | memcpy(&aci_file_access, &file_data[fah_offset], sizeof(FileAccessHeader)); | ||
| 47 | |||
| 48 | return Loader::ResultStatus::Success; | ||
| 49 | } | ||
| 50 | |||
| 51 | bool ProgramMetadata::Is64BitProgram() const { | ||
| 52 | return npdm_header.has_64_bit_instructions; | ||
| 53 | } | ||
| 54 | |||
| 55 | ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const { | ||
| 56 | return npdm_header.address_space_type; | ||
| 57 | } | ||
| 58 | |||
| 59 | u8 ProgramMetadata::GetMainThreadPriority() const { | ||
| 60 | return npdm_header.main_thread_priority; | ||
| 61 | } | ||
| 62 | |||
| 63 | u8 ProgramMetadata::GetMainThreadCore() const { | ||
| 64 | return npdm_header.main_thread_cpu; | ||
| 65 | } | ||
| 66 | |||
| 67 | u32 ProgramMetadata::GetMainThreadStackSize() const { | ||
| 68 | return npdm_header.main_stack_size; | ||
| 69 | } | ||
| 70 | |||
| 71 | u64 ProgramMetadata::GetTitleID() const { | ||
| 72 | return aci_header.title_id; | ||
| 73 | } | ||
| 74 | |||
| 75 | u64 ProgramMetadata::GetFilesystemPermissions() const { | ||
| 76 | return aci_file_access.permissions; | ||
| 77 | } | ||
| 78 | |||
| 79 | void ProgramMetadata::Print() const { | ||
| 80 | LOG_DEBUG(Service_FS, "Magic: %.4s", npdm_header.magic.data()); | ||
| 81 | LOG_DEBUG(Service_FS, "Main thread priority: 0x%02x", npdm_header.main_thread_priority); | ||
| 82 | LOG_DEBUG(Service_FS, "Main thread core: %u", npdm_header.main_thread_cpu); | ||
| 83 | LOG_DEBUG(Service_FS, "Main thread stack size: 0x%x bytes", npdm_header.main_stack_size); | ||
| 84 | LOG_DEBUG(Service_FS, "Process category: %u", npdm_header.process_category); | ||
| 85 | LOG_DEBUG(Service_FS, "Flags: %02x", npdm_header.flags); | ||
| 86 | LOG_DEBUG(Service_FS, " > 64-bit instructions: %s", | ||
| 87 | npdm_header.has_64_bit_instructions ? "YES" : "NO"); | ||
| 88 | |||
| 89 | auto address_space = "Unknown"; | ||
| 90 | switch (npdm_header.address_space_type) { | ||
| 91 | case ProgramAddressSpaceType::Is64Bit: | ||
| 92 | address_space = "64-bit"; | ||
| 93 | break; | ||
| 94 | case ProgramAddressSpaceType::Is32Bit: | ||
| 95 | address_space = "32-bit"; | ||
| 96 | break; | ||
| 97 | } | ||
| 98 | |||
| 99 | LOG_DEBUG(Service_FS, " > Address space: %s\n", address_space); | ||
| 100 | |||
| 101 | // Begin ACID printing (potential perms, signed) | ||
| 102 | LOG_DEBUG(Service_FS, "Magic: %.4s", acid_header.magic.data()); | ||
| 103 | LOG_DEBUG(Service_FS, "Flags: %02x", acid_header.flags); | ||
| 104 | LOG_DEBUG(Service_FS, " > Is Retail: %s", acid_header.is_retail ? "YES" : "NO"); | ||
| 105 | LOG_DEBUG(Service_FS, "Title ID Min: %016" PRIX64, acid_header.title_id_min); | ||
| 106 | LOG_DEBUG(Service_FS, "Title ID Max: %016" PRIX64, acid_header.title_id_max); | ||
| 107 | LOG_DEBUG(Service_FS, "Filesystem Access: %016" PRIX64 "\n", acid_file_access.permissions); | ||
| 108 | |||
| 109 | // Begin ACI0 printing (actual perms, unsigned) | ||
| 110 | LOG_DEBUG(Service_FS, "Magic: %.4s", aci_header.magic.data()); | ||
| 111 | LOG_DEBUG(Service_FS, "Title ID: %016" PRIX64, aci_header.title_id); | ||
| 112 | LOG_DEBUG(Service_FS, "Filesystem Access: %016" PRIX64 "\n", aci_file_access.permissions); | ||
| 113 | } | ||
| 114 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h new file mode 100644 index 000000000..b80a08485 --- /dev/null +++ b/src/core/file_sys/program_metadata.h | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <string> | ||
| 9 | #include <vector> | ||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/swap.h" | ||
| 13 | |||
| 14 | namespace Loader { | ||
| 15 | enum class ResultStatus; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace FileSys { | ||
| 19 | |||
| 20 | enum class ProgramAddressSpaceType : u8 { | ||
| 21 | Is64Bit = 1, | ||
| 22 | Is32Bit = 2, | ||
| 23 | }; | ||
| 24 | |||
| 25 | enum class ProgramFilePermission : u64 { | ||
| 26 | MountContent = 1ULL << 0, | ||
| 27 | SaveDataBackup = 1ULL << 5, | ||
| 28 | SdCard = 1ULL << 21, | ||
| 29 | Calibration = 1ULL << 34, | ||
| 30 | Bit62 = 1ULL << 62, | ||
| 31 | Everything = 1ULL << 63, | ||
| 32 | }; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Helper which implements an interface to parse Program Description Metadata (NPDM) | ||
| 36 | * Data can either be loaded from a file path or with data and an offset into it. | ||
| 37 | */ | ||
| 38 | class ProgramMetadata { | ||
| 39 | public: | ||
| 40 | Loader::ResultStatus Load(const std::string& file_path); | ||
| 41 | Loader::ResultStatus Load(const std::vector<u8> file_data, size_t offset = 0); | ||
| 42 | |||
| 43 | bool Is64BitProgram() const; | ||
| 44 | ProgramAddressSpaceType GetAddressSpaceType() const; | ||
| 45 | u8 GetMainThreadPriority() const; | ||
| 46 | u8 GetMainThreadCore() const; | ||
| 47 | u32 GetMainThreadStackSize() const; | ||
| 48 | u64 GetTitleID() const; | ||
| 49 | u64 GetFilesystemPermissions() const; | ||
| 50 | |||
| 51 | void Print() const; | ||
| 52 | |||
| 53 | private: | ||
| 54 | struct Header { | ||
| 55 | std::array<char, 4> magic; | ||
| 56 | std::array<u8, 8> reserved; | ||
| 57 | union { | ||
| 58 | u8 flags; | ||
| 59 | |||
| 60 | BitField<0, 1, u8> has_64_bit_instructions; | ||
| 61 | BitField<1, 3, ProgramAddressSpaceType> address_space_type; | ||
| 62 | BitField<4, 4, u8> reserved_2; | ||
| 63 | }; | ||
| 64 | u8 reserved_3; | ||
| 65 | u8 main_thread_priority; | ||
| 66 | u8 main_thread_cpu; | ||
| 67 | std::array<u8, 8> reserved_4; | ||
| 68 | u32_le process_category; | ||
| 69 | u32_le main_stack_size; | ||
| 70 | std::array<u8, 0x10> application_name; | ||
| 71 | std::array<u8, 0x40> reserved_5; | ||
| 72 | u32_le aci_offset; | ||
| 73 | u32_le aci_size; | ||
| 74 | u32_le acid_offset; | ||
| 75 | u32_le acid_size; | ||
| 76 | }; | ||
| 77 | |||
| 78 | static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong"); | ||
| 79 | |||
| 80 | struct AcidHeader { | ||
| 81 | std::array<u8, 0x100> signature; | ||
| 82 | std::array<u8, 0x100> nca_modulus; | ||
| 83 | std::array<char, 4> magic; | ||
| 84 | u32_le nca_size; | ||
| 85 | std::array<u8, 0x4> reserved; | ||
| 86 | union { | ||
| 87 | u32 flags; | ||
| 88 | |||
| 89 | BitField<0, 1, u32> is_retail; | ||
| 90 | BitField<1, 31, u32> flags_unk; | ||
| 91 | }; | ||
| 92 | u64_le title_id_min; | ||
| 93 | u64_le title_id_max; | ||
| 94 | u32_le fac_offset; | ||
| 95 | u32_le fac_size; | ||
| 96 | u32_le sac_offset; | ||
| 97 | u32_le sac_size; | ||
| 98 | u32_le kac_offset; | ||
| 99 | u32_le kac_size; | ||
| 100 | INSERT_PADDING_BYTES(0x8); | ||
| 101 | }; | ||
| 102 | |||
| 103 | static_assert(sizeof(AcidHeader) == 0x240, "ACID header structure size is wrong"); | ||
| 104 | |||
| 105 | struct AciHeader { | ||
| 106 | std::array<char, 4> magic; | ||
| 107 | std::array<u8, 0xC> reserved; | ||
| 108 | u64_le title_id; | ||
| 109 | INSERT_PADDING_BYTES(0x8); | ||
| 110 | u32_le fah_offset; | ||
| 111 | u32_le fah_size; | ||
| 112 | u32_le sac_offset; | ||
| 113 | u32_le sac_size; | ||
| 114 | u32_le kac_offset; | ||
| 115 | u32_le kac_size; | ||
| 116 | INSERT_PADDING_BYTES(0x8); | ||
| 117 | }; | ||
| 118 | |||
| 119 | static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong"); | ||
| 120 | |||
| 121 | #pragma pack(push, 1) | ||
| 122 | |||
| 123 | struct FileAccessControl { | ||
| 124 | u8 version; | ||
| 125 | INSERT_PADDING_BYTES(3); | ||
| 126 | u64_le permissions; | ||
| 127 | std::array<u8, 0x20> unknown; | ||
| 128 | }; | ||
| 129 | |||
| 130 | static_assert(sizeof(FileAccessControl) == 0x2C, "FS access control structure size is wrong"); | ||
| 131 | |||
| 132 | struct FileAccessHeader { | ||
| 133 | u8 version; | ||
| 134 | INSERT_PADDING_BYTES(3); | ||
| 135 | u64_le permissions; | ||
| 136 | u32_le unk_offset; | ||
| 137 | u32_le unk_size; | ||
| 138 | u32_le unk_offset_2; | ||
| 139 | u32_le unk_size_2; | ||
| 140 | }; | ||
| 141 | |||
| 142 | static_assert(sizeof(FileAccessHeader) == 0x1C, "FS access header structure size is wrong"); | ||
| 143 | |||
| 144 | #pragma pack(pop) | ||
| 145 | |||
| 146 | Header npdm_header; | ||
| 147 | AciHeader aci_header; | ||
| 148 | AcidHeader acid_header; | ||
| 149 | |||
| 150 | FileAccessControl acid_file_access; | ||
| 151 | FileAccessHeader aci_file_access; | ||
| 152 | }; | ||
| 153 | |||
| 154 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index e0de49f05..b21427948 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp | |||
| @@ -23,7 +23,7 @@ ResultVal<std::unique_ptr<FileSystemBackend>> RomFS_Factory::Open(const Path& pa | |||
| 23 | return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive)); | 23 | return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive)); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | ResultCode RomFS_Factory::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { | 26 | ResultCode RomFS_Factory::Format(const Path& path) { |
| 27 | LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); | 27 | LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); |
| 28 | // TODO(bunnei): Find the right error code for this | 28 | // TODO(bunnei): Find the right error code for this |
| 29 | return ResultCode(-1); | 29 | return ResultCode(-1); |
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h index 10ea13966..e0698e642 100644 --- a/src/core/file_sys/romfs_factory.h +++ b/src/core/file_sys/romfs_factory.h | |||
| @@ -23,7 +23,7 @@ public: | |||
| 23 | return "ArchiveFactory_RomFS"; | 23 | return "ArchiveFactory_RomFS"; |
| 24 | } | 24 | } |
| 25 | ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override; | 25 | ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override; |
| 26 | ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | 26 | ResultCode Format(const Path& path) override; |
| 27 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | 27 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; |
| 28 | 28 | ||
| 29 | private: | 29 | private: |
diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index ca1463d7c..f1f9b4d04 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp | |||
| @@ -14,8 +14,8 @@ std::string RomFS_FileSystem::GetName() const { | |||
| 14 | return "RomFS"; | 14 | return "RomFS"; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const Path& path, | 17 | ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const std::string& path, |
| 18 | const Mode& mode) const { | 18 | Mode mode) const { |
| 19 | return MakeResult<std::unique_ptr<StorageBackend>>( | 19 | return MakeResult<std::unique_ptr<StorageBackend>>( |
| 20 | std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size)); | 20 | std::make_unique<RomFS_Storage>(romfs_file, data_offset, data_size)); |
| 21 | } | 21 | } |
| @@ -48,7 +48,7 @@ ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const | |||
| 48 | return ResultCode(-1); | 48 | return ResultCode(-1); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | ResultCode RomFS_FileSystem::CreateFile(const Path& path, u64 size) const { | 51 | ResultCode RomFS_FileSystem::CreateFile(const std::string& path, u64 size) const { |
| 52 | LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).", | 52 | LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).", |
| 53 | GetName().c_str()); | 53 | GetName().c_str()); |
| 54 | // TODO(bunnei): Use correct error code | 54 | // TODO(bunnei): Use correct error code |
| @@ -79,6 +79,12 @@ u64 RomFS_FileSystem::GetFreeSpaceSize() const { | |||
| 79 | return 0; | 79 | return 0; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | ResultVal<FileSys::EntryType> RomFS_FileSystem::GetEntryType(const std::string& path) const { | ||
| 83 | LOG_CRITICAL(Service_FS, "Called within an ROMFS archive (path %s).", path.c_str()); | ||
| 84 | // TODO(wwylele): Use correct error code | ||
| 85 | return ResultCode(-1); | ||
| 86 | } | ||
| 87 | |||
| 82 | ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { | 88 | ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { |
| 83 | LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); | 89 | LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); |
| 84 | romfs_file->Seek(data_offset + offset, SEEK_SET); | 90 | romfs_file->Seek(data_offset + offset, SEEK_SET); |
diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h index 900ea567a..cedd70645 100644 --- a/src/core/file_sys/romfs_filesystem.h +++ b/src/core/file_sys/romfs_filesystem.h | |||
| @@ -29,17 +29,18 @@ public: | |||
| 29 | 29 | ||
| 30 | std::string GetName() const override; | 30 | std::string GetName() const override; |
| 31 | 31 | ||
| 32 | ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const Path& path, | 32 | ResultVal<std::unique_ptr<StorageBackend>> OpenFile(const std::string& path, |
| 33 | const Mode& mode) const override; | 33 | Mode mode) const override; |
| 34 | ResultCode DeleteFile(const Path& path) const override; | 34 | ResultCode DeleteFile(const Path& path) const override; |
| 35 | ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; | 35 | ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; |
| 36 | ResultCode DeleteDirectory(const Path& path) const override; | 36 | ResultCode DeleteDirectory(const Path& path) const override; |
| 37 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; | 37 | ResultCode DeleteDirectoryRecursively(const Path& path) const override; |
| 38 | ResultCode CreateFile(const Path& path, u64 size) const override; | 38 | ResultCode CreateFile(const std::string& path, u64 size) const override; |
| 39 | ResultCode CreateDirectory(const Path& path) const override; | 39 | ResultCode CreateDirectory(const Path& path) const override; |
| 40 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 40 | ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 41 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; | 41 | ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override; |
| 42 | u64 GetFreeSpaceSize() const override; | 42 | u64 GetFreeSpaceSize() const override; |
| 43 | ResultVal<EntryType> GetEntryType(const std::string& path) const override; | ||
| 43 | 44 | ||
| 44 | protected: | 45 | protected: |
| 45 | std::shared_ptr<FileUtil::IOFile> romfs_file; | 46 | std::shared_ptr<FileUtil::IOFile> romfs_file; |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp new file mode 100644 index 000000000..14868fed2 --- /dev/null +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cinttypes> | ||
| 6 | #include <memory> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/string_util.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/file_sys/disk_filesystem.h" | ||
| 12 | #include "core/file_sys/savedata_factory.h" | ||
| 13 | #include "core/hle/kernel/process.h" | ||
| 14 | |||
| 15 | namespace FileSys { | ||
| 16 | |||
| 17 | SaveData_Factory::SaveData_Factory(std::string nand_directory) | ||
| 18 | : nand_directory(std::move(nand_directory)) {} | ||
| 19 | |||
| 20 | ResultVal<std::unique_ptr<FileSystemBackend>> SaveData_Factory::Open(const Path& path) { | ||
| 21 | std::string save_directory = GetFullPath(); | ||
| 22 | // Return an error if the save data doesn't actually exist. | ||
| 23 | if (!FileUtil::IsDirectory(save_directory)) { | ||
| 24 | // TODO(Subv): Find out correct error code. | ||
| 25 | return ResultCode(-1); | ||
| 26 | } | ||
| 27 | |||
| 28 | auto archive = std::make_unique<Disk_FileSystem>(save_directory); | ||
| 29 | return MakeResult<std::unique_ptr<FileSystemBackend>>(std::move(archive)); | ||
| 30 | } | ||
| 31 | |||
| 32 | ResultCode SaveData_Factory::Format(const Path& path) { | ||
| 33 | LOG_WARNING(Service_FS, "Format archive %s", GetName().c_str()); | ||
| 34 | // Create the save data directory. | ||
| 35 | if (!FileUtil::CreateFullPath(GetFullPath())) { | ||
| 36 | // TODO(Subv): Find the correct error code. | ||
| 37 | return ResultCode(-1); | ||
| 38 | } | ||
| 39 | |||
| 40 | return RESULT_SUCCESS; | ||
| 41 | } | ||
| 42 | |||
| 43 | ResultVal<ArchiveFormatInfo> SaveData_Factory::GetFormatInfo(const Path& path) const { | ||
| 44 | LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||
| 45 | // TODO(bunnei): Find the right error code for this | ||
| 46 | return ResultCode(-1); | ||
| 47 | } | ||
| 48 | |||
| 49 | std::string SaveData_Factory::GetFullPath() const { | ||
| 50 | u64 title_id = Core::CurrentProcess()->program_id; | ||
| 51 | // TODO(Subv): Somehow obtain this value. | ||
| 52 | u32 user = 0; | ||
| 53 | return Common::StringFromFormat("%ssave/%016" PRIX64 "/%08X/", nand_directory.c_str(), title_id, | ||
| 54 | user); | ||
| 55 | } | ||
| 56 | |||
| 57 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h new file mode 100644 index 000000000..73a42aab6 --- /dev/null +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/filesystem.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | namespace FileSys { | ||
| 14 | |||
| 15 | /// File system interface to the SaveData archive | ||
| 16 | class SaveData_Factory final : public FileSystemFactory { | ||
| 17 | public: | ||
| 18 | explicit SaveData_Factory(std::string nand_directory); | ||
| 19 | |||
| 20 | std::string GetName() const override { | ||
| 21 | return "SaveData_Factory"; | ||
| 22 | } | ||
| 23 | ResultVal<std::unique_ptr<FileSystemBackend>> Open(const Path& path) override; | ||
| 24 | ResultCode Format(const Path& path) override; | ||
| 25 | ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||
| 26 | |||
| 27 | private: | ||
| 28 | std::string nand_directory; | ||
| 29 | |||
| 30 | std::string GetFullPath() const; | ||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace FileSys | ||
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 0dcaede67..a6602e12c 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -91,6 +91,10 @@ struct BufferDescriptorX { | |||
| 91 | address |= static_cast<VAddr>(address_bits_36_38) << 36; | 91 | address |= static_cast<VAddr>(address_bits_36_38) << 36; |
| 92 | return address; | 92 | return address; |
| 93 | } | 93 | } |
| 94 | |||
| 95 | u64 Size() const { | ||
| 96 | return static_cast<u64>(size); | ||
| 97 | } | ||
| 94 | }; | 98 | }; |
| 95 | static_assert(sizeof(BufferDescriptorX) == 8, "BufferDescriptorX size is incorrect"); | 99 | static_assert(sizeof(BufferDescriptorX) == 8, "BufferDescriptorX size is incorrect"); |
| 96 | 100 | ||
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 6066d8a18..3f87c4297 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -118,7 +118,8 @@ public: | |||
| 118 | 118 | ||
| 119 | AlignWithPadding(); | 119 | AlignWithPadding(); |
| 120 | 120 | ||
| 121 | if (context.Session()->IsDomain()) { | 121 | const bool request_has_domain_header{context.GetDomainMessageHeader() != nullptr}; |
| 122 | if (context.Session()->IsDomain() && request_has_domain_header) { | ||
| 122 | IPC::DomainMessageHeader domain_header{}; | 123 | IPC::DomainMessageHeader domain_header{}; |
| 123 | domain_header.num_objects = num_domain_objects; | 124 | domain_header.num_objects = num_domain_objects; |
| 124 | PushRaw(domain_header); | 125 | PushRaw(domain_header); |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp deleted file mode 100644 index 776d342f0..000000000 --- a/src/core/hle/kernel/address_arbiter.cpp +++ /dev/null | |||
| @@ -1,91 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "core/hle/kernel/address_arbiter.h" | ||
| 8 | #include "core/hle/kernel/errors.h" | ||
| 9 | #include "core/hle/kernel/thread.h" | ||
| 10 | #include "core/memory.h" | ||
| 11 | |||
| 12 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | // Kernel namespace | ||
| 14 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | AddressArbiter::AddressArbiter() {} | ||
| 18 | AddressArbiter::~AddressArbiter() {} | ||
| 19 | |||
| 20 | SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) { | ||
| 21 | SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); | ||
| 22 | |||
| 23 | address_arbiter->name = std::move(name); | ||
| 24 | |||
| 25 | return address_arbiter; | ||
| 26 | } | ||
| 27 | |||
| 28 | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | ||
| 29 | u64 nanoseconds) { | ||
| 30 | switch (type) { | ||
| 31 | |||
| 32 | // Signal thread(s) waiting for arbitrate address... | ||
| 33 | case ArbitrationType::Signal: | ||
| 34 | // Negative value means resume all threads | ||
| 35 | if (value < 0) { | ||
| 36 | ArbitrateAllThreads(address); | ||
| 37 | } else { | ||
| 38 | // Resume first N threads | ||
| 39 | for (int i = 0; i < value; i++) | ||
| 40 | ArbitrateHighestPriorityThread(address); | ||
| 41 | } | ||
| 42 | break; | ||
| 43 | |||
| 44 | // Wait current thread (acquire the arbiter)... | ||
| 45 | case ArbitrationType::WaitIfLessThan: | ||
| 46 | if ((s32)Memory::Read32(address) < value) { | ||
| 47 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | ||
| 48 | } | ||
| 49 | break; | ||
| 50 | case ArbitrationType::WaitIfLessThanWithTimeout: | ||
| 51 | if ((s32)Memory::Read32(address) < value) { | ||
| 52 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | ||
| 53 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||
| 54 | } | ||
| 55 | break; | ||
| 56 | case ArbitrationType::DecrementAndWaitIfLessThan: { | ||
| 57 | s32 memory_value = Memory::Read32(address); | ||
| 58 | if (memory_value < value) { | ||
| 59 | // Only change the memory value if the thread should wait | ||
| 60 | Memory::Write32(address, (s32)memory_value - 1); | ||
| 61 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | ||
| 62 | } | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: { | ||
| 66 | s32 memory_value = Memory::Read32(address); | ||
| 67 | if (memory_value < value) { | ||
| 68 | // Only change the memory value if the thread should wait | ||
| 69 | Memory::Write32(address, (s32)memory_value - 1); | ||
| 70 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | ||
| 71 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||
| 72 | } | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | |||
| 76 | default: | ||
| 77 | LOG_ERROR(Kernel, "unknown type=%d", type); | ||
| 78 | return ERR_INVALID_ENUM_VALUE_FND; | ||
| 79 | } | ||
| 80 | |||
| 81 | // The calls that use a timeout seem to always return a Timeout error even if they did not put | ||
| 82 | // the thread to sleep | ||
| 83 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || | ||
| 84 | type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { | ||
| 85 | |||
| 86 | return RESULT_TIMEOUT; | ||
| 87 | } | ||
| 88 | return RESULT_SUCCESS; | ||
| 89 | } | ||
| 90 | |||
| 91 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h deleted file mode 100644 index f902ddf2d..000000000 --- a/src/core/hle/kernel/address_arbiter.h +++ /dev/null | |||
| @@ -1,60 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | |||
| 11 | // Address arbiters are an underlying kernel synchronization object that can be created/used via | ||
| 12 | // supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR | ||
| 13 | // applications use them as an underlying mechanism to implement thread-safe barriers, events, and | ||
| 14 | // semphores. | ||
| 15 | |||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 17 | // Kernel namespace | ||
| 18 | |||
| 19 | namespace Kernel { | ||
| 20 | |||
| 21 | enum class ArbitrationType : u32 { | ||
| 22 | Signal, | ||
| 23 | WaitIfLessThan, | ||
| 24 | DecrementAndWaitIfLessThan, | ||
| 25 | WaitIfLessThanWithTimeout, | ||
| 26 | DecrementAndWaitIfLessThanWithTimeout, | ||
| 27 | }; | ||
| 28 | |||
| 29 | class AddressArbiter final : public Object { | ||
| 30 | public: | ||
| 31 | /** | ||
| 32 | * Creates an address arbiter. | ||
| 33 | * | ||
| 34 | * @param name Optional name used for debugging. | ||
| 35 | * @returns The created AddressArbiter. | ||
| 36 | */ | ||
| 37 | static SharedPtr<AddressArbiter> Create(std::string name = "Unknown"); | ||
| 38 | |||
| 39 | std::string GetTypeName() const override { | ||
| 40 | return "Arbiter"; | ||
| 41 | } | ||
| 42 | std::string GetName() const override { | ||
| 43 | return name; | ||
| 44 | } | ||
| 45 | |||
| 46 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | ||
| 47 | HandleType GetHandleType() const override { | ||
| 48 | return HANDLE_TYPE; | ||
| 49 | } | ||
| 50 | |||
| 51 | std::string name; ///< Name of address arbiter object (optional) | ||
| 52 | |||
| 53 | ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); | ||
| 54 | |||
| 55 | private: | ||
| 56 | AddressArbiter(); | ||
| 57 | ~AddressArbiter() override; | ||
| 58 | }; | ||
| 59 | |||
| 60 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 3beb55753..822449cd5 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <utility> | 5 | #include <utility> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| 9 | #include "core/hle/kernel/handle_table.h" | 10 | #include "core/hle/kernel/handle_table.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| @@ -77,7 +78,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { | |||
| 77 | if (handle == CurrentThread) { | 78 | if (handle == CurrentThread) { |
| 78 | return GetCurrentThread(); | 79 | return GetCurrentThread(); |
| 79 | } else if (handle == CurrentProcess) { | 80 | } else if (handle == CurrentProcess) { |
| 80 | return g_current_process; | 81 | return Core::CurrentProcess(); |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | if (!IsValid(handle)) { | 84 | if (!IsValid(handle)) { |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index db104e8a2..293756790 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -7,11 +7,13 @@ | |||
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 10 | #include "core/hle/kernel/event.h" | ||
| 10 | #include "core/hle/kernel/handle_table.h" | 11 | #include "core/hle/kernel/handle_table.h" |
| 11 | #include "core/hle/kernel/hle_ipc.h" | 12 | #include "core/hle/kernel/hle_ipc.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" |
| 14 | #include "core/hle/kernel/server_session.h" | 15 | #include "core/hle/kernel/server_session.h" |
| 16 | #include "core/memory.h" | ||
| 15 | 17 | ||
| 16 | namespace Kernel { | 18 | namespace Kernel { |
| 17 | 19 | ||
| @@ -25,6 +27,32 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s | |||
| 25 | boost::range::remove_erase(connected_sessions, server_session); | 27 | boost::range::remove_erase(connected_sessions, server_session); |
| 26 | } | 28 | } |
| 27 | 29 | ||
| 30 | SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, | ||
| 31 | const std::string& reason, u64 timeout, | ||
| 32 | WakeupCallback&& callback) { | ||
| 33 | |||
| 34 | // Put the client thread to sleep until the wait event is signaled or the timeout expires. | ||
| 35 | thread->wakeup_callback = | ||
| 36 | [context = *this, callback](ThreadWakeupReason reason, SharedPtr<Thread> thread, | ||
| 37 | SharedPtr<WaitObject> object, size_t index) mutable -> bool { | ||
| 38 | ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); | ||
| 39 | callback(thread, context, reason); | ||
| 40 | context.WriteToOutgoingCommandBuffer(*thread); | ||
| 41 | return true; | ||
| 42 | }; | ||
| 43 | |||
| 44 | auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); | ||
| 45 | thread->status = THREADSTATUS_WAIT_HLE_EVENT; | ||
| 46 | thread->wait_objects = {event}; | ||
| 47 | event->AddWaitingThread(thread); | ||
| 48 | |||
| 49 | if (timeout > 0) { | ||
| 50 | thread->WakeAfterDelay(timeout); | ||
| 51 | } | ||
| 52 | |||
| 53 | return event; | ||
| 54 | } | ||
| 55 | |||
| 28 | HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) | 56 | HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) |
| 29 | : server_session(std::move(server_session)) { | 57 | : server_session(std::move(server_session)) { |
| 30 | cmd_buf[0] = 0; | 58 | cmd_buf[0] = 0; |
| @@ -34,7 +62,7 @@ HLERequestContext::~HLERequestContext() = default; | |||
| 34 | 62 | ||
| 35 | void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | 63 | void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { |
| 36 | IPC::RequestParser rp(src_cmdbuf); | 64 | IPC::RequestParser rp(src_cmdbuf); |
| 37 | command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); | 65 | command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); |
| 38 | 66 | ||
| 39 | if (command_header->type == IPC::CommandType::Close) { | 67 | if (command_header->type == IPC::CommandType::Close) { |
| 40 | // Close does not populate the rest of the IPC header | 68 | // Close does not populate the rest of the IPC header |
| @@ -44,7 +72,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | |||
| 44 | // If handle descriptor is present, add size of it | 72 | // If handle descriptor is present, add size of it |
| 45 | if (command_header->enable_handle_descriptor) { | 73 | if (command_header->enable_handle_descriptor) { |
| 46 | handle_descriptor_header = | 74 | handle_descriptor_header = |
| 47 | std::make_unique<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); | 75 | std::make_shared<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); |
| 48 | if (handle_descriptor_header->send_current_pid) { | 76 | if (handle_descriptor_header->send_current_pid) { |
| 49 | rp.Skip(2, false); | 77 | rp.Skip(2, false); |
| 50 | } | 78 | } |
| @@ -84,13 +112,18 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { | |||
| 84 | 112 | ||
| 85 | if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) { | 113 | if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) { |
| 86 | // If this is an incoming message, only CommandType "Request" has a domain header | 114 | // If this is an incoming message, only CommandType "Request" has a domain header |
| 87 | // All outgoing domain messages have the domain header | 115 | // All outgoing domain messages have the domain header, if only incoming has it |
| 88 | domain_message_header = | 116 | if (incoming || domain_message_header) { |
| 89 | std::make_unique<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); | 117 | domain_message_header = |
| 118 | std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); | ||
| 119 | } else { | ||
| 120 | if (Session()->IsDomain()) | ||
| 121 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); | ||
| 122 | } | ||
| 90 | } | 123 | } |
| 91 | 124 | ||
| 92 | data_payload_header = | 125 | data_payload_header = |
| 93 | std::make_unique<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); | 126 | std::make_shared<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); |
| 94 | 127 | ||
| 95 | data_payload_offset = rp.GetCurrentOffset(); | 128 | data_payload_offset = rp.GetCurrentOffset(); |
| 96 | 129 | ||
| @@ -153,8 +186,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb | |||
| 153 | return RESULT_SUCCESS; | 186 | return RESULT_SUCCESS; |
| 154 | } | 187 | } |
| 155 | 188 | ||
| 156 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, | 189 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { |
| 157 | HandleTable& dst_table) { | 190 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; |
| 191 | Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), | ||
| 192 | dst_cmdbuf.size() * sizeof(u32)); | ||
| 193 | |||
| 158 | // The header was already built in the internal command buffer. Attempt to parse it to verify | 194 | // The header was already built in the internal command buffer. Attempt to parse it to verify |
| 159 | // the integrity and then copy it over to the target command buffer. | 195 | // the integrity and then copy it over to the target command buffer. |
| 160 | ParseCommandBuffer(cmd_buf.data(), false); | 196 | ParseCommandBuffer(cmd_buf.data(), false); |
| @@ -165,7 +201,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | |||
| 165 | if (domain_message_header) | 201 | if (domain_message_header) |
| 166 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); | 202 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); |
| 167 | 203 | ||
| 168 | std::copy_n(cmd_buf.begin(), size, dst_cmdbuf); | 204 | std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data()); |
| 169 | 205 | ||
| 170 | if (command_header->enable_handle_descriptor) { | 206 | if (command_header->enable_handle_descriptor) { |
| 171 | ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), | 207 | ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), |
| @@ -195,7 +231,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | |||
| 195 | 231 | ||
| 196 | // TODO(Subv): Translate the X/A/B/W buffers. | 232 | // TODO(Subv): Translate the X/A/B/W buffers. |
| 197 | 233 | ||
| 198 | if (Session()->IsDomain()) { | 234 | if (Session()->IsDomain() && domain_message_header) { |
| 199 | ASSERT(domain_message_header->num_objects == domain_objects.size()); | 235 | ASSERT(domain_message_header->num_objects == domain_objects.size()); |
| 200 | // Write the domain objects to the command buffer, these go after the raw untranslated data. | 236 | // Write the domain objects to the command buffer, these go after the raw untranslated data. |
| 201 | // TODO(Subv): This completely ignores C buffers. | 237 | // TODO(Subv): This completely ignores C buffers. |
| @@ -207,7 +243,106 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | |||
| 207 | dst_cmdbuf[domain_offset++] = static_cast<u32_le>(request_handlers.size()); | 243 | dst_cmdbuf[domain_offset++] = static_cast<u32_le>(request_handlers.size()); |
| 208 | } | 244 | } |
| 209 | } | 245 | } |
| 246 | |||
| 247 | // Copy the translated command buffer back into the thread's command buffer area. | ||
| 248 | Memory::WriteBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), | ||
| 249 | dst_cmdbuf.size() * sizeof(u32)); | ||
| 250 | |||
| 210 | return RESULT_SUCCESS; | 251 | return RESULT_SUCCESS; |
| 211 | } | 252 | } |
| 212 | 253 | ||
| 254 | std::vector<u8> HLERequestContext::ReadBuffer() const { | ||
| 255 | std::vector<u8> buffer; | ||
| 256 | const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[0].Size()}; | ||
| 257 | |||
| 258 | if (is_buffer_a) { | ||
| 259 | buffer.resize(BufferDescriptorA()[0].Size()); | ||
| 260 | Memory::ReadBlock(BufferDescriptorA()[0].Address(), buffer.data(), buffer.size()); | ||
| 261 | } else { | ||
| 262 | buffer.resize(BufferDescriptorX()[0].Size()); | ||
| 263 | Memory::ReadBlock(BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); | ||
| 264 | } | ||
| 265 | |||
| 266 | return buffer; | ||
| 267 | } | ||
| 268 | |||
| 269 | size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size) const { | ||
| 270 | const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()}; | ||
| 271 | |||
| 272 | ASSERT_MSG(size <= GetWriteBufferSize(), "Size %d is too big", size); | ||
| 273 | |||
| 274 | if (is_buffer_b) { | ||
| 275 | Memory::WriteBlock(BufferDescriptorB()[0].Address(), buffer, size); | ||
| 276 | } else { | ||
| 277 | Memory::WriteBlock(BufferDescriptorC()[0].Address(), buffer, size); | ||
| 278 | } | ||
| 279 | |||
| 280 | return size; | ||
| 281 | } | ||
| 282 | |||
| 283 | size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer) const { | ||
| 284 | return WriteBuffer(buffer.data(), buffer.size()); | ||
| 285 | } | ||
| 286 | |||
| 287 | size_t HLERequestContext::GetReadBufferSize() const { | ||
| 288 | const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[0].Size()}; | ||
| 289 | return is_buffer_a ? BufferDescriptorA()[0].Size() : BufferDescriptorX()[0].Size(); | ||
| 290 | } | ||
| 291 | |||
| 292 | size_t HLERequestContext::GetWriteBufferSize() const { | ||
| 293 | const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()}; | ||
| 294 | return is_buffer_b ? BufferDescriptorB()[0].Size() : BufferDescriptorC()[0].Size(); | ||
| 295 | } | ||
| 296 | |||
| 297 | std::string HLERequestContext::Description() const { | ||
| 298 | if (!command_header) { | ||
| 299 | return "No command header available"; | ||
| 300 | } | ||
| 301 | std::ostringstream s; | ||
| 302 | s << "IPC::CommandHeader: Type:" << static_cast<u32>(command_header->type.Value()); | ||
| 303 | s << ", X(Pointer):" << command_header->num_buf_x_descriptors; | ||
| 304 | if (command_header->num_buf_x_descriptors) { | ||
| 305 | s << '['; | ||
| 306 | for (u64 i = 0; i < command_header->num_buf_x_descriptors; ++i) { | ||
| 307 | s << "0x" << std::hex << BufferDescriptorX()[i].Size(); | ||
| 308 | if (i < command_header->num_buf_x_descriptors - 1) | ||
| 309 | s << ", "; | ||
| 310 | } | ||
| 311 | s << ']'; | ||
| 312 | } | ||
| 313 | s << ", A(Send):" << command_header->num_buf_a_descriptors; | ||
| 314 | if (command_header->num_buf_a_descriptors) { | ||
| 315 | s << '['; | ||
| 316 | for (u64 i = 0; i < command_header->num_buf_a_descriptors; ++i) { | ||
| 317 | s << "0x" << std::hex << BufferDescriptorA()[i].Size(); | ||
| 318 | if (i < command_header->num_buf_a_descriptors - 1) | ||
| 319 | s << ", "; | ||
| 320 | } | ||
| 321 | s << ']'; | ||
| 322 | } | ||
| 323 | s << ", B(Receive):" << command_header->num_buf_b_descriptors; | ||
| 324 | if (command_header->num_buf_b_descriptors) { | ||
| 325 | s << '['; | ||
| 326 | for (u64 i = 0; i < command_header->num_buf_b_descriptors; ++i) { | ||
| 327 | s << "0x" << std::hex << BufferDescriptorB()[i].Size(); | ||
| 328 | if (i < command_header->num_buf_b_descriptors - 1) | ||
| 329 | s << ", "; | ||
| 330 | } | ||
| 331 | s << ']'; | ||
| 332 | } | ||
| 333 | s << ", C(ReceiveList):" << BufferDescriptorC().size(); | ||
| 334 | if (!BufferDescriptorC().empty()) { | ||
| 335 | s << '['; | ||
| 336 | for (u64 i = 0; i < BufferDescriptorC().size(); ++i) { | ||
| 337 | s << "0x" << std::hex << BufferDescriptorC()[i].Size(); | ||
| 338 | if (i < BufferDescriptorC().size() - 1) | ||
| 339 | s << ", "; | ||
| 340 | } | ||
| 341 | s << ']'; | ||
| 342 | } | ||
| 343 | s << ", data_size:" << command_header->data_size.Value(); | ||
| 344 | |||
| 345 | return s.str(); | ||
| 346 | } | ||
| 347 | |||
| 213 | } // namespace Kernel | 348 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index da8335b35..8b35da4c9 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string> | ||
| 9 | #include <vector> | 10 | #include <vector> |
| 10 | #include <boost/container/small_vector.hpp> | 11 | #include <boost/container/small_vector.hpp> |
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -13,6 +14,7 @@ | |||
| 13 | #include "core/hle/ipc.h" | 14 | #include "core/hle/ipc.h" |
| 14 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/kernel/server_session.h" | 16 | #include "core/hle/kernel/server_session.h" |
| 17 | #include "core/hle/kernel/thread.h" | ||
| 16 | 18 | ||
| 17 | namespace Service { | 19 | namespace Service { |
| 18 | class ServiceFrameworkBase; | 20 | class ServiceFrameworkBase; |
| @@ -24,6 +26,7 @@ class Domain; | |||
| 24 | class HandleTable; | 26 | class HandleTable; |
| 25 | class HLERequestContext; | 27 | class HLERequestContext; |
| 26 | class Process; | 28 | class Process; |
| 29 | class Event; | ||
| 27 | 30 | ||
| 28 | /** | 31 | /** |
| 29 | * Interface implemented by HLE Session handlers. | 32 | * Interface implemented by HLE Session handlers. |
| @@ -102,14 +105,31 @@ public: | |||
| 102 | return server_session; | 105 | return server_session; |
| 103 | } | 106 | } |
| 104 | 107 | ||
| 108 | using WakeupCallback = std::function<void(SharedPtr<Thread> thread, HLERequestContext& context, | ||
| 109 | ThreadWakeupReason reason)>; | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Puts the specified guest thread to sleep until the returned event is signaled or until the | ||
| 113 | * specified timeout expires. | ||
| 114 | * @param thread Thread to be put to sleep. | ||
| 115 | * @param reason Reason for pausing the thread, to be used for debugging purposes. | ||
| 116 | * @param timeout Timeout in nanoseconds after which the thread will be awoken and the callback | ||
| 117 | * invoked with a Timeout reason. | ||
| 118 | * @param callback Callback to be invoked when the thread is resumed. This callback must write | ||
| 119 | * the entire command response once again, regardless of the state of it before this function | ||
| 120 | * was called. | ||
| 121 | * @returns Event that when signaled will resume the thread and call the callback function. | ||
| 122 | */ | ||
| 123 | SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, | ||
| 124 | u64 timeout, WakeupCallback&& callback); | ||
| 125 | |||
| 105 | void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); | 126 | void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); |
| 106 | 127 | ||
| 107 | /// Populates this context with data from the requesting process/thread. | 128 | /// Populates this context with data from the requesting process/thread. |
| 108 | ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, | 129 | ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, |
| 109 | HandleTable& src_table); | 130 | HandleTable& src_table); |
| 110 | /// Writes data from this context back to the requesting process/thread. | 131 | /// Writes data from this context back to the requesting process/thread. |
| 111 | ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, | 132 | ResultCode WriteToOutgoingCommandBuffer(Thread& thread); |
| 112 | HandleTable& dst_table); | ||
| 113 | 133 | ||
| 114 | u32_le GetCommand() const { | 134 | u32_le GetCommand() const { |
| 115 | return command; | 135 | return command; |
| @@ -139,10 +159,25 @@ public: | |||
| 139 | return buffer_c_desciptors; | 159 | return buffer_c_desciptors; |
| 140 | } | 160 | } |
| 141 | 161 | ||
| 142 | const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { | 162 | const std::shared_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { |
| 143 | return domain_message_header; | 163 | return domain_message_header; |
| 144 | } | 164 | } |
| 145 | 165 | ||
| 166 | /// Helper function to read a buffer using the appropriate buffer descriptor | ||
| 167 | std::vector<u8> ReadBuffer() const; | ||
| 168 | |||
| 169 | /// Helper function to write a buffer using the appropriate buffer descriptor | ||
| 170 | size_t WriteBuffer(const void* buffer, size_t size) const; | ||
| 171 | |||
| 172 | /// Helper function to write a buffer using the appropriate buffer descriptor | ||
| 173 | size_t WriteBuffer(const std::vector<u8>& buffer) const; | ||
| 174 | |||
| 175 | /// Helper function to get the size of the input buffer | ||
| 176 | size_t GetReadBufferSize() const; | ||
| 177 | |||
| 178 | /// Helper function to get the size of the output buffer | ||
| 179 | size_t GetWriteBufferSize() const; | ||
| 180 | |||
| 146 | template <typename T> | 181 | template <typename T> |
| 147 | SharedPtr<T> GetCopyObject(size_t index) { | 182 | SharedPtr<T> GetCopyObject(size_t index) { |
| 148 | ASSERT(index < copy_objects.size()); | 183 | ASSERT(index < copy_objects.size()); |
| @@ -187,6 +222,8 @@ public: | |||
| 187 | return domain_objects.size(); | 222 | return domain_objects.size(); |
| 188 | } | 223 | } |
| 189 | 224 | ||
| 225 | std::string Description() const; | ||
| 226 | |||
| 190 | private: | 227 | private: |
| 191 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | 228 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; |
| 192 | SharedPtr<Kernel::ServerSession> server_session; | 229 | SharedPtr<Kernel::ServerSession> server_session; |
| @@ -195,10 +232,10 @@ private: | |||
| 195 | boost::container::small_vector<SharedPtr<Object>, 8> copy_objects; | 232 | boost::container::small_vector<SharedPtr<Object>, 8> copy_objects; |
| 196 | boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; | 233 | boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; |
| 197 | 234 | ||
| 198 | std::unique_ptr<IPC::CommandHeader> command_header; | 235 | std::shared_ptr<IPC::CommandHeader> command_header; |
| 199 | std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; | 236 | std::shared_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; |
| 200 | std::unique_ptr<IPC::DataPayloadHeader> data_payload_header; | 237 | std::shared_ptr<IPC::DataPayloadHeader> data_payload_header; |
| 201 | std::unique_ptr<IPC::DomainMessageHeader> domain_message_header; | 238 | std::shared_ptr<IPC::DomainMessageHeader> domain_message_header; |
| 202 | std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; | 239 | std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; |
| 203 | std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; | 240 | std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; |
| 204 | std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; | 241 | std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b0c3f4ae1..b325b879b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -41,7 +41,6 @@ void Shutdown() { | |||
| 41 | g_object_address_table.Clear(); | 41 | g_object_address_table.Clear(); |
| 42 | 42 | ||
| 43 | Kernel::ThreadingShutdown(); | 43 | Kernel::ThreadingShutdown(); |
| 44 | g_current_process = nullptr; | ||
| 45 | 44 | ||
| 46 | Kernel::TimersShutdown(); | 45 | Kernel::TimersShutdown(); |
| 47 | Kernel::ResourceLimitsShutdown(); | 46 | Kernel::ResourceLimitsShutdown(); |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c77e58f3c..053bf4e17 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -33,10 +33,6 @@ enum class HandleType : u32 { | |||
| 33 | ServerSession, | 33 | ServerSession, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | enum { | ||
| 37 | DEFAULT_STACK_SIZE = 0x10000, | ||
| 38 | }; | ||
| 39 | |||
| 40 | enum class ResetType { | 36 | enum class ResetType { |
| 41 | OneShot, | 37 | OneShot, |
| 42 | Sticky, | 38 | Sticky, |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 8e74059ea..3694afc60 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -20,12 +20,9 @@ namespace Kernel { | |||
| 20 | // Lists all processes that exist in the current session. | 20 | // Lists all processes that exist in the current session. |
| 21 | static std::vector<SharedPtr<Process>> process_list; | 21 | static std::vector<SharedPtr<Process>> process_list; |
| 22 | 22 | ||
| 23 | SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) { | 23 | SharedPtr<CodeSet> CodeSet::Create(std::string name) { |
| 24 | SharedPtr<CodeSet> codeset(new CodeSet); | 24 | SharedPtr<CodeSet> codeset(new CodeSet); |
| 25 | |||
| 26 | codeset->name = std::move(name); | 25 | codeset->name = std::move(name); |
| 27 | codeset->program_id = program_id; | ||
| 28 | |||
| 29 | return codeset; | 26 | return codeset; |
| 30 | } | 27 | } |
| 31 | 28 | ||
| @@ -41,6 +38,7 @@ SharedPtr<Process> Process::Create(std::string&& name) { | |||
| 41 | process->flags.raw = 0; | 38 | process->flags.raw = 0; |
| 42 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | 39 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); |
| 43 | process->status = ProcessStatus::Created; | 40 | process->status = ProcessStatus::Created; |
| 41 | process->program_id = 0; | ||
| 44 | 42 | ||
| 45 | process_list.push_back(process); | 43 | process_list.push_back(process); |
| 46 | return process; | 44 | return process; |
| @@ -119,11 +117,12 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { | 119 | void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { |
| 122 | // Allocate and map stack | 120 | // Allocate and map the main thread stack |
| 121 | // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part | ||
| 122 | // of the user address space. | ||
| 123 | vm_manager | 123 | vm_manager |
| 124 | .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, | 124 | .MapMemoryBlock(Memory::STACK_VADDR, std::make_shared<std::vector<u8>>(stack_size, 0), 0, |
| 125 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, | 125 | stack_size, MemoryState::Mapped) |
| 126 | MemoryState::Heap) | ||
| 127 | .Unwrap(); | 126 | .Unwrap(); |
| 128 | misc_memory_used += stack_size; | 127 | misc_memory_used += stack_size; |
| 129 | memory_region->used += stack_size; | 128 | memory_region->used += stack_size; |
| @@ -155,9 +154,9 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { | |||
| 155 | }; | 154 | }; |
| 156 | 155 | ||
| 157 | // Map CodeSet segments | 156 | // Map CodeSet segments |
| 158 | MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::Code); | 157 | MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic); |
| 159 | MapSegment(module_->rodata, VMAPermission::Read, MemoryState::Static); | 158 | MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable); |
| 160 | MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::Static); | 159 | MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable); |
| 161 | } | 160 | } |
| 162 | 161 | ||
| 163 | VAddr Process::GetLinearHeapAreaAddress() const { | 162 | VAddr Process::GetLinearHeapAreaAddress() const { |
| @@ -184,6 +183,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per | |||
| 184 | // Initialize heap | 183 | // Initialize heap |
| 185 | heap_memory = std::make_shared<std::vector<u8>>(); | 184 | heap_memory = std::make_shared<std::vector<u8>>(); |
| 186 | heap_start = heap_end = target; | 185 | heap_start = heap_end = target; |
| 186 | } else { | ||
| 187 | vm_manager.UnmapRange(heap_start, heap_end - heap_start); | ||
| 187 | } | 188 | } |
| 188 | 189 | ||
| 189 | // If necessary, expand backing vector to cover new heap extents. | 190 | // If necessary, expand backing vector to cover new heap extents. |
| @@ -203,7 +204,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per | |||
| 203 | size, MemoryState::Heap)); | 204 | size, MemoryState::Heap)); |
| 204 | vm_manager.Reprotect(vma, perms); | 205 | vm_manager.Reprotect(vma, perms); |
| 205 | 206 | ||
| 206 | heap_used += size; | 207 | heap_used = size; |
| 207 | memory_region->used += size; | 208 | memory_region->used += size; |
| 208 | 209 | ||
| 209 | return MakeResult<VAddr>(heap_end - size); | 210 | return MakeResult<VAddr>(heap_end - size); |
| @@ -290,7 +291,7 @@ ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | |||
| 290 | 291 | ||
| 291 | CASCADE_RESULT(auto new_vma, | 292 | CASCADE_RESULT(auto new_vma, |
| 292 | vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, | 293 | vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, |
| 293 | vma->second.meminfo_state)); | 294 | MemoryState::Mapped)); |
| 294 | // Protect mirror with permissions from old region | 295 | // Protect mirror with permissions from old region |
| 295 | vm_manager.Reprotect(new_vma, vma->second.permissions); | 296 | vm_manager.Reprotect(new_vma, vma->second.permissions); |
| 296 | // Remove permissions from old region | 297 | // Remove permissions from old region |
| @@ -321,5 +322,4 @@ SharedPtr<Process> GetProcessById(u32 process_id) { | |||
| 321 | return *itr; | 322 | return *itr; |
| 322 | } | 323 | } |
| 323 | 324 | ||
| 324 | SharedPtr<Process> g_current_process; | ||
| 325 | } // namespace Kernel | 325 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index add98472f..68e77a4d1 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -56,7 +56,7 @@ class ResourceLimit; | |||
| 56 | struct MemoryRegionInfo; | 56 | struct MemoryRegionInfo; |
| 57 | 57 | ||
| 58 | struct CodeSet final : public Object { | 58 | struct CodeSet final : public Object { |
| 59 | static SharedPtr<CodeSet> Create(std::string name, u64 program_id); | 59 | static SharedPtr<CodeSet> Create(std::string name); |
| 60 | 60 | ||
| 61 | std::string GetTypeName() const override { | 61 | std::string GetTypeName() const override { |
| 62 | return "CodeSet"; | 62 | return "CodeSet"; |
| @@ -72,8 +72,6 @@ struct CodeSet final : public Object { | |||
| 72 | 72 | ||
| 73 | /// Name of the process | 73 | /// Name of the process |
| 74 | std::string name; | 74 | std::string name; |
| 75 | /// Title ID corresponding to the process | ||
| 76 | u64 program_id; | ||
| 77 | 75 | ||
| 78 | std::shared_ptr<std::vector<u8>> memory; | 76 | std::shared_ptr<std::vector<u8>> memory; |
| 79 | 77 | ||
| @@ -113,6 +111,9 @@ public: | |||
| 113 | 111 | ||
| 114 | static u32 next_process_id; | 112 | static u32 next_process_id; |
| 115 | 113 | ||
| 114 | /// Title ID corresponding to the process | ||
| 115 | u64 program_id; | ||
| 116 | |||
| 116 | /// Resource limit descriptor for this process | 117 | /// Resource limit descriptor for this process |
| 117 | SharedPtr<ResourceLimit> resource_limit; | 118 | SharedPtr<ResourceLimit> resource_limit; |
| 118 | 119 | ||
| @@ -202,5 +203,4 @@ void ClearProcessList(); | |||
| 202 | /// Retrieves a process from the current list of processes. | 203 | /// Retrieves a process from the current list of processes. |
| 203 | SharedPtr<Process> GetProcessById(u32 process_id); | 204 | SharedPtr<Process> GetProcessById(u32 process_id); |
| 204 | 205 | ||
| 205 | extern SharedPtr<Process> g_current_process; | ||
| 206 | } // namespace Kernel | 206 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp new file mode 100644 index 000000000..921f27efb --- /dev/null +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/hle/kernel/process.h" | ||
| 8 | #include "core/hle/kernel/scheduler.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | Scheduler::Scheduler(ARM_Interface* cpu_core) : cpu_core(cpu_core) {} | ||
| 13 | |||
| 14 | Scheduler::~Scheduler() { | ||
| 15 | for (auto& thread : thread_list) { | ||
| 16 | thread->Stop(); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | bool Scheduler::HaveReadyThreads() { | ||
| 21 | return ready_queue.get_first() != nullptr; | ||
| 22 | } | ||
| 23 | |||
| 24 | Thread* Scheduler::GetCurrentThread() const { | ||
| 25 | return current_thread.get(); | ||
| 26 | } | ||
| 27 | |||
| 28 | Thread* Scheduler::PopNextReadyThread() { | ||
| 29 | Thread* next = nullptr; | ||
| 30 | Thread* thread = GetCurrentThread(); | ||
| 31 | |||
| 32 | if (thread && thread->status == THREADSTATUS_RUNNING) { | ||
| 33 | // We have to do better than the current thread. | ||
| 34 | // This call returns null when that's not possible. | ||
| 35 | next = ready_queue.pop_first_better(thread->current_priority); | ||
| 36 | if (!next) { | ||
| 37 | // Otherwise just keep going with the current thread | ||
| 38 | next = thread; | ||
| 39 | } | ||
| 40 | } else { | ||
| 41 | next = ready_queue.pop_first(); | ||
| 42 | } | ||
| 43 | |||
| 44 | return next; | ||
| 45 | } | ||
| 46 | |||
| 47 | void Scheduler::SwitchContext(Thread* new_thread) { | ||
| 48 | Thread* previous_thread = GetCurrentThread(); | ||
| 49 | |||
| 50 | // Save context for previous thread | ||
| 51 | if (previous_thread) { | ||
| 52 | previous_thread->last_running_ticks = CoreTiming::GetTicks(); | ||
| 53 | cpu_core->SaveContext(previous_thread->context); | ||
| 54 | |||
| 55 | if (previous_thread->status == THREADSTATUS_RUNNING) { | ||
| 56 | // This is only the case when a reschedule is triggered without the current thread | ||
| 57 | // yielding execution (i.e. an event triggered, system core time-sliced, etc) | ||
| 58 | ready_queue.push_front(previous_thread->current_priority, previous_thread); | ||
| 59 | previous_thread->status = THREADSTATUS_READY; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | // Load context of new thread | ||
| 64 | if (new_thread) { | ||
| 65 | ASSERT_MSG(new_thread->status == THREADSTATUS_READY, | ||
| 66 | "Thread must be ready to become running."); | ||
| 67 | |||
| 68 | // Cancel any outstanding wakeup events for this thread | ||
| 69 | new_thread->CancelWakeupTimer(); | ||
| 70 | |||
| 71 | auto previous_process = Core::CurrentProcess(); | ||
| 72 | |||
| 73 | current_thread = new_thread; | ||
| 74 | |||
| 75 | ready_queue.remove(new_thread->current_priority, new_thread); | ||
| 76 | new_thread->status = THREADSTATUS_RUNNING; | ||
| 77 | |||
| 78 | if (previous_process != current_thread->owner_process) { | ||
| 79 | Core::CurrentProcess() = current_thread->owner_process; | ||
| 80 | SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); | ||
| 81 | } | ||
| 82 | |||
| 83 | cpu_core->LoadContext(new_thread->context); | ||
| 84 | cpu_core->SetTlsAddress(new_thread->GetTLSAddress()); | ||
| 85 | } else { | ||
| 86 | current_thread = nullptr; | ||
| 87 | // Note: We do not reset the current process and current page table when idling because | ||
| 88 | // technically we haven't changed processes, our threads are just paused. | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | void Scheduler::Reschedule() { | ||
| 93 | Thread* cur = GetCurrentThread(); | ||
| 94 | Thread* next = PopNextReadyThread(); | ||
| 95 | |||
| 96 | if (cur && next) { | ||
| 97 | LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); | ||
| 98 | } else if (cur) { | ||
| 99 | LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); | ||
| 100 | } else if (next) { | ||
| 101 | LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); | ||
| 102 | } | ||
| 103 | |||
| 104 | SwitchContext(next); | ||
| 105 | } | ||
| 106 | |||
| 107 | void Scheduler::AddThread(SharedPtr<Thread> thread, u32 priority) { | ||
| 108 | thread_list.push_back(thread); | ||
| 109 | ready_queue.prepare(priority); | ||
| 110 | } | ||
| 111 | |||
| 112 | void Scheduler::RemoveThread(Thread* thread) { | ||
| 113 | thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), | ||
| 114 | thread_list.end()); | ||
| 115 | } | ||
| 116 | |||
| 117 | void Scheduler::ScheduleThread(Thread* thread, u32 priority) { | ||
| 118 | ASSERT(thread->status == THREADSTATUS_READY); | ||
| 119 | ready_queue.push_back(priority, thread); | ||
| 120 | } | ||
| 121 | |||
| 122 | void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { | ||
| 123 | ASSERT(thread->status == THREADSTATUS_READY); | ||
| 124 | ready_queue.remove(priority, thread); | ||
| 125 | } | ||
| 126 | |||
| 127 | void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { | ||
| 128 | // If thread was ready, adjust queues | ||
| 129 | if (thread->status == THREADSTATUS_READY) | ||
| 130 | ready_queue.move(thread, thread->current_priority, priority); | ||
| 131 | else | ||
| 132 | ready_queue.prepare(priority); | ||
| 133 | } | ||
| 134 | |||
| 135 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h new file mode 100644 index 000000000..27d0247d6 --- /dev/null +++ b/src/core/hle/kernel/scheduler.h | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/thread_queue_list.h" | ||
| 10 | #include "core/arm/arm_interface.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | class Scheduler final { | ||
| 16 | public: | ||
| 17 | explicit Scheduler(ARM_Interface* cpu_core); | ||
| 18 | ~Scheduler(); | ||
| 19 | |||
| 20 | /// Returns whether there are any threads that are ready to run. | ||
| 21 | bool HaveReadyThreads(); | ||
| 22 | |||
| 23 | /// Reschedules to the next available thread (call after current thread is suspended) | ||
| 24 | void Reschedule(); | ||
| 25 | |||
| 26 | /// Gets the current running thread | ||
| 27 | Thread* GetCurrentThread() const; | ||
| 28 | |||
| 29 | /// Adds a new thread to the scheduler | ||
| 30 | void AddThread(SharedPtr<Thread> thread, u32 priority); | ||
| 31 | |||
| 32 | /// Removes a thread from the scheduler | ||
| 33 | void RemoveThread(Thread* thread); | ||
| 34 | |||
| 35 | /// Schedules a thread that has become "ready" | ||
| 36 | void ScheduleThread(Thread* thread, u32 priority); | ||
| 37 | |||
| 38 | /// Unschedules a thread that was already scheduled | ||
| 39 | void UnscheduleThread(Thread* thread, u32 priority); | ||
| 40 | |||
| 41 | /// Sets the priority of a thread in the scheduler | ||
| 42 | void SetThreadPriority(Thread* thread, u32 priority); | ||
| 43 | |||
| 44 | /// Returns a list of all threads managed by the scheduler | ||
| 45 | const std::vector<SharedPtr<Thread>>& GetThreadList() const { | ||
| 46 | return thread_list; | ||
| 47 | } | ||
| 48 | |||
| 49 | private: | ||
| 50 | /** | ||
| 51 | * Pops and returns the next thread from the thread queue | ||
| 52 | * @return A pointer to the next ready thread | ||
| 53 | */ | ||
| 54 | Thread* PopNextReadyThread(); | ||
| 55 | |||
| 56 | /** | ||
| 57 | * Switches the CPU's active thread context to that of the specified thread | ||
| 58 | * @param new_thread The thread to switch to | ||
| 59 | */ | ||
| 60 | void SwitchContext(Thread* new_thread); | ||
| 61 | |||
| 62 | /// Lists all thread ids that aren't deleted/etc. | ||
| 63 | std::vector<SharedPtr<Thread>> thread_list; | ||
| 64 | |||
| 65 | /// Lists only ready thread ids. | ||
| 66 | Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue; | ||
| 67 | |||
| 68 | SharedPtr<Thread> current_thread = nullptr; | ||
| 69 | |||
| 70 | ARM_Interface* cpu_core; | ||
| 71 | }; | ||
| 72 | |||
| 73 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 54481f7f1..9b4a0ef0a 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <tuple> | 5 | #include <tuple> |
| 6 | 6 | ||
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 8 | #include "core/hle/kernel/client_port.h" | 9 | #include "core/hle/kernel/client_port.h" |
| 9 | #include "core/hle/kernel/client_session.h" | 10 | #include "core/hle/kernel/client_session.h" |
| @@ -57,6 +58,33 @@ void ServerSession::Acquire(Thread* thread) { | |||
| 57 | pending_requesting_threads.pop_back(); | 58 | pending_requesting_threads.pop_back(); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 61 | ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { | ||
| 62 | auto& domain_message_header = context.GetDomainMessageHeader(); | ||
| 63 | if (domain_message_header) { | ||
| 64 | // If there is a DomainMessageHeader, then this is CommandType "Request" | ||
| 65 | const u32 object_id{context.GetDomainMessageHeader()->object_id}; | ||
| 66 | switch (domain_message_header->command) { | ||
| 67 | case IPC::DomainMessageHeader::CommandType::SendMessage: | ||
| 68 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); | ||
| 69 | |||
| 70 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | ||
| 71 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); | ||
| 72 | |||
| 73 | domain_request_handlers[object_id - 1] = nullptr; | ||
| 74 | |||
| 75 | IPC::ResponseBuilder rb{context, 2}; | ||
| 76 | rb.Push(RESULT_SUCCESS); | ||
| 77 | return RESULT_SUCCESS; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); | ||
| 82 | ASSERT(false); | ||
| 83 | } | ||
| 84 | |||
| 85 | return RESULT_SUCCESS; | ||
| 86 | } | ||
| 87 | |||
| 60 | ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { | 88 | ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { |
| 61 | // The ServerSession received a sync request, this means that there's new data available | 89 | // The ServerSession received a sync request, this means that there's new data available |
| 62 | // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or | 90 | // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or |
| @@ -64,49 +92,42 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { | |||
| 64 | 92 | ||
| 65 | Kernel::HLERequestContext context(this); | 93 | Kernel::HLERequestContext context(this); |
| 66 | u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); | 94 | u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); |
| 67 | context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, | 95 | context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), |
| 68 | Kernel::g_handle_table); | 96 | Kernel::g_handle_table); |
| 69 | 97 | ||
| 70 | // If the session has been converted to a domain, handle the doomain request | 98 | ResultCode result = RESULT_SUCCESS; |
| 71 | if (IsDomain()) { | 99 | // If the session has been converted to a domain, handle the domain request |
| 72 | auto& domain_message_header = context.GetDomainMessageHeader(); | 100 | if (IsDomain() && context.GetDomainMessageHeader()) { |
| 73 | if (domain_message_header) { | 101 | result = HandleDomainSyncRequest(context); |
| 74 | // If there is a DomainMessageHeader, then this is CommandType "Request" | ||
| 75 | const u32 object_id{context.GetDomainMessageHeader()->object_id}; | ||
| 76 | switch (domain_message_header->command) { | ||
| 77 | case IPC::DomainMessageHeader::CommandType::SendMessage: | ||
| 78 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); | ||
| 79 | |||
| 80 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | ||
| 81 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); | ||
| 82 | |||
| 83 | domain_request_handlers[object_id - 1] = nullptr; | ||
| 84 | |||
| 85 | IPC::ResponseBuilder rb{context, 2}; | ||
| 86 | rb.Push(RESULT_SUCCESS); | ||
| 87 | return RESULT_SUCCESS; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); | ||
| 92 | ASSERT(false); | ||
| 93 | } | ||
| 94 | // If there is no domain header, the regular session handler is used | 102 | // If there is no domain header, the regular session handler is used |
| 103 | } else if (hle_handler != nullptr) { | ||
| 104 | // If this ServerSession has an associated HLE handler, forward the request to it. | ||
| 105 | result = hle_handler->HandleSyncRequest(context); | ||
| 95 | } | 106 | } |
| 96 | 107 | ||
| 97 | // If this ServerSession has an associated HLE handler, forward the request to it. | 108 | if (thread->status == THREADSTATUS_RUNNING) { |
| 98 | ResultCode result{RESULT_SUCCESS}; | 109 | // Put the thread to sleep until the server replies, it will be awoken in |
| 99 | if (hle_handler != nullptr) { | 110 | // svcReplyAndReceive for LLE servers. |
| 100 | // Attempt to translate the incoming request's command buffer. | 111 | thread->status = THREADSTATUS_WAIT_IPC; |
| 101 | ResultCode translate_result = TranslateHLERequest(this); | 112 | |
| 102 | if (translate_result.IsError()) | 113 | if (hle_handler != nullptr) { |
| 103 | return translate_result; | 114 | // For HLE services, we put the request threads to sleep for a short duration to |
| 104 | 115 | // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for | |
| 105 | result = hle_handler->HandleSyncRequest(context); | 116 | // other reasons like an async callback. The IPC overhead is needed to prevent |
| 106 | } else { | 117 | // starvation when a thread only does sync requests to HLE services while a |
| 107 | // Add the thread to the list of threads that have issued a sync request with this | 118 | // lower-priority thread is waiting to run. |
| 108 | // server. | 119 | |
| 109 | pending_requesting_threads.push_back(std::move(thread)); | 120 | // This delay was approximated in a homebrew application by measuring the average time |
| 121 | // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC | ||
| 122 | // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have | ||
| 123 | // a high variance and vary between models. | ||
| 124 | static constexpr u64 IPCDelayNanoseconds = 39000; | ||
| 125 | thread->WakeAfterDelay(IPCDelayNanoseconds); | ||
| 126 | } else { | ||
| 127 | // Add the thread to the list of threads that have issued a sync request with this | ||
| 128 | // server. | ||
| 129 | pending_requesting_threads.push_back(std::move(thread)); | ||
| 130 | } | ||
| 110 | } | 131 | } |
| 111 | 132 | ||
| 112 | // If this ServerSession does not have an HLE implementation, just wake up the threads waiting | 133 | // If this ServerSession does not have an HLE implementation, just wake up the threads waiting |
| @@ -140,9 +161,4 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& n | |||
| 140 | 161 | ||
| 141 | return std::make_tuple(std::move(server_session), std::move(client_session)); | 162 | return std::make_tuple(std::move(server_session), std::move(client_session)); |
| 142 | } | 163 | } |
| 143 | |||
| 144 | ResultCode TranslateHLERequest(ServerSession* server_session) { | ||
| 145 | // TODO(Subv): Implement this function once multiple concurrent processes are supported. | ||
| 146 | return RESULT_SUCCESS; | ||
| 147 | } | ||
| 148 | } // namespace Kernel | 164 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 144692106..2da807042 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -21,6 +21,7 @@ class ServerSession; | |||
| 21 | class Session; | 21 | class Session; |
| 22 | class SessionRequestHandler; | 22 | class SessionRequestHandler; |
| 23 | class Thread; | 23 | class Thread; |
| 24 | class HLERequestContext; | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS | 27 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS |
| @@ -116,17 +117,12 @@ private: | |||
| 116 | */ | 117 | */ |
| 117 | static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); | 118 | static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); |
| 118 | 119 | ||
| 120 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an | ||
| 121 | /// object handle. | ||
| 122 | ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); | ||
| 123 | |||
| 119 | /// When set to True, converts the session to a domain at the end of the command | 124 | /// When set to True, converts the session to a domain at the end of the command |
| 120 | bool convert_to_domain{}; | 125 | bool convert_to_domain{}; |
| 121 | }; | 126 | }; |
| 122 | 127 | ||
| 123 | /** | ||
| 124 | * Performs command buffer translation for an HLE IPC request. | ||
| 125 | * The command buffer from the ServerSession thread's TLS is copied into a | ||
| 126 | * buffer and all descriptors in the buffer are processed. | ||
| 127 | * TODO(Subv): Implement this function, currently we do not support multiple processes running at | ||
| 128 | * once, but once that is implemented we'll need to properly translate all descriptors | ||
| 129 | * in the command buffer. | ||
| 130 | */ | ||
| 131 | ResultCode TranslateHLERequest(ServerSession* server_session); | ||
| 132 | } // namespace Kernel | 128 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 835fc710b..4d6cd7462 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/errors.h" | 8 | #include "core/hle/kernel/errors.h" |
| 8 | #include "core/hle/kernel/memory.h" | 9 | #include "core/hle/kernel/memory.h" |
| 9 | #include "core/hle/kernel/shared_memory.h" | 10 | #include "core/hle/kernel/shared_memory.h" |
| @@ -51,8 +52,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | // Refresh the address mappings for the current process. | 54 | // Refresh the address mappings for the current process. |
| 54 | if (Kernel::g_current_process != nullptr) { | 55 | if (Core::CurrentProcess() != nullptr) { |
| 55 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); | 56 | Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); |
| 56 | } | 57 | } |
| 57 | } else { | 58 | } else { |
| 58 | auto& vm_manager = shared_memory->owner_process->vm_manager; | 59 | auto& vm_manager = shared_memory->owner_process->vm_manager; |
| @@ -111,13 +112,6 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 111 | return ERR_INVALID_COMBINATION; | 112 | return ERR_INVALID_COMBINATION; |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | // Heap-backed memory blocks can not be mapped with other_permissions = DontCare | ||
| 115 | if (base_address != 0 && other_permissions == MemoryPermission::DontCare) { | ||
| 116 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%llx name=%s, permissions don't match", | ||
| 117 | GetObjectId(), address, name.c_str()); | ||
| 118 | return ERR_INVALID_COMBINATION; | ||
| 119 | } | ||
| 120 | |||
| 121 | // Error out if the provided permissions are not compatible with what the creator process needs. | 115 | // Error out if the provided permissions are not compatible with what the creator process needs. |
| 122 | if (other_permissions != MemoryPermission::DontCare && | 116 | if (other_permissions != MemoryPermission::DontCare && |
| 123 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { | 117 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { |
| @@ -126,12 +120,6 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 126 | return ERR_WRONG_PERMISSION; | 120 | return ERR_WRONG_PERMISSION; |
| 127 | } | 121 | } |
| 128 | 122 | ||
| 129 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. | ||
| 130 | /*if (was_created_with_shared_device_mem && address != 0) { | ||
| 131 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, | ||
| 132 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 133 | }*/ | ||
| 134 | |||
| 135 | // TODO(Subv): The same process that created a SharedMemory object | 123 | // TODO(Subv): The same process that created a SharedMemory object |
| 136 | // can not map it in its own address space unless it was created with addr=0, result 0xD900182C. | 124 | // can not map it in its own address space unless it was created with addr=0, result 0xD900182C. |
| 137 | 125 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4d20ef134..118ce3ee5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -3,10 +3,12 @@ | |||
| 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 <cinttypes> | ||
| 6 | 7 | ||
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "common/microprofile.h" | 9 | #include "common/microprofile.h" |
| 9 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | 12 | #include "core/core_timing.h" |
| 11 | #include "core/hle/kernel/client_port.h" | 13 | #include "core/hle/kernel/client_port.h" |
| 12 | #include "core/hle/kernel/client_session.h" | 14 | #include "core/hle/kernel/client_session.h" |
| @@ -30,7 +32,7 @@ namespace Kernel { | |||
| 30 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 32 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 31 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 33 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 32 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size); | 34 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size); |
| 33 | auto& process = *g_current_process; | 35 | auto& process = *Core::CurrentProcess(); |
| 34 | CASCADE_RESULT(*heap_addr, | 36 | CASCADE_RESULT(*heap_addr, |
| 35 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); | 37 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); |
| 36 | return RESULT_SUCCESS; | 38 | return RESULT_SUCCESS; |
| @@ -45,14 +47,14 @@ static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state | |||
| 45 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 47 | static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 46 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, | 48 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, |
| 47 | src_addr, size); | 49 | src_addr, size); |
| 48 | return g_current_process->MirrorMemory(dst_addr, src_addr, size); | 50 | return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); |
| 49 | } | 51 | } |
| 50 | 52 | ||
| 51 | /// Unmaps a region that was previously mapped with svcMapMemory | 53 | /// Unmaps a region that was previously mapped with svcMapMemory |
| 52 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | 54 | static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { |
| 53 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, | 55 | LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, |
| 54 | src_addr, size); | 56 | src_addr, size); |
| 55 | return g_current_process->UnmapMemory(dst_addr, src_addr, size); | 57 | return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); |
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | /// Connect to an OS service given the port name, returns the handle to the port to out | 60 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| @@ -305,23 +307,23 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 305 | LOG_TRACE(Kernel_SVC, "called info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, | 307 | LOG_TRACE(Kernel_SVC, "called info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, |
| 306 | info_sub_id, handle); | 308 | info_sub_id, handle); |
| 307 | 309 | ||
| 308 | auto& vm_manager = g_current_process->vm_manager; | 310 | auto& vm_manager = Core::CurrentProcess()->vm_manager; |
| 309 | 311 | ||
| 310 | switch (static_cast<GetInfoType>(info_id)) { | 312 | switch (static_cast<GetInfoType>(info_id)) { |
| 311 | case GetInfoType::AllowedCpuIdBitmask: | 313 | case GetInfoType::AllowedCpuIdBitmask: |
| 312 | *result = g_current_process->allowed_processor_mask; | 314 | *result = Core::CurrentProcess()->allowed_processor_mask; |
| 313 | break; | 315 | break; |
| 314 | case GetInfoType::AllowedThreadPrioBitmask: | 316 | case GetInfoType::AllowedThreadPrioBitmask: |
| 315 | *result = g_current_process->allowed_thread_priority_mask; | 317 | *result = Core::CurrentProcess()->allowed_thread_priority_mask; |
| 316 | break; | 318 | break; |
| 317 | case GetInfoType::MapRegionBaseAddr: | 319 | case GetInfoType::MapRegionBaseAddr: |
| 318 | *result = vm_manager.GetMapRegionBaseAddr(); | 320 | *result = Memory::MAP_REGION_VADDR; |
| 319 | break; | 321 | break; |
| 320 | case GetInfoType::MapRegionSize: | 322 | case GetInfoType::MapRegionSize: |
| 321 | *result = vm_manager.GetAddressSpaceSize(); | 323 | *result = Memory::MAP_REGION_SIZE; |
| 322 | break; | 324 | break; |
| 323 | case GetInfoType::HeapRegionBaseAddr: | 325 | case GetInfoType::HeapRegionBaseAddr: |
| 324 | *result = vm_manager.GetNewMapRegionBaseAddr() + vm_manager.GetNewMapRegionSize(); | 326 | *result = Memory::HEAP_VADDR; |
| 325 | break; | 327 | break; |
| 326 | case GetInfoType::HeapRegionSize: | 328 | case GetInfoType::HeapRegionSize: |
| 327 | *result = Memory::HEAP_SIZE; | 329 | *result = Memory::HEAP_SIZE; |
| @@ -345,13 +347,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 345 | *result = vm_manager.GetAddressSpaceSize(); | 347 | *result = vm_manager.GetAddressSpaceSize(); |
| 346 | break; | 348 | break; |
| 347 | case GetInfoType::NewMapRegionBaseAddr: | 349 | case GetInfoType::NewMapRegionBaseAddr: |
| 348 | *result = vm_manager.GetNewMapRegionBaseAddr(); | 350 | *result = Memory::NEW_MAP_REGION_VADDR; |
| 349 | break; | 351 | break; |
| 350 | case GetInfoType::NewMapRegionSize: | 352 | case GetInfoType::NewMapRegionSize: |
| 351 | *result = vm_manager.GetNewMapRegionSize(); | 353 | *result = Memory::NEW_MAP_REGION_SIZE; |
| 352 | break; | 354 | break; |
| 353 | case GetInfoType::IsVirtualAddressMemoryEnabled: | 355 | case GetInfoType::IsVirtualAddressMemoryEnabled: |
| 354 | *result = g_current_process->is_virtual_address_memory_enabled; | 356 | *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; |
| 355 | break; | 357 | break; |
| 356 | case GetInfoType::TitleId: | 358 | case GetInfoType::TitleId: |
| 357 | LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); | 359 | LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query titleid, returned 0"); |
| @@ -391,7 +393,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | |||
| 391 | 393 | ||
| 392 | // Note: The kernel uses the current process's resource limit instead of | 394 | // Note: The kernel uses the current process's resource limit instead of |
| 393 | // the one from the thread owner's resource limit. | 395 | // the one from the thread owner's resource limit. |
| 394 | SharedPtr<ResourceLimit>& resource_limit = g_current_process->resource_limit; | 396 | SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; |
| 395 | if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { | 397 | if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { |
| 396 | return ERR_NOT_AUTHORIZED; | 398 | return ERR_NOT_AUTHORIZED; |
| 397 | } | 399 | } |
| @@ -434,7 +436,7 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 434 | case MemoryPermission::WriteExecute: | 436 | case MemoryPermission::WriteExecute: |
| 435 | case MemoryPermission::ReadWriteExecute: | 437 | case MemoryPermission::ReadWriteExecute: |
| 436 | case MemoryPermission::DontCare: | 438 | case MemoryPermission::DontCare: |
| 437 | return shared_memory->Map(g_current_process.get(), addr, permissions_type, | 439 | return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, |
| 438 | MemoryPermission::DontCare); | 440 | MemoryPermission::DontCare); |
| 439 | default: | 441 | default: |
| 440 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); | 442 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); |
| @@ -443,6 +445,16 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 443 | return RESULT_SUCCESS; | 445 | return RESULT_SUCCESS; |
| 444 | } | 446 | } |
| 445 | 447 | ||
| 448 | static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { | ||
| 449 | LOG_WARNING(Kernel_SVC, | ||
| 450 | "called, shared_memory_handle=0x%08X, addr=0x%" PRIx64 ", size=0x%" PRIx64 "", | ||
| 451 | shared_memory_handle, addr, size); | ||
| 452 | |||
| 453 | SharedPtr<SharedMemory> shared_memory = g_handle_table.Get<SharedMemory>(shared_memory_handle); | ||
| 454 | |||
| 455 | return shared_memory->Unmap(Core::CurrentProcess().get(), addr); | ||
| 456 | } | ||
| 457 | |||
| 446 | /// Query process memory | 458 | /// Query process memory |
| 447 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, | 459 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, |
| 448 | Handle process_handle, u64 addr) { | 460 | Handle process_handle, u64 addr) { |
| @@ -452,11 +464,11 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i | |||
| 452 | } | 464 | } |
| 453 | auto vma = process->vm_manager.FindVMA(addr); | 465 | auto vma = process->vm_manager.FindVMA(addr); |
| 454 | memory_info->attributes = 0; | 466 | memory_info->attributes = 0; |
| 455 | if (vma == g_current_process->vm_manager.vma_map.end()) { | 467 | if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) { |
| 456 | memory_info->base_address = 0; | 468 | memory_info->base_address = 0; |
| 457 | memory_info->permission = static_cast<u32>(VMAPermission::None); | 469 | memory_info->permission = static_cast<u32>(VMAPermission::None); |
| 458 | memory_info->size = 0; | 470 | memory_info->size = 0; |
| 459 | memory_info->type = static_cast<u32>(MemoryState::Free); | 471 | memory_info->type = static_cast<u32>(MemoryState::Unmapped); |
| 460 | } else { | 472 | } else { |
| 461 | memory_info->base_address = vma->second.base; | 473 | memory_info->base_address = vma->second.base; |
| 462 | memory_info->permission = static_cast<u32>(vma->second.permissions); | 474 | memory_info->permission = static_cast<u32>(vma->second.permissions); |
| @@ -476,16 +488,17 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd | |||
| 476 | 488 | ||
| 477 | /// Exits the current process | 489 | /// Exits the current process |
| 478 | static void ExitProcess() { | 490 | static void ExitProcess() { |
| 479 | LOG_INFO(Kernel_SVC, "Process %u exiting", g_current_process->process_id); | 491 | LOG_INFO(Kernel_SVC, "Process %u exiting", Core::CurrentProcess()->process_id); |
| 480 | 492 | ||
| 481 | ASSERT_MSG(g_current_process->status == ProcessStatus::Running, "Process has already exited"); | 493 | ASSERT_MSG(Core::CurrentProcess()->status == ProcessStatus::Running, |
| 494 | "Process has already exited"); | ||
| 482 | 495 | ||
| 483 | g_current_process->status = ProcessStatus::Exited; | 496 | Core::CurrentProcess()->status = ProcessStatus::Exited; |
| 484 | 497 | ||
| 485 | // Stop all the process threads that are currently waiting for objects. | 498 | // Stop all the process threads that are currently waiting for objects. |
| 486 | auto& thread_list = GetThreadList(); | 499 | auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); |
| 487 | for (auto& thread : thread_list) { | 500 | for (auto& thread : thread_list) { |
| 488 | if (thread->owner_process != g_current_process) | 501 | if (thread->owner_process != Core::CurrentProcess()) |
| 489 | continue; | 502 | continue; |
| 490 | 503 | ||
| 491 | if (thread == GetCurrentThread()) | 504 | if (thread == GetCurrentThread()) |
| @@ -514,14 +527,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 514 | return ERR_OUT_OF_RANGE; | 527 | return ERR_OUT_OF_RANGE; |
| 515 | } | 528 | } |
| 516 | 529 | ||
| 517 | SharedPtr<ResourceLimit>& resource_limit = g_current_process->resource_limit; | 530 | SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; |
| 518 | if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { | 531 | if (resource_limit->GetMaxResourceValue(ResourceTypes::PRIORITY) > priority) { |
| 519 | return ERR_NOT_AUTHORIZED; | 532 | return ERR_NOT_AUTHORIZED; |
| 520 | } | 533 | } |
| 521 | 534 | ||
| 522 | if (processor_id == THREADPROCESSORID_DEFAULT) { | 535 | if (processor_id == THREADPROCESSORID_DEFAULT) { |
| 523 | // Set the target CPU to the one specified in the process' exheader. | 536 | // Set the target CPU to the one specified in the process' exheader. |
| 524 | processor_id = g_current_process->ideal_processor; | 537 | processor_id = Core::CurrentProcess()->ideal_processor; |
| 525 | ASSERT(processor_id != THREADPROCESSORID_DEFAULT); | 538 | ASSERT(processor_id != THREADPROCESSORID_DEFAULT); |
| 526 | } | 539 | } |
| 527 | 540 | ||
| @@ -543,7 +556,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 543 | 556 | ||
| 544 | CASCADE_RESULT(SharedPtr<Thread> thread, | 557 | CASCADE_RESULT(SharedPtr<Thread> thread, |
| 545 | Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, | 558 | Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, |
| 546 | g_current_process)); | 559 | Core::CurrentProcess())); |
| 547 | CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); | 560 | CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); |
| 548 | *out_handle = thread->guest_handle; | 561 | *out_handle = thread->guest_handle; |
| 549 | 562 | ||
| @@ -585,7 +598,7 @@ static void SleepThread(s64 nanoseconds) { | |||
| 585 | 598 | ||
| 586 | // Don't attempt to yield execution if there are no available threads to run, | 599 | // Don't attempt to yield execution if there are no available threads to run, |
| 587 | // this way we avoid a useless reschedule to the idle thread. | 600 | // this way we avoid a useless reschedule to the idle thread. |
| 588 | if (nanoseconds == 0 && !HaveReadyThreads()) | 601 | if (nanoseconds == 0 && !Core::System::GetInstance().Scheduler().HaveReadyThreads()) |
| 589 | return; | 602 | return; |
| 590 | 603 | ||
| 591 | // Sleep current thread and check for next thread to schedule | 604 | // Sleep current thread and check for next thread to schedule |
| @@ -761,6 +774,16 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 761 | return RESULT_SUCCESS; | 774 | return RESULT_SUCCESS; |
| 762 | } | 775 | } |
| 763 | 776 | ||
| 777 | static ResultCode ClearEvent(Handle handle) { | ||
| 778 | LOG_TRACE(Kernel_SVC, "called, event=0xX", handle); | ||
| 779 | |||
| 780 | SharedPtr<Event> evt = g_handle_table.Get<Event>(handle); | ||
| 781 | if (evt == nullptr) | ||
| 782 | return ERR_INVALID_HANDLE; | ||
| 783 | evt->Clear(); | ||
| 784 | return RESULT_SUCCESS; | ||
| 785 | } | ||
| 786 | |||
| 764 | namespace { | 787 | namespace { |
| 765 | struct FunctionDef { | 788 | struct FunctionDef { |
| 766 | using Func = void(); | 789 | using Func = void(); |
| @@ -790,9 +813,9 @@ static const FunctionDef SVC_Table[] = { | |||
| 790 | {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, | 813 | {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, |
| 791 | {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, | 814 | {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, |
| 792 | {0x11, nullptr, "SignalEvent"}, | 815 | {0x11, nullptr, "SignalEvent"}, |
| 793 | {0x12, nullptr, "ClearEvent"}, | 816 | {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, |
| 794 | {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, | 817 | {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, |
| 795 | {0x14, nullptr, "UnmapSharedMemory"}, | 818 | {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, |
| 796 | {0x15, SvcWrap<CreateTransferMemory>, "CreateTransferMemory"}, | 819 | {0x15, SvcWrap<CreateTransferMemory>, "CreateTransferMemory"}, |
| 797 | {0x16, SvcWrap<CloseHandle>, "CloseHandle"}, | 820 | {0x16, SvcWrap<CloseHandle>, "CloseHandle"}, |
| 798 | {0x17, SvcWrap<ResetSignal>, "ResetSignal"}, | 821 | {0x17, SvcWrap<ResetSignal>, "ResetSignal"}, |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 7a165d8dc..b224f5e67 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -91,6 +91,11 @@ void SvcWrap() { | |||
| 91 | FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw); | 91 | FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2), (u32)PARAM(3)).raw); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | template <ResultCode func(u32, u64, u64)> | ||
| 95 | void SvcWrap() { | ||
| 96 | FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw); | ||
| 97 | } | ||
| 98 | |||
| 94 | template <ResultCode func(u32*, u64, u64, s64)> | 99 | template <ResultCode func(u32*, u64, u64, s64)> |
| 95 | void SvcWrap() { | 100 | void SvcWrap() { |
| 96 | u32 param_1 = 0; | 101 | u32 param_1 = 0; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1a33cc6cb..145f50887 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -41,14 +41,6 @@ void Thread::Acquire(Thread* thread) { | |||
| 41 | // us to simply use a pool index or similar. | 41 | // us to simply use a pool index or similar. |
| 42 | static Kernel::HandleTable wakeup_callback_handle_table; | 42 | static Kernel::HandleTable wakeup_callback_handle_table; |
| 43 | 43 | ||
| 44 | // Lists all thread ids that aren't deleted/etc. | ||
| 45 | static std::vector<SharedPtr<Thread>> thread_list; | ||
| 46 | |||
| 47 | // Lists only ready thread ids. | ||
| 48 | static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue; | ||
| 49 | |||
| 50 | static SharedPtr<Thread> current_thread; | ||
| 51 | |||
| 52 | // The first available thread id at startup | 44 | // The first available thread id at startup |
| 53 | static u32 next_thread_id; | 45 | static u32 next_thread_id; |
| 54 | 46 | ||
| @@ -63,20 +55,6 @@ inline static u32 const NewThreadId() { | |||
| 63 | Thread::Thread() {} | 55 | Thread::Thread() {} |
| 64 | Thread::~Thread() {} | 56 | Thread::~Thread() {} |
| 65 | 57 | ||
| 66 | Thread* GetCurrentThread() { | ||
| 67 | return current_thread.get(); | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Check if the specified thread is waiting on the specified address to be arbitrated | ||
| 72 | * @param thread The thread to test | ||
| 73 | * @param wait_address The address to test against | ||
| 74 | * @return True if the thread is waiting, false otherwise | ||
| 75 | */ | ||
| 76 | static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { | ||
| 77 | return thread->status == THREADSTATUS_WAIT_ARB && wait_address == thread->wait_address; | ||
| 78 | } | ||
| 79 | |||
| 80 | void Thread::Stop() { | 58 | void Thread::Stop() { |
| 81 | // Cancel any outstanding wakeup events for this thread | 59 | // Cancel any outstanding wakeup events for this thread |
| 82 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | 60 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); |
| @@ -86,7 +64,7 @@ void Thread::Stop() { | |||
| 86 | // Clean up thread from ready queue | 64 | // Clean up thread from ready queue |
| 87 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) | 65 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) |
| 88 | if (status == THREADSTATUS_READY) { | 66 | if (status == THREADSTATUS_READY) { |
| 89 | ready_queue.remove(current_priority, this); | 67 | Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority); |
| 90 | } | 68 | } |
| 91 | 69 | ||
| 92 | status = THREADSTATUS_DEAD; | 70 | status = THREADSTATUS_DEAD; |
| @@ -106,113 +84,7 @@ void Thread::Stop() { | |||
| 106 | u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; | 84 | u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; |
| 107 | u64 tls_slot = | 85 | u64 tls_slot = |
| 108 | ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | 86 | ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; |
| 109 | Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); | 87 | Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot); |
| 110 | } | ||
| 111 | |||
| 112 | Thread* ArbitrateHighestPriorityThread(u32 address) { | ||
| 113 | Thread* highest_priority_thread = nullptr; | ||
| 114 | u32 priority = THREADPRIO_LOWEST; | ||
| 115 | |||
| 116 | // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | ||
| 117 | for (auto& thread : thread_list) { | ||
| 118 | if (!CheckWait_AddressArbiter(thread.get(), address)) | ||
| 119 | continue; | ||
| 120 | |||
| 121 | if (thread == nullptr) | ||
| 122 | continue; | ||
| 123 | |||
| 124 | if (thread->current_priority <= priority) { | ||
| 125 | highest_priority_thread = thread.get(); | ||
| 126 | priority = thread->current_priority; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | // If a thread was arbitrated, resume it | ||
| 131 | if (nullptr != highest_priority_thread) { | ||
| 132 | highest_priority_thread->ResumeFromWait(); | ||
| 133 | } | ||
| 134 | |||
| 135 | return highest_priority_thread; | ||
| 136 | } | ||
| 137 | |||
| 138 | void ArbitrateAllThreads(u32 address) { | ||
| 139 | // Resume all threads found to be waiting on the address | ||
| 140 | for (auto& thread : thread_list) { | ||
| 141 | if (CheckWait_AddressArbiter(thread.get(), address)) | ||
| 142 | thread->ResumeFromWait(); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Switches the CPU's active thread context to that of the specified thread | ||
| 148 | * @param new_thread The thread to switch to | ||
| 149 | */ | ||
| 150 | static void SwitchContext(Thread* new_thread) { | ||
| 151 | Thread* previous_thread = GetCurrentThread(); | ||
| 152 | |||
| 153 | // Save context for previous thread | ||
| 154 | if (previous_thread) { | ||
| 155 | previous_thread->last_running_ticks = CoreTiming::GetTicks(); | ||
| 156 | Core::CPU().SaveContext(previous_thread->context); | ||
| 157 | |||
| 158 | if (previous_thread->status == THREADSTATUS_RUNNING) { | ||
| 159 | // This is only the case when a reschedule is triggered without the current thread | ||
| 160 | // yielding execution (i.e. an event triggered, system core time-sliced, etc) | ||
| 161 | ready_queue.push_front(previous_thread->current_priority, previous_thread); | ||
| 162 | previous_thread->status = THREADSTATUS_READY; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | // Load context of new thread | ||
| 167 | if (new_thread) { | ||
| 168 | ASSERT_MSG(new_thread->status == THREADSTATUS_READY, | ||
| 169 | "Thread must be ready to become running."); | ||
| 170 | |||
| 171 | // Cancel any outstanding wakeup events for this thread | ||
| 172 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); | ||
| 173 | |||
| 174 | auto previous_process = Kernel::g_current_process; | ||
| 175 | |||
| 176 | current_thread = new_thread; | ||
| 177 | |||
| 178 | ready_queue.remove(new_thread->current_priority, new_thread); | ||
| 179 | new_thread->status = THREADSTATUS_RUNNING; | ||
| 180 | |||
| 181 | if (previous_process != current_thread->owner_process) { | ||
| 182 | Kernel::g_current_process = current_thread->owner_process; | ||
| 183 | SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); | ||
| 184 | } | ||
| 185 | |||
| 186 | Core::CPU().LoadContext(new_thread->context); | ||
| 187 | Core::CPU().SetTlsAddress(new_thread->GetTLSAddress()); | ||
| 188 | } else { | ||
| 189 | current_thread = nullptr; | ||
| 190 | // Note: We do not reset the current process and current page table when idling because | ||
| 191 | // technically we haven't changed processes, our threads are just paused. | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | /** | ||
| 196 | * Pops and returns the next thread from the thread queue | ||
| 197 | * @return A pointer to the next ready thread | ||
| 198 | */ | ||
| 199 | static Thread* PopNextReadyThread() { | ||
| 200 | Thread* next; | ||
| 201 | Thread* thread = GetCurrentThread(); | ||
| 202 | |||
| 203 | if (thread && thread->status == THREADSTATUS_RUNNING) { | ||
| 204 | // We have to do better than the current thread. | ||
| 205 | // This call returns null when that's not possible. | ||
| 206 | next = ready_queue.pop_first_better(thread->current_priority); | ||
| 207 | if (!next) { | ||
| 208 | // Otherwise just keep going with the current thread | ||
| 209 | next = thread; | ||
| 210 | } | ||
| 211 | } else { | ||
| 212 | next = ready_queue.pop_first(); | ||
| 213 | } | ||
| 214 | |||
| 215 | return next; | ||
| 216 | } | 88 | } |
| 217 | 89 | ||
| 218 | void WaitCurrentThread_Sleep() { | 90 | void WaitCurrentThread_Sleep() { |
| @@ -220,17 +92,10 @@ void WaitCurrentThread_Sleep() { | |||
| 220 | thread->status = THREADSTATUS_WAIT_SLEEP; | 92 | thread->status = THREADSTATUS_WAIT_SLEEP; |
| 221 | } | 93 | } |
| 222 | 94 | ||
| 223 | void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { | ||
| 224 | Thread* thread = GetCurrentThread(); | ||
| 225 | thread->wait_address = wait_address; | ||
| 226 | thread->status = THREADSTATUS_WAIT_ARB; | ||
| 227 | } | ||
| 228 | |||
| 229 | void ExitCurrentThread() { | 95 | void ExitCurrentThread() { |
| 230 | Thread* thread = GetCurrentThread(); | 96 | Thread* thread = GetCurrentThread(); |
| 231 | thread->Stop(); | 97 | thread->Stop(); |
| 232 | thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), | 98 | Core::System::GetInstance().Scheduler().RemoveThread(thread); |
| 233 | thread_list.end()); | ||
| 234 | } | 99 | } |
| 235 | 100 | ||
| 236 | /** | 101 | /** |
| @@ -248,7 +113,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 248 | bool resume = true; | 113 | bool resume = true; |
| 249 | 114 | ||
| 250 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || | 115 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 251 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { | 116 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || |
| 117 | thread->status == THREADSTATUS_WAIT_HLE_EVENT) { | ||
| 252 | 118 | ||
| 253 | // Remove the thread from each of its waiting objects' waitlists | 119 | // Remove the thread from each of its waiting objects' waitlists |
| 254 | for (auto& object : thread->wait_objects) | 120 | for (auto& object : thread->wait_objects) |
| @@ -282,8 +148,9 @@ void Thread::ResumeFromWait() { | |||
| 282 | switch (status) { | 148 | switch (status) { |
| 283 | case THREADSTATUS_WAIT_SYNCH_ALL: | 149 | case THREADSTATUS_WAIT_SYNCH_ALL: |
| 284 | case THREADSTATUS_WAIT_SYNCH_ANY: | 150 | case THREADSTATUS_WAIT_SYNCH_ANY: |
| 285 | case THREADSTATUS_WAIT_ARB: | 151 | case THREADSTATUS_WAIT_HLE_EVENT: |
| 286 | case THREADSTATUS_WAIT_SLEEP: | 152 | case THREADSTATUS_WAIT_SLEEP: |
| 153 | case THREADSTATUS_WAIT_IPC: | ||
| 287 | break; | 154 | break; |
| 288 | 155 | ||
| 289 | case THREADSTATUS_READY: | 156 | case THREADSTATUS_READY: |
| @@ -307,32 +174,12 @@ void Thread::ResumeFromWait() { | |||
| 307 | 174 | ||
| 308 | wakeup_callback = nullptr; | 175 | wakeup_callback = nullptr; |
| 309 | 176 | ||
| 310 | ready_queue.push_back(current_priority, this); | ||
| 311 | status = THREADSTATUS_READY; | 177 | status = THREADSTATUS_READY; |
| 178 | Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority); | ||
| 312 | Core::System::GetInstance().PrepareReschedule(); | 179 | Core::System::GetInstance().PrepareReschedule(); |
| 313 | } | 180 | } |
| 314 | 181 | ||
| 315 | /** | 182 | /** |
| 316 | * Prints the thread queue for debugging purposes | ||
| 317 | */ | ||
| 318 | static void DebugThreadQueue() { | ||
| 319 | Thread* thread = GetCurrentThread(); | ||
| 320 | if (!thread) { | ||
| 321 | LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); | ||
| 322 | } else { | ||
| 323 | LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, | ||
| 324 | GetCurrentThread()->GetObjectId()); | ||
| 325 | } | ||
| 326 | |||
| 327 | for (auto& t : thread_list) { | ||
| 328 | u32 priority = ready_queue.contains(t.get()); | ||
| 329 | if (priority != -1) { | ||
| 330 | LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId()); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | /** | ||
| 336 | * Finds a free location for the TLS section of a thread. | 183 | * Finds a free location for the TLS section of a thread. |
| 337 | * @param tls_slots The TLS page array of the thread's owner process. | 184 | * @param tls_slots The TLS page array of the thread's owner process. |
| 338 | * Returns a tuple of (page, slot, alloc_needed) where: | 185 | * Returns a tuple of (page, slot, alloc_needed) where: |
| @@ -399,8 +246,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 399 | 246 | ||
| 400 | SharedPtr<Thread> thread(new Thread); | 247 | SharedPtr<Thread> thread(new Thread); |
| 401 | 248 | ||
| 402 | thread_list.push_back(thread); | 249 | Core::System::GetInstance().Scheduler().AddThread(thread, priority); |
| 403 | ready_queue.prepare(priority); | ||
| 404 | 250 | ||
| 405 | thread->thread_id = NewThreadId(); | 251 | thread->thread_id = NewThreadId(); |
| 406 | thread->status = THREADSTATUS_DORMANT; | 252 | thread->status = THREADSTATUS_DORMANT; |
| @@ -453,7 +299,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 453 | // TODO(Subv): Find the correct MemoryState for this region. | 299 | // TODO(Subv): Find the correct MemoryState for this region. |
| 454 | vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, | 300 | vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, |
| 455 | linheap_memory, offset, Memory::PAGE_SIZE, | 301 | linheap_memory, offset, Memory::PAGE_SIZE, |
| 456 | MemoryState::ThreadLocalStorage); | 302 | MemoryState::ThreadLocal); |
| 457 | } | 303 | } |
| 458 | 304 | ||
| 459 | // Mark the slot as used | 305 | // Mark the slot as used |
| @@ -471,12 +317,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 471 | void Thread::SetPriority(u32 priority) { | 317 | void Thread::SetPriority(u32 priority) { |
| 472 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, | 318 | ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, |
| 473 | "Invalid priority value."); | 319 | "Invalid priority value."); |
| 474 | // If thread was ready, adjust queues | 320 | Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); |
| 475 | if (status == THREADSTATUS_READY) | ||
| 476 | ready_queue.move(this, current_priority, priority); | ||
| 477 | else | ||
| 478 | ready_queue.prepare(priority); | ||
| 479 | |||
| 480 | nominal_priority = current_priority = priority; | 321 | nominal_priority = current_priority = priority; |
| 481 | } | 322 | } |
| 482 | 323 | ||
| @@ -490,22 +331,18 @@ void Thread::UpdatePriority() { | |||
| 490 | } | 331 | } |
| 491 | 332 | ||
| 492 | void Thread::BoostPriority(u32 priority) { | 333 | void Thread::BoostPriority(u32 priority) { |
| 493 | // If thread was ready, adjust queues | 334 | Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); |
| 494 | if (status == THREADSTATUS_READY) | ||
| 495 | ready_queue.move(this, current_priority, priority); | ||
| 496 | else | ||
| 497 | ready_queue.prepare(priority); | ||
| 498 | current_priority = priority; | 335 | current_priority = priority; |
| 499 | } | 336 | } |
| 500 | 337 | ||
| 501 | SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, | 338 | SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, |
| 502 | SharedPtr<Process> owner_process) { | 339 | SharedPtr<Process> owner_process) { |
| 503 | // Setup page table so we can write to memory | 340 | // Setup page table so we can write to memory |
| 504 | SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); | 341 | SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); |
| 505 | 342 | ||
| 506 | // Initialize new "main" thread | 343 | // Initialize new "main" thread |
| 507 | auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, | 344 | auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, |
| 508 | Memory::HEAP_VADDR_END, owner_process); | 345 | Memory::STACK_VADDR_END, owner_process); |
| 509 | 346 | ||
| 510 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); | 347 | SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); |
| 511 | 348 | ||
| @@ -520,25 +357,6 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, | |||
| 520 | return thread; | 357 | return thread; |
| 521 | } | 358 | } |
| 522 | 359 | ||
| 523 | bool HaveReadyThreads() { | ||
| 524 | return ready_queue.get_first() != nullptr; | ||
| 525 | } | ||
| 526 | |||
| 527 | void Reschedule() { | ||
| 528 | Thread* cur = GetCurrentThread(); | ||
| 529 | Thread* next = PopNextReadyThread(); | ||
| 530 | |||
| 531 | if (cur && next) { | ||
| 532 | LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); | ||
| 533 | } else if (cur) { | ||
| 534 | LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); | ||
| 535 | } else if (next) { | ||
| 536 | LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); | ||
| 537 | } | ||
| 538 | |||
| 539 | SwitchContext(next); | ||
| 540 | } | ||
| 541 | |||
| 542 | void Thread::SetWaitSynchronizationResult(ResultCode result) { | 360 | void Thread::SetWaitSynchronizationResult(ResultCode result) { |
| 543 | context.cpu_registers[0] = result.raw; | 361 | context.cpu_registers[0] = result.raw; |
| 544 | } | 362 | } |
| @@ -561,25 +379,20 @@ VAddr Thread::GetCommandBufferAddress() const { | |||
| 561 | 379 | ||
| 562 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 380 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 563 | 381 | ||
| 382 | /** | ||
| 383 | * Gets the current thread | ||
| 384 | */ | ||
| 385 | Thread* GetCurrentThread() { | ||
| 386 | return Core::System::GetInstance().Scheduler().GetCurrentThread(); | ||
| 387 | } | ||
| 388 | |||
| 564 | void ThreadingInit() { | 389 | void ThreadingInit() { |
| 565 | ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | 390 | ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); |
| 566 | |||
| 567 | current_thread = nullptr; | ||
| 568 | next_thread_id = 1; | 391 | next_thread_id = 1; |
| 569 | } | 392 | } |
| 570 | 393 | ||
| 571 | void ThreadingShutdown() { | 394 | void ThreadingShutdown() { |
| 572 | current_thread = nullptr; | 395 | Kernel::ClearProcessList(); |
| 573 | |||
| 574 | for (auto& t : thread_list) { | ||
| 575 | t->Stop(); | ||
| 576 | } | ||
| 577 | thread_list.clear(); | ||
| 578 | ready_queue.clear(); | ||
| 579 | } | ||
| 580 | |||
| 581 | const std::vector<SharedPtr<Thread>>& GetThreadList() { | ||
| 582 | return thread_list; | ||
| 583 | } | 396 | } |
| 584 | 397 | ||
| 585 | } // namespace Kernel | 398 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0a1ada27d..dbf47e269 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -38,8 +38,9 @@ enum ThreadProcessorId : s32 { | |||
| 38 | enum ThreadStatus { | 38 | enum ThreadStatus { |
| 39 | THREADSTATUS_RUNNING, ///< Currently running | 39 | THREADSTATUS_RUNNING, ///< Currently running |
| 40 | THREADSTATUS_READY, ///< Ready to run | 40 | THREADSTATUS_READY, ///< Ready to run |
| 41 | THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter | 41 | THREADSTATUS_WAIT_HLE_EVENT, ///< Waiting for hle event to finish |
| 42 | THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC | 42 | THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC |
| 43 | THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request | ||
| 43 | THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false | 44 | THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false |
| 44 | THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true | 45 | THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true |
| 45 | THREADSTATUS_DORMANT, ///< Created but not yet made ready | 46 | THREADSTATUS_DORMANT, ///< Created but not yet made ready |
| @@ -249,28 +250,6 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, | |||
| 249 | SharedPtr<Process> owner_process); | 250 | SharedPtr<Process> owner_process); |
| 250 | 251 | ||
| 251 | /** | 252 | /** |
| 252 | * Returns whether there are any threads that are ready to run. | ||
| 253 | */ | ||
| 254 | bool HaveReadyThreads(); | ||
| 255 | |||
| 256 | /** | ||
| 257 | * Reschedules to the next available thread (call after current thread is suspended) | ||
| 258 | */ | ||
| 259 | void Reschedule(); | ||
| 260 | |||
| 261 | /** | ||
| 262 | * Arbitrate the highest priority thread that is waiting | ||
| 263 | * @param address The address for which waiting threads should be arbitrated | ||
| 264 | */ | ||
| 265 | Thread* ArbitrateHighestPriorityThread(VAddr address); | ||
| 266 | |||
| 267 | /** | ||
| 268 | * Arbitrate all threads currently waiting. | ||
| 269 | * @param address The address for which waiting threads should be arbitrated | ||
| 270 | */ | ||
| 271 | void ArbitrateAllThreads(VAddr address); | ||
| 272 | |||
| 273 | /** | ||
| 274 | * Gets the current thread | 253 | * Gets the current thread |
| 275 | */ | 254 | */ |
| 276 | Thread* GetCurrentThread(); | 255 | Thread* GetCurrentThread(); |
| @@ -301,9 +280,4 @@ void ThreadingInit(); | |||
| 301 | */ | 280 | */ |
| 302 | void ThreadingShutdown(); | 281 | void ThreadingShutdown(); |
| 303 | 282 | ||
| 304 | /** | ||
| 305 | * Get a const reference to the thread list for debug use | ||
| 306 | */ | ||
| 307 | const std::vector<SharedPtr<Thread>>& GetThreadList(); | ||
| 308 | |||
| 309 | } // namespace Kernel | 283 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index d5b36d71a..1c2f873aa 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -18,8 +18,26 @@ namespace Kernel { | |||
| 18 | 18 | ||
| 19 | static const char* GetMemoryStateName(MemoryState state) { | 19 | static const char* GetMemoryStateName(MemoryState state) { |
| 20 | static const char* names[] = { | 20 | static const char* names[] = { |
| 21 | "Free", "Reserved", "IO", "Static", "Code", "Private", | 21 | "Unmapped", |
| 22 | "Shared", "Continuous", "Aliased", "Alias", "AliasCode", "Locked", | 22 | "Io", |
| 23 | "Normal", | ||
| 24 | "CodeStatic", | ||
| 25 | "CodeMutable", | ||
| 26 | "Heap", | ||
| 27 | "Shared", | ||
| 28 | "Unknown1" | ||
| 29 | "ModuleCodeStatic", | ||
| 30 | "ModuleCodeMutable", | ||
| 31 | "IpcBuffer0", | ||
| 32 | "Mapped", | ||
| 33 | "ThreadLocal", | ||
| 34 | "TransferMemoryIsolated", | ||
| 35 | "TransferMemory", | ||
| 36 | "ProcessMemory", | ||
| 37 | "Unknown2" | ||
| 38 | "IpcBuffer1", | ||
| 39 | "IpcBuffer3", | ||
| 40 | "KernelStack", | ||
| 23 | }; | 41 | }; |
| 24 | 42 | ||
| 25 | return names[(int)state]; | 43 | return names[(int)state]; |
| @@ -142,7 +160,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) { | |||
| 142 | VirtualMemoryArea& vma = vma_handle->second; | 160 | VirtualMemoryArea& vma = vma_handle->second; |
| 143 | vma.type = VMAType::Free; | 161 | vma.type = VMAType::Free; |
| 144 | vma.permissions = VMAPermission::None; | 162 | vma.permissions = VMAPermission::None; |
| 145 | vma.meminfo_state = MemoryState::Free; | 163 | vma.meminfo_state = MemoryState::Unmapped; |
| 146 | 164 | ||
| 147 | vma.backing_block = nullptr; | 165 | vma.backing_block = nullptr; |
| 148 | vma.offset = 0; | 166 | vma.offset = 0; |
| @@ -166,6 +184,9 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) { | |||
| 166 | } | 184 | } |
| 167 | 185 | ||
| 168 | ASSERT(FindVMA(target)->second.size >= size); | 186 | ASSERT(FindVMA(target)->second.size >= size); |
| 187 | |||
| 188 | Core::CPU().UnmapMemory(target, size); | ||
| 189 | |||
| 169 | return RESULT_SUCCESS; | 190 | return RESULT_SUCCESS; |
| 170 | } | 191 | } |
| 171 | 192 | ||
| @@ -377,19 +398,4 @@ u64 VMManager::GetAddressSpaceSize() { | |||
| 377 | return MAX_ADDRESS; | 398 | return MAX_ADDRESS; |
| 378 | } | 399 | } |
| 379 | 400 | ||
| 380 | VAddr VMManager::GetMapRegionBaseAddr() { | ||
| 381 | LOG_WARNING(Kernel, "(STUBBED) called"); | ||
| 382 | return Memory::HEAP_VADDR; | ||
| 383 | } | ||
| 384 | |||
| 385 | VAddr VMManager::GetNewMapRegionBaseAddr() { | ||
| 386 | LOG_WARNING(Kernel, "(STUBBED) called"); | ||
| 387 | return 0x8000000; | ||
| 388 | } | ||
| 389 | |||
| 390 | u64 VMManager::GetNewMapRegionSize() { | ||
| 391 | LOG_WARNING(Kernel, "(STUBBED) called"); | ||
| 392 | return 0x8000000; | ||
| 393 | } | ||
| 394 | |||
| 395 | } // namespace Kernel | 401 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 8de704a60..4d66146f6 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -41,15 +41,24 @@ enum class VMAPermission : u8 { | |||
| 41 | 41 | ||
| 42 | /// Set of values returned in MemoryInfo.state by svcQueryMemory. | 42 | /// Set of values returned in MemoryInfo.state by svcQueryMemory. |
| 43 | enum class MemoryState : u32 { | 43 | enum class MemoryState : u32 { |
| 44 | Free = 0, | 44 | Unmapped = 0x0, |
| 45 | IO = 1, | 45 | Io = 0x1, |
| 46 | Normal = 2, | 46 | Normal = 0x2, |
| 47 | Code = 3, | 47 | CodeStatic = 0x3, |
| 48 | Static = 4, | 48 | CodeMutable = 0x4, |
| 49 | Heap = 5, | 49 | Heap = 0x5, |
| 50 | Shared = 6, | 50 | Shared = 0x6, |
| 51 | Mapped = 6, | 51 | ModuleCodeStatic = 0x8, |
| 52 | ThreadLocalStorage = 12, | 52 | ModuleCodeMutable = 0x9, |
| 53 | IpcBuffer0 = 0xA, | ||
| 54 | Mapped = 0xB, | ||
| 55 | ThreadLocal = 0xC, | ||
| 56 | TransferMemoryIsolated = 0xD, | ||
| 57 | TransferMemory = 0xE, | ||
| 58 | ProcessMemory = 0xF, | ||
| 59 | IpcBuffer1 = 0x11, | ||
| 60 | IpcBuffer3 = 0x12, | ||
| 61 | KernelStack = 0x13, | ||
| 53 | }; | 62 | }; |
| 54 | 63 | ||
| 55 | /** | 64 | /** |
| @@ -66,7 +75,7 @@ struct VirtualMemoryArea { | |||
| 66 | VMAType type = VMAType::Free; | 75 | VMAType type = VMAType::Free; |
| 67 | VMAPermission permissions = VMAPermission::None; | 76 | VMAPermission permissions = VMAPermission::None; |
| 68 | /// Tag returned by svcQueryMemory. Not otherwise used. | 77 | /// Tag returned by svcQueryMemory. Not otherwise used. |
| 69 | MemoryState meminfo_state = MemoryState::Free; | 78 | MemoryState meminfo_state = MemoryState::Unmapped; |
| 70 | 79 | ||
| 71 | // Settings for type = AllocatedMemoryBlock | 80 | // Settings for type = AllocatedMemoryBlock |
| 72 | /// Memory block backing this VMA. | 81 | /// Memory block backing this VMA. |
| @@ -192,15 +201,6 @@ public: | |||
| 192 | /// Gets the total address space address size, used by svcGetInfo | 201 | /// Gets the total address space address size, used by svcGetInfo |
| 193 | u64 GetAddressSpaceSize(); | 202 | u64 GetAddressSpaceSize(); |
| 194 | 203 | ||
| 195 | /// Gets the map region base address, used by svcGetInfo | ||
| 196 | VAddr GetMapRegionBaseAddr(); | ||
| 197 | |||
| 198 | /// Gets the base address for a new memory region, used by svcGetInfo | ||
| 199 | VAddr GetNewMapRegionBaseAddr(); | ||
| 200 | |||
| 201 | /// Gets the size for a new memory region, used by svcGetInfo | ||
| 202 | u64 GetNewMapRegionSize(); | ||
| 203 | |||
| 204 | /// Each VMManager has its own page table, which is set as the main one when the owning process | 204 | /// Each VMManager has its own page table, which is set as the main one when the owning process |
| 205 | /// is scheduled. | 205 | /// is scheduled. |
| 206 | Memory::PageTable page_table; | 206 | Memory::PageTable page_table; |
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index ec147b84c..b08ac72c1 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp | |||
| @@ -39,7 +39,8 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | |||
| 39 | for (const auto& thread : waiting_threads) { | 39 | for (const auto& thread : waiting_threads) { |
| 40 | // The list of waiting threads must not contain threads that are not waiting to be awakened. | 40 | // The list of waiting threads must not contain threads that are not waiting to be awakened. |
| 41 | ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || | 41 | ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 42 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL, | 42 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || |
| 43 | thread->status == THREADSTATUS_WAIT_HLE_EVENT, | ||
| 43 | "Inconsistent thread statuses in waiting_threads"); | 44 | "Inconsistent thread statuses in waiting_threads"); |
| 44 | 45 | ||
| 45 | if (thread->current_priority >= candidate_priority) | 46 | if (thread->current_priority >= candidate_priority) |
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 656e1b4a7..97fef7a48 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -108,11 +108,11 @@ union ResultCode { | |||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | constexpr bool IsSuccess() const { | 110 | constexpr bool IsSuccess() const { |
| 111 | return is_error.ExtractValue(raw) == 0; | 111 | return raw == 0; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | constexpr bool IsError() const { | 114 | constexpr bool IsError() const { |
| 115 | return is_error.ExtractValue(raw) == 1; | 115 | return raw != 0; |
| 116 | } | 116 | } |
| 117 | }; | 117 | }; |
| 118 | 118 | ||
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index ee7d07aa7..52c3491d5 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp | |||
| @@ -65,12 +65,19 @@ void ACC_U0::GetUserExistence(Kernel::HLERequestContext& ctx) { | |||
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | void ACC_U0::ListAllUsers(Kernel::HLERequestContext& ctx) { | 67 | void ACC_U0::ListAllUsers(Kernel::HLERequestContext& ctx) { |
| 68 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 68 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; | 69 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; |
| 69 | const auto& output_buffer = ctx.BufferDescriptorC()[0]; | 70 | ctx.WriteBuffer(user_ids.data(), user_ids.size()); |
| 70 | Memory::WriteBlock(output_buffer.Address(), user_ids.data(), user_ids.size()); | 71 | IPC::ResponseBuilder rb{ctx, 2}; |
| 72 | rb.Push(RESULT_SUCCESS); | ||
| 73 | } | ||
| 74 | |||
| 75 | void ACC_U0::ListOpenUsers(Kernel::HLERequestContext& ctx) { | ||
| 76 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 77 | constexpr std::array<u128, 10> user_ids{DEFAULT_USER_ID}; | ||
| 78 | ctx.WriteBuffer(user_ids.data(), user_ids.size()); | ||
| 71 | IPC::ResponseBuilder rb{ctx, 2}; | 79 | IPC::ResponseBuilder rb{ctx, 2}; |
| 72 | rb.Push(RESULT_SUCCESS); | 80 | rb.Push(RESULT_SUCCESS); |
| 73 | LOG_DEBUG(Service_ACC, "called"); | ||
| 74 | } | 81 | } |
| 75 | 82 | ||
| 76 | void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) { | 83 | void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) { |
| @@ -104,6 +111,7 @@ ACC_U0::ACC_U0() : ServiceFramework("acc:u0") { | |||
| 104 | static const FunctionInfo functions[] = { | 111 | static const FunctionInfo functions[] = { |
| 105 | {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, | 112 | {1, &ACC_U0::GetUserExistence, "GetUserExistence"}, |
| 106 | {2, &ACC_U0::ListAllUsers, "ListAllUsers"}, | 113 | {2, &ACC_U0::ListAllUsers, "ListAllUsers"}, |
| 114 | {3, &ACC_U0::ListOpenUsers, "ListOpenUsers"}, | ||
| 107 | {4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"}, | 115 | {4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"}, |
| 108 | {5, &ACC_U0::GetProfile, "GetProfile"}, | 116 | {5, &ACC_U0::GetProfile, "GetProfile"}, |
| 109 | {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, | 117 | {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, |
diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h index d7732e75b..222f37282 100644 --- a/src/core/hle/service/acc/acc_u0.h +++ b/src/core/hle/service/acc/acc_u0.h | |||
| @@ -29,6 +29,7 @@ public: | |||
| 29 | private: | 29 | private: |
| 30 | void GetUserExistence(Kernel::HLERequestContext& ctx); | 30 | void GetUserExistence(Kernel::HLERequestContext& ctx); |
| 31 | void ListAllUsers(Kernel::HLERequestContext& ctx); | 31 | void ListAllUsers(Kernel::HLERequestContext& ctx); |
| 32 | void ListOpenUsers(Kernel::HLERequestContext& ctx); | ||
| 32 | void GetLastOpenedUser(Kernel::HLERequestContext& ctx); | 33 | void GetLastOpenedUser(Kernel::HLERequestContext& ctx); |
| 33 | void GetProfile(Kernel::HLERequestContext& ctx); | 34 | void GetProfile(Kernel::HLERequestContext& ctx); |
| 34 | void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); | 35 | void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 07cea8717..d9f003ed4 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -2,12 +2,15 @@ | |||
| 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 <cinttypes> | ||
| 6 | #include "core/file_sys/filesystem.h" | ||
| 5 | #include "core/hle/ipc_helpers.h" | 7 | #include "core/hle/ipc_helpers.h" |
| 6 | #include "core/hle/kernel/event.h" | 8 | #include "core/hle/kernel/event.h" |
| 7 | #include "core/hle/service/am/am.h" | 9 | #include "core/hle/service/am/am.h" |
| 8 | #include "core/hle/service/am/applet_ae.h" | 10 | #include "core/hle/service/am/applet_ae.h" |
| 9 | #include "core/hle/service/am/applet_oe.h" | 11 | #include "core/hle/service/am/applet_oe.h" |
| 10 | #include "core/hle/service/apm/apm.h" | 12 | #include "core/hle/service/apm/apm.h" |
| 13 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 11 | #include "core/hle/service/nvflinger/nvflinger.h" | 14 | #include "core/hle/service/nvflinger/nvflinger.h" |
| 12 | 15 | ||
| 13 | namespace Service { | 16 | namespace Service { |
| @@ -34,7 +37,38 @@ void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) | |||
| 34 | rb.Push(RESULT_SUCCESS); | 37 | rb.Push(RESULT_SUCCESS); |
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | IAudioController::IAudioController() : ServiceFramework("IAudioController") {} | 40 | IAudioController::IAudioController() : ServiceFramework("IAudioController") { |
| 41 | static const FunctionInfo functions[] = { | ||
| 42 | {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, | ||
| 43 | {1, &IAudioController::GetMainAppletExpectedMasterVolume, | ||
| 44 | "GetMainAppletExpectedMasterVolume"}, | ||
| 45 | {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, | ||
| 46 | "GetLibraryAppletExpectedMasterVolume"}, | ||
| 47 | {3, nullptr, "ChangeMainAppletMasterVolume"}, | ||
| 48 | {4, nullptr, "SetTransparentVolumeRate"}, | ||
| 49 | }; | ||
| 50 | RegisterHandlers(functions); | ||
| 51 | } | ||
| 52 | |||
| 53 | void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) { | ||
| 54 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 55 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 56 | rb.Push(RESULT_SUCCESS); | ||
| 57 | } | ||
| 58 | |||
| 59 | void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { | ||
| 60 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 61 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 62 | rb.Push(RESULT_SUCCESS); | ||
| 63 | rb.Push(volume); | ||
| 64 | } | ||
| 65 | |||
| 66 | void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) { | ||
| 67 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 68 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 69 | rb.Push(RESULT_SUCCESS); | ||
| 70 | rb.Push(volume); | ||
| 71 | } | ||
| 38 | 72 | ||
| 39 | IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {} | 73 | IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {} |
| 40 | 74 | ||
| @@ -46,6 +80,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 46 | {1, &ISelfController::LockExit, "LockExit"}, | 80 | {1, &ISelfController::LockExit, "LockExit"}, |
| 47 | {2, &ISelfController::UnlockExit, "UnlockExit"}, | 81 | {2, &ISelfController::UnlockExit, "UnlockExit"}, |
| 48 | {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, | 82 | {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, |
| 83 | {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, | ||
| 49 | {11, &ISelfController::SetOperationModeChangedNotification, | 84 | {11, &ISelfController::SetOperationModeChangedNotification, |
| 50 | "SetOperationModeChangedNotification"}, | 85 | "SetOperationModeChangedNotification"}, |
| 51 | {12, &ISelfController::SetPerformanceModeChangedNotification, | 86 | {12, &ISelfController::SetPerformanceModeChangedNotification, |
| @@ -98,6 +133,13 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo | |||
| 98 | LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag)); | 133 | LOG_WARNING(Service_AM, "(STUBBED) called flag=%u", static_cast<u32>(flag)); |
| 99 | } | 134 | } |
| 100 | 135 | ||
| 136 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { | ||
| 137 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 138 | rb.Push(RESULT_SUCCESS); | ||
| 139 | |||
| 140 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 141 | } | ||
| 142 | |||
| 101 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { | 143 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| 102 | IPC::RequestParser rp{ctx}; | 144 | IPC::RequestParser rp{ctx}; |
| 103 | 145 | ||
| @@ -306,11 +348,11 @@ private: | |||
| 306 | 348 | ||
| 307 | u64 offset = rp.Pop<u64>(); | 349 | u64 offset = rp.Pop<u64>(); |
| 308 | 350 | ||
| 309 | const auto& output_buffer = ctx.BufferDescriptorC()[0]; | 351 | const size_t size{ctx.GetWriteBufferSize()}; |
| 310 | 352 | ||
| 311 | ASSERT(offset + output_buffer.Size() <= buffer.size()); | 353 | ASSERT(offset + size <= buffer.size()); |
| 312 | 354 | ||
| 313 | Memory::WriteBlock(output_buffer.Address(), buffer.data() + offset, output_buffer.Size()); | 355 | ctx.WriteBuffer(buffer.data() + offset, size); |
| 314 | 356 | ||
| 315 | IPC::ResponseBuilder rb{ctx, 2}; | 357 | IPC::ResponseBuilder rb{ctx, 2}; |
| 316 | 358 | ||
| @@ -377,9 +419,25 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 377 | } | 419 | } |
| 378 | 420 | ||
| 379 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | 421 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { |
| 380 | LOG_WARNING(Service, "(STUBBED) called"); | 422 | IPC::RequestParser rp{ctx}; |
| 381 | IPC::ResponseBuilder rb{ctx, 2}; | 423 | u128 uid = rp.PopRaw<u128>(); |
| 382 | rb.Push(RESULT_SUCCESS); | 424 | |
| 425 | LOG_WARNING(Service, "(STUBBED) called uid = %016" PRIX64 "%016" PRIX64, uid[1], uid[0]); | ||
| 426 | |||
| 427 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 428 | |||
| 429 | FileSys::Path unused; | ||
| 430 | auto savedata = FileSystem::OpenFileSystem(FileSystem::Type::SaveData, unused); | ||
| 431 | if (savedata.Failed()) { | ||
| 432 | // Create the save data and return an error indicating that the operation was performed. | ||
| 433 | FileSystem::FormatFileSystem(FileSystem::Type::SaveData); | ||
| 434 | // TODO(Subv): Find out the correct error code for this. | ||
| 435 | rb.Push(ResultCode(ErrorModule::FS, 40)); | ||
| 436 | } else { | ||
| 437 | rb.Push(RESULT_SUCCESS); | ||
| 438 | } | ||
| 439 | |||
| 440 | rb.Push<u64>(0); | ||
| 383 | } | 441 | } |
| 384 | 442 | ||
| 385 | void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { | 443 | void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 793ac6555..27dbd8c95 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -36,6 +36,13 @@ private: | |||
| 36 | class IAudioController final : public ServiceFramework<IAudioController> { | 36 | class IAudioController final : public ServiceFramework<IAudioController> { |
| 37 | public: | 37 | public: |
| 38 | IAudioController(); | 38 | IAudioController(); |
| 39 | |||
| 40 | private: | ||
| 41 | void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx); | ||
| 42 | void GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx); | ||
| 43 | void GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx); | ||
| 44 | |||
| 45 | u32 volume{100}; | ||
| 39 | }; | 46 | }; |
| 40 | 47 | ||
| 41 | class IDisplayController final : public ServiceFramework<IDisplayController> { | 48 | class IDisplayController final : public ServiceFramework<IDisplayController> { |
| @@ -62,6 +69,7 @@ private: | |||
| 62 | void UnlockExit(Kernel::HLERequestContext& ctx); | 69 | void UnlockExit(Kernel::HLERequestContext& ctx); |
| 63 | void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); | 70 | void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); |
| 64 | void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); | 71 | void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); |
| 72 | void SetScreenShotPermission(Kernel::HLERequestContext& ctx); | ||
| 65 | 73 | ||
| 66 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 74 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| 67 | Kernel::SharedPtr<Kernel::Event> launchable_event; | 75 | Kernel::SharedPtr<Kernel::Event> launchable_event; |
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 260683201..8b55d2fcb 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -2,16 +2,44 @@ | |||
| 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/hle/ipc_helpers.h" | ||
| 5 | #include "core/hle/service/aoc/aoc_u.h" | 7 | #include "core/hle/service/aoc/aoc_u.h" |
| 6 | 8 | ||
| 7 | namespace Service { | 9 | namespace Service { |
| 8 | namespace AOC { | 10 | namespace AOC { |
| 9 | 11 | ||
| 12 | AOC_U::AOC_U() : ServiceFramework("aoc:u") { | ||
| 13 | static const FunctionInfo functions[] = { | ||
| 14 | {0, nullptr, "CountAddOnContentByApplicationId"}, | ||
| 15 | {1, nullptr, "ListAddOnContentByApplicationId"}, | ||
| 16 | {2, &AOC_U::CountAddOnContent, "CountAddOnContent"}, | ||
| 17 | {3, &AOC_U::ListAddOnContent, "ListAddOnContent"}, | ||
| 18 | {4, nullptr, "GetAddOnContentBaseIdByApplicationId"}, | ||
| 19 | {5, nullptr, "GetAddOnContentBaseId"}, | ||
| 20 | {6, nullptr, "PrepareAddOnContentByApplicationId"}, | ||
| 21 | {7, nullptr, "PrepareAddOnContent"}, | ||
| 22 | }; | ||
| 23 | RegisterHandlers(functions); | ||
| 24 | } | ||
| 25 | |||
| 26 | void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { | ||
| 27 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 28 | rb.Push(RESULT_SUCCESS); | ||
| 29 | rb.Push<u64>(0); | ||
| 30 | LOG_WARNING(Service_AOC, "(STUBBED) called"); | ||
| 31 | } | ||
| 32 | |||
| 33 | void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | ||
| 34 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 35 | rb.Push(RESULT_SUCCESS); | ||
| 36 | rb.Push<u64>(0); | ||
| 37 | LOG_WARNING(Service_AOC, "(STUBBED) called"); | ||
| 38 | } | ||
| 39 | |||
| 10 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 40 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
| 11 | std::make_shared<AOC_U>()->InstallAsService(service_manager); | 41 | std::make_shared<AOC_U>()->InstallAsService(service_manager); |
| 12 | } | 42 | } |
| 13 | 43 | ||
| 14 | AOC_U::AOC_U() : ServiceFramework("aoc:u") {} | ||
| 15 | |||
| 16 | } // namespace AOC | 44 | } // namespace AOC |
| 17 | } // namespace Service | 45 | } // namespace Service |
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h index 0cbbf1e5d..6e0ba15a5 100644 --- a/src/core/hle/service/aoc/aoc_u.h +++ b/src/core/hle/service/aoc/aoc_u.h | |||
| @@ -13,6 +13,10 @@ class AOC_U final : public ServiceFramework<AOC_U> { | |||
| 13 | public: | 13 | public: |
| 14 | AOC_U(); | 14 | AOC_U(); |
| 15 | ~AOC_U() = default; | 15 | ~AOC_U() = default; |
| 16 | |||
| 17 | private: | ||
| 18 | void CountAddOnContent(Kernel::HLERequestContext& ctx); | ||
| 19 | void ListAddOnContent(Kernel::HLERequestContext& ctx); | ||
| 16 | }; | 20 | }; |
| 17 | 21 | ||
| 18 | /// Registers all AOC services with the specified service manager. | 22 | /// Registers all AOC services with the specified service manager. |
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index f56ba2ea1..e873d768f 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -52,7 +52,9 @@ public: | |||
| 52 | CoreTiming::ScheduleEvent(audio_ticks, audio_event); | 52 | CoreTiming::ScheduleEvent(audio_ticks, audio_event); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | ~IAudioOut() = default; | 55 | ~IAudioOut() { |
| 56 | CoreTiming::UnscheduleEvent(audio_event, 0); | ||
| 57 | } | ||
| 56 | 58 | ||
| 57 | private: | 59 | private: |
| 58 | void StartAudioOut(Kernel::HLERequestContext& ctx) { | 60 | void StartAudioOut(Kernel::HLERequestContext& ctx) { |
| @@ -99,8 +101,6 @@ private: | |||
| 99 | void GetReleasedAudioOutBuffer_1(Kernel::HLERequestContext& ctx) { | 101 | void GetReleasedAudioOutBuffer_1(Kernel::HLERequestContext& ctx) { |
| 100 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 102 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 101 | 103 | ||
| 102 | const auto& buffer = ctx.BufferDescriptorB()[0]; | ||
| 103 | |||
| 104 | // TODO(st4rk): This is how libtransistor currently implements the | 104 | // TODO(st4rk): This is how libtransistor currently implements the |
| 105 | // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address | 105 | // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address |
| 106 | // is used to know which buffer should be filled with data and send again to the service | 106 | // is used to know which buffer should be filled with data and send again to the service |
| @@ -112,7 +112,7 @@ private: | |||
| 112 | queue_keys.pop_back(); | 112 | queue_keys.pop_back(); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | Memory::WriteBlock(buffer.Address(), &key, sizeof(u64)); | 115 | ctx.WriteBuffer(&key, sizeof(u64)); |
| 116 | 116 | ||
| 117 | IPC::ResponseBuilder rb{ctx, 3}; | 117 | IPC::ResponseBuilder rb{ctx, 3}; |
| 118 | rb.Push(RESULT_SUCCESS); | 118 | rb.Push(RESULT_SUCCESS); |
| @@ -158,10 +158,8 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { | |||
| 158 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 158 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 159 | IPC::RequestParser rp{ctx}; | 159 | IPC::RequestParser rp{ctx}; |
| 160 | 160 | ||
| 161 | auto& buffer = ctx.BufferDescriptorB()[0]; | ||
| 162 | const std::string audio_interface = "AudioInterface"; | 161 | const std::string audio_interface = "AudioInterface"; |
| 163 | 162 | ctx.WriteBuffer(audio_interface.c_str(), audio_interface.size()); | |
| 164 | Memory::WriteBlock(buffer.Address(), &audio_interface[0], audio_interface.size()); | ||
| 165 | 163 | ||
| 166 | IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); | 164 | IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); |
| 167 | 165 | ||
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index c8d8ba748..1cbca6c4b 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -45,7 +45,9 @@ public: | |||
| 45 | // Start the audio event | 45 | // Start the audio event |
| 46 | CoreTiming::ScheduleEvent(audio_ticks, audio_event); | 46 | CoreTiming::ScheduleEvent(audio_ticks, audio_event); |
| 47 | } | 47 | } |
| 48 | ~IAudioRenderer() = default; | 48 | ~IAudioRenderer() { |
| 49 | CoreTiming::UnscheduleEvent(audio_event, 0); | ||
| 50 | } | ||
| 49 | 51 | ||
| 50 | private: | 52 | private: |
| 51 | void UpdateAudioCallback() { | 53 | void UpdateAudioCallback() { |
| @@ -53,7 +55,8 @@ private: | |||
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { | 57 | void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { |
| 56 | AudioRendererResponseData response_data = {0}; | 58 | LOG_DEBUG(Service_Audio, "%s", ctx.Description().c_str()); |
| 59 | AudioRendererResponseData response_data{}; | ||
| 57 | 60 | ||
| 58 | response_data.section_0_size = | 61 | response_data.section_0_size = |
| 59 | response_data.state_entries.size() * sizeof(AudioRendererStateEntry); | 62 | response_data.state_entries.size() * sizeof(AudioRendererStateEntry); |
| @@ -69,9 +72,7 @@ private: | |||
| 69 | response_data.state_entries[i].state = 5; | 72 | response_data.state_entries[i].state = 5; |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | auto& buffer = ctx.BufferDescriptorB()[0]; | 75 | ctx.WriteBuffer(&response_data, response_data.total_size); |
| 73 | |||
| 74 | Memory::WriteBlock(buffer.Address(), &response_data, response_data.total_size); | ||
| 75 | 76 | ||
| 76 | IPC::ResponseBuilder rb{ctx, 2}; | 77 | IPC::ResponseBuilder rb{ctx, 2}; |
| 77 | 78 | ||
| @@ -179,10 +180,10 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 179 | } | 180 | } |
| 180 | 181 | ||
| 181 | void AudRenU::GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx) { | 182 | void AudRenU::GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx) { |
| 182 | IPC::ResponseBuilder rb{ctx, 2}; | 183 | IPC::ResponseBuilder rb{ctx, 3}; |
| 183 | 184 | ||
| 184 | rb.Push(RESULT_SUCCESS); | 185 | rb.Push(RESULT_SUCCESS); |
| 185 | 186 | rb.Push<u32>(100); | |
| 186 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 187 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 187 | } | 188 | } |
| 188 | 189 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 4b47548fd..ef05955b9 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -3,7 +3,9 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <boost/container/flat_map.hpp> | 5 | #include <boost/container/flat_map.hpp> |
| 6 | #include "common/file_util.h" | ||
| 6 | #include "core/file_sys/filesystem.h" | 7 | #include "core/file_sys/filesystem.h" |
| 8 | #include "core/file_sys/savedata_factory.h" | ||
| 7 | #include "core/hle/service/filesystem/filesystem.h" | 9 | #include "core/hle/service/filesystem/filesystem.h" |
| 8 | #include "core/hle/service/filesystem/fsp_srv.h" | 10 | #include "core/hle/service/filesystem/fsp_srv.h" |
| 9 | 11 | ||
| @@ -41,12 +43,30 @@ ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, | |||
| 41 | return itr->second->Open(path); | 43 | return itr->second->Open(path); |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | void UnregisterFileSystems() { | 46 | ResultCode FormatFileSystem(Type type) { |
| 47 | LOG_TRACE(Service_FS, "Formatting FileSystem with type=%d", type); | ||
| 48 | |||
| 49 | auto itr = filesystem_map.find(type); | ||
| 50 | if (itr == filesystem_map.end()) { | ||
| 51 | // TODO(bunnei): Find a better error code for this | ||
| 52 | return ResultCode(-1); | ||
| 53 | } | ||
| 54 | |||
| 55 | FileSys::Path unused; | ||
| 56 | return itr->second->Format(unused); | ||
| 57 | } | ||
| 58 | |||
| 59 | void RegisterFileSystems() { | ||
| 45 | filesystem_map.clear(); | 60 | filesystem_map.clear(); |
| 61 | |||
| 62 | std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||
| 63 | |||
| 64 | auto savedata = std::make_unique<FileSys::SaveData_Factory>(std::move(nand_directory)); | ||
| 65 | RegisterFileSystem(std::move(savedata), Type::SaveData); | ||
| 46 | } | 66 | } |
| 47 | 67 | ||
| 48 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 68 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
| 49 | UnregisterFileSystems(); | 69 | RegisterFileSystems(); |
| 50 | std::make_shared<FSP_SRV>()->InstallAsService(service_manager); | 70 | std::make_shared<FSP_SRV>()->InstallAsService(service_manager); |
| 51 | } | 71 | } |
| 52 | 72 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index a674c9493..8d30e94a1 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -25,6 +25,7 @@ namespace FileSystem { | |||
| 25 | /// Supported FileSystem types | 25 | /// Supported FileSystem types |
| 26 | enum class Type { | 26 | enum class Type { |
| 27 | RomFS = 1, | 27 | RomFS = 1, |
| 28 | SaveData = 2, | ||
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | /** | 31 | /** |
| @@ -43,6 +44,13 @@ ResultCode RegisterFileSystem(std::unique_ptr<FileSys::FileSystemFactory>&& fact | |||
| 43 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, | 44 | ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, |
| 44 | FileSys::Path& path); | 45 | FileSys::Path& path); |
| 45 | 46 | ||
| 47 | /** | ||
| 48 | * Formats a file system | ||
| 49 | * @param type Type of the file system to format | ||
| 50 | * @return ResultCode of the operation | ||
| 51 | */ | ||
| 52 | ResultCode FormatFileSystem(Type type); | ||
| 53 | |||
| 46 | /// Registers all Filesystem services with the specified service manager. | 54 | /// Registers all Filesystem services with the specified service manager. |
| 47 | void InstallInterfaces(SM::ServiceManager& service_manager); | 55 | void InstallInterfaces(SM::ServiceManager& service_manager); |
| 48 | 56 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 34d4fd035..97b3fa290 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 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 <cinttypes> | ||
| 5 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | 7 | #include "core/core.h" |
| 7 | #include "core/file_sys/filesystem.h" | 8 | #include "core/file_sys/filesystem.h" |
| @@ -33,12 +34,10 @@ private: | |||
| 33 | IPC::RequestParser rp{ctx}; | 34 | IPC::RequestParser rp{ctx}; |
| 34 | const s64 offset = rp.Pop<s64>(); | 35 | const s64 offset = rp.Pop<s64>(); |
| 35 | const s64 length = rp.Pop<s64>(); | 36 | const s64 length = rp.Pop<s64>(); |
| 36 | const auto& descriptor = ctx.BufferDescriptorB()[0]; | ||
| 37 | 37 | ||
| 38 | LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); | 38 | LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); |
| 39 | 39 | ||
| 40 | // Error checking | 40 | // Error checking |
| 41 | ASSERT_MSG(length == descriptor.Size(), "unexpected size difference"); | ||
| 42 | if (length < 0) { | 41 | if (length < 0) { |
| 43 | IPC::ResponseBuilder rb{ctx, 2}; | 42 | IPC::ResponseBuilder rb{ctx, 2}; |
| 44 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); | 43 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); |
| @@ -60,17 +59,194 @@ private: | |||
| 60 | } | 59 | } |
| 61 | 60 | ||
| 62 | // Write the data to memory | 61 | // Write the data to memory |
| 63 | Memory::WriteBlock(descriptor.Address(), output.data(), descriptor.Size()); | 62 | ctx.WriteBuffer(output); |
| 64 | 63 | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | 64 | IPC::ResponseBuilder rb{ctx, 2}; |
| 66 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 67 | } | 66 | } |
| 68 | }; | 67 | }; |
| 69 | 68 | ||
| 69 | class IFile final : public ServiceFramework<IFile> { | ||
| 70 | public: | ||
| 71 | explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend) | ||
| 72 | : ServiceFramework("IFile"), backend(std::move(backend)) { | ||
| 73 | static const FunctionInfo functions[] = { | ||
| 74 | {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, {2, nullptr, "Flush"}, | ||
| 75 | {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, | ||
| 76 | }; | ||
| 77 | RegisterHandlers(functions); | ||
| 78 | } | ||
| 79 | |||
| 80 | private: | ||
| 81 | std::unique_ptr<FileSys::StorageBackend> backend; | ||
| 82 | |||
| 83 | void Read(Kernel::HLERequestContext& ctx) { | ||
| 84 | IPC::RequestParser rp{ctx}; | ||
| 85 | const u64 unk = rp.Pop<u64>(); | ||
| 86 | const s64 offset = rp.Pop<s64>(); | ||
| 87 | const s64 length = rp.Pop<s64>(); | ||
| 88 | |||
| 89 | LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); | ||
| 90 | |||
| 91 | // Error checking | ||
| 92 | if (length < 0) { | ||
| 93 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 94 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | if (offset < 0) { | ||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 99 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); | ||
| 100 | return; | ||
| 101 | } | ||
| 102 | |||
| 103 | // Read the data from the Storage backend | ||
| 104 | std::vector<u8> output(length); | ||
| 105 | ResultVal<size_t> res = backend->Read(offset, length, output.data()); | ||
| 106 | if (res.Failed()) { | ||
| 107 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 108 | rb.Push(res.Code()); | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | |||
| 112 | // Write the data to memory | ||
| 113 | ctx.WriteBuffer(output); | ||
| 114 | |||
| 115 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 116 | rb.Push(RESULT_SUCCESS); | ||
| 117 | rb.Push(static_cast<u64>(*res)); | ||
| 118 | } | ||
| 119 | |||
| 120 | void Write(Kernel::HLERequestContext& ctx) { | ||
| 121 | IPC::RequestParser rp{ctx}; | ||
| 122 | const u64 unk = rp.Pop<u64>(); | ||
| 123 | const s64 offset = rp.Pop<s64>(); | ||
| 124 | const s64 length = rp.Pop<s64>(); | ||
| 125 | |||
| 126 | LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); | ||
| 127 | |||
| 128 | // Error checking | ||
| 129 | if (length < 0) { | ||
| 130 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 131 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | if (offset < 0) { | ||
| 135 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 136 | rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); | ||
| 137 | return; | ||
| 138 | } | ||
| 139 | |||
| 140 | // Write the data to the Storage backend | ||
| 141 | std::vector<u8> data = ctx.ReadBuffer(); | ||
| 142 | ResultVal<size_t> res = backend->Write(offset, length, true, data.data()); | ||
| 143 | if (res.Failed()) { | ||
| 144 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 145 | rb.Push(res.Code()); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | |||
| 149 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 150 | rb.Push(RESULT_SUCCESS); | ||
| 151 | } | ||
| 152 | }; | ||
| 153 | |||
| 154 | class IFileSystem final : public ServiceFramework<IFileSystem> { | ||
| 155 | public: | ||
| 156 | explicit IFileSystem(std::unique_ptr<FileSys::FileSystemBackend>&& backend) | ||
| 157 | : ServiceFramework("IFileSystem"), backend(std::move(backend)) { | ||
| 158 | static const FunctionInfo functions[] = { | ||
| 159 | {0, &IFileSystem::CreateFile, "CreateFile"}, | ||
| 160 | {7, &IFileSystem::GetEntryType, "GetEntryType"}, | ||
| 161 | {8, &IFileSystem::OpenFile, "OpenFile"}, | ||
| 162 | {10, &IFileSystem::Commit, "Commit"}, | ||
| 163 | }; | ||
| 164 | RegisterHandlers(functions); | ||
| 165 | } | ||
| 166 | |||
| 167 | void CreateFile(Kernel::HLERequestContext& ctx) { | ||
| 168 | IPC::RequestParser rp{ctx}; | ||
| 169 | |||
| 170 | auto file_buffer = ctx.ReadBuffer(); | ||
| 171 | auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||
| 172 | |||
| 173 | std::string name(file_buffer.begin(), end); | ||
| 174 | |||
| 175 | u64 mode = rp.Pop<u64>(); | ||
| 176 | u32 size = rp.Pop<u32>(); | ||
| 177 | |||
| 178 | LOG_DEBUG(Service_FS, "called file %s mode 0x%" PRIX64 " size 0x%08X", name.c_str(), mode, | ||
| 179 | size); | ||
| 180 | |||
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 182 | rb.Push(backend->CreateFile(name, size)); | ||
| 183 | } | ||
| 184 | |||
| 185 | void OpenFile(Kernel::HLERequestContext& ctx) { | ||
| 186 | IPC::RequestParser rp{ctx}; | ||
| 187 | |||
| 188 | auto file_buffer = ctx.ReadBuffer(); | ||
| 189 | auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||
| 190 | |||
| 191 | std::string name(file_buffer.begin(), end); | ||
| 192 | |||
| 193 | auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); | ||
| 194 | |||
| 195 | LOG_DEBUG(Service_FS, "called file %s mode %u", name.c_str(), static_cast<u32>(mode)); | ||
| 196 | |||
| 197 | auto result = backend->OpenFile(name, mode); | ||
| 198 | if (result.Failed()) { | ||
| 199 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 200 | rb.Push(result.Code()); | ||
| 201 | return; | ||
| 202 | } | ||
| 203 | |||
| 204 | auto file = std::move(result.Unwrap()); | ||
| 205 | |||
| 206 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 207 | rb.Push(RESULT_SUCCESS); | ||
| 208 | rb.PushIpcInterface<IFile>(std::move(file)); | ||
| 209 | } | ||
| 210 | |||
| 211 | void GetEntryType(Kernel::HLERequestContext& ctx) { | ||
| 212 | IPC::RequestParser rp{ctx}; | ||
| 213 | |||
| 214 | auto file_buffer = ctx.ReadBuffer(); | ||
| 215 | auto end = std::find(file_buffer.begin(), file_buffer.end(), '\0'); | ||
| 216 | |||
| 217 | std::string name(file_buffer.begin(), end); | ||
| 218 | |||
| 219 | LOG_DEBUG(Service_FS, "called file %s", name.c_str()); | ||
| 220 | |||
| 221 | auto result = backend->GetEntryType(name); | ||
| 222 | if (result.Failed()) { | ||
| 223 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 224 | rb.Push(result.Code()); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 229 | rb.Push(RESULT_SUCCESS); | ||
| 230 | rb.Push<u32>(static_cast<u32>(*result)); | ||
| 231 | } | ||
| 232 | |||
| 233 | void Commit(Kernel::HLERequestContext& ctx) { | ||
| 234 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 237 | rb.Push(RESULT_SUCCESS); | ||
| 238 | } | ||
| 239 | |||
| 240 | private: | ||
| 241 | std::unique_ptr<FileSys::FileSystemBackend> backend; | ||
| 242 | }; | ||
| 243 | |||
| 70 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { | 244 | FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { |
| 71 | static const FunctionInfo functions[] = { | 245 | static const FunctionInfo functions[] = { |
| 72 | {1, &FSP_SRV::Initalize, "Initalize"}, | 246 | {1, &FSP_SRV::Initalize, "Initalize"}, |
| 73 | {18, &FSP_SRV::MountSdCard, "MountSdCard"}, | 247 | {18, &FSP_SRV::MountSdCard, "MountSdCard"}, |
| 248 | {22, &FSP_SRV::CreateSaveData, "CreateSaveData"}, | ||
| 249 | {51, &FSP_SRV::MountSaveData, "MountSaveData"}, | ||
| 74 | {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, | 250 | {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, |
| 75 | {202, nullptr, "OpenDataStorageByDataId"}, | 251 | {202, nullptr, "OpenDataStorageByDataId"}, |
| 76 | {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"}, | 252 | {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"}, |
| @@ -104,6 +280,30 @@ void FSP_SRV::MountSdCard(Kernel::HLERequestContext& ctx) { | |||
| 104 | rb.Push(RESULT_SUCCESS); | 280 | rb.Push(RESULT_SUCCESS); |
| 105 | } | 281 | } |
| 106 | 282 | ||
| 283 | void FSP_SRV::CreateSaveData(Kernel::HLERequestContext& ctx) { | ||
| 284 | IPC::RequestParser rp{ctx}; | ||
| 285 | |||
| 286 | auto save_struct = rp.PopRaw<std::array<u8, 0x40>>(); | ||
| 287 | auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); | ||
| 288 | u128 uid = rp.PopRaw<u128>(); | ||
| 289 | |||
| 290 | LOG_WARNING(Service_FS, "(STUBBED) called uid = %016" PRIX64 "%016" PRIX64, uid[1], uid[0]); | ||
| 291 | |||
| 292 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 293 | rb.Push(RESULT_SUCCESS); | ||
| 294 | } | ||
| 295 | |||
| 296 | void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { | ||
| 297 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 298 | |||
| 299 | FileSys::Path unused; | ||
| 300 | auto filesystem = OpenFileSystem(Type::SaveData, unused).Unwrap(); | ||
| 301 | |||
| 302 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 303 | rb.Push(RESULT_SUCCESS); | ||
| 304 | rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); | ||
| 305 | } | ||
| 306 | |||
| 107 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 307 | void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { |
| 108 | LOG_WARNING(Service_FS, "(STUBBED) called"); | 308 | LOG_WARNING(Service_FS, "(STUBBED) called"); |
| 109 | 309 | ||
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 56afc4b90..e15ba4375 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -24,6 +24,8 @@ private: | |||
| 24 | 24 | ||
| 25 | void Initalize(Kernel::HLERequestContext& ctx); | 25 | void Initalize(Kernel::HLERequestContext& ctx); |
| 26 | void MountSdCard(Kernel::HLERequestContext& ctx); | 26 | void MountSdCard(Kernel::HLERequestContext& ctx); |
| 27 | void CreateSaveData(Kernel::HLERequestContext& ctx); | ||
| 28 | void MountSaveData(Kernel::HLERequestContext& ctx); | ||
| 27 | void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); | 29 | void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); |
| 28 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 30 | void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 29 | void OpenRomStorage(Kernel::HLERequestContext& ctx); | 31 | void OpenRomStorage(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp new file mode 100644 index 000000000..26593bb0c --- /dev/null +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/friend/friend.h" | ||
| 8 | #include "core/hle/service/friend/friend_a.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | namespace Friend { | ||
| 12 | |||
| 13 | void Module::Interface::Unknown(Kernel::HLERequestContext& ctx) { | ||
| 14 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 15 | rb.Push(RESULT_SUCCESS); | ||
| 16 | LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||
| 17 | } | ||
| 18 | |||
| 19 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | ||
| 20 | : ServiceFramework(name), module(std::move(module)) {} | ||
| 21 | |||
| 22 | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||
| 23 | auto module = std::make_shared<Module>(); | ||
| 24 | std::make_shared<Friend_A>(module)->InstallAsService(service_manager); | ||
| 25 | } | ||
| 26 | |||
| 27 | } // namespace Friend | ||
| 28 | } // namespace Service | ||
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h new file mode 100644 index 000000000..ffa498397 --- /dev/null +++ b/src/core/hle/service/friend/friend.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace Friend { | ||
| 11 | |||
| 12 | class Module final { | ||
| 13 | public: | ||
| 14 | class Interface : public ServiceFramework<Interface> { | ||
| 15 | public: | ||
| 16 | Interface(std::shared_ptr<Module> module, const char* name); | ||
| 17 | |||
| 18 | void Unknown(Kernel::HLERequestContext& ctx); | ||
| 19 | |||
| 20 | protected: | ||
| 21 | std::shared_ptr<Module> module; | ||
| 22 | }; | ||
| 23 | }; | ||
| 24 | |||
| 25 | /// Registers all Friend services with the specified service manager. | ||
| 26 | void InstallInterfaces(SM::ServiceManager& service_manager); | ||
| 27 | |||
| 28 | } // namespace Friend | ||
| 29 | } // namespace Service | ||
diff --git a/src/core/hle/service/friend/friend_a.cpp b/src/core/hle/service/friend/friend_a.cpp new file mode 100644 index 000000000..e1f2397c2 --- /dev/null +++ b/src/core/hle/service/friend/friend_a.cpp | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/friend/friend_a.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace Friend { | ||
| 9 | |||
| 10 | Friend_A::Friend_A(std::shared_ptr<Module> module) | ||
| 11 | : Module::Interface(std::move(module), "friend:a") { | ||
| 12 | static const FunctionInfo functions[] = { | ||
| 13 | {0, &Friend_A::Unknown, "Unknown"}, | ||
| 14 | }; | ||
| 15 | RegisterHandlers(functions); | ||
| 16 | } | ||
| 17 | |||
| 18 | } // namespace Friend | ||
| 19 | } // namespace Service | ||
diff --git a/src/core/hle/service/friend/friend_a.h b/src/core/hle/service/friend/friend_a.h new file mode 100644 index 000000000..68fa58297 --- /dev/null +++ b/src/core/hle/service/friend/friend_a.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/friend/friend.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace Friend { | ||
| 11 | |||
| 12 | class Friend_A final : public Module::Interface { | ||
| 13 | public: | ||
| 14 | explicit Friend_A(std::shared_ptr<Module> module); | ||
| 15 | }; | ||
| 16 | |||
| 17 | } // namespace Friend | ||
| 18 | } // namespace Service | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d757d2eae..7e04ad8d4 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -45,6 +45,10 @@ public: | |||
| 45 | CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); | 45 | CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | ~IAppletResource() { | ||
| 49 | CoreTiming::UnscheduleEvent(pad_update_event, 0); | ||
| 50 | } | ||
| 51 | |||
| 48 | private: | 52 | private: |
| 49 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 53 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 50 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 54 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| @@ -176,7 +180,10 @@ public: | |||
| 176 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, | 180 | {0, &Hid::CreateAppletResource, "CreateAppletResource"}, |
| 177 | {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, | 181 | {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, |
| 178 | {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, | 182 | {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, |
| 183 | {21, &Hid::ActivateMouse, "ActivateMouse"}, | ||
| 184 | {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, | ||
| 179 | {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, | 185 | {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, |
| 186 | {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, | ||
| 180 | {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, | 187 | {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, |
| 181 | {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, | 188 | {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, |
| 182 | {103, &Hid::ActivateNpad, "ActivateNpad"}, | 189 | {103, &Hid::ActivateNpad, "ActivateNpad"}, |
| @@ -184,9 +191,15 @@ public: | |||
| 184 | "AcquireNpadStyleSetUpdateEventHandle"}, | 191 | "AcquireNpadStyleSetUpdateEventHandle"}, |
| 185 | {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, | 192 | {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, |
| 186 | {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, | 193 | {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, |
| 194 | {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, | ||
| 195 | "SetNpadJoyAssignmentModeSingleByDefault"}, | ||
| 187 | {124, nullptr, "SetNpadJoyAssignmentModeDual"}, | 196 | {124, nullptr, "SetNpadJoyAssignmentModeDual"}, |
| 188 | {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, | 197 | {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, |
| 198 | {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, | ||
| 199 | {201, &Hid::SendVibrationValue, "SendVibrationValue"}, | ||
| 200 | {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, | ||
| 189 | {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, | 201 | {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, |
| 202 | {206, &Hid::SendVibrationValues, "SendVibrationValues"}, | ||
| 190 | }; | 203 | }; |
| 191 | RegisterHandlers(functions); | 204 | RegisterHandlers(functions); |
| 192 | 205 | ||
| @@ -222,12 +235,30 @@ private: | |||
| 222 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 235 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 223 | } | 236 | } |
| 224 | 237 | ||
| 238 | void ActivateMouse(Kernel::HLERequestContext& ctx) { | ||
| 239 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 240 | rb.Push(RESULT_SUCCESS); | ||
| 241 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 242 | } | ||
| 243 | |||
| 244 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { | ||
| 245 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 246 | rb.Push(RESULT_SUCCESS); | ||
| 247 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 248 | } | ||
| 249 | |||
| 225 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 250 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 226 | IPC::ResponseBuilder rb{ctx, 2}; | 251 | IPC::ResponseBuilder rb{ctx, 2}; |
| 227 | rb.Push(RESULT_SUCCESS); | 252 | rb.Push(RESULT_SUCCESS); |
| 228 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 253 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 229 | } | 254 | } |
| 230 | 255 | ||
| 256 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | ||
| 257 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 258 | rb.Push(RESULT_SUCCESS); | ||
| 259 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 260 | } | ||
| 261 | |||
| 231 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 262 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 232 | IPC::ResponseBuilder rb{ctx, 2}; | 263 | IPC::ResponseBuilder rb{ctx, 2}; |
| 233 | rb.Push(RESULT_SUCCESS); | 264 | rb.Push(RESULT_SUCCESS); |
| @@ -266,18 +297,49 @@ private: | |||
| 266 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 297 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 267 | } | 298 | } |
| 268 | 299 | ||
| 300 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | ||
| 301 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 302 | rb.Push(RESULT_SUCCESS); | ||
| 303 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 304 | } | ||
| 305 | |||
| 306 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { | ||
| 307 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 308 | rb.Push(RESULT_SUCCESS); | ||
| 309 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 310 | } | ||
| 311 | |||
| 312 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | ||
| 313 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 314 | rb.Push(RESULT_SUCCESS); | ||
| 315 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 316 | } | ||
| 317 | |||
| 269 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | 318 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { |
| 270 | IPC::ResponseBuilder rb{ctx, 2}; | 319 | IPC::ResponseBuilder rb{ctx, 2}; |
| 271 | rb.Push(RESULT_SUCCESS); | 320 | rb.Push(RESULT_SUCCESS); |
| 272 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 321 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 273 | } | 322 | } |
| 274 | 323 | ||
| 324 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | ||
| 325 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 326 | rb.Push(RESULT_SUCCESS); | ||
| 327 | rb.Push<u64>(0); | ||
| 328 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 329 | } | ||
| 330 | |||
| 275 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | 331 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { |
| 276 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 332 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 277 | rb.Push(RESULT_SUCCESS); | 333 | rb.Push(RESULT_SUCCESS); |
| 278 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); | 334 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); |
| 279 | LOG_DEBUG(Service_HID, "called"); | 335 | LOG_DEBUG(Service_HID, "called"); |
| 280 | } | 336 | } |
| 337 | |||
| 338 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { | ||
| 339 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 340 | rb.Push(RESULT_SUCCESS); | ||
| 341 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 342 | } | ||
| 281 | }; | 343 | }; |
| 282 | 344 | ||
| 283 | void ReloadInputDevices() {} | 345 | void ReloadInputDevices() {} |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 290a2ee74..dd2d5fe63 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.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 "core/hle/ipc_helpers.h" | 5 | #include "core/hle/ipc_helpers.h" |
| 6 | #include "core/hle/kernel/event.h" | ||
| 6 | #include "core/hle/service/nifm/nifm.h" | 7 | #include "core/hle/service/nifm/nifm.h" |
| 7 | #include "core/hle/service/nifm/nifm_a.h" | 8 | #include "core/hle/service/nifm/nifm_a.h" |
| 8 | #include "core/hle/service/nifm/nifm_s.h" | 9 | #include "core/hle/service/nifm/nifm_s.h" |
| @@ -28,10 +29,10 @@ class IRequest final : public ServiceFramework<IRequest> { | |||
| 28 | public: | 29 | public: |
| 29 | explicit IRequest() : ServiceFramework("IRequest") { | 30 | explicit IRequest() : ServiceFramework("IRequest") { |
| 30 | static const FunctionInfo functions[] = { | 31 | static const FunctionInfo functions[] = { |
| 31 | {0, nullptr, "GetRequestState"}, | 32 | {0, &IRequest::GetRequestState, "GetRequestState"}, |
| 32 | {1, nullptr, "GetResult"}, | 33 | {1, &IRequest::GetResult, "GetResult"}, |
| 33 | {2, nullptr, "GetSystemEventReadableHandles"}, | 34 | {2, &IRequest::GetSystemEventReadableHandles, "GetSystemEventReadableHandles"}, |
| 34 | {3, nullptr, "Cancel"}, | 35 | {3, &IRequest::Cancel, "Cancel"}, |
| 35 | {4, nullptr, "Submit"}, | 36 | {4, nullptr, "Submit"}, |
| 36 | {5, nullptr, "SetRequirement"}, | 37 | {5, nullptr, "SetRequirement"}, |
| 37 | {6, nullptr, "SetRequirementPreset"}, | 38 | {6, nullptr, "SetRequirementPreset"}, |
| @@ -55,7 +56,37 @@ public: | |||
| 55 | {25, nullptr, "UnregisterSocketDescriptor"}, | 56 | {25, nullptr, "UnregisterSocketDescriptor"}, |
| 56 | }; | 57 | }; |
| 57 | RegisterHandlers(functions); | 58 | RegisterHandlers(functions); |
| 59 | |||
| 60 | event1 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event1"); | ||
| 61 | event2 = Kernel::Event::Create(Kernel::ResetType::OneShot, "IRequest:Event2"); | ||
| 62 | } | ||
| 63 | |||
| 64 | private: | ||
| 65 | void GetRequestState(Kernel::HLERequestContext& ctx) { | ||
| 66 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 67 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 68 | rb.Push(RESULT_SUCCESS); | ||
| 69 | rb.Push<u32>(0); | ||
| 70 | } | ||
| 71 | void GetResult(Kernel::HLERequestContext& ctx) { | ||
| 72 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 73 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 74 | rb.Push(RESULT_SUCCESS); | ||
| 75 | rb.Push<u32>(0); | ||
| 76 | } | ||
| 77 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { | ||
| 78 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 79 | IPC::ResponseBuilder rb{ctx, 2, 2}; | ||
| 80 | rb.Push(RESULT_SUCCESS); | ||
| 81 | rb.PushCopyObjects(event1, event2); | ||
| 58 | } | 82 | } |
| 83 | void Cancel(Kernel::HLERequestContext& ctx) { | ||
| 84 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 85 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 86 | rb.Push(RESULT_SUCCESS); | ||
| 87 | } | ||
| 88 | |||
| 89 | Kernel::SharedPtr<Kernel::Event> event1, event2; | ||
| 59 | }; | 90 | }; |
| 60 | 91 | ||
| 61 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { | 92 | class INetworkProfile final : public ServiceFramework<INetworkProfile> { |
| @@ -70,13 +101,56 @@ public: | |||
| 70 | } | 101 | } |
| 71 | }; | 102 | }; |
| 72 | 103 | ||
| 104 | class IGeneralService final : public ServiceFramework<IGeneralService> { | ||
| 105 | public: | ||
| 106 | IGeneralService(); | ||
| 107 | |||
| 108 | private: | ||
| 109 | void GetClientId(Kernel::HLERequestContext& ctx) { | ||
| 110 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 111 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 112 | rb.Push(RESULT_SUCCESS); | ||
| 113 | rb.Push<u64>(0); | ||
| 114 | } | ||
| 115 | void CreateScanRequest(Kernel::HLERequestContext& ctx) { | ||
| 116 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 117 | |||
| 118 | rb.Push(RESULT_SUCCESS); | ||
| 119 | rb.PushIpcInterface<IScanRequest>(); | ||
| 120 | |||
| 121 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 122 | } | ||
| 123 | void CreateRequest(Kernel::HLERequestContext& ctx) { | ||
| 124 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 125 | |||
| 126 | rb.Push(RESULT_SUCCESS); | ||
| 127 | rb.PushIpcInterface<IRequest>(); | ||
| 128 | |||
| 129 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 130 | } | ||
| 131 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | ||
| 132 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 133 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 134 | rb.Push(RESULT_SUCCESS); | ||
| 135 | } | ||
| 136 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { | ||
| 137 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 138 | |||
| 139 | rb.Push(RESULT_SUCCESS); | ||
| 140 | rb.PushIpcInterface<INetworkProfile>(); | ||
| 141 | |||
| 142 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 143 | } | ||
| 144 | }; | ||
| 145 | |||
| 73 | IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { | 146 | IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { |
| 74 | static const FunctionInfo functions[] = { | 147 | static const FunctionInfo functions[] = { |
| 75 | {1, &IGeneralService::GetClientId, "GetClientId"}, | 148 | {1, &IGeneralService::GetClientId, "GetClientId"}, |
| 76 | {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, | 149 | {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, |
| 77 | {4, &IGeneralService::CreateRequest, "CreateRequest"}, | 150 | {4, &IGeneralService::CreateRequest, "CreateRequest"}, |
| 78 | {6, nullptr, "GetCurrentNetworkProfile"}, | 151 | {5, nullptr, "GetCurrentNetworkProfile"}, |
| 79 | {7, nullptr, "EnumerateNetworkInterfaces"}, | 152 | {6, nullptr, "EnumerateNetworkInterfaces"}, |
| 153 | {7, nullptr, "EnumerateNetworkProfiles"}, | ||
| 80 | {8, nullptr, "GetNetworkProfile"}, | 154 | {8, nullptr, "GetNetworkProfile"}, |
| 81 | {9, nullptr, "SetNetworkProfile"}, | 155 | {9, nullptr, "SetNetworkProfile"}, |
| 82 | {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, | 156 | {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, |
| @@ -111,50 +185,28 @@ IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { | |||
| 111 | RegisterHandlers(functions); | 185 | RegisterHandlers(functions); |
| 112 | } | 186 | } |
| 113 | 187 | ||
| 114 | void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) { | 188 | void Module::Interface::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { |
| 115 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 116 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 117 | rb.Push(RESULT_SUCCESS); | ||
| 118 | rb.Push<u64>(0); | ||
| 119 | } | ||
| 120 | |||
| 121 | void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) { | ||
| 122 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 189 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 123 | |||
| 124 | rb.Push(RESULT_SUCCESS); | 190 | rb.Push(RESULT_SUCCESS); |
| 125 | rb.PushIpcInterface<IScanRequest>(); | 191 | rb.PushIpcInterface<IGeneralService>(); |
| 126 | |||
| 127 | LOG_DEBUG(Service_NIFM, "called"); | 192 | LOG_DEBUG(Service_NIFM, "called"); |
| 128 | } | 193 | } |
| 129 | 194 | ||
| 130 | void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) { | 195 | void Module::Interface::CreateGeneralService(Kernel::HLERequestContext& ctx) { |
| 131 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 196 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 132 | |||
| 133 | rb.Push(RESULT_SUCCESS); | 197 | rb.Push(RESULT_SUCCESS); |
| 134 | rb.PushIpcInterface<IRequest>(); | 198 | rb.PushIpcInterface<IGeneralService>(); |
| 135 | |||
| 136 | LOG_DEBUG(Service_NIFM, "called"); | 199 | LOG_DEBUG(Service_NIFM, "called"); |
| 137 | } | 200 | } |
| 138 | 201 | ||
| 139 | void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | 202 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
| 140 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 203 | : ServiceFramework(name), module(std::move(module)) {} |
| 141 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 142 | rb.Push(RESULT_SUCCESS); | ||
| 143 | } | ||
| 144 | |||
| 145 | void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { | ||
| 146 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 147 | |||
| 148 | rb.Push(RESULT_SUCCESS); | ||
| 149 | rb.PushIpcInterface<INetworkProfile>(); | ||
| 150 | |||
| 151 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 152 | } | ||
| 153 | 204 | ||
| 154 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 205 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
| 155 | std::make_shared<NIFM_A>()->InstallAsService(service_manager); | 206 | auto module = std::make_shared<Module>(); |
| 156 | std::make_shared<NIFM_S>()->InstallAsService(service_manager); | 207 | std::make_shared<NIFM_A>(module)->InstallAsService(service_manager); |
| 157 | std::make_shared<NIFM_U>()->InstallAsService(service_manager); | 208 | std::make_shared<NIFM_S>(module)->InstallAsService(service_manager); |
| 209 | std::make_shared<NIFM_U>(module)->InstallAsService(service_manager); | ||
| 158 | } | 210 | } |
| 159 | 211 | ||
| 160 | } // namespace NIFM | 212 | } // namespace NIFM |
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h index 6edbfe4a4..11d263b12 100644 --- a/src/core/hle/service/nifm/nifm.h +++ b/src/core/hle/service/nifm/nifm.h | |||
| @@ -9,16 +9,18 @@ | |||
| 9 | namespace Service { | 9 | namespace Service { |
| 10 | namespace NIFM { | 10 | namespace NIFM { |
| 11 | 11 | ||
| 12 | class IGeneralService final : public ServiceFramework<IGeneralService> { | 12 | class Module final { |
| 13 | public: | 13 | public: |
| 14 | IGeneralService(); | 14 | class Interface : public ServiceFramework<Interface> { |
| 15 | 15 | public: | |
| 16 | private: | 16 | Interface(std::shared_ptr<Module> module, const char* name); |
| 17 | void GetClientId(Kernel::HLERequestContext& ctx); | 17 | |
| 18 | void CreateScanRequest(Kernel::HLERequestContext& ctx); | 18 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); |
| 19 | void CreateRequest(Kernel::HLERequestContext& ctx); | 19 | void CreateGeneralService(Kernel::HLERequestContext& ctx); |
| 20 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx); | 20 | |
| 21 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx); | 21 | protected: |
| 22 | std::shared_ptr<Module> module; | ||
| 23 | }; | ||
| 22 | }; | 24 | }; |
| 23 | 25 | ||
| 24 | void InstallInterfaces(SM::ServiceManager& service_manager); | 26 | void InstallInterfaces(SM::ServiceManager& service_manager); |
diff --git a/src/core/hle/service/nifm/nifm_a.cpp b/src/core/hle/service/nifm/nifm_a.cpp index ee61d8ff4..f75df8c04 100644 --- a/src/core/hle/service/nifm/nifm_a.cpp +++ b/src/core/hle/service/nifm/nifm_a.cpp | |||
| @@ -2,29 +2,12 @@ | |||
| 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/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/nifm/nifm.h" | ||
| 8 | #include "core/hle/service/nifm/nifm_a.h" | 5 | #include "core/hle/service/nifm/nifm_a.h" |
| 9 | 6 | ||
| 10 | namespace Service { | 7 | namespace Service { |
| 11 | namespace NIFM { | 8 | namespace NIFM { |
| 12 | 9 | ||
| 13 | void NIFM_A::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { | 10 | NIFM_A::NIFM_A(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:a") { |
| 14 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 15 | rb.Push(RESULT_SUCCESS); | ||
| 16 | rb.PushIpcInterface<IGeneralService>(); | ||
| 17 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 18 | } | ||
| 19 | |||
| 20 | void NIFM_A::CreateGeneralService(Kernel::HLERequestContext& ctx) { | ||
| 21 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 22 | rb.Push(RESULT_SUCCESS); | ||
| 23 | rb.PushIpcInterface<IGeneralService>(); | ||
| 24 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 25 | } | ||
| 26 | |||
| 27 | NIFM_A::NIFM_A() : ServiceFramework("nifm:a") { | ||
| 28 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 29 | {4, &NIFM_A::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, | 12 | {4, &NIFM_A::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, |
| 30 | {5, &NIFM_A::CreateGeneralService, "CreateGeneralService"}, | 13 | {5, &NIFM_A::CreateGeneralService, "CreateGeneralService"}, |
diff --git a/src/core/hle/service/nifm/nifm_a.h b/src/core/hle/service/nifm/nifm_a.h index 06a92a93c..eaea14e29 100644 --- a/src/core/hle/service/nifm/nifm_a.h +++ b/src/core/hle/service/nifm/nifm_a.h | |||
| @@ -4,20 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | 7 | #include "core/hle/service/nifm/nifm.h" |
| 8 | #include "core/hle/service/service.h" | ||
| 9 | 8 | ||
| 10 | namespace Service { | 9 | namespace Service { |
| 11 | namespace NIFM { | 10 | namespace NIFM { |
| 12 | 11 | ||
| 13 | class NIFM_A final : public ServiceFramework<NIFM_A> { | 12 | class NIFM_A final : public Module::Interface { |
| 14 | public: | 13 | public: |
| 15 | NIFM_A(); | 14 | explicit NIFM_A(std::shared_ptr<Module> module); |
| 16 | ~NIFM_A() = default; | ||
| 17 | |||
| 18 | private: | ||
| 19 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); | ||
| 20 | void CreateGeneralService(Kernel::HLERequestContext& ctx); | ||
| 21 | }; | 15 | }; |
| 22 | 16 | ||
| 23 | } // namespace NIFM | 17 | } // namespace NIFM |
diff --git a/src/core/hle/service/nifm/nifm_s.cpp b/src/core/hle/service/nifm/nifm_s.cpp index c38b2a4c7..9c0b300e4 100644 --- a/src/core/hle/service/nifm/nifm_s.cpp +++ b/src/core/hle/service/nifm/nifm_s.cpp | |||
| @@ -2,29 +2,12 @@ | |||
| 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/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/nifm/nifm.h" | ||
| 8 | #include "core/hle/service/nifm/nifm_s.h" | 5 | #include "core/hle/service/nifm/nifm_s.h" |
| 9 | 6 | ||
| 10 | namespace Service { | 7 | namespace Service { |
| 11 | namespace NIFM { | 8 | namespace NIFM { |
| 12 | 9 | ||
| 13 | void NIFM_S::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { | 10 | NIFM_S::NIFM_S(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:s") { |
| 14 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 15 | rb.Push(RESULT_SUCCESS); | ||
| 16 | rb.PushIpcInterface<IGeneralService>(); | ||
| 17 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 18 | } | ||
| 19 | |||
| 20 | void NIFM_S::CreateGeneralService(Kernel::HLERequestContext& ctx) { | ||
| 21 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 22 | rb.Push(RESULT_SUCCESS); | ||
| 23 | rb.PushIpcInterface<IGeneralService>(); | ||
| 24 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 25 | } | ||
| 26 | |||
| 27 | NIFM_S::NIFM_S() : ServiceFramework("nifm:s") { | ||
| 28 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 29 | {4, &NIFM_S::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, | 12 | {4, &NIFM_S::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, |
| 30 | {5, &NIFM_S::CreateGeneralService, "CreateGeneralService"}, | 13 | {5, &NIFM_S::CreateGeneralService, "CreateGeneralService"}, |
diff --git a/src/core/hle/service/nifm/nifm_s.h b/src/core/hle/service/nifm/nifm_s.h index d11a1ec29..f9e2d8039 100644 --- a/src/core/hle/service/nifm/nifm_s.h +++ b/src/core/hle/service/nifm/nifm_s.h | |||
| @@ -4,20 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | 7 | #include "core/hle/service/nifm/nifm.h" |
| 8 | #include "core/hle/service/service.h" | ||
| 9 | 8 | ||
| 10 | namespace Service { | 9 | namespace Service { |
| 11 | namespace NIFM { | 10 | namespace NIFM { |
| 12 | 11 | ||
| 13 | class NIFM_S final : public ServiceFramework<NIFM_S> { | 12 | class NIFM_S final : public Module::Interface { |
| 14 | public: | 13 | public: |
| 15 | NIFM_S(); | 14 | explicit NIFM_S(std::shared_ptr<Module> module); |
| 16 | ~NIFM_S() = default; | ||
| 17 | |||
| 18 | private: | ||
| 19 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); | ||
| 20 | void CreateGeneralService(Kernel::HLERequestContext& ctx); | ||
| 21 | }; | 15 | }; |
| 22 | 16 | ||
| 23 | } // namespace NIFM | 17 | } // namespace NIFM |
diff --git a/src/core/hle/service/nifm/nifm_u.cpp b/src/core/hle/service/nifm/nifm_u.cpp index a5895c13c..44e6f483d 100644 --- a/src/core/hle/service/nifm/nifm_u.cpp +++ b/src/core/hle/service/nifm/nifm_u.cpp | |||
| @@ -2,29 +2,12 @@ | |||
| 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/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/nifm/nifm.h" | ||
| 8 | #include "core/hle/service/nifm/nifm_u.h" | 5 | #include "core/hle/service/nifm/nifm_u.h" |
| 9 | 6 | ||
| 10 | namespace Service { | 7 | namespace Service { |
| 11 | namespace NIFM { | 8 | namespace NIFM { |
| 12 | 9 | ||
| 13 | void NIFM_U::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { | 10 | NIFM_U::NIFM_U(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "nifm:u") { |
| 14 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 15 | rb.Push(RESULT_SUCCESS); | ||
| 16 | rb.PushIpcInterface<IGeneralService>(); | ||
| 17 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 18 | } | ||
| 19 | |||
| 20 | void NIFM_U::CreateGeneralService(Kernel::HLERequestContext& ctx) { | ||
| 21 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 22 | rb.Push(RESULT_SUCCESS); | ||
| 23 | rb.PushIpcInterface<IGeneralService>(); | ||
| 24 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 25 | } | ||
| 26 | |||
| 27 | NIFM_U::NIFM_U() : ServiceFramework("nifm:u") { | ||
| 28 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 29 | {4, &NIFM_U::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, | 12 | {4, &NIFM_U::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, |
| 30 | {5, &NIFM_U::CreateGeneralService, "CreateGeneralService"}, | 13 | {5, &NIFM_U::CreateGeneralService, "CreateGeneralService"}, |
diff --git a/src/core/hle/service/nifm/nifm_u.h b/src/core/hle/service/nifm/nifm_u.h index da40b604f..912006775 100644 --- a/src/core/hle/service/nifm/nifm_u.h +++ b/src/core/hle/service/nifm/nifm_u.h | |||
| @@ -4,20 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | 7 | #include "core/hle/service/nifm/nifm.h" |
| 8 | #include "core/hle/service/service.h" | ||
| 9 | 8 | ||
| 10 | namespace Service { | 9 | namespace Service { |
| 11 | namespace NIFM { | 10 | namespace NIFM { |
| 12 | 11 | ||
| 13 | class NIFM_U final : public ServiceFramework<NIFM_U> { | 12 | class NIFM_U final : public Module::Interface { |
| 14 | public: | 13 | public: |
| 15 | NIFM_U(); | 14 | explicit NIFM_U(std::shared_ptr<Module> module); |
| 16 | ~NIFM_U() = default; | ||
| 17 | |||
| 18 | private: | ||
| 19 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx); | ||
| 20 | void CreateGeneralService(Kernel::HLERequestContext& ctx); | ||
| 21 | }; | 15 | }; |
| 22 | 16 | ||
| 23 | } // namespace NIFM | 17 | } // namespace NIFM |
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp new file mode 100644 index 000000000..45681c50f --- /dev/null +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/ns/ns.h" | ||
| 6 | #include "core/hle/service/ns/pl_u.h" | ||
| 7 | |||
| 8 | namespace Service { | ||
| 9 | namespace NS { | ||
| 10 | |||
| 11 | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||
| 12 | std::make_shared<PL_U>()->InstallAsService(service_manager); | ||
| 13 | } | ||
| 14 | |||
| 15 | } // namespace NS | ||
| 16 | } // namespace Service | ||
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h new file mode 100644 index 000000000..a4b7e3ded --- /dev/null +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace NS { | ||
| 11 | |||
| 12 | /// Registers all NS services with the specified service manager. | ||
| 13 | void InstallInterfaces(SM::ServiceManager& service_manager); | ||
| 14 | |||
| 15 | } // namespace NS | ||
| 16 | } // namespace Service | ||
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp new file mode 100644 index 000000000..695e295ca --- /dev/null +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_paths.h" | ||
| 6 | #include "common/file_util.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 9 | #include "core/hle/service/ns/pl_u.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace NS { | ||
| 13 | |||
| 14 | struct FontRegion { | ||
| 15 | u32 offset; | ||
| 16 | u32 size; | ||
| 17 | }; | ||
| 18 | |||
| 19 | // The below data is specific to shared font data dumped from Switch on f/w 2.2 | ||
| 20 | // Virtual address and offsets/sizes likely will vary by dump | ||
| 21 | static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; | ||
| 22 | static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; | ||
| 23 | static constexpr std::array<FontRegion, 6> SHARED_FONT_REGIONS{ | ||
| 24 | FontRegion{0x00000008, 0x001fe764}, FontRegion{0x001fe774, 0x00773e58}, | ||
| 25 | FontRegion{0x009725d4, 0x0001aca8}, FontRegion{0x0098d284, 0x00369cec}, | ||
| 26 | FontRegion{0x00cf6f78, 0x0039b858}, FontRegion{0x010927d8, 0x00019e80}, | ||
| 27 | }; | ||
| 28 | |||
| 29 | enum class LoadState : u32 { | ||
| 30 | Loading = 0, | ||
| 31 | Done = 1, | ||
| 32 | }; | ||
| 33 | |||
| 34 | PL_U::PL_U() : ServiceFramework("pl:u") { | ||
| 35 | static const FunctionInfo functions[] = { | ||
| 36 | {1, &PL_U::GetLoadState, "GetLoadState"}, | ||
| 37 | {2, &PL_U::GetSize, "GetSize"}, | ||
| 38 | {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, | ||
| 39 | {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}}; | ||
| 40 | RegisterHandlers(functions); | ||
| 41 | |||
| 42 | // Attempt to load shared font data from disk | ||
| 43 | const std::string filepath{FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT}; | ||
| 44 | FileUtil::CreateFullPath(filepath); // Create path if not already created | ||
| 45 | FileUtil::IOFile file(filepath, "rb"); | ||
| 46 | |||
| 47 | if (file.IsOpen()) { | ||
| 48 | // Read shared font data | ||
| 49 | ASSERT(file.GetSize() == SHARED_FONT_MEM_SIZE); | ||
| 50 | shared_font = std::make_shared<std::vector<u8>>(static_cast<size_t>(file.GetSize())); | ||
| 51 | file.ReadBytes(shared_font->data(), shared_font->size()); | ||
| 52 | } else { | ||
| 53 | LOG_WARNING(Service_NS, "Unable to load shared font: %s", filepath.c_str()); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { | ||
| 58 | IPC::RequestParser rp{ctx}; | ||
| 59 | const u32 font_id{rp.Pop<u32>()}; | ||
| 60 | |||
| 61 | LOG_DEBUG(Service_NS, "called, font_id=%d", font_id); | ||
| 62 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 63 | rb.Push(RESULT_SUCCESS); | ||
| 64 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); | ||
| 65 | } | ||
| 66 | |||
| 67 | void PL_U::GetSize(Kernel::HLERequestContext& ctx) { | ||
| 68 | IPC::RequestParser rp{ctx}; | ||
| 69 | const u32 font_id{rp.Pop<u32>()}; | ||
| 70 | |||
| 71 | LOG_DEBUG(Service_NS, "called, font_id=%d", font_id); | ||
| 72 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 73 | rb.Push(RESULT_SUCCESS); | ||
| 74 | rb.Push<u32>(SHARED_FONT_REGIONS[font_id].size); | ||
| 75 | } | ||
| 76 | |||
| 77 | void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | ||
| 78 | IPC::RequestParser rp{ctx}; | ||
| 79 | const u32 font_id{rp.Pop<u32>()}; | ||
| 80 | |||
| 81 | LOG_DEBUG(Service_NS, "called, font_id=%d", font_id); | ||
| 82 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 83 | rb.Push(RESULT_SUCCESS); | ||
| 84 | rb.Push<u32>(SHARED_FONT_REGIONS[font_id].offset); | ||
| 85 | } | ||
| 86 | |||
| 87 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | ||
| 88 | if (shared_font != nullptr) { | ||
| 89 | // TODO(bunnei): This is a less-than-ideal solution to load a RAM dump of the Switch shared | ||
| 90 | // font data. This (likely) relies on exact address, size, and offsets from the original | ||
| 91 | // dump. In the future, we need to replace this with a more robust solution. | ||
| 92 | |||
| 93 | // Map backing memory for the font data | ||
| 94 | Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, shared_font, 0, | ||
| 95 | SHARED_FONT_MEM_SIZE, | ||
| 96 | Kernel::MemoryState::Shared); | ||
| 97 | |||
| 98 | // Create shared font memory object | ||
| 99 | shared_font_mem = Kernel::SharedMemory::Create( | ||
| 100 | Core::CurrentProcess(), SHARED_FONT_MEM_SIZE, Kernel::MemoryPermission::ReadWrite, | ||
| 101 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, | ||
| 102 | "PL_U:shared_font_mem"); | ||
| 103 | } | ||
| 104 | |||
| 105 | LOG_DEBUG(Service_NS, "called"); | ||
| 106 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 107 | rb.Push(RESULT_SUCCESS); | ||
| 108 | rb.PushCopyObjects(shared_font_mem); | ||
| 109 | } | ||
| 110 | |||
| 111 | } // namespace NS | ||
| 112 | } // namespace Service | ||
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h new file mode 100644 index 000000000..7a4766338 --- /dev/null +++ b/src/core/hle/service/ns/pl_u.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/hle/kernel/shared_memory.h" | ||
| 9 | #include "core/hle/service/service.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace NS { | ||
| 13 | |||
| 14 | class PL_U final : public ServiceFramework<PL_U> { | ||
| 15 | public: | ||
| 16 | PL_U(); | ||
| 17 | ~PL_U() = default; | ||
| 18 | |||
| 19 | private: | ||
| 20 | void GetLoadState(Kernel::HLERequestContext& ctx); | ||
| 21 | void GetSize(Kernel::HLERequestContext& ctx); | ||
| 22 | void GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx); | ||
| 23 | void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); | ||
| 24 | |||
| 25 | /// Handle to shared memory region designated for a shared font | ||
| 26 | Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | ||
| 27 | |||
| 28 | /// Backing memory for the shared font data | ||
| 29 | std::shared_ptr<std::vector<u8>> shared_font; | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace NS | ||
| 33 | } // namespace Service | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index ee99ab280..45711d686 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | |||
| @@ -17,6 +17,8 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector< | |||
| 17 | switch (static_cast<IoctlCommand>(command.raw)) { | 17 | switch (static_cast<IoctlCommand>(command.raw)) { |
| 18 | case IoctlCommand::IocGetConfigCommand: | 18 | case IoctlCommand::IocGetConfigCommand: |
| 19 | return NvOsGetConfigU32(input, output); | 19 | return NvOsGetConfigU32(input, output); |
| 20 | case IoctlCommand::IocCtrlEventWaitCommand: | ||
| 21 | return IocCtrlEventWait(input, output); | ||
| 20 | } | 22 | } |
| 21 | UNIMPLEMENTED(); | 23 | UNIMPLEMENTED(); |
| 22 | return 0; | 24 | return 0; |
| @@ -45,6 +47,18 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& | |||
| 45 | return 0; | 47 | return 0; |
| 46 | } | 48 | } |
| 47 | 49 | ||
| 50 | u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 51 | IocCtrlEventWaitParams params{}; | ||
| 52 | std::memcpy(¶ms, input.data(), sizeof(params)); | ||
| 53 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, syncpt_id=%u threshold=%u timeout=%d", | ||
| 54 | params.syncpt_id, params.threshold, params.timeout); | ||
| 55 | |||
| 56 | // TODO(Subv): Implement actual syncpt waiting. | ||
| 57 | params.value = 0; | ||
| 58 | std::memcpy(output.data(), ¶ms, sizeof(params)); | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 48 | } // namespace Devices | 62 | } // namespace Devices |
| 49 | } // namespace Nvidia | 63 | } // namespace Nvidia |
| 50 | } // namespace Service | 64 | } // namespace Service |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index fd02a5e45..0ca01aa6d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | |||
| @@ -31,6 +31,7 @@ private: | |||
| 31 | IocModuleRegRDWRCommand = 0xC008010E, | 31 | IocModuleRegRDWRCommand = 0xC008010E, |
| 32 | IocSyncptWaitexCommand = 0xC0100019, | 32 | IocSyncptWaitexCommand = 0xC0100019, |
| 33 | IocSyncptReadMaxCommand = 0xC008001A, | 33 | IocSyncptReadMaxCommand = 0xC008001A, |
| 34 | IocCtrlEventWaitCommand = 0xC010001D, | ||
| 34 | IocGetConfigCommand = 0xC183001B, | 35 | IocGetConfigCommand = 0xC183001B, |
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| @@ -41,7 +42,17 @@ private: | |||
| 41 | }; | 42 | }; |
| 42 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); | 43 | static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); |
| 43 | 44 | ||
| 45 | struct IocCtrlEventWaitParams { | ||
| 46 | u32_le syncpt_id; | ||
| 47 | u32_le threshold; | ||
| 48 | s32_le timeout; | ||
| 49 | u32_le value; | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); | ||
| 52 | |||
| 44 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); | 53 | u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); |
| 54 | |||
| 55 | u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 45 | }; | 56 | }; |
| 46 | 57 | ||
| 47 | } // namespace Devices | 58 | } // namespace Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index cd8c0c605..b3842eb4c 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -103,11 +103,8 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 103 | [&](const auto& entry) { return entry.second->id == params.id; }); | 103 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| 104 | ASSERT(itr != handles.end()); | 104 | ASSERT(itr != handles.end()); |
| 105 | 105 | ||
| 106 | // Make a new handle for the object | 106 | // Return the existing handle instead of creating a new one. |
| 107 | u32 handle = next_handle++; | 107 | params.handle = itr->first; |
| 108 | handles[handle] = itr->second; | ||
| 109 | |||
| 110 | params.handle = handle; | ||
| 111 | 108 | ||
| 112 | std::memcpy(output.data(), ¶ms, sizeof(params)); | 109 | std::memcpy(output.data(), ¶ms, sizeof(params)); |
| 113 | return 0; | 110 | return 0; |
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 1a5efaeaf..c70370f1f 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -15,9 +15,8 @@ namespace Nvidia { | |||
| 15 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { | 15 | void NVDRV::Open(Kernel::HLERequestContext& ctx) { |
| 16 | LOG_DEBUG(Service_NVDRV, "called"); | 16 | LOG_DEBUG(Service_NVDRV, "called"); |
| 17 | 17 | ||
| 18 | auto buffer = ctx.BufferDescriptorA()[0]; | 18 | const auto& buffer = ctx.ReadBuffer(); |
| 19 | 19 | std::string device_name(buffer.begin(), buffer.end()); | |
| 20 | std::string device_name = Memory::ReadCString(buffer.Address(), buffer.Size()); | ||
| 21 | 20 | ||
| 22 | u32 fd = nvdrv->Open(device_name); | 21 | u32 fd = nvdrv->Open(device_name); |
| 23 | IPC::ResponseBuilder rb{ctx, 4}; | 22 | IPC::ResponseBuilder rb{ctx, 4}; |
| @@ -33,25 +32,13 @@ void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) { | |||
| 33 | u32 fd = rp.Pop<u32>(); | 32 | u32 fd = rp.Pop<u32>(); |
| 34 | u32 command = rp.Pop<u32>(); | 33 | u32 command = rp.Pop<u32>(); |
| 35 | 34 | ||
| 35 | std::vector<u8> output(ctx.GetWriteBufferSize()); | ||
| 36 | |||
| 36 | IPC::ResponseBuilder rb{ctx, 3}; | 37 | IPC::ResponseBuilder rb{ctx, 3}; |
| 37 | rb.Push(RESULT_SUCCESS); | 38 | rb.Push(RESULT_SUCCESS); |
| 38 | if (ctx.BufferDescriptorA()[0].Size() != 0) { | 39 | rb.Push(nvdrv->Ioctl(fd, command, ctx.ReadBuffer(), output)); |
| 39 | auto input_buffer = ctx.BufferDescriptorA()[0]; | 40 | |
| 40 | auto output_buffer = ctx.BufferDescriptorB()[0]; | 41 | ctx.WriteBuffer(output); |
| 41 | std::vector<u8> input(input_buffer.Size()); | ||
| 42 | std::vector<u8> output(output_buffer.Size()); | ||
| 43 | Memory::ReadBlock(input_buffer.Address(), input.data(), input_buffer.Size()); | ||
| 44 | rb.Push(nvdrv->Ioctl(fd, command, input, output)); | ||
| 45 | Memory::WriteBlock(output_buffer.Address(), output.data(), output_buffer.Size()); | ||
| 46 | } else { | ||
| 47 | auto input_buffer = ctx.BufferDescriptorX()[0]; | ||
| 48 | auto output_buffer = ctx.BufferDescriptorC()[0]; | ||
| 49 | std::vector<u8> input(input_buffer.size); | ||
| 50 | std::vector<u8> output(output_buffer.size); | ||
| 51 | Memory::ReadBlock(input_buffer.Address(), input.data(), input_buffer.size); | ||
| 52 | rb.Push(nvdrv->Ioctl(fd, command, input, output)); | ||
| 53 | Memory::WriteBlock(output_buffer.Address(), output.data(), output_buffer.size); | ||
| 54 | } | ||
| 55 | } | 42 | } |
| 56 | 43 | ||
| 57 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { | 44 | void NVDRV::Close(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index e44644624..6a55ff96d 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -17,6 +17,13 @@ namespace Devices { | |||
| 17 | class nvdevice; | 17 | class nvdevice; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | struct IoctlFence { | ||
| 21 | u32 id; | ||
| 22 | u32 value; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size"); | ||
| 26 | |||
| 20 | class Module final { | 27 | class Module final { |
| 21 | public: | 28 | public: |
| 22 | Module(); | 29 | Module(); |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index ff7b6b039..e4ff2e267 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -26,26 +26,30 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { | |||
| 26 | LOG_WARNING(Service, "Adding graphics buffer %u", slot); | 26 | LOG_WARNING(Service, "Adding graphics buffer %u", slot); |
| 27 | 27 | ||
| 28 | queue.emplace_back(buffer); | 28 | queue.emplace_back(buffer); |
| 29 | |||
| 30 | if (buffer_wait_event) { | ||
| 31 | buffer_wait_event->Signal(); | ||
| 32 | } | ||
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { | 35 | boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { |
| 32 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { | 36 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { |
| 33 | // Only consider free buffers. Buffers become free once again after they've been Acquired | 37 | // Only consider free buffers. Buffers become free once again after they've been Acquired |
| 34 | // and Released by the compositor, see the NVFlinger::Compose method. | 38 | // and Released by the compositor, see the NVFlinger::Compose method. |
| 35 | if (buffer.status != Buffer::Status::Free) | 39 | if (buffer.status != Buffer::Status::Free) { |
| 36 | return false; | 40 | return false; |
| 41 | } | ||
| 37 | 42 | ||
| 38 | // Make sure that the parameters match. | 43 | // Make sure that the parameters match. |
| 39 | auto& igbp_buffer = buffer.igbp_buffer; | 44 | return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height; |
| 40 | return igbp_buffer.format == pixel_format && igbp_buffer.width == width && | ||
| 41 | igbp_buffer.height == height; | ||
| 42 | }); | 45 | }); |
| 46 | |||
| 43 | if (itr == queue.end()) { | 47 | if (itr == queue.end()) { |
| 44 | LOG_CRITICAL(Service_NVDRV, "no free buffers for pixel_format=%d, width=%d, height=%d", | 48 | return boost::none; |
| 45 | pixel_format, width, height); | ||
| 46 | itr = queue.begin(); | ||
| 47 | } | 49 | } |
| 48 | 50 | ||
| 51 | buffer_wait_event = nullptr; | ||
| 52 | |||
| 49 | itr->status = Buffer::Status::Dequeued; | 53 | itr->status = Buffer::Status::Dequeued; |
| 50 | return itr->slot; | 54 | return itr->slot; |
| 51 | } | 55 | } |
| @@ -83,6 +87,10 @@ void BufferQueue::ReleaseBuffer(u32 slot) { | |||
| 83 | ASSERT(itr != queue.end()); | 87 | ASSERT(itr != queue.end()); |
| 84 | ASSERT(itr->status == Buffer::Status::Acquired); | 88 | ASSERT(itr->status == Buffer::Status::Acquired); |
| 85 | itr->status = Buffer::Status::Free; | 89 | itr->status = Buffer::Status::Free; |
| 90 | |||
| 91 | if (buffer_wait_event) { | ||
| 92 | buffer_wait_event->Signal(); | ||
| 93 | } | ||
| 86 | } | 94 | } |
| 87 | 95 | ||
| 88 | u32 BufferQueue::Query(QueryType type) { | 96 | u32 BufferQueue::Query(QueryType type) { |
| @@ -98,5 +106,10 @@ u32 BufferQueue::Query(QueryType type) { | |||
| 98 | return 0; | 106 | return 0; |
| 99 | } | 107 | } |
| 100 | 108 | ||
| 109 | void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event) { | ||
| 110 | ASSERT_MSG(!buffer_wait_event, "buffer_wait_event only supports a single waiting thread!"); | ||
| 111 | buffer_wait_event = std::move(wait_event); | ||
| 112 | } | ||
| 113 | |||
| 101 | } // namespace NVFlinger | 114 | } // namespace NVFlinger |
| 102 | } // namespace Service | 115 | } // namespace Service |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index ef9732769..686eadca7 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -69,12 +69,13 @@ public: | |||
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); | 71 | void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); |
| 72 | u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); | 72 | boost::optional<u32> DequeueBuffer(u32 width, u32 height); |
| 73 | const IGBPBuffer& RequestBuffer(u32 slot) const; | 73 | const IGBPBuffer& RequestBuffer(u32 slot) const; |
| 74 | void QueueBuffer(u32 slot, BufferTransformFlags transform); | 74 | void QueueBuffer(u32 slot, BufferTransformFlags transform); |
| 75 | boost::optional<const Buffer&> AcquireBuffer(); | 75 | boost::optional<const Buffer&> AcquireBuffer(); |
| 76 | void ReleaseBuffer(u32 slot); | 76 | void ReleaseBuffer(u32 slot); |
| 77 | u32 Query(QueryType type); | 77 | u32 Query(QueryType type); |
| 78 | void SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_event); | ||
| 78 | 79 | ||
| 79 | u32 GetId() const { | 80 | u32 GetId() const { |
| 80 | return id; | 81 | return id; |
| @@ -90,6 +91,9 @@ private: | |||
| 90 | 91 | ||
| 91 | std::vector<Buffer> queue; | 92 | std::vector<Buffer> queue; |
| 92 | Kernel::SharedPtr<Kernel::Event> native_handle; | 93 | Kernel::SharedPtr<Kernel::Event> native_handle; |
| 94 | |||
| 95 | /// Used to signal waiting thread when no buffers are available | ||
| 96 | Kernel::SharedPtr<Kernel::Event> buffer_wait_event; | ||
| 93 | }; | 97 | }; |
| 94 | 98 | ||
| 95 | } // namespace NVFlinger | 99 | } // namespace NVFlinger |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 2089462b7..0d30f54dc 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/alignment.h" | 7 | #include "common/alignment.h" |
| 8 | #include "common/scope_exit.h" | 8 | #include "common/scope_exit.h" |
| 9 | #include "core/core.h" | ||
| 9 | #include "core/core_timing.h" | 10 | #include "core/core_timing.h" |
| 10 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | 11 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" |
| 11 | #include "core/hle/service/nvdrv/nvdrv.h" | 12 | #include "core/hle/service/nvdrv/nvdrv.h" |
| @@ -129,6 +130,7 @@ void NVFlinger::Compose() { | |||
| 129 | 130 | ||
| 130 | if (buffer == boost::none) { | 131 | if (buffer == boost::none) { |
| 131 | // There was no queued buffer to draw, render previous frame | 132 | // There was no queued buffer to draw, render previous frame |
| 133 | Core::System::GetInstance().perf_stats.EndGameFrame(); | ||
| 132 | VideoCore::g_renderer->SwapBuffers({}); | 134 | VideoCore::g_renderer->SwapBuffers({}); |
| 133 | continue; | 135 | continue; |
| 134 | } | 136 | } |
| @@ -148,6 +150,9 @@ void NVFlinger::Compose() { | |||
| 148 | igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform); | 150 | igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform); |
| 149 | 151 | ||
| 150 | buffer_queue->ReleaseBuffer(buffer->slot); | 152 | buffer_queue->ReleaseBuffer(buffer->slot); |
| 153 | |||
| 154 | // TODO(Subv): Figure out when we should actually signal this event. | ||
| 155 | buffer_queue->GetNativeHandle()->Signal(); | ||
| 151 | } | 156 | } |
| 152 | } | 157 | } |
| 153 | 158 | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 1dd04a12f..a1ca8a033 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/string_util.h" | 9 | #include "common/string_util.h" |
| 10 | #include "core/core.h" | ||
| 10 | #include "core/hle/ipc.h" | 11 | #include "core/hle/ipc.h" |
| 11 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 12 | #include "core/hle/kernel/client_port.h" | 13 | #include "core/hle/kernel/client_port.h" |
| @@ -20,13 +21,15 @@ | |||
| 20 | #include "core/hle/service/apm/apm.h" | 21 | #include "core/hle/service/apm/apm.h" |
| 21 | #include "core/hle/service/audio/audio.h" | 22 | #include "core/hle/service/audio/audio.h" |
| 22 | #include "core/hle/service/filesystem/filesystem.h" | 23 | #include "core/hle/service/filesystem/filesystem.h" |
| 24 | #include "core/hle/service/friend/friend.h" | ||
| 23 | #include "core/hle/service/hid/hid.h" | 25 | #include "core/hle/service/hid/hid.h" |
| 24 | #include "core/hle/service/lm/lm.h" | 26 | #include "core/hle/service/lm/lm.h" |
| 25 | #include "core/hle/service/nifm/nifm.h" | 27 | #include "core/hle/service/nifm/nifm.h" |
| 28 | #include "core/hle/service/ns/ns.h" | ||
| 26 | #include "core/hle/service/nvdrv/nvdrv.h" | 29 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 27 | #include "core/hle/service/pctl/pctl.h" | 30 | #include "core/hle/service/pctl/pctl.h" |
| 28 | #include "core/hle/service/service.h" | 31 | #include "core/hle/service/service.h" |
| 29 | #include "core/hle/service/set/set.h" | 32 | #include "core/hle/service/set/settings.h" |
| 30 | #include "core/hle/service/sm/controller.h" | 33 | #include "core/hle/service/sm/controller.h" |
| 31 | #include "core/hle/service/sm/sm.h" | 34 | #include "core/hle/service/sm/sm.h" |
| 32 | #include "core/hle/service/sockets/sockets.h" | 35 | #include "core/hle/service/sockets/sockets.h" |
| @@ -149,9 +152,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co | |||
| 149 | UNIMPLEMENTED_MSG("command_type=%d", context.GetCommandType()); | 152 | UNIMPLEMENTED_MSG("command_type=%d", context.GetCommandType()); |
| 150 | } | 153 | } |
| 151 | 154 | ||
| 152 | u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); | 155 | context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread()); |
| 153 | context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process, | ||
| 154 | Kernel::g_handle_table); | ||
| 155 | 156 | ||
| 156 | return RESULT_SUCCESS; | 157 | return RESULT_SUCCESS; |
| 157 | } | 158 | } |
| @@ -179,9 +180,11 @@ void Init() { | |||
| 179 | APM::InstallInterfaces(*SM::g_service_manager); | 180 | APM::InstallInterfaces(*SM::g_service_manager); |
| 180 | Audio::InstallInterfaces(*SM::g_service_manager); | 181 | Audio::InstallInterfaces(*SM::g_service_manager); |
| 181 | FileSystem::InstallInterfaces(*SM::g_service_manager); | 182 | FileSystem::InstallInterfaces(*SM::g_service_manager); |
| 183 | Friend::InstallInterfaces(*SM::g_service_manager); | ||
| 182 | HID::InstallInterfaces(*SM::g_service_manager); | 184 | HID::InstallInterfaces(*SM::g_service_manager); |
| 183 | LM::InstallInterfaces(*SM::g_service_manager); | 185 | LM::InstallInterfaces(*SM::g_service_manager); |
| 184 | NIFM::InstallInterfaces(*SM::g_service_manager); | 186 | NIFM::InstallInterfaces(*SM::g_service_manager); |
| 187 | NS::InstallInterfaces(*SM::g_service_manager); | ||
| 185 | Nvidia::InstallInterfaces(*SM::g_service_manager); | 188 | Nvidia::InstallInterfaces(*SM::g_service_manager); |
| 186 | PCTL::InstallInterfaces(*SM::g_service_manager); | 189 | PCTL::InstallInterfaces(*SM::g_service_manager); |
| 187 | Sockets::InstallInterfaces(*SM::g_service_manager); | 190 | Sockets::InstallInterfaces(*SM::g_service_manager); |
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 1062ba8b3..aa7c924e7 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -17,9 +17,7 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | |||
| 17 | u32 id = rp.Pop<u32>(); | 17 | u32 id = rp.Pop<u32>(); |
| 18 | constexpr std::array<u8, 13> lang_codes{}; | 18 | constexpr std::array<u8, 13> lang_codes{}; |
| 19 | 19 | ||
| 20 | const auto& output_buffer = ctx.BufferDescriptorC()[0]; | 20 | ctx.WriteBuffer(lang_codes.data(), lang_codes.size()); |
| 21 | |||
| 22 | Memory::WriteBlock(output_buffer.Address(), lang_codes.data(), lang_codes.size()); | ||
| 23 | 21 | ||
| 24 | IPC::ResponseBuilder rb{ctx, 2}; | 22 | IPC::ResponseBuilder rb{ctx, 2}; |
| 25 | 23 | ||
| @@ -28,16 +26,19 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | |||
| 28 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 26 | LOG_WARNING(Service_SET, "(STUBBED) called"); |
| 29 | } | 27 | } |
| 30 | 28 | ||
| 31 | SET::SET(const char* name) : ServiceFramework(name) { | 29 | SET::SET() : ServiceFramework("set") { |
| 32 | static const FunctionInfo functions[] = { | 30 | static const FunctionInfo functions[] = { |
| 31 | {0, nullptr, "GetLanguageCode"}, | ||
| 33 | {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, | 32 | {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, |
| 33 | {2, nullptr, "MakeLanguageCode"}, | ||
| 34 | {3, nullptr, "GetAvailableLanguageCodeCount"}, | ||
| 35 | {4, nullptr, "GetRegionCode"}, | ||
| 36 | {5, nullptr, "GetAvailableLanguageCodes2"}, | ||
| 37 | {6, nullptr, "GetAvailableLanguageCodeCount2"}, | ||
| 38 | {7, nullptr, "GetKeyCodeMap"}, | ||
| 34 | }; | 39 | }; |
| 35 | RegisterHandlers(functions); | 40 | RegisterHandlers(functions); |
| 36 | } | 41 | } |
| 37 | 42 | ||
| 38 | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||
| 39 | std::make_shared<SET>("set")->InstallAsService(service_manager); | ||
| 40 | } | ||
| 41 | |||
| 42 | } // namespace Set | 43 | } // namespace Set |
| 43 | } // namespace Service | 44 | } // namespace Service |
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 61e957946..7b7814ed1 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h | |||
| @@ -11,15 +11,12 @@ namespace Set { | |||
| 11 | 11 | ||
| 12 | class SET final : public ServiceFramework<SET> { | 12 | class SET final : public ServiceFramework<SET> { |
| 13 | public: | 13 | public: |
| 14 | explicit SET(const char* name); | 14 | explicit SET(); |
| 15 | ~SET() = default; | 15 | ~SET() = default; |
| 16 | 16 | ||
| 17 | private: | 17 | private: |
| 18 | void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); | 18 | void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | /// Registers all Set services with the specified service manager. | ||
| 22 | void InstallInterfaces(SM::ServiceManager& service_manager); | ||
| 23 | |||
| 24 | } // namespace Set | 21 | } // namespace Set |
| 25 | } // namespace Service | 22 | } // namespace Service |
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp new file mode 100644 index 000000000..6231acd96 --- /dev/null +++ b/src/core/hle/service/set/set_cal.cpp | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/set/set_cal.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace Set { | ||
| 9 | |||
| 10 | SET_CAL::SET_CAL() : ServiceFramework("set:cal") { | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {0, nullptr, "GetBluetoothBdAddress"}, | ||
| 13 | {1, nullptr, "GetConfigurationId1"}, | ||
| 14 | {2, nullptr, "GetAccelerometerOffset"}, | ||
| 15 | {3, nullptr, "GetAccelerometerScale"}, | ||
| 16 | {4, nullptr, "GetGyroscopeOffset"}, | ||
| 17 | {5, nullptr, "GetGyroscopeScale"}, | ||
| 18 | {6, nullptr, "GetWirelessLanMacAddress"}, | ||
| 19 | {7, nullptr, "GetWirelessLanCountryCodeCount"}, | ||
| 20 | {8, nullptr, "GetWirelessLanCountryCodes"}, | ||
| 21 | {9, nullptr, "GetSerialNumber"}, | ||
| 22 | {10, nullptr, "SetInitialSystemAppletProgramId"}, | ||
| 23 | {11, nullptr, "SetOverlayDispProgramId"}, | ||
| 24 | {12, nullptr, "GetBatteryLot"}, | ||
| 25 | {14, nullptr, "GetEciDeviceCertificate"}, | ||
| 26 | {15, nullptr, "GetEticketDeviceCertificate"}, | ||
| 27 | {16, nullptr, "GetSslKey"}, | ||
| 28 | {17, nullptr, "GetSslCertificate"}, | ||
| 29 | {18, nullptr, "GetGameCardKey"}, | ||
| 30 | {19, nullptr, "GetGameCardCertificate"}, | ||
| 31 | {20, nullptr, "GetEciDeviceKey"}, | ||
| 32 | {21, nullptr, "GetEticketDeviceKey"}, | ||
| 33 | {22, nullptr, "GetSpeakerParameter"}, | ||
| 34 | {23, nullptr, "GetLcdVendorId"}, | ||
| 35 | }; | ||
| 36 | RegisterHandlers(functions); | ||
| 37 | } | ||
| 38 | |||
| 39 | } // namespace Set | ||
| 40 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h new file mode 100644 index 000000000..9c0b851d0 --- /dev/null +++ b/src/core/hle/service/set/set_cal.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace Set { | ||
| 11 | |||
| 12 | class SET_CAL final : public ServiceFramework<SET_CAL> { | ||
| 13 | public: | ||
| 14 | explicit SET_CAL(); | ||
| 15 | ~SET_CAL() = default; | ||
| 16 | }; | ||
| 17 | |||
| 18 | } // namespace Set | ||
| 19 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp new file mode 100644 index 000000000..8320d4250 --- /dev/null +++ b/src/core/hle/service/set/set_fd.cpp | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/set/set_fd.h" | ||
| 6 | |||
| 7 | namespace Service { | ||
| 8 | namespace Set { | ||
| 9 | |||
| 10 | SET_FD::SET_FD() : ServiceFramework("set:fd") { | ||
| 11 | static const FunctionInfo functions[] = { | ||
| 12 | {2, nullptr, "SetSettingsItemValue"}, | ||
| 13 | {3, nullptr, "ResetSettingsItemValue"}, | ||
| 14 | {4, nullptr, "CreateSettingsItemKeyIterator"}, | ||
| 15 | {10, nullptr, "ReadSettings"}, | ||
| 16 | {11, nullptr, "ResetSettings"}, | ||
| 17 | {20, nullptr, "SetWebInspectorFlag"}, | ||
| 18 | {21, nullptr, "SetAllowedSslHosts"}, | ||
| 19 | {22, nullptr, "SetHostFsMountPoint"}, | ||
| 20 | }; | ||
| 21 | RegisterHandlers(functions); | ||
| 22 | } | ||
| 23 | |||
| 24 | } // namespace Set | ||
| 25 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h new file mode 100644 index 000000000..65b36bcb3 --- /dev/null +++ b/src/core/hle/service/set/set_fd.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace Set { | ||
| 11 | |||
| 12 | class SET_FD final : public ServiceFramework<SET_FD> { | ||
| 13 | public: | ||
| 14 | explicit SET_FD(); | ||
| 15 | ~SET_FD() = default; | ||
| 16 | }; | ||
| 17 | |||
| 18 | } // namespace Set | ||
| 19 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp new file mode 100644 index 000000000..363abd10a --- /dev/null +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/kernel/client_port.h" | ||
| 8 | #include "core/hle/service/set/set_sys.h" | ||
| 9 | |||
| 10 | namespace Service { | ||
| 11 | namespace Set { | ||
| 12 | |||
| 13 | void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { | ||
| 14 | |||
| 15 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 16 | |||
| 17 | rb.Push(RESULT_SUCCESS); | ||
| 18 | rb.Push<u32>(0); | ||
| 19 | |||
| 20 | LOG_WARNING(Service_SET, "(STUBBED) called"); | ||
| 21 | } | ||
| 22 | |||
| 23 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | ||
| 24 | static const FunctionInfo functions[] = { | ||
| 25 | {0, nullptr, "SetLanguageCode"}, | ||
| 26 | {1, nullptr, "SetNetworkSettings"}, | ||
| 27 | {2, nullptr, "GetNetworkSettings"}, | ||
| 28 | {3, nullptr, "GetFirmwareVersion"}, | ||
| 29 | {4, nullptr, "GetFirmwareVersion2"}, | ||
| 30 | {7, nullptr, "GetLockScreenFlag"}, | ||
| 31 | {8, nullptr, "SetLockScreenFlag"}, | ||
| 32 | {9, nullptr, "GetBacklightSettings"}, | ||
| 33 | {10, nullptr, "SetBacklightSettings"}, | ||
| 34 | {11, nullptr, "SetBluetoothDevicesSettings"}, | ||
| 35 | {12, nullptr, "GetBluetoothDevicesSettings"}, | ||
| 36 | {13, nullptr, "GetExternalSteadyClockSourceId"}, | ||
| 37 | {14, nullptr, "SetExternalSteadyClockSourceId"}, | ||
| 38 | {15, nullptr, "GetUserSystemClockContext"}, | ||
| 39 | {16, nullptr, "SetUserSystemClockContext"}, | ||
| 40 | {17, nullptr, "GetAccountSettings"}, | ||
| 41 | {18, nullptr, "SetAccountSettings"}, | ||
| 42 | {19, nullptr, "GetAudioVolume"}, | ||
| 43 | {20, nullptr, "SetAudioVolume"}, | ||
| 44 | {21, nullptr, "GetEulaVersions"}, | ||
| 45 | {22, nullptr, "SetEulaVersions"}, | ||
| 46 | {23, &SET_SYS::GetColorSetId, "GetColorSetId"}, | ||
| 47 | {24, nullptr, "SetColorSetId"}, | ||
| 48 | {25, nullptr, "GetConsoleInformationUploadFlag"}, | ||
| 49 | {26, nullptr, "SetConsoleInformationUploadFlag"}, | ||
| 50 | {27, nullptr, "GetAutomaticApplicationDownloadFlag"}, | ||
| 51 | {28, nullptr, "SetAutomaticApplicationDownloadFlag"}, | ||
| 52 | {29, nullptr, "GetNotificationSettings"}, | ||
| 53 | {30, nullptr, "SetNotificationSettings"}, | ||
| 54 | {31, nullptr, "GetAccountNotificationSettings"}, | ||
| 55 | {32, nullptr, "SetAccountNotificationSettings"}, | ||
| 56 | {35, nullptr, "GetVibrationMasterVolume"}, | ||
| 57 | {36, nullptr, "SetVibrationMasterVolume"}, | ||
| 58 | {37, nullptr, "GetSettingsItemValueSize"}, | ||
| 59 | {38, nullptr, "GetSettingsItemValue"}, | ||
| 60 | {39, nullptr, "GetTvSettings"}, | ||
| 61 | {40, nullptr, "SetTvSettings"}, | ||
| 62 | {41, nullptr, "GetEdid"}, | ||
| 63 | {42, nullptr, "SetEdid"}, | ||
| 64 | {43, nullptr, "GetAudioOutputMode"}, | ||
| 65 | {44, nullptr, "SetAudioOutputMode"}, | ||
| 66 | {45, nullptr, "IsForceMuteOnHeadphoneRemoved"}, | ||
| 67 | {46, nullptr, "SetForceMuteOnHeadphoneRemoved"}, | ||
| 68 | {47, nullptr, "GetQuestFlag"}, | ||
| 69 | {48, nullptr, "SetQuestFlag"}, | ||
| 70 | {49, nullptr, "GetDataDeletionSettings"}, | ||
| 71 | {50, nullptr, "SetDataDeletionSettings"}, | ||
| 72 | {51, nullptr, "GetInitialSystemAppletProgramId"}, | ||
| 73 | {52, nullptr, "GetOverlayDispProgramId"}, | ||
| 74 | {53, nullptr, "GetDeviceTimeZoneLocationName"}, | ||
| 75 | {54, nullptr, "SetDeviceTimeZoneLocationName"}, | ||
| 76 | {55, nullptr, "GetWirelessCertificationFileSize"}, | ||
| 77 | {56, nullptr, "GetWirelessCertificationFile"}, | ||
| 78 | {57, nullptr, "SetRegionCode"}, | ||
| 79 | {58, nullptr, "GetNetworkSystemClockContext"}, | ||
| 80 | {59, nullptr, "SetNetworkSystemClockContext"}, | ||
| 81 | {60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 82 | {61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"}, | ||
| 83 | {62, nullptr, "GetDebugModeFlag"}, | ||
| 84 | {63, nullptr, "GetPrimaryAlbumStorage"}, | ||
| 85 | {64, nullptr, "SetPrimaryAlbumStorage"}, | ||
| 86 | {65, nullptr, "GetUsb30EnableFlag"}, | ||
| 87 | {66, nullptr, "SetUsb30EnableFlag"}, | ||
| 88 | {67, nullptr, "GetBatteryLot"}, | ||
| 89 | {68, nullptr, "GetSerialNumber"}, | ||
| 90 | {69, nullptr, "GetNfcEnableFlag"}, | ||
| 91 | {70, nullptr, "SetNfcEnableFlag"}, | ||
| 92 | {71, nullptr, "GetSleepSettings"}, | ||
| 93 | {72, nullptr, "SetSleepSettings"}, | ||
| 94 | {73, nullptr, "GetWirelessLanEnableFlag"}, | ||
| 95 | {74, nullptr, "SetWirelessLanEnableFlag"}, | ||
| 96 | {75, nullptr, "GetInitialLaunchSettings"}, | ||
| 97 | {76, nullptr, "SetInitialLaunchSettings"}, | ||
| 98 | {77, nullptr, "GetDeviceNickName"}, | ||
| 99 | {78, nullptr, "SetDeviceNickName"}, | ||
| 100 | {79, nullptr, "GetProductModel"}, | ||
| 101 | {80, nullptr, "GetLdnChannel"}, | ||
| 102 | {81, nullptr, "SetLdnChannel"}, | ||
| 103 | {82, nullptr, "AcquireTelemetryDirtyFlagEventHandle"}, | ||
| 104 | {83, nullptr, "GetTelemetryDirtyFlags"}, | ||
| 105 | {84, nullptr, "GetPtmBatteryLot"}, | ||
| 106 | {85, nullptr, "SetPtmBatteryLot"}, | ||
| 107 | {86, nullptr, "GetPtmFuelGaugeParameter"}, | ||
| 108 | {87, nullptr, "SetPtmFuelGaugeParameter"}, | ||
| 109 | {88, nullptr, "GetBluetoothEnableFlag"}, | ||
| 110 | {89, nullptr, "SetBluetoothEnableFlag"}, | ||
| 111 | {90, nullptr, "GetMiiAuthorId"}, | ||
| 112 | {91, nullptr, "SetShutdownRtcValue"}, | ||
| 113 | {92, nullptr, "GetShutdownRtcValue"}, | ||
| 114 | {93, nullptr, "AcquireFatalDirtyFlagEventHandle"}, | ||
| 115 | {94, nullptr, "GetFatalDirtyFlags"}, | ||
| 116 | {95, nullptr, "GetAutoUpdateEnableFlag"}, | ||
| 117 | {96, nullptr, "SetAutoUpdateEnableFlag"}, | ||
| 118 | {97, nullptr, "GetNxControllerSettings"}, | ||
| 119 | {98, nullptr, "SetNxControllerSettings"}, | ||
| 120 | {99, nullptr, "GetBatteryPercentageFlag"}, | ||
| 121 | {100, nullptr, "SetBatteryPercentageFlag"}, | ||
| 122 | {101, nullptr, "GetExternalRtcResetFlag"}, | ||
| 123 | {102, nullptr, "SetExternalRtcResetFlag"}, | ||
| 124 | {103, nullptr, "GetUsbFullKeyEnableFlag"}, | ||
| 125 | {104, nullptr, "SetUsbFullKeyEnableFlag"}, | ||
| 126 | {105, nullptr, "SetExternalSteadyClockInternalOffset"}, | ||
| 127 | {106, nullptr, "GetExternalSteadyClockInternalOffset"}, | ||
| 128 | {107, nullptr, "GetBacklightSettingsEx"}, | ||
| 129 | {108, nullptr, "SetBacklightSettingsEx"}, | ||
| 130 | {109, nullptr, "GetHeadphoneVolumeWarningCount"}, | ||
| 131 | {110, nullptr, "SetHeadphoneVolumeWarningCount"}, | ||
| 132 | {111, nullptr, "GetBluetoothAfhEnableFlag"}, | ||
| 133 | {112, nullptr, "SetBluetoothAfhEnableFlag"}, | ||
| 134 | {113, nullptr, "GetBluetoothBoostEnableFlag"}, | ||
| 135 | {114, nullptr, "SetBluetoothBoostEnableFlag"}, | ||
| 136 | {115, nullptr, "GetInRepairProcessEnableFlag"}, | ||
| 137 | {116, nullptr, "SetInRepairProcessEnableFlag"}, | ||
| 138 | {117, nullptr, "GetHeadphoneVolumeUpdateFlag"}, | ||
| 139 | {118, nullptr, "SetHeadphoneVolumeUpdateFlag"}, | ||
| 140 | {119, nullptr, "NeedsToUpdateHeadphoneVolume"}, | ||
| 141 | {120, nullptr, "GetPushNotificationActivityModeOnSleep"}, | ||
| 142 | {121, nullptr, "SetPushNotificationActivityModeOnSleep"}, | ||
| 143 | {122, nullptr, "GetServiceDiscoveryControlSettings"}, | ||
| 144 | {123, nullptr, "SetServiceDiscoveryControlSettings"}, | ||
| 145 | {124, nullptr, "GetErrorReportSharePermission"}, | ||
| 146 | {125, nullptr, "SetErrorReportSharePermission"}, | ||
| 147 | {126, nullptr, "GetAppletLaunchFlags"}, | ||
| 148 | {127, nullptr, "SetAppletLaunchFlags"}, | ||
| 149 | {128, nullptr, "GetConsoleSixAxisSensorAccelerationBias"}, | ||
| 150 | {129, nullptr, "SetConsoleSixAxisSensorAccelerationBias"}, | ||
| 151 | {130, nullptr, "GetConsoleSixAxisSensorAngularVelocityBias"}, | ||
| 152 | {131, nullptr, "SetConsoleSixAxisSensorAngularVelocityBias"}, | ||
| 153 | {132, nullptr, "GetConsoleSixAxisSensorAccelerationGain"}, | ||
| 154 | {133, nullptr, "SetConsoleSixAxisSensorAccelerationGain"}, | ||
| 155 | {134, nullptr, "GetConsoleSixAxisSensorAngularVelocityGain"}, | ||
| 156 | {135, nullptr, "SetConsoleSixAxisSensorAngularVelocityGain"}, | ||
| 157 | {136, nullptr, "GetKeyboardLayout"}, | ||
| 158 | {137, nullptr, "SetKeyboardLayout"}, | ||
| 159 | {138, nullptr, "GetWebInspectorFlag"}, | ||
| 160 | {139, nullptr, "GetAllowedSslHosts"}, | ||
| 161 | {140, nullptr, "GetHostFsMountPoint"}, | ||
| 162 | }; | ||
| 163 | RegisterHandlers(functions); | ||
| 164 | } | ||
| 165 | |||
| 166 | } // namespace Set | ||
| 167 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h new file mode 100644 index 000000000..105f1a3c7 --- /dev/null +++ b/src/core/hle/service/set/set_sys.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace Set { | ||
| 11 | |||
| 12 | class SET_SYS final : public ServiceFramework<SET_SYS> { | ||
| 13 | public: | ||
| 14 | explicit SET_SYS(); | ||
| 15 | ~SET_SYS() = default; | ||
| 16 | |||
| 17 | private: | ||
| 18 | void GetColorSetId(Kernel::HLERequestContext& ctx); | ||
| 19 | }; | ||
| 20 | |||
| 21 | } // namespace Set | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp new file mode 100644 index 000000000..c6bc9e240 --- /dev/null +++ b/src/core/hle/service/set/settings.cpp | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/set/set.h" | ||
| 6 | #include "core/hle/service/set/set_cal.h" | ||
| 7 | #include "core/hle/service/set/set_fd.h" | ||
| 8 | #include "core/hle/service/set/set_sys.h" | ||
| 9 | #include "core/hle/service/set/settings.h" | ||
| 10 | |||
| 11 | namespace Service { | ||
| 12 | namespace Set { | ||
| 13 | |||
| 14 | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||
| 15 | std::make_shared<SET>()->InstallAsService(service_manager); | ||
| 16 | std::make_shared<SET_CAL>()->InstallAsService(service_manager); | ||
| 17 | std::make_shared<SET_FD>()->InstallAsService(service_manager); | ||
| 18 | std::make_shared<SET_SYS>()->InstallAsService(service_manager); | ||
| 19 | } | ||
| 20 | |||
| 21 | } // namespace Set | ||
| 22 | } // namespace Service | ||
diff --git a/src/core/hle/service/set/settings.h b/src/core/hle/service/set/settings.h new file mode 100644 index 000000000..6c8d5a58c --- /dev/null +++ b/src/core/hle/service/set/settings.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace Set { | ||
| 11 | |||
| 12 | /// Registers all Settings services with the specified service manager. | ||
| 13 | void InstallInterfaces(SM::ServiceManager& service_manager); | ||
| 14 | |||
| 15 | } // namespace Set | ||
| 16 | } // namespace Service | ||
diff --git a/src/core/hle/service/sockets/bsd_u.cpp b/src/core/hle/service/sockets/bsd_u.cpp index 629ffb040..2ca1000ca 100644 --- a/src/core/hle/service/sockets/bsd_u.cpp +++ b/src/core/hle/service/sockets/bsd_u.cpp | |||
| @@ -17,6 +17,15 @@ void BSD_U::RegisterClient(Kernel::HLERequestContext& ctx) { | |||
| 17 | rb.Push<u32>(0); // bsd errno | 17 | rb.Push<u32>(0); // bsd errno |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | void BSD_U::StartMonitoring(Kernel::HLERequestContext& ctx) { | ||
| 21 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 22 | |||
| 23 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 24 | |||
| 25 | rb.Push(RESULT_SUCCESS); | ||
| 26 | rb.Push<u32>(0); // bsd errno | ||
| 27 | } | ||
| 28 | |||
| 20 | void BSD_U::Socket(Kernel::HLERequestContext& ctx) { | 29 | void BSD_U::Socket(Kernel::HLERequestContext& ctx) { |
| 21 | IPC::RequestParser rp{ctx}; | 30 | IPC::RequestParser rp{ctx}; |
| 22 | 31 | ||
| @@ -67,6 +76,7 @@ void BSD_U::Close(Kernel::HLERequestContext& ctx) { | |||
| 67 | 76 | ||
| 68 | BSD_U::BSD_U() : ServiceFramework("bsd:u") { | 77 | BSD_U::BSD_U() : ServiceFramework("bsd:u") { |
| 69 | static const FunctionInfo functions[] = {{0, &BSD_U::RegisterClient, "RegisterClient"}, | 78 | static const FunctionInfo functions[] = {{0, &BSD_U::RegisterClient, "RegisterClient"}, |
| 79 | {1, &BSD_U::StartMonitoring, "StartMonitoring"}, | ||
| 70 | {2, &BSD_U::Socket, "Socket"}, | 80 | {2, &BSD_U::Socket, "Socket"}, |
| 71 | {11, &BSD_U::SendTo, "SendTo"}, | 81 | {11, &BSD_U::SendTo, "SendTo"}, |
| 72 | {14, &BSD_U::Connect, "Connect"}, | 82 | {14, &BSD_U::Connect, "Connect"}, |
diff --git a/src/core/hle/service/sockets/bsd_u.h b/src/core/hle/service/sockets/bsd_u.h index fde08a22b..4e1252e9d 100644 --- a/src/core/hle/service/sockets/bsd_u.h +++ b/src/core/hle/service/sockets/bsd_u.h | |||
| @@ -17,6 +17,7 @@ public: | |||
| 17 | 17 | ||
| 18 | private: | 18 | private: |
| 19 | void RegisterClient(Kernel::HLERequestContext& ctx); | 19 | void RegisterClient(Kernel::HLERequestContext& ctx); |
| 20 | void StartMonitoring(Kernel::HLERequestContext& ctx); | ||
| 20 | void Socket(Kernel::HLERequestContext& ctx); | 21 | void Socket(Kernel::HLERequestContext& ctx); |
| 21 | void Connect(Kernel::HLERequestContext& ctx); | 22 | void Connect(Kernel::HLERequestContext& ctx); |
| 22 | void SendTo(Kernel::HLERequestContext& ctx); | 23 | void SendTo(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 364ddcea2..ad49f4265 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -146,6 +146,13 @@ void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | |||
| 146 | LOG_DEBUG(Service_Time, "called"); | 146 | LOG_DEBUG(Service_Time, "called"); |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { | ||
| 150 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 151 | rb.Push(RESULT_SUCCESS); | ||
| 152 | rb.PushIpcInterface<ISystemClock>(); | ||
| 153 | LOG_DEBUG(Service_Time, "called"); | ||
| 154 | } | ||
| 155 | |||
| 149 | Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) | 156 | Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) |
| 150 | : ServiceFramework(name), time(std::move(time)) {} | 157 | : ServiceFramework(name), time(std::move(time)) {} |
| 151 | 158 | ||
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index 1cbbadb21..197029e7a 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h | |||
| @@ -56,6 +56,7 @@ public: | |||
| 56 | void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx); | 56 | void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx); |
| 57 | void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); | 57 | void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); |
| 58 | void GetTimeZoneService(Kernel::HLERequestContext& ctx); | 58 | void GetTimeZoneService(Kernel::HLERequestContext& ctx); |
| 59 | void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); | ||
| 59 | 60 | ||
| 60 | protected: | 61 | protected: |
| 61 | std::shared_ptr<Module> time; | 62 | std::shared_ptr<Module> time; |
diff --git a/src/core/hle/service/time/time_s.cpp b/src/core/hle/service/time/time_s.cpp index 1634d3300..b172b2bd6 100644 --- a/src/core/hle/service/time/time_s.cpp +++ b/src/core/hle/service/time/time_s.cpp | |||
| @@ -10,6 +10,10 @@ namespace Time { | |||
| 10 | TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:s") { | 10 | TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:s") { |
| 11 | static const FunctionInfo functions[] = { | 11 | static const FunctionInfo functions[] = { |
| 12 | {0, &TIME_S::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | 12 | {0, &TIME_S::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, |
| 13 | {1, &TIME_S::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | ||
| 14 | {2, &TIME_S::GetStandardSteadyClock, "GetStandardSteadyClock"}, | ||
| 15 | {3, &TIME_S::GetTimeZoneService, "GetTimeZoneService"}, | ||
| 16 | {4, &TIME_S::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | ||
| 13 | }; | 17 | }; |
| 14 | RegisterHandlers(functions); | 18 | RegisterHandlers(functions); |
| 15 | } | 19 | } |
diff --git a/src/core/hle/service/time/time_u.cpp b/src/core/hle/service/time/time_u.cpp index ae4f78adf..fc1ace325 100644 --- a/src/core/hle/service/time/time_u.cpp +++ b/src/core/hle/service/time/time_u.cpp | |||
| @@ -13,6 +13,7 @@ TIME_U::TIME_U(std::shared_ptr<Module> time) : Module::Interface(std::move(time) | |||
| 13 | {1, &TIME_U::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, | 13 | {1, &TIME_U::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, |
| 14 | {2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"}, | 14 | {2, &TIME_U::GetStandardSteadyClock, "GetStandardSteadyClock"}, |
| 15 | {3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"}, | 15 | {3, &TIME_U::GetTimeZoneService, "GetTimeZoneService"}, |
| 16 | {4, &TIME_U::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, | ||
| 16 | }; | 17 | }; |
| 17 | RegisterHandlers(functions); | 18 | RegisterHandlers(functions); |
| 18 | } | 19 | } |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 8b4ed30d2..7b6453447 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/scope_exit.h" | 8 | #include "common/scope_exit.h" |
| 9 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 11 | #include "core/hle/service/nvflinger/buffer_queue.h" | 12 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 12 | #include "core/hle/service/vi/vi.h" | 13 | #include "core/hle/service/vi/vi.h" |
| 13 | #include "core/hle/service/vi/vi_m.h" | 14 | #include "core/hle/service/vi/vi_m.h" |
| @@ -38,6 +39,7 @@ public: | |||
| 38 | 39 | ||
| 39 | template <typename T> | 40 | template <typename T> |
| 40 | T Read() { | 41 | T Read() { |
| 42 | ASSERT(read_index + sizeof(T) <= buffer.size()); | ||
| 41 | T val; | 43 | T val; |
| 42 | std::memcpy(&val, buffer.data() + read_index, sizeof(T)); | 44 | std::memcpy(&val, buffer.data() + read_index, sizeof(T)); |
| 43 | read_index += sizeof(T); | 45 | read_index += sizeof(T); |
| @@ -47,6 +49,7 @@ public: | |||
| 47 | 49 | ||
| 48 | template <typename T> | 50 | template <typename T> |
| 49 | T ReadUnaligned() { | 51 | T ReadUnaligned() { |
| 52 | ASSERT(read_index + sizeof(T) <= buffer.size()); | ||
| 50 | T val; | 53 | T val; |
| 51 | std::memcpy(&val, buffer.data() + read_index, sizeof(T)); | 54 | std::memcpy(&val, buffer.data() + read_index, sizeof(T)); |
| 52 | read_index += sizeof(T); | 55 | read_index += sizeof(T); |
| @@ -54,6 +57,7 @@ public: | |||
| 54 | } | 57 | } |
| 55 | 58 | ||
| 56 | std::vector<u8> ReadBlock(size_t length) { | 59 | std::vector<u8> ReadBlock(size_t length) { |
| 60 | ASSERT(read_index + length <= buffer.size()); | ||
| 57 | const u8* const begin = buffer.data() + read_index; | 61 | const u8* const begin = buffer.data() + read_index; |
| 58 | const u8* const end = begin + length; | 62 | const u8* const end = begin + length; |
| 59 | std::vector<u8> data(begin, end); | 63 | std::vector<u8> data(begin, end); |
| @@ -86,7 +90,18 @@ public: | |||
| 86 | write_index = Common::AlignUp(write_index, 4); | 90 | write_index = Common::AlignUp(write_index, 4); |
| 87 | } | 91 | } |
| 88 | 92 | ||
| 93 | template <typename T> | ||
| 94 | void WriteObject(const T& val) { | ||
| 95 | u32_le size = static_cast<u32>(sizeof(val)); | ||
| 96 | Write(size); | ||
| 97 | // TODO(Subv): Support file descriptors. | ||
| 98 | Write<u32_le>(0); // Fd count. | ||
| 99 | Write(val); | ||
| 100 | } | ||
| 101 | |||
| 89 | void Deserialize() { | 102 | void Deserialize() { |
| 103 | ASSERT(buffer.size() > sizeof(Header)); | ||
| 104 | |||
| 90 | Header header{}; | 105 | Header header{}; |
| 91 | std::memcpy(&header, buffer.data(), sizeof(Header)); | 106 | std::memcpy(&header, buffer.data(), sizeof(Header)); |
| 92 | 107 | ||
| @@ -262,10 +277,11 @@ public: | |||
| 262 | Data data; | 277 | Data data; |
| 263 | }; | 278 | }; |
| 264 | 279 | ||
| 265 | // TODO(bunnei): Remove this. When set to 1, games will think a fence is valid and boot further. | 280 | struct BufferProducerFence { |
| 266 | // This will break libnx and potentially other apps that more stringently check this. This is here | 281 | u32 is_valid; |
| 267 | // purely as a convenience, and should go away once we implement fences. | 282 | std::array<Nvidia::IoctlFence, 4> fences; |
| 268 | static constexpr u32 FENCE_HACK = 0; | 283 | }; |
| 284 | static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size"); | ||
| 269 | 285 | ||
| 270 | class IGBPDequeueBufferResponseParcel : public Parcel { | 286 | class IGBPDequeueBufferResponseParcel : public Parcel { |
| 271 | public: | 287 | public: |
| @@ -274,20 +290,16 @@ public: | |||
| 274 | 290 | ||
| 275 | protected: | 291 | protected: |
| 276 | void SerializeData() override { | 292 | void SerializeData() override { |
| 277 | // TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx. | 293 | // TODO(Subv): Find out how this Fence is used. |
| 278 | Write<u32>(0); | 294 | BufferProducerFence fence = {}; |
| 279 | Write<u32>(FENCE_HACK); | 295 | fence.is_valid = 1; |
| 280 | Write<u32>(0); | 296 | for (auto& fence_ : fence.fences) |
| 281 | Write<u32>(0); | 297 | fence_.id = -1; |
| 282 | Write<u32>(0); | 298 | |
| 283 | Write<u32>(0); | 299 | Write(slot); |
| 284 | Write<u32>(0); | 300 | Write<u32_le>(1); |
| 285 | Write<u32>(0); | 301 | WriteObject(fence); |
| 286 | Write<u32>(0); | 302 | Write<u32_le>(0); |
| 287 | Write<u32>(0); | ||
| 288 | Write<u32>(0); | ||
| 289 | Write<u32>(0); | ||
| 290 | Write<u32>(0); | ||
| 291 | } | 303 | } |
| 292 | 304 | ||
| 293 | u32_le slot; | 305 | u32_le slot; |
| @@ -316,11 +328,10 @@ public: | |||
| 316 | 328 | ||
| 317 | protected: | 329 | protected: |
| 318 | void SerializeData() override { | 330 | void SerializeData() override { |
| 319 | // TODO(bunnei): Find out what this all means. Writing anything non-zero here breaks libnx. | 331 | // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx try |
| 320 | Write<u32_le>(0); | 332 | // to read an IGBPBuffer object from the parcel. |
| 321 | Write<u32_le>(FENCE_HACK); | 333 | Write<u32_le>(1); |
| 322 | Write<u32_le>(0); | 334 | WriteObject(buffer); |
| 323 | Write(buffer); | ||
| 324 | Write<u32_le>(0); | 335 | Write<u32_le>(0); |
| 325 | } | 336 | } |
| 326 | 337 | ||
| @@ -429,7 +440,7 @@ public: | |||
| 429 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, | 440 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, |
| 430 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, | 441 | {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, |
| 431 | {2, &IHOSBinderDriver::GetNativeHandle, "GetNativeHandle"}, | 442 | {2, &IHOSBinderDriver::GetNativeHandle, "GetNativeHandle"}, |
| 432 | {3, &IHOSBinderDriver::TransactParcelAuto, "TransactParcelAuto"}, | 443 | {3, &IHOSBinderDriver::TransactParcel, "TransactParcelAuto"}, |
| 433 | }; | 444 | }; |
| 434 | RegisterHandlers(functions); | 445 | RegisterHandlers(functions); |
| 435 | } | 446 | } |
| @@ -453,95 +464,79 @@ private: | |||
| 453 | SetPreallocatedBuffer = 14 | 464 | SetPreallocatedBuffer = 14 |
| 454 | }; | 465 | }; |
| 455 | 466 | ||
| 456 | void TransactParcel(u32 id, TransactionId transaction, const std::vector<u8>& input_data, | 467 | void TransactParcel(Kernel::HLERequestContext& ctx) { |
| 457 | VAddr output_addr, u64 output_size) { | 468 | IPC::RequestParser rp{ctx}; |
| 469 | u32 id = rp.Pop<u32>(); | ||
| 470 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); | ||
| 471 | u32 flags = rp.Pop<u32>(); | ||
| 458 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | 472 | auto buffer_queue = nv_flinger->GetBufferQueue(id); |
| 459 | 473 | ||
| 474 | LOG_DEBUG(Service_VI, "called, transaction=%x", transaction); | ||
| 475 | |||
| 460 | if (transaction == TransactionId::Connect) { | 476 | if (transaction == TransactionId::Connect) { |
| 461 | IGBPConnectRequestParcel request{input_data}; | 477 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; |
| 462 | IGBPConnectResponseParcel response{1280, 720}; | 478 | IGBPConnectResponseParcel response{1280, 720}; |
| 463 | std::vector<u8> response_buffer = response.Serialize(); | 479 | ctx.WriteBuffer(response.Serialize()); |
| 464 | Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size()); | ||
| 465 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { | 480 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { |
| 466 | IGBPSetPreallocatedBufferRequestParcel request{input_data}; | 481 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; |
| 467 | 482 | ||
| 468 | buffer_queue->SetPreallocatedBuffer(request.data.slot, request.buffer); | 483 | buffer_queue->SetPreallocatedBuffer(request.data.slot, request.buffer); |
| 469 | 484 | ||
| 470 | IGBPSetPreallocatedBufferResponseParcel response{}; | 485 | IGBPSetPreallocatedBufferResponseParcel response{}; |
| 471 | std::vector<u8> response_buffer = response.Serialize(); | 486 | ctx.WriteBuffer(response.Serialize()); |
| 472 | Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size()); | ||
| 473 | } else if (transaction == TransactionId::DequeueBuffer) { | 487 | } else if (transaction == TransactionId::DequeueBuffer) { |
| 474 | IGBPDequeueBufferRequestParcel request{input_data}; | 488 | IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; |
| 475 | 489 | const u32 width{request.data.width}; | |
| 476 | u32 slot = buffer_queue->DequeueBuffer(request.data.pixel_format, request.data.width, | 490 | const u32 height{request.data.height}; |
| 477 | request.data.height); | 491 | boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); |
| 478 | 492 | ||
| 479 | IGBPDequeueBufferResponseParcel response{slot}; | 493 | if (slot != boost::none) { |
| 480 | std::vector<u8> response_buffer = response.Serialize(); | 494 | // Buffer is available |
| 481 | Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size()); | 495 | IGBPDequeueBufferResponseParcel response{*slot}; |
| 496 | ctx.WriteBuffer(response.Serialize()); | ||
| 497 | } else { | ||
| 498 | // Wait the current thread until a buffer becomes available | ||
| 499 | auto wait_event = ctx.SleepClientThread( | ||
| 500 | Kernel::GetCurrentThread(), "IHOSBinderDriver::DequeueBuffer", -1, | ||
| 501 | [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, | ||
| 502 | ThreadWakeupReason reason) { | ||
| 503 | // Repeat TransactParcel DequeueBuffer when a buffer is available | ||
| 504 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | ||
| 505 | boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); | ||
| 506 | IGBPDequeueBufferResponseParcel response{*slot}; | ||
| 507 | ctx.WriteBuffer(response.Serialize()); | ||
| 508 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 509 | rb.Push(RESULT_SUCCESS); | ||
| 510 | }); | ||
| 511 | buffer_queue->SetBufferWaitEvent(std::move(wait_event)); | ||
| 512 | } | ||
| 482 | } else if (transaction == TransactionId::RequestBuffer) { | 513 | } else if (transaction == TransactionId::RequestBuffer) { |
| 483 | IGBPRequestBufferRequestParcel request{input_data}; | 514 | IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; |
| 484 | 515 | ||
| 485 | auto& buffer = buffer_queue->RequestBuffer(request.slot); | 516 | auto& buffer = buffer_queue->RequestBuffer(request.slot); |
| 486 | 517 | ||
| 487 | IGBPRequestBufferResponseParcel response{buffer}; | 518 | IGBPRequestBufferResponseParcel response{buffer}; |
| 488 | std::vector<u8> response_buffer = response.Serialize(); | 519 | ctx.WriteBuffer(response.Serialize()); |
| 489 | Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size()); | ||
| 490 | } else if (transaction == TransactionId::QueueBuffer) { | 520 | } else if (transaction == TransactionId::QueueBuffer) { |
| 491 | IGBPQueueBufferRequestParcel request{input_data}; | 521 | IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()}; |
| 492 | 522 | ||
| 493 | buffer_queue->QueueBuffer(request.data.slot, request.data.transform); | 523 | buffer_queue->QueueBuffer(request.data.slot, request.data.transform); |
| 494 | 524 | ||
| 495 | IGBPQueueBufferResponseParcel response{1280, 720}; | 525 | IGBPQueueBufferResponseParcel response{1280, 720}; |
| 496 | std::vector<u8> response_buffer = response.Serialize(); | 526 | ctx.WriteBuffer(response.Serialize()); |
| 497 | Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size()); | ||
| 498 | } else if (transaction == TransactionId::Query) { | 527 | } else if (transaction == TransactionId::Query) { |
| 499 | IGBPQueryRequestParcel request{input_data}; | 528 | IGBPQueryRequestParcel request{ctx.ReadBuffer()}; |
| 500 | 529 | ||
| 501 | u32 value = | 530 | u32 value = |
| 502 | buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type)); | 531 | buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type)); |
| 503 | 532 | ||
| 504 | IGBPQueryResponseParcel response{value}; | 533 | IGBPQueryResponseParcel response{value}; |
| 505 | std::vector<u8> response_buffer = response.Serialize(); | 534 | ctx.WriteBuffer(response.Serialize()); |
| 506 | Memory::WriteBlock(output_addr, response_buffer.data(), response_buffer.size()); | ||
| 507 | } else if (transaction == TransactionId::CancelBuffer) { | 535 | } else if (transaction == TransactionId::CancelBuffer) { |
| 508 | LOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); | 536 | LOG_WARNING(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); |
| 509 | } else { | 537 | } else { |
| 510 | ASSERT_MSG(false, "Unimplemented"); | 538 | ASSERT_MSG(false, "Unimplemented"); |
| 511 | } | 539 | } |
| 512 | } | ||
| 513 | |||
| 514 | void TransactParcel(Kernel::HLERequestContext& ctx) { | ||
| 515 | IPC::RequestParser rp{ctx}; | ||
| 516 | u32 id = rp.Pop<u32>(); | ||
| 517 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); | ||
| 518 | u32 flags = rp.Pop<u32>(); | ||
| 519 | LOG_DEBUG(Service_VI, "called, transaction=%x", transaction); | ||
| 520 | |||
| 521 | auto& input_buffer = ctx.BufferDescriptorA()[0]; | ||
| 522 | auto& output_buffer = ctx.BufferDescriptorB()[0]; | ||
| 523 | std::vector<u8> input_data(input_buffer.Size()); | ||
| 524 | Memory::ReadBlock(input_buffer.Address(), input_data.data(), input_buffer.Size()); | ||
| 525 | |||
| 526 | TransactParcel(id, transaction, input_data, output_buffer.Address(), output_buffer.Size()); | ||
| 527 | |||
| 528 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 529 | rb.Push(RESULT_SUCCESS); | ||
| 530 | } | ||
| 531 | |||
| 532 | void TransactParcelAuto(Kernel::HLERequestContext& ctx) { | ||
| 533 | IPC::RequestParser rp{ctx}; | ||
| 534 | u32 id = rp.Pop<u32>(); | ||
| 535 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); | ||
| 536 | u32 flags = rp.Pop<u32>(); | ||
| 537 | LOG_DEBUG(Service_VI, "called, transaction=%x", transaction); | ||
| 538 | |||
| 539 | auto& input_buffer = ctx.BufferDescriptorX()[0]; | ||
| 540 | auto& output_buffer = ctx.BufferDescriptorC()[0]; | ||
| 541 | std::vector<u8> input_data(input_buffer.size); | ||
| 542 | Memory::ReadBlock(input_buffer.Address(), input_data.data(), input_buffer.size); | ||
| 543 | |||
| 544 | TransactParcel(id, transaction, input_data, output_buffer.Address(), output_buffer.Size()); | ||
| 545 | 540 | ||
| 546 | IPC::ResponseBuilder rb{ctx, 2}; | 541 | IPC::ResponseBuilder rb{ctx, 2}; |
| 547 | rb.Push(RESULT_SUCCESS); | 542 | rb.Push(RESULT_SUCCESS); |
| @@ -719,18 +714,13 @@ void IApplicationDisplayService::OpenLayer(Kernel::HLERequestContext& ctx) { | |||
| 719 | u64 layer_id = rp.Pop<u64>(); | 714 | u64 layer_id = rp.Pop<u64>(); |
| 720 | u64 aruid = rp.Pop<u64>(); | 715 | u64 aruid = rp.Pop<u64>(); |
| 721 | 716 | ||
| 722 | auto& buffer = ctx.BufferDescriptorB()[0]; | ||
| 723 | |||
| 724 | u64 display_id = nv_flinger->OpenDisplay(display_name); | 717 | u64 display_id = nv_flinger->OpenDisplay(display_name); |
| 725 | u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); | 718 | u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); |
| 726 | 719 | ||
| 727 | NativeWindow native_window{buffer_queue_id}; | 720 | NativeWindow native_window{buffer_queue_id}; |
| 728 | auto data = native_window.Serialize(); | ||
| 729 | Memory::WriteBlock(buffer.Address(), data.data(), data.size()); | ||
| 730 | |||
| 731 | IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); | 721 | IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); |
| 732 | rb.Push(RESULT_SUCCESS); | 722 | rb.Push(RESULT_SUCCESS); |
| 733 | rb.Push<u64>(data.size()); | 723 | rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); |
| 734 | } | 724 | } |
| 735 | 725 | ||
| 736 | void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx) { | 726 | void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx) { |
| @@ -741,21 +731,16 @@ void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx | |||
| 741 | rp.Pop<u32>(); // padding | 731 | rp.Pop<u32>(); // padding |
| 742 | u64 display_id = rp.Pop<u64>(); | 732 | u64 display_id = rp.Pop<u64>(); |
| 743 | 733 | ||
| 744 | auto& buffer = ctx.BufferDescriptorB()[0]; | ||
| 745 | |||
| 746 | // TODO(Subv): What's the difference between a Stray and a Managed layer? | 734 | // TODO(Subv): What's the difference between a Stray and a Managed layer? |
| 747 | 735 | ||
| 748 | u64 layer_id = nv_flinger->CreateLayer(display_id); | 736 | u64 layer_id = nv_flinger->CreateLayer(display_id); |
| 749 | u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); | 737 | u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); |
| 750 | 738 | ||
| 751 | NativeWindow native_window{buffer_queue_id}; | 739 | NativeWindow native_window{buffer_queue_id}; |
| 752 | auto data = native_window.Serialize(); | ||
| 753 | Memory::WriteBlock(buffer.Address(), data.data(), data.size()); | ||
| 754 | |||
| 755 | IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); | 740 | IPC::ResponseBuilder rb = rp.MakeBuilder(6, 0, 0); |
| 756 | rb.Push(RESULT_SUCCESS); | 741 | rb.Push(RESULT_SUCCESS); |
| 757 | rb.Push(layer_id); | 742 | rb.Push(layer_id); |
| 758 | rb.Push<u64>(data.size()); | 743 | rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize())); |
| 759 | } | 744 | } |
| 760 | 745 | ||
| 761 | void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ctx) { | 746 | void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ctx) { |
| @@ -781,8 +766,7 @@ void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext& | |||
| 781 | void IApplicationDisplayService::ListDisplays(Kernel::HLERequestContext& ctx) { | 766 | void IApplicationDisplayService::ListDisplays(Kernel::HLERequestContext& ctx) { |
| 782 | IPC::RequestParser rp{ctx}; | 767 | IPC::RequestParser rp{ctx}; |
| 783 | DisplayInfo display_info; | 768 | DisplayInfo display_info; |
| 784 | auto& buffer = ctx.BufferDescriptorB()[0]; | 769 | ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); |
| 785 | Memory::WriteBlock(buffer.Address(), &display_info, sizeof(DisplayInfo)); | ||
| 786 | IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); | 770 | IPC::ResponseBuilder rb = rp.MakeBuilder(4, 0, 0); |
| 787 | rb.Push(RESULT_SUCCESS); | 771 | rb.Push(RESULT_SUCCESS); |
| 788 | rb.Push<u64>(1); | 772 | rb.Push<u64>(1); |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 661803b5f..aa09ed323 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -53,6 +53,7 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileUti | |||
| 53 | FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& file, | 53 | FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& file, |
| 54 | const std::string& filepath) { | 54 | const std::string& filepath) { |
| 55 | bool is_main_found{}; | 55 | bool is_main_found{}; |
| 56 | bool is_npdm_found{}; | ||
| 56 | bool is_rtld_found{}; | 57 | bool is_rtld_found{}; |
| 57 | bool is_sdk_found{}; | 58 | bool is_sdk_found{}; |
| 58 | 59 | ||
| @@ -67,6 +68,9 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& fil | |||
| 67 | // Verify filename | 68 | // Verify filename |
| 68 | if (Common::ToLower(virtual_name) == "main") { | 69 | if (Common::ToLower(virtual_name) == "main") { |
| 69 | is_main_found = true; | 70 | is_main_found = true; |
| 71 | } else if (Common::ToLower(virtual_name) == "main.npdm") { | ||
| 72 | is_npdm_found = true; | ||
| 73 | return true; | ||
| 70 | } else if (Common::ToLower(virtual_name) == "rtld") { | 74 | } else if (Common::ToLower(virtual_name) == "rtld") { |
| 71 | is_rtld_found = true; | 75 | is_rtld_found = true; |
| 72 | } else if (Common::ToLower(virtual_name) == "sdk") { | 76 | } else if (Common::ToLower(virtual_name) == "sdk") { |
| @@ -83,14 +87,14 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& fil | |||
| 83 | } | 87 | } |
| 84 | 88 | ||
| 85 | // We are done if we've found and verified all required NSOs | 89 | // We are done if we've found and verified all required NSOs |
| 86 | return !(is_main_found && is_rtld_found && is_sdk_found); | 90 | return !(is_main_found && is_npdm_found && is_rtld_found && is_sdk_found); |
| 87 | }; | 91 | }; |
| 88 | 92 | ||
| 89 | // Search the directory recursively, looking for the required modules | 93 | // Search the directory recursively, looking for the required modules |
| 90 | const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; | 94 | const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; |
| 91 | FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); | 95 | FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); |
| 92 | 96 | ||
| 93 | if (is_main_found && is_rtld_found && is_sdk_found) { | 97 | if (is_main_found && is_npdm_found && is_rtld_found && is_sdk_found) { |
| 94 | return FileType::DeconstructedRomDirectory; | 98 | return FileType::DeconstructedRomDirectory; |
| 95 | } | 99 | } |
| 96 | 100 | ||
| @@ -106,11 +110,17 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 106 | return ResultStatus::Error; | 110 | return ResultStatus::Error; |
| 107 | } | 111 | } |
| 108 | 112 | ||
| 109 | process = Kernel::Process::Create("main"); | 113 | const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; |
| 114 | const std::string npdm_path = directory + DIR_SEP + "main.npdm"; | ||
| 115 | |||
| 116 | ResultStatus result = metadata.Load(npdm_path); | ||
| 117 | if (result != ResultStatus::Success) { | ||
| 118 | return result; | ||
| 119 | } | ||
| 120 | metadata.Print(); | ||
| 110 | 121 | ||
| 111 | // Load NSO modules | 122 | // Load NSO modules |
| 112 | VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; | 123 | VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; |
| 113 | const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; | ||
| 114 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", | 124 | for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", |
| 115 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { | 125 | "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { |
| 116 | const std::string path = directory + DIR_SEP + module; | 126 | const std::string path = directory + DIR_SEP + module; |
| @@ -123,11 +133,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( | |||
| 123 | } | 133 | } |
| 124 | } | 134 | } |
| 125 | 135 | ||
| 136 | process->program_id = metadata.GetTitleID(); | ||
| 126 | process->svc_access_mask.set(); | 137 | process->svc_access_mask.set(); |
| 127 | process->address_mappings = default_address_mappings; | 138 | process->address_mappings = default_address_mappings; |
| 128 | process->resource_limit = | 139 | process->resource_limit = |
| 129 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 140 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 130 | process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); | 141 | process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), |
| 142 | metadata.GetMainThreadStackSize()); | ||
| 131 | 143 | ||
| 132 | // Find the RomFS by searching for a ".romfs" file in this directory | 144 | // Find the RomFS by searching for a ".romfs" file in this directory |
| 133 | filepath_romfs = FindRomFS(directory); | 145 | filepath_romfs = FindRomFS(directory); |
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 536a2dab7..23295d911 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 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/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/loader/loader.h" | 11 | #include "core/loader/loader.h" |
| 11 | 12 | ||
| @@ -41,6 +42,7 @@ public: | |||
| 41 | private: | 42 | private: |
| 42 | std::string filepath_romfs; | 43 | std::string filepath_romfs; |
| 43 | std::string filepath; | 44 | std::string filepath; |
| 45 | FileSys::ProgramMetadata metadata; | ||
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | } // namespace Loader | 48 | } // namespace Loader |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index b87320656..0ba8c6fd2 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -300,7 +300,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | |||
| 300 | std::vector<u8> program_image(total_image_size); | 300 | std::vector<u8> program_image(total_image_size); |
| 301 | size_t current_image_position = 0; | 301 | size_t current_image_position = 0; |
| 302 | 302 | ||
| 303 | SharedPtr<CodeSet> codeset = CodeSet::Create("", 0); | 303 | SharedPtr<CodeSet> codeset = CodeSet::Create(""); |
| 304 | 304 | ||
| 305 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | 305 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 306 | Elf32_Phdr* p = &segments[i]; | 306 | Elf32_Phdr* p = &segments[i]; |
| @@ -406,7 +406,6 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 406 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); | 406 | SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); |
| 407 | codeset->name = filename; | 407 | codeset->name = filename; |
| 408 | 408 | ||
| 409 | process = Kernel::Process::Create("main"); | ||
| 410 | process->LoadModule(codeset, codeset->entrypoint); | 409 | process->LoadModule(codeset, codeset->entrypoint); |
| 411 | process->svc_access_mask.set(); | 410 | process->svc_access_mask.set(); |
| 412 | process->address_mappings = default_address_mappings; | 411 | process->address_mappings = default_address_mappings; |
| @@ -415,7 +414,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 415 | process->resource_limit = | 414 | process->resource_limit = |
| 416 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 415 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 417 | 416 | ||
| 418 | process->Run(codeset->entrypoint, 48, Kernel::DEFAULT_STACK_SIZE); | 417 | process->Run(codeset->entrypoint, 48, Memory::STACK_SIZE); |
| 419 | 418 | ||
| 420 | is_loaded = true; | 419 | is_loaded = true; |
| 421 | return ResultStatus::Success; | 420 | return ResultStatus::Success; |
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 6f8a2f21e..6dcd1ce48 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "core/core.h" | ||
| 11 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 12 | #include "core/hle/kernel/resource_limit.h" | 13 | #include "core/hle/kernel/resource_limit.h" |
| 13 | #include "core/loader/nro.h" | 14 | #include "core/loader/nro.h" |
| @@ -83,7 +84,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { | |||
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | // Build program image | 86 | // Build program image |
| 86 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("", 0); | 87 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); |
| 87 | std::vector<u8> program_image; | 88 | std::vector<u8> program_image; |
| 88 | program_image.resize(PageAlignSize(nro_header.file_size)); | 89 | program_image.resize(PageAlignSize(nro_header.file_size)); |
| 89 | file.Seek(0, SEEK_SET); | 90 | file.Seek(0, SEEK_SET); |
| @@ -112,7 +113,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { | |||
| 112 | // Load codeset for current process | 113 | // Load codeset for current process |
| 113 | codeset->name = path; | 114 | codeset->name = path; |
| 114 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 115 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 115 | Kernel::g_current_process->LoadModule(codeset, load_base); | 116 | Core::CurrentProcess()->LoadModule(codeset, load_base); |
| 116 | 117 | ||
| 117 | return true; | 118 | return true; |
| 118 | } | 119 | } |
| @@ -125,8 +126,6 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 125 | return ResultStatus::Error; | 126 | return ResultStatus::Error; |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | process = Kernel::Process::Create("main"); | ||
| 129 | |||
| 130 | // Load NRO | 129 | // Load NRO |
| 131 | static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; | 130 | static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; |
| 132 | 131 | ||
| @@ -138,7 +137,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 138 | process->address_mappings = default_address_mappings; | 137 | process->address_mappings = default_address_mappings; |
| 139 | process->resource_limit = | 138 | process->resource_limit = |
| 140 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 139 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 141 | process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE); | 140 | process->Run(base_addr, 48, Memory::STACK_SIZE); |
| 142 | 141 | ||
| 143 | is_loaded = true; | 142 | is_loaded = true; |
| 144 | return ResultStatus::Success; | 143 | return ResultStatus::Success; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 407025da0..100aa022e 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/core.h" | ||
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/resource_limit.h" | 14 | #include "core/hle/kernel/resource_limit.h" |
| 14 | #include "core/loader/nso.h" | 15 | #include "core/loader/nso.h" |
| @@ -109,7 +110,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { | |||
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | // Build program image | 112 | // Build program image |
| 112 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create("", 0); | 113 | Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(""); |
| 113 | std::vector<u8> program_image; | 114 | std::vector<u8> program_image; |
| 114 | for (int i = 0; i < nso_header.segments.size(); ++i) { | 115 | for (int i = 0; i < nso_header.segments.size(); ++i) { |
| 115 | std::vector<u8> data = | 116 | std::vector<u8> data = |
| @@ -142,7 +143,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& path, VAddr load_base) { | |||
| 142 | // Load codeset for current process | 143 | // Load codeset for current process |
| 143 | codeset->name = path; | 144 | codeset->name = path; |
| 144 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 145 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 145 | Kernel::g_current_process->LoadModule(codeset, load_base); | 146 | Core::CurrentProcess()->LoadModule(codeset, load_base); |
| 146 | 147 | ||
| 147 | return load_base + image_size; | 148 | return load_base + image_size; |
| 148 | } | 149 | } |
| @@ -155,8 +156,6 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 155 | return ResultStatus::Error; | 156 | return ResultStatus::Error; |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | process = Kernel::Process::Create("main"); | ||
| 159 | |||
| 160 | // Load module | 159 | // Load module |
| 161 | LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); | 160 | LoadModule(filepath, Memory::PROCESS_IMAGE_VADDR); |
| 162 | LOG_DEBUG(Loader, "loaded module %s @ 0x%" PRIx64, filepath.c_str(), | 161 | LOG_DEBUG(Loader, "loaded module %s @ 0x%" PRIx64, filepath.c_str(), |
| @@ -166,7 +165,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { | |||
| 166 | process->address_mappings = default_address_mappings; | 165 | process->address_mappings = default_address_mappings; |
| 167 | process->resource_limit = | 166 | process->resource_limit = |
| 168 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 167 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 169 | process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); | 168 | process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Memory::STACK_SIZE); |
| 170 | 169 | ||
| 171 | is_loaded = true; | 170 | is_loaded = true; |
| 172 | return ResultStatus::Success; | 171 | return ResultStatus::Success; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index cc1ed16b6..4e34d8334 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -109,7 +109,7 @@ static std::set<MemoryHookPointer> GetSpecialHandlers(const PageTable& page_tabl | |||
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static std::set<MemoryHookPointer> GetSpecialHandlers(VAddr vaddr, u64 size) { | 111 | static std::set<MemoryHookPointer> GetSpecialHandlers(VAddr vaddr, u64 size) { |
| 112 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 112 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 113 | return GetSpecialHandlers(page_table, vaddr, size); | 113 | return GetSpecialHandlers(page_table, vaddr, size); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| @@ -118,6 +118,11 @@ boost::optional<T> ReadSpecial(VAddr addr); | |||
| 118 | 118 | ||
| 119 | template <typename T> | 119 | template <typename T> |
| 120 | T Read(const VAddr vaddr) { | 120 | T Read(const VAddr vaddr) { |
| 121 | if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) { | ||
| 122 | LOG_ERROR(HW_Memory, "Read%lu after page table @ 0x%016" PRIX64, sizeof(T) * 8, vaddr); | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 121 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 126 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 122 | switch (type) { | 127 | switch (type) { |
| 123 | case PageType::Unmapped: | 128 | case PageType::Unmapped: |
| @@ -146,6 +151,12 @@ bool WriteSpecial(VAddr addr, const T data); | |||
| 146 | 151 | ||
| 147 | template <typename T> | 152 | template <typename T> |
| 148 | void Write(const VAddr vaddr, const T data) { | 153 | void Write(const VAddr vaddr, const T data) { |
| 154 | if ((vaddr >> PAGE_BITS) >= PAGE_TABLE_NUM_ENTRIES) { | ||
| 155 | LOG_ERROR(HW_Memory, "Write%lu after page table 0x%08X @ 0x%016" PRIX64, sizeof(data) * 8, | ||
| 156 | (u32)data, vaddr); | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 149 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | 160 | const PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
| 150 | switch (type) { | 161 | switch (type) { |
| 151 | case PageType::Unmapped: | 162 | case PageType::Unmapped: |
| @@ -191,7 +202,7 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { | |||
| 191 | } | 202 | } |
| 192 | 203 | ||
| 193 | bool IsValidVirtualAddress(const VAddr vaddr) { | 204 | bool IsValidVirtualAddress(const VAddr vaddr) { |
| 194 | return IsValidVirtualAddress(*Kernel::g_current_process, vaddr); | 205 | return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr); |
| 195 | } | 206 | } |
| 196 | 207 | ||
| 197 | bool IsValidPhysicalAddress(const PAddr paddr) { | 208 | bool IsValidPhysicalAddress(const PAddr paddr) { |
| @@ -353,7 +364,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_ | |||
| 353 | } | 364 | } |
| 354 | 365 | ||
| 355 | void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { | 366 | void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { |
| 356 | ReadBlock(*Kernel::g_current_process, src_addr, dest_buffer, size); | 367 | ReadBlock(*Core::CurrentProcess(), src_addr, dest_buffer, size); |
| 357 | } | 368 | } |
| 358 | 369 | ||
| 359 | void Write8(const VAddr addr, const u8 data) { | 370 | void Write8(const VAddr addr, const u8 data) { |
| @@ -424,11 +435,11 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi | |||
| 424 | } | 435 | } |
| 425 | 436 | ||
| 426 | void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { | 437 | void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { |
| 427 | WriteBlock(*Kernel::g_current_process, dest_addr, src_buffer, size); | 438 | WriteBlock(*Core::CurrentProcess(), dest_addr, src_buffer, size); |
| 428 | } | 439 | } |
| 429 | 440 | ||
| 430 | void ZeroBlock(const VAddr dest_addr, const size_t size) { | 441 | void ZeroBlock(const VAddr dest_addr, const size_t size) { |
| 431 | const auto& process = *Kernel::g_current_process; | 442 | const auto& process = *Core::CurrentProcess(); |
| 432 | 443 | ||
| 433 | size_t remaining_size = size; | 444 | size_t remaining_size = size; |
| 434 | size_t page_index = dest_addr >> PAGE_BITS; | 445 | size_t page_index = dest_addr >> PAGE_BITS; |
| @@ -469,7 +480,7 @@ void ZeroBlock(const VAddr dest_addr, const size_t size) { | |||
| 469 | } | 480 | } |
| 470 | 481 | ||
| 471 | void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { | 482 | void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { |
| 472 | const auto& process = *Kernel::g_current_process; | 483 | const auto& process = *Core::CurrentProcess(); |
| 473 | 484 | ||
| 474 | size_t remaining_size = size; | 485 | size_t remaining_size = size; |
| 475 | size_t page_index = src_addr >> PAGE_BITS; | 486 | size_t page_index = src_addr >> PAGE_BITS; |
| @@ -515,7 +526,7 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { | |||
| 515 | 526 | ||
| 516 | template <> | 527 | template <> |
| 517 | boost::optional<u8> ReadSpecial<u8>(VAddr addr) { | 528 | boost::optional<u8> ReadSpecial<u8>(VAddr addr) { |
| 518 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 529 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 519 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u8))) | 530 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u8))) |
| 520 | if (auto result = handler->Read8(addr)) | 531 | if (auto result = handler->Read8(addr)) |
| 521 | return *result; | 532 | return *result; |
| @@ -524,7 +535,7 @@ boost::optional<u8> ReadSpecial<u8>(VAddr addr) { | |||
| 524 | 535 | ||
| 525 | template <> | 536 | template <> |
| 526 | boost::optional<u16> ReadSpecial<u16>(VAddr addr) { | 537 | boost::optional<u16> ReadSpecial<u16>(VAddr addr) { |
| 527 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 538 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 528 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u16))) | 539 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u16))) |
| 529 | if (auto result = handler->Read16(addr)) | 540 | if (auto result = handler->Read16(addr)) |
| 530 | return *result; | 541 | return *result; |
| @@ -533,7 +544,7 @@ boost::optional<u16> ReadSpecial<u16>(VAddr addr) { | |||
| 533 | 544 | ||
| 534 | template <> | 545 | template <> |
| 535 | boost::optional<u32> ReadSpecial<u32>(VAddr addr) { | 546 | boost::optional<u32> ReadSpecial<u32>(VAddr addr) { |
| 536 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 547 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 537 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u32))) | 548 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u32))) |
| 538 | if (auto result = handler->Read32(addr)) | 549 | if (auto result = handler->Read32(addr)) |
| 539 | return *result; | 550 | return *result; |
| @@ -542,7 +553,7 @@ boost::optional<u32> ReadSpecial<u32>(VAddr addr) { | |||
| 542 | 553 | ||
| 543 | template <> | 554 | template <> |
| 544 | boost::optional<u64> ReadSpecial<u64>(VAddr addr) { | 555 | boost::optional<u64> ReadSpecial<u64>(VAddr addr) { |
| 545 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 556 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 546 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u64))) | 557 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u64))) |
| 547 | if (auto result = handler->Read64(addr)) | 558 | if (auto result = handler->Read64(addr)) |
| 548 | return *result; | 559 | return *result; |
| @@ -551,7 +562,7 @@ boost::optional<u64> ReadSpecial<u64>(VAddr addr) { | |||
| 551 | 562 | ||
| 552 | template <> | 563 | template <> |
| 553 | bool WriteSpecial<u8>(VAddr addr, const u8 data) { | 564 | bool WriteSpecial<u8>(VAddr addr, const u8 data) { |
| 554 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 565 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 555 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u8))) | 566 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u8))) |
| 556 | if (handler->Write8(addr, data)) | 567 | if (handler->Write8(addr, data)) |
| 557 | return true; | 568 | return true; |
| @@ -560,7 +571,7 @@ bool WriteSpecial<u8>(VAddr addr, const u8 data) { | |||
| 560 | 571 | ||
| 561 | template <> | 572 | template <> |
| 562 | bool WriteSpecial<u16>(VAddr addr, const u16 data) { | 573 | bool WriteSpecial<u16>(VAddr addr, const u16 data) { |
| 563 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 574 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 564 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u16))) | 575 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u16))) |
| 565 | if (handler->Write16(addr, data)) | 576 | if (handler->Write16(addr, data)) |
| 566 | return true; | 577 | return true; |
| @@ -569,7 +580,7 @@ bool WriteSpecial<u16>(VAddr addr, const u16 data) { | |||
| 569 | 580 | ||
| 570 | template <> | 581 | template <> |
| 571 | bool WriteSpecial<u32>(VAddr addr, const u32 data) { | 582 | bool WriteSpecial<u32>(VAddr addr, const u32 data) { |
| 572 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 583 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 573 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u32))) | 584 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u32))) |
| 574 | if (handler->Write32(addr, data)) | 585 | if (handler->Write32(addr, data)) |
| 575 | return true; | 586 | return true; |
| @@ -578,7 +589,7 @@ bool WriteSpecial<u32>(VAddr addr, const u32 data) { | |||
| 578 | 589 | ||
| 579 | template <> | 590 | template <> |
| 580 | bool WriteSpecial<u64>(VAddr addr, const u64 data) { | 591 | bool WriteSpecial<u64>(VAddr addr, const u64 data) { |
| 581 | const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table; | 592 | const PageTable& page_table = Core::CurrentProcess()->vm_manager.page_table; |
| 582 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u64))) | 593 | for (const auto& handler : GetSpecialHandlers(page_table, addr, sizeof(u64))) |
| 583 | if (handler->Write64(addr, data)) | 594 | if (handler->Write64(addr, data)) |
| 584 | return true; | 595 | return true; |
| @@ -621,7 +632,7 @@ boost::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) { | |||
| 621 | } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { | 632 | } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { |
| 622 | return addr - VRAM_PADDR + VRAM_VADDR; | 633 | return addr - VRAM_PADDR + VRAM_VADDR; |
| 623 | } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { | 634 | } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { |
| 624 | return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapAreaAddress(); | 635 | return addr - FCRAM_PADDR + Core::CurrentProcess()->GetLinearHeapAreaAddress(); |
| 625 | } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { | 636 | } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { |
| 626 | return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; | 637 | return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; |
| 627 | } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { | 638 | } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { |
diff --git a/src/core/memory.h b/src/core/memory.h index f3ace7a98..f406cc848 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -129,21 +129,6 @@ enum : VAddr { | |||
| 129 | PROCESS_IMAGE_MAX_SIZE = 0x08000000, | 129 | PROCESS_IMAGE_MAX_SIZE = 0x08000000, |
| 130 | PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, | 130 | PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, |
| 131 | 131 | ||
| 132 | /// Area where IPC buffers are mapped onto. | ||
| 133 | IPC_MAPPING_VADDR = 0x04000000, | ||
| 134 | IPC_MAPPING_SIZE = 0x04000000, | ||
| 135 | IPC_MAPPING_VADDR_END = IPC_MAPPING_VADDR + IPC_MAPPING_SIZE, | ||
| 136 | |||
| 137 | /// Application heap (includes stack). | ||
| 138 | HEAP_VADDR = 0x108000000, | ||
| 139 | HEAP_SIZE = 0xF0000000, | ||
| 140 | HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, | ||
| 141 | |||
| 142 | /// Area where shared memory buffers are mapped onto. | ||
| 143 | SHARED_MEMORY_VADDR = 0x10000000, | ||
| 144 | SHARED_MEMORY_SIZE = 0x04000000, | ||
| 145 | SHARED_MEMORY_VADDR_END = SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE, | ||
| 146 | |||
| 147 | /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical | 132 | /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical |
| 148 | /// memory. | 133 | /// memory. |
| 149 | LINEAR_HEAP_VADDR = 0x14000000, | 134 | LINEAR_HEAP_VADDR = 0x14000000, |
| @@ -176,14 +161,39 @@ enum : VAddr { | |||
| 176 | SHARED_PAGE_SIZE = 0x00001000, | 161 | SHARED_PAGE_SIZE = 0x00001000, |
| 177 | SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, | 162 | SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, |
| 178 | 163 | ||
| 179 | /// Area where TLS (Thread-Local Storage) buffers are allocated. | ||
| 180 | TLS_AREA_VADDR = 0x228000000, | ||
| 181 | TLS_ENTRY_SIZE = 0x200, | ||
| 182 | |||
| 183 | /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS. | 164 | /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS. |
| 184 | NEW_LINEAR_HEAP_VADDR = 0x30000000, | 165 | NEW_LINEAR_HEAP_VADDR = 0x30000000, |
| 185 | NEW_LINEAR_HEAP_SIZE = 0x10000000, | 166 | NEW_LINEAR_HEAP_SIZE = 0x10000000, |
| 186 | NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE, | 167 | NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE, |
| 168 | |||
| 169 | /// Area where TLS (Thread-Local Storage) buffers are allocated. | ||
| 170 | TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END, | ||
| 171 | TLS_ENTRY_SIZE = 0x200, | ||
| 172 | TLS_AREA_SIZE = 0x10000000, | ||
| 173 | TLS_ADREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, | ||
| 174 | |||
| 175 | /// Application stack | ||
| 176 | STACK_VADDR = TLS_ADREA_VADDR_END, | ||
| 177 | STACK_SIZE = 0x10000, | ||
| 178 | STACK_VADDR_END = STACK_VADDR + STACK_SIZE, | ||
| 179 | |||
| 180 | /// Application heap | ||
| 181 | /// Size is confirmed to be a static value on fw 3.0.0 | ||
| 182 | HEAP_VADDR = 0x108000000, | ||
| 183 | HEAP_SIZE = 0x180000000, | ||
| 184 | HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, | ||
| 185 | |||
| 186 | /// New map region | ||
| 187 | /// Size is confirmed to be a static value on fw 3.0.0 | ||
| 188 | NEW_MAP_REGION_VADDR = HEAP_VADDR_END, | ||
| 189 | NEW_MAP_REGION_SIZE = 0x80000000, | ||
| 190 | NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE, | ||
| 191 | |||
| 192 | /// Map region | ||
| 193 | /// Size is confirmed to be a static value on fw 3.0.0 | ||
| 194 | MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, | ||
| 195 | MAP_REGION_SIZE = 0x1000000000, | ||
| 196 | MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, | ||
| 187 | }; | 197 | }; |
| 188 | 198 | ||
| 189 | /// Currently active page table | 199 | /// Currently active page table |
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 88bbbc95c..7f9f27e19 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp | |||
| @@ -15,8 +15,8 @@ static Memory::PageTable* page_table = nullptr; | |||
| 15 | TestEnvironment::TestEnvironment(bool mutable_memory_) | 15 | TestEnvironment::TestEnvironment(bool mutable_memory_) |
| 16 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { | 16 | : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { |
| 17 | 17 | ||
| 18 | Kernel::g_current_process = Kernel::Process::Create(""); | 18 | Core::CurrentProcess() = Kernel::Process::Create(""); |
| 19 | page_table = &Kernel::g_current_process->vm_manager.page_table; | 19 | page_table = &Core::CurrentProcess()->vm_manager.page_table; |
| 20 | 20 | ||
| 21 | page_table->pointers.fill(nullptr); | 21 | page_table->pointers.fill(nullptr); |
| 22 | page_table->special_regions.clear(); | 22 | page_table->special_regions.clear(); |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index ed87f8ff1..2f946e7be 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -7,6 +7,7 @@ add_library(video_core STATIC | |||
| 7 | engines/maxwell_3d.h | 7 | engines/maxwell_3d.h |
| 8 | engines/maxwell_compute.cpp | 8 | engines/maxwell_compute.cpp |
| 9 | engines/maxwell_compute.h | 9 | engines/maxwell_compute.h |
| 10 | gpu.cpp | ||
| 10 | gpu.h | 11 | gpu.h |
| 11 | memory_manager.cpp | 12 | memory_manager.cpp |
| 12 | memory_manager.h | 13 | memory_manager.h |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 21d672085..d4cdb4ab2 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -24,12 +24,37 @@ namespace Tegra { | |||
| 24 | 24 | ||
| 25 | enum class BufferMethods { | 25 | enum class BufferMethods { |
| 26 | BindObject = 0, | 26 | BindObject = 0, |
| 27 | SetGraphMacroCode = 0x45, | ||
| 28 | SetGraphMacroCodeArg = 0x46, | ||
| 29 | SetGraphMacroEntry = 0x47, | ||
| 27 | CountBufferMethods = 0x100, | 30 | CountBufferMethods = 0x100, |
| 28 | }; | 31 | }; |
| 29 | 32 | ||
| 30 | void GPU::WriteReg(u32 method, u32 subchannel, u32 value) { | 33 | void GPU::WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params) { |
| 31 | LOG_WARNING(HW_GPU, "Processing method %08X on subchannel %u value %08X", method, subchannel, | 34 | LOG_WARNING(HW_GPU, "Processing method %08X on subchannel %u value %08X remaining params %u", |
| 32 | value); | 35 | method, subchannel, value, remaining_params); |
| 36 | |||
| 37 | if (method == static_cast<u32>(BufferMethods::SetGraphMacroEntry)) { | ||
| 38 | // Prepare to upload a new macro, reset the upload counter. | ||
| 39 | LOG_DEBUG(HW_GPU, "Uploading GPU macro %08X", value); | ||
| 40 | current_macro_entry = value; | ||
| 41 | current_macro_code.clear(); | ||
| 42 | return; | ||
| 43 | } | ||
| 44 | |||
| 45 | if (method == static_cast<u32>(BufferMethods::SetGraphMacroCodeArg)) { | ||
| 46 | // Append a new code word to the current macro. | ||
| 47 | current_macro_code.push_back(value); | ||
| 48 | |||
| 49 | // There are no more params remaining, submit the code to the 3D engine. | ||
| 50 | if (remaining_params == 0) { | ||
| 51 | maxwell_3d->SubmitMacroCode(current_macro_entry, std::move(current_macro_code)); | ||
| 52 | current_macro_entry = InvalidGraphMacroEntry; | ||
| 53 | current_macro_code.clear(); | ||
| 54 | } | ||
| 55 | |||
| 56 | return; | ||
| 57 | } | ||
| 33 | 58 | ||
| 34 | if (method == static_cast<u32>(BufferMethods::BindObject)) { | 59 | if (method == static_cast<u32>(BufferMethods::BindObject)) { |
| 35 | // Bind the current subchannel to the desired engine id. | 60 | // Bind the current subchannel to the desired engine id. |
| @@ -54,7 +79,7 @@ void GPU::WriteReg(u32 method, u32 subchannel, u32 value) { | |||
| 54 | fermi_2d->WriteReg(method, value); | 79 | fermi_2d->WriteReg(method, value); |
| 55 | break; | 80 | break; |
| 56 | case EngineID::MAXWELL_B: | 81 | case EngineID::MAXWELL_B: |
| 57 | maxwell_3d->WriteReg(method, value); | 82 | maxwell_3d->WriteReg(method, value, remaining_params); |
| 58 | break; | 83 | break; |
| 59 | case EngineID::MAXWELL_COMPUTE_B: | 84 | case EngineID::MAXWELL_COMPUTE_B: |
| 60 | maxwell_compute->WriteReg(method, value); | 85 | maxwell_compute->WriteReg(method, value); |
| @@ -78,7 +103,8 @@ void GPU::ProcessCommandList(GPUVAddr address, u32 size) { | |||
| 78 | case SubmissionMode::Increasing: { | 103 | case SubmissionMode::Increasing: { |
| 79 | // Increase the method value with each argument. | 104 | // Increase the method value with each argument. |
| 80 | for (unsigned i = 0; i < header.arg_count; ++i) { | 105 | for (unsigned i = 0; i < header.arg_count; ++i) { |
| 81 | WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr)); | 106 | WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr), |
| 107 | header.arg_count - i - 1); | ||
| 82 | current_addr += sizeof(u32); | 108 | current_addr += sizeof(u32); |
| 83 | } | 109 | } |
| 84 | break; | 110 | break; |
| @@ -87,27 +113,31 @@ void GPU::ProcessCommandList(GPUVAddr address, u32 size) { | |||
| 87 | case SubmissionMode::NonIncreasing: { | 113 | case SubmissionMode::NonIncreasing: { |
| 88 | // Use the same method value for all arguments. | 114 | // Use the same method value for all arguments. |
| 89 | for (unsigned i = 0; i < header.arg_count; ++i) { | 115 | for (unsigned i = 0; i < header.arg_count; ++i) { |
| 90 | WriteReg(header.method, header.subchannel, Memory::Read32(current_addr)); | 116 | WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), |
| 117 | header.arg_count - i - 1); | ||
| 91 | current_addr += sizeof(u32); | 118 | current_addr += sizeof(u32); |
| 92 | } | 119 | } |
| 93 | break; | 120 | break; |
| 94 | } | 121 | } |
| 95 | case SubmissionMode::IncreaseOnce: { | 122 | case SubmissionMode::IncreaseOnce: { |
| 96 | ASSERT(header.arg_count.Value() >= 1); | 123 | ASSERT(header.arg_count.Value() >= 1); |
| 124 | |||
| 97 | // Use the original method for the first argument and then the next method for all other | 125 | // Use the original method for the first argument and then the next method for all other |
| 98 | // arguments. | 126 | // arguments. |
| 99 | WriteReg(header.method, header.subchannel, Memory::Read32(current_addr)); | 127 | WriteReg(header.method, header.subchannel, Memory::Read32(current_addr), |
| 128 | header.arg_count - 1); | ||
| 100 | current_addr += sizeof(u32); | 129 | current_addr += sizeof(u32); |
| 101 | // Use the same method value for all arguments. | 130 | |
| 102 | for (unsigned i = 1; i < header.arg_count; ++i) { | 131 | for (unsigned i = 1; i < header.arg_count; ++i) { |
| 103 | WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr)); | 132 | WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr), |
| 133 | header.arg_count - i - 1); | ||
| 104 | current_addr += sizeof(u32); | 134 | current_addr += sizeof(u32); |
| 105 | } | 135 | } |
| 106 | break; | 136 | break; |
| 107 | } | 137 | } |
| 108 | case SubmissionMode::Inline: { | 138 | case SubmissionMode::Inline: { |
| 109 | // The register value is stored in the bits 16-28 as an immediate | 139 | // The register value is stored in the bits 16-28 as an immediate |
| 110 | WriteReg(header.method, header.subchannel, header.inline_data); | 140 | WriteReg(header.method, header.subchannel, header.inline_data, 0); |
| 111 | break; | 141 | break; |
| 112 | } | 142 | } |
| 113 | default: | 143 | default: |
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h index b511bfcf7..f7214ffec 100644 --- a/src/video_core/command_processor.h +++ b/src/video_core/command_processor.h | |||
| @@ -34,6 +34,4 @@ static_assert(std::is_standard_layout<CommandHeader>::value == true, | |||
| 34 | "CommandHeader does not use standard layout"); | 34 | "CommandHeader does not use standard layout"); |
| 35 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); | 35 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); |
| 36 | 36 | ||
| 37 | void ProcessCommandList(VAddr address, u32 size); | ||
| 38 | |||
| 39 | } // namespace Tegra | 37 | } // namespace Tegra |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 9f699399f..4fdea0fdc 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -8,17 +8,126 @@ | |||
| 8 | namespace Tegra { | 8 | namespace Tegra { |
| 9 | namespace Engines { | 9 | namespace Engines { |
| 10 | 10 | ||
| 11 | /// First register id that is actually a Macro call. | ||
| 12 | constexpr u32 MacroRegistersStart = 0xE00; | ||
| 13 | |||
| 14 | const std::unordered_map<u32, Maxwell3D::MethodInfo> Maxwell3D::method_handlers = { | ||
| 15 | {0xE1A, {"BindTextureInfoBuffer", 1, &Maxwell3D::BindTextureInfoBuffer}}, | ||
| 16 | {0xE24, {"SetShader", 5, &Maxwell3D::SetShader}}, | ||
| 17 | {0xE2A, {"BindStorageBuffer", 1, &Maxwell3D::BindStorageBuffer}}, | ||
| 18 | }; | ||
| 19 | |||
| 11 | Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {} | 20 | Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {} |
| 12 | 21 | ||
| 13 | void Maxwell3D::WriteReg(u32 method, u32 value) { | 22 | void Maxwell3D::SubmitMacroCode(u32 entry, std::vector<u32> code) { |
| 23 | uploaded_macros[entry * 2 + MacroRegistersStart] = std::move(code); | ||
| 24 | } | ||
| 25 | |||
| 26 | void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) { | ||
| 27 | // TODO(Subv): Write an interpreter for the macros uploaded via registers 0x45 and 0x47 | ||
| 28 | |||
| 29 | // The requested macro must have been uploaded already. | ||
| 30 | ASSERT_MSG(uploaded_macros.find(method) != uploaded_macros.end(), "Macro %08X was not uploaded", | ||
| 31 | method); | ||
| 32 | |||
| 33 | auto itr = method_handlers.find(method); | ||
| 34 | ASSERT_MSG(itr != method_handlers.end(), "Unhandled method call %08X", method); | ||
| 35 | |||
| 36 | ASSERT(itr->second.arguments == parameters.size()); | ||
| 37 | |||
| 38 | (this->*itr->second.handler)(parameters); | ||
| 39 | |||
| 40 | // Reset the current macro and its parameters. | ||
| 41 | executing_macro = 0; | ||
| 42 | macro_params.clear(); | ||
| 43 | } | ||
| 44 | |||
| 45 | void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | ||
| 14 | ASSERT_MSG(method < Regs::NUM_REGS, | 46 | ASSERT_MSG(method < Regs::NUM_REGS, |
| 15 | "Invalid Maxwell3D register, increase the size of the Regs structure"); | 47 | "Invalid Maxwell3D register, increase the size of the Regs structure"); |
| 16 | 48 | ||
| 49 | // It is an error to write to a register other than the current macro's ARG register before it | ||
| 50 | // has finished execution. | ||
| 51 | if (executing_macro != 0) { | ||
| 52 | ASSERT(method == executing_macro + 1); | ||
| 53 | } | ||
| 54 | |||
| 55 | // Methods after 0xE00 are special, they're actually triggers for some microcode that was | ||
| 56 | // uploaded to the GPU during initialization. | ||
| 57 | if (method >= MacroRegistersStart) { | ||
| 58 | // We're trying to execute a macro | ||
| 59 | if (executing_macro == 0) { | ||
| 60 | // A macro call must begin by writing the macro method's register, not its argument. | ||
| 61 | ASSERT_MSG((method % 2) == 0, | ||
| 62 | "Can't start macro execution by writing to the ARGS register"); | ||
| 63 | executing_macro = method; | ||
| 64 | } | ||
| 65 | |||
| 66 | macro_params.push_back(value); | ||
| 67 | |||
| 68 | // Call the macro when there are no more parameters in the command buffer | ||
| 69 | if (remaining_params == 0) { | ||
| 70 | CallMacroMethod(executing_macro, macro_params); | ||
| 71 | } | ||
| 72 | return; | ||
| 73 | } | ||
| 74 | |||
| 17 | regs.reg_array[method] = value; | 75 | regs.reg_array[method] = value; |
| 18 | 76 | ||
| 19 | #define MAXWELL3D_REG_INDEX(field_name) (offsetof(Regs, field_name) / sizeof(u32)) | 77 | #define MAXWELL3D_REG_INDEX(field_name) (offsetof(Regs, field_name) / sizeof(u32)) |
| 20 | 78 | ||
| 21 | switch (method) { | 79 | switch (method) { |
| 80 | case MAXWELL3D_REG_INDEX(code_address.code_address_high): | ||
| 81 | case MAXWELL3D_REG_INDEX(code_address.code_address_low): { | ||
| 82 | // Note: For some reason games (like Puyo Puyo Tetris) seem to write 0 to the CODE_ADDRESS | ||
| 83 | // register, we do not currently know if that's intended or a bug, so we assert it lest | ||
| 84 | // stuff breaks in other places (like the shader address calculation). | ||
| 85 | ASSERT_MSG(regs.code_address.CodeAddress() == 0, "Unexpected CODE_ADDRESS register value."); | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): | ||
| 89 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): | ||
| 90 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]): | ||
| 91 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]): | ||
| 92 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]): | ||
| 93 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]): | ||
| 94 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]): | ||
| 95 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]): | ||
| 96 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]): | ||
| 97 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]): | ||
| 98 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]): | ||
| 99 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]): | ||
| 100 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]): | ||
| 101 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): | ||
| 102 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): | ||
| 103 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { | ||
| 104 | ProcessCBData(value); | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { | ||
| 108 | ProcessCBBind(Regs::ShaderStage::Vertex); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | case MAXWELL3D_REG_INDEX(cb_bind[1].raw_config): { | ||
| 112 | ProcessCBBind(Regs::ShaderStage::TesselationControl); | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | case MAXWELL3D_REG_INDEX(cb_bind[2].raw_config): { | ||
| 116 | ProcessCBBind(Regs::ShaderStage::TesselationEval); | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | case MAXWELL3D_REG_INDEX(cb_bind[3].raw_config): { | ||
| 120 | ProcessCBBind(Regs::ShaderStage::Geometry); | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | case MAXWELL3D_REG_INDEX(cb_bind[4].raw_config): { | ||
| 124 | ProcessCBBind(Regs::ShaderStage::Fragment); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | case MAXWELL3D_REG_INDEX(draw.vertex_end_gl): { | ||
| 128 | DrawArrays(); | ||
| 129 | break; | ||
| 130 | } | ||
| 22 | case MAXWELL3D_REG_INDEX(query.query_get): { | 131 | case MAXWELL3D_REG_INDEX(query.query_get): { |
| 23 | ProcessQueryGet(); | 132 | ProcessQueryGet(); |
| 24 | break; | 133 | break; |
| @@ -47,5 +156,118 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 47 | UNIMPLEMENTED_MSG("Query mode %u not implemented", regs.query.query_get.mode.Value()); | 156 | UNIMPLEMENTED_MSG("Query mode %u not implemented", regs.query.query_get.mode.Value()); |
| 48 | } | 157 | } |
| 49 | } | 158 | } |
| 159 | |||
| 160 | void Maxwell3D::DrawArrays() { | ||
| 161 | LOG_WARNING(HW_GPU, "Game requested a DrawArrays, ignoring"); | ||
| 162 | } | ||
| 163 | |||
| 164 | void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) { | ||
| 165 | /** | ||
| 166 | * Parameters description: | ||
| 167 | * [0] = Shader stage, usually 4 for FragmentShader | ||
| 168 | */ | ||
| 169 | |||
| 170 | u32 stage = parameters[0]; | ||
| 171 | |||
| 172 | // Perform the same operations as the real macro code. | ||
| 173 | GPUVAddr address = static_cast<GPUVAddr>(regs.tex_info_buffers.address[stage]) << 8; | ||
| 174 | u32 size = regs.tex_info_buffers.size[stage]; | ||
| 175 | |||
| 176 | regs.const_buffer.cb_size = size; | ||
| 177 | regs.const_buffer.cb_address_high = address >> 32; | ||
| 178 | regs.const_buffer.cb_address_low = address & 0xFFFFFFFF; | ||
| 179 | } | ||
| 180 | |||
| 181 | void Maxwell3D::SetShader(const std::vector<u32>& parameters) { | ||
| 182 | /** | ||
| 183 | * Parameters description: | ||
| 184 | * [0] = Shader Program. | ||
| 185 | * [1] = Unknown, presumably the shader id. | ||
| 186 | * [2] = Offset to the start of the shader, after the 0x30 bytes header. | ||
| 187 | * [3] = Shader Stage. | ||
| 188 | * [4] = Const Buffer Address >> 8. | ||
| 189 | */ | ||
| 190 | auto shader_program = static_cast<Regs::ShaderProgram>(parameters[0]); | ||
| 191 | // TODO(Subv): This address is probably an offset from the CODE_ADDRESS register. | ||
| 192 | GPUVAddr address = parameters[2]; | ||
| 193 | auto shader_stage = static_cast<Regs::ShaderStage>(parameters[3]); | ||
| 194 | GPUVAddr cb_address = parameters[4] << 8; | ||
| 195 | |||
| 196 | auto& shader = state.shader_programs[static_cast<size_t>(shader_program)]; | ||
| 197 | shader.program = shader_program; | ||
| 198 | shader.stage = shader_stage; | ||
| 199 | shader.address = address; | ||
| 200 | |||
| 201 | // Perform the same operations as the real macro code. | ||
| 202 | // TODO(Subv): Early exit if register 0xD1C + shader_program contains the same as params[1]. | ||
| 203 | auto& shader_regs = regs.shader_config[static_cast<size_t>(shader_program)]; | ||
| 204 | shader_regs.start_id = address; | ||
| 205 | // TODO(Subv): Write params[1] to register 0xD1C + shader_program. | ||
| 206 | // TODO(Subv): Write params[2] to register 0xD22 + shader_program. | ||
| 207 | |||
| 208 | // Note: This value is hardcoded in the macro's code. | ||
| 209 | static constexpr u32 DefaultCBSize = 0x10000; | ||
| 210 | regs.const_buffer.cb_size = DefaultCBSize; | ||
| 211 | regs.const_buffer.cb_address_high = cb_address >> 32; | ||
| 212 | regs.const_buffer.cb_address_low = cb_address & 0xFFFFFFFF; | ||
| 213 | |||
| 214 | // Write a hardcoded 0x11 to CB_BIND, this binds the current const buffer to buffer c1[] in the | ||
| 215 | // shader. It's likely that these are the constants for the shader. | ||
| 216 | regs.cb_bind[static_cast<size_t>(shader_stage)].valid.Assign(1); | ||
| 217 | regs.cb_bind[static_cast<size_t>(shader_stage)].index.Assign(1); | ||
| 218 | |||
| 219 | ProcessCBBind(shader_stage); | ||
| 220 | } | ||
| 221 | |||
| 222 | void Maxwell3D::BindStorageBuffer(const std::vector<u32>& parameters) { | ||
| 223 | /** | ||
| 224 | * Parameters description: | ||
| 225 | * [0] = Buffer offset >> 2 | ||
| 226 | */ | ||
| 227 | |||
| 228 | u32 buffer_offset = parameters[0] << 2; | ||
| 229 | |||
| 230 | // Perform the same operations as the real macro code. | ||
| 231 | // Note: This value is hardcoded in the macro's code. | ||
| 232 | static constexpr u32 DefaultCBSize = 0x5F00; | ||
| 233 | regs.const_buffer.cb_size = DefaultCBSize; | ||
| 234 | |||
| 235 | GPUVAddr address = regs.ssbo_info.BufferAddress(); | ||
| 236 | regs.const_buffer.cb_address_high = address >> 32; | ||
| 237 | regs.const_buffer.cb_address_low = address & 0xFFFFFFFF; | ||
| 238 | |||
| 239 | regs.const_buffer.cb_pos = buffer_offset; | ||
| 240 | } | ||
| 241 | |||
| 242 | void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { | ||
| 243 | // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage. | ||
| 244 | auto& shader = state.shader_stages[static_cast<size_t>(stage)]; | ||
| 245 | auto& bind_data = regs.cb_bind[static_cast<size_t>(stage)]; | ||
| 246 | |||
| 247 | auto& buffer = shader.const_buffers[bind_data.index]; | ||
| 248 | |||
| 249 | buffer.enabled = bind_data.valid.Value() != 0; | ||
| 250 | buffer.index = bind_data.index; | ||
| 251 | buffer.address = regs.const_buffer.BufferAddress(); | ||
| 252 | buffer.size = regs.const_buffer.cb_size; | ||
| 253 | } | ||
| 254 | |||
| 255 | void Maxwell3D::ProcessCBData(u32 value) { | ||
| 256 | // Write the input value to the current const buffer at the current position. | ||
| 257 | GPUVAddr buffer_address = regs.const_buffer.BufferAddress(); | ||
| 258 | ASSERT(buffer_address != 0); | ||
| 259 | |||
| 260 | // Don't allow writing past the end of the buffer. | ||
| 261 | ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size); | ||
| 262 | |||
| 263 | VAddr address = | ||
| 264 | memory_manager.PhysicalToVirtualAddress(buffer_address + regs.const_buffer.cb_pos); | ||
| 265 | |||
| 266 | Memory::Write32(address, value); | ||
| 267 | |||
| 268 | // Increment the current buffer position. | ||
| 269 | regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; | ||
| 270 | } | ||
| 271 | |||
| 50 | } // namespace Engines | 272 | } // namespace Engines |
| 51 | } // namespace Tegra | 273 | } // namespace Tegra |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 1eeef6857..5d9b0043b 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -4,6 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include <unordered_map> | ||
| 9 | #include <vector> | ||
| 7 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| 8 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 9 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -18,21 +21,63 @@ public: | |||
| 18 | ~Maxwell3D() = default; | 21 | ~Maxwell3D() = default; |
| 19 | 22 | ||
| 20 | /// Write the value to the register identified by method. | 23 | /// Write the value to the register identified by method. |
| 21 | void WriteReg(u32 method, u32 value); | 24 | void WriteReg(u32 method, u32 value, u32 remaining_params); |
| 25 | |||
| 26 | /// Uploads the code for a GPU macro program associated with the specified entry. | ||
| 27 | void SubmitMacroCode(u32 entry, std::vector<u32> code); | ||
| 22 | 28 | ||
| 23 | /// Register structure of the Maxwell3D engine. | 29 | /// Register structure of the Maxwell3D engine. |
| 24 | /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. | 30 | /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. |
| 25 | struct Regs { | 31 | struct Regs { |
| 26 | static constexpr size_t NUM_REGS = 0xE36; | 32 | static constexpr size_t NUM_REGS = 0xE36; |
| 27 | 33 | ||
| 34 | static constexpr size_t NumCBData = 16; | ||
| 35 | static constexpr size_t NumVertexArrays = 32; | ||
| 36 | static constexpr size_t MaxShaderProgram = 6; | ||
| 37 | static constexpr size_t MaxShaderStage = 5; | ||
| 38 | // Maximum number of const buffers per shader stage. | ||
| 39 | static constexpr size_t MaxConstBuffers = 16; | ||
| 40 | |||
| 28 | enum class QueryMode : u32 { | 41 | enum class QueryMode : u32 { |
| 29 | Write = 0, | 42 | Write = 0, |
| 30 | Sync = 1, | 43 | Sync = 1, |
| 31 | }; | 44 | }; |
| 32 | 45 | ||
| 46 | enum class ShaderProgram : u32 { | ||
| 47 | VertexA = 0, | ||
| 48 | VertexB = 1, | ||
| 49 | TesselationControl = 2, | ||
| 50 | TesselationEval = 3, | ||
| 51 | Geometry = 4, | ||
| 52 | Fragment = 5, | ||
| 53 | }; | ||
| 54 | |||
| 55 | enum class ShaderStage : u32 { | ||
| 56 | Vertex = 0, | ||
| 57 | TesselationControl = 1, | ||
| 58 | TesselationEval = 2, | ||
| 59 | Geometry = 3, | ||
| 60 | Fragment = 4, | ||
| 61 | }; | ||
| 62 | |||
| 33 | union { | 63 | union { |
| 34 | struct { | 64 | struct { |
| 35 | INSERT_PADDING_WORDS(0x6C0); | 65 | INSERT_PADDING_WORDS(0x582); |
| 66 | struct { | ||
| 67 | u32 code_address_high; | ||
| 68 | u32 code_address_low; | ||
| 69 | |||
| 70 | GPUVAddr CodeAddress() const { | ||
| 71 | return static_cast<GPUVAddr>( | ||
| 72 | (static_cast<GPUVAddr>(code_address_high) << 32) | code_address_low); | ||
| 73 | } | ||
| 74 | } code_address; | ||
| 75 | INSERT_PADDING_WORDS(1); | ||
| 76 | struct { | ||
| 77 | u32 vertex_end_gl; | ||
| 78 | u32 vertex_begin_gl; | ||
| 79 | } draw; | ||
| 80 | INSERT_PADDING_WORDS(0x139); | ||
| 36 | struct { | 81 | struct { |
| 37 | u32 query_address_high; | 82 | u32 query_address_high; |
| 38 | u32 query_address_low; | 83 | u32 query_address_low; |
| @@ -49,7 +94,98 @@ public: | |||
| 49 | (static_cast<GPUVAddr>(query_address_high) << 32) | query_address_low); | 94 | (static_cast<GPUVAddr>(query_address_high) << 32) | query_address_low); |
| 50 | } | 95 | } |
| 51 | } query; | 96 | } query; |
| 52 | INSERT_PADDING_WORDS(0x772); | 97 | |
| 98 | INSERT_PADDING_WORDS(0x3C); | ||
| 99 | |||
| 100 | struct { | ||
| 101 | union { | ||
| 102 | BitField<0, 12, u32> stride; | ||
| 103 | BitField<12, 1, u32> enable; | ||
| 104 | }; | ||
| 105 | u32 start_high; | ||
| 106 | u32 start_low; | ||
| 107 | u32 divisor; | ||
| 108 | |||
| 109 | GPUVAddr StartAddress() const { | ||
| 110 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(start_high) << 32) | | ||
| 111 | start_low); | ||
| 112 | } | ||
| 113 | } vertex_array[NumVertexArrays]; | ||
| 114 | |||
| 115 | INSERT_PADDING_WORDS(0x40); | ||
| 116 | |||
| 117 | struct { | ||
| 118 | u32 limit_high; | ||
| 119 | u32 limit_low; | ||
| 120 | |||
| 121 | GPUVAddr LimitAddress() const { | ||
| 122 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(limit_high) << 32) | | ||
| 123 | limit_low); | ||
| 124 | } | ||
| 125 | } vertex_array_limit[NumVertexArrays]; | ||
| 126 | |||
| 127 | struct { | ||
| 128 | union { | ||
| 129 | BitField<0, 1, u32> enable; | ||
| 130 | BitField<4, 4, ShaderProgram> program; | ||
| 131 | }; | ||
| 132 | u32 start_id; | ||
| 133 | INSERT_PADDING_WORDS(1); | ||
| 134 | u32 gpr_alloc; | ||
| 135 | ShaderStage type; | ||
| 136 | INSERT_PADDING_WORDS(9); | ||
| 137 | } shader_config[MaxShaderProgram]; | ||
| 138 | |||
| 139 | INSERT_PADDING_WORDS(0x8C); | ||
| 140 | |||
| 141 | struct { | ||
| 142 | u32 cb_size; | ||
| 143 | u32 cb_address_high; | ||
| 144 | u32 cb_address_low; | ||
| 145 | u32 cb_pos; | ||
| 146 | u32 cb_data[NumCBData]; | ||
| 147 | |||
| 148 | GPUVAddr BufferAddress() const { | ||
| 149 | return static_cast<GPUVAddr>( | ||
| 150 | (static_cast<GPUVAddr>(cb_address_high) << 32) | cb_address_low); | ||
| 151 | } | ||
| 152 | } const_buffer; | ||
| 153 | |||
| 154 | INSERT_PADDING_WORDS(0x10); | ||
| 155 | |||
| 156 | struct { | ||
| 157 | union { | ||
| 158 | u32 raw_config; | ||
| 159 | BitField<0, 1, u32> valid; | ||
| 160 | BitField<4, 5, u32> index; | ||
| 161 | }; | ||
| 162 | INSERT_PADDING_WORDS(7); | ||
| 163 | } cb_bind[MaxShaderStage]; | ||
| 164 | |||
| 165 | INSERT_PADDING_WORDS(0x56); | ||
| 166 | |||
| 167 | u32 tex_cb_index; | ||
| 168 | |||
| 169 | INSERT_PADDING_WORDS(0x395); | ||
| 170 | |||
| 171 | struct { | ||
| 172 | /// Compressed address of a buffer that holds information about bound SSBOs. | ||
| 173 | /// This address is usually bound to c0 in the shaders. | ||
| 174 | u32 buffer_address; | ||
| 175 | |||
| 176 | GPUVAddr BufferAddress() const { | ||
| 177 | return static_cast<GPUVAddr>(buffer_address) << 8; | ||
| 178 | } | ||
| 179 | } ssbo_info; | ||
| 180 | |||
| 181 | INSERT_PADDING_WORDS(0x11); | ||
| 182 | |||
| 183 | struct { | ||
| 184 | u32 address[MaxShaderStage]; | ||
| 185 | u32 size[MaxShaderStage]; | ||
| 186 | } tex_info_buffers; | ||
| 187 | |||
| 188 | INSERT_PADDING_WORDS(0x102); | ||
| 53 | }; | 189 | }; |
| 54 | std::array<u32, NUM_REGS> reg_array; | 190 | std::array<u32, NUM_REGS> reg_array; |
| 55 | }; | 191 | }; |
| @@ -57,18 +193,89 @@ public: | |||
| 57 | 193 | ||
| 58 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size"); | 194 | static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size"); |
| 59 | 195 | ||
| 196 | struct State { | ||
| 197 | struct ConstBufferInfo { | ||
| 198 | GPUVAddr address; | ||
| 199 | u32 index; | ||
| 200 | u32 size; | ||
| 201 | bool enabled; | ||
| 202 | }; | ||
| 203 | |||
| 204 | struct ShaderProgramInfo { | ||
| 205 | Regs::ShaderStage stage; | ||
| 206 | Regs::ShaderProgram program; | ||
| 207 | GPUVAddr address; | ||
| 208 | }; | ||
| 209 | |||
| 210 | struct ShaderStageInfo { | ||
| 211 | std::array<ConstBufferInfo, Regs::MaxConstBuffers> const_buffers; | ||
| 212 | }; | ||
| 213 | |||
| 214 | std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages; | ||
| 215 | std::array<ShaderProgramInfo, Regs::MaxShaderProgram> shader_programs; | ||
| 216 | }; | ||
| 217 | |||
| 218 | State state{}; | ||
| 219 | |||
| 60 | private: | 220 | private: |
| 221 | MemoryManager& memory_manager; | ||
| 222 | |||
| 223 | std::unordered_map<u32, std::vector<u32>> uploaded_macros; | ||
| 224 | |||
| 225 | /// Macro method that is currently being executed / being fed parameters. | ||
| 226 | u32 executing_macro = 0; | ||
| 227 | /// Parameters that have been submitted to the macro call so far. | ||
| 228 | std::vector<u32> macro_params; | ||
| 229 | |||
| 230 | /** | ||
| 231 | * Call a macro on this engine. | ||
| 232 | * @param method Method to call | ||
| 233 | * @param parameters Arguments to the method call | ||
| 234 | */ | ||
| 235 | void CallMacroMethod(u32 method, const std::vector<u32>& parameters); | ||
| 236 | |||
| 61 | /// Handles a write to the QUERY_GET register. | 237 | /// Handles a write to the QUERY_GET register. |
| 62 | void ProcessQueryGet(); | 238 | void ProcessQueryGet(); |
| 63 | 239 | ||
| 64 | MemoryManager& memory_manager; | 240 | /// Handles a write to the CB_DATA[i] register. |
| 241 | void ProcessCBData(u32 value); | ||
| 242 | |||
| 243 | /// Handles a write to the CB_BIND register. | ||
| 244 | void ProcessCBBind(Regs::ShaderStage stage); | ||
| 245 | |||
| 246 | /// Handles a write to the VERTEX_END_GL register, triggering a draw. | ||
| 247 | void DrawArrays(); | ||
| 248 | |||
| 249 | /// Method call handlers | ||
| 250 | void BindTextureInfoBuffer(const std::vector<u32>& parameters); | ||
| 251 | void SetShader(const std::vector<u32>& parameters); | ||
| 252 | void BindStorageBuffer(const std::vector<u32>& parameters); | ||
| 253 | |||
| 254 | struct MethodInfo { | ||
| 255 | const char* name; | ||
| 256 | u32 arguments; | ||
| 257 | void (Maxwell3D::*handler)(const std::vector<u32>& parameters); | ||
| 258 | }; | ||
| 259 | |||
| 260 | static const std::unordered_map<u32, MethodInfo> method_handlers; | ||
| 65 | }; | 261 | }; |
| 66 | 262 | ||
| 67 | #define ASSERT_REG_POSITION(field_name, position) \ | 263 | #define ASSERT_REG_POSITION(field_name, position) \ |
| 68 | static_assert(offsetof(Maxwell3D::Regs, field_name) == position * 4, \ | 264 | static_assert(offsetof(Maxwell3D::Regs, field_name) == position * 4, \ |
| 69 | "Field " #field_name " has invalid position") | 265 | "Field " #field_name " has invalid position") |
| 70 | 266 | ||
| 267 | ASSERT_REG_POSITION(code_address, 0x582); | ||
| 268 | ASSERT_REG_POSITION(draw, 0x585); | ||
| 71 | ASSERT_REG_POSITION(query, 0x6C0); | 269 | ASSERT_REG_POSITION(query, 0x6C0); |
| 270 | ASSERT_REG_POSITION(vertex_array[0], 0x700); | ||
| 271 | ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); | ||
| 272 | ASSERT_REG_POSITION(shader_config[0], 0x800); | ||
| 273 | ASSERT_REG_POSITION(const_buffer, 0x8E0); | ||
| 274 | ASSERT_REG_POSITION(cb_bind[0], 0x904); | ||
| 275 | ASSERT_REG_POSITION(tex_cb_index, 0x982); | ||
| 276 | ASSERT_REG_POSITION(ssbo_info, 0xD18); | ||
| 277 | ASSERT_REG_POSITION(tex_info_buffers.address[0], 0xD2A); | ||
| 278 | ASSERT_REG_POSITION(tex_info_buffers.size[0], 0xD2F); | ||
| 72 | 279 | ||
| 73 | #undef ASSERT_REG_POSITION | 280 | #undef ASSERT_REG_POSITION |
| 74 | 281 | ||
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp new file mode 100644 index 000000000..c384d236e --- /dev/null +++ b/src/video_core/gpu.cpp | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "video_core/engines/fermi_2d.h" | ||
| 6 | #include "video_core/engines/maxwell_3d.h" | ||
| 7 | #include "video_core/engines/maxwell_compute.h" | ||
| 8 | #include "video_core/gpu.h" | ||
| 9 | |||
| 10 | namespace Tegra { | ||
| 11 | |||
| 12 | GPU::GPU() { | ||
| 13 | memory_manager = std::make_unique<MemoryManager>(); | ||
| 14 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager); | ||
| 15 | fermi_2d = std::make_unique<Engines::Fermi2D>(); | ||
| 16 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | ||
| 17 | } | ||
| 18 | |||
| 19 | GPU::~GPU() = default; | ||
| 20 | |||
| 21 | } // namespace Tegra | ||
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index ba7781756..2a9064ba3 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -6,14 +6,18 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <unordered_map> | 8 | #include <unordered_map> |
| 9 | #include <vector> | ||
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "video_core/engines/fermi_2d.h" | ||
| 11 | #include "video_core/engines/maxwell_3d.h" | ||
| 12 | #include "video_core/engines/maxwell_compute.h" | ||
| 13 | #include "video_core/memory_manager.h" | 11 | #include "video_core/memory_manager.h" |
| 14 | 12 | ||
| 15 | namespace Tegra { | 13 | namespace Tegra { |
| 16 | 14 | ||
| 15 | namespace Engines { | ||
| 16 | class Fermi2D; | ||
| 17 | class Maxwell3D; | ||
| 18 | class MaxwellCompute; | ||
| 19 | } // namespace Engines | ||
| 20 | |||
| 17 | enum class EngineID { | 21 | enum class EngineID { |
| 18 | FERMI_TWOD_A = 0x902D, // 2D Engine | 22 | FERMI_TWOD_A = 0x902D, // 2D Engine |
| 19 | MAXWELL_B = 0xB197, // 3D Engine | 23 | MAXWELL_B = 0xB197, // 3D Engine |
| @@ -24,13 +28,8 @@ enum class EngineID { | |||
| 24 | 28 | ||
| 25 | class GPU final { | 29 | class GPU final { |
| 26 | public: | 30 | public: |
| 27 | GPU() { | 31 | GPU(); |
| 28 | memory_manager = std::make_unique<MemoryManager>(); | 32 | ~GPU(); |
| 29 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(*memory_manager); | ||
| 30 | fermi_2d = std::make_unique<Engines::Fermi2D>(); | ||
| 31 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | ||
| 32 | } | ||
| 33 | ~GPU() = default; | ||
| 34 | 33 | ||
| 35 | /// Processes a command list stored at the specified address in GPU memory. | 34 | /// Processes a command list stored at the specified address in GPU memory. |
| 36 | void ProcessCommandList(GPUVAddr address, u32 size); | 35 | void ProcessCommandList(GPUVAddr address, u32 size); |
| @@ -38,8 +37,10 @@ public: | |||
| 38 | std::unique_ptr<MemoryManager> memory_manager; | 37 | std::unique_ptr<MemoryManager> memory_manager; |
| 39 | 38 | ||
| 40 | private: | 39 | private: |
| 40 | static constexpr u32 InvalidGraphMacroEntry = 0xFFFFFFFF; | ||
| 41 | |||
| 41 | /// Writes a single register in the engine bound to the specified subchannel | 42 | /// Writes a single register in the engine bound to the specified subchannel |
| 42 | void WriteReg(u32 method, u32 subchannel, u32 value); | 43 | void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params); |
| 43 | 44 | ||
| 44 | /// Mapping of command subchannels to their bound engine ids. | 45 | /// Mapping of command subchannels to their bound engine ids. |
| 45 | std::unordered_map<u32, EngineID> bound_engines; | 46 | std::unordered_map<u32, EngineID> bound_engines; |
| @@ -50,6 +51,11 @@ private: | |||
| 50 | std::unique_ptr<Engines::Fermi2D> fermi_2d; | 51 | std::unique_ptr<Engines::Fermi2D> fermi_2d; |
| 51 | /// Compute engine | 52 | /// Compute engine |
| 52 | std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; | 53 | std::unique_ptr<Engines::MaxwellCompute> maxwell_compute; |
| 54 | |||
| 55 | /// Entry of the macro that is currently being uploaded | ||
| 56 | u32 current_macro_entry = InvalidGraphMacroEntry; | ||
| 57 | /// Code being uploaded for the current macro | ||
| 58 | std::vector<u32> current_macro_code; | ||
| 53 | }; | 59 | }; |
| 54 | 60 | ||
| 55 | } // namespace Tegra | 61 | } // namespace Tegra |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index f9ddb9edc..71dc58e5d 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -78,7 +78,7 @@ void Config::ReadValues() { | |||
| 78 | 78 | ||
| 79 | qt_config->beginGroup("Core"); | 79 | qt_config->beginGroup("Core"); |
| 80 | Settings::values.cpu_core = | 80 | Settings::values.cpu_core = |
| 81 | static_cast<Settings::CpuCore>(qt_config->value("cpu_core", 0).toInt()); | 81 | static_cast<Settings::CpuCore>(qt_config->value("cpu_core", 1).toInt()); |
| 82 | qt_config->endGroup(); | 82 | qt_config->endGroup(); |
| 83 | 83 | ||
| 84 | qt_config->beginGroup("Renderer"); | 84 | qt_config->beginGroup("Renderer"); |
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index e4a6d16ae..cae2864e5 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "yuzu/debugger/wait_tree.h" | 5 | #include "yuzu/debugger/wait_tree.h" |
| 6 | #include "yuzu/util/util.h" | 6 | #include "yuzu/util/util.h" |
| 7 | 7 | ||
| 8 | #include "core/core.h" | ||
| 8 | #include "core/hle/kernel/condition_variable.h" | 9 | #include "core/hle/kernel/condition_variable.h" |
| 9 | #include "core/hle/kernel/event.h" | 10 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/kernel/mutex.h" | 11 | #include "core/hle/kernel/mutex.h" |
| @@ -50,7 +51,7 @@ std::size_t WaitTreeItem::Row() const { | |||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { | 53 | std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { |
| 53 | const auto& threads = Kernel::GetThreadList(); | 54 | const auto& threads = Core::System::GetInstance().Scheduler().GetThreadList(); |
| 54 | std::vector<std::unique_ptr<WaitTreeThread>> item_list; | 55 | std::vector<std::unique_ptr<WaitTreeThread>> item_list; |
| 55 | item_list.reserve(threads.size()); | 56 | item_list.reserve(threads.size()); |
| 56 | for (std::size_t i = 0; i < threads.size(); ++i) { | 57 | for (std::size_t i = 0; i < threads.size(); ++i) { |
| @@ -149,8 +150,8 @@ QString WaitTreeThread::GetText() const { | |||
| 149 | case THREADSTATUS_READY: | 150 | case THREADSTATUS_READY: |
| 150 | status = tr("ready"); | 151 | status = tr("ready"); |
| 151 | break; | 152 | break; |
| 152 | case THREADSTATUS_WAIT_ARB: | 153 | case THREADSTATUS_WAIT_HLE_EVENT: |
| 153 | status = tr("waiting for address 0x%1").arg(thread.wait_address, 8, 16, QLatin1Char('0')); | 154 | status = tr("waiting for HLE return"); |
| 154 | break; | 155 | break; |
| 155 | case THREADSTATUS_WAIT_SLEEP: | 156 | case THREADSTATUS_WAIT_SLEEP: |
| 156 | status = tr("sleeping"); | 157 | status = tr("sleeping"); |
| @@ -179,7 +180,7 @@ QColor WaitTreeThread::GetColor() const { | |||
| 179 | return QColor(Qt::GlobalColor::darkGreen); | 180 | return QColor(Qt::GlobalColor::darkGreen); |
| 180 | case THREADSTATUS_READY: | 181 | case THREADSTATUS_READY: |
| 181 | return QColor(Qt::GlobalColor::darkBlue); | 182 | return QColor(Qt::GlobalColor::darkBlue); |
| 182 | case THREADSTATUS_WAIT_ARB: | 183 | case THREADSTATUS_WAIT_HLE_EVENT: |
| 183 | return QColor(Qt::GlobalColor::darkRed); | 184 | return QColor(Qt::GlobalColor::darkRed); |
| 184 | case THREADSTATUS_WAIT_SLEEP: | 185 | case THREADSTATUS_WAIT_SLEEP: |
| 185 | return QColor(Qt::GlobalColor::darkYellow); | 186 | return QColor(Qt::GlobalColor::darkYellow); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e5252abdc..5802b9855 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -187,7 +187,8 @@ void GMainWindow::InitializeHotkeys() { | |||
| 187 | RegisterHotkey("Main Window", "Load File", QKeySequence::Open); | 187 | RegisterHotkey("Main Window", "Load File", QKeySequence::Open); |
| 188 | RegisterHotkey("Main Window", "Start Emulation"); | 188 | RegisterHotkey("Main Window", "Start Emulation"); |
| 189 | RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); | 189 | RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); |
| 190 | RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence::Cancel, Qt::ApplicationShortcut); | 190 | RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), |
| 191 | Qt::ApplicationShortcut); | ||
| 191 | LoadHotkeys(); | 192 | LoadHotkeys(); |
| 192 | 193 | ||
| 193 | connect(GetHotkey("Main Window", "Load File", this), &QShortcut::activated, this, | 194 | connect(GetHotkey("Main Window", "Load File", this), &QShortcut::activated, this, |