summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt86
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp18
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp2
-rw-r--r--src/core/core.cpp38
-rw-r--r--src/core/core.h60
-rw-r--r--src/core/core_cpu.cpp1
-rw-r--r--src/core/core_timing.cpp14
-rw-r--r--src/core/core_timing.h11
-rw-r--r--src/core/crypto/aes_util.cpp115
-rw-r--r--src/core/crypto/aes_util.h64
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp56
-rw-r--r--src/core/crypto/ctr_encryption_layer.h33
-rw-r--r--src/core/crypto/encryption_layer.cpp42
-rw-r--r--src/core/crypto/encryption_layer.h33
-rw-r--r--src/core/crypto/key_manager.cpp208
-rw-r--r--src/core/crypto/key_manager.h120
-rw-r--r--src/core/crypto/sha_util.cpp5
-rw-r--r--src/core/crypto/sha_util.h20
-rw-r--r--src/core/file_sys/card_image.cpp149
-rw-r--r--src/core/file_sys/card_image.h96
-rw-r--r--src/core/file_sys/content_archive.cpp236
-rw-r--r--src/core/file_sys/content_archive.h31
-rw-r--r--src/core/file_sys/partition_filesystem.cpp5
-rw-r--r--src/core/file_sys/romfs.cpp124
-rw-r--r--src/core/file_sys/romfs.h35
-rw-r--r--src/core/file_sys/vfs.cpp43
-rw-r--r--src/core/file_sys/vfs.h23
-rw-r--r--src/core/file_sys/vfs_offset.cpp7
-rw-r--r--src/core/file_sys/vfs_offset.h3
-rw-r--r--src/core/file_sys/vfs_real.cpp6
-rw-r--r--src/core/file_sys/vfs_real.h3
-rw-r--r--src/core/file_sys/vfs_vector.cpp86
-rw-r--r--src/core/file_sys/vfs_vector.h44
-rw-r--r--src/core/gdbstub/gdbstub.cpp175
-rw-r--r--src/core/gdbstub/gdbstub.h8
-rw-r--r--src/core/hle/ipc_helpers.h7
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp38
-rw-r--r--src/core/hle/kernel/address_arbiter.h4
-rw-r--r--src/core/hle/kernel/client_port.cpp17
-rw-r--r--src/core/hle/kernel/client_port.h16
-rw-r--r--src/core/hle/kernel/client_session.cpp2
-rw-r--r--src/core/hle/kernel/client_session.h2
-rw-r--r--src/core/hle/kernel/event.cpp4
-rw-r--r--src/core/hle/kernel/event.h14
-rw-r--r--src/core/hle/kernel/handle_table.cpp1
-rw-r--r--src/core/hle/kernel/handle_table.h2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp7
-rw-r--r--src/core/hle/kernel/hle_ipc.h3
-rw-r--r--src/core/hle/kernel/kernel.cpp8
-rw-r--r--src/core/hle/kernel/kernel.h112
-rw-r--r--src/core/hle/kernel/memory.cpp92
-rw-r--r--src/core/hle/kernel/memory.h31
-rw-r--r--src/core/hle/kernel/mutex.cpp7
-rw-r--r--src/core/hle/kernel/mutex.h8
-rw-r--r--src/core/hle/kernel/object.cpp35
-rw-r--r--src/core/hle/kernel/object.h100
-rw-r--r--src/core/hle/kernel/object_address_table.cpp36
-rw-r--r--src/core/hle/kernel/object_address_table.h62
-rw-r--r--src/core/hle/kernel/process.cpp84
-rw-r--r--src/core/hle/kernel/process.h64
-rw-r--r--src/core/hle/kernel/resource_limit.h2
-rw-r--r--src/core/hle/kernel/scheduler.cpp4
-rw-r--r--src/core/hle/kernel/scheduler.h4
-rw-r--r--src/core/hle/kernel/server_port.cpp2
-rw-r--r--src/core/hle/kernel/server_port.h3
-rw-r--r--src/core/hle/kernel/server_session.cpp4
-rw-r--r--src/core/hle/kernel/server_session.h6
-rw-r--r--src/core/hle/kernel/session.h2
-rw-r--r--src/core/hle/kernel/shared_memory.cpp37
-rw-r--r--src/core/hle/kernel/shared_memory.h8
-rw-r--r--src/core/hle/kernel/svc.cpp6
-rw-r--r--src/core/hle/kernel/thread.cpp56
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/kernel/timer.cpp2
-rw-r--r--src/core/hle/kernel/timer.h2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp36
-rw-r--r--src/core/hle/kernel/vm_manager.h8
-rw-r--r--src/core/hle/kernel/wait_object.cpp5
-rw-r--r--src/core/hle/kernel/wait_object.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp30
-rw-r--r--src/core/hle/service/am/am.cpp9
-rw-r--r--src/core/hle/service/am/idle.cpp24
-rw-r--r--src/core/hle/service/am/idle.h16
-rw-r--r--src/core/hle/service/am/omm.cpp42
-rw-r--r--src/core/hle/service/am/omm.h16
-rw-r--r--src/core/hle/service/am/spsm.cpp30
-rw-r--r--src/core/hle/service/am/spsm.h16
-rw-r--r--src/core/hle/service/apm/apm.cpp1
-rw-r--r--src/core/hle/service/apm/interface.cpp25
-rw-r--r--src/core/hle/service/apm/interface.h8
-rw-r--r--src/core/hle/service/arp/arp.cpp75
-rw-r--r--src/core/hle/service/arp/arp.h16
-rw-r--r--src/core/hle/service/audio/audctl.cpp45
-rw-r--r--src/core/hle/service/audio/audctl.h16
-rw-r--r--src/core/hle/service/audio/auddbg.cpp20
-rw-r--r--src/core/hle/service/audio/auddbg.h16
-rw-r--r--src/core/hle/service/audio/audin_a.cpp22
-rw-r--r--src/core/hle/service/audio/audin_a.h16
-rw-r--r--src/core/hle/service/audio/audio.cpp16
-rw-r--r--src/core/hle/service/audio/audout_a.cpp24
-rw-r--r--src/core/hle/service/audio/audout_a.h16
-rw-r--r--src/core/hle/service/audio/audout_u.cpp199
-rw-r--r--src/core/hle/service/audio/audout_u.h24
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp20
-rw-r--r--src/core/hle/service/audio/audrec_a.h16
-rw-r--r--src/core/hle/service/audio/audren_a.cpp26
-rw-r--r--src/core/hle/service/audio/audren_a.h16
-rw-r--r--src/core/hle/service/audio/audren_u.cpp208
-rw-r--r--src/core/hle/service/audio/audren_u.h19
-rw-r--r--src/core/hle/service/audio/hwopus.cpp135
-rw-r--r--src/core/hle/service/audio/hwopus.h1
-rw-r--r--src/core/hle/service/bpc/bpc.cpp57
-rw-r--r--src/core/hle/service/bpc/bpc.h15
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp72
-rw-r--r--src/core/hle/service/btdrv/btdrv.h16
-rw-r--r--src/core/hle/service/btm/btm.cpp121
-rw-r--r--src/core/hle/service/btm/btm.h15
-rw-r--r--src/core/hle/service/caps/caps.cpp152
-rw-r--r--src/core/hle/service/caps/caps.h15
-rw-r--r--src/core/hle/service/fgm/fgm.cpp75
-rw-r--r--src/core/hle/service/fgm/fgm.h15
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp4
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.cpp22
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.h16
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.cpp23
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.h16
-rw-r--r--src/core/hle/service/hid/hid.cpp19
-rw-r--r--src/core/hle/service/lbl/lbl.cpp90
-rw-r--r--src/core/hle/service/lbl/lbl.h15
-rw-r--r--src/core/hle/service/lm/lm.cpp8
-rw-r--r--src/core/hle/service/mig/mig.cpp34
-rw-r--r--src/core/hle/service/mig/mig.h15
-rw-r--r--src/core/hle/service/mii/mii.cpp107
-rw-r--r--src/core/hle/service/mii/mii.h15
-rw-r--r--src/core/hle/service/ncm/ncm.cpp59
-rw-r--r--src/core/hle/service/ncm/ncm.h15
-rw-r--r--src/core/hle/service/nfc/nfc.cpp222
-rw-r--r--src/core/hle/service/nfc/nfc.h15
-rw-r--r--src/core/hle/service/ns/ns.cpp447
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp2
-rw-r--r--src/core/hle/service/nvdrv/interface.h1
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp5
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h8
-rw-r--r--src/core/hle/service/pcie/pcie.cpp64
-rw-r--r--src/core/hle/service/pcie/pcie.h15
-rw-r--r--src/core/hle/service/pcv/pcv.cpp84
-rw-r--r--src/core/hle/service/pcv/pcv.h15
-rw-r--r--src/core/hle/service/psc/psc.cpp77
-rw-r--r--src/core/hle/service/psc/psc.h15
-rw-r--r--src/core/hle/service/service.cpp36
-rw-r--r--src/core/hle/service/service.h3
-rw-r--r--src/core/hle/service/set/set.cpp15
-rw-r--r--src/core/hle/service/set/set.h2
-rw-r--r--src/core/hle/service/sm/sm.h8
-rw-r--r--src/core/hle/service/time/time.cpp4
-rw-r--r--src/core/hle/service/usb/usb.cpp238
-rw-r--r--src/core/hle/service/usb/usb.h15
-rw-r--r--src/core/hle/service/wlan/wlan.cpp172
-rw-r--r--src/core/hle/service/wlan/wlan.h15
-rw-r--r--src/core/hw/aes/ccm.cpp28
-rw-r--r--src/core/hw/hw.cpp96
-rw-r--r--src/core/hw/hw.h50
-rw-r--r--src/core/hw/lcd.cpp67
-rw-r--r--src/core/hw/lcd.h86
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp11
-rw-r--r--src/core/loader/deconstructed_rom_directory.h6
-rw-r--r--src/core/loader/elf.cpp6
-rw-r--r--src/core/loader/loader.cpp9
-rw-r--r--src/core/loader/loader.h6
-rw-r--r--src/core/loader/nca.cpp63
-rw-r--r--src/core/loader/nca.h6
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/loader/nso.h2
-rw-r--r--src/core/loader/xci.cpp74
-rw-r--r--src/core/loader/xci.h44
-rw-r--r--src/core/memory.cpp146
-rw-r--r--src/core/memory.h111
-rw-r--r--src/core/perf_stats.cpp17
-rw-r--r--src/core/perf_stats.h8
-rw-r--r--src/core/settings.cpp10
-rw-r--r--src/core/settings.h9
195 files changed, 5710 insertions, 1847 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index b74e495ef..0abf7edc1 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,16 @@ add_library(core STATIC
12 core_timing.h 12 core_timing.h
13 core_timing_util.cpp 13 core_timing_util.cpp
14 core_timing_util.h 14 core_timing_util.h
15 crypto/aes_util.cpp
16 crypto/aes_util.h
17 crypto/encryption_layer.cpp
18 crypto/encryption_layer.h
19 crypto/key_manager.cpp
20 crypto/key_manager.h
21 crypto/ctr_encryption_layer.cpp
22 crypto/ctr_encryption_layer.h
23 file_sys/card_image.cpp
24 file_sys/card_image.h
15 file_sys/content_archive.cpp 25 file_sys/content_archive.cpp
16 file_sys/content_archive.h 26 file_sys/content_archive.h
17 file_sys/control_metadata.cpp 27 file_sys/control_metadata.cpp
@@ -23,6 +33,8 @@ add_library(core STATIC
23 file_sys/partition_filesystem.h 33 file_sys/partition_filesystem.h
24 file_sys/program_metadata.cpp 34 file_sys/program_metadata.cpp
25 file_sys/program_metadata.h 35 file_sys/program_metadata.h
36 file_sys/romfs.cpp
37 file_sys/romfs.h
26 file_sys/romfs_factory.cpp 38 file_sys/romfs_factory.cpp
27 file_sys/romfs_factory.h 39 file_sys/romfs_factory.h
28 file_sys/savedata_factory.cpp 40 file_sys/savedata_factory.cpp
@@ -35,6 +47,8 @@ add_library(core STATIC
35 file_sys/vfs_offset.h 47 file_sys/vfs_offset.h
36 file_sys/vfs_real.cpp 48 file_sys/vfs_real.cpp
37 file_sys/vfs_real.h 49 file_sys/vfs_real.h
50 file_sys/vfs_vector.cpp
51 file_sys/vfs_vector.h
38 frontend/emu_window.cpp 52 frontend/emu_window.cpp
39 frontend/emu_window.h 53 frontend/emu_window.h
40 frontend/framebuffer_layout.cpp 54 frontend/framebuffer_layout.cpp
@@ -59,12 +73,10 @@ add_library(core STATIC
59 hle/kernel/hle_ipc.h 73 hle/kernel/hle_ipc.h
60 hle/kernel/kernel.cpp 74 hle/kernel/kernel.cpp
61 hle/kernel/kernel.h 75 hle/kernel/kernel.h
62 hle/kernel/memory.cpp
63 hle/kernel/memory.h
64 hle/kernel/mutex.cpp 76 hle/kernel/mutex.cpp
65 hle/kernel/mutex.h 77 hle/kernel/mutex.h
66 hle/kernel/object_address_table.cpp 78 hle/kernel/object.cpp
67 hle/kernel/object_address_table.h 79 hle/kernel/object.h
68 hle/kernel/process.cpp 80 hle/kernel/process.cpp
69 hle/kernel/process.h 81 hle/kernel/process.h
70 hle/kernel/resource_limit.cpp 82 hle/kernel/resource_limit.cpp
@@ -110,23 +122,41 @@ add_library(core STATIC
110 hle/service/am/applet_ae.h 122 hle/service/am/applet_ae.h
111 hle/service/am/applet_oe.cpp 123 hle/service/am/applet_oe.cpp
112 hle/service/am/applet_oe.h 124 hle/service/am/applet_oe.h
125 hle/service/am/idle.cpp
126 hle/service/am/idle.h
127 hle/service/am/omm.cpp
128 hle/service/am/omm.h
129 hle/service/am/spsm.cpp
130 hle/service/am/spsm.h
113 hle/service/aoc/aoc_u.cpp 131 hle/service/aoc/aoc_u.cpp
114 hle/service/aoc/aoc_u.h 132 hle/service/aoc/aoc_u.h
115 hle/service/apm/apm.cpp 133 hle/service/apm/apm.cpp
116 hle/service/apm/apm.h 134 hle/service/apm/apm.h
117 hle/service/apm/interface.cpp 135 hle/service/apm/interface.cpp
118 hle/service/apm/interface.h 136 hle/service/apm/interface.h
137 hle/service/arp/arp.cpp
138 hle/service/arp/arp.h
139 hle/service/audio/audctl.cpp
140 hle/service/audio/audctl.h
141 hle/service/audio/auddbg.cpp
142 hle/service/audio/auddbg.h
143 hle/service/audio/audin_a.cpp
144 hle/service/audio/audin_a.h
119 hle/service/audio/audin_u.cpp 145 hle/service/audio/audin_u.cpp
120 hle/service/audio/audin_u.h 146 hle/service/audio/audin_u.h
121 hle/service/audio/audio.cpp 147 hle/service/audio/audio.cpp
122 hle/service/audio/audio.h 148 hle/service/audio/audio.h
149 hle/service/audio/audout_a.cpp
150 hle/service/audio/audout_a.h
123 hle/service/audio/audout_u.cpp 151 hle/service/audio/audout_u.cpp
124 hle/service/audio/audout_u.h 152 hle/service/audio/audout_u.h
153 hle/service/audio/audrec_a.cpp
154 hle/service/audio/audrec_a.h
125 hle/service/audio/audrec_u.cpp 155 hle/service/audio/audrec_u.cpp
126 hle/service/audio/audrec_u.h 156 hle/service/audio/audrec_u.h
157 hle/service/audio/audren_a.cpp
158 hle/service/audio/audren_a.h
127 hle/service/audio/audren_u.cpp 159 hle/service/audio/audren_u.cpp
128 hle/service/audio/audren_u.cpp
129 hle/service/audio/audren_u.h
130 hle/service/audio/audren_u.h 160 hle/service/audio/audren_u.h
131 hle/service/audio/codecctl.cpp 161 hle/service/audio/codecctl.cpp
132 hle/service/audio/codecctl.h 162 hle/service/audio/codecctl.h
@@ -136,6 +166,14 @@ add_library(core STATIC
136 hle/service/bcat/bcat.h 166 hle/service/bcat/bcat.h
137 hle/service/bcat/module.cpp 167 hle/service/bcat/module.cpp
138 hle/service/bcat/module.h 168 hle/service/bcat/module.h
169 hle/service/bpc/bpc.cpp
170 hle/service/bpc/bpc.h
171 hle/service/btdrv/btdrv.cpp
172 hle/service/btdrv/btdrv.h
173 hle/service/btm/btm.cpp
174 hle/service/btm/btm.h
175 hle/service/caps/caps.cpp
176 hle/service/caps/caps.h
139 hle/service/erpt/erpt.cpp 177 hle/service/erpt/erpt.cpp
140 hle/service/erpt/erpt.h 178 hle/service/erpt/erpt.h
141 hle/service/es/es.cpp 179 hle/service/es/es.cpp
@@ -150,8 +188,14 @@ add_library(core STATIC
150 hle/service/fatal/fatal_u.h 188 hle/service/fatal/fatal_u.h
151 hle/service/filesystem/filesystem.cpp 189 hle/service/filesystem/filesystem.cpp
152 hle/service/filesystem/filesystem.h 190 hle/service/filesystem/filesystem.h
191 hle/service/filesystem/fsp_ldr.cpp
192 hle/service/filesystem/fsp_ldr.h
193 hle/service/filesystem/fsp_pr.cpp
194 hle/service/filesystem/fsp_pr.h
153 hle/service/filesystem/fsp_srv.cpp 195 hle/service/filesystem/fsp_srv.cpp
154 hle/service/filesystem/fsp_srv.h 196 hle/service/filesystem/fsp_srv.h
197 hle/service/fgm/fgm.cpp
198 hle/service/fgm/fgm.h
155 hle/service/friend/friend.cpp 199 hle/service/friend/friend.cpp
156 hle/service/friend/friend.h 200 hle/service/friend/friend.h
157 hle/service/friend/interface.cpp 201 hle/service/friend/interface.cpp
@@ -164,14 +208,24 @@ add_library(core STATIC
164 hle/service/hid/irs.h 208 hle/service/hid/irs.h
165 hle/service/hid/xcd.cpp 209 hle/service/hid/xcd.cpp
166 hle/service/hid/xcd.h 210 hle/service/hid/xcd.h
211 hle/service/lbl/lbl.cpp
212 hle/service/lbl/lbl.h
167 hle/service/ldn/ldn.cpp 213 hle/service/ldn/ldn.cpp
168 hle/service/ldn/ldn.h 214 hle/service/ldn/ldn.h
169 hle/service/ldr/ldr.cpp 215 hle/service/ldr/ldr.cpp
170 hle/service/ldr/ldr.h 216 hle/service/ldr/ldr.h
171 hle/service/lm/lm.cpp 217 hle/service/lm/lm.cpp
172 hle/service/lm/lm.h 218 hle/service/lm/lm.h
219 hle/service/mig/mig.cpp
220 hle/service/mig/mig.h
221 hle/service/mii/mii.cpp
222 hle/service/mii/mii.h
173 hle/service/mm/mm_u.cpp 223 hle/service/mm/mm_u.cpp
174 hle/service/mm/mm_u.h 224 hle/service/mm/mm_u.h
225 hle/service/ncm/ncm.cpp
226 hle/service/ncm/ncm.h
227 hle/service/nfc/nfc.cpp
228 hle/service/nfc/nfc.h
175 hle/service/nfp/nfp.cpp 229 hle/service/nfp/nfp.cpp
176 hle/service/nfp/nfp.h 230 hle/service/nfp/nfp.h
177 hle/service/nfp/nfp_user.cpp 231 hle/service/nfp/nfp_user.cpp
@@ -209,14 +263,20 @@ add_library(core STATIC
209 hle/service/nvflinger/buffer_queue.h 263 hle/service/nvflinger/buffer_queue.h
210 hle/service/nvflinger/nvflinger.cpp 264 hle/service/nvflinger/nvflinger.cpp
211 hle/service/nvflinger/nvflinger.h 265 hle/service/nvflinger/nvflinger.h
266 hle/service/pcie/pcie.cpp
267 hle/service/pcie/pcie.h
212 hle/service/pctl/module.cpp 268 hle/service/pctl/module.cpp
213 hle/service/pctl/module.h 269 hle/service/pctl/module.h
214 hle/service/pctl/pctl.cpp 270 hle/service/pctl/pctl.cpp
215 hle/service/pctl/pctl.h 271 hle/service/pctl/pctl.h
272 hle/service/pcv/pcv.cpp
273 hle/service/pcv/pcv.h
216 hle/service/pm/pm.cpp 274 hle/service/pm/pm.cpp
217 hle/service/pm/pm.h 275 hle/service/pm/pm.h
218 hle/service/prepo/prepo.cpp 276 hle/service/prepo/prepo.cpp
219 hle/service/prepo/prepo.h 277 hle/service/prepo/prepo.h
278 hle/service/psc/psc.cpp
279 hle/service/psc/psc.h
220 hle/service/service.cpp 280 hle/service/service.cpp
221 hle/service/service.h 281 hle/service/service.h
222 hle/service/set/set.cpp 282 hle/service/set/set.cpp
@@ -255,6 +315,8 @@ add_library(core STATIC
255 hle/service/time/interface.h 315 hle/service/time/interface.h
256 hle/service/time/time.cpp 316 hle/service/time/time.cpp
257 hle/service/time/time.h 317 hle/service/time/time.h
318 hle/service/usb/usb.cpp
319 hle/service/usb/usb.h
258 hle/service/vi/vi.cpp 320 hle/service/vi/vi.cpp
259 hle/service/vi/vi.h 321 hle/service/vi/vi.h
260 hle/service/vi/vi_m.cpp 322 hle/service/vi/vi_m.cpp
@@ -263,10 +325,8 @@ add_library(core STATIC
263 hle/service/vi/vi_s.h 325 hle/service/vi/vi_s.h
264 hle/service/vi/vi_u.cpp 326 hle/service/vi/vi_u.cpp
265 hle/service/vi/vi_u.h 327 hle/service/vi/vi_u.h
266 hw/hw.cpp 328 hle/service/wlan/wlan.cpp
267 hw/hw.h 329 hle/service/wlan/wlan.h
268 hw/lcd.cpp
269 hw/lcd.h
270 loader/deconstructed_rom_directory.cpp 330 loader/deconstructed_rom_directory.cpp
271 loader/deconstructed_rom_directory.h 331 loader/deconstructed_rom_directory.h
272 loader/elf.cpp 332 loader/elf.cpp
@@ -281,6 +341,8 @@ add_library(core STATIC
281 loader/nro.h 341 loader/nro.h
282 loader/nso.cpp 342 loader/nso.cpp
283 loader/nso.h 343 loader/nso.h
344 loader/xci.cpp
345 loader/xci.h
284 memory.cpp 346 memory.cpp
285 memory.h 347 memory.h
286 memory_hook.cpp 348 memory_hook.cpp
@@ -299,8 +361,8 @@ add_library(core STATIC
299 361
300create_target_directory_groups(core) 362create_target_directory_groups(core)
301 363
302target_link_libraries(core PUBLIC common PRIVATE video_core) 364target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
303target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static unicorn) 365target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn)
304 366
305if (ARCHITECTURE_x86_64) 367if (ARCHITECTURE_x86_64)
306 target_sources(core PRIVATE 368 target_sources(core PRIVATE
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 57b8634b9..ceb3f7683 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -10,7 +10,7 @@
10#include "core/arm/dynarmic/arm_dynarmic.h" 10#include "core/arm/dynarmic/arm_dynarmic.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "core/core_timing.h" 12#include "core/core_timing.h"
13#include "core/hle/kernel/memory.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/svc.h" 14#include "core/hle/kernel/svc.h"
15#include "core/memory.h" 15#include "core/memory.h"
16 16
@@ -139,14 +139,12 @@ void ARM_Dynarmic::Step() {
139} 139}
140 140
141ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index) 141ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, size_t core_index)
142 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), 142 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
143 jit(MakeJit()), exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>( 143 exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} {
144 exclusive_monitor)}, 144 ThreadContext ctx;
145 core_index{core_index} {
146 ARM_Interface::ThreadContext ctx;
147 inner_unicorn.SaveContext(ctx); 145 inner_unicorn.SaveContext(ctx);
148 LoadContext(ctx);
149 PageTableChanged(); 146 PageTableChanged();
147 LoadContext(ctx);
150} 148}
151 149
152ARM_Dynarmic::~ARM_Dynarmic() = default; 150ARM_Dynarmic::~ARM_Dynarmic() = default;
@@ -205,7 +203,7 @@ u64 ARM_Dynarmic::GetTlsAddress() const {
205 return cb->tpidrro_el0; 203 return cb->tpidrro_el0;
206} 204}
207 205
208void ARM_Dynarmic::SetTlsAddress(u64 address) { 206void ARM_Dynarmic::SetTlsAddress(VAddr address) {
209 cb->tpidrro_el0 = address; 207 cb->tpidrro_el0 = address;
210} 208}
211 209
@@ -217,7 +215,7 @@ void ARM_Dynarmic::SetTPIDR_EL0(u64 value) {
217 cb->tpidr_el0 = value; 215 cb->tpidr_el0 = value;
218} 216}
219 217
220void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { 218void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
221 ctx.cpu_registers = jit->GetRegisters(); 219 ctx.cpu_registers = jit->GetRegisters();
222 ctx.sp = jit->GetSP(); 220 ctx.sp = jit->GetSP();
223 ctx.pc = jit->GetPC(); 221 ctx.pc = jit->GetPC();
@@ -226,7 +224,7 @@ void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
226 ctx.fpscr = jit->GetFpcr(); 224 ctx.fpscr = jit->GetFpcr();
227} 225}
228 226
229void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { 227void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
230 jit->SetRegisters(ctx.cpu_registers); 228 jit->SetRegisters(ctx.cpu_registers);
231 jit->SetSP(ctx.sp); 229 jit->SetSP(ctx.sp);
232 jit->SetPC(ctx.pc); 230 jit->SetPC(ctx.pc);
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
index 4c11f35a4..6bc349460 100644
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ b/src/core/arm/unicorn/arm_unicorn.cpp
@@ -203,7 +203,7 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) {
203 } 203 }
204 Kernel::Thread* thread = Kernel::GetCurrentThread(); 204 Kernel::Thread* thread = Kernel::GetCurrentThread();
205 SaveContext(thread->context); 205 SaveContext(thread->context);
206 if (last_bkpt_hit || (num_instructions == 1)) { 206 if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
207 last_bkpt_hit = false; 207 last_bkpt_hit = false;
208 GDBStub::Break(); 208 GDBStub::Break();
209 GDBStub::SendTrap(thread, 5); 209 GDBStub::SendTrap(thread, 5);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index b7f4b4532..085ba68d0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -15,11 +15,10 @@
15#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
16#include "core/hle/service/sm/controller.h" 16#include "core/hle/service/sm/controller.h"
17#include "core/hle/service/sm/sm.h" 17#include "core/hle/service/sm/sm.h"
18#include "core/hw/hw.h"
19#include "core/loader/loader.h" 18#include "core/loader/loader.h"
20#include "core/memory_setup.h"
21#include "core/settings.h" 19#include "core/settings.h"
22#include "file_sys/vfs_real.h" 20#include "file_sys/vfs_real.h"
21#include "video_core/renderer_base.h"
23#include "video_core/video_core.h" 22#include "video_core/video_core.h"
24 23
25namespace Core { 24namespace Core {
@@ -63,7 +62,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
63 // execute. Otherwise, get out of the loop function. 62 // execute. Otherwise, get out of the loop function.
64 if (GDBStub::GetCpuHaltFlag()) { 63 if (GDBStub::GetCpuHaltFlag()) {
65 if (GDBStub::GetCpuStepFlag()) { 64 if (GDBStub::GetCpuStepFlag()) {
66 GDBStub::SetCpuStepFlag(false);
67 tight_loop = false; 65 tight_loop = false;
68 } else { 66 } else {
69 return ResultStatus::Success; 67 return ResultStatus::Success;
@@ -79,6 +77,10 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
79 } 77 }
80 } 78 }
81 79
80 if (GDBStub::IsServerEnabled()) {
81 GDBStub::SetCpuStepFlag(false);
82 }
83
82 return status; 84 return status;
83} 85}
84 86
@@ -86,7 +88,7 @@ System::ResultStatus System::SingleStep() {
86 return RunLoop(false); 88 return RunLoop(false);
87} 89}
88 90
89System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) { 91System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) {
90 app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath)); 92 app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath));
91 93
92 if (!app_loader) { 94 if (!app_loader) {
@@ -101,8 +103,10 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
101 static_cast<int>(system_mode.second)); 103 static_cast<int>(system_mode.second));
102 104
103 switch (system_mode.second) { 105 switch (system_mode.second) {
104 case Loader::ResultStatus::ErrorEncrypted: 106 case Loader::ResultStatus::ErrorMissingKeys:
105 return ResultStatus::ErrorLoader_ErrorEncrypted; 107 return ResultStatus::ErrorLoader_ErrorMissingKeys;
108 case Loader::ResultStatus::ErrorDecrypting:
109 return ResultStatus::ErrorLoader_ErrorDecrypting;
106 case Loader::ResultStatus::ErrorInvalidFormat: 110 case Loader::ResultStatus::ErrorInvalidFormat:
107 return ResultStatus::ErrorLoader_ErrorInvalidFormat; 111 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
108 case Loader::ResultStatus::ErrorUnsupportedArch: 112 case Loader::ResultStatus::ErrorUnsupportedArch:
@@ -112,7 +116,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
112 } 116 }
113 } 117 }
114 118
115 ResultStatus init_result{Init(emu_window, system_mode.first.get())}; 119 ResultStatus init_result{Init(emu_window)};
116 if (init_result != ResultStatus::Success) { 120 if (init_result != ResultStatus::Success) {
117 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", 121 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
118 static_cast<int>(init_result)); 122 static_cast<int>(init_result));
@@ -126,8 +130,10 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
126 System::Shutdown(); 130 System::Shutdown();
127 131
128 switch (load_result) { 132 switch (load_result) {
129 case Loader::ResultStatus::ErrorEncrypted: 133 case Loader::ResultStatus::ErrorMissingKeys:
130 return ResultStatus::ErrorLoader_ErrorEncrypted; 134 return ResultStatus::ErrorLoader_ErrorMissingKeys;
135 case Loader::ResultStatus::ErrorDecrypting:
136 return ResultStatus::ErrorLoader_ErrorDecrypting;
131 case Loader::ResultStatus::ErrorInvalidFormat: 137 case Loader::ResultStatus::ErrorInvalidFormat:
132 return ResultStatus::ErrorLoader_ErrorInvalidFormat; 138 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
133 case Loader::ResultStatus::ErrorUnsupportedArch: 139 case Loader::ResultStatus::ErrorUnsupportedArch:
@@ -163,7 +169,7 @@ Cpu& System::CpuCore(size_t core_index) {
163 return *cpu_cores[core_index]; 169 return *cpu_cores[core_index];
164} 170}
165 171
166System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { 172System::ResultStatus System::Init(EmuWindow& emu_window) {
167 LOG_DEBUG(HW_Memory, "initialized OK"); 173 LOG_DEBUG(HW_Memory, "initialized OK");
168 174
169 CoreTiming::Init(); 175 CoreTiming::Init();
@@ -176,19 +182,20 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
176 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index); 182 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index);
177 } 183 }
178 184
179 gpu_core = std::make_unique<Tegra::GPU>();
180 telemetry_session = std::make_unique<Core::TelemetrySession>(); 185 telemetry_session = std::make_unique<Core::TelemetrySession>();
181 service_manager = std::make_shared<Service::SM::ServiceManager>(); 186 service_manager = std::make_shared<Service::SM::ServiceManager>();
182 187
183 HW::Init(); 188 Kernel::Init();
184 Kernel::Init(system_mode);
185 Service::Init(service_manager); 189 Service::Init(service_manager);
186 GDBStub::Init(); 190 GDBStub::Init();
187 191
188 if (!VideoCore::Init(emu_window)) { 192 renderer = VideoCore::CreateRenderer(emu_window);
193 if (!renderer->Init()) {
189 return ResultStatus::ErrorVideoCore; 194 return ResultStatus::ErrorVideoCore;
190 } 195 }
191 196
197 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
198
192 // Create threads for CPU cores 1-3, and build thread_to_cpu map 199 // Create threads for CPU cores 1-3, and build thread_to_cpu map
193 // CPU core 0 is run on the main thread 200 // CPU core 0 is run on the main thread
194 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; 201 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
@@ -220,11 +227,10 @@ void System::Shutdown() {
220 perf_results.frametime * 1000.0); 227 perf_results.frametime * 1000.0);
221 228
222 // Shutdown emulation session 229 // Shutdown emulation session
223 VideoCore::Shutdown(); 230 renderer.reset();
224 GDBStub::Shutdown(); 231 GDBStub::Shutdown();
225 Service::Shutdown(); 232 Service::Shutdown();
226 Kernel::Shutdown(); 233 Kernel::Shutdown();
227 HW::Shutdown();
228 service_manager.reset(); 234 service_manager.reset();
229 telemetry_session.reset(); 235 telemetry_session.reset();
230 gpu_core.reset(); 236 gpu_core.reset();
diff --git a/src/core/core.h b/src/core/core.h
index c123fe401..c8ca4b247 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -11,7 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/arm/exclusive_monitor.h" 12#include "core/arm/exclusive_monitor.h"
13#include "core/core_cpu.h" 13#include "core/core_cpu.h"
14#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/object.h"
15#include "core/hle/kernel/scheduler.h" 15#include "core/hle/kernel/scheduler.h"
16#include "core/loader/loader.h" 16#include "core/loader/loader.h"
17#include "core/memory.h" 17#include "core/memory.h"
@@ -27,6 +27,10 @@ namespace Service::SM {
27class ServiceManager; 27class ServiceManager;
28} 28}
29 29
30namespace VideoCore {
31class RendererBase;
32}
33
30namespace Core { 34namespace Core {
31 35
32class System { 36class System {
@@ -43,12 +47,14 @@ public:
43 47
44 /// Enumeration representing the return values of the System Initialize and Load process. 48 /// Enumeration representing the return values of the System Initialize and Load process.
45 enum class ResultStatus : u32 { 49 enum class ResultStatus : u32 {
46 Success, ///< Succeeded 50 Success, ///< Succeeded
47 ErrorNotInitialized, ///< Error trying to use core prior to initialization 51 ErrorNotInitialized, ///< Error trying to use core prior to initialization
48 ErrorGetLoader, ///< Error finding the correct application loader 52 ErrorGetLoader, ///< Error finding the correct application loader
49 ErrorSystemMode, ///< Error determining the system mode 53 ErrorSystemMode, ///< Error determining the system mode
50 ErrorLoader, ///< Error loading the specified application 54 ErrorLoader, ///< Error loading the specified application
51 ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption 55 ErrorLoader_ErrorMissingKeys, ///< Error because the key/keys needed to run could not be
56 ///< found.
57 ErrorLoader_ErrorDecrypting, ///< Error loading the specified application due to encryption
52 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an 58 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
53 /// invalid format 59 /// invalid format
54 ErrorSystemFiles, ///< Error in finding system files 60 ErrorSystemFiles, ///< Error in finding system files
@@ -76,16 +82,28 @@ public:
76 */ 82 */
77 ResultStatus SingleStep(); 83 ResultStatus SingleStep();
78 84
85 /**
86 * Invalidate the CPU instruction caches
87 * This function should only be used by GDB Stub to support breakpoints, memory updates and
88 * step/continue commands.
89 */
90 void InvalidateCpuInstructionCaches() {
91 for (auto& cpu : cpu_cores) {
92 cpu->ArmInterface().ClearInstructionCache();
93 }
94 }
95
79 /// Shutdown the emulated system. 96 /// Shutdown the emulated system.
80 void Shutdown(); 97 void Shutdown();
81 98
82 /** 99 /**
83 * Load an executable application. 100 * Load an executable application.
84 * @param emu_window Pointer to the host-system window used for video output and keyboard input. 101 * @param emu_window Reference to the host-system window used for video output and keyboard
102 * input.
85 * @param filepath String path to the executable application to load on the host file system. 103 * @param filepath String path to the executable application to load on the host file system.
86 * @returns ResultStatus code, indicating if the operation succeeded. 104 * @returns ResultStatus code, indicating if the operation succeeded.
87 */ 105 */
88 ResultStatus Load(EmuWindow* emu_window, const std::string& filepath); 106 ResultStatus Load(EmuWindow& emu_window, const std::string& filepath);
89 107
90 /** 108 /**
91 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an 109 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -126,11 +144,26 @@ public:
126 /// Gets a CPU interface to the CPU core with the specified index 144 /// Gets a CPU interface to the CPU core with the specified index
127 Cpu& CpuCore(size_t core_index); 145 Cpu& CpuCore(size_t core_index);
128 146
129 /// Gets the GPU interface 147 /// Gets a mutable reference to the GPU interface
130 Tegra::GPU& GPU() { 148 Tegra::GPU& GPU() {
131 return *gpu_core; 149 return *gpu_core;
132 } 150 }
133 151
152 /// Gets an immutable reference to the GPU interface.
153 const Tegra::GPU& GPU() const {
154 return *gpu_core;
155 }
156
157 /// Gets a mutable reference to the renderer.
158 VideoCore::RendererBase& Renderer() {
159 return *renderer;
160 }
161
162 /// Gets an immutable reference to the renderer.
163 const VideoCore::RendererBase& Renderer() const {
164 return *renderer;
165 }
166
134 /// Gets the scheduler for the CPU core that is currently running 167 /// Gets the scheduler for the CPU core that is currently running
135 Kernel::Scheduler& CurrentScheduler() { 168 Kernel::Scheduler& CurrentScheduler() {
136 return *CurrentCpuCore().Scheduler(); 169 return *CurrentCpuCore().Scheduler();
@@ -186,14 +219,15 @@ private:
186 219
187 /** 220 /**
188 * Initialize the emulated system. 221 * Initialize the emulated system.
189 * @param emu_window Pointer to the host-system window used for video output and keyboard input. 222 * @param emu_window Reference to the host-system window used for video output and keyboard
190 * @param system_mode The system mode. 223 * input.
191 * @return ResultStatus code, indicating if the operation succeeded. 224 * @return ResultStatus code, indicating if the operation succeeded.
192 */ 225 */
193 ResultStatus Init(EmuWindow* emu_window, u32 system_mode); 226 ResultStatus Init(EmuWindow& emu_window);
194 227
195 /// AppLoader used to load the current executing application 228 /// AppLoader used to load the current executing application
196 std::unique_ptr<Loader::AppLoader> app_loader; 229 std::unique_ptr<Loader::AppLoader> app_loader;
230 std::unique_ptr<VideoCore::RendererBase> renderer;
197 std::unique_ptr<Tegra::GPU> gpu_core; 231 std::unique_ptr<Tegra::GPU> gpu_core;
198 std::shared_ptr<Tegra::DebugContext> debug_context; 232 std::shared_ptr<Tegra::DebugContext> debug_context;
199 Kernel::SharedPtr<Kernel::Process> current_process; 233 Kernel::SharedPtr<Kernel::Process> current_process;
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 54e15a701..46a522fcd 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -12,7 +12,6 @@
12#include "core/arm/unicorn/arm_unicorn.h" 12#include "core/arm/unicorn/arm_unicorn.h"
13#include "core/core_cpu.h" 13#include "core/core_cpu.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/scheduler.h" 15#include "core/hle/kernel/scheduler.h"
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
18#include "core/settings.h" 17#include "core/settings.h"
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index a1b6f96f1..d3bb6f818 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -141,7 +141,7 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user
141 ForceExceptionCheck(cycles_into_future); 141 ForceExceptionCheck(cycles_into_future);
142 142
143 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); 143 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
144 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<Event>()); 144 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
145} 145}
146 146
147void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) { 147void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
@@ -156,7 +156,7 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
156 // Removing random items breaks the invariant so we have to re-establish it. 156 // Removing random items breaks the invariant so we have to re-establish it.
157 if (itr != event_queue.end()) { 157 if (itr != event_queue.end()) {
158 event_queue.erase(itr, event_queue.end()); 158 event_queue.erase(itr, event_queue.end());
159 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<Event>()); 159 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
160 } 160 }
161} 161}
162 162
@@ -167,7 +167,7 @@ void RemoveEvent(const EventType* event_type) {
167 // Removing random items breaks the invariant so we have to re-establish it. 167 // Removing random items breaks the invariant so we have to re-establish it.
168 if (itr != event_queue.end()) { 168 if (itr != event_queue.end()) {
169 event_queue.erase(itr, event_queue.end()); 169 event_queue.erase(itr, event_queue.end());
170 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<Event>()); 170 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
171 } 171 }
172} 172}
173 173
@@ -190,7 +190,7 @@ void MoveEvents() {
190 for (Event ev; ts_queue.Pop(ev);) { 190 for (Event ev; ts_queue.Pop(ev);) {
191 ev.fifo_order = event_fifo_id++; 191 ev.fifo_order = event_fifo_id++;
192 event_queue.emplace_back(std::move(ev)); 192 event_queue.emplace_back(std::move(ev));
193 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<Event>()); 193 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
194 } 194 }
195} 195}
196 196
@@ -205,7 +205,7 @@ void Advance() {
205 205
206 while (!event_queue.empty() && event_queue.front().time <= global_timer) { 206 while (!event_queue.empty() && event_queue.front().time <= global_timer) {
207 Event evt = std::move(event_queue.front()); 207 Event evt = std::move(event_queue.front());
208 std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<Event>()); 208 std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
209 event_queue.pop_back(); 209 event_queue.pop_back();
210 evt.type->callback(evt.userdata, static_cast<int>(global_timer - evt.time)); 210 evt.type->callback(evt.userdata, static_cast<int>(global_timer - evt.time));
211 } 211 }
@@ -226,8 +226,8 @@ void Idle() {
226 downcount = 0; 226 downcount = 0;
227} 227}
228 228
229u64 GetGlobalTimeUs() { 229std::chrono::microseconds GetGlobalTimeUs() {
230 return GetTicks() * 1000000 / BASE_CLOCK_RATE; 230 return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
231} 231}
232 232
233int GetDowncount() { 233int GetDowncount() {
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 7fe6380ad..dfa161c0d 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -17,12 +17,17 @@
17 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") 17 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
18 */ 18 */
19 19
20#include <chrono>
20#include <functional> 21#include <functional>
21#include <string> 22#include <string>
22#include "common/common_types.h" 23#include "common/common_types.h"
23 24
24namespace CoreTiming { 25namespace CoreTiming {
25 26
27struct EventType;
28
29using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
30
26/** 31/**
27 * CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is 32 * CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
28 * required to end slice -1 and start slice 0 before the first cycle of code is executed. 33 * required to end slice -1 and start slice 0 before the first cycle of code is executed.
@@ -30,8 +35,6 @@ namespace CoreTiming {
30void Init(); 35void Init();
31void Shutdown(); 36void Shutdown();
32 37
33typedef std::function<void(u64 userdata, int cycles_late)> TimedCallback;
34
35/** 38/**
36 * This should only be called from the emu thread, if you are calling it any other thread, you are 39 * This should only be called from the emu thread, if you are calling it any other thread, you are
37 * doing something evil 40 * doing something evil
@@ -40,8 +43,6 @@ u64 GetTicks();
40u64 GetIdleTicks(); 43u64 GetIdleTicks();
41void AddTicks(u64 ticks); 44void AddTicks(u64 ticks);
42 45
43struct EventType;
44
45/** 46/**
46 * Returns the event_type identifier. if name is not unique, it will assert. 47 * Returns the event_type identifier. if name is not unique, it will assert.
47 */ 48 */
@@ -86,7 +87,7 @@ void ClearPendingEvents();
86 87
87void ForceExceptionCheck(s64 cycles); 88void ForceExceptionCheck(s64 cycles);
88 89
89u64 GetGlobalTimeUs(); 90std::chrono::microseconds GetGlobalTimeUs();
90 91
91int GetDowncount(); 92int GetDowncount();
92 93
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
new file mode 100644
index 000000000..a9876c83e
--- /dev/null
+++ b/src/core/crypto/aes_util.cpp
@@ -0,0 +1,115 @@
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 <mbedtls/cipher.h>
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/crypto/aes_util.h"
9#include "core/crypto/key_manager.h"
10
11namespace Core::Crypto {
12namespace {
13std::vector<u8> CalculateNintendoTweak(size_t sector_id) {
14 std::vector<u8> out(0x10);
15 for (size_t i = 0xF; i <= 0xF; --i) {
16 out[i] = sector_id & 0xFF;
17 sector_id >>= 8;
18 }
19 return out;
20}
21} // Anonymous namespace
22
23static_assert(static_cast<size_t>(Mode::CTR) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_CTR),
24 "CTR has incorrect value.");
25static_assert(static_cast<size_t>(Mode::ECB) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_ECB),
26 "ECB has incorrect value.");
27static_assert(static_cast<size_t>(Mode::XTS) == static_cast<size_t>(MBEDTLS_CIPHER_AES_128_XTS),
28 "XTS has incorrect value.");
29
30// Structure to hide mbedtls types from header file
31struct CipherContext {
32 mbedtls_cipher_context_t encryption_context;
33 mbedtls_cipher_context_t decryption_context;
34};
35
36template <typename Key, size_t KeySize>
37Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
38 : ctx(std::make_unique<CipherContext>()) {
39 mbedtls_cipher_init(&ctx->encryption_context);
40 mbedtls_cipher_init(&ctx->decryption_context);
41
42 ASSERT_MSG((mbedtls_cipher_setup(
43 &ctx->encryption_context,
44 mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode))) ||
45 mbedtls_cipher_setup(
46 &ctx->decryption_context,
47 mbedtls_cipher_info_from_type(static_cast<mbedtls_cipher_type_t>(mode)))) == 0,
48 "Failed to initialize mbedtls ciphers.");
49
50 ASSERT(
51 !mbedtls_cipher_setkey(&ctx->encryption_context, key.data(), KeySize * 8, MBEDTLS_ENCRYPT));
52 ASSERT(
53 !mbedtls_cipher_setkey(&ctx->decryption_context, key.data(), KeySize * 8, MBEDTLS_DECRYPT));
54 //"Failed to set key on mbedtls ciphers.");
55}
56
57template <typename Key, size_t KeySize>
58AESCipher<Key, KeySize>::~AESCipher() {
59 mbedtls_cipher_free(&ctx->encryption_context);
60 mbedtls_cipher_free(&ctx->decryption_context);
61}
62
63template <typename Key, size_t KeySize>
64void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
65 ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
66 mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
67 "Failed to set IV on mbedtls ciphers.");
68}
69
70template <typename Key, size_t KeySize>
71void AESCipher<Key, KeySize>::Transcode(const u8* src, size_t size, u8* dest, Op op) const {
72 auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
73
74 mbedtls_cipher_reset(context);
75
76 size_t written = 0;
77 if (mbedtls_cipher_get_cipher_mode(context) == MBEDTLS_MODE_XTS) {
78 mbedtls_cipher_update(context, src, size, dest, &written);
79 if (written != size) {
80 LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
81 size, written);
82 }
83 } else {
84 const auto block_size = mbedtls_cipher_get_block_size(context);
85
86 for (size_t offset = 0; offset < size; offset += block_size) {
87 auto length = std::min<size_t>(block_size, size - offset);
88 mbedtls_cipher_update(context, src + offset, length, dest + offset, &written);
89 if (written != length) {
90 LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
91 length, written);
92 }
93 }
94 }
95
96 mbedtls_cipher_finish(context, nullptr, nullptr);
97}
98
99template <typename Key, size_t KeySize>
100void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id,
101 size_t sector_size, Op op) {
102 if (size % sector_size > 0) {
103 LOG_CRITICAL(Crypto, "Data size must be a multiple of sector size.");
104 return;
105 }
106
107 for (size_t i = 0; i < size; i += sector_size) {
108 SetIV(CalculateNintendoTweak(sector_id++));
109 Transcode<u8, u8>(src + i, sector_size, dest + i, op);
110 }
111}
112
113template class AESCipher<Key128>;
114template class AESCipher<Key256>;
115} // namespace Core::Crypto \ No newline at end of file
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h
new file mode 100644
index 000000000..8ce9d6612
--- /dev/null
+++ b/src/core/crypto/aes_util.h
@@ -0,0 +1,64 @@
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 <type_traits>
9#include <vector>
10#include "common/common_types.h"
11#include "core/file_sys/vfs.h"
12
13namespace Core::Crypto {
14
15struct CipherContext;
16
17enum class Mode {
18 CTR = 11,
19 ECB = 2,
20 XTS = 70,
21};
22
23enum class Op {
24 Encrypt,
25 Decrypt,
26};
27
28template <typename Key, size_t KeySize = sizeof(Key)>
29class AESCipher {
30 static_assert(std::is_same_v<Key, std::array<u8, KeySize>>, "Key must be std::array of u8.");
31 static_assert(KeySize == 0x10 || KeySize == 0x20, "KeySize must be 128 or 256.");
32
33public:
34 AESCipher(Key key, Mode mode);
35
36 ~AESCipher();
37
38 void SetIV(std::vector<u8> iv);
39
40 template <typename Source, typename Dest>
41 void Transcode(const Source* src, size_t size, Dest* dest, Op op) const {
42 static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
43 "Transcode source and destination types must be trivially copyable.");
44 Transcode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), op);
45 }
46
47 void Transcode(const u8* src, size_t size, u8* dest, Op op) const;
48
49 template <typename Source, typename Dest>
50 void XTSTranscode(const Source* src, size_t size, Dest* dest, size_t sector_id,
51 size_t sector_size, Op op) {
52 static_assert(std::is_trivially_copyable_v<Source> && std::is_trivially_copyable_v<Dest>,
53 "XTSTranscode source and destination types must be trivially copyable.");
54 XTSTranscode(reinterpret_cast<const u8*>(src), size, reinterpret_cast<u8*>(dest), sector_id,
55 sector_size, op);
56 }
57
58 void XTSTranscode(const u8* src, size_t size, u8* dest, size_t sector_id, size_t sector_size,
59 Op op);
60
61private:
62 std::unique_ptr<CipherContext> ctx;
63};
64} // namespace Core::Crypto
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp
new file mode 100644
index 000000000..106db02b3
--- /dev/null
+++ b/src/core/crypto/ctr_encryption_layer.cpp
@@ -0,0 +1,56 @@
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 "common/assert.h"
7#include "core/crypto/ctr_encryption_layer.h"
8
9namespace Core::Crypto {
10
11CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, size_t base_offset)
12 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
13 iv(16, 0) {}
14
15size_t CTREncryptionLayer::Read(u8* data, size_t length, size_t offset) const {
16 if (length == 0)
17 return 0;
18
19 const auto sector_offset = offset & 0xF;
20 if (sector_offset == 0) {
21 UpdateIV(base_offset + offset);
22 std::vector<u8> raw = base->ReadBytes(length, offset);
23 if (raw.size() != length)
24 return Read(data, raw.size(), offset);
25 cipher.Transcode(raw.data(), length, data, Op::Decrypt);
26 return length;
27 }
28
29 // offset does not fall on block boundary (0x10)
30 std::vector<u8> block = base->ReadBytes(0x10, offset - sector_offset);
31 UpdateIV(base_offset + offset - sector_offset);
32 cipher.Transcode(block.data(), block.size(), block.data(), Op::Decrypt);
33 size_t read = 0x10 - sector_offset;
34
35 if (length + sector_offset < 0x10) {
36 std::memcpy(data, block.data() + sector_offset, std::min<u64>(length, read));
37 return read;
38 }
39 std::memcpy(data, block.data() + sector_offset, read);
40 return read + Read(data + read, length - read, offset + read);
41}
42
43void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
44 const auto length = std::min(iv_.size(), iv.size());
45 iv.assign(iv_.cbegin(), iv_.cbegin() + length);
46}
47
48void CTREncryptionLayer::UpdateIV(size_t offset) const {
49 offset >>= 4;
50 for (size_t i = 0; i < 8; ++i) {
51 iv[16 - i - 1] = offset & 0xFF;
52 offset >>= 8;
53 }
54 cipher.SetIV(iv);
55}
56} // namespace Core::Crypto
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
new file mode 100644
index 000000000..11b8683c7
--- /dev/null
+++ b/src/core/crypto/ctr_encryption_layer.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 <vector>
8#include "core/crypto/aes_util.h"
9#include "core/crypto/encryption_layer.h"
10#include "core/crypto/key_manager.h"
11
12namespace Core::Crypto {
13
14// Sits on top of a VirtualFile and provides CTR-mode AES decription.
15class CTREncryptionLayer : public EncryptionLayer {
16public:
17 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, size_t base_offset);
18
19 size_t Read(u8* data, size_t length, size_t offset) const override;
20
21 void SetIV(const std::vector<u8>& iv);
22
23private:
24 size_t base_offset;
25
26 // Must be mutable as operations modify cipher contexts.
27 mutable AESCipher<Key128> cipher;
28 mutable std::vector<u8> iv;
29
30 void UpdateIV(size_t offset) const;
31};
32
33} // namespace Core::Crypto
diff --git a/src/core/crypto/encryption_layer.cpp b/src/core/crypto/encryption_layer.cpp
new file mode 100644
index 000000000..4204527e3
--- /dev/null
+++ b/src/core/crypto/encryption_layer.cpp
@@ -0,0 +1,42 @@
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/crypto/encryption_layer.h"
6
7namespace Core::Crypto {
8
9EncryptionLayer::EncryptionLayer(FileSys::VirtualFile base_) : base(std::move(base_)) {}
10
11std::string EncryptionLayer::GetName() const {
12 return base->GetName();
13}
14
15size_t EncryptionLayer::GetSize() const {
16 return base->GetSize();
17}
18
19bool EncryptionLayer::Resize(size_t new_size) {
20 return false;
21}
22
23std::shared_ptr<FileSys::VfsDirectory> EncryptionLayer::GetContainingDirectory() const {
24 return base->GetContainingDirectory();
25}
26
27bool EncryptionLayer::IsWritable() const {
28 return false;
29}
30
31bool EncryptionLayer::IsReadable() const {
32 return true;
33}
34
35size_t EncryptionLayer::Write(const u8* data, size_t length, size_t offset) {
36 return 0;
37}
38
39bool EncryptionLayer::Rename(std::string_view name) {
40 return base->Rename(name);
41}
42} // namespace Core::Crypto
diff --git a/src/core/crypto/encryption_layer.h b/src/core/crypto/encryption_layer.h
new file mode 100644
index 000000000..7f05af9b4
--- /dev/null
+++ b/src/core/crypto/encryption_layer.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 "common/common_types.h"
8#include "core/file_sys/vfs.h"
9
10namespace Core::Crypto {
11
12// Basically non-functional class that implements all of the methods that are irrelevant to an
13// EncryptionLayer. Reduces duplicate code.
14class EncryptionLayer : public FileSys::VfsFile {
15public:
16 explicit EncryptionLayer(FileSys::VirtualFile base);
17
18 size_t Read(u8* data, size_t length, size_t offset) const override = 0;
19
20 std::string GetName() const override;
21 size_t GetSize() const override;
22 bool Resize(size_t new_size) override;
23 std::shared_ptr<FileSys::VfsDirectory> GetContainingDirectory() const override;
24 bool IsWritable() const override;
25 bool IsReadable() const override;
26 size_t Write(const u8* data, size_t length, size_t offset) override;
27 bool Rename(std::string_view name) override;
28
29protected:
30 FileSys::VirtualFile base;
31};
32
33} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
new file mode 100644
index 000000000..fc45e7ab5
--- /dev/null
+++ b/src/core/crypto/key_manager.cpp
@@ -0,0 +1,208 @@
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 <algorithm>
6#include <array>
7#include <fstream>
8#include <locale>
9#include <sstream>
10#include <string_view>
11#include "common/common_paths.h"
12#include "common/file_util.h"
13#include "core/crypto/key_manager.h"
14#include "core/settings.h"
15
16namespace Core::Crypto {
17
18static u8 ToHexNibble(char c1) {
19 if (c1 >= 65 && c1 <= 70)
20 return c1 - 55;
21 if (c1 >= 97 && c1 <= 102)
22 return c1 - 87;
23 if (c1 >= 48 && c1 <= 57)
24 return c1 - 48;
25 throw std::logic_error("Invalid hex digit");
26}
27
28template <size_t Size>
29static std::array<u8, Size> HexStringToArray(std::string_view str) {
30 std::array<u8, Size> out{};
31 for (size_t i = 0; i < 2 * Size; i += 2) {
32 auto d1 = str[i];
33 auto d2 = str[i + 1];
34 out[i / 2] = (ToHexNibble(d1) << 4) | ToHexNibble(d2);
35 }
36 return out;
37}
38
39std::array<u8, 16> operator""_array16(const char* str, size_t len) {
40 if (len != 32)
41 throw std::logic_error("Not of correct size.");
42 return HexStringToArray<16>(str);
43}
44
45std::array<u8, 32> operator""_array32(const char* str, size_t len) {
46 if (len != 64)
47 throw std::logic_error("Not of correct size.");
48 return HexStringToArray<32>(str);
49}
50
51KeyManager::KeyManager() {
52 // Initialize keys
53 const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
54 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
55 if (Settings::values.use_dev_keys) {
56 dev_mode = true;
57 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);
58 } else {
59 dev_mode = false;
60 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "prod.keys", false);
61 }
62
63 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true);
64}
65
66void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
67 std::ifstream file(filename);
68 if (!file.is_open())
69 return;
70
71 std::string line;
72 while (std::getline(file, line)) {
73 std::vector<std::string> out;
74 std::stringstream stream(line);
75 std::string item;
76 while (std::getline(stream, item, '='))
77 out.push_back(std::move(item));
78
79 if (out.size() != 2)
80 continue;
81
82 out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end());
83 out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end());
84
85 if (is_title_keys) {
86 auto rights_id_raw = HexStringToArray<16>(out[0]);
87 u128 rights_id{};
88 std::memcpy(rights_id.data(), rights_id_raw.data(), rights_id_raw.size());
89 Key128 key = HexStringToArray<16>(out[1]);
90 SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
91 } else {
92 std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower);
93 if (s128_file_id.find(out[0]) != s128_file_id.end()) {
94 const auto index = s128_file_id.at(out[0]);
95 Key128 key = HexStringToArray<16>(out[1]);
96 SetKey(index.type, key, index.field1, index.field2);
97 } else if (s256_file_id.find(out[0]) != s256_file_id.end()) {
98 const auto index = s256_file_id.at(out[0]);
99 Key256 key = HexStringToArray<32>(out[1]);
100 SetKey(index.type, key, index.field1, index.field2);
101 }
102 }
103 }
104}
105
106void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
107 const std::string& filename, bool title) {
108 if (FileUtil::Exists(dir1 + DIR_SEP + filename))
109 LoadFromFile(dir1 + DIR_SEP + filename, title);
110 else if (FileUtil::Exists(dir2 + DIR_SEP + filename))
111 LoadFromFile(dir2 + DIR_SEP + filename, title);
112}
113
114bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const {
115 return s128_keys.find({id, field1, field2}) != s128_keys.end();
116}
117
118bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const {
119 return s256_keys.find({id, field1, field2}) != s256_keys.end();
120}
121
122Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const {
123 if (!HasKey(id, field1, field2))
124 return {};
125 return s128_keys.at({id, field1, field2});
126}
127
128Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
129 if (!HasKey(id, field1, field2))
130 return {};
131 return s256_keys.at({id, field1, field2});
132}
133
134void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
135 s128_keys[{id, field1, field2}] = key;
136}
137
138void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
139 s256_keys[{id, field1, field2}] = key;
140}
141
142bool KeyManager::KeyFileExists(bool title) {
143 const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
144 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
145 if (title) {
146 return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
147 FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
148 }
149
150 if (Settings::values.use_dev_keys) {
151 return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
152 FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
153 }
154
155 return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
156 FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
157}
158
159const std::unordered_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
160 {"master_key_00", {S128KeyType::Master, 0, 0}},
161 {"master_key_01", {S128KeyType::Master, 1, 0}},
162 {"master_key_02", {S128KeyType::Master, 2, 0}},
163 {"master_key_03", {S128KeyType::Master, 3, 0}},
164 {"master_key_04", {S128KeyType::Master, 4, 0}},
165 {"package1_key_00", {S128KeyType::Package1, 0, 0}},
166 {"package1_key_01", {S128KeyType::Package1, 1, 0}},
167 {"package1_key_02", {S128KeyType::Package1, 2, 0}},
168 {"package1_key_03", {S128KeyType::Package1, 3, 0}},
169 {"package1_key_04", {S128KeyType::Package1, 4, 0}},
170 {"package2_key_00", {S128KeyType::Package2, 0, 0}},
171 {"package2_key_01", {S128KeyType::Package2, 1, 0}},
172 {"package2_key_02", {S128KeyType::Package2, 2, 0}},
173 {"package2_key_03", {S128KeyType::Package2, 3, 0}},
174 {"package2_key_04", {S128KeyType::Package2, 4, 0}},
175 {"titlekek_00", {S128KeyType::Titlekek, 0, 0}},
176 {"titlekek_01", {S128KeyType::Titlekek, 1, 0}},
177 {"titlekek_02", {S128KeyType::Titlekek, 2, 0}},
178 {"titlekek_03", {S128KeyType::Titlekek, 3, 0}},
179 {"titlekek_04", {S128KeyType::Titlekek, 4, 0}},
180 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
181 {"key_area_key_application_00",
182 {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Application)}},
183 {"key_area_key_application_01",
184 {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Application)}},
185 {"key_area_key_application_02",
186 {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Application)}},
187 {"key_area_key_application_03",
188 {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Application)}},
189 {"key_area_key_application_04",
190 {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Application)}},
191 {"key_area_key_ocean_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}},
192 {"key_area_key_ocean_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}},
193 {"key_area_key_ocean_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}},
194 {"key_area_key_ocean_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}},
195 {"key_area_key_ocean_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}},
196 {"key_area_key_system_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::System)}},
197 {"key_area_key_system_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::System)}},
198 {"key_area_key_system_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::System)}},
199 {"key_area_key_system_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::System)}},
200 {"key_area_key_system_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::System)}},
201};
202
203const std::unordered_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
204 {"header_key", {S256KeyType::Header, 0, 0}},
205 {"sd_card_save_key", {S256KeyType::SDSave, 0, 0}},
206 {"sd_card_nca_key", {S256KeyType::SDNCA, 0, 0}},
207};
208} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
new file mode 100644
index 000000000..c4c53cefc
--- /dev/null
+++ b/src/core/crypto/key_manager.h
@@ -0,0 +1,120 @@
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 <type_traits>
10#include <unordered_map>
11#include <vector>
12#include <fmt/format.h>
13#include "common/common_types.h"
14
15namespace Core::Crypto {
16
17using Key128 = std::array<u8, 0x10>;
18using Key256 = std::array<u8, 0x20>;
19using SHA256Hash = std::array<u8, 0x20>;
20
21static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big.");
22static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big.");
23
24enum class S256KeyType : u64 {
25 Header, //
26 SDSave, //
27 SDNCA, //
28};
29
30enum class S128KeyType : u64 {
31 Master, // f1=crypto revision
32 Package1, // f1=crypto revision
33 Package2, // f1=crypto revision
34 Titlekek, // f1=crypto revision
35 ETicketRSAKek, //
36 KeyArea, // f1=crypto revision f2=type {app, ocean, system}
37 SDSeed, //
38 Titlekey, // f1=rights id LSB f2=rights id MSB
39};
40
41enum class KeyAreaKeyType : u8 {
42 Application,
43 Ocean,
44 System,
45};
46
47template <typename KeyType>
48struct KeyIndex {
49 KeyType type;
50 u64 field1;
51 u64 field2;
52
53 std::string DebugInfo() const {
54 u8 key_size = 16;
55 if constexpr (std::is_same_v<KeyType, S256KeyType>)
56 key_size = 32;
57 return fmt::format("key_size={:02X}, key={:02X}, field1={:016X}, field2={:016X}", key_size,
58 static_cast<u8>(type), field1, field2);
59 }
60};
61
62// The following two (== and hash) are so KeyIndex can be a key in unordered_map
63
64template <typename KeyType>
65bool operator==(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
66 return std::tie(lhs.type, lhs.field1, lhs.field2) == std::tie(rhs.type, rhs.field1, rhs.field2);
67}
68
69template <typename KeyType>
70bool operator!=(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) {
71 return !operator==(lhs, rhs);
72}
73
74} // namespace Core::Crypto
75
76namespace std {
77template <typename KeyType>
78struct hash<Core::Crypto::KeyIndex<KeyType>> {
79 size_t operator()(const Core::Crypto::KeyIndex<KeyType>& k) const {
80 using std::hash;
81
82 return ((hash<u64>()(static_cast<u64>(k.type)) ^ (hash<u64>()(k.field1) << 1)) >> 1) ^
83 (hash<u64>()(k.field2) << 1);
84 }
85};
86} // namespace std
87
88namespace Core::Crypto {
89
90std::array<u8, 0x10> operator"" _array16(const char* str, size_t len);
91std::array<u8, 0x20> operator"" _array32(const char* str, size_t len);
92
93class KeyManager {
94public:
95 KeyManager();
96
97 bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
98 bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const;
99
100 Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
101 Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const;
102
103 void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
104 void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
105
106 static bool KeyFileExists(bool title);
107
108private:
109 std::unordered_map<KeyIndex<S128KeyType>, Key128> s128_keys;
110 std::unordered_map<KeyIndex<S256KeyType>, Key256> s256_keys;
111
112 bool dev_mode;
113 void LoadFromFile(const std::string& filename, bool is_title_keys);
114 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
115 const std::string& filename, bool title);
116
117 static const std::unordered_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
118 static const std::unordered_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
119};
120} // namespace Core::Crypto
diff --git a/src/core/crypto/sha_util.cpp b/src/core/crypto/sha_util.cpp
new file mode 100644
index 000000000..180008a85
--- /dev/null
+++ b/src/core/crypto/sha_util.cpp
@@ -0,0 +1,5 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5namespace Crypto {} // namespace Crypto
diff --git a/src/core/crypto/sha_util.h b/src/core/crypto/sha_util.h
new file mode 100644
index 000000000..fa3fa9d33
--- /dev/null
+++ b/src/core/crypto/sha_util.h
@@ -0,0 +1,20 @@
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 "common/assert.h"
8#include "core/file_sys/vfs.h"
9#include "key_manager.h"
10#include "mbedtls/cipher.h"
11
12namespace Crypto {
13typedef std::array<u8, 0x20> SHA256Hash;
14
15inline SHA256Hash operator"" _HASH(const char* data, size_t len) {
16 if (len != 0x40)
17 return {};
18}
19
20} // namespace Crypto
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
new file mode 100644
index 000000000..395eea8ae
--- /dev/null
+++ b/src/core/file_sys/card_image.cpp
@@ -0,0 +1,149 @@
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 <array>
6#include <string>
7#include <core/loader/loader.h>
8#include "core/file_sys/card_image.h"
9#include "core/file_sys/partition_filesystem.h"
10#include "core/file_sys/vfs_offset.h"
11
12namespace FileSys {
13
14XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
15 if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
16 status = Loader::ResultStatus::ErrorInvalidFormat;
17 return;
18 }
19
20 if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) {
21 status = Loader::ResultStatus::ErrorInvalidFormat;
22 return;
23 }
24
25 PartitionFilesystem main_hfs(
26 std::make_shared<OffsetVfsFile>(file, header.hfs_size, header.hfs_offset));
27
28 if (main_hfs.GetStatus() != Loader::ResultStatus::Success) {
29 status = main_hfs.GetStatus();
30 return;
31 }
32
33 static constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure",
34 "logo"};
35
36 for (XCIPartition partition :
37 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
38 auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]);
39 if (raw != nullptr)
40 partitions[static_cast<size_t>(partition)] = std::make_shared<PartitionFilesystem>(raw);
41 }
42
43 auto result = AddNCAFromPartition(XCIPartition::Secure);
44 if (result != Loader::ResultStatus::Success) {
45 status = result;
46 return;
47 }
48
49 result = AddNCAFromPartition(XCIPartition::Update);
50 if (result != Loader::ResultStatus::Success) {
51 status = result;
52 return;
53 }
54
55 result = AddNCAFromPartition(XCIPartition::Normal);
56 if (result != Loader::ResultStatus::Success) {
57 status = result;
58 return;
59 }
60
61 if (GetFormatVersion() >= 0x2) {
62 result = AddNCAFromPartition(XCIPartition::Logo);
63 if (result != Loader::ResultStatus::Success) {
64 status = result;
65 return;
66 }
67 }
68
69 status = Loader::ResultStatus::Success;
70}
71
72Loader::ResultStatus XCI::GetStatus() const {
73 return status;
74}
75
76VirtualDir XCI::GetPartition(XCIPartition partition) const {
77 return partitions[static_cast<size_t>(partition)];
78}
79
80VirtualDir XCI::GetSecurePartition() const {
81 return GetPartition(XCIPartition::Secure);
82}
83
84VirtualDir XCI::GetNormalPartition() const {
85 return GetPartition(XCIPartition::Normal);
86}
87
88VirtualDir XCI::GetUpdatePartition() const {
89 return GetPartition(XCIPartition::Update);
90}
91
92VirtualDir XCI::GetLogoPartition() const {
93 return GetPartition(XCIPartition::Logo);
94}
95
96std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
97 const auto iter =
98 std::find_if(ncas.begin(), ncas.end(),
99 [type](const std::shared_ptr<NCA>& nca) { return nca->GetType() == type; });
100 return iter == ncas.end() ? nullptr : *iter;
101}
102
103VirtualFile XCI::GetNCAFileByType(NCAContentType type) const {
104 auto nca = GetNCAByType(type);
105 if (nca != nullptr)
106 return nca->GetBaseFile();
107 return nullptr;
108}
109
110std::vector<std::shared_ptr<VfsFile>> XCI::GetFiles() const {
111 return {};
112}
113
114std::vector<std::shared_ptr<VfsDirectory>> XCI::GetSubdirectories() const {
115 return std::vector<std::shared_ptr<VfsDirectory>>();
116}
117
118std::string XCI::GetName() const {
119 return file->GetName();
120}
121
122std::shared_ptr<VfsDirectory> XCI::GetParentDirectory() const {
123 return file->GetContainingDirectory();
124}
125
126bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
127 return false;
128}
129
130Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
131 if (partitions[static_cast<size_t>(part)] == nullptr) {
132 return Loader::ResultStatus::ErrorInvalidFormat;
133 }
134
135 for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
136 if (file->GetExtension() != "nca")
137 continue;
138 auto nca = std::make_shared<NCA>(file);
139 if (nca->GetStatus() == Loader::ResultStatus::Success)
140 ncas.push_back(std::move(nca));
141 }
142
143 return Loader::ResultStatus::Success;
144}
145
146u8 XCI::GetFormatVersion() const {
147 return GetLogoPartition() == nullptr ? 0x1 : 0x2;
148}
149} // namespace FileSys
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
new file mode 100644
index 000000000..e089d737c
--- /dev/null
+++ b/src/core/file_sys/card_image.h
@@ -0,0 +1,96 @@
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 <vector>
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/file_sys/content_archive.h"
12#include "core/file_sys/vfs.h"
13#include "core/loader/loader.h"
14
15namespace FileSys {
16
17enum class GamecardSize : u8 {
18 S_1GB = 0xFA,
19 S_2GB = 0xF8,
20 S_4GB = 0xF0,
21 S_8GB = 0xE0,
22 S_16GB = 0xE1,
23 S_32GB = 0xE2,
24};
25
26struct GamecardInfo {
27 std::array<u8, 0x70> data;
28};
29static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size.");
30
31struct GamecardHeader {
32 std::array<u8, 0x100> signature;
33 u32_le magic;
34 u32_le secure_area_start;
35 u32_le backup_area_start;
36 u8 kek_index;
37 GamecardSize size;
38 u8 header_version;
39 u8 flags;
40 u64_le package_id;
41 u64_le valid_data_end;
42 u128 info_iv;
43 u64_le hfs_offset;
44 u64_le hfs_size;
45 std::array<u8, 0x20> hfs_header_hash;
46 std::array<u8, 0x20> initial_data_hash;
47 u32_le secure_mode_flag;
48 u32_le title_key_flag;
49 u32_le key_flag;
50 u32_le normal_area_end;
51 GamecardInfo info;
52};
53static_assert(sizeof(GamecardHeader) == 0x200, "GamecardHeader has incorrect size.");
54
55enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
56
57class XCI : public ReadOnlyVfsDirectory {
58public:
59 explicit XCI(VirtualFile file);
60
61 Loader::ResultStatus GetStatus() const;
62
63 u8 GetFormatVersion() const;
64
65 VirtualDir GetPartition(XCIPartition partition) const;
66 VirtualDir GetSecurePartition() const;
67 VirtualDir GetNormalPartition() const;
68 VirtualDir GetUpdatePartition() const;
69 VirtualDir GetLogoPartition() const;
70
71 std::shared_ptr<NCA> GetNCAByType(NCAContentType type) const;
72 VirtualFile GetNCAFileByType(NCAContentType type) const;
73
74 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
75
76 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
77
78 std::string GetName() const override;
79
80 std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
81
82protected:
83 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
84
85private:
86 Loader::ResultStatus AddNCAFromPartition(XCIPartition part);
87
88 VirtualFile file;
89 GamecardHeader header{};
90
91 Loader::ResultStatus status;
92
93 std::vector<VirtualDir> partitions;
94 std::vector<std::shared_ptr<NCA>> ncas;
95};
96} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index d6b20c047..3529166ac 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -4,9 +4,12 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <utility> 6#include <utility>
7 7#include <boost/optional.hpp>
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/crypto/aes_util.h"
10#include "core/crypto/ctr_encryption_layer.h"
9#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
12#include "core/file_sys/romfs.h"
10#include "core/file_sys/vfs_offset.h" 13#include "core/file_sys/vfs_offset.h"
11#include "core/loader/loader.h" 14#include "core/loader/loader.h"
12 15
@@ -28,11 +31,19 @@ enum class NCASectionFilesystemType : u8 {
28struct NCASectionHeaderBlock { 31struct NCASectionHeaderBlock {
29 INSERT_PADDING_BYTES(3); 32 INSERT_PADDING_BYTES(3);
30 NCASectionFilesystemType filesystem_type; 33 NCASectionFilesystemType filesystem_type;
31 u8 crypto_type; 34 NCASectionCryptoType crypto_type;
32 INSERT_PADDING_BYTES(3); 35 INSERT_PADDING_BYTES(3);
33}; 36};
34static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); 37static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size.");
35 38
39struct NCASectionRaw {
40 NCASectionHeaderBlock header;
41 std::array<u8, 0x138> block_data;
42 std::array<u8, 0x8> section_ctr;
43 INSERT_PADDING_BYTES(0xB8);
44};
45static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size.");
46
36struct PFS0Superblock { 47struct PFS0Superblock {
37 NCASectionHeaderBlock header_block; 48 NCASectionHeaderBlock header_block;
38 std::array<u8, 0x20> hash; 49 std::array<u8, 0x20> hash;
@@ -42,79 +53,200 @@ struct PFS0Superblock {
42 u64_le hash_table_size; 53 u64_le hash_table_size;
43 u64_le pfs0_header_offset; 54 u64_le pfs0_header_offset;
44 u64_le pfs0_size; 55 u64_le pfs0_size;
45 INSERT_PADDING_BYTES(432); 56 INSERT_PADDING_BYTES(0x1B0);
46}; 57};
47static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size."); 58static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size.");
48 59
49struct IVFCLevel {
50 u64_le offset;
51 u64_le size;
52 u32_le block_size;
53 u32_le reserved;
54};
55static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
56
57struct RomFSSuperblock { 60struct RomFSSuperblock {
58 NCASectionHeaderBlock header_block; 61 NCASectionHeaderBlock header_block;
59 u32_le magic; 62 IVFCHeader ivfc;
60 u32_le magic_number; 63 INSERT_PADDING_BYTES(0x118);
61 INSERT_PADDING_BYTES(8);
62 std::array<IVFCLevel, 6> levels;
63 INSERT_PADDING_BYTES(64);
64}; 64};
65static_assert(sizeof(RomFSSuperblock) == 0xE8, "RomFSSuperblock has incorrect size."); 65static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size.");
66
67union NCASectionHeader {
68 NCASectionRaw raw;
69 PFS0Superblock pfs0;
70 RomFSSuperblock romfs;
71};
72static_assert(sizeof(NCASectionHeader) == 0x200, "NCASectionHeader has incorrect size.");
73
74bool IsValidNCA(const NCAHeader& header) {
75 // TODO(DarkLordZach): Add NCA2/NCA0 support.
76 return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
77}
78
79u8 NCA::GetCryptoRevision() const {
80 u8 master_key_id = header.crypto_type;
81 if (header.crypto_type_2 > master_key_id)
82 master_key_id = header.crypto_type_2;
83 if (master_key_id > 0)
84 --master_key_id;
85 return master_key_id;
86}
87
88boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
89 const auto master_key_id = GetCryptoRevision();
90
91 if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index))
92 return boost::none;
93
94 std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
95 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
96 keys.GetKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index),
97 Core::Crypto::Mode::ECB);
98 cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt);
99
100 Core::Crypto::Key128 out;
101 if (type == NCASectionCryptoType::XTS)
102 std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
103 else if (type == NCASectionCryptoType::CTR)
104 std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin());
105 else
106 LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}",
107 static_cast<u8>(type));
108 u128 out_128{};
109 memcpy(out_128.data(), out.data(), 16);
110 LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
111 master_key_id, header.key_index, out_128[1], out_128[0]);
112
113 return out;
114}
115
116boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const {
117 const auto master_key_id = GetCryptoRevision();
118
119 u128 rights_id{};
120 memcpy(rights_id.data(), header.rights_id.data(), 16);
121 if (rights_id == u128{})
122 return boost::none;
123
124 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
125 if (titlekey == Core::Crypto::Key128{})
126 return boost::none;
127 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
128 keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB);
129 cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt);
130
131 return titlekey;
132}
133
134VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) const {
135 if (!encrypted)
136 return in;
137
138 switch (s_header.raw.header.crypto_type) {
139 case NCASectionCryptoType::NONE:
140 LOG_DEBUG(Crypto, "called with mode=NONE");
141 return in;
142 case NCASectionCryptoType::CTR:
143 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
144 {
145 boost::optional<Core::Crypto::Key128> key = boost::none;
146 if (std::find_if_not(header.rights_id.begin(), header.rights_id.end(),
147 [](char c) { return c == 0; }) == header.rights_id.end()) {
148 key = GetKeyAreaKey(NCASectionCryptoType::CTR);
149 } else {
150 key = GetTitlekey();
151 }
152
153 if (key == boost::none)
154 return nullptr;
155 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
156 std::move(in), key.value(), starting_offset);
157 std::vector<u8> iv(16);
158 for (u8 i = 0; i < 8; ++i)
159 iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
160 out->SetIV(iv);
161 return std::static_pointer_cast<VfsFile>(out);
162 }
163 case NCASectionCryptoType::XTS:
164 // TODO(DarkLordZach): Implement XTSEncryptionLayer.
165 default:
166 LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}",
167 static_cast<u8>(s_header.raw.header.crypto_type));
168 return nullptr;
169 }
170}
66 171
67NCA::NCA(VirtualFile file_) : file(std::move(file_)) { 172NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
68 if (sizeof(NCAHeader) != file->ReadObject(&header)) 173 if (sizeof(NCAHeader) != file->ReadObject(&header))
69 LOG_CRITICAL(Loader, "File reader errored out during header read."); 174 LOG_ERROR(Loader, "File reader errored out during header read.");
175
176 encrypted = false;
70 177
71 if (!IsValidNCA(header)) { 178 if (!IsValidNCA(header)) {
72 status = Loader::ResultStatus::ErrorInvalidFormat; 179 NCAHeader dec_header{};
73 return; 180 Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
181 keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
182 cipher.XTSTranscode(&header, sizeof(NCAHeader), &dec_header, 0, 0x200,
183 Core::Crypto::Op::Decrypt);
184 if (IsValidNCA(dec_header)) {
185 header = dec_header;
186 encrypted = true;
187 } else {
188 if (!keys.HasKey(Core::Crypto::S256KeyType::Header))
189 status = Loader::ResultStatus::ErrorMissingKeys;
190 else
191 status = Loader::ResultStatus::ErrorDecrypting;
192 return;
193 }
74 } 194 }
75 195
76 std::ptrdiff_t number_sections = 196 const std::ptrdiff_t number_sections =
77 std::count_if(std::begin(header.section_tables), std::end(header.section_tables), 197 std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
78 [](NCASectionTableEntry entry) { return entry.media_offset > 0; }); 198 [](NCASectionTableEntry entry) { return entry.media_offset > 0; });
79 199
200 std::vector<NCASectionHeader> sections(number_sections);
201 const auto length_sections = SECTION_HEADER_SIZE * number_sections;
202
203 if (encrypted) {
204 auto raw = file->ReadBytes(length_sections, SECTION_HEADER_OFFSET);
205 Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
206 keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
207 cipher.XTSTranscode(raw.data(), length_sections, sections.data(), 2, SECTION_HEADER_SIZE,
208 Core::Crypto::Op::Decrypt);
209 } else {
210 file->ReadBytes(sections.data(), length_sections, SECTION_HEADER_OFFSET);
211 }
212
80 for (std::ptrdiff_t i = 0; i < number_sections; ++i) { 213 for (std::ptrdiff_t i = 0; i < number_sections; ++i) {
81 // Seek to beginning of this section. 214 auto section = sections[i];
82 NCASectionHeaderBlock block{};
83 if (sizeof(NCASectionHeaderBlock) !=
84 file->ReadObject(&block, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
85 LOG_CRITICAL(Loader, "File reader errored out during header read.");
86
87 if (block.filesystem_type == NCASectionFilesystemType::ROMFS) {
88 RomFSSuperblock sb{};
89 if (sizeof(RomFSSuperblock) !=
90 file->ReadObject(&sb, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE))
91 LOG_CRITICAL(Loader, "File reader errored out during header read.");
92 215
216 if (section.raw.header.filesystem_type == NCASectionFilesystemType::ROMFS) {
93 const size_t romfs_offset = 217 const size_t romfs_offset =
94 header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER + 218 header.section_tables[i].media_offset * MEDIA_OFFSET_MULTIPLIER +
95 sb.levels[IVFC_MAX_LEVEL - 1].offset; 219 section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].offset;
96 const size_t romfs_size = sb.levels[IVFC_MAX_LEVEL - 1].size; 220 const size_t romfs_size = section.romfs.ivfc.levels[IVFC_MAX_LEVEL - 1].size;
97 files.emplace_back(std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset)); 221 auto dec =
98 romfs = files.back(); 222 Decrypt(section, std::make_shared<OffsetVfsFile>(file, romfs_size, romfs_offset),
99 } else if (block.filesystem_type == NCASectionFilesystemType::PFS0) { 223 romfs_offset);
100 PFS0Superblock sb{}; 224 if (dec != nullptr) {
101 // Seek back to beginning of this section. 225 files.push_back(std::move(dec));
102 if (sizeof(PFS0Superblock) != 226 romfs = files.back();
103 file->ReadObject(&sb, SECTION_HEADER_OFFSET + i * SECTION_HEADER_SIZE)) 227 } else {
104 LOG_CRITICAL(Loader, "File reader errored out during header read."); 228 status = Loader::ResultStatus::ErrorMissingKeys;
105 229 return;
230 }
231 } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) {
106 u64 offset = (static_cast<u64>(header.section_tables[i].media_offset) * 232 u64 offset = (static_cast<u64>(header.section_tables[i].media_offset) *
107 MEDIA_OFFSET_MULTIPLIER) + 233 MEDIA_OFFSET_MULTIPLIER) +
108 sb.pfs0_header_offset; 234 section.pfs0.pfs0_header_offset;
109 u64 size = MEDIA_OFFSET_MULTIPLIER * (header.section_tables[i].media_end_offset - 235 u64 size = MEDIA_OFFSET_MULTIPLIER * (header.section_tables[i].media_end_offset -
110 header.section_tables[i].media_offset); 236 header.section_tables[i].media_offset);
111 auto npfs = std::make_shared<PartitionFilesystem>( 237 auto dec =
112 std::make_shared<OffsetVfsFile>(file, size, offset)); 238 Decrypt(section, std::make_shared<OffsetVfsFile>(file, size, offset), offset);
239 if (dec != nullptr) {
240 auto npfs = std::make_shared<PartitionFilesystem>(std::move(dec));
113 241
114 if (npfs->GetStatus() == Loader::ResultStatus::Success) { 242 if (npfs->GetStatus() == Loader::ResultStatus::Success) {
115 dirs.emplace_back(npfs); 243 dirs.push_back(std::move(npfs));
116 if (IsDirectoryExeFS(dirs.back())) 244 if (IsDirectoryExeFS(dirs.back()))
117 exefs = dirs.back(); 245 exefs = dirs.back();
246 }
247 } else {
248 status = Loader::ResultStatus::ErrorMissingKeys;
249 return;
118 } 250 }
119 } 251 }
120 } 252 }
@@ -164,6 +296,10 @@ VirtualDir NCA::GetExeFS() const {
164 return exefs; 296 return exefs;
165} 297}
166 298
299VirtualFile NCA::GetBaseFile() const {
300 return file;
301}
302
167bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { 303bool NCA::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
168 return false; 304 return false;
169} 305}
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 0b8b9db61..a8879d9a8 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -8,14 +8,18 @@
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include <vector> 10#include <vector>
11 11#include <boost/optional.hpp>
12#include "common/common_funcs.h" 12#include "common/common_funcs.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/swap.h" 14#include "common/swap.h"
15#include "core/crypto/key_manager.h"
15#include "core/file_sys/partition_filesystem.h" 16#include "core/file_sys/partition_filesystem.h"
17#include "core/loader/loader.h"
16 18
17namespace FileSys { 19namespace FileSys {
18 20
21union NCASectionHeader;
22
19enum class NCAContentType : u8 { 23enum class NCAContentType : u8 {
20 Program = 0, 24 Program = 0,
21 Meta = 1, 25 Meta = 1,
@@ -24,6 +28,13 @@ enum class NCAContentType : u8 {
24 Data = 4, 28 Data = 4,
25}; 29};
26 30
31enum class NCASectionCryptoType : u8 {
32 NONE = 1,
33 XTS = 2,
34 CTR = 3,
35 BKTR = 4,
36};
37
27struct NCASectionTableEntry { 38struct NCASectionTableEntry {
28 u32_le media_offset; 39 u32_le media_offset;
29 u32_le media_end_offset; 40 u32_le media_end_offset;
@@ -48,7 +59,7 @@ struct NCAHeader {
48 std::array<u8, 0x10> rights_id; 59 std::array<u8, 0x10> rights_id;
49 std::array<NCASectionTableEntry, 0x4> section_tables; 60 std::array<NCASectionTableEntry, 0x4> section_tables;
50 std::array<std::array<u8, 0x20>, 0x4> hash_tables; 61 std::array<std::array<u8, 0x20>, 0x4> hash_tables;
51 std::array<std::array<u8, 0x10>, 0x4> key_area; 62 std::array<u8, 0x40> key_area;
52 INSERT_PADDING_BYTES(0xC0); 63 INSERT_PADDING_BYTES(0xC0);
53}; 64};
54static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size."); 65static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size.");
@@ -58,10 +69,7 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
58 return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr; 69 return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr;
59} 70}
60 71
61inline bool IsValidNCA(const NCAHeader& header) { 72bool IsValidNCA(const NCAHeader& header);
62 return header.magic == Common::MakeMagic('N', 'C', 'A', '2') ||
63 header.magic == Common::MakeMagic('N', 'C', 'A', '3');
64}
65 73
66// An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) conatiner. 74// An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) conatiner.
67// After construction, use GetStatus to determine if the file is valid and ready to be used. 75// After construction, use GetStatus to determine if the file is valid and ready to be used.
@@ -81,10 +89,17 @@ public:
81 VirtualFile GetRomFS() const; 89 VirtualFile GetRomFS() const;
82 VirtualDir GetExeFS() const; 90 VirtualDir GetExeFS() const;
83 91
92 VirtualFile GetBaseFile() const;
93
84protected: 94protected:
85 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; 95 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
86 96
87private: 97private:
98 u8 GetCryptoRevision() const;
99 boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
100 boost::optional<Core::Crypto::Key128> GetTitlekey() const;
101 VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset) const;
102
88 std::vector<VirtualDir> dirs; 103 std::vector<VirtualDir> dirs;
89 std::vector<VirtualFile> files; 104 std::vector<VirtualFile> files;
90 105
@@ -95,6 +110,10 @@ private:
95 NCAHeader header{}; 110 NCAHeader header{};
96 111
97 Loader::ResultStatus status{}; 112 Loader::ResultStatus status{};
113
114 bool encrypted;
115
116 Core::Crypto::KeyManager keys;
98}; 117};
99 118
100} // namespace FileSys 119} // namespace FileSys
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 521e21078..47e032b19 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -97,9 +97,8 @@ void PartitionFilesystem::PrintDebugInfo() const {
97 LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic); 97 LOG_DEBUG(Service_FS, "Magic: {:.4}", pfs_header.magic);
98 LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries); 98 LOG_DEBUG(Service_FS, "Files: {}", pfs_header.num_entries);
99 for (u32 i = 0; i < pfs_header.num_entries; i++) { 99 for (u32 i = 0; i < pfs_header.num_entries; i++) {
100 LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes, at 0x{:X})", i, 100 LOG_DEBUG(Service_FS, " > File {}: {} (0x{:X} bytes)", i,
101 pfs_files[i]->GetName(), pfs_files[i]->GetSize(), 101 pfs_files[i]->GetName(), pfs_files[i]->GetSize());
102 dynamic_cast<OffsetVfsFile*>(pfs_files[i].get())->GetOffset());
103 } 102 }
104} 103}
105 104
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
new file mode 100644
index 000000000..ff3ddb29c
--- /dev/null
+++ b/src/core/file_sys/romfs.cpp
@@ -0,0 +1,124 @@
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_types.h"
6#include "common/swap.h"
7#include "core/file_sys/romfs.h"
8#include "core/file_sys/vfs.h"
9#include "core/file_sys/vfs_offset.h"
10#include "core/file_sys/vfs_vector.h"
11
12namespace FileSys {
13
14constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF;
15
16struct TableLocation {
17 u64_le offset;
18 u64_le size;
19};
20static_assert(sizeof(TableLocation) == 0x10, "TableLocation has incorrect size.");
21
22struct RomFSHeader {
23 u64_le header_size;
24 TableLocation directory_hash;
25 TableLocation directory_meta;
26 TableLocation file_hash;
27 TableLocation file_meta;
28 u64_le data_offset;
29};
30static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
31
32struct DirectoryEntry {
33 u32_le sibling;
34 u32_le child_dir;
35 u32_le child_file;
36 u32_le hash;
37 u32_le name_length;
38};
39static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size.");
40
41struct FileEntry {
42 u32_le parent;
43 u32_le sibling;
44 u64_le offset;
45 u64_le size;
46 u32_le hash;
47 u32_le name_length;
48};
49static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
50
51template <typename Entry>
52static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) {
53 Entry entry{};
54 if (file->ReadObject(&entry, offset) != sizeof(Entry))
55 return {};
56 std::string string(entry.name_length, '\0');
57 if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size())
58 return {};
59 return {entry, string};
60}
61
62void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset,
63 std::shared_ptr<VectorVfsDirectory> parent) {
64 while (true) {
65 auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset);
66
67 parent->AddFile(std::make_shared<OffsetVfsFile>(
68 file, entry.first.size, entry.first.offset + data_offset, entry.second, parent));
69
70 if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
71 break;
72
73 this_file_offset = entry.first.sibling;
74 }
75}
76
77void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset,
78 u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) {
79 while (true) {
80 auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset);
81 auto current = std::make_shared<VectorVfsDirectory>(
82 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parent, entry.second);
83
84 if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
85 ProcessFile(file, file_offset, data_offset, entry.first.child_file, current);
86 }
87
88 if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
89 ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir,
90 current);
91 }
92
93 parent->AddDirectory(current);
94 if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
95 break;
96 this_dir_offset = entry.first.sibling;
97 }
98}
99
100VirtualDir ExtractRomFS(VirtualFile file) {
101 RomFSHeader header{};
102 if (file->ReadObject(&header) != sizeof(RomFSHeader))
103 return nullptr;
104
105 if (header.header_size != sizeof(RomFSHeader))
106 return nullptr;
107
108 const u64 file_offset = header.file_meta.offset;
109 const u64 dir_offset = header.directory_meta.offset + 4;
110
111 const auto root =
112 std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{},
113 file->GetContainingDirectory(), file->GetName());
114
115 ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root);
116
117 VirtualDir out = std::move(root);
118
119 while (out->GetSubdirectory("") != nullptr)
120 out = out->GetSubdirectory("");
121
122 return out;
123}
124} // namespace FileSys
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
new file mode 100644
index 000000000..03a876d22
--- /dev/null
+++ b/src/core/file_sys/romfs.h
@@ -0,0 +1,35 @@
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 "common/common_funcs.h"
9#include "common/swap.h"
10#include "core/file_sys/vfs.h"
11
12namespace FileSys {
13
14struct IVFCLevel {
15 u64_le offset;
16 u64_le size;
17 u32_le block_size;
18 u32_le reserved;
19};
20static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size.");
21
22struct IVFCHeader {
23 u32_le magic;
24 u32_le magic_number;
25 INSERT_PADDING_BYTES(8);
26 std::array<IVFCLevel, 6> levels;
27 INSERT_PADDING_BYTES(64);
28};
29static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size.");
30
31// Converts a RomFS binary blob to VFS Filesystem
32// Returns nullptr on failure
33VirtualDir ExtractRomFS(VirtualFile file);
34
35} // namespace FileSys
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index b99a4fd5b..dae1c16ef 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -46,6 +46,13 @@ size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {
46 return Write(data.data(), data.size(), offset); 46 return Write(data.data(), data.size(), offset);
47} 47}
48 48
49std::string VfsFile::GetFullPath() const {
50 if (GetContainingDirectory() == nullptr)
51 return "/" + GetName();
52
53 return GetContainingDirectory()->GetFullPath() + "/" + GetName();
54}
55
49std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const { 56std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
50 auto vec = FileUtil::SplitPathComponents(path); 57 auto vec = FileUtil::SplitPathComponents(path);
51 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 58 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
@@ -243,6 +250,13 @@ bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
243 return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize(); 250 return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
244} 251}
245 252
253std::string VfsDirectory::GetFullPath() const {
254 if (IsRoot())
255 return GetName();
256
257 return GetParentDirectory()->GetFullPath() + "/" + GetName();
258}
259
246bool ReadOnlyVfsDirectory::IsWritable() const { 260bool ReadOnlyVfsDirectory::IsWritable() const {
247 return false; 261 return false;
248} 262}
@@ -270,4 +284,33 @@ bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
270bool ReadOnlyVfsDirectory::Rename(std::string_view name) { 284bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
271 return false; 285 return false;
272} 286}
287
288bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size) {
289 if (file1->GetSize() != file2->GetSize())
290 return false;
291
292 std::vector<u8> f1_v(block_size);
293 std::vector<u8> f2_v(block_size);
294 for (size_t i = 0; i < file1->GetSize(); i += block_size) {
295 auto f1_vs = file1->Read(f1_v.data(), block_size, i);
296 auto f2_vs = file2->Read(f2_v.data(), block_size, i);
297
298 if (f1_vs != f2_vs)
299 return false;
300 auto iters = std::mismatch(f1_v.begin(), f1_v.end(), f2_v.begin(), f2_v.end());
301 if (iters.first != f1_v.end() && iters.second != f2_v.end())
302 return false;
303 }
304
305 return true;
306}
307
308bool VfsRawCopy(VirtualFile src, VirtualFile dest) {
309 if (src == nullptr || dest == nullptr)
310 return false;
311 if (!dest->Resize(src->GetSize()))
312 return false;
313 std::vector<u8> data = src->ReadAllBytes();
314 return dest->WriteBytes(data, 0) == data.size();
315}
273} // namespace FileSys 316} // namespace FileSys
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 4a13b8378..fab9e2b45 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -113,6 +113,9 @@ struct VfsFile : NonCopyable {
113 113
114 // Renames the file to name. Returns whether or not the operation was successsful. 114 // Renames the file to name. Returns whether or not the operation was successsful.
115 virtual bool Rename(std::string_view name) = 0; 115 virtual bool Rename(std::string_view name) = 0;
116
117 // Returns the full path of this file as a string, recursively
118 virtual std::string GetFullPath() const;
116}; 119};
117 120
118// A class representing a directory in an abstract filesystem. 121// A class representing a directory in an abstract filesystem.
@@ -213,6 +216,17 @@ struct VfsDirectory : NonCopyable {
213 return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p)); 216 return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p));
214 } 217 }
215 218
219 bool InterpretAsDirectory(const std::function<VirtualDir(VirtualFile)>& function,
220 const std::string& file) {
221 auto file_p = GetFile(file);
222 if (file_p == nullptr)
223 return false;
224 return ReplaceFileWithSubdirectory(file_p, function(file_p));
225 }
226
227 // Returns the full path of this directory as a string, recursively
228 virtual std::string GetFullPath() const;
229
216protected: 230protected:
217 // Backend for InterpretAsDirectory. 231 // Backend for InterpretAsDirectory.
218 // Removes all references to file and adds a reference to dir in the directory's implementation. 232 // Removes all references to file and adds a reference to dir in the directory's implementation.
@@ -230,4 +244,13 @@ struct ReadOnlyVfsDirectory : public VfsDirectory {
230 bool DeleteFile(std::string_view name) override; 244 bool DeleteFile(std::string_view name) override;
231 bool Rename(std::string_view name) override; 245 bool Rename(std::string_view name) override;
232}; 246};
247
248// Compare the two files, byte-for-byte, in increments specificed by block_size
249bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x200);
250
251// A method that copies the raw data between two different implementations of VirtualFile. If you
252// are using the same implementation, it is probably better to use the Copy method in the parent
253// directory of src/dest.
254bool VfsRawCopy(VirtualFile src, VirtualFile dest);
255
233} // namespace FileSys 256} // namespace FileSys
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index a40331cef..847cde2f5 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -10,8 +10,9 @@
10namespace FileSys { 10namespace FileSys {
11 11
12OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_, 12OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, size_t size_, size_t offset_,
13 std::string name_) 13 std::string name_, VirtualDir parent_)
14 : file(std::move(file_)), offset(offset_), size(size_), name(std::move(name_)) {} 14 : file(file_), offset(offset_), size(size_), name(std::move(name_)),
15 parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
15 16
16std::string OffsetVfsFile::GetName() const { 17std::string OffsetVfsFile::GetName() const {
17 return name.empty() ? file->GetName() : name; 18 return name.empty() ? file->GetName() : name;
@@ -35,7 +36,7 @@ bool OffsetVfsFile::Resize(size_t new_size) {
35} 36}
36 37
37std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const { 38std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
38 return file->GetContainingDirectory(); 39 return parent;
39} 40}
40 41
41bool OffsetVfsFile::IsWritable() const { 42bool OffsetVfsFile::IsWritable() const {
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 4f471e3ba..235970dc5 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -17,7 +17,7 @@ namespace FileSys {
17// the size of this wrapper. 17// the size of this wrapper.
18struct OffsetVfsFile : public VfsFile { 18struct OffsetVfsFile : public VfsFile {
19 OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0, 19 OffsetVfsFile(std::shared_ptr<VfsFile> file, size_t size, size_t offset = 0,
20 std::string new_name = ""); 20 std::string new_name = "", VirtualDir new_parent = nullptr);
21 21
22 std::string GetName() const override; 22 std::string GetName() const override;
23 size_t GetSize() const override; 23 size_t GetSize() const override;
@@ -44,6 +44,7 @@ private:
44 size_t offset; 44 size_t offset;
45 size_t size; 45 size_t size;
46 std::string name; 46 std::string name;
47 VirtualDir parent;
47}; 48};
48 49
49} // namespace FileSys 50} // namespace FileSys
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 9ce2e1efa..82d54da4a 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -195,6 +195,12 @@ bool RealVfsDirectory::Rename(std::string_view name) {
195 return FileUtil::Rename(path, new_name); 195 return FileUtil::Rename(path, new_name);
196} 196}
197 197
198std::string RealVfsDirectory::GetFullPath() const {
199 auto out = path;
200 std::replace(out.begin(), out.end(), '\\', '/');
201 return out;
202}
203
198bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { 204bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
199 const auto iter = std::find(files.begin(), files.end(), file); 205 const auto iter = std::find(files.begin(), files.end(), file);
200 if (iter == files.end()) 206 if (iter == files.end())
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 2151211c9..243d58576 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -41,7 +41,7 @@ private:
41 41
42// An implementation of VfsDirectory that represents a directory on the user's computer. 42// An implementation of VfsDirectory that represents a directory on the user's computer.
43struct RealVfsDirectory : public VfsDirectory { 43struct RealVfsDirectory : public VfsDirectory {
44 RealVfsDirectory(const std::string& path, Mode perms); 44 RealVfsDirectory(const std::string& path, Mode perms = Mode::Read);
45 45
46 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 46 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
47 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 47 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
@@ -54,6 +54,7 @@ struct RealVfsDirectory : public VfsDirectory {
54 bool DeleteSubdirectory(std::string_view name) override; 54 bool DeleteSubdirectory(std::string_view name) override;
55 bool DeleteFile(std::string_view name) override; 55 bool DeleteFile(std::string_view name) override;
56 bool Rename(std::string_view name) override; 56 bool Rename(std::string_view name) override;
57 std::string GetFullPath() const override;
57 58
58protected: 59protected:
59 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; 60 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
new file mode 100644
index 000000000..fda603960
--- /dev/null
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -0,0 +1,86 @@
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 <algorithm>
6#include <utility>
7#include "core/file_sys/vfs_vector.h"
8
9namespace FileSys {
10VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
11 std::vector<VirtualDir> dirs_, VirtualDir parent_,
12 std::string name_)
13 : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
14 name(std::move(name_)) {}
15
16std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
17 return files;
18}
19
20std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const {
21 return dirs;
22}
23
24bool VectorVfsDirectory::IsWritable() const {
25 return false;
26}
27
28bool VectorVfsDirectory::IsReadable() const {
29 return true;
30}
31
32std::string VectorVfsDirectory::GetName() const {
33 return name;
34}
35
36std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const {
37 return parent;
38}
39
40template <typename T>
41static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view name) {
42 const auto iter =
43 std::find_if(vec.begin(), vec.end(), [name](const T& e) { return e->GetName() == name; });
44 if (iter == vec.end())
45 return false;
46
47 vec.erase(iter);
48 return true;
49}
50
51bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) {
52 return FindAndRemoveVectorElement(dirs, name);
53}
54
55bool VectorVfsDirectory::DeleteFile(std::string_view name) {
56 return FindAndRemoveVectorElement(files, name);
57}
58
59bool VectorVfsDirectory::Rename(std::string_view name_) {
60 name = name_;
61 return true;
62}
63
64std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
65 return nullptr;
66}
67
68std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) {
69 return nullptr;
70}
71
72void VectorVfsDirectory::AddFile(VirtualFile file) {
73 files.push_back(std::move(file));
74}
75
76void VectorVfsDirectory::AddDirectory(VirtualDir dir) {
77 dirs.push_back(std::move(dir));
78}
79
80bool VectorVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
81 if (!DeleteFile(file->GetName()))
82 return false;
83 dirs.emplace_back(std::move(dir));
84 return true;
85}
86} // namespace FileSys
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
new file mode 100644
index 000000000..ba469647b
--- /dev/null
+++ b/src/core/file_sys/vfs_vector.h
@@ -0,0 +1,44 @@
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/file_sys/vfs.h"
8
9namespace FileSys {
10
11// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
12// Vector data is supplied upon construction.
13struct VectorVfsDirectory : public VfsDirectory {
14 explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
15 std::vector<VirtualDir> dirs = {}, VirtualDir parent = nullptr,
16 std::string name = "");
17
18 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
19 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
20 bool IsWritable() const override;
21 bool IsReadable() const override;
22 std::string GetName() const override;
23 std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
24 bool DeleteSubdirectory(std::string_view name) override;
25 bool DeleteFile(std::string_view name) override;
26 bool Rename(std::string_view name) override;
27 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
28 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
29
30 virtual void AddFile(VirtualFile file);
31 virtual void AddDirectory(VirtualDir dir);
32
33protected:
34 bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
35
36private:
37 std::vector<VirtualFile> files;
38 std::vector<VirtualDir> dirs;
39
40 VirtualDir parent;
41 std::string name;
42};
43
44} // namespace FileSys
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 5ca573652..332e5c3d0 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -37,45 +37,46 @@
37#include "core/core.h" 37#include "core/core.h"
38#include "core/core_cpu.h" 38#include "core/core_cpu.h"
39#include "core/gdbstub/gdbstub.h" 39#include "core/gdbstub/gdbstub.h"
40#include "core/hle/kernel/kernel.h"
41#include "core/hle/kernel/scheduler.h" 40#include "core/hle/kernel/scheduler.h"
42#include "core/loader/loader.h" 41#include "core/loader/loader.h"
43#include "core/memory.h" 42#include "core/memory.h"
44 43
45const int GDB_BUFFER_SIZE = 10000; 44namespace GDBStub {
45namespace {
46constexpr int GDB_BUFFER_SIZE = 10000;
46 47
47const char GDB_STUB_START = '$'; 48constexpr char GDB_STUB_START = '$';
48const char GDB_STUB_END = '#'; 49constexpr char GDB_STUB_END = '#';
49const char GDB_STUB_ACK = '+'; 50constexpr char GDB_STUB_ACK = '+';
50const char GDB_STUB_NACK = '-'; 51constexpr char GDB_STUB_NACK = '-';
51 52
52#ifndef SIGTRAP 53#ifndef SIGTRAP
53const u32 SIGTRAP = 5; 54constexpr u32 SIGTRAP = 5;
54#endif 55#endif
55 56
56#ifndef SIGTERM 57#ifndef SIGTERM
57const u32 SIGTERM = 15; 58constexpr u32 SIGTERM = 15;
58#endif 59#endif
59 60
60#ifndef MSG_WAITALL 61#ifndef MSG_WAITALL
61const u32 MSG_WAITALL = 8; 62constexpr u32 MSG_WAITALL = 8;
62#endif 63#endif
63 64
64const u32 LR_REGISTER = 30; 65constexpr u32 LR_REGISTER = 30;
65const u32 SP_REGISTER = 31; 66constexpr u32 SP_REGISTER = 31;
66const u32 PC_REGISTER = 32; 67constexpr u32 PC_REGISTER = 32;
67const u32 CPSR_REGISTER = 33; 68constexpr u32 CPSR_REGISTER = 33;
68const u32 UC_ARM64_REG_Q0 = 34; 69constexpr u32 UC_ARM64_REG_Q0 = 34;
69const u32 FPSCR_REGISTER = 66; 70constexpr u32 FPSCR_REGISTER = 66;
70 71
71// TODO/WiP - Used while working on support for FPU 72// TODO/WiP - Used while working on support for FPU
72const u32 TODO_DUMMY_REG_997 = 997; 73constexpr u32 TODO_DUMMY_REG_997 = 997;
73const u32 TODO_DUMMY_REG_998 = 998; 74constexpr u32 TODO_DUMMY_REG_998 = 998;
74 75
75// For sample XML files see the GDB source /gdb/features 76// For sample XML files see the GDB source /gdb/features
76// GDB also wants the l character at the start 77// GDB also wants the l character at the start
77// This XML defines what the registers are for this specific ARM device 78// This XML defines what the registers are for this specific ARM device
78static const char* target_xml = 79constexpr char target_xml[] =
79 R"(l<?xml version="1.0"?> 80 R"(l<?xml version="1.0"?>
80<!DOCTYPE target SYSTEM "gdb-target.dtd"> 81<!DOCTYPE target SYSTEM "gdb-target.dtd">
81<target version="1.0"> 82<target version="1.0">
@@ -141,30 +142,28 @@ static const char* target_xml =
141</target> 142</target>
142)"; 143)";
143 144
144namespace GDBStub { 145int gdbserver_socket = -1;
145
146static int gdbserver_socket = -1;
147 146
148static u8 command_buffer[GDB_BUFFER_SIZE]; 147u8 command_buffer[GDB_BUFFER_SIZE];
149static u32 command_length; 148u32 command_length;
150 149
151static u32 latest_signal = 0; 150u32 latest_signal = 0;
152static bool memory_break = false; 151bool memory_break = false;
153 152
154static Kernel::Thread* current_thread = nullptr; 153Kernel::Thread* current_thread = nullptr;
155static u32 current_core = 0; 154u32 current_core = 0;
156 155
157// Binding to a port within the reserved ports range (0-1023) requires root permissions, 156// Binding to a port within the reserved ports range (0-1023) requires root permissions,
158// so default to a port outside of that range. 157// so default to a port outside of that range.
159static u16 gdbstub_port = 24689; 158u16 gdbstub_port = 24689;
160 159
161static bool halt_loop = true; 160bool halt_loop = true;
162static bool step_loop = false; 161bool step_loop = false;
163static bool send_trap = false; 162bool send_trap = false;
164 163
165// If set to false, the server will never be started and no 164// If set to false, the server will never be started and no
166// gdbstub-related functions will be executed. 165// gdbstub-related functions will be executed.
167static std::atomic<bool> server_enabled(false); 166std::atomic<bool> server_enabled(false);
168 167
169#ifdef _WIN32 168#ifdef _WIN32
170WSADATA InitData; 169WSADATA InitData;
@@ -172,23 +171,26 @@ WSADATA InitData;
172 171
173struct Breakpoint { 172struct Breakpoint {
174 bool active; 173 bool active;
175 PAddr addr; 174 VAddr addr;
176 u64 len; 175 u64 len;
176 std::array<u8, 4> inst;
177}; 177};
178 178
179static std::map<u64, Breakpoint> breakpoints_execute; 179using BreakpointMap = std::map<VAddr, Breakpoint>;
180static std::map<u64, Breakpoint> breakpoints_read; 180BreakpointMap breakpoints_execute;
181static std::map<u64, Breakpoint> breakpoints_write; 181BreakpointMap breakpoints_read;
182BreakpointMap breakpoints_write;
182 183
183struct Module { 184struct Module {
184 std::string name; 185 std::string name;
185 PAddr beg; 186 VAddr beg;
186 PAddr end; 187 VAddr end;
187}; 188};
188 189
189static std::vector<Module> modules; 190std::vector<Module> modules;
191} // Anonymous namespace
190 192
191void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { 193void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
192 Module module; 194 Module module;
193 if (add_elf_ext) { 195 if (add_elf_ext) {
194 Common::SplitPath(name, nullptr, &module.name, nullptr); 196 Common::SplitPath(name, nullptr, &module.name, nullptr);
@@ -419,11 +421,11 @@ static u8 CalculateChecksum(const u8* buffer, size_t length) {
419} 421}
420 422
421/** 423/**
422 * Get the list of breakpoints for a given breakpoint type. 424 * Get the map of breakpoints for a given breakpoint type.
423 * 425 *
424 * @param type Type of breakpoint list. 426 * @param type Type of breakpoint map.
425 */ 427 */
426static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) { 428static BreakpointMap& GetBreakpointMap(BreakpointType type) {
427 switch (type) { 429 switch (type) {
428 case BreakpointType::Execute: 430 case BreakpointType::Execute:
429 return breakpoints_execute; 431 return breakpoints_execute;
@@ -442,20 +444,24 @@ static std::map<u64, Breakpoint>& GetBreakpointList(BreakpointType type) {
442 * @param type Type of breakpoint. 444 * @param type Type of breakpoint.
443 * @param addr Address of breakpoint. 445 * @param addr Address of breakpoint.
444 */ 446 */
445static void RemoveBreakpoint(BreakpointType type, PAddr addr) { 447static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
446 std::map<u64, Breakpoint>& p = GetBreakpointList(type); 448 BreakpointMap& p = GetBreakpointMap(type);
447 449
448 auto bp = p.find(static_cast<u64>(addr)); 450 const auto bp = p.find(addr);
449 if (bp != p.end()) { 451 if (bp == p.end()) {
450 LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", 452 return;
451 bp->second.len, bp->second.addr, static_cast<int>(type));
452 p.erase(static_cast<u64>(addr));
453 } 453 }
454
455 LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
456 bp->second.len, bp->second.addr, static_cast<int>(type));
457 Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
458 Core::System::GetInstance().InvalidateCpuInstructionCaches();
459 p.erase(addr);
454} 460}
455 461
456BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) { 462BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) {
457 std::map<u64, Breakpoint>& p = GetBreakpointList(type); 463 const BreakpointMap& p = GetBreakpointMap(type);
458 auto next_breakpoint = p.lower_bound(static_cast<u64>(addr)); 464 const auto next_breakpoint = p.lower_bound(addr);
459 BreakpointAddress breakpoint; 465 BreakpointAddress breakpoint;
460 466
461 if (next_breakpoint != p.end()) { 467 if (next_breakpoint != p.end()) {
@@ -469,36 +475,38 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type)
469 return breakpoint; 475 return breakpoint;
470} 476}
471 477
472bool CheckBreakpoint(PAddr addr, BreakpointType type) { 478bool CheckBreakpoint(VAddr addr, BreakpointType type) {
473 if (!IsConnected()) { 479 if (!IsConnected()) {
474 return false; 480 return false;
475 } 481 }
476 482
477 std::map<u64, Breakpoint>& p = GetBreakpointList(type); 483 const BreakpointMap& p = GetBreakpointMap(type);
484 const auto bp = p.find(addr);
478 485
479 auto bp = p.find(static_cast<u64>(addr)); 486 if (bp == p.end()) {
480 if (bp != p.end()) { 487 return false;
481 u64 len = bp->second.len; 488 }
482 489
483 // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints 490 u64 len = bp->second.len;
484 // no matter if it's a 4-byte or 2-byte instruction. When you execute a
485 // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on
486 // two instructions instead of the single instruction you placed the breakpoint
487 // on. So, as a way to make sure that execution breakpoints are only breaking
488 // on the instruction that was specified, set the length of an execution
489 // breakpoint to 1. This should be fine since the CPU should never begin executing
490 // an instruction anywhere except the beginning of the instruction.
491 if (type == BreakpointType::Execute) {
492 len = 1;
493 }
494 491
495 if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { 492 // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
496 LOG_DEBUG(Debug_GDBStub, 493 // no matter if it's a 4-byte or 2-byte instruction. When you execute a
497 "Found breakpoint type {} @ {:016X}, range: {:016X}" 494 // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on
498 " - {:016X} ({:X} bytes)", 495 // two instructions instead of the single instruction you placed the breakpoint
499 static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len); 496 // on. So, as a way to make sure that execution breakpoints are only breaking
500 return true; 497 // on the instruction that was specified, set the length of an execution
501 } 498 // breakpoint to 1. This should be fine since the CPU should never begin executing
499 // an instruction anywhere except the beginning of the instruction.
500 if (type == BreakpointType::Execute) {
501 len = 1;
502 }
503
504 if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
505 LOG_DEBUG(Debug_GDBStub,
506 "Found breakpoint type {} @ {:016X}, range: {:016X}"
507 " - {:016X} ({:X} bytes)",
508 static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
509 return true;
502 } 510 }
503 511
504 return false; 512 return false;
@@ -932,6 +940,7 @@ static void WriteMemory() {
932 940
933 GdbHexToMem(data.data(), len_pos + 1, len); 941 GdbHexToMem(data.data(), len_pos + 1, len);
934 Memory::WriteBlock(addr, data.data(), len); 942 Memory::WriteBlock(addr, data.data(), len);
943 Core::System::GetInstance().InvalidateCpuInstructionCaches();
935 SendReply("OK"); 944 SendReply("OK");
936} 945}
937 946
@@ -951,6 +960,7 @@ static void Step() {
951 step_loop = true; 960 step_loop = true;
952 halt_loop = true; 961 halt_loop = true;
953 send_trap = true; 962 send_trap = true;
963 Core::System::GetInstance().InvalidateCpuInstructionCaches();
954} 964}
955 965
956/// Tell the CPU if we hit a memory breakpoint. 966/// Tell the CPU if we hit a memory breakpoint.
@@ -967,6 +977,7 @@ static void Continue() {
967 memory_break = false; 977 memory_break = false;
968 step_loop = false; 978 step_loop = false;
969 halt_loop = false; 979 halt_loop = false;
980 Core::System::GetInstance().InvalidateCpuInstructionCaches();
970} 981}
971 982
972/** 983/**
@@ -976,13 +987,17 @@ static void Continue() {
976 * @param addr Address of breakpoint. 987 * @param addr Address of breakpoint.
977 * @param len Length of breakpoint. 988 * @param len Length of breakpoint.
978 */ 989 */
979static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { 990static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
980 std::map<u64, Breakpoint>& p = GetBreakpointList(type); 991 BreakpointMap& p = GetBreakpointMap(type);
981 992
982 Breakpoint breakpoint; 993 Breakpoint breakpoint;
983 breakpoint.active = true; 994 breakpoint.active = true;
984 breakpoint.addr = addr; 995 breakpoint.addr = addr;
985 breakpoint.len = len; 996 breakpoint.len = len;
997 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
998 static constexpr std::array<u8, 4> btrap{{0xd4, 0x20, 0x7d, 0x0}};
999 Memory::WriteBlock(addr, btrap.data(), btrap.size());
1000 Core::System::GetInstance().InvalidateCpuInstructionCaches();
986 p.insert({addr, breakpoint}); 1001 p.insert({addr, breakpoint});
987 1002
988 LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", 1003 LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
@@ -1016,7 +1031,7 @@ static void AddBreakpoint() {
1016 1031
1017 auto start_offset = command_buffer + 3; 1032 auto start_offset = command_buffer + 3;
1018 auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); 1033 auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
1019 PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); 1034 VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
1020 1035
1021 start_offset = addr_pos + 1; 1036 start_offset = addr_pos + 1;
1022 u64 len = 1037 u64 len =
@@ -1065,7 +1080,7 @@ static void RemoveBreakpoint() {
1065 1080
1066 auto start_offset = command_buffer + 3; 1081 auto start_offset = command_buffer + 3;
1067 auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); 1082 auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
1068 PAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); 1083 VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
1069 1084
1070 if (type == BreakpointType::Access) { 1085 if (type == BreakpointType::Access) {
1071 // Access is made up of Read and Write types, so add both breakpoints 1086 // Access is made up of Read and Write types, so add both breakpoints
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index a6b50c26c..5a36524b2 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -22,7 +22,7 @@ enum class BreakpointType {
22}; 22};
23 23
24struct BreakpointAddress { 24struct BreakpointAddress {
25 PAddr address; 25 VAddr address;
26 BreakpointType type; 26 BreakpointType type;
27}; 27};
28 28
@@ -53,7 +53,7 @@ bool IsServerEnabled();
53bool IsConnected(); 53bool IsConnected();
54 54
55/// Register module. 55/// Register module.
56void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true); 56void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext = true);
57 57
58/** 58/**
59 * Signal to the gdbstub server that it should halt CPU execution. 59 * Signal to the gdbstub server that it should halt CPU execution.
@@ -74,7 +74,7 @@ void HandlePacket();
74 * @param addr Address to search from. 74 * @param addr Address to search from.
75 * @param type Type of breakpoint. 75 * @param type Type of breakpoint.
76 */ 76 */
77BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointType type); 77BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, GDBStub::BreakpointType type);
78 78
79/** 79/**
80 * Check if a breakpoint of the specified type exists at the given address. 80 * Check if a breakpoint of the specified type exists at the given address.
@@ -82,7 +82,7 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy
82 * @param addr Address of breakpoint. 82 * @param addr Address of breakpoint.
83 * @param type Type of breakpoint. 83 * @param type Type of breakpoint.
84 */ 84 */
85bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); 85bool CheckBreakpoint(VAddr addr, GDBStub::BreakpointType type);
86 86
87/// If set to true, the CPU will halt at the beginning of the next CPU loop. 87/// If set to true, the CPU will halt at the beginning of the next CPU loop.
88bool GetCpuHaltFlag(); 88bool GetCpuHaltFlag();
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 7fb0da408..d3a734831 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -5,15 +5,18 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstring>
9#include <memory>
8#include <tuple> 10#include <tuple>
9#include <type_traits> 11#include <type_traits>
10#include <utility> 12#include <utility>
13#include "common/assert.h"
14#include "common/common_types.h"
11#include "core/hle/ipc.h" 15#include "core/hle/ipc.h"
12#include "core/hle/kernel/client_port.h" 16#include "core/hle/kernel/client_port.h"
13#include "core/hle/kernel/client_session.h" 17#include "core/hle/kernel/client_session.h"
14#include "core/hle/kernel/handle_table.h"
15#include "core/hle/kernel/hle_ipc.h" 18#include "core/hle/kernel/hle_ipc.h"
16#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/object.h"
17#include "core/hle/kernel/server_port.h" 20#include "core/hle/kernel/server_port.h"
18 21
19namespace IPC { 22namespace IPC {
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 233fdab25..03a954a9f 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <vector>
7
5#include "common/assert.h" 8#include "common/assert.h"
6#include "common/common_funcs.h"
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "core/core.h" 10#include "core/core.h"
9#include "core/hle/kernel/errors.h" 11#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/object.h"
11#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
12#include "core/hle/kernel/thread.h" 14#include "core/hle/kernel/thread.h"
13#include "core/hle/lock.h" 15#include "core/hle/result.h"
14#include "core/memory.h" 16#include "core/memory.h"
15 17
16namespace Kernel { 18namespace Kernel {
@@ -30,9 +32,8 @@ static ResultCode WaitForAddress(VAddr address, s64 timeout) {
30} 32}
31 33
32// Gets the threads waiting on an address. 34// Gets the threads waiting on an address.
33static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_threads, 35static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) {
34 VAddr address) { 36 const auto RetrieveWaitingThreads =
35 auto RetrieveWaitingThreads =
36 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) { 37 [](size_t core_index, std::vector<SharedPtr<Thread>>& waiting_threads, VAddr arb_addr) {
37 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); 38 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
38 auto& thread_list = scheduler->GetThreadList(); 39 auto& thread_list = scheduler->GetThreadList();
@@ -43,16 +44,20 @@ static void GetThreadsWaitingOnAddress(std::vector<SharedPtr<Thread>>& waiting_t
43 } 44 }
44 }; 45 };
45 46
46 // Retrieve a list of all threads that are waiting for this address. 47 // Retrieve all threads that are waiting for this address.
47 RetrieveWaitingThreads(0, waiting_threads, address); 48 std::vector<SharedPtr<Thread>> threads;
48 RetrieveWaitingThreads(1, waiting_threads, address); 49 RetrieveWaitingThreads(0, threads, address);
49 RetrieveWaitingThreads(2, waiting_threads, address); 50 RetrieveWaitingThreads(1, threads, address);
50 RetrieveWaitingThreads(3, waiting_threads, address); 51 RetrieveWaitingThreads(2, threads, address);
52 RetrieveWaitingThreads(3, threads, address);
53
51 // Sort them by priority, such that the highest priority ones come first. 54 // Sort them by priority, such that the highest priority ones come first.
52 std::sort(waiting_threads.begin(), waiting_threads.end(), 55 std::sort(threads.begin(), threads.end(),
53 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { 56 [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) {
54 return lhs->current_priority < rhs->current_priority; 57 return lhs->current_priority < rhs->current_priority;
55 }); 58 });
59
60 return threads;
56} 61}
57 62
58// Wake up num_to_wake (or all) threads in a vector. 63// Wake up num_to_wake (or all) threads in a vector.
@@ -74,9 +79,7 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num
74 79
75// Signals an address being waited on. 80// Signals an address being waited on.
76ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { 81ResultCode SignalToAddress(VAddr address, s32 num_to_wake) {
77 // Get threads waiting on the address. 82 std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
78 std::vector<SharedPtr<Thread>> waiting_threads;
79 GetThreadsWaitingOnAddress(waiting_threads, address);
80 83
81 WakeThreads(waiting_threads, num_to_wake); 84 WakeThreads(waiting_threads, num_to_wake);
82 return RESULT_SUCCESS; 85 return RESULT_SUCCESS;
@@ -108,12 +111,11 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu
108 } 111 }
109 112
110 // Get threads waiting on the address. 113 // Get threads waiting on the address.
111 std::vector<SharedPtr<Thread>> waiting_threads; 114 std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);
112 GetThreadsWaitingOnAddress(waiting_threads, address);
113 115
114 // Determine the modified value depending on the waiting count. 116 // Determine the modified value depending on the waiting count.
115 s32 updated_value; 117 s32 updated_value;
116 if (waiting_threads.size() == 0) { 118 if (waiting_threads.empty()) {
117 updated_value = value - 1; 119 updated_value = value - 1;
118 } else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) { 120 } else if (num_to_wake <= 0 || waiting_threads.size() <= static_cast<u32>(num_to_wake)) {
119 updated_value = value + 1; 121 updated_value = value + 1;
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index f20f3dbc0..e3657b8e9 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/result.h" 7#include "common/common_types.h"
8
9union ResultCode;
8 10
9namespace Kernel { 11namespace Kernel {
10 12
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index fb2b6f7a3..134e41ebc 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -2,19 +2,20 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h" 5#include <tuple>
6
6#include "core/hle/kernel/client_port.h" 7#include "core/hle/kernel/client_port.h"
7#include "core/hle/kernel/client_session.h" 8#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/errors.h" 9#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/hle_ipc.h" 10#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/object.h"
11#include "core/hle/kernel/server_port.h" 12#include "core/hle/kernel/server_port.h"
12#include "core/hle/kernel/server_session.h" 13#include "core/hle/kernel/server_session.h"
13 14
14namespace Kernel { 15namespace Kernel {
15 16
16ClientPort::ClientPort() {} 17ClientPort::ClientPort() = default;
17ClientPort::~ClientPort() {} 18ClientPort::~ClientPort() = default;
18 19
19ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { 20ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
20 // Note: Threads do not wait for the server endpoint to call 21 // Note: Threads do not wait for the server endpoint to call
@@ -39,4 +40,12 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
39 return MakeResult(std::get<SharedPtr<ClientSession>>(sessions)); 40 return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
40} 41}
41 42
43void ClientPort::ConnectionClosed() {
44 if (active_sessions == 0) {
45 return;
46 }
47
48 --active_sessions;
49}
50
42} // namespace Kernel 51} // namespace Kernel
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index a829aeb6d..b1269ea5c 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -6,7 +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/hle/kernel/kernel.h" 9#include "core/hle/kernel/object.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11 11
12namespace Kernel { 12namespace Kernel {
@@ -37,14 +37,20 @@ public:
37 */ 37 */
38 ResultVal<SharedPtr<ClientSession>> Connect(); 38 ResultVal<SharedPtr<ClientSession>> Connect();
39 39
40 SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. 40 /**
41 u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have 41 * Signifies that a previously active connection has been closed,
42 u32 active_sessions; ///< Number of currently open sessions to this port 42 * decreasing the total number of active connections to this port.
43 std::string name; ///< Name of client port (optional) 43 */
44 void ConnectionClosed();
44 45
45private: 46private:
46 ClientPort(); 47 ClientPort();
47 ~ClientPort() override; 48 ~ClientPort() override;
49
50 SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
51 u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
52 u32 active_sessions = 0; ///< Number of currently open sessions to this port
53 std::string name; ///< Name of client port (optional)
48}; 54};
49 55
50} // namespace Kernel 56} // namespace Kernel
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 72773d8b1..fdffc648d 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -2,8 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
6
7#include "core/hle/kernel/client_session.h" 5#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/errors.h" 6#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/hle_ipc.h" 7#include "core/hle/kernel/hle_ipc.h"
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 2258f95bc..dabd93ed7 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -7,7 +7,7 @@
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" 10#include "core/hle/kernel/object.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12 12
13namespace Kernel { 13namespace Kernel {
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 9cae2369f..5623c4b6a 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -3,11 +3,9 @@
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 <map>
7#include <vector>
8#include "common/assert.h" 6#include "common/assert.h"
9#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/object.h"
11#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
12 10
13namespace Kernel { 11namespace Kernel {
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index e5c924a75..3c20c05e8 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/wait_object.h" 9#include "core/hle/kernel/wait_object.h"
10 10
11namespace Kernel { 11namespace Kernel {
@@ -31,10 +31,9 @@ public:
31 return HANDLE_TYPE; 31 return HANDLE_TYPE;
32 } 32 }
33 33
34 ResetType reset_type; ///< Current ResetType 34 ResetType GetResetType() const {
35 35 return reset_type;
36 bool signaled; ///< Whether the event has already been signaled 36 }
37 std::string name; ///< Name of event (optional)
38 37
39 bool ShouldWait(Thread* thread) const override; 38 bool ShouldWait(Thread* thread) const override;
40 void Acquire(Thread* thread) override; 39 void Acquire(Thread* thread) override;
@@ -47,6 +46,11 @@ public:
47private: 46private:
48 Event(); 47 Event();
49 ~Event() override; 48 ~Event() override;
49
50 ResetType reset_type; ///< Current ResetType
51
52 bool signaled; ///< Whether the event has already been signaled
53 std::string name; ///< Name of event (optional)
50}; 54};
51 55
52} // namespace Kernel 56} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 7dd67f80f..28e21428a 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -8,7 +8,6 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/errors.h" 9#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/handle_table.h" 10#include "core/hle/kernel/handle_table.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/process.h" 11#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
14 13
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index ba968c666..22ddda630 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -7,7 +7,7 @@
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/object.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12 12
13namespace Kernel { 13namespace Kernel {
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index f24392520..5dd1b68d7 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -2,17 +2,22 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <array>
7#include <sstream>
5#include <utility> 8#include <utility>
6 9
7#include <boost/range/algorithm_ext/erase.hpp> 10#include <boost/range/algorithm_ext/erase.hpp>
11
8#include "common/assert.h" 12#include "common/assert.h"
9#include "common/common_funcs.h" 13#include "common/common_funcs.h"
10#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/logging/log.h"
11#include "core/hle/ipc_helpers.h" 16#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 17#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/handle_table.h" 18#include "core/hle/kernel/handle_table.h"
14#include "core/hle/kernel/hle_ipc.h" 19#include "core/hle/kernel/hle_ipc.h"
15#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/object.h"
16#include "core/hle/kernel/process.h" 21#include "core/hle/kernel/process.h"
17#include "core/hle/kernel/server_session.h" 22#include "core/hle/kernel/server_session.h"
18#include "core/memory.h" 23#include "core/memory.h"
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 84727f748..9ce52db24 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <iterator>
9#include <memory> 8#include <memory>
10#include <string> 9#include <string>
11#include <type_traits> 10#include <type_traits>
@@ -14,7 +13,7 @@
14#include "common/common_types.h" 13#include "common/common_types.h"
15#include "common/swap.h" 14#include "common/swap.h"
16#include "core/hle/ipc.h" 15#include "core/hle/ipc.h"
17#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/object.h"
18#include "core/hle/kernel/server_session.h" 17#include "core/hle/kernel/server_session.h"
19#include "core/hle/kernel/thread.h" 18#include "core/hle/kernel/thread.h"
20 19
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1beb98566..1b0cd0abf 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -4,8 +4,6 @@
4 4
5#include "core/hle/kernel/handle_table.h" 5#include "core/hle/kernel/handle_table.h"
6#include "core/hle/kernel/kernel.h" 6#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/memory.h"
8#include "core/hle/kernel/object_address_table.h"
9#include "core/hle/kernel/process.h" 7#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/resource_limit.h" 8#include "core/hle/kernel/resource_limit.h"
11#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
@@ -16,9 +14,7 @@ namespace Kernel {
16unsigned int Object::next_object_id; 14unsigned int Object::next_object_id;
17 15
18/// Initialize the kernel 16/// Initialize the kernel
19void Init(u32 system_mode) { 17void Init() {
20 Kernel::MemoryInit(system_mode);
21
22 Kernel::ResourceLimitsInit(); 18 Kernel::ResourceLimitsInit();
23 Kernel::ThreadingInit(); 19 Kernel::ThreadingInit();
24 Kernel::TimersInit(); 20 Kernel::TimersInit();
@@ -33,13 +29,11 @@ void Init(u32 system_mode) {
33void Shutdown() { 29void Shutdown() {
34 // Free all kernel objects 30 // Free all kernel objects
35 g_handle_table.Clear(); 31 g_handle_table.Clear();
36 g_object_address_table.Clear();
37 32
38 Kernel::ThreadingShutdown(); 33 Kernel::ThreadingShutdown();
39 34
40 Kernel::TimersShutdown(); 35 Kernel::TimersShutdown();
41 Kernel::ResourceLimitsShutdown(); 36 Kernel::ResourceLimitsShutdown();
42 Kernel::MemoryShutdown();
43} 37}
44 38
45} // namespace Kernel 39} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 402ae900f..131311472 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,122 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <string>
9#include <utility>
10#include <boost/smart_ptr/intrusive_ptr.hpp>
11#include "common/assert.h"
12#include "common/common_types.h" 7#include "common/common_types.h"
13 8
14namespace Kernel { 9namespace Kernel {
15 10
16using Handle = u32;
17
18enum class HandleType : u32 {
19 Unknown,
20 Event,
21 SharedMemory,
22 Thread,
23 Process,
24 AddressArbiter,
25 Timer,
26 ResourceLimit,
27 CodeSet,
28 ClientPort,
29 ServerPort,
30 ClientSession,
31 ServerSession,
32};
33
34enum class ResetType {
35 OneShot,
36 Sticky,
37 Pulse,
38};
39
40class Object : NonCopyable {
41public:
42 virtual ~Object() {}
43
44 /// Returns a unique identifier for the object. For debugging purposes only.
45 unsigned int GetObjectId() const {
46 return object_id;
47 }
48
49 virtual std::string GetTypeName() const {
50 return "[BAD KERNEL OBJECT TYPE]";
51 }
52 virtual std::string GetName() const {
53 return "[UNKNOWN KERNEL OBJECT]";
54 }
55 virtual Kernel::HandleType GetHandleType() const = 0;
56
57 /**
58 * Check if a thread can wait on the object
59 * @return True if a thread can wait on the object, otherwise false
60 */
61 bool IsWaitable() const {
62 switch (GetHandleType()) {
63 case HandleType::Event:
64 case HandleType::Thread:
65 case HandleType::Timer:
66 case HandleType::ServerPort:
67 case HandleType::ServerSession:
68 return true;
69
70 case HandleType::Unknown:
71 case HandleType::SharedMemory:
72 case HandleType::Process:
73 case HandleType::AddressArbiter:
74 case HandleType::ResourceLimit:
75 case HandleType::CodeSet:
76 case HandleType::ClientPort:
77 case HandleType::ClientSession:
78 return false;
79 }
80
81 UNREACHABLE();
82 }
83
84public:
85 static unsigned int next_object_id;
86
87private:
88 friend void intrusive_ptr_add_ref(Object*);
89 friend void intrusive_ptr_release(Object*);
90
91 unsigned int ref_count = 0;
92 unsigned int object_id = next_object_id++;
93};
94
95// Special functions used by boost::instrusive_ptr to do automatic ref-counting
96inline void intrusive_ptr_add_ref(Object* object) {
97 ++object->ref_count;
98}
99
100inline void intrusive_ptr_release(Object* object) {
101 if (--object->ref_count == 0) {
102 delete object;
103 }
104}
105
106template <typename T>
107using SharedPtr = boost::intrusive_ptr<T>;
108
109/**
110 * Attempts to downcast the given Object pointer to a pointer to T.
111 * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
112 */
113template <typename T>
114inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
115 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
116 return boost::static_pointer_cast<T>(std::move(object));
117 }
118 return nullptr;
119}
120
121/// Initialize the kernel with the specified system mode. 11/// Initialize the kernel with the specified system mode.
122void Init(u32 system_mode); 12void Init();
123 13
124/// Shutdown the kernel 14/// Shutdown the kernel
125void Shutdown(); 15void Shutdown();
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
deleted file mode 100644
index 94eac677c..000000000
--- a/src/core/hle/kernel/memory.cpp
+++ /dev/null
@@ -1,92 +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 <algorithm>
6#include <cinttypes>
7#include <map>
8#include <memory>
9#include <utility>
10#include <vector>
11#include "common/assert.h"
12#include "common/common_types.h"
13#include "common/logging/log.h"
14#include "core/hle/kernel/memory.h"
15#include "core/hle/kernel/vm_manager.h"
16#include "core/hle/result.h"
17#include "core/memory.h"
18#include "core/memory_setup.h"
19
20////////////////////////////////////////////////////////////////////////////////////////////////////
21
22namespace Kernel {
23
24MemoryRegionInfo memory_regions[3];
25
26/// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system
27/// memory configuration type.
28static const u32 memory_region_sizes[8][3] = {
29 // Old 3DS layouts
30 {0x04000000, 0x02C00000, 0x01400000}, // 0
31 {/* This appears to be unused. */}, // 1
32 {0x06000000, 0x00C00000, 0x01400000}, // 2
33 {0x05000000, 0x01C00000, 0x01400000}, // 3
34 {0x04800000, 0x02400000, 0x01400000}, // 4
35 {0x02000000, 0x04C00000, 0x01400000}, // 5
36
37 // New 3DS layouts
38 {0x07C00000, 0x06400000, 0x02000000}, // 6
39 {0x0B200000, 0x02E00000, 0x02000000}, // 7
40};
41
42void MemoryInit(u32 mem_type) {
43 // TODO(yuriks): On the n3DS, all o3DS configurations (<=5) are forced to 6 instead.
44 ASSERT_MSG(mem_type <= 5, "New 3DS memory configuration aren't supported yet!");
45 ASSERT(mem_type != 1);
46
47 // The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with
48 // the sizes specified in the memory_region_sizes table.
49 VAddr base = 0;
50 for (int i = 0; i < 3; ++i) {
51 memory_regions[i].base = base;
52 memory_regions[i].size = memory_region_sizes[mem_type][i];
53 memory_regions[i].used = 0;
54 memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
55 // Reserve enough space for this region of FCRAM.
56 // We do not want this block of memory to be relocated when allocating from it.
57 memory_regions[i].linear_heap_memory->reserve(memory_regions[i].size);
58
59 base += memory_regions[i].size;
60 }
61
62 // We must've allocated the entire FCRAM by the end
63 ASSERT(base == Memory::FCRAM_SIZE);
64}
65
66void MemoryShutdown() {
67 for (auto& region : memory_regions) {
68 region.base = 0;
69 region.size = 0;
70 region.used = 0;
71 region.linear_heap_memory = nullptr;
72 }
73}
74
75MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
76 switch (region) {
77 case MemoryRegion::APPLICATION:
78 return &memory_regions[0];
79 case MemoryRegion::SYSTEM:
80 return &memory_regions[1];
81 case MemoryRegion::BASE:
82 return &memory_regions[2];
83 default:
84 UNREACHABLE();
85 }
86}
87
88void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {}
89
90void MapSharedPages(VMManager& address_space) {}
91
92} // namespace Kernel
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
deleted file mode 100644
index 61e30c679..000000000
--- a/src/core/hle/kernel/memory.h
+++ /dev/null
@@ -1,31 +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 <memory>
8#include "common/common_types.h"
9#include "core/hle/kernel/process.h"
10
11namespace Kernel {
12
13class VMManager;
14
15struct MemoryRegionInfo {
16 u64 base; // Not an address, but offset from start of FCRAM
17 u64 size;
18 u64 used;
19
20 std::shared_ptr<std::vector<u8>> linear_heap_memory;
21};
22
23void MemoryInit(u32 mem_type);
24void MemoryShutdown();
25MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
26
27void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
28void MapSharedPages(VMManager& address_space);
29
30extern MemoryRegionInfo memory_regions[3];
31} // namespace Kernel
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index feb7b88d2..cb7f58b35 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -3,16 +3,19 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <utility>
6#include <vector> 7#include <vector>
8
7#include <boost/range/algorithm_ext/erase.hpp> 9#include <boost/range/algorithm_ext/erase.hpp>
10
8#include "common/assert.h" 11#include "common/assert.h"
9#include "core/core.h" 12#include "core/core.h"
10#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
11#include "core/hle/kernel/handle_table.h" 14#include "core/hle/kernel/handle_table.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/mutex.h" 15#include "core/hle/kernel/mutex.h"
14#include "core/hle/kernel/object_address_table.h" 16#include "core/hle/kernel/object.h"
15#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
18#include "core/hle/result.h"
16 19
17namespace Kernel { 20namespace Kernel {
18 21
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 3117e7c70..45268bbe9 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -4,12 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8#include "common/common_types.h" 7#include "common/common_types.h"
9#include "common/swap.h" 8#include "core/hle/kernel/object.h"
10#include "core/hle/kernel/kernel.h" 9
11#include "core/hle/kernel/wait_object.h" 10union ResultCode;
12#include "core/hle/result.h"
13 11
14namespace Kernel { 12namespace Kernel {
15 13
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
new file mode 100644
index 000000000..cdba272f5
--- /dev/null
+++ b/src/core/hle/kernel/object.cpp
@@ -0,0 +1,35 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/kernel/object.h"
7
8namespace Kernel {
9
10Object::~Object() = default;
11
12bool Object::IsWaitable() const {
13 switch (GetHandleType()) {
14 case HandleType::Event:
15 case HandleType::Thread:
16 case HandleType::Timer:
17 case HandleType::ServerPort:
18 case HandleType::ServerSession:
19 return true;
20
21 case HandleType::Unknown:
22 case HandleType::SharedMemory:
23 case HandleType::Process:
24 case HandleType::AddressArbiter:
25 case HandleType::ResourceLimit:
26 case HandleType::CodeSet:
27 case HandleType::ClientPort:
28 case HandleType::ClientSession:
29 return false;
30 }
31
32 UNREACHABLE();
33}
34
35} // namespace Kernel
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
new file mode 100644
index 000000000..83df68dfd
--- /dev/null
+++ b/src/core/hle/kernel/object.h
@@ -0,0 +1,100 @@
1// Copyright 2018 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 <string>
8#include <utility>
9
10#include <boost/smart_ptr/intrusive_ptr.hpp>
11
12#include "common/common_types.h"
13
14namespace Kernel {
15
16using Handle = u32;
17
18enum class HandleType : u32 {
19 Unknown,
20 Event,
21 SharedMemory,
22 Thread,
23 Process,
24 AddressArbiter,
25 Timer,
26 ResourceLimit,
27 CodeSet,
28 ClientPort,
29 ServerPort,
30 ClientSession,
31 ServerSession,
32};
33
34enum class ResetType {
35 OneShot,
36 Sticky,
37 Pulse,
38};
39
40class Object : NonCopyable {
41public:
42 virtual ~Object();
43
44 /// Returns a unique identifier for the object. For debugging purposes only.
45 unsigned int GetObjectId() const {
46 return object_id;
47 }
48
49 virtual std::string GetTypeName() const {
50 return "[BAD KERNEL OBJECT TYPE]";
51 }
52 virtual std::string GetName() const {
53 return "[UNKNOWN KERNEL OBJECT]";
54 }
55 virtual HandleType GetHandleType() const = 0;
56
57 /**
58 * Check if a thread can wait on the object
59 * @return True if a thread can wait on the object, otherwise false
60 */
61 bool IsWaitable() const;
62
63public:
64 static unsigned int next_object_id;
65
66private:
67 friend void intrusive_ptr_add_ref(Object*);
68 friend void intrusive_ptr_release(Object*);
69
70 unsigned int ref_count = 0;
71 unsigned int object_id = next_object_id++;
72};
73
74// Special functions used by boost::instrusive_ptr to do automatic ref-counting
75inline void intrusive_ptr_add_ref(Object* object) {
76 ++object->ref_count;
77}
78
79inline void intrusive_ptr_release(Object* object) {
80 if (--object->ref_count == 0) {
81 delete object;
82 }
83}
84
85template <typename T>
86using SharedPtr = boost::intrusive_ptr<T>;
87
88/**
89 * Attempts to downcast the given Object pointer to a pointer to T.
90 * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
91 */
92template <typename T>
93inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
94 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
95 return boost::static_pointer_cast<T>(std::move(object));
96 }
97 return nullptr;
98}
99
100} // namespace Kernel
diff --git a/src/core/hle/kernel/object_address_table.cpp b/src/core/hle/kernel/object_address_table.cpp
deleted file mode 100644
index ca8a833a1..000000000
--- a/src/core/hle/kernel/object_address_table.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
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 <utility>
6
7#include "common/assert.h"
8#include "core/hle/kernel/object_address_table.h"
9
10namespace Kernel {
11
12ObjectAddressTable g_object_address_table;
13
14void ObjectAddressTable::Insert(VAddr addr, SharedPtr<Object> obj) {
15 ASSERT_MSG(objects.find(addr) == objects.end(), "Object already exists with addr=0x{:X}", addr);
16 objects[addr] = std::move(obj);
17}
18
19void ObjectAddressTable::Close(VAddr addr) {
20 ASSERT_MSG(objects.find(addr) != objects.end(), "Object does not exist with addr=0x{:X}", addr);
21 objects.erase(addr);
22}
23
24SharedPtr<Object> ObjectAddressTable::GetGeneric(VAddr addr) const {
25 auto iter = objects.find(addr);
26 if (iter != objects.end()) {
27 return iter->second;
28 }
29 return {};
30}
31
32void ObjectAddressTable::Clear() {
33 objects.clear();
34}
35
36} // namespace Kernel
diff --git a/src/core/hle/kernel/object_address_table.h b/src/core/hle/kernel/object_address_table.h
deleted file mode 100644
index a09004b32..000000000
--- a/src/core/hle/kernel/object_address_table.h
+++ /dev/null
@@ -1,62 +0,0 @@
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 <map>
8#include "common/common_types.h"
9#include "core/hle/kernel/kernel.h"
10
11namespace Kernel {
12
13/**
14 * This class is used to keep a table of Kernel objects and their respective addresses in emulated
15 * memory. For certain Switch SVCs, Kernel objects are referenced by an address to an object the
16 * guest application manages, so we use this table to look these kernel objects up. This is similiar
17 * to the HandleTable class.
18 */
19class ObjectAddressTable final : NonCopyable {
20public:
21 ObjectAddressTable() = default;
22
23 /**
24 * Inserts an object and address pair into the table.
25 */
26 void Insert(VAddr addr, SharedPtr<Object> obj);
27
28 /**
29 * Closes an object by its address, removing it from the table and decreasing the object's
30 * ref-count.
31 * @return `RESULT_SUCCESS` or one of the following errors:
32 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
33 */
34 void Close(VAddr addr);
35
36 /**
37 * Looks up an object by its address.
38 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
39 */
40 SharedPtr<Object> GetGeneric(VAddr addr) const;
41
42 /**
43 * Looks up an object by its address while verifying its type.
44 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
45 * type differs from the requested one.
46 */
47 template <class T>
48 SharedPtr<T> Get(VAddr addr) const {
49 return DynamicObjectCast<T>(GetGeneric(addr));
50 }
51
52 /// Closes all addresses held in this table.
53 void Clear();
54
55private:
56 /// Stores the Object referenced by the address
57 std::map<VAddr, SharedPtr<Object>> objects;
58};
59
60extern ObjectAddressTable g_object_address_table;
61
62} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0c0506085..edf34c5a3 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -8,7 +8,6 @@
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/hle/kernel/errors.h" 10#include "core/hle/kernel/errors.h"
11#include "core/hle/kernel/memory.h"
12#include "core/hle/kernel/process.h" 11#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/resource_limit.h" 12#include "core/hle/kernel/resource_limit.h"
14#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
@@ -125,14 +124,6 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
125 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, 124 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
126 MemoryState::Mapped) 125 MemoryState::Mapped)
127 .Unwrap(); 126 .Unwrap();
128 misc_memory_used += stack_size;
129 memory_region->used += stack_size;
130
131 // Map special address mappings
132 MapSharedPages(vm_manager);
133 for (const auto& mapping : address_mappings) {
134 HandleSpecialMapping(vm_manager, mapping);
135 }
136 127
137 vm_manager.LogLayout(); 128 vm_manager.LogLayout();
138 status = ProcessStatus::Running; 129 status = ProcessStatus::Running;
@@ -141,37 +132,19 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
141} 132}
142 133
143void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { 134void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
144 memory_region = GetMemoryRegion(flags.memory_region); 135 const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
145 136 MemoryState memory_state) {
146 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
147 MemoryState memory_state) {
148 auto vma = vm_manager 137 auto vma = vm_manager
149 .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, 138 .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset,
150 segment.size, memory_state) 139 segment.size, memory_state)
151 .Unwrap(); 140 .Unwrap();
152 vm_manager.Reprotect(vma, permissions); 141 vm_manager.Reprotect(vma, permissions);
153 misc_memory_used += segment.size;
154 memory_region->used += segment.size;
155 }; 142 };
156 143
157 // Map CodeSet segments 144 // Map CodeSet segments
158 MapSegment(module_->code, VMAPermission::ReadExecute, MemoryState::CodeStatic); 145 MapSegment(module_->CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic);
159 MapSegment(module_->rodata, VMAPermission::Read, MemoryState::CodeMutable); 146 MapSegment(module_->RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable);
160 MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable); 147 MapSegment(module_->DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable);
161}
162
163VAddr Process::GetLinearHeapAreaAddress() const {
164 // Starting from system version 8.0.0 a new linear heap layout is supported to allow usage of
165 // the extra RAM in the n3DS.
166 return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR;
167}
168
169VAddr Process::GetLinearHeapBase() const {
170 return GetLinearHeapAreaAddress() + memory_region->base;
171}
172
173VAddr Process::GetLinearHeapLimit() const {
174 return GetLinearHeapBase() + memory_region->size;
175} 148}
176 149
177ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 150ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
@@ -206,7 +179,6 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
206 vm_manager.Reprotect(vma, perms); 179 vm_manager.Reprotect(vma, perms);
207 180
208 heap_used = size; 181 heap_used = size;
209 memory_region->used += size;
210 182
211 return MakeResult<VAddr>(heap_end - size); 183 return MakeResult<VAddr>(heap_end - size);
212} 184}
@@ -226,52 +198,6 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
226 return result; 198 return result;
227 199
228 heap_used -= size; 200 heap_used -= size;
229 memory_region->used -= size;
230
231 return RESULT_SUCCESS;
232}
233
234ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) {
235 UNIMPLEMENTED();
236 return {};
237}
238
239ResultCode Process::LinearFree(VAddr target, u32 size) {
240 auto& linheap_memory = memory_region->linear_heap_memory;
241
242 if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
243 target + size < target) {
244
245 return ERR_INVALID_ADDRESS;
246 }
247
248 if (size == 0) {
249 return RESULT_SUCCESS;
250 }
251
252 VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
253 if (target + size > heap_end) {
254 return ERR_INVALID_ADDRESS_STATE;
255 }
256
257 ResultCode result = vm_manager.UnmapRange(target, size);
258 if (result.IsError())
259 return result;
260
261 linear_heap_used -= size;
262 memory_region->used -= size;
263
264 if (target + size == heap_end) {
265 // End of linear heap has been freed, so check what's the last allocated block in it and
266 // reduce the size.
267 auto vma = vm_manager.FindVMA(target);
268 ASSERT(vma != vm_manager.vma_map.end());
269 ASSERT(vma->second.type == VMAType::Free);
270 VAddr new_end = vma->second.base;
271 if (new_end >= GetLinearHeapBase()) {
272 linheap_memory->resize(new_end - GetLinearHeapBase());
273 }
274 }
275 201
276 return RESULT_SUCCESS; 202 return RESULT_SUCCESS;
277} 203}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 68e77a4d1..992689186 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <bitset> 8#include <bitset>
8#include <cstddef> 9#include <cstddef>
9#include <memory> 10#include <memory>
@@ -12,7 +13,7 @@
12#include <boost/container/static_vector.hpp> 13#include <boost/container/static_vector.hpp>
13#include "common/bit_field.h" 14#include "common/bit_field.h"
14#include "common/common_types.h" 15#include "common/common_types.h"
15#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/object.h"
16#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
17#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
18 19
@@ -53,9 +54,14 @@ union ProcessFlags {
53enum class ProcessStatus { Created, Running, Exited }; 54enum class ProcessStatus { Created, Running, Exited };
54 55
55class ResourceLimit; 56class ResourceLimit;
56struct MemoryRegionInfo;
57 57
58struct CodeSet final : public Object { 58struct CodeSet final : public Object {
59 struct Segment {
60 size_t offset = 0;
61 VAddr addr = 0;
62 u32 size = 0;
63 };
64
59 static SharedPtr<CodeSet> Create(std::string name); 65 static SharedPtr<CodeSet> Create(std::string name);
60 66
61 std::string GetTypeName() const override { 67 std::string GetTypeName() const override {
@@ -70,24 +76,38 @@ struct CodeSet final : public Object {
70 return HANDLE_TYPE; 76 return HANDLE_TYPE;
71 } 77 }
72 78
73 /// Name of the process 79 Segment& CodeSegment() {
74 std::string name; 80 return segments[0];
81 }
75 82
76 std::shared_ptr<std::vector<u8>> memory; 83 const Segment& CodeSegment() const {
84 return segments[0];
85 }
77 86
78 struct Segment { 87 Segment& RODataSegment() {
79 size_t offset = 0; 88 return segments[1];
80 VAddr addr = 0; 89 }
81 u32 size = 0; 90
82 }; 91 const Segment& RODataSegment() const {
92 return segments[1];
93 }
94
95 Segment& DataSegment() {
96 return segments[2];
97 }
98
99 const Segment& DataSegment() const {
100 return segments[2];
101 }
83 102
84 Segment segments[3]; 103 std::shared_ptr<std::vector<u8>> memory;
85 Segment& code = segments[0];
86 Segment& rodata = segments[1];
87 Segment& data = segments[2];
88 104
105 std::array<Segment, 3> segments;
89 VAddr entrypoint; 106 VAddr entrypoint;
90 107
108 /// Name of the process
109 std::string name;
110
91private: 111private:
92 CodeSet(); 112 CodeSet();
93 ~CodeSet() override; 113 ~CodeSet() override;
@@ -163,12 +183,11 @@ public:
163 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous 183 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
164 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe. 184 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
165 std::shared_ptr<std::vector<u8>> heap_memory; 185 std::shared_ptr<std::vector<u8>> heap_memory;
166 // The left/right bounds of the address space covered by heap_memory.
167 VAddr heap_start = 0, heap_end = 0;
168 186
169 u64 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0; 187 // The left/right bounds of the address space covered by heap_memory.
170 188 VAddr heap_start = 0;
171 MemoryRegionInfo* memory_region = nullptr; 189 VAddr heap_end = 0;
190 u64 heap_used = 0;
172 191
173 /// The Thread Local Storage area is allocated as processes create threads, 192 /// The Thread Local Storage area is allocated as processes create threads,
174 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part 193 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
@@ -179,16 +198,9 @@ public:
179 198
180 std::string name; 199 std::string name;
181 200
182 VAddr GetLinearHeapAreaAddress() const;
183 VAddr GetLinearHeapBase() const;
184 VAddr GetLinearHeapLimit() const;
185
186 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); 201 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
187 ResultCode HeapFree(VAddr target, u32 size); 202 ResultCode HeapFree(VAddr target, u32 size);
188 203
189 ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
190 ResultCode LinearFree(VAddr target, u32 size);
191
192 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); 204 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
193 205
194 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); 206 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index cc689a27a..0fa141db3 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/object.h"
9 9
10namespace Kernel { 10namespace Kernel {
11 11
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index e307eec98..94065c736 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -2,8 +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 <algorithm>
5#include <utility> 6#include <utility>
6 7
8#include "common/assert.h"
9#include "common/logging/log.h"
10#include "core/arm/arm_interface.h"
7#include "core/core.h" 11#include "core/core.h"
8#include "core/core_timing.h" 12#include "core/core_timing.h"
9#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index a3b5fb8ca..1a4ee8f36 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -8,9 +8,11 @@
8#include <vector> 8#include <vector>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/thread_queue_list.h" 10#include "common/thread_queue_list.h"
11#include "core/arm/arm_interface.h" 11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13 13
14class ARM_Interface;
15
14namespace Kernel { 16namespace Kernel {
15 17
16class Scheduler final { 18class Scheduler final {
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 0b7061403..7b6211fd8 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -6,7 +6,7 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/hle/kernel/client_port.h" 7#include "core/hle/kernel/client_port.h"
8#include "core/hle/kernel/errors.h" 8#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/object.h"
10#include "core/hle/kernel/server_port.h" 10#include "core/hle/kernel/server_port.h"
11#include "core/hle/kernel/server_session.h" 11#include "core/hle/kernel/server_session.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 9ef4ecc35..7f6d6b3eb 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -7,8 +7,9 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include <tuple> 9#include <tuple>
10#include <vector>
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/wait_object.h" 13#include "core/hle/kernel/wait_object.h"
13 14
14namespace Kernel { 15namespace Kernel {
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 29b163528..93560152f 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -5,6 +5,8 @@
5#include <tuple> 5#include <tuple>
6#include <utility> 6#include <utility>
7 7
8#include "common/assert.h"
9#include "common/logging/log.h"
8#include "core/core.h" 10#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/client_port.h" 12#include "core/hle/kernel/client_port.h"
@@ -25,7 +27,7 @@ ServerSession::~ServerSession() {
25 27
26 // Decrease the port's connection count. 28 // Decrease the port's connection count.
27 if (parent->port) 29 if (parent->port)
28 parent->port->active_sessions--; 30 parent->port->ConnectionClosed();
29 31
30 // TODO(Subv): Wake up all the ClientSession's waiting threads and set 32 // TODO(Subv): Wake up all the ClientSession's waiting threads and set
31 // the SendSyncRequest result to 0xC920181A. 33 // the SendSyncRequest result to 0xC920181A.
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 2da807042..2bce54fee 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -6,12 +6,12 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include "common/assert.h" 9#include <vector>
10
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/wait_object.h" 13#include "core/hle/kernel/wait_object.h"
13#include "core/hle/result.h" 14#include "core/hle/result.h"
14#include "core/memory.h"
15 15
16namespace Kernel { 16namespace Kernel {
17 17
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index e69b034a7..7a551f5e4 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/kernel.h" 7#include "core/hle/kernel/object.h"
8 8
9namespace Kernel { 9namespace Kernel {
10 10
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 4bf11c7e2..21ddc2f7d 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -3,10 +3,11 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <utility> 5#include <utility>
6
7#include "common/assert.h"
6#include "common/logging/log.h" 8#include "common/logging/log.h"
7#include "core/core.h" 9#include "core/core.h"
8#include "core/hle/kernel/errors.h" 10#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/memory.h"
10#include "core/hle/kernel/shared_memory.h" 11#include "core/hle/kernel/shared_memory.h"
11#include "core/memory.h" 12#include "core/memory.h"
12 13
@@ -28,35 +29,17 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
28 shared_memory->other_permissions = other_permissions; 29 shared_memory->other_permissions = other_permissions;
29 30
30 if (address == 0) { 31 if (address == 0) {
31 // We need to allocate a block from the Linear Heap ourselves. 32 shared_memory->backing_block = std::make_shared<std::vector<u8>>(size);
32 // We'll manually allocate some memory from the linear heap in the specified region. 33 shared_memory->backing_block_offset = 0;
33 MemoryRegionInfo* memory_region = GetMemoryRegion(region);
34 auto& linheap_memory = memory_region->linear_heap_memory;
35
36 ASSERT_MSG(linheap_memory->size() + size <= memory_region->size,
37 "Not enough space in region to allocate shared memory!");
38
39 shared_memory->backing_block = linheap_memory;
40 shared_memory->backing_block_offset = linheap_memory->size();
41 // Allocate some memory from the end of the linear heap for this region.
42 linheap_memory->insert(linheap_memory->end(), size, 0);
43 memory_region->used += size;
44
45 shared_memory->linear_heap_phys_address =
46 Memory::FCRAM_PADDR + memory_region->base +
47 static_cast<PAddr>(shared_memory->backing_block_offset);
48
49 // Increase the amount of used linear heap memory for the owner process.
50 if (shared_memory->owner_process != nullptr) {
51 shared_memory->owner_process->linear_heap_used += size;
52 }
53 34
54 // Refresh the address mappings for the current process. 35 // Refresh the address mappings for the current process.
55 if (Core::CurrentProcess() != nullptr) { 36 if (Core::CurrentProcess() != nullptr) {
56 Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); 37 Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(
38 shared_memory->backing_block.get());
57 } 39 }
58 } else { 40 } else {
59 auto& vm_manager = shared_memory->owner_process->vm_manager; 41 auto& vm_manager = shared_memory->owner_process->vm_manager;
42
60 // The memory is already available and mapped in the owner process. 43 // The memory is already available and mapped in the owner process.
61 auto vma = vm_manager.FindVMA(address); 44 auto vma = vm_manager.FindVMA(address);
62 ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address"); 45 ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
@@ -72,6 +55,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
72 } 55 }
73 56
74 shared_memory->base_address = address; 57 shared_memory->base_address = address;
58
75 return shared_memory; 59 return shared_memory;
76} 60}
77 61
@@ -122,11 +106,6 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
122 106
123 VAddr target_address = address; 107 VAddr target_address = address;
124 108
125 if (base_address == 0 && target_address == 0) {
126 // Calculate the address at which to map the memory block.
127 target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address).value();
128 }
129
130 // Map the memory block into the target process 109 // Map the memory block into the target process
131 auto result = target_process->vm_manager.MapMemoryBlock( 110 auto result = target_process->vm_manager.MapMemoryBlock(
132 target_address, backing_block, backing_block_offset, size, MemoryState::Shared); 111 target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 86f818e90..c50fee615 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -4,9 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
7#include <string> 8#include <string>
9#include <vector>
10
8#include "common/common_types.h" 11#include "common/common_types.h"
9#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/object.h"
10#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
11#include "core/hle/result.h" 14#include "core/hle/result.h"
12 15
@@ -108,9 +111,6 @@ public:
108 SharedPtr<Process> owner_process; 111 SharedPtr<Process> owner_process;
109 /// Address of shared memory block in the owner process if specified. 112 /// Address of shared memory block in the owner process if specified.
110 VAddr base_address; 113 VAddr base_address;
111 /// Physical address of the shared memory block in the linear heap if no address was specified
112 /// during creation.
113 PAddr linear_heap_phys_address;
114 /// Backing memory for this shared memory block. 114 /// Backing memory for this shared memory block.
115 std::shared_ptr<std::vector<u8>> backing_block; 115 std::shared_ptr<std::vector<u8>> backing_block;
116 /// Offset into the backing block for this shared memory. 116 /// Offset into the backing block for this shared memory.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 0b439401a..5db2db687 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -5,7 +5,10 @@
5#include <algorithm> 5#include <algorithm>
6#include <cinttypes> 6#include <cinttypes>
7#include <iterator> 7#include <iterator>
8#include <mutex>
9#include <vector>
8 10
11#include "common/assert.h"
9#include "common/logging/log.h" 12#include "common/logging/log.h"
10#include "common/microprofile.h" 13#include "common/microprofile.h"
11#include "common/string_util.h" 14#include "common/string_util.h"
@@ -17,7 +20,6 @@
17#include "core/hle/kernel/event.h" 20#include "core/hle/kernel/event.h"
18#include "core/hle/kernel/handle_table.h" 21#include "core/hle/kernel/handle_table.h"
19#include "core/hle/kernel/mutex.h" 22#include "core/hle/kernel/mutex.h"
20#include "core/hle/kernel/object_address_table.h"
21#include "core/hle/kernel/process.h" 23#include "core/hle/kernel/process.h"
22#include "core/hle/kernel/resource_limit.h" 24#include "core/hle/kernel/resource_limit.h"
23#include "core/hle/kernel/shared_memory.h" 25#include "core/hle/kernel/shared_memory.h"
@@ -265,7 +267,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
265 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, 267 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
266 info_sub_id, handle); 268 info_sub_id, handle);
267 269
268 auto& vm_manager = Core::CurrentProcess()->vm_manager; 270 const auto& vm_manager = Core::CurrentProcess()->vm_manager;
269 271
270 switch (static_cast<GetInfoType>(info_id)) { 272 switch (static_cast<GetInfoType>(info_id)) {
271 case GetInfoType::AllowedCpuIdBitmask: 273 case GetInfoType::AllowedCpuIdBitmask:
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 94735c86e..b9022feae 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -4,8 +4,11 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cinttypes> 6#include <cinttypes>
7#include <list>
8#include <vector> 7#include <vector>
8
9#include <boost/optional.hpp>
10#include <boost/range/algorithm_ext/erase.hpp>
11
9#include "common/assert.h" 12#include "common/assert.h"
10#include "common/common_types.h" 13#include "common/common_types.h"
11#include "common/logging/log.h" 14#include "common/logging/log.h"
@@ -17,9 +20,7 @@
17#include "core/core_timing_util.h" 20#include "core/core_timing_util.h"
18#include "core/hle/kernel/errors.h" 21#include "core/hle/kernel/errors.h"
19#include "core/hle/kernel/handle_table.h" 22#include "core/hle/kernel/handle_table.h"
20#include "core/hle/kernel/kernel.h" 23#include "core/hle/kernel/object.h"
21#include "core/hle/kernel/memory.h"
22#include "core/hle/kernel/mutex.h"
23#include "core/hle/kernel/process.h" 24#include "core/hle/kernel/process.h"
24#include "core/hle/kernel/thread.h" 25#include "core/hle/kernel/thread.h"
25#include "core/hle/result.h" 26#include "core/hle/result.h"
@@ -79,8 +80,8 @@ void Thread::Stop() {
79 wait_objects.clear(); 80 wait_objects.clear();
80 81
81 // Mark the TLS slot in the thread's page as free. 82 // Mark the TLS slot in the thread's page as free.
82 u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; 83 const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
83 u64 tls_slot = 84 const u64 tls_slot =
84 ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; 85 ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
85 Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot); 86 Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
86} 87}
@@ -250,13 +251,14 @@ void Thread::ResumeFromWait() {
250 * slot: The index of the first free slot in the indicated page. 251 * slot: The index of the first free slot in the indicated page.
251 * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full). 252 * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
252 */ 253 */
253std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& tls_slots) { 254static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
255 const std::vector<std::bitset<8>>& tls_slots) {
254 // Iterate over all the allocated pages, and try to find one where not all slots are used. 256 // Iterate over all the allocated pages, and try to find one where not all slots are used.
255 for (unsigned page = 0; page < tls_slots.size(); ++page) { 257 for (std::size_t page = 0; page < tls_slots.size(); ++page) {
256 const auto& page_tls_slots = tls_slots[page]; 258 const auto& page_tls_slots = tls_slots[page];
257 if (!page_tls_slots.all()) { 259 if (!page_tls_slots.all()) {
258 // We found a page with at least one free slot, find which slot it is 260 // We found a page with at least one free slot, find which slot it is
259 for (unsigned slot = 0; slot < page_tls_slots.size(); ++slot) { 261 for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) {
260 if (!page_tls_slots.test(slot)) { 262 if (!page_tls_slots.test(slot)) {
261 return std::make_tuple(page, slot, false); 263 return std::make_tuple(page, slot, false);
262 } 264 }
@@ -331,42 +333,22 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
331 333
332 // Find the next available TLS index, and mark it as used 334 // Find the next available TLS index, and mark it as used
333 auto& tls_slots = owner_process->tls_slots; 335 auto& tls_slots = owner_process->tls_slots;
334 bool needs_allocation = true;
335 u32 available_page; // Which allocated page has free space
336 u32 available_slot; // Which slot within the page is free
337
338 std::tie(available_page, available_slot, needs_allocation) = GetFreeThreadLocalSlot(tls_slots);
339 336
337 auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
340 if (needs_allocation) { 338 if (needs_allocation) {
341 // There are no already-allocated pages with free slots, lets allocate a new one.
342 // TLS pages are allocated from the BASE region in the linear heap.
343 MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
344 auto& linheap_memory = memory_region->linear_heap_memory;
345
346 if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
347 LOG_ERROR(Kernel_SVC,
348 "Not enough space in region to allocate a new TLS page for thread");
349 return ERR_OUT_OF_MEMORY;
350 }
351
352 size_t offset = linheap_memory->size();
353
354 // Allocate some memory from the end of the linear heap for this region.
355 linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
356 memory_region->used += Memory::PAGE_SIZE;
357 owner_process->linear_heap_used += Memory::PAGE_SIZE;
358
359 tls_slots.emplace_back(0); // The page is completely available at the start 339 tls_slots.emplace_back(0); // The page is completely available at the start
360 available_page = static_cast<u32>(tls_slots.size() - 1); 340 available_page = tls_slots.size() - 1;
361 available_slot = 0; // Use the first slot in the new page 341 available_slot = 0; // Use the first slot in the new page
362 342
343 // Allocate some memory from the end of the linear heap for this region.
344 const size_t offset = thread->tls_memory->size();
345 thread->tls_memory->insert(thread->tls_memory->end(), Memory::PAGE_SIZE, 0);
346
363 auto& vm_manager = owner_process->vm_manager; 347 auto& vm_manager = owner_process->vm_manager;
364 vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); 348 vm_manager.RefreshMemoryBlockMappings(thread->tls_memory.get());
365 349
366 // Map the page to the current process' address space.
367 // TODO(Subv): Find the correct MemoryState for this region.
368 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, 350 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
369 linheap_memory, offset, Memory::PAGE_SIZE, 351 thread->tls_memory, 0, Memory::PAGE_SIZE,
370 MemoryState::ThreadLocal); 352 MemoryState::ThreadLocal);
371 } 353 }
372 354
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 6218960d2..adc804248 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -4,15 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <functional>
7#include <memory> 8#include <memory>
8#include <string> 9#include <string>
9#include <unordered_map>
10#include <vector> 10#include <vector>
11#include <boost/container/flat_map.hpp> 11
12#include <boost/container/flat_set.hpp>
13#include "common/common_types.h" 12#include "common/common_types.h"
14#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
15#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/object.h"
16#include "core/hle/kernel/wait_object.h" 15#include "core/hle/kernel/wait_object.h"
17#include "core/hle/result.h" 16#include "core/hle/result.h"
18 17
@@ -266,6 +265,8 @@ public:
266private: 265private:
267 Thread(); 266 Thread();
268 ~Thread() override; 267 ~Thread() override;
268
269 std::shared_ptr<std::vector<u8>> tls_memory = std::make_shared<std::vector<u8>>();
269}; 270};
270 271
271/** 272/**
@@ -289,12 +290,6 @@ Thread* GetCurrentThread();
289void WaitCurrentThread_Sleep(); 290void WaitCurrentThread_Sleep();
290 291
291/** 292/**
292 * Waits the current thread from an ArbitrateAddress call
293 * @param wait_address Arbitration address used to resume from wait
294 */
295void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
296
297/**
298 * Stops the current thread and removes it from the thread_list 293 * Stops the current thread and removes it from the thread_list
299 */ 294 */
300void ExitCurrentThread(); 295void ExitCurrentThread();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 904a3d0a5..282360745 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -8,7 +8,7 @@
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/core_timing_util.h" 9#include "core/core_timing_util.h"
10#include "core/hle/kernel/handle_table.h" 10#include "core/hle/kernel/handle_table.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13#include "core/hle/kernel/timer.h" 13#include "core/hle/kernel/timer.h"
14 14
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index c63f0ed90..4dddc67e0 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -5,7 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/wait_object.h" 9#include "core/hle/kernel/wait_object.h"
10 10
11namespace Kernel { 11namespace Kernel {
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 9d26fd781..479cacb62 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.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 <algorithm>
5#include <iterator> 6#include <iterator>
6#include <utility> 7#include <utility>
7#include "common/assert.h" 8#include "common/assert.h"
@@ -175,9 +176,9 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
175 176
176ResultCode VMManager::UnmapRange(VAddr target, u64 size) { 177ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
177 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size)); 178 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
178 VAddr target_end = target + size; 179 const VAddr target_end = target + size;
179 180
180 VMAIter end = vma_map.end(); 181 const VMAIter end = vma_map.end();
181 // The comparison against the end of the range must be done using addresses since VMAs can be 182 // The comparison against the end of the range must be done using addresses since VMAs can be
182 // merged during this process, causing invalidation of the iterators. 183 // merged during this process, causing invalidation of the iterators.
183 while (vma != end && vma->second.base < target_end) { 184 while (vma != end && vma->second.base < target_end) {
@@ -207,9 +208,9 @@ VMManager::VMAHandle VMManager::Reprotect(VMAHandle vma_handle, VMAPermission ne
207 208
208ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_perms) { 209ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_perms) {
209 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size)); 210 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
210 VAddr target_end = target + size; 211 const VAddr target_end = target + size;
211 212
212 VMAIter end = vma_map.end(); 213 const VMAIter end = vma_map.end();
213 // The comparison against the end of the range must be done using addresses since VMAs can be 214 // The comparison against the end of the range must be done using addresses since VMAs can be
214 // merged during this process, causing invalidation of the iterators. 215 // merged during this process, causing invalidation of the iterators.
215 while (vma != end && vma->second.base < target_end) { 216 while (vma != end && vma->second.base < target_end) {
@@ -258,14 +259,14 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u64 size) {
258 return ERR_INVALID_ADDRESS; 259 return ERR_INVALID_ADDRESS;
259 } 260 }
260 261
261 VirtualMemoryArea& vma = vma_handle->second; 262 const VirtualMemoryArea& vma = vma_handle->second;
262 if (vma.type != VMAType::Free) { 263 if (vma.type != VMAType::Free) {
263 // Region is already allocated 264 // Region is already allocated
264 return ERR_INVALID_ADDRESS_STATE; 265 return ERR_INVALID_ADDRESS_STATE;
265 } 266 }
266 267
267 u64 start_in_vma = base - vma.base; 268 const VAddr start_in_vma = base - vma.base;
268 u64 end_in_vma = start_in_vma + size; 269 const VAddr end_in_vma = start_in_vma + size;
269 270
270 if (end_in_vma > vma.size) { 271 if (end_in_vma > vma.size) {
271 // Requested allocation doesn't fit inside VMA 272 // Requested allocation doesn't fit inside VMA
@@ -288,17 +289,16 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
288 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size); 289 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x{:016X}", size);
289 ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", target); 290 ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x{:016X}", target);
290 291
291 VAddr target_end = target + size; 292 const VAddr target_end = target + size;
292 ASSERT(target_end >= target); 293 ASSERT(target_end >= target);
293 ASSERT(target_end <= MAX_ADDRESS); 294 ASSERT(target_end <= MAX_ADDRESS);
294 ASSERT(size > 0); 295 ASSERT(size > 0);
295 296
296 VMAIter begin_vma = StripIterConstness(FindVMA(target)); 297 VMAIter begin_vma = StripIterConstness(FindVMA(target));
297 VMAIter i_end = vma_map.lower_bound(target_end); 298 const VMAIter i_end = vma_map.lower_bound(target_end);
298 for (auto i = begin_vma; i != i_end; ++i) { 299 if (std::any_of(begin_vma, i_end,
299 if (i->second.type == VMAType::Free) { 300 [](const auto& entry) { return entry.second.type == VMAType::Free; })) {
300 return ERR_INVALID_ADDRESS_STATE; 301 return ERR_INVALID_ADDRESS_STATE;
301 }
302 } 302 }
303 303
304 if (target != begin_vma->second.base) { 304 if (target != begin_vma->second.base) {
@@ -346,7 +346,7 @@ VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u64 offset_in_vma) {
346} 346}
347 347
348VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { 348VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
349 VMAIter next_vma = std::next(iter); 349 const VMAIter next_vma = std::next(iter);
350 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) { 350 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
351 iter->second.size += next_vma->second.size; 351 iter->second.size += next_vma->second.size;
352 vma_map.erase(next_vma); 352 vma_map.erase(next_vma);
@@ -382,22 +382,22 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
382 } 382 }
383} 383}
384 384
385u64 VMManager::GetTotalMemoryUsage() { 385u64 VMManager::GetTotalMemoryUsage() const {
386 LOG_WARNING(Kernel, "(STUBBED) called"); 386 LOG_WARNING(Kernel, "(STUBBED) called");
387 return 0xF8000000; 387 return 0xF8000000;
388} 388}
389 389
390u64 VMManager::GetTotalHeapUsage() { 390u64 VMManager::GetTotalHeapUsage() const {
391 LOG_WARNING(Kernel, "(STUBBED) called"); 391 LOG_WARNING(Kernel, "(STUBBED) called");
392 return 0x0; 392 return 0x0;
393} 393}
394 394
395VAddr VMManager::GetAddressSpaceBaseAddr() { 395VAddr VMManager::GetAddressSpaceBaseAddr() const {
396 LOG_WARNING(Kernel, "(STUBBED) called"); 396 LOG_WARNING(Kernel, "(STUBBED) called");
397 return 0x8000000; 397 return 0x8000000;
398} 398}
399 399
400u64 VMManager::GetAddressSpaceSize() { 400u64 VMManager::GetAddressSpaceSize() const {
401 LOG_WARNING(Kernel, "(STUBBED) called"); 401 LOG_WARNING(Kernel, "(STUBBED) called");
402 return MAX_ADDRESS; 402 return MAX_ADDRESS;
403} 403}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 38e4ebcd3..98bd04bea 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -190,16 +190,16 @@ public:
190 void LogLayout() const; 190 void LogLayout() const;
191 191
192 /// Gets the total memory usage, used by svcGetInfo 192 /// Gets the total memory usage, used by svcGetInfo
193 u64 GetTotalMemoryUsage(); 193 u64 GetTotalMemoryUsage() const;
194 194
195 /// Gets the total heap usage, used by svcGetInfo 195 /// Gets the total heap usage, used by svcGetInfo
196 u64 GetTotalHeapUsage(); 196 u64 GetTotalHeapUsage() const;
197 197
198 /// Gets the total address space base address, used by svcGetInfo 198 /// Gets the total address space base address, used by svcGetInfo
199 VAddr GetAddressSpaceBaseAddr(); 199 VAddr GetAddressSpaceBaseAddr() const;
200 200
201 /// Gets the total address space address size, used by svcGetInfo 201 /// Gets the total address space address size, used by svcGetInfo
202 u64 GetAddressSpaceSize(); 202 u64 GetAddressSpaceSize() const;
203 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.
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index 23af346d0..7681cdee7 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -5,11 +5,8 @@
5#include <algorithm> 5#include <algorithm>
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/hle/kernel/errors.h" 8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/memory.h"
11#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
12#include "core/hle/kernel/resource_limit.h"
13#include "core/hle/kernel/thread.h" 10#include "core/hle/kernel/thread.h"
14#include "core/hle/kernel/timer.h" 11#include "core/hle/kernel/timer.h"
15 12
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index 78bfd8c6c..b5fbc647b 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -7,7 +7,7 @@
7#include <vector> 7#include <vector>
8#include <boost/smart_ptr/intrusive_ptr.hpp> 8#include <boost/smart_ptr/intrusive_ptr.hpp>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/object.h"
11 11
12namespace Kernel { 12namespace Kernel {
13 13
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 0b158e015..6d15b46ed 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -10,6 +10,7 @@
10#include "core/hle/service/acc/acc_su.h" 10#include "core/hle/service/acc/acc_su.h"
11#include "core/hle/service/acc/acc_u0.h" 11#include "core/hle/service/acc/acc_u0.h"
12#include "core/hle/service/acc/acc_u1.h" 12#include "core/hle/service/acc/acc_u1.h"
13#include "core/settings.h"
13 14
14namespace Service::Account { 15namespace Service::Account {
15 16
@@ -31,13 +32,14 @@ struct ProfileBase {
31}; 32};
32static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size"); 33static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase structure has incorrect size");
33 34
35// TODO(ogniK): Generate a real user id based on username, md5(username) maybe?
34static constexpr u128 DEFAULT_USER_ID{1ull, 0ull}; 36static constexpr u128 DEFAULT_USER_ID{1ull, 0ull};
35 37
36class IProfile final : public ServiceFramework<IProfile> { 38class IProfile final : public ServiceFramework<IProfile> {
37public: 39public:
38 explicit IProfile(u128 user_id) : ServiceFramework("IProfile"), user_id(user_id) { 40 explicit IProfile(u128 user_id) : ServiceFramework("IProfile"), user_id(user_id) {
39 static const FunctionInfo functions[] = { 41 static const FunctionInfo functions[] = {
40 {0, nullptr, "Get"}, 42 {0, &IProfile::Get, "Get"},
41 {1, &IProfile::GetBase, "GetBase"}, 43 {1, &IProfile::GetBase, "GetBase"},
42 {10, nullptr, "GetImageSize"}, 44 {10, nullptr, "GetImageSize"},
43 {11, nullptr, "LoadImage"}, 45 {11, nullptr, "LoadImage"},
@@ -46,14 +48,36 @@ public:
46 } 48 }
47 49
48private: 50private:
51 void Get(Kernel::HLERequestContext& ctx) {
52 LOG_WARNING(Service_ACC, "(STUBBED) called");
53 ProfileBase profile_base{};
54 profile_base.user_id = user_id;
55 if (Settings::values.username.size() > profile_base.username.size()) {
56 std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
57 profile_base.username.begin());
58 } else {
59 std::copy(Settings::values.username.begin(), Settings::values.username.end(),
60 profile_base.username.begin());
61 }
62
63 IPC::ResponseBuilder rb{ctx, 16};
64 rb.Push(RESULT_SUCCESS);
65 rb.PushRaw(profile_base);
66 }
67
49 void GetBase(Kernel::HLERequestContext& ctx) { 68 void GetBase(Kernel::HLERequestContext& ctx) {
50 LOG_WARNING(Service_ACC, "(STUBBED) called"); 69 LOG_WARNING(Service_ACC, "(STUBBED) called");
51 70
52 // TODO(Subv): Retrieve this information from somewhere. 71 // TODO(Subv): Retrieve this information from somewhere.
53 ProfileBase profile_base{}; 72 ProfileBase profile_base{};
54 profile_base.user_id = user_id; 73 profile_base.user_id = user_id;
55 profile_base.username = {'y', 'u', 'z', 'u'}; 74 if (Settings::values.username.size() > profile_base.username.size()) {
56 75 std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
76 profile_base.username.begin());
77 } else {
78 std::copy(Settings::values.username.begin(), Settings::values.username.end(),
79 profile_base.username.begin());
80 }
57 IPC::ResponseBuilder rb{ctx, 16}; 81 IPC::ResponseBuilder rb{ctx, 16};
58 rb.Push(RESULT_SUCCESS); 82 rb.Push(RESULT_SUCCESS);
59 rb.PushRaw(profile_base); 83 rb.PushRaw(profile_base);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 97ef07bf9..9404d6b8c 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -11,6 +11,9 @@
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applet_ae.h" 12#include "core/hle/service/am/applet_ae.h"
13#include "core/hle/service/am/applet_oe.h" 13#include "core/hle/service/am/applet_oe.h"
14#include "core/hle/service/am/idle.h"
15#include "core/hle/service/am/omm.h"
16#include "core/hle/service/am/spsm.h"
14#include "core/hle/service/apm/apm.h" 17#include "core/hle/service/apm/apm.h"
15#include "core/hle/service/filesystem/filesystem.h" 18#include "core/hle/service/filesystem/filesystem.h"
16#include "core/hle/service/nvflinger/nvflinger.h" 19#include "core/hle/service/nvflinger/nvflinger.h"
@@ -649,7 +652,8 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
649 // TODO(bunnei): This should be configurable 652 // TODO(bunnei): This should be configurable
650 IPC::ResponseBuilder rb{ctx, 4}; 653 IPC::ResponseBuilder rb{ctx, 4};
651 rb.Push(RESULT_SUCCESS); 654 rb.Push(RESULT_SUCCESS);
652 rb.Push(static_cast<u64>(Service::Set::LanguageCode::EN_US)); 655 rb.Push(
656 static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
653 LOG_DEBUG(Service_AM, "called"); 657 LOG_DEBUG(Service_AM, "called");
654} 658}
655 659
@@ -689,6 +693,9 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
689 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { 693 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
690 std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager); 694 std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
691 std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager); 695 std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
696 std::make_shared<IdleSys>()->InstallAsService(service_manager);
697 std::make_shared<OMM>()->InstallAsService(service_manager);
698 std::make_shared<SPSM>()->InstallAsService(service_manager);
692} 699}
693 700
694IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") { 701IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") {
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp
new file mode 100644
index 000000000..af46e9494
--- /dev/null
+++ b/src/core/hle/service/am/idle.cpp
@@ -0,0 +1,24 @@
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/am/idle.h"
6
7namespace Service::AM {
8
9IdleSys::IdleSys() : ServiceFramework{"idle:sys"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetAutoPowerDownEvent"},
13 {1, nullptr, "Unknown1"},
14 {2, nullptr, "Unknown2"},
15 {3, nullptr, "Unknown3"},
16 {4, nullptr, "Unknown4"},
17 {5, nullptr, "Unknown5"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22}
23
24} // namespace Service::AM
diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h
new file mode 100644
index 000000000..1eb68d2c9
--- /dev/null
+++ b/src/core/hle/service/am/idle.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::AM {
10
11class IdleSys final : public ServiceFramework<IdleSys> {
12public:
13 explicit IdleSys();
14};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp
new file mode 100644
index 000000000..447fe8669
--- /dev/null
+++ b/src/core/hle/service/am/omm.cpp
@@ -0,0 +1,42 @@
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/am/omm.h"
6
7namespace Service::AM {
8
9OMM::OMM() : ServiceFramework{"omm"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetOperationMode"},
13 {1, nullptr, "GetOperationModeChangeEvent"},
14 {2, nullptr, "EnableAudioVisual"},
15 {3, nullptr, "DisableAudioVisual"},
16 {4, nullptr, "EnterSleepAndWait"},
17 {5, nullptr, "GetCradleStatus"},
18 {6, nullptr, "FadeInDisplay"},
19 {7, nullptr, "FadeOutDisplay"},
20 {8, nullptr, "Unknown1"},
21 {9, nullptr, "Unknown2"},
22 {10, nullptr, "Unknown3"},
23 {11, nullptr, "Unknown4"},
24 {12, nullptr, "Unknown5"},
25 {13, nullptr, "Unknown6"},
26 {14, nullptr, "Unknown7"},
27 {15, nullptr, "Unknown8"},
28 {16, nullptr, "Unknown9"},
29 {17, nullptr, "Unknown10"},
30 {18, nullptr, "Unknown11"},
31 {19, nullptr, "Unknown12"},
32 {20, nullptr, "Unknown13"},
33 {21, nullptr, "Unknown14"},
34 {22, nullptr, "Unknown15"},
35 {23, nullptr, "Unknown16"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40}
41
42} // namespace Service::AM
diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h
new file mode 100644
index 000000000..49e5d331c
--- /dev/null
+++ b/src/core/hle/service/am/omm.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::AM {
10
11class OMM final : public ServiceFramework<OMM> {
12public:
13 explicit OMM();
14};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp
new file mode 100644
index 000000000..a05d433d0
--- /dev/null
+++ b/src/core/hle/service/am/spsm.cpp
@@ -0,0 +1,30 @@
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/am/spsm.h"
6
7namespace Service::AM {
8
9SPSM::SPSM() : ServiceFramework{"spsm"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetState"},
13 {1, nullptr, "SleepSystemAndWaitAwake"},
14 {2, nullptr, "Unknown1"},
15 {3, nullptr, "Unknown2"},
16 {4, nullptr, "GetNotificationMessageEventHandle"},
17 {5, nullptr, "Unknown3"},
18 {6, nullptr, "Unknown4"},
19 {7, nullptr, "Unknown5"},
20 {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"},
21 {9, nullptr, "ChangeHomeButtonLongPressingTime"},
22 {10, nullptr, "Unknown6"},
23 {11, nullptr, "Unknown7"},
24 };
25 // clang-format on
26
27 RegisterHandlers(functions);
28}
29
30} // namespace Service::AM
diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h
new file mode 100644
index 000000000..57dde62e1
--- /dev/null
+++ b/src/core/hle/service/am/spsm.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::AM {
10
11class SPSM final : public ServiceFramework<SPSM> {
12public:
13 explicit SPSM();
14};
15
16} // namespace Service::AM
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index 7a185c6c8..4109cb7f7 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -13,6 +13,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
13 auto module_ = std::make_shared<Module>(); 13 auto module_ = std::make_shared<Module>();
14 std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); 14 std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager);
15 std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager); 15 std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager);
16 std::make_shared<APM_Sys>()->InstallAsService(service_manager);
16} 17}
17 18
18} // namespace Service::APM 19} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index ce943d829..4cd8132f5 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -74,6 +74,31 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
74 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 74 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
75 rb.Push(RESULT_SUCCESS); 75 rb.Push(RESULT_SUCCESS);
76 rb.PushIpcInterface<ISession>(); 76 rb.PushIpcInterface<ISession>();
77
78 LOG_DEBUG(Service_APM, "called");
79}
80
81APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
82 // clang-format off
83 static const FunctionInfo functions[] = {
84 {0, nullptr, "RequestPerformanceMode"},
85 {1, &APM_Sys::GetPerformanceEvent, "GetPerformanceEvent"},
86 {2, nullptr, "GetThrottlingState"},
87 {3, nullptr, "GetLastThrottlingState"},
88 {4, nullptr, "ClearLastThrottlingState"},
89 {5, nullptr, "LoadAndApplySettings"},
90 };
91 // clang-format on
92
93 RegisterHandlers(functions);
94}
95
96void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
97 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
98 rb.Push(RESULT_SUCCESS);
99 rb.PushIpcInterface<ISession>();
100
101 LOG_DEBUG(Service_APM, "called");
77} 102}
78 103
79} // namespace Service::APM 104} // namespace Service::APM
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index fa68c7d93..d14264ad7 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -19,4 +19,12 @@ private:
19 std::shared_ptr<Module> apm; 19 std::shared_ptr<Module> apm;
20}; 20};
21 21
22class APM_Sys final : public ServiceFramework<APM_Sys> {
23public:
24 explicit APM_Sys();
25
26private:
27 void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
28};
29
22} // namespace Service::APM 30} // namespace Service::APM
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp
new file mode 100644
index 000000000..358ef2576
--- /dev/null
+++ b/src/core/hle/service/arp/arp.cpp
@@ -0,0 +1,75 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/arp/arp.h"
11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13
14namespace Service::ARP {
15
16class ARP_R final : public ServiceFramework<ARP_R> {
17public:
18 explicit ARP_R() : ServiceFramework{"arp:r"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, nullptr, "GetApplicationLaunchProperty"},
22 {1, nullptr, "GetApplicationLaunchPropertyWithApplicationId"},
23 {2, nullptr, "GetApplicationControlProperty"},
24 {3, nullptr, "GetApplicationControlPropertyWithApplicationId"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29 }
30};
31
32class IRegistrar final : public ServiceFramework<IRegistrar> {
33public:
34 explicit IRegistrar() : ServiceFramework{"IRegistrar"} {
35 // clang-format off
36 static const FunctionInfo functions[] = {
37 {0, nullptr, "Issue"},
38 {1, nullptr, "SetApplicationLaunchProperty"},
39 {2, nullptr, "SetApplicationControlProperty"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44 }
45};
46
47class ARP_W final : public ServiceFramework<ARP_W> {
48public:
49 explicit ARP_W() : ServiceFramework{"arp:w"} {
50 // clang-format off
51 static const FunctionInfo functions[] = {
52 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
53 {1, nullptr, "DeleteProperties"},
54 };
55 // clang-format on
56
57 RegisterHandlers(functions);
58 }
59
60private:
61 void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
62 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
63 rb.Push(RESULT_SUCCESS);
64 rb.PushIpcInterface<IRegistrar>();
65
66 LOG_DEBUG(Service_ARP, "called");
67 }
68};
69
70void InstallInterfaces(SM::ServiceManager& sm) {
71 std::make_shared<ARP_R>()->InstallAsService(sm);
72 std::make_shared<ARP_W>()->InstallAsService(sm);
73}
74
75} // namespace Service::ARP
diff --git a/src/core/hle/service/arp/arp.h b/src/core/hle/service/arp/arp.h
new file mode 100644
index 000000000..9d100187c
--- /dev/null
+++ b/src/core/hle/service/arp/arp.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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::ARP {
12
13/// Registers all ARP services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm);
15
16} // namespace Service::ARP
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
new file mode 100644
index 000000000..37c3fdcac
--- /dev/null
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -0,0 +1,45 @@
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/audio/audctl.h"
6
7namespace Service::Audio {
8
9AudCtl::AudCtl() : ServiceFramework{"audctl"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetTargetVolume"},
13 {1, nullptr, "SetTargetVolume"},
14 {2, nullptr, "GetTargetVolumeMin"},
15 {3, nullptr, "GetTargetVolumeMax"},
16 {4, nullptr, "IsTargetMute"},
17 {5, nullptr, "SetTargetMute"},
18 {6, nullptr, "IsTargetConnected"},
19 {7, nullptr, "SetDefaultTarget"},
20 {8, nullptr, "GetDefaultTarget"},
21 {9, nullptr, "GetAudioOutputMode"},
22 {10, nullptr, "SetAudioOutputMode"},
23 {11, nullptr, "SetForceMutePolicy"},
24 {12, nullptr, "GetForceMutePolicy"},
25 {13, nullptr, "GetOutputModeSetting"},
26 {14, nullptr, "SetOutputModeSetting"},
27 {15, nullptr, "SetOutputTarget"},
28 {16, nullptr, "SetInputTargetForceEnabled"},
29 {17, nullptr, "SetHeadphoneOutputLevelMode"},
30 {18, nullptr, "GetHeadphoneOutputLevelMode"},
31 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
32 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
33 {21, nullptr, "GetAudioOutputTargetForPlayReport"},
34 {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
35 {23, nullptr, "SetSystemOutputMasterVolume"},
36 {24, nullptr, "GetSystemOutputMasterVolume"},
37 {25, nullptr, "GetAudioVolumeDataForPlayReport"},
38 {26, nullptr, "UpdateHeadphoneSettings"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43}
44
45} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h
new file mode 100644
index 000000000..ed837bdf2
--- /dev/null
+++ b/src/core/hle/service/audio/audctl.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::Audio {
10
11class AudCtl final : public ServiceFramework<AudCtl> {
12public:
13 explicit AudCtl();
14};
15
16} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp
new file mode 100644
index 000000000..b08c21a20
--- /dev/null
+++ b/src/core/hle/service/audio/auddbg.cpp
@@ -0,0 +1,20 @@
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/audio/auddbg.h"
6
7namespace Service::Audio {
8
9AudDbg::AudDbg(const char* name) : ServiceFramework{name} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendForDebug"},
13 {1, nullptr, "RequestResumeForDebug"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h
new file mode 100644
index 000000000..a2f540b75
--- /dev/null
+++ b/src/core/hle/service/audio/auddbg.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::Audio {
10
11class AudDbg final : public ServiceFramework<AudDbg> {
12public:
13 explicit AudDbg(const char* name);
14};
15
16} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
new file mode 100644
index 000000000..a70d5bca4
--- /dev/null
+++ b/src/core/hle/service/audio/audin_a.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/audio/audin_a.h"
6
7namespace Service::Audio {
8
9AudInA::AudInA() : ServiceFramework{"audin:a"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioIns"},
13 {1, nullptr, "RequestResumeAudioIns"},
14 {2, nullptr, "GetAudioInsProcessMasterVolume"},
15 {3, nullptr, "SetAudioInsProcessMasterVolume"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h
new file mode 100644
index 000000000..e4c75510f
--- /dev/null
+++ b/src/core/hle/service/audio/audin_a.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::Audio {
10
11class AudInA final : public ServiceFramework<AudInA> {
12public:
13 explicit AudInA();
14};
15
16} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index d231e91e1..6b5e15633 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,10 +2,16 @@
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 "core/hle/service/audio/audctl.h"
6#include "core/hle/service/audio/auddbg.h"
7#include "core/hle/service/audio/audin_a.h"
5#include "core/hle/service/audio/audin_u.h" 8#include "core/hle/service/audio/audin_u.h"
6#include "core/hle/service/audio/audio.h" 9#include "core/hle/service/audio/audio.h"
10#include "core/hle/service/audio/audout_a.h"
7#include "core/hle/service/audio/audout_u.h" 11#include "core/hle/service/audio/audout_u.h"
12#include "core/hle/service/audio/audrec_a.h"
8#include "core/hle/service/audio/audrec_u.h" 13#include "core/hle/service/audio/audrec_u.h"
14#include "core/hle/service/audio/audren_a.h"
9#include "core/hle/service/audio/audren_u.h" 15#include "core/hle/service/audio/audren_u.h"
10#include "core/hle/service/audio/codecctl.h" 16#include "core/hle/service/audio/codecctl.h"
11#include "core/hle/service/audio/hwopus.h" 17#include "core/hle/service/audio/hwopus.h"
@@ -13,12 +19,22 @@
13namespace Service::Audio { 19namespace Service::Audio {
14 20
15void InstallInterfaces(SM::ServiceManager& service_manager) { 21void InstallInterfaces(SM::ServiceManager& service_manager) {
22 std::make_shared<AudCtl>()->InstallAsService(service_manager);
23 std::make_shared<AudOutA>()->InstallAsService(service_manager);
16 std::make_shared<AudOutU>()->InstallAsService(service_manager); 24 std::make_shared<AudOutU>()->InstallAsService(service_manager);
25 std::make_shared<AudInA>()->InstallAsService(service_manager);
17 std::make_shared<AudInU>()->InstallAsService(service_manager); 26 std::make_shared<AudInU>()->InstallAsService(service_manager);
27 std::make_shared<AudRecA>()->InstallAsService(service_manager);
18 std::make_shared<AudRecU>()->InstallAsService(service_manager); 28 std::make_shared<AudRecU>()->InstallAsService(service_manager);
29 std::make_shared<AudRenA>()->InstallAsService(service_manager);
19 std::make_shared<AudRenU>()->InstallAsService(service_manager); 30 std::make_shared<AudRenU>()->InstallAsService(service_manager);
20 std::make_shared<CodecCtl>()->InstallAsService(service_manager); 31 std::make_shared<CodecCtl>()->InstallAsService(service_manager);
21 std::make_shared<HwOpus>()->InstallAsService(service_manager); 32 std::make_shared<HwOpus>()->InstallAsService(service_manager);
33
34 std::make_shared<AudDbg>("audin:d")->InstallAsService(service_manager);
35 std::make_shared<AudDbg>("audout:d")->InstallAsService(service_manager);
36 std::make_shared<AudDbg>("audrec:d")->InstallAsService(service_manager);
37 std::make_shared<AudDbg>("audren:d")->InstallAsService(service_manager);
22} 38}
23 39
24} // namespace Service::Audio 40} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
new file mode 100644
index 000000000..bf8d40157
--- /dev/null
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -0,0 +1,24 @@
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/audio/audout_a.h"
6
7namespace Service::Audio {
8
9AudOutA::AudOutA() : ServiceFramework{"audout:a"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioOuts"},
13 {1, nullptr, "RequestResumeAudioOuts"},
14 {2, nullptr, "GetAudioOutsProcessMasterVolume"},
15 {3, nullptr, "SetAudioOutsProcessMasterVolume"},
16 {4, nullptr, "GetAudioOutsProcessRecordVolume"},
17 {5, nullptr, "SetAudioOutsProcessRecordVolume"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22}
23
24} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h
new file mode 100644
index 000000000..91a069152
--- /dev/null
+++ b/src/core/hle/service/audio/audout_a.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::Audio {
10
11class AudOutA final : public ServiceFramework<AudOutA> {
12public:
13 explicit AudOutA();
14};
15
16} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 1dcd84d98..108a7c6eb 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -4,9 +4,10 @@
4 4
5#include <array> 5#include <array>
6#include <vector> 6#include <vector>
7
8#include "audio_core/codec.h"
7#include "common/logging/log.h" 9#include "common/logging/log.h"
8#include "core/core_timing.h" 10#include "core/core.h"
9#include "core/core_timing_util.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/event.h" 12#include "core/hle/kernel/event.h"
12#include "core/hle/kernel/hle_ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
@@ -14,17 +15,21 @@
14 15
15namespace Service::Audio { 16namespace Service::Audio {
16 17
17/// Switch sample rate frequency 18namespace ErrCodes {
18constexpr u32 sample_rate{48000}; 19enum {
19/// TODO(st4rk): dynamic number of channels, as I think Switch has support 20 ErrorUnknown = 2,
20/// to more audio channels (probably when Docked I guess) 21 BufferCountExceeded = 8,
21constexpr u32 audio_channels{2}; 22};
22/// TODO(st4rk): find a proper value for the audio_ticks 23}
23constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 500)}; 24
25constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
26constexpr int DefaultSampleRate{48000};
24 27
25class IAudioOut final : public ServiceFramework<IAudioOut> { 28class IAudioOut final : public ServiceFramework<IAudioOut> {
26public: 29public:
27 IAudioOut() : ServiceFramework("IAudioOut"), audio_out_state(AudioState::Stopped) { 30 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
31 : ServiceFramework("IAudioOut"), audio_params(audio_params), audio_core(audio_core) {
32
28 static const FunctionInfo functions[] = { 33 static const FunctionInfo functions[] = {
29 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 34 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
30 {1, &IAudioOut::StartAudioOut, "StartAudioOut"}, 35 {1, &IAudioOut::StartAudioOut, "StartAudioOut"},
@@ -32,66 +37,65 @@ public:
32 {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"}, 37 {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
33 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, 38 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
34 {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"}, 39 {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
35 {6, nullptr, "ContainsAudioOutBuffer"}, 40 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
36 {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"}, 41 {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
37 {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"}, 42 {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
38 {9, nullptr, "GetAudioOutBufferCount"}, 43 {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
39 {10, nullptr, "GetAudioOutPlayedSampleCount"}, 44 {10, nullptr, "GetAudioOutPlayedSampleCount"},
40 {11, nullptr, "FlushAudioOutBuffers"}, 45 {11, nullptr, "FlushAudioOutBuffers"},
41 }; 46 };
42 RegisterHandlers(functions); 47 RegisterHandlers(functions);
43 48
44 // This is the event handle used to check if the audio buffer was released 49 // This is the event handle used to check if the audio buffer was released
45 buffer_event = 50 buffer_event = Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
46 Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioOutBufferReleasedEvent");
47
48 // Register event callback to update the Audio Buffer
49 audio_event = CoreTiming::RegisterEvent(
50 "IAudioOut::UpdateAudioBuffersCallback", [this](u64 userdata, int cycles_late) {
51 UpdateAudioBuffersCallback();
52 CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
53 });
54
55 // Start the audio event
56 CoreTiming::ScheduleEvent(audio_ticks, audio_event);
57 }
58 51
59 ~IAudioOut() { 52 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
60 CoreTiming::UnscheduleEvent(audio_event, 0); 53 "IAudioOut", [=]() { buffer_event->Signal(); });
61 } 54 }
62 55
63private: 56private:
57 struct AudioBuffer {
58 u64_le next;
59 u64_le buffer;
60 u64_le buffer_capacity;
61 u64_le buffer_size;
62 u64_le offset;
63 };
64 static_assert(sizeof(AudioBuffer) == 0x28, "AudioBuffer is an invalid size");
65
64 void GetAudioOutState(Kernel::HLERequestContext& ctx) { 66 void GetAudioOutState(Kernel::HLERequestContext& ctx) {
65 LOG_DEBUG(Service_Audio, "called"); 67 LOG_DEBUG(Service_Audio, "called");
66 IPC::ResponseBuilder rb{ctx, 3}; 68 IPC::ResponseBuilder rb{ctx, 3};
67 rb.Push(RESULT_SUCCESS); 69 rb.Push(RESULT_SUCCESS);
68 rb.Push(static_cast<u32>(audio_out_state)); 70 rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
69 } 71 }
70 72
71 void StartAudioOut(Kernel::HLERequestContext& ctx) { 73 void StartAudioOut(Kernel::HLERequestContext& ctx) {
72 LOG_WARNING(Service_Audio, "(STUBBED) called"); 74 LOG_DEBUG(Service_Audio, "called");
73 75
74 // Start audio 76 if (stream->IsPlaying()) {
75 audio_out_state = AudioState::Started; 77 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown));
79 return;
80 }
81
82 audio_core.StartStream(stream);
76 83
77 IPC::ResponseBuilder rb{ctx, 2}; 84 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(RESULT_SUCCESS); 85 rb.Push(RESULT_SUCCESS);
79 } 86 }
80 87
81 void StopAudioOut(Kernel::HLERequestContext& ctx) { 88 void StopAudioOut(Kernel::HLERequestContext& ctx) {
82 LOG_WARNING(Service_Audio, "(STUBBED) called"); 89 LOG_DEBUG(Service_Audio, "called");
83
84 // Stop audio
85 audio_out_state = AudioState::Stopped;
86 90
87 queue_keys.clear(); 91 audio_core.StopStream(stream);
88 92
89 IPC::ResponseBuilder rb{ctx, 2}; 93 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
91 } 95 }
92 96
93 void RegisterBufferEvent(Kernel::HLERequestContext& ctx) { 97 void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
94 LOG_WARNING(Service_Audio, "(STUBBED) called"); 98 LOG_DEBUG(Service_Audio, "called");
95 99
96 IPC::ResponseBuilder rb{ctx, 2, 1}; 100 IPC::ResponseBuilder rb{ctx, 2, 1};
97 rb.Push(RESULT_SUCCESS); 101 rb.Push(RESULT_SUCCESS);
@@ -99,101 +103,107 @@ private:
99 } 103 }
100 104
101 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 105 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
102 LOG_WARNING(Service_Audio, "(STUBBED) called"); 106 LOG_DEBUG(Service_Audio, "(STUBBED) called {}", ctx.Description());
103 IPC::RequestParser rp{ctx}; 107 IPC::RequestParser rp{ctx};
104 108
105 const u64 key{rp.Pop<u64>()}; 109 const auto& input_buffer{ctx.ReadBuffer()};
106 queue_keys.insert(queue_keys.begin(), key); 110 ASSERT_MSG(input_buffer.size() == sizeof(AudioBuffer),
111 "AudioBuffer input is an invalid size!");
112 AudioBuffer audio_buffer{};
113 std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer));
114 const u64 tag{rp.Pop<u64>()};
115
116 std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
117 Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
118
119 if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
120 IPC::ResponseBuilder rb{ctx, 2};
121 rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded));
122 }
107 123
108 IPC::ResponseBuilder rb{ctx, 2}; 124 IPC::ResponseBuilder rb{ctx, 2};
109 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
110 } 126 }
111 127
112 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 128 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
113 LOG_WARNING(Service_Audio, "(STUBBED) called"); 129 LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
114 130 IPC::RequestParser rp{ctx};
115 // TODO(st4rk): This is how libtransistor currently implements the 131 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
116 // GetReleasedAudioOutBuffer, it should return the key (a VAddr) to the app and this address 132 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
117 // is used to know which buffer should be filled with data and send again to the service
118 // through AppendAudioOutBuffer. Check if this is the proper way to do it.
119 u64 key{0};
120
121 if (queue_keys.size()) {
122 key = queue_keys.back();
123 queue_keys.pop_back();
124 }
125 133
126 ctx.WriteBuffer(&key, sizeof(u64)); 134 std::vector<u64> tags{released_buffers};
135 tags.resize(max_count);
136 ctx.WriteBuffer(tags);
127 137
128 IPC::ResponseBuilder rb{ctx, 3}; 138 IPC::ResponseBuilder rb{ctx, 3};
129 rb.Push(RESULT_SUCCESS); 139 rb.Push(RESULT_SUCCESS);
130 // TODO(st4rk): This might be the total of released buffers, needs to be verified on 140 rb.Push<u32>(static_cast<u32>(released_buffers.size()));
131 // hardware
132 rb.Push<u32>(static_cast<u32>(queue_keys.size()));
133 } 141 }
134 142
135 void UpdateAudioBuffersCallback() { 143 void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
136 if (audio_out_state != AudioState::Started) { 144 LOG_DEBUG(Service_Audio, "called");
137 return; 145 IPC::RequestParser rp{ctx};
138 } 146 const u64 tag{rp.Pop<u64>()};
139 147 IPC::ResponseBuilder rb{ctx, 3};
140 if (queue_keys.empty()) { 148 rb.Push(RESULT_SUCCESS);
141 return; 149 rb.Push(stream->ContainsBuffer(tag));
142 } 150 }
143 151
144 buffer_event->Signal(); 152 void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
153 LOG_DEBUG(Service_Audio, "called");
154 IPC::ResponseBuilder rb{ctx, 3};
155 rb.Push(RESULT_SUCCESS);
156 rb.Push(static_cast<u32>(stream->GetQueueSize()));
145 } 157 }
146 158
147 enum class AudioState : u32 { 159 AudioCore::AudioOut& audio_core;
148 Started, 160 AudioCore::StreamPtr stream;
149 Stopped,
150 };
151 161
152 /// This is used to trigger the audio event callback that is going to read the samples from the 162 AudoutParams audio_params{};
153 /// audio_buffer list and enqueue the samples using the sink (audio_core).
154 CoreTiming::EventType* audio_event;
155 163
156 /// This is the evend handle used to check if the audio buffer was released 164 /// This is the evend handle used to check if the audio buffer was released
157 Kernel::SharedPtr<Kernel::Event> buffer_event; 165 Kernel::SharedPtr<Kernel::Event> buffer_event;
158
159 /// (st4rk): This is just a temporary workaround for the future implementation. Libtransistor
160 /// uses the key as an address in the App, so we need to return when the
161 /// GetReleasedAudioOutBuffer_1 is called, otherwise we'll run in problems, because
162 /// libtransistor uses the key returned as an pointer.
163 std::vector<u64> queue_keys;
164
165 AudioState audio_out_state;
166}; 166};
167 167
168void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { 168void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
169 LOG_WARNING(Service_Audio, "(STUBBED) called"); 169 LOG_DEBUG(Service_Audio, "called");
170 IPC::RequestParser rp{ctx}; 170 IPC::RequestParser rp{ctx};
171 171
172 constexpr std::array<char, 15> audio_interface{{"AudioInterface"}}; 172 ctx.WriteBuffer(DefaultDevice);
173 ctx.WriteBuffer(audio_interface);
174 173
175 IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0); 174 IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
176 175
177 rb.Push(RESULT_SUCCESS); 176 rb.Push(RESULT_SUCCESS);
178 // TODO(st4rk): We're currently returning only one audio interface (stringlist size). However, 177 rb.Push<u32>(1); // Amount of audio devices
179 // it's highly possible to have more than one interface (despite that libtransistor requires
180 // only one).
181 rb.Push<u32>(1);
182} 178}
183 179
184void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { 180void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
185 LOG_WARNING(Service_Audio, "(STUBBED) called"); 181 LOG_DEBUG(Service_Audio, "called");
186 182
187 if (!audio_out_interface) { 183 ctx.WriteBuffer(DefaultDevice);
188 audio_out_interface = std::make_shared<IAudioOut>(); 184 IPC::RequestParser rp{ctx};
185 auto params{rp.PopRaw<AudoutParams>()};
186 if (params.channel_count <= 2) {
187 // Mono does not exist for audout
188 params.channel_count = 2;
189 } else {
190 params.channel_count = 6;
189 } 191 }
192 if (!params.sample_rate) {
193 params.sample_rate = DefaultSampleRate;
194 }
195
196 // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl
197 // will likely need to be updated as well.
198 ASSERT_MSG(!audio_out_interface, "Unimplemented");
199 audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
190 200
191 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 201 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
192 rb.Push(RESULT_SUCCESS); 202 rb.Push(RESULT_SUCCESS);
193 rb.Push<u32>(sample_rate); 203 rb.Push<u32>(DefaultSampleRate);
194 rb.Push<u32>(audio_channels); 204 rb.Push<u32>(params.channel_count);
195 rb.Push<u32>(static_cast<u32>(PcmFormat::Int16)); 205 rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
196 rb.Push<u32>(0); // This field is unknown 206 rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
197 rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); 207 rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
198} 208}
199 209
@@ -203,6 +213,7 @@ AudOutU::AudOutU() : ServiceFramework("audout:u") {
203 {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"}, 213 {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
204 {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}}; 214 {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}};
205 RegisterHandlers(functions); 215 RegisterHandlers(functions);
216 audio_core = std::make_unique<AudioCore::AudioOut>();
206} 217}
207 218
208} // namespace Service::Audio 219} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index 847d86aa6..fd491f65d 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_out.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Kernel { 10namespace Kernel {
@@ -12,6 +13,18 @@ class HLERequestContext;
12 13
13namespace Service::Audio { 14namespace Service::Audio {
14 15
16struct AudoutParams {
17 s32_le sample_rate;
18 u16_le channel_count;
19 INSERT_PADDING_BYTES(2);
20};
21static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
22
23enum class AudioState : u32 {
24 Started,
25 Stopped,
26};
27
15class IAudioOut; 28class IAudioOut;
16 29
17class AudOutU final : public ServiceFramework<AudOutU> { 30class AudOutU final : public ServiceFramework<AudOutU> {
@@ -21,19 +34,10 @@ public:
21 34
22private: 35private:
23 std::shared_ptr<IAudioOut> audio_out_interface; 36 std::shared_ptr<IAudioOut> audio_out_interface;
37 std::unique_ptr<AudioCore::AudioOut> audio_core;
24 38
25 void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); 39 void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
26 void OpenAudioOutImpl(Kernel::HLERequestContext& ctx); 40 void OpenAudioOutImpl(Kernel::HLERequestContext& ctx);
27
28 enum class PcmFormat : u32 {
29 Invalid = 0,
30 Int8 = 1,
31 Int16 = 2,
32 Int24 = 3,
33 Int32 = 4,
34 PcmFloat = 5,
35 Adpcm = 6,
36 };
37}; 41};
38 42
39} // namespace Service::Audio 43} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
new file mode 100644
index 000000000..016eabf53
--- /dev/null
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -0,0 +1,20 @@
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/audio/audrec_a.h"
6
7namespace Service::Audio {
8
9AudRecA::AudRecA() : ServiceFramework{"audrec:a"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendFinalOutputRecorders"},
13 {1, nullptr, "RequestResumeFinalOutputRecorders"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h
new file mode 100644
index 000000000..9685047f2
--- /dev/null
+++ b/src/core/hle/service/audio/audrec_a.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::Audio {
10
11class AudRecA final : public ServiceFramework<AudRecA> {
12public:
13 explicit AudRecA();
14};
15
16} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
new file mode 100644
index 000000000..616ff3dc4
--- /dev/null
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -0,0 +1,26 @@
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/audio/audren_a.h"
6
7namespace Service::Audio {
8
9AudRenA::AudRenA() : ServiceFramework{"audren:a"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioRenderers"},
13 {1, nullptr, "RequestResumeAudioRenderers"},
14 {2, nullptr, "GetAudioRenderersProcessMasterVolume"},
15 {3, nullptr, "SetAudioRenderersProcessMasterVolume"},
16 {4, nullptr, "RegisterAppletResourceUserId"},
17 {5, nullptr, "UnregisterAppletResourceUserId"},
18 {6, nullptr, "GetAudioRenderersProcessRecordVolume"},
19 {7, nullptr, "SetAudioRenderersProcessRecordVolume"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h
new file mode 100644
index 000000000..5ecf2e184
--- /dev/null
+++ b/src/core/hle/service/audio/audren_a.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::Audio {
10
11class AudRenA final : public ServiceFramework<AudRenA> {
12public:
13 explicit AudRenA();
14};
15
16} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 6aed9e2fa..f99304de5 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -15,13 +15,10 @@
15 15
16namespace Service::Audio { 16namespace Service::Audio {
17 17
18/// TODO(bunnei): Find a proper value for the audio_ticks
19constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
20
21class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { 18class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
22public: 19public:
23 explicit IAudioRenderer(AudioRendererParameter audren_params) 20 explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params)
24 : ServiceFramework("IAudioRenderer"), worker_params(audren_params) { 21 : ServiceFramework("IAudioRenderer") {
25 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
26 {0, nullptr, "GetAudioRendererSampleRate"}, 23 {0, nullptr, "GetAudioRendererSampleRate"},
27 {1, nullptr, "GetAudioRendererSampleCount"}, 24 {1, nullptr, "GetAudioRendererSampleCount"},
@@ -39,21 +36,8 @@ public:
39 RegisterHandlers(functions); 36 RegisterHandlers(functions);
40 37
41 system_event = 38 system_event =
42 Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent"); 39 Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
43 40 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
44 // Register event callback to update the Audio Buffer
45 audio_event = CoreTiming::RegisterEvent(
46 "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
47 UpdateAudioCallback();
48 CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
49 });
50
51 // Start the audio event
52 CoreTiming::ScheduleEvent(audio_ticks, audio_event);
53 voice_status_list.resize(worker_params.voice_count);
54 }
55 ~IAudioRenderer() {
56 CoreTiming::UnscheduleEvent(audio_event, 0);
57 } 41 }
58 42
59private: 43private:
@@ -62,60 +46,9 @@ private:
62 } 46 }
63 47
64 void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { 48 void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
65 UpdateDataHeader config{}; 49 ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
66 auto buf = ctx.ReadBuffer();
67 std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader));
68 u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
69
70 std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
71 std::memcpy(mem_pool_info.data(),
72 buf.data() + sizeof(UpdateDataHeader) + config.behavior_size,
73 memory_pool_count * sizeof(MemoryPoolInfo));
74
75 std::vector<VoiceInfo> voice_info(worker_params.voice_count);
76 std::memcpy(voice_info.data(),
77 buf.data() + sizeof(UpdateDataHeader) + config.behavior_size +
78 config.memory_pools_size + config.voice_resource_size,
79 worker_params.voice_count * sizeof(VoiceInfo));
80
81 UpdateDataHeader response_data{worker_params};
82
83 ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
84
85 std::vector<u8> output(response_data.total_size);
86 std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader));
87 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
88 for (unsigned i = 0; i < memory_pool.size(); i++) {
89 if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach)
90 memory_pool[i].state = MemoryPoolStates::Attached;
91 else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach)
92 memory_pool[i].state = MemoryPoolStates::Detached;
93 }
94 std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(),
95 response_data.memory_pools_size);
96
97 for (unsigned i = 0; i < voice_info.size(); i++) {
98 if (voice_info[i].is_new) {
99 voice_status_list[i].played_sample_count = 0;
100 voice_status_list[i].wave_buffer_consumed = 0;
101 } else if (voice_info[i].play_state == (u8)PlayStates::Started) {
102 for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) {
103 voice_status_list[i].played_sample_count +=
104 (voice_info[i].wave_buffer[buff_idx].end_sample_offset -
105 voice_info[i].wave_buffer[buff_idx].start_sample_offset) /
106 2;
107 voice_status_list[i].wave_buffer_consumed++;
108 }
109 }
110 }
111 std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size,
112 voice_status_list.data(), response_data.voices_size);
113
114 ctx.WriteBuffer(output);
115
116 IPC::ResponseBuilder rb{ctx, 2}; 50 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(RESULT_SUCCESS); 51 rb.Push(RESULT_SUCCESS);
118
119 LOG_WARNING(Service_Audio, "(STUBBED) called"); 52 LOG_WARNING(Service_Audio, "(STUBBED) called");
120 } 53 }
121 54
@@ -136,8 +69,6 @@ private:
136 } 69 }
137 70
138 void QuerySystemEvent(Kernel::HLERequestContext& ctx) { 71 void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
139 // system_event->Signal();
140
141 IPC::ResponseBuilder rb{ctx, 2, 1}; 72 IPC::ResponseBuilder rb{ctx, 2, 1};
142 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
143 rb.PushCopyObjects(system_event); 74 rb.PushCopyObjects(system_event);
@@ -145,131 +76,8 @@ private:
145 LOG_WARNING(Service_Audio, "(STUBBED) called"); 76 LOG_WARNING(Service_Audio, "(STUBBED) called");
146 } 77 }
147 78
148 enum class MemoryPoolStates : u32 { // Should be LE
149 Invalid = 0x0,
150 Unknown = 0x1,
151 RequestDetach = 0x2,
152 Detached = 0x3,
153 RequestAttach = 0x4,
154 Attached = 0x5,
155 Released = 0x6,
156 };
157
158 enum class PlayStates : u8 {
159 Started = 0,
160 Stopped = 1,
161 };
162
163 struct MemoryPoolEntry {
164 MemoryPoolStates state;
165 u32_le unknown_4;
166 u32_le unknown_8;
167 u32_le unknown_c;
168 };
169 static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
170
171 struct MemoryPoolInfo {
172 u64_le pool_address;
173 u64_le pool_size;
174 MemoryPoolStates pool_state;
175 INSERT_PADDING_WORDS(3); // Unknown
176 };
177 static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
178
179 struct UpdateDataHeader {
180 UpdateDataHeader() {}
181
182 explicit UpdateDataHeader(const AudioRendererParameter& config) {
183 revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
184 behavior_size = 0xb0;
185 memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
186 voices_size = config.voice_count * 0x10;
187 voice_resource_size = 0x0;
188 effects_size = config.effect_count * 0x10;
189 mixes_size = 0x0;
190 sinks_size = config.sink_count * 0x20;
191 performance_manager_size = 0x10;
192 total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size +
193 voices_size + effects_size + sinks_size + performance_manager_size;
194 }
195
196 u32_le revision;
197 u32_le behavior_size;
198 u32_le memory_pools_size;
199 u32_le voices_size;
200 u32_le voice_resource_size;
201 u32_le effects_size;
202 u32_le mixes_size;
203 u32_le sinks_size;
204 u32_le performance_manager_size;
205 INSERT_PADDING_WORDS(6);
206 u32_le total_size;
207 };
208 static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
209
210 struct BiquadFilter {
211 u8 enable;
212 INSERT_PADDING_BYTES(1);
213 s16_le numerator[3];
214 s16_le denominator[2];
215 };
216 static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
217
218 struct WaveBuffer {
219 u64_le buffer_addr;
220 u64_le buffer_sz;
221 s32_le start_sample_offset;
222 s32_le end_sample_offset;
223 u8 loop;
224 u8 end_of_stream;
225 u8 sent_to_server;
226 INSERT_PADDING_BYTES(5);
227 u64 context_addr;
228 u64 context_sz;
229 INSERT_PADDING_BYTES(8);
230 };
231 static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
232
233 struct VoiceInfo {
234 u32_le id;
235 u32_le node_id;
236 u8 is_new;
237 u8 is_in_use;
238 u8 play_state;
239 u8 sample_format;
240 u32_le sample_rate;
241 u32_le priority;
242 u32_le sorting_order;
243 u32_le channel_count;
244 float_le pitch;
245 float_le volume;
246 BiquadFilter biquad_filter[2];
247 u32_le wave_buffer_count;
248 u16_le wave_buffer_head;
249 INSERT_PADDING_BYTES(6);
250 u64_le additional_params_addr;
251 u64_le additional_params_sz;
252 u32_le mix_id;
253 u32_le splitter_info_id;
254 WaveBuffer wave_buffer[4];
255 u32_le voice_channel_resource_ids[6];
256 INSERT_PADDING_BYTES(24);
257 };
258 static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
259
260 struct VoiceOutStatus {
261 u64_le played_sample_count;
262 u32_le wave_buffer_consumed;
263 INSERT_PADDING_WORDS(1);
264 };
265 static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
266
267 /// This is used to trigger the audio event callback.
268 CoreTiming::EventType* audio_event;
269
270 Kernel::SharedPtr<Kernel::Event> system_event; 79 Kernel::SharedPtr<Kernel::Event> system_event;
271 AudioRendererParameter worker_params; 80 std::unique_ptr<AudioCore::AudioRenderer> renderer;
272 std::vector<VoiceOutStatus> voice_status_list;
273}; 81};
274 82
275class IAudioDevice final : public ServiceFramework<IAudioDevice> { 83class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -368,7 +176,7 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
368 176
369void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 177void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
370 IPC::RequestParser rp{ctx}; 178 IPC::RequestParser rp{ctx};
371 auto params = rp.PopRaw<AudioRendererParameter>(); 179 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
372 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 180 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
373 181
374 rb.Push(RESULT_SUCCESS); 182 rb.Push(RESULT_SUCCESS);
@@ -379,7 +187,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
379 187
380void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { 188void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
381 IPC::RequestParser rp{ctx}; 189 IPC::RequestParser rp{ctx};
382 auto params = rp.PopRaw<AudioRendererParameter>(); 190 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
383 191
384 u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40); 192 u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
385 buffer_sz += params.unknown_c * 1024; 193 buffer_sz += params.unknown_c * 1024;
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index b9b81db4f..14907f8ae 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_renderer.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Kernel { 10namespace Kernel {
@@ -12,24 +13,6 @@ class HLERequestContext;
12 13
13namespace Service::Audio { 14namespace Service::Audio {
14 15
15struct AudioRendererParameter {
16 u32_le sample_rate;
17 u32_le sample_count;
18 u32_le unknown_8;
19 u32_le unknown_c;
20 u32_le voice_count;
21 u32_le sink_count;
22 u32_le effect_count;
23 u32_le unknown_1c;
24 u8 unknown_20;
25 INSERT_PADDING_BYTES(3);
26 u32_le splitter_count;
27 u32_le unknown_2c;
28 INSERT_PADDING_WORDS(1);
29 u32_le revision;
30};
31static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
32
33class AudRenU final : public ServiceFramework<AudRenU> { 16class AudRenU final : public ServiceFramework<AudRenU> {
34public: 17public:
35 explicit AudRenU(); 18 explicit AudRenU();
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 844df382c..371cd4997 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include <opus.h>
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
@@ -9,19 +11,142 @@
9 11
10namespace Service::Audio { 12namespace Service::Audio {
11 13
14struct OpusDeleter {
15 void operator()(void* ptr) const {
16 operator delete(ptr);
17 }
18};
19
20class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
21public:
22 IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoder, OpusDeleter> decoder, u32 sample_rate,
23 u32 channel_count)
24 : ServiceFramework("IHardwareOpusDecoderManager"), decoder(std::move(decoder)),
25 sample_rate(sample_rate), channel_count(channel_count) {
26 static const FunctionInfo functions[] = {
27 {0, &IHardwareOpusDecoderManager::DecodeInterleaved, "DecodeInterleaved"},
28 {1, nullptr, "SetContext"},
29 {2, nullptr, "DecodeInterleavedForMultiStream"},
30 {3, nullptr, "SetContextForMultiStream"},
31 {4, nullptr, "Unknown4"},
32 {5, nullptr, "Unknown5"},
33 {6, nullptr, "Unknown6"},
34 {7, nullptr, "Unknown7"},
35 };
36 RegisterHandlers(functions);
37 }
38
39private:
40 void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
41 u32 consumed = 0;
42 u32 sample_count = 0;
43 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
44 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
45 IPC::ResponseBuilder rb{ctx, 2};
46 // TODO(ogniK): Use correct error code
47 rb.Push(ResultCode(-1));
48 return;
49 }
50 IPC::ResponseBuilder rb{ctx, 4};
51 rb.Push(RESULT_SUCCESS);
52 rb.Push<u32>(consumed);
53 rb.Push<u32>(sample_count);
54 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
55 }
56
57 bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input,
58 std::vector<opus_int16>& output) {
59 size_t raw_output_sz = output.size() * sizeof(opus_int16);
60 if (sizeof(OpusHeader) > input.size())
61 return false;
62 OpusHeader hdr{};
63 std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
64 if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
65 return false;
66 }
67 auto frame = input.data() + sizeof(OpusHeader);
68 auto decoded_sample_count = opus_packet_get_nb_samples(
69 frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
70 static_cast<opus_int32>(sample_rate));
71 if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz)
72 return false;
73 auto out_sample_count =
74 opus_decode(decoder.get(), frame, hdr.sz, output.data(),
75 (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0);
76 if (out_sample_count < 0)
77 return false;
78 sample_count = out_sample_count;
79 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
80 return true;
81 }
82
83 struct OpusHeader {
84 u32_be sz; // Needs to be BE for some odd reason
85 INSERT_PADDING_WORDS(1);
86 };
87 static_assert(sizeof(OpusHeader) == 0x8, "OpusHeader is an invalid size");
88
89 std::unique_ptr<OpusDecoder, OpusDeleter> decoder;
90 u32 sample_rate;
91 u32 channel_count;
92};
93
94static size_t WorkerBufferSize(u32 channel_count) {
95 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
96 return opus_decoder_get_size(static_cast<int>(channel_count));
97}
98
12void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { 99void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
13 LOG_WARNING(Service_Audio, "(STUBBED) called"); 100 IPC::RequestParser rp{ctx};
101 auto sample_rate = rp.Pop<u32>();
102 auto channel_count = rp.Pop<u32>();
103 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
104 sample_rate == 12000 || sample_rate == 8000,
105 "Invalid sample rate");
106 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
107 u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
108 LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz);
109
14 IPC::ResponseBuilder rb{ctx, 3}; 110 IPC::ResponseBuilder rb{ctx, 3};
15 rb.Push(RESULT_SUCCESS); 111 rb.Push(RESULT_SUCCESS);
16 rb.Push<u32>(0x4000); 112 rb.Push<u32>(worker_buffer_sz);
113}
114
115void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
116 IPC::RequestParser rp{ctx};
117 auto sample_rate = rp.Pop<u32>();
118 auto channel_count = rp.Pop<u32>();
119 auto buffer_sz = rp.Pop<u32>();
120 LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
121 channel_count, buffer_sz);
122 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
123 sample_rate == 12000 || sample_rate == 8000,
124 "Invalid sample rate");
125 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
126
127 size_t worker_sz = WorkerBufferSize(channel_count);
128 ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
129 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
130 static_cast<OpusDecoder*>(operator new(worker_sz))};
131 if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
132 IPC::ResponseBuilder rb{ctx, 2};
133 // TODO(ogniK): Use correct error code
134 rb.Push(ResultCode(-1));
135 return;
136 }
137
138 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
139 rb.Push(RESULT_SUCCESS);
140 rb.PushIpcInterface<IHardwareOpusDecoderManager>(std::move(decoder), sample_rate,
141 channel_count);
17} 142}
18 143
19HwOpus::HwOpus() : ServiceFramework("hwopus") { 144HwOpus::HwOpus() : ServiceFramework("hwopus") {
20 static const FunctionInfo functions[] = { 145 static const FunctionInfo functions[] = {
21 {0, nullptr, "Initialize"}, 146 {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"},
22 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, 147 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
23 {2, nullptr, "InitializeMultiStream"}, 148 {2, nullptr, "OpenOpusDecoderForMultiStream"},
24 {3, nullptr, "GetWorkBufferSizeMultiStream"}, 149 {3, nullptr, "GetWorkBufferSizeForMultiStream"},
25 }; 150 };
26 RegisterHandlers(functions); 151 RegisterHandlers(functions);
27} 152}
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
index 090b8c825..5258d59f3 100644
--- a/src/core/hle/service/audio/hwopus.h
+++ b/src/core/hle/service/audio/hwopus.h
@@ -14,6 +14,7 @@ public:
14 ~HwOpus() = default; 14 ~HwOpus() = default;
15 15
16private: 16private:
17 void OpenOpusDecoder(Kernel::HLERequestContext& ctx);
17 void GetWorkBufferSize(Kernel::HLERequestContext& ctx); 18 void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
18}; 19};
19 20
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
new file mode 100644
index 000000000..1c1ecdb60
--- /dev/null
+++ b/src/core/hle/service/bpc/bpc.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 <memory>
6
7#include "core/hle/service/bpc/bpc.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::BPC {
12
13class BPC final : public ServiceFramework<BPC> {
14public:
15 explicit BPC() : ServiceFramework{"bpc"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "ShutdownSystem"},
19 {1, nullptr, "RebootSystem"},
20 {2, nullptr, "GetWakeupReason"},
21 {3, nullptr, "GetShutdownReason"},
22 {4, nullptr, "GetAcOk"},
23 {5, nullptr, "GetBoardPowerControlEvent"},
24 {6, nullptr, "GetSleepButtonState"},
25 {7, nullptr, "GetPowerEvent"},
26 {8, nullptr, "Unknown1"},
27 {9, nullptr, "Unknown2"},
28 {10, nullptr, "Unknown3"},
29 };
30 // clang-format on
31
32 RegisterHandlers(functions);
33 }
34};
35
36class BPC_R final : public ServiceFramework<BPC_R> {
37public:
38 explicit BPC_R() : ServiceFramework{"bpc:r"} {
39 // clang-format off
40 static const FunctionInfo functions[] = {
41 {0, nullptr, "GetExternalRtcValue"},
42 {1, nullptr, "SetExternalRtcValue"},
43 {2, nullptr, "ReadExternalRtcResetFlag"},
44 {3, nullptr, "ClearExternalRtcResetFlag"},
45 };
46 // clang-format on
47
48 RegisterHandlers(functions);
49 }
50};
51
52void InstallInterfaces(SM::ServiceManager& sm) {
53 std::make_shared<BPC>()->InstallAsService(sm);
54 std::make_shared<BPC_R>()->InstallAsService(sm);
55}
56
57} // namespace Service::BPC
diff --git a/src/core/hle/service/bpc/bpc.h b/src/core/hle/service/bpc/bpc.h
new file mode 100644
index 000000000..eaa37be8d
--- /dev/null
+++ b/src/core/hle/service/bpc/bpc.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::BPC {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::BPC
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
new file mode 100644
index 000000000..d0a15cc4c
--- /dev/null
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -0,0 +1,72 @@
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/btdrv/btdrv.h"
6#include "core/hle/service/service.h"
7#include "core/hle/service/sm/sm.h"
8
9namespace Service::BtDrv {
10
11class BtDrv final : public ServiceFramework<BtDrv> {
12public:
13 explicit BtDrv() : ServiceFramework{"btdrv"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, nullptr, "Unknown"},
17 {1, nullptr, "Init"},
18 {2, nullptr, "Enable"},
19 {3, nullptr, "Disable"},
20 {4, nullptr, "CleanupAndShutdown"},
21 {5, nullptr, "GetAdapterProperties"},
22 {6, nullptr, "GetAdapterProperty"},
23 {7, nullptr, "SetAdapterProperty"},
24 {8, nullptr, "StartDiscovery"},
25 {9, nullptr, "CancelDiscovery"},
26 {10, nullptr, "CreateBond"},
27 {11, nullptr, "RemoveBond"},
28 {12, nullptr, "CancelBond"},
29 {13, nullptr, "PinReply"},
30 {14, nullptr, "SspReply"},
31 {15, nullptr, "Unknown2"},
32 {16, nullptr, "InitInterfaces"},
33 {17, nullptr, "HidHostInterface_Connect"},
34 {18, nullptr, "HidHostInterface_Disconnect"},
35 {19, nullptr, "HidHostInterface_SendData"},
36 {20, nullptr, "HidHostInterface_SendData2"},
37 {21, nullptr, "HidHostInterface_SetReport"},
38 {22, nullptr, "HidHostInterface_GetReport"},
39 {23, nullptr, "HidHostInterface_WakeController"},
40 {24, nullptr, "HidHostInterface_AddPairedDevice"},
41 {25, nullptr, "HidHostInterface_GetPairedDevice"},
42 {26, nullptr, "HidHostInterface_CleanupAndShutdown"},
43 {27, nullptr, "Unknown3"},
44 {28, nullptr, "ExtInterface_SetTSI"},
45 {29, nullptr, "ExtInterface_SetBurstMode"},
46 {30, nullptr, "ExtInterface_SetZeroRetran"},
47 {31, nullptr, "ExtInterface_SetMcMode"},
48 {32, nullptr, "ExtInterface_StartLlrMode"},
49 {33, nullptr, "ExtInterface_ExitLlrMode"},
50 {34, nullptr, "ExtInterface_SetRadio"},
51 {35, nullptr, "ExtInterface_SetVisibility"},
52 {36, nullptr, "Unknown4"},
53 {37, nullptr, "Unknown5"},
54 {38, nullptr, "HidHostInterface_GetLatestPlr"},
55 {39, nullptr, "ExtInterface_GetPendingConnections"},
56 {40, nullptr, "HidHostInterface_GetChannelMap"},
57 {41, nullptr, "SetIsBluetoothBoostEnabled"},
58 {42, nullptr, "GetIsBluetoothBoostEnabled"},
59 {43, nullptr, "SetIsBluetoothAfhEnabled"},
60 {44, nullptr, "GetIsBluetoothAfhEnabled"},
61 };
62 // clang-format on
63
64 RegisterHandlers(functions);
65 }
66};
67
68void InstallInterfaces(SM::ServiceManager& sm) {
69 std::make_shared<BtDrv>()->InstallAsService(sm);
70}
71
72} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h
new file mode 100644
index 000000000..164e56f43
--- /dev/null
+++ b/src/core/hle/service/btdrv/btdrv.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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::BtDrv {
12
13/// Registers all BtDrv services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm);
15
16} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
new file mode 100644
index 000000000..b949bfabd
--- /dev/null
+++ b/src/core/hle/service/btm/btm.cpp
@@ -0,0 +1,121 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/btm/btm.h"
11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13
14namespace Service::BTM {
15
16class BTM final : public ServiceFramework<BTM> {
17public:
18 explicit BTM() : ServiceFramework{"btm"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, nullptr, "Unknown1"},
22 {1, nullptr, "Unknown2"},
23 {2, nullptr, "RegisterSystemEventForConnectedDeviceConditionImpl"},
24 {3, nullptr, "Unknown3"},
25 {4, nullptr, "Unknown4"},
26 {5, nullptr, "Unknown5"},
27 {6, nullptr, "Unknown6"},
28 {7, nullptr, "Unknown7"},
29 {8, nullptr, "RegisterSystemEventForRegisteredDeviceInfoImpl"},
30 {9, nullptr, "Unknown8"},
31 {10, nullptr, "Unknown9"},
32 {11, nullptr, "Unknown10"},
33 {12, nullptr, "Unknown11"},
34 {13, nullptr, "Unknown12"},
35 {14, nullptr, "EnableRadioImpl"},
36 {15, nullptr, "DisableRadioImpl"},
37 {16, nullptr, "Unknown13"},
38 {17, nullptr, "Unknown14"},
39 {18, nullptr, "Unknown15"},
40 {19, nullptr, "Unknown16"},
41 {20, nullptr, "Unknown17"},
42 {21, nullptr, "Unknown18"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47 }
48};
49
50class BTM_DBG final : public ServiceFramework<BTM_DBG> {
51public:
52 explicit BTM_DBG() : ServiceFramework{"btm:dbg"} {
53 // clang-format off
54 static const FunctionInfo functions[] = {
55 {0, nullptr, "RegisterSystemEventForDiscoveryImpl"},
56 {1, nullptr, "Unknown1"},
57 {2, nullptr, "Unknown2"},
58 {3, nullptr, "Unknown3"},
59 {4, nullptr, "Unknown4"},
60 {5, nullptr, "Unknown5"},
61 {6, nullptr, "Unknown6"},
62 {7, nullptr, "Unknown7"},
63 {8, nullptr, "Unknown8"},
64 };
65 // clang-format on
66
67 RegisterHandlers(functions);
68 }
69};
70
71class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
72public:
73 explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} {
74 // clang-format off
75 static const FunctionInfo functions[] = {
76 {0, nullptr, "StartGamepadPairingImpl"},
77 {1, nullptr, "CancelGamepadPairingImpl"},
78 {2, nullptr, "ClearGamepadPairingDatabaseImpl"},
79 {3, nullptr, "GetPairedGamepadCountImpl"},
80 {4, nullptr, "EnableRadioImpl"},
81 {5, nullptr, "DisableRadioImpl"},
82 {6, nullptr, "GetRadioOnOffImpl"},
83 {7, nullptr, "AcquireRadioEventImpl"},
84 {8, nullptr, "AcquireGamepadPairingEventImpl"},
85 {9, nullptr, "IsGamepadPairingStartedImpl"},
86 };
87 // clang-format on
88
89 RegisterHandlers(functions);
90 }
91};
92
93class BTM_SYS final : public ServiceFramework<BTM_SYS> {
94public:
95 explicit BTM_SYS() : ServiceFramework{"btm:sys"} {
96 // clang-format off
97 static const FunctionInfo functions[] = {
98 {0, &BTM_SYS::GetCoreImpl, "GetCoreImpl"},
99 };
100 // clang-format on
101
102 RegisterHandlers(functions);
103 }
104
105private:
106 void GetCoreImpl(Kernel::HLERequestContext& ctx) {
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(RESULT_SUCCESS);
109 rb.PushIpcInterface<IBtmSystemCore>();
110
111 LOG_DEBUG(Service_BTM, "called");
112 }
113};
114
115void InstallInterfaces(SM::ServiceManager& sm) {
116 std::make_shared<BTM>()->InstallAsService(sm);
117 std::make_shared<BTM_DBG>()->InstallAsService(sm);
118 std::make_shared<BTM_SYS>()->InstallAsService(sm);
119}
120
121} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
new file mode 100644
index 000000000..e6425a7e3
--- /dev/null
+++ b/src/core/hle/service/btm/btm.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::BTM {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::BTM
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
new file mode 100644
index 000000000..ae7b0720b
--- /dev/null
+++ b/src/core/hle/service/caps/caps.cpp
@@ -0,0 +1,152 @@
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 <memory>
6
7#include "core/hle/service/caps/caps.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::Capture {
12
13class CAPS_A final : public ServiceFramework<CAPS_A> {
14public:
15 explicit CAPS_A() : ServiceFramework{"caps:a"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "Unknown1"},
19 {1, nullptr, "Unknown2"},
20 {2, nullptr, "Unknown3"},
21 {3, nullptr, "Unknown4"},
22 {4, nullptr, "Unknown5"},
23 {5, nullptr, "Unknown6"},
24 {6, nullptr, "Unknown7"},
25 {7, nullptr, "Unknown8"},
26 {8, nullptr, "Unknown9"},
27 {9, nullptr, "Unknown10"},
28 {10, nullptr, "Unknown11"},
29 {11, nullptr, "Unknown12"},
30 {12, nullptr, "Unknown13"},
31 {13, nullptr, "Unknown14"},
32 {14, nullptr, "Unknown15"},
33 {301, nullptr, "Unknown16"},
34 {401, nullptr, "Unknown17"},
35 {501, nullptr, "Unknown18"},
36 {1001, nullptr, "Unknown19"},
37 {1002, nullptr, "Unknown20"},
38 {8001, nullptr, "Unknown21"},
39 {8002, nullptr, "Unknown22"},
40 {8011, nullptr, "Unknown23"},
41 {8012, nullptr, "Unknown24"},
42 {8021, nullptr, "Unknown25"},
43 {10011, nullptr, "Unknown26"},
44 };
45 // clang-format on
46
47 RegisterHandlers(functions);
48 }
49};
50
51class CAPS_C final : public ServiceFramework<CAPS_C> {
52public:
53 explicit CAPS_C() : ServiceFramework{"caps:c"} {
54 // clang-format off
55 static const FunctionInfo functions[] = {
56 {2001, nullptr, "Unknown1"},
57 {2002, nullptr, "Unknown2"},
58 {2011, nullptr, "Unknown3"},
59 {2012, nullptr, "Unknown4"},
60 {2013, nullptr, "Unknown5"},
61 {2014, nullptr, "Unknown6"},
62 {2101, nullptr, "Unknown7"},
63 {2102, nullptr, "Unknown8"},
64 {2201, nullptr, "Unknown9"},
65 {2301, nullptr, "Unknown10"},
66 };
67 // clang-format on
68
69 RegisterHandlers(functions);
70 }
71};
72
73class CAPS_SC final : public ServiceFramework<CAPS_SC> {
74public:
75 explicit CAPS_SC() : ServiceFramework{"caps:sc"} {
76 // clang-format off
77 static const FunctionInfo functions[] = {
78 {1, nullptr, "Unknown1"},
79 {2, nullptr, "Unknown2"},
80 {1001, nullptr, "Unknown3"},
81 {1002, nullptr, "Unknown4"},
82 {1003, nullptr, "Unknown5"},
83 {1011, nullptr, "Unknown6"},
84 {1012, nullptr, "Unknown7"},
85 {1201, nullptr, "Unknown8"},
86 {1202, nullptr, "Unknown9"},
87 {1203, nullptr, "Unknown10"},
88 };
89 // clang-format on
90
91 RegisterHandlers(functions);
92 }
93};
94
95class CAPS_SS final : public ServiceFramework<CAPS_SS> {
96public:
97 explicit CAPS_SS() : ServiceFramework{"caps:ss"} {
98 // clang-format off
99 static const FunctionInfo functions[] = {
100 {201, nullptr, "Unknown1"},
101 {202, nullptr, "Unknown2"},
102 {203, nullptr, "Unknown3"},
103 {204, nullptr, "Unknown4"},
104 };
105 // clang-format on
106
107 RegisterHandlers(functions);
108 }
109};
110
111class CAPS_SU final : public ServiceFramework<CAPS_SU> {
112public:
113 explicit CAPS_SU() : ServiceFramework{"caps:su"} {
114 // clang-format off
115 static const FunctionInfo functions[] = {
116 {201, nullptr, "SaveScreenShot"},
117 {203, nullptr, "SaveScreenShotEx0"},
118 };
119 // clang-format on
120
121 RegisterHandlers(functions);
122 }
123};
124
125class CAPS_U final : public ServiceFramework<CAPS_U> {
126public:
127 explicit CAPS_U() : ServiceFramework{"caps:u"} {
128 // clang-format off
129 static const FunctionInfo functions[] = {
130 {102, nullptr, "GetAlbumFileListByAruid"},
131 {103, nullptr, "DeleteAlbumFileByAruid"},
132 {104, nullptr, "GetAlbumFileSizeByAruid"},
133 {110, nullptr, "LoadAlbumScreenShotImageByAruid"},
134 {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
135 {60002, nullptr, "OpenAccessorSessionForApplication"},
136 };
137 // clang-format on
138
139 RegisterHandlers(functions);
140 }
141};
142
143void InstallInterfaces(SM::ServiceManager& sm) {
144 std::make_shared<CAPS_A>()->InstallAsService(sm);
145 std::make_shared<CAPS_C>()->InstallAsService(sm);
146 std::make_shared<CAPS_SC>()->InstallAsService(sm);
147 std::make_shared<CAPS_SS>()->InstallAsService(sm);
148 std::make_shared<CAPS_SU>()->InstallAsService(sm);
149 std::make_shared<CAPS_U>()->InstallAsService(sm);
150}
151
152} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
new file mode 100644
index 000000000..471185dfa
--- /dev/null
+++ b/src/core/hle/service/caps/caps.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::Capture {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::Capture
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
new file mode 100644
index 000000000..566fbf924
--- /dev/null
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -0,0 +1,75 @@
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 <memory>
6
7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/service/fgm/fgm.h"
10#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h"
12
13namespace Service::FGM {
14
15class IRequest final : public ServiceFramework<IRequest> {
16public:
17 explicit IRequest() : ServiceFramework{"IRequest"} {
18 // clang-format off
19 static const FunctionInfo functions[] = {
20 {0, nullptr, "Initialize"},
21 {1, nullptr, "Set"},
22 {2, nullptr, "Get"},
23 {3, nullptr, "Cancel"},
24 };
25 // clang-format on
26
27 RegisterHandlers(functions);
28 }
29};
30
31class FGM final : public ServiceFramework<FGM> {
32public:
33 explicit FGM(const char* name) : ServiceFramework{name} {
34 // clang-format off
35 static const FunctionInfo functions[] = {
36 {0, &FGM::Initialize, "Initialize"},
37 };
38 // clang-format on
39
40 RegisterHandlers(functions);
41 }
42
43private:
44 void Initialize(Kernel::HLERequestContext& ctx) {
45 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
46 rb.Push(RESULT_SUCCESS);
47 rb.PushIpcInterface<IRequest>();
48
49 LOG_DEBUG(Service_FGM, "called");
50 }
51};
52
53class FGM_DBG final : public ServiceFramework<FGM_DBG> {
54public:
55 explicit FGM_DBG() : ServiceFramework{"fgm:dbg"} {
56 // clang-format off
57 static const FunctionInfo functions[] = {
58 {0, nullptr, "Initialize"},
59 {1, nullptr, "Read"},
60 {2, nullptr, "Cancel"},
61 };
62 // clang-format on
63
64 RegisterHandlers(functions);
65 }
66};
67
68void InstallInterfaces(SM::ServiceManager& sm) {
69 std::make_shared<FGM>("fgm")->InstallAsService(sm);
70 std::make_shared<FGM>("fgm:0")->InstallAsService(sm);
71 std::make_shared<FGM>("fgm:9")->InstallAsService(sm);
72 std::make_shared<FGM_DBG>()->InstallAsService(sm);
73}
74
75} // namespace Service::FGM
diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h
new file mode 100644
index 000000000..e59691264
--- /dev/null
+++ b/src/core/hle/service/fgm/fgm.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::FGM {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::FGM
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index fdd2fda18..e17d637e4 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -14,6 +14,8 @@
14#include "core/file_sys/vfs_offset.h" 14#include "core/file_sys/vfs_offset.h"
15#include "core/file_sys/vfs_real.h" 15#include "core/file_sys/vfs_real.h"
16#include "core/hle/service/filesystem/filesystem.h" 16#include "core/hle/service/filesystem/filesystem.h"
17#include "core/hle/service/filesystem/fsp_ldr.h"
18#include "core/hle/service/filesystem/fsp_pr.h"
17#include "core/hle/service/filesystem/fsp_srv.h" 19#include "core/hle/service/filesystem/fsp_srv.h"
18 20
19namespace Service::FileSystem { 21namespace Service::FileSystem {
@@ -298,6 +300,8 @@ void RegisterFileSystems() {
298 300
299void InstallInterfaces(SM::ServiceManager& service_manager) { 301void InstallInterfaces(SM::ServiceManager& service_manager) {
300 RegisterFileSystems(); 302 RegisterFileSystems();
303 std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
304 std::make_shared<FSP_PR>()->InstallAsService(service_manager);
301 std::make_shared<FSP_SRV>()->InstallAsService(service_manager); 305 std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
302} 306}
303 307
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp
new file mode 100644
index 000000000..0ab9c2606
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_ldr.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/filesystem/fsp_ldr.h"
6#include "core/hle/service/service.h"
7
8namespace Service::FileSystem {
9
10FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "OpenCodeFileSystem"},
14 {1, nullptr, "IsArchivedProgram"},
15 {2, nullptr, "SetCurrentProcess"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h
new file mode 100644
index 000000000..fa8e11b4c
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_ldr.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::FileSystem {
10
11class FSP_LDR final : public ServiceFramework<FSP_LDR> {
12public:
13 explicit FSP_LDR();
14};
15
16} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp
new file mode 100644
index 000000000..32b0ae454
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_pr.cpp
@@ -0,0 +1,23 @@
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/filesystem/fsp_pr.h"
6#include "core/hle/service/service.h"
7
8namespace Service::FileSystem {
9
10FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "RegisterProgram"},
14 {1, nullptr, "UnregisterProgram"},
15 {2, nullptr, "SetCurrentProcess"},
16 {256, nullptr, "SetEnabledProgramVerification"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21}
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h
new file mode 100644
index 000000000..62edcd08a
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp_pr.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::FileSystem {
10
11class FSP_PR final : public ServiceFramework<FSP_PR> {
12public:
13 explicit FSP_PR();
14};
15
16} // namespace Service::FileSystem
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e4619a547..8f0262e34 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -326,7 +326,7 @@ public:
326 {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, 326 {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
327 {80, nullptr, "GetGyroscopeZeroDriftMode"}, 327 {80, nullptr, "GetGyroscopeZeroDriftMode"},
328 {81, nullptr, "ResetGyroscopeZeroDriftMode"}, 328 {81, nullptr, "ResetGyroscopeZeroDriftMode"},
329 {82, nullptr, "IsSixAxisSensorAtRest"}, 329 {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
330 {91, nullptr, "ActivateGesture"}, 330 {91, nullptr, "ActivateGesture"},
331 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, 331 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
332 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, 332 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
@@ -337,13 +337,14 @@ public:
337 "AcquireNpadStyleSetUpdateEventHandle"}, 337 "AcquireNpadStyleSetUpdateEventHandle"},
338 {107, nullptr, "DisconnectNpad"}, 338 {107, nullptr, "DisconnectNpad"},
339 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, 339 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
340 {109, nullptr, "ActivateNpadWithRevision"},
340 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, 341 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
341 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, 342 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
342 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, 343 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault,
343 "SetNpadJoyAssignmentModeSingleByDefault"}, 344 "SetNpadJoyAssignmentModeSingleByDefault"},
344 {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, 345 {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
345 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, 346 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
346 {125, nullptr, "MergeSingleJoyAsDualJoy"}, 347 {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
347 {126, nullptr, "StartLrAssignmentMode"}, 348 {126, nullptr, "StartLrAssignmentMode"},
348 {127, nullptr, "StopLrAssignmentMode"}, 349 {127, nullptr, "StopLrAssignmentMode"},
349 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, 350 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
@@ -455,6 +456,14 @@ private:
455 LOG_WARNING(Service_HID, "(STUBBED) called"); 456 LOG_WARNING(Service_HID, "(STUBBED) called");
456 } 457 }
457 458
459 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
460 IPC::ResponseBuilder rb{ctx, 2};
461 rb.Push(RESULT_SUCCESS);
462 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
463 rb.Push(true);
464 LOG_WARNING(Service_HID, "(STUBBED) called");
465 }
466
458 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 467 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
459 IPC::ResponseBuilder rb{ctx, 2}; 468 IPC::ResponseBuilder rb{ctx, 2};
460 rb.Push(RESULT_SUCCESS); 469 rb.Push(RESULT_SUCCESS);
@@ -530,6 +539,12 @@ private:
530 LOG_WARNING(Service_HID, "(STUBBED) called"); 539 LOG_WARNING(Service_HID, "(STUBBED) called");
531 } 540 }
532 541
542 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
543 IPC::ResponseBuilder rb{ctx, 2};
544 rb.Push(RESULT_SUCCESS);
545 LOG_WARNING(Service_HID, "(STUBBED) called");
546 }
547
533 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 548 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
534 IPC::ResponseBuilder rb{ctx, 2}; 549 IPC::ResponseBuilder rb{ctx, 2};
535 rb.Push(RESULT_SUCCESS); 550 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
new file mode 100644
index 000000000..8fc8b1057
--- /dev/null
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -0,0 +1,90 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/lbl/lbl.h"
11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13
14namespace Service::LBL {
15
16class LBL final : public ServiceFramework<LBL> {
17public:
18 explicit LBL() : ServiceFramework{"lbl"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, nullptr, "Unknown1"},
22 {1, nullptr, "Unknown2"},
23 {2, nullptr, "Unknown3"},
24 {3, nullptr, "Unknown4"},
25 {4, nullptr, "Unknown5"},
26 {5, nullptr, "Unknown6"},
27 {6, nullptr, "TurnOffBacklight"},
28 {7, nullptr, "TurnOnBacklight"},
29 {8, nullptr, "GetBacklightStatus"},
30 {9, nullptr, "Unknown7"},
31 {10, nullptr, "Unknown8"},
32 {11, nullptr, "Unknown9"},
33 {12, nullptr, "Unknown10"},
34 {13, nullptr, "Unknown11"},
35 {14, nullptr, "Unknown12"},
36 {15, nullptr, "Unknown13"},
37 {16, nullptr, "ReadRawLightSensor"},
38 {17, nullptr, "Unknown14"},
39 {18, nullptr, "Unknown15"},
40 {19, nullptr, "Unknown16"},
41 {20, nullptr, "Unknown17"},
42 {21, nullptr, "Unknown18"},
43 {22, nullptr, "Unknown19"},
44 {23, nullptr, "Unknown20"},
45 {24, nullptr, "Unknown21"},
46 {25, nullptr, "Unknown22"},
47 {26, &LBL::EnableVrMode, "EnableVrMode"},
48 {27, &LBL::DisableVrMode, "DisableVrMode"},
49 {28, &LBL::GetVrMode, "GetVrMode"},
50 };
51 // clang-format on
52
53 RegisterHandlers(functions);
54 }
55
56private:
57 void EnableVrMode(Kernel::HLERequestContext& ctx) {
58 IPC::ResponseBuilder rb{ctx, 2};
59 rb.Push(RESULT_SUCCESS);
60
61 vr_mode_enabled = true;
62
63 LOG_DEBUG(Service_LBL, "called");
64 }
65
66 void DisableVrMode(Kernel::HLERequestContext& ctx) {
67 IPC::ResponseBuilder rb{ctx, 2};
68 rb.Push(RESULT_SUCCESS);
69
70 vr_mode_enabled = false;
71
72 LOG_DEBUG(Service_LBL, "called");
73 }
74
75 void GetVrMode(Kernel::HLERequestContext& ctx) {
76 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS);
78 rb.Push(vr_mode_enabled);
79
80 LOG_DEBUG(Service_LBL, "called");
81 }
82
83 bool vr_mode_enabled = false;
84};
85
86void InstallInterfaces(SM::ServiceManager& sm) {
87 std::make_shared<LBL>()->InstallAsService(sm);
88}
89
90} // namespace Service::LBL
diff --git a/src/core/hle/service/lbl/lbl.h b/src/core/hle/service/lbl/lbl.h
new file mode 100644
index 000000000..bf6f400f8
--- /dev/null
+++ b/src/core/hle/service/lbl/lbl.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::LBL {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::LBL
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index b497376d7..2e99ddf51 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -13,11 +13,11 @@
13 13
14namespace Service::LM { 14namespace Service::LM {
15 15
16class Logger final : public ServiceFramework<Logger> { 16class ILogger final : public ServiceFramework<ILogger> {
17public: 17public:
18 Logger() : ServiceFramework("Logger") { 18 ILogger() : ServiceFramework("ILogger") {
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {0x00000000, &Logger::Initialize, "Initialize"}, 20 {0x00000000, &ILogger::Initialize, "Initialize"},
21 {0x00000001, nullptr, "SetDestination"}, 21 {0x00000001, nullptr, "SetDestination"},
22 }; 22 };
23 RegisterHandlers(functions); 23 RegisterHandlers(functions);
@@ -182,7 +182,7 @@ public:
182 void OpenLogger(Kernel::HLERequestContext& ctx) { 182 void OpenLogger(Kernel::HLERequestContext& ctx) {
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 183 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 184 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<Logger>(); 185 rb.PushIpcInterface<ILogger>();
186 186
187 LOG_DEBUG(Service_LM, "called"); 187 LOG_DEBUG(Service_LM, "called");
188 } 188 }
diff --git a/src/core/hle/service/mig/mig.cpp b/src/core/hle/service/mig/mig.cpp
new file mode 100644
index 000000000..d16367f2c
--- /dev/null
+++ b/src/core/hle/service/mig/mig.cpp
@@ -0,0 +1,34 @@
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 <memory>
6
7#include "core/hle/service/mig/mig.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::Migration {
12
13class MIG_USR final : public ServiceFramework<MIG_USR> {
14public:
15 explicit MIG_USR() : ServiceFramework{"mig:usr"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {10, nullptr, "TryGetLastMigrationInfo"},
19 {100, nullptr, "CreateServer"},
20 {101, nullptr, "ResumeServer"},
21 {200, nullptr, "CreateClient"},
22 {201, nullptr, "ResumeClient"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27 }
28};
29
30void InstallInterfaces(SM::ServiceManager& sm) {
31 std::make_shared<MIG_USR>()->InstallAsService(sm);
32}
33
34} // namespace Service::Migration
diff --git a/src/core/hle/service/mig/mig.h b/src/core/hle/service/mig/mig.h
new file mode 100644
index 000000000..288c1c1b3
--- /dev/null
+++ b/src/core/hle/service/mig/mig.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::Migration {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::Migration
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
new file mode 100644
index 000000000..a6197124a
--- /dev/null
+++ b/src/core/hle/service/mii/mii.cpp
@@ -0,0 +1,107 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/mii/mii.h"
11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13
14namespace Service::Mii {
15
16class IDatabaseService final : public ServiceFramework<IDatabaseService> {
17public:
18 explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, nullptr, "IsUpdated"},
22 {1, nullptr, "IsFullDatabase"},
23 {2, nullptr, "GetCount"},
24 {3, nullptr, "Get"},
25 {4, nullptr, "Get1"},
26 {5, nullptr, "UpdateLatest"},
27 {6, nullptr, "BuildRandom"},
28 {7, nullptr, "BuildDefault"},
29 {8, nullptr, "Get2"},
30 {9, nullptr, "Get3"},
31 {10, nullptr, "UpdateLatest1"},
32 {11, nullptr, "FindIndex"},
33 {12, nullptr, "Move"},
34 {13, nullptr, "AddOrReplace"},
35 {14, nullptr, "Delete"},
36 {15, nullptr, "DestroyFile"},
37 {16, nullptr, "DeleteFile"},
38 {17, nullptr, "Format"},
39 {18, nullptr, "Import"},
40 {19, nullptr, "Export"},
41 {20, nullptr, "IsBrokenDatabaseWithClearFlag"},
42 {21, nullptr, "GetIndex"},
43 {22, nullptr, "SetInterfaceVersion"},
44 {23, nullptr, "Convert"},
45 };
46 // clang-format on
47
48 RegisterHandlers(functions);
49 }
50};
51
52class MiiDBModule final : public ServiceFramework<MiiDBModule> {
53public:
54 explicit MiiDBModule(const char* name) : ServiceFramework{name} {
55 // clang-format off
56 static const FunctionInfo functions[] = {
57 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
58 };
59 // clang-format on
60
61 RegisterHandlers(functions);
62 }
63
64private:
65 void GetDatabaseService(Kernel::HLERequestContext& ctx) {
66 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
67 rb.Push(RESULT_SUCCESS);
68 rb.PushIpcInterface<IDatabaseService>();
69
70 LOG_DEBUG(Service_Mii, "called");
71 }
72};
73
74class MiiImg final : public ServiceFramework<MiiImg> {
75public:
76 explicit MiiImg() : ServiceFramework{"miiimg"} {
77 // clang-format off
78 static const FunctionInfo functions[] = {
79 {0, nullptr, "Initialize"},
80 {10, nullptr, "Reload"},
81 {11, nullptr, "GetCount"},
82 {12, nullptr, "IsEmpty"},
83 {13, nullptr, "IsFull"},
84 {14, nullptr, "GetAttribute"},
85 {15, nullptr, "LoadImage"},
86 {16, nullptr, "AddOrUpdateImage"},
87 {17, nullptr, "DeleteImages"},
88 {100, nullptr, "DeleteFile"},
89 {101, nullptr, "DestroyFile"},
90 {102, nullptr, "ImportFile"},
91 {103, nullptr, "ExportFile"},
92 {104, nullptr, "ForceInitialize"},
93 };
94 // clang-format on
95
96 RegisterHandlers(functions);
97 }
98};
99
100void InstallInterfaces(SM::ServiceManager& sm) {
101 std::make_shared<MiiDBModule>("mii:e")->InstallAsService(sm);
102 std::make_shared<MiiDBModule>("mii:u")->InstallAsService(sm);
103
104 std::make_shared<MiiImg>()->InstallAsService(sm);
105}
106
107} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h
new file mode 100644
index 000000000..7ce9be50e
--- /dev/null
+++ b/src/core/hle/service/mii/mii.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::Mii {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::Mii
diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp
new file mode 100644
index 000000000..0297edca0
--- /dev/null
+++ b/src/core/hle/service/ncm/ncm.cpp
@@ -0,0 +1,59 @@
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 <memory>
6
7#include "core/hle/service/ncm/ncm.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::NCM {
12
13class LocationResolver final : public ServiceFramework<LocationResolver> {
14public:
15 explicit LocationResolver() : ServiceFramework{"lr"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "OpenLocationResolver"},
19 {1, nullptr, "OpenRegisteredLocationResolver"},
20 {2, nullptr, "RefreshLocationResolver"},
21 {3, nullptr, "OpenAddOnContentLocationResolver"},
22 };
23 // clang-format on
24
25 RegisterHandlers(functions);
26 }
27};
28
29class NCM final : public ServiceFramework<NCM> {
30public:
31 explicit NCM() : ServiceFramework{"ncm"} {
32 // clang-format off
33 static const FunctionInfo functions[] = {
34 {0, nullptr, "CreateContentStorage"},
35 {1, nullptr, "CreateContentMetaDatabase"},
36 {2, nullptr, "VerifyContentStorage"},
37 {3, nullptr, "VerifyContentMetaDatabase"},
38 {4, nullptr, "OpenContentStorage"},
39 {5, nullptr, "OpenContentMetaDatabase"},
40 {6, nullptr, "CloseContentStorageForcibly"},
41 {7, nullptr, "CloseContentMetaDatabaseForcibly"},
42 {8, nullptr, "CleanupContentMetaDatabase"},
43 {9, nullptr, "OpenContentStorage2"},
44 {10, nullptr, "CloseContentStorage"},
45 {11, nullptr, "OpenContentMetaDatabase2"},
46 {12, nullptr, "CloseContentMetaDatabase"},
47 };
48 // clang-format on
49
50 RegisterHandlers(functions);
51 }
52};
53
54void InstallInterfaces(SM::ServiceManager& sm) {
55 std::make_shared<LocationResolver>()->InstallAsService(sm);
56 std::make_shared<NCM>()->InstallAsService(sm);
57}
58
59} // namespace Service::NCM
diff --git a/src/core/hle/service/ncm/ncm.h b/src/core/hle/service/ncm/ncm.h
new file mode 100644
index 000000000..7bc8518a6
--- /dev/null
+++ b/src/core/hle/service/ncm/ncm.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::NCM {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::NCM
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
new file mode 100644
index 000000000..8fec97db8
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -0,0 +1,222 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/nfc/nfc.h"
11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13
14namespace Service::NFC {
15
16class IAm final : public ServiceFramework<IAm> {
17public:
18 explicit IAm() : ServiceFramework{"IAm"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, nullptr, "Initialize"},
22 {1, nullptr, "Finalize"},
23 {2, nullptr, "NotifyForegroundApplet"},
24 };
25 // clang-format on
26
27 RegisterHandlers(functions);
28 }
29};
30
31class NFC_AM final : public ServiceFramework<NFC_AM> {
32public:
33 explicit NFC_AM() : ServiceFramework{"nfc:am"} {
34 // clang-format off
35 static const FunctionInfo functions[] = {
36 {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"},
37 };
38 // clang-format on
39
40 RegisterHandlers(functions);
41 }
42
43private:
44 void CreateAmInterface(Kernel::HLERequestContext& ctx) {
45 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
46 rb.Push(RESULT_SUCCESS);
47 rb.PushIpcInterface<IAm>();
48
49 LOG_DEBUG(Service_NFC, "called");
50 }
51};
52
53class MFIUser final : public ServiceFramework<MFIUser> {
54public:
55 explicit MFIUser() : ServiceFramework{"IUser"} {
56 // clang-format off
57 static const FunctionInfo functions[] = {
58 {0, nullptr, "Initialize"},
59 {1, nullptr, "Finalize"},
60 {2, nullptr, "ListDevices"},
61 {3, nullptr, "StartDetection"},
62 {4, nullptr, "StopDetection"},
63 {5, nullptr, "Read"},
64 {6, nullptr, "Write"},
65 {7, nullptr, "GetTagInfo"},
66 {8, nullptr, "GetActivateEventHandle"},
67 {9, nullptr, "GetDeactivateEventHandle"},
68 {10, nullptr, "GetState"},
69 {11, nullptr, "GetDeviceState"},
70 {12, nullptr, "GetNpadId"},
71 {13, nullptr, "GetAvailabilityChangeEventHandle"},
72 };
73 // clang-format on
74
75 RegisterHandlers(functions);
76 }
77};
78
79class NFC_MF_U final : public ServiceFramework<NFC_MF_U> {
80public:
81 explicit NFC_MF_U() : ServiceFramework{"nfc:mf:u"} {
82 // clang-format off
83 static const FunctionInfo functions[] = {
84 {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"},
85 };
86 // clang-format on
87
88 RegisterHandlers(functions);
89 }
90
91private:
92 void CreateUserInterface(Kernel::HLERequestContext& ctx) {
93 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
94 rb.Push(RESULT_SUCCESS);
95 rb.PushIpcInterface<MFIUser>();
96
97 LOG_DEBUG(Service_NFC, "called");
98 }
99};
100
101class IUser final : public ServiceFramework<IUser> {
102public:
103 explicit IUser() : ServiceFramework{"IUser"} {
104 // clang-format off
105 static const FunctionInfo functions[] = {
106 {0, nullptr, "Initialize"},
107 {1, nullptr, "Finalize"},
108 {2, nullptr, "GetState"},
109 {3, nullptr, "IsNfcEnabled"},
110 {400, nullptr, "Initialize"},
111 {401, nullptr, "Finalize"},
112 {402, nullptr, "GetState"},
113 {403, nullptr, "IsNfcEnabled"},
114 {404, nullptr, "ListDevices"},
115 {405, nullptr, "GetDeviceState"},
116 {406, nullptr, "GetNpadId"},
117 {407, nullptr, "AttachAvailabilityChangeEvent"},
118 {408, nullptr, "StartDetection"},
119 {409, nullptr, "StopDetection"},
120 {410, nullptr, "GetTagInfo"},
121 {411, nullptr, "AttachActivateEvent"},
122 {412, nullptr, "AttachDeactivateEvent"},
123 {1000, nullptr, "ReadMifare"},
124 {1001, nullptr, "WriteMifare"},
125 {1300, nullptr, "SendCommandByPassThrough"},
126 {1301, nullptr, "KeepPassThroughSession"},
127 {1302, nullptr, "ReleasePassThroughSession"},
128 };
129 // clang-format on
130
131 RegisterHandlers(functions);
132 }
133};
134
135class NFC_U final : public ServiceFramework<NFC_U> {
136public:
137 explicit NFC_U() : ServiceFramework{"nfc:u"} {
138 // clang-format off
139 static const FunctionInfo functions[] = {
140 {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
141 };
142 // clang-format on
143
144 RegisterHandlers(functions);
145 }
146
147private:
148 void CreateUserInterface(Kernel::HLERequestContext& ctx) {
149 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
150 rb.Push(RESULT_SUCCESS);
151 rb.PushIpcInterface<IUser>();
152
153 LOG_DEBUG(Service_NFC, "called");
154 }
155};
156
157class ISystem final : public ServiceFramework<ISystem> {
158public:
159 explicit ISystem() : ServiceFramework{"ISystem"} {
160 // clang-format off
161 static const FunctionInfo functions[] = {
162 {0, nullptr, "Initialize"},
163 {1, nullptr, "Finalize"},
164 {2, nullptr, "GetState"},
165 {3, nullptr, "IsNfcEnabled"},
166 {100, nullptr, "SetNfcEnabled"},
167 {400, nullptr, "InitializeSystem"},
168 {401, nullptr, "FinalizeSystem"},
169 {402, nullptr, "GetState"},
170 {403, nullptr, "IsNfcEnabled"},
171 {404, nullptr, "ListDevices"},
172 {405, nullptr, "GetDeviceState"},
173 {406, nullptr, "GetNpadId"},
174 {407, nullptr, "AttachAvailabilityChangeEvent"},
175 {408, nullptr, "StartDetection"},
176 {409, nullptr, "StopDetection"},
177 {410, nullptr, "GetTagInfo"},
178 {411, nullptr, "AttachActivateEvent"},
179 {412, nullptr, "AttachDeactivateEvent"},
180 {500, nullptr, "SetNfcEnabled"},
181 {1000, nullptr, "ReadMifare"},
182 {1001, nullptr, "WriteMifare"},
183 {1300, nullptr, "SendCommandByPassThrough"},
184 {1301, nullptr, "KeepPassThroughSession"},
185 {1302, nullptr, "ReleasePassThroughSession"},
186 };
187 // clang-format on
188
189 RegisterHandlers(functions);
190 }
191};
192
193class NFC_SYS final : public ServiceFramework<NFC_SYS> {
194public:
195 explicit NFC_SYS() : ServiceFramework{"nfc:sys"} {
196 // clang-format off
197 static const FunctionInfo functions[] = {
198 {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"},
199 };
200 // clang-format on
201
202 RegisterHandlers(functions);
203 }
204
205private:
206 void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
207 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
208 rb.Push(RESULT_SUCCESS);
209 rb.PushIpcInterface<ISystem>();
210
211 LOG_DEBUG(Service_NFC, "called");
212 }
213};
214
215void InstallInterfaces(SM::ServiceManager& sm) {
216 std::make_shared<NFC_AM>()->InstallAsService(sm);
217 std::make_shared<NFC_MF_U>()->InstallAsService(sm);
218 std::make_shared<NFC_U>()->InstallAsService(sm);
219 std::make_shared<NFC_SYS>()->InstallAsService(sm);
220}
221
222} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
new file mode 100644
index 000000000..4d2d815f9
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::NFC {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::NFC
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 89c703310..98017267c 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,12 +2,459 @@
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 "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h"
5#include "core/hle/service/ns/ns.h" 7#include "core/hle/service/ns/ns.h"
6#include "core/hle/service/ns/pl_u.h" 8#include "core/hle/service/ns/pl_u.h"
7 9
8namespace Service::NS { 10namespace Service::NS {
9 11
12class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
13public:
14 explicit IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, nullptr, "CreateUserAccount"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22 }
23};
24
25class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
26public:
27 explicit IApplicationManagerInterface() : ServiceFramework{"IApplicationManagerInterface"} {
28 // clang-format off
29 static const FunctionInfo functions[] = {
30 {0, nullptr, "ListApplicationRecord"},
31 {1, nullptr, "GenerateApplicationRecordCount"},
32 {2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
33 {3, nullptr, "GetApplicationViewDeprecated"},
34 {4, nullptr, "DeleteApplicationEntity"},
35 {5, nullptr, "DeleteApplicationCompletely"},
36 {6, nullptr, "IsAnyApplicationEntityRedundant"},
37 {7, nullptr, "DeleteRedundantApplicationEntity"},
38 {8, nullptr, "IsApplicationEntityMovable"},
39 {9, nullptr, "MoveApplicationEntity"},
40 {11, nullptr, "CalculateApplicationOccupiedSize"},
41 {16, nullptr, "PushApplicationRecord"},
42 {17, nullptr, "ListApplicationRecordContentMeta"},
43 {19, nullptr, "LaunchApplication"},
44 {21, nullptr, "GetApplicationContentPath"},
45 {22, nullptr, "TerminateApplication"},
46 {23, nullptr, "ResolveApplicationContentPath"},
47 {26, nullptr, "BeginInstallApplication"},
48 {27, nullptr, "DeleteApplicationRecord"},
49 {30, nullptr, "RequestApplicationUpdateInfo"},
50 {32, nullptr, "CancelApplicationDownload"},
51 {33, nullptr, "ResumeApplicationDownload"},
52 {35, nullptr, "UpdateVersionList"},
53 {36, nullptr, "PushLaunchVersion"},
54 {37, nullptr, "ListRequiredVersion"},
55 {38, nullptr, "CheckApplicationLaunchVersion"},
56 {39, nullptr, "CheckApplicationLaunchRights"},
57 {40, nullptr, "GetApplicationLogoData"},
58 {41, nullptr, "CalculateApplicationDownloadRequiredSize"},
59 {42, nullptr, "CleanupSdCard"},
60 {43, nullptr, "CheckSdCardMountStatus"},
61 {44, nullptr, "GetSdCardMountStatusChangedEvent"},
62 {45, nullptr, "GetGameCardAttachmentEvent"},
63 {46, nullptr, "GetGameCardAttachmentInfo"},
64 {47, nullptr, "GetTotalSpaceSize"},
65 {48, nullptr, "GetFreeSpaceSize"},
66 {49, nullptr, "GetSdCardRemovedEvent"},
67 {52, nullptr, "GetGameCardUpdateDetectionEvent"},
68 {53, nullptr, "DisableApplicationAutoDelete"},
69 {54, nullptr, "EnableApplicationAutoDelete"},
70 {55, nullptr, "GetApplicationDesiredLanguage"},
71 {56, nullptr, "SetApplicationTerminateResult"},
72 {57, nullptr, "ClearApplicationTerminateResult"},
73 {58, nullptr, "GetLastSdCardMountUnexpectedResult"},
74 {59, nullptr, "ConvertApplicationLanguageToLanguageCode"},
75 {60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
76 {61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
77 {62, nullptr, "GetGameCardStopper"},
78 {63, nullptr, "IsSystemProgramInstalled"},
79 {64, nullptr, "StartApplyDeltaTask"},
80 {65, nullptr, "GetRequestServerStopper"},
81 {66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
82 {67, nullptr, "CancelApplicationApplyDelta"},
83 {68, nullptr, "ResumeApplicationApplyDelta"},
84 {69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
85 {70, nullptr, "ResumeAll"},
86 {71, nullptr, "GetStorageSize"},
87 {80, nullptr, "RequestDownloadApplication"},
88 {81, nullptr, "RequestDownloadAddOnContent"},
89 {82, nullptr, "DownloadApplication"},
90 {83, nullptr, "CheckApplicationResumeRights"},
91 {84, nullptr, "GetDynamicCommitEvent"},
92 {85, nullptr, "RequestUpdateApplication2"},
93 {86, nullptr, "EnableApplicationCrashReport"},
94 {87, nullptr, "IsApplicationCrashReportEnabled"},
95 {90, nullptr, "BoostSystemMemoryResourceLimit"},
96 {100, nullptr, "ResetToFactorySettings"},
97 {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
98 {102, nullptr, "ResetToFactorySettingsForRefurbishment"},
99 {200, nullptr, "CalculateUserSaveDataStatistics"},
100 {201, nullptr, "DeleteUserSaveDataAll"},
101 {210, nullptr, "DeleteUserSystemSaveData"},
102 {220, nullptr, "UnregisterNetworkServiceAccount"},
103 {300, nullptr, "GetApplicationShellEvent"},
104 {301, nullptr, "PopApplicationShellEventInfo"},
105 {302, nullptr, "LaunchLibraryApplet"},
106 {303, nullptr, "TerminateLibraryApplet"},
107 {304, nullptr, "LaunchSystemApplet"},
108 {305, nullptr, "TerminateSystemApplet"},
109 {306, nullptr, "LaunchOverlayApplet"},
110 {307, nullptr, "TerminateOverlayApplet"},
111 {400, nullptr, "GetApplicationControlData"},
112 {401, nullptr, "InvalidateAllApplicationControlCache"},
113 {402, nullptr, "RequestDownloadApplicationControlData"},
114 {403, nullptr, "GetMaxApplicationControlCacheCount"},
115 {404, nullptr, "InvalidateApplicationControlCache"},
116 {405, nullptr, "ListApplicationControlCacheEntryInfo"},
117 {502, nullptr, "RequestCheckGameCardRegistration"},
118 {503, nullptr, "RequestGameCardRegistrationGoldPoint"},
119 {504, nullptr, "RequestRegisterGameCard"},
120 {505, nullptr, "GetGameCardMountFailureEvent"},
121 {506, nullptr, "IsGameCardInserted"},
122 {507, nullptr, "EnsureGameCardAccess"},
123 {508, nullptr, "GetLastGameCardMountFailureResult"},
124 {509, nullptr, "ListApplicationIdOnGameCard"},
125 {600, nullptr, "CountApplicationContentMeta"},
126 {601, nullptr, "ListApplicationContentMetaStatus"},
127 {602, nullptr, "ListAvailableAddOnContent"},
128 {603, nullptr, "GetOwnedApplicationContentMetaStatus"},
129 {604, nullptr, "RegisterContentsExternalKey"},
130 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
131 {606, nullptr, "GetContentMetaStorage"},
132 {700, nullptr, "PushDownloadTaskList"},
133 {701, nullptr, "ClearTaskStatusList"},
134 {702, nullptr, "RequestDownloadTaskList"},
135 {703, nullptr, "RequestEnsureDownloadTask"},
136 {704, nullptr, "ListDownloadTaskStatus"},
137 {705, nullptr, "RequestDownloadTaskListData"},
138 {800, nullptr, "RequestVersionList"},
139 {801, nullptr, "ListVersionList"},
140 {802, nullptr, "RequestVersionListData"},
141 {900, nullptr, "GetApplicationRecord"},
142 {901, nullptr, "GetApplicationRecordProperty"},
143 {902, nullptr, "EnableApplicationAutoUpdate"},
144 {903, nullptr, "DisableApplicationAutoUpdate"},
145 {904, nullptr, "TouchApplication"},
146 {905, nullptr, "RequestApplicationUpdate"},
147 {906, nullptr, "IsApplicationUpdateRequested"},
148 {907, nullptr, "WithdrawApplicationUpdateRequest"},
149 {908, nullptr, "ListApplicationRecordInstalledContentMeta"},
150 {909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
151 {1000, nullptr, "RequestVerifyApplicationDeprecated"},
152 {1001, nullptr, "CorruptApplicationForDebug"},
153 {1002, nullptr, "RequestVerifyAddOnContentsRights"},
154 {1003, nullptr, "RequestVerifyApplication"},
155 {1004, nullptr, "CorruptContentForDebug"},
156 {1200, nullptr, "NeedsUpdateVulnerability"},
157 {1300, nullptr, "IsAnyApplicationEntityInstalled"},
158 {1301, nullptr, "DeleteApplicationContentEntities"},
159 {1302, nullptr, "CleanupUnrecordedApplicationEntity"},
160 {1303, nullptr, "CleanupAddOnContentsWithNoRights"},
161 {1304, nullptr, "DeleteApplicationContentEntity"},
162 {1305, nullptr, "TryDeleteRunningApplicationEntity"},
163 {1306, nullptr, "TryDeleteRunningApplicationCompletely"},
164 {1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
165 {1400, nullptr, "PrepareShutdown"},
166 {1500, nullptr, "FormatSdCard"},
167 {1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
168 {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
169 {1504, nullptr, "InsertSdCard"},
170 {1505, nullptr, "RemoveSdCard"},
171 {1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
172 {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
173 {1700, nullptr, "ListApplicationDownloadingContentMeta"},
174 {1701, nullptr, "GetApplicationView"},
175 {1702, nullptr, "GetApplicationDownloadTaskStatus"},
176 {1703, nullptr, "GetApplicationViewDownloadErrorContext"},
177 {1800, nullptr, "IsNotificationSetupCompleted"},
178 {1801, nullptr, "GetLastNotificationInfoCount"},
179 {1802, nullptr, "ListLastNotificationInfo"},
180 {1803, nullptr, "ListNotificationTask"},
181 {1900, nullptr, "IsActiveAccount"},
182 {1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
183 {1902, nullptr, "GetApplicationTicketInfo"},
184 {2000, nullptr, "GetSystemDeliveryInfo"},
185 {2001, nullptr, "SelectLatestSystemDeliveryInfo"},
186 {2002, nullptr, "VerifyDeliveryProtocolVersion"},
187 {2003, nullptr, "GetApplicationDeliveryInfo"},
188 {2004, nullptr, "HasAllContentsToDeliver"},
189 {2005, nullptr, "CompareApplicationDeliveryInfo"},
190 {2006, nullptr, "CanDeliverApplication"},
191 {2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
192 {2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
193 {2009, nullptr, "EstimateRequiredSize"},
194 {2010, nullptr, "RequestReceiveApplication"},
195 {2011, nullptr, "CommitReceiveApplication"},
196 {2012, nullptr, "GetReceiveApplicationProgress"},
197 {2013, nullptr, "RequestSendApplication"},
198 {2014, nullptr, "GetSendApplicationProgress"},
199 {2015, nullptr, "CompareSystemDeliveryInfo"},
200 {2016, nullptr, "ListNotCommittedContentMeta"},
201 {2017, nullptr, "CreateDownloadTask"},
202 };
203 // clang-format on
204
205 RegisterHandlers(functions);
206 }
207};
208
209class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
210public:
211 explicit IApplicationVersionInterface() : ServiceFramework{"IApplicationVersionInterface"} {
212 // clang-format off
213 static const FunctionInfo functions[] = {
214 {0, nullptr, "GetLaunchRequiredVersion"},
215 {1, nullptr, "UpgradeLaunchRequiredVersion"},
216 {35, nullptr, "UpdateVersionList"},
217 {36, nullptr, "PushLaunchVersion"},
218 {37, nullptr, "ListRequiredVersion"},
219 {800, nullptr, "RequestVersionList"},
220 {801, nullptr, "ListVersionList"},
221 {802, nullptr, "RequestVersionListData"},
222 {1000, nullptr, "PerformAutoUpdate"},
223 };
224 // clang-format on
225
226 RegisterHandlers(functions);
227 }
228};
229
230class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
231public:
232 explicit IContentManagerInterface() : ServiceFramework{"IContentManagerInterface"} {
233 // clang-format off
234 static const FunctionInfo functions[] = {
235 {11, nullptr, "CalculateApplicationOccupiedSize"},
236 {43, nullptr, "CheckSdCardMountStatus"},
237 {47, nullptr, "GetTotalSpaceSize"},
238 {48, nullptr, "GetFreeSpaceSize"},
239 {600, nullptr, "CountApplicationContentMeta"},
240 {601, nullptr, "ListApplicationContentMetaStatus"},
241 {605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
242 {607, nullptr, "IsAnyApplicationRunning"},
243 };
244 // clang-format on
245
246 RegisterHandlers(functions);
247 }
248};
249
250class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
251public:
252 explicit IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
253 // clang-format off
254 static const FunctionInfo functions[] = {
255 {21, nullptr, "GetApplicationContentPath"},
256 {23, nullptr, "ResolveApplicationContentPath"},
257 };
258 // clang-format on
259
260 RegisterHandlers(functions);
261 }
262};
263
264class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
265public:
266 explicit IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} {
267 // clang-format off
268 static const FunctionInfo functions[] = {
269 {701, nullptr, "ClearTaskStatusList"},
270 {702, nullptr, "RequestDownloadTaskList"},
271 {703, nullptr, "RequestEnsureDownloadTask"},
272 {704, nullptr, "ListDownloadTaskStatus"},
273 {705, nullptr, "RequestDownloadTaskListData"},
274 {706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
275 {707, nullptr, "EnableAutoCommit"},
276 {708, nullptr, "DisableAutoCommit"},
277 {709, nullptr, "TriggerDynamicCommitEvent"},
278 };
279 // clang-format on
280
281 RegisterHandlers(functions);
282 }
283};
284
285class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
286public:
287 explicit IECommerceInterface() : ServiceFramework{"IECommerceInterface"} {
288 // clang-format off
289 static const FunctionInfo functions[] = {
290 {0, nullptr, "RequestLinkDevice"},
291 };
292 // clang-format on
293
294 RegisterHandlers(functions);
295 }
296};
297
298class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
299public:
300 explicit IFactoryResetInterface() : ServiceFramework{"IFactoryResetInterface"} {
301 // clang-format off
302 static const FunctionInfo functions[] = {
303 {100, nullptr, "ResetToFactorySettings"},
304 {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
305 {102, nullptr, "ResetToFactorySettingsForRefurbishment "},
306 };
307 // clang-format on
308
309 RegisterHandlers(functions);
310 }
311};
312
313class NS final : public ServiceFramework<NS> {
314public:
315 explicit NS(const char* name) : ServiceFramework{name} {
316 // clang-format off
317 static const FunctionInfo functions[] = {
318 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
319 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
320 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
321 {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
322 {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
323 {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
324 {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
325 {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
326 };
327 // clang-format on
328
329 RegisterHandlers(functions);
330 }
331
332private:
333 template <typename T>
334 void PushInterface(Kernel::HLERequestContext& ctx) {
335 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
336 rb.Push(RESULT_SUCCESS);
337 rb.PushIpcInterface<T>();
338
339 LOG_DEBUG(Service_NS, "called");
340 }
341};
342
343class NS_DEV final : public ServiceFramework<NS_DEV> {
344public:
345 explicit NS_DEV() : ServiceFramework{"ns:dev"} {
346 // clang-format off
347 static const FunctionInfo functions[] = {
348 {0, nullptr, "LaunchProgram"},
349 {1, nullptr, "TerminateProcess"},
350 {2, nullptr, "TerminateProgram"},
351 {3, nullptr, "GetShellEventHandle"},
352 {4, nullptr, "GetShellEventInfo"},
353 {5, nullptr, "TerminateApplication"},
354 {6, nullptr, "PrepareLaunchProgramFromHost"},
355 {7, nullptr, "LaunchApplication"},
356 {8, nullptr, "LaunchApplicationWithStorageId"},
357 };
358 // clang-format on
359
360 RegisterHandlers(functions);
361 }
362};
363
364class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> {
365public:
366 explicit ISystemUpdateControl() : ServiceFramework{"ISystemUpdateControl"} {
367 // clang-format off
368 static const FunctionInfo functions[] = {
369 {0, nullptr, "HasDownloaded"},
370 {1, nullptr, "RequestCheckLatestUpdate"},
371 {2, nullptr, "RequestDownloadLatestUpdate"},
372 {3, nullptr, "GetDownloadProgress"},
373 {4, nullptr, "ApplyDownloadedUpdate"},
374 {5, nullptr, "RequestPrepareCardUpdate"},
375 {6, nullptr, "GetPrepareCardUpdateProgress"},
376 {7, nullptr, "HasPreparedCardUpdate"},
377 {8, nullptr, "ApplyCardUpdate"},
378 {9, nullptr, "GetDownloadedEulaDataSize"},
379 {10, nullptr, "GetDownloadedEulaData"},
380 {11, nullptr, "SetupCardUpdate"},
381 {12, nullptr, "GetPreparedCardUpdateEulaDataSize"},
382 {13, nullptr, "GetPreparedCardUpdateEulaData"},
383 {14, nullptr, "SetupCardUpdateViaSystemUpdater"},
384 {15, nullptr, "HasReceived"},
385 {16, nullptr, "RequestReceiveSystemUpdate"},
386 {17, nullptr, "GetReceiveProgress"},
387 {18, nullptr, "ApplyReceivedUpdate"},
388 {19, nullptr, "GetReceivedEulaDataSize"},
389 {20, nullptr, "GetReceivedEulaData"},
390 {21, nullptr, "SetupToReceiveSystemUpdate"},
391 };
392 // clang-format on
393
394 RegisterHandlers(functions);
395 }
396};
397
398class NS_SU final : public ServiceFramework<NS_SU> {
399public:
400 explicit NS_SU() : ServiceFramework{"ns:su"} {
401 // clang-format off
402 static const FunctionInfo functions[] = {
403 {0, nullptr, "GetBackgroundNetworkUpdateState"},
404 {1, &NS_SU::OpenSystemUpdateControl, "OpenSystemUpdateControl"},
405 {2, nullptr, "NotifyExFatDriverRequired"},
406 {3, nullptr, "ClearExFatDriverStatusForDebug"},
407 {4, nullptr, "RequestBackgroundNetworkUpdate"},
408 {5, nullptr, "NotifyBackgroundNetworkUpdate"},
409 {6, nullptr, "NotifyExFatDriverDownloadedForDebug"},
410 {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"},
411 {10, nullptr, "NotifySystemUpdateForContentDelivery"},
412 {11, nullptr, "PrepareShutdown"},
413 {16, nullptr, "DestroySystemUpdateTask"},
414 {17, nullptr, "RequestSendSystemUpdate"},
415 {18, nullptr, "GetSendSystemUpdateProgress"},
416 };
417 // clang-format on
418
419 RegisterHandlers(functions);
420 }
421
422private:
423 void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
424 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
425 rb.Push(RESULT_SUCCESS);
426 rb.PushIpcInterface<ISystemUpdateControl>();
427
428 LOG_DEBUG(Service_NS, "called");
429 }
430};
431
432class NS_VM final : public ServiceFramework<NS_VM> {
433public:
434 explicit NS_VM() : ServiceFramework{"ns:vm"} {
435 // clang-format off
436 static const FunctionInfo functions[] = {
437 {1200, nullptr, "NeedsUpdateVulnerability"},
438 {1201, nullptr, "UpdateSafeSystemVersionForDebug"},
439 {1202, nullptr, "GetSafeSystemVersion"},
440 };
441 // clang-format on
442
443 RegisterHandlers(functions);
444 }
445};
446
10void InstallInterfaces(SM::ServiceManager& service_manager) { 447void InstallInterfaces(SM::ServiceManager& service_manager) {
448 std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
449 std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
450 std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
451 std::make_shared<NS>("ns:rt")->InstallAsService(service_manager);
452 std::make_shared<NS>("ns:web")->InstallAsService(service_manager);
453
454 std::make_shared<NS_DEV>()->InstallAsService(service_manager);
455 std::make_shared<NS_SU>()->InstallAsService(service_manager);
456 std::make_shared<NS_VM>()->InstallAsService(service_manager);
457
11 std::make_shared<PL_U>()->InstallAsService(service_manager); 458 std::make_shared<PL_U>()->InstallAsService(service_manager);
12} 459}
13 460
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index ed69a4325..8bc49935a 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -7,8 +7,8 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 8#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
9#include "core/hle/service/nvdrv/devices/nvmap.h" 9#include "core/hle/service/nvdrv/devices/nvmap.h"
10#include "video_core/gpu.h"
10#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
11#include "video_core/video_core.h"
12 12
13namespace Service::Nvidia::Devices { 13namespace Service::Nvidia::Devices {
14 14
@@ -30,9 +30,9 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
30 addr, offset, width, height, stride, static_cast<PixelFormat>(format), 30 addr, offset, width, height, stride, static_cast<PixelFormat>(format),
31 transform, crop_rect}; 31 transform, crop_rect};
32 32
33 Core::System::GetInstance().perf_stats.EndGameFrame(); 33 auto& instance = Core::System::GetInstance();
34 34 instance.perf_stats.EndGameFrame();
35 VideoCore::g_renderer->SwapBuffers(framebuffer); 35 instance.Renderer().SwapBuffers(framebuffer);
36} 36}
37 37
38} // namespace Service::Nvidia::Devices 38} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 57b128b40..be2b79256 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -2,14 +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> 5#include <cstring>
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/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" 9#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
10#include "core/hle/service/nvdrv/devices/nvmap.h" 10#include "core/hle/service/nvdrv/devices/nvmap.h"
11#include "video_core/memory_manager.h"
12#include "video_core/rasterizer_interface.h"
11#include "video_core/renderer_base.h" 13#include "video_core/renderer_base.h"
12#include "video_core/video_core.h"
13 14
14namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
15 16
@@ -150,15 +151,16 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
150 151
151 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); 152 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
152 153
153 auto& gpu = Core::System::GetInstance().GPU(); 154 const auto itr = buffer_mappings.find(params.offset);
154
155 auto itr = buffer_mappings.find(params.offset);
156
157 ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping"); 155 ASSERT_MSG(itr != buffer_mappings.end(), "Tried to unmap invalid mapping");
158 156
157 auto& system_instance = Core::System::GetInstance();
158
159 // Remove this memory region from the rasterizer cache. 159 // Remove this memory region from the rasterizer cache.
160 VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(params.offset, itr->second.size); 160 system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(params.offset,
161 itr->second.size);
161 162
163 auto& gpu = system_instance.GPU();
162 params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size); 164 params.offset = gpu.memory_manager->UnmapBuffer(params.offset, itr->second.size);
163 165
164 buffer_mappings.erase(itr->second.offset); 166 buffer_mappings.erase(itr->second.offset);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 671b092e1..5685eb2be 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -2,6 +2,9 @@
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 <cstdlib>
6#include <cstring>
7
5#include "common/assert.h" 8#include "common/assert.h"
6#include "common/logging/log.h" 9#include "common/logging/log.h"
7#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" 10#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 090261a60..6b496e9fe 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -5,8 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstdlib>
9#include <cstring>
10#include <vector> 8#include <vector>
11#include "common/common_types.h" 9#include "common/common_types.h"
12#include "core/hle/service/nvdrv/devices/nvdevice.h" 10#include "core/hle/service/nvdrv/devices/nvdevice.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 44e062f50..ae421247d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -2,7 +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 <cstring>
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/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 8#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
@@ -97,7 +97,9 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>&
97u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 97u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
98 LOG_DEBUG(Service_NVDRV, "called"); 98 LOG_DEBUG(Service_NVDRV, "called");
99 IoctlActiveSlotMask params{}; 99 IoctlActiveSlotMask params{};
100 std::memcpy(&params, input.data(), input.size()); 100 if (input.size() > 0) {
101 std::memcpy(&params, input.data(), input.size());
102 }
101 params.slot = 0x07; 103 params.slot = 0x07;
102 params.mask = 0x01; 104 params.mask = 0x01;
103 std::memcpy(output.data(), &params, output.size()); 105 std::memcpy(output.data(), &params, output.size());
@@ -107,7 +109,9 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
107u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 109u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
108 LOG_DEBUG(Service_NVDRV, "called"); 110 LOG_DEBUG(Service_NVDRV, "called");
109 IoctlZcullGetCtxSize params{}; 111 IoctlZcullGetCtxSize params{};
110 std::memcpy(&params, input.data(), input.size()); 112 if (input.size() > 0) {
113 std::memcpy(&params, input.data(), input.size());
114 }
111 params.size = 0x1; 115 params.size = 0x1;
112 std::memcpy(output.data(), &params, output.size()); 116 std::memcpy(output.data(), &params, output.size());
113 return 0; 117 return 0;
@@ -116,7 +120,11 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
116u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 120u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
117 LOG_DEBUG(Service_NVDRV, "called"); 121 LOG_DEBUG(Service_NVDRV, "called");
118 IoctlNvgpuGpuZcullGetInfoArgs params{}; 122 IoctlNvgpuGpuZcullGetInfoArgs params{};
119 std::memcpy(&params, input.data(), input.size()); 123
124 if (input.size() > 0) {
125 std::memcpy(&params, input.data(), input.size());
126 }
127
120 params.width_align_pixels = 0x20; 128 params.width_align_pixels = 0x20;
121 params.height_align_pixels = 0x20; 129 params.height_align_pixels = 0x20;
122 params.pixel_squares_by_aliquots = 0x400; 130 params.pixel_squares_by_aliquots = 0x400;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 126782573..116dabedb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -2,12 +2,14 @@
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 <cstring>
6#include <map>
7#include "common/assert.h" 6#include "common/assert.h"
8#include "common/logging/log.h" 7#include "common/logging/log.h"
9#include "core/core.h" 8#include "core/core.h"
10#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
10#include "core/memory.h"
11#include "video_core/gpu.h"
12#include "video_core/memory_manager.h"
11 13
12namespace Service::Nvidia::Devices { 14namespace Service::Nvidia::Devices {
13 15
@@ -132,9 +134,12 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
132 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", 134 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
133 params.address, params.num_entries, params.flags); 135 params.address, params.num_entries, params.flags);
134 136
135 auto entries = std::vector<IoctlGpfifoEntry>(); 137 ASSERT_MSG(input.size() ==
136 entries.resize(params.num_entries); 138 sizeof(IoctlSubmitGpfifo) + params.num_entries * sizeof(IoctlGpfifoEntry),
137 std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)], 139 "Incorrect input size");
140
141 std::vector<IoctlGpfifoEntry> entries(params.num_entries);
142 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
138 params.num_entries * sizeof(IoctlGpfifoEntry)); 143 params.num_entries * sizeof(IoctlGpfifoEntry));
139 for (auto entry : entries) { 144 for (auto entry : entries) {
140 Tegra::GPUVAddr va_addr = entry.Address(); 145 Tegra::GPUVAddr va_addr = entry.Address();
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index aa8df2e6e..650ed8fbc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -6,6 +6,7 @@
6 6
7#include <memory> 7#include <memory>
8#include <vector> 8#include <vector>
9#include "common/bit_field.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "common/swap.h" 11#include "common/swap.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h" 12#include "core/hle/service/nvdrv/devices/nvdevice.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index b51c73ee8..364619e67 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
5#include "common/assert.h" 7#include "common/assert.h"
6#include "common/logging/log.h" 8#include "common/logging/log.h"
7#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" 9#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 0192aecdd..6ad74421b 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -4,11 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <cstdlib>
9#include <cstring>
10#include <vector> 7#include <vector>
11#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/swap.h"
12#include "core/hle/service/nvdrv/devices/nvdevice.h" 10#include "core/hle/service/nvdrv/devices/nvdevice.h"
13 11
14namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 724eeb139..e9305bfb3 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -3,7 +3,7 @@
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#include <cstring>
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 959b5ba29..1c3529bb6 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <string>
9#include "core/hle/kernel/event.h" 8#include "core/hle/kernel/event.h"
10#include "core/hle/service/nvdrv/nvdrv.h" 9#include "core/hle/service/nvdrv/nvdrv.h"
11#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 1555ea806..e8b30921a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -54,7 +54,7 @@ u32 Module::Open(const std::string& device_name) {
54 return fd; 54 return fd;
55} 55}
56 56
57u32 Module::Ioctl(u32 fd, u32_le command, const std::vector<u8>& input, std::vector<u8>& output) { 57u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, std::vector<u8>& output) {
58 auto itr = open_files.find(fd); 58 auto itr = open_files.find(fd);
59 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); 59 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
60 60
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index 9ca6e5512..0e8e21bad 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -4,8 +4,6 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/hle/ipc_helpers.h"
8#include "core/hle/service/nvdrv/nvdrv.h"
9#include "core/hle/service/nvdrv/nvmemp.h" 7#include "core/hle/service/nvdrv/nvmemp.h"
10 8
11namespace Service::Nvidia { 9namespace Service::Nvidia {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 7132b18ad..adf180509 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -4,9 +4,8 @@
4 4
5#include <algorithm> 5#include <algorithm>
6 6
7#include "common/alignment.h" 7#include "common/assert.h"
8#include "common/scope_exit.h" 8#include "common/logging/log.h"
9#include "core/core_timing.h"
10#include "core/hle/service/nvflinger/buffer_queue.h" 9#include "core/hle/service/nvflinger/buffer_queue.h"
11 10
12namespace Service { 11namespace Service {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 5344441e1..570aa8493 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -3,8 +3,11 @@
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 <boost/optional.hpp>
6 7
7#include "common/alignment.h" 8#include "common/alignment.h"
9#include "common/assert.h"
10#include "common/logging/log.h"
8#include "common/microprofile.h" 11#include "common/microprofile.h"
9#include "common/scope_exit.h" 12#include "common/scope_exit.h"
10#include "core/core.h" 13#include "core/core.h"
@@ -31,7 +34,7 @@ NVFlinger::NVFlinger() {
31 34
32 // Schedule the screen composition events 35 // Schedule the screen composition events
33 composition_event = 36 composition_event =
34 CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) { 37 CoreTiming::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) {
35 Compose(); 38 Compose();
36 CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); 39 CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event);
37 }); 40 });
@@ -43,7 +46,7 @@ NVFlinger::~NVFlinger() {
43 CoreTiming::UnscheduleEvent(composition_event, 0); 46 CoreTiming::UnscheduleEvent(composition_event, 0);
44} 47}
45 48
46u64 NVFlinger::OpenDisplay(const std::string& name) { 49u64 NVFlinger::OpenDisplay(std::string_view name) {
47 LOG_WARNING(Service, "Opening display {}", name); 50 LOG_WARNING(Service, "Opening display {}", name);
48 51
49 // TODO(Subv): Currently we only support the Default display. 52 // TODO(Subv): Currently we only support the Default display.
@@ -127,9 +130,11 @@ void NVFlinger::Compose() {
127 MicroProfileFlip(); 130 MicroProfileFlip();
128 131
129 if (buffer == boost::none) { 132 if (buffer == boost::none) {
133 auto& system_instance = Core::System::GetInstance();
134
130 // There was no queued buffer to draw, render previous frame 135 // There was no queued buffer to draw, render previous frame
131 Core::System::GetInstance().perf_stats.EndGameFrame(); 136 system_instance.perf_stats.EndGameFrame();
132 VideoCore::g_renderer->SwapBuffers({}); 137 system_instance.Renderer().SwapBuffers({});
133 continue; 138 continue;
134 } 139 }
135 140
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 2c908297b..5374df175 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -5,7 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <boost/optional.hpp> 8#include <string>
9#include <string_view>
10#include <vector>
11
12#include "common/common_types.h"
9#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/event.h"
10 14
11namespace CoreTiming { 15namespace CoreTiming {
@@ -41,7 +45,7 @@ public:
41 ~NVFlinger(); 45 ~NVFlinger();
42 46
43 /// Opens the specified display and returns the id. 47 /// Opens the specified display and returns the id.
44 u64 OpenDisplay(const std::string& name); 48 u64 OpenDisplay(std::string_view name);
45 49
46 /// Creates a layer on the specified display and returns the layer id. 50 /// Creates a layer on the specified display and returns the layer id.
47 u64 CreateLayer(u64 display_id); 51 u64 CreateLayer(u64 display_id);
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
new file mode 100644
index 000000000..39cf05eba
--- /dev/null
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -0,0 +1,64 @@
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 <memory>
6
7#include "core/hle/service/pcie/pcie.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::PCIe {
12
13class ISession final : public ServiceFramework<ISession> {
14public:
15 explicit ISession() : ServiceFramework{"ISession"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "QueryFunctions"},
19 {1, nullptr, "AcquireFunction"},
20 {2, nullptr, "ReleaseFunction"},
21 {3, nullptr, "GetFunctionState"},
22 {4, nullptr, "GetBarProfile"},
23 {5, nullptr, "ReadConfig"},
24 {6, nullptr, "WriteConfig"},
25 {7, nullptr, "ReadBarRegion"},
26 {8, nullptr, "WriteBarRegion"},
27 {9, nullptr, "FindCapability"},
28 {10, nullptr, "FindExtendedCapability"},
29 {11, nullptr, "MapDma"},
30 {12, nullptr, "UnmapDma"},
31 {13, nullptr, "UnmapDmaBusAddress"},
32 {14, nullptr, "GetDmaBusAddress"},
33 {15, nullptr, "GetDmaBusAddressRange"},
34 {16, nullptr, "SetDmaEnable"},
35 {17, nullptr, "AcquireIrq"},
36 {18, nullptr, "ReleaseIrq"},
37 {19, nullptr, "SetIrqEnable"},
38 {20, nullptr, "SetAspmEnable"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43 }
44};
45
46class PCIe final : public ServiceFramework<PCIe> {
47public:
48 explicit PCIe() : ServiceFramework{"pcie"} {
49 // clang-format off
50 static const FunctionInfo functions[] = {
51 {0, nullptr, "RegisterClassDriver"},
52 {1, nullptr, "QueryFunctionsUnregistered"},
53 };
54 // clang-format on
55
56 RegisterHandlers(functions);
57 }
58};
59
60void InstallInterfaces(SM::ServiceManager& sm) {
61 std::make_shared<PCIe>()->InstallAsService(sm);
62}
63
64} // namespace Service::PCIe
diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h
new file mode 100644
index 000000000..59c22ca45
--- /dev/null
+++ b/src/core/hle/service/pcie/pcie.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::PCIe {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::PCIe
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
new file mode 100644
index 000000000..d6891a659
--- /dev/null
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -0,0 +1,84 @@
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 <memory>
6
7#include "core/hle/service/pcv/pcv.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::PCV {
12
13class PCV final : public ServiceFramework<PCV> {
14public:
15 explicit PCV() : ServiceFramework{"pcv"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SetPowerEnabled"},
19 {1, nullptr, "SetClockEnabled"},
20 {2, nullptr, "SetClockRate"},
21 {3, nullptr, "GetClockRate"},
22 {4, nullptr, "GetState"},
23 {5, nullptr, "GetPossibleClockRates"},
24 {6, nullptr, "SetMinVClockRate"},
25 {7, nullptr, "SetReset"},
26 {8, nullptr, "SetVoltageEnabled"},
27 {9, nullptr, "GetVoltageEnabled"},
28 {10, nullptr, "GetVoltageRange"},
29 {11, nullptr, "SetVoltageValue"},
30 {12, nullptr, "GetVoltageValue"},
31 {13, nullptr, "GetTemperatureThresholds"},
32 {14, nullptr, "SetTemperature"},
33 {15, nullptr, "Initialize"},
34 {16, nullptr, "IsInitialized"},
35 {17, nullptr, "Finalize"},
36 {18, nullptr, "PowerOn"},
37 {19, nullptr, "PowerOff"},
38 {20, nullptr, "ChangeVoltage"},
39 {21, nullptr, "GetPowerClockInfoEvent"},
40 {22, nullptr, "GetOscillatorClock"},
41 {23, nullptr, "GetDvfsTable"},
42 {24, nullptr, "GetModuleStateTable"},
43 {25, nullptr, "GetPowerDomainStateTable"},
44 {26, nullptr, "GetFuseInfo"},
45 };
46 // clang-format on
47
48 RegisterHandlers(functions);
49 }
50};
51
52class PCV_ARB final : public ServiceFramework<PCV_ARB> {
53public:
54 explicit PCV_ARB() : ServiceFramework{"pcv:arb"} {
55 // clang-format off
56 static const FunctionInfo functions[] = {
57 {0, nullptr, "ReleaseControl"},
58 };
59 // clang-format on
60
61 RegisterHandlers(functions);
62 }
63};
64
65class PCV_IMM final : public ServiceFramework<PCV_IMM> {
66public:
67 explicit PCV_IMM() : ServiceFramework{"pcv:imm"} {
68 // clang-format off
69 static const FunctionInfo functions[] = {
70 {0, nullptr, "SetClockRate"},
71 };
72 // clang-format on
73
74 RegisterHandlers(functions);
75 }
76};
77
78void InstallInterfaces(SM::ServiceManager& sm) {
79 std::make_shared<PCV>()->InstallAsService(sm);
80 std::make_shared<PCV_ARB>()->InstallAsService(sm);
81 std::make_shared<PCV_IMM>()->InstallAsService(sm);
82}
83
84} // namespace Service::PCV
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h
new file mode 100644
index 000000000..219a893c3
--- /dev/null
+++ b/src/core/hle/service/pcv/pcv.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::PCV {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::PCV
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
new file mode 100644
index 000000000..bbad870a2
--- /dev/null
+++ b/src/core/hle/service/psc/psc.cpp
@@ -0,0 +1,77 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/service/psc/psc.h"
10#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h"
12
13namespace Service::PSC {
14
15class PSC_C final : public ServiceFramework<PSC_C> {
16public:
17 explicit PSC_C() : ServiceFramework{"psc:c"} {
18 // clang-format off
19 static const FunctionInfo functions[] = {
20 {0, nullptr, "Unknown1"},
21 {1, nullptr, "Unknown2"},
22 {2, nullptr, "Unknown3"},
23 {3, nullptr, "Unknown4"},
24 {4, nullptr, "Unknown5"},
25 {5, nullptr, "Unknown6"},
26 {6, nullptr, "Unknown7"},
27 };
28 // clang-format on
29
30 RegisterHandlers(functions);
31 }
32};
33
34class IPmModule final : public ServiceFramework<IPmModule> {
35public:
36 explicit IPmModule() : ServiceFramework{"IPmModule"} {
37 // clang-format off
38 static const FunctionInfo functions[] = {
39 {0, nullptr, "Initialize"},
40 {1, nullptr, "GetRequest"},
41 {2, nullptr, "Acknowledge"},
42 {3, nullptr, "Unknown1"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47 }
48};
49
50class PSC_M final : public ServiceFramework<PSC_M> {
51public:
52 explicit PSC_M() : ServiceFramework{"psc:m"} {
53 // clang-format off
54 static const FunctionInfo functions[] = {
55 {0, &PSC_M::GetPmModule, "GetPmModule"},
56 };
57 // clang-format on
58
59 RegisterHandlers(functions);
60 }
61
62private:
63 void GetPmModule(Kernel::HLERequestContext& ctx) {
64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
65 rb.Push(RESULT_SUCCESS);
66 rb.PushIpcInterface<IPmModule>();
67
68 LOG_DEBUG(Service_PSC, "called");
69 }
70};
71
72void InstallInterfaces(SM::ServiceManager& sm) {
73 std::make_shared<PSC_C>()->InstallAsService(sm);
74 std::make_shared<PSC_M>()->InstallAsService(sm);
75}
76
77} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
new file mode 100644
index 000000000..5052eb02c
--- /dev/null
+++ b/src/core/hle/service/psc/psc.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::PSC {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::PSC
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 8b84fd349..889cdd41a 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -19,28 +19,42 @@
19#include "core/hle/service/am/am.h" 19#include "core/hle/service/am/am.h"
20#include "core/hle/service/aoc/aoc_u.h" 20#include "core/hle/service/aoc/aoc_u.h"
21#include "core/hle/service/apm/apm.h" 21#include "core/hle/service/apm/apm.h"
22#include "core/hle/service/arp/arp.h"
22#include "core/hle/service/audio/audio.h" 23#include "core/hle/service/audio/audio.h"
23#include "core/hle/service/bcat/bcat.h" 24#include "core/hle/service/bcat/bcat.h"
25#include "core/hle/service/bpc/bpc.h"
26#include "core/hle/service/btdrv/btdrv.h"
27#include "core/hle/service/btm/btm.h"
28#include "core/hle/service/caps/caps.h"
24#include "core/hle/service/erpt/erpt.h" 29#include "core/hle/service/erpt/erpt.h"
25#include "core/hle/service/es/es.h" 30#include "core/hle/service/es/es.h"
26#include "core/hle/service/eupld/eupld.h" 31#include "core/hle/service/eupld/eupld.h"
27#include "core/hle/service/fatal/fatal.h" 32#include "core/hle/service/fatal/fatal.h"
33#include "core/hle/service/fgm/fgm.h"
28#include "core/hle/service/filesystem/filesystem.h" 34#include "core/hle/service/filesystem/filesystem.h"
29#include "core/hle/service/friend/friend.h" 35#include "core/hle/service/friend/friend.h"
30#include "core/hle/service/grc/grc.h" 36#include "core/hle/service/grc/grc.h"
31#include "core/hle/service/hid/hid.h" 37#include "core/hle/service/hid/hid.h"
38#include "core/hle/service/lbl/lbl.h"
32#include "core/hle/service/ldn/ldn.h" 39#include "core/hle/service/ldn/ldn.h"
33#include "core/hle/service/ldr/ldr.h" 40#include "core/hle/service/ldr/ldr.h"
34#include "core/hle/service/lm/lm.h" 41#include "core/hle/service/lm/lm.h"
42#include "core/hle/service/mig/mig.h"
43#include "core/hle/service/mii/mii.h"
35#include "core/hle/service/mm/mm_u.h" 44#include "core/hle/service/mm/mm_u.h"
45#include "core/hle/service/ncm/ncm.h"
46#include "core/hle/service/nfc/nfc.h"
36#include "core/hle/service/nfp/nfp.h" 47#include "core/hle/service/nfp/nfp.h"
37#include "core/hle/service/nifm/nifm.h" 48#include "core/hle/service/nifm/nifm.h"
38#include "core/hle/service/nim/nim.h" 49#include "core/hle/service/nim/nim.h"
39#include "core/hle/service/ns/ns.h" 50#include "core/hle/service/ns/ns.h"
40#include "core/hle/service/nvdrv/nvdrv.h" 51#include "core/hle/service/nvdrv/nvdrv.h"
52#include "core/hle/service/pcie/pcie.h"
41#include "core/hle/service/pctl/pctl.h" 53#include "core/hle/service/pctl/pctl.h"
54#include "core/hle/service/pcv/pcv.h"
42#include "core/hle/service/pm/pm.h" 55#include "core/hle/service/pm/pm.h"
43#include "core/hle/service/prepo/prepo.h" 56#include "core/hle/service/prepo/prepo.h"
57#include "core/hle/service/psc/psc.h"
44#include "core/hle/service/service.h" 58#include "core/hle/service/service.h"
45#include "core/hle/service/set/settings.h" 59#include "core/hle/service/set/settings.h"
46#include "core/hle/service/sm/controller.h" 60#include "core/hle/service/sm/controller.h"
@@ -49,7 +63,9 @@
49#include "core/hle/service/spl/module.h" 63#include "core/hle/service/spl/module.h"
50#include "core/hle/service/ssl/ssl.h" 64#include "core/hle/service/ssl/ssl.h"
51#include "core/hle/service/time/time.h" 65#include "core/hle/service/time/time.h"
66#include "core/hle/service/usb/usb.h"
52#include "core/hle/service/vi/vi.h" 67#include "core/hle/service/vi/vi.h"
68#include "core/hle/service/wlan/wlan.h"
53 69
54using Kernel::ClientPort; 70using Kernel::ClientPort;
55using Kernel::ServerPort; 71using Kernel::ServerPort;
@@ -193,34 +209,50 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
193 AM::InstallInterfaces(*sm, nv_flinger); 209 AM::InstallInterfaces(*sm, nv_flinger);
194 AOC::InstallInterfaces(*sm); 210 AOC::InstallInterfaces(*sm);
195 APM::InstallInterfaces(*sm); 211 APM::InstallInterfaces(*sm);
196 BCAT::InstallInterfaces(*sm); 212 ARP::InstallInterfaces(*sm);
197 Audio::InstallInterfaces(*sm); 213 Audio::InstallInterfaces(*sm);
214 BCAT::InstallInterfaces(*sm);
215 BPC::InstallInterfaces(*sm);
216 BtDrv::InstallInterfaces(*sm);
217 BTM::InstallInterfaces(*sm);
218 Capture::InstallInterfaces(*sm);
198 ERPT::InstallInterfaces(*sm); 219 ERPT::InstallInterfaces(*sm);
199 ES::InstallInterfaces(*sm); 220 ES::InstallInterfaces(*sm);
200 EUPLD::InstallInterfaces(*sm); 221 EUPLD::InstallInterfaces(*sm);
201 Fatal::InstallInterfaces(*sm); 222 Fatal::InstallInterfaces(*sm);
223 FGM::InstallInterfaces(*sm);
202 FileSystem::InstallInterfaces(*sm); 224 FileSystem::InstallInterfaces(*sm);
203 Friend::InstallInterfaces(*sm); 225 Friend::InstallInterfaces(*sm);
204 GRC::InstallInterfaces(*sm); 226 GRC::InstallInterfaces(*sm);
205 HID::InstallInterfaces(*sm); 227 HID::InstallInterfaces(*sm);
228 LBL::InstallInterfaces(*sm);
206 LDN::InstallInterfaces(*sm); 229 LDN::InstallInterfaces(*sm);
207 LDR::InstallInterfaces(*sm); 230 LDR::InstallInterfaces(*sm);
208 LM::InstallInterfaces(*sm); 231 LM::InstallInterfaces(*sm);
232 Migration::InstallInterfaces(*sm);
233 Mii::InstallInterfaces(*sm);
209 MM::InstallInterfaces(*sm); 234 MM::InstallInterfaces(*sm);
235 NCM::InstallInterfaces(*sm);
236 NFC::InstallInterfaces(*sm);
210 NFP::InstallInterfaces(*sm); 237 NFP::InstallInterfaces(*sm);
211 NIFM::InstallInterfaces(*sm); 238 NIFM::InstallInterfaces(*sm);
212 NIM::InstallInterfaces(*sm); 239 NIM::InstallInterfaces(*sm);
213 NS::InstallInterfaces(*sm); 240 NS::InstallInterfaces(*sm);
214 Nvidia::InstallInterfaces(*sm); 241 Nvidia::InstallInterfaces(*sm);
242 PCIe::InstallInterfaces(*sm);
215 PCTL::InstallInterfaces(*sm); 243 PCTL::InstallInterfaces(*sm);
244 PCV::InstallInterfaces(*sm);
216 PlayReport::InstallInterfaces(*sm); 245 PlayReport::InstallInterfaces(*sm);
217 PM::InstallInterfaces(*sm); 246 PM::InstallInterfaces(*sm);
247 PSC::InstallInterfaces(*sm);
248 Set::InstallInterfaces(*sm);
218 Sockets::InstallInterfaces(*sm); 249 Sockets::InstallInterfaces(*sm);
219 SPL::InstallInterfaces(*sm); 250 SPL::InstallInterfaces(*sm);
220 SSL::InstallInterfaces(*sm); 251 SSL::InstallInterfaces(*sm);
221 Time::InstallInterfaces(*sm); 252 Time::InstallInterfaces(*sm);
253 USB::InstallInterfaces(*sm);
222 VI::InstallInterfaces(*sm, nv_flinger); 254 VI::InstallInterfaces(*sm, nv_flinger);
223 Set::InstallInterfaces(*sm); 255 WLAN::InstallInterfaces(*sm);
224 256
225 LOG_DEBUG(Service, "initialized OK"); 257 LOG_DEBUG(Service, "initialized OK");
226} 258}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 180f22703..046c5e18d 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -8,10 +8,9 @@
8#include <string> 8#include <string>
9#include <unordered_map> 9#include <unordered_map>
10#include <boost/container/flat_map.hpp> 10#include <boost/container/flat_map.hpp>
11#include "common/bit_field.h"
12#include "common/common_types.h" 11#include "common/common_types.h"
13#include "core/hle/kernel/hle_ipc.h" 12#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/object.h"
15 14
16//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
17// Namespace Service 16// Namespace Service
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 1651f6122..a461e72ec 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/kernel/client_port.h" 8#include "core/hle/kernel/client_port.h"
9#include "core/hle/kernel/client_session.h" 9#include "core/hle/kernel/client_session.h"
10#include "core/hle/service/set/set.h" 10#include "core/hle/service/set/set.h"
11#include "core/settings.h"
11 12
12namespace Service::Set { 13namespace Service::Set {
13 14
@@ -31,6 +32,10 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
31 LanguageCode::ZH_HANT, 32 LanguageCode::ZH_HANT,
32}}; 33}};
33 34
35LanguageCode GetLanguageCodeFromIndex(size_t index) {
36 return available_language_codes.at(index);
37}
38
34void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { 39void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
35 ctx.WriteBuffer(available_language_codes); 40 ctx.WriteBuffer(available_language_codes);
36 41
@@ -49,9 +54,17 @@ void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
49 LOG_DEBUG(Service_SET, "called"); 54 LOG_DEBUG(Service_SET, "called");
50} 55}
51 56
57void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
58 IPC::ResponseBuilder rb{ctx, 4};
59 rb.Push(RESULT_SUCCESS);
60 rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index]));
61
62 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
63}
64
52SET::SET() : ServiceFramework("set") { 65SET::SET() : ServiceFramework("set") {
53 static const FunctionInfo functions[] = { 66 static const FunctionInfo functions[] = {
54 {0, nullptr, "GetLanguageCode"}, 67 {0, &SET::GetLanguageCode, "GetLanguageCode"},
55 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, 68 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
56 {2, nullptr, "MakeLanguageCode"}, 69 {2, nullptr, "MakeLanguageCode"},
57 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, 70 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index a2472ec4c..4232b6162 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -28,6 +28,7 @@ enum class LanguageCode : u64 {
28 ZH_HANS = 0x00736E61482D687A, 28 ZH_HANS = 0x00736E61482D687A,
29 ZH_HANT = 0x00746E61482D687A, 29 ZH_HANT = 0x00746E61482D687A,
30}; 30};
31LanguageCode GetLanguageCodeFromIndex(size_t idx);
31 32
32class SET final : public ServiceFramework<SET> { 33class SET final : public ServiceFramework<SET> {
33public: 34public:
@@ -35,6 +36,7 @@ public:
35 ~SET() = default; 36 ~SET() = default;
36 37
37private: 38private:
39 void GetLanguageCode(Kernel::HLERequestContext& ctx);
38 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); 40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
39 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); 41 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
40}; 42};
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index e2a00e4f6..e8ea62f08 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -4,9 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
7#include <string> 8#include <string>
8#include <unordered_map> 9#include <unordered_map>
9#include "core/hle/kernel/kernel.h" 10
11#include "core/hle/kernel/object.h"
10#include "core/hle/result.h" 12#include "core/hle/result.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12 14
@@ -19,6 +21,8 @@ class SessionRequestHandler;
19 21
20namespace Service::SM { 22namespace Service::SM {
21 23
24class Controller;
25
22/// Interface to "sm:" service 26/// Interface to "sm:" service
23class SM final : public ServiceFramework<SM> { 27class SM final : public ServiceFramework<SM> {
24public: 28public:
@@ -32,8 +36,6 @@ private:
32 std::shared_ptr<ServiceManager> service_manager; 36 std::shared_ptr<ServiceManager> service_manager;
33}; 37};
34 38
35class Controller;
36
37constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(-1); 39constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(-1);
38constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); 40constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1);
39constexpr ResultCode ERR_INVALID_NAME_SIZE(-1); 41constexpr ResultCode ERR_INVALID_NAME_SIZE(-1);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 37b58bb77..2172c681b 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -80,8 +80,8 @@ public:
80 {5, nullptr, "GetTimeZoneRuleVersion"}, 80 {5, nullptr, "GetTimeZoneRuleVersion"},
81 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, 81 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
82 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 82 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
83 {200, nullptr, "ToPosixTime"}, 83 {201, nullptr, "ToPosixTime"},
84 {201, nullptr, "ToPosixTimeWithMyRule"}, 84 {202, nullptr, "ToPosixTimeWithMyRule"},
85 }; 85 };
86 RegisterHandlers(functions); 86 RegisterHandlers(functions);
87 } 87 }
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
new file mode 100644
index 000000000..e7fb5a419
--- /dev/null
+++ b/src/core/hle/service/usb/usb.cpp
@@ -0,0 +1,238 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h"
12#include "core/hle/service/usb/usb.h"
13
14namespace Service::USB {
15
16class IDsInterface final : public ServiceFramework<IDsInterface> {
17public:
18 explicit IDsInterface() : ServiceFramework{"IDsInterface"} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, nullptr, "GetDsEndpoint"},
22 {1, nullptr, "GetSetupEvent"},
23 {2, nullptr, "Unknown"},
24 {3, nullptr, "EnableInterface"},
25 {4, nullptr, "DisableInterface"},
26 {5, nullptr, "CtrlInPostBufferAsync"},
27 {6, nullptr, "CtrlOutPostBufferAsync"},
28 {7, nullptr, "GetCtrlInCompletionEvent"},
29 {8, nullptr, "GetCtrlInReportData"},
30 {9, nullptr, "GetCtrlOutCompletionEvent"},
31 {10, nullptr, "GetCtrlOutReportData"},
32 {11, nullptr, "StallCtrl"},
33 {12, nullptr, "AppendConfigurationData"},
34 };
35 // clang-format on
36
37 RegisterHandlers(functions);
38 }
39};
40
41class USB_DS final : public ServiceFramework<USB_DS> {
42public:
43 explicit USB_DS() : ServiceFramework{"usb:ds"} {
44 // clang-format off
45 static const FunctionInfo functions[] = {
46 {0, nullptr, "BindDevice"},
47 {1, nullptr, "BindClientProcess"},
48 {2, nullptr, "GetDsInterface"},
49 {3, nullptr, "GetStateChangeEvent"},
50 {4, nullptr, "GetState"},
51 {5, nullptr, "ClearDeviceData"},
52 {6, nullptr, "AddUsbStringDescriptor"},
53 {7, nullptr, "DeleteUsbStringDescriptor"},
54 {8, nullptr, "SetUsbDeviceDescriptor"},
55 {9, nullptr, "SetBinaryObjectStore"},
56 {10, nullptr, "Enable"},
57 {11, nullptr, "Disable"},
58 };
59 // clang-format on
60
61 RegisterHandlers(functions);
62 }
63};
64
65class IClientEpSession final : public ServiceFramework<IClientEpSession> {
66public:
67 explicit IClientEpSession() : ServiceFramework{"IClientEpSession"} {
68 // clang-format off
69 static const FunctionInfo functions[] = {
70 {0, nullptr, "Unknown1"},
71 {1, nullptr, "Unknown2"},
72 {2, nullptr, "Unknown3"},
73 {3, nullptr, "Unknown4"},
74 {4, nullptr, "PostBufferAsync"},
75 {5, nullptr, "Unknown5"},
76 {6, nullptr, "Unknown6"},
77 {7, nullptr, "Unknown7"},
78 {8, nullptr, "Unknown8"},
79 };
80 // clang-format on
81
82 RegisterHandlers(functions);
83 }
84};
85
86class IClientIfSession final : public ServiceFramework<IClientIfSession> {
87public:
88 explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} {
89 // clang-format off
90 static const FunctionInfo functions[] = {
91 {0, nullptr, "Unknown1"},
92 {1, nullptr, "Unknown2"},
93 {2, nullptr, "Unknown3"},
94 {3, nullptr, "Unknown4"},
95 {4, nullptr, "Unknown5"},
96 {5, nullptr, "CtrlXferAsync"},
97 {6, nullptr, "Unknown6"},
98 {7, nullptr, "GetCtrlXferReport"},
99 {8, nullptr, "Unknown7"},
100 {9, nullptr, "GetClientEpSession"},
101 };
102 // clang-format on
103
104 RegisterHandlers(functions);
105 }
106};
107
108class USB_HS final : public ServiceFramework<USB_HS> {
109public:
110 explicit USB_HS() : ServiceFramework{"usb:hs"} {
111 // clang-format off
112 static const FunctionInfo functions[] = {
113 {0, nullptr, "BindClientProcess"},
114 {1, nullptr, "Unknown1"},
115 {2, nullptr, "Unknown2"},
116 {3, nullptr, "Unknown3"},
117 {4, nullptr, "Unknown4"},
118 {5, nullptr, "Unknown5"},
119 {6, nullptr, "GetInterfaceStateChangeEvent"},
120 {7, nullptr, "GetClientIfSession"},
121 };
122 // clang-format on
123
124 RegisterHandlers(functions);
125 }
126};
127
128class IPdSession final : public ServiceFramework<IPdSession> {
129public:
130 explicit IPdSession() : ServiceFramework{"IPdSession"} {
131 // clang-format off
132 static const FunctionInfo functions[] = {
133 {0, nullptr, "BindNoticeEvent"},
134 {1, nullptr, "Unknown1"},
135 {2, nullptr, "GetStatus"},
136 {3, nullptr, "GetNotice"},
137 {4, nullptr, "Unknown2"},
138 {5, nullptr, "Unknown3"},
139 {6, nullptr, "ReplyPowerRequest"},
140 };
141 // clang-format on
142
143 RegisterHandlers(functions);
144 }
145};
146
147class USB_PD final : public ServiceFramework<USB_PD> {
148public:
149 explicit USB_PD() : ServiceFramework{"usb:pd"} {
150 // clang-format off
151 static const FunctionInfo functions[] = {
152 {0, &USB_PD::GetPdSession, "GetPdSession"},
153 };
154 // clang-format on
155
156 RegisterHandlers(functions);
157 }
158
159private:
160 void GetPdSession(Kernel::HLERequestContext& ctx) {
161 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
162 rb.Push(RESULT_SUCCESS);
163 rb.PushIpcInterface<IPdSession>();
164
165 LOG_DEBUG(Service_USB, "called");
166 }
167};
168
169class IPdCradleSession final : public ServiceFramework<IPdCradleSession> {
170public:
171 explicit IPdCradleSession() : ServiceFramework{"IPdCradleSession"} {
172 // clang-format off
173 static const FunctionInfo functions[] = {
174 {0, nullptr, "VdmUserWrite"},
175 {1, nullptr, "VdmUserRead"},
176 {2, nullptr, "Vdm20Init"},
177 {3, nullptr, "GetFwType"},
178 {4, nullptr, "GetFwRevision"},
179 {5, nullptr, "GetManufacturerId"},
180 {6, nullptr, "GetDeviceId"},
181 {7, nullptr, "Unknown1"},
182 {8, nullptr, "Unknown2"},
183 };
184 // clang-format on
185
186 RegisterHandlers(functions);
187 }
188};
189
190class USB_PD_C final : public ServiceFramework<USB_PD_C> {
191public:
192 explicit USB_PD_C() : ServiceFramework{"usb:pd:c"} {
193 // clang-format off
194 static const FunctionInfo functions[] = {
195 {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"},
196 };
197 // clang-format on
198
199 RegisterHandlers(functions);
200 }
201
202private:
203 void GetPdCradleSession(Kernel::HLERequestContext& ctx) {
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(RESULT_SUCCESS);
206 rb.PushIpcInterface<IPdCradleSession>();
207
208 LOG_DEBUG(Service_USB, "called");
209 }
210};
211
212class USB_PM final : public ServiceFramework<USB_PM> {
213public:
214 explicit USB_PM() : ServiceFramework{"usb:pm"} {
215 // clang-format off
216 static const FunctionInfo functions[] = {
217 {0, nullptr, "Unknown1"},
218 {1, nullptr, "Unknown2"},
219 {2, nullptr, "Unknown3"},
220 {3, nullptr, "Unknown4"},
221 {4, nullptr, "Unknown5"},
222 {5, nullptr, "Unknown6"},
223 };
224 // clang-format on
225
226 RegisterHandlers(functions);
227 }
228};
229
230void InstallInterfaces(SM::ServiceManager& sm) {
231 std::make_shared<USB_DS>()->InstallAsService(sm);
232 std::make_shared<USB_HS>()->InstallAsService(sm);
233 std::make_shared<USB_PD>()->InstallAsService(sm);
234 std::make_shared<USB_PD_C>()->InstallAsService(sm);
235 std::make_shared<USB_PM>()->InstallAsService(sm);
236}
237
238} // namespace Service::USB
diff --git a/src/core/hle/service/usb/usb.h b/src/core/hle/service/usb/usb.h
new file mode 100644
index 000000000..970a11fe8
--- /dev/null
+++ b/src/core/hle/service/usb/usb.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::USB {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::USB
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
new file mode 100644
index 000000000..2654594c1
--- /dev/null
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -0,0 +1,172 @@
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 <memory>
6
7#include "core/hle/service/service.h"
8#include "core/hle/service/sm/sm.h"
9#include "core/hle/service/wlan/wlan.h"
10
11namespace Service::WLAN {
12
13class WLANInfra final : public ServiceFramework<WLANInfra> {
14public:
15 explicit WLANInfra() : ServiceFramework{"wlan:inf"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "Unknown1"},
19 {1, nullptr, "Unknown2"},
20 {2, nullptr, "GetMacAddress"},
21 {3, nullptr, "StartScan"},
22 {4, nullptr, "StopScan"},
23 {5, nullptr, "Connect"},
24 {6, nullptr, "CancelConnect"},
25 {7, nullptr, "Disconnect"},
26 {8, nullptr, "Unknown3"},
27 {9, nullptr, "Unknown4"},
28 {10, nullptr, "GetState"},
29 {11, nullptr, "GetScanResult"},
30 {12, nullptr, "GetRssi"},
31 {13, nullptr, "ChangeRxAntenna"},
32 {14, nullptr, "Unknown5"},
33 {15, nullptr, "Unknown6"},
34 {16, nullptr, "RequestWakeUp"},
35 {17, nullptr, "RequestIfUpDown"},
36 {18, nullptr, "Unknown7"},
37 {19, nullptr, "Unknown8"},
38 {20, nullptr, "Unknown9"},
39 {21, nullptr, "Unknown10"},
40 {22, nullptr, "Unknown11"},
41 {23, nullptr, "Unknown12"},
42 {24, nullptr, "Unknown13"},
43 {25, nullptr, "Unknown14"},
44 {26, nullptr, "Unknown15"},
45 {27, nullptr, "Unknown16"},
46 };
47 // clang-format on
48
49 RegisterHandlers(functions);
50 }
51};
52
53class WLANLocal final : public ServiceFramework<WLANLocal> {
54public:
55 explicit WLANLocal() : ServiceFramework{"wlan:lcl"} {
56 // clang-format off
57 static const FunctionInfo functions[] = {
58 {0, nullptr, "Unknown1"},
59 {1, nullptr, "Unknown2"},
60 {2, nullptr, "Unknown3"},
61 {3, nullptr, "Unknown4"},
62 {4, nullptr, "Unknown5"},
63 {5, nullptr, "Unknown6"},
64 {6, nullptr, "GetMacAddress"},
65 {7, nullptr, "CreateBss"},
66 {8, nullptr, "DestroyBss"},
67 {9, nullptr, "StartScan"},
68 {10, nullptr, "StopScan"},
69 {11, nullptr, "Connect"},
70 {12, nullptr, "CancelConnect"},
71 {13, nullptr, "Join"},
72 {14, nullptr, "CancelJoin"},
73 {15, nullptr, "Disconnect"},
74 {16, nullptr, "SetBeaconLostCount"},
75 {17, nullptr, "Unknown7"},
76 {18, nullptr, "Unknown8"},
77 {19, nullptr, "Unknown9"},
78 {20, nullptr, "GetBssIndicationEvent"},
79 {21, nullptr, "GetBssIndicationInfo"},
80 {22, nullptr, "GetState"},
81 {23, nullptr, "GetAllowedChannels"},
82 {24, nullptr, "AddIe"},
83 {25, nullptr, "DeleteIe"},
84 {26, nullptr, "Unknown10"},
85 {27, nullptr, "Unknown11"},
86 {28, nullptr, "CreateRxEntry"},
87 {29, nullptr, "DeleteRxEntry"},
88 {30, nullptr, "Unknown12"},
89 {31, nullptr, "Unknown13"},
90 {32, nullptr, "AddMatchingDataToRxEntry"},
91 {33, nullptr, "RemoveMatchingDataFromRxEntry"},
92 {34, nullptr, "GetScanResult"},
93 {35, nullptr, "Unknown14"},
94 {36, nullptr, "SetActionFrameWithBeacon"},
95 {37, nullptr, "CancelActionFrameWithBeacon"},
96 {38, nullptr, "CreateRxEntryForActionFrame"},
97 {39, nullptr, "DeleteRxEntryForActionFrame"},
98 {40, nullptr, "Unknown15"},
99 {41, nullptr, "Unknown16"},
100 {42, nullptr, "CancelGetActionFrame"},
101 {43, nullptr, "GetRssi"},
102 {44, nullptr, "Unknown17"},
103 {45, nullptr, "Unknown18"},
104 {46, nullptr, "Unknown19"},
105 {47, nullptr, "Unknown20"},
106 {48, nullptr, "Unknown21"},
107 };
108 // clang-format on
109
110 RegisterHandlers(functions);
111 }
112};
113
114class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> {
115public:
116 explicit WLANLocalGetFrame() : ServiceFramework{"wlan:lg"} {
117 // clang-format off
118 static const FunctionInfo functions[] = {
119 {0, nullptr, "Unknown"},
120 };
121 // clang-format on
122
123 RegisterHandlers(functions);
124 }
125};
126
127class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> {
128public:
129 explicit WLANSocketGetFrame() : ServiceFramework{"wlan:sg"} {
130 // clang-format off
131 static const FunctionInfo functions[] = {
132 {0, nullptr, "Unknown"},
133 };
134 // clang-format on
135
136 RegisterHandlers(functions);
137 }
138};
139
140class WLANSocketManager final : public ServiceFramework<WLANSocketManager> {
141public:
142 explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} {
143 // clang-format off
144 static const FunctionInfo functions[] = {
145 {0, nullptr, "Unknown1"},
146 {1, nullptr, "Unknown2"},
147 {2, nullptr, "Unknown3"},
148 {3, nullptr, "Unknown4"},
149 {4, nullptr, "Unknown5"},
150 {5, nullptr, "Unknown6"},
151 {6, nullptr, "GetMacAddress"},
152 {7, nullptr, "SwitchTsfTimerFunction"},
153 {8, nullptr, "Unknown7"},
154 {9, nullptr, "Unknown8"},
155 {10, nullptr, "Unknown9"},
156 {11, nullptr, "Unknown10"},
157 };
158 // clang-format on
159
160 RegisterHandlers(functions);
161 }
162};
163
164void InstallInterfaces(SM::ServiceManager& sm) {
165 std::make_shared<WLANInfra>()->InstallAsService(sm);
166 std::make_shared<WLANLocal>()->InstallAsService(sm);
167 std::make_shared<WLANLocalGetFrame>()->InstallAsService(sm);
168 std::make_shared<WLANSocketGetFrame>()->InstallAsService(sm);
169 std::make_shared<WLANSocketManager>()->InstallAsService(sm);
170}
171
172} // namespace Service::WLAN
diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h
new file mode 100644
index 000000000..054ea928a
--- /dev/null
+++ b/src/core/hle/service/wlan/wlan.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::WLAN {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::WLAN
diff --git a/src/core/hw/aes/ccm.cpp b/src/core/hw/aes/ccm.cpp
deleted file mode 100644
index 1ee37aaa4..000000000
--- a/src/core/hw/aes/ccm.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/alignment.h"
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hw/aes/ccm.h"
10#include "core/hw/aes/key.h"
11
12namespace HW {
13namespace AES {
14
15std::vector<u8> EncryptSignCCM(const std::vector<u8>& pdata, const CCMNonce& nonce,
16 size_t slot_id) {
17 UNIMPLEMENTED();
18 return {};
19}
20
21std::vector<u8> DecryptVerifyCCM(const std::vector<u8>& cipher, const CCMNonce& nonce,
22 size_t slot_id) {
23 UNIMPLEMENTED();
24 return {};
25}
26
27} // namespace AES
28} // namespace HW
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
deleted file mode 100644
index 2f48068c1..000000000
--- a/src/core/hw/hw.cpp
+++ /dev/null
@@ -1,96 +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/hw/hw.h"
8#include "core/hw/lcd.h"
9
10namespace HW {
11
12template <typename T>
13inline void Read(T& var, const u32 addr) {
14 switch (addr & 0xFFFFF000) {
15 case VADDR_GPU:
16 case VADDR_GPU + 0x1000:
17 case VADDR_GPU + 0x2000:
18 case VADDR_GPU + 0x3000:
19 case VADDR_GPU + 0x4000:
20 case VADDR_GPU + 0x5000:
21 case VADDR_GPU + 0x6000:
22 case VADDR_GPU + 0x7000:
23 case VADDR_GPU + 0x8000:
24 case VADDR_GPU + 0x9000:
25 case VADDR_GPU + 0xA000:
26 case VADDR_GPU + 0xB000:
27 case VADDR_GPU + 0xC000:
28 case VADDR_GPU + 0xD000:
29 case VADDR_GPU + 0xE000:
30 case VADDR_GPU + 0xF000:
31 break;
32 case VADDR_LCD:
33 LCD::Read(var, addr);
34 break;
35 default:
36 LOG_ERROR(HW_Memory, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr);
37 break;
38 }
39}
40
41template <typename T>
42inline void Write(u32 addr, const T data) {
43 switch (addr & 0xFFFFF000) {
44 case VADDR_GPU:
45 case VADDR_GPU + 0x1000:
46 case VADDR_GPU + 0x2000:
47 case VADDR_GPU + 0x3000:
48 case VADDR_GPU + 0x4000:
49 case VADDR_GPU + 0x5000:
50 case VADDR_GPU + 0x6000:
51 case VADDR_GPU + 0x7000:
52 case VADDR_GPU + 0x8000:
53 case VADDR_GPU + 0x9000:
54 case VADDR_GPU + 0xA000:
55 case VADDR_GPU + 0xB000:
56 case VADDR_GPU + 0xC000:
57 case VADDR_GPU + 0xD000:
58 case VADDR_GPU + 0xE000:
59 case VADDR_GPU + 0xF000:
60 break;
61 case VADDR_LCD:
62 LCD::Write(addr, data);
63 break;
64 default:
65 LOG_ERROR(HW_Memory, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr);
66 break;
67 }
68}
69
70// Explicitly instantiate template functions because we aren't defining this in the header:
71
72template void Read<u64>(u64& var, const u32 addr);
73template void Read<u32>(u32& var, const u32 addr);
74template void Read<u16>(u16& var, const u32 addr);
75template void Read<u8>(u8& var, const u32 addr);
76
77template void Write<u64>(u32 addr, const u64 data);
78template void Write<u32>(u32 addr, const u32 data);
79template void Write<u16>(u32 addr, const u16 data);
80template void Write<u8>(u32 addr, const u8 data);
81
82/// Update hardware
83void Update() {}
84
85/// Initialize hardware
86void Init() {
87 LCD::Init();
88 LOG_DEBUG(HW, "Initialized OK");
89}
90
91/// Shutdown hardware
92void Shutdown() {
93 LCD::Shutdown();
94 LOG_DEBUG(HW, "Shutdown OK");
95}
96} // namespace HW
diff --git a/src/core/hw/hw.h b/src/core/hw/hw.h
deleted file mode 100644
index 5890d2b5c..000000000
--- a/src/core/hw/hw.h
+++ /dev/null
@@ -1,50 +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
9namespace HW {
10
11/// Beginnings of IO register regions, in the user VA space.
12enum : u32 {
13 VADDR_HASH = 0x1EC01000,
14 VADDR_CSND = 0x1EC03000,
15 VADDR_DSP = 0x1EC40000,
16 VADDR_PDN = 0x1EC41000,
17 VADDR_CODEC = 0x1EC41000,
18 VADDR_SPI = 0x1EC42000,
19 VADDR_SPI_2 = 0x1EC43000, // Only used under TWL_FIRM?
20 VADDR_I2C = 0x1EC44000,
21 VADDR_CODEC_2 = 0x1EC45000,
22 VADDR_HID = 0x1EC46000,
23 VADDR_GPIO = 0x1EC47000,
24 VADDR_I2C_2 = 0x1EC48000,
25 VADDR_SPI_3 = 0x1EC60000,
26 VADDR_I2C_3 = 0x1EC61000,
27 VADDR_MIC = 0x1EC62000,
28 VADDR_PXI = 0x1EC63000,
29 VADDR_LCD = 0x1ED02000,
30 VADDR_DSP_2 = 0x1ED03000,
31 VADDR_HASH_2 = 0x1EE01000,
32 VADDR_GPU = 0x1EF00000,
33};
34
35template <typename T>
36void Read(T& var, const u32 addr);
37
38template <typename T>
39void Write(u32 addr, const T data);
40
41/// Update hardware
42void Update();
43
44/// Initialize hardware
45void Init();
46
47/// Shutdown hardware
48void Shutdown();
49
50} // namespace HW
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
deleted file mode 100644
index 0b62174d5..000000000
--- a/src/core/hw/lcd.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/logging/log.h"
8#include "core/hw/hw.h"
9#include "core/hw/lcd.h"
10#include "core/tracer/recorder.h"
11
12namespace LCD {
13
14Regs g_regs;
15
16template <typename T>
17inline void Read(T& var, const u32 raw_addr) {
18 u32 addr = raw_addr - HW::VADDR_LCD;
19 u32 index = addr / 4;
20
21 // Reads other than u32 are untested, so I'd rather have them abort than silently fail
22 if (index >= 0x400 || !std::is_same<T, u32>::value) {
23 LOG_ERROR(HW_LCD, "Unknown Read{} @ 0x{:08X}", sizeof(var) * 8, addr);
24 return;
25 }
26
27 var = g_regs[index];
28}
29
30template <typename T>
31inline void Write(u32 addr, const T data) {
32 addr -= HW::VADDR_LCD;
33 u32 index = addr / 4;
34
35 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
36 if (index >= 0x400 || !std::is_same<T, u32>::value) {
37 LOG_ERROR(HW_LCD, "Unknown Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, data, addr);
38 return;
39 }
40
41 g_regs[index] = static_cast<u32>(data);
42}
43
44// Explicitly instantiate template functions because we aren't defining this in the header:
45
46template void Read<u64>(u64& var, const u32 addr);
47template void Read<u32>(u32& var, const u32 addr);
48template void Read<u16>(u16& var, const u32 addr);
49template void Read<u8>(u8& var, const u32 addr);
50
51template void Write<u64>(u32 addr, const u64 data);
52template void Write<u32>(u32 addr, const u32 data);
53template void Write<u16>(u32 addr, const u16 data);
54template void Write<u8>(u32 addr, const u8 data);
55
56/// Initialize hardware
57void Init() {
58 memset(&g_regs, 0, sizeof(g_regs));
59 LOG_DEBUG(HW_LCD, "Initialized OK");
60}
61
62/// Shutdown hardware
63void Shutdown() {
64 LOG_DEBUG(HW_LCD, "Shutdown OK");
65}
66
67} // namespace LCD
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
deleted file mode 100644
index d2db9700f..000000000
--- a/src/core/hw/lcd.h
+++ /dev/null
@@ -1,86 +0,0 @@
1// Copyright 2015 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 <cstddef>
8#include <type_traits>
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12
13#define LCD_REG_INDEX(field_name) (offsetof(LCD::Regs, field_name) / sizeof(u32))
14
15namespace LCD {
16
17struct Regs {
18
19 union ColorFill {
20 u32 raw;
21
22 BitField<0, 8, u32> color_r;
23 BitField<8, 8, u32> color_g;
24 BitField<16, 8, u32> color_b;
25 BitField<24, 1, u32> is_enabled;
26 };
27
28 INSERT_PADDING_WORDS(0x81);
29 ColorFill color_fill_top;
30 INSERT_PADDING_WORDS(0xE);
31 u32 backlight_top;
32
33 INSERT_PADDING_WORDS(0x1F0);
34
35 ColorFill color_fill_bottom;
36 INSERT_PADDING_WORDS(0xE);
37 u32 backlight_bottom;
38 INSERT_PADDING_WORDS(0x16F);
39
40 static constexpr size_t NumIds() {
41 return sizeof(Regs) / sizeof(u32);
42 }
43
44 const u32& operator[](int index) const {
45 const u32* content = reinterpret_cast<const u32*>(this);
46 return content[index];
47 }
48
49 u32& operator[](int index) {
50 u32* content = reinterpret_cast<u32*>(this);
51 return content[index];
52 }
53};
54static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
55
56// TODO: MSVC does not support using offsetof() on non-static data members even though this
57// is technically allowed since C++11. This macro should be enabled once MSVC adds
58// support for that.
59#ifndef _MSC_VER
60#define ASSERT_REG_POSITION(field_name, position) \
61 static_assert(offsetof(Regs, field_name) == position * 4, \
62 "Field " #field_name " has invalid position")
63
64ASSERT_REG_POSITION(color_fill_top, 0x81);
65ASSERT_REG_POSITION(backlight_top, 0x90);
66ASSERT_REG_POSITION(color_fill_bottom, 0x281);
67ASSERT_REG_POSITION(backlight_bottom, 0x290);
68
69#undef ASSERT_REG_POSITION
70#endif // !defined(_MSC_VER)
71
72extern Regs g_regs;
73
74template <typename T>
75void Read(T& var, const u32 addr);
76
77template <typename T>
78void Write(u32 addr, const T data);
79
80/// Initialize hardware
81void Init();
82
83/// Shutdown hardware
84void Shutdown();
85
86} // namespace LCD
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index b0277a875..9a8cdd0ff 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -20,6 +20,10 @@ namespace Loader {
20AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) 20AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file)
21 : AppLoader(std::move(file)) {} 21 : AppLoader(std::move(file)) {}
22 22
23AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
24 FileSys::VirtualDir directory)
25 : AppLoader(directory->GetFile("main")), dir(std::move(directory)) {}
26
23FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) { 27FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) {
24 if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) { 28 if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) {
25 return FileType::DeconstructedRomDirectory; 29 return FileType::DeconstructedRomDirectory;
@@ -34,7 +38,12 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
34 return ResultStatus::ErrorAlreadyLoaded; 38 return ResultStatus::ErrorAlreadyLoaded;
35 } 39 }
36 40
37 const FileSys::VirtualDir dir = file->GetContainingDirectory(); 41 if (dir == nullptr) {
42 if (file == nullptr)
43 return ResultStatus::ErrorInvalidFormat;
44 dir = file->GetContainingDirectory();
45 }
46
38 const FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); 47 const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
39 if (npdm == nullptr) 48 if (npdm == nullptr)
40 return ResultStatus::ErrorInvalidFormat; 49 return ResultStatus::ErrorInvalidFormat;
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 982a037f7..7d5433563 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -7,7 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/object.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
13namespace Loader { 13namespace Loader {
@@ -22,6 +22,9 @@ class AppLoader_DeconstructedRomDirectory final : public AppLoader {
22public: 22public:
23 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file); 23 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file);
24 24
25 // Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
26 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory);
27
25 /** 28 /**
26 * Returns the type of the file 29 * Returns the type of the file
27 * @param file std::shared_ptr<VfsFile> open file 30 * @param file std::shared_ptr<VfsFile> open file
@@ -40,6 +43,7 @@ public:
40private: 43private:
41 FileSys::ProgramMetadata metadata; 44 FileSys::ProgramMetadata metadata;
42 FileSys::VirtualFile romfs; 45 FileSys::VirtualFile romfs;
46 FileSys::VirtualDir dir;
43}; 47};
44 48
45} // namespace Loader 49} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 352938dcb..a7133f5a6 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -311,11 +311,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
311 CodeSet::Segment* codeset_segment; 311 CodeSet::Segment* codeset_segment;
312 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); 312 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
313 if (permission_flags == (PF_R | PF_X)) { 313 if (permission_flags == (PF_R | PF_X)) {
314 codeset_segment = &codeset->code; 314 codeset_segment = &codeset->CodeSegment();
315 } else if (permission_flags == (PF_R)) { 315 } else if (permission_flags == (PF_R)) {
316 codeset_segment = &codeset->rodata; 316 codeset_segment = &codeset->RODataSegment();
317 } else if (permission_flags == (PF_R | PF_W)) { 317 } else if (permission_flags == (PF_R | PF_W)) {
318 codeset_segment = &codeset->data; 318 codeset_segment = &codeset->DataSegment();
319 } else { 319 } else {
320 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, 320 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,
321 p->p_flags); 321 p->p_flags);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index cbc4177c6..57e6c0365 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -13,6 +13,7 @@
13#include "core/loader/nca.h" 13#include "core/loader/nca.h"
14#include "core/loader/nro.h" 14#include "core/loader/nro.h"
15#include "core/loader/nso.h" 15#include "core/loader/nso.h"
16#include "core/loader/xci.h"
16 17
17namespace Loader { 18namespace Loader {
18 19
@@ -35,6 +36,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
35 CHECK_TYPE(NSO) 36 CHECK_TYPE(NSO)
36 CHECK_TYPE(NRO) 37 CHECK_TYPE(NRO)
37 CHECK_TYPE(NCA) 38 CHECK_TYPE(NCA)
39 CHECK_TYPE(XCI)
38 40
39#undef CHECK_TYPE 41#undef CHECK_TYPE
40 42
@@ -60,6 +62,8 @@ FileType GuessFromFilename(const std::string& name) {
60 return FileType::NSO; 62 return FileType::NSO;
61 if (extension == "nca") 63 if (extension == "nca")
62 return FileType::NCA; 64 return FileType::NCA;
65 if (extension == "xci")
66 return FileType::XCI;
63 67
64 return FileType::Unknown; 68 return FileType::Unknown;
65} 69}
@@ -74,6 +78,8 @@ const char* GetFileTypeString(FileType type) {
74 return "NSO"; 78 return "NSO";
75 case FileType::NCA: 79 case FileType::NCA:
76 return "NCA"; 80 return "NCA";
81 case FileType::XCI:
82 return "XCI";
77 case FileType::DeconstructedRomDirectory: 83 case FileType::DeconstructedRomDirectory:
78 return "Directory"; 84 return "Directory";
79 case FileType::Error: 85 case FileType::Error:
@@ -111,6 +117,9 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
111 case FileType::NCA: 117 case FileType::NCA:
112 return std::make_unique<AppLoader_NCA>(std::move(file)); 118 return std::make_unique<AppLoader_NCA>(std::move(file));
113 119
120 case FileType::XCI:
121 return std::make_unique<AppLoader_XCI>(std::move(file));
122
114 // NX deconstructed ROM directory. 123 // NX deconstructed ROM directory.
115 case FileType::DeconstructedRomDirectory: 124 case FileType::DeconstructedRomDirectory:
116 return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file)); 125 return std::make_unique<AppLoader_DeconstructedRomDirectory>(std::move(file));
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index fbf11e5d0..e69ab85ef 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -14,7 +14,7 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/file_util.h" 15#include "common/file_util.h"
16#include "core/file_sys/vfs.h" 16#include "core/file_sys/vfs.h"
17#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/object.h"
18 18
19namespace Kernel { 19namespace Kernel {
20struct AddressMapping; 20struct AddressMapping;
@@ -31,6 +31,7 @@ enum class FileType {
31 NSO, 31 NSO,
32 NRO, 32 NRO,
33 NCA, 33 NCA,
34 XCI,
34 DeconstructedRomDirectory, 35 DeconstructedRomDirectory,
35}; 36};
36 37
@@ -72,7 +73,8 @@ enum class ResultStatus {
72 ErrorNotUsed, 73 ErrorNotUsed,
73 ErrorAlreadyLoaded, 74 ErrorAlreadyLoaded,
74 ErrorMemoryAllocationFailed, 75 ErrorMemoryAllocationFailed,
75 ErrorEncrypted, 76 ErrorMissingKeys,
77 ErrorDecrypting,
76 ErrorUnsupportedArch, 78 ErrorUnsupportedArch,
77}; 79};
78 80
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index c80df23be..dbc67c0b5 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -22,15 +22,14 @@
22 22
23namespace Loader { 23namespace Loader {
24 24
25AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} 25AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_)
26 : AppLoader(std::move(file_)), nca(std::make_unique<FileSys::NCA>(file)) {}
26 27
27FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) { 28FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
28 // TODO(DarkLordZach): Assuming everything is decrypted. Add crypto support. 29 FileSys::NCA nca(file);
29 FileSys::NCAHeader header{};
30 if (sizeof(FileSys::NCAHeader) != file->ReadObject(&header))
31 return FileType::Error;
32 30
33 if (IsValidNCA(header) && header.content_type == FileSys::NCAContentType::Program) 31 if (nca.GetStatus() == ResultStatus::Success &&
32 nca.GetType() == FileSys::NCAContentType::Program)
34 return FileType::NCA; 33 return FileType::NCA;
35 34
36 return FileType::Error; 35 return FileType::Error;
@@ -41,8 +40,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
41 return ResultStatus::ErrorAlreadyLoaded; 40 return ResultStatus::ErrorAlreadyLoaded;
42 } 41 }
43 42
44 nca = std::make_unique<FileSys::NCA>(file); 43 const auto result = nca->GetStatus();
45 ResultStatus result = nca->GetStatus();
46 if (result != ResultStatus::Success) { 44 if (result != ResultStatus::Success) {
47 return result; 45 return result;
48 } 46 }
@@ -50,44 +48,16 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
50 if (nca->GetType() != FileSys::NCAContentType::Program) 48 if (nca->GetType() != FileSys::NCAContentType::Program)
51 return ResultStatus::ErrorInvalidFormat; 49 return ResultStatus::ErrorInvalidFormat;
52 50
53 auto exefs = nca->GetExeFS(); 51 const auto exefs = nca->GetExeFS();
54 52
55 if (exefs == nullptr) 53 if (exefs == nullptr)
56 return ResultStatus::ErrorInvalidFormat; 54 return ResultStatus::ErrorInvalidFormat;
57 55
58 result = metadata.Load(exefs->GetFile("main.npdm")); 56 directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
59 if (result != ResultStatus::Success) {
60 return result;
61 }
62 metadata.Print();
63
64 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
65 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
66 return ResultStatus::ErrorUnsupportedArch;
67 }
68 57
69 VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; 58 const auto load_result = directory_loader->Load(process);
70 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", 59 if (load_result != ResultStatus::Success)
71 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { 60 return load_result;
72 const VAddr load_addr = next_load_addr;
73
74 next_load_addr = AppLoader_NSO::LoadModule(exefs->GetFile(module), load_addr);
75 if (next_load_addr) {
76 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
77 // Register module with GDBStub
78 GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
79 } else {
80 next_load_addr = load_addr;
81 }
82 }
83
84 process->program_id = metadata.GetTitleID();
85 process->svc_access_mask.set();
86 process->address_mappings = default_address_mappings;
87 process->resource_limit =
88 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
89 process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
90 metadata.GetMainThreadStackSize());
91 61
92 if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) 62 if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0)
93 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); 63 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
@@ -98,12 +68,21 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
98} 68}
99 69
100ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { 70ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
101 if (nca == nullptr || nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0) 71 if (nca == nullptr)
72 return ResultStatus::ErrorNotLoaded;
73 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
102 return ResultStatus::ErrorNotUsed; 74 return ResultStatus::ErrorNotUsed;
103 dir = nca->GetRomFS(); 75 dir = nca->GetRomFS();
104 return ResultStatus::Success; 76 return ResultStatus::Success;
105} 77}
106 78
79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
80 if (nca == nullptr)
81 return ResultStatus::ErrorNotLoaded;
82 out_program_id = nca->GetTitleId();
83 return ResultStatus::Success;
84}
85
107AppLoader_NCA::~AppLoader_NCA() = default; 86AppLoader_NCA::~AppLoader_NCA() = default;
108 87
109} // namespace Loader 88} // namespace Loader
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 52c95953a..0fd2d0417 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -8,8 +8,9 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/file_sys/content_archive.h" 9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/program_metadata.h" 10#include "core/file_sys/program_metadata.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/object.h"
12#include "core/loader/loader.h" 12#include "core/loader/loader.h"
13#include "deconstructed_rom_directory.h"
13 14
14namespace Loader { 15namespace Loader {
15 16
@@ -33,12 +34,15 @@ public:
33 34
34 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 35 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
35 36
37 ResultStatus ReadProgramId(u64& out_program_id) override;
38
36 ~AppLoader_NCA(); 39 ~AppLoader_NCA();
37 40
38private: 41private:
39 FileSys::ProgramMetadata metadata; 42 FileSys::ProgramMetadata metadata;
40 43
41 std::unique_ptr<FileSys::NCA> nca; 44 std::unique_ptr<FileSys::NCA> nca;
45 std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
42}; 46};
43 47
44} // namespace Loader 48} // namespace Loader
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 7d3ec2a76..dc053cdad 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -159,7 +159,7 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
159 // Resize program image to include .bss section and page align each section 159 // Resize program image to include .bss section and page align each section
160 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); 160 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
161 } 161 }
162 codeset->data.size += bss_size; 162 codeset->DataSegment().size += bss_size;
163 program_image.resize(static_cast<u32>(program_image.size()) + bss_size); 163 program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
164 164
165 // Load codeset for current process 165 // Load codeset for current process
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 04a0f497e..bb01c9e25 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -6,7 +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/hle/kernel/kernel.h" 9#include "core/hle/kernel/object.h"
10#include "core/loader/linker.h" 10#include "core/loader/linker.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 06b1b33f4..fee7d58c6 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -127,7 +127,7 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
127 // Resize program image to include .bss section and page align each section 127 // Resize program image to include .bss section and page align each section
128 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); 128 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
129 } 129 }
130 codeset->data.size += bss_size; 130 codeset->DataSegment().size += bss_size;
131 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)}; 131 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
132 program_image.resize(image_size); 132 program_image.resize(image_size);
133 133
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 3f7567500..aaeb1f2a9 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -6,7 +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/hle/kernel/kernel.h" 9#include "core/hle/kernel/object.h"
10#include "core/loader/linker.h" 10#include "core/loader/linker.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
new file mode 100644
index 000000000..eb4dee2c2
--- /dev/null
+++ b/src/core/loader/xci.cpp
@@ -0,0 +1,74 @@
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 <vector>
6
7#include "common/file_util.h"
8#include "common/logging/log.h"
9#include "common/string_util.h"
10#include "common/swap.h"
11#include "core/core.h"
12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/program_metadata.h"
15#include "core/file_sys/romfs.h"
16#include "core/gdbstub/gdbstub.h"
17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/resource_limit.h"
19#include "core/hle/service/filesystem/filesystem.h"
20#include "core/loader/nso.h"
21#include "core/loader/xci.h"
22#include "core/memory.h"
23
24namespace Loader {
25
26AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
27 : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
28 nca_loader(std::make_unique<AppLoader_NCA>(
29 xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {}
30
31AppLoader_XCI::~AppLoader_XCI() = default;
32
33FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
34 FileSys::XCI xci(file);
35
36 if (xci.GetStatus() == ResultStatus::Success &&
37 xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr &&
38 AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) ==
39 FileType::NCA) {
40 return FileType::XCI;
41 }
42
43 return FileType::Error;
44}
45
46ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
47 if (is_loaded) {
48 return ResultStatus::ErrorAlreadyLoaded;
49 }
50
51 if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) {
52 if (!Core::Crypto::KeyManager::KeyFileExists(false))
53 return ResultStatus::ErrorMissingKeys;
54 return ResultStatus::ErrorDecrypting;
55 }
56
57 auto result = nca_loader->Load(process);
58 if (result != ResultStatus::Success)
59 return result;
60
61 is_loaded = true;
62
63 return ResultStatus::Success;
64}
65
66ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& dir) {
67 return nca_loader->ReadRomFS(dir);
68}
69
70ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
71 return nca_loader->ReadProgramId(out_program_id);
72}
73
74} // namespace Loader
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
new file mode 100644
index 000000000..0dbcfbdf8
--- /dev/null
+++ b/src/core/loader/xci.h
@@ -0,0 +1,44 @@
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 "common/common_types.h"
9#include "core/file_sys/card_image.h"
10#include "core/loader/loader.h"
11#include "core/loader/nca.h"
12
13namespace Loader {
14
15/// Loads an XCI file
16class AppLoader_XCI final : public AppLoader {
17public:
18 explicit AppLoader_XCI(FileSys::VirtualFile file);
19 ~AppLoader_XCI();
20
21 /**
22 * Returns the type of the file
23 * @param file std::shared_ptr<VfsFile> open file
24 * @return FileType found, or FileType::Error if this loader doesn't know it
25 */
26 static FileType IdentifyType(const FileSys::VirtualFile& file);
27
28 FileType GetFileType() override {
29 return IdentifyType(file);
30 }
31
32 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
33
34 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
35 ResultStatus ReadProgramId(u64& out_program_id) override;
36
37private:
38 FileSys::ProgramMetadata metadata;
39
40 std::unique_ptr<FileSys::XCI> xci;
41 std::unique_ptr<AppLoader_NCA> nca_loader;
42};
43
44} // namespace Loader
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index e753e3436..1133bcbaf 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,7 +14,6 @@
14#include "common/swap.h" 14#include "common/swap.h"
15#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/kernel/memory.h"
18#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
19#include "core/hle/lock.h" 18#include "core/hle/lock.h"
20#include "core/memory.h" 19#include "core/memory.h"
@@ -24,8 +23,6 @@
24 23
25namespace Memory { 24namespace Memory {
26 25
27static std::array<u8, Memory::VRAM_SIZE> vram;
28
29static PageTable* current_page_table = nullptr; 26static PageTable* current_page_table = nullptr;
30 27
31void SetCurrentPageTable(PageTable* page_table) { 28void SetCurrentPageTable(PageTable* page_table) {
@@ -102,22 +99,6 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin
102} 99}
103 100
104/** 101/**
105 * This function should only be called for virtual addreses with attribute `PageType::Special`.
106 */
107static std::set<MemoryHookPointer> GetSpecialHandlers(const PageTable& page_table, VAddr vaddr,
108 u64 size) {
109 std::set<MemoryHookPointer> result;
110 auto interval = boost::icl::discrete_interval<VAddr>::closed(vaddr, vaddr + size - 1);
111 auto interval_list = page_table.special_regions.equal_range(interval);
112 for (auto it = interval_list.first; it != interval_list.second; ++it) {
113 for (const auto& region : it->second) {
114 result.insert(region.handler);
115 }
116 }
117 return result;
118}
119
120/**
121 * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) 102 * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned)
122 * using a VMA from the current process 103 * using a VMA from the current process
123 */ 104 */
@@ -242,10 +223,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
242 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 223 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
243} 224}
244 225
245bool IsValidPhysicalAddress(const PAddr paddr) {
246 return GetPhysicalPointer(paddr) != nullptr;
247}
248
249u8* GetPointer(const VAddr vaddr) { 226u8* GetPointer(const VAddr vaddr) {
250 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 227 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
251 if (page_pointer) { 228 if (page_pointer) {
@@ -274,61 +251,6 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
274 return string; 251 return string;
275} 252}
276 253
277u8* GetPhysicalPointer(PAddr address) {
278 struct MemoryArea {
279 PAddr paddr_base;
280 u32 size;
281 };
282
283 static constexpr MemoryArea memory_areas[] = {
284 {VRAM_PADDR, VRAM_SIZE},
285 {IO_AREA_PADDR, IO_AREA_SIZE},
286 {DSP_RAM_PADDR, DSP_RAM_SIZE},
287 {FCRAM_PADDR, FCRAM_N3DS_SIZE},
288 };
289
290 const auto area =
291 std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) {
292 return address >= area.paddr_base && address < area.paddr_base + area.size;
293 });
294
295 if (area == std::end(memory_areas)) {
296 LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ 0x{:016X}", address);
297 return nullptr;
298 }
299
300 if (area->paddr_base == IO_AREA_PADDR) {
301 LOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:016X}", address);
302 return nullptr;
303 }
304
305 u64 offset_into_region = address - area->paddr_base;
306
307 u8* target_pointer = nullptr;
308 switch (area->paddr_base) {
309 case VRAM_PADDR:
310 target_pointer = vram.data() + offset_into_region;
311 break;
312 case DSP_RAM_PADDR:
313 break;
314 case FCRAM_PADDR:
315 for (const auto& region : Kernel::memory_regions) {
316 if (offset_into_region >= region.base &&
317 offset_into_region < region.base + region.size) {
318 target_pointer =
319 region.linear_heap_memory->data() + offset_into_region - region.base;
320 break;
321 }
322 }
323 ASSERT_MSG(target_pointer != nullptr, "Invalid FCRAM address");
324 break;
325 default:
326 UNREACHABLE();
327 }
328
329 return target_pointer;
330}
331
332void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) { 254void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) {
333 if (gpu_addr == 0) { 255 if (gpu_addr == 0) {
334 return; 256 return;
@@ -404,43 +326,45 @@ void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached)
404} 326}
405 327
406void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { 328void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
329 auto& system_instance = Core::System::GetInstance();
330
407 // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be 331 // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
408 // null here 332 // null here
409 if (VideoCore::g_renderer == nullptr) { 333 if (!system_instance.IsPoweredOn()) {
410 return; 334 return;
411 } 335 }
412 336
413 VAddr end = start + size; 337 VAddr end = start + size;
414 338
415 auto CheckRegion = [&](VAddr region_start, VAddr region_end) { 339 const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
416 if (start >= region_end || end <= region_start) { 340 if (start >= region_end || end <= region_start) {
417 // No overlap with region 341 // No overlap with region
418 return; 342 return;
419 } 343 }
420 344
421 VAddr overlap_start = std::max(start, region_start); 345 const VAddr overlap_start = std::max(start, region_start);
422 VAddr overlap_end = std::min(end, region_end); 346 const VAddr overlap_end = std::min(end, region_end);
423 347
424 std::vector<Tegra::GPUVAddr> gpu_addresses = 348 const std::vector<Tegra::GPUVAddr> gpu_addresses =
425 Core::System::GetInstance().GPU().memory_manager->CpuToGpuAddress(overlap_start); 349 system_instance.GPU().memory_manager->CpuToGpuAddress(overlap_start);
426 350
427 if (gpu_addresses.empty()) { 351 if (gpu_addresses.empty()) {
428 return; 352 return;
429 } 353 }
430 354
431 u64 overlap_size = overlap_end - overlap_start; 355 const u64 overlap_size = overlap_end - overlap_start;
432 356
433 for (const auto& gpu_address : gpu_addresses) { 357 for (const auto& gpu_address : gpu_addresses) {
434 auto* rasterizer = VideoCore::g_renderer->Rasterizer(); 358 auto& rasterizer = system_instance.Renderer().Rasterizer();
435 switch (mode) { 359 switch (mode) {
436 case FlushMode::Flush: 360 case FlushMode::Flush:
437 rasterizer->FlushRegion(gpu_address, overlap_size); 361 rasterizer.FlushRegion(gpu_address, overlap_size);
438 break; 362 break;
439 case FlushMode::Invalidate: 363 case FlushMode::Invalidate:
440 rasterizer->InvalidateRegion(gpu_address, overlap_size); 364 rasterizer.InvalidateRegion(gpu_address, overlap_size);
441 break; 365 break;
442 case FlushMode::FlushAndInvalidate: 366 case FlushMode::FlushAndInvalidate:
443 rasterizer->FlushAndInvalidateRegion(gpu_address, overlap_size); 367 rasterizer.FlushAndInvalidateRegion(gpu_address, overlap_size);
444 break; 368 break;
445 } 369 }
446 } 370 }
@@ -666,48 +590,4 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) {
666 CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size); 590 CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size);
667} 591}
668 592
669boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) {
670 if (addr == 0) {
671 return 0;
672 } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
673 return addr - VRAM_VADDR + VRAM_PADDR;
674 } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
675 return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
676 } else if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
677 return addr - NEW_LINEAR_HEAP_VADDR + FCRAM_PADDR;
678 } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
679 return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
680 } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
681 return addr - IO_AREA_VADDR + IO_AREA_PADDR;
682 }
683
684 return boost::none;
685}
686
687PAddr VirtualToPhysicalAddress(const VAddr addr) {
688 auto paddr = TryVirtualToPhysicalAddress(addr);
689 if (!paddr) {
690 LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:016X}", addr);
691 // To help with debugging, set bit on address so that it's obviously invalid.
692 return addr | 0x80000000;
693 }
694 return *paddr;
695}
696
697boost::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) {
698 if (addr == 0) {
699 return 0;
700 } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
701 return addr - VRAM_PADDR + VRAM_VADDR;
702 } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
703 return addr - FCRAM_PADDR + Core::CurrentProcess()->GetLinearHeapAreaAddress();
704 } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
705 return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
706 } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
707 return addr - IO_AREA_PADDR + IO_AREA_VADDR;
708 }
709
710 return boost::none;
711}
712
713} // namespace Memory 593} // namespace Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index 8d5d017a4..b7fb3b9ed 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -6,12 +6,9 @@
6 6
7#include <array> 7#include <array>
8#include <cstddef> 8#include <cstddef>
9#include <map>
10#include <string> 9#include <string>
11#include <tuple> 10#include <tuple>
12#include <vector>
13#include <boost/icl/interval_map.hpp> 11#include <boost/icl/interval_map.hpp>
14#include <boost/optional.hpp>
15#include "common/common_types.h" 12#include "common/common_types.h"
16#include "core/memory_hook.h" 13#include "core/memory_hook.h"
17#include "video_core/memory_manager.h" 14#include "video_core/memory_manager.h"
@@ -85,40 +82,6 @@ struct PageTable {
85 std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; 82 std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
86}; 83};
87 84
88/// Physical memory regions as seen from the ARM11
89enum : PAddr {
90 /// IO register area
91 IO_AREA_PADDR = 0x10100000,
92 IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB)
93 IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE,
94
95 /// MPCore internal memory region
96 MPCORE_RAM_PADDR = 0x17E00000,
97 MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB)
98 MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE,
99
100 /// Video memory
101 VRAM_PADDR = 0x18000000,
102 VRAM_SIZE = 0x00600000, ///< VRAM size (6MB)
103 VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE,
104
105 /// DSP memory
106 DSP_RAM_PADDR = 0x1FF00000,
107 DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB)
108 DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE,
109
110 /// AXI WRAM
111 AXI_WRAM_PADDR = 0x1FF80000,
112 AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB)
113 AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE,
114
115 /// Main FCRAM
116 FCRAM_PADDR = 0x20000000,
117 FCRAM_SIZE = 0x08000000, ///< FCRAM size on the Old 3DS (128MB)
118 FCRAM_N3DS_SIZE = 0x10000000, ///< FCRAM size on the New 3DS (256MB)
119 FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE,
120};
121
122/// Virtual user-space memory regions 85/// Virtual user-space memory regions
123enum : VAddr { 86enum : VAddr {
124 /// Where the application text, data and bss reside. 87 /// Where the application text, data and bss reside.
@@ -126,24 +89,6 @@ enum : VAddr {
126 PROCESS_IMAGE_MAX_SIZE = 0x08000000, 89 PROCESS_IMAGE_MAX_SIZE = 0x08000000,
127 PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, 90 PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
128 91
129 /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical
130 /// memory.
131 LINEAR_HEAP_VADDR = 0x14000000,
132 LINEAR_HEAP_SIZE = 0x08000000,
133 LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE,
134
135 /// Maps 1:1 to the IO register area.
136 IO_AREA_VADDR = 0x1EC00000,
137 IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE,
138
139 /// Maps 1:1 to VRAM.
140 VRAM_VADDR = 0x1F000000,
141 VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE,
142
143 /// Maps 1:1 to DSP memory.
144 DSP_RAM_VADDR = 0x1FF00000,
145 DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE,
146
147 /// Read-only page containing kernel and system configuration values. 92 /// Read-only page containing kernel and system configuration values.
148 CONFIG_MEMORY_VADDR = 0x1FF80000, 93 CONFIG_MEMORY_VADDR = 0x1FF80000,
149 CONFIG_MEMORY_SIZE = 0x00001000, 94 CONFIG_MEMORY_SIZE = 0x00001000,
@@ -154,13 +99,8 @@ enum : VAddr {
154 SHARED_PAGE_SIZE = 0x00001000, 99 SHARED_PAGE_SIZE = 0x00001000,
155 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, 100 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
156 101
157 /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
158 NEW_LINEAR_HEAP_VADDR = 0x30000000,
159 NEW_LINEAR_HEAP_SIZE = 0x10000000,
160 NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
161
162 /// Area where TLS (Thread-Local Storage) buffers are allocated. 102 /// Area where TLS (Thread-Local Storage) buffers are allocated.
163 TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END, 103 TLS_AREA_VADDR = 0x40000000,
164 TLS_ENTRY_SIZE = 0x200, 104 TLS_ENTRY_SIZE = 0x200,
165 TLS_AREA_SIZE = 0x10000000, 105 TLS_AREA_SIZE = 0x10000000,
166 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, 106 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
@@ -200,12 +140,10 @@ void SetCurrentPageTable(PageTable* page_table);
200PageTable* GetCurrentPageTable(); 140PageTable* GetCurrentPageTable();
201 141
202/// Determines if the given VAddr is valid for the specified process. 142/// Determines if the given VAddr is valid for the specified process.
203bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr); 143bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
204bool IsValidVirtualAddress(const VAddr addr); 144bool IsValidVirtualAddress(VAddr vaddr);
205/// Determines if the given VAddr is a kernel address 145/// Determines if the given VAddr is a kernel address
206bool IsKernelVirtualAddress(const VAddr addr); 146bool IsKernelVirtualAddress(VAddr vaddr);
207
208bool IsValidPhysicalAddress(const PAddr addr);
209 147
210u8 Read8(VAddr addr); 148u8 Read8(VAddr addr);
211u16 Read16(VAddr addr); 149u16 Read16(VAddr addr);
@@ -217,42 +155,17 @@ void Write16(VAddr addr, u16 data);
217void Write32(VAddr addr, u32 data); 155void Write32(VAddr addr, u32 data);
218void Write64(VAddr addr, u64 data); 156void Write64(VAddr addr, u64 data);
219 157
220void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 158void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, size_t size);
221 size_t size); 159void ReadBlock(VAddr src_addr, void* dest_buffer, size_t size);
222void ReadBlock(const VAddr src_addr, void* dest_buffer, size_t size); 160void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
223void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
224 size_t size); 161 size_t size);
225void WriteBlock(const VAddr dest_addr, const void* src_buffer, size_t size); 162void WriteBlock(VAddr dest_addr, const void* src_buffer, size_t size);
226void ZeroBlock(const VAddr dest_addr, const size_t size); 163void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, size_t size);
227void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size); 164void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size);
228 165
229u8* GetPointer(VAddr virtual_address); 166u8* GetPointer(VAddr vaddr);
230
231std::string ReadCString(VAddr virtual_address, std::size_t max_length);
232
233/**
234 * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
235 * address. This should be used by services to translate addresses for use by the hardware.
236 */
237boost::optional<PAddr> TryVirtualToPhysicalAddress(VAddr addr);
238
239/**
240 * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
241 * address. This should be used by services to translate addresses for use by the hardware.
242 *
243 * @deprecated Use TryVirtualToPhysicalAddress(), which reports failure.
244 */
245PAddr VirtualToPhysicalAddress(VAddr addr);
246 167
247/** 168std::string ReadCString(VAddr vaddr, std::size_t max_length);
248 * Undoes a mapping performed by VirtualToPhysicalAddress().
249 */
250boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr);
251
252/**
253 * Gets a pointer to the memory region beginning at the specified physical address.
254 */
255u8* GetPhysicalPointer(PAddr address);
256 169
257enum class FlushMode { 170enum class FlushMode {
258 /// Write back modified surfaces to RAM 171 /// Write back modified surfaces to RAM
@@ -266,7 +179,7 @@ enum class FlushMode {
266/** 179/**
267 * Mark each page touching the region as cached. 180 * Mark each page touching the region as cached.
268 */ 181 */
269void RasterizerMarkRegionCached(Tegra::GPUVAddr start, u64 size, bool cached); 182void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached);
270 183
271/** 184/**
272 * Flushes and invalidates any externally cached rasterizer resources touching the given virtual 185 * Flushes and invalidates any externally cached rasterizer resources touching the given virtual
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 5f53b16d3..8e09b9b63 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -40,22 +40,21 @@ void PerfStats::EndGameFrame() {
40 game_frames += 1; 40 game_frames += 1;
41} 41}
42 42
43PerfStats::Results PerfStats::GetAndResetStats(u64 current_system_time_us) { 43PerfStats::Results PerfStats::GetAndResetStats(microseconds current_system_time_us) {
44 std::lock_guard<std::mutex> lock(object_mutex); 44 std::lock_guard<std::mutex> lock(object_mutex);
45 45
46 auto now = Clock::now(); 46 const auto now = Clock::now();
47 // Walltime elapsed since stats were reset 47 // Walltime elapsed since stats were reset
48 auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); 48 const auto interval = duration_cast<DoubleSecs>(now - reset_point).count();
49 49
50 auto system_us_per_second = 50 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval;
51 static_cast<double>(current_system_time_us - reset_point_system_us) / interval;
52 51
53 Results results{}; 52 Results results{};
54 results.system_fps = static_cast<double>(system_frames) / interval; 53 results.system_fps = static_cast<double>(system_frames) / interval;
55 results.game_fps = static_cast<double>(game_frames) / interval; 54 results.game_fps = static_cast<double>(game_frames) / interval;
56 results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / 55 results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() /
57 static_cast<double>(system_frames); 56 static_cast<double>(system_frames);
58 results.emulation_speed = system_us_per_second / 1'000'000.0; 57 results.emulation_speed = system_us_per_second.count() / 1'000'000.0;
59 58
60 // Reset counters 59 // Reset counters
61 reset_point = now; 60 reset_point = now;
@@ -74,10 +73,10 @@ double PerfStats::GetLastFrameTimeScale() {
74 return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; 73 return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
75} 74}
76 75
77void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) { 76void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
78 // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher 77 // Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher
79 // values increase the time needed to recover and limit framerate again after spikes. 78 // values increase the time needed to recover and limit framerate again after spikes.
80 constexpr microseconds MAX_LAG_TIME_US = 25ms; 79 constexpr microseconds MAX_LAG_TIME_US = 25us;
81 80
82 if (!Settings::values.toggle_framelimit) { 81 if (!Settings::values.toggle_framelimit) {
83 return; 82 return;
@@ -85,7 +84,7 @@ void FrameLimiter::DoFrameLimiting(u64 current_system_time_us) {
85 84
86 auto now = Clock::now(); 85 auto now = Clock::now();
87 86
88 frame_limiting_delta_err += microseconds(current_system_time_us - previous_system_time_us); 87 frame_limiting_delta_err += current_system_time_us - previous_system_time_us;
89 frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime); 88 frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
90 frame_limiting_delta_err = 89 frame_limiting_delta_err =
91 std::clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US); 90 std::clamp(frame_limiting_delta_err, -MAX_LAG_TIME_US, MAX_LAG_TIME_US);
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index 362b205c8..6e4619701 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -33,7 +33,7 @@ public:
33 void EndSystemFrame(); 33 void EndSystemFrame();
34 void EndGameFrame(); 34 void EndGameFrame();
35 35
36 Results GetAndResetStats(u64 current_system_time_us); 36 Results GetAndResetStats(std::chrono::microseconds current_system_time_us);
37 37
38 /** 38 /**
39 * Gets the ratio between walltime and the emulated time of the previous system frame. This is 39 * Gets the ratio between walltime and the emulated time of the previous system frame. This is
@@ -47,7 +47,7 @@ private:
47 /// Point when the cumulative counters were reset 47 /// Point when the cumulative counters were reset
48 Clock::time_point reset_point = Clock::now(); 48 Clock::time_point reset_point = Clock::now();
49 /// System time when the cumulative counters were reset 49 /// System time when the cumulative counters were reset
50 u64 reset_point_system_us = 0; 50 std::chrono::microseconds reset_point_system_us{0};
51 51
52 /// Cumulative duration (excluding v-sync/frame-limiting) of frames since last reset 52 /// Cumulative duration (excluding v-sync/frame-limiting) of frames since last reset
53 Clock::duration accumulated_frametime = Clock::duration::zero(); 53 Clock::duration accumulated_frametime = Clock::duration::zero();
@@ -68,11 +68,11 @@ class FrameLimiter {
68public: 68public:
69 using Clock = std::chrono::high_resolution_clock; 69 using Clock = std::chrono::high_resolution_clock;
70 70
71 void DoFrameLimiting(u64 current_system_time_us); 71 void DoFrameLimiting(std::chrono::microseconds current_system_time_us);
72 72
73private: 73private:
74 /// Emulated system time (in microseconds) at the last limiter invocation 74 /// Emulated system time (in microseconds) at the last limiter invocation
75 u64 previous_system_time_us = 0; 75 std::chrono::microseconds previous_system_time_us{0};
76 /// Walltime at the last limiter invocation 76 /// Walltime at the last limiter invocation
77 Clock::time_point previous_walltime = Clock::now(); 77 Clock::time_point previous_walltime = Clock::now();
78 78
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 444bcc387..a4623223d 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -2,13 +2,13 @@
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 "core/core.h"
5#include "core/gdbstub/gdbstub.h" 6#include "core/gdbstub/gdbstub.h"
6#include "core/hle/service/hid/hid.h" 7#include "core/hle/service/hid/hid.h"
7#include "core/settings.h" 8#include "core/settings.h"
9#include "video_core/renderer_base.h"
8#include "video_core/video_core.h" 10#include "video_core/video_core.h"
9 11
10#include "core/frontend/emu_window.h"
11
12namespace Settings { 12namespace Settings {
13 13
14Values values = {}; 14Values values = {};
@@ -20,9 +20,9 @@ void Apply() {
20 20
21 VideoCore::g_toggle_framelimit_enabled = values.toggle_framelimit; 21 VideoCore::g_toggle_framelimit_enabled = values.toggle_framelimit;
22 22
23 if (VideoCore::g_emu_window) { 23 auto& system_instance = Core::System::GetInstance();
24 auto layout = VideoCore::g_emu_window->GetFramebufferLayout(); 24 if (system_instance.IsPoweredOn()) {
25 VideoCore::g_emu_window->UpdateCurrentFramebufferLayout(layout.width, layout.height); 25 system_instance.Renderer().UpdateCurrentFramebufferLayout();
26 } 26 }
27 27
28 Service::HID::ReloadInputDevices(); 28 Service::HID::ReloadInputDevices();
diff --git a/src/core/settings.h b/src/core/settings.h
index 7150d9755..73dc3061f 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -112,6 +112,8 @@ static const std::array<const char*, NumAnalogs> mapping = {{
112struct Values { 112struct Values {
113 // System 113 // System
114 bool use_docked_mode; 114 bool use_docked_mode;
115 std::string username;
116 int language_index;
115 117
116 // Controls 118 // Controls
117 std::array<std::string, NativeButton::NumButtons> buttons; 119 std::array<std::string, NativeButton::NumButtons> buttons;
@@ -137,6 +139,13 @@ struct Values {
137 139
138 std::string log_filter; 140 std::string log_filter;
139 141
142 bool use_dev_keys;
143
144 // Audio
145 std::string sink_id;
146 std::string audio_device_id;
147 float volume;
148
140 // Debugging 149 // Debugging
141 bool use_gdbstub; 150 bool use_gdbstub;
142 u16 gdbstub_port; 151 u16 gdbstub_port;