summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE.md4
-rwxr-xr-x.travis-deps.sh2
-rw-r--r--CMakeLists.txt180
-rw-r--r--README.md2
-rw-r--r--externals/CMakeLists.txt52
-rw-r--r--externals/cryptopp/CMakeLists.txt6
-rw-r--r--externals/glad/CMakeLists.txt3
-rw-r--r--externals/inih/CMakeLists.txt1
-rw-r--r--src/audio_core/CMakeLists.txt5
-rw-r--r--src/citra/CMakeLists.txt6
-rw-r--r--src/citra/citra.cpp2
-rw-r--r--src/citra_qt/CMakeLists.txt2
-rw-r--r--src/citra_qt/bootmanager.cpp5
-rw-r--r--src/citra_qt/bootmanager.h3
-rw-r--r--src/citra_qt/debugger/graphics/graphics_cmdlists.cpp1
-rw-r--r--src/citra_qt/debugger/wait_tree.cpp1
-rw-r--r--src/citra_qt/debugger/wait_tree.h4
-rw-r--r--src/citra_qt/game_list_p.h2
-rw-r--r--src/citra_qt/main.cpp123
-rw-r--r--src/citra_qt/main.h3
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/core/CMakeLists.txt18
-rw-r--r--src/core/core.cpp29
-rw-r--r--src/core/core.h17
-rw-r--r--src/core/file_sys/archive_ncch.cpp39
-rw-r--r--src/core/hle/ipc_helpers.h2
-rw-r--r--src/core/hle/kernel/address_arbiter.h1
-rw-r--r--src/core/hle/kernel/client_port.cpp12
-rw-r--r--src/core/hle/kernel/client_port.h1
-rw-r--r--src/core/hle/kernel/client_session.cpp2
-rw-r--r--src/core/hle/kernel/client_session.h3
-rw-r--r--src/core/hle/kernel/event.h1
-rw-r--r--src/core/hle/kernel/handle_table.cpp97
-rw-r--r--src/core/hle/kernel/handle_table.h126
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp24
-rw-r--r--src/core/hle/kernel/hle_ipc.h53
-rw-r--r--src/core/hle/kernel/kernel.cpp164
-rw-r--r--src/core/hle/kernel/kernel.h181
-rw-r--r--src/core/hle/kernel/memory.cpp1
-rw-r--r--src/core/hle/kernel/mutex.h1
-rw-r--r--src/core/hle/kernel/resource_limit.cpp1
-rw-r--r--src/core/hle/kernel/semaphore.h2
-rw-r--r--src/core/hle/kernel/server_port.cpp4
-rw-r--r--src/core/hle/kernel/server_port.h22
-rw-r--r--src/core/hle/kernel/server_session.cpp19
-rw-r--r--src/core/hle/kernel/server_session.h28
-rw-r--r--src/core/hle/kernel/thread.cpp1
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/kernel/timer.cpp1
-rw-r--r--src/core/hle/kernel/timer.h1
-rw-r--r--src/core/hle/kernel/wait_object.cpp99
-rw-r--r--src/core/hle/kernel/wait_object.h67
-rw-r--r--src/core/hle/result.h19
-rw-r--r--src/core/hle/service/ac/ac.cpp5
-rw-r--r--src/core/hle/service/am/am.cpp6
-rw-r--r--src/core/hle/service/apt/apt.cpp2
-rw-r--r--src/core/hle/service/apt/apt.h2
-rw-r--r--src/core/hle/service/boss/boss.cpp3
-rw-r--r--src/core/hle/service/cam/cam.cpp549
-rw-r--r--src/core/hle/service/cam/cam.h13
-rw-r--r--src/core/hle/service/cecd/cecd.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg.cpp3
-rw-r--r--src/core/hle/service/csnd_snd.cpp3
-rw-r--r--src/core/hle/service/dlp/dlp_srvr.cpp1
-rw-r--r--src/core/hle/service/dsp_dsp.cpp6
-rw-r--r--src/core/hle/service/err_f.cpp4
-rw-r--r--src/core/hle/service/frd/frd.cpp5
-rw-r--r--src/core/hle/service/fs/archive.cpp19
-rw-r--r--src/core/hle/service/fs/archive.h6
-rw-r--r--src/core/hle/service/fs/fs_user.cpp40
-rw-r--r--src/core/hle/service/gsp_gpu.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/ir/ir_rst.cpp1
-rw-r--r--src/core/hle/service/ir/ir_user.cpp1
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.cpp1
-rw-r--r--src/core/hle/service/mic_u.cpp2
-rw-r--r--src/core/hle/service/ndm/ndm.cpp2
-rw-r--r--src/core/hle/service/nfc/nfc.cpp2
-rw-r--r--src/core/hle/service/nim/nim.cpp1
-rw-r--r--src/core/hle/service/nwm/nwm_uds.cpp1
-rw-r--r--src/core/hle/service/nwm/uds_beacon.cpp7
-rw-r--r--src/core/hle/service/service.cpp43
-rw-r--r--src/core/hle/service/service.h58
-rw-r--r--src/core/hle/service/sm/sm.cpp59
-rw-r--r--src/core/hle/service/sm/sm.h49
-rw-r--r--src/core/hle/service/sm/srv.cpp (renamed from src/core/hle/service/srv.cpp)71
-rw-r--r--src/core/hle/service/sm/srv.h (renamed from src/core/hle/service/srv.h)5
-rw-r--r--src/core/hle/service/soc_u.cpp1
-rw-r--r--src/core/hle/service/ssl_c.cpp2
-rw-r--r--src/core/hle/service/y2r_u.cpp2
-rw-r--r--src/core/hle/svc.cpp7
-rw-r--r--src/core/loader/loader.h7
-rw-r--r--src/core/loader/ncch.cpp12
-rw-r--r--src/core/loader/ncch.h4
-rw-r--r--src/input_common/CMakeLists.txt3
-rw-r--r--src/tests/CMakeLists.txt6
-rw-r--r--src/video_core/CMakeLists.txt7
-rw-r--r--src/video_core/regs_texturing.h27
-rw-r--r--src/video_core/swrasterizer/rasterizer.cpp53
99 files changed, 1572 insertions, 981 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 9727c5712..ae11db988 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,7 +1,7 @@
1<!--- 1<!---
2 2
3Please read the FAQ: 3Please read the FAQ:
4https://citra-emu.org/wiki/FAQ 4https://citra-emu.org/wiki/faq/
5 5
6THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO: 6THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO:
7https://community.citra-emu.org/ 7https://community.citra-emu.org/
@@ -22,4 +22,4 @@ When submitting an issue, please check the following:
22 - For graphical issues, comparison screenshots with real hardware. 22 - For graphical issues, comparison screenshots with real hardware.
23 - For emulation inaccuracies, a test-case (if able). 23 - For emulation inaccuracies, a test-case (if able).
24 24
25---> \ No newline at end of file 25--->
diff --git a/.travis-deps.sh b/.travis-deps.sh
index 1404fe19f..451886984 100755
--- a/.travis-deps.sh
+++ b/.travis-deps.sh
@@ -11,7 +11,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
11 11
12 if [ ! -e $HOME/.local/bin/cmake ]; then 12 if [ ! -e $HOME/.local/bin/cmake ]; then
13 echo "CMake not found in the cache, get and extract it..." 13 echo "CMake not found in the cache, get and extract it..."
14 curl -L http://www.cmake.org/files/v3.2/cmake-3.2.0-Linux-i386.tar.gz \ 14 curl -L http://www.cmake.org/files/v3.6/cmake-3.6.3-Linux-x86_64.tar.gz \
15 | tar -xz -C $HOME/.local --strip-components=1 15 | tar -xz -C $HOME/.local --strip-components=1
16 else 16 else
17 echo "Using cached CMake" 17 echo "Using cached CMake"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 121b0f2f8..1f0af2d41 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,20 +1,25 @@
1# CMake 3.2 required for cmake to know the right flags for CXX standard on OSX 1# CMake 3.6 required for FindBoost to define IMPORTED libs properly on unknown Boost versions
2cmake_minimum_required(VERSION 3.2) 2cmake_minimum_required(VERSION 3.6)
3set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) 3list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
4list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
4 5
5function(download_bundled_external remote_path lib_name prefix_var) 6project(citra)
6 set(prefix "${CMAKE_BINARY_DIR}/externals/${lib_name}") 7
7 if (NOT EXISTS "${prefix}") 8option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
8 message(STATUS "Downloading binaries for ${lib_name}...") 9option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
9 file(DOWNLOAD 10
10 https://github.com/citra-emu/ext-windows-bin/raw/master/${remote_path}${lib_name}.7z 11option(ENABLE_QT "Enable the Qt frontend" ON)
11 "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z" SHOW_PROGRESS) 12option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
12 execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z" 13
13 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals") 14if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)
14 endif() 15 message(STATUS "Copying pre-commit hook")
15 message(STATUS "Using bundled binaries at ${prefix}") 16 file(COPY hooks/pre-commit
16 set(${prefix_var} "${prefix}" PARENT_SCOPE) 17 DESTINATION ${CMAKE_SOURCE_DIR}/.git/hooks)
17endfunction() 18endif()
19
20
21# Detect current compilation architecture and create standard definitions
22# =======================================================================
18 23
19include(CheckSymbolExists) 24include(CheckSymbolExists)
20function(detect_architecture symbol arch) 25function(detect_architecture symbol arch)
@@ -33,20 +38,6 @@ function(detect_architecture symbol arch)
33 endif() 38 endif()
34endfunction() 39endfunction()
35 40
36project(citra)
37
38option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
39option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
40
41option(ENABLE_QT "Enable the Qt frontend" ON)
42option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
43
44if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit)
45 message(STATUS "Copying pre-commit hook")
46 file(COPY hooks/pre-commit
47 DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks)
48endif()
49
50if (MSVC) 41if (MSVC)
51 detect_architecture("_M_AMD64" x86_64) 42 detect_architecture("_M_AMD64" x86_64)
52 detect_architecture("_M_IX86" x86) 43 detect_architecture("_M_IX86" x86)
@@ -63,6 +54,10 @@ if (NOT DEFINED ARCHITECTURE)
63endif() 54endif()
64message(STATUS "Target architecture: ${ARCHITECTURE}") 55message(STATUS "Target architecture: ${ARCHITECTURE}")
65 56
57
58# Configure compilation flags
59# ===========================
60
66set(CMAKE_CXX_STANDARD 14) 61set(CMAKE_CXX_STANDARD 14)
67set(CMAKE_CXX_STANDARD_REQUIRED ON) 62set(CMAKE_CXX_STANDARD_REQUIRED ON)
68 63
@@ -130,28 +125,44 @@ add_definitions(-DSINGLETHREADED)
130set_property(DIRECTORY APPEND PROPERTY 125set_property(DIRECTORY APPEND PROPERTY
131 COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>) 126 COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
132 127
128
129# System imported libraries
130# ======================
131
132# This function downloads a binary library package from our external repo.
133# Params:
134# remote_path: path to the file to download, relative to the remote repository root
135# prefix_var: name of a variable which will be set with the path to the extracted contents
136function(download_bundled_external remote_path lib_name prefix_var)
137 set(prefix "${CMAKE_BINARY_DIR}/externals/${lib_name}")
138 if (NOT EXISTS "${prefix}")
139 message(STATUS "Downloading binaries for ${lib_name}...")
140 file(DOWNLOAD
141 https://github.com/citra-emu/ext-windows-bin/raw/master/${remote_path}${lib_name}.7z
142 "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z" SHOW_PROGRESS)
143 execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z"
144 WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
145 endif()
146 message(STATUS "Using bundled binaries at ${prefix}")
147 set(${prefix_var} "${prefix}" PARENT_SCOPE)
148endfunction()
149
133find_package(PNG QUIET) 150find_package(PNG QUIET)
134if (PNG_FOUND) 151if (NOT PNG_FOUND)
135 add_definitions(-DHAVE_PNG)
136else()
137 message(STATUS "libpng not found. Some debugging features have been disabled.") 152 message(STATUS "libpng not found. Some debugging features have been disabled.")
138endif() 153endif()
139 154
140find_package(Boost 1.57.0 QUIET) 155find_package(Boost 1.63.0 QUIET)
141if (NOT Boost_FOUND) 156if (NOT Boost_FOUND)
142 message(STATUS "Boost 1.57.0 or newer not found, falling back to externals") 157 message(STATUS "Boost 1.63.0 or newer not found, falling back to externals")
143 set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
144endif()
145include_directories(${Boost_INCLUDE_DIR})
146
147# Include bundled CMake modules
148list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/externals/cmake-modules")
149 158
150find_package(OpenGL REQUIRED) 159 set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost")
151include_directories(${OPENGL_INCLUDE_DIR}) 160 set(Boost_NO_SYSTEM_PATHS OFF)
161 find_package(Boost QUIET REQUIRED)
162endif()
152 163
153# Prefer the -pthread flag on Linux. 164# Prefer the -pthread flag on Linux.
154set (THREADS_PREFER_PTHREAD_FLAG ON) 165set(THREADS_PREFER_PTHREAD_FLAG ON)
155find_package(Threads REQUIRED) 166find_package(Threads REQUIRED)
156 167
157if (ENABLE_SDL2) 168if (ENABLE_SDL2)
@@ -174,10 +185,43 @@ if (ENABLE_SDL2)
174 else() 185 else()
175 find_package(SDL2 REQUIRED) 186 find_package(SDL2 REQUIRED)
176 endif() 187 endif()
188
189 if (SDL2_FOUND)
190 # TODO(yuriks): Make FindSDL2.cmake export an IMPORTED library instead
191 add_library(SDL2 INTERFACE)
192 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
193 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
194 endif()
177else() 195else()
178 set(SDL2_FOUND NO) 196 set(SDL2_FOUND NO)
179endif() 197endif()
180 198
199if (ENABLE_QT)
200 if (CITRA_USE_BUNDLED_QT)
201 if (MSVC14 AND ARCHITECTURE_x86_64)
202 set(QT_VER qt-5.7-msvc2015_64)
203 else()
204 message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
205 endif()
206
207 if (DEFINED QT_VER)
208 download_bundled_external("qt/" ${QT_VER} QT_PREFIX)
209 endif()
210
211 set(QT_PREFIX_HINT HINTS "${QT_PREFIX}")
212 else()
213 # Passing an empty HINTS seems to cause default system paths to get ignored in CMake 2.8 so
214 # make sure to not pass anything if we don't have one.
215 set(QT_PREFIX_HINT)
216 endif()
217
218 find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
219endif()
220
221
222# Platform-specific library requirements
223# ======================================
224
181IF (APPLE) 225IF (APPLE)
182 FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related 226 FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
183 set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) 227 set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
@@ -206,28 +250,9 @@ if (UNIX OR MINGW)
206 endif() 250 endif()
207endif() 251endif()
208 252
209if (ENABLE_QT)
210 if (CITRA_USE_BUNDLED_QT)
211 if (MSVC14 AND ARCHITECTURE_x86_64)
212 set(QT_VER qt-5.7-msvc2015_64)
213 else()
214 message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
215 endif()
216
217 if (DEFINED QT_VER)
218 download_bundled_external("qt/" ${QT_VER} QT_PREFIX)
219 endif()
220 253
221 set(QT_PREFIX_HINT HINTS "${QT_PREFIX}") 254# Include source code
222 else() 255# ===================
223 # Passing an empty HINTS seems to cause default system paths to get ignored in CMake 2.8 so
224 # make sure to not pass anything if we don't have one.
225 set(QT_PREFIX_HINT)
226 endif()
227
228 find_package(Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QT_PREFIX_HINT})
229 set(CITRA_QT_LIBS Qt5::Widgets Qt5::OpenGL)
230endif()
231 256
232# This function should be passed a list of all files in a target. It will automatically generate 257# This function should be passed a list of all files in a target. It will automatically generate
233# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the 258# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the
@@ -251,30 +276,13 @@ get_git_head_revision(GIT_REF_SPEC GIT_REV)
251git_describe(GIT_DESC --always --long --dirty) 276git_describe(GIT_DESC --always --long --dirty)
252git_branch_name(GIT_BRANCH) 277git_branch_name(GIT_BRANCH)
253 278
254set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
255include_directories(${INI_PREFIX})
256add_subdirectory(${INI_PREFIX})
257
258add_subdirectory(externals) 279add_subdirectory(externals)
259 280add_subdirectory(src)
260option(DYNARMIC_TESTS OFF)
261set(DYNARMIC_NO_BUNDLED_FMT ON)
262add_subdirectory(externals/dynarmic)
263
264add_subdirectory(externals/glad)
265include_directories(externals/microprofile)
266include_directories(externals/nihstro/include)
267
268if (MSVC)
269 add_subdirectory(externals/getopt)
270endif()
271
272# process subdirectories
273add_subdirectory(externals/soundtouch)
274
275enable_testing() 281enable_testing()
276 282
277add_subdirectory(src) 283
284# Installation instructions
285# =========================
278 286
279# Install freedesktop.org metadata files, following those specifications: 287# Install freedesktop.org metadata files, following those specifications:
280# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html 288# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
diff --git a/README.md b/README.md
index df1d0b4eb..8de62d0ef 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Citra Emulator
7 7
8Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and macOS. Citra only emulates a subset of 3DS hardware, and therefore is generally only useful for running/debugging homebrew applications. At this time, Citra is even able to boot several commercial games! Most of these do not run to a playable state, but we are working every day to advance the project forward. 8Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and macOS. Citra only emulates a subset of 3DS hardware, and therefore is generally only useful for running/debugging homebrew applications. At this time, Citra is even able to boot several commercial games! Most of these do not run to a playable state, but we are working every day to advance the project forward.
9 9
10Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://citra-emu.org/wiki/FAQ/) before getting started with the project. 10Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://citra-emu.org/wiki/faq/) before getting started with the project.
11 11
12Check out our [website](https://citra-emu.org/)! 12Check out our [website](https://citra-emu.org/)!
13 13
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 57fc5d566..1e04931ee 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -1,12 +1,52 @@
1# Definitions for all external bundled libraries
2
3# Catch
4add_library(catch-single-include INTERFACE)
5target_include_directories(catch-single-include INTERFACE catch/single_include)
6
7# Crypto++
8add_subdirectory(cryptopp)
9
10# Dynarmic
11# Dynarmic will skip defining xbyak if it's already defined, we then define it below
12add_library(xbyak INTERFACE)
13option(DYNARMIC_TESTS OFF)
14set(DYNARMIC_NO_BUNDLED_FMT ON)
15add_subdirectory(dynarmic)
16
17# libfmt
18add_subdirectory(fmt)
19
20# getopt
21if (MSVC)
22 add_subdirectory(getopt)
23endif()
24
25# Glad
26add_subdirectory(glad)
27
28# inih
29add_subdirectory(inih)
30
31# MicroProfile
32add_library(microprofile INTERFACE)
33target_include_directories(microprofile INTERFACE ./microprofile)
34
35# Nihstro
36add_library(nihstro-headers INTERFACE)
37target_include_directories(nihstro-headers INTERFACE ./nihstro/include)
38
39# SoundTouch
40add_subdirectory(soundtouch)
41# The SoundTouch target doesn't export the necessary include paths as properties by default
42target_include_directories(SoundTouch INTERFACE ./soundtouch/include)
43
1# Xbyak 44# Xbyak
2if (ARCHITECTURE_x86_64) 45if (ARCHITECTURE_x86_64)
3 add_library(xbyak INTERFACE) 46 # Defined before "dynarmic" above
4 target_include_directories(xbyak INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak) 47 # add_library(xbyak INTERFACE)
48 target_include_directories(xbyak INTERFACE ./xbyak/xbyak)
5 if (NOT MSVC) 49 if (NOT MSVC)
6 target_compile_options(xbyak INTERFACE -fno-operator-names) 50 target_compile_options(xbyak INTERFACE -fno-operator-names)
7 endif() 51 endif()
8endif() 52endif()
9
10add_subdirectory(cryptopp)
11
12add_subdirectory(fmt)
diff --git a/externals/cryptopp/CMakeLists.txt b/externals/cryptopp/CMakeLists.txt
index 653af1e4b..864de18bb 100644
--- a/externals/cryptopp/CMakeLists.txt
+++ b/externals/cryptopp/CMakeLists.txt
@@ -10,6 +10,7 @@
10# - disabled installation 10# - disabled installation
11# - disabled documentation 11# - disabled documentation
12# - configured to build a static library only 12# - configured to build a static library only
13# - adds include directories to the library target
13 14
14include(TestBigEndian) 15include(TestBigEndian)
15include(CheckCXXCompilerFlag) 16include(CheckCXXCompilerFlag)
@@ -148,14 +149,15 @@ endif()
148# Compile targets 149# Compile targets
149#============================================================================ 150#============================================================================
150add_library(cryptopp STATIC ${cryptopp_SOURCES}) 151add_library(cryptopp STATIC ${cryptopp_SOURCES})
152target_include_directories(cryptopp INTERFACE .)
151 153
152#============================================================================ 154#============================================================================
153# Third-party libraries 155# Third-party libraries
154#============================================================================ 156#============================================================================
155 157
156if(WIN32) 158if(WIN32)
157 target_link_libraries(cryptopp ws2_32) 159 target_link_libraries(cryptopp PRIVATE ws2_32)
158endif() 160endif()
159 161
160find_package(Threads) 162find_package(Threads)
161target_link_libraries(cryptopp ${CMAKE_THREAD_LIBS_INIT}) 163target_link_libraries(cryptopp PRIVATE ${CMAKE_THREAD_LIBS_INIT})
diff --git a/externals/glad/CMakeLists.txt b/externals/glad/CMakeLists.txt
index a97d4aa73..6d35a844b 100644
--- a/externals/glad/CMakeLists.txt
+++ b/externals/glad/CMakeLists.txt
@@ -9,6 +9,7 @@ set(HEADERS
9create_directory_groups(${SRCS} ${HEADERS}) 9create_directory_groups(${SRCS} ${HEADERS})
10add_library(glad STATIC ${SRCS} ${HEADERS}) 10add_library(glad STATIC ${SRCS} ${HEADERS})
11target_include_directories(glad PUBLIC "include/") 11target_include_directories(glad PUBLIC "include/")
12
12if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") 13if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
13 target_link_libraries(glad dl) 14 target_link_libraries(glad PRIVATE dl)
14endif() 15endif()
diff --git a/externals/inih/CMakeLists.txt b/externals/inih/CMakeLists.txt
index c87f78bfc..cff36a581 100644
--- a/externals/inih/CMakeLists.txt
+++ b/externals/inih/CMakeLists.txt
@@ -9,3 +9,4 @@ set(HEADERS
9 9
10create_directory_groups(${SRCS} ${HEADERS}) 10create_directory_groups(${SRCS} ${HEADERS})
11add_library(inih ${SRCS} ${HEADERS}) 11add_library(inih ${SRCS} ${HEADERS})
12target_include_directories(inih INTERFACE .)
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index c571213fc..0ad86bb7a 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -27,12 +27,9 @@ set(HEADERS
27 time_stretch.h 27 time_stretch.h
28 ) 28 )
29 29
30include_directories(../../externals/soundtouch/include)
31
32if(SDL2_FOUND) 30if(SDL2_FOUND)
33 set(SRCS ${SRCS} sdl2_sink.cpp) 31 set(SRCS ${SRCS} sdl2_sink.cpp)
34 set(HEADERS ${HEADERS} sdl2_sink.h) 32 set(HEADERS ${HEADERS} sdl2_sink.h)
35 include_directories(${SDL2_INCLUDE_DIR})
36endif() 33endif()
37 34
38create_directory_groups(${SRCS} ${HEADERS}) 35create_directory_groups(${SRCS} ${HEADERS})
@@ -42,6 +39,6 @@ target_link_libraries(audio_core PUBLIC common core)
42target_link_libraries(audio_core PRIVATE SoundTouch) 39target_link_libraries(audio_core PRIVATE SoundTouch)
43 40
44if(SDL2_FOUND) 41if(SDL2_FOUND)
45 target_link_libraries(audio_core PRIVATE ${SDL2_LIBRARY}) 42 target_link_libraries(audio_core PRIVATE SDL2)
46 target_compile_definitions(audio_core PRIVATE HAVE_SDL2) 43 target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
47endif() 44endif()
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index 9eddb342b..d72d2b5f4 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -15,15 +15,13 @@ set(HEADERS
15 15
16create_directory_groups(${SRCS} ${HEADERS}) 16create_directory_groups(${SRCS} ${HEADERS})
17 17
18include_directories(${SDL2_INCLUDE_DIR})
19
20add_executable(citra ${SRCS} ${HEADERS}) 18add_executable(citra ${SRCS} ${HEADERS})
21target_link_libraries(citra PRIVATE common core input_common) 19target_link_libraries(citra PRIVATE common core input_common)
22target_link_libraries(citra PRIVATE ${SDL2_LIBRARY} ${OPENGL_gl_LIBRARY} inih glad) 20target_link_libraries(citra PRIVATE inih glad)
23if (MSVC) 21if (MSVC)
24 target_link_libraries(citra PRIVATE getopt) 22 target_link_libraries(citra PRIVATE getopt)
25endif() 23endif()
26target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 24target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads)
27 25
28if(UNIX AND NOT APPLE) 26if(UNIX AND NOT APPLE)
29 install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") 27 install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index c0dac9e8f..dd357ff72 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -144,7 +144,7 @@ int main(int argc, char** argv) {
144 LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before " 144 LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before "
145 "being used with Citra. \n\n For more information on dumping and " 145 "being used with Citra. \n\n For more information on dumping and "
146 "decrypting games, please refer to: " 146 "decrypting games, please refer to: "
147 "https://citra-emu.org/wiki/Dumping-Game-Cartridges"); 147 "https://citra-emu.org/wiki/dumping-game-cartridges/");
148 return -1; 148 return -1;
149 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: 149 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
150 LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported."); 150 LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 809e0b938..4841cbf05 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -92,7 +92,7 @@ else()
92 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) 92 add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS})
93endif() 93endif()
94target_link_libraries(citra-qt PRIVATE audio_core common core input_common video_core) 94target_link_libraries(citra-qt PRIVATE audio_core common core input_common video_core)
95target_link_libraries(citra-qt PRIVATE ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS} glad) 95target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::OpenGL Qt5::Widgets)
96target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 96target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
97 97
98if(UNIX AND NOT APPLE) 98if(UNIX AND NOT APPLE)
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 06b62f44c..a8a4aed8b 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -37,7 +37,10 @@ void EmuThread::run() {
37 if (!was_active) 37 if (!was_active)
38 emit DebugModeLeft(); 38 emit DebugModeLeft();
39 39
40 Core::System::GetInstance().RunLoop(); 40 Core::System::ResultStatus result = Core::System::GetInstance().RunLoop();
41 if (result != Core::System::ResultStatus::Success) {
42 emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
43 }
41 44
42 was_active = running || exec_step; 45 was_active = running || exec_step;
43 if (!was_active && !stop_run) 46 if (!was_active && !stop_run)
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 9d39f1af8..4b3a3b3cc 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -10,6 +10,7 @@
10#include <QGLWidget> 10#include <QGLWidget>
11#include <QThread> 11#include <QThread>
12#include "common/thread.h" 12#include "common/thread.h"
13#include "core/core.h"
13#include "core/frontend/emu_window.h" 14#include "core/frontend/emu_window.h"
14#include "core/frontend/motion_emu.h" 15#include "core/frontend/motion_emu.h"
15 16
@@ -97,6 +98,8 @@ signals:
97 * Qt::BlockingQueuedConnection (additionally block source thread until slot returns) 98 * Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
98 */ 99 */
99 void DebugModeLeft(); 100 void DebugModeLeft();
101
102 void ErrorThrown(Core::System::ResultStatus, std::string);
100}; 103};
101 104
102class GRenderWindow : public QWidget, public EmuWindow { 105class GRenderWindow : public QWidget, public EmuWindow {
diff --git a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
index c68fe753b..7d06ec28a 100644
--- a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
@@ -17,6 +17,7 @@
17#include "citra_qt/util/spinbox.h" 17#include "citra_qt/util/spinbox.h"
18#include "citra_qt/util/util.h" 18#include "citra_qt/util/util.h"
19#include "common/vector_math.h" 19#include "common/vector_math.h"
20#include "core/memory.h"
20#include "video_core/debug_utils/debug_utils.h" 21#include "video_core/debug_utils/debug_utils.h"
21#include "video_core/pica_state.h" 22#include "video_core/pica_state.h"
22#include "video_core/regs.h" 23#include "video_core/regs.h"
diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index b6ecf3819..8c244b6b2 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -10,6 +10,7 @@
10#include "core/hle/kernel/semaphore.h" 10#include "core/hle/kernel/semaphore.h"
11#include "core/hle/kernel/thread.h" 11#include "core/hle/kernel/thread.h"
12#include "core/hle/kernel/timer.h" 12#include "core/hle/kernel/timer.h"
13#include "core/hle/kernel/wait_object.h"
13 14
14WaitTreeItem::~WaitTreeItem() {} 15WaitTreeItem::~WaitTreeItem() {}
15 16
diff --git a/src/citra_qt/debugger/wait_tree.h b/src/citra_qt/debugger/wait_tree.h
index ee9708fc1..06ef58ea7 100644
--- a/src/citra_qt/debugger/wait_tree.h
+++ b/src/citra_qt/debugger/wait_tree.h
@@ -4,12 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <boost/container/flat_set.hpp>
8
9#include <QAbstractItemModel> 7#include <QAbstractItemModel>
10#include <QDockWidget> 8#include <QDockWidget>
11#include <QTreeView> 9#include <QTreeView>
12 10#include <boost/container/flat_set.hpp>
13#include "core/core.h" 11#include "core/core.h"
14#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
15 13
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index d1118ff7f..12212a3a4 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -10,10 +10,8 @@
10#include <QStandardItem> 10#include <QStandardItem>
11#include <QString> 11#include <QString>
12#include "citra_qt/util/util.h" 12#include "citra_qt/util/util.h"
13#include "common/color.h"
14#include "common/string_util.h" 13#include "common/string_util.h"
15#include "core/loader/smdh.h" 14#include "core/loader/smdh.h"
16#include "video_core/utils.h"
17 15
18/** 16/**
19 * Gets the game icon from SMDH data. 17 * Gets the game icon from SMDH data.
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index eb2c7d613..4f5b2ddab 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -93,6 +93,14 @@ void GMainWindow::InitializeWidgets() {
93 ui.horizontalLayout->addWidget(game_list); 93 ui.horizontalLayout->addWidget(game_list);
94 94
95 // Create status bar 95 // Create status bar
96 message_label = new QLabel();
97 // Configured separately for left alignment
98 message_label->setVisible(false);
99 message_label->setFrameStyle(QFrame::NoFrame);
100 message_label->setContentsMargins(4, 0, 4, 0);
101 message_label->setAlignment(Qt::AlignLeft);
102 statusBar()->addPermanentWidget(message_label, 1);
103
96 emu_speed_label = new QLabel(); 104 emu_speed_label = new QLabel();
97 emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% " 105 emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
98 "indicate emulation is running faster or slower than a 3DS.")); 106 "indicate emulation is running faster or slower than a 3DS."));
@@ -108,7 +116,7 @@ void GMainWindow::InitializeWidgets() {
108 label->setVisible(false); 116 label->setVisible(false);
109 label->setFrameStyle(QFrame::NoFrame); 117 label->setFrameStyle(QFrame::NoFrame);
110 label->setContentsMargins(4, 0, 4, 0); 118 label->setContentsMargins(4, 0, 4, 0);
111 statusBar()->addPermanentWidget(label); 119 statusBar()->addPermanentWidget(label, 0);
112 } 120 }
113 statusBar()->setVisible(true); 121 statusBar()->setVisible(true);
114 setStyleSheet("QStatusBar::item{border: none;}"); 122 setStyleSheet("QStatusBar::item{border: none;}");
@@ -300,9 +308,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
300 render_window->MakeCurrent(); 308 render_window->MakeCurrent();
301 309
302 if (!gladLoadGL()) { 310 if (!gladLoadGL()) {
303 QMessageBox::critical(this, tr("Error while starting Citra!"), 311 QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"),
304 tr("Failed to initialize the video core!\n\n" 312 tr("Your GPU may not support OpenGL 3.3, or you do not"
305 "Please ensure that your GPU supports OpenGL 3.3 and that you "
306 "have the latest graphics driver.")); 313 "have the latest graphics driver."));
307 return false; 314 return false;
308 } 315 }
@@ -327,18 +334,17 @@ bool GMainWindow::LoadROM(const QString& filename) {
327 break; 334 break;
328 335
329 case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: { 336 case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: {
330 // Build the MessageBox ourselves to have clickable link 337 QMessageBox::critical(
331 QMessageBox popup_error; 338 this, tr("Error while loading ROM!"),
332 popup_error.setTextFormat(Qt::RichText);
333 popup_error.setWindowTitle(tr("Error while loading ROM!"));
334 popup_error.setText(
335 tr("The game that you are trying to load must be decrypted before being used with " 339 tr("The game that you are trying to load must be decrypted before being used with "
336 "Citra.<br/><br/>" 340 "Citra. A real 3DS is required.<br/><br/>"
337 "For more information on dumping and decrypting games, please see: <a " 341 "For more information on dumping and decrypting games, please see the following "
338 "href='https://citra-emu.org/wiki/Dumping-Game-Cartridges'>https://" 342 "wiki pages: <ul>"
339 "citra-emu.org/wiki/Dumping-Game-Cartridges</a>")); 343 "<li><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Dumping Game "
340 popup_error.setIcon(QMessageBox::Critical); 344 "Cartridges</a></li>"
341 popup_error.exec(); 345 "<li><a href='https://citra-emu.org/wiki/dumping-installed-titles/'>Dumping "
346 "Installed Titles</a></li>"
347 "</ul>"));
342 break; 348 break;
343 } 349 }
344 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: 350 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
@@ -346,8 +352,23 @@ bool GMainWindow::LoadROM(const QString& filename) {
346 tr("The ROM format is not supported.")); 352 tr("The ROM format is not supported."));
347 break; 353 break;
348 354
355 case Core::System::ResultStatus::ErrorVideoCore:
356 QMessageBox::critical(
357 this, tr("An error occured in the video core."),
358 tr("Citra has encountered an error while running the video core, please see the "
359 "log for more details."
360 "For more information on accessing the log, please see the following page: "
361 "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
362 "to "
363 "Upload the Log File</a>."
364 "Ensure that you have the latest graphics drivers for your GPU."));
365
366 break;
367
349 default: 368 default:
350 QMessageBox::critical(this, tr("Error while loading ROM!"), tr("Unknown error!")); 369 QMessageBox::critical(
370 this, tr("Error while loading ROM!"),
371 tr("An unknown error occured. Please see the log for more details."));
351 break; 372 break;
352 } 373 }
353 return false; 374 return false;
@@ -424,6 +445,7 @@ void GMainWindow::ShutdownGame() {
424 445
425 // Disable status bar updates 446 // Disable status bar updates
426 status_bar_update_timer.stop(); 447 status_bar_update_timer.stop();
448 message_label->setVisible(false);
427 emu_speed_label->setVisible(false); 449 emu_speed_label->setVisible(false);
428 game_fps_label->setVisible(false); 450 game_fps_label->setVisible(false);
429 emu_frametime_label->setVisible(false); 451 emu_frametime_label->setVisible(false);
@@ -530,6 +552,10 @@ void GMainWindow::OnMenuRecentFile() {
530 552
531void GMainWindow::OnStartGame() { 553void GMainWindow::OnStartGame() {
532 emu_thread->SetRunning(true); 554 emu_thread->SetRunning(true);
555 qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
556 qRegisterMetaType<std::string>("std::string");
557 connect(emu_thread.get(), SIGNAL(ErrorThrown(Core::System::ResultStatus, std::string)), this,
558 SLOT(OnCoreError(Core::System::ResultStatus, std::string)));
533 559
534 ui.action_Start->setEnabled(false); 560 ui.action_Start->setEnabled(false);
535 ui.action_Start->setText(tr("Continue")); 561 ui.action_Start->setText(tr("Continue"));
@@ -622,11 +648,74 @@ void GMainWindow::UpdateStatusBar() {
622 emu_frametime_label->setVisible(true); 648 emu_frametime_label->setVisible(true);
623} 649}
624 650
651void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
652 QMessageBox::StandardButton answer;
653 QString status_message;
654 const QString common_message =
655 tr("The game you are trying to load requires additional files from your 3DS to be dumped "
656 "before playing.<br/><br/>For more information on dumping these files, please see the "
657 "following wiki page: <a "
658 "href='https://citra-emu.org/wiki/"
659 "dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumping System "
660 "Archives and the Shared Fonts from a 3DS Console</a>.<br/><br/>Would you like to quit "
661 "back to the game list? Continuing emulation may result in crashes, corrupted save "
662 "data, or other bugs.");
663 switch (result) {
664 case Core::System::ResultStatus::ErrorSystemFiles: {
665 QString message = "Citra was unable to locate a 3DS system archive";
666 if (!details.empty()) {
667 message.append(tr(": %1. ").arg(details.c_str()));
668 } else {
669 message.append(". ");
670 }
671 message.append(common_message);
672
673 answer = QMessageBox::question(this, tr("System Archive Not Found"), message,
674 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
675 status_message = "System Archive Missing";
676 break;
677 }
678
679 case Core::System::ResultStatus::ErrorSharedFont: {
680 QString message = tr("Citra was unable to locate the 3DS shared fonts. ");
681 message.append(common_message);
682 answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
683 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
684 status_message = "Shared Font Missing";
685 break;
686 }
687
688 default:
689 answer = QMessageBox::question(
690 this, tr("Fatal Error"),
691 tr("Citra has encountered a fatal error, please see the log for more details. "
692 "For more information on accessing the log, please see the following page: "
693 "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to "
694 "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? "
695 "Continuing emulation may result in crashes, corrupted save data, or other bugs."),
696 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
697 status_message = "Fatal Error encountered";
698 break;
699 }
700
701 if (answer == QMessageBox::Yes) {
702 if (emu_thread) {
703 ShutdownGame();
704 }
705 } else {
706 // Only show the message if the game is still running.
707 if (emu_thread) {
708 message_label->setText(status_message);
709 message_label->setVisible(true);
710 }
711 }
712}
713
625bool GMainWindow::ConfirmClose() { 714bool GMainWindow::ConfirmClose() {
626 if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) 715 if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
627 return true; 716 return true;
628 717
629 auto answer = 718 QMessageBox::StandardButton answer =
630 QMessageBox::question(this, tr("Citra"), tr("Are you sure you want to close Citra?"), 719 QMessageBox::question(this, tr("Citra"), tr("Are you sure you want to close Citra?"),
631 QMessageBox::Yes | QMessageBox::No, QMessageBox::No); 720 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
632 return answer != QMessageBox::No; 721 return answer != QMessageBox::No;
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index cb2e87cbd..952a50974 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -8,6 +8,7 @@
8#include <memory> 8#include <memory>
9#include <QMainWindow> 9#include <QMainWindow>
10#include <QTimer> 10#include <QTimer>
11#include "core/core.h"
11#include "ui_main.h" 12#include "ui_main.h"
12 13
13class Config; 14class Config;
@@ -125,6 +126,7 @@ private slots:
125 void OnDisplayTitleBars(bool); 126 void OnDisplayTitleBars(bool);
126 void ToggleWindowMode(); 127 void ToggleWindowMode();
127 void OnCreateGraphicsSurfaceViewer(); 128 void OnCreateGraphicsSurfaceViewer();
129 void OnCoreError(Core::System::ResultStatus, std::string);
128 130
129private: 131private:
130 void UpdateStatusBar(); 132 void UpdateStatusBar();
@@ -135,6 +137,7 @@ private:
135 GameList* game_list; 137 GameList* game_list;
136 138
137 // Status bar elements 139 // Status bar elements
140 QLabel* message_label = nullptr;
138 QLabel* emu_speed_label = nullptr; 141 QLabel* emu_speed_label = nullptr;
139 QLabel* game_fps_label = nullptr; 142 QLabel* game_fps_label = nullptr;
140 QLabel* emu_frametime_label = nullptr; 143 QLabel* emu_frametime_label = nullptr;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index a33a8cdbe..7e83e64b0 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -95,6 +95,7 @@ endif()
95create_directory_groups(${SRCS} ${HEADERS}) 95create_directory_groups(${SRCS} ${HEADERS})
96 96
97add_library(common STATIC ${SRCS} ${HEADERS}) 97add_library(common STATIC ${SRCS} ${HEADERS})
98target_link_libraries(common PUBLIC Boost::boost microprofile)
98if (ARCHITECTURE_x86_64) 99if (ARCHITECTURE_x86_64)
99 target_link_libraries(common PRIVATE xbyak) 100 target_link_libraries(common PRIVATE xbyak)
100endif() 101endif()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7aa81e885..6e602b0c5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -45,6 +45,8 @@ set(SRCS
45 hle/kernel/client_port.cpp 45 hle/kernel/client_port.cpp
46 hle/kernel/client_session.cpp 46 hle/kernel/client_session.cpp
47 hle/kernel/event.cpp 47 hle/kernel/event.cpp
48 hle/kernel/handle_table.cpp
49 hle/kernel/hle_ipc.cpp
48 hle/kernel/kernel.cpp 50 hle/kernel/kernel.cpp
49 hle/kernel/memory.cpp 51 hle/kernel/memory.cpp
50 hle/kernel/mutex.cpp 52 hle/kernel/mutex.cpp
@@ -57,6 +59,7 @@ set(SRCS
57 hle/kernel/thread.cpp 59 hle/kernel/thread.cpp
58 hle/kernel/timer.cpp 60 hle/kernel/timer.cpp
59 hle/kernel/vm_manager.cpp 61 hle/kernel/vm_manager.cpp
62 hle/kernel/wait_object.cpp
60 hle/service/ac/ac.cpp 63 hle/service/ac/ac.cpp
61 hle/service/ac/ac_i.cpp 64 hle/service/ac/ac_i.cpp
62 hle/service/ac/ac_u.cpp 65 hle/service/ac/ac_u.cpp
@@ -153,8 +156,9 @@ set(SRCS
153 hle/service/qtm/qtm_sp.cpp 156 hle/service/qtm/qtm_sp.cpp
154 hle/service/qtm/qtm_u.cpp 157 hle/service/qtm/qtm_u.cpp
155 hle/service/service.cpp 158 hle/service/service.cpp
159 hle/service/sm/sm.cpp
160 hle/service/sm/srv.cpp
156 hle/service/soc_u.cpp 161 hle/service/soc_u.cpp
157 hle/service/srv.cpp
158 hle/service/ssl_c.cpp 162 hle/service/ssl_c.cpp
159 hle/service/y2r_u.cpp 163 hle/service/y2r_u.cpp
160 hle/shared_page.cpp 164 hle/shared_page.cpp
@@ -236,6 +240,8 @@ set(HEADERS
236 hle/kernel/client_session.h 240 hle/kernel/client_session.h
237 hle/kernel/errors.h 241 hle/kernel/errors.h
238 hle/kernel/event.h 242 hle/kernel/event.h
243 hle/kernel/handle_table.h
244 hle/kernel/hle_ipc.h
239 hle/kernel/kernel.h 245 hle/kernel/kernel.h
240 hle/kernel/memory.h 246 hle/kernel/memory.h
241 hle/kernel/mutex.h 247 hle/kernel/mutex.h
@@ -249,6 +255,7 @@ set(HEADERS
249 hle/kernel/thread.h 255 hle/kernel/thread.h
250 hle/kernel/timer.h 256 hle/kernel/timer.h
251 hle/kernel/vm_manager.h 257 hle/kernel/vm_manager.h
258 hle/kernel/wait_object.h
252 hle/result.h 259 hle/result.h
253 hle/service/ac/ac.h 260 hle/service/ac/ac.h
254 hle/service/ac/ac_i.h 261 hle/service/ac/ac_i.h
@@ -346,8 +353,9 @@ set(HEADERS
346 hle/service/qtm/qtm_sp.h 353 hle/service/qtm/qtm_sp.h
347 hle/service/qtm/qtm_u.h 354 hle/service/qtm/qtm_u.h
348 hle/service/service.h 355 hle/service/service.h
356 hle/service/sm/sm.h
357 hle/service/sm/srv.h
349 hle/service/soc_u.h 358 hle/service/soc_u.h
350 hle/service/srv.h
351 hle/service/ssl_c.h 359 hle/service/ssl_c.h
352 hle/service/y2r_u.h 360 hle/service/y2r_u.h
353 hle/shared_page.h 361 hle/shared_page.h
@@ -374,11 +382,7 @@ set(HEADERS
374 telemetry_session.h 382 telemetry_session.h
375 ) 383 )
376 384
377include_directories(../../externals/dynarmic/include)
378include_directories(../../externals/cryptopp)
379
380create_directory_groups(${SRCS} ${HEADERS}) 385create_directory_groups(${SRCS} ${HEADERS})
381
382add_library(core STATIC ${SRCS} ${HEADERS}) 386add_library(core STATIC ${SRCS} ${HEADERS})
383target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 387target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
384target_link_libraries(core PRIVATE cryptopp dynarmic) 388target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 450e7566d..5429bcb26 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -3,7 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <memory>
6 6#include <utility>
7#include "audio_core/audio_core.h" 7#include "audio_core/audio_core.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
@@ -26,6 +26,7 @@ namespace Core {
26/*static*/ System System::s_instance; 26/*static*/ System System::s_instance;
27 27
28System::ResultStatus System::RunLoop(int tight_loop) { 28System::ResultStatus System::RunLoop(int tight_loop) {
29 status = ResultStatus::Success;
29 if (!cpu_core) { 30 if (!cpu_core) {
30 return ResultStatus::ErrorNotInitialized; 31 return ResultStatus::ErrorNotInitialized;
31 } 32 }
@@ -59,7 +60,7 @@ System::ResultStatus System::RunLoop(int tight_loop) {
59 HW::Update(); 60 HW::Update();
60 Reschedule(); 61 Reschedule();
61 62
62 return ResultStatus::Success; 63 return status;
63} 64}
64 65
65System::ResultStatus System::SingleStep() { 66System::ResultStatus System::SingleStep() {
@@ -73,14 +74,25 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
73 LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str()); 74 LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
74 return ResultStatus::ErrorGetLoader; 75 return ResultStatus::ErrorGetLoader;
75 } 76 }
77 std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
78 app_loader->LoadKernelSystemMode();
79
80 if (system_mode.second != Loader::ResultStatus::Success) {
81 LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
82 static_cast<int>(system_mode.second));
83 System::Shutdown();
76 84
77 boost::optional<u32> system_mode{app_loader->LoadKernelSystemMode()}; 85 switch (system_mode.second) {
78 if (!system_mode) { 86 case Loader::ResultStatus::ErrorEncrypted:
79 LOG_CRITICAL(Core, "Failed to determine system mode!"); 87 return ResultStatus::ErrorLoader_ErrorEncrypted;
80 return ResultStatus::ErrorSystemMode; 88 case Loader::ResultStatus::ErrorInvalidFormat:
89 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
90 default:
91 return ResultStatus::ErrorSystemMode;
92 }
81 } 93 }
82 94
83 ResultStatus init_result{Init(emu_window, system_mode.get())}; 95 ResultStatus init_result{Init(emu_window, system_mode.first.get())};
84 if (init_result != ResultStatus::Success) { 96 if (init_result != ResultStatus::Success) {
85 LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result); 97 LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result);
86 System::Shutdown(); 98 System::Shutdown();
@@ -101,7 +113,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
101 return ResultStatus::ErrorLoader; 113 return ResultStatus::ErrorLoader;
102 } 114 }
103 } 115 }
104 return ResultStatus::Success; 116 status = ResultStatus::Success;
117 return status;
105} 118}
106 119
107void System::PrepareReschedule() { 120void System::PrepareReschedule() {
diff --git a/src/core/core.h b/src/core/core.h
index 6af772831..4e3b6b409 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -40,7 +40,10 @@ public:
40 ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption 40 ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
41 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an 41 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
42 /// invalid format 42 /// invalid format
43 ErrorSystemFiles, ///< Error in finding system files
44 ErrorSharedFont, ///< Error in finding shared font
43 ErrorVideoCore, ///< Error in the video core 45 ErrorVideoCore, ///< Error in the video core
46 ErrorUnknown ///< Any other error
44 }; 47 };
45 48
46 /** 49 /**
@@ -105,6 +108,17 @@ public:
105 PerfStats perf_stats; 108 PerfStats perf_stats;
106 FrameLimiter frame_limiter; 109 FrameLimiter frame_limiter;
107 110
111 void SetStatus(ResultStatus new_status, const char* details = nullptr) {
112 status = new_status;
113 if (details) {
114 status_details = details;
115 }
116 }
117
118 const std::string& GetStatusDetails() const {
119 return status_details;
120 }
121
108private: 122private:
109 /** 123 /**
110 * Initialize the emulated system. 124 * Initialize the emulated system.
@@ -130,6 +144,9 @@ private:
130 std::unique_ptr<Core::TelemetrySession> telemetry_session; 144 std::unique_ptr<Core::TelemetrySession> telemetry_session;
131 145
132 static System s_instance; 146 static System s_instance;
147
148 ResultStatus status = ResultStatus::Success;
149 std::string status_details = "";
133}; 150};
134 151
135inline ARM_Interface& CPU() { 152inline ARM_Interface& CPU() {
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 89455e39c..6d9007731 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -9,7 +9,9 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/string_util.h" 11#include "common/string_util.h"
12#include "core/core.h"
12#include "core/file_sys/archive_ncch.h" 13#include "core/file_sys/archive_ncch.h"
14#include "core/file_sys/errors.h"
13#include "core/file_sys/ivfc_archive.h" 15#include "core/file_sys/ivfc_archive.h"
14#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
15 17
@@ -33,11 +35,44 @@ ArchiveFactory_NCCH::ArchiveFactory_NCCH(const std::string& nand_directory)
33ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) { 35ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) {
34 auto vec = path.AsBinary(); 36 auto vec = path.AsBinary();
35 const u32* data = reinterpret_cast<u32*>(vec.data()); 37 const u32* data = reinterpret_cast<u32*>(vec.data());
36 std::string file_path = GetNCCHPath(mount_point, data[1], data[0]); 38 u32 high = data[1];
39 u32 low = data[0];
40 std::string file_path = GetNCCHPath(mount_point, high, low);
37 auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb"); 41 auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb");
38 42
39 if (!file->IsOpen()) { 43 if (!file->IsOpen()) {
40 return ResultCode(-1); // TODO(Subv): Find the right error code 44 // High Title ID of the archive: The category (https://3dbrew.org/wiki/Title_list).
45 constexpr u32 shared_data_archive = 0x0004009B;
46 constexpr u32 system_data_archive = 0x000400DB;
47
48 // Low Title IDs.
49 constexpr u32 mii_data = 0x00010202;
50 constexpr u32 region_manifest = 0x00010402;
51 constexpr u32 ng_word_list = 0x00010302;
52
53 LOG_DEBUG(Service_FS, "Full Path: %s. Category: 0x%X. Path: 0x%X.", path.DebugStr().c_str(),
54 high, low);
55
56 if (high == shared_data_archive) {
57 if (low == mii_data) {
58 LOG_ERROR(Service_FS, "Failed to get a handle for shared data archive: Mii data. ");
59 Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles,
60 "Mii data");
61 } else if (low == region_manifest) {
62 LOG_ERROR(Service_FS,
63 "Failed to get a handle for shared data archive: region manifest.");
64 Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles,
65 "Region manifest");
66 }
67 } else if (high == system_data_archive) {
68 if (low == ng_word_list) {
69 LOG_ERROR(Service_FS,
70 "Failed to get a handle for system data archive: NG bad word list.");
71 Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles,
72 "NG bad word list");
73 }
74 }
75 return ERROR_NOT_FOUND;
41 } 76 }
42 auto size = file->GetSize(); 77 auto size = file->GetSize();
43 78
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 06c4c5a85..d7348c09d 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -3,7 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6
6#include "core/hle/ipc.h" 7#include "core/hle/ipc.h"
8#include "core/hle/kernel/handle_table.h"
7#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
8 10
9namespace IPC { 11namespace IPC {
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 6a7af93a9..1d24401b1 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/result.h"
9 10
10// Address arbiters are an underlying kernel synchronization object that can be created/used via 11// Address arbiters are an underlying kernel synchronization object that can be created/used via
11// supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR 12// supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index 03ffdece1..ce5d94e99 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -6,6 +6,7 @@
6#include "core/hle/kernel/client_port.h" 6#include "core/hle/kernel/client_port.h"
7#include "core/hle/kernel/client_session.h" 7#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/errors.h" 8#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/server_port.h" 11#include "core/hle/kernel/server_port.h"
11#include "core/hle/kernel/server_session.h" 12#include "core/hle/kernel/server_session.h"
@@ -25,20 +26,17 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
25 active_sessions++; 26 active_sessions++;
26 27
27 // Create a new session pair, let the created sessions inherit the parent port's HLE handler. 28 // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
28 auto sessions = 29 auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), this);
29 ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler, this);
30 auto client_session = std::get<SharedPtr<ClientSession>>(sessions);
31 auto server_session = std::get<SharedPtr<ServerSession>>(sessions);
32 30
33 if (server_port->hle_handler) 31 if (server_port->hle_handler)
34 server_port->hle_handler->ClientConnected(server_session); 32 server_port->hle_handler->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
35 else 33 else
36 server_port->pending_sessions.push_back(std::move(server_session)); 34 server_port->pending_sessions.push_back(std::get<SharedPtr<ServerSession>>(sessions));
37 35
38 // Wake the threads waiting on the ServerPort 36 // Wake the threads waiting on the ServerPort
39 server_port->WakeupAllWaitingThreads(); 37 server_port->WakeupAllWaitingThreads();
40 38
41 return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); 39 return MakeResult(std::get<SharedPtr<ClientSession>>(sessions));
42} 40}
43 41
44} // namespace 42} // namespace
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 511490c7c..8f7d6ac44 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/result.h"
10 11
11namespace Kernel { 12namespace Kernel {
12 13
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 783b1c061..6bc49ff64 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -5,6 +5,8 @@
5#include "common/assert.h" 5#include "common/assert.h"
6 6
7#include "core/hle/kernel/client_session.h" 7#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/server_session.h" 10#include "core/hle/kernel/server_session.h"
9 11
10namespace Kernel { 12namespace Kernel {
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 9f3adb72b..2de379c09 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -6,10 +6,9 @@
6 6
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9
10#include "common/common_types.h" 9#include "common/common_types.h"
11
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
13 12
14namespace Kernel { 13namespace Kernel {
15 14
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 3e3673508..cc41abb85 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/wait_object.h"
9 10
10namespace Kernel { 11namespace Kernel {
11 12
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
new file mode 100644
index 000000000..c7322d883
--- /dev/null
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -0,0 +1,97 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <utility>
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/process.h"
12#include "core/hle/kernel/thread.h"
13
14namespace Kernel {
15
16HandleTable g_handle_table;
17
18HandleTable::HandleTable() {
19 next_generation = 1;
20 Clear();
21}
22
23ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
24 DEBUG_ASSERT(obj != nullptr);
25
26 u16 slot = next_free_slot;
27 if (slot >= generations.size()) {
28 LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
29 return ERR_OUT_OF_HANDLES;
30 }
31 next_free_slot = generations[slot];
32
33 u16 generation = next_generation++;
34
35 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
36 // CTR-OS doesn't use generation 0, so skip straight to 1.
37 if (next_generation >= (1 << 15))
38 next_generation = 1;
39
40 generations[slot] = generation;
41 objects[slot] = std::move(obj);
42
43 Handle handle = generation | (slot << 15);
44 return MakeResult<Handle>(handle);
45}
46
47ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
48 SharedPtr<Object> object = GetGeneric(handle);
49 if (object == nullptr) {
50 LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
51 return ERR_INVALID_HANDLE;
52 }
53 return Create(std::move(object));
54}
55
56ResultCode HandleTable::Close(Handle handle) {
57 if (!IsValid(handle))
58 return ERR_INVALID_HANDLE;
59
60 u16 slot = GetSlot(handle);
61
62 objects[slot] = nullptr;
63
64 generations[slot] = next_free_slot;
65 next_free_slot = slot;
66 return RESULT_SUCCESS;
67}
68
69bool HandleTable::IsValid(Handle handle) const {
70 size_t slot = GetSlot(handle);
71 u16 generation = GetGeneration(handle);
72
73 return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
74}
75
76SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
77 if (handle == CurrentThread) {
78 return GetCurrentThread();
79 } else if (handle == CurrentProcess) {
80 return g_current_process;
81 }
82
83 if (!IsValid(handle)) {
84 return nullptr;
85 }
86 return objects[GetSlot(handle)];
87}
88
89void HandleTable::Clear() {
90 for (u16 i = 0; i < MAX_COUNT; ++i) {
91 generations[i] = i + 1;
92 objects[i] = nullptr;
93 }
94 next_free_slot = 0;
95}
96
97} // namespace
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
new file mode 100644
index 000000000..d6aaefbf7
--- /dev/null
+++ b/src/core/hle/kernel/handle_table.h
@@ -0,0 +1,126 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <cstddef>
9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
12
13namespace Kernel {
14
15enum KernelHandle : Handle {
16 CurrentThread = 0xFFFF8000,
17 CurrentProcess = 0xFFFF8001,
18};
19
20/**
21 * This class allows the creation of Handles, which are references to objects that can be tested
22 * for validity and looked up. Here they are used to pass references to kernel objects to/from the
23 * emulated process. it has been designed so that it follows the same handle format and has
24 * approximately the same restrictions as the handle manager in the CTR-OS.
25 *
26 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
27 * The slot index is used to index into the arrays in this class to access the data corresponding
28 * to the Handle.
29 *
30 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
31 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
32 * value of the counter is stored into the Handle as well as in the handle table (in the
33 * "generations" array). When looking up a handle, the Handle's generation must match with the
34 * value stored on the class, otherwise the Handle is considered invalid.
35 *
36 * To find free slots when allocating a Handle without needing to scan the entire object array, the
37 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
38 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
39 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
40 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
41 * verified and isn't likely to cause any problems.
42 */
43class HandleTable final : NonCopyable {
44public:
45 HandleTable();
46
47 /**
48 * Allocates a handle for the given object.
49 * @return The created Handle or one of the following errors:
50 * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
51 */
52 ResultVal<Handle> Create(SharedPtr<Object> obj);
53
54 /**
55 * Returns a new handle that points to the same object as the passed in handle.
56 * @return The duplicated Handle or one of the following errors:
57 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
58 * - Any errors returned by `Create()`.
59 */
60 ResultVal<Handle> Duplicate(Handle handle);
61
62 /**
63 * Closes a handle, removing it from the table and decreasing the object's ref-count.
64 * @return `RESULT_SUCCESS` or one of the following errors:
65 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
66 */
67 ResultCode Close(Handle handle);
68
69 /// Checks if a handle is valid and points to an existing object.
70 bool IsValid(Handle handle) const;
71
72 /**
73 * Looks up a handle.
74 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
75 */
76 SharedPtr<Object> GetGeneric(Handle handle) const;
77
78 /**
79 * Looks up a handle while verifying its type.
80 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
81 * type differs from the requested one.
82 */
83 template <class T>
84 SharedPtr<T> Get(Handle handle) const {
85 return DynamicObjectCast<T>(GetGeneric(handle));
86 }
87
88 /// Closes all handles held in this table.
89 void Clear();
90
91private:
92 /**
93 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
94 * reduced by ExHeader values, but this is not emulated here.
95 */
96 static const size_t MAX_COUNT = 4096;
97
98 static u16 GetSlot(Handle handle) {
99 return handle >> 15;
100 }
101 static u16 GetGeneration(Handle handle) {
102 return handle & 0x7FFF;
103 }
104
105 /// Stores the Object referenced by the handle or null if the slot is empty.
106 std::array<SharedPtr<Object>, MAX_COUNT> objects;
107
108 /**
109 * The value of `next_generation` when the handle was created, used to check for validity. For
110 * empty slots, contains the index of the next free slot in the list.
111 */
112 std::array<u16, MAX_COUNT> generations;
113
114 /**
115 * Global counter of the number of created handles. Stored in `generations` when a handle is
116 * created, and wraps around to 1 when it hits 0x8000.
117 */
118 u16 next_generation;
119
120 /// Head of the free slots linked list.
121 u16 next_free_slot;
122};
123
124extern HandleTable g_handle_table;
125
126} // namespace
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
new file mode 100644
index 000000000..0922b3f47
--- /dev/null
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -0,0 +1,24 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <boost/range/algorithm_ext/erase.hpp>
6#include "common/assert.h"
7#include "common/common_types.h"
8#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/server_session.h"
11
12namespace Kernel {
13
14void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) {
15 server_session->SetHleHandler(shared_from_this());
16 connected_sessions.push_back(server_session);
17}
18
19void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_session) {
20 server_session->SetHleHandler(nullptr);
21 boost::range::remove_erase(connected_sessions, server_session);
22}
23
24} // namespace Kernel
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
new file mode 100644
index 000000000..14f682f44
--- /dev/null
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -0,0 +1,53 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <vector>
9#include "core/hle/kernel/kernel.h"
10
11namespace Kernel {
12
13class ServerSession;
14
15/**
16 * Interface implemented by HLE Session handlers.
17 * This can be provided to a ServerSession in order to hook into several relevant events
18 * (such as a new connection or a SyncRequest) so they can be implemented in the emulator.
19 */
20class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
21public:
22 /**
23 * Handles a sync request from the emulated application.
24 * @param server_session The ServerSession that was triggered for this sync request,
25 * it should be used to differentiate which client (As in ClientSession) we're answering to.
26 * TODO(Subv): Use a wrapper structure to hold all the information relevant to
27 * this request (ServerSession, Originator thread, Translated command buffer, etc).
28 * @returns ResultCode the result code of the translate operation.
29 */
30 virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0;
31
32 /**
33 * Signals that a client has just connected to this HLE handler and keeps the
34 * associated ServerSession alive for the duration of the connection.
35 * @param server_session Owning pointer to the ServerSession associated with the connection.
36 */
37 void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
38
39 /**
40 * Signals that a client has just disconnected from this HLE handler and releases the
41 * associated ServerSession.
42 * @param server_session ServerSession associated with the connection.
43 */
44 void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
45
46protected:
47 /// List of sessions that are connected to this handler.
48 /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
49 // for the duration of the connection.
50 std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
51};
52
53} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 7f84e01aa..7470a97ca 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,11 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/hle/config_mem.h" 5#include "core/hle/config_mem.h"
9#include "core/hle/kernel/errors.h" 6#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/kernel.h" 7#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/memory.h" 8#include "core/hle/kernel/memory.h"
12#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
@@ -18,165 +15,6 @@
18namespace Kernel { 15namespace Kernel {
19 16
20unsigned int Object::next_object_id; 17unsigned int Object::next_object_id;
21HandleTable g_handle_table;
22
23void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
24 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
25 if (itr == waiting_threads.end())
26 waiting_threads.push_back(std::move(thread));
27}
28
29void WaitObject::RemoveWaitingThread(Thread* thread) {
30 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
31 // If a thread passed multiple handles to the same object,
32 // the kernel might attempt to remove the thread from the object's
33 // waiting threads list multiple times.
34 if (itr != waiting_threads.end())
35 waiting_threads.erase(itr);
36}
37
38SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
39 Thread* candidate = nullptr;
40 s32 candidate_priority = THREADPRIO_LOWEST + 1;
41
42 for (const auto& thread : waiting_threads) {
43 // The list of waiting threads must not contain threads that are not waiting to be awakened.
44 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
45 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
46 "Inconsistent thread statuses in waiting_threads");
47
48 if (thread->current_priority >= candidate_priority)
49 continue;
50
51 if (ShouldWait(thread.get()))
52 continue;
53
54 // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
55 // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
56 bool ready_to_run = true;
57 if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
58 ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
59 [&thread](const SharedPtr<WaitObject>& object) {
60 return object->ShouldWait(thread.get());
61 });
62 }
63
64 if (ready_to_run) {
65 candidate = thread.get();
66 candidate_priority = thread->current_priority;
67 }
68 }
69
70 return candidate;
71}
72
73void WaitObject::WakeupAllWaitingThreads() {
74 while (auto thread = GetHighestPriorityReadyThread()) {
75 if (!thread->IsSleepingOnWaitAll()) {
76 Acquire(thread.get());
77 // Set the output index of the WaitSynchronizationN call to the index of this object.
78 if (thread->wait_set_output) {
79 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
80 thread->wait_set_output = false;
81 }
82 } else {
83 for (auto& object : thread->wait_objects) {
84 object->Acquire(thread.get());
85 }
86 // Note: This case doesn't update the output index of WaitSynchronizationN.
87 }
88
89 for (auto& object : thread->wait_objects)
90 object->RemoveWaitingThread(thread.get());
91 thread->wait_objects.clear();
92
93 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
94 thread->ResumeFromWait();
95 }
96}
97
98const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
99 return waiting_threads;
100}
101
102HandleTable::HandleTable() {
103 next_generation = 1;
104 Clear();
105}
106
107ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
108 DEBUG_ASSERT(obj != nullptr);
109
110 u16 slot = next_free_slot;
111 if (slot >= generations.size()) {
112 LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
113 return ERR_OUT_OF_HANDLES;
114 }
115 next_free_slot = generations[slot];
116
117 u16 generation = next_generation++;
118
119 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
120 // CTR-OS doesn't use generation 0, so skip straight to 1.
121 if (next_generation >= (1 << 15))
122 next_generation = 1;
123
124 generations[slot] = generation;
125 objects[slot] = std::move(obj);
126
127 Handle handle = generation | (slot << 15);
128 return MakeResult<Handle>(handle);
129}
130
131ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
132 SharedPtr<Object> object = GetGeneric(handle);
133 if (object == nullptr) {
134 LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
135 return ERR_INVALID_HANDLE;
136 }
137 return Create(std::move(object));
138}
139
140ResultCode HandleTable::Close(Handle handle) {
141 if (!IsValid(handle))
142 return ERR_INVALID_HANDLE;
143
144 u16 slot = GetSlot(handle);
145
146 objects[slot] = nullptr;
147
148 generations[slot] = next_free_slot;
149 next_free_slot = slot;
150 return RESULT_SUCCESS;
151}
152
153bool HandleTable::IsValid(Handle handle) const {
154 size_t slot = GetSlot(handle);
155 u16 generation = GetGeneration(handle);
156
157 return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
158}
159
160SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
161 if (handle == CurrentThread) {
162 return GetCurrentThread();
163 } else if (handle == CurrentProcess) {
164 return g_current_process;
165 }
166
167 if (!IsValid(handle)) {
168 return nullptr;
169 }
170 return objects[GetSlot(handle)];
171}
172
173void HandleTable::Clear() {
174 for (u16 i = 0; i < MAX_COUNT; ++i) {
175 generations[i] = i + 1;
176 objects[i] = nullptr;
177 }
178 next_free_slot = 0;
179}
180 18
181/// Initialize the kernel 19/// Initialize the kernel
182void Init(u32 system_mode) { 20void Init(u32 system_mode) {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 94f2025a0..9cf288b08 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,26 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <array>
9#include <cstddef> 7#include <cstddef>
10#include <string> 8#include <string>
11#include <vector> 9#include <utility>
12#include <boost/smart_ptr/intrusive_ptr.hpp> 10#include <boost/smart_ptr/intrusive_ptr.hpp>
13#include "common/common_types.h" 11#include "common/common_types.h"
14#include "core/hle/result.h"
15 12
16namespace Kernel { 13namespace Kernel {
17 14
18using Handle = u32; 15using Handle = u32;
19 16
20class Thread;
21
22enum KernelHandle : Handle {
23 CurrentThread = 0xFFFF8000,
24 CurrentProcess = 0xFFFF8001,
25};
26
27enum class HandleType : u32 { 17enum class HandleType : u32 {
28 Unknown, 18 Unknown,
29 Event, 19 Event,
@@ -121,170 +111,17 @@ inline void intrusive_ptr_release(Object* object) {
121template <typename T> 111template <typename T>
122using SharedPtr = boost::intrusive_ptr<T>; 112using SharedPtr = boost::intrusive_ptr<T>;
123 113
124/// Class that represents a Kernel object that a thread can be waiting on
125class WaitObject : public Object {
126public:
127 /**
128 * Check if the specified thread should wait until the object is available
129 * @param thread The thread about which we're deciding.
130 * @return True if the current thread should wait due to this object being unavailable
131 */
132 virtual bool ShouldWait(Thread* thread) const = 0;
133
134 /// Acquire/lock the object for the specified thread if it is available
135 virtual void Acquire(Thread* thread) = 0;
136
137 /**
138 * Add a thread to wait on this object
139 * @param thread Pointer to thread to add
140 */
141 virtual void AddWaitingThread(SharedPtr<Thread> thread);
142
143 /**
144 * Removes a thread from waiting on this object (e.g. if it was resumed already)
145 * @param thread Pointer to thread to remove
146 */
147 virtual void RemoveWaitingThread(Thread* thread);
148
149 /**
150 * Wake up all threads waiting on this object that can be awoken, in priority order,
151 * and set the synchronization result and output of the thread.
152 */
153 virtual void WakeupAllWaitingThreads();
154
155 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
156 SharedPtr<Thread> GetHighestPriorityReadyThread();
157
158 /// Get a const reference to the waiting threads list for debug use
159 const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
160
161private:
162 /// Threads waiting for this object to become available
163 std::vector<SharedPtr<Thread>> waiting_threads;
164};
165
166/** 114/**
167 * This class allows the creation of Handles, which are references to objects that can be tested 115 * Attempts to downcast the given Object pointer to a pointer to T.
168 * for validity and looked up. Here they are used to pass references to kernel objects to/from the 116 * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
169 * emulated process. it has been designed so that it follows the same handle format and has
170 * approximately the same restrictions as the handle manager in the CTR-OS.
171 *
172 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
173 * The slot index is used to index into the arrays in this class to access the data corresponding
174 * to the Handle.
175 *
176 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
177 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
178 * value of the counter is stored into the Handle as well as in the handle table (in the
179 * "generations" array). When looking up a handle, the Handle's generation must match with the
180 * value stored on the class, otherwise the Handle is considered invalid.
181 *
182 * To find free slots when allocating a Handle without needing to scan the entire object array, the
183 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
184 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
185 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
186 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
187 * verified and isn't likely to cause any problems.
188 */ 117 */
189class HandleTable final : NonCopyable { 118template <typename T>
190public: 119inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
191 HandleTable(); 120 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
192 121 return boost::static_pointer_cast<T>(std::move(object));
193 /**
194 * Allocates a handle for the given object.
195 * @return The created Handle or one of the following errors:
196 * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
197 */
198 ResultVal<Handle> Create(SharedPtr<Object> obj);
199
200 /**
201 * Returns a new handle that points to the same object as the passed in handle.
202 * @return The duplicated Handle or one of the following errors:
203 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
204 * - Any errors returned by `Create()`.
205 */
206 ResultVal<Handle> Duplicate(Handle handle);
207
208 /**
209 * Closes a handle, removing it from the table and decreasing the object's ref-count.
210 * @return `RESULT_SUCCESS` or one of the following errors:
211 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
212 */
213 ResultCode Close(Handle handle);
214
215 /// Checks if a handle is valid and points to an existing object.
216 bool IsValid(Handle handle) const;
217
218 /**
219 * Looks up a handle.
220 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
221 */
222 SharedPtr<Object> GetGeneric(Handle handle) const;
223
224 /**
225 * Looks up a handle while verifying its type.
226 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
227 * type differs from the handle type `T::HANDLE_TYPE`.
228 */
229 template <class T>
230 SharedPtr<T> Get(Handle handle) const {
231 SharedPtr<Object> object = GetGeneric(handle);
232 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
233 return boost::static_pointer_cast<T>(std::move(object));
234 }
235 return nullptr;
236 }
237
238 /**
239 * Looks up a handle while verifying that it is an object that a thread can wait on
240 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or it is
241 * not a waitable object.
242 */
243 SharedPtr<WaitObject> GetWaitObject(Handle handle) const {
244 SharedPtr<Object> object = GetGeneric(handle);
245 if (object != nullptr && object->IsWaitable()) {
246 return boost::static_pointer_cast<WaitObject>(std::move(object));
247 }
248 return nullptr;
249 }
250
251 /// Closes all handles held in this table.
252 void Clear();
253
254private:
255 /**
256 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
257 * reduced by ExHeader values, but this is not emulated here.
258 */
259 static const size_t MAX_COUNT = 4096;
260
261 static u16 GetSlot(Handle handle) {
262 return handle >> 15;
263 }
264 static u16 GetGeneration(Handle handle) {
265 return handle & 0x7FFF;
266 } 122 }
267 123 return nullptr;
268 /// Stores the Object referenced by the handle or null if the slot is empty. 124}
269 std::array<SharedPtr<Object>, MAX_COUNT> objects;
270
271 /**
272 * The value of `next_generation` when the handle was created, used to check for validity. For
273 * empty slots, contains the index of the next free slot in the list.
274 */
275 std::array<u16, MAX_COUNT> generations;
276
277 /**
278 * Global counter of the number of created handles. Stored in `generations` when a handle is
279 * created, and wraps around to 1 when it hits 0x8000.
280 */
281 u16 next_generation;
282
283 /// Head of the free slots linked list.
284 u16 next_free_slot;
285};
286
287extern HandleTable g_handle_table;
288 125
289/// Initialize the kernel with the specified system mode. 126/// Initialize the kernel with the specified system mode.
290void Init(u32 system_mode); 127void Init(u32 system_mode);
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 8250a90b5..804f23b1c 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <cinttypes> 6#include <cinttypes>
6#include <map> 7#include <map>
7#include <memory> 8#include <memory>
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index c57adf400..bacacd690 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/wait_object.h"
10 11
11namespace Kernel { 12namespace Kernel {
12 13
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 3f51bc5de..a8f10a3ee 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include "common/assert.h"
6#include "common/logging/log.h" 7#include "common/logging/log.h"
7#include "core/hle/kernel/resource_limit.h" 8#include "core/hle/kernel/resource_limit.h"
8 9
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index cde94f7cc..7b0cacf2e 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -8,6 +8,8 @@
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/wait_object.h"
12#include "core/hle/result.h"
11 13
12namespace Kernel { 14namespace Kernel {
13 15
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index fd3bbbcad..4d20c39a1 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -24,14 +24,12 @@ void ServerPort::Acquire(Thread* thread) {
24} 24}
25 25
26std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( 26std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
27 u32 max_sessions, std::string name, 27 u32 max_sessions, std::string name) {
28 std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
29 28
30 SharedPtr<ServerPort> server_port(new ServerPort); 29 SharedPtr<ServerPort> server_port(new ServerPort);
31 SharedPtr<ClientPort> client_port(new ClientPort); 30 SharedPtr<ClientPort> client_port(new ClientPort);
32 31
33 server_port->name = name + "_Server"; 32 server_port->name = name + "_Server";
34 server_port->hle_handler = std::move(hle_handler);
35 client_port->name = name + "_Client"; 33 client_port->name = name + "_Client";
36 client_port->server_port = server_port; 34 client_port->server_port = server_port;
37 client_port->max_sessions = max_sessions; 35 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 6f8bdb6a9..f1419cd46 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -9,28 +9,24 @@
9#include <tuple> 9#include <tuple>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12 12#include "core/hle/kernel/wait_object.h"
13namespace Service {
14class SessionRequestHandler;
15}
16 13
17namespace Kernel { 14namespace Kernel {
18 15
19class ClientPort; 16class ClientPort;
17class SessionRequestHandler;
20 18
21class ServerPort final : public WaitObject { 19class ServerPort final : public WaitObject {
22public: 20public:
23 /** 21 /**
24 * Creates a pair of ServerPort and an associated ClientPort. 22 * Creates a pair of ServerPort and an associated ClientPort.
23 *
25 * @param max_sessions Maximum number of sessions to the port 24 * @param max_sessions Maximum number of sessions to the port
26 * @param name Optional name of the ports 25 * @param name Optional name of the ports
27 * @param hle_handler Optional HLE handler template for the port,
28 * ServerSessions crated from this port will inherit a reference to this handler.
29 * @return The created port tuple 26 * @return The created port tuple
30 */ 27 */
31 static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( 28 static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
32 u32 max_sessions, std::string name = "UnknownPort", 29 u32 max_sessions, std::string name = "UnknownPort");
33 std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
34 30
35 std::string GetTypeName() const override { 31 std::string GetTypeName() const override {
36 return "ServerPort"; 32 return "ServerPort";
@@ -44,6 +40,14 @@ public:
44 return HANDLE_TYPE; 40 return HANDLE_TYPE;
45 } 41 }
46 42
43 /**
44 * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
45 * will inherit a reference to this handler.
46 */
47 void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) {
48 hle_handler = std::move(hle_handler_);
49 }
50
47 std::string name; ///< Name of port (optional) 51 std::string name; ///< Name of port (optional)
48 52
49 std::vector<SharedPtr<WaitObject>> 53 std::vector<SharedPtr<WaitObject>>
@@ -51,7 +55,7 @@ public:
51 55
52 /// This session's HLE request handler template (optional) 56 /// This session's HLE request handler template (optional)
53 /// ServerSessions created from this port inherit a reference to this handler. 57 /// ServerSessions created from this port inherit a reference to this handler.
54 std::shared_ptr<Service::SessionRequestHandler> hle_handler; 58 std::shared_ptr<SessionRequestHandler> hle_handler;
55 59
56 bool ShouldWait(Thread* thread) const override; 60 bool ShouldWait(Thread* thread) const override;
57 void Acquire(Thread* thread) override; 61 void Acquire(Thread* thread) override;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 500b909ab..2dc709bc9 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -4,8 +4,11 @@
4 4
5#include <tuple> 5#include <tuple>
6 6
7#include "core/hle/kernel/client_port.h"
7#include "core/hle/kernel/client_session.h" 8#include "core/hle/kernel/client_session.h"
9#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/server_session.h" 10#include "core/hle/kernel/server_session.h"
11#include "core/hle/kernel/session.h"
9#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
10 13
11namespace Kernel { 14namespace Kernel {
@@ -25,16 +28,14 @@ ServerSession::~ServerSession() {
25 parent->server = nullptr; 28 parent->server = nullptr;
26} 29}
27 30
28ResultVal<SharedPtr<ServerSession>> ServerSession::Create( 31ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name) {
29 std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
30 SharedPtr<ServerSession> server_session(new ServerSession); 32 SharedPtr<ServerSession> server_session(new ServerSession);
31 33
32 server_session->name = std::move(name); 34 server_session->name = std::move(name);
33 server_session->signaled = false; 35 server_session->signaled = false;
34 server_session->hle_handler = std::move(hle_handler);
35 server_session->parent = nullptr; 36 server_session->parent = nullptr;
36 37
37 return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); 38 return MakeResult(std::move(server_session));
38} 39}
39 40
40bool ServerSession::ShouldWait(Thread* thread) const { 41bool ServerSession::ShouldWait(Thread* thread) const {
@@ -68,13 +69,9 @@ ResultCode ServerSession::HandleSyncRequest() {
68 return RESULT_SUCCESS; 69 return RESULT_SUCCESS;
69} 70}
70 71
71ServerSession::SessionPair ServerSession::CreateSessionPair( 72ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name,
72 const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler, 73 SharedPtr<ClientPort> port) {
73 SharedPtr<ClientPort> port) { 74 auto server_session = ServerSession::Create(name + "_Server").MoveFrom();
74
75 auto server_session =
76 ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom();
77
78 SharedPtr<ClientSession> client_session(new ClientSession); 75 SharedPtr<ClientSession> client_session(new ClientSession);
79 client_session->name = name + "_Client"; 76 client_session->name = name + "_Client";
80 77
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index c907d487c..28f365b9e 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -10,9 +10,8 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/session.h" 12#include "core/hle/kernel/session.h"
13#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/wait_object.h"
14#include "core/hle/result.h" 14#include "core/hle/result.h"
15#include "core/hle/service/service.h"
16#include "core/memory.h" 15#include "core/memory.h"
17 16
18namespace Kernel { 17namespace Kernel {
@@ -20,6 +19,8 @@ namespace Kernel {
20class ClientSession; 19class ClientSession;
21class ClientPort; 20class ClientPort;
22class ServerSession; 21class ServerSession;
22class SessionRequestHandler;
23class Thread;
23 24
24/** 25/**
25 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS 26 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
@@ -49,14 +50,20 @@ public:
49 /** 50 /**
50 * Creates a pair of ServerSession and an associated ClientSession. 51 * Creates a pair of ServerSession and an associated ClientSession.
51 * @param name Optional name of the ports. 52 * @param name Optional name of the ports.
52 * @param hle_handler Optional HLE handler for this server session.
53 * @param client_port Optional The ClientPort that spawned this session. 53 * @param client_port Optional The ClientPort that spawned this session.
54 * @return The created session tuple 54 * @return The created session tuple
55 */ 55 */
56 static SessionPair CreateSessionPair( 56 static SessionPair CreateSessionPair(const std::string& name = "Unknown",
57 const std::string& name = "Unknown", 57 SharedPtr<ClientPort> client_port = nullptr);
58 std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr, 58
59 SharedPtr<ClientPort> client_port = nullptr); 59 /**
60 * Sets the HLE handler for the session. This handler will be called to service IPC requests
61 * instead of the regular IPC machinery. (The regular IPC machinery is currently not
62 * implemented.)
63 */
64 void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) {
65 hle_handler = std::move(hle_handler_);
66 }
60 67
61 /** 68 /**
62 * Handle a sync request from the emulated application. 69 * Handle a sync request from the emulated application.
@@ -71,7 +78,7 @@ public:
71 std::string name; ///< The name of this session (optional) 78 std::string name; ///< The name of this session (optional)
72 bool signaled; ///< Whether there's new data available to this ServerSession 79 bool signaled; ///< Whether there's new data available to this ServerSession
73 std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint. 80 std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.
74 std::shared_ptr<Service::SessionRequestHandler> 81 std::shared_ptr<SessionRequestHandler>
75 hle_handler; ///< This session's HLE request handler (optional) 82 hle_handler; ///< This session's HLE request handler (optional)
76 83
77private: 84private:
@@ -82,12 +89,9 @@ private:
82 * Creates a server session. The server session can have an optional HLE handler, 89 * Creates a server session. The server session can have an optional HLE handler,
83 * which will be invoked to handle the IPC requests that this session receives. 90 * which will be invoked to handle the IPC requests that this session receives.
84 * @param name Optional name of the server session. 91 * @param name Optional name of the server session.
85 * @param hle_handler Optional HLE handler for this server session.
86 * @return The created server session 92 * @return The created server session
87 */ 93 */
88 static ResultVal<SharedPtr<ServerSession>> Create( 94 static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
89 std::string name = "Unknown",
90 std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
91}; 95};
92 96
93/** 97/**
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 519ff51a8..75ce626f8 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -15,6 +15,7 @@
15#include "core/core.h" 15#include "core/core.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/hle/kernel/errors.h" 17#include "core/hle/kernel/errors.h"
18#include "core/hle/kernel/handle_table.h"
18#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/kernel.h"
19#include "core/hle/kernel/memory.h" 20#include "core/hle/kernel/memory.h"
20#include "core/hle/kernel/mutex.h" 21#include "core/hle/kernel/mutex.h"
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7b5169cfc..6a3566f15 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -12,6 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/wait_object.h"
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16 17
17enum ThreadPriority : s32 { 18enum ThreadPriority : s32 {
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index a00c75679..6f2cf3b02 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -6,6 +6,7 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core_timing.h" 8#include "core/core_timing.h"
9#include "core/hle/kernel/handle_table.h"
9#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/thread.h" 11#include "core/hle/kernel/thread.h"
11#include "core/hle/kernel/timer.h" 12#include "core/hle/kernel/timer.h"
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index b0f818933..82552372d 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/wait_object.h"
9 10
10namespace Kernel { 11namespace Kernel {
11 12
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
new file mode 100644
index 000000000..f245eda6c
--- /dev/null
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -0,0 +1,99 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/hle/config_mem.h"
9#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/memory.h"
12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/resource_limit.h"
14#include "core/hle/kernel/thread.h"
15#include "core/hle/kernel/timer.h"
16#include "core/hle/shared_page.h"
17
18namespace Kernel {
19
20void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
21 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
22 if (itr == waiting_threads.end())
23 waiting_threads.push_back(std::move(thread));
24}
25
26void WaitObject::RemoveWaitingThread(Thread* thread) {
27 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
28 // If a thread passed multiple handles to the same object,
29 // the kernel might attempt to remove the thread from the object's
30 // waiting threads list multiple times.
31 if (itr != waiting_threads.end())
32 waiting_threads.erase(itr);
33}
34
35SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
36 Thread* candidate = nullptr;
37 s32 candidate_priority = THREADPRIO_LOWEST + 1;
38
39 for (const auto& thread : waiting_threads) {
40 // The list of waiting threads must not contain threads that are not waiting to be awakened.
41 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
42 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
43 "Inconsistent thread statuses in waiting_threads");
44
45 if (thread->current_priority >= candidate_priority)
46 continue;
47
48 if (ShouldWait(thread.get()))
49 continue;
50
51 // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
52 // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
53 bool ready_to_run = true;
54 if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
55 ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
56 [&thread](const SharedPtr<WaitObject>& object) {
57 return object->ShouldWait(thread.get());
58 });
59 }
60
61 if (ready_to_run) {
62 candidate = thread.get();
63 candidate_priority = thread->current_priority;
64 }
65 }
66
67 return candidate;
68}
69
70void WaitObject::WakeupAllWaitingThreads() {
71 while (auto thread = GetHighestPriorityReadyThread()) {
72 if (!thread->IsSleepingOnWaitAll()) {
73 Acquire(thread.get());
74 // Set the output index of the WaitSynchronizationN call to the index of this object.
75 if (thread->wait_set_output) {
76 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
77 thread->wait_set_output = false;
78 }
79 } else {
80 for (auto& object : thread->wait_objects) {
81 object->Acquire(thread.get());
82 }
83 // Note: This case doesn't update the output index of WaitSynchronizationN.
84 }
85
86 for (auto& object : thread->wait_objects)
87 object->RemoveWaitingThread(thread.get());
88 thread->wait_objects.clear();
89
90 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
91 thread->ResumeFromWait();
92 }
93}
94
95const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
96 return waiting_threads;
97}
98
99} // namespace Kernel
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
new file mode 100644
index 000000000..861578186
--- /dev/null
+++ b/src/core/hle/kernel/wait_object.h
@@ -0,0 +1,67 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include <boost/smart_ptr/intrusive_ptr.hpp>
9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h"
11
12namespace Kernel {
13
14class Thread;
15
16/// Class that represents a Kernel object that a thread can be waiting on
17class WaitObject : public Object {
18public:
19 /**
20 * Check if the specified thread should wait until the object is available
21 * @param thread The thread about which we're deciding.
22 * @return True if the current thread should wait due to this object being unavailable
23 */
24 virtual bool ShouldWait(Thread* thread) const = 0;
25
26 /// Acquire/lock the object for the specified thread if it is available
27 virtual void Acquire(Thread* thread) = 0;
28
29 /**
30 * Add a thread to wait on this object
31 * @param thread Pointer to thread to add
32 */
33 virtual void AddWaitingThread(SharedPtr<Thread> thread);
34
35 /**
36 * Removes a thread from waiting on this object (e.g. if it was resumed already)
37 * @param thread Pointer to thread to remove
38 */
39 virtual void RemoveWaitingThread(Thread* thread);
40
41 /**
42 * Wake up all threads waiting on this object that can be awoken, in priority order,
43 * and set the synchronization result and output of the thread.
44 */
45 virtual void WakeupAllWaitingThreads();
46
47 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
48 SharedPtr<Thread> GetHighestPriorityReadyThread();
49
50 /// Get a const reference to the waiting threads list for debug use
51 const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
52
53private:
54 /// Threads waiting for this object to become available
55 std::vector<SharedPtr<Thread>> waiting_threads;
56};
57
58// Specialization of DynamicObjectCast for WaitObjects
59template <>
60inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
61 if (object != nullptr && object->IsWaitable()) {
62 return boost::static_pointer_cast<WaitObject>(std::move(object));
63 }
64 return nullptr;
65}
66
67} // namespace Kernel
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index c49650f7d..5f2cdbb96 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -416,6 +416,16 @@ ResultVal<T> MakeResult(Args&&... args) {
416} 416}
417 417
418/** 418/**
419 * Deducible overload of MakeResult, allowing the template parameter to be ommited if you're just
420 * copy or move constructing.
421 */
422template <typename Arg>
423ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) {
424 return ResultVal<std::remove_reference_t<Arg>>::WithCode(RESULT_SUCCESS,
425 std::forward<Arg>(arg));
426}
427
428/**
419 * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps 429 * Check for the success of `source` (which must evaluate to a ResultVal). If it succeeds, unwraps
420 * the contained value and assigns it to `target`, which can be either an l-value expression or a 430 * the contained value and assigns it to `target`, which can be either an l-value expression or a
421 * variable declaration. If it fails the return code is returned from the current function. Thus it 431 * variable declaration. If it fails the return code is returned from the current function. Thus it
@@ -426,3 +436,12 @@ ResultVal<T> MakeResult(Args&&... args) {
426 if (CONCAT2(check_result_L, __LINE__).Failed()) \ 436 if (CONCAT2(check_result_L, __LINE__).Failed()) \
427 return CONCAT2(check_result_L, __LINE__).Code(); \ 437 return CONCAT2(check_result_L, __LINE__).Code(); \
428 target = std::move(*CONCAT2(check_result_L, __LINE__)) 438 target = std::move(*CONCAT2(check_result_L, __LINE__))
439
440/**
441 * Analogous to CASCADE_RESULT, but for a bare ResultCode. The code will be propagated if
442 * non-success, or discarded otherwise.
443 */
444#define CASCADE_CODE(source) \
445 auto CONCAT2(check_result_L, __LINE__) = source; \
446 if (CONCAT2(check_result_L, __LINE__).IsError()) \
447 return CONCAT2(check_result_L, __LINE__);
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp
index aa270a2c3..e3dd23949 100644
--- a/src/core/hle/service/ac/ac.cpp
+++ b/src/core/hle/service/ac/ac.cpp
@@ -4,11 +4,16 @@
4 4
5#include <array> 5#include <array>
6 6
7#include "common/common_types.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/hle/ipc.h"
8#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/handle_table.h"
12#include "core/hle/result.h"
9#include "core/hle/service/ac/ac.h" 13#include "core/hle/service/ac/ac.h"
10#include "core/hle/service/ac/ac_i.h" 14#include "core/hle/service/ac/ac_i.h"
11#include "core/hle/service/ac/ac_u.h" 15#include "core/hle/service/ac/ac_u.h"
16#include "core/memory.h"
12 17
13namespace Service { 18namespace Service {
14namespace AC { 19namespace AC {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d344a622f..961305e9f 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -2,8 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
5#include <cinttypes> 6#include <cinttypes>
7#include "common/common_types.h"
6#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/hle/ipc.h"
10#include "core/hle/result.h"
7#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
8#include "core/hle/service/am/am_app.h" 12#include "core/hle/service/am/am_app.h"
9#include "core/hle/service/am/am_net.h" 13#include "core/hle/service/am/am_net.h"
@@ -176,8 +180,6 @@ void GetTicketList(Service::Interface* self) {
176} 180}
177 181
178void Init() { 182void Init() {
179 using namespace Kernel;
180
181 AddService(new AM_APP_Interface); 183 AddService(new AM_APP_Interface);
182 AddService(new AM_NET_Interface); 184 AddService(new AM_NET_Interface);
183 AddService(new AM_SYS_Interface); 185 AddService(new AM_SYS_Interface);
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 366d1eacf..4c587e3c8 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -5,6 +5,7 @@
5#include "common/common_paths.h" 5#include "common/common_paths.h"
6#include "common/file_util.h" 6#include "common/file_util.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/hle/applets/applet.h" 9#include "core/hle/applets/applet.h"
9#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/mutex.h" 11#include "core/hle/kernel/mutex.h"
@@ -74,6 +75,7 @@ void GetSharedFont(Service::Interface* self) {
74 LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); 75 LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
75 rb.Push<u32>(-1); // TODO: Find the right error code 76 rb.Push<u32>(-1); // TODO: Find the right error code
76 rb.Skip(1 + 2, true); 77 rb.Skip(1 + 2, true);
78 Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSharedFont);
77 return; 79 return;
78 } 80 }
79 81
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e63b61450..ee80926d2 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
8#include "common/common_funcs.h"
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "common/swap.h" 10#include "common/swap.h"
9#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp
index 91056189a..2bba3aff6 100644
--- a/src/core/hle/service/boss/boss.cpp
+++ b/src/core/hle/service/boss/boss.cpp
@@ -3,6 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cinttypes> 5#include <cinttypes>
6#include "common/logging/log.h"
7#include "core/hle/ipc.h"
8#include "core/hle/result.h"
6#include "core/hle/service/boss/boss.h" 9#include "core/hle/service/boss/boss.h"
7#include "core/hle/service/boss/boss_p.h" 10#include "core/hle/service/boss/boss_p.h"
8#include "core/hle/service/boss/boss_u.h" 11#include "core/hle/service/boss/boss_u.h"
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index 95665e754..7394c844f 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -11,13 +11,17 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/core_timing.h" 12#include "core/core_timing.h"
13#include "core/frontend/camera/factory.h" 13#include "core/frontend/camera/factory.h"
14#include "core/hle/ipc.h"
15#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
17#include "core/hle/result.h"
15#include "core/hle/service/cam/cam.h" 18#include "core/hle/service/cam/cam.h"
16#include "core/hle/service/cam/cam_c.h" 19#include "core/hle/service/cam/cam_c.h"
17#include "core/hle/service/cam/cam_q.h" 20#include "core/hle/service/cam/cam_q.h"
18#include "core/hle/service/cam/cam_s.h" 21#include "core/hle/service/cam/cam_s.h"
19#include "core/hle/service/cam/cam_u.h" 22#include "core/hle/service/cam/cam_u.h"
20#include "core/hle/service/service.h" 23#include "core/hle/service/service.h"
24#include "core/memory.h"
21#include "core/settings.h" 25#include "core/settings.h"
22 26
23namespace Service { 27namespace Service {
@@ -55,7 +59,7 @@ struct PortConfig {
55 u16 x1; // x-coordinate of ending position for trimming 59 u16 x1; // x-coordinate of ending position for trimming
56 u16 y1; // y-coordinate of ending position for trimming 60 u16 y1; // y-coordinate of ending position for trimming
57 61
58 u32 transfer_bytes; 62 u16 transfer_bytes;
59 63
60 Kernel::SharedPtr<Kernel::Event> completion_event; 64 Kernel::SharedPtr<Kernel::Event> completion_event;
61 Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event; 65 Kernel::SharedPtr<Kernel::Event> buffer_error_interrupt_event;
@@ -225,8 +229,7 @@ static void ActivatePort(int port_id, int camera_id) {
225template <int max_index> 229template <int max_index>
226class CommandParamBitSet : public BitSet8 { 230class CommandParamBitSet : public BitSet8 {
227public: 231public:
228 explicit CommandParamBitSet(u32 command_param) 232 explicit CommandParamBitSet(u8 command_param) : BitSet8(command_param) {}
229 : BitSet8(static_cast<u8>(command_param & 0xFF)) {}
230 233
231 bool IsValid() const { 234 bool IsValid() const {
232 return m_val < (1 << max_index); 235 return m_val < (1 << max_index);
@@ -244,9 +247,10 @@ using CameraSet = CommandParamBitSet<3>;
244} // namespace 247} // namespace
245 248
246void StartCapture(Service::Interface* self) { 249void StartCapture(Service::Interface* self) {
247 u32* cmd_buff = Kernel::GetCommandBuffer(); 250 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 1, 0);
251 const PortSet port_select(rp.Pop<u8>());
248 252
249 const PortSet port_select(cmd_buff[1]); 253 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
250 254
251 if (port_select.IsValid()) { 255 if (port_select.IsValid()) {
252 for (int i : port_select) { 256 for (int i : port_select) {
@@ -267,21 +271,20 @@ void StartCapture(Service::Interface* self) {
267 LOG_WARNING(Service_CAM, "port %u already started", i); 271 LOG_WARNING(Service_CAM, "port %u already started", i);
268 } 272 }
269 } 273 }
270 cmd_buff[1] = RESULT_SUCCESS.raw; 274 rb.Push(RESULT_SUCCESS);
271 } else { 275 } else {
272 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 276 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
273 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 277 rb.Push(ERROR_INVALID_ENUM_VALUE);
274 } 278 }
275 279
276 cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0);
277
278 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 280 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
279} 281}
280 282
281void StopCapture(Service::Interface* self) { 283void StopCapture(Service::Interface* self) {
282 u32* cmd_buff = Kernel::GetCommandBuffer(); 284 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 1, 0);
285 const PortSet port_select(rp.Pop<u8>());
283 286
284 const PortSet port_select(cmd_buff[1]); 287 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
285 288
286 if (port_select.IsValid()) { 289 if (port_select.IsValid()) {
287 for (int i : port_select) { 290 for (int i : port_select) {
@@ -293,21 +296,20 @@ void StopCapture(Service::Interface* self) {
293 LOG_WARNING(Service_CAM, "port %u already stopped", i); 296 LOG_WARNING(Service_CAM, "port %u already stopped", i);
294 } 297 }
295 } 298 }
296 cmd_buff[1] = RESULT_SUCCESS.raw; 299 rb.Push(RESULT_SUCCESS);
297 } else { 300 } else {
298 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 301 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
299 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 302 rb.Push(ERROR_INVALID_ENUM_VALUE);
300 } 303 }
301 304
302 cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0);
303
304 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 305 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
305} 306}
306 307
307void IsBusy(Service::Interface* self) { 308void IsBusy(Service::Interface* self) {
308 u32* cmd_buff = Kernel::GetCommandBuffer(); 309 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
310 const PortSet port_select(rp.Pop<u8>());
309 311
310 const PortSet port_select(cmd_buff[1]); 312 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
311 313
312 if (port_select.IsValid()) { 314 if (port_select.IsValid()) {
313 bool is_busy = true; 315 bool is_busy = true;
@@ -315,80 +317,74 @@ void IsBusy(Service::Interface* self) {
315 for (int i : port_select) { 317 for (int i : port_select) {
316 is_busy &= ports[i].is_busy; 318 is_busy &= ports[i].is_busy;
317 } 319 }
318 cmd_buff[1] = RESULT_SUCCESS.raw; 320 rb.Push(RESULT_SUCCESS);
319 cmd_buff[2] = is_busy ? 1 : 0; 321 rb.Push(is_busy);
320 } else { 322 } else {
321 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 323 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
322 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 324 rb.Push(ERROR_INVALID_ENUM_VALUE);
325 rb.Skip(1, false);
323 } 326 }
324 327
325 cmd_buff[0] = IPC::MakeHeader(0x3, 2, 0);
326
327 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 328 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
328} 329}
329 330
330void ClearBuffer(Service::Interface* self) { 331void ClearBuffer(Service::Interface* self) {
331 u32* cmd_buff = Kernel::GetCommandBuffer(); 332 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x04, 1, 0);
332 333 const PortSet port_select(rp.Pop<u8>());
333 const PortSet port_select(cmd_buff[1]);
334 334
335 cmd_buff[0] = IPC::MakeHeader(0x4, 1, 0); 335 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
336 cmd_buff[1] = RESULT_SUCCESS.raw; 336 rb.Push(RESULT_SUCCESS);
337 337
338 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); 338 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
339} 339}
340 340
341void GetVsyncInterruptEvent(Service::Interface* self) { 341void GetVsyncInterruptEvent(Service::Interface* self) {
342 u32* cmd_buff = Kernel::GetCommandBuffer(); 342 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x05, 1, 0);
343 343 const PortSet port_select(rp.Pop<u8>());
344 const PortSet port_select(cmd_buff[1]);
345 344
345 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
346 if (port_select.IsSingle()) { 346 if (port_select.IsSingle()) {
347 int port = *port_select.begin(); 347 int port = *port_select.begin();
348 cmd_buff[1] = RESULT_SUCCESS.raw; 348 rb.Push(RESULT_SUCCESS);
349 cmd_buff[2] = IPC::CopyHandleDesc(); 349 rb.PushCopyHandles(
350 cmd_buff[3] = Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom(); 350 Kernel::g_handle_table.Create(ports[port].vsync_interrupt_event).MoveFrom());
351 } else { 351 } else {
352 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 352 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
353 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 353 rb.Push(ERROR_INVALID_ENUM_VALUE);
354 cmd_buff[2] = IPC::CopyHandleDesc(); 354 rb.PushCopyHandles(0);
355 cmd_buff[2] = 0;
356 } 355 }
357 356
358 cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2);
359
360 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); 357 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
361} 358}
362 359
363void GetBufferErrorInterruptEvent(Service::Interface* self) { 360void GetBufferErrorInterruptEvent(Service::Interface* self) {
364 u32* cmd_buff = Kernel::GetCommandBuffer(); 361 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x06, 1, 0);
365 362 const PortSet port_select(rp.Pop<u8>());
366 const PortSet port_select(cmd_buff[1]);
367 363
364 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
368 if (port_select.IsSingle()) { 365 if (port_select.IsSingle()) {
369 int port = *port_select.begin(); 366 int port = *port_select.begin();
370 cmd_buff[1] = RESULT_SUCCESS.raw; 367 rb.Push(RESULT_SUCCESS);
371 cmd_buff[2] = IPC::CopyHandleDesc(); 368 rb.PushCopyHandles(
372 cmd_buff[3] = 369 Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom());
373 Kernel::g_handle_table.Create(ports[port].buffer_error_interrupt_event).MoveFrom();
374 } else { 370 } else {
375 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 371 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
376 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 372 rb.Push(ERROR_INVALID_ENUM_VALUE);
377 cmd_buff[2] = IPC::CopyHandleDesc(); 373 rb.PushCopyHandles(0);
378 cmd_buff[2] = 0;
379 } 374 }
380 375
381 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val); 376 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u", port_select.m_val);
382} 377}
383 378
384void SetReceiving(Service::Interface* self) { 379void SetReceiving(Service::Interface* self) {
385 u32* cmd_buff = Kernel::GetCommandBuffer(); 380 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x07, 4, 2);
386 381 const VAddr dest = rp.Pop<u32>();
387 const VAddr dest = cmd_buff[1]; 382 const PortSet port_select(rp.Pop<u8>());
388 const PortSet port_select(cmd_buff[2]); 383 const u32 image_size = rp.Pop<u32>();
389 const u32 image_size = cmd_buff[3]; 384 const u16 trans_unit = rp.Pop<u16>();
390 const u32 trans_unit = cmd_buff[4] & 0xFFFF; 385 rp.PopHandle(); // Handle to destination process. not used
391 386
387 IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
392 if (port_select.IsSingle()) { 388 if (port_select.IsSingle()) {
393 int port_id = *port_select.begin(); 389 int port_id = *port_select.begin();
394 PortConfig& port = ports[port_id]; 390 PortConfig& port = ports[port_id];
@@ -403,149 +399,145 @@ void SetReceiving(Service::Interface* self) {
403 port.is_pending_receiving = true; 399 port.is_pending_receiving = true;
404 } 400 }
405 401
406 cmd_buff[1] = RESULT_SUCCESS.raw; 402 rb.Push(RESULT_SUCCESS);
407 cmd_buff[2] = IPC::CopyHandleDesc(); 403 rb.PushCopyHandles(Kernel::g_handle_table.Create(port.completion_event).MoveFrom());
408 cmd_buff[3] = Kernel::g_handle_table.Create(port.completion_event).MoveFrom();
409 } else { 404 } else {
410 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 405 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
411 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 406 rb.Push(ERROR_INVALID_ENUM_VALUE);
407 rb.PushCopyHandles(0);
412 } 408 }
413 409
414 cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2);
415
416 LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest, 410 LOG_DEBUG(Service_CAM, "called, addr=0x%X, port_select=%u, image_size=%u, trans_unit=%u", dest,
417 port_select.m_val, image_size, trans_unit); 411 port_select.m_val, image_size, trans_unit);
418} 412}
419 413
420void IsFinishedReceiving(Service::Interface* self) { 414void IsFinishedReceiving(Service::Interface* self) {
421 u32* cmd_buff = Kernel::GetCommandBuffer(); 415 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 1, 0);
422 416 const PortSet port_select(rp.Pop<u8>());
423 const PortSet port_select(cmd_buff[1]);
424 417
418 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
425 if (port_select.IsSingle()) { 419 if (port_select.IsSingle()) {
426 int port = *port_select.begin(); 420 int port = *port_select.begin();
427 cmd_buff[1] = RESULT_SUCCESS.raw; 421 bool is_busy = ports[port].is_receiving || ports[port].is_pending_receiving;
428 cmd_buff[2] = (ports[port].is_receiving || ports[port].is_pending_receiving) ? 0 : 1; 422 rb.Push(RESULT_SUCCESS);
423 rb.Push(!is_busy);
429 } else { 424 } else {
430 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 425 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
431 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 426 rb.Push(ERROR_INVALID_ENUM_VALUE);
427 rb.Skip(1, false);
432 } 428 }
433 429
434 cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
435
436 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 430 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
437} 431}
438 432
439void SetTransferLines(Service::Interface* self) { 433void SetTransferLines(Service::Interface* self) {
440 u32* cmd_buff = Kernel::GetCommandBuffer(); 434 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x09, 4, 0);
441 435 const PortSet port_select(rp.Pop<u8>());
442 const PortSet port_select(cmd_buff[1]); 436 const u16 transfer_lines = rp.Pop<u16>();
443 const u32 transfer_lines = cmd_buff[2] & 0xFFFF; 437 const u16 width = rp.Pop<u16>();
444 const u32 width = cmd_buff[3] & 0xFFFF; 438 const u16 height = rp.Pop<u16>();
445 const u32 height = cmd_buff[4] & 0xFFFF;
446 439
440 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
447 if (port_select.IsValid()) { 441 if (port_select.IsValid()) {
448 for (int i : port_select) { 442 for (int i : port_select) {
449 ports[i].transfer_bytes = transfer_lines * width * 2; 443 ports[i].transfer_bytes = transfer_lines * width * 2;
450 } 444 }
451 cmd_buff[1] = RESULT_SUCCESS.raw; 445 rb.Push(RESULT_SUCCESS);
452 } else { 446 } else {
453 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 447 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
454 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 448 rb.Push(ERROR_INVALID_ENUM_VALUE);
455 } 449 }
456 450
457 cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
458
459 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u", 451 LOG_WARNING(Service_CAM, "(STUBBED) called, port_select=%u, lines=%u, width=%u, height=%u",
460 port_select.m_val, transfer_lines, width, height); 452 port_select.m_val, transfer_lines, width, height);
461} 453}
462 454
463void GetMaxLines(Service::Interface* self) { 455void GetMaxLines(Service::Interface* self) {
464 u32* cmd_buff = Kernel::GetCommandBuffer(); 456 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0A, 2, 0);
457 const u16 width = rp.Pop<u16>();
458 const u16 height = rp.Pop<u16>();
465 459
466 const u32 width = cmd_buff[1] & 0xFFFF; 460 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
467 const u32 height = cmd_buff[2] & 0xFFFF;
468 461
469 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 462 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
470 constexpr u32 MIN_TRANSFER_UNIT = 256; 463 constexpr u32 MIN_TRANSFER_UNIT = 256;
471 constexpr u32 MAX_BUFFER_SIZE = 2560; 464 constexpr u32 MAX_BUFFER_SIZE = 2560;
472 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { 465 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
473 cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; 466 rb.Push(ERROR_OUT_OF_RANGE);
467 rb.Skip(1, false);
474 } else { 468 } else {
475 u32 lines = MAX_BUFFER_SIZE / width; 469 u32 lines = MAX_BUFFER_SIZE / width;
476 if (lines > height) { 470 if (lines > height) {
477 lines = height; 471 lines = height;
478 } 472 }
479 cmd_buff[1] = RESULT_SUCCESS.raw; 473 ResultCode result = RESULT_SUCCESS;
480 while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) { 474 while (height % lines != 0 || (lines * width * 2 % MIN_TRANSFER_UNIT != 0)) {
481 --lines; 475 --lines;
482 if (lines == 0) { 476 if (lines == 0) {
483 cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; 477 result = ERROR_OUT_OF_RANGE;
484 break; 478 break;
485 } 479 }
486 } 480 }
487 cmd_buff[2] = lines; 481 rb.Push(result);
482 rb.Push(lines);
488 } 483 }
489 484
490 cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
491
492 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); 485 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
493} 486}
494 487
495void SetTransferBytes(Service::Interface* self) { 488void SetTransferBytes(Service::Interface* self) {
496 u32* cmd_buff = Kernel::GetCommandBuffer(); 489 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0B, 4, 0);
497 490 const PortSet port_select(rp.Pop<u8>());
498 const PortSet port_select(cmd_buff[1]); 491 const u16 transfer_bytes = rp.Pop<u16>();
499 const u32 transfer_bytes = cmd_buff[2] & 0xFFFF; 492 const u16 width = rp.Pop<u16>();
500 const u32 width = cmd_buff[3] & 0xFFFF; 493 const u16 height = rp.Pop<u16>();
501 const u32 height = cmd_buff[4] & 0xFFFF;
502 494
495 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
503 if (port_select.IsValid()) { 496 if (port_select.IsValid()) {
504 for (int i : port_select) { 497 for (int i : port_select) {
505 ports[i].transfer_bytes = transfer_bytes; 498 ports[i].transfer_bytes = transfer_bytes;
506 } 499 }
507 cmd_buff[1] = RESULT_SUCCESS.raw; 500 rb.Push(RESULT_SUCCESS);
508 } else { 501 } else {
509 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 502 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
510 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 503 rb.Push(ERROR_INVALID_ENUM_VALUE);
511 } 504 }
512 505
513 cmd_buff[0] = IPC::MakeHeader(0xB, 1, 0);
514
515 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u", 506 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u, bytes=%u, width=%u, height=%u",
516 port_select.m_val, transfer_bytes, width, height); 507 port_select.m_val, transfer_bytes, width, height);
517} 508}
518 509
519void GetTransferBytes(Service::Interface* self) { 510void GetTransferBytes(Service::Interface* self) {
520 u32* cmd_buff = Kernel::GetCommandBuffer(); 511 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0C, 1, 0);
521 512 const PortSet port_select(rp.Pop<u8>());
522 const PortSet port_select(cmd_buff[1]);
523 513
514 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
524 if (port_select.IsSingle()) { 515 if (port_select.IsSingle()) {
525 int port = *port_select.begin(); 516 int port = *port_select.begin();
526 cmd_buff[1] = RESULT_SUCCESS.raw; 517 rb.Push(RESULT_SUCCESS);
527 cmd_buff[2] = ports[port].transfer_bytes; 518 rb.Push(ports[port].transfer_bytes);
528 } else { 519 } else {
529 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 520 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
530 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 521 rb.Push(ERROR_INVALID_ENUM_VALUE);
522 rb.Skip(1, false);
531 } 523 }
532 524
533 cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
534
535 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val); 525 LOG_WARNING(Service_CAM, "(STUBBED)called, port_select=%u", port_select.m_val);
536} 526}
537 527
538void GetMaxBytes(Service::Interface* self) { 528void GetMaxBytes(Service::Interface* self) {
539 u32* cmd_buff = Kernel::GetCommandBuffer(); 529 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 2, 0);
530 const u16 width = rp.Pop<u16>();
531 const u16 height = rp.Pop<u16>();
540 532
541 const u32 width = cmd_buff[1] & 0xFFFF; 533 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
542 const u32 height = cmd_buff[2] & 0xFFFF;
543 534
544 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480 535 // Note: the result of the algorithm below are hwtested with width < 640 and with height < 480
545 constexpr u32 MIN_TRANSFER_UNIT = 256; 536 constexpr u32 MIN_TRANSFER_UNIT = 256;
546 constexpr u32 MAX_BUFFER_SIZE = 2560; 537 constexpr u32 MAX_BUFFER_SIZE = 2560;
547 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) { 538 if (width * height * 2 % MIN_TRANSFER_UNIT != 0) {
548 cmd_buff[1] = ERROR_OUT_OF_RANGE.raw; 539 rb.Push(ERROR_OUT_OF_RANGE);
540 rb.Skip(1, false);
549 } else { 541 } else {
550 u32 bytes = MAX_BUFFER_SIZE; 542 u32 bytes = MAX_BUFFER_SIZE;
551 543
@@ -553,63 +545,59 @@ void GetMaxBytes(Service::Interface* self) {
553 bytes -= MIN_TRANSFER_UNIT; 545 bytes -= MIN_TRANSFER_UNIT;
554 } 546 }
555 547
556 cmd_buff[1] = RESULT_SUCCESS.raw; 548 rb.Push(RESULT_SUCCESS);
557 cmd_buff[2] = bytes; 549 rb.Push(bytes);
558 } 550 }
559 cmd_buff[0] = IPC::MakeHeader(0xD, 2, 0);
560 551
561 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height); 552 LOG_DEBUG(Service_CAM, "called, width=%u, height=%u", width, height);
562} 553}
563 554
564void SetTrimming(Service::Interface* self) { 555void SetTrimming(Service::Interface* self) {
565 u32* cmd_buff = Kernel::GetCommandBuffer(); 556 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0E, 2, 0);
566 557 const PortSet port_select(rp.Pop<u8>());
567 const PortSet port_select(cmd_buff[1]); 558 const bool trim = rp.Pop<bool>();
568 const bool trim = (cmd_buff[2] & 0xFF) != 0;
569 559
560 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
570 if (port_select.IsValid()) { 561 if (port_select.IsValid()) {
571 for (int i : port_select) { 562 for (int i : port_select) {
572 ports[i].is_trimming = trim; 563 ports[i].is_trimming = trim;
573 } 564 }
574 cmd_buff[1] = RESULT_SUCCESS.raw; 565 rb.Push(RESULT_SUCCESS);
575 } else { 566 } else {
576 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 567 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
577 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 568 rb.Push(ERROR_INVALID_ENUM_VALUE);
578 } 569 }
579 570
580 cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0);
581
582 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim); 571 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim=%d", port_select.m_val, trim);
583} 572}
584 573
585void IsTrimming(Service::Interface* self) { 574void IsTrimming(Service::Interface* self) {
586 u32* cmd_buff = Kernel::GetCommandBuffer(); 575 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 1, 0);
587 576 const PortSet port_select(rp.Pop<u8>());
588 const PortSet port_select(cmd_buff[1]);
589 577
578 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
590 if (port_select.IsSingle()) { 579 if (port_select.IsSingle()) {
591 int port = *port_select.begin(); 580 int port = *port_select.begin();
592 cmd_buff[1] = RESULT_SUCCESS.raw; 581 rb.Push(RESULT_SUCCESS);
593 cmd_buff[2] = ports[port].is_trimming; 582 rb.Push(ports[port].is_trimming);
594 } else { 583 } else {
595 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 584 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
596 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 585 rb.Push(ERROR_INVALID_ENUM_VALUE);
586 rb.Skip(1, false);
597 } 587 }
598 588
599 cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
600
601 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 589 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
602} 590}
603 591
604void SetTrimmingParams(Service::Interface* self) { 592void SetTrimmingParams(Service::Interface* self) {
605 u32* cmd_buff = Kernel::GetCommandBuffer(); 593 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x10, 5, 0);
606 594 const PortSet port_select(rp.Pop<u8>());
607 const PortSet port_select(cmd_buff[1]); 595 const u16 x0 = rp.Pop<u16>();
608 const u16 x0 = static_cast<u16>(cmd_buff[2] & 0xFFFF); 596 const u16 y0 = rp.Pop<u16>();
609 const u16 y0 = static_cast<u16>(cmd_buff[3] & 0xFFFF); 597 const u16 x1 = rp.Pop<u16>();
610 const u16 x1 = static_cast<u16>(cmd_buff[4] & 0xFFFF); 598 const u16 y1 = rp.Pop<u16>();
611 const u16 y1 = static_cast<u16>(cmd_buff[5] & 0xFFFF); 599
612 600 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
613 if (port_select.IsValid()) { 601 if (port_select.IsValid()) {
614 for (int i : port_select) { 602 for (int i : port_select) {
615 ports[i].x0 = x0; 603 ports[i].x0 = x0;
@@ -617,49 +605,46 @@ void SetTrimmingParams(Service::Interface* self) {
617 ports[i].x1 = x1; 605 ports[i].x1 = x1;
618 ports[i].y1 = y1; 606 ports[i].y1 = y1;
619 } 607 }
620 cmd_buff[1] = RESULT_SUCCESS.raw; 608 rb.Push(RESULT_SUCCESS);
621 } else { 609 } else {
622 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 610 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
623 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 611 rb.Push(ERROR_INVALID_ENUM_VALUE);
624 } 612 }
625 613
626 cmd_buff[0] = IPC::MakeHeader(0x10, 1, 0);
627
628 LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val, 614 LOG_DEBUG(Service_CAM, "called, port_select=%u, x0=%u, y0=%u, x1=%u, y1=%u", port_select.m_val,
629 x0, y0, x1, y1); 615 x0, y0, x1, y1);
630} 616}
631 617
632void GetTrimmingParams(Service::Interface* self) { 618void GetTrimmingParams(Service::Interface* self) {
633 u32* cmd_buff = Kernel::GetCommandBuffer(); 619 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x11, 1, 0);
634 620 const PortSet port_select(rp.Pop<u8>());
635 const PortSet port_select(cmd_buff[1]);
636 621
622 IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
637 if (port_select.IsSingle()) { 623 if (port_select.IsSingle()) {
638 int port = *port_select.begin(); 624 int port = *port_select.begin();
639 cmd_buff[1] = RESULT_SUCCESS.raw; 625 rb.Push(RESULT_SUCCESS);
640 cmd_buff[2] = ports[port].x0; 626 rb.Push(ports[port].x0);
641 cmd_buff[3] = ports[port].y0; 627 rb.Push(ports[port].y0);
642 cmd_buff[4] = ports[port].x1; 628 rb.Push(ports[port].x1);
643 cmd_buff[5] = ports[port].y1; 629 rb.Push(ports[port].y1);
644 } else { 630 } else {
645 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 631 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
646 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 632 rb.Push(ERROR_INVALID_ENUM_VALUE);
633 rb.Skip(4, false);
647 } 634 }
648 635
649 cmd_buff[0] = IPC::MakeHeader(0x11, 5, 0);
650
651 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val); 636 LOG_DEBUG(Service_CAM, "called, port_select=%u", port_select.m_val);
652} 637}
653 638
654void SetTrimmingParamsCenter(Service::Interface* self) { 639void SetTrimmingParamsCenter(Service::Interface* self) {
655 u32* cmd_buff = Kernel::GetCommandBuffer(); 640 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 5, 0);
656 641 const PortSet port_select(rp.Pop<u8>());
657 const PortSet port_select(cmd_buff[1]); 642 const u16 trim_w = rp.Pop<u16>();
658 const u16 trim_w = static_cast<u16>(cmd_buff[2] & 0xFFFF); 643 const u16 trim_h = rp.Pop<u16>();
659 const u16 trim_h = static_cast<u16>(cmd_buff[3] & 0xFFFF); 644 const u16 cam_w = rp.Pop<u16>();
660 const u16 cam_w = static_cast<u16>(cmd_buff[4] & 0xFFFF); 645 const u16 cam_h = rp.Pop<u16>();
661 const u16 cam_h = static_cast<u16>(cmd_buff[5] & 0xFFFF); 646
662 647 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
663 if (port_select.IsValid()) { 648 if (port_select.IsValid()) {
664 for (int i : port_select) { 649 for (int i : port_select) {
665 ports[i].x0 = (cam_w - trim_w) / 2; 650 ports[i].x0 = (cam_w - trim_w) / 2;
@@ -667,23 +652,21 @@ void SetTrimmingParamsCenter(Service::Interface* self) {
667 ports[i].x1 = ports[i].x0 + trim_w; 652 ports[i].x1 = ports[i].x0 + trim_w;
668 ports[i].y1 = ports[i].y0 + trim_h; 653 ports[i].y1 = ports[i].y0 + trim_h;
669 } 654 }
670 cmd_buff[1] = RESULT_SUCCESS.raw; 655 rb.Push(RESULT_SUCCESS);
671 } else { 656 } else {
672 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val); 657 LOG_ERROR(Service_CAM, "invalid port_select=%u", port_select.m_val);
673 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 658 rb.Push(ERROR_INVALID_ENUM_VALUE);
674 } 659 }
675 660
676 cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
677
678 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u", 661 LOG_DEBUG(Service_CAM, "called, port_select=%u, trim_w=%u, trim_h=%u, cam_w=%u, cam_h=%u",
679 port_select.m_val, trim_w, trim_h, cam_w, cam_h); 662 port_select.m_val, trim_w, trim_h, cam_w, cam_h);
680} 663}
681 664
682void Activate(Service::Interface* self) { 665void Activate(Service::Interface* self) {
683 u32* cmd_buff = Kernel::GetCommandBuffer(); 666 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x13, 1, 0);
684 667 const CameraSet camera_select(rp.Pop<u8>());
685 const CameraSet camera_select(cmd_buff[1]);
686 668
669 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
687 if (camera_select.IsValid()) { 670 if (camera_select.IsValid()) {
688 if (camera_select.m_val == 0) { // deactive all 671 if (camera_select.m_val == 0) { // deactive all
689 for (int i = 0; i < 2; ++i) { 672 for (int i = 0; i < 2; ++i) {
@@ -694,10 +677,10 @@ void Activate(Service::Interface* self) {
694 } 677 }
695 ports[i].is_active = false; 678 ports[i].is_active = false;
696 } 679 }
697 cmd_buff[1] = RESULT_SUCCESS.raw; 680 rb.Push(RESULT_SUCCESS);
698 } else if (camera_select[0] && camera_select[1]) { 681 } else if (camera_select[0] && camera_select[1]) {
699 LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated"); 682 LOG_ERROR(Service_CAM, "camera 0 and 1 can't be both activated");
700 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 683 rb.Push(ERROR_INVALID_ENUM_VALUE);
701 } else { 684 } else {
702 if (camera_select[0]) { 685 if (camera_select[0]) {
703 ActivatePort(0, 0); 686 ActivatePort(0, 0);
@@ -708,24 +691,22 @@ void Activate(Service::Interface* self) {
708 if (camera_select[2]) { 691 if (camera_select[2]) {
709 ActivatePort(1, 2); 692 ActivatePort(1, 2);
710 } 693 }
711 cmd_buff[1] = RESULT_SUCCESS.raw; 694 rb.Push(RESULT_SUCCESS);
712 } 695 }
713 } else { 696 } else {
714 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); 697 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
715 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 698 rb.Push(ERROR_INVALID_ENUM_VALUE);
716 } 699 }
717 700
718 cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
719
720 LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val); 701 LOG_DEBUG(Service_CAM, "called, camera_select=%u", camera_select.m_val);
721} 702}
722 703
723void SwitchContext(Service::Interface* self) { 704void SwitchContext(Service::Interface* self) {
724 u32* cmd_buff = Kernel::GetCommandBuffer(); 705 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 2, 0);
725 706 const CameraSet camera_select(rp.Pop<u8>());
726 const CameraSet camera_select(cmd_buff[1]); 707 const ContextSet context_select(rp.Pop<u8>());
727 const ContextSet context_select(cmd_buff[2]);
728 708
709 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
729 if (camera_select.IsValid() && context_select.IsSingle()) { 710 if (camera_select.IsValid() && context_select.IsSingle()) {
730 int context = *context_select.begin(); 711 int context = *context_select.begin();
731 for (int camera : camera_select) { 712 for (int camera : camera_select) {
@@ -736,26 +717,24 @@ void SwitchContext(Service::Interface* self) {
736 cameras[camera].impl->SetFormat(context_config.format); 717 cameras[camera].impl->SetFormat(context_config.format);
737 cameras[camera].impl->SetResolution(context_config.resolution); 718 cameras[camera].impl->SetResolution(context_config.resolution);
738 } 719 }
739 cmd_buff[1] = RESULT_SUCCESS.raw; 720 rb.Push(RESULT_SUCCESS);
740 } else { 721 } else {
741 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 722 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
742 context_select.m_val); 723 context_select.m_val);
743 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 724 rb.Push(ERROR_INVALID_ENUM_VALUE);
744 } 725 }
745 726
746 cmd_buff[0] = IPC::MakeHeader(0x14, 1, 0);
747
748 LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val, 727 LOG_DEBUG(Service_CAM, "called, camera_select=%u, context_select=%u", camera_select.m_val,
749 context_select.m_val); 728 context_select.m_val);
750} 729}
751 730
752void FlipImage(Service::Interface* self) { 731void FlipImage(Service::Interface* self) {
753 u32* cmd_buff = Kernel::GetCommandBuffer(); 732 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 3, 0);
754 733 const CameraSet camera_select(rp.Pop<u8>());
755 const CameraSet camera_select(cmd_buff[1]); 734 const Flip flip = static_cast<Flip>(rp.Pop<u8>());
756 const Flip flip = static_cast<Flip>(cmd_buff[2] & 0xFF); 735 const ContextSet context_select(rp.Pop<u8>());
757 const ContextSet context_select(cmd_buff[3]);
758 736
737 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
759 if (camera_select.IsValid() && context_select.IsValid()) { 738 if (camera_select.IsValid() && context_select.IsValid()) {
760 for (int camera : camera_select) { 739 for (int camera : camera_select) {
761 for (int context : context_select) { 740 for (int context : context_select) {
@@ -765,32 +744,30 @@ void FlipImage(Service::Interface* self) {
765 } 744 }
766 } 745 }
767 } 746 }
768 cmd_buff[1] = RESULT_SUCCESS.raw; 747 rb.Push(RESULT_SUCCESS);
769 } else { 748 } else {
770 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 749 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
771 context_select.m_val); 750 context_select.m_val);
772 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 751 rb.Push(ERROR_INVALID_ENUM_VALUE);
773 } 752 }
774 753
775 cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0);
776
777 LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u", 754 LOG_DEBUG(Service_CAM, "called, camera_select=%u, flip=%d, context_select=%u",
778 camera_select.m_val, static_cast<int>(flip), context_select.m_val); 755 camera_select.m_val, static_cast<int>(flip), context_select.m_val);
779} 756}
780 757
781void SetDetailSize(Service::Interface* self) { 758void SetDetailSize(Service::Interface* self) {
782 u32* cmd_buff = Kernel::GetCommandBuffer(); 759 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 8, 0);
783 760 const CameraSet camera_select(rp.Pop<u8>());
784 const CameraSet camera_select(cmd_buff[1]);
785 Resolution resolution; 761 Resolution resolution;
786 resolution.width = static_cast<u16>(cmd_buff[2] & 0xFFFF); 762 resolution.width = rp.Pop<u16>();
787 resolution.height = static_cast<u16>(cmd_buff[3] & 0xFFFF); 763 resolution.height = rp.Pop<u16>();
788 resolution.crop_x0 = static_cast<u16>(cmd_buff[4] & 0xFFFF); 764 resolution.crop_x0 = rp.Pop<u16>();
789 resolution.crop_y0 = static_cast<u16>(cmd_buff[5] & 0xFFFF); 765 resolution.crop_y0 = rp.Pop<u16>();
790 resolution.crop_x1 = static_cast<u16>(cmd_buff[6] & 0xFFFF); 766 resolution.crop_x1 = rp.Pop<u16>();
791 resolution.crop_y1 = static_cast<u16>(cmd_buff[7] & 0xFFFF); 767 resolution.crop_y1 = rp.Pop<u16>();
792 const ContextSet context_select(cmd_buff[8]); 768 const ContextSet context_select(rp.Pop<u8>());
793 769
770 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
794 if (camera_select.IsValid() && context_select.IsValid()) { 771 if (camera_select.IsValid() && context_select.IsValid()) {
795 for (int camera : camera_select) { 772 for (int camera : camera_select) {
796 for (int context : context_select) { 773 for (int context : context_select) {
@@ -800,15 +777,13 @@ void SetDetailSize(Service::Interface* self) {
800 } 777 }
801 } 778 }
802 } 779 }
803 cmd_buff[1] = RESULT_SUCCESS.raw; 780 rb.Push(RESULT_SUCCESS);
804 } else { 781 } else {
805 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 782 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
806 context_select.m_val); 783 context_select.m_val);
807 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 784 rb.Push(ERROR_INVALID_ENUM_VALUE);
808 } 785 }
809 786
810 cmd_buff[0] = IPC::MakeHeader(0x1E, 1, 0);
811
812 LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, " 787 LOG_DEBUG(Service_CAM, "called, camera_select=%u, width=%u, height=%u, crop_x0=%u, crop_y0=%u, "
813 "crop_x1=%u, crop_y1=%u, context_select=%u", 788 "crop_x1=%u, crop_y1=%u, context_select=%u",
814 camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0, 789 camera_select.m_val, resolution.width, resolution.height, resolution.crop_x0,
@@ -816,12 +791,12 @@ void SetDetailSize(Service::Interface* self) {
816} 791}
817 792
818void SetSize(Service::Interface* self) { 793void SetSize(Service::Interface* self) {
819 u32* cmd_buff = Kernel::GetCommandBuffer(); 794 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 3, 0);
820 795 const CameraSet camera_select(rp.Pop<u8>());
821 const CameraSet camera_select(cmd_buff[1]); 796 const u8 size = rp.Pop<u8>();
822 const u32 size = cmd_buff[2] & 0xFF; 797 const ContextSet context_select(rp.Pop<u8>());
823 const ContextSet context_select(cmd_buff[3]);
824 798
799 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
825 if (camera_select.IsValid() && context_select.IsValid()) { 800 if (camera_select.IsValid() && context_select.IsValid()) {
826 for (int camera : camera_select) { 801 for (int camera : camera_select) {
827 for (int context : context_select) { 802 for (int context : context_select) {
@@ -831,49 +806,45 @@ void SetSize(Service::Interface* self) {
831 } 806 }
832 } 807 }
833 } 808 }
834 cmd_buff[1] = RESULT_SUCCESS.raw; 809 rb.Push(RESULT_SUCCESS);
835 } else { 810 } else {
836 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 811 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
837 context_select.m_val); 812 context_select.m_val);
838 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 813 rb.Push(ERROR_INVALID_ENUM_VALUE);
839 } 814 }
840 815
841 cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0);
842
843 LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u", 816 LOG_DEBUG(Service_CAM, "called, camera_select=%u, size=%u, context_select=%u",
844 camera_select.m_val, size, context_select.m_val); 817 camera_select.m_val, size, context_select.m_val);
845} 818}
846 819
847void SetFrameRate(Service::Interface* self) { 820void SetFrameRate(Service::Interface* self) {
848 u32* cmd_buff = Kernel::GetCommandBuffer(); 821 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x20, 2, 0);
849 822 const CameraSet camera_select(rp.Pop<u8>());
850 const CameraSet camera_select(cmd_buff[1]); 823 const FrameRate frame_rate = static_cast<FrameRate>(rp.Pop<u8>());
851 const FrameRate frame_rate = static_cast<FrameRate>(cmd_buff[2] & 0xFF);
852 824
825 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
853 if (camera_select.IsValid()) { 826 if (camera_select.IsValid()) {
854 for (int camera : camera_select) { 827 for (int camera : camera_select) {
855 cameras[camera].frame_rate = frame_rate; 828 cameras[camera].frame_rate = frame_rate;
856 // TODO(wwylele): consider hinting the actual camera with the expected frame rate 829 // TODO(wwylele): consider hinting the actual camera with the expected frame rate
857 } 830 }
858 cmd_buff[1] = RESULT_SUCCESS.raw; 831 rb.Push(RESULT_SUCCESS);
859 } else { 832 } else {
860 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val); 833 LOG_ERROR(Service_CAM, "invalid camera_select=%u", camera_select.m_val);
861 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 834 rb.Push(ERROR_INVALID_ENUM_VALUE);
862 } 835 }
863 836
864 cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
865
866 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d", 837 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select=%u, frame_rate=%d",
867 camera_select.m_val, static_cast<int>(frame_rate)); 838 camera_select.m_val, static_cast<int>(frame_rate));
868} 839}
869 840
870void SetEffect(Service::Interface* self) { 841void SetEffect(Service::Interface* self) {
871 u32* cmd_buff = Kernel::GetCommandBuffer(); 842 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x22, 3, 0);
872 843 const CameraSet camera_select(rp.Pop<u8>());
873 const CameraSet camera_select(cmd_buff[1]); 844 const Effect effect = static_cast<Effect>(rp.Pop<u8>());
874 const Effect effect = static_cast<Effect>(cmd_buff[2] & 0xFF); 845 const ContextSet context_select(rp.Pop<u8>());
875 const ContextSet context_select(cmd_buff[3]);
876 846
847 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
877 if (camera_select.IsValid() && context_select.IsValid()) { 848 if (camera_select.IsValid() && context_select.IsValid()) {
878 for (int camera : camera_select) { 849 for (int camera : camera_select) {
879 for (int context : context_select) { 850 for (int context : context_select) {
@@ -883,26 +854,24 @@ void SetEffect(Service::Interface* self) {
883 } 854 }
884 } 855 }
885 } 856 }
886 cmd_buff[1] = RESULT_SUCCESS.raw; 857 rb.Push(RESULT_SUCCESS);
887 } else { 858 } else {
888 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 859 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
889 context_select.m_val); 860 context_select.m_val);
890 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 861 rb.Push(ERROR_INVALID_ENUM_VALUE);
891 } 862 }
892 863
893 cmd_buff[0] = IPC::MakeHeader(0x22, 1, 0);
894
895 LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u", 864 LOG_DEBUG(Service_CAM, "called, camera_select=%u, effect=%d, context_select=%u",
896 camera_select.m_val, static_cast<int>(effect), context_select.m_val); 865 camera_select.m_val, static_cast<int>(effect), context_select.m_val);
897} 866}
898 867
899void SetOutputFormat(Service::Interface* self) { 868void SetOutputFormat(Service::Interface* self) {
900 u32* cmd_buff = Kernel::GetCommandBuffer(); 869 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0);
901 870 const CameraSet camera_select(rp.Pop<u8>());
902 const CameraSet camera_select(cmd_buff[1]); 871 const OutputFormat format = static_cast<OutputFormat>(rp.Pop<u8>());
903 const OutputFormat format = static_cast<OutputFormat>(cmd_buff[2] & 0xFF); 872 const ContextSet context_select(rp.Pop<u8>());
904 const ContextSet context_select(cmd_buff[3]);
905 873
874 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
906 if (camera_select.IsValid() && context_select.IsValid()) { 875 if (camera_select.IsValid() && context_select.IsValid()) {
907 for (int camera : camera_select) { 876 for (int camera : camera_select) {
908 for (int context : context_select) { 877 for (int context : context_select) {
@@ -912,34 +881,32 @@ void SetOutputFormat(Service::Interface* self) {
912 } 881 }
913 } 882 }
914 } 883 }
915 cmd_buff[1] = RESULT_SUCCESS.raw; 884 rb.Push(RESULT_SUCCESS);
916 } else { 885 } else {
917 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val, 886 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", camera_select.m_val,
918 context_select.m_val); 887 context_select.m_val);
919 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 888 rb.Push(ERROR_INVALID_ENUM_VALUE);
920 } 889 }
921 890
922 cmd_buff[0] = IPC::MakeHeader(0x25, 1, 0);
923
924 LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u", 891 LOG_DEBUG(Service_CAM, "called, camera_select=%u, format=%d, context_select=%u",
925 camera_select.m_val, static_cast<int>(format), context_select.m_val); 892 camera_select.m_val, static_cast<int>(format), context_select.m_val);
926} 893}
927 894
928void SynchronizeVsyncTiming(Service::Interface* self) { 895void SynchronizeVsyncTiming(Service::Interface* self) {
929 u32* cmd_buff = Kernel::GetCommandBuffer(); 896 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x29, 2, 0);
897 const u8 camera_select1 = rp.Pop<u8>();
898 const u8 camera_select2 = rp.Pop<u8>();
930 899
931 const u32 camera_select1 = cmd_buff[1] & 0xFF; 900 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
932 const u32 camera_select2 = cmd_buff[2] & 0xFF; 901 rb.Push(RESULT_SUCCESS);
933
934 cmd_buff[0] = IPC::MakeHeader(0x29, 1, 0);
935 cmd_buff[1] = RESULT_SUCCESS.raw;
936 902
937 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u", 903 LOG_WARNING(Service_CAM, "(STUBBED) called, camera_select1=%u, camera_select2=%u",
938 camera_select1, camera_select2); 904 camera_select1, camera_select2);
939} 905}
940 906
941void GetStereoCameraCalibrationData(Service::Interface* self) { 907void GetStereoCameraCalibrationData(Service::Interface* self) {
942 u32* cmd_buff = Kernel::GetCommandBuffer(); 908 IPC::RequestBuilder rb =
909 IPC::RequestParser(Kernel::GetCommandBuffer(), 0x2B, 0, 0).MakeBuilder(17, 0);
943 910
944 // Default values taken from yuriks' 3DS. Valid data is required here or games using the 911 // Default values taken from yuriks' 3DS. Valid data is required here or games using the
945 // calibration get stuck in an infinite CPU loop. 912 // calibration get stuck in an infinite CPU loop.
@@ -958,34 +925,28 @@ void GetStereoCameraCalibrationData(Service::Interface* self) {
958 data.imageWidth = 640; 925 data.imageWidth = 640;
959 data.imageHeight = 480; 926 data.imageHeight = 480;
960 927
961 cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0); 928 rb.Push(RESULT_SUCCESS);
962 cmd_buff[1] = RESULT_SUCCESS.raw; 929 rb.PushRaw(data);
963 memcpy(&cmd_buff[2], &data, sizeof(data));
964 930
965 LOG_TRACE(Service_CAM, "called"); 931 LOG_TRACE(Service_CAM, "called");
966} 932}
967 933
968void SetPackageParameterWithoutContext(Service::Interface* self) { 934void SetPackageParameterWithoutContext(Service::Interface* self) {
969 u32* cmd_buff = Kernel::GetCommandBuffer(); 935 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x33, 11, 0);
970 936
971 PackageParameterWithoutContext package; 937 PackageParameterWithoutContext package;
972 std::memcpy(&package, cmd_buff + 1, sizeof(package)); 938 rp.PopRaw(package);
973 939
974 cmd_buff[0] = IPC::MakeHeader(0x33, 1, 0); 940 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
975 cmd_buff[1] = RESULT_SUCCESS.raw; 941 rb.Push(RESULT_SUCCESS);
976 942
977 LOG_WARNING(Service_CAM, "(STUBBED) called"); 943 LOG_WARNING(Service_CAM, "(STUBBED) called");
978} 944}
979 945
980template <typename PackageParameterType, int command_id> 946template <typename PackageParameterType>
981static void SetPackageParameter() { 947static ResultCode SetPackageParameter(const PackageParameterType& package) {
982 u32* cmd_buff = Kernel::GetCommandBuffer(); 948 const CameraSet camera_select(package.camera_select);
983 949 const ContextSet context_select(package.context_select);
984 PackageParameterType package;
985 std::memcpy(&package, cmd_buff + 1, sizeof(package));
986
987 const CameraSet camera_select(static_cast<u32>(package.camera_select));
988 const ContextSet context_select(static_cast<u32>(package.context_select));
989 950
990 if (camera_select.IsValid() && context_select.IsValid()) { 951 if (camera_select.IsValid() && context_select.IsValid()) {
991 for (int camera_id : camera_select) { 952 for (int camera_id : camera_select) {
@@ -1002,53 +963,66 @@ static void SetPackageParameter() {
1002 } 963 }
1003 } 964 }
1004 } 965 }
1005 cmd_buff[1] = RESULT_SUCCESS.raw; 966 return RESULT_SUCCESS;
1006 } else { 967 } else {
1007 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select, 968 LOG_ERROR(Service_CAM, "invalid camera_select=%u, context_select=%u", package.camera_select,
1008 package.context_select); 969 package.context_select);
1009 cmd_buff[1] = ERROR_INVALID_ENUM_VALUE.raw; 970 return ERROR_INVALID_ENUM_VALUE;
1010 } 971 }
1011
1012 cmd_buff[0] = IPC::MakeHeader(command_id, 1, 0);
1013
1014 LOG_DEBUG(Service_CAM, "called");
1015} 972}
1016 973
1017Resolution PackageParameterWithContext::GetResolution() { 974Resolution PackageParameterWithContext::GetResolution() const {
1018 return PRESET_RESOLUTION[static_cast<int>(size)]; 975 return PRESET_RESOLUTION[static_cast<int>(size)];
1019} 976}
1020 977
1021void SetPackageParameterWithContext(Service::Interface* self) { 978void SetPackageParameterWithContext(Service::Interface* self) {
1022 SetPackageParameter<PackageParameterWithContext, 0x34>(); 979 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x34, 5, 0);
980
981 PackageParameterWithContext package;
982 rp.PopRaw(package);
983
984 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
985 ResultCode result = SetPackageParameter(package);
986 rb.Push(result);
987
988 LOG_DEBUG(Service_CAM, "called");
1023} 989}
1024 990
1025void SetPackageParameterWithContextDetail(Service::Interface* self) { 991void SetPackageParameterWithContextDetail(Service::Interface* self) {
1026 SetPackageParameter<PackageParameterWithContextDetail, 0x35>(); 992 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x35, 7, 0);
993
994 PackageParameterWithContextDetail package;
995 rp.PopRaw(package);
996
997 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
998 ResultCode result = SetPackageParameter(package);
999 rb.Push(result);
1000
1001 LOG_DEBUG(Service_CAM, "called");
1027} 1002}
1028 1003
1029void GetSuitableY2rStandardCoefficient(Service::Interface* self) { 1004void GetSuitableY2rStandardCoefficient(Service::Interface* self) {
1030 u32* cmd_buff = Kernel::GetCommandBuffer(); 1005 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x36, 0, 0);
1031 1006 IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
1032 cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0); 1007 rb.Push(RESULT_SUCCESS);
1033 cmd_buff[1] = RESULT_SUCCESS.raw; 1008 rb.Push<u32>(0);
1034 cmd_buff[2] = 0;
1035 1009
1036 LOG_WARNING(Service_CAM, "(STUBBED) called"); 1010 LOG_WARNING(Service_CAM, "(STUBBED) called");
1037} 1011}
1038 1012
1039void PlayShutterSound(Service::Interface* self) { 1013void PlayShutterSound(Service::Interface* self) {
1040 u32* cmd_buff = Kernel::GetCommandBuffer(); 1014 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x38, 1, 0);
1041 1015 u8 sound_id = rp.Pop<u8>();
1042 u8 sound_id = cmd_buff[1] & 0xFF;
1043 1016
1044 cmd_buff[0] = IPC::MakeHeader(0x38, 1, 0); 1017 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
1045 cmd_buff[1] = RESULT_SUCCESS.raw; 1018 rb.Push(RESULT_SUCCESS);
1046 1019
1047 LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); 1020 LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id);
1048} 1021}
1049 1022
1050void DriverInitialize(Service::Interface* self) { 1023void DriverInitialize(Service::Interface* self) {
1051 u32* cmd_buff = Kernel::GetCommandBuffer(); 1024 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x39, 0, 0);
1025 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
1052 1026
1053 for (int camera_id = 0; camera_id < NumCameras; ++camera_id) { 1027 for (int camera_id = 0; camera_id < NumCameras; ++camera_id) {
1054 CameraConfig& camera = cameras[camera_id]; 1028 CameraConfig& camera = cameras[camera_id];
@@ -1074,14 +1048,14 @@ void DriverInitialize(Service::Interface* self) {
1074 port.Clear(); 1048 port.Clear();
1075 } 1049 }
1076 1050
1077 cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0); 1051 rb.Push(RESULT_SUCCESS);
1078 cmd_buff[1] = RESULT_SUCCESS.raw;
1079 1052
1080 LOG_DEBUG(Service_CAM, "called"); 1053 LOG_DEBUG(Service_CAM, "called");
1081} 1054}
1082 1055
1083void DriverFinalize(Service::Interface* self) { 1056void DriverFinalize(Service::Interface* self) {
1084 u32* cmd_buff = Kernel::GetCommandBuffer(); 1057 IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3A, 0, 0);
1058 IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
1085 1059
1086 CancelReceiving(0); 1060 CancelReceiving(0);
1087 CancelReceiving(1); 1061 CancelReceiving(1);
@@ -1090,8 +1064,7 @@ void DriverFinalize(Service::Interface* self) {
1090 camera.impl = nullptr; 1064 camera.impl = nullptr;
1091 } 1065 }
1092 1066
1093 cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0); 1067 rb.Push(RESULT_SUCCESS);
1094 cmd_buff[1] = RESULT_SUCCESS.raw;
1095 1068
1096 LOG_DEBUG(Service_CAM, "called"); 1069 LOG_DEBUG(Service_CAM, "called");
1097} 1070}
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 34a9c8479..b6da721d8 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -184,9 +184,10 @@ struct PackageParameterWithoutContext {
184 s16 auto_white_balance_window_y; 184 s16 auto_white_balance_window_y;
185 s16 auto_white_balance_window_width; 185 s16 auto_white_balance_window_width;
186 s16 auto_white_balance_window_height; 186 s16 auto_white_balance_window_height;
187 INSERT_PADDING_WORDS(4);
187}; 188};
188 189
189static_assert(sizeof(PackageParameterWithoutContext) == 28, 190static_assert(sizeof(PackageParameterWithoutContext) == 44,
190 "PackageParameterCameraWithoutContext structure size is wrong"); 191 "PackageParameterCameraWithoutContext structure size is wrong");
191 192
192struct PackageParameterWithContext { 193struct PackageParameterWithContext {
@@ -196,11 +197,12 @@ struct PackageParameterWithContext {
196 Effect effect; 197 Effect effect;
197 Size size; 198 Size size;
198 INSERT_PADDING_BYTES(3); 199 INSERT_PADDING_BYTES(3);
200 INSERT_PADDING_WORDS(3);
199 201
200 Resolution GetResolution(); 202 Resolution GetResolution() const;
201}; 203};
202 204
203static_assert(sizeof(PackageParameterWithContext) == 8, 205static_assert(sizeof(PackageParameterWithContext) == 20,
204 "PackageParameterWithContext structure size is wrong"); 206 "PackageParameterWithContext structure size is wrong");
205 207
206struct PackageParameterWithContextDetail { 208struct PackageParameterWithContextDetail {
@@ -209,13 +211,14 @@ struct PackageParameterWithContextDetail {
209 Flip flip; 211 Flip flip;
210 Effect effect; 212 Effect effect;
211 Resolution resolution; 213 Resolution resolution;
214 INSERT_PADDING_WORDS(3);
212 215
213 Resolution GetResolution() { 216 Resolution GetResolution() const {
214 return resolution; 217 return resolution;
215 } 218 }
216}; 219};
217 220
218static_assert(sizeof(PackageParameterWithContextDetail) == 16, 221static_assert(sizeof(PackageParameterWithContextDetail) == 28,
219 "PackageParameterWithContextDetail structure size is wrong"); 222 "PackageParameterWithContextDetail structure size is wrong");
220 223
221/** 224/**
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index eb04273db..bd9814244 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -3,7 +3,10 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc.h"
6#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/event.h"
8#include "core/hle/kernel/handle_table.h"
9#include "core/hle/result.h"
7#include "core/hle/service/cecd/cecd.h" 10#include "core/hle/service/cecd/cecd.h"
8#include "core/hle/service/cecd/cecd_ndm.h" 11#include "core/hle/service/cecd/cecd_ndm.h"
9#include "core/hle/service/cecd/cecd_s.h" 12#include "core/hle/service/cecd/cecd_s.h"
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index caa41ded7..5a7878b31 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -13,6 +13,8 @@
13#include "core/file_sys/archive_systemsavedata.h" 13#include "core/file_sys/archive_systemsavedata.h"
14#include "core/file_sys/errors.h" 14#include "core/file_sys/errors.h"
15#include "core/file_sys/file_backend.h" 15#include "core/file_sys/file_backend.h"
16#include "core/hle/ipc.h"
17#include "core/hle/ipc_helpers.h"
16#include "core/hle/result.h" 18#include "core/hle/result.h"
17#include "core/hle/service/cfg/cfg.h" 19#include "core/hle/service/cfg/cfg.h"
18#include "core/hle/service/cfg/cfg_i.h" 20#include "core/hle/service/cfg/cfg_i.h"
@@ -21,6 +23,7 @@
21#include "core/hle/service/cfg/cfg_u.h" 23#include "core/hle/service/cfg/cfg_u.h"
22#include "core/hle/service/fs/archive.h" 24#include "core/hle/service/fs/archive.h"
23#include "core/hle/service/service.h" 25#include "core/hle/service/service.h"
26#include "core/memory.h"
24#include "core/settings.h" 27#include "core/settings.h"
25 28
26namespace Service { 29namespace Service {
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 6cf62f9bc..1455f20ca 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -4,9 +4,12 @@
4 4
5#include <cstring> 5#include <cstring>
6#include "common/alignment.h" 6#include "common/alignment.h"
7#include "core/hle/ipc.h"
8#include "core/hle/kernel/handle_table.h"
7#include "core/hle/kernel/mutex.h" 9#include "core/hle/kernel/mutex.h"
8#include "core/hle/kernel/shared_memory.h" 10#include "core/hle/kernel/shared_memory.h"
9#include "core/hle/service/csnd_snd.h" 11#include "core/hle/service/csnd_snd.h"
12#include "core/memory.h"
10 13
11namespace Service { 14namespace Service {
12namespace CSND { 15namespace CSND {
diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp
index 25c07f401..32cfa2c44 100644
--- a/src/core/hle/service/dlp/dlp_srvr.cpp
+++ b/src/core/hle/service/dlp/dlp_srvr.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/hle/ipc.h"
7#include "core/hle/result.h" 8#include "core/hle/result.h"
8#include "core/hle/service/dlp/dlp_srvr.h" 9#include "core/hle/service/dlp/dlp_srvr.h"
9 10
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 79171a0bc..363066d14 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -3,12 +3,18 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
6#include <cinttypes> 7#include <cinttypes>
7#include "audio_core/hle/pipe.h" 8#include "audio_core/hle/pipe.h"
9#include "common/assert.h"
8#include "common/hash.h" 10#include "common/hash.h"
9#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/hle/ipc.h"
10#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/handle_table.h"
15#include "core/hle/result.h"
11#include "core/hle/service/dsp_dsp.h" 16#include "core/hle/service/dsp_dsp.h"
17#include "core/memory.h"
12 18
13using DspPipe = DSP::HLE::DspPipe; 19using DspPipe = DSP::HLE::DspPipe;
14 20
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 9da55f328..7c8f4339f 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -6,10 +6,11 @@
6#include <chrono> 6#include <chrono>
7#include <iomanip> 7#include <iomanip>
8#include <sstream> 8#include <sstream>
9
10#include "common/bit_field.h" 9#include "common/bit_field.h"
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/core.h"
13#include "core/hle/ipc.h"
13#include "core/hle/result.h" 14#include "core/hle/result.h"
14#include "core/hle/service/err_f.h" 15#include "core/hle/service/err_f.h"
15 16
@@ -172,6 +173,7 @@ static void ThrowFatalError(Interface* self) {
172 const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); 173 const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]);
173 LOG_CRITICAL(Service_ERR, "Fatal error type: %s", 174 LOG_CRITICAL(Service_ERR, "Fatal error type: %s",
174 GetErrType(errinfo->errinfo_common.specifier).c_str()); 175 GetErrType(errinfo->errinfo_common.specifier).c_str());
176 Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorUnknown);
175 177
176 // Generic Info 178 // Generic Info
177 LogGenericInfo(errinfo->errinfo_common); 179 LogGenericInfo(errinfo->errinfo_common);
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
index 34fdf7f53..76ecda8b7 100644
--- a/src/core/hle/service/frd/frd.cpp
+++ b/src/core/hle/service/frd/frd.cpp
@@ -2,11 +2,16 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
6#include "common/logging/log.h"
5#include "common/string_util.h" 7#include "common/string_util.h"
8#include "core/hle/ipc.h"
9#include "core/hle/result.h"
6#include "core/hle/service/frd/frd.h" 10#include "core/hle/service/frd/frd.h"
7#include "core/hle/service/frd/frd_a.h" 11#include "core/hle/service/frd/frd_a.h"
8#include "core/hle/service/frd/frd_u.h" 12#include "core/hle/service/frd/frd_u.h"
9#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
14#include "core/memory.h"
10 15
11namespace Service { 16namespace Service {
12namespace FRD { 17namespace FRD {
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 632712f2c..3605ef175 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -24,7 +24,11 @@
24#include "core/file_sys/directory_backend.h" 24#include "core/file_sys/directory_backend.h"
25#include "core/file_sys/errors.h" 25#include "core/file_sys/errors.h"
26#include "core/file_sys/file_backend.h" 26#include "core/file_sys/file_backend.h"
27#include "core/hle/ipc.h"
28#include "core/hle/kernel/client_port.h"
27#include "core/hle/kernel/client_session.h" 29#include "core/hle/kernel/client_session.h"
30#include "core/hle/kernel/handle_table.h"
31#include "core/hle/kernel/server_session.h"
28#include "core/hle/result.h" 32#include "core/hle/result.h"
29#include "core/hle/service/fs/archive.h" 33#include "core/hle/service/fs/archive.h"
30#include "core/hle/service/fs/fs_user.h" 34#include "core/hle/service/fs/fs_user.h"
@@ -83,6 +87,10 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path&
83File::~File() {} 87File::~File() {}
84 88
85void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { 89void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
90 using Kernel::ClientSession;
91 using Kernel::ServerSession;
92 using Kernel::SharedPtr;
93
86 u32* cmd_buff = Kernel::GetCommandBuffer(); 94 u32* cmd_buff = Kernel::GetCommandBuffer();
87 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 95 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
88 switch (cmd) { 96 switch (cmd) {
@@ -161,10 +169,9 @@ void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_ses
161 169
162 case FileCommand::OpenLinkFile: { 170 case FileCommand::OpenLinkFile: {
163 LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); 171 LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
164 auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); 172 auto sessions = ServerSession::CreateSessionPair(GetName());
165 ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); 173 ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
166 cmd_buff[3] = Kernel::g_handle_table 174 cmd_buff[3] = Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions))
167 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
168 .ValueOr(INVALID_HANDLE); 175 .ValueOr(INVALID_HANDLE);
169 break; 176 break;
170 } 177 }
@@ -258,9 +265,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
258 265
259 auto itr = id_code_map.find(id_code); 266 auto itr = id_code_map.find(id_code);
260 if (itr == id_code_map.end()) { 267 if (itr == id_code_map.end()) {
261 // TODO: Verify error against hardware 268 return FileSys::ERROR_NOT_FOUND;
262 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound,
263 ErrorLevel::Permanent);
264 } 269 }
265 270
266 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); 271 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 2ea956e0b..3a3371c88 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -8,7 +8,7 @@
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/archive_backend.h" 10#include "core/file_sys/archive_backend.h"
11#include "core/hle/kernel/server_session.h" 11#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13 13
14namespace FileSys { 14namespace FileSys {
@@ -43,7 +43,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
43 43
44typedef u64 ArchiveHandle; 44typedef u64 ArchiveHandle;
45 45
46class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> { 46class File final : public Kernel::SessionRequestHandler {
47public: 47public:
48 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); 48 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
49 ~File(); 49 ~File();
@@ -60,7 +60,7 @@ protected:
60 void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; 60 void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
61}; 61};
62 62
63class Directory final : public SessionRequestHandler { 63class Directory final : public Kernel::SessionRequestHandler {
64public: 64public:
65 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); 65 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
66 ~Directory(); 66 ~Directory();
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index e53a970d3..34e1783ec 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -8,8 +8,13 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/scope_exit.h" 9#include "common/scope_exit.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/core.h"
11#include "core/file_sys/errors.h" 12#include "core/file_sys/errors.h"
13#include "core/hle/ipc.h"
14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/client_port.h"
12#include "core/hle/kernel/client_session.h" 16#include "core/hle/kernel/client_session.h"
17#include "core/hle/kernel/server_session.h"
13#include "core/hle/result.h" 18#include "core/hle/result.h"
14#include "core/hle/service/fs/archive.h" 19#include "core/hle/service/fs/archive.h"
15#include "core/hle/service/fs/fs_user.h" 20#include "core/hle/service/fs/fs_user.h"
@@ -18,8 +23,9 @@
18//////////////////////////////////////////////////////////////////////////////////////////////////// 23////////////////////////////////////////////////////////////////////////////////////////////////////
19// Namespace FS_User 24// Namespace FS_User
20 25
21using Kernel::SharedPtr; 26using Kernel::ClientSession;
22using Kernel::ServerSession; 27using Kernel::ServerSession;
28using Kernel::SharedPtr;
23 29
24namespace Service { 30namespace Service {
25namespace FS { 31namespace FS {
@@ -77,11 +83,11 @@ static void OpenFile(Service::Interface* self) {
77 rb.Push(file_res.Code()); 83 rb.Push(file_res.Code());
78 if (file_res.Succeeded()) { 84 if (file_res.Succeeded()) {
79 std::shared_ptr<File> file = *file_res; 85 std::shared_ptr<File> file = *file_res;
80 auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); 86 auto sessions = ServerSession::CreateSessionPair(file->GetName());
81 file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); 87 file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
82 rb.PushMoveHandles(Kernel::g_handle_table 88
83 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) 89 rb.PushMoveHandles(
84 .MoveFrom()); 90 Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom());
85 } else { 91 } else {
86 rb.PushMoveHandles(0); 92 rb.PushMoveHandles(0);
87 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 93 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
@@ -130,7 +136,7 @@ static void OpenFileDirectly(Service::Interface* self) {
130 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); 136 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
131 if (archive_handle.Failed()) { 137 if (archive_handle.Failed()) {
132 LOG_ERROR(Service_FS, 138 LOG_ERROR(Service_FS,
133 "failed to get a handle for archive archive_id=0x%08X archive_path=%s", 139 "Failed to get a handle for archive archive_id=0x%08X archive_path=%s",
134 static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); 140 static_cast<u32>(archive_id), archive_path.DebugStr().c_str());
135 cmd_buff[1] = archive_handle.Code().raw; 141 cmd_buff[1] = archive_handle.Code().raw;
136 cmd_buff[3] = 0; 142 cmd_buff[3] = 0;
@@ -143,11 +149,11 @@ static void OpenFileDirectly(Service::Interface* self) {
143 cmd_buff[1] = file_res.Code().raw; 149 cmd_buff[1] = file_res.Code().raw;
144 if (file_res.Succeeded()) { 150 if (file_res.Succeeded()) {
145 std::shared_ptr<File> file = *file_res; 151 std::shared_ptr<File> file = *file_res;
146 auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); 152 auto sessions = ServerSession::CreateSessionPair(file->GetName());
147 file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); 153 file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
148 cmd_buff[3] = Kernel::g_handle_table 154
149 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) 155 cmd_buff[3] =
150 .MoveFrom(); 156 Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom();
151 } else { 157 } else {
152 cmd_buff[3] = 0; 158 cmd_buff[3] = 0;
153 LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", 159 LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u",
@@ -410,11 +416,11 @@ static void OpenDirectory(Service::Interface* self) {
410 cmd_buff[1] = dir_res.Code().raw; 416 cmd_buff[1] = dir_res.Code().raw;
411 if (dir_res.Succeeded()) { 417 if (dir_res.Succeeded()) {
412 std::shared_ptr<Directory> directory = *dir_res; 418 std::shared_ptr<Directory> directory = *dir_res;
413 auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); 419 auto sessions = ServerSession::CreateSessionPair(directory->GetName());
414 directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); 420 directory->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions));
415 cmd_buff[3] = Kernel::g_handle_table 421
416 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) 422 cmd_buff[3] =
417 .MoveFrom(); 423 Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom();
418 } else { 424 } else {
419 LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", 425 LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
420 dirname_type, dirname_size, dir_path.DebugStr().c_str()); 426 dirname_type, dirname_size, dir_path.DebugStr().c_str());
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 94f6b8a9c..6ff0f4812 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -5,7 +5,9 @@
5#include "common/bit_field.h" 5#include "common/bit_field.h"
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc.h"
8#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/handle_table.h"
9#include "core/hle/kernel/shared_memory.h" 11#include "core/hle/kernel/shared_memory.h"
10#include "core/hle/result.h" 12#include "core/hle/result.h"
11#include "core/hle/service/gsp_gpu.h" 13#include "core/hle/service/gsp_gpu.h"
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 64d01cdd7..5255f6dc8 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -10,7 +10,9 @@
10#include "core/core_timing.h" 10#include "core/core_timing.h"
11#include "core/frontend/emu_window.h" 11#include "core/frontend/emu_window.h"
12#include "core/frontend/input.h" 12#include "core/frontend/input.h"
13#include "core/hle/ipc.h"
13#include "core/hle/kernel/event.h" 14#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/handle_table.h"
14#include "core/hle/kernel/shared_memory.h" 16#include "core/hle/kernel/shared_memory.h"
15#include "core/hle/service/hid/hid.h" 17#include "core/hle/service/hid/hid.h"
16#include "core/hle/service/hid/hid_spvr.h" 18#include "core/hle/service/hid/hid_spvr.h"
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
index 53807cd91..0de698003 100644
--- a/src/core/hle/service/ir/ir_rst.cpp
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -6,6 +6,7 @@
6#include "common/bit_field.h" 6#include "common/bit_field.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/frontend/input.h" 8#include "core/frontend/input.h"
9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/shared_memory.h" 11#include "core/hle/kernel/shared_memory.h"
11#include "core/hle/service/hid/hid.h" 12#include "core/hle/service/hid/hid.h"
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index 369115f09..fdecdce64 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -7,6 +7,7 @@
7#include <boost/optional.hpp> 7#include <boost/optional.hpp>
8#include "common/string_util.h" 8#include "common/string_util.h"
9#include "common/swap.h" 9#include "common/swap.h"
10#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/event.h" 11#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/shared_memory.h" 12#include "core/hle/kernel/shared_memory.h"
12#include "core/hle/service/ir/extra_hid.h" 13#include "core/hle/service/ir/extra_hid.h"
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp
index d1e6d869f..7255ea026 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp
@@ -7,6 +7,7 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/arm/arm_interface.h" 8#include "core/arm/arm_interface.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/process.h" 11#include "core/hle/kernel/process.h"
11#include "core/hle/kernel/vm_manager.h" 12#include "core/hle/kernel/vm_manager.h"
12#include "core/hle/service/ldr_ro/cro_helper.h" 13#include "core/hle/service/ldr_ro/cro_helper.h"
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index e98388560..35212b59b 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -3,7 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc.h"
6#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/event.h"
8#include "core/hle/kernel/handle_table.h"
7#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/shared_memory.h" 10#include "core/hle/kernel/shared_memory.h"
9#include "core/hle/service/mic_u.h" 11#include "core/hle/service/mic_u.h"
diff --git a/src/core/hle/service/ndm/ndm.cpp b/src/core/hle/service/ndm/ndm.cpp
index 5eb97f0d3..096c0cdac 100644
--- a/src/core/hle/service/ndm/ndm.cpp
+++ b/src/core/hle/service/ndm/ndm.cpp
@@ -2,8 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
5#include "common/common_types.h" 6#include "common/common_types.h"
6#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/ipc.h"
7#include "core/hle/service/ndm/ndm.h" 9#include "core/hle/service/ndm/ndm.h"
8#include "core/hle/service/ndm/ndm_u.h" 10#include "core/hle/service/ndm/ndm_u.h"
9#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index fd3c7d9c2..b44a9f668 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -2,7 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/ipc.h"
5#include "core/hle/kernel/event.h" 6#include "core/hle/kernel/event.h"
7#include "core/hle/kernel/handle_table.h"
6#include "core/hle/service/nfc/nfc.h" 8#include "core/hle/service/nfc/nfc.h"
7#include "core/hle/service/nfc/nfc_m.h" 9#include "core/hle/service/nfc/nfc_m.h"
8#include "core/hle/service/nfc/nfc_u.h" 10#include "core/hle/service/nfc/nfc_u.h"
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 63c334cb2..d5624fe54 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/hle/ipc.h"
7#include "core/hle/service/nim/nim.h" 8#include "core/hle/service/nim/nim.h"
8#include "core/hle/service/nim/nim_aoc.h" 9#include "core/hle/service/nim/nim_aoc.h"
9#include "core/hle/service/nim/nim_s.h" 10#include "core/hle/service/nim/nim_s.h"
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index a82cc9bd3..6c4600f25 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/core_timing.h" 11#include "core/core_timing.h"
12#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/shared_memory.h" 14#include "core/hle/kernel/shared_memory.h"
14#include "core/hle/result.h" 15#include "core/hle/result.h"
diff --git a/src/core/hle/service/nwm/uds_beacon.cpp b/src/core/hle/service/nwm/uds_beacon.cpp
index c6e5bc5f1..6332b404c 100644
--- a/src/core/hle/service/nwm/uds_beacon.cpp
+++ b/src/core/hle/service/nwm/uds_beacon.cpp
@@ -3,14 +3,13 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6
7#include "core/hle/service/nwm/nwm_uds.h"
8#include "core/hle/service/nwm/uds_beacon.h"
9
10#include <cryptopp/aes.h> 6#include <cryptopp/aes.h>
11#include <cryptopp/md5.h> 7#include <cryptopp/md5.h>
12#include <cryptopp/modes.h> 8#include <cryptopp/modes.h>
13#include <cryptopp/sha.h> 9#include <cryptopp/sha.h>
10#include "common/assert.h"
11#include "core/hle/service/nwm/nwm_uds.h"
12#include "core/hle/service/nwm/uds_beacon.h"
14 13
15namespace Service { 14namespace Service {
16namespace NWM { 15namespace NWM {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 0672ac2e3..0d443aa44 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -2,11 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <boost/range/algorithm_ext/erase.hpp>
6
7#include "common/logging/log.h" 5#include "common/logging/log.h"
8#include "common/string_util.h" 6#include "common/string_util.h"
7#include "core/hle/kernel/client_port.h"
9#include "core/hle/kernel/server_port.h" 8#include "core/hle/kernel/server_port.h"
9#include "core/hle/kernel/server_session.h"
10#include "core/hle/service/ac/ac.h" 10#include "core/hle/service/ac/ac.h"
11#include "core/hle/service/act/act.h" 11#include "core/hle/service/act/act.h"
12#include "core/hle/service/am/am.h" 12#include "core/hle/service/am/am.h"
@@ -39,15 +39,15 @@
39#include "core/hle/service/ptm/ptm.h" 39#include "core/hle/service/ptm/ptm.h"
40#include "core/hle/service/qtm/qtm.h" 40#include "core/hle/service/qtm/qtm.h"
41#include "core/hle/service/service.h" 41#include "core/hle/service/service.h"
42#include "core/hle/service/sm/sm.h"
43#include "core/hle/service/sm/srv.h"
42#include "core/hle/service/soc_u.h" 44#include "core/hle/service/soc_u.h"
43#include "core/hle/service/srv.h"
44#include "core/hle/service/ssl_c.h" 45#include "core/hle/service/ssl_c.h"
45#include "core/hle/service/y2r_u.h" 46#include "core/hle/service/y2r_u.h"
46 47
47namespace Service { 48namespace Service {
48 49
49std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; 50std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
50std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
51 51
52/** 52/**
53 * Creates a function string for logging, complete with the name (or header code, depending 53 * Creates a function string for logging, complete with the name (or header code, depending
@@ -66,16 +66,6 @@ static std::string MakeFunctionString(const char* name, const char* port_name,
66 return function_string; 66 return function_string;
67} 67}
68 68
69void SessionRequestHandler::ClientConnected(
70 Kernel::SharedPtr<Kernel::ServerSession> server_session) {
71 connected_sessions.push_back(server_session);
72}
73
74void SessionRequestHandler::ClientDisconnected(
75 Kernel::SharedPtr<Kernel::ServerSession> server_session) {
76 boost::range::remove_erase(connected_sessions, server_session);
77}
78
79Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} 69Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {}
80Interface::~Interface() = default; 70Interface::~Interface() = default;
81 71
@@ -116,24 +106,27 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {
116// Module interface 106// Module interface
117 107
118static void AddNamedPort(Interface* interface_) { 108static void AddNamedPort(Interface* interface_) {
119 auto ports = 109 Kernel::SharedPtr<Kernel::ServerPort> server_port;
120 Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), 110 Kernel::SharedPtr<Kernel::ClientPort> client_port;
121 std::shared_ptr<Interface>(interface_)); 111 std::tie(server_port, client_port) =
122 auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); 112 Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName());
113
114 server_port->SetHleHandler(std::shared_ptr<Interface>(interface_));
123 g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); 115 g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port));
124} 116}
125 117
126void AddService(Interface* interface_) { 118void AddService(Interface* interface_) {
127 auto ports = 119 auto server_port =
128 Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), 120 SM::g_service_manager
129 std::shared_ptr<Interface>(interface_)); 121 ->RegisterService(interface_->GetPortName(), interface_->GetMaxSessions())
130 auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); 122 .MoveFrom();
131 g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); 123 server_port->SetHleHandler(std::shared_ptr<Interface>(interface_));
132} 124}
133 125
134/// Initialize ServiceManager 126/// Initialize ServiceManager
135void Init() { 127void Init() {
136 AddNamedPort(new SRV::SRV); 128 SM::g_service_manager = std::make_unique<SM::ServiceManager>();
129 AddNamedPort(new SM::SRV);
137 AddNamedPort(new ERR::ERR_F); 130 AddNamedPort(new ERR::ERR_F);
138 131
139 FS::ArchiveInit(); 132 FS::ArchiveInit();
@@ -194,7 +187,7 @@ void Shutdown() {
194 AC::Shutdown(); 187 AC::Shutdown();
195 FS::ArchiveShutdown(); 188 FS::ArchiveShutdown();
196 189
197 g_srv_services.clear(); 190 SM::g_service_manager = nullptr;
198 g_kernel_named_ports.clear(); 191 g_kernel_named_ports.clear();
199 LOG_DEBUG(Service, "shutdown OK"); 192 LOG_DEBUG(Service, "shutdown OK");
200} 193}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index e6a5f1417..8933d57cc 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -8,21 +8,19 @@
8#include <string> 8#include <string>
9#include <unordered_map> 9#include <unordered_map>
10#include <boost/container/flat_map.hpp> 10#include <boost/container/flat_map.hpp>
11#include "common/bit_field.h"
11#include "common/common_types.h" 12#include "common/common_types.h"
12#include "core/hle/ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
13#include "core/hle/ipc_helpers.h" 14#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/client_port.h" 15
15#include "core/hle/kernel/thread.h" 16////////////////////////////////////////////////////////////////////////////////////////////////////
16#include "core/hle/result.h" 17// Namespace Service
17#include "core/memory.h"
18 18
19namespace Kernel { 19namespace Kernel {
20class ClientPort;
20class ServerSession; 21class ServerSession;
21} 22}
22 23
23////////////////////////////////////////////////////////////////////////////////////////////////////
24// Namespace Service
25
26namespace Service { 24namespace Service {
27 25
28static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) 26static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
@@ -30,48 +28,10 @@ static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 character
30static const u32 DefaultMaxSessions = 10; 28static const u32 DefaultMaxSessions = 10;
31 29
32/** 30/**
33 * Interface implemented by HLE Session handlers.
34 * This can be provided to a ServerSession in order to hook into several relevant events
35 * (such as a new connection or a SyncRequest) so they can be implemented in the emulator.
36 */
37class SessionRequestHandler {
38public:
39 /**
40 * Handles a sync request from the emulated application.
41 * @param server_session The ServerSession that was triggered for this sync request,
42 * it should be used to differentiate which client (As in ClientSession) we're answering to.
43 * TODO(Subv): Use a wrapper structure to hold all the information relevant to
44 * this request (ServerSession, Originator thread, Translated command buffer, etc).
45 * @returns ResultCode the result code of the translate operation.
46 */
47 virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0;
48
49 /**
50 * Signals that a client has just connected to this HLE handler and keeps the
51 * associated ServerSession alive for the duration of the connection.
52 * @param server_session Owning pointer to the ServerSession associated with the connection.
53 */
54 void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
55
56 /**
57 * Signals that a client has just disconnected from this HLE handler and releases the
58 * associated ServerSession.
59 * @param server_session ServerSession associated with the connection.
60 */
61 void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
62
63protected:
64 /// List of sessions that are connected to this handler.
65 /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
66 // for the duration of the connection.
67 std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
68};
69
70/**
71 * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a 31 * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a
72 * table mapping header ids to handler functions. 32 * table mapping header ids to handler functions.
73 */ 33 */
74class Interface : public SessionRequestHandler { 34class Interface : public Kernel::SessionRequestHandler {
75public: 35public:
76 /** 36 /**
77 * Creates an HLE interface with the specified max sessions. 37 * Creates an HLE interface with the specified max sessions.
@@ -149,8 +109,6 @@ void Shutdown();
149 109
150/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. 110/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
151extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; 111extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
152/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
153extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
154 112
155/// Adds a service to the services table 113/// Adds a service to the services table
156void AddService(Interface* interface_); 114void AddService(Interface* interface_);
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
new file mode 100644
index 000000000..361f7a0a9
--- /dev/null
+++ b/src/core/hle/service/sm/sm.cpp
@@ -0,0 +1,59 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <tuple>
6#include "core/hle/kernel/client_port.h"
7#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/server_port.h"
9#include "core/hle/result.h"
10#include "core/hle/service/sm/sm.h"
11
12namespace Service {
13namespace SM {
14
15static ResultCode ValidateServiceName(const std::string& name) {
16 if (name.size() <= 0 || name.size() > 8) {
17 return ERR_INVALID_NAME_SIZE;
18 }
19 if (name.find('\0') != std::string::npos) {
20 return ERR_NAME_CONTAINS_NUL;
21 }
22 return RESULT_SUCCESS;
23}
24
25ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService(
26 std::string name, unsigned int max_sessions) {
27
28 CASCADE_CODE(ValidateServiceName(name));
29 Kernel::SharedPtr<Kernel::ServerPort> server_port;
30 Kernel::SharedPtr<Kernel::ClientPort> client_port;
31 std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name);
32
33 registered_services.emplace(name, std::move(client_port));
34 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
35}
36
37ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
38 const std::string& name) {
39
40 CASCADE_CODE(ValidateServiceName(name));
41 auto it = registered_services.find(name);
42 if (it == registered_services.end()) {
43 return ERR_SERVICE_NOT_REGISTERED;
44 }
45
46 return MakeResult<Kernel::SharedPtr<Kernel::ClientPort>>(it->second);
47}
48
49ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService(
50 const std::string& name) {
51
52 CASCADE_RESULT(auto client_port, GetServicePort(name));
53 return client_port->Connect();
54}
55
56std::unique_ptr<ServiceManager> g_service_manager;
57
58} // namespace SM
59} // namespace Service
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
new file mode 100644
index 000000000..5fac5455c
--- /dev/null
+++ b/src/core/hle/service/sm/sm.h
@@ -0,0 +1,49 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include <unordered_map>
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/result.h"
11#include "core/hle/service/service.h"
12
13namespace Kernel {
14class ClientPort;
15class ClientSession;
16class ServerPort;
17class SessionRequestHandler;
18} // namespace Kernel
19
20namespace Service {
21namespace SM {
22
23constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(1, ErrorModule::SRV, ErrorSummary::WouldBlock,
24 ErrorLevel::Temporary); // 0xD0406401
25constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(2, ErrorModule::SRV, ErrorSummary::WouldBlock,
26 ErrorLevel::Temporary); // 0xD0406402
27constexpr ResultCode ERR_INVALID_NAME_SIZE(5, ErrorModule::SRV, ErrorSummary::WrongArgument,
28 ErrorLevel::Permanent); // 0xD9006405
29constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::InvalidArgument,
30 ErrorLevel::Permanent); // 0xD8E06406
31constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument,
32 ErrorLevel::Permanent); // 0xD9006407
33
34class ServiceManager {
35public:
36 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
37 unsigned int max_sessions);
38 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
39 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
40
41private:
42 /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
43 std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services;
44};
45
46extern std::unique_ptr<ServiceManager> g_service_manager;
47
48} // namespace SM
49} // namespace Service
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/sm/srv.cpp
index 130c9d25e..063b1b0fc 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -6,15 +6,21 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/hle/ipc.h"
10#include "core/hle/kernel/client_port.h"
9#include "core/hle/kernel/client_session.h" 11#include "core/hle/kernel/client_session.h"
10#include "core/hle/kernel/event.h" 12#include "core/hle/kernel/handle_table.h"
13#include "core/hle/kernel/semaphore.h"
11#include "core/hle/kernel/server_session.h" 14#include "core/hle/kernel/server_session.h"
12#include "core/hle/service/srv.h" 15#include "core/hle/service/sm/sm.h"
16#include "core/hle/service/sm/srv.h"
13 17
14namespace Service { 18namespace Service {
15namespace SRV { 19namespace SM {
16 20
17static Kernel::SharedPtr<Kernel::Event> event_handle; 21constexpr int MAX_PENDING_NOTIFICATIONS = 16;
22
23static Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore;
18 24
19/** 25/**
20 * SRV::RegisterClient service function 26 * SRV::RegisterClient service function
@@ -51,14 +57,13 @@ static void RegisterClient(Interface* self) {
51static void EnableNotification(Interface* self) { 57static void EnableNotification(Interface* self) {
52 u32* cmd_buff = Kernel::GetCommandBuffer(); 58 u32* cmd_buff = Kernel::GetCommandBuffer();
53 59
54 // TODO(bunnei): Change to a semaphore once these have been implemented 60 notification_semaphore =
55 event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); 61 Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap();
56 event_handle->Clear();
57 62
58 cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 63 cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042
59 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 64 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
60 cmd_buff[2] = IPC::CopyHandleDesc(1); 65 cmd_buff[2] = IPC::CopyHandleDesc(1);
61 cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); 66 cmd_buff[3] = Kernel::g_handle_table.Create(notification_semaphore).MoveFrom();
62 LOG_WARNING(Service_SRV, "(STUBBED) called"); 67 LOG_WARNING(Service_SRV, "(STUBBED) called");
63} 68}
64 69
@@ -77,25 +82,41 @@ static void GetServiceHandle(Interface* self) {
77 ResultCode res = RESULT_SUCCESS; 82 ResultCode res = RESULT_SUCCESS;
78 u32* cmd_buff = Kernel::GetCommandBuffer(); 83 u32* cmd_buff = Kernel::GetCommandBuffer();
79 84
80 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 85 size_t name_len = cmd_buff[3];
81 auto it = Service::g_srv_services.find(port_name); 86 if (name_len > Service::kMaxPortSize) {
87 cmd_buff[1] = ERR_INVALID_NAME_SIZE.raw;
88 LOG_ERROR(Service_SRV, "called name_len=0x%X, failed with code=0x%08X", name_len,
89 cmd_buff[1]);
90 return;
91 }
92 std::string name(reinterpret_cast<const char*>(&cmd_buff[1]), name_len);
93 bool return_port_on_failure = (cmd_buff[4] & 1) == 0;
82 94
83 if (it != Service::g_srv_services.end()) { 95 // TODO(yuriks): Permission checks go here
84 auto client_port = it->second;
85 96
86 auto client_session = client_port->Connect(); 97 auto client_port = g_service_manager->GetServicePort(name);
87 res = client_session.Code(); 98 if (client_port.Failed()) {
99 cmd_buff[1] = client_port.Code().raw;
100 LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(),
101 cmd_buff[1]);
102 return;
103 }
88 104
89 if (client_session.Succeeded()) { 105 auto session = client_port.Unwrap()->Connect();
90 // Return the client session 106 cmd_buff[1] = session.Code().raw;
91 cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); 107 if (session.Succeeded()) {
92 } 108 cmd_buff[3] = Kernel::g_handle_table.Create(session.MoveFrom()).MoveFrom();
93 LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); 109 LOG_DEBUG(Service_SRV, "called service=%s, session handle=0x%08X", name.c_str(),
110 cmd_buff[3]);
111 } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED && return_port_on_failure) {
112 cmd_buff[1] = ERR_MAX_CONNECTIONS_REACHED.raw;
113 cmd_buff[3] = Kernel::g_handle_table.Create(client_port.MoveFrom()).MoveFrom();
114 LOG_WARNING(Service_SRV, "called service=%s, *port* handle=0x%08X", name.c_str(),
115 cmd_buff[3]);
94 } else { 116 } else {
95 LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); 117 LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(),
96 res = UnimplementedFunction(ErrorModule::SRV); 118 cmd_buff[1]);
97 } 119 }
98 cmd_buff[1] = res.raw;
99} 120}
100 121
101/** 122/**
@@ -177,12 +198,12 @@ const Interface::FunctionInfo FunctionTable[] = {
177 198
178SRV::SRV() { 199SRV::SRV() {
179 Register(FunctionTable); 200 Register(FunctionTable);
180 event_handle = nullptr; 201 notification_semaphore = nullptr;
181} 202}
182 203
183SRV::~SRV() { 204SRV::~SRV() {
184 event_handle = nullptr; 205 notification_semaphore = nullptr;
185} 206}
186 207
187} // namespace SRV 208} // namespace SM
188} // namespace Service 209} // namespace Service
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/sm/srv.h
index d3a9de879..4196ca1e2 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/sm/srv.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Service { 10namespace Service {
10namespace SRV { 11namespace SM {
11 12
12/// Interface to "srv:" service 13/// Interface to "srv:" service
13class SRV final : public Interface { 14class SRV final : public Interface {
@@ -20,5 +21,5 @@ public:
20 } 21 }
21}; 22};
22 23
23} // namespace SRV 24} // namespace SM
24} // namespace Service 25} // namespace Service
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 530614e6f..3d215d42d 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -11,6 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/scope_exit.h" 13#include "common/scope_exit.h"
14#include "core/hle/ipc.h"
14#include "core/hle/kernel/server_session.h" 15#include "core/hle/kernel/server_session.h"
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16#include "core/hle/service/soc_u.h" 17#include "core/hle/service/soc_u.h"
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index 09ced9d7a..300acca75 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -4,7 +4,9 @@
4 4
5#include <random> 5#include <random>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/hle/ipc.h"
7#include "core/hle/service/ssl_c.h" 8#include "core/hle/service/ssl_c.h"
9#include "core/memory.h"
8 10
9namespace Service { 11namespace Service {
10namespace SSL { 12namespace SSL {
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index c0837d49d..bb7bf2d67 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -6,6 +6,8 @@
6#include "common/common_funcs.h" 6#include "common/common_funcs.h"
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/hle/ipc.h"
10#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 11#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
11#include "core/hle/service/y2r_u.h" 13#include "core/hle/service/y2r_u.h"
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 30230d65a..e68b9f16a 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <cinttypes> 6#include <cinttypes>
6#include <map> 7#include <map>
7#include "common/logging/log.h" 8#include "common/logging/log.h"
@@ -16,6 +17,7 @@
16#include "core/hle/kernel/client_session.h" 17#include "core/hle/kernel/client_session.h"
17#include "core/hle/kernel/errors.h" 18#include "core/hle/kernel/errors.h"
18#include "core/hle/kernel/event.h" 19#include "core/hle/kernel/event.h"
20#include "core/hle/kernel/handle_table.h"
19#include "core/hle/kernel/memory.h" 21#include "core/hle/kernel/memory.h"
20#include "core/hle/kernel/mutex.h" 22#include "core/hle/kernel/mutex.h"
21#include "core/hle/kernel/process.h" 23#include "core/hle/kernel/process.h"
@@ -27,6 +29,7 @@
27#include "core/hle/kernel/thread.h" 29#include "core/hle/kernel/thread.h"
28#include "core/hle/kernel/timer.h" 30#include "core/hle/kernel/timer.h"
29#include "core/hle/kernel/vm_manager.h" 31#include "core/hle/kernel/vm_manager.h"
32#include "core/hle/kernel/wait_object.h"
30#include "core/hle/result.h" 33#include "core/hle/result.h"
31#include "core/hle/service/service.h" 34#include "core/hle/service/service.h"
32 35
@@ -244,7 +247,7 @@ static ResultCode CloseHandle(Kernel::Handle handle) {
244 247
245/// Wait for a handle to synchronize, timeout after the specified nanoseconds 248/// Wait for a handle to synchronize, timeout after the specified nanoseconds
246static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) { 249static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) {
247 auto object = Kernel::g_handle_table.GetWaitObject(handle); 250 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle);
248 Kernel::Thread* thread = Kernel::GetCurrentThread(); 251 Kernel::Thread* thread = Kernel::GetCurrentThread();
249 252
250 if (object == nullptr) 253 if (object == nullptr)
@@ -299,7 +302,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
299 std::vector<ObjectPtr> objects(handle_count); 302 std::vector<ObjectPtr> objects(handle_count);
300 303
301 for (int i = 0; i < handle_count; ++i) { 304 for (int i = 0; i < handle_count; ++i) {
302 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 305 auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]);
303 if (object == nullptr) 306 if (object == nullptr)
304 return ERR_INVALID_HANDLE; 307 return ERR_INVALID_HANDLE;
305 objects[i] = object; 308 objects[i] = object;
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 1d80766ae..48bbf687d 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -8,6 +8,7 @@
8#include <initializer_list> 8#include <initializer_list>
9#include <memory> 9#include <memory>
10#include <string> 10#include <string>
11#include <utility>
11#include <vector> 12#include <vector>
12#include <boost/optional.hpp> 13#include <boost/optional.hpp>
13#include "common/common_types.h" 14#include "common/common_types.h"
@@ -100,11 +101,11 @@ public:
100 * Loads the system mode that this application needs. 101 * Loads the system mode that this application needs.
101 * This function defaults to 2 (96MB allocated to the application) if it can't read the 102 * This function defaults to 2 (96MB allocated to the application) if it can't read the
102 * information. 103 * information.
103 * @returns Optional with the kernel system mode 104 * @returns A pair with the optional system mode, and and the status.
104 */ 105 */
105 virtual boost::optional<u32> LoadKernelSystemMode() { 106 virtual std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() {
106 // 96MB allocated to the application. 107 // 96MB allocated to the application.
107 return 2; 108 return std::make_pair(2, ResultStatus::Success);
108 } 109 }
109 110
110 /** 111 /**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index beeb13ffa..ffc019560 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -121,12 +121,16 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
121 return FileType::Error; 121 return FileType::Error;
122} 122}
123 123
124boost::optional<u32> AppLoader_NCCH::LoadKernelSystemMode() { 124std::pair<boost::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() {
125 if (!is_loaded) { 125 if (!is_loaded) {
126 if (LoadExeFS() != ResultStatus::Success) 126 ResultStatus res = LoadExeFS();
127 return boost::none; 127 if (res != ResultStatus::Success) {
128 return std::make_pair(boost::none, res);
129 }
128 } 130 }
129 return exheader_header.arm11_system_local_caps.system_mode.Value(); 131 // Set the system mode as the one from the exheader.
132 return std::make_pair(exheader_header.arm11_system_local_caps.system_mode.Value(),
133 ResultStatus::Success);
130} 134}
131 135
132ResultStatus AppLoader_NCCH::LoadExec() { 136ResultStatus AppLoader_NCCH::LoadExec() {
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 4ef95b5c6..0ebd47fd5 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -179,9 +179,9 @@ public:
179 179
180 /** 180 /**
181 * Loads the Exheader and returns the system mode for this application. 181 * Loads the Exheader and returns the system mode for this application.
182 * @return Optional with the kernel system mode 182 * @returns A pair with the optional system mode, and and the status.
183 */ 183 */
184 boost::optional<u32> LoadKernelSystemMode() override; 184 std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() override;
185 185
186 ResultStatus ReadCode(std::vector<u8>& buffer) override; 186 ResultStatus ReadCode(std::vector<u8>& buffer) override;
187 187
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index 5b306e42e..e3e36ada7 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -13,7 +13,6 @@ set(HEADERS
13if(SDL2_FOUND) 13if(SDL2_FOUND)
14 set(SRCS ${SRCS} sdl/sdl.cpp) 14 set(SRCS ${SRCS} sdl/sdl.cpp)
15 set(HEADERS ${HEADERS} sdl/sdl.h) 15 set(HEADERS ${HEADERS} sdl/sdl.h)
16 include_directories(${SDL2_INCLUDE_DIR})
17endif() 16endif()
18 17
19create_directory_groups(${SRCS} ${HEADERS}) 18create_directory_groups(${SRCS} ${HEADERS})
@@ -22,6 +21,6 @@ add_library(input_common STATIC ${SRCS} ${HEADERS})
22target_link_libraries(input_common PUBLIC core PRIVATE common) 21target_link_libraries(input_common PUBLIC core PRIVATE common)
23 22
24if(SDL2_FOUND) 23if(SDL2_FOUND)
25 target_link_libraries(input_common PRIVATE ${SDL2_LIBRARY}) 24 target_link_libraries(input_common PRIVATE SDL2)
26 target_compile_definitions(input_common PRIVATE HAVE_SDL2) 25 target_compile_definitions(input_common PRIVATE HAVE_SDL2)
27endif() 26endif()
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 85f2f2985..00d7c636a 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -10,11 +10,9 @@ set(HEADERS
10 10
11create_directory_groups(${SRCS} ${HEADERS}) 11create_directory_groups(${SRCS} ${HEADERS})
12 12
13include_directories(../../externals/catch/single_include/)
14
15add_executable(tests ${SRCS} ${HEADERS}) 13add_executable(tests ${SRCS} ${HEADERS})
16target_link_libraries(tests PRIVATE common core) 14target_link_libraries(tests PRIVATE common core)
17target_link_libraries(tests PRIVATE glad) # To support linker work-around 15target_link_libraries(tests PRIVATE glad) # To support linker work-around
18target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 16target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads)
19 17
20add_test(NAME tests COMMAND $<TARGET_FILE:tests>) 18add_test(NAME tests COMMAND tests)
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index e455f03bd..0961a3251 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -80,14 +80,13 @@ create_directory_groups(${SRCS} ${HEADERS})
80 80
81add_library(video_core STATIC ${SRCS} ${HEADERS}) 81add_library(video_core STATIC ${SRCS} ${HEADERS})
82target_link_libraries(video_core PUBLIC common core) 82target_link_libraries(video_core PUBLIC common core)
83target_link_libraries(video_core PRIVATE glad) 83target_link_libraries(video_core PRIVATE glad nihstro-headers)
84 84
85if (ARCHITECTURE_x86_64) 85if (ARCHITECTURE_x86_64)
86 target_link_libraries(video_core PRIVATE xbyak) 86 target_link_libraries(video_core PRIVATE xbyak)
87endif() 87endif()
88 88
89if (PNG_FOUND) 89if (PNG_FOUND)
90 target_link_libraries(video_core PRIVATE ${PNG_LIBRARIES}) 90 target_link_libraries(video_core PRIVATE PNG::PNG)
91 target_include_directories(video_core PRIVATE ${PNG_INCLUDE_DIRS}) 91 target_compile_definitions(video_core PRIVATE HAVE_PNG)
92 target_compile_definitions(video_core PRIVATE ${PNG_DEFINITIONS})
93endif() 92endif()
diff --git a/src/video_core/regs_texturing.h b/src/video_core/regs_texturing.h
index e4038b41b..3f5355fa9 100644
--- a/src/video_core/regs_texturing.h
+++ b/src/video_core/regs_texturing.h
@@ -133,7 +133,32 @@ struct TexturingRegs {
133 BitField<16, 1, u32> clear_texture_cache; // TODO: unimplemented 133 BitField<16, 1, u32> clear_texture_cache; // TODO: unimplemented
134 } main_config; 134 } main_config;
135 TextureConfig texture0; 135 TextureConfig texture0;
136 INSERT_PADDING_WORDS(0x8); 136
137 enum class CubeFace {
138 PositiveX = 0,
139 NegativeX = 1,
140 PositiveY = 2,
141 NegativeY = 3,
142 PositiveZ = 4,
143 NegativeZ = 5,
144 };
145
146 BitField<0, 22, u32> cube_address[5];
147
148 PAddr GetCubePhysicalAddress(CubeFace face) const {
149 PAddr address = texture0.address;
150 if (face != CubeFace::PositiveX) {
151 // Bits [22:27] from the main texture address is shared with all cubemap additional
152 // addresses.
153 auto& face_addr = cube_address[static_cast<size_t>(face) - 1];
154 address &= ~face_addr.mask;
155 address |= face_addr;
156 }
157 // A multiplier of 8 is also needed in the same way as the main address.
158 return address * 8;
159 }
160
161 INSERT_PADDING_WORDS(0x3);
137 BitField<0, 4, TextureFormat> texture0_format; 162 BitField<0, 4, TextureFormat> texture0_format;
138 BitField<0, 1, u32> fragment_lighting_enable; 163 BitField<0, 1, u32> fragment_lighting_enable;
139 INSERT_PADDING_WORDS(0x1); 164 INSERT_PADDING_WORDS(0x1);
diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp
index e9edf0360..8b7b1defb 100644
--- a/src/video_core/swrasterizer/rasterizer.cpp
+++ b/src/video_core/swrasterizer/rasterizer.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <cmath> 7#include <cmath>
8#include <tuple>
8#include "common/assert.h" 9#include "common/assert.h"
9#include "common/bit_field.h" 10#include "common/bit_field.h"
10#include "common/color.h" 11#include "common/color.h"
@@ -70,6 +71,49 @@ static int SignedArea(const Math::Vec2<Fix12P4>& vtx1, const Math::Vec2<Fix12P4>
70 return Math::Cross(vec1, vec2).z; 71 return Math::Cross(vec1, vec2).z;
71}; 72};
72 73
74/// Convert a 3D vector for cube map coordinates to 2D texture coordinates along with the face name
75static std::tuple<float24, float24, PAddr> ConvertCubeCoord(float24 u, float24 v, float24 w,
76 const TexturingRegs& regs) {
77 const float abs_u = std::abs(u.ToFloat32());
78 const float abs_v = std::abs(v.ToFloat32());
79 const float abs_w = std::abs(w.ToFloat32());
80 float24 x, y, z;
81 PAddr addr;
82 if (abs_u > abs_v && abs_u > abs_w) {
83 if (u > float24::FromFloat32(0)) {
84 addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveX);
85 y = -v;
86 } else {
87 addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeX);
88 y = v;
89 }
90 x = -w;
91 z = u;
92 } else if (abs_v > abs_w) {
93 if (v > float24::FromFloat32(0)) {
94 addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveY);
95 x = u;
96 } else {
97 addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeY);
98 x = -u;
99 }
100 y = w;
101 z = v;
102 } else {
103 if (w > float24::FromFloat32(0)) {
104 addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::PositiveZ);
105 y = -v;
106 } else {
107 addr = regs.GetCubePhysicalAddress(TexturingRegs::CubeFace::NegativeZ);
108 y = v;
109 }
110 x = u;
111 z = w;
112 }
113 const float24 half = float24::FromFloat32(0.5f);
114 return std::make_tuple(x / z * half + half, y / z * half + half, addr);
115}
116
73MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240)); 117MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240));
74 118
75/** 119/**
@@ -284,10 +328,16 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
284 328
285 // Only unit 0 respects the texturing type (according to 3DBrew) 329 // Only unit 0 respects the texturing type (according to 3DBrew)
286 // TODO: Refactor so cubemaps and shadowmaps can be handled 330 // TODO: Refactor so cubemaps and shadowmaps can be handled
331 PAddr texture_address = texture.config.GetPhysicalAddress();
287 if (i == 0) { 332 if (i == 0) {
288 switch (texture.config.type) { 333 switch (texture.config.type) {
289 case TexturingRegs::TextureConfig::Texture2D: 334 case TexturingRegs::TextureConfig::Texture2D:
290 break; 335 break;
336 case TexturingRegs::TextureConfig::TextureCube: {
337 auto w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
338 std::tie(u, v, texture_address) = ConvertCubeCoord(u, v, w, regs.texturing);
339 break;
340 }
291 case TexturingRegs::TextureConfig::Projection2D: { 341 case TexturingRegs::TextureConfig::Projection2D: {
292 auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w); 342 auto tc0_w = GetInterpolatedAttribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
293 u /= tc0_w; 343 u /= tc0_w;
@@ -322,8 +372,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
322 t = texture.config.height - 1 - 372 t = texture.config.height - 1 -
323 GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); 373 GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
324 374
325 u8* texture_data = 375 const u8* texture_data = Memory::GetPhysicalPointer(texture_address);
326 Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
327 auto info = 376 auto info =
328 Texture::TextureInfo::FromPicaRegister(texture.config, texture.format); 377 Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
329 378