summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rwxr-xr-x.travis-build.sh2
-rwxr-xr-x.travis-deps.sh7
-rw-r--r--.travis.yml4
-rw-r--r--CMakeLists.txt23
-rw-r--r--dist/citra-qt.640
-rw-r--r--dist/citra.649
-rw-r--r--externals/CMakeLists.txt8
m---------externals/dynarmic0
m---------externals/xbyak0
-rw-r--r--src/audio_core/audio_core.cpp23
-rw-r--r--src/audio_core/hle/pipe.cpp2
-rw-r--r--src/audio_core/time_stretch.h2
-rw-r--r--src/citra/citra.cpp2
-rw-r--r--src/citra/citra.rc2
-rw-r--r--src/citra/config.cpp2
-rw-r--r--src/citra/default_ini.h4
-rw-r--r--src/citra_qt/bootmanager.h4
-rw-r--r--src/citra_qt/citra-qt.rc2
-rw-r--r--src/citra_qt/config.cpp2
-rw-r--r--src/citra_qt/configure_graphics.cpp2
-rw-r--r--src/citra_qt/configure_graphics.ui7
-rw-r--r--src/citra_qt/configure_input.cpp169
-rw-r--r--src/citra_qt/configure_input.h47
-rw-r--r--src/citra_qt/debugger/callstack.h4
-rw-r--r--src/citra_qt/debugger/disassembler.h2
-rw-r--r--src/citra_qt/debugger/graphics.cpp16
-rw-r--r--src/citra_qt/debugger/graphics.h2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.h4
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp42
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.h4
-rw-r--r--src/citra_qt/debugger/graphics_surface.h7
-rw-r--r--src/citra_qt/debugger/graphics_tracing.h4
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.h2
-rw-r--r--src/citra_qt/debugger/profiler.h6
-rw-r--r--src/citra_qt/debugger/ramview.h4
-rw-r--r--src/citra_qt/debugger/registers.h4
-rw-r--r--src/citra_qt/debugger/wait_tree.cpp1
-rw-r--r--src/citra_qt/debugger/wait_tree.h26
-rw-r--r--src/citra_qt/game_list.cpp18
-rw-r--r--src/citra_qt/game_list.h13
-rw-r--r--src/citra_qt/hotkeys.h2
-rw-r--r--src/citra_qt/util/spinbox.h2
-rw-r--r--src/common/CMakeLists.txt8
-rw-r--r--src/common/bit_set.h2
-rw-r--r--src/common/file_util.cpp11
-rw-r--r--src/common/logging/text_formatter.cpp2
-rw-r--r--src/common/string_util.cpp2
-rw-r--r--src/common/thread.cpp2
-rw-r--r--src/common/timer.cpp3
-rw-r--r--src/common/x64/xbyak_abi.h178
-rw-r--r--src/common/x64/xbyak_util.h49
-rw-r--r--src/core/CMakeLists.txt47
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp1
-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.cpp2
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp2
-rw-r--r--src/core/file_sys/archive_ncch.h2
-rw-r--r--src/core/file_sys/archive_other_savedata.cpp145
-rw-r--r--src/core/file_sys/archive_other_savedata.h52
-rw-r--r--src/core/file_sys/archive_romfs.h2
-rw-r--r--src/core/file_sys/archive_savedata.cpp79
-rw-r--r--src/core/file_sys/archive_savedata.h8
-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.cpp93
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.h30
-rw-r--r--src/core/file_sys/archive_systemsavedata.h2
-rw-r--r--src/core/file_sys/errors.h3
-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/gdbstub/gdbstub.cpp24
-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/ipc.h (renamed from src/core/hle/kernel/session.h)96
-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.h37
-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/result.h2
-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.cpp22
-rw-r--r--src/core/hle/service/csnd_snd.h21
-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.cpp72
-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.cpp56
-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.cpp3
-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/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.cpp32
-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.cpp48
-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_uds.cpp32
-rw-r--r--src/core/hle/service/nwm_uds.h17
-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.cpp148
-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.cpp19
-rw-r--r--src/core/hw/gpu.cpp47
-rw-r--r--src/core/hw/y2r.cpp2
-rw-r--r--src/core/hw/y2r.h9
-rw-r--r--src/core/memory.cpp10
-rw-r--r--src/core/settings.cpp1
-rw-r--r--src/core/settings.h1
-rw-r--r--src/tests/CMakeLists.txt2
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/command_processor.cpp6
-rw-r--r--src/video_core/gpu_debugger.h11
-rw-r--r--src/video_core/pica.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp33
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp31
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_state.h3
-rw-r--r--src/video_core/shader/shader.cpp2
-rw-r--r--src/video_core/shader/shader.h2
-rw-r--r--src/video_core/shader/shader_jit_x64.cpp439
-rw-r--r--src/video_core/shader/shader_jit_x64.h16
-rw-r--r--src/video_core/video_core.cpp1
-rw-r--r--src/video_core/video_core.h1
229 files changed, 3663 insertions, 1565 deletions
diff --git a/.gitmodules b/.gitmodules
index f498a60de..dbb1b0dd3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,3 +16,6 @@
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
+[submodule "xbyak"]
+ path = externals/xbyak
+ url = https://github.com/herumi/xbyak.git
diff --git a/.travis-build.sh b/.travis-build.sh
index 3310bacc5..df6e236b6 100755
--- a/.travis-build.sh
+++ b/.travis-build.sh
@@ -12,7 +12,7 @@ fi
# Only run clang-format on Linux because we don't have 4.0 on OS X images
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# Default clang-format points to default 3.5 version one
- CLANG_FORMAT=clang-format-4.0
+ CLANG_FORMAT=clang-format-3.9
$CLANG_FORMAT --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
diff --git a/.travis-deps.sh b/.travis-deps.sh
index 9fd21cc57..1404fe19f 100755
--- a/.travis-deps.sh
+++ b/.travis-deps.sh
@@ -27,6 +27,13 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
echo "Using cached SDL2"
fi
+ export DEBIAN_FRONTEND=noninteractive
+ # Amazing placebo security
+ curl http://apt.llvm.org/llvm-snapshot.gpg.key | sudo -E apt-key add -
+ sudo -E add-apt-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main"
+ sudo -E apt-get -yq update
+ sudo -E apt-get -yq install clang-format-3.9
+
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update
brew install qt5 sdl2 dylibbundler
diff --git a/.travis.yml b/.travis.yml
index a9e7aadd2..cc34e039c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,7 @@ language: cpp
matrix:
include:
- os: linux
- sudo: true
+ sudo: required
dist: trusty
- os: osx
sudo: false
@@ -17,7 +17,6 @@ addons:
apt:
sources:
- ubuntu-toolchain-r-test
- - llvm-toolchain-precise
packages:
- gcc-6
- g++-6
@@ -25,7 +24,6 @@ addons:
- libqt5opengl5-dev
- xorg-dev
- lib32stdc++6 # For CMake
- - clang-format-4.0
cache:
directories:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33d18f5ea..bcee98a5f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,6 +71,9 @@ if (NOT MSVC)
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
+ # Microprofile causes crashes when launching titles on MinGW
+ add_definitions(-DMICROPROFILE_ENABLED=0)
+
if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")
@@ -180,8 +183,10 @@ IF (APPLE)
FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
+ endif()
ELSEIF (WIN32)
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
@@ -251,6 +256,8 @@ set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
include_directories(${INI_PREFIX})
add_subdirectory(${INI_PREFIX})
+add_subdirectory(externals)
+
option(DYNARMIC_TESTS OFF)
add_subdirectory(externals/dynarmic)
@@ -286,3 +293,15 @@ if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.xml"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")
endif()
+
+if(UNIX)
+ if(ENABLE_SDL2)
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.6"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man6")
+ endif()
+
+ if (ENABLE_QT)
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra-qt.6"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man6")
+ endif()
+endif()
diff --git a/dist/citra-qt.6 b/dist/citra-qt.6
new file mode 100644
index 000000000..d09e96b5d
--- /dev/null
+++ b/dist/citra-qt.6
@@ -0,0 +1,40 @@
+.Dd November 22 2016
+.Dt citra-qt 6
+.Os
+.Sh NAME
+.Nm Citra-Qt
+.Nd Nintendo 3DS Emulator/Debugger (Qt)
+.Sh SYNOPSIS
+.Nm citra-qt
+.Op Ar file
+.Sh DESCRIPTION
+Citra is an experimental open-source Nintendo 3DS emulator/debugger.
+.Pp
+.Nm citra-qt
+is the Qt implementation.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $XDG_DATA_HOME/citra-emu
+Emulator storage.
+.It Pa $XDG_CONFIG_HOME/citra-emu
+Configuration files.
+.El
+.Sh AUTHORS
+This document is made available to you under the CC-BY license.
+.Pp
+Citra is made by a team of volunteers. These contributors are listed
+ at <\fBhttps://github.com/citra-emu/citra/contributors\fR>.
+.Pp
+.Sh SEE ALSO
+.Bl -tag -width Ds
+.It Xr citra 6
+The SDL frontend of the application
+.El
+.Pp
+Resources are available for this project:
+.Bl -tag -width Ds
+.It <\fBhttps://citra-emu.org\fR>
+The main homepage of the project.
+.It <\fBhttps://github.com/citra-emu/citra\fR>
+The main source code repository for the Citra emulator.
+.Pp
diff --git a/dist/citra.6 b/dist/citra.6
new file mode 100644
index 000000000..72483b1dd
--- /dev/null
+++ b/dist/citra.6
@@ -0,0 +1,49 @@
+.Dd November 22 2016
+.Dt citra 6
+.Os
+.Sh NAME
+.Nm Citra
+.Nd Nintendo 3DS Emulator/Debugger (SDL)
+.Sh SYNOPSIS
+.Nm citra
+.Op Ar options
+.Op Ar file
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl g Ar port , Fl Fl gdbport Ar port
+Starts the GDB stub on the specified port
+.It Fl h , Fl Fl help
+Shows syntax help and exits
+.It Fl v , Fl Fl version
+Describes the installed version and exits
+.Sh DESCRIPTION
+Citra is an experimental open-source Nintendo 3DS emulator/debugger.
+.Pp
+.Nm citra
+is the Simple DirectMedia Layer (SDL) implementation.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $XDG_DATA_HOME/citra-emu
+Emulator storage.
+.It Pa $XDG_CONFIG_HOME/citra-emu
+Configuration files.
+.El
+.Sh AUTHORS
+This document is made available to you under the CC-BY license.
+.Pp
+Citra is made by a team of volunteers. These contributors are listed
+ at <\fBhttps://github.com/citra-emu/citra/contributors\fR>.
+.Pp
+.Sh SEE ALSO
+.Bl -tag -width Ds
+.It Xr citra-qt 6
+The Qt frontend of the application
+.El
+.Pp
+Resources are available for this project:
+.Bl -tag -width Ds
+.It <\fBhttps://citra-emu.org\fR>
+The main homepage of the project.
+.It <\fBhttps://github.com/citra-emu/citra\fR>
+The main source code repository for the Citra emulator.
+.Pp
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
new file mode 100644
index 000000000..7e4b05ffc
--- /dev/null
+++ b/externals/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Xbyak
+if (ARCHITECTURE_x86_64)
+ add_library(xbyak INTERFACE)
+ target_include_directories(xbyak INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak)
+ if (NOT MSVC)
+ target_compile_options(xbyak INTERFACE -fno-operator-names)
+ endif()
+endif()
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject 5f11b4f50e285a7f6c4504e1966abeddff61b7a
+Subproject 34e19f135c0dd2feac4f77660f51aa4ea28a738
diff --git a/externals/xbyak b/externals/xbyak
new file mode 160000
+Subproject fe4765d2fed4e990ea5e9661b6bc5fc9bf48ec1
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index 49260de7c..ba6acf28e 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -23,9 +23,9 @@ static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
if (DSP::HLE::Tick()) {
// TODO(merry): Signal all the other interrupts as appropriate.
- DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
+ Service::DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
// HACK(merry): Added to prevent regressions. Will remove soon.
- DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Binary);
+ Service::DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Binary);
}
// Reschedule recurrent event
@@ -56,22 +56,17 @@ void AddAddressSpace(Kernel::VMManager& address_space) {
}
void SelectSink(std::string sink_id) {
- if (sink_id == "auto") {
- // Auto-select.
- // g_sink_details is ordered in terms of desirability, with the best choice at the front.
- const auto& sink_detail = g_sink_details.front();
- DSP::HLE::SetSink(sink_detail.factory());
- return;
- }
-
auto iter =
std::find_if(g_sink_details.begin(), g_sink_details.end(),
[sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
- if (iter == g_sink_details.end()) {
- LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id");
- DSP::HLE::SetSink(std::make_unique<NullSink>());
- return;
+ if (sink_id == "auto" || iter == g_sink_details.end()) {
+ if (sink_id != "auto") {
+ LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
+ }
+ // Auto-select.
+ // g_sink_details is ordered in terms of desirability, with the best choice at the front.
+ iter = g_sink_details.begin();
}
DSP::HLE::SetSink(iter->factory());
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
index bc69acbc2..24074a514 100644
--- a/src/audio_core/hle/pipe.cpp
+++ b/src/audio_core/hle/pipe.cpp
@@ -104,7 +104,7 @@ static void AudioPipeWriteStructAddresses() {
WriteU16(DspPipe::Audio, addr);
}
// Signal that we have data on this pipe.
- DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
+ Service::DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
}
void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h
index fa81718ed..e3e4dc353 100644
--- a/src/audio_core/time_stretch.h
+++ b/src/audio_core/time_stretch.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <cstddef>
#include <memory>
#include <vector>
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index f9387e61c..3114a71db 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -18,7 +18,7 @@
#endif
#ifdef _WIN32
-#include <Windows.h>
+#include <windows.h>
#endif
#include "citra/config.h"
diff --git a/src/citra/citra.rc b/src/citra/citra.rc
index b0edb2e6b..fea603004 100644
--- a/src/citra/citra.rc
+++ b/src/citra/citra.rc
@@ -5,5 +5,5 @@
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
-GLFW_ICON ICON "..\\..\\dist\\citra.ico"
+CITRA_ICON ICON "../../dist/citra.ico"
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index fe74fcd72..29462c982 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -66,6 +66,8 @@ void Config::ReadValues() {
Settings::values.use_scaled_resolution =
sdl2_config->GetBoolean("Renderer", "use_scaled_resolution", false);
Settings::values.use_vsync = sdl2_config->GetBoolean("Renderer", "use_vsync", false);
+ Settings::values.toggle_framelimit =
+ sdl2_config->GetBoolean("Renderer", "toggle_framelimit", true);
Settings::values.bg_red = (float)sdl2_config->GetReal("Renderer", "bg_red", 1.0);
Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 1.0);
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index b98dc4d83..001b18ac2 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -64,6 +64,10 @@ use_vsync =
# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen
layout_option =
+#Whether to toggle frame limiter on or off.
+# 0: Off , 1 (default): On
+toggle_framelimit =
+
# Swaps the prominent screen with the other screen.
# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen.
# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 67228b94f..af52f369b 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <atomic>
#include <condition_variable>
#include <mutex>
@@ -21,7 +23,7 @@ class EmuThread : public QThread {
Q_OBJECT
public:
- EmuThread(GRenderWindow* render_window);
+ explicit EmuThread(GRenderWindow* render_window);
/**
* Start emulation (on new thread)
diff --git a/src/citra_qt/citra-qt.rc b/src/citra_qt/citra-qt.rc
index 3c7239853..fea603004 100644
--- a/src/citra_qt/citra-qt.rc
+++ b/src/citra_qt/citra-qt.rc
@@ -5,5 +5,5 @@
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
-IDI_ICON1 ICON "..\\..\\dist\\citra.ico"
+CITRA_ICON ICON "../../dist/citra.ico"
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 3cdfe6443..06a4e9d25 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -47,6 +47,7 @@ void Config::ReadValues() {
Settings::values.use_scaled_resolution =
qt_config->value("use_scaled_resolution", false).toBool();
Settings::values.use_vsync = qt_config->value("use_vsync", false).toBool();
+ Settings::values.toggle_framelimit = qt_config->value("toggle_framelimit", true).toBool();
Settings::values.bg_red = qt_config->value("bg_red", 1.0).toFloat();
Settings::values.bg_green = qt_config->value("bg_green", 1.0).toFloat();
@@ -152,6 +153,7 @@ void Config::SaveValues() {
qt_config->setValue("use_shader_jit", Settings::values.use_shader_jit);
qt_config->setValue("use_scaled_resolution", Settings::values.use_scaled_resolution);
qt_config->setValue("use_vsync", Settings::values.use_vsync);
+ qt_config->setValue("toggle_framelimit", Settings::values.toggle_framelimit);
// Cast to double because Qt's written float values are not human-readable
qt_config->setValue("bg_red", (double)Settings::values.bg_red);
diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp
index 29834e11b..36f10c8d7 100644
--- a/src/citra_qt/configure_graphics.cpp
+++ b/src/citra_qt/configure_graphics.cpp
@@ -23,6 +23,7 @@ void ConfigureGraphics::setConfiguration() {
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit);
ui->toggle_scaled_resolution->setChecked(Settings::values.use_scaled_resolution);
ui->toggle_vsync->setChecked(Settings::values.use_vsync);
+ ui->toggle_framelimit->setChecked(Settings::values.toggle_framelimit);
ui->layout_combobox->setCurrentIndex(static_cast<int>(Settings::values.layout_option));
ui->swap_screen->setChecked(Settings::values.swap_screen);
}
@@ -32,6 +33,7 @@ void ConfigureGraphics::applyConfiguration() {
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();
Settings::values.use_scaled_resolution = ui->toggle_scaled_resolution->isChecked();
Settings::values.use_vsync = ui->toggle_vsync->isChecked();
+ Settings::values.toggle_framelimit = ui->toggle_framelimit->isChecked();
Settings::values.layout_option =
static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex());
Settings::values.swap_screen = ui->swap_screen->isChecked();
diff --git a/src/citra_qt/configure_graphics.ui b/src/citra_qt/configure_graphics.ui
index af16a4292..964aa0bbd 100644
--- a/src/citra_qt/configure_graphics.ui
+++ b/src/citra_qt/configure_graphics.ui
@@ -50,6 +50,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="toggle_framelimit">
+ <property name="text">
+ <string>Limit framerate</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp
index d321db71f..3e6803b8a 100644
--- a/src/citra_qt/configure_input.cpp
+++ b/src/citra_qt/configure_input.cpp
@@ -5,15 +5,33 @@
#include <memory>
#include <utility>
#include <QTimer>
+#include "citra_qt/config.h"
#include "citra_qt/configure_input.h"
+static QString getKeyName(Qt::Key key_code) {
+ switch (key_code) {
+ case Qt::Key_Shift:
+ return QObject::tr("Shift");
+ case Qt::Key_Control:
+ return QObject::tr("Ctrl");
+ case Qt::Key_Alt:
+ return QObject::tr("Alt");
+ case Qt::Key_Meta:
+ case -1:
+ return "";
+ default:
+ return QKeySequence(key_code).toString();
+ }
+}
+
ConfigureInput::ConfigureInput(QWidget* parent)
- : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
+ timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
+ setFocusPolicy(Qt::ClickFocus);
- // Initialize mapping of input enum to UI button.
- input_mapping = {
+ button_map = {
{Settings::NativeInput::Values::A, ui->buttonA},
{Settings::NativeInput::Values::B, ui->buttonB},
{Settings::NativeInput::Values::X, ui->buttonX},
@@ -40,114 +58,89 @@ ConfigureInput::ConfigureInput(QWidget* parent)
{Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod},
};
- // Attach handle click method to each button click.
- for (const auto& entry : input_mapping) {
- connect(entry.second, SIGNAL(released()), this, SLOT(handleClick()));
+ for (const auto& entry : button_map) {
+ const Settings::NativeInput::Values input_id = entry.first;
+ connect(entry.second, &QPushButton::released,
+ [this, input_id]() { handleClick(input_id); });
}
- connect(ui->buttonRestoreDefaults, SIGNAL(released()), this, SLOT(restoreDefaults()));
- setFocusPolicy(Qt::ClickFocus);
- timer = new QTimer(this);
+
+ connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
+
timer->setSingleShot(true);
- connect(timer, &QTimer::timeout, this, [&]() {
- key_pressed = Qt::Key_Escape;
- setKey();
+ connect(timer.get(), &QTimer::timeout, [this]() {
+ releaseKeyboard();
+ releaseMouse();
+ current_input_id = boost::none;
+ updateButtonLabels();
});
- this->setConfiguration();
-}
-void ConfigureInput::handleClick() {
- QPushButton* sender = qobject_cast<QPushButton*>(QObject::sender());
- previous_mapping = sender->text();
- sender->setText(tr("[waiting]"));
- sender->setFocus();
- grabKeyboard();
- grabMouse();
- changing_button = sender;
- timer->start(5000); // Cancel after 5 seconds
+ this->loadConfiguration();
}
void ConfigureInput::applyConfiguration() {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- int value = getKeyValue(input_mapping[Settings::NativeInput::Values(i)]->text());
- Settings::values.input_mappings[Settings::NativeInput::All[i]] = value;
+ for (const auto& input_id : Settings::NativeInput::All) {
+ const size_t index = static_cast<size_t>(input_id);
+ Settings::values.input_mappings[index] = static_cast<int>(key_map[input_id]);
}
Settings::Apply();
}
-void ConfigureInput::setConfiguration() {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- QString keyValue = getKeyName(Settings::values.input_mappings[i]);
- input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue);
+void ConfigureInput::loadConfiguration() {
+ for (const auto& input_id : Settings::NativeInput::All) {
+ const size_t index = static_cast<size_t>(input_id);
+ key_map[input_id] = static_cast<Qt::Key>(Settings::values.input_mappings[index]);
}
+ updateButtonLabels();
}
-void ConfigureInput::keyPressEvent(QKeyEvent* event) {
- if (!changing_button)
- return;
- if (!event || event->key() == Qt::Key_unknown)
- return;
- key_pressed = event->key();
- timer->stop();
- setKey();
+void ConfigureInput::restoreDefaults() {
+ for (const auto& input_id : Settings::NativeInput::All) {
+ const size_t index = static_cast<size_t>(input_id);
+ key_map[input_id] = static_cast<Qt::Key>(Config::defaults[index].toInt());
+ }
+ updateButtonLabels();
+ applyConfiguration();
}
-void ConfigureInput::setKey() {
- const QString key_value = getKeyName(key_pressed);
- if (key_pressed == Qt::Key_Escape)
- changing_button->setText(previous_mapping);
- else
- changing_button->setText(key_value);
- removeDuplicates(key_value);
- key_pressed = Qt::Key_unknown;
- releaseKeyboard();
- releaseMouse();
- changing_button = nullptr;
- previous_mapping = nullptr;
+void ConfigureInput::updateButtonLabels() {
+ for (const auto& input_id : Settings::NativeInput::All) {
+ button_map[input_id]->setText(getKeyName(key_map[input_id]));
+ }
}
-QString ConfigureInput::getKeyName(int key_code) const {
- if (key_code == Qt::Key_Shift)
- return tr("Shift");
- if (key_code == Qt::Key_Control)
- return tr("Ctrl");
- if (key_code == Qt::Key_Alt)
- return tr("Alt");
- if (key_code == Qt::Key_Meta)
- return "";
- if (key_code == -1)
- return "";
+void ConfigureInput::handleClick(Settings::NativeInput::Values input_id) {
+ QPushButton* button = button_map[input_id];
+ button->setText(tr("[press key]"));
+ button->setFocus();
- return QKeySequence(key_code).toString();
-}
+ current_input_id = input_id;
-Qt::Key ConfigureInput::getKeyValue(const QString& text) const {
- if (text == "Shift")
- return Qt::Key_Shift;
- if (text == "Ctrl")
- return Qt::Key_Control;
- if (text == "Alt")
- return Qt::Key_Alt;
- if (text == "Meta")
- return Qt::Key_unknown;
- if (text == "")
- return Qt::Key_unknown;
-
- return Qt::Key(QKeySequence(text)[0]);
+ grabKeyboard();
+ grabMouse();
+ timer->start(5000); // Cancel after 5 seconds
}
-void ConfigureInput::removeDuplicates(const QString& newValue) {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- if (changing_button != input_mapping[Settings::NativeInput::Values(i)]) {
- const QString oldValue = input_mapping[Settings::NativeInput::Values(i)]->text();
- if (newValue == oldValue)
- input_mapping[Settings::NativeInput::Values(i)]->setText("");
- }
- }
+void ConfigureInput::keyPressEvent(QKeyEvent* event) {
+ releaseKeyboard();
+ releaseMouse();
+
+ if (!current_input_id || !event)
+ return;
+
+ if (event->key() != Qt::Key_Escape)
+ setInput(*current_input_id, static_cast<Qt::Key>(event->key()));
+
+ updateButtonLabels();
+ current_input_id = boost::none;
+ timer->stop();
}
-void ConfigureInput::restoreDefaults() {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- const QString keyValue = getKeyName(Config::defaults[i].toInt());
- input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue);
+void ConfigureInput::setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed) {
+ // Remove duplicates
+ for (auto& pair : key_map) {
+ if (pair.second == key_pressed)
+ pair.second = Qt::Key_unknown;
}
+
+ key_map[input_id] = key_pressed;
}
diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h
index 5183b904d..bc343db83 100644
--- a/src/citra_qt/configure_input.h
+++ b/src/citra_qt/configure_input.h
@@ -7,7 +7,7 @@
#include <memory>
#include <QKeyEvent>
#include <QWidget>
-#include "citra_qt/config.h"
+#include <boost/optional.hpp>
#include "core/settings.h"
#include "ui_configure_input.h"
@@ -30,35 +30,28 @@ public:
private:
std::unique_ptr<Ui::ConfigureInput> ui;
- std::map<Settings::NativeInput::Values, QPushButton*> input_mapping;
- int key_pressed;
- QPushButton* changing_button = nullptr; ///< button currently waiting for key press.
- QString previous_mapping;
- QTimer* timer;
- /// Load configuration settings into button text
- void setConfiguration();
+ /// This input is currently awaiting configuration.
+ /// (i.e.: its corresponding QPushButton has been pressed.)
+ boost::optional<Settings::NativeInput::Values> current_input_id;
+ std::unique_ptr<QTimer> timer;
- /// Check all inputs for duplicate keys. Clears out any other button with the same value as this
- /// button's new value.
- void removeDuplicates(const QString& newValue);
-
- /// Handle key press event for input tab when a button is 'waiting'.
- void keyPressEvent(QKeyEvent* event) override;
-
- /// Convert key ASCII value to its' letter/name
- QString getKeyName(int key_code) const;
-
- /// Convert letter/name of key to its ASCII value.
- Qt::Key getKeyValue(const QString& text) const;
-
- /// Set button text to name of key pressed.
- void setKey();
-
-private slots:
- /// Event handler for all button released() event.
- void handleClick();
+ /// Each input is represented by a QPushButton.
+ std::map<Settings::NativeInput::Values, QPushButton*> button_map;
+ /// Each input is configured to respond to the press of a Qt::Key.
+ std::map<Settings::NativeInput::Values, Qt::Key> key_map;
+ /// Load configuration settings.
+ void loadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
+ /// Update UI to reflect current configuration.
+ void updateButtonLabels();
+
+ /// Called when the button corresponding to input_id was pressed.
+ void handleClick(Settings::NativeInput::Values input_id);
+ /// Handle key press events.
+ void keyPressEvent(QKeyEvent* event) override;
+ /// Configure input input_id to respond to key key_pressed.
+ void setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed);
};
diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h
index 765757986..f04ab9c7e 100644
--- a/src/citra_qt/debugger/callstack.h
+++ b/src/citra_qt/debugger/callstack.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <QDockWidget>
#include "ui_callstack.h"
@@ -11,7 +13,7 @@ class CallstackWidget : public QDockWidget {
Q_OBJECT
public:
- CallstackWidget(QWidget* parent = nullptr);
+ explicit CallstackWidget(QWidget* parent = nullptr);
public slots:
void OnDebugModeEntered();
diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h
index 2ca6c2bd4..895f6ac89 100644
--- a/src/citra_qt/debugger/disassembler.h
+++ b/src/citra_qt/debugger/disassembler.h
@@ -17,7 +17,7 @@ class DisassemblerModel : public QAbstractListModel {
Q_OBJECT
public:
- DisassemblerModel(QObject* parent);
+ explicit DisassemblerModel(QObject* parent);
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics.cpp
index ef6712bfa..ef337827a 100644
--- a/src/citra_qt/debugger/graphics.cpp
+++ b/src/citra_qt/debugger/graphics.cpp
@@ -22,15 +22,15 @@ QVariant GPUCommandStreamItemModel::data(const QModelIndex& index, int role) con
return QVariant();
int command_index = index.row();
- const GSP_GPU::Command& command = GetDebugger()->ReadGXCommandHistory(command_index);
+ const Service::GSP::Command& command = GetDebugger()->ReadGXCommandHistory(command_index);
if (role == Qt::DisplayRole) {
- std::map<GSP_GPU::CommandId, const char*> command_names = {
- {GSP_GPU::CommandId::REQUEST_DMA, "REQUEST_DMA"},
- {GSP_GPU::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST"},
- {GSP_GPU::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL"},
- {GSP_GPU::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER"},
- {GSP_GPU::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY"},
- {GSP_GPU::CommandId::CACHE_FLUSH, "CACHE_FLUSH"},
+ std::map<Service::GSP::CommandId, const char*> command_names = {
+ {Service::GSP::CommandId::REQUEST_DMA, "REQUEST_DMA"},
+ {Service::GSP::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST"},
+ {Service::GSP::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL"},
+ {Service::GSP::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER"},
+ {Service::GSP::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY"},
+ {Service::GSP::CommandId::CACHE_FLUSH, "CACHE_FLUSH"},
};
const u32* command_data = reinterpret_cast<const u32*>(&command);
QString str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9")
diff --git a/src/citra_qt/debugger/graphics.h b/src/citra_qt/debugger/graphics.h
index bedf3e596..8837fb792 100644
--- a/src/citra_qt/debugger/graphics.h
+++ b/src/citra_qt/debugger/graphics.h
@@ -13,7 +13,7 @@ class GPUCommandStreamItemModel : public QAbstractListModel,
Q_OBJECT
public:
- GPUCommandStreamItemModel(QObject* parent);
+ explicit GPUCommandStreamItemModel(QObject* parent);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics_breakpoints.h
index 5fc40c916..bec72a2db 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.h
+++ b/src/citra_qt/debugger/graphics_breakpoints.h
@@ -20,8 +20,8 @@ class GraphicsBreakPointsWidget : public QDockWidget, Pica::DebugContext::BreakP
using Event = Pica::DebugContext::Event;
public:
- GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent = nullptr);
+ explicit GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent = nullptr);
void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnPicaResume() override;
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 8a784d108..98b619dea 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -21,7 +21,8 @@
#include "video_core/pica.h"
#include "video_core/pica_state.h"
-QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) {
+namespace {
+QImage LoadTexture(const u8* src, const Pica::DebugUtils::TextureInfo& info) {
QImage decoded_image(info.width, info.height, QImage::Format_ARGB32);
for (int y = 0; y < info.height; ++y) {
for (int x = 0; x < info.width; ++x) {
@@ -35,7 +36,8 @@ QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) {
class TextureInfoWidget : public QWidget {
public:
- TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr)
+ TextureInfoWidget(const u8* src, const Pica::DebugUtils::TextureInfo& info,
+ QWidget* parent = nullptr)
: QWidget(parent) {
QLabel* image_widget = new QLabel;
QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info));
@@ -47,6 +49,7 @@ public:
setLayout(layout);
}
};
+} // Anonymous namespace
GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) {}
@@ -65,7 +68,6 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
const auto& write = pica_trace.writes[index.row()];
if (role == Qt::DisplayRole) {
- QString content;
switch (index.column()) {
case 0:
return QString::fromLatin1(Pica::Regs::GetCommandName(write.cmd_id).c_str());
@@ -122,19 +124,21 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
COMMAND_IN_RANGE(command_id, texture2)) {
- unsigned index;
+ unsigned texture_index;
if (COMMAND_IN_RANGE(command_id, texture0)) {
- index = 0;
+ texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
- index = 1;
+ texture_index = 1;
} else if (COMMAND_IN_RANGE(command_id, texture2)) {
- index = 2;
+ texture_index = 2;
} else {
UNREACHABLE_MSG("Unknown texture command");
}
- auto config = Pica::g_state.regs.GetTextures()[index].config;
- auto format = Pica::g_state.regs.GetTextures()[index].format;
- auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
+
+ const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ const auto config = texture.config;
+ const auto format = texture.format;
+ const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
// TODO: Open a surface debugger
}
@@ -148,19 +152,21 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
COMMAND_IN_RANGE(command_id, texture2)) {
- unsigned index;
+ unsigned texture_index;
if (COMMAND_IN_RANGE(command_id, texture0)) {
- index = 0;
+ texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
- index = 1;
+ texture_index = 1;
} else {
- index = 2;
+ texture_index = 2;
}
- auto config = Pica::g_state.regs.GetTextures()[index].config;
- auto format = Pica::g_state.regs.GetTextures()[index].format;
- auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
- u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
+ const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ const auto config = texture.config;
+ const auto format = texture.format;
+
+ const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
+ const u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
new_info_widget = new TextureInfoWidget(src, info);
}
if (command_info_widget) {
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h
index fa2b9122b..8f40b94c5 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics_cmdlists.h
@@ -20,7 +20,7 @@ public:
CommandIdRole = Qt::UserRole,
};
- GPUCommandListModel(QObject* parent);
+ explicit GPUCommandListModel(QObject* parent);
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -39,7 +39,7 @@ class GPUCommandListWidget : public QDockWidget {
Q_OBJECT
public:
- GPUCommandListWidget(QWidget* parent = nullptr);
+ explicit GPUCommandListWidget(QWidget* parent = nullptr);
public slots:
void OnToggleTracing();
diff --git a/src/citra_qt/debugger/graphics_surface.h b/src/citra_qt/debugger/graphics_surface.h
index 21e6b5b8b..19ffb55fb 100644
--- a/src/citra_qt/debugger/graphics_surface.h
+++ b/src/citra_qt/debugger/graphics_surface.h
@@ -18,7 +18,8 @@ class SurfacePicture : public QLabel {
Q_OBJECT
public:
- SurfacePicture(QWidget* parent = 0, GraphicsSurfaceWidget* surface_widget = nullptr);
+ explicit SurfacePicture(QWidget* parent = nullptr,
+ GraphicsSurfaceWidget* surface_widget = nullptr);
~SurfacePicture();
protected slots:
@@ -71,8 +72,8 @@ class GraphicsSurfaceWidget : public BreakPointObserverDock {
static unsigned int NibblesPerPixel(Format format);
public:
- GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent = nullptr);
+ explicit GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent = nullptr);
void Pick(int x, int y);
public slots:
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h
index e04a3dac3..20acc91e7 100644
--- a/src/citra_qt/debugger/graphics_tracing.h
+++ b/src/citra_qt/debugger/graphics_tracing.h
@@ -12,8 +12,8 @@ class GraphicsTracingWidget : public BreakPointObserverDock {
Q_OBJECT
public:
- GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent = nullptr);
+ explicit GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent = nullptr);
private slots:
void StartRecording();
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.h b/src/citra_qt/debugger/graphics_vertex_shader.h
index ec42f24bb..6e62fbb9b 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.h
+++ b/src/citra_qt/debugger/graphics_vertex_shader.h
@@ -19,7 +19,7 @@ class GraphicsVertexShaderModel : public QAbstractTableModel {
Q_OBJECT
public:
- GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent);
+ explicit GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent);
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index d8c6487aa..c8912fd5a 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -15,7 +15,7 @@ class ProfilerModel : public QAbstractItemModel {
Q_OBJECT
public:
- ProfilerModel(QObject* parent);
+ explicit ProfilerModel(QObject* parent);
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
@@ -37,7 +37,7 @@ class ProfilerWidget : public QDockWidget {
Q_OBJECT
public:
- ProfilerWidget(QWidget* parent = nullptr);
+ explicit ProfilerWidget(QWidget* parent = nullptr);
private slots:
void setProfilingInfoUpdateEnabled(bool enable);
@@ -53,7 +53,7 @@ class MicroProfileDialog : public QWidget {
Q_OBJECT
public:
- MicroProfileDialog(QWidget* parent = nullptr);
+ explicit MicroProfileDialog(QWidget* parent = nullptr);
/// Returns a QAction that can be used to toggle visibility of this dialog.
QAction* toggleViewAction();
diff --git a/src/citra_qt/debugger/ramview.h b/src/citra_qt/debugger/ramview.h
index 8043c59e8..d01cea93b 100644
--- a/src/citra_qt/debugger/ramview.h
+++ b/src/citra_qt/debugger/ramview.h
@@ -2,13 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include "qhexedit.h"
class GRamView : public QHexEdit {
Q_OBJECT
public:
- GRamView(QWidget* parent = nullptr);
+ explicit GRamView(QWidget* parent = nullptr);
public slots:
void OnCPUStepped();
diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h
index 54c9a8155..55bda5b59 100644
--- a/src/citra_qt/debugger/registers.h
+++ b/src/citra_qt/debugger/registers.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <QDockWidget>
#include "ui_registers.h"
@@ -13,7 +15,7 @@ class RegistersWidget : public QDockWidget {
Q_OBJECT
public:
- RegistersWidget(QWidget* parent = nullptr);
+ explicit RegistersWidget(QWidget* parent = nullptr);
public slots:
void OnDebugModeEntered();
diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index b2e7f4a97..5a308bf7f 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -8,7 +8,6 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/semaphore.h"
-#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
diff --git a/src/citra_qt/debugger/wait_tree.h b/src/citra_qt/debugger/wait_tree.h
index 5d1d964d1..ee9708fc1 100644
--- a/src/citra_qt/debugger/wait_tree.h
+++ b/src/citra_qt/debugger/wait_tree.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <boost/container/flat_set.hpp>
#include <QAbstractItemModel>
@@ -49,7 +51,7 @@ private:
class WaitTreeText : public WaitTreeItem {
Q_OBJECT
public:
- WaitTreeText(const QString& text);
+ explicit WaitTreeText(const QString& text);
QString GetText() const override;
private:
@@ -65,7 +67,7 @@ public:
class WaitTreeWaitObject : public WaitTreeExpandableItem {
Q_OBJECT
public:
- WaitTreeWaitObject(const Kernel::WaitObject& object);
+ explicit WaitTreeWaitObject(const Kernel::WaitObject& object);
static std::unique_ptr<WaitTreeWaitObject> make(const Kernel::WaitObject& object);
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -92,7 +94,7 @@ private:
class WaitTreeThread : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeThread(const Kernel::Thread& thread);
+ explicit WaitTreeThread(const Kernel::Thread& thread);
QString GetText() const override;
QColor GetColor() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -101,35 +103,37 @@ public:
class WaitTreeEvent : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeEvent(const Kernel::Event& object);
+ explicit WaitTreeEvent(const Kernel::Event& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeMutex : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeMutex(const Kernel::Mutex& object);
+ explicit WaitTreeMutex(const Kernel::Mutex& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeSemaphore : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeSemaphore(const Kernel::Semaphore& object);
+ explicit WaitTreeSemaphore(const Kernel::Semaphore& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeTimer : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeTimer(const Kernel::Timer& object);
+ explicit WaitTreeTimer(const Kernel::Timer& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeMutexList : public WaitTreeExpandableItem {
Q_OBJECT
public:
- WaitTreeMutexList(const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list);
+ explicit WaitTreeMutexList(
+ const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list);
+
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -140,7 +144,7 @@ private:
class WaitTreeThreadList : public WaitTreeExpandableItem {
Q_OBJECT
public:
- WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list);
+ explicit WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list);
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -152,7 +156,7 @@ class WaitTreeModel : public QAbstractItemModel {
Q_OBJECT
public:
- WaitTreeModel(QObject* parent = nullptr);
+ explicit WaitTreeModel(QObject* parent = nullptr);
QVariant data(const QModelIndex& index, int role) const override;
QModelIndex index(int row, int column, const QModelIndex& parent) const override;
@@ -171,7 +175,7 @@ class WaitTreeWidget : public QDockWidget {
Q_OBJECT
public:
- WaitTreeWidget(QWidget* parent = nullptr);
+ explicit WaitTreeWidget(QWidget* parent = nullptr);
public slots:
void OnDebugModeEntered();
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index 07bc35308..e536628dd 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -13,7 +13,7 @@
#include "game_list_p.h"
#include "ui_settings.h"
-GameList::GameList(QWidget* parent) {
+GameList::GameList(QWidget* parent) : QWidget{parent} {
QVBoxLayout* layout = new QVBoxLayout;
tree_view = new QTreeView;
@@ -34,8 +34,7 @@ GameList::GameList(QWidget* parent) {
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size");
- connect(tree_view, SIGNAL(activated(const QModelIndex&)), this,
- SLOT(ValidateEntry(const QModelIndex&)));
+ connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
// We must register all custom types with the Qt Automoc system so that we are able to use it
// with
@@ -50,7 +49,7 @@ GameList::~GameList() {
emit ShouldCancelWorker();
}
-void GameList::AddEntry(QList<QStandardItem*> entry_items) {
+void GameList::AddEntry(const QList<QStandardItem*>& entry_items) {
item_model->invisibleRootItem()->appendRow(entry_items);
}
@@ -86,12 +85,13 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
emit ShouldCancelWorker();
GameListWorker* worker = new GameListWorker(dir_path, deep_scan);
- connect(worker, SIGNAL(EntryReady(QList<QStandardItem*>)), this,
- SLOT(AddEntry(QList<QStandardItem*>)), Qt::QueuedConnection);
- connect(worker, SIGNAL(Finished()), this, SLOT(DonePopulating()), Qt::QueuedConnection);
+ connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
+ connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating,
+ Qt::QueuedConnection);
// Use DirectConnection here because worker->Cancel() is thread-safe and we want it to cancel
// without delay.
- connect(this, SIGNAL(ShouldCancelWorker()), worker, SLOT(Cancel()), Qt::DirectConnection);
+ connect(this, &GameList::ShouldCancelWorker, worker, &GameListWorker::Cancel,
+ Qt::DirectConnection);
QThreadPool::globalInstance()->start(worker);
current_worker = std::move(worker);
@@ -151,6 +151,6 @@ void GameListWorker::run() {
}
void GameListWorker::Cancel() {
- disconnect(this, 0, 0, 0);
+ disconnect(this, nullptr, nullptr, nullptr);
stop_processing = true;
}
diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h
index a22e9bc60..30b2c79a8 100644
--- a/src/citra_qt/game_list.h
+++ b/src/citra_qt/game_list.h
@@ -25,7 +25,7 @@ public:
COLUMN_COUNT, // Number of columns
};
- GameList(QWidget* parent = nullptr);
+ explicit GameList(QWidget* parent = nullptr);
~GameList() override;
void PopulateAsync(const QString& dir_path, bool deep_scan);
@@ -33,18 +33,15 @@ public:
void SaveInterfaceLayout();
void LoadInterfaceLayout();
-public slots:
- void AddEntry(QList<QStandardItem*> entry_items);
-
-private slots:
- void ValidateEntry(const QModelIndex& item);
- void DonePopulating();
-
signals:
void GameChosen(QString game_path);
void ShouldCancelWorker();
private:
+ void AddEntry(const QList<QStandardItem*>& entry_items);
+ void ValidateEntry(const QModelIndex& item);
+ void DonePopulating();
+
QTreeView* tree_view = nullptr;
QStandardItemModel* item_model = nullptr;
GameListWorker* current_worker = nullptr;
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h
index 350103c6f..46f48c2d8 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/citra_qt/hotkeys.h
@@ -55,7 +55,7 @@ class GHotkeysDialog : public QWidget {
Q_OBJECT
public:
- GHotkeysDialog(QWidget* parent = nullptr);
+ explicit GHotkeysDialog(QWidget* parent = nullptr);
private:
Ui::hotkeys ui;
diff --git a/src/citra_qt/util/spinbox.h b/src/citra_qt/util/spinbox.h
index a57355cd6..2fa1db3a4 100644
--- a/src/citra_qt/util/spinbox.h
+++ b/src/citra_qt/util/spinbox.h
@@ -42,7 +42,7 @@ class CSpinBox : public QAbstractSpinBox {
Q_OBJECT
public:
- CSpinBox(QWidget* parent = nullptr);
+ explicit CSpinBox(QWidget* parent = nullptr);
void stepBy(int steps) override;
StepEnabled stepEnabled() const override;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 74a271f08..e6c2ce335 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -71,9 +71,15 @@ if(ARCHITECTURE_x86_64)
set(HEADERS ${HEADERS}
x64/abi.h
x64/cpu_detect.h
- x64/emitter.h)
+ x64/emitter.h
+ x64/xbyak_abi.h
+ x64/xbyak_util.h
+ )
endif()
create_directory_groups(${SRCS} ${HEADERS})
add_library(common STATIC ${SRCS} ${HEADERS})
+if (ARCHITECTURE_x86_64)
+ target_link_libraries(common xbyak)
+endif()
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index c48b3b769..3059d0cb0 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -16,7 +16,7 @@ namespace Common {
// Helper functions:
-#ifdef _WIN32
+#ifdef _MSC_VER
template <typename T>
static inline int CountSetBits(T v) {
// from https://graphics.stanford.edu/~seander/bithacks.html
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index b6161f2dc..c618495f7 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -40,9 +40,20 @@
#endif
#if defined(__APPLE__)
+// CFURL contains __attribute__ directives that gcc does not know how to parse, so we need to just
+// ignore them if we're not using clang. The macro is only used to prevent linking against
+// functions that don't exist on older versions of macOS, and the worst case scenario is a linker
+// error, so this is perfectly safe, just inconvenient.
+#ifndef __clang__
+#define availability(...)
+#endif
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFURL.h>
+#ifdef availability
+#undef availability
+#endif
+
#endif
#include <algorithm>
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index d61c1696b..9d423766f 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -7,7 +7,7 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
#endif
#include "common/assert.h"
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index df1008180..bad311793 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -14,7 +14,7 @@
#ifdef _WIN32
#include <codecvt>
-#include <Windows.h>
+#include <windows.h>
#include "common/common_funcs.h"
#else
#include <iconv.h>
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 9bb2f4e1d..9e207118f 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -6,7 +6,7 @@
#ifdef __APPLE__
#include <mach/mach.h>
#elif defined(_WIN32)
-#include <Windows.h>
+#include <windows.h>
#else
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index e843cbd9c..c9803109e 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -4,7 +4,8 @@
#include <time.h>
#ifdef _WIN32
-#include <Windows.h>
+#include <windows.h>
+// windows.h needs to be included before other windows headers
#include <mmsystem.h>
#include <sys/timeb.h>
#else
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
new file mode 100644
index 000000000..6090d93e1
--- /dev/null
+++ b/src/common/x64/xbyak_abi.h
@@ -0,0 +1,178 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <initializer_list>
+#include <xbyak.h>
+#include "common/assert.h"
+#include "common/bit_set.h"
+
+namespace Common {
+namespace X64 {
+
+int RegToIndex(const Xbyak::Reg& reg) {
+ using Kind = Xbyak::Reg::Kind;
+ ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
+ "RegSet only support GPRs and XMM registers.");
+ ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
+ return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
+}
+
+inline Xbyak::Reg64 IndexToReg64(int reg_index) {
+ ASSERT(reg_index < 16);
+ return Xbyak::Reg64(reg_index);
+}
+
+inline Xbyak::Xmm IndexToXmm(int reg_index) {
+ ASSERT(reg_index >= 16 && reg_index < 32);
+ return Xbyak::Xmm(reg_index - 16);
+}
+
+inline Xbyak::Reg IndexToReg(int reg_index) {
+ if (reg_index < 16) {
+ return IndexToReg64(reg_index);
+ } else {
+ return IndexToXmm(reg_index);
+ }
+}
+
+inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
+ BitSet32 bits;
+ for (const Xbyak::Reg& reg : regs) {
+ bits[RegToIndex(reg)] = true;
+ }
+ return bits;
+}
+
+const BitSet32 ABI_ALL_GPRS(0x0000FFFF);
+const BitSet32 ABI_ALL_XMMS(0xFFFF0000);
+
+#ifdef _WIN32
+
+// Microsoft x64 ABI
+const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
+const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
+const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
+const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
+const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
+
+const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rcx, Xbyak::util::rdx, Xbyak::util::r8, Xbyak::util::r9, Xbyak::util::r10,
+ Xbyak::util::r11,
+ // XMMs
+ Xbyak::util::xmm0, Xbyak::util::xmm1, Xbyak::util::xmm2, Xbyak::util::xmm3, Xbyak::util::xmm4,
+ Xbyak::util::xmm5,
+});
+
+const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rbx, Xbyak::util::rsi, Xbyak::util::rdi, Xbyak::util::rbp, Xbyak::util::r12,
+ Xbyak::util::r13, Xbyak::util::r14, Xbyak::util::r15,
+ // XMMs
+ Xbyak::util::xmm6, Xbyak::util::xmm7, Xbyak::util::xmm8, Xbyak::util::xmm9, Xbyak::util::xmm10,
+ Xbyak::util::xmm11, Xbyak::util::xmm12, Xbyak::util::xmm13, Xbyak::util::xmm14,
+ Xbyak::util::xmm15,
+});
+
+constexpr size_t ABI_SHADOW_SPACE = 0x20;
+
+#else
+
+// System V x86-64 ABI
+const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
+const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
+const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
+const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
+const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
+
+const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rcx, Xbyak::util::rdx, Xbyak::util::rdi, Xbyak::util::rsi, Xbyak::util::r8,
+ Xbyak::util::r9, Xbyak::util::r10, Xbyak::util::r11,
+ // XMMs
+ Xbyak::util::xmm0, Xbyak::util::xmm1, Xbyak::util::xmm2, Xbyak::util::xmm3, Xbyak::util::xmm4,
+ Xbyak::util::xmm5, Xbyak::util::xmm6, Xbyak::util::xmm7, Xbyak::util::xmm8, Xbyak::util::xmm9,
+ Xbyak::util::xmm10, Xbyak::util::xmm11, Xbyak::util::xmm12, Xbyak::util::xmm13,
+ Xbyak::util::xmm14, Xbyak::util::xmm15,
+});
+
+const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rbx, Xbyak::util::rbp, Xbyak::util::r12, Xbyak::util::r13, Xbyak::util::r14,
+ Xbyak::util::r15,
+});
+
+constexpr size_t ABI_SHADOW_SPACE = 0;
+
+#endif
+
+void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size,
+ s32* out_subtraction, s32* out_xmm_offset) {
+ int count = (regs & ABI_ALL_GPRS).Count();
+ rsp_alignment -= count * 8;
+ size_t subtraction = 0;
+ int xmm_count = (regs & ABI_ALL_XMMS).Count();
+ if (xmm_count) {
+ // If we have any XMMs to save, we must align the stack here.
+ subtraction = rsp_alignment & 0xF;
+ }
+ subtraction += 0x10 * xmm_count;
+ size_t xmm_base_subtraction = subtraction;
+ subtraction += needed_frame_size;
+ subtraction += ABI_SHADOW_SPACE;
+ // Final alignment.
+ rsp_alignment -= subtraction;
+ subtraction += rsp_alignment & 0xF;
+
+ *out_subtraction = (s32)subtraction;
+ *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
+}
+
+size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
+ size_t rsp_alignment, size_t needed_frame_size = 0) {
+ s32 subtraction, xmm_offset;
+ ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
+
+ for (int reg_index : (regs & ABI_ALL_GPRS)) {
+ code.push(IndexToReg64(reg_index));
+ }
+
+ if (subtraction != 0) {
+ code.sub(code.rsp, subtraction);
+ }
+
+ for (int reg_index : (regs & ABI_ALL_XMMS)) {
+ code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index));
+ xmm_offset += 0x10;
+ }
+
+ return ABI_SHADOW_SPACE;
+}
+
+void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, size_t rsp_alignment,
+ size_t needed_frame_size = 0) {
+ s32 subtraction, xmm_offset;
+ ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
+
+ for (int reg_index : (regs & ABI_ALL_XMMS)) {
+ code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]);
+ xmm_offset += 0x10;
+ }
+
+ if (subtraction != 0) {
+ code.add(code.rsp, subtraction);
+ }
+
+ // GPRs need to be popped in reverse order
+ for (int reg_index = 15; reg_index >= 0; reg_index--) {
+ if (regs[reg_index]) {
+ code.pop(IndexToReg64(reg_index));
+ }
+ }
+}
+
+} // namespace X64
+} // namespace Common
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
new file mode 100644
index 000000000..0f52f704b
--- /dev/null
+++ b/src/common/x64/xbyak_util.h
@@ -0,0 +1,49 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <type_traits>
+#include <xbyak.h>
+#include "common/x64/xbyak_abi.h"
+
+namespace Common {
+namespace X64 {
+
+// Constants for use with cmpps/cmpss
+enum {
+ CMP_EQ = 0,
+ CMP_LT = 1,
+ CMP_LE = 2,
+ CMP_UNORD = 3,
+ CMP_NEQ = 4,
+ CMP_NLT = 5,
+ CMP_NLE = 6,
+ CMP_ORD = 7,
+};
+
+inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
+ u64 distance = target - (ref + 5);
+ return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
+}
+
+inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
+ return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target);
+}
+
+template <typename T>
+inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
+ static_assert(std::is_pointer<T>(), "Argument must be a (function) pointer.");
+ size_t addr = reinterpret_cast<size_t>(f);
+ if (IsWithin2G(code, addr)) {
+ code.call(f);
+ } else {
+ // ABI_RETURN is a safe temp register to use before a call
+ code.mov(ABI_RETURN, addr);
+ code.call(ABI_RETURN);
+ }
+}
+
+} // namespace X64
+} // namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 299f1f261..af224166a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -18,10 +18,12 @@ set(SRCS
file_sys/archive_backend.cpp
file_sys/archive_extsavedata.cpp
file_sys/archive_ncch.cpp
+ file_sys/archive_other_savedata.cpp
file_sys/archive_romfs.cpp
file_sys/archive_savedata.cpp
file_sys/archive_sdmc.cpp
file_sys/archive_sdmcwriteonly.cpp
+ file_sys/archive_source_sd_savedata.cpp
file_sys/archive_systemsavedata.cpp
file_sys/disk_archive.cpp
file_sys/ivfc_archive.cpp
@@ -36,6 +38,7 @@ set(SRCS
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
@@ -44,14 +47,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
@@ -71,10 +75,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
@@ -103,8 +109,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
@@ -116,9 +127,15 @@ set(SRCS
hle/service/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
@@ -163,10 +180,12 @@ set(HEADERS
file_sys/archive_backend.h
file_sys/archive_extsavedata.h
file_sys/archive_ncch.h
+ file_sys/archive_other_savedata.h
file_sys/archive_romfs.h
file_sys/archive_savedata.h
file_sys/archive_sdmc.h
file_sys/archive_sdmcwriteonly.h
+ file_sys/archive_source_sd_savedata.h
file_sys/archive_systemsavedata.h
file_sys/directory_backend.h
file_sys/disk_archive.h
@@ -178,12 +197,14 @@ set(HEADERS
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
@@ -192,15 +213,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
@@ -220,10 +242,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
@@ -252,8 +276,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
@@ -265,9 +294,15 @@ set(HEADERS
hle/service/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
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index ca8a94ee9..fc4254670 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"
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..6efa18159 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -22,7 +22,7 @@ std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core
/// 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
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index e1c4931ec..5b172df4a 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;
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_other_savedata.cpp b/src/core/file_sys/archive_other_savedata.cpp
new file mode 100644
index 000000000..d3cf080da
--- /dev/null
+++ b/src/core/file_sys/archive_other_savedata.cpp
@@ -0,0 +1,145 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <tuple>
+#include "core/file_sys/archive_other_savedata.h"
+#include "core/file_sys/errors.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/service/fs/archive.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+// TODO(wwylele): The storage info in exheader should be checked before accessing these archives
+
+using Service::FS::MediaType;
+
+namespace {
+
+template <typename T>
+ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_reader) {
+ if (path.GetType() != Binary) {
+ LOG_ERROR(Service_FS, "Wrong path type %d", static_cast<int>(path.GetType()));
+ return ERROR_INVALID_PATH;
+ }
+
+ std::vector<u8> vec_data = path.AsBinary();
+
+ if (vec_data.size() != 12) {
+ LOG_ERROR(Service_FS, "Wrong path length %zu", vec_data.size());
+ return ERROR_INVALID_PATH;
+ }
+
+ const u32* data = reinterpret_cast<const u32*>(vec_data.data());
+ auto media_type = static_cast<MediaType>(data[0]);
+
+ if (media_type != MediaType::SDMC && media_type != MediaType::GameCard) {
+ LOG_ERROR(Service_FS, "Unsupported media type %u", static_cast<u32>(media_type));
+
+ // Note: this is strange, but the error code was verified with a real 3DS
+ return ERROR_UNSUPPORTED_OPEN_FLAGS;
+ }
+
+ return MakeResult<std::tuple<MediaType, u64>>(media_type, program_id_reader(data));
+}
+
+ResultVal<std::tuple<MediaType, u64>> ParsePathPermitted(const Path& path) {
+ return ParsePath(path,
+ [](const u32* data) -> u64 { return (data[1] << 8) | 0x0004000000000000ULL; });
+}
+
+ResultVal<std::tuple<MediaType, u64>> ParsePathGeneral(const Path& path) {
+ return ParsePath(
+ path, [](const u32* data) -> u64 { return data[1] | (static_cast<u64>(data[2]) << 32); });
+}
+
+} // namespace
+
+ArchiveFactory_OtherSaveDataPermitted::ArchiveFactory_OtherSaveDataPermitted(
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata)
+ : sd_savedata_source(sd_savedata) {}
+
+ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataPermitted::Open(
+ const Path& path) {
+ MediaType media_type;
+ u64 program_id;
+ CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path));
+
+ if (media_type == MediaType::GameCard) {
+ LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
+ return ERROR_GAMECARD_NOT_INSERTED;
+ }
+
+ return sd_savedata_source->Open(program_id);
+}
+
+ResultCode ArchiveFactory_OtherSaveDataPermitted::Format(
+ const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
+ LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive.");
+ return ERROR_INVALID_PATH;
+}
+
+ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo(
+ const Path& path) const {
+ MediaType media_type;
+ u64 program_id;
+ CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path));
+
+ if (media_type == MediaType::GameCard) {
+ LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
+ return ERROR_GAMECARD_NOT_INSERTED;
+ }
+
+ return sd_savedata_source->GetFormatInfo(program_id);
+}
+
+ArchiveFactory_OtherSaveDataGeneral::ArchiveFactory_OtherSaveDataGeneral(
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata)
+ : sd_savedata_source(sd_savedata) {}
+
+ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataGeneral::Open(
+ const Path& path) {
+ MediaType media_type;
+ u64 program_id;
+ CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path));
+
+ if (media_type == MediaType::GameCard) {
+ LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
+ return ERROR_GAMECARD_NOT_INSERTED;
+ }
+
+ return sd_savedata_source->Open(program_id);
+}
+
+ResultCode ArchiveFactory_OtherSaveDataGeneral::Format(
+ const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
+ MediaType media_type;
+ u64 program_id;
+ CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path));
+
+ if (media_type == MediaType::GameCard) {
+ LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
+ return ERROR_GAMECARD_NOT_INSERTED;
+ }
+
+ return sd_savedata_source->Format(program_id, format_info);
+}
+
+ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataGeneral::GetFormatInfo(
+ const Path& path) const {
+ MediaType media_type;
+ u64 program_id;
+ CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path));
+
+ if (media_type == MediaType::GameCard) {
+ LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard");
+ return ERROR_GAMECARD_NOT_INSERTED;
+ }
+
+ return sd_savedata_source->GetFormatInfo(program_id);
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h
new file mode 100644
index 000000000..d80725158
--- /dev/null
+++ b/src/core/file_sys/archive_other_savedata.h
@@ -0,0 +1,52 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/file_sys/archive_source_sd_savedata.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+/// File system interface to the OtherSaveDataPermitted archive
+class ArchiveFactory_OtherSaveDataPermitted final : public ArchiveFactory {
+public:
+ explicit ArchiveFactory_OtherSaveDataPermitted(
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source);
+
+ std::string GetName() const override {
+ return "OtherSaveDataPermitted";
+ }
+
+ ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
+ ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
+ ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
+
+private:
+ std::string mount_point;
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
+};
+
+/// File system interface to the OtherSaveDataGeneral archive
+class ArchiveFactory_OtherSaveDataGeneral final : public ArchiveFactory {
+public:
+ explicit ArchiveFactory_OtherSaveDataGeneral(
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source);
+
+ std::string GetName() const override {
+ return "OtherSaveDataGeneral";
+ }
+
+ ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
+ ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
+ ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
+
+private:
+ std::string mount_point;
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
+};
+
+} // namespace FileSys
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_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index ecb44a215..61f7654f7 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -2,96 +2,29 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <algorithm>
-#include <memory>
-#include "common/common_types.h"
-#include "common/file_util.h"
-#include "common/logging/log.h"
-#include "common/string_util.h"
#include "core/file_sys/archive_savedata.h"
-#include "core/file_sys/savedata_archive.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/service/fs/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
-static 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());
-}
-
-static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
- u32 high = (u32)(program_id >> 32);
- u32 low = (u32)(program_id & 0xFFFFFFFF);
- return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high,
- low);
-}
-
-static std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) {
- u32 high = (u32)(program_id >> 32);
- u32 low = (u32)(program_id & 0xFFFFFFFF);
- return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(),
- high, low);
-}
-
-ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory)
- : mount_point(GetSaveDataContainerPath(sdmc_directory)) {
- LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
-}
+ArchiveFactory_SaveData::ArchiveFactory_SaveData(
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata)
+ : sd_savedata_source(sd_savedata) {}
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
- std::string concrete_mount_point =
- GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
- if (!FileUtil::Exists(concrete_mount_point)) {
- // When a SaveData archive is created for the first time, it is not yet formatted and the
- // save file/directory structure expected by the game has not yet been initialized.
- // Returning the NotFormatted error code will signal the game to provision the SaveData
- // archive with the files and folders that it expects.
- return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
- ErrorSummary::InvalidState, ErrorLevel::Status);
- }
-
- auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
- return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
+ return sd_savedata_source->Open(Kernel::g_current_process->codeset->program_id);
}
ResultCode ArchiveFactory_SaveData::Format(const Path& path,
const FileSys::ArchiveFormatInfo& format_info) {
- std::string concrete_mount_point =
- GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
- FileUtil::DeleteDirRecursively(concrete_mount_point);
- FileUtil::CreateFullPath(concrete_mount_point);
-
- // Write the format metadata
- std::string metadata_path =
- GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
- FileUtil::IOFile file(metadata_path, "wb");
-
- if (file.IsOpen()) {
- file.WriteBytes(&format_info, sizeof(format_info));
- return RESULT_SUCCESS;
- }
- return RESULT_SUCCESS;
+ return sd_savedata_source->Format(Kernel::g_current_process->codeset->program_id, format_info);
}
ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
- std::string metadata_path =
- GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
- FileUtil::IOFile file(metadata_path, "rb");
-
- if (!file.IsOpen()) {
- LOG_ERROR(Service_FS, "Could not open metadata information for archive");
- // TODO(Subv): Verify error code
- return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
- ErrorSummary::InvalidState, ErrorLevel::Status);
- }
-
- ArchiveFormatInfo info = {};
- file.ReadBytes(&info, sizeof(info));
- return MakeResult<ArchiveFormatInfo>(info);
+ return sd_savedata_source->GetFormatInfo(Kernel::g_current_process->codeset->program_id);
}
} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index 6a372865a..41aa6f189 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -4,10 +4,7 @@
#pragma once
-#include <memory>
-#include <string>
-#include "core/file_sys/archive_backend.h"
-#include "core/hle/result.h"
+#include "core/file_sys/archive_source_sd_savedata.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
@@ -17,7 +14,7 @@ namespace FileSys {
/// File system interface to the SaveData archive
class ArchiveFactory_SaveData final : public ArchiveFactory {
public:
- ArchiveFactory_SaveData(const std::string& mount_point);
+ explicit ArchiveFactory_SaveData(std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source);
std::string GetName() const override {
return "SaveData";
@@ -30,6 +27,7 @@ public:
private:
std::string mount_point;
+ std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
};
} // namespace FileSys
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
new file mode 100644
index 000000000..2d8a950a3
--- /dev/null
+++ b/src/core/file_sys/archive_source_sd_savedata.cpp
@@ -0,0 +1,93 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/file_util.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+#include "core/file_sys/archive_source_sd_savedata.h"
+#include "core/file_sys/savedata_archive.h"
+#include "core/hle/service/fs/archive.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+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());
+}
+
+std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
+ u32 high = static_cast<u32>(program_id >> 32);
+ u32 low = static_cast<u32>(program_id & 0xFFFFFFFF);
+ return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high,
+ low);
+}
+
+std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) {
+ u32 high = static_cast<u32>(program_id >> 32);
+ u32 low = static_cast<u32>(program_id & 0xFFFFFFFF);
+ return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(),
+ high, low);
+}
+
+} // namespace
+
+ArchiveSource_SDSaveData::ArchiveSource_SDSaveData(const std::string& sdmc_directory)
+ : mount_point(GetSaveDataContainerPath(sdmc_directory)) {
+ LOG_INFO(Service_FS, "Directory %s set as SaveData.", mount_point.c_str());
+}
+
+ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 program_id) {
+ std::string concrete_mount_point = GetSaveDataPath(mount_point, program_id);
+ if (!FileUtil::Exists(concrete_mount_point)) {
+ // When a SaveData archive is created for the first time, it is not yet formatted and the
+ // save file/directory structure expected by the game has not yet been initialized.
+ // Returning the NotFormatted error code will signal the game to provision the SaveData
+ // archive with the files and folders that it expects.
+ return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
+ ErrorSummary::InvalidState, ErrorLevel::Status);
+ }
+
+ auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point));
+ return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
+}
+
+ResultCode ArchiveSource_SDSaveData::Format(u64 program_id,
+ const FileSys::ArchiveFormatInfo& format_info) {
+ std::string concrete_mount_point = GetSaveDataPath(mount_point, program_id);
+ FileUtil::DeleteDirRecursively(concrete_mount_point);
+ FileUtil::CreateFullPath(concrete_mount_point);
+
+ // Write the format metadata
+ std::string metadata_path = GetSaveDataMetadataPath(mount_point, program_id);
+ FileUtil::IOFile file(metadata_path, "wb");
+
+ if (file.IsOpen()) {
+ file.WriteBytes(&format_info, sizeof(format_info));
+ return RESULT_SUCCESS;
+ }
+ return RESULT_SUCCESS;
+}
+
+ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program_id) const {
+ std::string metadata_path = GetSaveDataMetadataPath(mount_point, program_id);
+ FileUtil::IOFile file(metadata_path, "rb");
+
+ if (!file.IsOpen()) {
+ LOG_ERROR(Service_FS, "Could not open metadata information for archive");
+ // TODO(Subv): Verify error code
+ return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
+ ErrorSummary::InvalidState, ErrorLevel::Status);
+ }
+
+ ArchiveFormatInfo info = {};
+ file.ReadBytes(&info, sizeof(info));
+ return MakeResult<ArchiveFormatInfo>(info);
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h
new file mode 100644
index 000000000..b33126c31
--- /dev/null
+++ b/src/core/file_sys/archive_source_sd_savedata.h
@@ -0,0 +1,30 @@
+// 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 "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FileSys namespace
+
+namespace FileSys {
+
+/// A common source of SD save data archive
+class ArchiveSource_SDSaveData {
+public:
+ explicit ArchiveSource_SDSaveData(const std::string& mount_point);
+
+ ResultVal<std::unique_ptr<ArchiveBackend>> Open(u64 program_id);
+ ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info);
+ ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const;
+
+private:
+ std::string mount_point;
+};
+
+} // namespace FileSys
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/errors.h b/src/core/file_sys/errors.h
index fd1b07df0..4d5f62b08 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -36,5 +36,8 @@ const ResultCode ERROR_ALREADY_EXISTS(ErrorDescription::FS_AlreadyExists, ErrorM
ErrorSummary::NothingHappened, ErrorLevel::Status);
const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS,
ErrorSummary::Canceled, ErrorLevel::Status);
+const ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrorDescription::FS_GameCardNotInserted,
+ ErrorModule::FS, ErrorSummary::NotFound,
+ ErrorLevel::Status);
} // namespace FileSys
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/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index aea43e92b..1303bafc1 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>
@@ -130,7 +131,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;
@@ -902,7 +906,7 @@ 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) {
@@ -914,12 +918,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 +1002,7 @@ void Init() {
}
void Shutdown() {
- if (!g_server_enabled) {
+ if (!server_enabled) {
return;
}
@@ -1015,8 +1019,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/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/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.h b/src/core/hle/kernel/kernel.h
index 4227d2373..1adcf6c71 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -31,22 +31,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 +81,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;
}
}
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/result.h b/src/core/hle/result.h
index f7356f9d8..53864a3a7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -18,10 +18,12 @@ enum class ErrorDescription : u32 {
Success = 0,
WrongPermission = 46,
OS_InvalidBufferDescriptor = 48,
+ MaxConnectionsReached = 52,
WrongAddress = 53,
FS_ArchiveNotMounted = 101,
FS_FileNotFound = 112,
FS_PathNotFound = 113,
+ FS_GameCardNotInserted = 141,
FS_NotFound = 120,
FS_FileAlreadyExists = 180,
FS_DirectoryAlreadyExists = 185,
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 d554c3f54..65655f45d 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"
@@ -528,9 +529,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..6544e89a2 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -9,10 +9,8 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/csnd_snd.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CSND_SND
-
-namespace CSND_SND {
+namespace Service {
+namespace CSND {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010140, Initialize, "Initialize"},
@@ -29,17 +27,14 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000C0000, nullptr, "Reset"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+CSND_SND::CSND_SND() {
Register(FunctionTable);
}
static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr;
static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
-void Initialize(Service::Interface* self) {
+void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
@@ -56,7 +51,7 @@ void Initialize(Service::Interface* self) {
cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
}
-void ExecuteType0Commands(Service::Interface* self) {
+void ExecuteType0Commands(Interface* self) {
u32* const cmd_buff = Kernel::GetCommandBuffer();
u8* const ptr = shared_memory->GetPointer(cmd_buff[1]);
@@ -74,15 +69,16 @@ void ExecuteType0Commands(Service::Interface* self) {
}
}
-void AcquireSoundChannels(Service::Interface* self) {
+void AcquireSoundChannels(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = 0;
cmd_buff[2] = 0xFFFFFF00;
}
-void Shutdown(Service::Interface* self) {
+void Shutdown(Interface* self) {
shared_memory = nullptr;
mutex = nullptr;
}
-} // 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..c8d83fa7d 100644
--- a/src/core/hle/service/csnd_snd.h
+++ b/src/core/hle/service/csnd_snd.h
@@ -6,14 +6,12 @@
#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";
@@ -28,9 +26,10 @@ struct Type0Command {
u8 parameters[20];
};
-void Initialize(Service::Interface* self);
-void ExecuteType0Commands(Service::Interface* self);
-void AcquireSoundChannels(Service::Interface* self);
-void Shutdown(Service::Interface* self);
+void Initialize(Interface* self);
+void ExecuteType0Commands(Interface* self);
+void AcquireSoundChannels(Interface* self);
+void Shutdown(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 4c29784e8..09205e4b2 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -16,6 +16,7 @@
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/archive_ncch.h"
+#include "core/file_sys/archive_other_savedata.h"
#include "core/file_sys/archive_savedata.h"
#include "core/file_sys/archive_sdmc.h"
#include "core/file_sys/archive_sdmcwriteonly.h"
@@ -23,6 +24,7 @@
#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"
@@ -92,7 +94,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) {
@@ -102,8 +104,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,
@@ -115,7 +117,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);
@@ -128,22 +130,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;
@@ -152,14 +154,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;
}
@@ -172,7 +173,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;
}
@@ -193,10 +198,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,
@@ -205,18 +209,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());
@@ -226,7 +228,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;
}
@@ -236,10 +238,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);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -306,9 +307,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;
@@ -317,8 +318,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) {
@@ -397,8 +398,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;
@@ -407,8 +408,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) {
@@ -535,8 +536,17 @@ void RegisterArchiveTypes() {
sdmc_directory.c_str());
// Create the SaveData archive
- auto savedata_factory = std::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
+ auto sd_savedata_source = std::make_shared<FileSys::ArchiveSource_SDSaveData>(sdmc_directory);
+ auto savedata_factory = std::make_unique<FileSys::ArchiveFactory_SaveData>(sd_savedata_source);
RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
+ auto other_savedata_permitted_factory =
+ std::make_unique<FileSys::ArchiveFactory_OtherSaveDataPermitted>(sd_savedata_source);
+ RegisterArchiveType(std::move(other_savedata_permitted_factory),
+ ArchiveIdCode::OtherSaveDataPermitted);
+ auto other_savedata_general_factory =
+ std::make_unique<FileSys::ArchiveFactory_OtherSaveDataGeneral>(sd_savedata_source);
+ RegisterArchiveType(std::move(other_savedata_general_factory),
+ ArchiveIdCode::OtherSaveDataGeneral);
auto extsavedata_factory =
std::make_unique<FileSys::ArchiveFactory_ExtSaveData>(sdmc_directory, false);
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 21ed9717b..7ba62ede0 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 {
@@ -34,40 +34,46 @@ enum class ArchiveIdCode : u32 {
SDMC = 0x00000009,
SDMCWriteOnly = 0x0000000A,
NCCH = 0x2345678A,
+ OtherSaveDataGeneral = 0x567890B2,
+ OtherSaveDataPermitted = 0x567890B4,
};
/// Media types for the archives
-enum class MediaType : u32 { NAND = 0, SDMC = 1 };
+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;
};
/**
@@ -97,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
@@ -176,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 710e0e485..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,13 +338,13 @@ 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];
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_GSP, "(STUBBED) called mode=0x%08X", mode);
+ LOG_DEBUG(Service_GSP, "(STUBBED) called mode=0x%08X", mode);
}
/**
@@ -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..18a1b6a16 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -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/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..9e5d6a318 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];
@@ -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];
@@ -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];
@@ -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];
@@ -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..7ced36439 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -7,10 +7,8 @@
#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,7 +47,7 @@ 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];
@@ -68,7 +66,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 +85,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 +109,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 +123,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 +138,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 +153,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 +168,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 +183,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 +198,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 +213,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 +230,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 +248,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 +263,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 +278,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 +292,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 +322,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 +333,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_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 80081aae2..e3160d4b4 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -7,10 +7,8 @@
#include "core/hle/kernel/event.h"
#include "core/hle/service/nwm_uds.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NWM_UDS
-
-namespace NWM_UDS {
+namespace Service {
+namespace NWM {
static Kernel::SharedPtr<Kernel::Event> handle_event;
@@ -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];
@@ -120,24 +118,26 @@ static void Initialize(Service::Interface* self) {
const Interface::FunctionInfo FunctionTable[] = {
{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 +146,15 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00220402, nullptr, "ScanOnConnection"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+NWM_UDS::NWM_UDS() {
handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM_UDS::handle_event");
Register(FunctionTable);
}
-Interface::~Interface() {
+NWM_UDS::~NWM_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_uds.h
index 0ced2359c..55db748f6 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/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..25a7aeea8 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/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,50 +117,60 @@ 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();
+ 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 NWM::NWM_UDS);
+ 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");
}
@@ -148,21 +178,21 @@ void Init() {
/// 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 a4a00d9b2..ef25acc4a 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"
@@ -225,20 +227,29 @@ 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
+/// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Handle handle) {
- SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(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
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 45dedea68..1a1ee90b2 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -8,7 +8,10 @@
#include "common/color.h"
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/math_util.h"
#include "common/microprofile.h"
+#include "common/thread.h"
+#include "common/timer.h"
#include "common/vector_math.h"
#include "core/core_timing.h"
#include "core/hle/service/gsp_gpu.h"
@@ -35,6 +38,14 @@ const u64 frame_ticks = 268123480ull / 60;
static int vblank_event;
/// Total number of frames drawn
static u64 frame_count;
+/// Start clock for frame limiter
+static u32 time_point;
+/// Total delay caused by slow frames
+static float time_delay;
+constexpr float FIXED_FRAME_TIME = 1000.0f / 60;
+// Max lag caused by slow frames. Can be adjusted to compensate for too many slow frames. Higher
+// values increases time needed to limit frame rate after spikes
+constexpr float MAX_LAG_TIME = 18;
template <typename T>
inline void Read(T& var, const u32 raw_addr) {
@@ -419,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);
}
}
@@ -462,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;
}
@@ -476,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);
@@ -512,6 +523,21 @@ template void Write<u32>(u32 addr, const u32 data);
template void Write<u16>(u32 addr, const u16 data);
template void Write<u8>(u32 addr, const u8 data);
+static void FrameLimiter() {
+ time_delay += FIXED_FRAME_TIME;
+ time_delay = MathUtil::Clamp(time_delay, -MAX_LAG_TIME, MAX_LAG_TIME);
+ s32 desired_time = static_cast<s32>(time_delay);
+ s32 elapsed_time = static_cast<s32>(Common::Timer::GetTimeMs() - time_point);
+
+ if (elapsed_time < desired_time) {
+ Common::SleepCurrentThread(desired_time - elapsed_time);
+ }
+
+ u32 frame_time = Common::Timer::GetTimeMs() - time_point;
+
+ time_delay -= frame_time;
+}
+
/// Update hardware
static void VBlankCallback(u64 userdata, int cycles_late) {
frame_count++;
@@ -522,12 +548,18 @@ 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();
+ if (!Settings::values.use_vsync && Settings::values.toggle_framelimit) {
+ FrameLimiter();
+ }
+
+ time_point = Common::Timer::GetTimeMs();
+
// Reschedule recurrent event
CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event);
}
@@ -563,6 +595,7 @@ void Init() {
framebuffer_sub.active_fb = 0;
frame_count = 0;
+ time_point = Common::Timer::GetTimeMs();
vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback);
CoreTiming::ScheduleEvent(frame_ticks, vblank_event);
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/memory.cpp b/src/core/memory.cpp
index 65e4bba85..d058dc844 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -357,14 +357,24 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
}
}
+static void RoundToPages(PAddr& start, u32& size) {
+ PAddr start_rounded_down = start & ~PAGE_MASK;
+ PAddr end_rounded_up = ((start + size) + PAGE_MASK) & ~PAGE_MASK;
+
+ start = start_rounded_down;
+ size = end_rounded_up - start_rounded_down;
+}
+
void RasterizerFlushRegion(PAddr start, u32 size) {
if (VideoCore::g_renderer != nullptr) {
+ RoundToPages(start, size);
VideoCore::g_renderer->Rasterizer()->FlushRegion(start, size);
}
}
void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) {
if (VideoCore::g_renderer != nullptr) {
+ RoundToPages(start, size);
VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size);
}
}
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 05f41f798..626e06cd9 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -21,6 +21,7 @@ void Apply() {
VideoCore::g_hw_renderer_enabled = values.use_hw_renderer;
VideoCore::g_shader_jit_enabled = values.use_shader_jit;
VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution;
+ VideoCore::g_toggle_framelimit_enabled = values.toggle_framelimit;
if (VideoCore::g_emu_window) {
auto layout = VideoCore::g_emu_window->GetFramebufferLayout();
diff --git a/src/core/settings.h b/src/core/settings.h
index 7470fdbeb..db4c8fada 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -90,6 +90,7 @@ struct Values {
bool use_shader_jit;
bool use_scaled_resolution;
bool use_vsync;
+ bool toggle_framelimit;
LayoutOption layout_option;
bool swap_screen;
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 89237e477..b47156ca4 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -13,6 +13,6 @@ include_directories(../../externals/catch/single_include/)
add_executable(tests ${SRCS} ${HEADERS})
target_link_libraries(tests core video_core audio_core common)
-target_link_libraries(tests ${PLATFORM_LIBRARIES})
+target_link_libraries(tests ${PLATFORM_LIBRARIES} Threads::Threads)
add_test(NAME tests COMMAND $<TARGET_FILE:tests>)
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 581a37897..9aa446a8f 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -59,6 +59,9 @@ create_directory_groups(${SRCS} ${HEADERS})
add_library(video_core STATIC ${SRCS} ${HEADERS})
target_link_libraries(video_core glad)
+if (ARCHITECTURE_x86_64)
+ target_link_libraries(video_core xbyak)
+endif()
if (PNG_FOUND)
target_link_libraries(video_core ${PNG_LIBRARIES})
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index c80c96762..8a5d8533c 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -68,7 +68,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
switch (id) {
// Trigger IRQ
case PICA_REG_INDEX(trigger_irq):
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
break;
case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E):
@@ -251,7 +251,6 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
ASSERT(vertex != -1);
bool vertex_cache_hit = false;
- Shader::OutputRegisters output_registers;
if (is_indexed) {
if (g_debug_context && Pica::g_debug_context->recorder) {
@@ -279,10 +278,9 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
(void*)&input);
g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes());
- output_registers = shader_unit.output_registers;
// Retrieve vertex from register data
- output_vertex = output_registers.ToVertex(regs.vs);
+ output_vertex = shader_unit.output_registers.ToVertex(regs.vs);
if (is_indexed) {
vertex_cache[vertex_cache_pos] = output_vertex;
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h
index 3c6636d66..c1f9b43c2 100644
--- a/src/video_core/gpu_debugger.h
+++ b/src/video_core/gpu_debugger.h
@@ -28,7 +28,8 @@ public:
* @note All methods in this class are called from the GSP thread
*/
virtual void GXCommandProcessed(int total_command_count) {
- const GSP_GPU::Command& cmd = observed->ReadGXCommandHistory(total_command_count - 1);
+ const Service::GSP::Command& cmd =
+ observed->ReadGXCommandHistory(total_command_count - 1);
LOG_TRACE(Debug_GPU, "Received command: id=%x", (int)cmd.id.Value());
}
@@ -48,16 +49,16 @@ public:
return;
gx_command_history.emplace_back();
- GSP_GPU::Command& cmd = gx_command_history.back();
+ Service::GSP::Command& cmd = gx_command_history.back();
- memcpy(&cmd, command_data, sizeof(GSP_GPU::Command));
+ memcpy(&cmd, command_data, sizeof(Service::GSP::Command));
ForEachObserver([this](DebuggerObserver* observer) {
observer->GXCommandProcessed(static_cast<int>(this->gx_command_history.size()));
});
}
- const GSP_GPU::Command& ReadGXCommandHistory(int index) const {
+ const Service::GSP::Command& ReadGXCommandHistory(int index) const {
// TODO: Is this thread-safe?
return gx_command_history[index];
}
@@ -80,5 +81,5 @@ private:
std::vector<DebuggerObserver*> observers;
- std::vector<GSP_GPU::Command> gx_command_history;
+ std::vector<Service::GSP::Command> gx_command_history;
};
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 99bd59a69..b2db609ec 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -40,7 +40,7 @@ namespace Pica {
// field offset. Otherwise, the compiler will fail to compile this code.
#define PICA_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
((typename std::enable_if<backup_workaround_index == PICA_REG_INDEX(field_name), \
- size_t>::type) PICA_REG_INDEX(field_name))
+ size_t>::type)PICA_REG_INDEX(field_name))
#endif // _MSC_VER
struct Regs {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 1b734aaa5..cc7e782a4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -189,10 +189,6 @@ void RasterizerOpenGL::DrawTriangles() {
GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
(has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return;
- }
-
// Sync the viewport
// These registers hold half-width and half-height, so must be multiplied by 2
GLsizei viewport_width = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_x).ToFloat32() * 2;
@@ -715,7 +711,11 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
CachedSurface src_params;
src_params.addr = config.GetPhysicalInputAddress();
- src_params.width = config.output_width;
+ // It's important to use the correct source input width to properly skip over parts of the input
+ // image which will be cropped from the output but still affect the stride of the input image.
+ src_params.width = config.input_width;
+ // Using the output's height is fine because we don't read or skip over the remaining part of
+ // the image, and it allows for smaller texture cache lookup rectangles.
src_params.height = config.output_height;
src_params.is_tiled = !config.input_linear;
src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.input_format);
@@ -736,6 +736,11 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe
return false;
}
+ // Adjust the source rectangle to take into account parts of the input lines being cropped
+ if (config.input_width > config.output_width) {
+ src_rect.right -= (config.input_width - config.output_width) * src_surface->res_scale_width;
+ }
+
// Require destination surface to have same resolution scale as source to preserve scaling
dst_params.res_scale_width = src_surface->res_scale_width;
dst_params.res_scale_height = src_surface->res_scale_height;
@@ -798,10 +803,6 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f};
// TODO: Handle additional pixel format and fill value size combinations to accelerate more
@@ -886,10 +887,6 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
dst_surface->texture.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
GLfloat value_float;
if (dst_surface->pixel_format == CachedSurface::PixelFormat::D16) {
value_float = config.value_32bit / 65535.0f; // 2^16 - 1
@@ -905,10 +902,6 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
dst_surface->texture.handle, 0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
GLfloat value_float = (config.value_32bit & 0xFFFFFF) / 16777215.0f; // 2^24 - 1
GLint value_int = (config.value_32bit >> 24);
@@ -938,7 +931,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
src_params.addr = framebuffer_addr;
src_params.width = config.width;
src_params.height = config.height;
- src_params.stride = pixel_stride;
+ src_params.pixel_stride = pixel_stride;
src_params.is_tiled = false;
src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.color_format);
@@ -1074,7 +1067,9 @@ void RasterizerOpenGL::SetShader() {
GLint block_size;
glGetActiveUniformBlockiv(current_shader->shader.handle, block_index,
GL_UNIFORM_BLOCK_DATA_SIZE, &block_size);
- ASSERT_MSG(block_size == sizeof(UniformData), "Uniform block size did not match!");
+ ASSERT_MSG(block_size == sizeof(UniformData),
+ "Uniform block size did not match! Got %d, expected %zu",
+ static_cast<int>(block_size), sizeof(UniformData));
glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
// Update uniforms
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5cbad9b43..0b2e48407 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -103,7 +103,7 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
}
}
-bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
+void RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
CachedSurface::SurfaceType type,
const MathUtil::Rectangle<int>& src_rect,
const MathUtil::Rectangle<int>& dst_rect) {
@@ -158,14 +158,6 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
}
- if (OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
@@ -174,8 +166,6 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
cur_state.draw.read_framebuffer = old_fbs[0];
cur_state.draw.draw_framebuffer = old_fbs[1];
cur_state.Apply();
-
- return true;
}
bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface,
@@ -189,9 +179,9 @@ bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface,
return false;
}
- return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle,
- CachedSurface::GetFormatType(src_surface->pixel_format), src_rect,
- dst_rect);
+ BlitTextures(src_surface->texture.handle, dst_surface->texture.handle,
+ CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect);
+ return true;
}
static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format,
@@ -291,6 +281,9 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
MICROPROFILE_SCOPE(OpenGL_SurfaceUpload);
+ // Stride only applies to linear images.
+ ASSERT(params.pixel_stride == 0 || !params.is_tiled);
+
std::shared_ptr<CachedSurface> new_surface = std::make_shared<CachedSurface>();
new_surface->addr = params.addr;
@@ -299,7 +292,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
new_surface->texture.Create();
new_surface->width = params.width;
new_surface->height = params.height;
- new_surface->stride = params.stride;
+ new_surface->pixel_stride = params.pixel_stride;
new_surface->res_scale_width = params.res_scale_width;
new_surface->res_scale_height = params.res_scale_height;
@@ -325,14 +318,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
cur_state.Apply();
glActiveTexture(GL_TEXTURE0);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->stride);
if (!new_surface->is_tiled) {
// TODO: Ensure this will always be a color format, not a depth or other format
ASSERT((size_t)new_surface->pixel_format < fb_format_tuples.size());
const FormatTuple& tuple = fb_format_tuples[(unsigned int)params.pixel_format];
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->pixel_stride);
glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0,
tuple.format, tuple.type, texture_src_data);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} else {
SurfaceType type = CachedSurface::GetFormatType(new_surface->pixel_format);
if (type != SurfaceType::Depth && type != SurfaceType::DepthStencil) {
@@ -391,7 +385,6 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo
0, tuple.format, tuple.type, temp_fb_depth_buffer.data());
}
}
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
// If not 1x scale, blit 1x texture to a new scaled texture and replace texture in surface
if (new_surface->res_scale_width != 1.f || new_surface->res_scale_height != 1.f) {
@@ -701,13 +694,14 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
cur_state.Apply();
glActiveTexture(GL_TEXTURE0);
- glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->stride);
if (!surface->is_tiled) {
// TODO: Ensure this will always be a color format, not a depth or other format
ASSERT((size_t)surface->pixel_format < fb_format_tuples.size());
const FormatTuple& tuple = fb_format_tuples[(unsigned int)surface->pixel_format];
+ glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->pixel_stride);
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, dst_buffer);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
} else {
SurfaceType type = CachedSurface::GetFormatType(surface->pixel_format);
if (type != SurfaceType::Depth && type != SurfaceType::DepthStencil) {
@@ -750,7 +744,6 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) {
false);
}
}
- glPixelStorei(GL_PACK_ROW_LENGTH, 0);
surface->dirty = false;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 849530d86..b50e8292b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -171,7 +171,8 @@ struct CachedSurface {
OGLTexture texture;
u32 width;
u32 height;
- u32 stride = 0;
+ /// Stride between lines, in pixels. Only valid for images in linear format.
+ u32 pixel_stride = 0;
float res_scale_width = 1.f;
float res_scale_height = 1.f;
@@ -186,7 +187,7 @@ public:
~RasterizerCacheOpenGL();
/// Blits one texture to another
- bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type,
+ void BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type,
const MathUtil::Rectangle<int>& src_rect,
const MathUtil::Rectangle<int>& dst_rect);
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index fe07aa6eb..4da241d83 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -4,6 +4,7 @@
#include <vector>
#include <glad/glad.h>
+#include "common/assert.h"
#include "common/logging/log.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
@@ -31,7 +32,7 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
if (info_log_length > 1) {
std::vector<char> vertex_shader_error(info_log_length);
glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]);
- if (result) {
+ if (result == GL_TRUE) {
LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]);
} else {
LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", &vertex_shader_error[0]);
@@ -51,7 +52,7 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
if (info_log_length > 1) {
std::vector<char> fragment_shader_error(info_log_length);
glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr, &fragment_shader_error[0]);
- if (result) {
+ if (result == GL_TRUE) {
LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
} else {
LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s",
@@ -75,13 +76,20 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
if (info_log_length > 1) {
std::vector<char> program_error(info_log_length);
glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]);
- if (result) {
+ if (result == GL_TRUE) {
LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]);
} else {
LOG_ERROR(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]);
}
}
+ // If the program linking failed at least one of the shaders was probably bad
+ if (result == GL_FALSE) {
+ LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader);
+ LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader);
+ }
+ ASSERT_MSG(result == GL_TRUE, "Shader not linked");
+
glDeleteShader(vertex_shader_id);
glDeleteShader(fragment_shader_id);
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 2a731f483..3c03b424a 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -232,19 +232,6 @@ void OpenGLState::Apply() const {
cur_state = *this;
}
-GLenum OpenGLState::CheckFBStatus(GLenum target) {
- GLenum fb_status = glCheckFramebufferStatus(target);
- if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
- const char* fb_description =
- (target == GL_READ_FRAMEBUFFER ? "READ"
- : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK"));
- LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description,
- fb_status);
- }
-
- return fb_status;
-}
-
void OpenGLState::ResetTexture(GLuint handle) {
for (auto& unit : cur_state.texture_units) {
if (unit.texture_2d == handle) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 01dead883..aee3c2946 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -90,9 +90,6 @@ public:
/// Apply this state as the current OpenGL state
void Apply() const;
- /// Check the status of the current OpenGL read or draw framebuffer configuration
- static GLenum CheckFBStatus(GLenum target);
-
/// Resets and unbinds any references to the given resource in the current OpenGL state
static void ResetTexture(GLuint handle);
static void ResetSampler(GLuint handle);
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 3febe739c..c7f23dab9 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -25,7 +25,7 @@ namespace Pica {
namespace Shader {
-OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) {
+OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) const {
// Setup output data
OutputVertex ret;
// TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 8858d67f8..0111d8c0f 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -85,7 +85,7 @@ struct OutputRegisters {
alignas(16) Math::Vec4<float24> value[16];
- OutputVertex ToVertex(const Regs::ShaderConfig& config);
+ OutputVertex ToVertex(const Regs::ShaderConfig& config) const;
};
static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD");
diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp
index 211c703ab..3ba31d474 100644
--- a/src/video_core/shader/shader_jit_x64.cpp
+++ b/src/video_core/shader/shader_jit_x64.cpp
@@ -6,24 +6,30 @@
#include <cmath>
#include <cstdint>
#include <nihstro/shader_bytecode.h>
+#include <smmintrin.h>
#include <xmmintrin.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/vector_math.h"
-#include "common/x64/abi.h"
#include "common/x64/cpu_detect.h"
-#include "common/x64/emitter.h"
-#include "shader.h"
-#include "shader_jit_x64.h"
+#include "common/x64/xbyak_abi.h"
+#include "common/x64/xbyak_util.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
+#include "video_core/shader/shader.h"
+#include "video_core/shader/shader_jit_x64.h"
+
+using namespace Common::X64;
+using namespace Xbyak::util;
+using Xbyak::Label;
+using Xbyak::Reg32;
+using Xbyak::Reg64;
+using Xbyak::Xmm;
namespace Pica {
namespace Shader {
-using namespace Gen;
-
typedef void (JitShader::*JitFunction)(Instruction instr);
const JitFunction instr_table[64] = {
@@ -98,44 +104,47 @@ const JitFunction instr_table[64] = {
// purposes, as documented below:
/// Pointer to the uniform memory
-static const X64Reg SETUP = R9;
+static const Reg64 SETUP = r9;
/// The two 32-bit VS address offset registers set by the MOVA instruction
-static const X64Reg ADDROFFS_REG_0 = R10;
-static const X64Reg ADDROFFS_REG_1 = R11;
-/// VS loop count register
-static const X64Reg LOOPCOUNT_REG = R12;
+static const Reg64 ADDROFFS_REG_0 = r10;
+static const Reg64 ADDROFFS_REG_1 = r11;
+/// VS loop count register (Multiplied by 16)
+static const Reg32 LOOPCOUNT_REG = r12d;
/// Current VS loop iteration number (we could probably use LOOPCOUNT_REG, but this quicker)
-static const X64Reg LOOPCOUNT = RSI;
-/// Number to increment LOOPCOUNT_REG by on each loop iteration
-static const X64Reg LOOPINC = RDI;
+static const Reg32 LOOPCOUNT = esi;
+/// Number to increment LOOPCOUNT_REG by on each loop iteration (Multiplied by 16)
+static const Reg32 LOOPINC = edi;
/// Result of the previous CMP instruction for the X-component comparison
-static const X64Reg COND0 = R13;
+static const Reg64 COND0 = r13;
/// Result of the previous CMP instruction for the Y-component comparison
-static const X64Reg COND1 = R14;
+static const Reg64 COND1 = r14;
/// Pointer to the UnitState instance for the current VS unit
-static const X64Reg STATE = R15;
+static const Reg64 STATE = r15;
/// SIMD scratch register
-static const X64Reg SCRATCH = XMM0;
+static const Xmm SCRATCH = xmm0;
/// Loaded with the first swizzled source register, otherwise can be used as a scratch register
-static const X64Reg SRC1 = XMM1;
+static const Xmm SRC1 = xmm1;
/// Loaded with the second swizzled source register, otherwise can be used as a scratch register
-static const X64Reg SRC2 = XMM2;
+static const Xmm SRC2 = xmm2;
/// Loaded with the third swizzled source register, otherwise can be used as a scratch register
-static const X64Reg SRC3 = XMM3;
+static const Xmm SRC3 = xmm3;
/// Additional scratch register
-static const X64Reg SCRATCH2 = XMM4;
+static const Xmm SCRATCH2 = xmm4;
/// Constant vector of [1.0f, 1.0f, 1.0f, 1.0f], used to efficiently set a vector to one
-static const X64Reg ONE = XMM14;
+static const Xmm ONE = xmm14;
/// Constant vector of [-0.f, -0.f, -0.f, -0.f], used to efficiently negate a vector with XOR
-static const X64Reg NEGBIT = XMM15;
+static const Xmm NEGBIT = xmm15;
// State registers that must not be modified by external functions calls
// Scratch registers, e.g., SRC1 and SCRATCH, have to be saved on the side if needed
-static const BitSet32 persistent_regs = {
- SETUP, STATE, // Pointers to register blocks
- ADDROFFS_REG_0, ADDROFFS_REG_1, LOOPCOUNT_REG, COND0, COND1, // Cached registers
- ONE + 16, NEGBIT + 16, // Constants
-};
+static const BitSet32 persistent_regs = BuildRegSet({
+ // Pointers to register blocks
+ SETUP, STATE,
+ // Cached registers
+ ADDROFFS_REG_0, ADDROFFS_REG_1, LOOPCOUNT_REG, COND0, COND1,
+ // Constants
+ ONE, NEGBIT,
+});
/// Raw constant for the source register selector that indicates no swizzling is performed
static const u8 NO_SRC_REG_SWIZZLE = 0x1b;
@@ -157,7 +166,8 @@ static void LogCritical(const char* msg) {
void JitShader::Compile_Assert(bool condition, const char* msg) {
if (!condition) {
- ABI_CallFunctionP(reinterpret_cast<const void*>(LogCritical), const_cast<char*>(msg));
+ mov(ABI_PARAM1, reinterpret_cast<size_t>(msg));
+ CallFarFunction(*this, LogCritical);
}
}
@@ -169,8 +179,8 @@ void JitShader::Compile_Assert(bool condition, const char* msg) {
* @param dest Destination XMM register to store the loaded, swizzled source register
*/
void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRegister src_reg,
- X64Reg dest) {
- X64Reg src_ptr;
+ Xmm dest) {
+ Reg64 src_ptr;
size_t src_offset;
if (src_reg.GetRegisterType() == RegisterType::FloatUniform) {
@@ -206,13 +216,13 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
if (src_num == offset_src && address_register_index != 0) {
switch (address_register_index) {
case 1: // address offset 1
- MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_0, SCALE_1, src_offset_disp));
+ movaps(dest, xword[src_ptr + ADDROFFS_REG_0 + src_offset_disp]);
break;
case 2: // address offset 2
- MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_1, SCALE_1, src_offset_disp));
+ movaps(dest, xword[src_ptr + ADDROFFS_REG_1 + src_offset_disp]);
break;
case 3: // address offset 3
- MOVAPS(dest, MComplex(src_ptr, LOOPCOUNT_REG, SCALE_1, src_offset_disp));
+ movaps(dest, xword[src_ptr + LOOPCOUNT_REG.cvt64() + src_offset_disp]);
break;
default:
UNREACHABLE();
@@ -220,7 +230,7 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
}
} else {
// Load the source
- MOVAPS(dest, MDisp(src_ptr, src_offset_disp));
+ movaps(dest, xword[src_ptr + src_offset_disp]);
}
SwizzlePattern swiz = {g_state.vs.swizzle_data[operand_desc_id]};
@@ -232,17 +242,17 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
sel = ((sel & 0xc0) >> 6) | ((sel & 3) << 6) | ((sel & 0xc) << 2) | ((sel & 0x30) >> 2);
// Shuffle inputs for swizzle
- SHUFPS(dest, R(dest), sel);
+ shufps(dest, dest, sel);
}
// If the source register should be negated, flip the negative bit using XOR
const bool negate[] = {swiz.negate_src1, swiz.negate_src2, swiz.negate_src3};
if (negate[src_num - 1]) {
- XORPS(dest, R(NEGBIT));
+ xorps(dest, NEGBIT);
}
}
-void JitShader::Compile_DestEnable(Instruction instr, X64Reg src) {
+void JitShader::Compile_DestEnable(Instruction instr, Xmm src) {
DestRegister dest;
unsigned operand_desc_id;
if (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD ||
@@ -263,21 +273,21 @@ void JitShader::Compile_DestEnable(Instruction instr, X64Reg src) {
// If all components are enabled, write the result to the destination register
if (swiz.dest_mask == NO_DEST_REG_MASK) {
// Store dest back to memory
- MOVAPS(MDisp(STATE, dest_offset_disp), src);
+ movaps(xword[STATE + dest_offset_disp], src);
} else {
// Not all components are enabled, so mask the result when storing to the destination
// register...
- MOVAPS(SCRATCH, MDisp(STATE, dest_offset_disp));
+ movaps(SCRATCH, xword[STATE + dest_offset_disp]);
if (Common::GetCPUCaps().sse4_1) {
u8 mask = ((swiz.dest_mask & 1) << 3) | ((swiz.dest_mask & 8) >> 3) |
((swiz.dest_mask & 2) << 1) | ((swiz.dest_mask & 4) >> 1);
- BLENDPS(SCRATCH, R(src), mask);
+ blendps(SCRATCH, src, mask);
} else {
- MOVAPS(SCRATCH2, R(src));
- UNPCKHPS(SCRATCH2, R(SCRATCH)); // Unpack X/Y components of source and destination
- UNPCKLPS(SCRATCH, R(src)); // Unpack Z/W components of source and destination
+ movaps(SCRATCH2, src);
+ unpckhps(SCRATCH2, SCRATCH); // Unpack X/Y components of source and destination
+ unpcklps(SCRATCH, src); // Unpack Z/W components of source and destination
// Compute selector to selectively copy source components to destination for SHUFPS
// instruction
@@ -285,62 +295,62 @@ void JitShader::Compile_DestEnable(Instruction instr, X64Reg src) {
((swiz.DestComponentEnabled(1) ? 3 : 2) << 2) |
((swiz.DestComponentEnabled(2) ? 0 : 1) << 4) |
((swiz.DestComponentEnabled(3) ? 2 : 3) << 6);
- SHUFPS(SCRATCH, R(SCRATCH2), sel);
+ shufps(SCRATCH, SCRATCH2, sel);
}
// Store dest back to memory
- MOVAPS(MDisp(STATE, dest_offset_disp), SCRATCH);
+ movaps(xword[STATE + dest_offset_disp], SCRATCH);
}
}
-void JitShader::Compile_SanitizedMul(Gen::X64Reg src1, Gen::X64Reg src2, Gen::X64Reg scratch) {
- MOVAPS(scratch, R(src1));
- CMPPS(scratch, R(src2), CMP_ORD);
+void JitShader::Compile_SanitizedMul(Xmm src1, Xmm src2, Xmm scratch) {
+ movaps(scratch, src1);
+ cmpordps(scratch, src2);
- MULPS(src1, R(src2));
+ mulps(src1, src2);
- MOVAPS(src2, R(src1));
- CMPPS(src2, R(src2), CMP_UNORD);
+ movaps(src2, src1);
+ cmpunordps(src2, src2);
- XORPS(scratch, R(src2));
- ANDPS(src1, R(scratch));
+ xorps(scratch, src2);
+ andps(src1, scratch);
}
void JitShader::Compile_EvaluateCondition(Instruction instr) {
// Note: NXOR is used below to check for equality
switch (instr.flow_control.op) {
case Instruction::FlowControlType::Or:
- MOV(32, R(RAX), R(COND0));
- MOV(32, R(RBX), R(COND1));
- XOR(32, R(RAX), Imm32(instr.flow_control.refx.Value() ^ 1));
- XOR(32, R(RBX), Imm32(instr.flow_control.refy.Value() ^ 1));
- OR(32, R(RAX), R(RBX));
+ mov(eax, COND0);
+ mov(ebx, COND1);
+ xor(eax, (instr.flow_control.refx.Value() ^ 1));
+ xor(ebx, (instr.flow_control.refy.Value() ^ 1));
+ or (eax, ebx);
break;
case Instruction::FlowControlType::And:
- MOV(32, R(RAX), R(COND0));
- MOV(32, R(RBX), R(COND1));
- XOR(32, R(RAX), Imm32(instr.flow_control.refx.Value() ^ 1));
- XOR(32, R(RBX), Imm32(instr.flow_control.refy.Value() ^ 1));
- AND(32, R(RAX), R(RBX));
+ mov(eax, COND0);
+ mov(ebx, COND1);
+ xor(eax, (instr.flow_control.refx.Value() ^ 1));
+ xor(ebx, (instr.flow_control.refy.Value() ^ 1));
+ and(eax, ebx);
break;
case Instruction::FlowControlType::JustX:
- MOV(32, R(RAX), R(COND0));
- XOR(32, R(RAX), Imm32(instr.flow_control.refx.Value() ^ 1));
+ mov(eax, COND0);
+ xor(eax, (instr.flow_control.refx.Value() ^ 1));
break;
case Instruction::FlowControlType::JustY:
- MOV(32, R(RAX), R(COND1));
- XOR(32, R(RAX), Imm32(instr.flow_control.refy.Value() ^ 1));
+ mov(eax, COND1);
+ xor(eax, (instr.flow_control.refy.Value() ^ 1));
break;
}
}
void JitShader::Compile_UniformCondition(Instruction instr) {
- int offset =
+ size_t offset =
ShaderSetup::UniformOffset(RegisterType::BoolUniform, instr.flow_control.bool_uniform_id);
- CMP(sizeof(bool) * 8, MDisp(SETUP, offset), Imm8(0));
+ cmp(byte[SETUP + offset], 0);
}
BitSet32 JitShader::PersistentCallerSavedRegs() {
@@ -350,7 +360,7 @@ BitSet32 JitShader::PersistentCallerSavedRegs() {
void JitShader::Compile_ADD(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
- ADDPS(SRC1, R(SRC2));
+ addps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -360,15 +370,15 @@ void JitShader::Compile_DP3(Instruction instr) {
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC2, R(SRC2), _MM_SHUFFLE(1, 1, 1, 1));
+ movaps(SRC2, SRC1);
+ shufps(SRC2, SRC2, _MM_SHUFFLE(1, 1, 1, 1));
- MOVAPS(SRC3, R(SRC1));
- SHUFPS(SRC3, R(SRC3), _MM_SHUFFLE(2, 2, 2, 2));
+ movaps(SRC3, SRC1);
+ shufps(SRC3, SRC3, _MM_SHUFFLE(2, 2, 2, 2));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 0, 0, 0));
- ADDPS(SRC1, R(SRC2));
- ADDPS(SRC1, R(SRC3));
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 0, 0, 0));
+ addps(SRC1, SRC2);
+ addps(SRC1, SRC3);
Compile_DestEnable(instr, SRC1);
}
@@ -379,13 +389,13 @@ void JitShader::Compile_DP4(Instruction instr) {
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
+ addps(SRC1, SRC2);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
+ addps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -401,50 +411,50 @@ void JitShader::Compile_DPH(Instruction instr) {
if (Common::GetCPUCaps().sse4_1) {
// Set 4th component to 1.0
- BLENDPS(SRC1, R(ONE), 0x8); // 0b1000
+ blendps(SRC1, ONE, 0b1000);
} else {
// Set 4th component to 1.0
- MOVAPS(SCRATCH, R(SRC1));
- UNPCKHPS(SCRATCH, R(ONE)); // XYZW, 1111 -> Z1__
- UNPCKLPD(SRC1, R(SCRATCH)); // XYZW, Z1__ -> XYZ1
+ movaps(SCRATCH, SRC1);
+ unpckhps(SCRATCH, ONE); // XYZW, 1111 -> Z1__
+ unpcklpd(SRC1, SCRATCH); // XYZW, Z1__ -> XYZ1
}
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
+ addps(SRC1, SRC2);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
+ addps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
void JitShader::Compile_EX2(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
- MOVSS(XMM0, R(SRC1));
+ movss(xmm0, SRC1); // ABI_PARAM1
- ABI_PushRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
- ABI_CallFunction(reinterpret_cast<const void*>(exp2f));
- ABI_PopRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
+ ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
+ CallFarFunction(*this, exp2f);
+ ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
- SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(0, 0, 0, 0));
- MOVAPS(SRC1, R(XMM0));
+ shufps(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0)); // ABI_RETURN
+ movaps(SRC1, xmm0);
Compile_DestEnable(instr, SRC1);
}
void JitShader::Compile_LG2(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
- MOVSS(XMM0, R(SRC1));
+ movss(xmm0, SRC1); // ABI_PARAM1
- ABI_PushRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
- ABI_CallFunction(reinterpret_cast<const void*>(log2f));
- ABI_PopRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
+ ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
+ CallFarFunction(*this, log2f);
+ ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
- SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(0, 0, 0, 0));
- MOVAPS(SRC1, R(XMM0));
+ shufps(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0)); // ABI_RETURN
+ movaps(SRC1, xmm0);
Compile_DestEnable(instr, SRC1);
}
@@ -464,8 +474,8 @@ void JitShader::Compile_SGE(Instruction instr) {
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
}
- CMPPS(SRC2, R(SRC1), CMP_LE);
- ANDPS(SRC2, R(ONE));
+ cmpleps(SRC2, SRC1);
+ andps(SRC2, ONE);
Compile_DestEnable(instr, SRC2);
}
@@ -479,8 +489,8 @@ void JitShader::Compile_SLT(Instruction instr) {
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
}
- CMPPS(SRC1, R(SRC2), CMP_LT);
- ANDPS(SRC1, R(ONE));
+ cmpltps(SRC1, SRC2);
+ andps(SRC1, ONE);
Compile_DestEnable(instr, SRC1);
}
@@ -489,10 +499,10 @@ void JitShader::Compile_FLR(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
if (Common::GetCPUCaps().sse4_1) {
- ROUNDFLOORPS(SRC1, R(SRC1));
+ roundps(SRC1, SRC1, _MM_FROUND_FLOOR);
} else {
- CVTPS2DQ(SRC1, R(SRC1));
- CVTDQ2PS(SRC1, R(SRC1));
+ cvttps2dq(SRC1, SRC1);
+ cvtdq2ps(SRC1, SRC1);
}
Compile_DestEnable(instr, SRC1);
@@ -502,7 +512,7 @@ void JitShader::Compile_MAX(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
// SSE semantics match PICA200 ones: In case of NaN, SRC2 is returned.
- MAXPS(SRC1, R(SRC2));
+ maxps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -510,7 +520,7 @@ void JitShader::Compile_MIN(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
// SSE semantics match PICA200 ones: In case of NaN, SRC2 is returned.
- MINPS(SRC1, R(SRC2));
+ minps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -524,37 +534,37 @@ void JitShader::Compile_MOVA(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
// Convert floats to integers using truncation (only care about X and Y components)
- CVTTPS2DQ(SRC1, R(SRC1));
+ cvttps2dq(SRC1, SRC1);
// Get result
- MOVQ_xmm(R(RAX), SRC1);
+ movq(rax, SRC1);
// Handle destination enable
if (swiz.DestComponentEnabled(0) && swiz.DestComponentEnabled(1)) {
// Move and sign-extend low 32 bits
- MOVSX(64, 32, ADDROFFS_REG_0, R(RAX));
+ movsxd(ADDROFFS_REG_0, eax);
// Move and sign-extend high 32 bits
- SHR(64, R(RAX), Imm8(32));
- MOVSX(64, 32, ADDROFFS_REG_1, R(RAX));
+ shr(rax, 32);
+ movsxd(ADDROFFS_REG_1, eax);
// Multiply by 16 to be used as an offset later
- SHL(64, R(ADDROFFS_REG_0), Imm8(4));
- SHL(64, R(ADDROFFS_REG_1), Imm8(4));
+ shl(ADDROFFS_REG_0, 4);
+ shl(ADDROFFS_REG_1, 4);
} else {
if (swiz.DestComponentEnabled(0)) {
// Move and sign-extend low 32 bits
- MOVSX(64, 32, ADDROFFS_REG_0, R(RAX));
+ movsxd(ADDROFFS_REG_0, eax);
// Multiply by 16 to be used as an offset later
- SHL(64, R(ADDROFFS_REG_0), Imm8(4));
+ shl(ADDROFFS_REG_0, 4);
} else if (swiz.DestComponentEnabled(1)) {
// Move and sign-extend high 32 bits
- SHR(64, R(RAX), Imm8(32));
- MOVSX(64, 32, ADDROFFS_REG_1, R(RAX));
+ shr(rax, 32);
+ movsxd(ADDROFFS_REG_1, eax);
// Multiply by 16 to be used as an offset later
- SHL(64, R(ADDROFFS_REG_1), Imm8(4));
+ shl(ADDROFFS_REG_1, 4);
}
}
}
@@ -569,8 +579,8 @@ void JitShader::Compile_RCP(Instruction instr) {
// TODO(bunnei): RCPSS is a pretty rough approximation, this might cause problems if Pica
// performs this operation more accurately. This should be checked on hardware.
- RCPSS(SRC1, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
+ rcpss(SRC1, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
Compile_DestEnable(instr, SRC1);
}
@@ -580,8 +590,8 @@ void JitShader::Compile_RSQ(Instruction instr) {
// TODO(bunnei): RSQRTSS is a pretty rough approximation, this might cause problems if Pica
// performs this operation more accurately. This should be checked on hardware.
- RSQRTSS(SRC1, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
+ rsqrtss(SRC1, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
Compile_DestEnable(instr, SRC1);
}
@@ -589,34 +599,35 @@ void JitShader::Compile_RSQ(Instruction instr) {
void JitShader::Compile_NOP(Instruction instr) {}
void JitShader::Compile_END(Instruction instr) {
- ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8);
- RET();
+ ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8);
+ ret();
}
void JitShader::Compile_CALL(Instruction instr) {
// Push offset of the return
- PUSH(64, Imm32(instr.flow_control.dest_offset + instr.flow_control.num_instructions));
+ push(qword, (instr.flow_control.dest_offset + instr.flow_control.num_instructions));
// Call the subroutine
- FixupBranch b = CALL();
- fixup_branches.push_back({b, instr.flow_control.dest_offset});
+ call(instruction_labels[instr.flow_control.dest_offset]);
// Skip over the return offset that's on the stack
- ADD(64, R(RSP), Imm32(8));
+ add(rsp, 8);
}
void JitShader::Compile_CALLC(Instruction instr) {
Compile_EvaluateCondition(instr);
- FixupBranch b = J_CC(CC_Z, true);
+ Label b;
+ jz(b);
Compile_CALL(instr);
- SetJumpTarget(b);
+ L(b);
}
void JitShader::Compile_CALLU(Instruction instr) {
Compile_UniformCondition(instr);
- FixupBranch b = J_CC(CC_Z, true);
+ Label b;
+ jz(b);
Compile_CALL(instr);
- SetJumpTarget(b);
+ L(b);
}
void JitShader::Compile_CMP(Instruction instr) {
@@ -633,33 +644,33 @@ void JitShader::Compile_CMP(Instruction instr) {
static const u8 cmp[] = {CMP_EQ, CMP_NEQ, CMP_LT, CMP_LE, CMP_LT, CMP_LE};
bool invert_op_x = (op_x == Op::GreaterThan || op_x == Op::GreaterEqual);
- Gen::X64Reg lhs_x = invert_op_x ? SRC2 : SRC1;
- Gen::X64Reg rhs_x = invert_op_x ? SRC1 : SRC2;
+ Xmm lhs_x = invert_op_x ? SRC2 : SRC1;
+ Xmm rhs_x = invert_op_x ? SRC1 : SRC2;
if (op_x == op_y) {
// Compare X-component and Y-component together
- CMPPS(lhs_x, R(rhs_x), cmp[op_x]);
- MOVQ_xmm(R(COND0), lhs_x);
+ cmpps(lhs_x, rhs_x, cmp[op_x]);
+ movq(COND0, lhs_x);
- MOV(64, R(COND1), R(COND0));
+ mov(COND1, COND0);
} else {
bool invert_op_y = (op_y == Op::GreaterThan || op_y == Op::GreaterEqual);
- Gen::X64Reg lhs_y = invert_op_y ? SRC2 : SRC1;
- Gen::X64Reg rhs_y = invert_op_y ? SRC1 : SRC2;
+ Xmm lhs_y = invert_op_y ? SRC2 : SRC1;
+ Xmm rhs_y = invert_op_y ? SRC1 : SRC2;
// Compare X-component
- MOVAPS(SCRATCH, R(lhs_x));
- CMPSS(SCRATCH, R(rhs_x), cmp[op_x]);
+ movaps(SCRATCH, lhs_x);
+ cmpss(SCRATCH, rhs_x, cmp[op_x]);
// Compare Y-component
- CMPPS(lhs_y, R(rhs_y), cmp[op_y]);
+ cmpps(lhs_y, rhs_y, cmp[op_y]);
- MOVQ_xmm(R(COND0), SCRATCH);
- MOVQ_xmm(R(COND1), lhs_y);
+ movq(COND0, SCRATCH);
+ movq(COND1, lhs_y);
}
- SHR(32, R(COND0), Imm8(31));
- SHR(64, R(COND1), Imm8(63));
+ shr(COND0.cvt32(), 31); // ignores upper 32 bits in source
+ shr(COND1, 63);
}
void JitShader::Compile_MAD(Instruction instr) {
@@ -674,7 +685,7 @@ void JitShader::Compile_MAD(Instruction instr) {
}
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- ADDPS(SRC1, R(SRC3));
+ addps(SRC1, SRC3);
Compile_DestEnable(instr, SRC1);
}
@@ -682,6 +693,7 @@ void JitShader::Compile_MAD(Instruction instr) {
void JitShader::Compile_IF(Instruction instr) {
Compile_Assert(instr.flow_control.dest_offset >= program_counter,
"Backwards if-statements not supported");
+ Label l_else, l_endif;
// Evaluate the "IF" condition
if (instr.opcode.Value() == OpCode::Id::IFU) {
@@ -689,26 +701,25 @@ void JitShader::Compile_IF(Instruction instr) {
} else if (instr.opcode.Value() == OpCode::Id::IFC) {
Compile_EvaluateCondition(instr);
}
- FixupBranch b = J_CC(CC_Z, true);
+ jz(l_else, T_NEAR);
// Compile the code that corresponds to the condition evaluating as true
Compile_Block(instr.flow_control.dest_offset);
// If there isn't an "ELSE" condition, we are done here
if (instr.flow_control.num_instructions == 0) {
- SetJumpTarget(b);
+ L(l_else);
return;
}
- FixupBranch b2 = J(true);
-
- SetJumpTarget(b);
+ jmp(l_endif, T_NEAR);
+ L(l_else);
// This code corresponds to the "ELSE" condition
// Comple the code that corresponds to the condition evaluating as false
Compile_Block(instr.flow_control.dest_offset + instr.flow_control.num_instructions);
- SetJumpTarget(b2);
+ L(l_endif);
}
void JitShader::Compile_LOOP(Instruction instr) {
@@ -718,25 +729,29 @@ void JitShader::Compile_LOOP(Instruction instr) {
looping = true;
- int offset =
+ // This decodes the fields from the integer uniform at index instr.flow_control.int_uniform_id.
+ // The Y (LOOPCOUNT_REG) and Z (LOOPINC) component are kept multiplied by 16 (Left shifted by
+ // 4 bits) to be used as an offset into the 16-byte vector registers later
+ size_t offset =
ShaderSetup::UniformOffset(RegisterType::IntUniform, instr.flow_control.int_uniform_id);
- MOV(32, R(LOOPCOUNT), MDisp(SETUP, offset));
- MOV(32, R(LOOPCOUNT_REG), R(LOOPCOUNT));
- SHR(32, R(LOOPCOUNT_REG), Imm8(8));
- AND(32, R(LOOPCOUNT_REG), Imm32(0xff)); // Y-component is the start
- MOV(32, R(LOOPINC), R(LOOPCOUNT));
- SHR(32, R(LOOPINC), Imm8(16));
- MOVZX(32, 8, LOOPINC, R(LOOPINC)); // Z-component is the incrementer
- MOVZX(32, 8, LOOPCOUNT, R(LOOPCOUNT)); // X-component is iteration count
- ADD(32, R(LOOPCOUNT), Imm8(1)); // Iteration count is X-component + 1
-
- auto loop_start = GetCodePtr();
+ mov(LOOPCOUNT, dword[SETUP + offset]);
+ mov(LOOPCOUNT_REG, LOOPCOUNT);
+ shr(LOOPCOUNT_REG, 4);
+ and(LOOPCOUNT_REG, 0xFF0); // Y-component is the start
+ mov(LOOPINC, LOOPCOUNT);
+ shr(LOOPINC, 12);
+ and(LOOPINC, 0xFF0); // Z-component is the incrementer
+ movzx(LOOPCOUNT, LOOPCOUNT.cvt8()); // X-component is iteration count
+ add(LOOPCOUNT, 1); // Iteration count is X-component + 1
+
+ Label l_loop_start;
+ L(l_loop_start);
Compile_Block(instr.flow_control.dest_offset + 1);
- ADD(32, R(LOOPCOUNT_REG), R(LOOPINC)); // Increment LOOPCOUNT_REG by Z-component
- SUB(32, R(LOOPCOUNT), Imm8(1)); // Increment loop count by 1
- J_CC(CC_NZ, loop_start); // Loop if not equal
+ add(LOOPCOUNT_REG, LOOPINC); // Increment LOOPCOUNT_REG by Z-component
+ sub(LOOPCOUNT, 1); // Increment loop count by 1
+ jnz(l_loop_start); // Loop if not equal
looping = false;
}
@@ -752,8 +767,12 @@ void JitShader::Compile_JMP(Instruction instr) {
bool inverted_condition =
(instr.opcode.Value() == OpCode::Id::JMPU) && (instr.flow_control.num_instructions & 1);
- FixupBranch b = J_CC(inverted_condition ? CC_Z : CC_NZ, true);
- fixup_branches.push_back({b, instr.flow_control.dest_offset});
+ Label& b = instruction_labels[instr.flow_control.dest_offset];
+ if (inverted_condition) {
+ jz(b, T_NEAR);
+ } else {
+ jnz(b, T_NEAR);
+ }
}
void JitShader::Compile_Block(unsigned end) {
@@ -764,13 +783,14 @@ void JitShader::Compile_Block(unsigned end) {
void JitShader::Compile_Return() {
// Peek return offset on the stack and check if we're at that offset
- MOV(64, R(RAX), MDisp(RSP, 8));
- CMP(32, R(RAX), Imm32(program_counter));
+ mov(rax, qword[rsp + 8]);
+ cmp(eax, (program_counter));
// If so, jump back to before CALL
- FixupBranch b = J_CC(CC_NZ, true);
- RET();
- SetJumpTarget(b);
+ Label b;
+ jnz(b);
+ ret();
+ L(b);
}
void JitShader::Compile_NextInstr() {
@@ -778,9 +798,7 @@ void JitShader::Compile_NextInstr() {
Compile_Return();
}
- ASSERT_MSG(code_ptr[program_counter] == nullptr,
- "Tried to compile already compiled shader location!");
- code_ptr[program_counter] = GetCodePtr();
+ L(instruction_labels[program_counter]);
Instruction instr = GetVertexShaderInstruction(program_counter++);
@@ -821,64 +839,53 @@ void JitShader::FindReturnOffsets() {
void JitShader::Compile() {
// Reset flow control state
- program = (CompiledShader*)GetCodePtr();
+ program = (CompiledShader*)getCurr();
program_counter = 0;
looping = false;
- code_ptr.fill(nullptr);
- fixup_branches.clear();
+ instruction_labels.fill(Xbyak::Label());
// Find all `CALL` instructions and identify return locations
FindReturnOffsets();
// The stack pointer is 8 modulo 16 at the entry of a procedure
- ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8);
+ ABI_PushRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8);
- MOV(PTRBITS, R(SETUP), R(ABI_PARAM1));
- MOV(PTRBITS, R(STATE), R(ABI_PARAM2));
+ mov(SETUP, ABI_PARAM1);
+ mov(STATE, ABI_PARAM2);
// Zero address/loop registers
- XOR(64, R(ADDROFFS_REG_0), R(ADDROFFS_REG_0));
- XOR(64, R(ADDROFFS_REG_1), R(ADDROFFS_REG_1));
- XOR(64, R(LOOPCOUNT_REG), R(LOOPCOUNT_REG));
+ xor(ADDROFFS_REG_0.cvt32(), ADDROFFS_REG_0.cvt32());
+ xor(ADDROFFS_REG_1.cvt32(), ADDROFFS_REG_1.cvt32());
+ xor(LOOPCOUNT_REG, LOOPCOUNT_REG);
// Used to set a register to one
static const __m128 one = {1.f, 1.f, 1.f, 1.f};
- MOV(PTRBITS, R(RAX), ImmPtr(&one));
- MOVAPS(ONE, MatR(RAX));
+ mov(rax, reinterpret_cast<size_t>(&one));
+ movaps(ONE, xword[rax]);
// Used to negate registers
static const __m128 neg = {-0.f, -0.f, -0.f, -0.f};
- MOV(PTRBITS, R(RAX), ImmPtr(&neg));
- MOVAPS(NEGBIT, MatR(RAX));
+ mov(rax, reinterpret_cast<size_t>(&neg));
+ movaps(NEGBIT, xword[rax]);
// Jump to start of the shader program
- JMPptr(R(ABI_PARAM3));
+ jmp(ABI_PARAM3);
// Compile entire program
Compile_Block(static_cast<unsigned>(g_state.vs.program_code.size()));
- // Set the target for any incomplete branches now that the entire shader program has been
- // emitted
- for (const auto& branch : fixup_branches) {
- SetJumpTarget(branch.first, code_ptr[branch.second]);
- }
-
// Free memory that's no longer needed
return_offsets.clear();
return_offsets.shrink_to_fit();
- fixup_branches.clear();
- fixup_branches.shrink_to_fit();
- uintptr_t size =
- reinterpret_cast<uintptr_t>(GetCodePtr()) - reinterpret_cast<uintptr_t>(program);
- ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!");
+ ready();
+ uintptr_t size = reinterpret_cast<uintptr_t>(getCurr()) - reinterpret_cast<uintptr_t>(program);
+ ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!");
LOG_DEBUG(HW_GPU, "Compiled shader size=%lu", size);
}
-JitShader::JitShader() {
- AllocCodeSpace(MAX_SHADER_SIZE);
-}
+JitShader::JitShader() : Xbyak::CodeGenerator(MAX_SHADER_SIZE) {}
} // namespace Shader
diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h
index 98de5ecef..e0ecde3f2 100644
--- a/src/video_core/shader/shader_jit_x64.h
+++ b/src/video_core/shader/shader_jit_x64.h
@@ -9,6 +9,7 @@
#include <utility>
#include <vector>
#include <nihstro/shader_bytecode.h>
+#include <xbyak.h>
#include "common/bit_set.h"
#include "common/common_types.h"
#include "common/x64/emitter.h"
@@ -29,12 +30,12 @@ constexpr size_t MAX_SHADER_SIZE = 1024 * 64;
* This class implements the shader JIT compiler. It recompiles a Pica shader program into x86_64
* code that can be executed on the host machine directly.
*/
-class JitShader : public Gen::XCodeBlock {
+class JitShader : public Xbyak::CodeGenerator {
public:
JitShader();
void Run(const ShaderSetup& setup, UnitState<false>& state, unsigned offset) const {
- program(&setup, &state, code_ptr[offset]);
+ program(&setup, &state, instruction_labels[offset].getAddress());
}
void Compile();
@@ -71,14 +72,14 @@ private:
void Compile_NextInstr();
void Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRegister src_reg,
- Gen::X64Reg dest);
- void Compile_DestEnable(Instruction instr, Gen::X64Reg dest);
+ Xbyak::Xmm dest);
+ void Compile_DestEnable(Instruction instr, Xbyak::Xmm dest);
/**
* Compiles a `MUL src1, src2` operation, properly handling the PICA semantics when multiplying
* zero by inf. Clobbers `src2` and `scratch`.
*/
- void Compile_SanitizedMul(Gen::X64Reg src1, Gen::X64Reg src2, Gen::X64Reg scratch);
+ void Compile_SanitizedMul(Xbyak::Xmm src1, Xbyak::Xmm src2, Xbyak::Xmm scratch);
void Compile_EvaluateCondition(Instruction instr);
void Compile_UniformCondition(Instruction instr);
@@ -103,7 +104,7 @@ private:
void FindReturnOffsets();
/// Mapping of Pica VS instructions to pointers in the emitted code
- std::array<const u8*, 1024> code_ptr;
+ std::array<Xbyak::Label, 1024> instruction_labels;
/// Offsets in code where a return needs to be inserted
std::vector<unsigned> return_offsets;
@@ -111,9 +112,6 @@ private:
unsigned program_counter = 0; ///< Offset of the next instruction to decode
bool looping = false; ///< True if compiling a loop, used to check for nested loops
- /// Branches that need to be fixed up once the entire shader program is compiled
- std::vector<std::pair<Gen::FixupBranch, unsigned>> fixup_branches;
-
using CompiledShader = void(const void* setup, void* state, const u8* start_addr);
CompiledShader* program = nullptr;
};
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 83e33dfc2..8db882f59 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -21,6 +21,7 @@ std::atomic<bool> g_hw_renderer_enabled;
std::atomic<bool> g_shader_jit_enabled;
std::atomic<bool> g_scaled_resolution_enabled;
std::atomic<bool> g_vsync_enabled;
+std::atomic<bool> g_toggle_framelimit_enabled;
/// Initialize the video core
bool Init(EmuWindow* emu_window) {
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index e2d725ab1..c397c1974 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -38,6 +38,7 @@ extern EmuWindow* g_emu_window; ///< Emu window
extern std::atomic<bool> g_hw_renderer_enabled;
extern std::atomic<bool> g_shader_jit_enabled;
extern std::atomic<bool> g_scaled_resolution_enabled;
+extern std::atomic<bool> g_toggle_framelimit_enabled;
/// Start the video core
void Start();