summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/logging/backend.cpp3
-rw-r--r--src/common/logging/log.h3
-rw-r--r--src/core/CMakeLists.txt26
-rw-r--r--src/core/arm/arm_interface.h6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp31
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h2
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp7
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h1
-rw-r--r--src/core/core.cpp25
-rw-r--r--src/core/core.h21
-rw-r--r--src/core/file_sys/disk_filesystem.cpp146
-rw-r--r--src/core/file_sys/disk_filesystem.h66
-rw-r--r--src/core/file_sys/errors.h25
-rw-r--r--src/core/file_sys/filesystem.h28
-rw-r--r--src/core/file_sys/program_metadata.cpp114
-rw-r--r--src/core/file_sys/program_metadata.h154
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/romfs_filesystem.cpp12
-rw-r--r--src/core/file_sys/romfs_filesystem.h7
-rw-r--r--src/core/file_sys/savedata_factory.cpp57
-rw-r--r--src/core/file_sys/savedata_factory.h33
-rw-r--r--src/core/hle/ipc.h4
-rw-r--r--src/core/hle/ipc_helpers.h3
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp91
-rw-r--r--src/core/hle/kernel/address_arbiter.h60
-rw-r--r--src/core/hle/kernel/handle_table.cpp3
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp155
-rw-r--r--src/core/hle/kernel/hle_ipc.h51
-rw-r--r--src/core/hle/kernel/kernel.cpp1
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/process.cpp28
-rw-r--r--src/core/hle/kernel/process.h8
-rw-r--r--src/core/hle/kernel/scheduler.cpp135
-rw-r--r--src/core/hle/kernel/scheduler.h73
-rw-r--r--src/core/hle/kernel/server_session.cpp102
-rw-r--r--src/core/hle/kernel/server_session.h14
-rw-r--r--src/core/hle/kernel/shared_memory.cpp18
-rw-r--r--src/core/hle/kernel/svc.cpp77
-rw-r--r--src/core/hle/kernel/svc_wrap.h5
-rw-r--r--src/core/hle/kernel/thread.cpp231
-rw-r--r--src/core/hle/kernel/thread.h30
-rw-r--r--src/core/hle/kernel/vm_manager.cpp42
-rw-r--r--src/core/hle/kernel/vm_manager.h38
-rw-r--r--src/core/hle/kernel/wait_object.cpp3
-rw-r--r--src/core/hle/result.h4
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp14
-rw-r--r--src/core/hle/service/acc/acc_u0.h1
-rw-r--r--src/core/hle/service/am/am.cpp72
-rw-r--r--src/core/hle/service/am/am.h8
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp32
-rw-r--r--src/core/hle/service/aoc/aoc_u.h4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp15
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp24
-rw-r--r--src/core/hle/service/filesystem/filesystem.h8
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp206
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h2
-rw-r--r--src/core/hle/service/friend/friend.cpp28
-rw-r--r--src/core/hle/service/friend/friend.h29
-rw-r--r--src/core/hle/service/friend/friend_a.cpp19
-rw-r--r--src/core/hle/service/friend/friend_a.h18
-rw-r--r--src/core/hle/service/hid/hid.cpp62
-rw-r--r--src/core/hle/service/nifm/nifm.cpp128
-rw-r--r--src/core/hle/service/nifm/nifm.h20
-rw-r--r--src/core/hle/service/nifm/nifm_a.cpp19
-rw-r--r--src/core/hle/service/nifm/nifm_a.h12
-rw-r--r--src/core/hle/service/nifm/nifm_s.cpp19
-rw-r--r--src/core/hle/service/nifm/nifm_s.h12
-rw-r--r--src/core/hle/service/nifm/nifm_u.cpp19
-rw-r--r--src/core/hle/service/nifm/nifm_u.h12
-rw-r--r--src/core/hle/service/ns/ns.cpp16
-rw-r--r--src/core/hle/service/ns/ns.h16
-rw-r--r--src/core/hle/service/ns/pl_u.cpp112
-rw-r--r--src/core/hle/service/ns/pl_u.h33
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp7
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp27
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h7
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp29
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp5
-rw-r--r--src/core/hle/service/service.cpp11
-rw-r--r--src/core/hle/service/set/set.cpp17
-rw-r--r--src/core/hle/service/set/set.h5
-rw-r--r--src/core/hle/service/set/set_cal.cpp40
-rw-r--r--src/core/hle/service/set/set_cal.h19
-rw-r--r--src/core/hle/service/set/set_fd.cpp25
-rw-r--r--src/core/hle/service/set/set_fd.h19
-rw-r--r--src/core/hle/service/set/set_sys.cpp167
-rw-r--r--src/core/hle/service/set/set_sys.h22
-rw-r--r--src/core/hle/service/set/settings.cpp22
-rw-r--r--src/core/hle/service/set/settings.h16
-rw-r--r--src/core/hle/service/sockets/bsd_u.cpp10
-rw-r--r--src/core/hle/service/sockets/bsd_u.h1
-rw-r--r--src/core/hle/service/time/time.cpp7
-rw-r--r--src/core/hle/service/time/time.h1
-rw-r--r--src/core/hle/service/time/time_s.cpp4
-rw-r--r--src/core/hle/service/time/time_u.cpp1
-rw-r--r--src/core/hle/service/vi/vi.cpp176
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp22
-rw-r--r--src/core/loader/deconstructed_rom_directory.h2
-rw-r--r--src/core/loader/elf.cpp5
-rw-r--r--src/core/loader/nro.cpp9
-rw-r--r--src/core/loader/nso.cpp9
-rw-r--r--src/core/memory.cpp41
-rw-r--r--src/core/memory.h48
-rw-r--r--src/tests/core/arm/arm_test_common.cpp4
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/command_processor.cpp50
-rw-r--r--src/video_core/command_processor.h2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp224
-rw-r--r--src/video_core/engines/maxwell_3d.h215
-rw-r--r--src/video_core/gpu.cpp21
-rw-r--r--src/video_core/gpu.h28
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/debugger/wait_tree.cpp9
-rw-r--r--src/yuzu/main.cpp3
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
91std::unique_ptr<Dynarmic::A64::Jit> MakeJit(const std::unique_ptr<ARM_Dynarmic_Callbacks>& cb) { 109std::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
150void ARM_Dynarmic::UnmapMemory(u64 address, size_t size) {
151 inner_unicorn.UnmapMemory(address, size);
152}
153
129void ARM_Dynarmic::SetPC(u64 pc) { 154void 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
81void ARM_Unicorn::UnmapMemory(VAddr address, size_t size) {
82 CHECKED(uc_mem_unmap(uc, address, size));
83}
84
80void ARM_Unicorn::SetPC(u64 pc) { 85void 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
143System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { 143System::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
179inline 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
12namespace FileSys {
13
14std::string Disk_FileSystem::GetName() const {
15 return "Disk";
16}
17
18ResultVal<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
33ResultCode 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
39ResultCode 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
45ResultCode 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
51ResultCode 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
57ResultCode 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
78ResultCode 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
84ResultCode 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
90ResultVal<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
95u64 Disk_FileSystem::GetFreeSpaceSize() const {
96 LOG_WARNING(Service_FS, "(STUBBED) called");
97 return 0;
98}
99
100ResultVal<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
110ResultVal<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
116ResultVal<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
127u64 Disk_Storage::GetSize() const {
128 return file->GetSize();
129}
130
131bool Disk_Storage::SetSize(const u64 size) const {
132 LOG_WARNING(Service_FS, "(STUBBED) called");
133 return false;
134}
135
136u32 Disk_Directory::Read(const u32 count, Entry* entries) {
137 LOG_WARNING(Service_FS, "(STUBBED) called");
138 return 0;
139}
140
141bool 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
17namespace FileSys {
18
19class Disk_FileSystem : public FileSystemBackend {
20public:
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
39protected:
40 std::string base_directory;
41};
42
43class Disk_Storage : public StorageBackend {
44public:
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
56private:
57 std::shared_ptr<FileUtil::IOFile> file;
58};
59
60class Disk_Directory : public DirectoryBackend {
61public:
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
11namespace ErrCodes { 11namespace ErrCodes {
12enum { 12enum {
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
17constexpr 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
38constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1)); 20constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1));
39constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1)); 21constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1));
40constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1)); 22constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1));
41constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1)); 23constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1));
42constexpr ResultCode ERROR_PATH_NOT_FOUND(ResultCode(-1));
43constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1)); 24constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1));
44constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1)); 25constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1));
45constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ResultCode(-1)); 26constexpr 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
30union Mode { 30enum 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
35enum class Mode : u32 {
36 Read = 1,
37 Write = 2,
35}; 38};
36 39
37class Path { 40class 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
158class FileSystemFactory : NonCopyable { 167class 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
11namespace FileSys {
12
13Loader::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
30Loader::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
51bool ProgramMetadata::Is64BitProgram() const {
52 return npdm_header.has_64_bit_instructions;
53}
54
55ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {
56 return npdm_header.address_space_type;
57}
58
59u8 ProgramMetadata::GetMainThreadPriority() const {
60 return npdm_header.main_thread_priority;
61}
62
63u8 ProgramMetadata::GetMainThreadCore() const {
64 return npdm_header.main_thread_cpu;
65}
66
67u32 ProgramMetadata::GetMainThreadStackSize() const {
68 return npdm_header.main_stack_size;
69}
70
71u64 ProgramMetadata::GetTitleID() const {
72 return aci_header.title_id;
73}
74
75u64 ProgramMetadata::GetFilesystemPermissions() const {
76 return aci_file_access.permissions;
77}
78
79void 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
14namespace Loader {
15enum class ResultStatus;
16}
17
18namespace FileSys {
19
20enum class ProgramAddressSpaceType : u8 {
21 Is64Bit = 1,
22 Is32Bit = 2,
23};
24
25enum 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 */
38class ProgramMetadata {
39public:
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
53private:
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
26ResultCode RomFS_Factory::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { 26ResultCode 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
29private: 29private:
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
17ResultVal<std::unique_ptr<StorageBackend>> RomFS_FileSystem::OpenFile(const Path& path, 17ResultVal<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
51ResultCode RomFS_FileSystem::CreateFile(const Path& path, u64 size) const { 51ResultCode 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
82ResultVal<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
82ResultVal<size_t> RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { 88ResultVal<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
44protected: 45protected:
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
15namespace FileSys {
16
17SaveData_Factory::SaveData_Factory(std::string nand_directory)
18 : nand_directory(std::move(nand_directory)) {}
19
20ResultVal<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
32ResultCode 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
43ResultVal<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
49std::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
13namespace FileSys {
14
15/// File system interface to the SaveData archive
16class SaveData_Factory final : public FileSystemFactory {
17public:
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
27private:
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};
95static_assert(sizeof(BufferDescriptorX) == 8, "BufferDescriptorX size is incorrect"); 99static_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
15namespace Kernel {
16
17AddressArbiter::AddressArbiter() {}
18AddressArbiter::~AddressArbiter() {}
19
20SharedPtr<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
28ResultCode 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
19namespace Kernel {
20
21enum class ArbitrationType : u32 {
22 Signal,
23 WaitIfLessThan,
24 DecrementAndWaitIfLessThan,
25 WaitIfLessThanWithTimeout,
26 DecrementAndWaitIfLessThanWithTimeout,
27};
28
29class AddressArbiter final : public Object {
30public:
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
55private:
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
16namespace Kernel { 18namespace 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
30SharedPtr<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
28HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) 56HLERequestContext::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
35void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { 63void 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
156ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, 189ResultCode 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
254std::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
269size_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
283size_t HLERequestContext::WriteBuffer(const std::vector<u8>& buffer) const {
284 return WriteBuffer(buffer.data(), buffer.size());
285}
286
287size_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
292size_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
297std::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
17namespace Service { 19namespace Service {
18class ServiceFrameworkBase; 20class ServiceFrameworkBase;
@@ -24,6 +26,7 @@ class Domain;
24class HandleTable; 26class HandleTable;
25class HLERequestContext; 27class HLERequestContext;
26class Process; 28class Process;
29class 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
190private: 227private:
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
36enum {
37 DEFAULT_STACK_SIZE = 0x10000,
38};
39
40enum class ResetType { 36enum 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.
21static std::vector<SharedPtr<Process>> process_list; 21static std::vector<SharedPtr<Process>> process_list;
22 22
23SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) { 23SharedPtr<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
121void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { 119void 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
163VAddr Process::GetLinearHeapAreaAddress() const { 162VAddr 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
324SharedPtr<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;
56struct MemoryRegionInfo; 56struct MemoryRegionInfo;
57 57
58struct CodeSet final : public Object { 58struct 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.
203SharedPtr<Process> GetProcessById(u32 process_id); 204SharedPtr<Process> GetProcessById(u32 process_id);
204 205
205extern 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
10namespace Kernel {
11
12Scheduler::Scheduler(ARM_Interface* cpu_core) : cpu_core(cpu_core) {}
13
14Scheduler::~Scheduler() {
15 for (auto& thread : thread_list) {
16 thread->Stop();
17 }
18}
19
20bool Scheduler::HaveReadyThreads() {
21 return ready_queue.get_first() != nullptr;
22}
23
24Thread* Scheduler::GetCurrentThread() const {
25 return current_thread.get();
26}
27
28Thread* 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
47void 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
92void 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
107void Scheduler::AddThread(SharedPtr<Thread> thread, u32 priority) {
108 thread_list.push_back(thread);
109 ready_queue.prepare(priority);
110}
111
112void Scheduler::RemoveThread(Thread* thread) {
113 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
114 thread_list.end());
115}
116
117void Scheduler::ScheduleThread(Thread* thread, u32 priority) {
118 ASSERT(thread->status == THREADSTATUS_READY);
119 ready_queue.push_back(priority, thread);
120}
121
122void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
123 ASSERT(thread->status == THREADSTATUS_READY);
124 ready_queue.remove(priority, thread);
125}
126
127void 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
13namespace Kernel {
14
15class Scheduler final {
16public:
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
49private:
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
61ResultCode 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
60ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { 88ResultCode 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
144ResultCode 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;
21class Session; 21class Session;
22class SessionRequestHandler; 22class SessionRequestHandler;
23class Thread; 23class Thread;
24class 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 */
131ResultCode 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.
31static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { 33static 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
45static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 47static 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
52static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 54static 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
448static 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
447static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, 459static 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
478static void ExitProcess() { 490static 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
777static 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
764namespace { 787namespace {
765struct FunctionDef { 788struct 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
94template <ResultCode func(u32, u64, u64)>
95void SvcWrap() {
96 FuncReturn(func((u32)PARAM(0), PARAM(1), PARAM(2)).raw);
97}
98
94template <ResultCode func(u32*, u64, u64, s64)> 99template <ResultCode func(u32*, u64, u64, s64)>
95void SvcWrap() { 100void 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.
42static Kernel::HandleTable wakeup_callback_handle_table; 42static Kernel::HandleTable wakeup_callback_handle_table;
43 43
44// Lists all thread ids that aren't deleted/etc.
45static std::vector<SharedPtr<Thread>> thread_list;
46
47// Lists only ready thread ids.
48static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
49
50static SharedPtr<Thread> current_thread;
51
52// The first available thread id at startup 44// The first available thread id at startup
53static u32 next_thread_id; 45static u32 next_thread_id;
54 46
@@ -63,20 +55,6 @@ inline static u32 const NewThreadId() {
63Thread::Thread() {} 55Thread::Thread() {}
64Thread::~Thread() {} 56Thread::~Thread() {}
65 57
66Thread* 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 */
76static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) {
77 return thread->status == THREADSTATUS_WAIT_ARB && wait_address == thread->wait_address;
78}
79
80void Thread::Stop() { 58void 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
112Thread* 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
138void 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 */
150static 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 */
199static 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
218void WaitCurrentThread_Sleep() { 90void 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
223void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
224 Thread* thread = GetCurrentThread();
225 thread->wait_address = wait_address;
226 thread->status = THREADSTATUS_WAIT_ARB;
227}
228
229void ExitCurrentThread() { 95void 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 */
318static 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,
471void Thread::SetPriority(u32 priority) { 317void 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
492void Thread::BoostPriority(u32 priority) { 333void 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
501SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, 338SharedPtr<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
523bool HaveReadyThreads() {
524 return ready_queue.get_first() != nullptr;
525}
526
527void 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
542void Thread::SetWaitSynchronizationResult(ResultCode result) { 360void 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 */
385Thread* GetCurrentThread() {
386 return Core::System::GetInstance().Scheduler().GetCurrentThread();
387}
388
564void ThreadingInit() { 389void 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
571void ThreadingShutdown() { 394void 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
581const 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 {
38enum ThreadStatus { 38enum 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 */
254bool HaveReadyThreads();
255
256/**
257 * Reschedules to the next available thread (call after current thread is suspended)
258 */
259void 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 */
265Thread* ArbitrateHighestPriorityThread(VAddr address);
266
267/**
268 * Arbitrate all threads currently waiting.
269 * @param address The address for which waiting threads should be arbitrated
270 */
271void ArbitrateAllThreads(VAddr address);
272
273/**
274 * Gets the current thread 253 * Gets the current thread
275 */ 254 */
276Thread* GetCurrentThread(); 255Thread* GetCurrentThread();
@@ -301,9 +280,4 @@ void ThreadingInit();
301 */ 280 */
302void ThreadingShutdown(); 281void ThreadingShutdown();
303 282
304/**
305 * Get a const reference to the thread list for debug use
306 */
307const 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
19static const char* GetMemoryStateName(MemoryState state) { 19static 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
380VAddr VMManager::GetMapRegionBaseAddr() {
381 LOG_WARNING(Kernel, "(STUBBED) called");
382 return Memory::HEAP_VADDR;
383}
384
385VAddr VMManager::GetNewMapRegionBaseAddr() {
386 LOG_WARNING(Kernel, "(STUBBED) called");
387 return 0x8000000;
388}
389
390u64 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.
43enum class MemoryState : u32 { 43enum 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
67void ACC_U0::ListAllUsers(Kernel::HLERequestContext& ctx) { 67void 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
75void 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
76void ACC_U0::GetProfile(Kernel::HLERequestContext& ctx) { 83void 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:
29private: 29private:
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
13namespace Service { 16namespace 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
37IAudioController::IAudioController() : ServiceFramework("IAudioController") {} 40IAudioController::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
53void 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
59void 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
66void 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
39IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {} 73IDisplayController::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
136void 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
101void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { 143void 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
379void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { 421void 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
385void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { 443void 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:
36class IAudioController final : public ServiceFramework<IAudioController> { 36class IAudioController final : public ServiceFramework<IAudioController> {
37public: 37public:
38 IAudioController(); 38 IAudioController();
39
40private:
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
41class IDisplayController final : public ServiceFramework<IDisplayController> { 48class 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
7namespace Service { 9namespace Service {
8namespace AOC { 10namespace AOC {
9 11
12AOC_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
26void 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
33void 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
10void InstallInterfaces(SM::ServiceManager& service_manager) { 40void 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
14AOC_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> {
13public: 13public:
14 AOC_U(); 14 AOC_U();
15 ~AOC_U() = default; 15 ~AOC_U() = default;
16
17private:
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
57private: 59private:
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
50private: 52private:
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
181void AudRenU::GetAudioRenderersProcessMasterVolume(Kernel::HLERequestContext& ctx) { 182void 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
44void UnregisterFileSystems() { 46ResultCode 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
59void 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
48void InstallInterfaces(SM::ServiceManager& service_manager) { 68void 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
26enum class Type { 26enum 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
43ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenFileSystem(Type type, 44ResultVal<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 */
52ResultCode FormatFileSystem(Type type);
53
46/// Registers all Filesystem services with the specified service manager. 54/// Registers all Filesystem services with the specified service manager.
47void InstallInterfaces(SM::ServiceManager& service_manager); 55void 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
69class IFile final : public ServiceFramework<IFile> {
70public:
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
80private:
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
154class IFileSystem final : public ServiceFramework<IFileSystem> {
155public:
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
240private:
241 std::unique_ptr<FileSys::FileSystemBackend> backend;
242};
243
70FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { 244FSP_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
283void 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
296void 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
107void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 307void 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
10namespace Service {
11namespace Friend {
12
13void 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
19Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
20 : ServiceFramework(name), module(std::move(module)) {}
21
22void 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
9namespace Service {
10namespace Friend {
11
12class Module final {
13public:
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.
26void 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
7namespace Service {
8namespace Friend {
9
10Friend_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
9namespace Service {
10namespace Friend {
11
12class Friend_A final : public Module::Interface {
13public:
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
48private: 52private:
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
283void ReloadInputDevices() {} 345void 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> {
28public: 29public:
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
64private:
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
61class INetworkProfile final : public ServiceFramework<INetworkProfile> { 92class INetworkProfile final : public ServiceFramework<INetworkProfile> {
@@ -70,13 +101,56 @@ public:
70 } 101 }
71}; 102};
72 103
104class IGeneralService final : public ServiceFramework<IGeneralService> {
105public:
106 IGeneralService();
107
108private:
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
73IGeneralService::IGeneralService() : ServiceFramework("IGeneralService") { 146IGeneralService::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
114void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) { 188void 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
121void 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
130void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) { 195void 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
139void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 202Module::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
145void 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
154void InstallInterfaces(SM::ServiceManager& service_manager) { 205void 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 @@
9namespace Service { 9namespace Service {
10namespace NIFM { 10namespace NIFM {
11 11
12class IGeneralService final : public ServiceFramework<IGeneralService> { 12class Module final {
13public: 13public:
14 IGeneralService(); 14 class Interface : public ServiceFramework<Interface> {
15 15 public:
16private: 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
24void InstallInterfaces(SM::ServiceManager& service_manager); 26void 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
10namespace Service { 7namespace Service {
11namespace NIFM { 8namespace NIFM {
12 9
13void NIFM_A::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { 10NIFM_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
20void 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
27NIFM_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
10namespace Service { 9namespace Service {
11namespace NIFM { 10namespace NIFM {
12 11
13class NIFM_A final : public ServiceFramework<NIFM_A> { 12class NIFM_A final : public Module::Interface {
14public: 13public:
15 NIFM_A(); 14 explicit NIFM_A(std::shared_ptr<Module> module);
16 ~NIFM_A() = default;
17
18private:
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
10namespace Service { 7namespace Service {
11namespace NIFM { 8namespace NIFM {
12 9
13void NIFM_S::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { 10NIFM_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
20void 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
27NIFM_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
10namespace Service { 9namespace Service {
11namespace NIFM { 10namespace NIFM {
12 11
13class NIFM_S final : public ServiceFramework<NIFM_S> { 12class NIFM_S final : public Module::Interface {
14public: 13public:
15 NIFM_S(); 14 explicit NIFM_S(std::shared_ptr<Module> module);
16 ~NIFM_S() = default;
17
18private:
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
10namespace Service { 7namespace Service {
11namespace NIFM { 8namespace NIFM {
12 9
13void NIFM_U::CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { 10NIFM_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
20void 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
27NIFM_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
10namespace Service { 9namespace Service {
11namespace NIFM { 10namespace NIFM {
12 11
13class NIFM_U final : public ServiceFramework<NIFM_U> { 12class NIFM_U final : public Module::Interface {
14public: 13public:
15 NIFM_U(); 14 explicit NIFM_U(std::shared_ptr<Module> module);
16 ~NIFM_U() = default;
17
18private:
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
8namespace Service {
9namespace NS {
10
11void 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
9namespace Service {
10namespace NS {
11
12/// Registers all NS services with the specified service manager.
13void 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
11namespace Service {
12namespace NS {
13
14struct 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
21static constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
22static constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
23static 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
29enum class LoadState : u32 {
30 Loading = 0,
31 Done = 1,
32};
33
34PL_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
57void 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
67void 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
77void 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
87void 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
11namespace Service {
12namespace NS {
13
14class PL_U final : public ServiceFramework<PL_U> {
15public:
16 PL_U();
17 ~PL_U() = default;
18
19private:
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
50u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
51 IocCtrlEventWaitParams params{};
52 std::memcpy(&params, 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(), &params, 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(), &params, sizeof(params)); 109 std::memcpy(output.data(), &params, 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 {
15void NVDRV::Open(Kernel::HLERequestContext& ctx) { 15void 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
57void NVDRV::Close(Kernel::HLERequestContext& ctx) { 44void 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 {
17class nvdevice; 17class nvdevice;
18} 18}
19 19
20struct IoctlFence {
21 u32 id;
22 u32 value;
23};
24
25static_assert(sizeof(IoctlFence) == 8, "IoctlFence has wrong size");
26
20class Module final { 27class Module final {
21public: 28public:
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
31u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { 35boost::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
88u32 BufferQueue::Query(QueryType type) { 96u32 BufferQueue::Query(QueryType type) {
@@ -98,5 +106,10 @@ u32 BufferQueue::Query(QueryType type) {
98 return 0; 106 return 0;
99} 107}
100 108
109void 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
31SET::SET(const char* name) : ServiceFramework(name) { 29SET::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
38void 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
12class SET final : public ServiceFramework<SET> { 12class SET final : public ServiceFramework<SET> {
13public: 13public:
14 explicit SET(const char* name); 14 explicit SET();
15 ~SET() = default; 15 ~SET() = default;
16 16
17private: 17private:
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.
22void 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
7namespace Service {
8namespace Set {
9
10SET_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
9namespace Service {
10namespace Set {
11
12class SET_CAL final : public ServiceFramework<SET_CAL> {
13public:
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
7namespace Service {
8namespace Set {
9
10SET_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
9namespace Service {
10namespace Set {
11
12class SET_FD final : public ServiceFramework<SET_FD> {
13public:
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
10namespace Service {
11namespace Set {
12
13void 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
23SET_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
9namespace Service {
10namespace Set {
11
12class SET_SYS final : public ServiceFramework<SET_SYS> {
13public:
14 explicit SET_SYS();
15 ~SET_SYS() = default;
16
17private:
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
11namespace Service {
12namespace Set {
13
14void 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
9namespace Service {
10namespace Set {
11
12/// Registers all Settings services with the specified service manager.
13void 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
20void 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
20void BSD_U::Socket(Kernel::HLERequestContext& ctx) { 29void 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
68BSD_U::BSD_U() : ServiceFramework("bsd:u") { 77BSD_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
18private: 18private:
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
149void 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
149Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) 156Module::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 {
10TIME_S::TIME_S(std::shared_ptr<Module> time) : Module::Interface(std::move(time), "time:s") { 10TIME_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. 280struct 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;
268static constexpr u32 FENCE_HACK = 0; 283};
284static_assert(sizeof(BufferProducerFence) == 36, "BufferProducerFence has wrong size");
269 285
270class IGBPDequeueBufferResponseParcel : public Parcel { 286class IGBPDequeueBufferResponseParcel : public Parcel {
271public: 287public:
@@ -274,20 +290,16 @@ public:
274 290
275protected: 291protected:
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
317protected: 329protected:
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
736void IApplicationDisplayService::CreateStrayLayer(Kernel::HLERequestContext& ctx) { 726void 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
761void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ctx) { 746void IApplicationDisplayService::DestroyStrayLayer(Kernel::HLERequestContext& ctx) {
@@ -781,8 +766,7 @@ void IApplicationDisplayService::SetLayerScalingMode(Kernel::HLERequestContext&
781void IApplicationDisplayService::ListDisplays(Kernel::HLERequestContext& ctx) { 766void 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
53FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& file, 53FileType 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:
41private: 42private:
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
111static std::set<MemoryHookPointer> GetSpecialHandlers(VAddr vaddr, u64 size) { 111static 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
119template <typename T> 119template <typename T>
120T Read(const VAddr vaddr) { 120T 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
147template <typename T> 152template <typename T>
148void Write(const VAddr vaddr, const T data) { 153void 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
193bool IsValidVirtualAddress(const VAddr vaddr) { 204bool IsValidVirtualAddress(const VAddr vaddr) {
194 return IsValidVirtualAddress(*Kernel::g_current_process, vaddr); 205 return IsValidVirtualAddress(*Core::CurrentProcess(), vaddr);
195} 206}
196 207
197bool IsValidPhysicalAddress(const PAddr paddr) { 208bool IsValidPhysicalAddress(const PAddr paddr) {
@@ -353,7 +364,7 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_
353} 364}
354 365
355void ReadBlock(const VAddr src_addr, void* dest_buffer, const size_t size) { 366void 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
359void Write8(const VAddr addr, const u8 data) { 370void 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
426void WriteBlock(const VAddr dest_addr, const void* src_buffer, const size_t size) { 437void 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
430void ZeroBlock(const VAddr dest_addr, const size_t size) { 441void 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
471void CopyBlock(VAddr dest_addr, VAddr src_addr, const size_t size) { 482void 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
516template <> 527template <>
517boost::optional<u8> ReadSpecial<u8>(VAddr addr) { 528boost::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
525template <> 536template <>
526boost::optional<u16> ReadSpecial<u16>(VAddr addr) { 537boost::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
534template <> 545template <>
535boost::optional<u32> ReadSpecial<u32>(VAddr addr) { 546boost::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
543template <> 554template <>
544boost::optional<u64> ReadSpecial<u64>(VAddr addr) { 555boost::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
552template <> 563template <>
553bool WriteSpecial<u8>(VAddr addr, const u8 data) { 564bool 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
561template <> 572template <>
562bool WriteSpecial<u16>(VAddr addr, const u16 data) { 573bool 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
570template <> 581template <>
571bool WriteSpecial<u32>(VAddr addr, const u32 data) { 582bool 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
579template <> 590template <>
580bool WriteSpecial<u64>(VAddr addr, const u64 data) { 591bool 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;
15TestEnvironment::TestEnvironment(bool mutable_memory_) 15TestEnvironment::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
25enum class BufferMethods { 25enum 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
30void GPU::WriteReg(u32 method, u32 subchannel, u32 value) { 33void 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");
35static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); 35static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
36 36
37void 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 @@
8namespace Tegra { 8namespace Tegra {
9namespace Engines { 9namespace Engines {
10 10
11/// First register id that is actually a Macro call.
12constexpr u32 MacroRegistersStart = 0xE00;
13
14const 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
11Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {} 20Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
12 21
13void Maxwell3D::WriteReg(u32 method, u32 value) { 22void Maxwell3D::SubmitMacroCode(u32 entry, std::vector<u32> code) {
23 uploaded_macros[entry * 2 + MacroRegistersStart] = std::move(code);
24}
25
26void 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
45void 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
160void Maxwell3D::DrawArrays() {
161 LOG_WARNING(HW_GPU, "Game requested a DrawArrays, ignoring");
162}
163
164void 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
181void 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
222void 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
242void 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
255void 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
60private: 220private:
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
267ASSERT_REG_POSITION(code_address, 0x582);
268ASSERT_REG_POSITION(draw, 0x585);
71ASSERT_REG_POSITION(query, 0x6C0); 269ASSERT_REG_POSITION(query, 0x6C0);
270ASSERT_REG_POSITION(vertex_array[0], 0x700);
271ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
272ASSERT_REG_POSITION(shader_config[0], 0x800);
273ASSERT_REG_POSITION(const_buffer, 0x8E0);
274ASSERT_REG_POSITION(cb_bind[0], 0x904);
275ASSERT_REG_POSITION(tex_cb_index, 0x982);
276ASSERT_REG_POSITION(ssbo_info, 0xD18);
277ASSERT_REG_POSITION(tex_info_buffers.address[0], 0xD2A);
278ASSERT_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
10namespace Tegra {
11
12GPU::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
19GPU::~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
15namespace Tegra { 13namespace Tegra {
16 14
15namespace Engines {
16class Fermi2D;
17class Maxwell3D;
18class MaxwellCompute;
19} // namespace Engines
20
17enum class EngineID { 21enum 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
25class GPU final { 29class GPU final {
26public: 30public:
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
40private: 39private:
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
52std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { 53std::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,