diff options
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 | ||
| 3 | Please read the FAQ: | 3 | Please read the FAQ: |
| 4 | https://citra-emu.org/wiki/FAQ | 4 | https://citra-emu.org/wiki/faq/ |
| 5 | 5 | ||
| 6 | THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO: | 6 | THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO: |
| 7 | https://community.citra-emu.org/ | 7 | https://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 |
| 2 | cmake_minimum_required(VERSION 3.2) | 2 | cmake_minimum_required(VERSION 3.6) |
| 3 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) | 3 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") |
| 4 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules") | ||
| 4 | 5 | ||
| 5 | function(download_bundled_external remote_path lib_name prefix_var) | 6 | project(citra) |
| 6 | set(prefix "${CMAKE_BINARY_DIR}/externals/${lib_name}") | 7 | |
| 7 | if (NOT EXISTS "${prefix}") | 8 | option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) |
| 8 | message(STATUS "Downloading binaries for ${lib_name}...") | 9 | option(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 | 11 | option(ENABLE_QT "Enable the Qt frontend" ON) |
| 11 | "${CMAKE_BINARY_DIR}/externals/${lib_name}.7z" SHOW_PROGRESS) | 12 | option(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") | 14 | if(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) |
| 17 | endfunction() | 18 | endif() |
| 19 | |||
| 20 | |||
| 21 | # Detect current compilation architecture and create standard definitions | ||
| 22 | # ======================================================================= | ||
| 18 | 23 | ||
| 19 | include(CheckSymbolExists) | 24 | include(CheckSymbolExists) |
| 20 | function(detect_architecture symbol arch) | 25 | function(detect_architecture symbol arch) |
| @@ -33,20 +38,6 @@ function(detect_architecture symbol arch) | |||
| 33 | endif() | 38 | endif() |
| 34 | endfunction() | 39 | endfunction() |
| 35 | 40 | ||
| 36 | project(citra) | ||
| 37 | |||
| 38 | option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) | ||
| 39 | option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF) | ||
| 40 | |||
| 41 | option(ENABLE_QT "Enable the Qt frontend" ON) | ||
| 42 | option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF) | ||
| 43 | |||
| 44 | if(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) | ||
| 48 | endif() | ||
| 49 | |||
| 50 | if (MSVC) | 41 | if (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) | |||
| 63 | endif() | 54 | endif() |
| 64 | message(STATUS "Target architecture: ${ARCHITECTURE}") | 55 | message(STATUS "Target architecture: ${ARCHITECTURE}") |
| 65 | 56 | ||
| 57 | |||
| 58 | # Configure compilation flags | ||
| 59 | # =========================== | ||
| 60 | |||
| 66 | set(CMAKE_CXX_STANDARD 14) | 61 | set(CMAKE_CXX_STANDARD 14) |
| 67 | set(CMAKE_CXX_STANDARD_REQUIRED ON) | 62 | set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 68 | 63 | ||
| @@ -130,28 +125,44 @@ add_definitions(-DSINGLETHREADED) | |||
| 130 | set_property(DIRECTORY APPEND PROPERTY | 125 | set_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 | ||
| 136 | function(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) | ||
| 148 | endfunction() | ||
| 149 | |||
| 133 | find_package(PNG QUIET) | 150 | find_package(PNG QUIET) |
| 134 | if (PNG_FOUND) | 151 | if (NOT PNG_FOUND) |
| 135 | add_definitions(-DHAVE_PNG) | ||
| 136 | else() | ||
| 137 | message(STATUS "libpng not found. Some debugging features have been disabled.") | 152 | message(STATUS "libpng not found. Some debugging features have been disabled.") |
| 138 | endif() | 153 | endif() |
| 139 | 154 | ||
| 140 | find_package(Boost 1.57.0 QUIET) | 155 | find_package(Boost 1.63.0 QUIET) |
| 141 | if (NOT Boost_FOUND) | 156 | if (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") | ||
| 144 | endif() | ||
| 145 | include_directories(${Boost_INCLUDE_DIR}) | ||
| 146 | |||
| 147 | # Include bundled CMake modules | ||
| 148 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/externals/cmake-modules") | ||
| 149 | 158 | ||
| 150 | find_package(OpenGL REQUIRED) | 159 | set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost") |
| 151 | include_directories(${OPENGL_INCLUDE_DIR}) | 160 | set(Boost_NO_SYSTEM_PATHS OFF) |
| 161 | find_package(Boost QUIET REQUIRED) | ||
| 162 | endif() | ||
| 152 | 163 | ||
| 153 | # Prefer the -pthread flag on Linux. | 164 | # Prefer the -pthread flag on Linux. |
| 154 | set (THREADS_PREFER_PTHREAD_FLAG ON) | 165 | set(THREADS_PREFER_PTHREAD_FLAG ON) |
| 155 | find_package(Threads REQUIRED) | 166 | find_package(Threads REQUIRED) |
| 156 | 167 | ||
| 157 | if (ENABLE_SDL2) | 168 | if (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() | ||
| 177 | else() | 195 | else() |
| 178 | set(SDL2_FOUND NO) | 196 | set(SDL2_FOUND NO) |
| 179 | endif() | 197 | endif() |
| 180 | 198 | ||
| 199 | if (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}) | ||
| 219 | endif() | ||
| 220 | |||
| 221 | |||
| 222 | # Platform-specific library requirements | ||
| 223 | # ====================================== | ||
| 224 | |||
| 181 | IF (APPLE) | 225 | IF (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() |
| 207 | endif() | 251 | endif() |
| 208 | 252 | ||
| 209 | if (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) | ||
| 230 | endif() | ||
| 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) | |||
| 251 | git_describe(GIT_DESC --always --long --dirty) | 276 | git_describe(GIT_DESC --always --long --dirty) |
| 252 | git_branch_name(GIT_BRANCH) | 277 | git_branch_name(GIT_BRANCH) |
| 253 | 278 | ||
| 254 | set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih") | ||
| 255 | include_directories(${INI_PREFIX}) | ||
| 256 | add_subdirectory(${INI_PREFIX}) | ||
| 257 | |||
| 258 | add_subdirectory(externals) | 279 | add_subdirectory(externals) |
| 259 | 280 | add_subdirectory(src) | |
| 260 | option(DYNARMIC_TESTS OFF) | ||
| 261 | set(DYNARMIC_NO_BUNDLED_FMT ON) | ||
| 262 | add_subdirectory(externals/dynarmic) | ||
| 263 | |||
| 264 | add_subdirectory(externals/glad) | ||
| 265 | include_directories(externals/microprofile) | ||
| 266 | include_directories(externals/nihstro/include) | ||
| 267 | |||
| 268 | if (MSVC) | ||
| 269 | add_subdirectory(externals/getopt) | ||
| 270 | endif() | ||
| 271 | |||
| 272 | # process subdirectories | ||
| 273 | add_subdirectory(externals/soundtouch) | ||
| 274 | |||
| 275 | enable_testing() | 281 | enable_testing() |
| 276 | 282 | ||
| 277 | add_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 |
| @@ -7,7 +7,7 @@ Citra Emulator | |||
| 7 | 7 | ||
| 8 | Citra 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. | 8 | Citra 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 | ||
| 10 | Citra 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. | 10 | Citra 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 | ||
| 12 | Check out our [website](https://citra-emu.org/)! | 12 | Check 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 | ||
| 4 | add_library(catch-single-include INTERFACE) | ||
| 5 | target_include_directories(catch-single-include INTERFACE catch/single_include) | ||
| 6 | |||
| 7 | # Crypto++ | ||
| 8 | add_subdirectory(cryptopp) | ||
| 9 | |||
| 10 | # Dynarmic | ||
| 11 | # Dynarmic will skip defining xbyak if it's already defined, we then define it below | ||
| 12 | add_library(xbyak INTERFACE) | ||
| 13 | option(DYNARMIC_TESTS OFF) | ||
| 14 | set(DYNARMIC_NO_BUNDLED_FMT ON) | ||
| 15 | add_subdirectory(dynarmic) | ||
| 16 | |||
| 17 | # libfmt | ||
| 18 | add_subdirectory(fmt) | ||
| 19 | |||
| 20 | # getopt | ||
| 21 | if (MSVC) | ||
| 22 | add_subdirectory(getopt) | ||
| 23 | endif() | ||
| 24 | |||
| 25 | # Glad | ||
| 26 | add_subdirectory(glad) | ||
| 27 | |||
| 28 | # inih | ||
| 29 | add_subdirectory(inih) | ||
| 30 | |||
| 31 | # MicroProfile | ||
| 32 | add_library(microprofile INTERFACE) | ||
| 33 | target_include_directories(microprofile INTERFACE ./microprofile) | ||
| 34 | |||
| 35 | # Nihstro | ||
| 36 | add_library(nihstro-headers INTERFACE) | ||
| 37 | target_include_directories(nihstro-headers INTERFACE ./nihstro/include) | ||
| 38 | |||
| 39 | # SoundTouch | ||
| 40 | add_subdirectory(soundtouch) | ||
| 41 | # The SoundTouch target doesn't export the necessary include paths as properties by default | ||
| 42 | target_include_directories(SoundTouch INTERFACE ./soundtouch/include) | ||
| 43 | |||
| 1 | # Xbyak | 44 | # Xbyak |
| 2 | if (ARCHITECTURE_x86_64) | 45 | if (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() |
| 8 | endif() | 52 | endif() |
| 9 | |||
| 10 | add_subdirectory(cryptopp) | ||
| 11 | |||
| 12 | add_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 | ||
| 14 | include(TestBigEndian) | 15 | include(TestBigEndian) |
| 15 | include(CheckCXXCompilerFlag) | 16 | include(CheckCXXCompilerFlag) |
| @@ -148,14 +149,15 @@ endif() | |||
| 148 | # Compile targets | 149 | # Compile targets |
| 149 | #============================================================================ | 150 | #============================================================================ |
| 150 | add_library(cryptopp STATIC ${cryptopp_SOURCES}) | 151 | add_library(cryptopp STATIC ${cryptopp_SOURCES}) |
| 152 | target_include_directories(cryptopp INTERFACE .) | ||
| 151 | 153 | ||
| 152 | #============================================================================ | 154 | #============================================================================ |
| 153 | # Third-party libraries | 155 | # Third-party libraries |
| 154 | #============================================================================ | 156 | #============================================================================ |
| 155 | 157 | ||
| 156 | if(WIN32) | 158 | if(WIN32) |
| 157 | target_link_libraries(cryptopp ws2_32) | 159 | target_link_libraries(cryptopp PRIVATE ws2_32) |
| 158 | endif() | 160 | endif() |
| 159 | 161 | ||
| 160 | find_package(Threads) | 162 | find_package(Threads) |
| 161 | target_link_libraries(cryptopp ${CMAKE_THREAD_LIBS_INIT}) | 163 | target_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 | |||
| 9 | create_directory_groups(${SRCS} ${HEADERS}) | 9 | create_directory_groups(${SRCS} ${HEADERS}) |
| 10 | add_library(glad STATIC ${SRCS} ${HEADERS}) | 10 | add_library(glad STATIC ${SRCS} ${HEADERS}) |
| 11 | target_include_directories(glad PUBLIC "include/") | 11 | target_include_directories(glad PUBLIC "include/") |
| 12 | |||
| 12 | if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") | 13 | if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") |
| 13 | target_link_libraries(glad dl) | 14 | target_link_libraries(glad PRIVATE dl) |
| 14 | endif() | 15 | endif() |
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 | ||
| 10 | create_directory_groups(${SRCS} ${HEADERS}) | 10 | create_directory_groups(${SRCS} ${HEADERS}) |
| 11 | add_library(inih ${SRCS} ${HEADERS}) | 11 | add_library(inih ${SRCS} ${HEADERS}) |
| 12 | target_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 | ||
| 30 | include_directories(../../externals/soundtouch/include) | ||
| 31 | |||
| 32 | if(SDL2_FOUND) | 30 | if(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}) | ||
| 36 | endif() | 33 | endif() |
| 37 | 34 | ||
| 38 | create_directory_groups(${SRCS} ${HEADERS}) | 35 | create_directory_groups(${SRCS} ${HEADERS}) |
| @@ -42,6 +39,6 @@ target_link_libraries(audio_core PUBLIC common core) | |||
| 42 | target_link_libraries(audio_core PRIVATE SoundTouch) | 39 | target_link_libraries(audio_core PRIVATE SoundTouch) |
| 43 | 40 | ||
| 44 | if(SDL2_FOUND) | 41 | if(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) |
| 47 | endif() | 44 | endif() |
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 | ||
| 16 | create_directory_groups(${SRCS} ${HEADERS}) | 16 | create_directory_groups(${SRCS} ${HEADERS}) |
| 17 | 17 | ||
| 18 | include_directories(${SDL2_INCLUDE_DIR}) | ||
| 19 | |||
| 20 | add_executable(citra ${SRCS} ${HEADERS}) | 18 | add_executable(citra ${SRCS} ${HEADERS}) |
| 21 | target_link_libraries(citra PRIVATE common core input_common) | 19 | target_link_libraries(citra PRIVATE common core input_common) |
| 22 | target_link_libraries(citra PRIVATE ${SDL2_LIBRARY} ${OPENGL_gl_LIBRARY} inih glad) | 20 | target_link_libraries(citra PRIVATE inih glad) |
| 23 | if (MSVC) | 21 | if (MSVC) |
| 24 | target_link_libraries(citra PRIVATE getopt) | 22 | target_link_libraries(citra PRIVATE getopt) |
| 25 | endif() | 23 | endif() |
| 26 | target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 24 | target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads) |
| 27 | 25 | ||
| 28 | if(UNIX AND NOT APPLE) | 26 | if(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}) |
| 93 | endif() | 93 | endif() |
| 94 | target_link_libraries(citra-qt PRIVATE audio_core common core input_common video_core) | 94 | target_link_libraries(citra-qt PRIVATE audio_core common core input_common video_core) |
| 95 | target_link_libraries(citra-qt PRIVATE ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS} glad) | 95 | target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::OpenGL Qt5::Widgets) |
| 96 | target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 96 | target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) |
| 97 | 97 | ||
| 98 | if(UNIX AND NOT APPLE) | 98 | if(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 | ||
| 102 | class GRenderWindow : public QWidget, public EmuWindow { | 105 | class 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 | ||
| 14 | WaitTreeItem::~WaitTreeItem() {} | 15 | WaitTreeItem::~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 | ||
| 531 | void GMainWindow::OnStartGame() { | 553 | void 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 | ||
| 651 | void 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 | |||
| 625 | bool GMainWindow::ConfirmClose() { | 714 | bool 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 | ||
| 13 | class Config; | 14 | class 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 | ||
| 129 | private: | 131 | private: |
| 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() | |||
| 95 | create_directory_groups(${SRCS} ${HEADERS}) | 95 | create_directory_groups(${SRCS} ${HEADERS}) |
| 96 | 96 | ||
| 97 | add_library(common STATIC ${SRCS} ${HEADERS}) | 97 | add_library(common STATIC ${SRCS} ${HEADERS}) |
| 98 | target_link_libraries(common PUBLIC Boost::boost microprofile) | ||
| 98 | if (ARCHITECTURE_x86_64) | 99 | if (ARCHITECTURE_x86_64) |
| 99 | target_link_libraries(common PRIVATE xbyak) | 100 | target_link_libraries(common PRIVATE xbyak) |
| 100 | endif() | 101 | endif() |
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 | ||
| 377 | include_directories(../../externals/dynarmic/include) | ||
| 378 | include_directories(../../externals/cryptopp) | ||
| 379 | |||
| 380 | create_directory_groups(${SRCS} ${HEADERS}) | 385 | create_directory_groups(${SRCS} ${HEADERS}) |
| 381 | |||
| 382 | add_library(core STATIC ${SRCS} ${HEADERS}) | 386 | add_library(core STATIC ${SRCS} ${HEADERS}) |
| 383 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 387 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 384 | target_link_libraries(core PRIVATE cryptopp dynarmic) | 388 | target_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 | ||
| 28 | System::ResultStatus System::RunLoop(int tight_loop) { | 28 | System::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 | ||
| 65 | System::ResultStatus System::SingleStep() { | 66 | System::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 | ||
| 107 | void System::PrepareReschedule() { | 120 | void 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 | |||
| 108 | private: | 122 | private: |
| 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 | ||
| 135 | inline ARM_Interface& CPU() { | 152 | inline 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) | |||
| 33 | ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_NCCH::Open(const Path& path) { | 35 | ResultVal<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 | ||
| 9 | namespace IPC { | 11 | namespace 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 | ||
| 11 | namespace Kernel { | 12 | namespace 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 | ||
| 10 | namespace Kernel { | 12 | namespace 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 | ||
| 14 | namespace Kernel { | 13 | namespace 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 | ||
| 10 | namespace Kernel { | 11 | namespace 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 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | HandleTable g_handle_table; | ||
| 17 | |||
| 18 | HandleTable::HandleTable() { | ||
| 19 | next_generation = 1; | ||
| 20 | Clear(); | ||
| 21 | } | ||
| 22 | |||
| 23 | ResultVal<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 | |||
| 47 | ResultVal<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 | |||
| 56 | ResultCode 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 | |||
| 69 | bool 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 | |||
| 76 | SharedPtr<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 | |||
| 89 | void 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 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | enum 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 | */ | ||
| 43 | class HandleTable final : NonCopyable { | ||
| 44 | public: | ||
| 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 | |||
| 91 | private: | ||
| 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 | |||
| 124 | extern 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 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) { | ||
| 15 | server_session->SetHleHandler(shared_from_this()); | ||
| 16 | connected_sessions.push_back(server_session); | ||
| 17 | } | ||
| 18 | |||
| 19 | void 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 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | class 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 | */ | ||
| 20 | class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { | ||
| 21 | public: | ||
| 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 | |||
| 46 | protected: | ||
| 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 @@ | |||
| 18 | namespace Kernel { | 15 | namespace Kernel { |
| 19 | 16 | ||
| 20 | unsigned int Object::next_object_id; | 17 | unsigned int Object::next_object_id; |
| 21 | HandleTable g_handle_table; | ||
| 22 | |||
| 23 | void 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 | |||
| 29 | void 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 | |||
| 38 | SharedPtr<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 | |||
| 73 | void 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 | |||
| 98 | const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { | ||
| 99 | return waiting_threads; | ||
| 100 | } | ||
| 101 | |||
| 102 | HandleTable::HandleTable() { | ||
| 103 | next_generation = 1; | ||
| 104 | Clear(); | ||
| 105 | } | ||
| 106 | |||
| 107 | ResultVal<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 | |||
| 131 | ResultVal<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 | |||
| 140 | ResultCode 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 | |||
| 153 | bool 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 | |||
| 160 | SharedPtr<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 | |||
| 173 | void 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 |
| 182 | void Init(u32 system_mode) { | 20 | void 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 | ||
| 16 | namespace Kernel { | 13 | namespace Kernel { |
| 17 | 14 | ||
| 18 | using Handle = u32; | 15 | using Handle = u32; |
| 19 | 16 | ||
| 20 | class Thread; | ||
| 21 | |||
| 22 | enum KernelHandle : Handle { | ||
| 23 | CurrentThread = 0xFFFF8000, | ||
| 24 | CurrentProcess = 0xFFFF8001, | ||
| 25 | }; | ||
| 26 | |||
| 27 | enum class HandleType : u32 { | 17 | enum class HandleType : u32 { |
| 28 | Unknown, | 18 | Unknown, |
| 29 | Event, | 19 | Event, |
| @@ -121,170 +111,17 @@ inline void intrusive_ptr_release(Object* object) { | |||
| 121 | template <typename T> | 111 | template <typename T> |
| 122 | using SharedPtr = boost::intrusive_ptr<T>; | 112 | using SharedPtr = boost::intrusive_ptr<T>; |
| 123 | 113 | ||
| 124 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 125 | class WaitObject : public Object { | ||
| 126 | public: | ||
| 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 | |||
| 161 | private: | ||
| 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 | */ |
| 189 | class HandleTable final : NonCopyable { | 118 | template <typename T> |
| 190 | public: | 119 | inline 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 | |||
| 254 | private: | ||
| 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 | |||
| 287 | extern HandleTable g_handle_table; | ||
| 288 | 125 | ||
| 289 | /// Initialize the kernel with the specified system mode. | 126 | /// Initialize the kernel with the specified system mode. |
| 290 | void Init(u32 system_mode); | 127 | void 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 | ||
| 11 | namespace Kernel { | 12 | namespace 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 | ||
| 12 | namespace Kernel { | 14 | namespace 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 | ||
| 26 | std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( | 26 | std::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" | |
| 13 | namespace Service { | ||
| 14 | class SessionRequestHandler; | ||
| 15 | } | ||
| 16 | 13 | ||
| 17 | namespace Kernel { | 14 | namespace Kernel { |
| 18 | 15 | ||
| 19 | class ClientPort; | 16 | class ClientPort; |
| 17 | class SessionRequestHandler; | ||
| 20 | 18 | ||
| 21 | class ServerPort final : public WaitObject { | 19 | class ServerPort final : public WaitObject { |
| 22 | public: | 20 | public: |
| 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 | ||
| 11 | namespace Kernel { | 14 | namespace Kernel { |
| @@ -25,16 +28,14 @@ ServerSession::~ServerSession() { | |||
| 25 | parent->server = nullptr; | 28 | parent->server = nullptr; |
| 26 | } | 29 | } |
| 27 | 30 | ||
| 28 | ResultVal<SharedPtr<ServerSession>> ServerSession::Create( | 31 | ResultVal<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 | ||
| 40 | bool ServerSession::ShouldWait(Thread* thread) const { | 41 | bool ServerSession::ShouldWait(Thread* thread) const { |
| @@ -68,13 +69,9 @@ ResultCode ServerSession::HandleSyncRequest() { | |||
| 68 | return RESULT_SUCCESS; | 69 | return RESULT_SUCCESS; |
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | ServerSession::SessionPair ServerSession::CreateSessionPair( | 72 | ServerSession::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 | ||
| 18 | namespace Kernel { | 17 | namespace Kernel { |
| @@ -20,6 +19,8 @@ namespace Kernel { | |||
| 20 | class ClientSession; | 19 | class ClientSession; |
| 21 | class ClientPort; | 20 | class ClientPort; |
| 22 | class ServerSession; | 21 | class ServerSession; |
| 22 | class SessionRequestHandler; | ||
| 23 | class 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 | ||
| 77 | private: | 84 | private: |
| @@ -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 | ||
| 17 | enum ThreadPriority : s32 { | 18 | enum 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 | ||
| 10 | namespace Kernel { | 11 | namespace 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 | |||
| 18 | namespace Kernel { | ||
| 19 | |||
| 20 | void 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 | |||
| 26 | void 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 | |||
| 35 | SharedPtr<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 | |||
| 70 | void 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 | |||
| 95 | const 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 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | class Thread; | ||
| 15 | |||
| 16 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 17 | class WaitObject : public Object { | ||
| 18 | public: | ||
| 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 | |||
| 53 | private: | ||
| 54 | /// Threads waiting for this object to become available | ||
| 55 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 56 | }; | ||
| 57 | |||
| 58 | // Specialization of DynamicObjectCast for WaitObjects | ||
| 59 | template <> | ||
| 60 | inline 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 | */ | ||
| 422 | template <typename Arg> | ||
| 423 | ResultVal<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 | ||
| 13 | namespace Service { | 18 | namespace Service { |
| 14 | namespace AC { | 19 | namespace 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 | ||
| 178 | void Init() { | 182 | void 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 | ||
| 23 | namespace Service { | 27 | namespace 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) { | |||
| 225 | template <int max_index> | 229 | template <int max_index> |
| 226 | class CommandParamBitSet : public BitSet8 { | 230 | class CommandParamBitSet : public BitSet8 { |
| 227 | public: | 231 | public: |
| 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 | ||
| 246 | void StartCapture(Service::Interface* self) { | 249 | void 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 | ||
| 281 | void StopCapture(Service::Interface* self) { | 283 | void 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 | ||
| 307 | void IsBusy(Service::Interface* self) { | 308 | void 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 | ||
| 330 | void ClearBuffer(Service::Interface* self) { | 331 | void 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 | ||
| 341 | void GetVsyncInterruptEvent(Service::Interface* self) { | 341 | void 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 | ||
| 363 | void GetBufferErrorInterruptEvent(Service::Interface* self) { | 360 | void 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 | ||
| 384 | void SetReceiving(Service::Interface* self) { | 379 | void 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 | ||
| 420 | void IsFinishedReceiving(Service::Interface* self) { | 414 | void 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 | ||
| 439 | void SetTransferLines(Service::Interface* self) { | 433 | void 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 | ||
| 463 | void GetMaxLines(Service::Interface* self) { | 455 | void 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 | ||
| 495 | void SetTransferBytes(Service::Interface* self) { | 488 | void 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 | ||
| 519 | void GetTransferBytes(Service::Interface* self) { | 510 | void 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 | ||
| 538 | void GetMaxBytes(Service::Interface* self) { | 528 | void 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 | ||
| 564 | void SetTrimming(Service::Interface* self) { | 555 | void 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 | ||
| 585 | void IsTrimming(Service::Interface* self) { | 574 | void 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 | ||
| 604 | void SetTrimmingParams(Service::Interface* self) { | 592 | void 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 | ||
| 632 | void GetTrimmingParams(Service::Interface* self) { | 618 | void 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 | ||
| 654 | void SetTrimmingParamsCenter(Service::Interface* self) { | 639 | void 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 | ||
| 682 | void Activate(Service::Interface* self) { | 665 | void 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 | ||
| 723 | void SwitchContext(Service::Interface* self) { | 704 | void 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 | ||
| 752 | void FlipImage(Service::Interface* self) { | 731 | void 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 | ||
| 781 | void SetDetailSize(Service::Interface* self) { | 758 | void 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 | ||
| 818 | void SetSize(Service::Interface* self) { | 793 | void 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 | ||
| 847 | void SetFrameRate(Service::Interface* self) { | 820 | void 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 | ||
| 870 | void SetEffect(Service::Interface* self) { | 841 | void 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 | ||
| 899 | void SetOutputFormat(Service::Interface* self) { | 868 | void 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 | ||
| 928 | void SynchronizeVsyncTiming(Service::Interface* self) { | 895 | void 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 | ||
| 941 | void GetStereoCameraCalibrationData(Service::Interface* self) { | 907 | void 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 | ||
| 968 | void SetPackageParameterWithoutContext(Service::Interface* self) { | 934 | void 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 | ||
| 980 | template <typename PackageParameterType, int command_id> | 946 | template <typename PackageParameterType> |
| 981 | static void SetPackageParameter() { | 947 | static 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 | ||
| 1017 | Resolution PackageParameterWithContext::GetResolution() { | 974 | Resolution PackageParameterWithContext::GetResolution() const { |
| 1018 | return PRESET_RESOLUTION[static_cast<int>(size)]; | 975 | return PRESET_RESOLUTION[static_cast<int>(size)]; |
| 1019 | } | 976 | } |
| 1020 | 977 | ||
| 1021 | void SetPackageParameterWithContext(Service::Interface* self) { | 978 | void 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 | ||
| 1025 | void SetPackageParameterWithContextDetail(Service::Interface* self) { | 991 | void 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 | ||
| 1029 | void GetSuitableY2rStandardCoefficient(Service::Interface* self) { | 1004 | void 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 | ||
| 1039 | void PlayShutterSound(Service::Interface* self) { | 1013 | void 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 | ||
| 1050 | void DriverInitialize(Service::Interface* self) { | 1023 | void 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 | ||
| 1083 | void DriverFinalize(Service::Interface* self) { | 1056 | void 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 | ||
| 189 | static_assert(sizeof(PackageParameterWithoutContext) == 28, | 190 | static_assert(sizeof(PackageParameterWithoutContext) == 44, |
| 190 | "PackageParameterCameraWithoutContext structure size is wrong"); | 191 | "PackageParameterCameraWithoutContext structure size is wrong"); |
| 191 | 192 | ||
| 192 | struct PackageParameterWithContext { | 193 | struct 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 | ||
| 203 | static_assert(sizeof(PackageParameterWithContext) == 8, | 205 | static_assert(sizeof(PackageParameterWithContext) == 20, |
| 204 | "PackageParameterWithContext structure size is wrong"); | 206 | "PackageParameterWithContext structure size is wrong"); |
| 205 | 207 | ||
| 206 | struct PackageParameterWithContextDetail { | 208 | struct 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 | ||
| 218 | static_assert(sizeof(PackageParameterWithContextDetail) == 16, | 221 | static_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 | ||
| 26 | namespace Service { | 29 | namespace 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 | ||
| 11 | namespace Service { | 14 | namespace Service { |
| 12 | namespace CSND { | 15 | namespace 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 | ||
| 13 | using DspPipe = DSP::HLE::DspPipe; | 19 | using 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 | ||
| 11 | namespace Service { | 16 | namespace Service { |
| 12 | namespace FRD { | 17 | namespace 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& | |||
| 83 | File::~File() {} | 87 | File::~File() {} |
| 84 | 88 | ||
| 85 | void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { | 89 | void 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 | ||
| 14 | namespace FileSys { | 14 | namespace FileSys { |
| @@ -43,7 +43,7 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; | |||
| 43 | 43 | ||
| 44 | typedef u64 ArchiveHandle; | 44 | typedef u64 ArchiveHandle; |
| 45 | 45 | ||
| 46 | class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> { | 46 | class File final : public Kernel::SessionRequestHandler { |
| 47 | public: | 47 | public: |
| 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 | ||
| 63 | class Directory final : public SessionRequestHandler { | 63 | class Directory final : public Kernel::SessionRequestHandler { |
| 64 | public: | 64 | public: |
| 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 | ||
| 21 | using Kernel::SharedPtr; | 26 | using Kernel::ClientSession; |
| 22 | using Kernel::ServerSession; | 27 | using Kernel::ServerSession; |
| 28 | using Kernel::SharedPtr; | ||
| 23 | 29 | ||
| 24 | namespace Service { | 30 | namespace Service { |
| 25 | namespace FS { | 31 | namespace 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 | ||
| 15 | namespace Service { | 14 | namespace Service { |
| 16 | namespace NWM { | 15 | namespace 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 | ||
| 47 | namespace Service { | 48 | namespace Service { |
| 48 | 49 | ||
| 49 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | 50 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; |
| 50 | std::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 | ||
| 69 | void SessionRequestHandler::ClientConnected( | ||
| 70 | Kernel::SharedPtr<Kernel::ServerSession> server_session) { | ||
| 71 | connected_sessions.push_back(server_session); | ||
| 72 | } | ||
| 73 | |||
| 74 | void SessionRequestHandler::ClientDisconnected( | ||
| 75 | Kernel::SharedPtr<Kernel::ServerSession> server_session) { | ||
| 76 | boost::range::remove_erase(connected_sessions, server_session); | ||
| 77 | } | ||
| 78 | |||
| 79 | Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} | 69 | Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} |
| 80 | Interface::~Interface() = default; | 70 | Interface::~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 | ||
| 118 | static void AddNamedPort(Interface* interface_) { | 108 | static 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 | ||
| 126 | void AddService(Interface* interface_) { | 118 | void 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 |
| 135 | void Init() { | 127 | void 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 | ||
| 19 | namespace Kernel { | 19 | namespace Kernel { |
| 20 | class ClientPort; | ||
| 20 | class ServerSession; | 21 | class ServerSession; |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 24 | // Namespace Service | ||
| 25 | |||
| 26 | namespace Service { | 24 | namespace Service { |
| 27 | 25 | ||
| 28 | static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) | 26 | static 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 | |||
| 30 | static const u32 DefaultMaxSessions = 10; | 28 | static 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 | */ | ||
| 37 | class SessionRequestHandler { | ||
| 38 | public: | ||
| 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 | |||
| 63 | protected: | ||
| 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 | */ |
| 74 | class Interface : public SessionRequestHandler { | 34 | class Interface : public Kernel::SessionRequestHandler { |
| 75 | public: | 35 | public: |
| 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. |
| 151 | extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | 111 | extern 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. | ||
| 153 | extern 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 |
| 156 | void AddService(Interface* interface_); | 114 | void 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 | |||
| 12 | namespace Service { | ||
| 13 | namespace SM { | ||
| 14 | |||
| 15 | static 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 | |||
| 25 | ResultVal<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 | |||
| 37 | ResultVal<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 | |||
| 49 | ResultVal<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 | |||
| 56 | std::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 | |||
| 13 | namespace Kernel { | ||
| 14 | class ClientPort; | ||
| 15 | class ClientSession; | ||
| 16 | class ServerPort; | ||
| 17 | class SessionRequestHandler; | ||
| 18 | } // namespace Kernel | ||
| 19 | |||
| 20 | namespace Service { | ||
| 21 | namespace SM { | ||
| 22 | |||
| 23 | constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(1, ErrorModule::SRV, ErrorSummary::WouldBlock, | ||
| 24 | ErrorLevel::Temporary); // 0xD0406401 | ||
| 25 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(2, ErrorModule::SRV, ErrorSummary::WouldBlock, | ||
| 26 | ErrorLevel::Temporary); // 0xD0406402 | ||
| 27 | constexpr ResultCode ERR_INVALID_NAME_SIZE(5, ErrorModule::SRV, ErrorSummary::WrongArgument, | ||
| 28 | ErrorLevel::Permanent); // 0xD9006405 | ||
| 29 | constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::InvalidArgument, | ||
| 30 | ErrorLevel::Permanent); // 0xD8E06406 | ||
| 31 | constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument, | ||
| 32 | ErrorLevel::Permanent); // 0xD9006407 | ||
| 33 | |||
| 34 | class ServiceManager { | ||
| 35 | public: | ||
| 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 | |||
| 41 | private: | ||
| 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 | |||
| 46 | extern 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 | ||
| 14 | namespace Service { | 18 | namespace Service { |
| 15 | namespace SRV { | 19 | namespace SM { |
| 16 | 20 | ||
| 17 | static Kernel::SharedPtr<Kernel::Event> event_handle; | 21 | constexpr int MAX_PENDING_NOTIFICATIONS = 16; |
| 22 | |||
| 23 | static 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) { | |||
| 51 | static void EnableNotification(Interface* self) { | 57 | static 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 | ||
| 178 | SRV::SRV() { | 199 | SRV::SRV() { |
| 179 | Register(FunctionTable); | 200 | Register(FunctionTable); |
| 180 | event_handle = nullptr; | 201 | notification_semaphore = nullptr; |
| 181 | } | 202 | } |
| 182 | 203 | ||
| 183 | SRV::~SRV() { | 204 | SRV::~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 | ||
| 9 | namespace Service { | 10 | namespace Service { |
| 10 | namespace SRV { | 11 | namespace SM { |
| 11 | 12 | ||
| 12 | /// Interface to "srv:" service | 13 | /// Interface to "srv:" service |
| 13 | class SRV final : public Interface { | 14 | class 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 | ||
| 9 | namespace Service { | 11 | namespace Service { |
| 10 | namespace SSL { | 12 | namespace 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 |
| 246 | static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) { | 249 | static 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 | ||
| 124 | boost::optional<u32> AppLoader_NCCH::LoadKernelSystemMode() { | 124 | std::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 | ||
| 132 | ResultStatus AppLoader_NCCH::LoadExec() { | 136 | ResultStatus 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 | |||
| 13 | if(SDL2_FOUND) | 13 | if(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}) | ||
| 17 | endif() | 16 | endif() |
| 18 | 17 | ||
| 19 | create_directory_groups(${SRCS} ${HEADERS}) | 18 | create_directory_groups(${SRCS} ${HEADERS}) |
| @@ -22,6 +21,6 @@ add_library(input_common STATIC ${SRCS} ${HEADERS}) | |||
| 22 | target_link_libraries(input_common PUBLIC core PRIVATE common) | 21 | target_link_libraries(input_common PUBLIC core PRIVATE common) |
| 23 | 22 | ||
| 24 | if(SDL2_FOUND) | 23 | if(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) |
| 27 | endif() | 26 | endif() |
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 | ||
| 11 | create_directory_groups(${SRCS} ${HEADERS}) | 11 | create_directory_groups(${SRCS} ${HEADERS}) |
| 12 | 12 | ||
| 13 | include_directories(../../externals/catch/single_include/) | ||
| 14 | |||
| 15 | add_executable(tests ${SRCS} ${HEADERS}) | 13 | add_executable(tests ${SRCS} ${HEADERS}) |
| 16 | target_link_libraries(tests PRIVATE common core) | 14 | target_link_libraries(tests PRIVATE common core) |
| 17 | target_link_libraries(tests PRIVATE glad) # To support linker work-around | 15 | target_link_libraries(tests PRIVATE glad) # To support linker work-around |
| 18 | target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 16 | target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads) |
| 19 | 17 | ||
| 20 | add_test(NAME tests COMMAND $<TARGET_FILE:tests>) | 18 | add_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 | ||
| 81 | add_library(video_core STATIC ${SRCS} ${HEADERS}) | 81 | add_library(video_core STATIC ${SRCS} ${HEADERS}) |
| 82 | target_link_libraries(video_core PUBLIC common core) | 82 | target_link_libraries(video_core PUBLIC common core) |
| 83 | target_link_libraries(video_core PRIVATE glad) | 83 | target_link_libraries(video_core PRIVATE glad nihstro-headers) |
| 84 | 84 | ||
| 85 | if (ARCHITECTURE_x86_64) | 85 | if (ARCHITECTURE_x86_64) |
| 86 | target_link_libraries(video_core PRIVATE xbyak) | 86 | target_link_libraries(video_core PRIVATE xbyak) |
| 87 | endif() | 87 | endif() |
| 88 | 88 | ||
| 89 | if (PNG_FOUND) | 89 | if (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}) | ||
| 93 | endif() | 92 | endif() |
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 | ||
| 75 | static 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 | |||
| 73 | MICROPROFILE_DEFINE(GPU_Rasterization, "GPU", "Rasterization", MP_RGB(50, 50, 240)); | 117 | MICROPROFILE_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 | ||