summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt69
-rw-r--r--src/core/arm/arm_interface.h19
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h8
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom_trans.h2
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp2
-rw-r--r--src/core/core.cpp135
-rw-r--r--src/core/core.h148
-rw-r--r--src/core/core_timing.cpp27
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp9
-rw-r--r--src/core/file_sys/archive_ncch.cpp2
-rw-r--r--src/core/file_sys/archive_ncch.h2
-rw-r--r--src/core/file_sys/archive_romfs.h2
-rw-r--r--src/core/file_sys/archive_sdmc.h4
-rw-r--r--src/core/file_sys/archive_sdmcwriteonly.h4
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.cpp7
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.h2
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp2
-rw-r--r--src/core/file_sys/archive_systemsavedata.h2
-rw-r--r--src/core/file_sys/path_parser.h2
-rw-r--r--src/core/file_sys/savedata_archive.h2
-rw-r--r--src/core/frontend/emu_window.cpp107
-rw-r--r--src/core/frontend/emu_window.h290
-rw-r--r--src/core/frontend/key_map.cpp152
-rw-r--r--src/core/frontend/key_map.h93
-rw-r--r--src/core/gdbstub/gdbstub.cpp83
-rw-r--r--src/core/gdbstub/gdbstub.h11
-rw-r--r--src/core/hle/applets/applet.cpp4
-rw-r--r--src/core/hle/applets/applet.h10
-rw-r--r--src/core/hle/applets/erreula.cpp4
-rw-r--r--src/core/hle/applets/erreula.h8
-rw-r--r--src/core/hle/applets/mii_selector.cpp4
-rw-r--r--src/core/hle/applets/mii_selector.h9
-rw-r--r--src/core/hle/applets/swkbd.cpp8
-rw-r--r--src/core/hle/applets/swkbd.h9
-rw-r--r--src/core/hle/function_wrappers.h76
-rw-r--r--src/core/hle/hle.cpp58
-rw-r--r--src/core/hle/hle.h23
-rw-r--r--src/core/hle/ipc.h (renamed from src/core/hle/kernel/session.h)96
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp3
-rw-r--r--src/core/hle/kernel/client_port.cpp32
-rw-r--r--src/core/hle/kernel/client_port.h13
-rw-r--r--src/core/hle/kernel/client_session.cpp40
-rw-r--r--src/core/hle/kernel/client_session.h65
-rw-r--r--src/core/hle/kernel/kernel.cpp59
-rw-r--r--src/core/hle/kernel/kernel.h48
-rw-r--r--src/core/hle/kernel/server_port.cpp4
-rw-r--r--src/core/hle/kernel/server_port.h14
-rw-r--r--src/core/hle/kernel/server_session.cpp79
-rw-r--r--src/core/hle/kernel/server_session.h94
-rw-r--r--src/core/hle/kernel/thread.cpp127
-rw-r--r--src/core/hle/kernel/thread.h53
-rw-r--r--src/core/hle/kernel/timer.cpp4
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/ac_u.cpp40
-rw-r--r--src/core/hle/service/ac_u.h17
-rw-r--r--src/core/hle/service/act/act.cpp18
-rw-r--r--src/core/hle/service/act/act.h14
-rw-r--r--src/core/hle/service/act/act_a.cpp30
-rw-r--r--src/core/hle/service/act/act_a.h (renamed from src/core/hle/service/act_a.h)13
-rw-r--r--src/core/hle/service/act/act_u.cpp (renamed from src/core/hle/service/act_u.cpp)20
-rw-r--r--src/core/hle/service/act/act_u.h (renamed from src/core/hle/service/act_u.h)13
-rw-r--r--src/core/hle/service/act_a.cpp26
-rw-r--r--src/core/hle/service/am/am.cpp10
-rw-r--r--src/core/hle/service/am/am.h20
-rw-r--r--src/core/hle/service/am/am_app.cpp5
-rw-r--r--src/core/hle/service/am/am_net.cpp157
-rw-r--r--src/core/hle/service/am/am_sys.cpp71
-rw-r--r--src/core/hle/service/am/am_u.cpp96
-rw-r--r--src/core/hle/service/apt/apt.cpp12
-rw-r--r--src/core/hle/service/apt/apt.h7
-rw-r--r--src/core/hle/service/apt/apt_a.cpp79
-rw-r--r--src/core/hle/service/apt/apt_s.cpp5
-rw-r--r--src/core/hle/service/apt/apt_u.cpp2
-rw-r--r--src/core/hle/service/boss/boss_p.cpp71
-rw-r--r--src/core/hle/service/cecd/cecd.cpp10
-rw-r--r--src/core/hle/service/cecd/cecd_ndm.cpp23
-rw-r--r--src/core/hle/service/cecd/cecd_ndm.h22
-rw-r--r--src/core/hle/service/cecd/cecd_s.cpp26
-rw-r--r--src/core/hle/service/cecd/cecd_s.h4
-rw-r--r--src/core/hle/service/cecd/cecd_u.cpp17
-rw-r--r--src/core/hle/service/cecd/cecd_u.h4
-rw-r--r--src/core/hle/service/cfg/cfg.cpp8
-rw-r--r--src/core/hle/service/cfg/cfg_i.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg_i.h4
-rw-r--r--src/core/hle/service/cfg/cfg_nor.cpp23
-rw-r--r--src/core/hle/service/cfg/cfg_nor.h22
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg_s.h4
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg_u.h4
-rw-r--r--src/core/hle/service/csnd_snd.cpp140
-rw-r--r--src/core/hle/service/csnd_snd.h26
-rw-r--r--src/core/hle/service/dlp/dlp.h2
-rw-r--r--src/core/hle/service/dlp/dlp_srvr.cpp7
-rw-r--r--src/core/hle/service/dsp_dsp.cpp7
-rw-r--r--src/core/hle/service/dsp_dsp.h7
-rw-r--r--src/core/hle/service/err_f.cpp16
-rw-r--r--src/core/hle/service/err_f.h13
-rw-r--r--src/core/hle/service/fs/archive.cpp65
-rw-r--r--src/core/hle/service/fs/archive.h36
-rw-r--r--src/core/hle/service/fs/fs_user.cpp35
-rw-r--r--src/core/hle/service/gsp_gpu.cpp54
-rw-r--r--src/core/hle/service/gsp_gpu.h17
-rw-r--r--src/core/hle/service/gsp_lcd.cpp18
-rw-r--r--src/core/hle/service/gsp_lcd.h14
-rw-r--r--src/core/hle/service/hid/hid.cpp5
-rw-r--r--src/core/hle/service/http_c.cpp18
-rw-r--r--src/core/hle/service/http_c.h13
-rw-r--r--src/core/hle/service/ir/ir.cpp3
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.cpp9
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.h9
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.cpp40
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.h13
-rw-r--r--src/core/hle/service/ldr_ro/memory_synchronizer.cpp9
-rw-r--r--src/core/hle/service/ldr_ro/memory_synchronizer.h9
-rw-r--r--src/core/hle/service/mic_u.cpp51
-rw-r--r--src/core/hle/service/mic_u.h17
-rw-r--r--src/core/hle/service/mvd/mvd.cpp17
-rw-r--r--src/core/hle/service/mvd/mvd.h14
-rw-r--r--src/core/hle/service/mvd/mvd_std.cpp32
-rw-r--r--src/core/hle/service/mvd/mvd_std.h22
-rw-r--r--src/core/hle/service/nfc/nfc.cpp18
-rw-r--r--src/core/hle/service/nfc/nfc.h14
-rw-r--r--src/core/hle/service/nfc/nfc_m.cpp44
-rw-r--r--src/core/hle/service/nfc/nfc_m.h22
-rw-r--r--src/core/hle/service/nfc/nfc_u.cpp41
-rw-r--r--src/core/hle/service/nfc/nfc_u.h22
-rw-r--r--src/core/hle/service/nim/nim_s.cpp1
-rw-r--r--src/core/hle/service/nim/nim_u.cpp1
-rw-r--r--src/core/hle/service/ns_s.cpp14
-rw-r--r--src/core/hle/service/ns_s.h14
-rw-r--r--src/core/hle/service/nwm/nwm.cpp28
-rw-r--r--src/core/hle/service/nwm/nwm.h14
-rw-r--r--src/core/hle/service/nwm/nwm_cec.cpp19
-rw-r--r--src/core/hle/service/nwm/nwm_cec.h22
-rw-r--r--src/core/hle/service/nwm/nwm_ext.cpp19
-rw-r--r--src/core/hle/service/nwm/nwm_ext.h22
-rw-r--r--src/core/hle/service/nwm/nwm_inf.cpp21
-rw-r--r--src/core/hle/service/nwm/nwm_inf.h22
-rw-r--r--src/core/hle/service/nwm/nwm_sap.cpp20
-rw-r--r--src/core/hle/service/nwm/nwm_sap.h22
-rw-r--r--src/core/hle/service/nwm/nwm_soc.cpp20
-rw-r--r--src/core/hle/service/nwm/nwm_soc.h22
-rw-r--r--src/core/hle/service/nwm/nwm_tst.cpp20
-rw-r--r--src/core/hle/service/nwm/nwm_tst.h22
-rw-r--r--src/core/hle/service/nwm/nwm_uds.cpp (renamed from src/core/hle/service/nwm_uds.cpp)43
-rw-r--r--src/core/hle/service/nwm/nwm_uds.h (renamed from src/core/hle/service/nwm_uds.h)17
-rw-r--r--src/core/hle/service/pm_app.cpp29
-rw-r--r--src/core/hle/service/pm_app.h13
-rw-r--r--src/core/hle/service/ptm/ptm.cpp15
-rw-r--r--src/core/hle/service/ptm/ptm.h7
-rw-r--r--src/core/hle/service/ptm/ptm_gets.cpp37
-rw-r--r--src/core/hle/service/ptm/ptm_gets.h22
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp20
-rw-r--r--src/core/hle/service/ptm/ptm_play.h4
-rw-r--r--src/core/hle/service/ptm/ptm_sets.cpp20
-rw-r--r--src/core/hle/service/ptm/ptm_sets.h22
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.cpp27
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.h13
-rw-r--r--src/core/hle/service/ptm/ptm_u.cpp2
-rw-r--r--src/core/hle/service/ptm/ptm_u.h4
-rw-r--r--src/core/hle/service/qtm/qtm.cpp21
-rw-r--r--src/core/hle/service/qtm/qtm.h14
-rw-r--r--src/core/hle/service/qtm/qtm_s.cpp23
-rw-r--r--src/core/hle/service/qtm/qtm_s.h22
-rw-r--r--src/core/hle/service/qtm/qtm_sp.cpp23
-rw-r--r--src/core/hle/service/qtm/qtm_sp.h22
-rw-r--r--src/core/hle/service/qtm/qtm_u.cpp23
-rw-r--r--src/core/hle/service/qtm/qtm_u.h22
-rw-r--r--src/core/hle/service/service.cpp151
-rw-r--r--src/core/hle/service/service.h88
-rw-r--r--src/core/hle/service/soc_u.cpp56
-rw-r--r--src/core/hle/service/soc_u.h15
-rw-r--r--src/core/hle/service/srv.cpp38
-rw-r--r--src/core/hle/service/srv.h15
-rw-r--r--src/core/hle/service/ssl_c.cpp21
-rw-r--r--src/core/hle/service/ssl_c.h13
-rw-r--r--src/core/hle/service/y2r_u.cpp106
-rw-r--r--src/core/hle/service/y2r_u.h15
-rw-r--r--src/core/hle/svc.cpp298
-rw-r--r--src/core/hw/gpu.cpp14
-rw-r--r--src/core/hw/y2r.cpp2
-rw-r--r--src/core/hw/y2r.h9
-rw-r--r--src/core/loader/3dsx.h20
-rw-r--r--src/core/loader/elf.h8
-rw-r--r--src/core/loader/loader.h9
-rw-r--r--src/core/loader/ncch.cpp12
-rw-r--r--src/core/loader/ncch.h31
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/system.cpp55
-rw-r--r--src/core/system.h21
195 files changed, 4062 insertions, 1683 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8ce141e6a..3621449b3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -29,15 +29,17 @@ set(SRCS
file_sys/ivfc_archive.cpp
file_sys/path_parser.cpp
file_sys/savedata_archive.cpp
+ frontend/emu_window.cpp
+ frontend/key_map.cpp
gdbstub/gdbstub.cpp
hle/config_mem.cpp
- hle/hle.cpp
hle/applets/applet.cpp
hle/applets/erreula.cpp
hle/applets/mii_selector.cpp
hle/applets/swkbd.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/client_port.cpp
+ hle/kernel/client_session.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp
hle/kernel/memory.cpp
@@ -46,14 +48,15 @@ set(SRCS
hle/kernel/resource_limit.cpp
hle/kernel/semaphore.cpp
hle/kernel/server_port.cpp
- hle/kernel/session.cpp
+ hle/kernel/server_session.cpp
hle/kernel/shared_memory.cpp
hle/kernel/thread.cpp
hle/kernel/timer.cpp
hle/kernel/vm_manager.cpp
hle/service/ac_u.cpp
- hle/service/act_a.cpp
- hle/service/act_u.cpp
+ hle/service/act/act.cpp
+ hle/service/act/act_a.cpp
+ hle/service/act/act_u.cpp
hle/service/am/am.cpp
hle/service/am/am_app.cpp
hle/service/am/am_net.cpp
@@ -73,10 +76,12 @@ set(SRCS
hle/service/cam/cam_s.cpp
hle/service/cam/cam_u.cpp
hle/service/cecd/cecd.cpp
+ hle/service/cecd/cecd_ndm.cpp
hle/service/cecd/cecd_s.cpp
hle/service/cecd/cecd_u.cpp
hle/service/cfg/cfg.cpp
hle/service/cfg/cfg_i.cpp
+ hle/service/cfg/cfg_nor.cpp
hle/service/cfg/cfg_s.cpp
hle/service/cfg/cfg_u.cpp
hle/service/csnd_snd.cpp
@@ -105,8 +110,13 @@ set(SRCS
hle/service/ldr_ro/ldr_ro.cpp
hle/service/ldr_ro/memory_synchronizer.cpp
hle/service/mic_u.cpp
+ hle/service/mvd/mvd.cpp
+ hle/service/mvd/mvd_std.cpp
hle/service/ndm/ndm.cpp
hle/service/ndm/ndm_u.cpp
+ hle/service/nfc/nfc.cpp
+ hle/service/nfc/nfc_m.cpp
+ hle/service/nfc/nfc_u.cpp
hle/service/news/news.cpp
hle/service/news/news_s.cpp
hle/service/news/news_u.cpp
@@ -115,12 +125,25 @@ set(SRCS
hle/service/nim/nim_s.cpp
hle/service/nim/nim_u.cpp
hle/service/ns_s.cpp
- hle/service/nwm_uds.cpp
+ hle/service/nwm/nwm.cpp
+ hle/service/nwm/nwm_cec.cpp
+ hle/service/nwm/nwm_ext.cpp
+ hle/service/nwm/nwm_inf.cpp
+ hle/service/nwm/nwm_sap.cpp
+ hle/service/nwm/nwm_soc.cpp
+ hle/service/nwm/nwm_tst.cpp
+ hle/service/nwm/nwm_uds.cpp
hle/service/pm_app.cpp
hle/service/ptm/ptm.cpp
+ hle/service/ptm/ptm_gets.cpp
hle/service/ptm/ptm_play.cpp
+ hle/service/ptm/ptm_sets.cpp
hle/service/ptm/ptm_sysm.cpp
hle/service/ptm/ptm_u.cpp
+ hle/service/qtm/qtm.cpp
+ hle/service/qtm/qtm_s.cpp
+ hle/service/qtm/qtm_sp.cpp
+ hle/service/qtm/qtm_u.cpp
hle/service/service.cpp
hle/service/soc_u.cpp
hle/service/srv.cpp
@@ -140,7 +163,6 @@ set(SRCS
tracer/recorder.cpp
memory.cpp
settings.cpp
- system.cpp
)
set(HEADERS
@@ -178,16 +200,19 @@ set(HEADERS
file_sys/ivfc_archive.h
file_sys/path_parser.h
file_sys/savedata_archive.h
+ frontend/emu_window.h
+ frontend/key_map.h
gdbstub/gdbstub.h
hle/config_mem.h
hle/function_wrappers.h
- hle/hle.h
+ hle/ipc.h
hle/applets/applet.h
hle/applets/erreula.h
hle/applets/mii_selector.h
hle/applets/swkbd.h
hle/kernel/address_arbiter.h
hle/kernel/client_port.h
+ hle/kernel/client_session.h
hle/kernel/event.h
hle/kernel/kernel.h
hle/kernel/memory.h
@@ -196,15 +221,16 @@ set(HEADERS
hle/kernel/resource_limit.h
hle/kernel/semaphore.h
hle/kernel/server_port.h
- hle/kernel/session.h
+ hle/kernel/server_session.h
hle/kernel/shared_memory.h
hle/kernel/thread.h
hle/kernel/timer.h
hle/kernel/vm_manager.h
hle/result.h
hle/service/ac_u.h
- hle/service/act_a.h
- hle/service/act_u.h
+ hle/service/act/act.h
+ hle/service/act/act_a.h
+ hle/service/act/act_u.h
hle/service/am/am.h
hle/service/am/am_app.h
hle/service/am/am_net.h
@@ -224,10 +250,12 @@ set(HEADERS
hle/service/cam/cam_s.h
hle/service/cam/cam_u.h
hle/service/cecd/cecd.h
+ hle/service/cecd/cecd_ndm.h
hle/service/cecd/cecd_s.h
hle/service/cecd/cecd_u.h
hle/service/cfg/cfg.h
hle/service/cfg/cfg_i.h
+ hle/service/cfg/cfg_nor.h
hle/service/cfg/cfg_s.h
hle/service/cfg/cfg_u.h
hle/service/csnd_snd.h
@@ -256,8 +284,13 @@ set(HEADERS
hle/service/ldr_ro/ldr_ro.h
hle/service/ldr_ro/memory_synchronizer.h
hle/service/mic_u.h
+ hle/service/mvd/mvd.h
+ hle/service/mvd/mvd_std.h
hle/service/ndm/ndm.h
hle/service/ndm/ndm_u.h
+ hle/service/nfc/nfc.h
+ hle/service/nfc/nfc_m.h
+ hle/service/nfc/nfc_u.h
hle/service/news/news.h
hle/service/news/news_s.h
hle/service/news/news_u.h
@@ -266,12 +299,25 @@ set(HEADERS
hle/service/nim/nim_s.h
hle/service/nim/nim_u.h
hle/service/ns_s.h
- hle/service/nwm_uds.h
+ hle/service/nwm/nwm.h
+ hle/service/nwm/nwm_cec.h
+ hle/service/nwm/nwm_ext.h
+ hle/service/nwm/nwm_inf.h
+ hle/service/nwm/nwm_sap.h
+ hle/service/nwm/nwm_soc.h
+ hle/service/nwm/nwm_tst.h
+ hle/service/nwm/nwm_uds.h
hle/service/pm_app.h
hle/service/ptm/ptm.h
+ hle/service/ptm/ptm_gets.h
hle/service/ptm/ptm_play.h
+ hle/service/ptm/ptm_sets.h
hle/service/ptm/ptm_sysm.h
hle/service/ptm/ptm_u.h
+ hle/service/qtm/qtm.h
+ hle/service/qtm/qtm_s.h
+ hle/service/qtm/qtm_sp.h
+ hle/service/qtm/qtm_u.h
hle/service/service.h
hle/service/soc_u.h
hle/service/srv.h
@@ -294,7 +340,6 @@ set(HEADERS
memory_setup.h
mmio.h
settings.h
- system.h
)
include_directories(../../externals/dynarmic/include)
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index e466b21b2..ccd43f431 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -8,15 +8,22 @@
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
-namespace Core {
-struct ThreadContext;
-}
-
/// Generic ARM11 CPU interface
class ARM_Interface : NonCopyable {
public:
virtual ~ARM_Interface() {}
+ struct ThreadContext {
+ u32 cpu_registers[13];
+ u32 sp;
+ u32 lr;
+ u32 pc;
+ u32 cpsr;
+ u32 fpu_registers[64];
+ u32 fpscr;
+ u32 fpexc;
+ };
+
/**
* Runs the CPU for the given number of instructions
* @param num_instructions Number of instructions to run
@@ -124,13 +131,13 @@ public:
* Saves the current CPU context
* @param ctx Thread context to save
*/
- virtual void SaveContext(Core::ThreadContext& ctx) = 0;
+ virtual void SaveContext(ThreadContext& ctx) = 0;
/**
* Loads a CPU context
* @param ctx Thread context to load
*/
- virtual void LoadContext(const Core::ThreadContext& ctx) = 0;
+ virtual void LoadContext(const ThreadContext& ctx) = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index ca8a94ee9..9f25e3b00 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <dynarmic/dynarmic.h>
#include "common/assert.h"
#include "common/microprofile.h"
@@ -44,6 +45,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks(ARMul_State* interpeter_state) {
user_callbacks.user_arg = static_cast<void*>(interpeter_state);
user_callbacks.CallSVC = &SVC::CallSVC;
user_callbacks.IsReadOnlyMemory = &IsReadOnlyMemory;
+ user_callbacks.MemoryReadCode = &Memory::Read32;
user_callbacks.MemoryRead8 = &Memory::Read8;
user_callbacks.MemoryRead16 = &Memory::Read16;
user_callbacks.MemoryRead32 = &Memory::Read32;
@@ -136,7 +138,7 @@ void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
AddTicks(ticks_executed);
}
-void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) {
+void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers));
memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers));
@@ -149,7 +151,7 @@ void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) {
ctx.fpexc = interpreter_state->VFP[VFP_FPEXC];
}
-void ARM_Dynarmic::LoadContext(const Core::ThreadContext& ctx) {
+void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index ced86d29b..87ab53d81 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -10,10 +10,6 @@
#include "core/arm/arm_interface.h"
#include "core/arm/skyeye_common/armstate.h"
-namespace Core {
-struct ThreadContext;
-}
-
class ARM_Dynarmic final : public ARM_Interface {
public:
ARM_Dynarmic(PrivilegeMode initial_mode);
@@ -33,8 +29,8 @@ public:
void AddTicks(u64 ticks) override;
- void SaveContext(Core::ThreadContext& ctx) override;
- void LoadContext(const Core::ThreadContext& ctx) override;
+ void SaveContext(ThreadContext& ctx) override;
+ void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ExecuteInstructions(int num_instructions) override;
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 34c7f945e..81f9bf99e 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -89,7 +89,7 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
AddTicks(ticks_executed);
}
-void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
+void ARM_DynCom::SaveContext(ThreadContext& ctx) {
memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
@@ -102,7 +102,7 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
ctx.fpexc = state->VFP[VFP_FPEXC];
}
-void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
+void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 65db1f0f9..62c174f3c 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -10,10 +10,6 @@
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/armstate.h"
-namespace Core {
-struct ThreadContext;
-}
-
class ARM_DynCom final : public ARM_Interface {
public:
ARM_DynCom(PrivilegeMode initial_mode);
@@ -36,8 +32,8 @@ public:
void AddTicks(u64 ticks) override;
- void SaveContext(Core::ThreadContext& ctx) override;
- void LoadContext(const Core::ThreadContext& ctx) override;
+ void SaveContext(ThreadContext& ctx) override;
+ void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ExecuteInstructions(int num_instructions) override;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 7b8616702..67c45640a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -953,7 +953,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
#define GDB_BP_CHECK \
cpu->Cpsr &= ~(1 << 5); \
cpu->Cpsr |= cpu->TFlag << 5; \
- if (GDBStub::g_server_enabled) { \
+ if (GDBStub::IsServerEnabled()) { \
if (GDBStub::IsMemoryBreak() || (breakpoint_data.type != GDBStub::BreakpointType::None && \
PC == breakpoint_data.address)) { \
GDBStub::Break(); \
@@ -1649,7 +1649,7 @@ DISPATCH : {
}
// Find breakpoint if one exists within the block
- if (GDBStub::g_server_enabled && GDBStub::IsConnected()) {
+ if (GDBStub::IsConnected()) {
breakpoint_data =
GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute);
}
diff --git a/src/core/arm/dyncom/arm_dyncom_trans.h b/src/core/arm/dyncom/arm_dyncom_trans.h
index b1ec90662..632ff2cd6 100644
--- a/src/core/arm/dyncom/arm_dyncom_trans.h
+++ b/src/core/arm/dyncom/arm_dyncom_trans.h
@@ -1,3 +1,5 @@
+#pragma once
+
#include <cstddef>
#include "common/common_types.h"
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
index 1465b074e..c36b0208f 100644
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -182,7 +182,7 @@ void ARMul_State::ResetMPCoreCP15Registers() {
}
static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) {
- if (GDBStub::g_server_enabled && GDBStub::CheckBreakpoint(address, type)) {
+ if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) {
LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address);
GDBStub::Break(true);
}
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 49ac8be6e..202cd332b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -3,6 +3,8 @@
// Refer to the license.txt file included.
#include <memory>
+
+#include "audio_core/audio_core.h"
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
@@ -10,19 +12,25 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
-#include "core/hle/hle.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/service/service.h"
#include "core/hw/hw.h"
+#include "core/loader/loader.h"
#include "core/settings.h"
+#include "video_core/video_core.h"
namespace Core {
-std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core
-std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core
+/*static*/ System System::s_instance;
+
+System::ResultStatus System::RunLoop(int tight_loop) {
+ if (!cpu_core) {
+ return ResultStatus::ErrorNotInitialized;
+ }
-/// Run the core CPU loop
-void RunLoop(int tight_loop) {
- if (GDBStub::g_server_enabled) {
+ if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
@@ -32,7 +40,7 @@ void RunLoop(int tight_loop) {
GDBStub::SetCpuStepFlag(false);
tight_loop = 1;
} else {
- return;
+ return ResultStatus::Success;
}
}
}
@@ -43,48 +51,115 @@ void RunLoop(int tight_loop) {
LOG_TRACE(Core_ARM11, "Idling");
CoreTiming::Idle();
CoreTiming::Advance();
- HLE::Reschedule(__func__);
+ PrepareReschedule();
} else {
- g_app_core->Run(tight_loop);
+ cpu_core->Run(tight_loop);
}
HW::Update();
- if (HLE::IsReschedulePending()) {
- Kernel::Reschedule();
- }
+ Reschedule();
+
+ return ResultStatus::Success;
+}
+
+System::ResultStatus System::SingleStep() {
+ return RunLoop(1);
}
-/// Step the CPU one instruction
-void SingleStep() {
- RunLoop(1);
+System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {
+ if (app_loader) {
+ app_loader.reset();
+ }
+
+ app_loader = Loader::GetLoader(filepath);
+
+ if (!app_loader) {
+ LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
+ return ResultStatus::ErrorGetLoader;
+ }
+
+ boost::optional<u32> system_mode{app_loader->LoadKernelSystemMode()};
+ if (!system_mode) {
+ LOG_CRITICAL(Core, "Failed to determine system mode!");
+ return ResultStatus::ErrorSystemMode;
+ }
+
+ ResultStatus init_result{Init(emu_window, system_mode.get())};
+ if (init_result != ResultStatus::Success) {
+ LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result);
+ System::Shutdown();
+ return init_result;
+ }
+
+ const Loader::ResultStatus load_result{app_loader->Load()};
+ if (Loader::ResultStatus::Success != load_result) {
+ LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result);
+ System::Shutdown();
+
+ switch (load_result) {
+ case Loader::ResultStatus::ErrorEncrypted:
+ return ResultStatus::ErrorLoader_ErrorEncrypted;
+ case Loader::ResultStatus::ErrorInvalidFormat:
+ return ResultStatus::ErrorLoader_ErrorInvalidFormat;
+ default:
+ return ResultStatus::ErrorLoader;
+ }
+ }
+ return ResultStatus::Success;
}
-/// Halt the core
-void Halt(const char* msg) {
- // TODO(ShizZy): ImplementMe
+void System::PrepareReschedule() {
+ cpu_core->PrepareReschedule();
+ reschedule_pending = true;
}
-/// Kill the core
-void Stop() {
- // TODO(ShizZy): ImplementMe
+void System::Reschedule() {
+ if (!reschedule_pending) {
+ return;
+ }
+
+ reschedule_pending = false;
+ Kernel::Reschedule();
}
-/// Initialize the core
-void Init() {
+System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
+ if (cpu_core) {
+ cpu_core.reset();
+ }
+
+ Memory::Init();
+
if (Settings::values.use_cpu_jit) {
- g_sys_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
- g_app_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
+ cpu_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
} else {
- g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE);
- g_app_core = std::make_unique<ARM_DynCom>(USER32MODE);
+ cpu_core = std::make_unique<ARM_DynCom>(USER32MODE);
+ }
+
+ CoreTiming::Init();
+ HW::Init();
+ Kernel::Init(system_mode);
+ Service::Init();
+ AudioCore::Init();
+ GDBStub::Init();
+
+ if (!VideoCore::Init(emu_window)) {
+ return ResultStatus::ErrorVideoCore;
}
LOG_DEBUG(Core, "Initialized OK");
+
+ return ResultStatus::Success;
}
-void Shutdown() {
- g_app_core.reset();
- g_sys_core.reset();
+void System::Shutdown() {
+ GDBStub::Shutdown();
+ AudioCore::Shutdown();
+ VideoCore::Shutdown();
+ Service::Shutdown();
+ Kernel::Shutdown();
+ HW::Shutdown();
+ CoreTiming::Shutdown();
+ cpu_core.reset();
LOG_DEBUG(Core, "Shutdown OK");
}
diff --git a/src/core/core.h b/src/core/core.h
index ffbfa91c3..1015e8847 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -5,56 +5,118 @@
#pragma once
#include <memory>
+#include <string>
+
#include "common/common_types.h"
+#include "core/memory.h"
+class EmuWindow;
class ARM_Interface;
-////////////////////////////////////////////////////////////////////////////////////////////////////
+namespace Loader {
+class AppLoader;
+}
namespace Core {
-struct ThreadContext {
- u32 cpu_registers[13];
- u32 sp;
- u32 lr;
- u32 pc;
- u32 cpsr;
- u32 fpu_registers[64];
- u32 fpscr;
- u32 fpexc;
+class System {
+public:
+ /**
+ * Gets the instance of the System singleton class.
+ * @returns Reference to the instance of the System singleton class.
+ */
+ static System& GetInstance() {
+ return s_instance;
+ }
+
+ /// Enumeration representing the return values of the System Initialize and Load process.
+ enum class ResultStatus : u32 {
+ Success, ///< Succeeded
+ ErrorNotInitialized, ///< Error trying to use core prior to initialization
+ ErrorGetLoader, ///< Error finding the correct application loader
+ ErrorSystemMode, ///< Error determining the system mode
+ ErrorLoader, ///< Error loading the specified application
+ ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
+ ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
+ /// invalid format
+ ErrorVideoCore, ///< Error in the video core
+ };
+
+ /**
+ * Run the core CPU loop
+ * This function runs the core for the specified number of CPU instructions before trying to
+ * update hardware. This is much faster than SingleStep (and should be equivalent), as the CPU
+ * is not required to do a full dispatch with each instruction. NOTE: the number of instructions
+ * requested is not guaranteed to run, as this will be interrupted preemptively if a hardware
+ * update is requested (e.g. on a thread switch).
+ * @param tight_loop Number of instructions to execute.
+ * @return Result status, indicating whethor or not the operation succeeded.
+ */
+ ResultStatus RunLoop(int tight_loop = 1000);
+
+ /**
+ * Step the CPU one instruction
+ * @return Result status, indicating whethor or not the operation succeeded.
+ */
+ ResultStatus SingleStep();
+
+ /// Shutdown the emulated system.
+ void Shutdown();
+
+ /**
+ * Load an executable application.
+ * @param emu_window Pointer to the host-system window used for video output and keyboard input.
+ * @param filepath String path to the executable application to load on the host file system.
+ * @returns ResultStatus code, indicating if the operation succeeded.
+ */
+ ResultStatus Load(EmuWindow* emu_window, const std::string& filepath);
+
+ /**
+ * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
+ * application).
+ * @returns True if the emulated system is powered on, otherwise false.
+ */
+ bool IsPoweredOn() const {
+ return cpu_core != nullptr;
+ }
+
+ /// Prepare the core emulation for a reschedule
+ void PrepareReschedule();
+
+ /**
+ * Gets a reference to the emulated CPU.
+ * @returns A reference to the emulated CPU.
+ */
+ ARM_Interface& CPU() {
+ return *cpu_core;
+ }
+
+private:
+ /**
+ * Initialize the emulated system.
+ * @param emu_window Pointer to the host-system window used for video output and keyboard input.
+ * @param system_mode The system mode.
+ * @return ResultStatus code, indicating if the operation succeeded.
+ */
+ ResultStatus Init(EmuWindow* emu_window, u32 system_mode);
+
+ /// Reschedule the core emulation
+ void Reschedule();
+
+ /// AppLoader used to load the current executing application
+ std::unique_ptr<Loader::AppLoader> app_loader;
+
+ ///< ARM11 CPU core
+ std::unique_ptr<ARM_Interface> cpu_core;
+
+ /// When true, signals that a reschedule should happen
+ bool reschedule_pending{};
+
+ static System s_instance;
};
-extern std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core
-extern std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// Start the core
-void Start();
-
-/**
- * Run the core CPU loop
- * This function runs the core for the specified number of CPU instructions before trying to update
- * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not
- * required to do a full dispatch with each instruction. NOTE: the number of instructions requested
- * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
- * requested (e.g. on a thread switch).
- */
-void RunLoop(int tight_loop = 1000);
-
-/// Step the CPU one instruction
-void SingleStep();
-
-/// Halt the core
-void Halt(const char* msg);
-
-/// Kill the core
-void Stop();
-
-/// Initialize the core
-void Init();
-
-/// Shutdown the core
-void Shutdown();
+static ARM_Interface& CPU() {
+ return System::GetInstance().CPU();
+}
-} // namespace
+} // namespace Core
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 5220b55ea..a437d0823 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -130,7 +130,6 @@ int RegisterEvent(const char* name, TimedCallback callback) {
static void AntiCrashCallback(u64 userdata, int cycles_late) {
LOG_CRITICAL(Core_Timing, "Savestate broken: an unregistered event was called.");
- Core::Halt("invalid timing events");
}
void RestoreRegisterEvent(int event_type, const char* name, TimedCallback callback) {
@@ -147,7 +146,7 @@ void UnregisterAllEvents() {
}
void Init() {
- Core::g_app_core->down_count = INITIAL_SLICE_LENGTH;
+ Core::CPU().down_count = INITIAL_SLICE_LENGTH;
g_slice_length = INITIAL_SLICE_LENGTH;
global_timer = 0;
idled_cycles = 0;
@@ -187,7 +186,7 @@ void Shutdown() {
}
u64 GetTicks() {
- return (u64)global_timer + g_slice_length - Core::g_app_core->down_count;
+ return (u64)global_timer + g_slice_length - Core::CPU().down_count;
}
u64 GetIdleTicks() {
@@ -461,18 +460,18 @@ void MoveEvents() {
}
void ForceCheck() {
- s64 cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ s64 cycles_executed = g_slice_length - Core::CPU().down_count;
global_timer += cycles_executed;
// This will cause us to check for new events immediately.
- Core::g_app_core->down_count = 0;
+ Core::CPU().down_count = 0;
// But let's not eat a bunch more time in Advance() because of this.
g_slice_length = 0;
}
void Advance() {
- s64 cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ s64 cycles_executed = g_slice_length - Core::CPU().down_count;
global_timer += cycles_executed;
- Core::g_app_core->down_count = g_slice_length;
+ Core::CPU().down_count = g_slice_length;
if (has_ts_events)
MoveEvents();
@@ -481,7 +480,7 @@ void Advance() {
if (!first) {
if (g_slice_length < 10000) {
g_slice_length += 10000;
- Core::g_app_core->down_count += g_slice_length;
+ Core::CPU().down_count += g_slice_length;
}
} else {
// Note that events can eat cycles as well.
@@ -491,7 +490,7 @@ void Advance() {
const int diff = target - g_slice_length;
g_slice_length += diff;
- Core::g_app_core->down_count += diff;
+ Core::CPU().down_count += diff;
}
if (advance_callback)
advance_callback(static_cast<int>(cycles_executed));
@@ -507,12 +506,12 @@ void LogPendingEvents() {
}
void Idle(int max_idle) {
- s64 cycles_down = Core::g_app_core->down_count;
+ s64 cycles_down = Core::CPU().down_count;
if (max_idle != 0 && cycles_down > max_idle)
cycles_down = max_idle;
if (first && cycles_down > 0) {
- s64 cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ s64 cycles_executed = g_slice_length - Core::CPU().down_count;
s64 cycles_next_event = first->time - global_timer;
if (cycles_next_event < cycles_executed + cycles_down) {
@@ -527,9 +526,9 @@ void Idle(int max_idle) {
cycles_down / (float)(g_clock_rate_arm11 * 0.001f));
idled_cycles += cycles_down;
- Core::g_app_core->down_count -= cycles_down;
- if (Core::g_app_core->down_count == 0)
- Core::g_app_core->down_count = -1;
+ Core::CPU().down_count -= cycles_down;
+ if (Core::CPU().down_count == 0)
+ Core::CPU().down_count = -1;
}
std::string GetScheduledEventsSummary() {
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index e1c4931ec..51ce78435 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -64,7 +64,7 @@ private:
*/
class ExtSaveDataArchive : public SaveDataArchive {
public:
- ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {}
+ explicit ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {}
std::string GetName() const override {
return "ExtSaveDataArchive: " + mount_point;
@@ -141,11 +141,10 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path)
std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
if (shared)
- return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(),
- SYSTEM_ID.c_str());
+ return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID);
- return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
- SYSTEM_ID.c_str(), SDCARD_ID.c_str());
+ return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), SYSTEM_ID,
+ SDCARD_ID);
}
Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 6f1aadfc3..89455e39c 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -19,7 +19,7 @@
namespace FileSys {
static std::string GetNCCHContainerPath(const std::string& nand_directory) {
- return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID.c_str());
+ return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID);
}
static std::string GetNCCHPath(const std::string& mount_point, u32 high, u32 low) {
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 66b8ce75d..753b91f96 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -17,7 +17,7 @@ namespace FileSys {
/// File system interface to the NCCH archive
class ArchiveFactory_NCCH final : public ArchiveFactory {
public:
- ArchiveFactory_NCCH(const std::string& mount_point);
+ explicit ArchiveFactory_NCCH(const std::string& mount_point);
std::string GetName() const override {
return "NCCH";
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 8a8082a05..1eaf99b54 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -20,7 +20,7 @@ namespace FileSys {
/// File system interface to the RomFS archive
class ArchiveFactory_RomFS final : public ArchiveFactory {
public:
- ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
+ explicit ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
std::string GetName() const override {
return "RomFS";
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 9d99b110c..f6c70bfcc 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -17,7 +17,7 @@ namespace FileSys {
/// Archive backend for SDMC archive
class SDMCArchive : public ArchiveBackend {
public:
- SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
+ explicit SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
std::string GetName() const override {
return "SDMCArchive: " + mount_point;
@@ -43,7 +43,7 @@ protected:
/// File system interface to the SDMC archive
class ArchiveFactory_SDMC final : public ArchiveFactory {
public:
- ArchiveFactory_SDMC(const std::string& mount_point);
+ explicit ArchiveFactory_SDMC(const std::string& mount_point);
/**
* Initialize the archive.
diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h
index ed977485a..9cd38d96f 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.h
+++ b/src/core/file_sys/archive_sdmcwriteonly.h
@@ -19,7 +19,7 @@ namespace FileSys {
*/
class SDMCWriteOnlyArchive : public SDMCArchive {
public:
- SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {}
+ explicit SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {}
std::string GetName() const override {
return "SDMCWriteOnlyArchive: " + mount_point;
@@ -34,7 +34,7 @@ public:
/// File system interface to the SDMC write-only archive
class ArchiveFactory_SDMCWriteOnly final : public ArchiveFactory {
public:
- ArchiveFactory_SDMCWriteOnly(const std::string& mount_point);
+ explicit ArchiveFactory_SDMCWriteOnly(const std::string& mount_point);
/**
* Initialize the archive.
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp
index 2d8a950a3..e01357891 100644
--- a/src/core/file_sys/archive_source_sd_savedata.cpp
+++ b/src/core/file_sys/archive_source_sd_savedata.cpp
@@ -18,7 +18,7 @@ namespace {
std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
- SYSTEM_ID.c_str(), SDCARD_ID.c_str());
+ SYSTEM_ID, SDCARD_ID);
}
std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
@@ -90,4 +90,9 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program
return MakeResult<ArchiveFormatInfo>(info);
}
+std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point,
+ u64 program_id) {
+ return GetSaveDataPath(GetSaveDataContainerPath(mount_point), program_id);
+}
+
} // namespace FileSys
diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h
index b33126c31..b5fe43cc1 100644
--- a/src/core/file_sys/archive_source_sd_savedata.h
+++ b/src/core/file_sys/archive_source_sd_savedata.h
@@ -23,6 +23,8 @@ public:
ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info);
ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const;
+ static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id);
+
private:
std::string mount_point;
};
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 54e7793e0..8986b5c0e 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -26,7 +26,7 @@ std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& pa
}
std::string GetSystemSaveDataContainerPath(const std::string& mount_point) {
- return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str());
+ return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID);
}
Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) {
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index a24b89f2b..52eb6c630 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -18,7 +18,7 @@ namespace FileSys {
/// File system interface to the SystemSaveData archive
class ArchiveFactory_SystemSaveData final : public ArchiveFactory {
public:
- ArchiveFactory_SystemSaveData(const std::string& mount_point);
+ explicit ArchiveFactory_SystemSaveData(const std::string& mount_point);
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
diff --git a/src/core/file_sys/path_parser.h b/src/core/file_sys/path_parser.h
index 990802579..b9f52f65d 100644
--- a/src/core/file_sys/path_parser.h
+++ b/src/core/file_sys/path_parser.h
@@ -17,7 +17,7 @@ namespace FileSys {
*/
class PathParser {
public:
- PathParser(const Path& path);
+ explicit PathParser(const Path& path);
/**
* Checks if the Path is valid.
diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h
index 2fb6c452a..176d35710 100644
--- a/src/core/file_sys/savedata_archive.h
+++ b/src/core/file_sys/savedata_archive.h
@@ -18,7 +18,7 @@ namespace FileSys {
/// Archive backend for general save data archive type (SaveData and SystemSaveData)
class SaveDataArchive : public ArchiveBackend {
public:
- SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
+ explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
std::string GetName() const override {
return "SaveDataArchive: " + mount_point;
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
new file mode 100644
index 000000000..f6f90f9e1
--- /dev/null
+++ b/src/core/frontend/emu_window.cpp
@@ -0,0 +1,107 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <cmath>
+#include "common/assert.h"
+#include "core/frontend/emu_window.h"
+#include "core/frontend/key_map.h"
+#include "video_core/video_core.h"
+
+void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
+ pad_state.hex |= pad.hex;
+}
+
+void EmuWindow::ButtonReleased(Service::HID::PadState pad) {
+ pad_state.hex &= ~pad.hex;
+}
+
+void EmuWindow::CirclePadUpdated(float x, float y) {
+ constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
+
+ // Make sure the coordinates are in the unit circle,
+ // otherwise normalize it.
+ float r = x * x + y * y;
+ if (r > 1) {
+ r = std::sqrt(r);
+ x /= r;
+ y /= r;
+ }
+
+ circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS);
+ circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS);
+}
+
+/**
+ * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout
+ * @param layout FramebufferLayout object describing the framebuffer size and screen positions
+ * @param framebuffer_x Framebuffer x-coordinate to check
+ * @param framebuffer_y Framebuffer y-coordinate to check
+ * @return True if the coordinates are within the touchpad, otherwise false
+ */
+static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigned framebuffer_x,
+ unsigned framebuffer_y) {
+ return (
+ framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom &&
+ framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right);
+}
+
+std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
+ new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
+ new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1);
+
+ new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
+ new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1);
+
+ return std::make_tuple(new_x, new_y);
+}
+
+void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
+ if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
+ return;
+
+ touch_x = VideoCore::kScreenBottomWidth *
+ (framebuffer_x - framebuffer_layout.bottom_screen.left) /
+ (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
+ touch_y = VideoCore::kScreenBottomHeight *
+ (framebuffer_y - framebuffer_layout.bottom_screen.top) /
+ (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
+
+ touch_pressed = true;
+ pad_state.touch.Assign(1);
+}
+
+void EmuWindow::TouchReleased() {
+ touch_pressed = false;
+ touch_x = 0;
+ touch_y = 0;
+ pad_state.touch.Assign(0);
+}
+
+void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
+ if (!touch_pressed)
+ return;
+
+ if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
+ std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
+
+ TouchPressed(framebuffer_x, framebuffer_y);
+}
+
+void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
+ Layout::FramebufferLayout layout;
+ switch (Settings::values.layout_option) {
+ case Settings::LayoutOption::SingleScreen:
+ layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen);
+ break;
+ case Settings::LayoutOption::LargeScreen:
+ layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
+ break;
+ case Settings::LayoutOption::Default:
+ default:
+ layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
+ break;
+ }
+ NotifyFramebufferLayoutChanged(layout);
+}
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
new file mode 100644
index 000000000..835c4d500
--- /dev/null
+++ b/src/core/frontend/emu_window.h
@@ -0,0 +1,290 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <tuple>
+#include <utility>
+#include "common/common_types.h"
+#include "common/framebuffer_layout.h"
+#include "common/math_util.h"
+#include "core/hle/service/hid/hid.h"
+
+/**
+ * Abstraction class used to provide an interface between emulation code and the frontend
+ * (e.g. SDL, QGLWidget, GLFW, etc...).
+ *
+ * Design notes on the interaction between EmuWindow and the emulation core:
+ * - Generally, decisions on anything visible to the user should be left up to the GUI.
+ * For example, the emulation core should not try to dictate some window title or size.
+ * This stuff is not the core's business and only causes problems with regards to thread-safety
+ * anyway.
+ * - Under certain circumstances, it may be desirable for the core to politely request the GUI
+ * to set e.g. a minimum window size. However, the GUI should always be free to ignore any
+ * such hints.
+ * - EmuWindow may expose some of its state as read-only to the emulation core, however care
+ * should be taken to make sure the provided information is self-consistent. This requires
+ * some sort of synchronization (most of this is still a TODO).
+ * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
+ * re-read the upper points again and think about it if you don't see this.
+ */
+class EmuWindow {
+public:
+ /// Data structure to store emuwindow configuration
+ struct WindowConfig {
+ bool fullscreen;
+ int res_width;
+ int res_height;
+ std::pair<unsigned, unsigned> min_client_area_size;
+ };
+
+ /// Swap buffers to display the next frame
+ virtual void SwapBuffers() = 0;
+
+ /// Polls window events
+ virtual void PollEvents() = 0;
+
+ /// Makes the graphics context current for the caller thread
+ virtual void MakeCurrent() = 0;
+
+ /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
+ virtual void DoneCurrent() = 0;
+
+ virtual void ReloadSetKeymaps() = 0;
+
+ /**
+ * Signals a button press action to the HID module.
+ * @param pad_state indicates which button to press
+ * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
+ */
+ void ButtonPressed(Service::HID::PadState pad_state);
+
+ /**
+ * Signals a button release action to the HID module.
+ * @param pad_state indicates which button to press
+ * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
+ */
+ void ButtonReleased(Service::HID::PadState pad_state);
+
+ /**
+ * Signals a circle pad change action to the HID module.
+ * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0]
+ * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0]
+ * @note the coordinates will be normalized if the radius is larger than 1
+ */
+ void CirclePadUpdated(float x, float y);
+
+ /**
+ * Signal that a touch pressed event has occurred (e.g. mouse click pressed)
+ * @param framebuffer_x Framebuffer x-coordinate that was pressed
+ * @param framebuffer_y Framebuffer y-coordinate that was pressed
+ */
+ void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y);
+
+ /// Signal that a touch released event has occurred (e.g. mouse click released)
+ void TouchReleased();
+
+ /**
+ * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window)
+ * @param framebuffer_x Framebuffer x-coordinate
+ * @param framebuffer_y Framebuffer y-coordinate
+ */
+ void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y);
+
+ /**
+ * Gets the current pad state (which buttons are pressed).
+ * @note This should be called by the core emu thread to get a state set by the window thread.
+ * @note This doesn't include analog input like circle pad direction
+ * @todo Fix this function to be thread-safe.
+ * @return PadState object indicating the current pad state
+ */
+ Service::HID::PadState GetPadState() const {
+ return pad_state;
+ }
+
+ /**
+ * Gets the current circle pad state.
+ * @note This should be called by the core emu thread to get a state set by the window thread.
+ * @todo Fix this function to be thread-safe.
+ * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates
+ */
+ std::tuple<s16, s16> GetCirclePadState() const {
+ return std::make_tuple(circle_pad_x, circle_pad_y);
+ }
+
+ /**
+ * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
+ * @note This should be called by the core emu thread to get a state set by the window thread.
+ * @todo Fix this function to be thread-safe.
+ * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and
+ * `pressed` is true if the touch screen is currently being pressed
+ */
+ std::tuple<u16, u16, bool> GetTouchState() const {
+ return std::make_tuple(touch_x, touch_y, touch_pressed);
+ }
+
+ /**
+ * Gets the current accelerometer state (acceleration along each three axis).
+ * Axis explained:
+ * +x is the same direction as LEFT on D-pad.
+ * +y is normal to the touch screen, pointing outward.
+ * +z is the same direction as UP on D-pad.
+ * Units:
+ * 1 unit of return value = 1/512 g (measured by hw test),
+ * where g is the gravitational acceleration (9.8 m/sec2).
+ * @note This should be called by the core emu thread to get a state set by the window thread.
+ * @todo Implement accelerometer input in front-end.
+ * @return std::tuple of (x, y, z)
+ */
+ std::tuple<s16, s16, s16> GetAccelerometerState() const {
+ // stubbed
+ return std::make_tuple(0, -512, 0);
+ }
+
+ /**
+ * Gets the current gyroscope state (angular rates about each three axis).
+ * Axis explained:
+ * +x is the same direction as LEFT on D-pad.
+ * +y is normal to the touch screen, pointing outward.
+ * +z is the same direction as UP on D-pad.
+ * Orientation is determined by right-hand rule.
+ * Units:
+ * 1 unit of return value = (1/coef) deg/sec,
+ * where coef is the return value of GetGyroscopeRawToDpsCoefficient().
+ * @note This should be called by the core emu thread to get a state set by the window thread.
+ * @todo Implement gyroscope input in front-end.
+ * @return std::tuple of (x, y, z)
+ */
+ std::tuple<s16, s16, s16> GetGyroscopeState() const {
+ // stubbed
+ return std::make_tuple(0, 0, 0);
+ }
+
+ /**
+ * Gets the coefficient for units conversion of gyroscope state.
+ * The conversion formula is r = coefficient * v,
+ * where v is angular rate in deg/sec,
+ * and r is the gyroscope state.
+ * @return float-type coefficient
+ */
+ f32 GetGyroscopeRawToDpsCoefficient() const {
+ return 14.375f; // taken from hw test, and gyroscope's document
+ }
+
+ /**
+ * Returns currently active configuration.
+ * @note Accesses to the returned object need not be consistent because it may be modified in
+ * another thread
+ */
+ const WindowConfig& GetActiveConfig() const {
+ return active_config;
+ }
+
+ /**
+ * Requests the internal configuration to be replaced by the specified argument at some point in
+ * the future.
+ * @note This method is thread-safe, because it delays configuration changes to the GUI event
+ * loop. Hence there is no guarantee on when the requested configuration will be active.
+ */
+ void SetConfig(const WindowConfig& val) {
+ config = val;
+ }
+
+ /**
+ * Gets the framebuffer layout (width, height, and screen regions)
+ * @note This method is thread-safe
+ */
+ const Layout::FramebufferLayout& GetFramebufferLayout() const {
+ return framebuffer_layout;
+ }
+
+ /**
+ * Convenience method to update the current frame layout
+ * Read from the current settings to determine which layout to use.
+ */
+ void UpdateCurrentFramebufferLayout(unsigned width, unsigned height);
+
+protected:
+ EmuWindow() {
+ // TODO: Find a better place to set this.
+ config.min_client_area_size = std::make_pair(400u, 480u);
+ active_config = config;
+ pad_state.hex = 0;
+ touch_x = 0;
+ touch_y = 0;
+ circle_pad_x = 0;
+ circle_pad_y = 0;
+ touch_pressed = false;
+ }
+ virtual ~EmuWindow() {}
+
+ /**
+ * Processes any pending configuration changes from the last SetConfig call.
+ * This method invokes OnMinimalClientAreaChangeRequest if the corresponding configuration
+ * field changed.
+ * @note Implementations will usually want to call this from the GUI thread.
+ * @todo Actually call this in existing implementations.
+ */
+ void ProcessConfigurationChanges() {
+ // TODO: For proper thread safety, we should eventually implement a proper
+ // multiple-writer/single-reader queue...
+
+ if (config.min_client_area_size != active_config.min_client_area_size) {
+ OnMinimalClientAreaChangeRequest(config.min_client_area_size);
+ config.min_client_area_size = active_config.min_client_area_size;
+ }
+ }
+
+ /**
+ * Update framebuffer layout with the given parameter.
+ * @note EmuWindow implementations will usually use this in window resize event handlers.
+ */
+ void NotifyFramebufferLayoutChanged(const Layout::FramebufferLayout& layout) {
+ framebuffer_layout = layout;
+ }
+
+ /**
+ * Update internal client area size with the given parameter.
+ * @note EmuWindow implementations will usually use this in window resize event handlers.
+ */
+ void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) {
+ client_area_width = size.first;
+ client_area_height = size.second;
+ }
+
+private:
+ /**
+ * Handler called when the minimal client area was requested to be changed via SetConfig.
+ * For the request to be honored, EmuWindow implementations will usually reimplement this
+ * function.
+ */
+ virtual void OnMinimalClientAreaChangeRequest(
+ const std::pair<unsigned, unsigned>& minimal_size) {
+ // By default, ignore this request and do nothing.
+ }
+
+ Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
+
+ unsigned client_area_width; ///< Current client width, should be set by window impl.
+ unsigned client_area_height; ///< Current client height, should be set by window impl.
+
+ WindowConfig config; ///< Internal configuration (changes pending for being applied in
+ /// ProcessConfigurationChanges)
+ WindowConfig active_config; ///< Internal active configuration
+
+ bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
+
+ u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
+ u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
+
+ s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
+ s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
+
+ /**
+ * Clip the provided coordinates to be inside the touchscreen area.
+ */
+ std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
+
+ Service::HID::PadState pad_state;
+};
diff --git a/src/core/frontend/key_map.cpp b/src/core/frontend/key_map.cpp
new file mode 100644
index 000000000..15f0e079c
--- /dev/null
+++ b/src/core/frontend/key_map.cpp
@@ -0,0 +1,152 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <map>
+#include "core/frontend/emu_window.h"
+#include "core/frontend/key_map.h"
+
+namespace KeyMap {
+
+// TODO (wwylele): currently we treat c-stick as four direction buttons
+// and map it directly to EmuWindow::ButtonPressed.
+// It should go the analog input way like circle pad does.
+const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
+ Service::HID::PAD_A,
+ Service::HID::PAD_B,
+ Service::HID::PAD_X,
+ Service::HID::PAD_Y,
+ Service::HID::PAD_L,
+ Service::HID::PAD_R,
+ Service::HID::PAD_ZL,
+ Service::HID::PAD_ZR,
+ Service::HID::PAD_START,
+ Service::HID::PAD_SELECT,
+ Service::HID::PAD_NONE,
+ Service::HID::PAD_UP,
+ Service::HID::PAD_DOWN,
+ Service::HID::PAD_LEFT,
+ Service::HID::PAD_RIGHT,
+ Service::HID::PAD_C_UP,
+ Service::HID::PAD_C_DOWN,
+ Service::HID::PAD_C_LEFT,
+ Service::HID::PAD_C_RIGHT,
+
+ IndirectTarget::CirclePadUp,
+ IndirectTarget::CirclePadDown,
+ IndirectTarget::CirclePadLeft,
+ IndirectTarget::CirclePadRight,
+ IndirectTarget::CirclePadModifier,
+}};
+
+static std::map<HostDeviceKey, KeyTarget> key_map;
+static int next_device_id = 0;
+
+static bool circle_pad_up = false;
+static bool circle_pad_down = false;
+static bool circle_pad_left = false;
+static bool circle_pad_right = false;
+static bool circle_pad_modifier = false;
+
+static void UpdateCirclePad(EmuWindow& emu_window) {
+ constexpr float SQRT_HALF = 0.707106781f;
+ int x = 0, y = 0;
+
+ if (circle_pad_right)
+ ++x;
+ if (circle_pad_left)
+ --x;
+ if (circle_pad_up)
+ ++y;
+ if (circle_pad_down)
+ --y;
+
+ float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0f;
+ emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0f : SQRT_HALF),
+ y * modifier * (x == 0 ? 1.0f : SQRT_HALF));
+}
+
+int NewDeviceId() {
+ return next_device_id++;
+}
+
+void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
+ key_map[key] = target;
+}
+
+void ClearKeyMapping(int device_id) {
+ auto iter = key_map.begin();
+ while (iter != key_map.end()) {
+ if (iter->first.device_id == device_id)
+ key_map.erase(iter++);
+ else
+ ++iter;
+ }
+}
+
+void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
+ auto target = key_map.find(key);
+ if (target == key_map.end())
+ return;
+
+ if (target->second.direct) {
+ emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
+ } else {
+ switch (target->second.target.indirect_target) {
+ case IndirectTarget::CirclePadUp:
+ circle_pad_up = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadDown:
+ circle_pad_down = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadLeft:
+ circle_pad_left = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadRight:
+ circle_pad_right = true;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadModifier:
+ circle_pad_modifier = true;
+ UpdateCirclePad(emu_window);
+ break;
+ }
+ }
+}
+
+void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) {
+ auto target = key_map.find(key);
+ if (target == key_map.end())
+ return;
+
+ if (target->second.direct) {
+ emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
+ } else {
+ switch (target->second.target.indirect_target) {
+ case IndirectTarget::CirclePadUp:
+ circle_pad_up = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadDown:
+ circle_pad_down = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadLeft:
+ circle_pad_left = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadRight:
+ circle_pad_right = false;
+ UpdateCirclePad(emu_window);
+ break;
+ case IndirectTarget::CirclePadModifier:
+ circle_pad_modifier = false;
+ UpdateCirclePad(emu_window);
+ break;
+ }
+ }
+}
+}
diff --git a/src/core/frontend/key_map.h b/src/core/frontend/key_map.h
new file mode 100644
index 000000000..040794578
--- /dev/null
+++ b/src/core/frontend/key_map.h
@@ -0,0 +1,93 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <tuple>
+#include "core/hle/service/hid/hid.h"
+
+class EmuWindow;
+
+namespace KeyMap {
+
+/**
+ * Represents key mapping targets that are not real 3DS buttons.
+ * They will be handled by KeyMap and translated to 3DS input.
+ */
+enum class IndirectTarget {
+ CirclePadUp,
+ CirclePadDown,
+ CirclePadLeft,
+ CirclePadRight,
+ CirclePadModifier,
+};
+
+/**
+ * Represents a key mapping target. It can be a PadState that represents real 3DS buttons,
+ * or an IndirectTarget.
+ */
+struct KeyTarget {
+ bool direct;
+ union {
+ u32 direct_target_hex;
+ IndirectTarget indirect_target;
+ } target;
+
+ KeyTarget() : direct(true) {
+ target.direct_target_hex = 0;
+ }
+
+ KeyTarget(Service::HID::PadState pad) : direct(true) {
+ target.direct_target_hex = pad.hex;
+ }
+
+ KeyTarget(IndirectTarget i) : direct(false) {
+ target.indirect_target = i;
+ }
+};
+
+/**
+ * Represents a key for a specific host device.
+ */
+struct HostDeviceKey {
+ int key_code;
+ int device_id; ///< Uniquely identifies a host device
+
+ bool operator<(const HostDeviceKey& other) const {
+ return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id);
+ }
+
+ bool operator==(const HostDeviceKey& other) const {
+ return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id);
+ }
+};
+
+extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets;
+
+/**
+ * Generates a new device id, which uniquely identifies a host device within KeyMap.
+ */
+int NewDeviceId();
+
+/**
+ * Maps a device-specific key to a target (a PadState or an IndirectTarget).
+ */
+void SetKeyMapping(HostDeviceKey key, KeyTarget target);
+
+/**
+ * Clears all key mappings belonging to one device.
+ */
+void ClearKeyMapping(int device_id);
+
+/**
+ * Maps a key press action and call the corresponding function in EmuWindow
+ */
+void PressKey(EmuWindow& emu_window, HostDeviceKey key);
+
+/**
+ * Maps a key release action and call the corresponding function in EmuWindow
+ */
+void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
+}
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index aea43e92b..d88e25073 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -5,6 +5,7 @@
// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
#include <algorithm>
+#include <atomic>
#include <climits>
#include <csignal>
#include <cstdarg>
@@ -15,8 +16,8 @@
#include <fcntl.h>
#ifdef _WIN32
-#include <WinSock2.h>
-#include <common/x64/abi.h>
+#include <winsock2.h>
+// winsock2.h needs to be included first to prevent winsock.h being included by other includes
#include <io.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
@@ -34,6 +35,7 @@
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/loader/loader.h"
#include "core/memory.h"
const int GDB_BUFFER_SIZE = 10000;
@@ -130,7 +132,10 @@ static u16 gdbstub_port = 24689;
static bool halt_loop = true;
static bool step_loop = false;
-std::atomic<bool> g_server_enabled(false);
+
+// If set to false, the server will never be started and no
+// gdbstub-related functions will be executed.
+static std::atomic<bool> server_enabled(false);
#ifdef _WIN32
WSADATA InitData;
@@ -181,11 +186,10 @@ static u8 NibbleToHex(u8 n) {
/**
* Converts input hex string characters into an array of equivalent of u8 bytes.
*
-* @param dest Pointer to buffer to store u8 bytes.
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
-static u32 HexToInt(u8* src, u32 len) {
+static u32 HexToInt(const u8* src, size_t len) {
u32 output = 0;
while (len-- > 0) {
output = (output << 4) | HexCharToValue(src[0]);
@@ -201,7 +205,7 @@ static u32 HexToInt(u8* src, u32 len) {
* @param src Pointer to array of u8 bytes.
* @param len Length of src array.
*/
-static void MemToGdbHex(u8* dest, u8* src, u32 len) {
+static void MemToGdbHex(u8* dest, const u8* src, size_t len) {
while (len-- > 0) {
u8 tmp = *src++;
*dest++ = NibbleToHex(tmp >> 4);
@@ -216,7 +220,7 @@ static void MemToGdbHex(u8* dest, u8* src, u32 len) {
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
-static void GdbHexToMem(u8* dest, u8* src, u32 len) {
+static void GdbHexToMem(u8* dest, const u8* src, size_t len) {
while (len-- > 0) {
*dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
src += 2;
@@ -240,7 +244,7 @@ static void IntToGdbHex(u8* dest, u32 v) {
*
* @param src Pointer to hex string.
*/
-static u32 GdbHexToInt(u8* src) {
+static u32 GdbHexToInt(const u8* src) {
u32 output = 0;
for (int i = 0; i < 8; i += 2) {
@@ -264,7 +268,7 @@ static u8 ReadByte() {
}
/// Calculate the checksum of the current command buffer.
-static u8 CalculateChecksum(u8* buffer, u32 length) {
+static u8 CalculateChecksum(const u8* buffer, size_t length) {
return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>()));
}
@@ -446,9 +450,9 @@ static void SendSignal(u32 signal) {
latest_signal = signal;
- std::string buffer = Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15,
- htonl(Core::g_app_core->GetPC()), 13,
- htonl(Core::g_app_core->GetReg(13)));
+ std::string buffer =
+ Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15,
+ htonl(Core::CPU().GetPC()), 13, htonl(Core::CPU().GetReg(13)));
LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str());
SendReply(buffer.c_str());
}
@@ -535,15 +539,15 @@ static void ReadRegister() {
}
if (id <= R15_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetReg(id));
+ IntToGdbHex(reply, Core::CPU().GetReg(id));
} else if (id == CPSR_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetCPSR());
+ IntToGdbHex(reply, Core::CPU().GetCPSR());
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetVFPReg(
+ IntToGdbHex(reply, Core::CPU().GetVFPReg(
id - CPSR_REGISTER -
1)); // VFP registers should start at 26, so one after CSPR_REGISTER
} else if (id == FPSCR_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR
+ IntToGdbHex(reply, Core::CPU().GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR
IntToGdbHex(reply + 8, 0);
} else {
return SendReply("E01");
@@ -560,29 +564,29 @@ static void ReadRegisters() {
u8* bufptr = buffer;
for (int reg = 0; reg <= R15_REGISTER; reg++) {
- IntToGdbHex(bufptr + reg * CHAR_BIT, Core::g_app_core->GetReg(reg));
+ IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetReg(reg));
}
bufptr += (16 * CHAR_BIT);
- IntToGdbHex(bufptr, Core::g_app_core->GetCPSR());
+ IntToGdbHex(bufptr, Core::CPU().GetCPSR());
bufptr += CHAR_BIT;
for (int reg = 0; reg <= 31; reg++) {
- IntToGdbHex(bufptr + reg * CHAR_BIT, Core::g_app_core->GetVFPReg(reg));
+ IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetVFPReg(reg));
}
bufptr += (32 * CHAR_BIT);
- IntToGdbHex(bufptr, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR));
+ IntToGdbHex(bufptr, Core::CPU().GetVFPSystemReg(VFP_FPSCR));
SendReply(reinterpret_cast<char*>(buffer));
}
/// Modify data of register specified by gdb client.
static void WriteRegister() {
- u8* buffer_ptr = command_buffer + 3;
+ const u8* buffer_ptr = command_buffer + 3;
u32 id = HexCharToValue(command_buffer[1]);
if (command_buffer[2] != '=') {
@@ -592,13 +596,13 @@ static void WriteRegister() {
}
if (id <= R15_REGISTER) {
- Core::g_app_core->SetReg(id, GdbHexToInt(buffer_ptr));
+ Core::CPU().SetReg(id, GdbHexToInt(buffer_ptr));
} else if (id == CPSR_REGISTER) {
- Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr));
+ Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr));
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
- Core::g_app_core->SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr));
+ Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr));
} else if (id == FPSCR_REGISTER) {
- Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr));
+ Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr));
} else {
return SendReply("E01");
}
@@ -608,27 +612,26 @@ static void WriteRegister() {
/// Modify all registers with data received from the client.
static void WriteRegisters() {
- u8* buffer_ptr = command_buffer + 1;
+ const u8* buffer_ptr = command_buffer + 1;
if (command_buffer[0] != 'G')
return SendReply("E01");
for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
if (reg <= R15_REGISTER) {
- Core::g_app_core->SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
} else if (reg == CPSR_REGISTER) {
- Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT));
} else if (reg == CPSR_REGISTER - 1) {
// Dummy FPA register, ignore
} else if (reg < CPSR_REGISTER) {
// Dummy FPA registers, ignore
i += 2;
} else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) {
- Core::g_app_core->SetVFPReg(reg - CPSR_REGISTER - 1,
- GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
i++; // Skip padding
} else if (reg == FPSCR_REGISTER) {
- Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
}
}
@@ -653,7 +656,7 @@ static void ReadMemory() {
SendReply("E01");
}
- u8* data = Memory::GetPointer(addr);
+ const u8* data = Memory::GetPointer(addr);
if (!data) {
return SendReply("E00");
}
@@ -902,10 +905,10 @@ void SetServerPort(u16 port) {
void ToggleServer(bool status) {
if (status) {
- g_server_enabled = status;
+ server_enabled = status;
// Start server
- if (!IsConnected() && Core::g_sys_core != nullptr) {
+ if (!IsConnected() && Core::System().GetInstance().IsPoweredOn()) {
Init();
}
} else {
@@ -914,12 +917,12 @@ void ToggleServer(bool status) {
Shutdown();
}
- g_server_enabled = status;
+ server_enabled = status;
}
}
static void Init(u16 port) {
- if (!g_server_enabled) {
+ if (!server_enabled) {
// Set the halt loop to false in case the user enabled the gdbstub mid-execution.
// This way the CPU can still execute normally.
halt_loop = false;
@@ -998,7 +1001,7 @@ void Init() {
}
void Shutdown() {
- if (!g_server_enabled) {
+ if (!server_enabled) {
return;
}
@@ -1015,8 +1018,12 @@ void Shutdown() {
LOG_INFO(Debug_GDBStub, "GDB stopped.");
}
+bool IsServerEnabled() {
+ return server_enabled;
+}
+
bool IsConnected() {
- return g_server_enabled && gdbserver_socket != -1;
+ return IsServerEnabled() && gdbserver_socket != -1;
}
bool GetCpuHaltFlag() {
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index a7483bb10..38177e32c 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -5,7 +5,7 @@
// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
#pragma once
-#include <atomic>
+
#include "common/common_types.h"
namespace GDBStub {
@@ -24,10 +24,6 @@ struct BreakpointAddress {
BreakpointType type;
};
-/// If set to false, the server will never be started and no gdbstub-related functions will be
-/// executed.
-extern std::atomic<bool> g_server_enabled;
-
/**
* Set the port the gdbstub should use to listen for connections.
*
@@ -36,7 +32,7 @@ extern std::atomic<bool> g_server_enabled;
void SetServerPort(u16 port);
/**
- * Set the g_server_enabled flag and start or stop the server if possible.
+ * Starts or stops the server if possible.
*
* @param status Set the server to enabled or disabled.
*/
@@ -48,6 +44,9 @@ void Init();
/// Stop gdbstub server.
void Shutdown();
+/// Checks if the gdbstub server is enabled.
+bool IsServerEnabled();
+
/// Returns true if there is an active socket connection.
bool IsConnected();
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
index 4311d9897..645b2d5fe 100644
--- a/src/core/hle/applets/applet.cpp
+++ b/src/core/hle/applets/applet.cpp
@@ -101,6 +101,10 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter)
return result;
}
+bool Applet::IsRunning() const {
+ return is_running;
+}
+
bool IsLibraryAppletRunning() {
// Check the applets map for instances of any applet
for (auto itr = applets.begin(); itr != applets.end(); ++itr)
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
index bfdcad126..ebeed9813 100644
--- a/src/core/hle/applets/applet.h
+++ b/src/core/hle/applets/applet.h
@@ -13,8 +13,7 @@ namespace Applets {
class Applet {
public:
- virtual ~Applet() {}
- Applet(Service::APT::AppletId id) : id(id) {}
+ virtual ~Applet() = default;
/**
* Creates an instance of the Applet subclass identified by the parameter.
@@ -48,7 +47,7 @@ public:
/**
* Whether the applet is currently executing instead of the host application or not.
*/
- virtual bool IsRunning() const = 0;
+ bool IsRunning() const;
/**
* Handles an update tick for the Applet, lets it update the screen, send commands, etc.
@@ -56,6 +55,8 @@ public:
virtual void Update() = 0;
protected:
+ explicit Applet(Service::APT::AppletId id) : id(id) {}
+
/**
* Handles the Applet start event, triggered from the application.
* @param parameter Parameter data to handle.
@@ -65,6 +66,9 @@ protected:
Service::APT::AppletId id; ///< Id of this Applet
std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
+
+ /// Whether this applet is currently running instead of the host application or not.
+ bool is_running = false;
};
/// Returns whether a library applet is currently running
diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp
index e1379ac4d..75d7fd9fc 100644
--- a/src/core/hle/applets/erreula.cpp
+++ b/src/core/hle/applets/erreula.cpp
@@ -47,7 +47,7 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
}
ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
- started = true;
+ is_running = true;
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
// application.
@@ -62,7 +62,7 @@ ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parame
message.sender_id = static_cast<u32>(id);
Service::APT::SendParameter(message);
- started = false;
+ is_running = false;
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h
index a7ec7ec01..681bbea0c 100644
--- a/src/core/hle/applets/erreula.h
+++ b/src/core/hle/applets/erreula.h
@@ -17,18 +17,12 @@ public:
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
void Update() override;
- bool IsRunning() const override {
- return started;
- }
+private:
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
/// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
-
-private:
- /// Whether this applet is currently running instead of the host application or not.
- bool started = false;
};
} // namespace Applets
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index 3455b9201..07c7f5b99 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -55,7 +55,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
}
ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
- started = true;
+ is_running = true;
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
// application.
@@ -78,7 +78,7 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa
message.sender_id = static_cast<u32>(id);
Service::APT::SendParameter(message);
- started = false;
+ is_running = false;
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h
index e3ab9f0cd..ec00e29d2 100644
--- a/src/core/hle/applets/mii_selector.h
+++ b/src/core/hle/applets/mii_selector.h
@@ -65,23 +65,18 @@ ASSERT_REG_POSITION(unk_6C, 0x6C);
class MiiSelector final : public Applet {
public:
- MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) {}
+ MiiSelector(Service::APT::AppletId id) : Applet(id) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
void Update() override;
- bool IsRunning() const override {
- return started;
- }
+private:
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
/// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
- /// Whether this applet is currently running instead of the host application or not.
- bool started;
-
MiiConfig config;
};
}
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 1e21337f5..059297fbc 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -70,7 +70,7 @@ ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter cons
DrawScreenKeyboard();
- started = true;
+ is_running = true;
return RESULT_SUCCESS;
}
@@ -94,13 +94,13 @@ void SoftwareKeyboard::Update() {
}
void SoftwareKeyboard::DrawScreenKeyboard() {
- auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
+ auto bottom_screen = Service::GSP::GetFrameBufferInfo(0, 1);
auto info = bottom_screen->framebuffer_info[bottom_screen->index];
// TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
Memory::ZeroBlock(info.address_left, info.stride * 320);
- GSP_GPU::SetBufferSwap(1, info);
+ Service::GSP::SetBufferSwap(1, info);
}
void SoftwareKeyboard::Finalize() {
@@ -113,7 +113,7 @@ void SoftwareKeyboard::Finalize() {
message.sender_id = static_cast<u32>(id);
Service::APT::SendParameter(message);
- started = false;
+ is_running = false;
}
}
} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
index ea0b1fba9..cc92a8f19 100644
--- a/src/core/hle/applets/swkbd.h
+++ b/src/core/hle/applets/swkbd.h
@@ -52,14 +52,11 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config
class SoftwareKeyboard final : public Applet {
public:
- SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {}
+ SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
void Update() override;
- bool IsRunning() const override {
- return started;
- }
/**
* Draws a keyboard to the current bottom screen framebuffer.
@@ -72,6 +69,7 @@ public:
*/
void Finalize();
+private:
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
/// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo
@@ -82,9 +80,6 @@ public:
/// Configuration of this instance of the SoftwareKeyboard, as received from the application
SoftwareKeyboardConfig config;
-
- /// Whether this applet is currently running instead of the host application or not.
- bool started;
};
}
} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 8ce0f6d2b..7875971ce 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -7,14 +7,14 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/hle.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
#include "core/hle/svc.h"
#include "core/memory.h"
namespace HLE {
-#define PARAM(n) Core::g_app_core->GetReg(n)
+#define PARAM(n) Core::CPU().GetReg(n)
/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
static const ResultCode RESULT_INVALID(0xDEADC0DE);
@@ -24,7 +24,7 @@ static const ResultCode RESULT_INVALID(0xDEADC0DE);
* @param res Result to return
*/
static inline void FuncReturn(u32 res) {
- Core::g_app_core->SetReg(0, res);
+ Core::CPU().SetReg(0, res);
}
/**
@@ -33,8 +33,8 @@ static inline void FuncReturn(u32 res) {
* @todo Verify that this function is correct
*/
static inline void FuncReturn64(u64 res) {
- Core::g_app_core->SetReg(0, (u32)(res & 0xFFFFFFFF));
- Core::g_app_core->SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF));
+ Core::CPU().SetReg(0, (u32)(res & 0xFFFFFFFF));
+ Core::CPU().SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,7 +49,7 @@ template <ResultCode func(u32*, u32, u32, u32, u32, u32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -57,19 +57,19 @@ template <ResultCode func(u32*, s32, u32, u32, u32, s32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
template <ResultCode func(s32*, u32*, s32, bool, s64)>
void Wrap() {
s32 param_1 = 0;
- s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
+ s32 retval = func(&param_1, (Kernel::Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)))
.raw;
if (retval != RESULT_INVALID.raw) {
- Core::g_app_core->SetReg(1, (u32)param_1);
+ Core::CPU().SetReg(1, (u32)param_1);
FuncReturn(retval);
}
}
@@ -84,7 +84,7 @@ template <ResultCode func(u32*)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -102,24 +102,24 @@ void Wrap() {
MemoryInfo memory_info = {};
PageInfo page_info = {};
u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
- Core::g_app_core->SetReg(1, memory_info.base_address);
- Core::g_app_core->SetReg(2, memory_info.size);
- Core::g_app_core->SetReg(3, memory_info.permission);
- Core::g_app_core->SetReg(4, memory_info.state);
- Core::g_app_core->SetReg(5, page_info.flags);
+ Core::CPU().SetReg(1, memory_info.base_address);
+ Core::CPU().SetReg(2, memory_info.size);
+ Core::CPU().SetReg(3, memory_info.permission);
+ Core::CPU().SetReg(4, memory_info.state);
+ Core::CPU().SetReg(5, page_info.flags);
FuncReturn(retval);
}
-template <ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)>
+template <ResultCode func(MemoryInfo*, PageInfo*, Kernel::Handle, u32)>
void Wrap() {
MemoryInfo memory_info = {};
PageInfo page_info = {};
u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
- Core::g_app_core->SetReg(1, memory_info.base_address);
- Core::g_app_core->SetReg(2, memory_info.size);
- Core::g_app_core->SetReg(3, memory_info.permission);
- Core::g_app_core->SetReg(4, memory_info.state);
- Core::g_app_core->SetReg(5, page_info.flags);
+ Core::CPU().SetReg(1, memory_info.base_address);
+ Core::CPU().SetReg(2, memory_info.size);
+ Core::CPU().SetReg(3, memory_info.permission);
+ Core::CPU().SetReg(4, memory_info.state);
+ Core::CPU().SetReg(5, page_info.flags);
FuncReturn(retval);
}
@@ -127,7 +127,7 @@ template <ResultCode func(s32*, u32)>
void Wrap() {
s32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -140,7 +140,7 @@ template <ResultCode func(u32*, u32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -160,7 +160,7 @@ template <ResultCode func(u32*, const char*)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, (char*)Memory::GetPointer(PARAM(1))).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -168,7 +168,7 @@ template <ResultCode func(u32*, s32, s32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -176,7 +176,7 @@ template <ResultCode func(s32*, u32, s32)>
void Wrap() {
s32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -184,8 +184,8 @@ template <ResultCode func(s64*, u32, s32)>
void Wrap() {
s64 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, (u32)param_1);
- Core::g_app_core->SetReg(2, (u32)(param_1 >> 32));
+ Core::CPU().SetReg(1, (u32)param_1);
+ Core::CPU().SetReg(2, (u32)(param_1 >> 32));
FuncReturn(retval);
}
@@ -194,7 +194,7 @@ void Wrap() {
u32 param_1 = 0;
// The last parameter is passed in R0 instead of R4
u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -205,30 +205,30 @@ void Wrap() {
FuncReturn(func(PARAM(0), param1, param2).raw);
}
-template <ResultCode func(s64*, Handle, u32)>
+template <ResultCode func(s64*, Kernel::Handle, u32)>
void Wrap() {
s64 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, (u32)param_1);
- Core::g_app_core->SetReg(2, (u32)(param_1 >> 32));
+ Core::CPU().SetReg(1, (u32)param_1);
+ Core::CPU().SetReg(2, (u32)(param_1 >> 32));
FuncReturn(retval);
}
-template <ResultCode func(Handle, u32)>
+template <ResultCode func(Kernel::Handle, u32)>
void Wrap() {
FuncReturn(func(PARAM(0), PARAM(1)).raw);
}
-template <ResultCode func(Handle*, Handle*, const char*, u32)>
+template <ResultCode func(Kernel::Handle*, Kernel::Handle*, const char*, u32)>
void Wrap() {
- Handle param_1 = 0;
- Handle param_2 = 0;
+ Kernel::Handle param_1 = 0;
+ Kernel::Handle param_2 = 0;
u32 retval = func(&param_1, &param_2,
reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3))
.raw;
// The first out parameter is moved into R2 and the second is moved into R1.
- Core::g_app_core->SetReg(1, param_2);
- Core::g_app_core->SetReg(2, param_1);
+ Core::CPU().SetReg(1, param_2);
+ Core::CPU().SetReg(2, param_1);
FuncReturn(retval);
}
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
deleted file mode 100644
index 41b772163..000000000
--- a/src/core/hle/hle.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "core/arm/arm_interface.h"
-#include "core/core.h"
-#include "core/hle/hle.h"
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-namespace {
-
-bool reschedule; ///< If true, immediately reschedules the CPU to a new thread
-}
-
-namespace HLE {
-
-void Reschedule(const char* reason) {
- DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256,
- "Reschedule: Invalid or too long reason.");
-
- // TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE
- // routines. This simulates that time by artificially advancing the number of CPU "ticks".
- // The value was chosen empirically, it seems to work well enough for everything tested, but
- // is likely not ideal. We should find a more accurate way to simulate timing with HLE.
- Core::g_app_core->AddTicks(4000);
-
- Core::g_app_core->PrepareReschedule();
-
- reschedule = true;
-}
-
-bool IsReschedulePending() {
- return reschedule;
-}
-
-void DoneRescheduling() {
- reschedule = false;
-}
-
-void Init() {
- Service::Init();
-
- reschedule = false;
-
- LOG_DEBUG(Kernel, "initialized OK");
-}
-
-void Shutdown() {
- Service::Shutdown();
-
- LOG_DEBUG(Kernel, "shutdown OK");
-}
-
-} // namespace
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
deleted file mode 100644
index 23859e129..000000000
--- a/src/core/hle/hle.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-typedef u32 Handle;
-typedef s32 Result;
-
-const Handle INVALID_HANDLE = 0;
-
-namespace HLE {
-
-void Reschedule(const char* reason);
-bool IsReschedulePending();
-void DoneRescheduling();
-
-void Init();
-void Shutdown();
-
-} // namespace
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/ipc.h
index ec025f732..4e094faa7 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/ipc.h
@@ -1,17 +1,31 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
-#include <string>
-#include "common/assert.h"
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
-#include "core/hle/result.h"
#include "core/memory.h"
+namespace Kernel {
+
+static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
+
+/**
+ * Returns a pointer to the command buffer in the current thread's TLS
+ * TODO(Subv): This is not entirely correct, the command buffer should be copied from
+ * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
+ * the service handler process' memory.
+ * @param offset Optional offset into command buffer
+ * @return Pointer to command buffer
+ */
+inline u32* GetCommandBuffer(const int offset = 0) {
+ return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
+ offset);
+}
+}
+
namespace IPC {
enum DescriptorType : u32 {
@@ -144,75 +158,3 @@ inline DescriptorType GetDescriptorType(u32 descriptor) {
}
} // namespace IPC
-
-namespace Kernel {
-
-static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
-
-/**
- * Returns a pointer to the command buffer in the current thread's TLS
- * TODO(Subv): This is not entirely correct, the command buffer should be copied from
- * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
- * the service handler process' memory.
- * @param offset Optional offset into command buffer
- * @return Pointer to command buffer
- */
-inline u32* GetCommandBuffer(const int offset = 0) {
- return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
- offset);
-}
-
-/**
- * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
- * primitive for communication between different processes, and are used to implement service calls
- * to the various system services.
- *
- * To make a service call, the client must write the command header and parameters to the buffer
- * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
- * SVC call with its Session handle. The kernel will read the command header, using it to marshall
- * the parameters to the process at the server endpoint of the session. After the server replies to
- * the request, the response is marshalled back to the caller's TLS buffer and control is
- * transferred back to it.
- *
- * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC
- * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called
- * with the session handle, this class's SyncRequest method is called, which should read the TLS
- * buffer and emulate the call accordingly. Since the code can directly read the emulated memory,
- * no parameter marshalling is done.
- *
- * In the long term, this should be turned into the full-fledged IPC mechanism implemented by
- * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
- * opposed to HLE simulations.
- */
-class Session : public WaitObject {
-public:
- Session();
- ~Session() override;
-
- std::string GetTypeName() const override {
- return "Session";
- }
-
- static const HandleType HANDLE_TYPE = HandleType::Session;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- /**
- * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
- * aren't supported yet.
- */
- virtual ResultVal<bool> SyncRequest() = 0;
-
- // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object
- // passed into WaitSynchronization. Figure out the meaning of them.
-
- bool ShouldWait() override {
- return true;
- }
-
- void Acquire() override {
- ASSERT_MSG(!ShouldWait(), "object unavailable!");
- }
-};
-}
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 37eec4c84..01fab123e 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -4,7 +4,6 @@
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/thread.h"
#include "core/memory.h"
@@ -79,8 +78,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
ErrorSummary::WrongArgument, ErrorLevel::Usage);
}
- HLE::Reschedule(__func__);
-
// The calls that use a timeout seem to always return a Timeout error even if they did not put
// the thread to sleep
if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index aedc6f989..22645f4ec 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -4,12 +4,44 @@
#include "common/assert.h"
#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/server_session.h"
namespace Kernel {
ClientPort::ClientPort() {}
ClientPort::~ClientPort() {}
+ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
+ // Note: Threads do not wait for the server endpoint to call
+ // AcceptSession before returning from this call.
+
+ if (active_sessions >= max_sessions) {
+ // TODO(Subv): Return an error code in this situation after session disconnection is
+ // implemented.
+ /*return ResultCode(ErrorDescription::MaxConnectionsReached,
+ ErrorModule::OS, ErrorSummary::WouldBlock,
+ ErrorLevel::Temporary);*/
+ }
+ active_sessions++;
+
+ // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
+ auto sessions =
+ ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler);
+ auto client_session = std::get<SharedPtr<ClientSession>>(sessions);
+ auto server_session = std::get<SharedPtr<ServerSession>>(sessions);
+
+ if (server_port->hle_handler)
+ server_port->hle_handler->ClientConnected(server_session);
+
+ server_port->pending_sessions.push_back(std::move(server_session));
+
+ // Wake the threads waiting on the ServerPort
+ server_port->WakeupAllWaitingThreads();
+
+ return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
+}
+
} // namespace
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index d28147718..511490c7c 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -11,8 +11,9 @@
namespace Kernel {
class ServerPort;
+class ClientSession;
-class ClientPort : public Object {
+class ClientPort final : public Object {
public:
friend class ServerPort;
std::string GetTypeName() const override {
@@ -27,12 +28,20 @@ public:
return HANDLE_TYPE;
}
+ /**
+ * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
+ * list of pending sessions, and signals the ServerPort, causing any threads
+ * waiting on it to awake.
+ * @returns ClientSession The client endpoint of the created Session pair, or error code.
+ */
+ ResultVal<SharedPtr<ClientSession>> Connect();
+
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
u32 active_sessions; ///< Number of currently open sessions to this port
std::string name; ///< Name of client port (optional)
-protected:
+private:
ClientPort();
~ClientPort() override;
};
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
new file mode 100644
index 000000000..0331386ec
--- /dev/null
+++ b/src/core/hle/kernel/client_session.cpp
@@ -0,0 +1,40 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
+
+namespace Kernel {
+
+ClientSession::ClientSession() = default;
+ClientSession::~ClientSession() {
+ // This destructor will be called automatically when the last ClientSession handle is closed by
+ // the emulated application.
+
+ if (server_session->hle_handler)
+ server_session->hle_handler->ClientDisconnected(server_session);
+
+ // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client),
+ // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to
+ // 0xC920181A.
+}
+
+ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session,
+ std::string name) {
+ SharedPtr<ClientSession> client_session(new ClientSession);
+
+ client_session->name = std::move(name);
+ client_session->server_session = server_session;
+ client_session->session_status = SessionStatus::Open;
+ return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
+}
+
+ResultCode ClientSession::SendSyncRequest() {
+ // Signal the server session that new data is available
+ return server_session->HandleSyncRequest();
+}
+
+} // namespace
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
new file mode 100644
index 000000000..ed468dec6
--- /dev/null
+++ b/src/core/hle/kernel/client_session.h
@@ -0,0 +1,65 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+class ServerSession;
+
+enum class SessionStatus {
+ Open = 1,
+ ClosedByClient = 2,
+ ClosedBYServer = 3,
+};
+
+class ClientSession final : public Object {
+public:
+ friend class ServerSession;
+
+ std::string GetTypeName() const override {
+ return "ClientSession";
+ }
+
+ std::string GetName() const override {
+ return name;
+ }
+
+ static const HandleType HANDLE_TYPE = HandleType::ClientSession;
+ HandleType GetHandleType() const override {
+ return HANDLE_TYPE;
+ }
+
+ /**
+ * Sends an SyncRequest from the current emulated thread.
+ * @return ResultCode of the operation.
+ */
+ ResultCode SendSyncRequest();
+
+ std::string name; ///< Name of client port (optional)
+ ServerSession* server_session; ///< The server session associated with this client session.
+ SessionStatus session_status; ///< The session's current status.
+
+private:
+ ClientSession();
+ ~ClientSession() override;
+
+ /**
+ * Creates a client session.
+ * @param server_session The server session associated with this client session
+ * @param name Optional name of client session
+ * @return The created client session
+ */
+ static ResultVal<SharedPtr<ClientSession>> Create(ServerSession* server_session,
+ std::string name = "Unknown");
+};
+
+} // namespace
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0c8752670..1db8e102f 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <boost/range/algorithm_ext/erase.hpp>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/config_mem.h"
@@ -31,13 +32,61 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
waiting_threads.erase(itr);
}
-void WaitObject::WakeupAllWaitingThreads() {
- for (auto thread : waiting_threads)
- thread->ResumeFromWait();
+SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
+ // Remove the threads that are ready or already running from our waitlist
+ boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) {
+ return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY ||
+ thread->status == THREADSTATUS_DEAD;
+ });
+
+ // TODO(Subv): This call should be performed inside the loop below to check if an object can be
+ // acquired by a particular thread. This is useful for things like recursive locking of Mutexes.
+ if (ShouldWait())
+ return nullptr;
+
+ Thread* candidate = nullptr;
+ s32 candidate_priority = THREADPRIO_LOWEST + 1;
+
+ for (const auto& thread : waiting_threads) {
+ if (thread->current_priority >= candidate_priority)
+ continue;
- waiting_threads.clear();
+ bool ready_to_run =
+ std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
+ [](const SharedPtr<WaitObject>& object) { return object->ShouldWait(); });
+ if (ready_to_run) {
+ candidate = thread.get();
+ candidate_priority = thread->current_priority;
+ }
+ }
+
+ return candidate;
+}
- HLE::Reschedule(__func__);
+void WaitObject::WakeupAllWaitingThreads() {
+ while (auto thread = GetHighestPriorityReadyThread()) {
+ if (!thread->IsSleepingOnWaitAll()) {
+ Acquire();
+ // Set the output index of the WaitSynchronizationN call to the index of this object.
+ if (thread->wait_set_output) {
+ thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
+ thread->wait_set_output = false;
+ }
+ } else {
+ for (auto& object : thread->wait_objects) {
+ object->Acquire();
+ object->RemoveWaitingThread(thread.get());
+ }
+ // Note: This case doesn't update the output index of WaitSynchronizationN.
+ // Clear the thread's waitlist
+ thread->wait_objects.clear();
+ }
+
+ thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
+ thread->ResumeFromWait();
+ // Note: Removing the thread from the object's waitlist will be
+ // done by GetHighestPriorityReadyThread.
+ }
}
const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 231cf7b75..9503e7d04 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,11 +11,12 @@
#include <vector>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include "common/common_types.h"
-#include "core/hle/hle.h"
#include "core/hle/result.h"
namespace Kernel {
+using Handle = u32;
+
class Thread;
// TODO: Verify code
@@ -31,22 +32,21 @@ enum KernelHandle : Handle {
};
enum class HandleType : u32 {
- Unknown = 0,
-
- Session = 2,
- Event = 3,
- Mutex = 4,
- SharedMemory = 5,
- Redirection = 6,
- Thread = 7,
- Process = 8,
- AddressArbiter = 9,
- Semaphore = 10,
- Timer = 11,
- ResourceLimit = 12,
- CodeSet = 13,
- ClientPort = 14,
- ServerPort = 15,
+ Unknown,
+ Event,
+ Mutex,
+ SharedMemory,
+ Thread,
+ Process,
+ AddressArbiter,
+ Semaphore,
+ Timer,
+ ResourceLimit,
+ CodeSet,
+ ClientPort,
+ ServerPort,
+ ClientSession,
+ ServerSession,
};
enum {
@@ -82,23 +82,23 @@ public:
*/
bool IsWaitable() const {
switch (GetHandleType()) {
- case HandleType::Session:
- case HandleType::ServerPort:
case HandleType::Event:
case HandleType::Mutex:
case HandleType::Thread:
case HandleType::Semaphore:
case HandleType::Timer:
+ case HandleType::ServerPort:
+ case HandleType::ServerSession:
return true;
case HandleType::Unknown:
case HandleType::SharedMemory:
- case HandleType::Redirection:
case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
case HandleType::CodeSet:
case HandleType::ClientPort:
+ case HandleType::ClientSession:
return false;
}
}
@@ -152,9 +152,15 @@ public:
*/
void RemoveWaitingThread(Thread* thread);
- /// Wake up all threads waiting on this object
+ /**
+ * Wake up all threads waiting on this object that can be awoken, in priority order,
+ * and set the synchronization result and output of the thread.
+ */
void WakeupAllWaitingThreads();
+ /// Obtains the highest priority thread that is ready to run from this object's waiting list.
+ SharedPtr<Thread> GetHighestPriorityReadyThread();
+
/// Get a const reference to the waiting threads list for debug use
const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 8e3ec8a14..6c19aa7c0 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -24,12 +24,14 @@ void ServerPort::Acquire() {
}
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
- u32 max_sessions, std::string name) {
+ u32 max_sessions, std::string name,
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
SharedPtr<ServerPort> server_port(new ServerPort);
SharedPtr<ClientPort> client_port(new ClientPort);
server_port->name = name + "_Server";
+ server_port->hle_handler = std::move(hle_handler);
client_port->name = name + "_Client";
client_port->server_port = server_port;
client_port->max_sessions = max_sessions;
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index fa9448ca0..b0f8df62c 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -4,11 +4,16 @@
#pragma once
+#include <memory>
#include <string>
#include <tuple>
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
+namespace Service {
+class SessionRequestHandler;
+}
+
namespace Kernel {
class ClientPort;
@@ -19,10 +24,13 @@ public:
* Creates a pair of ServerPort and an associated ClientPort.
* @param max_sessions Maximum number of sessions to the port
* @param name Optional name of the ports
+ * @param hle_handler Optional HLE handler template for the port,
+ * ServerSessions crated from this port will inherit a reference to this handler.
* @return The created port tuple
*/
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
- u32 max_sessions, std::string name = "UnknownPort");
+ u32 max_sessions, std::string name = "UnknownPort",
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
std::string GetTypeName() const override {
return "ServerPort";
@@ -41,6 +49,10 @@ public:
std::vector<SharedPtr<WaitObject>>
pending_sessions; ///< ServerSessions waiting to be accepted by the port
+ /// This session's HLE request handler template (optional)
+ /// ServerSessions created from this port inherit a reference to this handler.
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler;
+
bool ShouldWait() override;
void Acquire() override;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
new file mode 100644
index 000000000..146458c1c
--- /dev/null
+++ b/src/core/hle/kernel/server_session.cpp
@@ -0,0 +1,79 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <tuple>
+
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+ServerSession::ServerSession() = default;
+ServerSession::~ServerSession() {
+ // This destructor will be called automatically when the last ServerSession handle is closed by
+ // the emulated application.
+ // TODO(Subv): Reduce the ClientPort's connection count,
+ // if the session is still open, set the connection status to 3 (Closed by server),
+}
+
+ResultVal<SharedPtr<ServerSession>> ServerSession::Create(
+ std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
+ SharedPtr<ServerSession> server_session(new ServerSession);
+
+ server_session->name = std::move(name);
+ server_session->signaled = false;
+ server_session->hle_handler = std::move(hle_handler);
+
+ return MakeResult<SharedPtr<ServerSession>>(std::move(server_session));
+}
+
+bool ServerSession::ShouldWait() {
+ return !signaled;
+}
+
+void ServerSession::Acquire() {
+ ASSERT_MSG(!ShouldWait(), "object unavailable!");
+ signaled = false;
+}
+
+ResultCode ServerSession::HandleSyncRequest() {
+ // The ServerSession received a sync request, this means that there's new data available
+ // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
+ // similar.
+
+ // If this ServerSession has an associated HLE handler, forward the request to it.
+ if (hle_handler != nullptr) {
+ // Attempt to translate the incoming request's command buffer.
+ ResultCode result = TranslateHLERequest(this);
+ if (result.IsError())
+ return result;
+ hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this));
+ // TODO(Subv): Translate the response command buffer.
+ }
+
+ // If this ServerSession does not have an HLE implementation, just wake up the threads waiting
+ // on it.
+ signaled = true;
+ WakeupAllWaitingThreads();
+ return RESULT_SUCCESS;
+}
+
+ServerSession::SessionPair ServerSession::CreateSessionPair(
+ const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
+ auto server_session =
+ ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom();
+ // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want
+ // to prevent the ServerSession's destructor from being called when the emulated
+ // application closes the last ServerSession handle.
+ auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom();
+
+ return std::make_tuple(std::move(server_session), std::move(client_session));
+}
+
+ResultCode TranslateHLERequest(ServerSession* server_session) {
+ // TODO(Subv): Implement this function once multiple concurrent processes are supported.
+ return RESULT_SUCCESS;
+}
+}
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
new file mode 100644
index 000000000..458284a5d
--- /dev/null
+++ b/src/core/hle/kernel/server_session.h
@@ -0,0 +1,94 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/result.h"
+#include "core/hle/service/service.h"
+#include "core/memory.h"
+
+namespace Kernel {
+
+class ClientSession;
+
+/**
+ * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
+ * primitive for communication between different processes, and are used to implement service calls
+ * to the various system services.
+ *
+ * To make a service call, the client must write the command header and parameters to the buffer
+ * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
+ * SVC call with its ClientSession handle. The kernel will read the command header, using it to
+ * marshall the parameters to the process at the server endpoint of the session.
+ * After the server replies to the request, the response is marshalled back to the caller's
+ * TLS buffer and control is transferred back to it.
+ */
+class ServerSession final : public WaitObject {
+public:
+ std::string GetTypeName() const override {
+ return "ServerSession";
+ }
+
+ static const HandleType HANDLE_TYPE = HandleType::ServerSession;
+ HandleType GetHandleType() const override {
+ return HANDLE_TYPE;
+ }
+
+ using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
+
+ /**
+ * Creates a pair of ServerSession and an associated ClientSession.
+ * @param name Optional name of the ports
+ * @return The created session tuple
+ */
+ static SessionPair CreateSessionPair(
+ const std::string& name = "Unknown",
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
+
+ /**
+ * Handle a sync request from the emulated application.
+ * @returns ResultCode from the operation.
+ */
+ ResultCode HandleSyncRequest();
+
+ bool ShouldWait() override;
+
+ void Acquire() override;
+
+ std::string name; ///< The name of this session (optional)
+ bool signaled; ///< Whether there's new data available to this ServerSession
+ std::shared_ptr<Service::SessionRequestHandler>
+ hle_handler; ///< This session's HLE request handler (optional)
+
+private:
+ ServerSession();
+ ~ServerSession() override;
+
+ /**
+ * Creates a server session. The server session can have an optional HLE handler,
+ * which will be invoked to handle the IPC requests that this session receives.
+ * @param name Optional name of the server session.
+ * @param hle_handler Optional HLE handler for this server session.
+ * @return The created server session
+ */
+ static ResultVal<SharedPtr<ServerSession>> Create(
+ std::string name = "Unknown",
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
+};
+
+/**
+ * Performs command buffer translation for an HLE IPC request.
+ * The command buffer from the ServerSession thread's TLS is copied into a
+ * buffer and all descriptors in the buffer are processed.
+ * TODO(Subv): Implement this function, currently we do not support multiple processes running at
+ * once, but once that is implemented we'll need to properly translate all descriptors
+ * in the command buffer.
+ */
+ResultCode TranslateHLERequest(ServerSession* server_session);
+}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 84d6d24c6..5fb95dada 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -14,7 +14,6 @@
#include "core/arm/skyeye_common/armstate.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
@@ -46,7 +45,7 @@ static std::vector<SharedPtr<Thread>> thread_list;
// Lists only ready thread ids.
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
-static Thread* current_thread;
+static SharedPtr<Thread> current_thread;
// The first available thread id at startup
static u32 next_thread_id;
@@ -63,7 +62,7 @@ Thread::Thread() {}
Thread::~Thread() {}
Thread* GetCurrentThread() {
- return current_thread;
+ return current_thread.get();
}
/**
@@ -120,8 +119,6 @@ void Thread::Stop() {
u32 tls_slot =
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
-
- HLE::Reschedule(__func__);
}
Thread* ArbitrateHighestPriorityThread(u32 address) {
@@ -181,50 +178,6 @@ static void PriorityBoostStarvedThreads() {
}
/**
- * Gets the registers for timeout parameter of the next WaitSynchronization call.
- * @param thread a pointer to the thread that is ready to call WaitSynchronization
- * @returns a tuple of two register pointers to low and high part of the timeout parameter
- */
-static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) {
- bool thumb_mode = (thread->context.cpsr & TBIT) != 0;
- u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE);
- u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF;
-
- if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) {
- // svc #0x24 (WaitSynchronization1)
- return std::make_tuple(&thread->context.cpu_registers[2],
- &thread->context.cpu_registers[3]);
- } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) {
- // svc #0x25 (WaitSynchronizationN)
- return std::make_tuple(&thread->context.cpu_registers[0],
- &thread->context.cpu_registers[4]);
- }
-
- UNREACHABLE();
-}
-
-/**
- * Updates the WaitSynchronization timeout parameter according to the difference
- * between ticks of the last WaitSynchronization call and the incoming one.
- * @param timeout_low a pointer to the register for the low part of the timeout parameter
- * @param timeout_high a pointer to the register for the high part of the timeout parameter
- * @param last_tick tick of the last WaitSynchronization call
- */
-static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) {
- s64 timeout = ((s64)*timeout_high << 32) | *timeout_low;
-
- if (timeout != -1) {
- timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds
-
- if (timeout < 0)
- timeout = 0;
-
- *timeout_low = timeout & 0xFFFFFFFF;
- *timeout_high = timeout >> 32;
- }
-}
-
-/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
@@ -234,7 +187,7 @@ static void SwitchContext(Thread* new_thread) {
// Save context for previous thread
if (previous_thread) {
previous_thread->last_running_ticks = CoreTiming::GetTicks();
- Core::g_app_core->SaveContext(previous_thread->context);
+ Core::CPU().SaveContext(previous_thread->context);
if (previous_thread->status == THREADSTATUS_RUNNING) {
// This is only the case when a reschedule is triggered without the current thread
@@ -254,40 +207,14 @@ static void SwitchContext(Thread* new_thread) {
current_thread = new_thread;
- // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun
- // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire
- // the requested wait object(s) before continuing.
- if (new_thread->waitsynch_waited) {
- // CPSR flag indicates CPU mode
- bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0;
-
- // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM
- new_thread->context.pc -= thumb_mode ? 2 : 4;
-
- // Get the register for timeout parameter
- u32 *timeout_low, *timeout_high;
- std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread);
-
- // Update the timeout parameter
- UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks);
- }
-
- // Clean up the thread's wait_objects, they'll be restored if needed during
- // the svcWaitSynchronization call
- for (size_t i = 0; i < new_thread->wait_objects.size(); ++i) {
- SharedPtr<WaitObject> object = new_thread->wait_objects[i];
- object->RemoveWaitingThread(new_thread);
- }
- new_thread->wait_objects.clear();
-
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
// Restores thread to its nominal priority if it has been temporarily changed
new_thread->current_priority = new_thread->nominal_priority;
- Core::g_app_core->LoadContext(new_thread->context);
- Core::g_app_core->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
+ Core::CPU().LoadContext(new_thread->context);
+ Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
} else {
current_thread = nullptr;
}
@@ -319,17 +246,13 @@ static Thread* PopNextReadyThread() {
void WaitCurrentThread_Sleep() {
Thread* thread = GetCurrentThread();
thread->status = THREADSTATUS_WAIT_SLEEP;
-
- HLE::Reschedule(__func__);
}
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
- bool wait_set_output, bool wait_all) {
+ bool wait_set_output) {
Thread* thread = GetCurrentThread();
thread->wait_set_output = wait_set_output;
- thread->wait_all = wait_all;
thread->wait_objects = std::move(wait_objects);
- thread->waitsynch_waited = true;
thread->status = THREADSTATUS_WAIT_SYNCH;
}
@@ -339,6 +262,13 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
thread->status = THREADSTATUS_WAIT_ARB;
}
+void ExitCurrentThread() {
+ Thread* thread = GetCurrentThread();
+ thread->Stop();
+ thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
+ thread_list.end());
+}
+
/**
* Callback that will wake up the thread it was scheduled for
* @param thread_handle The handle of the thread that's been awoken
@@ -351,15 +281,15 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
return;
}
- thread->waitsynch_waited = false;
-
if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
+ thread->wait_set_output = false;
+ // Remove the thread from each of its waiting objects' waitlists
+ for (auto& object : thread->wait_objects)
+ object->RemoveWaitingThread(thread.get());
+ thread->wait_objects.clear();
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
ErrorSummary::StatusChanged,
ErrorLevel::Info));
-
- if (thread->wait_set_output)
- thread->SetWaitSynchronizationOutput(-1);
}
thread->ResumeFromWait();
@@ -399,6 +329,7 @@ void Thread::ResumeFromWait() {
ready_queue.push_back(current_priority, this);
status = THREADSTATUS_READY;
+ Core::System::GetInstance().PrepareReschedule();
}
/**
@@ -453,9 +384,9 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
* @param entry_point Address of entry point for execution
* @param arg User argument for thread
*/
-static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point,
- u32 arg) {
- memset(&context, 0, sizeof(Core::ThreadContext));
+static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top,
+ u32 entry_point, u32 arg) {
+ memset(&context, 0, sizeof(ARM_Interface::ThreadContext));
context.cpu_registers[0] = arg;
context.pc = entry_point;
@@ -494,13 +425,11 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
thread->wait_set_output = false;
- thread->wait_all = false;
thread->wait_objects.clear();
thread->wait_address = 0;
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
thread->owner_process = g_current_process;
- thread->waitsynch_waited = false;
// Find the next available TLS index, and mark it as used
auto& tls_slots = Kernel::g_current_process->tls_slots;
@@ -555,8 +484,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
ready_queue.push_back(thread->current_priority, thread.get());
thread->status = THREADSTATUS_READY;
- HLE::Reschedule(__func__);
-
return MakeResult<SharedPtr<Thread>>(std::move(thread));
}
@@ -617,16 +544,6 @@ void Reschedule() {
Thread* cur = GetCurrentThread();
Thread* next = PopNextReadyThread();
- HLE::DoneRescheduling();
-
- // Don't bother switching to the same thread.
- // But if the thread was waiting on objects, we still need to switch it
- // to perform PC modification, change state to RUNNING, etc.
- // This occurs in the case when an object the thread is waiting on immediately wakes up
- // the current thread before Reschedule() is called.
- if (next == cur && (next == nullptr || next->waitsynch_waited == false))
- return;
-
if (cur && next) {
LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId());
} else if (cur) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index e0ffcea8a..c77ac644d 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -5,11 +5,13 @@
#pragma once
#include <string>
+#include <unordered_map>
#include <vector>
+#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include "common/common_types.h"
+#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
@@ -125,6 +127,16 @@ public:
void SetWaitSynchronizationOutput(s32 output);
/**
+ * Retrieves the index that this particular object occupies in the list of objects
+ * that the thread passed to WaitSynchronizationN.
+ * It is used to set the output value of WaitSynchronizationN when the thread is awakened.
+ * @param object Object to query the index of.
+ */
+ s32 GetWaitObjectIndex(const WaitObject* object) const {
+ return wait_objects_index.at(object->GetObjectId());
+ }
+
+ /**
* Stops a thread, invalidating it from further use
*/
void Stop();
@@ -137,7 +149,16 @@ public:
return tls_address;
}
- Core::ThreadContext context;
+ /**
+ * Returns whether this thread is waiting for all the objects in
+ * its wait list to become ready, as a result of a WaitSynchronizationN call
+ * with wait_all = true, or a ReplyAndReceive call.
+ */
+ bool IsSleepingOnWaitAll() const {
+ return !wait_objects.empty();
+ }
+
+ ARM_Interface::ThreadContext context;
u32 thread_id;
@@ -154,16 +175,22 @@ public:
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
- bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait
-
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
- SharedPtr<Process> owner_process; ///< Process that owns this thread
- std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
- VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
- bool wait_all; ///< True if the thread is waiting on all objects before resuming
- bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
+ SharedPtr<Process> owner_process; ///< Process that owns this thread
+
+ /// Objects that the thread is waiting on.
+ /// This is only populated when the thread should wait for all the objects to become ready.
+ std::vector<SharedPtr<WaitObject>> wait_objects;
+
+ /// Mapping of Object ids to their position in the last waitlist that this object waited on.
+ boost::container::flat_map<int, s32> wait_objects_index;
+
+ VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
+
+ /// True if the WaitSynchronizationN output parameter should be set on thread wakeup.
+ bool wait_set_output;
std::string name;
@@ -215,10 +242,9 @@ void WaitCurrentThread_Sleep();
* @param wait_objects Kernel objects that we are waiting on
* @param wait_set_output If true, set the output parameter on thread wakeup (for
* WaitSynchronizationN only)
- * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
*/
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
- bool wait_set_output, bool wait_all);
+ bool wait_set_output);
/**
* Waits the current thread from an ArbitrateAddress call
@@ -227,6 +253,11 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
/**
+ * Stops the current thread and removes it from the thread_list
+ */
+void ExitCurrentThread();
+
+/**
* Initialize threading
*/
void ThreadingInit();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index eac181f4e..b50cf520d 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -60,14 +60,10 @@ void Timer::Set(s64 initial, s64 interval) {
u64 initial_microseconds = initial / 1000;
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
callback_handle);
-
- HLE::Reschedule(__func__);
}
void Timer::Cancel() {
CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
-
- HLE::Reschedule(__func__);
}
void Timer::Clear() {
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 8d29117a8..53864a3a7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -18,6 +18,7 @@ enum class ErrorDescription : u32 {
Success = 0,
WrongPermission = 46,
OS_InvalidBufferDescriptor = 48,
+ MaxConnectionsReached = 52,
WrongAddress = 53,
FS_ArchiveNotMounted = 101,
FS_FileNotFound = 112,
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index fe367aca5..36204db4d 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -2,14 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
+
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/ac_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AC_U
-
-namespace AC_U {
+namespace Service {
+namespace AC {
struct ACConfig {
std::array<u8, 0x200> data;
@@ -31,7 +31,7 @@ static Kernel::SharedPtr<Kernel::Event> disconnect_event;
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void CreateDefaultConfig(Service::Interface* self) {
+static void CreateDefaultConfig(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 ac_config_addr = cmd_buff[65];
@@ -56,7 +56,7 @@ static void CreateDefaultConfig(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void ConnectAsync(Service::Interface* self) {
+static void ConnectAsync(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
connect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
@@ -77,7 +77,7 @@ static void ConnectAsync(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void GetConnectResult(Service::Interface* self) {
+static void GetConnectResult(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -94,7 +94,7 @@ static void GetConnectResult(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void CloseAsync(Service::Interface* self) {
+static void CloseAsync(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
if (ac_connected && disconnect_event) {
@@ -120,7 +120,7 @@ static void CloseAsync(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void GetCloseResult(Service::Interface* self) {
+static void GetCloseResult(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -134,7 +134,7 @@ static void GetCloseResult(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Output connection type, 0 = none, 1 = Old3DS Internet, 2 = New3DS Internet.
*/
-static void GetWifiStatus(Service::Interface* self) {
+static void GetWifiStatus(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(purpasmart96): This function is only a stub,
@@ -155,7 +155,7 @@ static void GetWifiStatus(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Infra Priority
*/
-static void GetInfraPriority(Service::Interface* self) {
+static void GetInfraPriority(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -177,7 +177,7 @@ static void GetInfraPriority(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Infra Priority
*/
-static void SetRequestEulaVersion(Service::Interface* self) {
+static void SetRequestEulaVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 major = cmd_buff[1] & 0xFF;
@@ -203,7 +203,7 @@ static void SetRequestEulaVersion(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void RegisterDisconnectEvent(Service::Interface* self) {
+static void RegisterDisconnectEvent(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
disconnect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
@@ -221,7 +221,7 @@ static void RegisterDisconnectEvent(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : bool, is connected
*/
-static void IsConnected(Service::Interface* self) {
+static void IsConnected(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -237,7 +237,7 @@ static void IsConnected(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetClientVersion(Service::Interface* self) {
+static void SetClientVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
const u32 version = cmd_buff[1];
@@ -271,10 +271,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00400042, SetClientVersion, "SetClientVersion"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+AC_U::AC_U() {
Register(FunctionTable);
ac_connected = false;
@@ -284,10 +281,11 @@ Interface::Interface() {
disconnect_event = nullptr;
}
-Interface::~Interface() {
+AC_U::~AC_U() {
close_event = nullptr;
connect_event = nullptr;
disconnect_event = nullptr;
}
-} // namespace
+} // namespace AC
+} // namespace Service
diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h
index 6592b21c9..573c32d7e 100644
--- a/src/core/hle/service/ac_u.h
+++ b/src/core/hle/service/ac_u.h
@@ -6,21 +6,18 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AC_U
+namespace Service {
+namespace AC {
-// socket service "ac:u"
-
-namespace AC_U {
-
-class Interface : public Service::Interface {
+class AC_U final : public Interface {
public:
- Interface();
- ~Interface();
+ AC_U();
+ ~AC_U();
std::string GetPortName() const override {
return "ac:u";
}
};
-} // namespace
+} // namespace AC
+} // namespace Service
diff --git a/src/core/hle/service/act/act.cpp b/src/core/hle/service/act/act.cpp
new file mode 100644
index 000000000..9600036c0
--- /dev/null
+++ b/src/core/hle/service/act/act.cpp
@@ -0,0 +1,18 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/act/act.h"
+#include "core/hle/service/act/act_a.h"
+#include "core/hle/service/act/act_u.h"
+
+namespace Service {
+namespace ACT {
+
+void Init() {
+ AddService(new ACT_A);
+ AddService(new ACT_U);
+}
+
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h
new file mode 100644
index 000000000..1425291aa
--- /dev/null
+++ b/src/core/hle/service/act/act.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace ACT {
+
+/// Initializes all ACT services
+void Init();
+
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act/act_a.cpp b/src/core/hle/service/act/act_a.cpp
new file mode 100644
index 000000000..5c523368f
--- /dev/null
+++ b/src/core/hle/service/act/act_a.cpp
@@ -0,0 +1,30 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/act/act.h"
+#include "core/hle/service/act/act_a.h"
+
+namespace Service {
+namespace ACT {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // act:u shared commands
+ {0x00010084, nullptr, "Initialize"},
+ {0x00020040, nullptr, "GetErrorCode"},
+ {0x000600C2, nullptr, "GetAccountDataBlock"},
+ {0x000B0042, nullptr, "AcquireEulaList"},
+ {0x000D0040, nullptr, "GenerateUuid"},
+ // act:a
+ {0x041300C2, nullptr, "UpdateMiiImage"},
+ {0x041B0142, nullptr, "AgreeEula"},
+ {0x04210042, nullptr, "UploadMii"},
+ {0x04230082, nullptr, "ValidateMailAddress"},
+};
+
+ACT_A::ACT_A() {
+ Register(FunctionTable);
+}
+
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_a.h b/src/core/hle/service/act/act_a.h
index 765cae644..e3adb03e5 100644
--- a/src/core/hle/service/act_a.h
+++ b/src/core/hle/service/act/act_a.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_A
+namespace Service {
+namespace ACT {
-namespace ACT_A {
-
-class Interface : public Service::Interface {
+class ACT_A final : public Service::Interface {
public:
- Interface();
+ ACT_A();
std::string GetPortName() const override {
return "act:a";
}
};
-} // namespace
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act/act_u.cpp
index 05de4d002..cf98aa1d6 100644
--- a/src/core/hle/service/act_u.cpp
+++ b/src/core/hle/service/act/act_u.cpp
@@ -2,25 +2,25 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/service/act_u.h"
+#include "core/hle/service/act/act.h"
+#include "core/hle/service/act/act_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_U
-
-namespace ACT_U {
+namespace Service {
+namespace ACT {
const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
{0x00010084, nullptr, "Initialize"},
{0x00020040, nullptr, "GetErrorCode"},
{0x000600C2, nullptr, "GetAccountDataBlock"},
+ {0x000B0042, nullptr, "AcquireEulaList"},
{0x000D0040, nullptr, "GenerateUuid"},
+ // clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+ACT_U::ACT_U() {
Register(FunctionTable);
}
-} // namespace
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_u.h b/src/core/hle/service/act/act_u.h
index be41454a4..9d8538fbf 100644
--- a/src/core/hle/service/act_u.h
+++ b/src/core/hle/service/act/act_u.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_U
+namespace Service {
+namespace ACT {
-namespace ACT_U {
-
-class Interface : public Service::Interface {
+class ACT_U final : public Interface {
public:
- Interface();
+ ACT_U();
std::string GetPortName() const override {
return "act:u";
}
};
-} // namespace
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_a.cpp b/src/core/hle/service/act_a.cpp
deleted file mode 100644
index 3a775fa90..000000000
--- a/src/core/hle/service/act_a.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/service/act_a.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_A
-
-namespace ACT_A {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x041300C2, nullptr, "UpdateMiiImage"},
- {0x041B0142, nullptr, "AgreeEula"},
- {0x04210042, nullptr, "UploadMii"},
- {0x04230082, nullptr, "ValidateMailAddress"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index f7a990d69..d344a622f 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -20,7 +20,7 @@ static std::array<u32, 3> am_titles_list_count = {0, 0, 0};
static u32 am_ticket_count = 0;
static u32 am_ticket_list_count = 0;
-void GetTitleCount(Service::Interface* self) {
+void GetNumPrograms(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 media_type = cmd_buff[1] & 0xFF;
@@ -81,7 +81,7 @@ void DeleteContents(Service::Interface* self) {
media_type, title_id, am_content_count[media_type], content_ids_pointer);
}
-void GetTitleList(Service::Interface* self) {
+void GetProgramList(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 media_type = cmd_buff[2] & 0xFF;
@@ -97,7 +97,7 @@ void GetTitleList(Service::Interface* self) {
media_type, am_titles_list_count[media_type], title_ids_output_pointer);
}
-void GetTitleInfo(Service::Interface* self) {
+void GetProgramInfos(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 media_type = cmd_buff[1] & 0xFF;
@@ -113,7 +113,7 @@ void GetTitleInfo(Service::Interface* self) {
}
void GetDataTitleInfos(Service::Interface* self) {
- GetTitleInfo(self);
+ GetProgramInfos(self);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
@@ -151,7 +151,7 @@ void DeleteTicket(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id);
}
-void GetTicketCount(Service::Interface* self) {
+void GetNumTickets(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 5676cdd5f..9bc2ca305 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -11,7 +11,7 @@ class Interface;
namespace AM {
/**
- * AM::GetTitleCount service function
+ * AM::GetNumPrograms service function
* Gets the number of installed titles in the requested media type
* Inputs:
* 0 : Command header (0x00010040)
@@ -20,7 +20,7 @@ namespace AM {
* 1 : Result, 0 on success, otherwise error code
* 2 : The number of titles in the requested media type
*/
-void GetTitleCount(Service::Interface* self);
+void GetNumPrograms(Service::Interface* self);
/**
* AM::FindContentInfos service function
@@ -62,7 +62,7 @@ void ListContentInfos(Service::Interface* self);
void DeleteContents(Service::Interface* self);
/**
- * AM::GetTitleList service function
+ * AM::GetProgramList service function
* Loads information about the desired number of titles from the desired media type into an array
* Inputs:
* 1 : Title count
@@ -72,10 +72,10 @@ void DeleteContents(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code
* 2 : The number of titles loaded from the requested media type
*/
-void GetTitleList(Service::Interface* self);
+void GetProgramList(Service::Interface* self);
/**
- * AM::GetTitleInfo service function
+ * AM::GetProgramInfos service function
* Inputs:
* 1 : u8 Mediatype
* 2 : Total titles
@@ -84,11 +84,11 @@ void GetTitleList(Service::Interface* self);
* Outputs:
* 1 : Result, 0 on success, otherwise error code
*/
-void GetTitleInfo(Service::Interface* self);
+void GetProgramInfos(Service::Interface* self);
/**
* AM::GetDataTitleInfos service function
- * Wrapper for AM::GetTitleInfo
+ * Wrapper for AM::GetProgramInfos
* Inputs:
* 1 : u8 Mediatype
* 2 : Total titles
@@ -135,12 +135,12 @@ void GetNumContentInfos(Service::Interface* self);
void DeleteTicket(Service::Interface* self);
/**
- * AM::GetTicketCount service function
+ * AM::GetNumTickets service function
* Outputs:
* 1 : Result, 0 on success, otherwise error code
- * 2 : Total titles
+ * 2 : Number of tickets
*/
-void GetTicketCount(Service::Interface* self);
+void GetNumTickets(Service::Interface* self);
/**
* AM::GetTicketList service function
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index bfc1ca6bd..218375c8f 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -14,9 +14,14 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x10030142, ListContentInfos, "ListContentInfos"},
{0x10040102, DeleteContents, "DeleteContents"},
{0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
+ {0x10060080, nullptr, "GetNumDataTitleTickets"},
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
+ {0x100801C2, nullptr, "GetItemRights"},
{0x100900C0, nullptr, "IsDataTitleInUse"},
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
+ {0x100B00C0, nullptr, "GetNumExistingContentInfos"},
+ {0x100C0142, nullptr, "ListExistingContentInfos"},
+ {0x100D0084, nullptr, "GetPatchTitleInfos"},
};
AM_APP_Interface::AM_APP_Interface() {
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index 3a597a34c..f3cd1d23f 100644
--- a/src/core/hle/service/am/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -9,61 +9,116 @@ namespace Service {
namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetTitleCount, "GetTitleCount"},
- {0x00020082, GetTitleList, "GetTitleList"},
- {0x00030084, GetTitleInfo, "GetTitleInfo"},
- {0x000400C0, nullptr, "DeleteApplicationTitle"},
- {0x000500C0, nullptr, "GetTitleProductCode"},
- {0x000600C0, nullptr, "GetTitleExtDataId"},
+ {0x00010040, GetNumPrograms, "GetNumPrograms"},
+ {0x00020082, GetProgramList, "GetProgramList"},
+ {0x00030084, GetProgramInfos, "GetProgramInfos"},
+ {0x000400C0, nullptr, "DeleteUserProgram"},
+ {0x000500C0, nullptr, "GetProductCode"},
+ {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"},
- {0x00080000, GetTicketCount, "GetTicketCount"},
+ {0x00080000, GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"},
- {0x000D0084, nullptr, "GetPendingTitleInfo"},
- {0x000E00C0, nullptr, "DeletePendingTitle"},
- {0x00140040, nullptr, "FinalizePendingTitles"},
- {0x00150040, nullptr, "DeleteAllPendingTitles"},
+ {0x000B0040, nullptr, "GetNumImportTitleContexts"},
+ {0x000C0082, nullptr, "GetImportTitleContextList"},
+ {0x000D0084, nullptr, "GetImportTitleContexts"},
+ {0x000E00C0, nullptr, "DeleteImportTitleContext"},
+ {0x000F00C0, nullptr, "GetNumImportContentContexts"},
+ {0x00100102, nullptr, "GetImportContentContextList"},
+ {0x00110104, nullptr, "GetImportContentContexts"},
+ {0x00120102, nullptr, "DeleteImportContentContexts"},
+ {0x00130040, nullptr, "NeedsCleanup"},
+ {0x00140040, nullptr, "DoCleanup"},
+ {0x00150040, nullptr, "DeleteAllImportContexts"},
+ {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
+ {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"},
- {0x00190040, nullptr, "ReloadDBS"},
- {0x001A00C0, nullptr, "GetDSiWareExportSize"},
- {0x001B0144, nullptr, "ExportDSiWare"},
- {0x001C0084, nullptr, "ImportDSiWare"},
- {0x00230080, nullptr, "TitleIDListGetTotal2"},
- {0x002400C2, nullptr, "GetTitleIDList2"},
- {0x04010080, nullptr, "InstallFIRM"},
- {0x04020040, nullptr, "StartInstallCIADB0"},
- {0x04030000, nullptr, "StartInstallCIADB1"},
- {0x04040002, nullptr, "AbortCIAInstall"},
- {0x04050002, nullptr, "CloseCIAFinalizeInstall"},
- {0x04060002, nullptr, "CloseCIA"},
- {0x040700C2, nullptr, "FinalizeTitlesInstall"},
- {0x04080042, nullptr, "GetCiaFileInfo"},
- {0x040E00C2, nullptr, "InstallTitlesFinish"},
- {0x040F0000, nullptr, "InstallNATIVEFIRM"},
- {0x041000C0, nullptr, "DeleteTitle"},
- {0x04120000, nullptr, "Initialize"},
- {0x041700C0, nullptr, "MigrateAGBtoSAV"},
- {0x08010000, nullptr, "OpenTicket"},
- {0x08020002, nullptr, "TicketAbortInstall"},
- {0x08030002, nullptr, "TicketFinalizeInstall"},
- {0x08040100, nullptr, "InstallTitleBegin"},
- {0x08050000, nullptr, "InstallTitleAbort"},
- {0x080600C0, nullptr, "InstallTitleResume"},
- {0x08070000, nullptr, "InstallTitleAbortTMD"},
- {0x08080000, nullptr, "InstallTitleFinish"},
- {0x080A0000, nullptr, "OpenTMD"},
- {0x080B0002, nullptr, "TMDAbortInstall"},
- {0x080C0042, nullptr, "TMDFinalizeInstall"},
- {0x080E0040, nullptr, "OpenContentCreate"},
- {0x080F0002, nullptr, "ContentAbortInstall"},
- {0x08100040, nullptr, "OpenContentResume"},
- {0x08120002, nullptr, "ContentFinalizeInstall"},
- {0x08130000, nullptr, "GetTotalContents"},
- {0x08140042, nullptr, "GetContentIndexes"},
- {0x08150044, nullptr, "GetContentsInfo"},
- {0x08180042, nullptr, "GetCTCert"},
- {0x08190108, nullptr, "SetCertificates"},
- {0x081B00C2, nullptr, "InstallTitlesFinish"},
+ {0x00190040, nullptr, "QueryAvailableTitleDatabase"},
+ {0x001A00C0, nullptr, "CalcTwlBackupSize"},
+ {0x001B0144, nullptr, "ExportTwlBackup"},
+ {0x001C0084, nullptr, "ImportTwlBackup"},
+ {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"},
+ {0x001E00C8, nullptr, "ReadTwlBackupInfo"},
+ {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"},
+ {0x00200000, nullptr, "GetTwlArchiveResourceInfo"},
+ {0x00210042, nullptr, "GetPersonalizedTicketInfoList"},
+ {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
+ {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
+ {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
+ {0x002500C0, nullptr, "CheckContentRights"},
+ {0x00260044, nullptr, "GetTicketLimitInfos"},
+ {0x00270044, nullptr, "GetDemoLaunchInfos"},
+ {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
+ {0x00290082, nullptr, "DeleteUserProgramsAtomically"},
+ {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
+ {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
+ {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
+ {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
+ {0x04010080, nullptr, "UpdateFirmwareTo"},
+ {0x04020040, nullptr, "BeginImportProgram"},
+ {0x04030000, nullptr, "BeginImportProgramTemporarily"},
+ {0x04040002, nullptr, "CancelImportProgram"},
+ {0x04050002, nullptr, "EndImportProgram"},
+ {0x04060002, nullptr, "EndImportProgramWithoutCommit"},
+ {0x040700C2, nullptr, "CommitImportPrograms"},
+ {0x04080042, nullptr, "GetProgramInfoFromCia"},
+ {0x04090004, nullptr, "GetSystemMenuDataFromCia"},
+ {0x040A0002, nullptr, "GetDependencyListFromCia"},
+ {0x040B0002, nullptr, "GetTransferSizeFromCia"},
+ {0x040C0002, nullptr, "GetCoreVersionFromCia"},
+ {0x040D0042, nullptr, "GetRequiredSizeFromCia"},
+ {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"},
+ {0x040F0000, nullptr, "UpdateFirmwareAuto"},
+ {0x041000C0, nullptr, "DeleteProgram"},
+ {0x04110044, nullptr, "GetTwlProgramListForReboot"},
+ {0x04120000, nullptr, "GetSystemUpdaterMutex"},
+ {0x04130002, nullptr, "GetMetaSizeFromCia"},
+ {0x04140044, nullptr, "GetMetaDataFromCia"},
+ {0x04150080, nullptr, "CheckDemoLaunchRights"},
+ {0x041600C0, nullptr, "GetInternalTitleLocationInfo"},
+ {0x041700C0, nullptr, "PerpetuateAgbSaveData"},
+ {0x04180040, nullptr, "BeginImportProgramForOverWrite"},
+ {0x04190000, nullptr, "BeginImportSystemProgram"},
+ {0x08010000, nullptr, "BeginImportTicket"},
+ {0x08020002, nullptr, "CancelImportTicket"},
+ {0x08030002, nullptr, "EndImportTicket"},
+ {0x08040100, nullptr, "BeginImportTitle"},
+ {0x08050000, nullptr, "StopImportTitle"},
+ {0x080600C0, nullptr, "ResumeImportTitle"},
+ {0x08070000, nullptr, "CancelImportTitle"},
+ {0x08080000, nullptr, "EndImportTitle"},
+ {0x080900C2, nullptr, "CommitImportTitles"},
+ {0x080A0000, nullptr, "BeginImportTmd"},
+ {0x080B0002, nullptr, "CancelImportTmd"},
+ {0x080C0042, nullptr, "EndImportTmd"},
+ {0x080D0042, nullptr, "CreateImportContentContexts"},
+ {0x080E0040, nullptr, "BeginImportContent"},
+ {0x080F0002, nullptr, "StopImportContent"},
+ {0x08100040, nullptr, "ResumeImportContent"},
+ {0x08110002, nullptr, "CancelImportContent"},
+ {0x08120002, nullptr, "EndImportContent"},
+ {0x08130000, nullptr, "GetNumCurrentImportContentContexts"},
+ {0x08140042, nullptr, "GetCurrentImportContentContextList"},
+ {0x08150044, nullptr, "GetCurrentImportContentContexts"},
+ {0x08160146, nullptr, "Sign"},
+ {0x08170146, nullptr, "Verify"},
+ {0x08180042, nullptr, "GetDeviceCert"},
+ {0x08190108, nullptr, "ImportCertificates"},
+ {0x081A0042, nullptr, "ImportCertificate"},
+ {0x081B00C2, nullptr, "CommitImportTitlesAndUpdateFirmwareAuto"},
+ {0x081C0100, nullptr, "DeleteTicketId"},
+ {0x081D0080, nullptr, "GetNumTicketIds"},
+ {0x081E0102, nullptr, "GetTicketIdList"},
+ {0x081F0080, nullptr, "GetNumTicketsOfProgram"},
+ {0x08200102, nullptr, "ListTicketInfos"},
+ {0x08210142, nullptr, "GetRightsOnlyTicketData"},
+ {0x08220000, nullptr, "GetNumCurrentContentInfos"},
+ {0x08230044, nullptr, "FindCurrentContentInfos"},
+ {0x08240082, nullptr, "ListCurrentContentInfos"},
+ {0x08250102, nullptr, "CalculateContextRequiredSize"},
+ {0x08260042, nullptr, "UpdateImportContentContexts"},
+ {0x08270000, nullptr, "DeleteAllDemoLaunchInfos"},
+ {0x082800C0, nullptr, "BeginImportTitleForOverWrite"},
};
AM_NET_Interface::AM_NET_Interface() {
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
index a2268303c..949b3591d 100644
--- a/src/core/hle/service/am/am_sys.cpp
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -9,27 +9,64 @@ namespace Service {
namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetTitleCount, "GetTitleCount"},
- {0x00020082, GetTitleList, "GetTitleList"},
- {0x00030084, GetTitleInfo, "GetTitleInfo"},
- {0x000400C0, nullptr, "DeleteApplicationTitle"},
- {0x000500C0, nullptr, "GetTitleProductCode"},
- {0x000600C0, nullptr, "GetTitleExtDataId"},
+ {0x00010040, GetNumPrograms, "GetNumPrograms"},
+ {0x00020082, GetProgramList, "GetProgramList"},
+ {0x00030084, GetProgramInfos, "GetProgramInfos"},
+ {0x000400C0, nullptr, "DeleteUserProgram"},
+ {0x000500C0, nullptr, "GetProductCode"},
+ {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"},
- {0x00080000, GetTicketCount, "GetTicketCount"},
+ {0x00080000, GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"},
- {0x000D0084, nullptr, "GetPendingTitleInfo"},
- {0x000E00C0, nullptr, "DeletePendingTitle"},
- {0x00140040, nullptr, "FinalizePendingTitles"},
- {0x00150040, nullptr, "DeleteAllPendingTitles"},
+ {0x000B0040, nullptr, "GetNumImportTitleContexts"},
+ {0x000C0082, nullptr, "GetImportTitleContextList"},
+ {0x000D0084, nullptr, "GetImportTitleContexts"},
+ {0x000E00C0, nullptr, "DeleteImportTitleContext"},
+ {0x000F00C0, nullptr, "GetNumImportContentContexts"},
+ {0x00100102, nullptr, "GetImportContentContextList"},
+ {0x00110104, nullptr, "GetImportContentContexts"},
+ {0x00120102, nullptr, "DeleteImportContentContexts"},
+ {0x00130040, nullptr, "NeedsCleanup"},
+ {0x00140040, nullptr, "DoCleanup"},
+ {0x00150040, nullptr, "DeleteAllImportContexts"},
+ {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
+ {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"},
- {0x00190040, nullptr, "ReloadDBS"},
- {0x001A00C0, nullptr, "GetDSiWareExportSize"},
- {0x001B0144, nullptr, "ExportDSiWare"},
- {0x001C0084, nullptr, "ImportDSiWare"},
- {0x00230080, nullptr, "GetPendingTitleCount"},
- {0x002400C2, nullptr, "GetPendingTitleList"},
+ {0x00190040, nullptr, "QueryAvailableTitleDatabase"},
+ {0x001A00C0, nullptr, "CalcTwlBackupSize"},
+ {0x001B0144, nullptr, "ExportTwlBackup"},
+ {0x001C0084, nullptr, "ImportTwlBackup"},
+ {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"},
+ {0x001E00C8, nullptr, "ReadTwlBackupInfo"},
+ {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"},
+ {0x00200000, nullptr, "GetTwlArchiveResourceInfo"},
+ {0x00210042, nullptr, "GetPersonalizedTicketInfoList"},
+ {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
+ {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
+ {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
+ {0x002500C0, nullptr, "CheckContentRights"},
+ {0x00260044, nullptr, "GetTicketLimitInfos"},
+ {0x00270044, nullptr, "GetDemoLaunchInfos"},
+ {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
+ {0x00290082, nullptr, "DeleteUserProgramsAtomically"},
+ {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
+ {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
+ {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
+ {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
+ {0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
+ {0x10020104, FindContentInfos, "FindContentInfos"},
+ {0x10030142, ListContentInfos, "ListContentInfos"},
+ {0x10040102, DeleteContents, "DeleteContents"},
+ {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
+ {0x10060080, nullptr, "GetNumDataTitleTickets"},
+ {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
+ {0x100801C2, nullptr, "GetItemRights"},
+ {0x100900C0, nullptr, "IsDataTitleInUse"},
+ {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
+ {0x100B00C0, nullptr, "GetNumExistingContentInfos"},
+ {0x100C0142, nullptr, "ListExistingContentInfos"},
+ {0x100D0084, nullptr, "GetPatchTitleInfos"},
};
AM_SYS_Interface::AM_SYS_Interface() {
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
index 151b5e42b..354d51610 100644
--- a/src/core/hle/service/am/am_u.cpp
+++ b/src/core/hle/service/am/am_u.cpp
@@ -9,40 +9,76 @@ namespace Service {
namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetTitleCount, "GetTitleCount"},
- {0x00020082, GetTitleList, "GetTitleList"},
- {0x00030084, GetTitleInfo, "GetTitleInfo"},
- {0x000400C0, nullptr, "DeleteApplicationTitle"},
- {0x000500C0, nullptr, "GetTitleProductCode"},
- {0x000600C0, nullptr, "GetTitleExtDataId"},
+ {0x00010040, GetNumPrograms, "GetNumPrograms"},
+ {0x00020082, GetProgramList, "GetProgramList"},
+ {0x00030084, GetProgramInfos, "GetProgramInfos"},
+ {0x000400C0, nullptr, "DeleteUserProgram"},
+ {0x000500C0, nullptr, "GetProductCode"},
+ {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"},
- {0x00080000, GetTicketCount, "GetTicketCount"},
+ {0x00080000, GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"},
- {0x000D0084, nullptr, "GetPendingTitleInfo"},
- {0x000E00C0, nullptr, "DeletePendingTitle"},
- {0x00140040, nullptr, "FinalizePendingTitles"},
- {0x00150040, nullptr, "DeleteAllPendingTitles"},
+ {0x000B0040, nullptr, "GetNumImportTitleContexts"},
+ {0x000C0082, nullptr, "GetImportTitleContextList"},
+ {0x000D0084, nullptr, "GetImportTitleContexts"},
+ {0x000E00C0, nullptr, "DeleteImportTitleContext"},
+ {0x000F00C0, nullptr, "GetNumImportContentContexts"},
+ {0x00100102, nullptr, "GetImportContentContextList"},
+ {0x00110104, nullptr, "GetImportContentContexts"},
+ {0x00120102, nullptr, "DeleteImportContentContexts"},
+ {0x00130040, nullptr, "NeedsCleanup"},
+ {0x00140040, nullptr, "DoCleanup"},
+ {0x00150040, nullptr, "DeleteAllImportContexts"},
+ {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
+ {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"},
- {0x00190040, nullptr, "ReloadDBS"},
- {0x001A00C0, nullptr, "GetDSiWareExportSize"},
- {0x001B0144, nullptr, "ExportDSiWare"},
- {0x001C0084, nullptr, "ImportDSiWare"},
- {0x00230080, nullptr, "TitleIDListGetTotal2"},
- {0x002400C2, nullptr, "GetTitleIDList2"},
- {0x04010080, nullptr, "InstallFIRM"},
- {0x04020040, nullptr, "StartInstallCIADB0"},
- {0x04030000, nullptr, "StartInstallCIADB1"},
- {0x04040002, nullptr, "AbortCIAInstall"},
- {0x04050002, nullptr, "CloseCIAFinalizeInstall"},
- {0x04060002, nullptr, "CloseCIA"},
- {0x040700C2, nullptr, "FinalizeTitlesInstall"},
- {0x04080042, nullptr, "GetCiaFileInfo"},
- {0x040E00C2, nullptr, "InstallTitlesFinish"},
- {0x040F0000, nullptr, "InstallNATIVEFIRM"},
- {0x041000C0, nullptr, "DeleteTitle"},
- {0x04120000, nullptr, "Initialize"},
- {0x041700C0, nullptr, "MigrateAGBtoSAV"},
+ {0x00190040, nullptr, "QueryAvailableTitleDatabase"},
+ {0x001A00C0, nullptr, "CalcTwlBackupSize"},
+ {0x001B0144, nullptr, "ExportTwlBackup"},
+ {0x001C0084, nullptr, "ImportTwlBackup"},
+ {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"},
+ {0x001E00C8, nullptr, "ReadTwlBackupInfo"},
+ {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"},
+ {0x00200000, nullptr, "GetTwlArchiveResourceInfo"},
+ {0x00210042, nullptr, "GetPersonalizedTicketInfoList"},
+ {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
+ {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
+ {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
+ {0x002500C0, nullptr, "CheckContentRights"},
+ {0x00260044, nullptr, "GetTicketLimitInfos"},
+ {0x00270044, nullptr, "GetDemoLaunchInfos"},
+ {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
+ {0x00290082, nullptr, "DeleteUserProgramsAtomically"},
+ {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
+ {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
+ {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
+ {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
+ {0x04010080, nullptr, "UpdateFirmwareTo"},
+ {0x04020040, nullptr, "BeginImportProgram"},
+ {0x04030000, nullptr, "BeginImportProgramTemporarily"},
+ {0x04040002, nullptr, "CancelImportProgram"},
+ {0x04050002, nullptr, "EndImportProgram"},
+ {0x04060002, nullptr, "EndImportProgramWithoutCommit"},
+ {0x040700C2, nullptr, "CommitImportPrograms"},
+ {0x04080042, nullptr, "GetProgramInfoFromCia"},
+ {0x04090004, nullptr, "GetSystemMenuDataFromCia"},
+ {0x040A0002, nullptr, "GetDependencyListFromCia"},
+ {0x040B0002, nullptr, "GetTransferSizeFromCia"},
+ {0x040C0002, nullptr, "GetCoreVersionFromCia"},
+ {0x040D0042, nullptr, "GetRequiredSizeFromCia"},
+ {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"},
+ {0x040F0000, nullptr, "UpdateFirmwareAuto"},
+ {0x041000C0, nullptr, "DeleteProgram"},
+ {0x04110044, nullptr, "GetTwlProgramListForReboot"},
+ {0x04120000, nullptr, "GetSystemUpdaterMutex"},
+ {0x04130002, nullptr, "GetMetaSizeFromCia"},
+ {0x04140044, nullptr, "GetMetaDataFromCia"},
+ {0x04150080, nullptr, "CheckDemoLaunchRights"},
+ {0x041600C0, nullptr, "GetInternalTitleLocationInfo"},
+ {0x041700C0, nullptr, "PerpetuateAgbSaveData"},
+ {0x04180040, nullptr, "BeginImportProgramForOverWrite"},
+ {0x04190000, nullptr, "BeginImportSystemProgram"},
};
AM_U_Interface::AM_U_Interface() {
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 31e5e07b2..615fe31ea 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -458,12 +458,16 @@ void GetStartupArgument(Service::Interface* self) {
return;
}
- LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , "
- "parameter_value=0x%08x",
- startup_argument_type, parameter_size, Memory::Read32(cmd_buff[41]));
+ u32 addr = cmd_buff[65];
+ if (addr && parameter_size) {
+ Memory::ZeroBlock(addr, parameter_size);
+ }
+
+ LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x",
+ startup_argument_type, parameter_size);
cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = (parameter_size > 0) ? 1 : 0;
+ cmd_buff[2] = 0;
}
void CheckNew3DSApp(Service::Interface* self) {
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 44dbd8757..80325361f 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -14,6 +14,9 @@ class Interface;
namespace APT {
+/// Each APT service can only have up to 2 sessions connected at the same time.
+static const u32 MaxAPTSessions = 2;
+
/// Holds information about the parameters used in Send/Glance/ReceiveParameter
struct MessageParameter {
u32 sender_id = 0;
@@ -407,9 +410,11 @@ void CancelLibraryApplet(Service::Interface* self);
* Inputs:
* 1 : Parameter Size (capped to 0x300)
* 2 : StartupArgumentType
+ * 65 : Output buffer for startup argument
* Outputs:
* 0 : Return header
- * 1 : u8, Exists (0 = does not exist, 1 = exists)
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : u8, Exists (0 = does not exist, 1 = exists)
*/
void GetStartupArgument(Service::Interface* self);
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index a7a0c8a41..62dc2d61d 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -9,37 +9,100 @@ namespace Service {
namespace APT {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetLockHandle, "GetLockHandle?"},
- {0x00020080, Initialize, "Initialize?"},
- {0x00030040, Enable, "Enable?"},
- {0x00040040, nullptr, "Finalize?"},
+ {0x00010040, GetLockHandle, "GetLockHandle"},
+ {0x00020080, Initialize, "Initialize"},
+ {0x00030040, Enable, "Enable"},
+ {0x00040040, nullptr, "Finalize"},
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
{0x00060040, GetAppletInfo, "GetAppletInfo"},
+ {0x00070000, nullptr, "GetLastSignaledAppletId"},
+ {0x00080000, nullptr, "CountRegisteredApplet"},
{0x00090040, IsRegistered, "IsRegistered"},
+ {0x000A0040, nullptr, "GetAttribute"},
{0x000B0040, InquireNotification, "InquireNotification"},
{0x000C0104, SendParameter, "SendParameter"},
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
{0x000E0080, GlanceParameter, "GlanceParameter"},
{0x000F0100, CancelParameter, "CancelParameter"},
+ {0x001000C2, nullptr, "DebugFunc"},
+ {0x001100C0, nullptr, "MapProgramIdForDebug"},
+ {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
+ {0x00130000, nullptr, "GetPreparationState"},
+ {0x00140040, nullptr, "SetPreparationState"},
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
+ {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
+ {0x00190040, nullptr, "PrepareToStartSystemApplet"},
+ {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
+ {0x001B00C4, nullptr, "StartApplication"},
+ {0x001C0000, nullptr, "WakeupApplication"},
+ {0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
+ {0x001F0084, nullptr, "StartSystemApplet"},
+ {0x00200044, nullptr, "StartNewestHomeMenu"},
+ {0x00210000, nullptr, "OrderToCloseApplication"},
+ {0x00220040, nullptr, "PrepareToCloseApplication"},
+ {0x00230040, nullptr, "PrepareToJumpToApplication"},
+ {0x00240044, nullptr, "JumpToApplication"},
+ {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
+ {0x00260000, nullptr, "PrepareToCloseSystemApplet"},
+ {0x00270044, nullptr, "CloseApplication"},
+ {0x00280044, nullptr, "CloseLibraryApplet"},
+ {0x00290044, nullptr, "CloseSystemApplet"},
+ {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
+ {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
+ {0x002C0044, nullptr, "JumpToHomeMenu"},
+ {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
+ {0x002E0044, nullptr, "LeaveHomeMenu"},
+ {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
+ {0x00300044, nullptr, "LeaveResidentApplet"},
+ {0x00310100, nullptr, "PrepareToDoApplicationJump"},
+ {0x00320084, nullptr, "DoApplicationJump"},
+ {0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
+ {0x00340084, nullptr, "SendDeliverArg"},
+ {0x00350080, nullptr, "ReceiveDeliverArg"},
+ {0x00360040, nullptr, "LoadSysMenuArg"},
+ {0x00370042, nullptr, "StoreSysMenuArg"},
+ {0x00380040, nullptr, "PreloadResidentApplet"},
+ {0x00390040, nullptr, "PrepareToStartResidentApplet"},
+ {0x003A0044, nullptr, "StartResidentApplet"},
{0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"},
+ {0x003C0042, nullptr, "SendDspSleep"},
+ {0x003D0042, nullptr, "SendDspWakeUp"},
{0x003E0080, nullptr, "ReplySleepQuery"},
- {0x00430040, NotifyToWait, "NotifyToWait?"},
- {0x00440000, GetSharedFont, "GetSharedFont?"},
- {0x004B00C2, AppletUtility, "AppletUtility?"},
+ {0x003F0040, nullptr, "ReplySleepNotificationComplete"},
+ {0x00400042, nullptr, "SendCaptureBufferInfo"},
+ {0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
+ {0x00420080, nullptr, "SleepSystem"},
+ {0x00430040, NotifyToWait, "NotifyToWait"},
+ {0x00440000, GetSharedFont, "GetSharedFont"},
+ {0x00450040, nullptr, "GetWirelessRebootInfo"},
+ {0x00460104, nullptr, "Wrap"},
+ {0x00470104, nullptr, "Unwrap"},
+ {0x00480100, nullptr, "GetProgramInfo"},
+ {0x00490180, nullptr, "Reboot"},
+ {0x004A0040, nullptr, "GetCaptureInfo"},
+ {0x004B00C2, AppletUtility, "AppletUtility"},
+ {0x004C0000, nullptr, "SetFatalErrDispMode"},
+ {0x004D0080, nullptr, "GetAppletProgramInfo"},
+ {0x004E0000, nullptr, "HardwareResetAsync"},
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
{0x00510080, GetStartupArgument, "GetStartupArgument"},
+ {0x00520104, nullptr, "Wrap1"},
+ {0x00530104, nullptr, "Unwrap1"},
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
+ {0x00570044, nullptr, "WakeupApplication2"},
+ {0x00580002, nullptr, "GetProgramID"},
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
{0x01020000, CheckNew3DS, "CheckNew3DS"},
+ {0x01040000, nullptr, "IsStandardMemoryLayout"},
+ {0x01050100, nullptr, "IsTitleAllowed"},
};
-APT_A_Interface::APT_A_Interface() {
+APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index c4556a5de..effd23dce 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -94,12 +94,15 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00530104, nullptr, "Unwrap1"},
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
+ {0x00570044, nullptr, "WakeupApplication2"},
{0x00580002, nullptr, "GetProgramID"},
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
{0x01020000, CheckNew3DS, "CheckNew3DS"},
+ {0x01040000, nullptr, "IsStandardMemoryLayout"},
+ {0x01050100, nullptr, "IsTitleAllowed"},
};
-APT_S_Interface::APT_S_Interface() {
+APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index a731c39f6..e06084a1e 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x01020000, CheckNew3DS, "CheckNew3DS"},
};
-APT_U_Interface::APT_U_Interface() {
+APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
index dfee8d055..ee941e228 100644
--- a/src/core/hle/service/boss/boss_p.cpp
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -2,16 +2,81 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/boss/boss.h"
#include "core/hle/service/boss/boss_p.h"
namespace Service {
namespace BOSS {
-// Empty arrays are illegal -- commented out until an entry is added.
-// const Interface::FunctionInfo FunctionTable[] = { };
+const Interface::FunctionInfo FunctionTable[] = {
+ // boss:u shared commands
+ {0x00010082, InitializeSession, "InitializeSession"},
+ {0x00020100, RegisterStorage, "RegisterStorage"},
+ {0x00030000, UnregisterStorage, "UnregisterStorage"},
+ {0x00040000, GetStorageInfo, "GetStorageInfo"},
+ {0x00050042, RegisterPrivateRootCa, "RegisterPrivateRootCa"},
+ {0x00060084, RegisterPrivateClientCert, "RegisterPrivateClientCert"},
+ {0x00070000, GetNewArrivalFlag, "GetNewArrivalFlag"},
+ {0x00080002, RegisterNewArrivalEvent, "RegisterNewArrivalEvent"},
+ {0x00090040, SetOptoutFlag, "SetOptoutFlag"},
+ {0x000A0000, GetOptoutFlag, "GetOptoutFlag"},
+ {0x000B00C2, RegisterTask, "RegisterTask"},
+ {0x000C0082, UnregisterTask, "UnregisterTask"},
+ {0x000D0082, ReconfigureTask, "ReconfigureTask"},
+ {0x000E0000, GetTaskIdList, "GetTaskIdList"},
+ {0x000F0042, GetStepIdList, "GetStepIdList"},
+ {0x00100102, GetNsDataIdList, "GetNsDataIdList"},
+ {0x00110102, GetOwnNsDataIdList, "GetOwnNsDataIdList"},
+ {0x00120102, GetNewDataNsDataIdList, "GetNewDataNsDataIdList"},
+ {0x00130102, GetOwnNewDataNsDataIdList, "GetOwnNewDataNsDataIdList"},
+ {0x00140082, SendProperty, "SendProperty"},
+ {0x00150042, SendPropertyHandle, "SendPropertyHandle"},
+ {0x00160082, ReceiveProperty, "ReceiveProperty"},
+ {0x00170082, UpdateTaskInterval, "UpdateTaskInterval"},
+ {0x00180082, UpdateTaskCount, "UpdateTaskCount"},
+ {0x00190042, GetTaskInterval, "GetTaskInterval"},
+ {0x001A0042, GetTaskCount, "GetTaskCount"},
+ {0x001B0042, GetTaskServiceStatus, "GetTaskServiceStatus"},
+ {0x001C0042, StartTask, "StartTask"},
+ {0x001D0042, StartTaskImmediate, "StartTaskImmediate"},
+ {0x001E0042, CancelTask, "CancelTask"},
+ {0x001F0000, GetTaskFinishHandle, "GetTaskFinishHandle"},
+ {0x00200082, GetTaskState, "GetTaskState"},
+ {0x00210042, GetTaskResult, "GetTaskResult"},
+ {0x00220042, GetTaskCommErrorCode, "GetTaskCommErrorCode"},
+ {0x002300C2, GetTaskStatus, "GetTaskStatus"},
+ {0x00240082, GetTaskError, "GetTaskError"},
+ {0x00250082, GetTaskInfo, "GetTaskInfo"},
+ {0x00260040, DeleteNsData, "DeleteNsData"},
+ {0x002700C2, GetNsDataHeaderInfo, "GetNsDataHeaderInfo"},
+ {0x00280102, ReadNsData, "ReadNsData"},
+ {0x00290080, SetNsDataAdditionalInfo, "SetNsDataAdditionalInfo"},
+ {0x002A0040, GetNsDataAdditionalInfo, "GetNsDataAdditionalInfo"},
+ {0x002B0080, SetNsDataNewFlag, "SetNsDataNewFlag"},
+ {0x002C0040, GetNsDataNewFlag, "GetNsDataNewFlag"},
+ {0x002D0040, GetNsDataLastUpdate, "GetNsDataLastUpdate"},
+ {0x002E0040, GetErrorCode, "GetErrorCode"},
+ {0x002F0140, RegisterStorageEntry, "RegisterStorageEntry"},
+ {0x00300000, GetStorageEntryInfo, "GetStorageEntryInfo"},
+ {0x00310100, SetStorageOption, "SetStorageOption"},
+ {0x00320000, GetStorageOption, "GetStorageOption"},
+ {0x00330042, StartBgImmediate, "StartBgImmediate"},
+ {0x00340042, GetTaskActivePriority, "GetTaskActivePriority"},
+ {0x003500C2, RegisterImmediateTask, "RegisterImmediateTask"},
+ {0x00360084, SetTaskQuery, "SetTaskQuery"},
+ {0x00370084, GetTaskQuery, "GetTaskQuery"},
+ // boss:p
+ {0x04040080, nullptr, "GetAppNewFlag"},
+ {0x04130082, nullptr, "SendPropertyPrivileged"},
+ {0x041500C0, nullptr, "DeleteNsDataPrivileged"},
+ {0x04160142, nullptr, "GetNsDataHeaderInfoPrivileged"},
+ {0x04170182, nullptr, "ReadNsDataPrivileged"},
+ {0x041A0100, nullptr, "SetNsDataNewFlagPrivileged"},
+ {0x041B00C0, nullptr, "GetNsDataNewFlagPrivileged"},
+};
BOSS_P_Interface::BOSS_P_Interface() {
- // Register(FunctionTable);
+ Register(FunctionTable);
}
} // namespace BOSS
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 515b344e6..eb04273db 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -5,6 +5,7 @@
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_ndm.h"
#include "core/hle/service/cecd/cecd_s.h"
#include "core/hle/service/cecd/cecd_u.h"
#include "core/hle/service/service.h"
@@ -43,12 +44,13 @@ void GetChangeStateEventHandle(Service::Interface* self) {
}
void Init() {
- AddService(new CECD_S_Interface);
- AddService(new CECD_U_Interface);
+ AddService(new CECD_NDM);
+ AddService(new CECD_S);
+ AddService(new CECD_U);
- cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::cecinfo_event");
+ cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event");
change_state_event =
- Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event");
+ Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event");
}
void Shutdown() {
diff --git a/src/core/hle/service/cecd/cecd_ndm.cpp b/src/core/hle/service/cecd/cecd_ndm.cpp
new file mode 100644
index 000000000..7baf93750
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_ndm.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_ndm.h"
+
+namespace Service {
+namespace CECD {
+
+static const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "Initialize"},
+ {0x00020000, nullptr, "Deinitialize"},
+ {0x00030000, nullptr, "ResumeDaemon"},
+ {0x00040040, nullptr, "SuspendDaemon"},
+};
+
+CECD_NDM::CECD_NDM() {
+ Register(FunctionTable);
+}
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_ndm.h b/src/core/hle/service/cecd/cecd_ndm.h
new file mode 100644
index 000000000..2e2e50ada
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_ndm.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CECD {
+
+class CECD_NDM : public Interface {
+public:
+ CECD_NDM();
+
+ std::string GetPortName() const override {
+ return "cecd:ndm";
+ }
+};
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp
index 7477b9320..eacda7d41 100644
--- a/src/core/hle/service/cecd/cecd_s.cpp
+++ b/src/core/hle/service/cecd/cecd_s.cpp
@@ -2,16 +2,34 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/cecd/cecd.h"
#include "core/hle/service/cecd/cecd_s.h"
namespace Service {
namespace CECD {
-// Empty arrays are illegal -- commented out until an entry is added.
-// const Interface::FunctionInfo FunctionTable[] = { };
+static const Interface::FunctionInfo FunctionTable[] = {
+ // cecd:u shared commands
+ {0x000100C2, nullptr, "OpenRawFile"},
+ {0x00020042, nullptr, "ReadRawFile"},
+ {0x00030104, nullptr, "ReadMessage"},
+ {0x00040106, nullptr, "ReadMessageWithHMAC"},
+ {0x00050042, nullptr, "WriteRawFile"},
+ {0x00060104, nullptr, "WriteMessage"},
+ {0x00070106, nullptr, "WriteMessageWithHMAC"},
+ {0x00080102, nullptr, "Delete"},
+ {0x000A00C4, nullptr, "GetSystemInfo"},
+ {0x000B0040, nullptr, "RunCommand"},
+ {0x000C0040, nullptr, "RunCommandAlt"},
+ {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"},
+ {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
+ {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"},
+ {0x00110104, nullptr, "OpenAndWrite"},
+ {0x00120104, nullptr, "OpenAndRead"},
+};
-CECD_S_Interface::CECD_S_Interface() {
- // Register(FunctionTable);
+CECD_S::CECD_S() {
+ Register(FunctionTable);
}
} // namespace CECD
diff --git a/src/core/hle/service/cecd/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h
index df5c01849..ab6c6789a 100644
--- a/src/core/hle/service/cecd/cecd_s.h
+++ b/src/core/hle/service/cecd/cecd_s.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CECD {
-class CECD_S_Interface : public Interface {
+class CECD_S : public Interface {
public:
- CECD_S_Interface();
+ CECD_S();
std::string GetPortName() const override {
return "cecd:s";
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
index 4b747de7b..3ed864f0b 100644
--- a/src/core/hle/service/cecd/cecd_u.cpp
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -9,13 +9,26 @@ namespace Service {
namespace CECD {
static const Interface::FunctionInfo FunctionTable[] = {
+ // cecd:u shared commands
+ {0x000100C2, nullptr, "OpenRawFile"},
+ {0x00020042, nullptr, "ReadRawFile"},
+ {0x00030104, nullptr, "ReadMessage"},
+ {0x00040106, nullptr, "ReadMessageWithHMAC"},
+ {0x00050042, nullptr, "WriteRawFile"},
+ {0x00060104, nullptr, "WriteMessage"},
+ {0x00070106, nullptr, "WriteMessageWithHMAC"},
+ {0x00080102, nullptr, "Delete"},
+ {0x000A00C4, nullptr, "GetSystemInfo"},
+ {0x000B0040, nullptr, "RunCommand"},
+ {0x000C0040, nullptr, "RunCommandAlt"},
{0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"},
{0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
{0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"},
- {0x00120104, nullptr, "ReadSavedData"},
+ {0x00110104, nullptr, "OpenAndWrite"},
+ {0x00120104, nullptr, "OpenAndRead"},
};
-CECD_U_Interface::CECD_U_Interface() {
+CECD_U::CECD_U() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cecd/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h
index 394030ffc..16e874ff5 100644
--- a/src/core/hle/service/cecd/cecd_u.h
+++ b/src/core/hle/service/cecd/cecd_u.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CECD {
-class CECD_U_Interface : public Interface {
+class CECD_U : public Interface {
public:
- CECD_U_Interface();
+ CECD_U();
std::string GetPortName() const override {
return "cecd:u";
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 5e340f4c8..0bf59eb76 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -12,6 +12,7 @@
#include "core/hle/result.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_i.h"
+#include "core/hle/service/cfg/cfg_nor.h"
#include "core/hle/service/cfg/cfg_s.h"
#include "core/hle/service/cfg/cfg_u.h"
#include "core/hle/service/fs/archive.h"
@@ -574,9 +575,10 @@ ResultCode LoadConfigNANDSaveFile() {
}
void Init() {
- AddService(new CFG_I_Interface);
- AddService(new CFG_S_Interface);
- AddService(new CFG_U_Interface);
+ AddService(new CFG_I);
+ AddService(new CFG_NOR);
+ AddService(new CFG_S);
+ AddService(new CFG_U);
LoadConfigNANDSaveFile();
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
index 2ff52c8b8..e8db0fc42 100644
--- a/src/core/hle/service/cfg/cfg_i.cpp
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -20,6 +20,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00080080, nullptr, "GoThroughTable"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
+ {0x000B0000, nullptr, "IsFangateSupported"},
// cfg:i
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
@@ -55,7 +56,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08180042, nullptr, "SecureInfoGetSerialNo"},
};
-CFG_I_Interface::CFG_I_Interface() {
+CFG_I::CFG_I() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h
index d0a2cce39..8cfd47633 100644
--- a/src/core/hle/service/cfg/cfg_i.h
+++ b/src/core/hle/service/cfg/cfg_i.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CFG {
-class CFG_I_Interface : public Service::Interface {
+class CFG_I final : public Interface {
public:
- CFG_I_Interface();
+ CFG_I();
std::string GetPortName() const override {
return "cfg:i";
diff --git a/src/core/hle/service/cfg/cfg_nor.cpp b/src/core/hle/service/cfg/cfg_nor.cpp
new file mode 100644
index 000000000..4ce02d115
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg_nor.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/cfg/cfg.h"
+#include "core/hle/service/cfg/cfg_nor.h"
+
+namespace Service {
+namespace CFG {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010040, nullptr, "Initialize"},
+ {0x00020000, nullptr, "Shutdown"},
+ {0x00050082, nullptr, "ReadData"},
+ {0x00060082, nullptr, "WriteData"},
+};
+
+CFG_NOR::CFG_NOR() {
+ Register(FunctionTable);
+}
+
+} // namespace CFG
+} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_nor.h b/src/core/hle/service/cfg/cfg_nor.h
new file mode 100644
index 000000000..c337718e7
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg_nor.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CFG {
+
+class CFG_NOR final : public Interface {
+public:
+ CFG_NOR();
+
+ std::string GetPortName() const override {
+ return "cfg:nor";
+ }
+};
+
+} // namespace CFG
+} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index eed26dec7..9386fe33d 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -20,6 +20,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00080080, nullptr, "GoThroughTable"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
+ {0x000B0000, nullptr, "IsFangateSupported"},
// cfg:s
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
@@ -32,7 +33,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
};
-CFG_S_Interface::CFG_S_Interface() {
+CFG_S::CFG_S() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h
index 5568d6485..99fea46ee 100644
--- a/src/core/hle/service/cfg/cfg_s.h
+++ b/src/core/hle/service/cfg/cfg_s.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CFG {
-class CFG_S_Interface : public Service::Interface {
+class CFG_S final : public Interface {
public:
- CFG_S_Interface();
+ CFG_S();
std::string GetPortName() const override {
return "cfg:s";
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index f28217134..7b66fee22 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -20,9 +20,10 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00080080, nullptr, "GoThroughTable"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
+ {0x000B0000, nullptr, "IsFangateSupported"},
};
-CFG_U_Interface::CFG_U_Interface() {
+CFG_U::CFG_U() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h
index 5303d8ac6..fc7844714 100644
--- a/src/core/hle/service/cfg/cfg_u.h
+++ b/src/core/hle/service/cfg/cfg_u.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CFG {
-class CFG_U_Interface : public Service::Interface {
+class CFG_U final : public Interface {
public:
- CFG_U_Interface();
+ CFG_U();
std::string GetPortName() const override {
return "cfg:u";
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 20c759ad7..6cf62f9bc 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -4,85 +4,137 @@
#include <cstring>
#include "common/alignment.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/csnd_snd.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CSND_SND
+namespace Service {
+namespace CSND {
-namespace CSND_SND {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00010140, Initialize, "Initialize"},
- {0x00020000, Shutdown, "Shutdown"},
- {0x00030040, ExecuteType0Commands, "ExecuteType0Commands"},
- {0x00040080, nullptr, "ExecuteType1Commands"},
- {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"},
- {0x00060000, nullptr, "ReleaseSoundChannels"},
- {0x00070000, nullptr, "AcquireCaptureDevice"},
- {0x00080040, nullptr, "ReleaseCaptureDevice"},
- {0x00090082, nullptr, "FlushDataCache"},
- {0x000A0082, nullptr, "StoreDataCache"},
- {0x000B0082, nullptr, "InvalidateDataCache"},
- {0x000C0000, nullptr, "Reset"},
+struct Type0Command {
+ // command id and next command offset
+ u32 command_id;
+ u32 finished;
+ u32 flags;
+ u8 parameters[20];
};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
+static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong");
static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr;
static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
-void Initialize(Service::Interface* self) {
+/**
+ * CSND_SND::Initialize service function
+ * Inputs:
+ * 0 : Header Code[0x00010140]
+ * 1 : Shared memory block size, for mem-block creation
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Handle-list header
+ * 3 : Mutex handle
+ * 4 : Shared memory block handle
+ */
+static void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
+
using Kernel::MemoryPermission;
shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite,
MemoryPermission::ReadWrite, 0,
Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
- mutex = Kernel::Mutex::Create(false);
+ mutex = Kernel::Mutex::Create(false, "CSND:mutex");
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = IPC::CopyHandleDesc(2);
cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
+
+ LOG_WARNING(Service_CSND, "(STUBBED) called");
}
-void ExecuteType0Commands(Service::Interface* self) {
- u32* const cmd_buff = Kernel::GetCommandBuffer();
- u8* const ptr = shared_memory->GetPointer(cmd_buff[1]);
+/**
+ * CSND_SND::Shutdown service function
+ * Inputs:
+ * 0 : Header Code[0x00020000]
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void Shutdown(Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
- if (shared_memory != nullptr && ptr != nullptr) {
- Type0Command command;
- std::memcpy(&command, ptr, sizeof(Type0Command));
+ shared_memory = nullptr;
+ mutex = nullptr;
- LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands");
- command.finished |= 1;
- cmd_buff[1] = 0;
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ LOG_WARNING(Service_CSND, "(STUBBED) called");
+}
- std::memcpy(ptr, &command, sizeof(Type0Command));
- } else {
+/**
+ * CSND_SND::ExecuteCommands service function
+ * Inputs:
+ * 0 : Header Code[0x00030040]
+ * 1 : Command offset in shared memory.
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Available channel bit mask
+ */
+static void ExecuteCommands(Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ if (shared_memory == nullptr) {
cmd_buff[1] = 1;
+ LOG_ERROR(Service_CSND, "called, shared memory not allocated");
+ return;
}
+
+ VAddr addr = cmd_buff[1];
+ u8* ptr = shared_memory->GetPointer(addr);
+
+ Type0Command command;
+ std::memcpy(&command, ptr, sizeof(Type0Command));
+ command.finished |= 1;
+ std::memcpy(ptr, &command, sizeof(Type0Command));
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CSND, "(STUBBED) called, addr=0x%08X", addr);
}
-void AcquireSoundChannels(Service::Interface* self) {
+/**
+ * CSND_SND::AcquireSoundChannels service function
+ * Inputs:
+ * 0 : Header Code[0x00050000]
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Available channel bit mask
+ */
+static void AcquireSoundChannels(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- cmd_buff[1] = 0;
+ cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0xFFFFFF00;
+ LOG_WARNING(Service_CSND, "(STUBBED) called");
}
-void Shutdown(Service::Interface* self) {
- shared_memory = nullptr;
- mutex = nullptr;
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010140, Initialize, "Initialize"},
+ {0x00020000, Shutdown, "Shutdown"},
+ {0x00030040, ExecuteCommands, "ExecuteCommands"},
+ {0x00040080, nullptr, "ExecuteType1Commands"},
+ {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"},
+ {0x00060000, nullptr, "ReleaseSoundChannels"},
+ {0x00070000, nullptr, "AcquireCaptureDevice"},
+ {0x00080040, nullptr, "ReleaseCaptureDevice"},
+ {0x00090082, nullptr, "FlushDataCache"},
+ {0x000A0082, nullptr, "StoreDataCache"},
+ {0x000B0082, nullptr, "InvalidateDataCache"},
+ {0x000C0000, nullptr, "Reset"},
+};
+
+CSND_SND::CSND_SND() {
+ Register(FunctionTable);
}
-} // namespace
+} // namespace CSND
+} // namespace Service
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h
index a146d116b..ca6d4513e 100644
--- a/src/core/hle/service/csnd_snd.h
+++ b/src/core/hle/service/csnd_snd.h
@@ -6,31 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CSND_SND
+namespace Service {
+namespace CSND {
-namespace CSND_SND {
-
-class Interface : public Service::Interface {
+class CSND_SND final : public Interface {
public:
- Interface();
+ CSND_SND();
std::string GetPortName() const override {
return "csnd:SND";
}
};
-struct Type0Command {
- // command id and next command offset
- u32 command_id;
- u32 finished;
- u32 flags;
- u8 parameters[20];
-};
-
-void Initialize(Service::Interface* self);
-void ExecuteType0Commands(Service::Interface* self);
-void AcquireSoundChannels(Service::Interface* self);
-void Shutdown(Service::Interface* self);
-
-} // namespace
+} // namespace CSND
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h
index ec2fe46e8..3185fe322 100644
--- a/src/core/hle/service/dlp/dlp.h
+++ b/src/core/hle/service/dlp/dlp.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
namespace Service {
namespace DLP {
diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp
index 49d5b8d1c..25c07f401 100644
--- a/src/core/hle/service/dlp/dlp_srvr.cpp
+++ b/src/core/hle/service/dlp/dlp_srvr.cpp
@@ -22,7 +22,14 @@ static void unk_0x000E0040(Interface* self) {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010183, nullptr, "Initialize"},
{0x00020000, nullptr, "Finalize"},
+ {0x00030000, nullptr, "GetServerState"},
+ {0x00050080, nullptr, "StartAccepting"},
+ {0x00070000, nullptr, "StartDistribution"},
{0x000800C0, nullptr, "SendWirelessRebootPassphrase"},
+ {0x00090040, nullptr, "AcceptClient"},
+ {0x000B0042, nullptr, "GetConnectingClients"},
+ {0x000C0040, nullptr, "GetClientInfo"},
+ {0x000D0040, nullptr, "GetClientState"},
{0x000E0040, unk_0x000E0040, "unk_0x000E0040"},
};
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index a15aa3696..fe8a6c2d6 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -12,9 +12,7 @@
using DspPipe = DSP::HLE::DspPipe;
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace DSP_DSP
-
+namespace Service {
namespace DSP_DSP {
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
@@ -582,4 +580,5 @@ Interface::~Interface() {
interrupt_events = {};
}
-} // namespace
+} // namespace DSP_DSP
+} // namespace Service
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index 3e97da6eb..691d6f716 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -13,12 +13,10 @@ enum class DspPipe;
}
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace DSP_DSP
-
+namespace Service {
namespace DSP_DSP {
-class Interface : public Service::Interface {
+class Interface final : public Service::Interface {
public:
Interface();
~Interface() override;
@@ -35,3 +33,4 @@ public:
void SignalPipeInterrupt(DSP::HLE::DspPipe pipe);
} // namespace DSP_DSP
+} // namespace Service
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 9905757c7..cd0a1a598 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -13,10 +13,8 @@
#include "core/hle/result.h"
#include "core/hle/service/err_f.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ERR_F
-
-namespace ERR_F {
+namespace Service {
+namespace ERR {
enum class FatalErrType : u32 {
Generic = 0,
@@ -167,7 +165,7 @@ static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) {
* 0 : Header code
* 1 : Result code
*/
-static void ThrowFatalError(Service::Interface* self) {
+static void ThrowFatalError(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
LOG_CRITICAL(Service_ERR, "Fatal error");
@@ -256,11 +254,9 @@ const Interface::FunctionInfo FunctionTable[] = {
// clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+ERR_F::ERR_F() {
Register(FunctionTable);
}
-} // namespace
+} // namespace ERR
+} // namespace Service
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index 892d8af9b..5b27fc871 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ERR_F
+namespace Service {
+namespace ERR {
-namespace ERR_F {
-
-class Interface : public Service::Interface {
+class ERR_F final : public Interface {
public:
- Interface();
+ ERR_F();
std::string GetPortName() const override {
return "err:f";
}
};
-} // namespace
+} // namespace ERR
+} // namespace Service
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index bef75f5df..6cddc1fdb 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -23,7 +23,7 @@
#include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
-#include "core/hle/hle.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
@@ -45,9 +45,7 @@ struct hash<Service::FS::ArchiveIdCode> {
};
}
-/// TODO(Subv): Confirm length of these strings
-const std::string SYSTEM_ID = "00000000000000000000000000000000";
-const std::string SDCARD_ID = "00000000000000000000000000000000";
+static constexpr Kernel::Handle INVALID_HANDLE{};
namespace Service {
namespace FS {
@@ -93,7 +91,7 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path&
File::~File() {}
-ResultVal<bool> File::SyncRequest() {
+void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
u32* cmd_buff = Kernel::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
switch (cmd) {
@@ -103,8 +101,8 @@ ResultVal<bool> File::SyncRequest() {
u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
u32 length = cmd_buff[3];
u32 address = cmd_buff[5];
- LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
- GetTypeName().c_str(), GetName().c_str(), offset, length, address);
+ LOG_TRACE(Service_FS, "Read %s: offset=0x%llx length=%d address=0x%x", GetName().c_str(),
+ offset, length, address);
if (offset + length > backend->GetSize()) {
LOG_ERROR(Service_FS,
@@ -116,7 +114,7 @@ ResultVal<bool> File::SyncRequest() {
ResultVal<size_t> read = backend->Read(offset, data.size(), data.data());
if (read.Failed()) {
cmd_buff[1] = read.Code().raw;
- return read.Code();
+ return;
}
Memory::WriteBlock(address, data.data(), *read);
cmd_buff[2] = static_cast<u32>(*read);
@@ -129,22 +127,22 @@ ResultVal<bool> File::SyncRequest() {
u32 length = cmd_buff[3];
u32 flush = cmd_buff[4];
u32 address = cmd_buff[6];
- LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
- GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
+ LOG_TRACE(Service_FS, "Write %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
+ GetName().c_str(), offset, length, address, flush);
std::vector<u8> data(length);
Memory::ReadBlock(address, data.data(), data.size());
ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
if (written.Failed()) {
cmd_buff[1] = written.Code().raw;
- return written.Code();
+ return;
}
cmd_buff[2] = static_cast<u32>(*written);
break;
}
case FileCommand::GetSize: {
- LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
+ LOG_TRACE(Service_FS, "GetSize %s", GetName().c_str());
u64 size = backend->GetSize();
cmd_buff[2] = (u32)size;
cmd_buff[3] = size >> 32;
@@ -153,14 +151,13 @@ ResultVal<bool> File::SyncRequest() {
case FileCommand::SetSize: {
u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
- LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(),
- size);
+ LOG_TRACE(Service_FS, "SetSize %s size=%llu", GetName().c_str(), size);
backend->SetSize(size);
break;
}
case FileCommand::Close: {
- LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ LOG_TRACE(Service_FS, "Close %s", GetName().c_str());
backend->Close();
break;
}
@@ -173,7 +170,11 @@ ResultVal<bool> File::SyncRequest() {
case FileCommand::OpenLinkFile: {
LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
- cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE);
+ auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this());
+ ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .ValueOr(INVALID_HANDLE);
break;
}
@@ -194,10 +195,9 @@ ResultVal<bool> File::SyncRequest() {
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
ResultCode error = UnimplementedFunction(ErrorModule::FS);
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
- return error;
+ return;
}
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- return MakeResult<bool>(false);
}
Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
@@ -206,18 +206,16 @@ Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
Directory::~Directory() {}
-ResultVal<bool> Directory::SyncRequest() {
+void Directory::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
u32* cmd_buff = Kernel::GetCommandBuffer();
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
switch (cmd) {
-
// Read from directory...
case DirectoryCommand::Read: {
u32 count = cmd_buff[1];
u32 address = cmd_buff[3];
std::vector<FileSys::Entry> entries(count);
- LOG_TRACE(Service_FS, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(),
- count);
+ LOG_TRACE(Service_FS, "Read %s: count=%d", GetName().c_str(), count);
// Number of entries actually read
u32 read = backend->Read(entries.size(), entries.data());
@@ -227,7 +225,7 @@ ResultVal<bool> Directory::SyncRequest() {
}
case DirectoryCommand::Close: {
- LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ LOG_TRACE(Service_FS, "Close %s", GetName().c_str());
backend->Close();
break;
}
@@ -237,10 +235,9 @@ ResultVal<bool> Directory::SyncRequest() {
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
ResultCode error = UnimplementedFunction(ErrorModule::FS);
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
- return MakeResult<bool>(false);
+ return;
}
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- return MakeResult<bool>(false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -307,9 +304,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
return RESULT_SUCCESS;
}
-ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path,
- const FileSys::Mode mode) {
+ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path,
+ const FileSys::Mode mode) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr)
return ERR_INVALID_ARCHIVE_HANDLE;
@@ -318,8 +315,8 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han
if (backend.Failed())
return backend.Code();
- auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path));
- return MakeResult<Kernel::SharedPtr<File>>(std::move(file));
+ auto file = std::shared_ptr<File>(new File(backend.MoveFrom(), path));
+ return MakeResult<std::shared_ptr<File>>(std::move(file));
}
ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
@@ -398,8 +395,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
}
}
-ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path) {
+ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr)
return ERR_INVALID_ARCHIVE_HANDLE;
@@ -408,8 +405,8 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a
if (backend.Failed())
return backend.Code();
- auto directory = Kernel::SharedPtr<Directory>(new Directory(backend.MoveFrom(), path));
- return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory));
+ auto directory = std::shared_ptr<Directory>(new Directory(backend.MoveFrom(), path));
+ return MakeResult<std::shared_ptr<Directory>>(std::move(directory));
}
ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 87089bd92..519c1f3a9 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -8,7 +8,7 @@
#include <string>
#include "common/common_types.h"
#include "core/file_sys/archive_backend.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/result.h"
namespace FileSys {
@@ -17,9 +17,9 @@ class FileBackend;
}
/// The unique system identifier hash, also known as ID0
-extern const std::string SYSTEM_ID;
+static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"};
/// The scrambled SD card CID, also known as ID1
-extern const std::string SDCARD_ID;
+static constexpr char SDCARD_ID[]{"00000000000000000000000000000000"};
namespace Service {
namespace FS {
@@ -43,33 +43,37 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
typedef u64 ArchiveHandle;
-class File : public Kernel::Session {
+class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> {
public:
File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
~File();
- std::string GetName() const override {
+ std::string GetName() const {
return "Path: " + path.DebugStr();
}
- ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the file
u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
+
+protected:
+ void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
};
-class Directory : public Kernel::Session {
+class Directory final : public SessionRequestHandler {
public:
Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
~Directory();
- std::string GetName() const override {
+ std::string GetName() const {
return "Directory: " + path.DebugStr();
}
- ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the directory
std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
+
+protected:
+ void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
};
/**
@@ -99,11 +103,11 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
* @param archive_handle Handle to an open Archive object
* @param path Path to the File inside of the Archive
* @param mode Mode under which to open the File
- * @return The opened File object as a Session
+ * @return The opened File object
*/
-ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path,
- const FileSys::Mode mode);
+ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path,
+ const FileSys::Mode mode);
/**
* Delete a File from an Archive
@@ -178,10 +182,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
* Open a Directory from an Archive
* @param archive_handle Handle to an open Archive object
* @param path Path to the Directory inside of the Archive
- * @return The opened Directory object as a Session
+ * @return The opened Directory object
*/
-ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path);
+ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path);
/**
* Get the free space in an Archive
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 9ec17b395..337da1387 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -8,6 +8,7 @@
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
@@ -17,7 +18,7 @@
// Namespace FS_User
using Kernel::SharedPtr;
-using Kernel::Session;
+using Kernel::ServerSession;
namespace Service {
namespace FS {
@@ -67,10 +68,16 @@ static void OpenFile(Service::Interface* self) {
LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex,
attributes);
- ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode);
+ ResultVal<std::shared_ptr<File>> file_res =
+ OpenFileFromArchive(archive_handle, file_path, mode);
cmd_buff[1] = file_res.Code().raw;
if (file_res.Succeeded()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
+ std::shared_ptr<File> file = *file_res;
+ auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
+ file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .MoveFrom();
} else {
cmd_buff[3] = 0;
LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
@@ -127,10 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) {
}
SCOPE_EXIT({ CloseArchive(*archive_handle); });
- ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode);
+ ResultVal<std::shared_ptr<File>> file_res =
+ OpenFileFromArchive(*archive_handle, file_path, mode);
cmd_buff[1] = file_res.Code().raw;
if (file_res.Succeeded()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
+ std::shared_ptr<File> file = *file_res;
+ auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
+ file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .MoveFrom();
} else {
cmd_buff[3] = 0;
LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u",
@@ -388,10 +401,16 @@ static void OpenDirectory(Service::Interface* self) {
LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size,
dir_path.DebugStr().c_str());
- ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path);
+ ResultVal<std::shared_ptr<Directory>> dir_res =
+ OpenDirectoryFromArchive(archive_handle, dir_path);
cmd_buff[1] = dir_res.Code().raw;
if (dir_res.Succeeded()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
+ std::shared_ptr<Directory> directory = *dir_res;
+ auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory);
+ directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .MoveFrom();
} else {
LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
dirname_type, dirname_size, dir_path.DebugStr().c_str());
@@ -1003,6 +1022,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08680000, nullptr, "GetMediaType"},
{0x08690000, nullptr, "GetNandEraseCount"},
{0x086A0082, nullptr, "ReadNandReport"},
+ {0x087A0180, nullptr, "AddSeed"},
+ {0x088600C0, nullptr, "CheckUpdatedDat"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 78cb761be..947958703 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -18,13 +18,11 @@
// Main graphics debugger object - TODO: Here is probably not the best place for this
GraphicsDebugger g_debugger;
-// Beginning address of HW regs
-const static u32 REGS_BEGIN = 0x1EB00000;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_GPU
+namespace Service {
+namespace GSP {
-namespace GSP_GPU {
+// Beginning address of HW regs
+const u32 REGS_BEGIN = 0x1EB00000;
const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(
ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX, ErrorSummary::InvalidArgument,
@@ -179,7 +177,7 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr
* 2 : number of registers to write sequentially
* 4 : pointer to source data array
*/
-static void WriteHWRegs(Service::Interface* self) {
+static void WriteHWRegs(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -199,7 +197,7 @@ static void WriteHWRegs(Service::Interface* self) {
* 4 : pointer to source data array
* 6 : pointer to mask array
*/
-static void WriteHWRegsWithMask(Service::Interface* self) {
+static void WriteHWRegsWithMask(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -211,7 +209,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
}
/// Read a GSP GPU hardware register
-static void ReadHWRegs(Service::Interface* self) {
+static void ReadHWRegs(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -298,7 +296,7 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
* Outputs:
* 1: Result code
*/
-static void SetBufferSwap(Service::Interface* self) {
+static void SetBufferSwap(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 screen_id = cmd_buff[1];
FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
@@ -319,7 +317,7 @@ static void SetBufferSwap(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void FlushDataCache(Service::Interface* self) {
+static void FlushDataCache(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 address = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -340,7 +338,7 @@ static void FlushDataCache(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetAxiConfigQoSMode(Service::Interface* self) {
+static void SetAxiConfigQoSMode(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 mode = cmd_buff[1];
@@ -359,7 +357,7 @@ static void SetAxiConfigQoSMode(Service::Interface* self) {
* 2 : Thread index into GSP command buffer
* 4 : Handle to GSP shared memory
*/
-static void RegisterInterruptRelayQueue(Service::Interface* self) {
+static void RegisterInterruptRelayQueue(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 flags = cmd_buff[1];
@@ -391,7 +389,7 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnregisterInterruptRelayQueue(Service::Interface* self) {
+static void UnregisterInterruptRelayQueue(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
g_thread_id = 0;
@@ -592,7 +590,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
* Outputs:
* 1: Result code
*/
-static void SetLcdForceBlack(Service::Interface* self) {
+static void SetLcdForceBlack(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
bool enable_black = cmd_buff[1] != 0;
@@ -609,7 +607,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
}
/// This triggers handling of the GX command written to the command buffer in shared memory.
-static void TriggerCmdReqQueue(Service::Interface* self) {
+static void TriggerCmdReqQueue(Interface* self) {
// Iterate through each thread's command queue...
for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) {
CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id);
@@ -638,6 +636,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
* Inputs:
* 0: Header 0x00180000
* Outputs:
+ * 0: Header Code[0x00180240]
* 1: Result code
* 2: Left framebuffer virtual address for the main screen
* 3: Right framebuffer virtual address for the main screen
@@ -648,7 +647,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
* 8: Bottom screen framebuffer format
* 9: Bottom screen framebuffer width
*/
-static void ImportDisplayCaptureInfo(Service::Interface* self) {
+static void ImportDisplayCaptureInfo(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
@@ -660,18 +659,19 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) {
FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0);
FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1);
+ cmd_buff[0] = IPC::MakeHeader(0x18, 0x9, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ // Top Screen
cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left;
cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right;
cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format;
cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride;
-
+ // Bottom Screen
cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left;
cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right;
cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format;
cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride;
- cmd_buff[1] = RESULT_SUCCESS.raw;
-
LOG_WARNING(Service_GSP, "called");
}
@@ -680,7 +680,7 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) {
* Outputs:
* 1: Result code
*/
-static void AcquireRight(Service::Interface* self) {
+static void AcquireRight(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
gpu_right_acquired = true;
@@ -695,7 +695,7 @@ static void AcquireRight(Service::Interface* self) {
* Outputs:
* 1: Result code
*/
-static void ReleaseRight(Service::Interface* self) {
+static void ReleaseRight(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
gpu_right_acquired = false;
@@ -739,10 +739,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x001F0082, nullptr, "StoreDataCache"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+GSP_GPU::GSP_GPU() {
Register(FunctionTable);
g_interrupt_event = nullptr;
@@ -757,10 +754,11 @@ Interface::Interface() {
first_initialization = true;
}
-Interface::~Interface() {
+GSP_GPU::~GSP_GPU() {
g_interrupt_event = nullptr;
g_shared_memory = nullptr;
gpu_right_acquired = false;
}
-} // namespace
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 79a72f77d..c6e24073b 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -11,10 +11,8 @@
#include "core/hle/result.h"
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_GPU
-
-namespace GSP_GPU {
+namespace Service {
+namespace GSP {
/// GSP interrupt ID
enum class InterruptId : u8 {
@@ -176,11 +174,10 @@ struct CommandBuffer {
};
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
-/// Interface to "srv:" service
-class Interface : public Service::Interface {
+class GSP_GPU final : public Interface {
public:
- Interface();
- ~Interface() override;
+ GSP_GPU();
+ ~GSP_GPU() override;
std::string GetPortName() const override {
return "gsp::Gpu";
@@ -203,4 +200,6 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
* @returns FramebufferUpdate Information about the specified framebuffer.
*/
FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
-} // namespace
+
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_lcd.cpp b/src/core/hle/service/gsp_lcd.cpp
index b916dd759..89cb4a3cc 100644
--- a/src/core/hle/service/gsp_lcd.cpp
+++ b/src/core/hle/service/gsp_lcd.cpp
@@ -4,26 +4,26 @@
#include "core/hle/service/gsp_lcd.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_LCD
-
-namespace GSP_LCD {
+namespace Service {
+namespace GSP {
const Interface::FunctionInfo FunctionTable[] = {
// clang-format off
+ {0x000A0080, nullptr, "SetBrightnessRaw"},
+ {0x000B0080, nullptr, "SetBrightness"},
{0x000F0000, nullptr, "PowerOnAllBacklights"},
{0x00100000, nullptr, "PowerOffAllBacklights"},
{0x00110040, nullptr, "PowerOnBacklight"},
{0x00120040, nullptr, "PowerOffBacklight"},
{0x00130040, nullptr, "SetLedForceOff"},
+ {0x00140000, nullptr, "GetVendor"},
+ {0x00150040, nullptr, "GetBrightness"},
// clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+GSP_LCD::GSP_LCD() {
Register(FunctionTable);
}
-} // namespace
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_lcd.h b/src/core/hle/service/gsp_lcd.h
index 56b3cfe86..e9686a5e7 100644
--- a/src/core/hle/service/gsp_lcd.h
+++ b/src/core/hle/service/gsp_lcd.h
@@ -6,19 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_LCD
+namespace Service {
+namespace GSP {
-namespace GSP_LCD {
-
-/// Interface to "gsp::Lcd" service
-class Interface : public Service::Interface {
+class GSP_LCD final : public Interface {
public:
- Interface();
+ GSP_LCD();
std::string GetPortName() const override {
return "gsp::Lcd";
}
};
-} // namespace
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 99baded11..676154bd4 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -3,9 +3,9 @@
// Refer to the license.txt file included.
#include <cmath>
-#include "common/emu_window.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
+#include "core/frontend/emu_window.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/hid.h"
@@ -37,7 +37,8 @@ static int enable_gyroscope_count = 0; // positive means enabled
static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
// 30 degree and 60 degree are angular thresholds for directions
- constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30;
+ constexpr float TAN30 = 0.577350269f;
+ constexpr float TAN60 = 1 / TAN30;
// a circle pad radius greater than 40 will trigger circle pad direction
constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40;
PadState state;
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
index 3cf62a4b8..b01d6e031 100644
--- a/src/core/hle/service/http_c.cpp
+++ b/src/core/hle/service/http_c.cpp
@@ -4,10 +4,8 @@
#include "core/hle/service/http_c.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace HTTP_C
-
-namespace HTTP_C {
+namespace Service {
+namespace HTTP {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010044, nullptr, "Initialize"},
@@ -55,6 +53,10 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002E0040, nullptr, "DestroyRootCertChain"},
{0x002F0082, nullptr, "RootCertChainAddCert"},
{0x00300080, nullptr, "RootCertChainAddDefaultCert"},
+ {0x00310080, nullptr, "RootCertChainRemoveCert"},
+ {0x00320084, nullptr, "OpenClientCertContext"},
+ {0x00330040, nullptr, "OpenDefaultClientCertContext"},
+ {0x00340040, nullptr, "CloseClientCertContext"},
{0x00350186, nullptr, "SetDefaultProxy"},
{0x00360000, nullptr, "ClearDNSCache"},
{0x00370080, nullptr, "SetKeepAlive"},
@@ -62,11 +64,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00390000, nullptr, "Finalize"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+HTTP_C::HTTP_C() {
Register(FunctionTable);
}
-} // namespace
+} // namespace HTTP
+} // namespace Service
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
index 5ea3d1df3..cff279c02 100644
--- a/src/core/hle/service/http_c.h
+++ b/src/core/hle/service/http_c.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace HTTP_C
+namespace Service {
+namespace HTTP {
-namespace HTTP_C {
-
-class Interface : public Service::Interface {
+class HTTP_C final : public Interface {
public:
- Interface();
+ HTTP_C();
std::string GetPortName() const override {
return "http:C";
}
};
-} // namespace
+} // namespace HTTP
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
index 4d6639ded..7f1731a50 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/ir/ir.h"
#include "core/hle/service/ir/ir_rst.h"
@@ -36,7 +37,7 @@ void InitializeIrNopShared(Interface* self) {
u32 send_buff_size = cmd_buff[4];
u32 unk2 = cmd_buff[5];
u8 baud_rate = cmd_buff[6] & 0xFF;
- Handle handle = cmd_buff[8];
+ Kernel::Handle handle = cmd_buff[8];
if (Kernel::g_handle_table.IsValid(handle)) {
transfer_shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle);
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp
index 4f0aa77eb..f78545f37 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.cpp
+++ b/src/core/hle/service/ldr_ro/cro_helper.cpp
@@ -7,10 +7,8 @@
#include "common/scope_exit.h"
#include "core/hle/service/ldr_ro/cro_helper.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F
ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument,
@@ -1493,4 +1491,5 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
return std::make_tuple(0, 0);
}
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h
index 6a0d0d3bf..060d5a55f 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.h
+++ b/src/core/hle/service/ldr_ro/cro_helper.h
@@ -11,10 +11,8 @@
#include "core/hle/result.h"
#include "core/memory.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
// GCC versions < 5.0 do not implement std::is_trivially_copyable.
// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
@@ -710,4 +708,5 @@ private:
ResultCode ApplyExitRelocations(VAddr crs_address);
};
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp
index ec183d1f5..8d00a7577 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp
@@ -12,10 +12,8 @@
#include "core/hle/service/ldr_ro/ldr_ro.h"
#include "core/hle/service/ldr_ro/memory_synchronizer.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9
ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal,
@@ -71,7 +69,7 @@ static bool VerifyBufferState(VAddr buffer_ptr, u32 size) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void Initialize(Service::Interface* self) {
+static void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr crs_buffer_ptr = cmd_buff[1];
u32 crs_size = cmd_buff[2];
@@ -196,7 +194,7 @@ static void Initialize(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void LoadCRR(Service::Interface* self) {
+static void LoadCRR(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 crr_buffer_ptr = cmd_buff[1];
u32 crr_size = cmd_buff[2];
@@ -229,7 +227,7 @@ static void LoadCRR(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnloadCRR(Service::Interface* self) {
+static void UnloadCRR(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 crr_buffer_ptr = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -276,7 +274,7 @@ static void UnloadCRR(Service::Interface* self) {
* unified one of two, with an additional parameter link_on_load_bug_fix.
* There is a dispatcher template below.
*/
-static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
+static void LoadCRO(Interface* self, bool link_on_load_bug_fix) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_buffer_ptr = cmd_buff[1];
VAddr cro_address = cmd_buff[2];
@@ -459,7 +457,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
}
}
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", cro.ModuleName().data(),
cro_address, cro_address + fix_size);
@@ -469,7 +467,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
}
template <bool link_on_load_bug_fix>
-static void LoadCRO(Service::Interface* self) {
+static void LoadCRO(Interface* self) {
LoadCRO(self, link_on_load_bug_fix);
}
@@ -486,7 +484,7 @@ static void LoadCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnloadCRO(Service::Interface* self) {
+static void UnloadCRO(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_address = cmd_buff[1];
u32 zero = cmd_buff[2];
@@ -564,7 +562,7 @@ static void UnloadCRO(Service::Interface* self) {
memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr);
}
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
cmd_buff[1] = result.raw;
}
@@ -580,7 +578,7 @@ static void UnloadCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void LinkCRO(Service::Interface* self) {
+static void LinkCRO(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_address = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -626,7 +624,7 @@ static void LinkCRO(Service::Interface* self) {
}
memory_synchronizer.SynchronizeOriginalMemory();
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
cmd_buff[1] = result.raw;
}
@@ -642,7 +640,7 @@ static void LinkCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnlinkCRO(Service::Interface* self) {
+static void UnlinkCRO(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_address = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -688,7 +686,7 @@ static void UnlinkCRO(Service::Interface* self) {
}
memory_synchronizer.SynchronizeOriginalMemory();
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
cmd_buff[1] = result.raw;
}
@@ -704,7 +702,7 @@ static void UnlinkCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void Shutdown(Service::Interface* self) {
+static void Shutdown(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr crs_buffer_ptr = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -762,14 +760,12 @@ const Interface::FunctionInfo FunctionTable[] = {
// clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+LDR_RO::LDR_RO() {
Register(FunctionTable);
loaded_crs = 0;
memory_synchronizer.Clear();
}
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h
index 331637cde..0f6fe7b60 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.h
+++ b/src/core/hle/service/ldr_ro/ldr_ro.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
+namespace Service {
+namespace LDR {
-namespace LDR_RO {
-
-class Interface : public Service::Interface {
+class LDR_RO final : public Interface {
public:
- Interface();
+ LDR_RO();
std::string GetPortName() const override {
return "ldr:ro";
}
};
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
index 989887264..0d44bf6bd 100644
--- a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
+++ b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
@@ -6,10 +6,8 @@
#include "common/assert.h"
#include "core/hle/service/ldr_ro/memory_synchronizer.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) {
auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(),
@@ -40,4 +38,5 @@ void MemorySynchronizer::SynchronizeOriginalMemory() {
}
}
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h
index 883ee4acf..438293a58 100644
--- a/src/core/hle/service/ldr_ro/memory_synchronizer.h
+++ b/src/core/hle/service/ldr_ro/memory_synchronizer.h
@@ -7,10 +7,8 @@
#include <vector>
#include "core/memory.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
/**
* This is a work-around before we implement memory aliasing.
@@ -40,4 +38,5 @@ private:
auto FindMemoryBlock(VAddr mapping, VAddr original);
};
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 1f851d328..4f1dd2fce 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -4,13 +4,12 @@
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/mic_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace MIC_U
-
-namespace MIC_U {
+namespace Service {
+namespace MIC {
enum class Encoding : u8 {
PCM8 = 0,
@@ -49,10 +48,10 @@ static bool audio_buffer_loop;
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void MapSharedMem(Service::Interface* self) {
+static void MapSharedMem(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
- Handle mem_handle = cmd_buff[3];
+ Kernel::Handle mem_handle = cmd_buff[3];
shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(mem_handle);
if (shared_memory) {
shared_memory->name = "MIC_U:shared_memory";
@@ -68,7 +67,7 @@ static void MapSharedMem(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnmapSharedMem(Service::Interface* self) {
+static void UnmapSharedMem(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -87,7 +86,7 @@ static void UnmapSharedMem(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void StartSampling(Service::Interface* self) {
+static void StartSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
encoding = static_cast<Encoding>(cmd_buff[1] & 0xFF);
@@ -111,7 +110,7 @@ static void StartSampling(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void AdjustSampling(Service::Interface* self) {
+static void AdjustSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
sample_rate = static_cast<SampleRate>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -125,7 +124,7 @@ static void AdjustSampling(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void StopSampling(Service::Interface* self) {
+static void StopSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
is_sampling = false;
@@ -140,7 +139,7 @@ static void StopSampling(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : 0 = sampling, non-zero = sampling
*/
-static void IsSampling(Service::Interface* self) {
+static void IsSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = is_sampling;
@@ -155,7 +154,7 @@ static void IsSampling(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 3 : Event handle
*/
-static void GetBufferFullEvent(Service::Interface* self) {
+static void GetBufferFullEvent(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[3] = Kernel::g_handle_table.Create(buffer_full_event).MoveFrom();
@@ -170,7 +169,7 @@ static void GetBufferFullEvent(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetGain(Service::Interface* self) {
+static void SetGain(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
mic_gain = cmd_buff[1] & 0xFF;
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -185,7 +184,7 @@ static void SetGain(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Gain
*/
-static void GetGain(Service::Interface* self) {
+static void GetGain(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = mic_gain;
@@ -200,7 +199,7 @@ static void GetGain(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetPower(Service::Interface* self) {
+static void SetPower(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
mic_power = static_cast<bool>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -215,7 +214,7 @@ static void SetPower(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Power
*/
-static void GetPower(Service::Interface* self) {
+static void GetPower(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = mic_power;
@@ -232,7 +231,7 @@ static void GetPower(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetIirFilterMic(Service::Interface* self) {
+static void SetIirFilterMic(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
@@ -250,7 +249,7 @@ static void SetIirFilterMic(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetClamp(Service::Interface* self) {
+static void SetClamp(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
clamp = static_cast<bool>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -265,7 +264,7 @@ static void SetClamp(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Clamp (0 = don't clamp, non-zero = clamp)
*/
-static void GetClamp(Service::Interface* self) {
+static void GetClamp(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = clamp;
@@ -280,7 +279,7 @@ static void GetClamp(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetAllowShellClosed(Service::Interface* self) {
+static void SetAllowShellClosed(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
allow_shell_closed = static_cast<bool>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -294,7 +293,7 @@ static void SetAllowShellClosed(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetClientVersion(Service::Interface* self) {
+static void SetClientVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
const u32 version = cmd_buff[1];
@@ -324,10 +323,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00100040, SetClientVersion, "SetClientVersion"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+MIC_U::MIC_U() {
Register(FunctionTable);
shared_memory = nullptr;
buffer_full_event =
@@ -338,9 +334,10 @@ Interface::Interface() {
clamp = false;
}
-Interface::~Interface() {
+MIC_U::~MIC_U() {
shared_memory = nullptr;
buffer_full_event = nullptr;
}
-} // namespace
+} // namespace MIC
+} // namespace Service
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
index 1cff7390e..ec2b67ab8 100644
--- a/src/core/hle/service/mic_u.h
+++ b/src/core/hle/service/mic_u.h
@@ -6,21 +6,18 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace MIC_U
+namespace Service {
+namespace MIC {
-// mic service
-
-namespace MIC_U {
-
-class Interface : public Service::Interface {
+class MIC_U final : public Interface {
public:
- Interface();
- ~Interface();
+ MIC_U();
+ ~MIC_U();
std::string GetPortName() const override {
return "mic:u";
}
};
-} // namespace
+} // namespace MIC
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd.cpp b/src/core/hle/service/mvd/mvd.cpp
new file mode 100644
index 000000000..9416fe5d6
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd.cpp
@@ -0,0 +1,17 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/mvd/mvd.h"
+#include "core/hle/service/mvd/mvd_std.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace MVD {
+
+void Init() {
+ AddService(new MVD_STD());
+}
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd.h b/src/core/hle/service/mvd/mvd.h
new file mode 100644
index 000000000..7b212e839
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace MVD {
+
+/// Initializes all MVD services.
+void Init();
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd_std.cpp b/src/core/hle/service/mvd/mvd_std.cpp
new file mode 100644
index 000000000..fd7ca87d3
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd_std.cpp
@@ -0,0 +1,32 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/mvd/mvd_std.h"
+
+namespace Service {
+namespace MVD {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ {0x00010082, nullptr, "Initialize"},
+ {0x00020000, nullptr, "Shutdown"},
+ {0x00030300, nullptr, "CalculateWorkBufSize"},
+ {0x000400C0, nullptr, "CalculateImageSize"},
+ {0x00080142, nullptr, "ProcessNALUnit"},
+ {0x00090042, nullptr, "ControlFrameRendering"},
+ {0x000A0000, nullptr, "GetStatus"},
+ {0x000B0000, nullptr, "GetStatusOther"},
+ {0x001D0042, nullptr, "GetConfig"},
+ {0x001E0044, nullptr, "SetConfig"},
+ {0x001F0902, nullptr, "SetOutputBuffer"},
+ {0x00210100, nullptr, "OverrideOutputBuffers"}
+ // clang-format on
+};
+
+MVD_STD::MVD_STD() {
+ Register(FunctionTable);
+}
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd_std.h b/src/core/hle/service/mvd/mvd_std.h
new file mode 100644
index 000000000..7db9e2e50
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd_std.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace MVD {
+
+class MVD_STD final : public Interface {
+public:
+ MVD_STD();
+
+ std::string GetPortName() const override {
+ return "mvd:std";
+ }
+};
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
new file mode 100644
index 000000000..d9738c6a1
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -0,0 +1,18 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfc/nfc.h"
+#include "core/hle/service/nfc/nfc_m.h"
+#include "core/hle/service/nfc/nfc_u.h"
+
+namespace Service {
+namespace NFC {
+
+void Init() {
+ AddService(new NFC_M());
+ AddService(new NFC_U());
+}
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
new file mode 100644
index 000000000..cd65a5fdc
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace NFC {
+
+/// Initialize all NFC services.
+void Init();
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp
new file mode 100644
index 000000000..717335c11
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_m.cpp
@@ -0,0 +1,44 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfc/nfc_m.h"
+
+namespace Service {
+namespace NFC {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // nfc:u shared commands
+ {0x00010040, nullptr, "Initialize"},
+ {0x00020040, nullptr, "Shutdown"},
+ {0x00030000, nullptr, "StartCommunication"},
+ {0x00040000, nullptr, "StopCommunication"},
+ {0x00050040, nullptr, "StartTagScanning"},
+ {0x00060000, nullptr, "StopTagScanning"},
+ {0x00070000, nullptr, "LoadAmiiboData"},
+ {0x00080000, nullptr, "ResetTagScanState"},
+ {0x00090002, nullptr, "UpdateStoredAmiiboData"},
+ {0x000D0000, nullptr, "GetTagState"},
+ {0x000F0000, nullptr, "CommunicationGetStatus"},
+ {0x00100000, nullptr, "GetTagInfo2"},
+ {0x00110000, nullptr, "GetTagInfo"},
+ {0x00120000, nullptr, "CommunicationGetResult"},
+ {0x00130040, nullptr, "OpenAppData"},
+ {0x00140384, nullptr, "InitializeWriteAppData"},
+ {0x00150040, nullptr, "ReadAppData"},
+ {0x00160242, nullptr, "WriteAppData"},
+ {0x00170000, nullptr, "GetAmiiboSettings"},
+ {0x00180000, nullptr, "GetAmiiboConfig"},
+ {0x00190000, nullptr, "GetAppDataInitStruct"},
+ // nfc:m
+ {0x04040A40, nullptr, "SetAmiiboSettings"}
+ // clang-format on
+};
+
+NFC_M::NFC_M() {
+ Register(FunctionTable);
+}
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_m.h b/src/core/hle/service/nfc/nfc_m.h
new file mode 100644
index 000000000..fae75535b
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_m.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NFC {
+
+class NFC_M final : public Interface {
+public:
+ NFC_M();
+
+ std::string GetPortName() const override {
+ return "nfc:m";
+ }
+};
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp
new file mode 100644
index 000000000..deffb0b4f
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_u.cpp
@@ -0,0 +1,41 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfc/nfc_u.h"
+
+namespace Service {
+namespace NFC {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ {0x00010040, nullptr, "Initialize"},
+ {0x00020040, nullptr, "Shutdown"},
+ {0x00030000, nullptr, "StartCommunication"},
+ {0x00040000, nullptr, "StopCommunication"},
+ {0x00050040, nullptr, "StartTagScanning"},
+ {0x00060000, nullptr, "StopTagScanning"},
+ {0x00070000, nullptr, "LoadAmiiboData"},
+ {0x00080000, nullptr, "ResetTagScanState"},
+ {0x00090002, nullptr, "UpdateStoredAmiiboData"},
+ {0x000D0000, nullptr, "GetTagState"},
+ {0x000F0000, nullptr, "CommunicationGetStatus"},
+ {0x00100000, nullptr, "GetTagInfo2"},
+ {0x00110000, nullptr, "GetTagInfo"},
+ {0x00120000, nullptr, "CommunicationGetResult"},
+ {0x00130040, nullptr, "OpenAppData"},
+ {0x00140384, nullptr, "InitializeWriteAppData"},
+ {0x00150040, nullptr, "ReadAppData"},
+ {0x00160242, nullptr, "WriteAppData"},
+ {0x00170000, nullptr, "GetAmiiboSettings"},
+ {0x00180000, nullptr, "GetAmiiboConfig"},
+ {0x00190000, nullptr, "GetAppDataInitStruct"},
+ // clang-format on
+};
+
+NFC_U::NFC_U() {
+ Register(FunctionTable);
+}
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_u.h b/src/core/hle/service/nfc/nfc_u.h
new file mode 100644
index 000000000..eb7507314
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_u.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NFC {
+
+class NFC_U final : public Interface {
+public:
+ NFC_U();
+
+ std::string GetPortName() const override {
+ return "nfc:u";
+ }
+};
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp
index e2ba693c9..28b87e6f7 100644
--- a/src/core/hle/service/nim/nim_s.cpp
+++ b/src/core/hle/service/nim/nim_s.cpp
@@ -10,6 +10,7 @@ namespace NIM {
const Interface::FunctionInfo FunctionTable[] = {
{0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"},
{0x0016020A, nullptr, "ListTitles"},
+ {0x00290000, nullptr, "AccountCheckBalanceSOAP"},
{0x002D0042, nullptr, "DownloadTickets"},
{0x00420240, nullptr, "StartDownload"},
};
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp
index 7e07d02e8..7664bad60 100644
--- a/src/core/hle/service/nim/nim_u.cpp
+++ b/src/core/hle/service/nim/nim_u.cpp
@@ -15,6 +15,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00050000, nullptr, "CheckForSysUpdateEvent"},
{0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
{0x000A0000, nullptr, "GetState"},
+ {0x000B0000, nullptr, "GetSystemTitleHash"},
};
NIM_U_Interface::NIM_U_Interface() {
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp
index 6693f7c08..215c9aacc 100644
--- a/src/core/hle/service/ns_s.cpp
+++ b/src/core/hle/service/ns_s.cpp
@@ -4,10 +4,8 @@
#include "core/hle/service/ns_s.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NS_S
-
-namespace NS_S {
+namespace Service {
+namespace NS {
const Interface::FunctionInfo FunctionTable[] = {
{0x000100C0, nullptr, "LaunchFIRM"},
@@ -27,11 +25,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00160000, nullptr, "RebootSystemClean"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+NS_S::NS_S() {
Register(FunctionTable);
}
-} // namespace
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns_s.h b/src/core/hle/service/ns_s.h
index 8d8e849b8..90288a521 100644
--- a/src/core/hle/service/ns_s.h
+++ b/src/core/hle/service/ns_s.h
@@ -6,19 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NS_S
+namespace Service {
+namespace NS {
-namespace NS_S {
-
-/// Interface to "NS:S" service
-class Interface : public Service::Interface {
+class NS_S final : public Interface {
public:
- Interface();
+ NS_S();
std::string GetPortName() const override {
return "ns:s";
}
};
-} // namespace
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm.cpp b/src/core/hle/service/nwm/nwm.cpp
new file mode 100644
index 000000000..9f1994dc3
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm.cpp
@@ -0,0 +1,28 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm.h"
+#include "core/hle/service/nwm/nwm_cec.h"
+#include "core/hle/service/nwm/nwm_ext.h"
+#include "core/hle/service/nwm/nwm_inf.h"
+#include "core/hle/service/nwm/nwm_sap.h"
+#include "core/hle/service/nwm/nwm_soc.h"
+#include "core/hle/service/nwm/nwm_tst.h"
+#include "core/hle/service/nwm/nwm_uds.h"
+
+namespace Service {
+namespace NWM {
+
+void Init() {
+ AddService(new NWM_CEC);
+ AddService(new NWM_EXT);
+ AddService(new NWM_INF);
+ AddService(new NWM_SAP);
+ AddService(new NWM_SOC);
+ AddService(new NWM_TST);
+ AddService(new NWM_UDS);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm.h b/src/core/hle/service/nwm/nwm.h
new file mode 100644
index 000000000..6926b29a6
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace NWM {
+
+/// Initialize all NWM services
+void Init();
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_cec.cpp b/src/core/hle/service/nwm/nwm_cec.cpp
new file mode 100644
index 000000000..7f03987df
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_cec.cpp
@@ -0,0 +1,19 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_cec.h"
+
+namespace Service {
+namespace NWM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000D0082, nullptr, "SendProbeRequest"},
+};
+
+NWM_CEC::NWM_CEC() {
+ Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_cec.h b/src/core/hle/service/nwm/nwm_cec.h
new file mode 100644
index 000000000..07b6addb5
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_cec.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_CEC final : public Interface {
+public:
+ NWM_CEC();
+
+ std::string GetPortName() const override {
+ return "nwm::CEC";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_ext.cpp b/src/core/hle/service/nwm/nwm_ext.cpp
new file mode 100644
index 000000000..605640a13
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_ext.cpp
@@ -0,0 +1,19 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_ext.h"
+
+namespace Service {
+namespace NWM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00080040, nullptr, "ControlWirelessEnabled"},
+};
+
+NWM_EXT::NWM_EXT() {
+ Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_ext.h b/src/core/hle/service/nwm/nwm_ext.h
new file mode 100644
index 000000000..51d39d9ea
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_ext.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_EXT final : public Interface {
+public:
+ NWM_EXT();
+
+ std::string GetPortName() const override {
+ return "nwm::EXT";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_inf.cpp b/src/core/hle/service/nwm/nwm_inf.cpp
new file mode 100644
index 000000000..c8470589b
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_inf.cpp
@@ -0,0 +1,21 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_inf.h"
+
+namespace Service {
+namespace NWM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000603C4, nullptr, "RecvBeaconBroadcastData"},
+ {0x00070742, nullptr, "ConnectToEncryptedAP"},
+ {0x00080302, nullptr, "ConnectToAP"},
+};
+
+NWM_INF::NWM_INF() {
+ Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_inf.h b/src/core/hle/service/nwm/nwm_inf.h
new file mode 100644
index 000000000..0043d769c
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_inf.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_INF final : public Interface {
+public:
+ NWM_INF();
+
+ std::string GetPortName() const override {
+ return "nwm::INF";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_sap.cpp b/src/core/hle/service/nwm/nwm_sap.cpp
new file mode 100644
index 000000000..fd29ed761
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_sap.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_sap.h"
+
+namespace Service {
+namespace NWM {
+
+/*
+const Interface::FunctionInfo FunctionTable[] = {
+};
+*/
+
+NWM_SAP::NWM_SAP() {
+ // Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_sap.h b/src/core/hle/service/nwm/nwm_sap.h
new file mode 100644
index 000000000..f692e06d4
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_sap.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_SAP final : public Interface {
+public:
+ NWM_SAP();
+
+ std::string GetPortName() const override {
+ return "nwm::SAP";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_soc.cpp b/src/core/hle/service/nwm/nwm_soc.cpp
new file mode 100644
index 000000000..fdffcb925
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_soc.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_soc.h"
+
+namespace Service {
+namespace NWM {
+
+/*
+const Interface::FunctionInfo FunctionTable[] = {
+};
+*/
+
+NWM_SOC::NWM_SOC() {
+ // Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_soc.h b/src/core/hle/service/nwm/nwm_soc.h
new file mode 100644
index 000000000..594941d7e
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_soc.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_SOC final : public Interface {
+public:
+ NWM_SOC();
+
+ std::string GetPortName() const override {
+ return "nwm::SOC";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_tst.cpp b/src/core/hle/service/nwm/nwm_tst.cpp
new file mode 100644
index 000000000..5f292e5db
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_tst.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_tst.h"
+
+namespace Service {
+namespace NWM {
+
+/*
+const Interface::FunctionInfo FunctionTable[] = {
+};
+*/
+
+NWM_TST::NWM_TST() {
+ // Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_tst.h b/src/core/hle/service/nwm/nwm_tst.h
new file mode 100644
index 000000000..8deca3216
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_tst.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_TST final : public Interface {
+public:
+ NWM_TST();
+
+ std::string GetPortName() const override {
+ return "nwm::TST";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 80081aae2..08fade320 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -5,14 +5,12 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
-#include "core/hle/service/nwm_uds.h"
+#include "core/hle/service/nwm/nwm_uds.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NWM_UDS
+namespace Service {
+namespace NWM {
-namespace NWM_UDS {
-
-static Kernel::SharedPtr<Kernel::Event> handle_event;
+static Kernel::SharedPtr<Kernel::Event> uds_handle_event;
/**
* NWM_UDS::Shutdown service function
@@ -22,7 +20,7 @@ static Kernel::SharedPtr<Kernel::Event> handle_event;
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void Shutdown(Service::Interface* self) {
+static void Shutdown(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(purpasmart): Verify return header on HW
@@ -50,7 +48,7 @@ static void Shutdown(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void RecvBeaconBroadcastData(Service::Interface* self) {
+static void RecvBeaconBroadcastData(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 out_buffer_size = cmd_buff[1];
u32 unk1 = cmd_buff[2];
@@ -90,7 +88,7 @@ static void RecvBeaconBroadcastData(Service::Interface* self) {
* 2 : Value 0
* 3 : Output handle
*/
-static void Initialize(Service::Interface* self) {
+static void InitializeWithVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 unk1 = cmd_buff[1];
u32 unk2 = cmd_buff[12];
@@ -103,7 +101,7 @@ static void Initialize(Service::Interface* self) {
/*
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0;
- cmd_buff[3] = Kernel::g_handle_table.Create(handle_event)
+ cmd_buff[3] = Kernel::g_handle_table.Create(uds_handle_event)
.MoveFrom(); // TODO(purpasmart): Verify if this is a event handle
*/
cmd_buff[0] = IPC::MakeHeader(0x1B, 1, 2);
@@ -118,26 +116,29 @@ static void Initialize(Service::Interface* self) {
}
const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010442, nullptr, "Initialize (deprecated)"},
{0x00020000, nullptr, "Scrap"},
{0x00030000, Shutdown, "Shutdown"},
- {0x00040402, nullptr, "CreateNetwork"},
+ {0x00040402, nullptr, "CreateNetwork (deprecated)"},
{0x00050040, nullptr, "EjectClient"},
{0x00060000, nullptr, "EjectSpectator"},
{0x00070080, nullptr, "UpdateNetworkAttribute"},
{0x00080000, nullptr, "DestroyNetwork"},
+ {0x00090442, nullptr, "ConnectNetwork (deprecated)"},
{0x000A0000, nullptr, "DisconnectNetwork"},
{0x000B0000, nullptr, "GetConnectionStatus"},
{0x000D0040, nullptr, "GetNodeInformation"},
+ {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"},
{0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"},
- {0x00100042, nullptr, "SetBeaconAdditionalData"},
+ {0x00100042, nullptr, "SetApplicationData"},
{0x00110040, nullptr, "GetApplicationData"},
{0x00120100, nullptr, "Bind"},
{0x00130040, nullptr, "Unbind"},
- {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
+ {0x001400C0, nullptr, "PullPacket"},
{0x00150080, nullptr, "SetMaxSendDelay"},
{0x00170182, nullptr, "SendTo"},
{0x001A0000, nullptr, "GetChannel"},
- {0x001B0302, Initialize, "Initialize"},
+ {0x001B0302, InitializeWithVersion, "InitializeWithVersion"},
{0x001D0044, nullptr, "BeginHostingNetwork"},
{0x001E0084, nullptr, "ConnectToNetwork"},
{0x001F0006, nullptr, "DecryptBeaconData"},
@@ -146,17 +147,15 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00220402, nullptr, "ScanOnConnection"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM_UDS::handle_event");
+NWM_UDS::NWM_UDS() {
+ uds_handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::uds_handle_event");
Register(FunctionTable);
}
-Interface::~Interface() {
- handle_event = nullptr;
+NWM_UDS::~NWM_UDS() {
+ uds_handle_event = nullptr;
}
-} // namespace
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index 0ced2359c..55db748f6 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm/nwm_uds.h
@@ -6,21 +6,20 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NWM_UDS
+// Local-WLAN service
-// local-WLAN service
+namespace Service {
+namespace NWM {
-namespace NWM_UDS {
-
-class Interface : public Service::Interface {
+class NWM_UDS final : public Interface {
public:
- Interface();
- ~Interface() override;
+ NWM_UDS();
+ ~NWM_UDS() override;
std::string GetPortName() const override {
return "nwm::UDS";
}
};
-} // namespace
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp
index 7d91694f6..caa16f952 100644
--- a/src/core/hle/service/pm_app.cpp
+++ b/src/core/hle/service/pm_app.cpp
@@ -4,31 +4,30 @@
#include "core/hle/service/pm_app.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace PM_APP
-
-namespace PM_APP {
+namespace Service {
+namespace PM {
const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
{0x00010140, nullptr, "LaunchTitle"},
- {0x00020082, nullptr, "LaunchFIRMSetParams"},
- {0x00030080, nullptr, "TerminateProcesse"},
- {0x00040100, nullptr, "TerminateProcessTID"},
- {0x000500C0, nullptr, "TerminateProcessTID_unknown"},
+ {0x00020082, nullptr, "LaunchFIRM"},
+ {0x00030080, nullptr, "TerminateApplication"},
+ {0x00040100, nullptr, "TerminateTitle"},
+ {0x000500C0, nullptr, "TerminateProcess"},
+ {0x00060082, nullptr, "PrepareForReboot"},
{0x00070042, nullptr, "GetFIRMLaunchParams"},
{0x00080100, nullptr, "GetTitleExheaderFlags"},
{0x00090042, nullptr, "SetFIRMLaunchParams"},
- {0x000A0140, nullptr, "SetResourceLimit"},
- {0x000B0140, nullptr, "GetResourceLimitMax"},
+ {0x000A0140, nullptr, "SetAppResourceLimit"},
+ {0x000B0140, nullptr, "GetAppResourceLimit"},
{0x000C0080, nullptr, "UnregisterProcess"},
{0x000D0240, nullptr, "LaunchTitleUpdate"},
+ // clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+PM_APP::PM_APP() {
Register(FunctionTable);
}
-} // namespace
+} // namespace PM
+} // namespace Service
diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h
index c1fb1f9da..151c69f3d 100644
--- a/src/core/hle/service/pm_app.h
+++ b/src/core/hle/service/pm_app.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace PM_APP
+namespace Service {
+namespace PM {
-namespace PM_APP {
-
-class Interface : public Service::Interface {
+class PM_APP final : public Interface {
public:
- Interface();
+ PM_APP();
std::string GetPortName() const override {
return "pm:app";
}
};
-} // namespace
+} // namespace PM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index cc859c14c..8ff808fd9 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -6,7 +6,9 @@
#include "core/file_sys/file_backend.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ptm/ptm_gets.h"
#include "core/hle/service/ptm/ptm_play.h"
+#include "core/hle/service/ptm/ptm_sets.h"
#include "core/hle/service/ptm/ptm_sysm.h"
#include "core/hle/service/ptm/ptm_u.h"
#include "core/hle/service/service.h"
@@ -81,7 +83,7 @@ void GetTotalStepCount(Service::Interface* self) {
LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-void IsLegacyPowerOff(Service::Interface* self) {
+void GetSoftwareClosedFlag(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
@@ -106,9 +108,12 @@ void CheckNew3DS(Service::Interface* self) {
}
void Init() {
- AddService(new PTM_Play_Interface);
- AddService(new PTM_Sysm_Interface);
- AddService(new PTM_U_Interface);
+ AddService(new PTM_Gets);
+ AddService(new PTM_Play);
+ AddService(new PTM_S);
+ AddService(new PTM_Sets);
+ AddService(new PTM_Sysm);
+ AddService(new PTM_U);
shell_open = true;
battery_is_charging = true;
@@ -137,7 +142,7 @@ void Init() {
Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode);
if (gamecoin_result.Succeeded()) {
auto gamecoin = gamecoin_result.MoveFrom();
- gamecoin->backend->Write(0, sizeof(GameCoin), 1,
+ gamecoin->backend->Write(0, sizeof(GameCoin), true,
reinterpret_cast<const u8*>(&default_game_coin));
gamecoin->backend->Close();
}
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 6e163a6f9..a1a628012 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -82,12 +82,13 @@ void GetBatteryChargeState(Interface* self);
void GetTotalStepCount(Interface* self);
/**
- * PTM::IsLegacyPowerOff service function
+ * PTM::GetSoftwareClosedFlag service function
* Outputs:
* 1: Result code, 0 on success, otherwise error code
- * 2: Whether the system is going through a power off
+ * 2: Whether or not the "software closed" dialog was requested by the last FIRM
+ * and should be displayed.
*/
-void IsLegacyPowerOff(Interface* self);
+void GetSoftwareClosedFlag(Interface* self);
/**
* PTM::CheckNew3DS service function
diff --git a/src/core/hle/service/ptm/ptm_gets.cpp b/src/core/hle/service/ptm/ptm_gets.cpp
new file mode 100644
index 000000000..b23e508d6
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_gets.cpp
@@ -0,0 +1,37 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ptm/ptm_gets.h"
+
+namespace Service {
+namespace PTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // ptm:u common commands
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, GetAdapterState, "GetAdapterState"},
+ {0x00060000, GetShellState, "GetShellState"},
+ {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
+ {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory"},
+ {0x000C0000, GetTotalStepCount, "GetTotalStepCount"},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+ // ptm:gets
+ {0x04010000, nullptr, "GetSystemTime"},
+};
+
+PTM_Gets::PTM_Gets() {
+ Register(FunctionTable);
+}
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_gets.h b/src/core/hle/service/ptm/ptm_gets.h
new file mode 100644
index 000000000..5552c9eff
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_gets.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace PTM {
+
+class PTM_Gets final : public Interface {
+public:
+ PTM_Gets();
+
+ std::string GetPortName() const override {
+ return "ptm:gets";
+ }
+};
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 2e0c6e1a3..bcb00e0d4 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -2,19 +2,37 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ptm_play.h"
namespace Service {
namespace PTM {
const Interface::FunctionInfo FunctionTable[] = {
+ // ptm:u common commands
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, GetAdapterState, "GetAdapterState"},
+ {0x00060000, GetShellState, "GetShellState"},
+ {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
+ {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory"},
+ {0x000C0000, GetTotalStepCount, "GetTotalStepCount"},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+ // ptm:play
{0x08070082, nullptr, "GetPlayHistory"},
{0x08080000, nullptr, "GetPlayHistoryStart"},
{0x08090000, nullptr, "GetPlayHistoryLength"},
{0x080B0080, nullptr, "CalcPlayHistoryStart"},
};
-PTM_Play_Interface::PTM_Play_Interface() {
+PTM_Play::PTM_Play() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/ptm/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h
index 47f229581..663faabee 100644
--- a/src/core/hle/service/ptm/ptm_play.h
+++ b/src/core/hle/service/ptm/ptm_play.h
@@ -9,9 +9,9 @@
namespace Service {
namespace PTM {
-class PTM_Play_Interface : public Service::Interface {
+class PTM_Play final : public Interface {
public:
- PTM_Play_Interface();
+ PTM_Play();
std::string GetPortName() const override {
return "ptm:play";
diff --git a/src/core/hle/service/ptm/ptm_sets.cpp b/src/core/hle/service/ptm/ptm_sets.cpp
new file mode 100644
index 000000000..a8c6cf227
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_sets.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ptm/ptm_sets.h"
+
+namespace Service {
+namespace PTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // Note that this service does not have access to ptm:u's common commands
+ {0x00010080, nullptr, "SetSystemTime"},
+};
+
+PTM_Sets::PTM_Sets() {
+ Register(FunctionTable);
+}
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_sets.h b/src/core/hle/service/ptm/ptm_sets.h
new file mode 100644
index 000000000..d33b047e5
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_sets.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace PTM {
+
+class PTM_Sets final : public Interface {
+public:
+ PTM_Sets();
+
+ std::string GetPortName() const override {
+ return "ptm:sets";
+ }
+};
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 693158dbf..f95dfdbb1 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -9,6 +9,23 @@ namespace Service {
namespace PTM {
const Interface::FunctionInfo FunctionTable[] = {
+ // ptm:u common commands
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, GetAdapterState, "GetAdapterState"},
+ {0x00060000, GetShellState, "GetShellState"},
+ {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
+ {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory"},
+ {0x000C0000, GetTotalStepCount, "GetTotalStepCount"},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+ // ptm:sysm
{0x040100C0, nullptr, "SetRtcAlarmEx"},
{0x04020042, nullptr, "ReplySleepQuery"},
{0x04030042, nullptr, "NotifySleepPreparationComplete"},
@@ -33,8 +50,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x080C0080, nullptr, "SetUserTime"},
{0x080D0000, nullptr, "InvalidateSystemTime"},
{0x080E0140, nullptr, "NotifyPlayEvent"},
- {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"},
- {0x08100000, nullptr, "ClearLegacyPowerOff"},
+ {0x080F0000, GetSoftwareClosedFlag, "GetSoftwareClosedFlag"},
+ {0x08100000, nullptr, "ClearSoftwareClosedFlag"},
{0x08110000, GetShellState, "GetShellState"},
{0x08120000, nullptr, "IsShutdownByBatteryEmpty"},
{0x08130000, nullptr, "FormatSavedata"},
@@ -42,7 +59,11 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08180040, nullptr, "ConfigureNew3DSCPU"},
};
-PTM_Sysm_Interface::PTM_Sysm_Interface() {
+PTM_S::PTM_S() {
+ Register(FunctionTable);
+}
+
+PTM_Sysm::PTM_Sysm() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/ptm/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h
index e37f20546..8afcebbba 100644
--- a/src/core/hle/service/ptm/ptm_sysm.h
+++ b/src/core/hle/service/ptm/ptm_sysm.h
@@ -9,9 +9,18 @@
namespace Service {
namespace PTM {
-class PTM_Sysm_Interface : public Interface {
+class PTM_S final : public Interface {
public:
- PTM_Sysm_Interface();
+ PTM_S();
+
+ std::string GetPortName() const override {
+ return "ptm:s";
+ }
+};
+
+class PTM_Sysm final : public Interface {
+public:
+ PTM_Sysm();
std::string GetPortName() const override {
return "ptm:sysm";
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp
index 65e868393..e0b65ba89 100644
--- a/src/core/hle/service/ptm/ptm_u.cpp
+++ b/src/core/hle/service/ptm/ptm_u.cpp
@@ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000F0084, nullptr, "GetStepHistoryAll"},
};
-PTM_U_Interface::PTM_U_Interface() {
+PTM_U::PTM_U() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/ptm/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h
index bf132f610..7b75d6e49 100644
--- a/src/core/hle/service/ptm/ptm_u.h
+++ b/src/core/hle/service/ptm/ptm_u.h
@@ -9,9 +9,9 @@
namespace Service {
namespace PTM {
-class PTM_U_Interface : public Interface {
+class PTM_U final : public Interface {
public:
- PTM_U_Interface();
+ PTM_U();
std::string GetPortName() const override {
return "ptm:u";
diff --git a/src/core/hle/service/qtm/qtm.cpp b/src/core/hle/service/qtm/qtm.cpp
new file mode 100644
index 000000000..f11542263
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm.cpp
@@ -0,0 +1,21 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm.h"
+#include "core/hle/service/qtm/qtm_s.h"
+#include "core/hle/service/qtm/qtm_sp.h"
+#include "core/hle/service/qtm/qtm_u.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+void Init() {
+ AddService(new QTM_S());
+ AddService(new QTM_SP());
+ AddService(new QTM_U());
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm.h b/src/core/hle/service/qtm/qtm.h
new file mode 100644
index 000000000..33b774c79
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace QTM {
+
+/// Initializes all QTM services.
+void Init();
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_s.cpp b/src/core/hle/service/qtm/qtm_s.cpp
new file mode 100644
index 000000000..ad7df24a0
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_s.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm_s.h"
+
+namespace Service {
+namespace QTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // qtm common commands
+ {0x00010080, nullptr, "GetHeadtrackingInfoRaw"},
+ {0x00020080, nullptr, "GetHeadtrackingInfo"},
+ // clang-format on
+};
+
+QTM_S::QTM_S() {
+ Register(FunctionTable);
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_s.h b/src/core/hle/service/qtm/qtm_s.h
new file mode 100644
index 000000000..e66138ed0
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_s.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+class QTM_S final : public Interface {
+public:
+ QTM_S();
+
+ std::string GetPortName() const override {
+ return "qtm:s";
+ }
+};
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_sp.cpp b/src/core/hle/service/qtm/qtm_sp.cpp
new file mode 100644
index 000000000..6e0695d34
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_sp.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm_sp.h"
+
+namespace Service {
+namespace QTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // qtm common commands
+ {0x00010080, nullptr, "GetHeadtrackingInfoRaw"},
+ {0x00020080, nullptr, "GetHeadtrackingInfo"},
+ // clang-format on
+};
+
+QTM_SP::QTM_SP() {
+ Register(FunctionTable);
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_sp.h b/src/core/hle/service/qtm/qtm_sp.h
new file mode 100644
index 000000000..0ae0618fc
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_sp.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+class QTM_SP final : public Interface {
+public:
+ QTM_SP();
+
+ std::string GetPortName() const override {
+ return "qtm:sp";
+ }
+};
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_u.cpp b/src/core/hle/service/qtm/qtm_u.cpp
new file mode 100644
index 000000000..a0f808432
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_u.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm_u.h"
+
+namespace Service {
+namespace QTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // qtm common commands
+ {0x00010080, nullptr, "GetHeadtrackingInfoRaw"},
+ {0x00020080, nullptr, "GetHeadtrackingInfo"},
+ // clang-format on
+};
+
+QTM_U::QTM_U() {
+ Register(FunctionTable);
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_u.h b/src/core/hle/service/qtm/qtm_u.h
new file mode 100644
index 000000000..1ed4c0adc
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_u.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+class QTM_U final : public Interface {
+public:
+ QTM_U();
+
+ std::string GetPortName() const override {
+ return "qtm:u";
+ }
+};
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ca7eeac8a..7e52a05d9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -2,11 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <boost/range/algorithm_ext/erase.hpp>
+
#include "common/logging/log.h"
#include "common/string_util.h"
+
+#include "core/hle/kernel/server_port.h"
#include "core/hle/service/ac_u.h"
-#include "core/hle/service/act_a.h"
-#include "core/hle/service/act_u.h"
+#include "core/hle/service/act/act.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/apt/apt.h"
#include "core/hle/service/boss/boss.h"
@@ -26,13 +29,16 @@
#include "core/hle/service/ir/ir.h"
#include "core/hle/service/ldr_ro/ldr_ro.h"
#include "core/hle/service/mic_u.h"
+#include "core/hle/service/mvd/mvd.h"
#include "core/hle/service/ndm/ndm.h"
#include "core/hle/service/news/news.h"
+#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/ns_s.h"
-#include "core/hle/service/nwm_uds.h"
+#include "core/hle/service/nwm/nwm.h"
#include "core/hle/service/pm_app.h"
#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/qtm/qtm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/soc_u.h"
#include "core/hle/service/srv.h"
@@ -41,8 +47,8 @@
namespace Service {
-std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
-std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
+std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
/**
* Creates a function string for logging, complete with the name (or header code, depending
@@ -61,7 +67,23 @@ static std::string MakeFunctionString(const char* name, const char* port_name,
return function_string;
}
-ResultVal<bool> Interface::SyncRequest() {
+void SessionRequestHandler::ClientConnected(
+ Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+ connected_sessions.push_back(server_session);
+}
+
+void SessionRequestHandler::ClientDisconnected(
+ Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+ boost::range::remove_erase(connected_sessions, server_session);
+}
+
+Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {}
+Interface::~Interface() = default;
+
+void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+ // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which
+ // session triggered each command.
+
u32* cmd_buff = Kernel::GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
@@ -75,14 +97,12 @@ ResultVal<bool> Interface::SyncRequest() {
// TODO(bunnei): Hack - ignore error
cmd_buff[1] = 0;
- return MakeResult<bool>(false);
+ return;
}
LOG_TRACE(Service, "%s",
MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
itr->second.func(this);
-
- return MakeResult<bool>(false); // TODO: Implement return from actual function
}
void Interface::Register(const FunctionInfo* functions, size_t n) {
@@ -97,72 +117,81 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {
// Module interface
static void AddNamedPort(Interface* interface_) {
- g_kernel_named_ports.emplace(interface_->GetPortName(), interface_);
+ auto ports =
+ Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(),
+ std::shared_ptr<Interface>(interface_));
+ auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports);
+ g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port));
}
void AddService(Interface* interface_) {
- g_srv_services.emplace(interface_->GetPortName(), interface_);
+ auto ports =
+ Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(),
+ std::shared_ptr<Interface>(interface_));
+ auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports);
+ g_srv_services.emplace(interface_->GetPortName(), std::move(client_port));
}
/// Initialize ServiceManager
void Init() {
- AddNamedPort(new SRV::Interface);
- AddNamedPort(new ERR_F::Interface);
-
- Service::FS::ArchiveInit();
- Service::AM::Init();
- Service::APT::Init();
- Service::BOSS::Init();
- Service::CAM::Init();
- Service::CECD::Init();
- Service::CFG::Init();
- Service::DLP::Init();
- Service::FRD::Init();
- Service::HID::Init();
- Service::IR::Init();
- Service::NEWS::Init();
- Service::NDM::Init();
- Service::NIM::Init();
- Service::PTM::Init();
-
- AddService(new AC_U::Interface);
- AddService(new ACT_A::Interface);
- AddService(new ACT_U::Interface);
- AddService(new CSND_SND::Interface);
+ AddNamedPort(new SRV::SRV);
+ AddNamedPort(new ERR::ERR_F);
+
+ FS::ArchiveInit();
+ ACT::Init();
+ AM::Init();
+ APT::Init();
+ BOSS::Init();
+ CAM::Init();
+ CECD::Init();
+ CFG::Init();
+ DLP::Init();
+ FRD::Init();
+ HID::Init();
+ IR::Init();
+ MVD::Init();
+ NDM::Init();
+ NEWS::Init();
+ NFC::Init();
+ NIM::Init();
+ NWM::Init();
+ PTM::Init();
+ QTM::Init();
+
+ AddService(new AC::AC_U);
+ AddService(new CSND::CSND_SND);
AddService(new DSP_DSP::Interface);
- AddService(new GSP_GPU::Interface);
- AddService(new GSP_LCD::Interface);
- AddService(new HTTP_C::Interface);
- AddService(new LDR_RO::Interface);
- AddService(new MIC_U::Interface);
- AddService(new NS_S::Interface);
- AddService(new NWM_UDS::Interface);
- AddService(new PM_APP::Interface);
- AddService(new SOC_U::Interface);
- AddService(new SSL_C::Interface);
- AddService(new Y2R_U::Interface);
+ AddService(new GSP::GSP_GPU);
+ AddService(new GSP::GSP_LCD);
+ AddService(new HTTP::HTTP_C);
+ AddService(new LDR::LDR_RO);
+ AddService(new MIC::MIC_U);
+ AddService(new NS::NS_S);
+ AddService(new PM::PM_APP);
+ AddService(new SOC::SOC_U);
+ AddService(new SSL::SSL_C);
+ AddService(new Y2R::Y2R_U);
LOG_DEBUG(Service, "initialized OK");
}
/// Shutdown ServiceManager
void Shutdown() {
-
- Service::PTM::Shutdown();
- Service::NDM::Shutdown();
- Service::NIM::Shutdown();
- Service::NEWS::Shutdown();
- Service::IR::Shutdown();
- Service::HID::Shutdown();
- Service::FRD::Shutdown();
- Service::DLP::Shutdown();
- Service::CFG::Shutdown();
- Service::CECD::Shutdown();
- Service::CAM::Shutdown();
- Service::BOSS::Shutdown();
- Service::APT::Shutdown();
- Service::AM::Shutdown();
- Service::FS::ArchiveShutdown();
+ PTM::Shutdown();
+ NIM::Shutdown();
+ NEWS::Shutdown();
+ NDM::Shutdown();
+ IR::Shutdown();
+ HID::Shutdown();
+ FRD::Shutdown();
+ DLP::Shutdown();
+ CFG::Shutdown();
+ CECD::Shutdown();
+ CAM::Shutdown();
+ BOSS::Shutdown();
+ APT::Shutdown();
+ AM::Shutdown();
+ FS::ArchiveShutdown();
g_srv_services.clear();
g_kernel_named_ports.clear();
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 29daacfc4..a7ba7688f 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -9,8 +9,15 @@
#include <unordered_map>
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/ipc.h"
+#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/thread.h"
#include "core/hle/result.h"
+#include "core/memory.h"
+
+namespace Kernel {
+class ServerSession;
+}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -18,14 +25,63 @@
namespace Service {
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
+/// Arbitrary default number of maximum connections to an HLE service.
+static const u32 DefaultMaxSessions = 10;
+
+/**
+ * Interface implemented by HLE Session handlers.
+ * This can be provided to a ServerSession in order to hook into several relevant events
+ * (such as a new connection or a SyncRequest) so they can be implemented in the emulator.
+ */
+class SessionRequestHandler {
+public:
+ /**
+ * Handles a sync request from the emulated application.
+ * @param server_session The ServerSession that was triggered for this sync request,
+ * it should be used to differentiate which client (As in ClientSession) we're answering to.
+ * TODO(Subv): Use a wrapper structure to hold all the information relevant to
+ * this request (ServerSession, Originator thread, Translated command buffer, etc).
+ * @returns ResultCode the result code of the translate operation.
+ */
+ virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0;
+
+ /**
+ * Signals that a client has just connected to this HLE handler and keeps the
+ * associated ServerSession alive for the duration of the connection.
+ * @param server_session Owning pointer to the ServerSession associated with the connection.
+ */
+ void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
+
+ /**
+ * Signals that a client has just disconnected from this HLE handler and releases the
+ * associated ServerSession.
+ * @param server_session ServerSession associated with the connection.
+ */
+ void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
-/// Interface to a CTROS service
-class Interface : public Kernel::Session {
- // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
- // just something that encapsulates a session and acts as a helper to implement service
- // processes.
+protected:
+ /// List of sessions that are connected to this handler.
+ /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
+ // for the duration of the connection.
+ std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
+};
+
+/**
+ * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a
+ * table mapping header ids to handler functions.
+ */
+class Interface : public SessionRequestHandler {
public:
- std::string GetName() const override {
+ /**
+ * Creates an HLE interface with the specified max sessions.
+ * @param max_sessions Maximum number of sessions that can be
+ * connected to this service at the same time.
+ */
+ Interface(u32 max_sessions = DefaultMaxSessions);
+
+ virtual ~Interface();
+
+ std::string GetName() const {
return GetPortName();
}
@@ -33,6 +89,15 @@ public:
version.raw = raw_version;
}
+ /**
+ * Gets the maximum allowed number of sessions that can be connected to this service
+ * at the same time.
+ * @returns The maximum number of connections allowed.
+ */
+ u32 GetMaxSessions() const {
+ return max_sessions;
+ }
+
typedef void (*Function)(Interface*);
struct FunctionInfo {
@@ -49,9 +114,9 @@ public:
return "[UNKNOWN SERVICE PORT]";
}
- ResultVal<bool> SyncRequest() override;
-
protected:
+ void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
+
/**
* Registers the functions in the service
*/
@@ -71,6 +136,7 @@ protected:
} version = {};
private:
+ u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle.
boost::container::flat_map<u32, FunctionInfo> m_functions;
};
@@ -81,9 +147,9 @@ void Init();
void Shutdown();
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
-extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
+extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
-extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
/// Adds a service to the services table
void AddService(Interface* interface_);
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 46b75db25..c3918cdd0 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -11,7 +11,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/result.h"
#include "core/hle/service/soc_u.h"
#include "core/memory.h"
@@ -53,12 +53,10 @@
#define closesocket(x) close(x)
#endif
-static const s32 SOCKET_ERROR_VALUE = -1;
+namespace Service {
+namespace SOC {
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SOC_U
-
-namespace SOC_U {
+const s32 SOCKET_ERROR_VALUE = -1;
/// Holds the translation from system network errors to 3DS network errors
static const std::unordered_map<int, int> error_map = {{
@@ -339,7 +337,7 @@ static void CleanupSockets() {
open_sockets.clear();
}
-static void Socket(Service::Interface* self) {
+static void Socket(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 domain = cmd_buffer[1]; // Address family
u32 type = cmd_buffer[2];
@@ -378,7 +376,7 @@ static void Socket(Service::Interface* self) {
cmd_buffer[2] = socket_handle;
}
-static void Bind(Service::Interface* self) {
+static void Bind(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 len = cmd_buffer[2];
@@ -406,7 +404,7 @@ static void Bind(Service::Interface* self) {
cmd_buffer[2] = res;
}
-static void Fcntl(Service::Interface* self) {
+static void Fcntl(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 ctr_cmd = cmd_buffer[2];
@@ -475,7 +473,7 @@ static void Fcntl(Service::Interface* self) {
}
}
-static void Listen(Service::Interface* self) {
+static void Listen(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 backlog = cmd_buffer[2];
@@ -490,7 +488,7 @@ static void Listen(Service::Interface* self) {
cmd_buffer[2] = ret;
}
-static void Accept(Service::Interface* self) {
+static void Accept(Interface* self) {
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
// preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
@@ -518,7 +516,7 @@ static void Accept(Service::Interface* self) {
cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0);
}
-static void GetHostId(Service::Interface* self) {
+static void GetHostId(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
char name[128];
@@ -536,7 +534,7 @@ static void GetHostId(Service::Interface* self) {
freeaddrinfo(res);
}
-static void Close(Service::Interface* self) {
+static void Close(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
@@ -553,7 +551,7 @@ static void Close(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void SendTo(Service::Interface* self) {
+static void SendTo(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 len = cmd_buffer[2];
@@ -597,7 +595,7 @@ static void SendTo(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void RecvFrom(Service::Interface* self) {
+static void RecvFrom(Interface* self) {
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
// preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
@@ -654,7 +652,7 @@ static void RecvFrom(Service::Interface* self) {
cmd_buffer[3] = total_received;
}
-static void Poll(Service::Interface* self) {
+static void Poll(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 nfds = cmd_buffer[1];
int timeout = cmd_buffer[2];
@@ -692,7 +690,7 @@ static void Poll(Service::Interface* self) {
cmd_buffer[2] = ret;
}
-static void GetSockName(Service::Interface* self) {
+static void GetSockName(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
socklen_t ctr_len = cmd_buffer[2];
@@ -720,7 +718,7 @@ static void GetSockName(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void Shutdown(Service::Interface* self) {
+static void Shutdown(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
int how = cmd_buffer[2];
@@ -733,7 +731,7 @@ static void Shutdown(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void GetPeerName(Service::Interface* self) {
+static void GetPeerName(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
socklen_t len = cmd_buffer[2];
@@ -761,7 +759,7 @@ static void GetPeerName(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void Connect(Service::Interface* self) {
+static void Connect(Interface* self) {
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
// preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
@@ -790,7 +788,7 @@ static void Connect(Service::Interface* self) {
cmd_buffer[2] = ret;
}
-static void InitializeSockets(Service::Interface* self) {
+static void InitializeSockets(Interface* self) {
// TODO(Subv): Implement
#ifdef _WIN32
WSADATA data;
@@ -802,7 +800,7 @@ static void InitializeSockets(Service::Interface* self) {
cmd_buffer[1] = RESULT_SUCCESS.raw;
}
-static void ShutdownSockets(Service::Interface* self) {
+static void ShutdownSockets(Interface* self) {
// TODO(Subv): Implement
CleanupSockets();
@@ -814,7 +812,7 @@ static void ShutdownSockets(Service::Interface* self) {
cmd_buffer[1] = 0;
}
-static void GetSockOpt(Service::Interface* self) {
+static void GetSockOpt(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 level = cmd_buffer[2];
@@ -849,7 +847,7 @@ static void GetSockOpt(Service::Interface* self) {
cmd_buffer[3] = optlen;
}
-static void SetSockOpt(Service::Interface* self) {
+static void SetSockOpt(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 level = cmd_buffer[2];
@@ -916,18 +914,16 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00230040, nullptr, "AddGlobalSocket"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+SOC_U::SOC_U() {
Register(FunctionTable);
}
-Interface::~Interface() {
+SOC_U::~SOC_U() {
CleanupSockets();
#ifdef _WIN32
WSACleanup();
#endif
}
-} // namespace
+} // namespace SOC
+} // namespace Service
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index 8d02ed30f..5f829fc1c 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -7,19 +7,18 @@
#include <string>
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SOC_U
+namespace Service {
+namespace SOC {
-namespace SOC_U {
-
-class Interface : public Service::Interface {
+class SOC_U final : public Interface {
public:
- Interface();
- ~Interface();
+ SOC_U();
+ ~SOC_U();
std::string GetPortName() const override {
return "soc:U";
}
};
-} // namespace
+} // namespace SOC
+} // namespace Service
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index b25be413a..3bd787147 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -2,14 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <tuple>
+
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/service/srv.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SRV
-
+namespace Service {
namespace SRV {
static Kernel::SharedPtr<Kernel::Event> event_handle;
@@ -23,7 +25,7 @@ static Kernel::SharedPtr<Kernel::Event> event_handle;
* 0: 0x00010040
* 1: ResultCode
*/
-static void RegisterClient(Service::Interface* self) {
+static void RegisterClient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
if (cmd_buff[1] != IPC::CallingPidDesc()) {
@@ -48,7 +50,7 @@ static void RegisterClient(Service::Interface* self) {
* 2: Translation descriptor: 0x20
* 3: Handle to semaphore signaled on process notification
*/
-static void EnableNotification(Service::Interface* self) {
+static void EnableNotification(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(bunnei): Change to a semaphore once these have been implemented
@@ -73,7 +75,7 @@ static void EnableNotification(Service::Interface* self) {
* 1: ResultCode
* 3: Service handle
*/
-static void GetServiceHandle(Service::Interface* self) {
+static void GetServiceHandle(Interface* self) {
ResultCode res = RESULT_SUCCESS;
u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -81,7 +83,15 @@ static void GetServiceHandle(Service::Interface* self) {
auto it = Service::g_srv_services.find(port_name);
if (it != Service::g_srv_services.end()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom();
+ auto client_port = it->second;
+
+ auto client_session = client_port->Connect();
+ res = client_session.Code();
+
+ if (client_session.Succeeded()) {
+ // Return the client session
+ cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom();
+ }
LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
} else {
LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
@@ -99,7 +109,7 @@ static void GetServiceHandle(Service::Interface* self) {
* 0: 0x00090040
* 1: ResultCode
*/
-static void Subscribe(Service::Interface* self) {
+static void Subscribe(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 notification_id = cmd_buff[1];
@@ -118,7 +128,7 @@ static void Subscribe(Service::Interface* self) {
* 0: 0x000A0040
* 1: ResultCode
*/
-static void Unsubscribe(Service::Interface* self) {
+static void Unsubscribe(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 notification_id = cmd_buff[1];
@@ -138,7 +148,7 @@ static void Unsubscribe(Service::Interface* self) {
* 0: 0x000C0040
* 1: ResultCode
*/
-static void PublishToSubscriber(Service::Interface* self) {
+static void PublishToSubscriber(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 notification_id = cmd_buff[1];
@@ -167,16 +177,14 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000E00C0, nullptr, "IsServiceRegistered"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+SRV::SRV() {
Register(FunctionTable);
event_handle = nullptr;
}
-Interface::~Interface() {
+SRV::~SRV() {
event_handle = nullptr;
}
} // namespace SRV
+} // namespace Service
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 96c89b025..d3a9de879 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -2,22 +2,23 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/service/service.h"
+#pragma once
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SRV
+#include "core/hle/service/service.h"
+namespace Service {
namespace SRV {
/// Interface to "srv:" service
-class Interface : public Service::Interface {
+class SRV final : public Interface {
public:
- Interface();
- ~Interface() override;
+ SRV();
+ ~SRV() override;
std::string GetPortName() const override {
return "srv:";
}
};
-} // namespace
+} // namespace SRV
+} // namespace Service
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index abab1d271..09ced9d7a 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -6,15 +6,13 @@
#include "common/common_types.h"
#include "core/hle/service/ssl_c.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SSL_C
-
-namespace SSL_C {
+namespace Service {
+namespace SSL {
// TODO: Implement a proper CSPRNG in the future when actual security is needed
static std::mt19937 rand_gen;
-static void Initialize(Service::Interface* self) {
+static void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// Seed random number generator when the SSL service is initialized
@@ -25,7 +23,7 @@ static void Initialize(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw;
}
-static void GenerateRandomData(Service::Interface* self) {
+static void GenerateRandomData(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
@@ -66,6 +64,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00050082, nullptr, "AddTrustedRootCA"},
{0x00060080, nullptr, "RootCertChainAddDefaultCert"},
{0x00070080, nullptr, "RootCertChainRemoveCert"},
+ {0x000D0084, nullptr, "OpenClientCertContext"},
{0x000E0040, nullptr, "OpenDefaultClientCertContext"},
{0x000F0040, nullptr, "CloseClientCertContext"},
{0x00110042, GenerateRandomData, "GenerateRandomData"},
@@ -73,19 +72,19 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00130040, nullptr, "StartConnection"},
{0x00140040, nullptr, "StartConnectionGetOut"},
{0x00150082, nullptr, "Read"},
+ {0x00160082, nullptr, "ReadPeek"},
{0x00170082, nullptr, "Write"},
{0x00180080, nullptr, "ContextSetRootCertChain"},
{0x00190080, nullptr, "ContextSetClientCert"},
{0x001B0080, nullptr, "ContextClearOpt"},
+ {0x001C00C4, nullptr, "ContextGetProtocolCipher"},
{0x001E0040, nullptr, "DestroyContext"},
{0x001F0082, nullptr, "ContextInitSharedmem"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+SSL_C::SSL_C() {
Register(FunctionTable);
}
-} // namespace
+} // namespace SSL_C
+} // namespace Service
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
index 58e87c1cb..fc50a2eb2 100644
--- a/src/core/hle/service/ssl_c.h
+++ b/src/core/hle/service/ssl_c.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SSL_C
+namespace Service {
+namespace SSL {
-namespace SSL_C {
-
-class Interface : public Service::Interface {
+class SSL_C final : public Interface {
public:
- Interface();
+ SSL_C();
std::string GetPortName() const override {
return "ssl:C";
}
};
-} // namespace
+} // namespace SSL
+} // namespace Service
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 097e09d28..a20194107 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -11,10 +11,8 @@
#include "core/hle/service/y2r_u.h"
#include "core/hw/y2r.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace Y2R_U
-
-namespace Y2R_U {
+namespace Service {
+namespace Y2R {
struct ConversionParameters {
InputFormat input_format;
@@ -83,7 +81,7 @@ ResultCode ConversionConfiguration::SetStandardCoefficient(
return RESULT_SUCCESS;
}
-static void SetInputFormat(Service::Interface* self) {
+static void SetInputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.input_format = static_cast<InputFormat>(cmd_buff[1]);
@@ -94,7 +92,7 @@ static void SetInputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
}
-static void GetInputFormat(Service::Interface* self) {
+static void GetInputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0);
@@ -104,7 +102,7 @@ static void GetInputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
}
-static void SetOutputFormat(Service::Interface* self) {
+static void SetOutputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.output_format = static_cast<OutputFormat>(cmd_buff[1]);
@@ -115,7 +113,7 @@ static void SetOutputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
}
-static void GetOutputFormat(Service::Interface* self) {
+static void GetOutputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x4, 2, 0);
@@ -125,7 +123,7 @@ static void GetOutputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
}
-static void SetRotation(Service::Interface* self) {
+static void SetRotation(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.rotation = static_cast<Rotation>(cmd_buff[1]);
@@ -136,7 +134,7 @@ static void SetRotation(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
}
-static void GetRotation(Service::Interface* self) {
+static void GetRotation(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x6, 2, 0);
@@ -146,7 +144,7 @@ static void GetRotation(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
}
-static void SetBlockAlignment(Service::Interface* self) {
+static void SetBlockAlignment(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.block_alignment = static_cast<BlockAlignment>(cmd_buff[1]);
@@ -157,7 +155,7 @@ static void SetBlockAlignment(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment);
}
-static void GetBlockAlignment(Service::Interface* self) {
+static void GetBlockAlignment(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
@@ -174,7 +172,7 @@ static void GetBlockAlignment(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetSpacialDithering(Service::Interface* self) {
+static void SetSpacialDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
spacial_dithering_enabled = cmd_buff[1] & 0xF;
@@ -190,7 +188,7 @@ static void SetSpacialDithering(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
-static void GetSpacialDithering(Service::Interface* self) {
+static void GetSpacialDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
@@ -207,7 +205,7 @@ static void GetSpacialDithering(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetTemporalDithering(Service::Interface* self) {
+static void SetTemporalDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
temporal_dithering_enabled = cmd_buff[1] & 0xF;
@@ -223,7 +221,7 @@ static void SetTemporalDithering(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
-static void GetTemporalDithering(Service::Interface* self) {
+static void GetTemporalDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
@@ -240,7 +238,7 @@ static void GetTemporalDithering(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetTransferEndInterrupt(Service::Interface* self) {
+static void SetTransferEndInterrupt(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
transfer_end_interrupt_enabled = cmd_buff[1] & 0xf;
@@ -256,7 +254,7 @@ static void SetTransferEndInterrupt(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
-static void GetTransferEndInterrupt(Service::Interface* self) {
+static void GetTransferEndInterrupt(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xE, 2, 0);
@@ -272,7 +270,7 @@ static void GetTransferEndInterrupt(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 3 : The handle of the completion event
*/
-static void GetTransferEndEvent(Service::Interface* self) {
+static void GetTransferEndEvent(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
@@ -282,7 +280,7 @@ static void GetTransferEndEvent(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void SetSendingY(Service::Interface* self) {
+static void SetSendingY(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_Y.address = cmd_buff[1];
@@ -299,7 +297,7 @@ static void SetSendingY(Service::Interface* self) {
cmd_buff[6]);
}
-static void SetSendingU(Service::Interface* self) {
+static void SetSendingU(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_U.address = cmd_buff[1];
@@ -316,7 +314,7 @@ static void SetSendingU(Service::Interface* self) {
cmd_buff[6]);
}
-static void SetSendingV(Service::Interface* self) {
+static void SetSendingV(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_V.address = cmd_buff[1];
@@ -333,7 +331,7 @@ static void SetSendingV(Service::Interface* self) {
cmd_buff[6]);
}
-static void SetSendingYUYV(Service::Interface* self) {
+static void SetSendingYUYV(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_YUYV.address = cmd_buff[1];
@@ -356,7 +354,7 @@ static void SetSendingYUYV(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingYuv(Service::Interface* self) {
+static void IsFinishedSendingYuv(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x14, 2, 0);
@@ -372,7 +370,7 @@ static void IsFinishedSendingYuv(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingY(Service::Interface* self) {
+static void IsFinishedSendingY(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x15, 2, 0);
@@ -388,7 +386,7 @@ static void IsFinishedSendingY(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingU(Service::Interface* self) {
+static void IsFinishedSendingU(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0);
@@ -404,7 +402,7 @@ static void IsFinishedSendingU(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingV(Service::Interface* self) {
+static void IsFinishedSendingV(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x17, 2, 0);
@@ -414,7 +412,7 @@ static void IsFinishedSendingV(Service::Interface* self) {
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
-static void SetReceiving(Service::Interface* self) {
+static void SetReceiving(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.dst.address = cmd_buff[1];
@@ -437,7 +435,7 @@ static void SetReceiving(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedReceiving(Service::Interface* self) {
+static void IsFinishedReceiving(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x19, 2, 0);
@@ -447,7 +445,7 @@ static void IsFinishedReceiving(Service::Interface* self) {
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
-static void SetInputLineWidth(Service::Interface* self) {
+static void SetInputLineWidth(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1A, 1, 0);
@@ -456,7 +454,7 @@ static void SetInputLineWidth(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]);
}
-static void GetInputLineWidth(Service::Interface* self) {
+static void GetInputLineWidth(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1B, 2, 0);
@@ -466,7 +464,7 @@ static void GetInputLineWidth(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_line_width=%u", conversion.input_line_width);
}
-static void SetInputLines(Service::Interface* self) {
+static void SetInputLines(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1C, 1, 0);
@@ -475,7 +473,7 @@ static void SetInputLines(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_lines=%u", cmd_buff[1]);
}
-static void GetInputLines(Service::Interface* self) {
+static void GetInputLines(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1D, 2, 0);
@@ -485,7 +483,7 @@ static void GetInputLines(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_lines=%u", conversion.input_lines);
}
-static void SetCoefficient(Service::Interface* self) {
+static void SetCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
const u16* coefficients = reinterpret_cast<const u16*>(&cmd_buff[1]);
@@ -499,7 +497,7 @@ static void SetCoefficient(Service::Interface* self) {
coefficients[5], coefficients[6], coefficients[7]);
}
-static void GetCoefficient(Service::Interface* self) {
+static void GetCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1F, 5, 0);
@@ -509,7 +507,7 @@ static void GetCoefficient(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void SetStandardCoefficient(Service::Interface* self) {
+static void SetStandardCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 index = cmd_buff[1];
@@ -520,7 +518,7 @@ static void SetStandardCoefficient(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", index);
}
-static void GetStandardCoefficient(Service::Interface* self) {
+static void GetStandardCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 index = cmd_buff[1];
@@ -539,7 +537,7 @@ static void GetStandardCoefficient(Service::Interface* self) {
}
}
-static void SetAlpha(Service::Interface* self) {
+static void SetAlpha(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.alpha = cmd_buff[1];
@@ -550,7 +548,7 @@ static void SetAlpha(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
}
-static void GetAlpha(Service::Interface* self) {
+static void GetAlpha(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x23, 2, 0);
@@ -560,7 +558,7 @@ static void GetAlpha(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
}
-static void SetDitheringWeightParams(Service::Interface* self) {
+static void SetDitheringWeightParams(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
std::memcpy(&dithering_weight_params, &cmd_buff[1], sizeof(DitheringWeightParams));
@@ -570,7 +568,7 @@ static void SetDitheringWeightParams(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void GetDitheringWeightParams(Service::Interface* self) {
+static void GetDitheringWeightParams(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x25, 9, 0);
@@ -580,7 +578,7 @@ static void GetDitheringWeightParams(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void StartConversion(Service::Interface* self) {
+static void StartConversion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
@@ -599,7 +597,7 @@ static void StartConversion(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void StopConversion(Service::Interface* self) {
+static void StopConversion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x27, 1, 0);
@@ -614,7 +612,7 @@ static void StopConversion(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : 1 if there's a conversion running, otherwise 0.
*/
-static void IsBusyConversion(Service::Interface* self) {
+static void IsBusyConversion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x28, 2, 0);
@@ -627,7 +625,7 @@ static void IsBusyConversion(Service::Interface* self) {
/**
* Y2R_U::SetPackageParameter service function
*/
-static void SetPackageParameter(Service::Interface* self) {
+static void SetPackageParameter(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
auto params = reinterpret_cast<const ConversionParameters*>(&cmd_buff[1]);
@@ -668,7 +666,7 @@ cleanup:
params->padding, params->alpha);
}
-static void PingProcess(Service::Interface* self) {
+static void PingProcess(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2A, 2, 0);
@@ -678,7 +676,7 @@ static void PingProcess(Service::Interface* self) {
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
-static void DriverInitialize(Service::Interface* self) {
+static void DriverInitialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.input_format = InputFormat::YUV422_Indiv8;
@@ -704,7 +702,7 @@ static void DriverInitialize(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void DriverFinalize(Service::Interface* self) {
+static void DriverFinalize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2C, 1, 0);
@@ -713,7 +711,7 @@ static void DriverFinalize(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void GetPackageParameter(Service::Interface* self) {
+static void GetPackageParameter(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2D, 4, 0);
@@ -771,18 +769,16 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002D0000, GetPackageParameter, "GetPackageParameter"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+Y2R_U::Y2R_U() {
completion_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Y2R:Completed");
std::memset(&conversion, 0, sizeof(conversion));
Register(FunctionTable);
}
-Interface::~Interface() {
+Y2R_U::~Y2R_U() {
completion_event = nullptr;
}
-} // namespace
+} // namespace Y2R
+} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 1b47b5322..dddeed0be 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -10,10 +10,8 @@
#include "core/hle/result.h"
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace Y2R_U
-
-namespace Y2R_U {
+namespace Service {
+namespace Y2R {
enum class InputFormat : u8 {
/// 8-bit input, with YUV components in separate planes and 4:2:2 subsampling.
@@ -127,14 +125,15 @@ struct DitheringWeightParams {
u16 w3_xOdd_yOdd;
};
-class Interface : public Service::Interface {
+class Y2R_U final : public Interface {
public:
- Interface();
- ~Interface() override;
+ Y2R_U();
+ ~Y2R_U() override;
std::string GetPortName() const override {
return "y2r:u";
}
};
-} // namespace
+} // namespace Y2R
+} // namespace Service
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index c6b80dc50..2ca270de3 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -13,6 +13,7 @@
#include "core/hle/function_wrappers.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
@@ -20,6 +21,7 @@
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@@ -41,6 +43,9 @@ const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
ErrorSummary::InvalidArgument,
ErrorLevel::Usage); // 0xE0E0181E
+const ResultCode ERR_SYNC_TIMEOUT(ErrorDescription::Timeout, ErrorModule::OS,
+ ErrorSummary::StatusChanged, ErrorLevel::Info);
+
const ResultCode ERR_MISALIGNED_ADDRESS{// 0xE0E01BF1
ErrorDescription::MisalignedAddress, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
@@ -161,7 +166,8 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
}
/// Maps a memory block to specified address
-static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
+static ResultCode MapMemoryBlock(Kernel::Handle handle, u32 addr, u32 permissions,
+ u32 other_permissions) {
using Kernel::SharedMemory;
using Kernel::MemoryPermission;
@@ -193,7 +199,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
}
-static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
+static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) {
using Kernel::SharedMemory;
LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr);
@@ -208,7 +214,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
}
/// Connect to an OS service given the port name, returns the handle to the port to out
-static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
+static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) {
if (port_name == nullptr)
return ERR_NOT_FOUND;
if (std::strlen(port_name) > 11)
@@ -222,54 +228,66 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
return ERR_NOT_FOUND;
}
- CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second));
+ auto client_port = it->second;
+
+ SharedPtr<Kernel::ClientSession> client_session;
+ CASCADE_RESULT(client_session, client_port->Connect());
+
+ // Return the client session
+ CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session));
return RESULT_SUCCESS;
}
-/// Synchronize to an OS service
-static ResultCode SendSyncRequest(Handle handle) {
- SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
+/// Makes a blocking IPC call to an OS service.
+static ResultCode SendSyncRequest(Kernel::Handle handle) {
+ SharedPtr<Kernel::ClientSession> session =
+ Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);
if (session == nullptr) {
return ERR_INVALID_HANDLE;
}
LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
- return session->SyncRequest().Code();
+ // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
+ // responds and cause a reschedule.
+ return session->SendSyncRequest();
}
/// Close a handle
-static ResultCode CloseHandle(Handle handle) {
+static ResultCode CloseHandle(Kernel::Handle handle) {
LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle);
return Kernel::g_handle_table.Close(handle);
}
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
-static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
+static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) {
auto object = Kernel::g_handle_table.GetWaitObject(handle);
Kernel::Thread* thread = Kernel::GetCurrentThread();
- thread->waitsynch_waited = false;
-
if (object == nullptr)
return ERR_INVALID_HANDLE;
LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,
object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds);
- HLE::Reschedule(__func__);
-
- // Check for next thread to schedule
if (object->ShouldWait()) {
+ if (nano_seconds == 0)
+ return ERR_SYNC_TIMEOUT;
+
object->AddWaitingThread(thread);
- Kernel::WaitCurrentThread_WaitSynchronization({object}, false, false);
+ // TODO(Subv): Perform things like update the mutex lock owner's priority to
+ // prevent priority inversion. Currently this is done in Mutex::ShouldWait,
+ // but it should be moved to a function that is called from here.
+ thread->status = THREADSTATUS_WAIT_SYNCH;
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
- // NOTE: output of this SVC will be set later depending on how the thread resumes
- return HLE::RESULT_INVALID;
+ // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread
+ // resumes due to a signal in its wait objects.
+ // Otherwise we retain the default value of timeout.
+ return ERR_SYNC_TIMEOUT;
}
object->Acquire();
@@ -278,13 +296,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
- s64 nano_seconds) {
- bool wait_thread = !wait_all;
- int handle_index = 0;
+static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count,
+ bool wait_all, s64 nano_seconds) {
Kernel::Thread* thread = Kernel::GetCurrentThread();
- bool was_waiting = thread->waitsynch_waited;
- thread->waitsynch_waited = false;
// Check if 'handles' is invalid
if (handles == nullptr)
@@ -300,94 +314,117 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
- // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if
- // necessary
- if (handle_count != 0) {
- bool selected = false; // True once an object has been selected
-
- Kernel::SharedPtr<Kernel::WaitObject> wait_object;
-
- for (int i = 0; i < handle_count; ++i) {
- auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
- if (object == nullptr)
- return ERR_INVALID_HANDLE;
-
- // Check if the current thread should wait on this object...
- if (object->ShouldWait()) {
-
- // Check we are waiting on all objects...
- if (wait_all)
- // Wait the thread
- wait_thread = true;
- } else {
- // Do not wait on this object, check if this object should be selected...
- if (!wait_all && (!selected || (wait_object == object && was_waiting))) {
- // Do not wait the thread
- wait_thread = false;
- handle_index = i;
- wait_object = object;
- selected = true;
- }
- }
- }
- } else {
- // If no handles were passed in, put the thread to sleep only when 'wait_all' is false
- // NOTE: This should deadlock the current thread if no timeout was specified
- if (!wait_all) {
- wait_thread = true;
- }
+ using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>;
+ std::vector<ObjectPtr> objects(handle_count);
+
+ for (int i = 0; i < handle_count; ++i) {
+ auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
+ if (object == nullptr)
+ return ERR_INVALID_HANDLE;
+ objects[i] = object;
}
- SCOPE_EXIT({
- HLE::Reschedule("WaitSynchronizationN");
- }); // Reschedule after putting the threads to sleep.
+ // Clear the mapping of wait object indices.
+ // We don't want any lingering state in this map.
+ // It will be repopulated later in the wait_all = false case.
+ thread->wait_objects_index.clear();
+
+ if (wait_all) {
+ bool all_available =
+ std::all_of(objects.begin(), objects.end(),
+ [](const ObjectPtr& object) { return !object->ShouldWait(); });
+ if (all_available) {
+ // We can acquire all objects right now, do so.
+ for (auto& object : objects)
+ object->Acquire();
+ // Note: In this case, the `out` parameter is not set,
+ // and retains whatever value it had before.
+ return RESULT_SUCCESS;
+ }
+
+ // Not all objects were available right now, prepare to suspend the thread.
- // If thread should wait, then set its state to waiting
- if (wait_thread) {
+ // If a timeout value of 0 was provided, just return the Timeout error code instead of
+ // suspending the thread.
+ if (nano_seconds == 0)
+ return ERR_SYNC_TIMEOUT;
- // Actually wait the current thread on each object if we decided to wait...
- std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
- wait_objects.reserve(handle_count);
+ // Put the thread to sleep
+ thread->status = THREADSTATUS_WAIT_SYNCH;
- for (int i = 0; i < handle_count; ++i) {
- auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
- object->AddWaitingThread(Kernel::GetCurrentThread());
- wait_objects.push_back(object);
+ // Add the thread to each of the objects' waiting threads.
+ for (auto& object : objects) {
+ object->AddWaitingThread(thread);
+ // TODO(Subv): Perform things like update the mutex lock owner's priority to
+ // prevent priority inversion. Currently this is done in Mutex::ShouldWait,
+ // but it should be moved to a function that is called from here.
}
- Kernel::WaitCurrentThread_WaitSynchronization(std::move(wait_objects), true, wait_all);
+ // Set the thread's waitlist to the list of objects passed to WaitSynchronizationN
+ thread->wait_objects = std::move(objects);
// Create an event to wake the thread up after the specified nanosecond delay has passed
- Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
-
- // NOTE: output of this SVC will be set later depending on how the thread resumes
- return HLE::RESULT_INVALID;
- }
+ thread->WakeAfterDelay(nano_seconds);
- // Acquire objects if we did not wait...
- for (int i = 0; i < handle_count; ++i) {
- auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
+ // This value gets set to -1 by default in this case, it is not modified after this.
+ *out = -1;
+ // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to
+ // a signal in one of its wait objects.
+ return ERR_SYNC_TIMEOUT;
+ } else {
+ // Find the first object that is acquirable in the provided list of objects
+ auto itr = std::find_if(objects.begin(), objects.end(),
+ [](const ObjectPtr& object) { return !object->ShouldWait(); });
- // Acquire the object if it is not waiting...
- if (!object->ShouldWait()) {
+ if (itr != objects.end()) {
+ // We found a ready object, acquire it and set the result value
+ Kernel::WaitObject* object = itr->get();
object->Acquire();
+ *out = std::distance(objects.begin(), itr);
+ return RESULT_SUCCESS;
+ }
+
+ // No objects were ready to be acquired, prepare to suspend the thread.
+
+ // If a timeout value of 0 was provided, just return the Timeout error code instead of
+ // suspending the thread.
+ if (nano_seconds == 0)
+ return ERR_SYNC_TIMEOUT;
+
+ // Put the thread to sleep
+ thread->status = THREADSTATUS_WAIT_SYNCH;
- // If this was the first non-waiting object and 'wait_all' is false, don't acquire
- // any other objects
- if (!wait_all)
- break;
+ // Clear the thread's waitlist, we won't use it for wait_all = false
+ thread->wait_objects.clear();
+
+ // Add the thread to each of the objects' waiting threads.
+ for (size_t i = 0; i < objects.size(); ++i) {
+ Kernel::WaitObject* object = objects[i].get();
+ // Set the index of this object in the mapping of Objects -> index for this thread.
+ thread->wait_objects_index[object->GetObjectId()] = static_cast<int>(i);
+ object->AddWaitingThread(thread);
+ // TODO(Subv): Perform things like update the mutex lock owner's priority to
+ // prevent priority inversion. Currently this is done in Mutex::ShouldWait,
+ // but it should be moved to a function that is called from here.
}
- }
- // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
- // not seem to set it to any meaningful value.
- *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0;
+ // Note: If no handles and no timeout were given, then the thread will deadlock, this is
+ // consistent with hardware behavior.
- return RESULT_SUCCESS;
+ // Create an event to wake the thread up after the specified nanosecond delay has passed
+ thread->WakeAfterDelay(nano_seconds);
+
+ // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
+ // signal in one of its wait objects.
+ // Otherwise we retain the default value of timeout, and -1 in the out parameter
+ thread->wait_set_output = true;
+ *out = -1;
+ return ERR_SYNC_TIMEOUT;
+ }
}
/// Create an address arbiter (to allocate access to shared resources)
-static ResultCode CreateAddressArbiter(Handle* out_handle) {
+static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) {
using Kernel::AddressArbiter;
SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create();
@@ -397,7 +434,7 @@ static ResultCode CreateAddressArbiter(Handle* out_handle) {
}
/// Arbitrate address
-static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value,
+static ResultCode ArbitrateAddress(Kernel::Handle handle, u32 address, u32 type, u32 value,
s64 nanoseconds) {
using Kernel::AddressArbiter;
@@ -440,7 +477,7 @@ static void OutputDebugString(const char* string) {
}
/// Get resource limit
-static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) {
+static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handle process_handle) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
SharedPtr<Kernel::Process> process =
@@ -454,7 +491,7 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle
}
/// Get resource limit current values
-static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle,
+static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle,
u32* names, u32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
@@ -471,8 +508,8 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim
}
/// Get resource limit max values
-static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names,
- u32 name_count) {
+static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle,
+ u32* names, u32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
@@ -488,7 +525,7 @@ static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit
}
/// Creates a new thread
-static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg,
+static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 entry_point, u32 arg,
u32 stack_top, s32 processor_id) {
using Kernel::Thread;
@@ -546,13 +583,13 @@ static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point
/// Called when a thread exits
static void ExitThread() {
- LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC());
+ LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC());
- Kernel::GetCurrentThread()->Stop();
+ Kernel::ExitCurrentThread();
}
/// Gets the priority for the specified thread
-static ResultCode GetThreadPriority(s32* priority, Handle handle) {
+static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) {
const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr)
return ERR_INVALID_HANDLE;
@@ -562,7 +599,7 @@ static ResultCode GetThreadPriority(s32* priority, Handle handle) {
}
/// Sets the priority for the specified thread
-static ResultCode SetThreadPriority(Handle handle, s32 priority) {
+static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) {
SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr)
return ERR_INVALID_HANDLE;
@@ -572,11 +609,11 @@ static ResultCode SetThreadPriority(Handle handle, s32 priority) {
}
/// Create a mutex
-static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
+static ResultCode CreateMutex(Kernel::Handle* out_handle, u32 initial_locked) {
using Kernel::Mutex;
SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0);
- mutex->name = Common::StringFromFormat("mutex-%08x", Core::g_app_core->GetReg(14));
+ mutex->name = Common::StringFromFormat("mutex-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex)));
LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
@@ -586,7 +623,7 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
}
/// Release a mutex
-static ResultCode ReleaseMutex(Handle handle) {
+static ResultCode ReleaseMutex(Kernel::Handle handle) {
using Kernel::Mutex;
LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle);
@@ -601,7 +638,7 @@ static ResultCode ReleaseMutex(Handle handle) {
}
/// Get the ID of the specified process
-static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
+static ResultCode GetProcessId(u32* process_id, Kernel::Handle process_handle) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
const SharedPtr<Kernel::Process> process =
@@ -614,7 +651,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
}
/// Get the ID of the process that owns the specified thread
-static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
+static ResultCode GetProcessIdOfThread(u32* process_id, Kernel::Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
const SharedPtr<Kernel::Thread> thread =
@@ -631,7 +668,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
}
/// Get the ID for the specified thread.
-static ResultCode GetThreadId(u32* thread_id, Handle handle) {
+static ResultCode GetThreadId(u32* thread_id, Kernel::Handle handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
@@ -643,11 +680,11 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) {
}
/// Creates a semaphore
-static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) {
+static ResultCode CreateSemaphore(Kernel::Handle* out_handle, s32 initial_count, s32 max_count) {
using Kernel::Semaphore;
CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count));
- semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::g_app_core->GetReg(14));
+ semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore)));
LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
@@ -656,7 +693,7 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max
}
/// Releases a certain number of slots in a semaphore
-static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
+static ResultCode ReleaseSemaphore(s32* count, Kernel::Handle handle, s32 release_count) {
using Kernel::Semaphore;
LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle);
@@ -672,7 +709,7 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
/// Query process memory
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info,
- Handle process_handle, u32 addr) {
+ Kernel::Handle process_handle, u32 addr) {
using Kernel::Process;
Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
if (process == nullptr)
@@ -700,11 +737,11 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32
}
/// Create an event
-static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
+static ResultCode CreateEvent(Kernel::Handle* out_handle, u32 reset_type) {
using Kernel::Event;
SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type));
- evt->name = Common::StringFromFormat("event-%08x", Core::g_app_core->GetReg(14));
+ evt->name = Common::StringFromFormat("event-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt)));
LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type,
@@ -713,14 +750,14 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
}
/// Duplicates a kernel handle
-static ResultCode DuplicateHandle(Handle* out, Handle handle) {
+static ResultCode DuplicateHandle(Kernel::Handle* out, Kernel::Handle handle) {
CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle));
LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out);
return RESULT_SUCCESS;
}
/// Signals an event
-static ResultCode SignalEvent(Handle handle) {
+static ResultCode SignalEvent(Kernel::Handle handle) {
using Kernel::Event;
LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
@@ -734,7 +771,7 @@ static ResultCode SignalEvent(Handle handle) {
}
/// Clears an event
-static ResultCode ClearEvent(Handle handle) {
+static ResultCode ClearEvent(Kernel::Handle handle) {
using Kernel::Event;
LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
@@ -747,11 +784,11 @@ static ResultCode ClearEvent(Handle handle) {
}
/// Creates a timer
-static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
+static ResultCode CreateTimer(Kernel::Handle* out_handle, u32 reset_type) {
using Kernel::Timer;
SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type));
- timer->name = Common::StringFromFormat("timer-%08x", Core::g_app_core->GetReg(14));
+ timer->name = Common::StringFromFormat("timer-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer)));
LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type,
@@ -760,7 +797,7 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
}
/// Clears a timer
-static ResultCode ClearTimer(Handle handle) {
+static ResultCode ClearTimer(Kernel::Handle handle) {
using Kernel::Timer;
LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
@@ -774,7 +811,7 @@ static ResultCode ClearTimer(Handle handle) {
}
/// Starts a timer
-static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
+static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) {
using Kernel::Timer;
LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
@@ -789,7 +826,7 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
}
/// Cancels a timer
-static ResultCode CancelTimer(Handle handle) {
+static ResultCode CancelTimer(Kernel::Handle handle) {
using Kernel::Timer;
LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
@@ -818,14 +855,13 @@ static void SleepThread(s64 nanoseconds) {
static s64 GetSystemTick() {
s64 result = CoreTiming::GetTicks();
// Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
- Core::g_app_core->AddTicks(
- 150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
+ Core::CPU().AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
return result;
}
/// Creates a memory block at the specified address with the specified permissions and size
-static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
- u32 other_permission) {
+static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 size,
+ u32 my_permission, u32 other_permission) {
using Kernel::SharedMemory;
if (size % Memory::PAGE_SIZE != 0)
@@ -876,8 +912,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
return RESULT_SUCCESS;
}
-static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name,
- u32 max_sessions) {
+static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port,
+ const char* name, u32 max_sessions) {
// TODO(Subv): Implement named ports.
ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented");
@@ -942,7 +978,7 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
return RESULT_SUCCESS;
}
-static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
+static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 type) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
using Kernel::Process;
@@ -1148,6 +1184,8 @@ void CallSVC(u32 immediate) {
if (info) {
if (info->func) {
info->func();
+ // TODO(Subv): Not all service functions should cause a reschedule in all cases.
+ Core::System::GetInstance().PrepareReschedule();
} else {
LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
}
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index cfba82e51..1a1ee90b2 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -430,9 +430,9 @@ inline void Write(u32 addr, const T data) {
// TODO: hwtest this
if (config.GetStartAddress() != 0) {
if (!is_second_filler) {
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PSC0);
} else {
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PSC1);
}
}
@@ -473,7 +473,7 @@ inline void Write(u32 addr, const T data) {
}
g_regs.display_transfer_config.trigger = 0;
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PPF);
}
break;
}
@@ -487,8 +487,8 @@ inline void Write(u32 addr, const T data) {
u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
- Pica::g_debug_context->recorder->MemoryAccessed(
- (u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress());
+ Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size,
+ config.GetPhysicalAddress());
}
Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
@@ -548,8 +548,8 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
// screen, or if both use the same interrupts and these two instead determine the
// beginning and end of the VBlank period. If needed, split the interrupt firing into
// two different intervals.
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1);
// Check for user input updates
Service::HID::Update();
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp
index 6a6c707a2..e697f84b3 100644
--- a/src/core/hw/y2r.cpp
+++ b/src/core/hw/y2r.cpp
@@ -18,7 +18,7 @@
namespace HW {
namespace Y2R {
-using namespace Y2R_U;
+using namespace Service::Y2R;
static const size_t MAX_TILES = 1024 / 8;
static const size_t TILE_SIZE = 8 * 8;
diff --git a/src/core/hw/y2r.h b/src/core/hw/y2r.h
index 6b6e71bec..25fcd781c 100644
--- a/src/core/hw/y2r.h
+++ b/src/core/hw/y2r.h
@@ -2,13 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-namespace Y2R_U {
+#pragma once
+
+namespace Service {
+namespace Y2R {
struct ConversionConfiguration;
}
+}
namespace HW {
namespace Y2R {
-
-void PerformConversion(Y2R_U::ConversionConfiguration& cvt);
+void PerformConversion(Service::Y2R::ConversionConfiguration& cvt);
}
}
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index cfcc21cc4..3f376778a 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -27,34 +27,14 @@ public:
*/
static FileType IdentifyType(FileUtil::IOFile& file);
- /**
- * Returns the type of this file
- * @return FileType corresponding to the loaded file
- */
FileType GetFileType() override {
return IdentifyType(file);
}
- /**
- * Load the bootable file
- * @return ResultStatus result of function
- */
ResultStatus Load() override;
- /**
- * Get the icon (typically icon section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
- /**
- * Get the RomFS of the application
- * @param romfs_file Reference to buffer to store data
- * @param offset Offset in the file to the RomFS
- * @param size Size of the RomFS in bytes
- * @return ResultStatus result of function
- */
ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
u64& size) override;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 584bf6e27..862aa90d8 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -26,18 +26,10 @@ public:
*/
static FileType IdentifyType(FileUtil::IOFile& file);
- /**
- * Returns the type of this file
- * @return FileType corresponding to the loaded file
- */
FileType GetFileType() override {
return IdentifyType(file);
}
- /**
- * Load the bootable file
- * @return ResultStatus result of function
- */
ResultStatus Load() override;
private:
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 5e3d46638..a6c2a745f 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -144,6 +144,15 @@ public:
}
/**
+ * Get the program id of the application
+ * @param out_program_id Reference to store program id into
+ * @return ResultStatus result of function
+ */
+ virtual ResultStatus ReadProgramId(u64& out_program_id) {
+ return ResultStatus::ErrorNotImplemented;
+ }
+
+ /**
* Get the RomFS of the application
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer
* @param romfs_file The file containing the RomFS
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index dce7f50f9..a204dc336 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -366,6 +366,18 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
return LoadSectionExeFS("logo", buffer);
}
+ResultStatus AppLoader_NCCH::ReadProgramId(u64& out_program_id) {
+ if (!file.IsOpen())
+ return ResultStatus::Error;
+
+ ResultStatus result = LoadExeFS();
+ if (result != ResultStatus::Success)
+ return result;
+
+ out_program_id = ncch_header.program_id;
+ return ResultStatus::Success;
+}
+
ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
u64& size) {
if (!file.IsOpen())
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index e9e11727b..fe08f5b45 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -171,18 +171,10 @@ public:
*/
static FileType IdentifyType(FileUtil::IOFile& file);
- /**
- * Returns the type of this file
- * @return FileType corresponding to the loaded file
- */
FileType GetFileType() override {
return IdentifyType(file);
}
- /**
- * Load the application
- * @return ResultStatus result of function
- */
ResultStatus Load() override;
/**
@@ -191,33 +183,20 @@ public:
*/
boost::optional<u32> LoadKernelSystemMode();
- /**
- * Get the code (typically .code section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadCode(std::vector<u8>& buffer) override;
- /**
- * Get the icon (typically icon section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
- /**
- * Get the banner (typically banner section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
+ ResultStatus ReadLogo(std::vector<u8>& buffer) override;
+
/**
- * Get the logo (typically logo section) of the application
- * @param buffer Reference to buffer to store data
+ * Get the program id of the application
+ * @param out_program_id Reference to store program id into
* @return ResultStatus result of function
*/
- ResultStatus ReadLogo(std::vector<u8>& buffer) override;
+ ResultStatus ReadProgramId(u64& out_program_id) override;
/**
* Get the RomFS of the application
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 626e06cd9..5d23c52f9 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -7,7 +7,7 @@
#include "settings.h"
#include "video_core/video_core.h"
-#include "common/emu_window.h"
+#include "core/frontend/emu_window.h"
namespace Settings {
diff --git a/src/core/system.cpp b/src/core/system.cpp
deleted file mode 100644
index a5f763805..000000000
--- a/src/core/system.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "audio_core/audio_core.h"
-#include "core/core.h"
-#include "core/core_timing.h"
-#include "core/gdbstub/gdbstub.h"
-#include "core/hle/hle.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory.h"
-#include "core/hw/hw.h"
-#include "core/system.h"
-#include "video_core/video_core.h"
-
-namespace System {
-
-static bool is_powered_on{false};
-
-Result Init(EmuWindow* emu_window, u32 system_mode) {
- Core::Init();
- CoreTiming::Init();
- Memory::Init();
- HW::Init();
- Kernel::Init(system_mode);
- HLE::Init();
- if (!VideoCore::Init(emu_window)) {
- return Result::ErrorInitVideoCore;
- }
- AudioCore::Init();
- GDBStub::Init();
-
- is_powered_on = true;
-
- return Result::Success;
-}
-
-bool IsPoweredOn() {
- return is_powered_on;
-}
-
-void Shutdown() {
- GDBStub::Shutdown();
- AudioCore::Shutdown();
- VideoCore::Shutdown();
- HLE::Shutdown();
- Kernel::Shutdown();
- HW::Shutdown();
- CoreTiming::Shutdown();
- Core::Shutdown();
-
- is_powered_on = false;
-}
-
-} // namespace
diff --git a/src/core/system.h b/src/core/system.h
deleted file mode 100644
index b41fc088a..000000000
--- a/src/core/system.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-class EmuWindow;
-
-namespace System {
-
-enum class Result {
- Success, ///< Everything is fine
- Error, ///< Something went wrong (no module specified)
- ErrorInitCore, ///< Something went wrong during core init
- ErrorInitVideoCore, ///< Something went wrong during video core init
-};
-
-Result Init(EmuWindow* emu_window, u32 system_mode);
-bool IsPoweredOn();
-void Shutdown();
-}