diff options
Diffstat (limited to 'src')
131 files changed, 2538 insertions, 1514 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index a72a907ef..0ad86bb7a 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt | |||
| @@ -27,20 +27,18 @@ 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}) |
| 39 | 36 | ||
| 40 | add_library(audio_core STATIC ${SRCS} ${HEADERS}) | 37 | add_library(audio_core STATIC ${SRCS} ${HEADERS}) |
| 41 | target_link_libraries(audio_core SoundTouch) | 38 | target_link_libraries(audio_core PUBLIC common core) |
| 39 | target_link_libraries(audio_core PRIVATE SoundTouch) | ||
| 42 | 40 | ||
| 43 | if(SDL2_FOUND) | 41 | if(SDL2_FOUND) |
| 44 | target_link_libraries(audio_core ${SDL2_LIBRARY}) | 42 | target_link_libraries(audio_core PRIVATE SDL2) |
| 45 | set_property(TARGET audio_core APPEND PROPERTY COMPILE_DEFINITIONS HAVE_SDL2) | 43 | target_compile_definitions(audio_core PRIVATE HAVE_SDL2) |
| 46 | endif() | 44 | endif() |
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt index 47231ba71..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 core video_core audio_core common input_common) | 19 | target_link_libraries(citra PRIVATE common core input_common) |
| 22 | target_link_libraries(citra ${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 getopt) | 22 | target_link_libraries(citra PRIVATE getopt) |
| 25 | endif() | 23 | endif() |
| 26 | target_link_libraries(citra ${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 76f5caeb1..dd357ff72 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp | |||
| @@ -33,7 +33,6 @@ | |||
| 33 | #include "core/gdbstub/gdbstub.h" | 33 | #include "core/gdbstub/gdbstub.h" |
| 34 | #include "core/loader/loader.h" | 34 | #include "core/loader/loader.h" |
| 35 | #include "core/settings.h" | 35 | #include "core/settings.h" |
| 36 | #include "video_core/video_core.h" | ||
| 37 | 36 | ||
| 38 | static void PrintHelp(const char* argv0) { | 37 | static void PrintHelp(const char* argv0) { |
| 39 | std::cout << "Usage: " << argv0 | 38 | std::cout << "Usage: " << argv0 |
| @@ -145,7 +144,7 @@ int main(int argc, char** argv) { | |||
| 145 | 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 " |
| 146 | "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 " |
| 147 | "decrypting games, please refer to: " | 146 | "decrypting games, please refer to: " |
| 148 | "https://citra-emu.org/wiki/Dumping-Game-Cartridges"); | 147 | "https://citra-emu.org/wiki/dumping-game-cartridges/"); |
| 149 | return -1; | 148 | return -1; |
| 150 | case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: | 149 | case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: |
| 151 | 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/config.cpp b/src/citra/config.cpp index a4162e9ad..f08b4069c 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -5,11 +5,11 @@ | |||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <SDL.h> | 6 | #include <SDL.h> |
| 7 | #include <inih/cpp/INIReader.h> | 7 | #include <inih/cpp/INIReader.h> |
| 8 | #include "citra/config.h" | ||
| 8 | #include "citra/default_ini.h" | 9 | #include "citra/default_ini.h" |
| 9 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 11 | #include "common/param_package.h" | 12 | #include "common/param_package.h" |
| 12 | #include "config.h" | ||
| 13 | #include "core/settings.h" | 13 | #include "core/settings.h" |
| 14 | #include "input_common/main.h" | 14 | #include "input_common/main.h" |
| 15 | 15 | ||
| @@ -21,6 +21,8 @@ Config::Config() { | |||
| 21 | Reload(); | 21 | Reload(); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | Config::~Config() = default; | ||
| 25 | |||
| 24 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | 26 | bool Config::LoadINI(const std::string& default_contents, bool retry) { |
| 25 | const char* location = this->sdl2_config_loc.c_str(); | 27 | const char* location = this->sdl2_config_loc.c_str(); |
| 26 | if (sdl2_config->ParseError() < 0) { | 28 | if (sdl2_config->ParseError() < 0) { |
diff --git a/src/citra/config.h b/src/citra/config.h index b1c31f59c..abc90f642 100644 --- a/src/citra/config.h +++ b/src/citra/config.h | |||
| @@ -6,7 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <inih/cpp/INIReader.h> | 9 | |
| 10 | class INIReader; | ||
| 10 | 11 | ||
| 11 | class Config { | 12 | class Config { |
| 12 | std::unique_ptr<INIReader> sdl2_config; | 13 | std::unique_ptr<INIReader> sdl2_config; |
| @@ -17,6 +18,7 @@ class Config { | |||
| 17 | 18 | ||
| 18 | public: | 19 | public: |
| 19 | Config(); | 20 | Config(); |
| 21 | ~Config(); | ||
| 20 | 22 | ||
| 21 | void Reload(); | 23 | void Reload(); |
| 22 | }; | 24 | }; |
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index 6bc0b0d00..47aadd60c 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp | |||
| @@ -12,10 +12,10 @@ | |||
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/scm_rev.h" | 13 | #include "common/scm_rev.h" |
| 14 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 15 | #include "core/3ds.h" | ||
| 15 | #include "core/settings.h" | 16 | #include "core/settings.h" |
| 16 | #include "input_common/keyboard.h" | 17 | #include "input_common/keyboard.h" |
| 17 | #include "input_common/main.h" | 18 | #include "input_common/main.h" |
| 18 | #include "video_core/video_core.h" | ||
| 19 | 19 | ||
| 20 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { | 20 | void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { |
| 21 | TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); | 21 | TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); |
| @@ -80,12 +80,12 @@ EmuWindow_SDL2::EmuWindow_SDL2() { | |||
| 80 | 80 | ||
| 81 | std::string window_title = Common::StringFromFormat("Citra %s| %s-%s ", Common::g_build_name, | 81 | std::string window_title = Common::StringFromFormat("Citra %s| %s-%s ", Common::g_build_name, |
| 82 | Common::g_scm_branch, Common::g_scm_desc); | 82 | Common::g_scm_branch, Common::g_scm_desc); |
| 83 | render_window = SDL_CreateWindow( | 83 | render_window = |
| 84 | window_title.c_str(), | 84 | SDL_CreateWindow(window_title.c_str(), |
| 85 | SDL_WINDOWPOS_UNDEFINED, // x position | 85 | SDL_WINDOWPOS_UNDEFINED, // x position |
| 86 | SDL_WINDOWPOS_UNDEFINED, // y position | 86 | SDL_WINDOWPOS_UNDEFINED, // y position |
| 87 | VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight, | 87 | Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight, |
| 88 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); | 88 | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); |
| 89 | 89 | ||
| 90 | if (render_window == nullptr) { | 90 | if (render_window == nullptr) { |
| 91 | LOG_CRITICAL(Frontend, "Failed to create SDL2 window! Exiting..."); | 91 | LOG_CRITICAL(Frontend, "Failed to create SDL2 window! Exiting..."); |
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 4e837668e..4841cbf05 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt | |||
| @@ -91,9 +91,9 @@ if (APPLE) | |||
| 91 | else() | 91 | 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 core video_core audio_core common input_common) | 94 | target_link_libraries(citra-qt PRIVATE audio_core common core input_common video_core) |
| 95 | target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) | 95 | target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::OpenGL Qt5::Widgets) |
| 96 | target_link_libraries(citra-qt ${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) |
| 99 | install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") | 99 | install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") |
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index bae576d6a..a8a4aed8b 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -12,12 +12,11 @@ | |||
| 12 | #include "common/microprofile.h" | 12 | #include "common/microprofile.h" |
| 13 | #include "common/scm_rev.h" | 13 | #include "common/scm_rev.h" |
| 14 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 15 | #include "core/3ds.h" | ||
| 15 | #include "core/core.h" | 16 | #include "core/core.h" |
| 16 | #include "core/settings.h" | 17 | #include "core/settings.h" |
| 17 | #include "input_common/keyboard.h" | 18 | #include "input_common/keyboard.h" |
| 18 | #include "input_common/main.h" | 19 | #include "input_common/main.h" |
| 19 | #include "video_core/debug_utils/debug_utils.h" | ||
| 20 | #include "video_core/video_core.h" | ||
| 21 | 20 | ||
| 22 | EmuThread::EmuThread(GRenderWindow* render_window) | 21 | EmuThread::EmuThread(GRenderWindow* render_window) |
| 23 | : exec_step(false), running(false), stop_run(false), render_window(render_window) {} | 22 | : exec_step(false), running(false), stop_run(false), render_window(render_window) {} |
| @@ -38,7 +37,10 @@ void EmuThread::run() { | |||
| 38 | if (!was_active) | 37 | if (!was_active) |
| 39 | emit DebugModeLeft(); | 38 | emit DebugModeLeft(); |
| 40 | 39 | ||
| 41 | 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 | } | ||
| 42 | 44 | ||
| 43 | was_active = running || exec_step; | 45 | was_active = running || exec_step; |
| 44 | if (!was_active && !stop_run) | 46 | if (!was_active && !stop_run) |
| @@ -266,8 +268,7 @@ void GRenderWindow::InitRenderTarget() { | |||
| 266 | child = new GGLWidgetInternal(fmt, this); | 268 | child = new GGLWidgetInternal(fmt, this); |
| 267 | QBoxLayout* layout = new QHBoxLayout(this); | 269 | QBoxLayout* layout = new QHBoxLayout(this); |
| 268 | 270 | ||
| 269 | resize(VideoCore::kScreenTopWidth, | 271 | resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight); |
| 270 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | ||
| 271 | layout->addWidget(child); | 272 | layout->addWidget(child); |
| 272 | layout->setMargin(0); | 273 | layout->setMargin(0); |
| 273 | setLayout(layout); | 274 | setLayout(layout); |
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..2b38712b9 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 | ||
| @@ -20,7 +18,6 @@ class WaitObject; | |||
| 20 | class Event; | 18 | class Event; |
| 21 | class Mutex; | 19 | class Mutex; |
| 22 | class Semaphore; | 20 | class Semaphore; |
| 23 | class Session; | ||
| 24 | class Thread; | 21 | class Thread; |
| 25 | class Timer; | 22 | class Timer; |
| 26 | } | 23 | } |
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 d7fad555f..4f5b2ddab 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -43,7 +43,6 @@ | |||
| 43 | #include "core/gdbstub/gdbstub.h" | 43 | #include "core/gdbstub/gdbstub.h" |
| 44 | #include "core/loader/loader.h" | 44 | #include "core/loader/loader.h" |
| 45 | #include "core/settings.h" | 45 | #include "core/settings.h" |
| 46 | #include "video_core/video_core.h" | ||
| 47 | 46 | ||
| 48 | #ifdef QT_STATICPLUGIN | 47 | #ifdef QT_STATICPLUGIN |
| 49 | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); | 48 | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); |
| @@ -94,6 +93,14 @@ void GMainWindow::InitializeWidgets() { | |||
| 94 | ui.horizontalLayout->addWidget(game_list); | 93 | ui.horizontalLayout->addWidget(game_list); |
| 95 | 94 | ||
| 96 | // 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 | |||
| 97 | emu_speed_label = new QLabel(); | 104 | emu_speed_label = new QLabel(); |
| 98 | 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% " |
| 99 | "indicate emulation is running faster or slower than a 3DS.")); | 106 | "indicate emulation is running faster or slower than a 3DS.")); |
| @@ -109,7 +116,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 109 | label->setVisible(false); | 116 | label->setVisible(false); |
| 110 | label->setFrameStyle(QFrame::NoFrame); | 117 | label->setFrameStyle(QFrame::NoFrame); |
| 111 | label->setContentsMargins(4, 0, 4, 0); | 118 | label->setContentsMargins(4, 0, 4, 0); |
| 112 | statusBar()->addPermanentWidget(label); | 119 | statusBar()->addPermanentWidget(label, 0); |
| 113 | } | 120 | } |
| 114 | statusBar()->setVisible(true); | 121 | statusBar()->setVisible(true); |
| 115 | setStyleSheet("QStatusBar::item{border: none;}"); | 122 | setStyleSheet("QStatusBar::item{border: none;}"); |
| @@ -301,9 +308,8 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 301 | render_window->MakeCurrent(); | 308 | render_window->MakeCurrent(); |
| 302 | 309 | ||
| 303 | if (!gladLoadGL()) { | 310 | if (!gladLoadGL()) { |
| 304 | QMessageBox::critical(this, tr("Error while starting Citra!"), | 311 | QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"), |
| 305 | tr("Failed to initialize the video core!\n\n" | 312 | tr("Your GPU may not support OpenGL 3.3, or you do not" |
| 306 | "Please ensure that your GPU supports OpenGL 3.3 and that you " | ||
| 307 | "have the latest graphics driver.")); | 313 | "have the latest graphics driver.")); |
| 308 | return false; | 314 | return false; |
| 309 | } | 315 | } |
| @@ -328,18 +334,17 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 328 | break; | 334 | break; |
| 329 | 335 | ||
| 330 | case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: { | 336 | case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: { |
| 331 | // Build the MessageBox ourselves to have clickable link | 337 | QMessageBox::critical( |
| 332 | QMessageBox popup_error; | 338 | this, tr("Error while loading ROM!"), |
| 333 | popup_error.setTextFormat(Qt::RichText); | ||
| 334 | popup_error.setWindowTitle(tr("Error while loading ROM!")); | ||
| 335 | popup_error.setText( | ||
| 336 | 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 " |
| 337 | "Citra.<br/><br/>" | 340 | "Citra. A real 3DS is required.<br/><br/>" |
| 338 | "For more information on dumping and decrypting games, please see: <a " | 341 | "For more information on dumping and decrypting games, please see the following " |
| 339 | "href='https://citra-emu.org/wiki/Dumping-Game-Cartridges'>https://" | 342 | "wiki pages: <ul>" |
| 340 | "citra-emu.org/wiki/Dumping-Game-Cartridges</a>")); | 343 | "<li><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Dumping Game " |
| 341 | popup_error.setIcon(QMessageBox::Critical); | 344 | "Cartridges</a></li>" |
| 342 | popup_error.exec(); | 345 | "<li><a href='https://citra-emu.org/wiki/dumping-installed-titles/'>Dumping " |
| 346 | "Installed Titles</a></li>" | ||
| 347 | "</ul>")); | ||
| 343 | break; | 348 | break; |
| 344 | } | 349 | } |
| 345 | case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: | 350 | case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: |
| @@ -347,8 +352,23 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 347 | tr("The ROM format is not supported.")); | 352 | tr("The ROM format is not supported.")); |
| 348 | break; | 353 | break; |
| 349 | 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 | |||
| 350 | default: | 368 | default: |
| 351 | 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.")); | ||
| 352 | break; | 372 | break; |
| 353 | } | 373 | } |
| 354 | return false; | 374 | return false; |
| @@ -425,6 +445,7 @@ void GMainWindow::ShutdownGame() { | |||
| 425 | 445 | ||
| 426 | // Disable status bar updates | 446 | // Disable status bar updates |
| 427 | status_bar_update_timer.stop(); | 447 | status_bar_update_timer.stop(); |
| 448 | message_label->setVisible(false); | ||
| 428 | emu_speed_label->setVisible(false); | 449 | emu_speed_label->setVisible(false); |
| 429 | game_fps_label->setVisible(false); | 450 | game_fps_label->setVisible(false); |
| 430 | emu_frametime_label->setVisible(false); | 451 | emu_frametime_label->setVisible(false); |
| @@ -531,6 +552,10 @@ void GMainWindow::OnMenuRecentFile() { | |||
| 531 | 552 | ||
| 532 | void GMainWindow::OnStartGame() { | 553 | void GMainWindow::OnStartGame() { |
| 533 | 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))); | ||
| 534 | 559 | ||
| 535 | ui.action_Start->setEnabled(false); | 560 | ui.action_Start->setEnabled(false); |
| 536 | ui.action_Start->setText(tr("Continue")); | 561 | ui.action_Start->setText(tr("Continue")); |
| @@ -623,11 +648,74 @@ void GMainWindow::UpdateStatusBar() { | |||
| 623 | emu_frametime_label->setVisible(true); | 648 | emu_frametime_label->setVisible(true); |
| 624 | } | 649 | } |
| 625 | 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 | |||
| 626 | bool GMainWindow::ConfirmClose() { | 714 | bool GMainWindow::ConfirmClose() { |
| 627 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) | 715 | if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) |
| 628 | return true; | 716 | return true; |
| 629 | 717 | ||
| 630 | auto answer = | 718 | QMessageBox::StandardButton answer = |
| 631 | 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?"), |
| 632 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | 720 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); |
| 633 | 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 6905d2d50..7e83e64b0 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -27,7 +27,6 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU | |||
| 27 | set(SRCS | 27 | set(SRCS |
| 28 | break_points.cpp | 28 | break_points.cpp |
| 29 | file_util.cpp | 29 | file_util.cpp |
| 30 | framebuffer_layout.cpp | ||
| 31 | hash.cpp | 30 | hash.cpp |
| 32 | logging/filter.cpp | 31 | logging/filter.cpp |
| 33 | logging/text_formatter.cpp | 32 | logging/text_formatter.cpp |
| @@ -56,7 +55,6 @@ set(HEADERS | |||
| 56 | common_paths.h | 55 | common_paths.h |
| 57 | common_types.h | 56 | common_types.h |
| 58 | file_util.h | 57 | file_util.h |
| 59 | framebuffer_layout.h | ||
| 60 | hash.h | 58 | hash.h |
| 61 | linear_disk_cache.h | 59 | linear_disk_cache.h |
| 62 | logging/text_formatter.h | 60 | logging/text_formatter.h |
| @@ -97,6 +95,7 @@ endif() | |||
| 97 | create_directory_groups(${SRCS} ${HEADERS}) | 95 | create_directory_groups(${SRCS} ${HEADERS}) |
| 98 | 96 | ||
| 99 | add_library(common STATIC ${SRCS} ${HEADERS}) | 97 | add_library(common STATIC ${SRCS} ${HEADERS}) |
| 98 | target_link_libraries(common PUBLIC Boost::boost microprofile) | ||
| 100 | if (ARCHITECTURE_x86_64) | 99 | if (ARCHITECTURE_x86_64) |
| 101 | target_link_libraries(common xbyak) | 100 | target_link_libraries(common PRIVATE xbyak) |
| 102 | endif() | 101 | endif() |
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 030f7caeb..0cc0a1be0 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -108,7 +108,7 @@ | |||
| 108 | * symptoms. | 108 | * symptoms. |
| 109 | */ | 109 | */ |
| 110 | #pragma pack(1) | 110 | #pragma pack(1) |
| 111 | template <std::size_t position, std::size_t bits, typename T> | 111 | template <std::size_t Position, std::size_t Bits, typename T> |
| 112 | struct BitField { | 112 | struct BitField { |
| 113 | private: | 113 | private: |
| 114 | // We hide the copy assigment operator here, because the default copy | 114 | // We hide the copy assigment operator here, because the default copy |
| @@ -117,7 +117,45 @@ private: | |||
| 117 | // We don't delete it because we want BitField to be trivially copyable. | 117 | // We don't delete it because we want BitField to be trivially copyable. |
| 118 | BitField& operator=(const BitField&) = default; | 118 | BitField& operator=(const BitField&) = default; |
| 119 | 119 | ||
| 120 | // StorageType is T for non-enum types and the underlying type of T if | ||
| 121 | // T is an enumeration. Note that T is wrapped within an enable_if in the | ||
| 122 | // former case to workaround compile errors which arise when using | ||
| 123 | // std::underlying_type<T>::type directly. | ||
| 124 | using StorageType = typename std::conditional_t<std::is_enum<T>::value, std::underlying_type<T>, | ||
| 125 | std::enable_if<true, T>>::type; | ||
| 126 | |||
| 127 | // Unsigned version of StorageType | ||
| 128 | using StorageTypeU = std::make_unsigned_t<StorageType>; | ||
| 129 | |||
| 120 | public: | 130 | public: |
| 131 | /// Constants to allow limited introspection of fields if needed | ||
| 132 | static constexpr size_t position = Position; | ||
| 133 | static constexpr size_t bits = Bits; | ||
| 134 | static constexpr StorageType mask = (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||
| 135 | |||
| 136 | /** | ||
| 137 | * Formats a value by masking and shifting it according to the field parameters. A value | ||
| 138 | * containing several bitfields can be assembled by formatting each of their values and ORing | ||
| 139 | * the results together. | ||
| 140 | */ | ||
| 141 | static constexpr FORCE_INLINE StorageType FormatValue(const T& value) { | ||
| 142 | return ((StorageType)value << position) & mask; | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Extracts a value from the passed storage. In most situations prefer use the member functions | ||
| 147 | * (such as Value() or operator T), but this can be used to extract a value from a bitfield | ||
| 148 | * union in a constexpr context. | ||
| 149 | */ | ||
| 150 | static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) { | ||
| 151 | if (std::numeric_limits<T>::is_signed) { | ||
| 152 | std::size_t shift = 8 * sizeof(T) - bits; | ||
| 153 | return (T)((storage << (shift - position)) >> shift); | ||
| 154 | } else { | ||
| 155 | return (T)((storage & mask) >> position); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 121 | // This constructor and assignment operator might be considered ambiguous: | 159 | // This constructor and assignment operator might be considered ambiguous: |
| 122 | // Would they initialize the storage or just the bitfield? | 160 | // Would they initialize the storage or just the bitfield? |
| 123 | // Hence, delete them. Use the Assign method to set bitfield values! | 161 | // Hence, delete them. Use the Assign method to set bitfield values! |
| @@ -126,23 +164,18 @@ public: | |||
| 126 | 164 | ||
| 127 | // Force default constructor to be created | 165 | // Force default constructor to be created |
| 128 | // so that we can use this within unions | 166 | // so that we can use this within unions |
| 129 | BitField() = default; | 167 | constexpr BitField() = default; |
| 130 | 168 | ||
| 131 | FORCE_INLINE operator T() const { | 169 | FORCE_INLINE operator T() const { |
| 132 | return Value(); | 170 | return Value(); |
| 133 | } | 171 | } |
| 134 | 172 | ||
| 135 | FORCE_INLINE void Assign(const T& value) { | 173 | FORCE_INLINE void Assign(const T& value) { |
| 136 | storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask()); | 174 | storage = (storage & ~mask) | FormatValue(value); |
| 137 | } | 175 | } |
| 138 | 176 | ||
| 139 | FORCE_INLINE T Value() const { | 177 | FORCE_INLINE T Value() const { |
| 140 | if (std::numeric_limits<T>::is_signed) { | 178 | return ExtractValue(storage); |
| 141 | std::size_t shift = 8 * sizeof(T) - bits; | ||
| 142 | return (T)((storage << (shift - position)) >> shift); | ||
| 143 | } else { | ||
| 144 | return (T)((storage & GetMask()) >> position); | ||
| 145 | } | ||
| 146 | } | 179 | } |
| 147 | 180 | ||
| 148 | // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015 | 181 | // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015 |
| @@ -151,20 +184,6 @@ public: | |||
| 151 | } | 184 | } |
| 152 | 185 | ||
| 153 | private: | 186 | private: |
| 154 | // StorageType is T for non-enum types and the underlying type of T if | ||
| 155 | // T is an enumeration. Note that T is wrapped within an enable_if in the | ||
| 156 | // former case to workaround compile errors which arise when using | ||
| 157 | // std::underlying_type<T>::type directly. | ||
| 158 | typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>, | ||
| 159 | std::enable_if<true, T>>::type::type StorageType; | ||
| 160 | |||
| 161 | // Unsigned version of StorageType | ||
| 162 | typedef typename std::make_unsigned<StorageType>::type StorageTypeU; | ||
| 163 | |||
| 164 | FORCE_INLINE StorageType GetMask() const { | ||
| 165 | return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position; | ||
| 166 | } | ||
| 167 | |||
| 168 | StorageType storage; | 187 | StorageType storage; |
| 169 | 188 | ||
| 170 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); | 189 | static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); |
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp index 03a19acba..fa367a4ca 100644 --- a/src/common/break_points.cpp +++ b/src/common/break_points.cpp | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <sstream> | 6 | #include <sstream> |
| 7 | #include "common/break_points.h" | 7 | #include "common/break_points.h" |
| 8 | #include "common/logging/log.h" | ||
| 9 | 8 | ||
| 10 | bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const { | 9 | bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const { |
| 11 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; | 10 | auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; }; |
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index b141e79ed..2e7877500 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM) | 7 | #if !defined(ARCHITECTURE_x86_64) && !defined(_M_ARM) |
| 8 | #include <cstdlib> // for exit | 8 | #include <cstdlib> // for exit |
| 9 | #endif | 9 | #endif |
| 10 | #include "common_types.h" | 10 | #include "common/common_types.h" |
| 11 | 11 | ||
| 12 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | 12 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) |
| 13 | 13 | ||
diff --git a/src/common/hash.cpp b/src/common/hash.cpp index f3d390dc5..a02e9e5b9 100644 --- a/src/common/hash.cpp +++ b/src/common/hash.cpp | |||
| @@ -5,9 +5,9 @@ | |||
| 5 | #if defined(_MSC_VER) | 5 | #if defined(_MSC_VER) |
| 6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
| 7 | #endif | 7 | #endif |
| 8 | #include "common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 9 | #include "common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "hash.h" | 10 | #include "common/hash.h" |
| 11 | 11 | ||
| 12 | namespace Common { | 12 | namespace Common { |
| 13 | 13 | ||
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 2cb3ab9cc..62f17fbb5 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <thread> | 7 | #include <thread> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "cpu_detect.h" | 9 | #include "common/x64/cpu_detect.h" |
| 10 | 10 | ||
| 11 | #ifdef _MSC_VER | 11 | #ifdef _MSC_VER |
| 12 | #include <intrin.h> | 12 | #include <intrin.h> |
diff --git a/src/core/3ds.h b/src/core/3ds.h new file mode 100644 index 000000000..8715e27db --- /dev/null +++ b/src/core/3ds.h | |||
| @@ -0,0 +1,21 @@ | |||
| 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 | namespace Core { | ||
| 8 | |||
| 9 | // 3DS Video Constants | ||
| 10 | // ------------------- | ||
| 11 | |||
| 12 | // NOTE: The LCDs actually rotate the image 90 degrees when displaying. Because of that the | ||
| 13 | // framebuffers in video memory are stored in column-major order and rendered sideways, causing | ||
| 14 | // the widths and heights of the framebuffers read by the LCD to be switched compared to the | ||
| 15 | // heights and widths of the screens listed here. | ||
| 16 | constexpr int kScreenTopWidth = 400; ///< 3DS top screen width | ||
| 17 | constexpr int kScreenTopHeight = 240; ///< 3DS top screen height | ||
| 18 | constexpr int kScreenBottomWidth = 320; ///< 3DS bottom screen width | ||
| 19 | constexpr int kScreenBottomHeight = 240; ///< 3DS bottom screen height | ||
| 20 | |||
| 21 | } // namespace Core | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 57504529f..b16a89990 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -32,6 +32,7 @@ set(SRCS | |||
| 32 | frontend/camera/factory.cpp | 32 | frontend/camera/factory.cpp |
| 33 | frontend/camera/interface.cpp | 33 | frontend/camera/interface.cpp |
| 34 | frontend/emu_window.cpp | 34 | frontend/emu_window.cpp |
| 35 | frontend/framebuffer_layout.cpp | ||
| 35 | frontend/motion_emu.cpp | 36 | frontend/motion_emu.cpp |
| 36 | gdbstub/gdbstub.cpp | 37 | gdbstub/gdbstub.cpp |
| 37 | hle/config_mem.cpp | 38 | hle/config_mem.cpp |
| @@ -44,6 +45,8 @@ set(SRCS | |||
| 44 | hle/kernel/client_port.cpp | 45 | hle/kernel/client_port.cpp |
| 45 | hle/kernel/client_session.cpp | 46 | hle/kernel/client_session.cpp |
| 46 | hle/kernel/event.cpp | 47 | hle/kernel/event.cpp |
| 48 | hle/kernel/handle_table.cpp | ||
| 49 | hle/kernel/hle_ipc.cpp | ||
| 47 | hle/kernel/kernel.cpp | 50 | hle/kernel/kernel.cpp |
| 48 | hle/kernel/memory.cpp | 51 | hle/kernel/memory.cpp |
| 49 | hle/kernel/mutex.cpp | 52 | hle/kernel/mutex.cpp |
| @@ -56,6 +59,7 @@ set(SRCS | |||
| 56 | hle/kernel/thread.cpp | 59 | hle/kernel/thread.cpp |
| 57 | hle/kernel/timer.cpp | 60 | hle/kernel/timer.cpp |
| 58 | hle/kernel/vm_manager.cpp | 61 | hle/kernel/vm_manager.cpp |
| 62 | hle/kernel/wait_object.cpp | ||
| 59 | hle/service/ac/ac.cpp | 63 | hle/service/ac/ac.cpp |
| 60 | hle/service/ac/ac_i.cpp | 64 | hle/service/ac/ac_i.cpp |
| 61 | hle/service/ac/ac_u.cpp | 65 | hle/service/ac/ac_u.cpp |
| @@ -152,8 +156,9 @@ set(SRCS | |||
| 152 | hle/service/qtm/qtm_sp.cpp | 156 | hle/service/qtm/qtm_sp.cpp |
| 153 | hle/service/qtm/qtm_u.cpp | 157 | hle/service/qtm/qtm_u.cpp |
| 154 | hle/service/service.cpp | 158 | hle/service/service.cpp |
| 159 | hle/service/sm/sm.cpp | ||
| 160 | hle/service/sm/srv.cpp | ||
| 155 | hle/service/soc_u.cpp | 161 | hle/service/soc_u.cpp |
| 156 | hle/service/srv.cpp | ||
| 157 | hle/service/ssl_c.cpp | 162 | hle/service/ssl_c.cpp |
| 158 | hle/service/y2r_u.cpp | 163 | hle/service/y2r_u.cpp |
| 159 | hle/shared_page.cpp | 164 | hle/shared_page.cpp |
| @@ -178,6 +183,7 @@ set(SRCS | |||
| 178 | ) | 183 | ) |
| 179 | 184 | ||
| 180 | set(HEADERS | 185 | set(HEADERS |
| 186 | 3ds.h | ||
| 181 | arm/arm_interface.h | 187 | arm/arm_interface.h |
| 182 | arm/dynarmic/arm_dynarmic.h | 188 | arm/dynarmic/arm_dynarmic.h |
| 183 | arm/dynarmic/arm_dynarmic_cp15.h | 189 | arm/dynarmic/arm_dynarmic_cp15.h |
| @@ -216,6 +222,7 @@ set(HEADERS | |||
| 216 | frontend/camera/factory.h | 222 | frontend/camera/factory.h |
| 217 | frontend/camera/interface.h | 223 | frontend/camera/interface.h |
| 218 | frontend/emu_window.h | 224 | frontend/emu_window.h |
| 225 | frontend/framebuffer_layout.h | ||
| 219 | frontend/input.h | 226 | frontend/input.h |
| 220 | frontend/motion_emu.h | 227 | frontend/motion_emu.h |
| 221 | gdbstub/gdbstub.h | 228 | gdbstub/gdbstub.h |
| @@ -231,7 +238,10 @@ set(HEADERS | |||
| 231 | hle/kernel/address_arbiter.h | 238 | hle/kernel/address_arbiter.h |
| 232 | hle/kernel/client_port.h | 239 | hle/kernel/client_port.h |
| 233 | hle/kernel/client_session.h | 240 | hle/kernel/client_session.h |
| 241 | hle/kernel/errors.h | ||
| 234 | hle/kernel/event.h | 242 | hle/kernel/event.h |
| 243 | hle/kernel/handle_table.h | ||
| 244 | hle/kernel/hle_ipc.h | ||
| 235 | hle/kernel/kernel.h | 245 | hle/kernel/kernel.h |
| 236 | hle/kernel/memory.h | 246 | hle/kernel/memory.h |
| 237 | hle/kernel/mutex.h | 247 | hle/kernel/mutex.h |
| @@ -245,6 +255,7 @@ set(HEADERS | |||
| 245 | hle/kernel/thread.h | 255 | hle/kernel/thread.h |
| 246 | hle/kernel/timer.h | 256 | hle/kernel/timer.h |
| 247 | hle/kernel/vm_manager.h | 257 | hle/kernel/vm_manager.h |
| 258 | hle/kernel/wait_object.h | ||
| 248 | hle/result.h | 259 | hle/result.h |
| 249 | hle/service/ac/ac.h | 260 | hle/service/ac/ac.h |
| 250 | hle/service/ac/ac_i.h | 261 | hle/service/ac/ac_i.h |
| @@ -342,8 +353,9 @@ set(HEADERS | |||
| 342 | hle/service/qtm/qtm_sp.h | 353 | hle/service/qtm/qtm_sp.h |
| 343 | hle/service/qtm/qtm_u.h | 354 | hle/service/qtm/qtm_u.h |
| 344 | hle/service/service.h | 355 | hle/service/service.h |
| 356 | hle/service/sm/sm.h | ||
| 357 | hle/service/sm/srv.h | ||
| 345 | hle/service/soc_u.h | 358 | hle/service/soc_u.h |
| 346 | hle/service/srv.h | ||
| 347 | hle/service/ssl_c.h | 359 | hle/service/ssl_c.h |
| 348 | hle/service/y2r_u.h | 360 | hle/service/y2r_u.h |
| 349 | hle/shared_page.h | 361 | hle/shared_page.h |
| @@ -370,11 +382,7 @@ set(HEADERS | |||
| 370 | telemetry_session.h | 382 | telemetry_session.h |
| 371 | ) | 383 | ) |
| 372 | 384 | ||
| 373 | include_directories(../../externals/dynarmic/include) | ||
| 374 | include_directories(../../externals/cryptopp) | ||
| 375 | |||
| 376 | create_directory_groups(${SRCS} ${HEADERS}) | 385 | create_directory_groups(${SRCS} ${HEADERS}) |
| 377 | |||
| 378 | add_library(core STATIC ${SRCS} ${HEADERS}) | 386 | add_library(core STATIC ${SRCS} ${HEADERS}) |
| 379 | 387 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | |
| 380 | target_link_libraries(core dynarmic cryptopp) | 388 | target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp dynarmic fmt) |
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_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index f454e7840..4867c9d17 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp | |||
| @@ -38,8 +38,7 @@ public: | |||
| 38 | ResultVal<size_t> Write(u64 offset, size_t length, bool flush, | 38 | ResultVal<size_t> Write(u64 offset, size_t length, bool flush, |
| 39 | const u8* buffer) const override { | 39 | const u8* buffer) const override { |
| 40 | if (offset > size) { | 40 | if (offset > size) { |
| 41 | return ResultCode(ErrorDescription::FS_WriteBeyondEnd, ErrorModule::FS, | 41 | return ERR_WRITE_BEYOND_END; |
| 42 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 43 | } else if (offset == size) { | 42 | } else if (offset == size) { |
| 44 | return MakeResult<size_t>(0); | 43 | return MakeResult<size_t>(0); |
| 45 | } | 44 | } |
| @@ -191,11 +190,9 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons | |||
| 191 | // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData. | 190 | // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData. |
| 192 | // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist. | 191 | // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist. |
| 193 | if (!shared) { | 192 | if (!shared) { |
| 194 | return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, | 193 | return ERR_NOT_FOUND_INVALID_STATE; |
| 195 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 196 | } else { | 194 | } else { |
| 197 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | 195 | return ERR_NOT_FORMATTED; |
| 198 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 199 | } | 196 | } |
| 200 | } | 197 | } |
| 201 | auto archive = std::make_unique<ExtSaveDataArchive>(fullpath); | 198 | auto archive = std::make_unique<ExtSaveDataArchive>(fullpath); |
| @@ -230,8 +227,7 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat | |||
| 230 | if (!file.IsOpen()) { | 227 | if (!file.IsOpen()) { |
| 231 | LOG_ERROR(Service_FS, "Could not open metadata information for archive"); | 228 | LOG_ERROR(Service_FS, "Could not open metadata information for archive"); |
| 232 | // TODO(Subv): Verify error code | 229 | // TODO(Subv): Verify error code |
| 233 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | 230 | return ERR_NOT_FORMATTED; |
| 234 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 235 | } | 231 | } |
| 236 | 232 | ||
| 237 | ArchiveFormatInfo info = {}; | 233 | ArchiveFormatInfo info = {}; |
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/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp index f31a68038..a7e331724 100644 --- a/src/core/file_sys/archive_source_sd_savedata.cpp +++ b/src/core/file_sys/archive_source_sd_savedata.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "common/string_util.h" | 7 | #include "common/string_util.h" |
| 8 | #include "core/file_sys/archive_source_sd_savedata.h" | 8 | #include "core/file_sys/archive_source_sd_savedata.h" |
| 9 | #include "core/file_sys/errors.h" | ||
| 9 | #include "core/file_sys/savedata_archive.h" | 10 | #include "core/file_sys/savedata_archive.h" |
| 10 | #include "core/hle/service/fs/archive.h" | 11 | #include "core/hle/service/fs/archive.h" |
| 11 | 12 | ||
| @@ -49,8 +50,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 pr | |||
| 49 | // save file/directory structure expected by the game has not yet been initialized. | 50 | // save file/directory structure expected by the game has not yet been initialized. |
| 50 | // Returning the NotFormatted error code will signal the game to provision the SaveData | 51 | // Returning the NotFormatted error code will signal the game to provision the SaveData |
| 51 | // archive with the files and folders that it expects. | 52 | // archive with the files and folders that it expects. |
| 52 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | 53 | return ERR_NOT_FORMATTED; |
| 53 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point)); | 56 | auto archive = std::make_unique<SaveDataArchive>(std::move(concrete_mount_point)); |
| @@ -81,8 +81,7 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program | |||
| 81 | if (!file.IsOpen()) { | 81 | if (!file.IsOpen()) { |
| 82 | LOG_ERROR(Service_FS, "Could not open metadata information for archive"); | 82 | LOG_ERROR(Service_FS, "Could not open metadata information for archive"); |
| 83 | // TODO(Subv): Verify error code | 83 | // TODO(Subv): Verify error code |
| 84 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | 84 | return ERR_NOT_FORMATTED; |
| 85 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 86 | } | 85 | } |
| 87 | 86 | ||
| 88 | ArchiveFormatInfo info = {}; | 87 | ArchiveFormatInfo info = {}; |
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 8986b5c0e..81423bffd 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 10 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "core/file_sys/archive_systemsavedata.h" | 11 | #include "core/file_sys/archive_systemsavedata.h" |
| 12 | #include "core/file_sys/errors.h" | ||
| 12 | #include "core/file_sys/savedata_archive.h" | 13 | #include "core/file_sys/savedata_archive.h" |
| 13 | #include "core/hle/service/fs/archive.h" | 14 | #include "core/hle/service/fs/archive.h" |
| 14 | 15 | ||
| @@ -53,8 +54,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c | |||
| 53 | std::string fullpath = GetSystemSaveDataPath(base_path, path); | 54 | std::string fullpath = GetSystemSaveDataPath(base_path, path); |
| 54 | if (!FileUtil::Exists(fullpath)) { | 55 | if (!FileUtil::Exists(fullpath)) { |
| 55 | // TODO(Subv): Check error code, this one is probably wrong | 56 | // TODO(Subv): Check error code, this one is probably wrong |
| 56 | return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, | 57 | return ERR_NOT_FORMATTED; |
| 57 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 58 | } | 58 | } |
| 59 | auto archive = std::make_unique<SaveDataArchive>(fullpath); | 59 | auto archive = std::make_unique<SaveDataArchive>(fullpath); |
| 60 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | 60 | return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); |
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index a243d9a13..98d80aabc 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 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 "core/file_sys/disk_archive.h" | 11 | #include "core/file_sys/disk_archive.h" |
| 12 | #include "core/file_sys/errors.h" | ||
| 12 | 13 | ||
| 13 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 14 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 14 | // FileSys namespace | 15 | // FileSys namespace |
| @@ -17,8 +18,7 @@ namespace FileSys { | |||
| 17 | 18 | ||
| 18 | ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { | 19 | ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { |
| 19 | if (!mode.read_flag) | 20 | if (!mode.read_flag) |
| 20 | return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, | 21 | return ERROR_INVALID_OPEN_FLAGS; |
| 21 | ErrorSummary::Canceled, ErrorLevel::Status); | ||
| 22 | 22 | ||
| 23 | file->Seek(offset, SEEK_SET); | 23 | file->Seek(offset, SEEK_SET); |
| 24 | return MakeResult<size_t>(file->ReadBytes(buffer, length)); | 24 | return MakeResult<size_t>(file->ReadBytes(buffer, length)); |
| @@ -27,8 +27,7 @@ ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buff | |||
| 27 | ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, | 27 | ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, |
| 28 | const u8* buffer) const { | 28 | const u8* buffer) const { |
| 29 | if (!mode.write_flag) | 29 | if (!mode.write_flag) |
| 30 | return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, | 30 | return ERROR_INVALID_OPEN_FLAGS; |
| 31 | ErrorSummary::Canceled, ErrorLevel::Status); | ||
| 32 | 31 | ||
| 33 | file->Seek(offset, SEEK_SET); | 32 | file->Seek(offset, SEEK_SET); |
| 34 | size_t written = file->WriteBytes(buffer, length); | 33 | size_t written = file->WriteBytes(buffer, length); |
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index 9fc8d753b..a974bc775 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h | |||
| @@ -2,52 +2,93 @@ | |||
| 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 | #pragma once | ||
| 6 | |||
| 5 | #include "core/hle/result.h" | 7 | #include "core/hle/result.h" |
| 6 | 8 | ||
| 7 | namespace FileSys { | 9 | namespace FileSys { |
| 8 | 10 | ||
| 9 | const ResultCode ERROR_INVALID_PATH(ErrorDescription::FS_InvalidPath, ErrorModule::FS, | 11 | namespace ErrCodes { |
| 10 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 12 | enum { |
| 11 | const ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrorDescription::FS_UnsupportedOpenFlags, | 13 | RomFSNotFound = 100, |
| 12 | ErrorModule::FS, ErrorSummary::NotSupported, | 14 | ArchiveNotMounted = 101, |
| 13 | ErrorLevel::Usage); | 15 | FileNotFound = 112, |
| 14 | const ResultCode ERROR_INVALID_OPEN_FLAGS(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, | 16 | PathNotFound = 113, |
| 15 | ErrorSummary::Canceled, ErrorLevel::Status); | 17 | GameCardNotInserted = 141, |
| 16 | const ResultCode ERROR_INVALID_READ_FLAG(ErrorDescription::FS_InvalidReadFlag, ErrorModule::FS, | 18 | NotFound = 120, |
| 17 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 19 | FileAlreadyExists = 180, |
| 18 | const ResultCode ERROR_FILE_NOT_FOUND(ErrorDescription::FS_FileNotFound, ErrorModule::FS, | 20 | DirectoryAlreadyExists = 185, |
| 19 | ErrorSummary::NotFound, ErrorLevel::Status); | 21 | AlreadyExists = 190, |
| 20 | const ResultCode ERROR_PATH_NOT_FOUND(ErrorDescription::FS_PathNotFound, ErrorModule::FS, | 22 | InvalidOpenFlags = 230, |
| 21 | ErrorSummary::NotFound, ErrorLevel::Status); | 23 | DirectoryNotEmpty = 240, |
| 22 | const ResultCode ERROR_NOT_FOUND(ErrorDescription::FS_NotFound, ErrorModule::FS, | 24 | NotAFile = 250, |
| 23 | ErrorSummary::NotFound, ErrorLevel::Status); | 25 | NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive |
| 24 | const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrorDescription::FS_UnexpectedFileOrDirectory, | 26 | ExeFSSectionNotFound = 567, |
| 25 | ErrorModule::FS, ErrorSummary::NotSupported, | 27 | CommandNotAllowed = 630, |
| 26 | ErrorLevel::Usage); | 28 | InvalidReadFlag = 700, |
| 27 | const ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC(ErrorDescription::FS_NotAFile, | 29 | InvalidPath = 702, |
| 28 | ErrorModule::FS, ErrorSummary::Canceled, | 30 | WriteBeyondEnd = 705, |
| 29 | ErrorLevel::Status); | 31 | UnsupportedOpenFlags = 760, |
| 30 | const ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrorDescription::FS_DirectoryAlreadyExists, | 32 | IncorrectExeFSReadSize = 761, |
| 31 | ErrorModule::FS, ErrorSummary::NothingHappened, | 33 | UnexpectedFileOrDirectory = 770, |
| 32 | ErrorLevel::Status); | 34 | }; |
| 33 | const ResultCode ERROR_FILE_ALREADY_EXISTS(ErrorDescription::FS_FileAlreadyExists, ErrorModule::FS, | 35 | } |
| 34 | ErrorSummary::NothingHappened, ErrorLevel::Status); | 36 | |
| 35 | const ResultCode ERROR_ALREADY_EXISTS(ErrorDescription::FS_AlreadyExists, ErrorModule::FS, | 37 | constexpr ResultCode ERROR_INVALID_PATH(ErrCodes::InvalidPath, ErrorModule::FS, |
| 36 | ErrorSummary::NothingHappened, ErrorLevel::Status); | 38 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); |
| 37 | const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpty, ErrorModule::FS, | 39 | constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ErrCodes::UnsupportedOpenFlags, ErrorModule::FS, |
| 38 | ErrorSummary::Canceled, ErrorLevel::Status); | 40 | ErrorSummary::NotSupported, ErrorLevel::Usage); |
| 39 | const ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrorDescription::FS_GameCardNotInserted, | 41 | constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ErrCodes::InvalidOpenFlags, ErrorModule::FS, |
| 40 | ErrorModule::FS, ErrorSummary::NotFound, | 42 | ErrorSummary::Canceled, ErrorLevel::Status); |
| 41 | ErrorLevel::Status); | 43 | constexpr ResultCode ERROR_INVALID_READ_FLAG(ErrCodes::InvalidReadFlag, ErrorModule::FS, |
| 42 | const ResultCode ERROR_INCORRECT_EXEFS_READ_SIZE(ErrorDescription::FS_IncorrectExeFSReadSize, | 44 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); |
| 43 | ErrorModule::FS, ErrorSummary::NotSupported, | 45 | constexpr ResultCode ERROR_FILE_NOT_FOUND(ErrCodes::FileNotFound, ErrorModule::FS, |
| 44 | ErrorLevel::Usage); | 46 | ErrorSummary::NotFound, ErrorLevel::Status); |
| 45 | const ResultCode ERROR_ROMFS_NOT_FOUND(ErrorDescription::FS_RomFSNotFound, ErrorModule::FS, | 47 | constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrCodes::PathNotFound, ErrorModule::FS, |
| 46 | ErrorSummary::NotFound, ErrorLevel::Status); | 48 | ErrorSummary::NotFound, ErrorLevel::Status); |
| 47 | const ResultCode ERROR_COMMAND_NOT_ALLOWED(ErrorDescription::FS_CommandNotAllowed, ErrorModule::FS, | 49 | constexpr ResultCode ERROR_NOT_FOUND(ErrCodes::NotFound, ErrorModule::FS, ErrorSummary::NotFound, |
| 48 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | 50 | ErrorLevel::Status); |
| 49 | const ResultCode ERROR_EXEFS_SECTION_NOT_FOUND(ErrorDescription::FS_ExeFSSectionNotFound, | 51 | constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ErrCodes::UnexpectedFileOrDirectory, |
| 50 | ErrorModule::FS, ErrorSummary::NotFound, | 52 | ErrorModule::FS, ErrorSummary::NotSupported, |
| 51 | ErrorLevel::Status); | 53 | ErrorLevel::Usage); |
| 54 | constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY_SDMC(ErrCodes::NotAFile, ErrorModule::FS, | ||
| 55 | ErrorSummary::Canceled, | ||
| 56 | ErrorLevel::Status); | ||
| 57 | constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ErrCodes::DirectoryAlreadyExists, | ||
| 58 | ErrorModule::FS, ErrorSummary::NothingHappened, | ||
| 59 | ErrorLevel::Status); | ||
| 60 | constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ErrCodes::FileAlreadyExists, ErrorModule::FS, | ||
| 61 | ErrorSummary::NothingHappened, ErrorLevel::Status); | ||
| 62 | constexpr ResultCode ERROR_ALREADY_EXISTS(ErrCodes::AlreadyExists, ErrorModule::FS, | ||
| 63 | ErrorSummary::NothingHappened, ErrorLevel::Status); | ||
| 64 | constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrCodes::DirectoryNotEmpty, ErrorModule::FS, | ||
| 65 | ErrorSummary::Canceled, ErrorLevel::Status); | ||
| 66 | constexpr ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrCodes::GameCardNotInserted, ErrorModule::FS, | ||
| 67 | ErrorSummary::NotFound, ErrorLevel::Status); | ||
| 68 | constexpr ResultCode ERROR_INCORRECT_EXEFS_READ_SIZE(ErrCodes::IncorrectExeFSReadSize, | ||
| 69 | ErrorModule::FS, ErrorSummary::NotSupported, | ||
| 70 | ErrorLevel::Usage); | ||
| 71 | constexpr ResultCode ERROR_ROMFS_NOT_FOUND(ErrCodes::RomFSNotFound, ErrorModule::FS, | ||
| 72 | ErrorSummary::NotFound, ErrorLevel::Status); | ||
| 73 | constexpr ResultCode ERROR_COMMAND_NOT_ALLOWED(ErrCodes::CommandNotAllowed, ErrorModule::FS, | ||
| 74 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 75 | constexpr ResultCode ERROR_EXEFS_SECTION_NOT_FOUND(ErrCodes::ExeFSSectionNotFound, ErrorModule::FS, | ||
| 76 | ErrorSummary::NotFound, ErrorLevel::Status); | ||
| 77 | |||
| 78 | /// Returned when a function is passed an invalid archive handle. | ||
| 79 | constexpr ResultCode ERR_INVALID_ARCHIVE_HANDLE(ErrCodes::ArchiveNotMounted, ErrorModule::FS, | ||
| 80 | ErrorSummary::NotFound, | ||
| 81 | ErrorLevel::Status); // 0xC8804465 | ||
| 82 | constexpr ResultCode ERR_WRITE_BEYOND_END(ErrCodes::WriteBeyondEnd, ErrorModule::FS, | ||
| 83 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Variant of ERROR_NOT_FOUND returned in some places in the code. Unknown if these usages are | ||
| 87 | * correct or a bug. | ||
| 88 | */ | ||
| 89 | constexpr ResultCode ERR_NOT_FOUND_INVALID_STATE(ErrCodes::NotFound, ErrorModule::FS, | ||
| 90 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 91 | constexpr ResultCode ERR_NOT_FORMATTED(ErrCodes::NotFormatted, ErrorModule::FS, | ||
| 92 | ErrorSummary::InvalidState, ErrorLevel::Status); | ||
| 52 | 93 | ||
| 53 | } // namespace FileSys | 94 | } // namespace FileSys |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 5fdb3a7e8..4f7d54a33 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -5,10 +5,10 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <cmath> | 6 | #include <cmath> |
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "core/3ds.h" | ||
| 8 | #include "core/core.h" | 9 | #include "core/core.h" |
| 9 | #include "core/frontend/emu_window.h" | 10 | #include "core/frontend/emu_window.h" |
| 10 | #include "core/settings.h" | 11 | #include "core/settings.h" |
| 11 | #include "video_core/video_core.h" | ||
| 12 | 12 | ||
| 13 | /** | 13 | /** |
| 14 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout | 14 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout |
| @@ -38,11 +38,9 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
| 38 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | 38 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) |
| 39 | return; | 39 | return; |
| 40 | 40 | ||
| 41 | touch_x = VideoCore::kScreenBottomWidth * | 41 | touch_x = Core::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) / |
| 42 | (framebuffer_x - framebuffer_layout.bottom_screen.left) / | ||
| 43 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); | 42 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); |
| 44 | touch_y = VideoCore::kScreenBottomHeight * | 43 | touch_y = Core::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) / |
| 45 | (framebuffer_y - framebuffer_layout.bottom_screen.top) / | ||
| 46 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); | 44 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); |
| 47 | 45 | ||
| 48 | touch_pressed = true; | 46 | touch_pressed = true; |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 36f2667fa..9414123a4 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | #include <tuple> | 8 | #include <tuple> |
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/framebuffer_layout.h" | ||
| 12 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 12 | #include "core/frontend/framebuffer_layout.h" | ||
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| 15 | * Abstraction class used to provide an interface between emulation code and the frontend | 15 | * Abstraction class used to provide an interface between emulation code and the frontend |
diff --git a/src/common/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index a2a0e7dad..d2d02f9ff 100644 --- a/src/common/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp | |||
| @@ -5,16 +5,20 @@ | |||
| 5 | #include <cmath> | 5 | #include <cmath> |
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/framebuffer_layout.h" | 8 | #include "core/3ds.h" |
| 9 | #include "core/frontend/framebuffer_layout.h" | ||
| 9 | #include "core/settings.h" | 10 | #include "core/settings.h" |
| 10 | #include "video_core/video_core.h" | ||
| 11 | 11 | ||
| 12 | namespace Layout { | 12 | namespace Layout { |
| 13 | 13 | ||
| 14 | static const float TOP_SCREEN_ASPECT_RATIO = | 14 | static const float TOP_SCREEN_ASPECT_RATIO = |
| 15 | static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth; | 15 | static_cast<float>(Core::kScreenTopHeight) / Core::kScreenTopWidth; |
| 16 | static const float BOT_SCREEN_ASPECT_RATIO = | 16 | static const float BOT_SCREEN_ASPECT_RATIO = |
| 17 | static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth; | 17 | static_cast<float>(Core::kScreenBottomHeight) / Core::kScreenBottomWidth; |
| 18 | |||
| 19 | float FramebufferLayout::GetScalingRatio() const { | ||
| 20 | return static_cast<float>(top_screen.GetWidth()) / Core::kScreenTopWidth; | ||
| 21 | } | ||
| 18 | 22 | ||
| 19 | // Finds the largest size subrectangle contained in window area that is confined to the aspect ratio | 23 | // Finds the largest size subrectangle contained in window area that is confined to the aspect ratio |
| 20 | template <class T> | 24 | template <class T> |
| @@ -106,10 +110,10 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped | |||
| 106 | float window_aspect_ratio = static_cast<float>(height) / width; | 110 | float window_aspect_ratio = static_cast<float>(height) / width; |
| 107 | float emulation_aspect_ratio = | 111 | float emulation_aspect_ratio = |
| 108 | swapped | 112 | swapped |
| 109 | ? VideoCore::kScreenBottomHeight * 4 / | 113 | ? Core::kScreenBottomHeight * 4 / |
| 110 | (VideoCore::kScreenBottomWidth * 4.0f + VideoCore::kScreenTopWidth) | 114 | (Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth) |
| 111 | : VideoCore::kScreenTopHeight * 4 / | 115 | : Core::kScreenTopHeight * 4 / |
| 112 | (VideoCore::kScreenTopWidth * 4.0f + VideoCore::kScreenBottomWidth); | 116 | (Core::kScreenTopWidth * 4.0f + Core::kScreenBottomWidth); |
| 113 | float large_screen_aspect_ratio = swapped ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO; | 117 | float large_screen_aspect_ratio = swapped ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO; |
| 114 | float small_screen_aspect_ratio = swapped ? TOP_SCREEN_ASPECT_RATIO : BOT_SCREEN_ASPECT_RATIO; | 118 | float small_screen_aspect_ratio = swapped ? TOP_SCREEN_ASPECT_RATIO : BOT_SCREEN_ASPECT_RATIO; |
| 115 | 119 | ||
diff --git a/src/common/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index f1df5c55a..9a7738969 100644 --- a/src/common/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h | |||
| @@ -5,7 +5,9 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/math_util.h" | 7 | #include "common/math_util.h" |
| 8 | |||
| 8 | namespace Layout { | 9 | namespace Layout { |
| 10 | |||
| 9 | /// Describes the layout of the window framebuffer (size and top/bottom screen positions) | 11 | /// Describes the layout of the window framebuffer (size and top/bottom screen positions) |
| 10 | struct FramebufferLayout { | 12 | struct FramebufferLayout { |
| 11 | unsigned width; | 13 | unsigned width; |
| @@ -14,6 +16,12 @@ struct FramebufferLayout { | |||
| 14 | bool bottom_screen_enabled; | 16 | bool bottom_screen_enabled; |
| 15 | MathUtil::Rectangle<unsigned> top_screen; | 17 | MathUtil::Rectangle<unsigned> top_screen; |
| 16 | MathUtil::Rectangle<unsigned> bottom_screen; | 18 | MathUtil::Rectangle<unsigned> bottom_screen; |
| 19 | |||
| 20 | /** | ||
| 21 | * Returns the ration of pixel size of the top screen, compared to the native size of the 3DS | ||
| 22 | * screen. | ||
| 23 | */ | ||
| 24 | float GetScalingRatio() const; | ||
| 17 | }; | 25 | }; |
| 18 | 26 | ||
| 19 | /** | 27 | /** |
| @@ -52,4 +60,5 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swap | |||
| 52 | * @return Newly created FramebufferLayout object with default screen regions initialized | 60 | * @return Newly created FramebufferLayout object with default screen regions initialized |
| 53 | */ | 61 | */ |
| 54 | FramebufferLayout CustomFrameLayout(unsigned width, unsigned height); | 62 | FramebufferLayout CustomFrameLayout(unsigned width, unsigned height); |
| 55 | } | 63 | |
| 64 | } // namespace Layout | ||
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index 07c7f5b99..89f08daa2 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/shared_memory.h" | 12 | #include "core/hle/kernel/shared_memory.h" |
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | #include "video_core/video_core.h" | ||
| 15 | 14 | ||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 17 | 16 | ||
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index 059297fbc..fdf8807b0 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include "core/hle/service/gsp_gpu.h" | 14 | #include "core/hle/service/gsp_gpu.h" |
| 15 | #include "core/hle/service/hid/hid.h" | 15 | #include "core/hle/service/hid/hid.h" |
| 16 | #include "core/memory.h" | 16 | #include "core/memory.h" |
| 17 | #include "video_core/video_core.h" | ||
| 18 | 17 | ||
| 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 20 | 19 | ||
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index f6eb900f0..18b6e7017 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -53,7 +53,7 @@ void Wrap() { | |||
| 53 | FuncReturn(retval); | 53 | FuncReturn(retval); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | template <ResultCode func(u32*, s32, u32, u32, u32, s32)> | 56 | template <ResultCode func(u32*, u32, u32, u32, u32, s32)> |
| 57 | void Wrap() { | 57 | void Wrap() { |
| 58 | u32 param_1 = 0; | 58 | u32 param_1 = 0; |
| 59 | u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; | 59 | u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; |
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 3a5d481a5..303ca090d 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/hle/kernel/errors.h" | ||
| 8 | #include "core/hle/kernel/thread.h" | 9 | #include "core/hle/kernel/thread.h" |
| 9 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 10 | 11 | ||
| @@ -43,6 +44,12 @@ inline u32* GetStaticBuffers(const int offset = 0) { | |||
| 43 | 44 | ||
| 44 | namespace IPC { | 45 | namespace IPC { |
| 45 | 46 | ||
| 47 | // These errors are commonly returned by invalid IPC translations, so alias them here for | ||
| 48 | // convenience. | ||
| 49 | // TODO(yuriks): These will probably go away once translation is implemented inside the kernel. | ||
| 50 | using Kernel::ERR_INVALID_BUFFER_DESCRIPTOR; | ||
| 51 | constexpr auto ERR_INVALID_HANDLE = Kernel::ERR_INVALID_HANDLE_OS; | ||
| 52 | |||
| 46 | enum DescriptorType : u32 { | 53 | enum DescriptorType : u32 { |
| 47 | // Buffer related desciptors types (mask : 0x0F) | 54 | // Buffer related desciptors types (mask : 0x0F) |
| 48 | StaticBuffer = 0x02, | 55 | StaticBuffer = 0x02, |
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.cpp b/src/core/hle/kernel/address_arbiter.cpp index 01fab123e..776d342f0 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 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/kernel/address_arbiter.h" | 7 | #include "core/hle/kernel/address_arbiter.h" |
| 8 | #include "core/hle/kernel/errors.h" | ||
| 8 | #include "core/hle/kernel/thread.h" | 9 | #include "core/hle/kernel/thread.h" |
| 9 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 10 | 11 | ||
| @@ -74,8 +75,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 74 | 75 | ||
| 75 | default: | 76 | default: |
| 76 | LOG_ERROR(Kernel, "unknown type=%d", type); | 77 | LOG_ERROR(Kernel, "unknown type=%d", type); |
| 77 | return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, | 78 | return ERR_INVALID_ENUM_VALUE_FND; |
| 78 | ErrorSummary::WrongArgument, ErrorLevel::Usage); | ||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | // The calls that use a timeout seem to always return a Timeout error even if they did not put | 81 | // The calls that use a timeout seem to always return a Timeout error even if they did not put |
| @@ -83,8 +83,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 83 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || | 83 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || |
| 84 | type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { | 84 | type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { |
| 85 | 85 | ||
| 86 | return ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged, | 86 | return RESULT_TIMEOUT; |
| 87 | ErrorLevel::Info); | ||
| 88 | } | 87 | } |
| 89 | return RESULT_SUCCESS; | 88 | return RESULT_SUCCESS; |
| 90 | } | 89 | } |
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 ddcf4c916..ce5d94e99 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 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" | ||
| 9 | #include "core/hle/kernel/hle_ipc.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 9 | #include "core/hle/kernel/server_port.h" | 11 | #include "core/hle/kernel/server_port.h" |
| 10 | #include "core/hle/kernel/server_session.h" | 12 | #include "core/hle/kernel/server_session.h" |
| @@ -19,26 +21,22 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { | |||
| 19 | // AcceptSession before returning from this call. | 21 | // AcceptSession before returning from this call. |
| 20 | 22 | ||
| 21 | if (active_sessions >= max_sessions) { | 23 | if (active_sessions >= max_sessions) { |
| 22 | return ResultCode(ErrorDescription::MaxConnectionsReached, ErrorModule::OS, | 24 | return ERR_MAX_CONNECTIONS_REACHED; |
| 23 | ErrorSummary::WouldBlock, ErrorLevel::Temporary); | ||
| 24 | } | 25 | } |
| 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 e297b7464..fef97af1f 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -5,7 +5,10 @@ | |||
| 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" |
| 11 | #include "core/hle/kernel/session.h" | ||
| 9 | 12 | ||
| 10 | namespace Kernel { | 13 | namespace Kernel { |
| 11 | 14 | ||
| @@ -14,9 +17,13 @@ ClientSession::~ClientSession() { | |||
| 14 | // This destructor will be called automatically when the last ClientSession handle is closed by | 17 | // This destructor will be called automatically when the last ClientSession handle is closed by |
| 15 | // the emulated application. | 18 | // the emulated application. |
| 16 | 19 | ||
| 17 | if (parent->server) { | 20 | // Local references to ServerSession and SessionRequestHandler are necessary to guarantee they |
| 18 | if (parent->server->hle_handler) | 21 | // will be kept alive until after ClientDisconnected() returns. |
| 19 | parent->server->hle_handler->ClientDisconnected(parent->server); | 22 | SharedPtr<ServerSession> server = parent->server; |
| 23 | if (server) { | ||
| 24 | std::shared_ptr<SessionRequestHandler> hle_handler = server->hle_handler; | ||
| 25 | if (hle_handler) | ||
| 26 | hle_handler->ClientDisconnected(server); | ||
| 20 | 27 | ||
| 21 | // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set | 28 | // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set |
| 22 | // their WaitSynchronization result to 0xC920181A. | 29 | // their WaitSynchronization result to 0xC920181A. |
| @@ -26,12 +33,13 @@ ClientSession::~ClientSession() { | |||
| 26 | } | 33 | } |
| 27 | 34 | ||
| 28 | ResultCode ClientSession::SendSyncRequest() { | 35 | ResultCode ClientSession::SendSyncRequest() { |
| 29 | // Signal the server session that new data is available | 36 | // Keep ServerSession alive until we're done working with it. |
| 30 | if (parent->server) | 37 | SharedPtr<ServerSession> server = parent->server; |
| 31 | return parent->server->HandleSyncRequest(); | 38 | if (server == nullptr) |
| 39 | return ERR_SESSION_CLOSED_BY_REMOTE; | ||
| 32 | 40 | ||
| 33 | return ResultCode(ErrorDescription::SessionClosedByRemote, ErrorModule::OS, | 41 | // Signal the server session that new data is available |
| 34 | ErrorSummary::Canceled, ErrorLevel::Status); | 42 | return server->HandleSyncRequest(); |
| 35 | } | 43 | } |
| 36 | 44 | ||
| 37 | } // namespace | 45 | } // namespace |
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/errors.h b/src/core/hle/kernel/errors.h new file mode 100644 index 000000000..b3b60e7df --- /dev/null +++ b/src/core/hle/kernel/errors.h | |||
| @@ -0,0 +1,98 @@ | |||
| 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 "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | namespace ErrCodes { | ||
| 12 | enum { | ||
| 13 | OutOfHandles = 19, | ||
| 14 | SessionClosedByRemote = 26, | ||
| 15 | PortNameTooLong = 30, | ||
| 16 | WrongPermission = 46, | ||
| 17 | InvalidBufferDescriptor = 48, | ||
| 18 | MaxConnectionsReached = 52, | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | // WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always | ||
| 23 | // double check that the code matches before re-using the constant. | ||
| 24 | |||
| 25 | constexpr ResultCode ERR_OUT_OF_HANDLES(ErrCodes::OutOfHandles, ErrorModule::Kernel, | ||
| 26 | ErrorSummary::OutOfResource, | ||
| 27 | ErrorLevel::Permanent); // 0xD8600413 | ||
| 28 | constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrCodes::SessionClosedByRemote, ErrorModule::OS, | ||
| 29 | ErrorSummary::Canceled, | ||
| 30 | ErrorLevel::Status); // 0xC920181A | ||
| 31 | constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrCodes::PortNameTooLong, ErrorModule::OS, | ||
| 32 | ErrorSummary::InvalidArgument, | ||
| 33 | ErrorLevel::Usage); // 0xE0E0181E | ||
| 34 | constexpr ResultCode ERR_WRONG_PERMISSION(ErrCodes::WrongPermission, ErrorModule::OS, | ||
| 35 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 36 | constexpr ResultCode ERR_INVALID_BUFFER_DESCRIPTOR(ErrCodes::InvalidBufferDescriptor, | ||
| 37 | ErrorModule::OS, ErrorSummary::WrongArgument, | ||
| 38 | ErrorLevel::Permanent); | ||
| 39 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrCodes::MaxConnectionsReached, ErrorModule::OS, | ||
| 40 | ErrorSummary::WouldBlock, | ||
| 41 | ErrorLevel::Temporary); // 0xD0401834 | ||
| 42 | |||
| 43 | constexpr ResultCode ERR_NOT_AUTHORIZED(ErrorDescription::NotAuthorized, ErrorModule::OS, | ||
| 44 | ErrorSummary::WrongArgument, | ||
| 45 | ErrorLevel::Permanent); // 0xD9001BEA | ||
| 46 | constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, | ||
| 47 | ErrorSummary::InvalidArgument, | ||
| 48 | ErrorLevel::Permanent); // 0xD8E007ED | ||
| 49 | constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(ErrorDescription::InvalidEnumValue, | ||
| 50 | ErrorModule::FND, ErrorSummary::InvalidArgument, | ||
| 51 | ErrorLevel::Permanent); // 0xD8E093ED | ||
| 52 | constexpr ResultCode ERR_INVALID_COMBINATION(ErrorDescription::InvalidCombination, ErrorModule::OS, | ||
| 53 | ErrorSummary::InvalidArgument, | ||
| 54 | ErrorLevel::Usage); // 0xE0E01BEE | ||
| 55 | constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorDescription::InvalidCombination, | ||
| 56 | ErrorModule::Kernel, | ||
| 57 | ErrorSummary::WrongArgument, | ||
| 58 | ErrorLevel::Permanent); // 0xD90007EE | ||
| 59 | constexpr ResultCode ERR_MISALIGNED_ADDRESS(ErrorDescription::MisalignedAddress, ErrorModule::OS, | ||
| 60 | ErrorSummary::InvalidArgument, | ||
| 61 | ErrorLevel::Usage); // 0xE0E01BF1 | ||
| 62 | constexpr ResultCode ERR_MISALIGNED_SIZE(ErrorDescription::MisalignedSize, ErrorModule::OS, | ||
| 63 | ErrorSummary::InvalidArgument, | ||
| 64 | ErrorLevel::Usage); // 0xE0E01BF2 | ||
| 65 | constexpr ResultCode ERR_OUT_OF_MEMORY(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | ||
| 66 | ErrorSummary::OutOfResource, | ||
| 67 | ErrorLevel::Permanent); // 0xD86007F3 | ||
| 68 | constexpr ResultCode ERR_NOT_IMPLEMENTED(ErrorDescription::NotImplemented, ErrorModule::OS, | ||
| 69 | ErrorSummary::InvalidArgument, | ||
| 70 | ErrorLevel::Usage); // 0xE0E01BF4 | ||
| 71 | constexpr ResultCode ERR_INVALID_ADDRESS(ErrorDescription::InvalidAddress, ErrorModule::OS, | ||
| 72 | ErrorSummary::InvalidArgument, | ||
| 73 | ErrorLevel::Usage); // 0xE0E01BF5 | ||
| 74 | constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorDescription::InvalidAddress, ErrorModule::OS, | ||
| 75 | ErrorSummary::InvalidState, | ||
| 76 | ErrorLevel::Usage); // 0xE0A01BF5 | ||
| 77 | constexpr ResultCode ERR_INVALID_POINTER(ErrorDescription::InvalidPointer, ErrorModule::Kernel, | ||
| 78 | ErrorSummary::InvalidArgument, | ||
| 79 | ErrorLevel::Permanent); // 0xD8E007F6 | ||
| 80 | constexpr ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, | ||
| 81 | ErrorSummary::InvalidArgument, | ||
| 82 | ErrorLevel::Permanent); // 0xD8E007F7 | ||
| 83 | /// Alternate code returned instead of ERR_INVALID_HANDLE in some code paths. | ||
| 84 | constexpr ResultCode ERR_INVALID_HANDLE_OS(ErrorDescription::InvalidHandle, ErrorModule::OS, | ||
| 85 | ErrorSummary::WrongArgument, | ||
| 86 | ErrorLevel::Permanent); // 0xD9001BF7 | ||
| 87 | constexpr ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, | ||
| 88 | ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA | ||
| 89 | constexpr ResultCode ERR_OUT_OF_RANGE(ErrorDescription::OutOfRange, ErrorModule::OS, | ||
| 90 | ErrorSummary::InvalidArgument, | ||
| 91 | ErrorLevel::Usage); // 0xE0E01BFD | ||
| 92 | constexpr ResultCode ERR_OUT_OF_RANGE_KERNEL(ErrorDescription::OutOfRange, ErrorModule::Kernel, | ||
| 93 | ErrorSummary::InvalidArgument, | ||
| 94 | ErrorLevel::Permanent); // 0xD8E007FD | ||
| 95 | constexpr ResultCode RESULT_TIMEOUT(ErrorDescription::Timeout, ErrorModule::OS, | ||
| 96 | ErrorSummary::StatusChanged, ErrorLevel::Info); | ||
| 97 | |||
| 98 | } // namespace Kernel | ||
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..a60b8ef00 --- /dev/null +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -0,0 +1,26 @@ | |||
| 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 | HLERequestContext::~HLERequestContext() = default; | ||
| 25 | |||
| 26 | } // 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..c30184eab --- /dev/null +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -0,0 +1,87 @@ | |||
| 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 | #include "core/hle/kernel/server_session.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | class ServiceFrameworkBase; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Interface implemented by HLE Session handlers. | ||
| 20 | * This can be provided to a ServerSession in order to hook into several relevant events | ||
| 21 | * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. | ||
| 22 | */ | ||
| 23 | class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { | ||
| 24 | public: | ||
| 25 | virtual ~SessionRequestHandler() = default; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Handles a sync request from the emulated application. | ||
| 29 | * @param server_session The ServerSession that was triggered for this sync request, | ||
| 30 | * it should be used to differentiate which client (As in ClientSession) we're answering to. | ||
| 31 | * TODO(Subv): Use a wrapper structure to hold all the information relevant to | ||
| 32 | * this request (ServerSession, Originator thread, Translated command buffer, etc). | ||
| 33 | * @returns ResultCode the result code of the translate operation. | ||
| 34 | */ | ||
| 35 | virtual void HandleSyncRequest(SharedPtr<ServerSession> server_session) = 0; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Signals that a client has just connected to this HLE handler and keeps the | ||
| 39 | * associated ServerSession alive for the duration of the connection. | ||
| 40 | * @param server_session Owning pointer to the ServerSession associated with the connection. | ||
| 41 | */ | ||
| 42 | void ClientConnected(SharedPtr<ServerSession> server_session); | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Signals that a client has just disconnected from this HLE handler and releases the | ||
| 46 | * associated ServerSession. | ||
| 47 | * @param server_session ServerSession associated with the connection. | ||
| 48 | */ | ||
| 49 | void ClientDisconnected(SharedPtr<ServerSession> server_session); | ||
| 50 | |||
| 51 | protected: | ||
| 52 | /// List of sessions that are connected to this handler. | ||
| 53 | /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list | ||
| 54 | // for the duration of the connection. | ||
| 55 | std::vector<SharedPtr<ServerSession>> connected_sessions; | ||
| 56 | }; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Class containing information about an in-flight IPC request being handled by an HLE service | ||
| 60 | * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and | ||
| 61 | * when possible use the APIs in this class to service the request. | ||
| 62 | */ | ||
| 63 | class HLERequestContext { | ||
| 64 | public: | ||
| 65 | ~HLERequestContext(); | ||
| 66 | |||
| 67 | /// Returns a pointer to the IPC command buffer for this request. | ||
| 68 | u32* CommandBuffer() const { | ||
| 69 | return cmd_buf; | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 73 | * Returns the session through which this request was made. This can be used as a map key to | ||
| 74 | * access per-client data on services. | ||
| 75 | */ | ||
| 76 | SharedPtr<ServerSession> Session() const { | ||
| 77 | return session; | ||
| 78 | } | ||
| 79 | |||
| 80 | private: | ||
| 81 | friend class Service::ServiceFrameworkBase; | ||
| 82 | |||
| 83 | u32* cmd_buf = nullptr; | ||
| 84 | SharedPtr<ServerSession> session; | ||
| 85 | }; | ||
| 86 | |||
| 87 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f599916f0..7470a97ca 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -2,10 +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" |
| 6 | #include "core/hle/kernel/handle_table.h" | ||
| 9 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/kernel/memory.h" | 8 | #include "core/hle/kernel/memory.h" |
| 11 | #include "core/hle/kernel/process.h" | 9 | #include "core/hle/kernel/process.h" |
| @@ -17,165 +15,6 @@ | |||
| 17 | namespace Kernel { | 15 | namespace Kernel { |
| 18 | 16 | ||
| 19 | unsigned int Object::next_object_id; | 17 | unsigned int Object::next_object_id; |
| 20 | HandleTable g_handle_table; | ||
| 21 | |||
| 22 | void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { | ||
| 23 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | ||
| 24 | if (itr == waiting_threads.end()) | ||
| 25 | waiting_threads.push_back(std::move(thread)); | ||
| 26 | } | ||
| 27 | |||
| 28 | void WaitObject::RemoveWaitingThread(Thread* thread) { | ||
| 29 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | ||
| 30 | // If a thread passed multiple handles to the same object, | ||
| 31 | // the kernel might attempt to remove the thread from the object's | ||
| 32 | // waiting threads list multiple times. | ||
| 33 | if (itr != waiting_threads.end()) | ||
| 34 | waiting_threads.erase(itr); | ||
| 35 | } | ||
| 36 | |||
| 37 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | ||
| 38 | Thread* candidate = nullptr; | ||
| 39 | s32 candidate_priority = THREADPRIO_LOWEST + 1; | ||
| 40 | |||
| 41 | for (const auto& thread : waiting_threads) { | ||
| 42 | // The list of waiting threads must not contain threads that are not waiting to be awakened. | ||
| 43 | ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || | ||
| 44 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL, | ||
| 45 | "Inconsistent thread statuses in waiting_threads"); | ||
| 46 | |||
| 47 | if (thread->current_priority >= candidate_priority) | ||
| 48 | continue; | ||
| 49 | |||
| 50 | if (ShouldWait(thread.get())) | ||
| 51 | continue; | ||
| 52 | |||
| 53 | // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or | ||
| 54 | // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready. | ||
| 55 | bool ready_to_run = true; | ||
| 56 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) { | ||
| 57 | ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), | ||
| 58 | [&thread](const SharedPtr<WaitObject>& object) { | ||
| 59 | return object->ShouldWait(thread.get()); | ||
| 60 | }); | ||
| 61 | } | ||
| 62 | |||
| 63 | if (ready_to_run) { | ||
| 64 | candidate = thread.get(); | ||
| 65 | candidate_priority = thread->current_priority; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | return candidate; | ||
| 70 | } | ||
| 71 | |||
| 72 | void WaitObject::WakeupAllWaitingThreads() { | ||
| 73 | while (auto thread = GetHighestPriorityReadyThread()) { | ||
| 74 | if (!thread->IsSleepingOnWaitAll()) { | ||
| 75 | Acquire(thread.get()); | ||
| 76 | // Set the output index of the WaitSynchronizationN call to the index of this object. | ||
| 77 | if (thread->wait_set_output) { | ||
| 78 | thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); | ||
| 79 | thread->wait_set_output = false; | ||
| 80 | } | ||
| 81 | } else { | ||
| 82 | for (auto& object : thread->wait_objects) { | ||
| 83 | object->Acquire(thread.get()); | ||
| 84 | } | ||
| 85 | // Note: This case doesn't update the output index of WaitSynchronizationN. | ||
| 86 | } | ||
| 87 | |||
| 88 | for (auto& object : thread->wait_objects) | ||
| 89 | object->RemoveWaitingThread(thread.get()); | ||
| 90 | thread->wait_objects.clear(); | ||
| 91 | |||
| 92 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 93 | thread->ResumeFromWait(); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { | ||
| 98 | return waiting_threads; | ||
| 99 | } | ||
| 100 | |||
| 101 | HandleTable::HandleTable() { | ||
| 102 | next_generation = 1; | ||
| 103 | Clear(); | ||
| 104 | } | ||
| 105 | |||
| 106 | ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | ||
| 107 | DEBUG_ASSERT(obj != nullptr); | ||
| 108 | |||
| 109 | u16 slot = next_free_slot; | ||
| 110 | if (slot >= generations.size()) { | ||
| 111 | LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); | ||
| 112 | return ERR_OUT_OF_HANDLES; | ||
| 113 | } | ||
| 114 | next_free_slot = generations[slot]; | ||
| 115 | |||
| 116 | u16 generation = next_generation++; | ||
| 117 | |||
| 118 | // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. | ||
| 119 | // CTR-OS doesn't use generation 0, so skip straight to 1. | ||
| 120 | if (next_generation >= (1 << 15)) | ||
| 121 | next_generation = 1; | ||
| 122 | |||
| 123 | generations[slot] = generation; | ||
| 124 | objects[slot] = std::move(obj); | ||
| 125 | |||
| 126 | Handle handle = generation | (slot << 15); | ||
| 127 | return MakeResult<Handle>(handle); | ||
| 128 | } | ||
| 129 | |||
| 130 | ResultVal<Handle> HandleTable::Duplicate(Handle handle) { | ||
| 131 | SharedPtr<Object> object = GetGeneric(handle); | ||
| 132 | if (object == nullptr) { | ||
| 133 | LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); | ||
| 134 | return ERR_INVALID_HANDLE; | ||
| 135 | } | ||
| 136 | return Create(std::move(object)); | ||
| 137 | } | ||
| 138 | |||
| 139 | ResultCode HandleTable::Close(Handle handle) { | ||
| 140 | if (!IsValid(handle)) | ||
| 141 | return ERR_INVALID_HANDLE; | ||
| 142 | |||
| 143 | u16 slot = GetSlot(handle); | ||
| 144 | |||
| 145 | objects[slot] = nullptr; | ||
| 146 | |||
| 147 | generations[slot] = next_free_slot; | ||
| 148 | next_free_slot = slot; | ||
| 149 | return RESULT_SUCCESS; | ||
| 150 | } | ||
| 151 | |||
| 152 | bool HandleTable::IsValid(Handle handle) const { | ||
| 153 | size_t slot = GetSlot(handle); | ||
| 154 | u16 generation = GetGeneration(handle); | ||
| 155 | |||
| 156 | return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; | ||
| 157 | } | ||
| 158 | |||
| 159 | SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { | ||
| 160 | if (handle == CurrentThread) { | ||
| 161 | return GetCurrentThread(); | ||
| 162 | } else if (handle == CurrentProcess) { | ||
| 163 | return g_current_process; | ||
| 164 | } | ||
| 165 | |||
| 166 | if (!IsValid(handle)) { | ||
| 167 | return nullptr; | ||
| 168 | } | ||
| 169 | return objects[GetSlot(handle)]; | ||
| 170 | } | ||
| 171 | |||
| 172 | void HandleTable::Clear() { | ||
| 173 | for (u16 i = 0; i < MAX_COUNT; ++i) { | ||
| 174 | generations[i] = i + 1; | ||
| 175 | objects[i] = nullptr; | ||
| 176 | } | ||
| 177 | next_free_slot = 0; | ||
| 178 | } | ||
| 179 | 18 | ||
| 180 | /// Initialize the kernel | 19 | /// Initialize the kernel |
| 181 | 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 bb8b99bb5..9cf288b08 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -4,33 +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 | // TODO: Verify code | ||
| 23 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | ||
| 24 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); | ||
| 25 | // TOOD: Verify code | ||
| 26 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, | ||
| 27 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 28 | |||
| 29 | enum KernelHandle : Handle { | ||
| 30 | CurrentThread = 0xFFFF8000, | ||
| 31 | CurrentProcess = 0xFFFF8001, | ||
| 32 | }; | ||
| 33 | |||
| 34 | enum class HandleType : u32 { | 17 | enum class HandleType : u32 { |
| 35 | Unknown, | 18 | Unknown, |
| 36 | Event, | 19 | Event, |
| @@ -128,170 +111,17 @@ inline void intrusive_ptr_release(Object* object) { | |||
| 128 | template <typename T> | 111 | template <typename T> |
| 129 | using SharedPtr = boost::intrusive_ptr<T>; | 112 | using SharedPtr = boost::intrusive_ptr<T>; |
| 130 | 113 | ||
| 131 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 132 | class WaitObject : public Object { | ||
| 133 | public: | ||
| 134 | /** | ||
| 135 | * Check if the specified thread should wait until the object is available | ||
| 136 | * @param thread The thread about which we're deciding. | ||
| 137 | * @return True if the current thread should wait due to this object being unavailable | ||
| 138 | */ | ||
| 139 | virtual bool ShouldWait(Thread* thread) const = 0; | ||
| 140 | |||
| 141 | /// Acquire/lock the object for the specified thread if it is available | ||
| 142 | virtual void Acquire(Thread* thread) = 0; | ||
| 143 | |||
| 144 | /** | ||
| 145 | * Add a thread to wait on this object | ||
| 146 | * @param thread Pointer to thread to add | ||
| 147 | */ | ||
| 148 | virtual void AddWaitingThread(SharedPtr<Thread> thread); | ||
| 149 | |||
| 150 | /** | ||
| 151 | * Removes a thread from waiting on this object (e.g. if it was resumed already) | ||
| 152 | * @param thread Pointer to thread to remove | ||
| 153 | */ | ||
| 154 | virtual void RemoveWaitingThread(Thread* thread); | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Wake up all threads waiting on this object that can be awoken, in priority order, | ||
| 158 | * and set the synchronization result and output of the thread. | ||
| 159 | */ | ||
| 160 | virtual void WakeupAllWaitingThreads(); | ||
| 161 | |||
| 162 | /// Obtains the highest priority thread that is ready to run from this object's waiting list. | ||
| 163 | SharedPtr<Thread> GetHighestPriorityReadyThread(); | ||
| 164 | |||
| 165 | /// Get a const reference to the waiting threads list for debug use | ||
| 166 | const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; | ||
| 167 | |||
| 168 | private: | ||
| 169 | /// Threads waiting for this object to become available | ||
| 170 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 171 | }; | ||
| 172 | |||
| 173 | /** | 114 | /** |
| 174 | * 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. |
| 175 | * 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. |
| 176 | * emulated process. it has been designed so that it follows the same handle format and has | ||
| 177 | * approximately the same restrictions as the handle manager in the CTR-OS. | ||
| 178 | * | ||
| 179 | * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0). | ||
| 180 | * The slot index is used to index into the arrays in this class to access the data corresponding | ||
| 181 | * to the Handle. | ||
| 182 | * | ||
| 183 | * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter | ||
| 184 | * is kept and incremented every time a Handle is created. This is the Handle's "generation". The | ||
| 185 | * value of the counter is stored into the Handle as well as in the handle table (in the | ||
| 186 | * "generations" array). When looking up a handle, the Handle's generation must match with the | ||
| 187 | * value stored on the class, otherwise the Handle is considered invalid. | ||
| 188 | * | ||
| 189 | * To find free slots when allocating a Handle without needing to scan the entire object array, the | ||
| 190 | * generations field of unallocated slots is re-purposed as a linked list of indices to free slots. | ||
| 191 | * When a Handle is created, an index is popped off the list and used for the new Handle. When it | ||
| 192 | * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is | ||
| 193 | * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been | ||
| 194 | * verified and isn't likely to cause any problems. | ||
| 195 | */ | 117 | */ |
| 196 | class HandleTable final : NonCopyable { | 118 | template <typename T> |
| 197 | public: | 119 | inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { |
| 198 | HandleTable(); | 120 | if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { |
| 199 | 121 | return boost::static_pointer_cast<T>(std::move(object)); | |
| 200 | /** | ||
| 201 | * Allocates a handle for the given object. | ||
| 202 | * @return The created Handle or one of the following errors: | ||
| 203 | * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded. | ||
| 204 | */ | ||
| 205 | ResultVal<Handle> Create(SharedPtr<Object> obj); | ||
| 206 | |||
| 207 | /** | ||
| 208 | * Returns a new handle that points to the same object as the passed in handle. | ||
| 209 | * @return The duplicated Handle or one of the following errors: | ||
| 210 | * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. | ||
| 211 | * - Any errors returned by `Create()`. | ||
| 212 | */ | ||
| 213 | ResultVal<Handle> Duplicate(Handle handle); | ||
| 214 | |||
| 215 | /** | ||
| 216 | * Closes a handle, removing it from the table and decreasing the object's ref-count. | ||
| 217 | * @return `RESULT_SUCCESS` or one of the following errors: | ||
| 218 | * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. | ||
| 219 | */ | ||
| 220 | ResultCode Close(Handle handle); | ||
| 221 | |||
| 222 | /// Checks if a handle is valid and points to an existing object. | ||
| 223 | bool IsValid(Handle handle) const; | ||
| 224 | |||
| 225 | /** | ||
| 226 | * Looks up a handle. | ||
| 227 | * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. | ||
| 228 | */ | ||
| 229 | SharedPtr<Object> GetGeneric(Handle handle) const; | ||
| 230 | |||
| 231 | /** | ||
| 232 | * Looks up a handle while verifying its type. | ||
| 233 | * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its | ||
| 234 | * type differs from the handle type `T::HANDLE_TYPE`. | ||
| 235 | */ | ||
| 236 | template <class T> | ||
| 237 | SharedPtr<T> Get(Handle handle) const { | ||
| 238 | SharedPtr<Object> object = GetGeneric(handle); | ||
| 239 | if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { | ||
| 240 | return boost::static_pointer_cast<T>(std::move(object)); | ||
| 241 | } | ||
| 242 | return nullptr; | ||
| 243 | } | ||
| 244 | |||
| 245 | /** | ||
| 246 | * Looks up a handle while verifying that it is an object that a thread can wait on | ||
| 247 | * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or it is | ||
| 248 | * not a waitable object. | ||
| 249 | */ | ||
| 250 | SharedPtr<WaitObject> GetWaitObject(Handle handle) const { | ||
| 251 | SharedPtr<Object> object = GetGeneric(handle); | ||
| 252 | if (object != nullptr && object->IsWaitable()) { | ||
| 253 | return boost::static_pointer_cast<WaitObject>(std::move(object)); | ||
| 254 | } | ||
| 255 | return nullptr; | ||
| 256 | } | ||
| 257 | |||
| 258 | /// Closes all handles held in this table. | ||
| 259 | void Clear(); | ||
| 260 | |||
| 261 | private: | ||
| 262 | /** | ||
| 263 | * This is the maximum limit of handles allowed per process in CTR-OS. It can be further | ||
| 264 | * reduced by ExHeader values, but this is not emulated here. | ||
| 265 | */ | ||
| 266 | static const size_t MAX_COUNT = 4096; | ||
| 267 | |||
| 268 | static u16 GetSlot(Handle handle) { | ||
| 269 | return handle >> 15; | ||
| 270 | } | ||
| 271 | static u16 GetGeneration(Handle handle) { | ||
| 272 | return handle & 0x7FFF; | ||
| 273 | } | 122 | } |
| 274 | 123 | return nullptr; | |
| 275 | /// Stores the Object referenced by the handle or null if the slot is empty. | 124 | } |
| 276 | std::array<SharedPtr<Object>, MAX_COUNT> objects; | ||
| 277 | |||
| 278 | /** | ||
| 279 | * The value of `next_generation` when the handle was created, used to check for validity. For | ||
| 280 | * empty slots, contains the index of the next free slot in the list. | ||
| 281 | */ | ||
| 282 | std::array<u16, MAX_COUNT> generations; | ||
| 283 | |||
| 284 | /** | ||
| 285 | * Global counter of the number of created handles. Stored in `generations` when a handle is | ||
| 286 | * created, and wraps around to 1 when it hits 0x8000. | ||
| 287 | */ | ||
| 288 | u16 next_generation; | ||
| 289 | |||
| 290 | /// Head of the free slots linked list. | ||
| 291 | u16 next_free_slot; | ||
| 292 | }; | ||
| 293 | |||
| 294 | extern HandleTable g_handle_table; | ||
| 295 | 125 | ||
| 296 | /// Initialize the kernel with the specified system mode. | 126 | /// Initialize the kernel with the specified system mode. |
| 297 | 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/process.cpp b/src/core/hle/kernel/process.cpp index 32cb25fb7..1c31ec950 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/hle/kernel/errors.h" | ||
| 9 | #include "core/hle/kernel/memory.h" | 10 | #include "core/hle/kernel/memory.h" |
| 10 | #include "core/hle/kernel/process.h" | 11 | #include "core/hle/kernel/process.h" |
| 11 | #include "core/hle/kernel/resource_limit.h" | 12 | #include "core/hle/kernel/resource_limit.h" |
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.cpp b/src/core/hle/kernel/semaphore.cpp index 8bda2f75d..fcf586728 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.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 "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/hle/kernel/errors.h" | ||
| 6 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 7 | #include "core/hle/kernel/semaphore.h" | 8 | #include "core/hle/kernel/semaphore.h" |
| 8 | #include "core/hle/kernel/thread.h" | 9 | #include "core/hle/kernel/thread.h" |
| @@ -16,8 +17,7 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou | |||
| 16 | std::string name) { | 17 | std::string name) { |
| 17 | 18 | ||
| 18 | if (initial_count > max_count) | 19 | if (initial_count > max_count) |
| 19 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | 20 | return ERR_INVALID_COMBINATION_KERNEL; |
| 20 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 21 | 21 | ||
| 22 | SharedPtr<Semaphore> semaphore(new Semaphore); | 22 | SharedPtr<Semaphore> semaphore(new Semaphore); |
| 23 | 23 | ||
| @@ -42,8 +42,7 @@ void Semaphore::Acquire(Thread* thread) { | |||
| 42 | 42 | ||
| 43 | ResultVal<s32> Semaphore::Release(s32 release_count) { | 43 | ResultVal<s32> Semaphore::Release(s32 release_count) { |
| 44 | if (max_count - available_count < release_count) | 44 | if (max_count - available_count < release_count) |
| 45 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, | 45 | return ERR_OUT_OF_RANGE_KERNEL; |
| 46 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 47 | 46 | ||
| 48 | s32 previous_count = available_count; | 47 | s32 previous_count = available_count; |
| 49 | available_count += release_count; | 48 | available_count += release_count; |
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..5365605da 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -9,10 +9,8 @@ | |||
| 9 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 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/wait_object.h" |
| 13 | #include "core/hle/kernel/thread.h" | ||
| 14 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 15 | #include "core/hle/service/service.h" | ||
| 16 | #include "core/memory.h" | 14 | #include "core/memory.h" |
| 17 | 15 | ||
| 18 | namespace Kernel { | 16 | namespace Kernel { |
| @@ -20,6 +18,9 @@ namespace Kernel { | |||
| 20 | class ClientSession; | 18 | class ClientSession; |
| 21 | class ClientPort; | 19 | class ClientPort; |
| 22 | class ServerSession; | 20 | class ServerSession; |
| 21 | class Session; | ||
| 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/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index bc1560d12..922e5ab58 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/hle/kernel/errors.h" | ||
| 7 | #include "core/hle/kernel/memory.h" | 8 | #include "core/hle/kernel/memory.h" |
| 8 | #include "core/hle/kernel/shared_memory.h" | 9 | #include "core/hle/kernel/shared_memory.h" |
| 9 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| @@ -102,24 +103,21 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 102 | 103 | ||
| 103 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare | 104 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare |
| 104 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { | 105 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { |
| 105 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, | 106 | return ERR_INVALID_COMBINATION; |
| 106 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | // Error out if the requested permissions don't match what the creator process allows. | 109 | // Error out if the requested permissions don't match what the creator process allows. |
| 110 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { | 110 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { |
| 111 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", | 111 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", |
| 112 | GetObjectId(), address, name.c_str()); | 112 | GetObjectId(), address, name.c_str()); |
| 113 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, | 113 | return ERR_INVALID_COMBINATION; |
| 114 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | // Heap-backed memory blocks can not be mapped with other_permissions = DontCare | 116 | // Heap-backed memory blocks can not be mapped with other_permissions = DontCare |
| 118 | if (base_address != 0 && other_permissions == MemoryPermission::DontCare) { | 117 | if (base_address != 0 && other_permissions == MemoryPermission::DontCare) { |
| 119 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", | 118 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", |
| 120 | GetObjectId(), address, name.c_str()); | 119 | GetObjectId(), address, name.c_str()); |
| 121 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, | 120 | return ERR_INVALID_COMBINATION; |
| 122 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | // Error out if the provided permissions are not compatible with what the creator process needs. | 123 | // Error out if the provided permissions are not compatible with what the creator process needs. |
| @@ -127,8 +125,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 127 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { | 125 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { |
| 128 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", | 126 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", |
| 129 | GetObjectId(), address, name.c_str()); | 127 | GetObjectId(), address, name.c_str()); |
| 130 | return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, | 128 | return ERR_WRONG_PERMISSION; |
| 131 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 132 | } | 129 | } |
| 133 | 130 | ||
| 134 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. | 131 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. |
| @@ -144,8 +141,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 144 | if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { | 141 | if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { |
| 145 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address", | 142 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address", |
| 146 | GetObjectId(), address, name.c_str()); | 143 | GetObjectId(), address, name.c_str()); |
| 147 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, | 144 | return ERR_INVALID_ADDRESS; |
| 148 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 149 | } | 145 | } |
| 150 | } | 146 | } |
| 151 | 147 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3b7555d87..75ce626f8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #include "core/arm/skyeye_common/armstate.h" | 14 | #include "core/arm/skyeye_common/armstate.h" |
| 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" | ||
| 18 | #include "core/hle/kernel/handle_table.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | 19 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/kernel/memory.h" | 20 | #include "core/hle/kernel/memory.h" |
| 19 | #include "core/hle/kernel/mutex.h" | 21 | #include "core/hle/kernel/mutex.h" |
| @@ -241,9 +243,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 241 | for (auto& object : thread->wait_objects) | 243 | for (auto& object : thread->wait_objects) |
| 242 | object->RemoveWaitingThread(thread.get()); | 244 | object->RemoveWaitingThread(thread.get()); |
| 243 | thread->wait_objects.clear(); | 245 | thread->wait_objects.clear(); |
| 244 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | 246 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); |
| 245 | ErrorSummary::StatusChanged, | ||
| 246 | ErrorLevel::Info)); | ||
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | thread->ResumeFromWait(); | 249 | thread->ResumeFromWait(); |
| @@ -351,10 +351,20 @@ static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_ | |||
| 351 | context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode | 351 | context.cpsr = USER32MODE | ((entry_point & 1) << 5); // Usermode and THUMB mode |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, | 354 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, |
| 355 | u32 arg, s32 processor_id, VAddr stack_top) { | 355 | u32 arg, s32 processor_id, VAddr stack_top) { |
| 356 | ASSERT_MSG(priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST, | 356 | // Check if priority is in ranged. Lowest priority -> highest priority id. |
| 357 | "Invalid thread priority"); | 357 | if (priority > THREADPRIO_LOWEST) { |
| 358 | LOG_ERROR(Kernel_SVC, "Invalid thread priority: %d", priority); | ||
| 359 | return ERR_OUT_OF_RANGE; | ||
| 360 | } | ||
| 361 | |||
| 362 | if (processor_id > THREADPROCESSORID_MAX) { | ||
| 363 | LOG_ERROR(Kernel_SVC, "Invalid processor id: %d", processor_id); | ||
| 364 | return ERR_OUT_OF_RANGE_KERNEL; | ||
| 365 | } | ||
| 366 | |||
| 367 | // TODO(yuriks): Other checks, returning 0xD9001BEA | ||
| 358 | 368 | ||
| 359 | if (!Memory::IsValidVirtualAddress(entry_point)) { | 369 | if (!Memory::IsValidVirtualAddress(entry_point)) { |
| 360 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); | 370 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); |
| @@ -399,8 +409,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 399 | if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { | 409 | if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { |
| 400 | LOG_ERROR(Kernel_SVC, | 410 | LOG_ERROR(Kernel_SVC, |
| 401 | "Not enough space in region to allocate a new TLS page for thread"); | 411 | "Not enough space in region to allocate a new TLS page for thread"); |
| 402 | return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | 412 | return ERR_OUT_OF_MEMORY; |
| 403 | ErrorSummary::OutOfResource, ErrorLevel::Permanent); | ||
| 404 | } | 413 | } |
| 405 | 414 | ||
| 406 | u32 offset = linheap_memory->size(); | 415 | u32 offset = linheap_memory->size(); |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 6ab31c70b..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 { |
| @@ -57,7 +58,7 @@ public: | |||
| 57 | * @param stack_top The address of the thread's stack top | 58 | * @param stack_top The address of the thread's stack top |
| 58 | * @return A shared pointer to the newly created thread | 59 | * @return A shared pointer to the newly created thread |
| 59 | */ | 60 | */ |
| 60 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | 61 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority, |
| 61 | u32 arg, s32 processor_id, VAddr stack_top); | 62 | u32 arg, s32 processor_id, VAddr stack_top); |
| 62 | 63 | ||
| 63 | std::string GetName() const override { | 64 | std::string GetName() const override { |
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/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 6dd24f846..cef1f7fa8 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <iterator> | 5 | #include <iterator> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "core/hle/kernel/errors.h" | ||
| 7 | #include "core/hle/kernel/vm_manager.h" | 8 | #include "core/hle/kernel/vm_manager.h" |
| 8 | #include "core/memory.h" | 9 | #include "core/memory.h" |
| 9 | #include "core/memory_setup.h" | 10 | #include "core/memory_setup.h" |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 9055664b2..38e0d74d0 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -13,14 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | const ResultCode ERR_INVALID_ADDRESS{// 0xE0E01BF5 | ||
| 17 | ErrorDescription::InvalidAddress, ErrorModule::OS, | ||
| 18 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 19 | |||
| 20 | const ResultCode ERR_INVALID_ADDRESS_STATE{// 0xE0A01BF5 | ||
| 21 | ErrorDescription::InvalidAddress, ErrorModule::OS, | ||
| 22 | ErrorSummary::InvalidState, ErrorLevel::Usage}; | ||
| 23 | |||
| 24 | enum class VMAType : u8 { | 16 | enum class VMAType : u8 { |
| 25 | /// VMA represents an unmapped region of the address space. | 17 | /// VMA represents an unmapped region of the address space. |
| 26 | Free, | 18 | Free, |
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 13b948871..5f2cdbb96 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -13,38 +13,15 @@ | |||
| 13 | 13 | ||
| 14 | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes | 14 | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes |
| 15 | 15 | ||
| 16 | /// Detailed description of the error. This listing is likely incomplete. | 16 | /** |
| 17 | * Detailed description of the error. Code 0 always means success. Codes 1000 and above are | ||
| 18 | * considered "well-known" and have common values between all modules. The meaning of other codes | ||
| 19 | * vary by module. | ||
| 20 | */ | ||
| 17 | enum class ErrorDescription : u32 { | 21 | enum class ErrorDescription : u32 { |
| 18 | Success = 0, | 22 | Success = 0, |
| 19 | SessionClosedByRemote = 26, | 23 | |
| 20 | WrongPermission = 46, | 24 | // Codes 1000 and above are considered "well-known" and have common values between all modules. |
| 21 | OS_InvalidBufferDescriptor = 48, | ||
| 22 | MaxConnectionsReached = 52, | ||
| 23 | WrongAddress = 53, | ||
| 24 | FS_RomFSNotFound = 100, | ||
| 25 | FS_ArchiveNotMounted = 101, | ||
| 26 | FS_FileNotFound = 112, | ||
| 27 | FS_PathNotFound = 113, | ||
| 28 | FS_GameCardNotInserted = 141, | ||
| 29 | FS_NotFound = 120, | ||
| 30 | FS_FileAlreadyExists = 180, | ||
| 31 | FS_DirectoryAlreadyExists = 185, | ||
| 32 | FS_AlreadyExists = 190, | ||
| 33 | FS_InvalidOpenFlags = 230, | ||
| 34 | FS_DirectoryNotEmpty = 240, | ||
| 35 | FS_NotAFile = 250, | ||
| 36 | FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive | ||
| 37 | OutofRangeOrMisalignedAddress = | ||
| 38 | 513, // TODO(purpasmart): Check if this name fits its actual usage | ||
| 39 | GPU_FirstInitialization = 519, | ||
| 40 | FS_ExeFSSectionNotFound = 567, | ||
| 41 | FS_CommandNotAllowed = 630, | ||
| 42 | FS_InvalidReadFlag = 700, | ||
| 43 | FS_InvalidPath = 702, | ||
| 44 | FS_WriteBeyondEnd = 705, | ||
| 45 | FS_UnsupportedOpenFlags = 760, | ||
| 46 | FS_IncorrectExeFSReadSize = 761, | ||
| 47 | FS_UnexpectedFileOrDirectory = 770, | ||
| 48 | InvalidSection = 1000, | 25 | InvalidSection = 1000, |
| 49 | TooLarge = 1001, | 26 | TooLarge = 1001, |
| 50 | NotAuthorized = 1002, | 27 | NotAuthorized = 1002, |
| @@ -218,7 +195,7 @@ enum class ErrorLevel : u32 { | |||
| 218 | union ResultCode { | 195 | union ResultCode { |
| 219 | u32 raw; | 196 | u32 raw; |
| 220 | 197 | ||
| 221 | BitField<0, 10, ErrorDescription> description; | 198 | BitField<0, 10, u32> description; |
| 222 | BitField<10, 8, ErrorModule> module; | 199 | BitField<10, 8, ErrorModule> module; |
| 223 | 200 | ||
| 224 | BitField<21, 6, ErrorSummary> summary; | 201 | BitField<21, 6, ErrorSummary> summary; |
| @@ -228,45 +205,46 @@ union ResultCode { | |||
| 228 | // error | 205 | // error |
| 229 | BitField<31, 1, u32> is_error; | 206 | BitField<31, 1, u32> is_error; |
| 230 | 207 | ||
| 231 | explicit ResultCode(u32 raw) : raw(raw) {} | 208 | constexpr explicit ResultCode(u32 raw) : raw(raw) {} |
| 232 | ResultCode(ErrorDescription description_, ErrorModule module_, ErrorSummary summary_, | ||
| 233 | ErrorLevel level_) | ||
| 234 | : raw(0) { | ||
| 235 | description.Assign(description_); | ||
| 236 | module.Assign(module_); | ||
| 237 | summary.Assign(summary_); | ||
| 238 | level.Assign(level_); | ||
| 239 | } | ||
| 240 | 209 | ||
| 241 | ResultCode& operator=(const ResultCode& o) { | 210 | constexpr ResultCode(ErrorDescription description, ErrorModule module, ErrorSummary summary, |
| 211 | ErrorLevel level) | ||
| 212 | : ResultCode(static_cast<u32>(description), module, summary, level) {} | ||
| 213 | |||
| 214 | constexpr ResultCode(u32 description_, ErrorModule module_, ErrorSummary summary_, | ||
| 215 | ErrorLevel level_) | ||
| 216 | : raw(description.FormatValue(description_) | module.FormatValue(module_) | | ||
| 217 | summary.FormatValue(summary_) | level.FormatValue(level_)) {} | ||
| 218 | |||
| 219 | constexpr ResultCode& operator=(const ResultCode& o) { | ||
| 242 | raw = o.raw; | 220 | raw = o.raw; |
| 243 | return *this; | 221 | return *this; |
| 244 | } | 222 | } |
| 245 | 223 | ||
| 246 | bool IsSuccess() const { | 224 | constexpr bool IsSuccess() const { |
| 247 | return is_error == 0; | 225 | return is_error.ExtractValue(raw) == 0; |
| 248 | } | 226 | } |
| 249 | 227 | ||
| 250 | bool IsError() const { | 228 | constexpr bool IsError() const { |
| 251 | return is_error == 1; | 229 | return is_error.ExtractValue(raw) == 1; |
| 252 | } | 230 | } |
| 253 | }; | 231 | }; |
| 254 | 232 | ||
| 255 | inline bool operator==(const ResultCode& a, const ResultCode& b) { | 233 | constexpr bool operator==(const ResultCode& a, const ResultCode& b) { |
| 256 | return a.raw == b.raw; | 234 | return a.raw == b.raw; |
| 257 | } | 235 | } |
| 258 | 236 | ||
| 259 | inline bool operator!=(const ResultCode& a, const ResultCode& b) { | 237 | constexpr bool operator!=(const ResultCode& a, const ResultCode& b) { |
| 260 | return a.raw != b.raw; | 238 | return a.raw != b.raw; |
| 261 | } | 239 | } |
| 262 | 240 | ||
| 263 | // Convenience functions for creating some common kinds of errors: | 241 | // Convenience functions for creating some common kinds of errors: |
| 264 | 242 | ||
| 265 | /// The default success `ResultCode`. | 243 | /// The default success `ResultCode`. |
| 266 | const ResultCode RESULT_SUCCESS(0); | 244 | constexpr ResultCode RESULT_SUCCESS(0); |
| 267 | 245 | ||
| 268 | /// Might be returned instead of a dummy success for unimplemented APIs. | 246 | /// Might be returned instead of a dummy success for unimplemented APIs. |
| 269 | inline ResultCode UnimplementedFunction(ErrorModule module) { | 247 | constexpr ResultCode UnimplementedFunction(ErrorModule module) { |
| 270 | return ResultCode(ErrorDescription::NotImplemented, module, ErrorSummary::NotSupported, | 248 | return ResultCode(ErrorDescription::NotImplemented, module, ErrorSummary::NotSupported, |
| 271 | ErrorLevel::Permanent); | 249 | ErrorLevel::Permanent); |
| 272 | } | 250 | } |
| @@ -438,6 +416,16 @@ ResultVal<T> MakeResult(Args&&... args) { | |||
| 438 | } | 416 | } |
| 439 | 417 | ||
| 440 | /** | 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 | /** | ||
| 441 | * 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 |
| 442 | * 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 |
| 443 | * 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 |
| @@ -448,3 +436,12 @@ ResultVal<T> MakeResult(Args&&... args) { | |||
| 448 | if (CONCAT2(check_result_L, __LINE__).Failed()) \ | 436 | if (CONCAT2(check_result_L, __LINE__).Failed()) \ |
| 449 | return CONCAT2(check_result_L, __LINE__).Code(); \ | 437 | return CONCAT2(check_result_L, __LINE__).Code(); \ |
| 450 | 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 e0de037f8..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" |
| @@ -24,9 +27,7 @@ void InitializeSession(Service::Interface* self) { | |||
| 24 | 27 | ||
| 25 | if (translation != IPC::CallingPidDesc()) { | 28 | if (translation != IPC::CallingPidDesc()) { |
| 26 | cmd_buff[0] = IPC::MakeHeader(0, 0x1, 0); // 0x40 | 29 | cmd_buff[0] = IPC::MakeHeader(0, 0x1, 0); // 0x40 |
| 27 | cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, | 30 | cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; |
| 28 | ErrorSummary::WrongArgument, ErrorLevel::Permanent) | ||
| 29 | .raw; | ||
| 30 | LOG_ERROR(Service_BOSS, "The translation was invalid, translation=0x%08X", translation); | 31 | LOG_ERROR(Service_BOSS, "The translation was invalid, translation=0x%08X", translation); |
| 31 | return; | 32 | return; |
| 32 | } | 33 | } |
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 8c8c1ec77..5a7878b31 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp | |||
| @@ -11,7 +11,10 @@ | |||
| 11 | #include "common/string_util.h" | 11 | #include "common/string_util.h" |
| 12 | #include "common/swap.h" | 12 | #include "common/swap.h" |
| 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/file_backend.h" | 15 | #include "core/file_sys/file_backend.h" |
| 16 | #include "core/hle/ipc.h" | ||
| 17 | #include "core/hle/ipc_helpers.h" | ||
| 15 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| 16 | #include "core/hle/service/cfg/cfg.h" | 19 | #include "core/hle/service/cfg/cfg.h" |
| 17 | #include "core/hle/service/cfg/cfg_i.h" | 20 | #include "core/hle/service/cfg/cfg_i.h" |
| @@ -20,6 +23,7 @@ | |||
| 20 | #include "core/hle/service/cfg/cfg_u.h" | 23 | #include "core/hle/service/cfg/cfg_u.h" |
| 21 | #include "core/hle/service/fs/archive.h" | 24 | #include "core/hle/service/fs/archive.h" |
| 22 | #include "core/hle/service/service.h" | 25 | #include "core/hle/service/service.h" |
| 26 | #include "core/memory.h" | ||
| 23 | #include "core/settings.h" | 27 | #include "core/settings.h" |
| 24 | 28 | ||
| 25 | namespace Service { | 29 | namespace Service { |
| @@ -411,7 +415,7 @@ ResultCode UpdateConfigNANDSavegame() { | |||
| 411 | ResultCode FormatConfig() { | 415 | ResultCode FormatConfig() { |
| 412 | ResultCode res = DeleteConfigNANDSaveFile(); | 416 | ResultCode res = DeleteConfigNANDSaveFile(); |
| 413 | // The delete command fails if the file doesn't exist, so we have to check that too | 417 | // The delete command fails if the file doesn't exist, so we have to check that too |
| 414 | if (!res.IsSuccess() && res.description != ErrorDescription::FS_FileNotFound) { | 418 | if (!res.IsSuccess() && res != FileSys::ERROR_FILE_NOT_FOUND) { |
| 415 | return res; | 419 | return res; |
| 416 | } | 420 | } |
| 417 | // Delete the old data | 421 | // Delete the old data |
| @@ -534,7 +538,7 @@ ResultCode LoadConfigNANDSaveFile() { | |||
| 534 | Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); | 538 | Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); |
| 535 | 539 | ||
| 536 | // If the archive didn't exist, create the files inside | 540 | // If the archive didn't exist, create the files inside |
| 537 | if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { | 541 | if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { |
| 538 | // Format the archive to create the directories | 542 | // Format the archive to create the directories |
| 539 | Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, | 543 | Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, |
| 540 | FileSys::ArchiveFormatInfo(), archive_path); | 544 | FileSys::ArchiveFormatInfo(), archive_path); |
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 39711ea97..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 | ||
| @@ -289,9 +295,7 @@ static void WriteProcessPipe(Service::Interface* self) { | |||
| 289 | "size=0x%X, buffer=0x%08X", | 295 | "size=0x%X, buffer=0x%08X", |
| 290 | cmd_buff[3], pipe_index, size, buffer); | 296 | cmd_buff[3], pipe_index, size, buffer); |
| 291 | cmd_buff[0] = IPC::MakeHeader(0, 1, 0); | 297 | cmd_buff[0] = IPC::MakeHeader(0, 1, 0); |
| 292 | cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, | 298 | cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; |
| 293 | ErrorSummary::WrongArgument, ErrorLevel::Permanent) | ||
| 294 | .raw; | ||
| 295 | return; | 299 | return; |
| 296 | } | 300 | } |
| 297 | 301 | ||
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 6cddc1fdb..3605ef175 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -22,8 +22,13 @@ | |||
| 22 | #include "core/file_sys/archive_sdmcwriteonly.h" | 22 | #include "core/file_sys/archive_sdmcwriteonly.h" |
| 23 | #include "core/file_sys/archive_systemsavedata.h" | 23 | #include "core/file_sys/archive_systemsavedata.h" |
| 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/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" | ||
| 26 | #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" | ||
| 27 | #include "core/hle/result.h" | 32 | #include "core/hle/result.h" |
| 28 | #include "core/hle/service/fs/archive.h" | 33 | #include "core/hle/service/fs/archive.h" |
| 29 | #include "core/hle/service/fs/fs_user.h" | 34 | #include "core/hle/service/fs/fs_user.h" |
| @@ -50,16 +55,6 @@ static constexpr Kernel::Handle INVALID_HANDLE{}; | |||
| 50 | namespace Service { | 55 | namespace Service { |
| 51 | namespace FS { | 56 | namespace FS { |
| 52 | 57 | ||
| 53 | // TODO: Verify code | ||
| 54 | /// Returned when a function is passed an invalid handle. | ||
| 55 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::FS, | ||
| 56 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 57 | |||
| 58 | /// Returned when a function is passed an invalid archive handle. | ||
| 59 | const ResultCode ERR_INVALID_ARCHIVE_HANDLE(ErrorDescription::FS_ArchiveNotMounted, ErrorModule::FS, | ||
| 60 | ErrorSummary::NotFound, | ||
| 61 | ErrorLevel::Status); // 0xC8804465 | ||
| 62 | |||
| 63 | // Command to access archive file | 58 | // Command to access archive file |
| 64 | enum class FileCommand : u32 { | 59 | enum class FileCommand : u32 { |
| 65 | Dummy1 = 0x000100C6, | 60 | Dummy1 = 0x000100C6, |
| @@ -92,6 +87,10 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& | |||
| 92 | File::~File() {} | 87 | File::~File() {} |
| 93 | 88 | ||
| 94 | 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 | |||
| 95 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 94 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 96 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | 95 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |
| 97 | switch (cmd) { | 96 | switch (cmd) { |
| @@ -170,10 +169,9 @@ void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_ses | |||
| 170 | 169 | ||
| 171 | case FileCommand::OpenLinkFile: { | 170 | case FileCommand::OpenLinkFile: { |
| 172 | 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()); |
| 173 | auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); | 172 | auto sessions = ServerSession::CreateSessionPair(GetName()); |
| 174 | ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | 173 | ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); |
| 175 | cmd_buff[3] = Kernel::g_handle_table | 174 | cmd_buff[3] = Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)) |
| 176 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | ||
| 177 | .ValueOr(INVALID_HANDLE); | 175 | .ValueOr(INVALID_HANDLE); |
| 178 | break; | 176 | break; |
| 179 | } | 177 | } |
| @@ -267,9 +265,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi | |||
| 267 | 265 | ||
| 268 | auto itr = id_code_map.find(id_code); | 266 | auto itr = id_code_map.find(id_code); |
| 269 | if (itr == id_code_map.end()) { | 267 | if (itr == id_code_map.end()) { |
| 270 | // TODO: Verify error against hardware | 268 | return FileSys::ERROR_NOT_FOUND; |
| 271 | return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, | ||
| 272 | ErrorLevel::Permanent); | ||
| 273 | } | 269 | } |
| 274 | 270 | ||
| 275 | 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)); |
| @@ -284,7 +280,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi | |||
| 284 | 280 | ||
| 285 | ResultCode CloseArchive(ArchiveHandle handle) { | 281 | ResultCode CloseArchive(ArchiveHandle handle) { |
| 286 | if (handle_map.erase(handle) == 0) | 282 | if (handle_map.erase(handle) == 0) |
| 287 | return ERR_INVALID_ARCHIVE_HANDLE; | 283 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 288 | else | 284 | else |
| 289 | return RESULT_SUCCESS; | 285 | return RESULT_SUCCESS; |
| 290 | } | 286 | } |
| @@ -309,7 +305,7 @@ ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handl | |||
| 309 | const FileSys::Mode mode) { | 305 | const FileSys::Mode mode) { |
| 310 | ArchiveBackend* archive = GetArchive(archive_handle); | 306 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 311 | if (archive == nullptr) | 307 | if (archive == nullptr) |
| 312 | return ERR_INVALID_ARCHIVE_HANDLE; | 308 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 313 | 309 | ||
| 314 | auto backend = archive->OpenFile(path, mode); | 310 | auto backend = archive->OpenFile(path, mode); |
| 315 | if (backend.Failed()) | 311 | if (backend.Failed()) |
| @@ -322,7 +318,7 @@ ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handl | |||
| 322 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 318 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 323 | ArchiveBackend* archive = GetArchive(archive_handle); | 319 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 324 | if (archive == nullptr) | 320 | if (archive == nullptr) |
| 325 | return ERR_INVALID_ARCHIVE_HANDLE; | 321 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 326 | 322 | ||
| 327 | return archive->DeleteFile(path); | 323 | return archive->DeleteFile(path); |
| 328 | } | 324 | } |
| @@ -334,7 +330,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, | |||
| 334 | ArchiveBackend* src_archive = GetArchive(src_archive_handle); | 330 | ArchiveBackend* src_archive = GetArchive(src_archive_handle); |
| 335 | ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); | 331 | ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); |
| 336 | if (src_archive == nullptr || dest_archive == nullptr) | 332 | if (src_archive == nullptr || dest_archive == nullptr) |
| 337 | return ERR_INVALID_ARCHIVE_HANDLE; | 333 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 338 | 334 | ||
| 339 | if (src_archive == dest_archive) { | 335 | if (src_archive == dest_archive) { |
| 340 | return src_archive->RenameFile(src_path, dest_path); | 336 | return src_archive->RenameFile(src_path, dest_path); |
| @@ -347,7 +343,7 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, | |||
| 347 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 343 | ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 348 | ArchiveBackend* archive = GetArchive(archive_handle); | 344 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 349 | if (archive == nullptr) | 345 | if (archive == nullptr) |
| 350 | return ERR_INVALID_ARCHIVE_HANDLE; | 346 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 351 | 347 | ||
| 352 | return archive->DeleteDirectory(path); | 348 | return archive->DeleteDirectory(path); |
| 353 | } | 349 | } |
| @@ -356,7 +352,7 @@ ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, | |||
| 356 | const FileSys::Path& path) { | 352 | const FileSys::Path& path) { |
| 357 | ArchiveBackend* archive = GetArchive(archive_handle); | 353 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 358 | if (archive == nullptr) | 354 | if (archive == nullptr) |
| 359 | return ERR_INVALID_ARCHIVE_HANDLE; | 355 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 360 | 356 | ||
| 361 | return archive->DeleteDirectoryRecursively(path); | 357 | return archive->DeleteDirectoryRecursively(path); |
| 362 | } | 358 | } |
| @@ -365,7 +361,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path | |||
| 365 | u64 file_size) { | 361 | u64 file_size) { |
| 366 | ArchiveBackend* archive = GetArchive(archive_handle); | 362 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 367 | if (archive == nullptr) | 363 | if (archive == nullptr) |
| 368 | return ERR_INVALID_ARCHIVE_HANDLE; | 364 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 369 | 365 | ||
| 370 | return archive->CreateFile(path, file_size); | 366 | return archive->CreateFile(path, file_size); |
| 371 | } | 367 | } |
| @@ -373,7 +369,7 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path | |||
| 373 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 369 | ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| 374 | ArchiveBackend* archive = GetArchive(archive_handle); | 370 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 375 | if (archive == nullptr) | 371 | if (archive == nullptr) |
| 376 | return ERR_INVALID_ARCHIVE_HANDLE; | 372 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 377 | 373 | ||
| 378 | return archive->CreateDirectory(path); | 374 | return archive->CreateDirectory(path); |
| 379 | } | 375 | } |
| @@ -385,7 +381,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, | |||
| 385 | ArchiveBackend* src_archive = GetArchive(src_archive_handle); | 381 | ArchiveBackend* src_archive = GetArchive(src_archive_handle); |
| 386 | ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); | 382 | ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); |
| 387 | if (src_archive == nullptr || dest_archive == nullptr) | 383 | if (src_archive == nullptr || dest_archive == nullptr) |
| 388 | return ERR_INVALID_ARCHIVE_HANDLE; | 384 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 389 | 385 | ||
| 390 | if (src_archive == dest_archive) { | 386 | if (src_archive == dest_archive) { |
| 391 | return src_archive->RenameDirectory(src_path, dest_path); | 387 | return src_archive->RenameDirectory(src_path, dest_path); |
| @@ -399,7 +395,7 @@ ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle arc | |||
| 399 | const FileSys::Path& path) { | 395 | const FileSys::Path& path) { |
| 400 | ArchiveBackend* archive = GetArchive(archive_handle); | 396 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 401 | if (archive == nullptr) | 397 | if (archive == nullptr) |
| 402 | return ERR_INVALID_ARCHIVE_HANDLE; | 398 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 403 | 399 | ||
| 404 | auto backend = archive->OpenDirectory(path); | 400 | auto backend = archive->OpenDirectory(path); |
| 405 | if (backend.Failed()) | 401 | if (backend.Failed()) |
| @@ -412,7 +408,7 @@ ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle arc | |||
| 412 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { | 408 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { |
| 413 | ArchiveBackend* archive = GetArchive(archive_handle); | 409 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 414 | if (archive == nullptr) | 410 | if (archive == nullptr) |
| 415 | return ERR_INVALID_ARCHIVE_HANDLE; | 411 | return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |
| 416 | return MakeResult<u64>(archive->GetFreeBytes()); | 412 | return MakeResult<u64>(archive->GetFreeBytes()); |
| 417 | } | 413 | } |
| 418 | 414 | ||
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 33b290699..34e1783ec 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -8,7 +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" | ||
| 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" | ||
| 11 | #include "core/hle/kernel/client_session.h" | 16 | #include "core/hle/kernel/client_session.h" |
| 17 | #include "core/hle/kernel/server_session.h" | ||
| 12 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| 13 | #include "core/hle/service/fs/archive.h" | 19 | #include "core/hle/service/fs/archive.h" |
| 14 | #include "core/hle/service/fs/fs_user.h" | 20 | #include "core/hle/service/fs/fs_user.h" |
| @@ -17,8 +23,9 @@ | |||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 18 | // Namespace FS_User | 24 | // Namespace FS_User |
| 19 | 25 | ||
| 20 | using Kernel::SharedPtr; | 26 | using Kernel::ClientSession; |
| 21 | using Kernel::ServerSession; | 27 | using Kernel::ServerSession; |
| 28 | using Kernel::SharedPtr; | ||
| 22 | 29 | ||
| 23 | namespace Service { | 30 | namespace Service { |
| 24 | namespace FS { | 31 | namespace FS { |
| @@ -76,11 +83,11 @@ static void OpenFile(Service::Interface* self) { | |||
| 76 | rb.Push(file_res.Code()); | 83 | rb.Push(file_res.Code()); |
| 77 | if (file_res.Succeeded()) { | 84 | if (file_res.Succeeded()) { |
| 78 | std::shared_ptr<File> file = *file_res; | 85 | std::shared_ptr<File> file = *file_res; |
| 79 | auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); | 86 | auto sessions = ServerSession::CreateSessionPair(file->GetName()); |
| 80 | file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | 87 | file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); |
| 81 | rb.PushMoveHandles(Kernel::g_handle_table | 88 | |
| 82 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | 89 | rb.PushMoveHandles( |
| 83 | .MoveFrom()); | 90 | Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom()); |
| 84 | } else { | 91 | } else { |
| 85 | rb.PushMoveHandles(0); | 92 | rb.PushMoveHandles(0); |
| 86 | 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()); |
| @@ -129,7 +136,7 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 129 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); | 136 | ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); |
| 130 | if (archive_handle.Failed()) { | 137 | if (archive_handle.Failed()) { |
| 131 | LOG_ERROR(Service_FS, | 138 | LOG_ERROR(Service_FS, |
| 132 | "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", |
| 133 | static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); | 140 | static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); |
| 134 | cmd_buff[1] = archive_handle.Code().raw; | 141 | cmd_buff[1] = archive_handle.Code().raw; |
| 135 | cmd_buff[3] = 0; | 142 | cmd_buff[3] = 0; |
| @@ -142,11 +149,11 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 142 | cmd_buff[1] = file_res.Code().raw; | 149 | cmd_buff[1] = file_res.Code().raw; |
| 143 | if (file_res.Succeeded()) { | 150 | if (file_res.Succeeded()) { |
| 144 | std::shared_ptr<File> file = *file_res; | 151 | std::shared_ptr<File> file = *file_res; |
| 145 | auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); | 152 | auto sessions = ServerSession::CreateSessionPair(file->GetName()); |
| 146 | file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | 153 | file->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); |
| 147 | cmd_buff[3] = Kernel::g_handle_table | 154 | |
| 148 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | 155 | cmd_buff[3] = |
| 149 | .MoveFrom(); | 156 | Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom(); |
| 150 | } else { | 157 | } else { |
| 151 | cmd_buff[3] = 0; | 158 | cmd_buff[3] = 0; |
| 152 | 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", |
| @@ -409,11 +416,11 @@ static void OpenDirectory(Service::Interface* self) { | |||
| 409 | cmd_buff[1] = dir_res.Code().raw; | 416 | cmd_buff[1] = dir_res.Code().raw; |
| 410 | if (dir_res.Succeeded()) { | 417 | if (dir_res.Succeeded()) { |
| 411 | std::shared_ptr<Directory> directory = *dir_res; | 418 | std::shared_ptr<Directory> directory = *dir_res; |
| 412 | auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); | 419 | auto sessions = ServerSession::CreateSessionPair(directory->GetName()); |
| 413 | directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | 420 | directory->ClientConnected(std::get<SharedPtr<ServerSession>>(sessions)); |
| 414 | cmd_buff[3] = Kernel::g_handle_table | 421 | |
| 415 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | 422 | cmd_buff[3] = |
| 416 | .MoveFrom(); | 423 | Kernel::g_handle_table.Create(std::get<SharedPtr<ClientSession>>(sessions)).MoveFrom(); |
| 417 | } else { | 424 | } else { |
| 418 | 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", |
| 419 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); | 426 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); |
| @@ -539,9 +546,7 @@ static void FormatSaveData(Service::Interface* self) { | |||
| 539 | if (archive_id != FS::ArchiveIdCode::SaveData) { | 546 | if (archive_id != FS::ArchiveIdCode::SaveData) { |
| 540 | LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", | 547 | LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", |
| 541 | static_cast<u32>(archive_id)); | 548 | static_cast<u32>(archive_id)); |
| 542 | cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS, | 549 | cmd_buff[1] = FileSys::ERROR_INVALID_PATH.raw; |
| 543 | ErrorSummary::InvalidArgument, ErrorLevel::Usage) | ||
| 544 | .raw; | ||
| 545 | return; | 550 | return; |
| 546 | } | 551 | } |
| 547 | 552 | ||
| @@ -802,9 +807,7 @@ static void InitializeWithSdkVersion(Service::Interface* self) { | |||
| 802 | cmd_buff[1] = RESULT_SUCCESS.raw; | 807 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 803 | } else { | 808 | } else { |
| 804 | LOG_ERROR(Service_FS, "ProcessId Header must be 0x20"); | 809 | LOG_ERROR(Service_FS, "ProcessId Header must be 0x20"); |
| 805 | cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, | 810 | cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; |
| 806 | ErrorSummary::WrongArgument, ErrorLevel::Permanent) | ||
| 807 | .raw; | ||
| 808 | } | 811 | } |
| 809 | } | 812 | } |
| 810 | 813 | ||
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index a960778a7..6ff0f4812 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -5,14 +5,16 @@ | |||
| 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" |
| 13 | #include "core/hle/service/gsp_gpu.h" | ||
| 11 | #include "core/hw/gpu.h" | 14 | #include "core/hw/gpu.h" |
| 12 | #include "core/hw/hw.h" | 15 | #include "core/hw/hw.h" |
| 13 | #include "core/hw/lcd.h" | 16 | #include "core/hw/lcd.h" |
| 14 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 15 | #include "gsp_gpu.h" | ||
| 16 | #include "video_core/debug_utils/debug_utils.h" | 18 | #include "video_core/debug_utils/debug_utils.h" |
| 17 | #include "video_core/gpu_debugger.h" | 19 | #include "video_core/gpu_debugger.h" |
| 18 | 20 | ||
| @@ -25,13 +27,24 @@ namespace GSP { | |||
| 25 | // Beginning address of HW regs | 27 | // Beginning address of HW regs |
| 26 | const u32 REGS_BEGIN = 0x1EB00000; | 28 | const u32 REGS_BEGIN = 0x1EB00000; |
| 27 | 29 | ||
| 28 | const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED( | 30 | namespace ErrCodes { |
| 29 | ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX, ErrorSummary::InvalidArgument, | 31 | enum { |
| 30 | ErrorLevel::Usage); // 0xE0E02A01 | 32 | // TODO(purpasmart): Check if this name fits its actual usage |
| 31 | const ResultCode ERR_GSP_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX, | 33 | OutofRangeOrMisalignedAddress = 513, |
| 34 | FirstInitialization = 519, | ||
| 35 | }; | ||
| 36 | } | ||
| 37 | |||
| 38 | constexpr ResultCode RESULT_FIRST_INITIALIZATION(ErrCodes::FirstInitialization, ErrorModule::GX, | ||
| 39 | ErrorSummary::Success, ErrorLevel::Success); | ||
| 40 | constexpr ResultCode ERR_REGS_OUTOFRANGE_OR_MISALIGNED(ErrCodes::OutofRangeOrMisalignedAddress, | ||
| 41 | ErrorModule::GX, | ||
| 42 | ErrorSummary::InvalidArgument, | ||
| 43 | ErrorLevel::Usage); // 0xE0E02A01 | ||
| 44 | constexpr ResultCode ERR_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX, | ||
| 32 | ErrorSummary::InvalidArgument, | 45 | ErrorSummary::InvalidArgument, |
| 33 | ErrorLevel::Usage); // 0xE0E02BF2 | 46 | ErrorLevel::Usage); // 0xE0E02BF2 |
| 34 | const ResultCode ERR_GSP_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX, | 47 | constexpr ResultCode ERR_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX, |
| 35 | ErrorSummary::InvalidArgument, | 48 | ErrorSummary::InvalidArgument, |
| 36 | ErrorLevel::Usage); // 0xE0E02BEC | 49 | ErrorLevel::Usage); // 0xE0E02BEC |
| 37 | 50 | ||
| @@ -93,11 +106,11 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_va | |||
| 93 | LOG_ERROR(Service_GSP, | 106 | LOG_ERROR(Service_GSP, |
| 94 | "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)", | 107 | "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)", |
| 95 | base_address, size_in_bytes); | 108 | base_address, size_in_bytes); |
| 96 | return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED; | 109 | return ERR_REGS_OUTOFRANGE_OR_MISALIGNED; |
| 97 | } else if (size_in_bytes <= max_size_in_bytes) { | 110 | } else if (size_in_bytes <= max_size_in_bytes) { |
| 98 | if (size_in_bytes & 3) { | 111 | if (size_in_bytes & 3) { |
| 99 | LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes); | 112 | LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes); |
| 100 | return ERR_GSP_REGS_MISALIGNED; | 113 | return ERR_REGS_MISALIGNED; |
| 101 | } else { | 114 | } else { |
| 102 | while (size_in_bytes > 0) { | 115 | while (size_in_bytes > 0) { |
| 103 | WriteSingleHWReg(base_address, Memory::Read32(data_vaddr)); | 116 | WriteSingleHWReg(base_address, Memory::Read32(data_vaddr)); |
| @@ -111,7 +124,7 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_va | |||
| 111 | 124 | ||
| 112 | } else { | 125 | } else { |
| 113 | LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes); | 126 | LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes); |
| 114 | return ERR_GSP_REGS_INVALID_SIZE; | 127 | return ERR_REGS_INVALID_SIZE; |
| 115 | } | 128 | } |
| 116 | } | 129 | } |
| 117 | 130 | ||
| @@ -134,11 +147,11 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr | |||
| 134 | LOG_ERROR(Service_GSP, | 147 | LOG_ERROR(Service_GSP, |
| 135 | "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)", | 148 | "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)", |
| 136 | base_address, size_in_bytes); | 149 | base_address, size_in_bytes); |
| 137 | return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED; | 150 | return ERR_REGS_OUTOFRANGE_OR_MISALIGNED; |
| 138 | } else if (size_in_bytes <= max_size_in_bytes) { | 151 | } else if (size_in_bytes <= max_size_in_bytes) { |
| 139 | if (size_in_bytes & 3) { | 152 | if (size_in_bytes & 3) { |
| 140 | LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes); | 153 | LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes); |
| 141 | return ERR_GSP_REGS_MISALIGNED; | 154 | return ERR_REGS_MISALIGNED; |
| 142 | } else { | 155 | } else { |
| 143 | while (size_in_bytes > 0) { | 156 | while (size_in_bytes > 0) { |
| 144 | const u32 reg_address = base_address + REGS_BEGIN; | 157 | const u32 reg_address = base_address + REGS_BEGIN; |
| @@ -164,7 +177,7 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr | |||
| 164 | 177 | ||
| 165 | } else { | 178 | } else { |
| 166 | LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes); | 179 | LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes); |
| 167 | return ERR_GSP_REGS_INVALID_SIZE; | 180 | return ERR_REGS_INVALID_SIZE; |
| 168 | } | 181 | } |
| 169 | } | 182 | } |
| 170 | 183 | ||
| @@ -372,9 +385,7 @@ static void RegisterInterruptRelayQueue(Interface* self) { | |||
| 372 | if (first_initialization) { | 385 | if (first_initialization) { |
| 373 | // This specific code is required for a successful initialization, rather than 0 | 386 | // This specific code is required for a successful initialization, rather than 0 |
| 374 | first_initialization = false; | 387 | first_initialization = false; |
| 375 | cmd_buff[1] = ResultCode(ErrorDescription::GPU_FirstInitialization, ErrorModule::GX, | 388 | cmd_buff[1] = RESULT_FIRST_INITIALIZATION.raw; |
| 376 | ErrorSummary::Success, ErrorLevel::Success) | ||
| 377 | .raw; | ||
| 378 | } else { | 389 | } else { |
| 379 | cmd_buff[1] = RESULT_SUCCESS.raw; | 390 | cmd_buff[1] = RESULT_SUCCESS.raw; |
| 380 | } | 391 | } |
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 226af0083..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" |
| @@ -267,8 +268,7 @@ static void InitializeIrNopShared(Interface* self) { | |||
| 267 | shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle); | 268 | shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle); |
| 268 | if (!shared_memory) { | 269 | if (!shared_memory) { |
| 269 | LOG_CRITICAL(Service_IR, "invalid shared memory handle 0x%08X", handle); | 270 | LOG_CRITICAL(Service_IR, "invalid shared memory handle 0x%08X", handle); |
| 270 | rb.Push(ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS, | 271 | rb.Push(IPC::ERR_INVALID_HANDLE); |
| 271 | ErrorSummary::WrongArgument, ErrorLevel::Permanent)); | ||
| 272 | return; | 272 | return; |
| 273 | } | 273 | } |
| 274 | shared_memory->name = "IR_USER: shared memory"; | 274 | shared_memory->name = "IR_USER: shared memory"; |
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 581816e81..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" |
| @@ -422,6 +423,102 @@ static void SetApplicationData(Interface* self) { | |||
| 422 | rb.Push(RESULT_SUCCESS); | 423 | rb.Push(RESULT_SUCCESS); |
| 423 | } | 424 | } |
| 424 | 425 | ||
| 426 | /** | ||
| 427 | * NWM_UDS::DecryptBeaconData service function. | ||
| 428 | * Decrypts the encrypted data tags contained in the 802.11 beacons. | ||
| 429 | * Inputs: | ||
| 430 | * 1 : Input network struct buffer descriptor. | ||
| 431 | * 2 : Input network struct buffer ptr. | ||
| 432 | * 3 : Input tag0 encrypted buffer descriptor. | ||
| 433 | * 4 : Input tag0 encrypted buffer ptr. | ||
| 434 | * 5 : Input tag1 encrypted buffer descriptor. | ||
| 435 | * 6 : Input tag1 encrypted buffer ptr. | ||
| 436 | * 64 : Output buffer descriptor. | ||
| 437 | * 65 : Output buffer ptr. | ||
| 438 | * Outputs: | ||
| 439 | * 0 : Return header | ||
| 440 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 441 | */ | ||
| 442 | static void DecryptBeaconData(Interface* self) { | ||
| 443 | IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 0, 6); | ||
| 444 | |||
| 445 | size_t desc_size; | ||
| 446 | const VAddr network_struct_addr = rp.PopStaticBuffer(&desc_size); | ||
| 447 | ASSERT(desc_size == sizeof(NetworkInfo)); | ||
| 448 | |||
| 449 | size_t data0_size; | ||
| 450 | const VAddr encrypted_data0_addr = rp.PopStaticBuffer(&data0_size); | ||
| 451 | |||
| 452 | size_t data1_size; | ||
| 453 | const VAddr encrypted_data1_addr = rp.PopStaticBuffer(&data1_size); | ||
| 454 | |||
| 455 | size_t output_buffer_size; | ||
| 456 | const VAddr output_buffer_addr = rp.PeekStaticBuffer(0, &output_buffer_size); | ||
| 457 | |||
| 458 | // This size is hardcoded in the 3DS UDS code. | ||
| 459 | ASSERT(output_buffer_size == sizeof(NodeInfo) * UDSMaxNodes); | ||
| 460 | |||
| 461 | LOG_WARNING(Service_NWM, "called in0=%08X in1=%08X out=%08X", encrypted_data0_addr, | ||
| 462 | encrypted_data1_addr, output_buffer_addr); | ||
| 463 | |||
| 464 | NetworkInfo net_info; | ||
| 465 | Memory::ReadBlock(network_struct_addr, &net_info, sizeof(net_info)); | ||
| 466 | |||
| 467 | // Read the encrypted data. | ||
| 468 | // The first 4 bytes should be the OUI and the OUI Type of the tags. | ||
| 469 | std::array<u8, 3> oui; | ||
| 470 | Memory::ReadBlock(encrypted_data0_addr, oui.data(), oui.size()); | ||
| 471 | ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); | ||
| 472 | Memory::ReadBlock(encrypted_data1_addr, oui.data(), oui.size()); | ||
| 473 | ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); | ||
| 474 | |||
| 475 | ASSERT_MSG(Memory::Read8(encrypted_data0_addr + 3) == | ||
| 476 | static_cast<u8>(NintendoTagId::EncryptedData0), | ||
| 477 | "Unexpected tag id"); | ||
| 478 | ASSERT_MSG(Memory::Read8(encrypted_data1_addr + 3) == | ||
| 479 | static_cast<u8>(NintendoTagId::EncryptedData1), | ||
| 480 | "Unexpected tag id"); | ||
| 481 | |||
| 482 | std::vector<u8> beacon_data(data0_size + data1_size); | ||
| 483 | Memory::ReadBlock(encrypted_data0_addr + 4, beacon_data.data(), data0_size); | ||
| 484 | Memory::ReadBlock(encrypted_data1_addr + 4, beacon_data.data() + data0_size, data1_size); | ||
| 485 | |||
| 486 | // Decrypt the data | ||
| 487 | DecryptBeaconData(net_info, beacon_data); | ||
| 488 | |||
| 489 | // The beacon data header contains the MD5 hash of the data. | ||
| 490 | BeaconData beacon_header; | ||
| 491 | std::memcpy(&beacon_header, beacon_data.data(), sizeof(beacon_header)); | ||
| 492 | |||
| 493 | // TODO(Subv): Verify the MD5 hash of the data and return 0xE1211005 if invalid. | ||
| 494 | |||
| 495 | u8 num_nodes = net_info.max_nodes; | ||
| 496 | |||
| 497 | std::vector<NodeInfo> nodes; | ||
| 498 | |||
| 499 | for (int i = 0; i < num_nodes; ++i) { | ||
| 500 | BeaconNodeInfo info; | ||
| 501 | std::memcpy(&info, beacon_data.data() + sizeof(beacon_header) + i * sizeof(info), | ||
| 502 | sizeof(info)); | ||
| 503 | |||
| 504 | // Deserialize the node information. | ||
| 505 | NodeInfo node{}; | ||
| 506 | node.friend_code_seed = info.friend_code_seed; | ||
| 507 | node.network_node_id = info.network_node_id; | ||
| 508 | for (int i = 0; i < info.username.size(); ++i) | ||
| 509 | node.username[i] = info.username[i]; | ||
| 510 | |||
| 511 | nodes.push_back(node); | ||
| 512 | } | ||
| 513 | |||
| 514 | Memory::ZeroBlock(output_buffer_addr, sizeof(NodeInfo) * UDSMaxNodes); | ||
| 515 | Memory::WriteBlock(output_buffer_addr, nodes.data(), sizeof(NodeInfo) * nodes.size()); | ||
| 516 | |||
| 517 | IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||
| 518 | rb.PushStaticBuffer(output_buffer_addr, output_buffer_size, 0); | ||
| 519 | rb.Push(RESULT_SUCCESS); | ||
| 520 | } | ||
| 521 | |||
| 425 | // Sends a 802.11 beacon frame with information about the current network. | 522 | // Sends a 802.11 beacon frame with information about the current network. |
| 426 | static void BeaconBroadcastCallback(u64 userdata, int cycles_late) { | 523 | static void BeaconBroadcastCallback(u64 userdata, int cycles_late) { |
| 427 | // Don't do anything if we're not actually hosting a network | 524 | // Don't do anything if we're not actually hosting a network |
| @@ -462,7 +559,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 462 | {0x001B0302, InitializeWithVersion, "InitializeWithVersion"}, | 559 | {0x001B0302, InitializeWithVersion, "InitializeWithVersion"}, |
| 463 | {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"}, | 560 | {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"}, |
| 464 | {0x001E0084, nullptr, "ConnectToNetwork"}, | 561 | {0x001E0084, nullptr, "ConnectToNetwork"}, |
| 465 | {0x001F0006, nullptr, "DecryptBeaconData"}, | 562 | {0x001F0006, DecryptBeaconData, "DecryptBeaconData"}, |
| 466 | {0x00200040, nullptr, "Flush"}, | 563 | {0x00200040, nullptr, "Flush"}, |
| 467 | {0x00210080, nullptr, "SetProbeResponseParam"}, | 564 | {0x00210080, nullptr, "SetProbeResponseParam"}, |
| 468 | {0x00220402, nullptr, "ScanOnConnection"}, | 565 | {0x00220402, nullptr, "ScanOnConnection"}, |
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/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 319e8c946..39382ef09 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.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 "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/file_sys/errors.h" | ||
| 6 | #include "core/file_sys/file_backend.h" | 7 | #include "core/file_sys/file_backend.h" |
| 7 | #include "core/hle/service/fs/archive.h" | 8 | #include "core/hle/service/fs/archive.h" |
| 8 | #include "core/hle/service/ptm/ptm.h" | 9 | #include "core/hle/service/ptm/ptm.h" |
| @@ -134,7 +135,7 @@ void Init() { | |||
| 134 | auto archive_result = | 135 | auto archive_result = |
| 135 | Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); | 136 | Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); |
| 136 | // If the archive didn't exist, create the files inside | 137 | // If the archive didn't exist, create the files inside |
| 137 | if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { | 138 | if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { |
| 138 | // Format the archive to create the directories | 139 | // Format the archive to create the directories |
| 139 | Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, | 140 | Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, |
| 140 | FileSys::ArchiveFormatInfo(), archive_path); | 141 | FileSys::ArchiveFormatInfo(), archive_path); |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 0672ac2e3..d34968428 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -2,11 +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 <boost/range/algorithm_ext/erase.hpp> | 5 | #include <fmt/format.h> |
| 6 | |||
| 7 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 8 | #include "common/string_util.h" | 7 | #include "common/string_util.h" |
| 8 | #include "core/hle/kernel/client_port.h" | ||
| 9 | #include "core/hle/kernel/server_port.h" | 9 | #include "core/hle/kernel/server_port.h" |
| 10 | #include "core/hle/kernel/server_session.h" | ||
| 10 | #include "core/hle/service/ac/ac.h" | 11 | #include "core/hle/service/ac/ac.h" |
| 11 | #include "core/hle/service/act/act.h" | 12 | #include "core/hle/service/act/act.h" |
| 12 | #include "core/hle/service/am/am.h" | 13 | #include "core/hle/service/am/am.h" |
| @@ -39,15 +40,20 @@ | |||
| 39 | #include "core/hle/service/ptm/ptm.h" | 40 | #include "core/hle/service/ptm/ptm.h" |
| 40 | #include "core/hle/service/qtm/qtm.h" | 41 | #include "core/hle/service/qtm/qtm.h" |
| 41 | #include "core/hle/service/service.h" | 42 | #include "core/hle/service/service.h" |
| 43 | #include "core/hle/service/sm/sm.h" | ||
| 44 | #include "core/hle/service/sm/srv.h" | ||
| 42 | #include "core/hle/service/soc_u.h" | 45 | #include "core/hle/service/soc_u.h" |
| 43 | #include "core/hle/service/srv.h" | ||
| 44 | #include "core/hle/service/ssl_c.h" | 46 | #include "core/hle/service/ssl_c.h" |
| 45 | #include "core/hle/service/y2r_u.h" | 47 | #include "core/hle/service/y2r_u.h" |
| 46 | 48 | ||
| 49 | using Kernel::ClientPort; | ||
| 50 | using Kernel::ServerPort; | ||
| 51 | using Kernel::ServerSession; | ||
| 52 | using Kernel::SharedPtr; | ||
| 53 | |||
| 47 | namespace Service { | 54 | namespace Service { |
| 48 | 55 | ||
| 49 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | 56 | std::unordered_map<std::string, SharedPtr<ClientPort>> g_kernel_named_ports; |
| 50 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; | ||
| 51 | 57 | ||
| 52 | /** | 58 | /** |
| 53 | * Creates a function string for logging, complete with the name (or header code, depending | 59 | * Creates a function string for logging, complete with the name (or header code, depending |
| @@ -66,20 +72,10 @@ static std::string MakeFunctionString(const char* name, const char* port_name, | |||
| 66 | return function_string; | 72 | return function_string; |
| 67 | } | 73 | } |
| 68 | 74 | ||
| 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) {} | 75 | Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} |
| 80 | Interface::~Interface() = default; | 76 | Interface::~Interface() = default; |
| 81 | 77 | ||
| 82 | void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { | 78 | void Interface::HandleSyncRequest(SharedPtr<ServerSession> server_session) { |
| 83 | // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which | 79 | // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which |
| 84 | // session triggered each command. | 80 | // session triggered each command. |
| 85 | 81 | ||
| @@ -113,27 +109,106 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { | |||
| 113 | } | 109 | } |
| 114 | 110 | ||
| 115 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 111 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 112 | |||
| 113 | ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions, | ||
| 114 | InvokerFn* handler_invoker) | ||
| 115 | : service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {} | ||
| 116 | |||
| 117 | ServiceFrameworkBase::~ServiceFrameworkBase() = default; | ||
| 118 | |||
| 119 | void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { | ||
| 120 | ASSERT(port == nullptr); | ||
| 121 | port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); | ||
| 122 | port->SetHleHandler(shared_from_this()); | ||
| 123 | } | ||
| 124 | |||
| 125 | void ServiceFrameworkBase::InstallAsNamedPort() { | ||
| 126 | ASSERT(port == nullptr); | ||
| 127 | SharedPtr<ServerPort> server_port; | ||
| 128 | SharedPtr<ClientPort> client_port; | ||
| 129 | std::tie(server_port, client_port) = ServerPort::CreatePortPair(max_sessions, service_name); | ||
| 130 | server_port->SetHleHandler(shared_from_this()); | ||
| 131 | AddNamedPort(service_name, std::move(client_port)); | ||
| 132 | } | ||
| 133 | |||
| 134 | void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, size_t n) { | ||
| 135 | handlers.reserve(handlers.size() + n); | ||
| 136 | for (size_t i = 0; i < n; ++i) { | ||
| 137 | // Usually this array is sorted by id already, so hint to insert at the end | ||
| 138 | handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info) { | ||
| 143 | IPC::Header header{cmd_buf[0]}; | ||
| 144 | int num_params = header.normal_params_size + header.translate_params_size; | ||
| 145 | std::string function_name = info == nullptr ? fmt::format("{:#08x}", cmd_buf[0]) : info->name; | ||
| 146 | |||
| 147 | fmt::MemoryWriter w; | ||
| 148 | w.write("function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name, | ||
| 149 | cmd_buf[0]); | ||
| 150 | for (int i = 1; i <= num_params; ++i) { | ||
| 151 | w.write(", [{}]={:#x}", i, cmd_buf[i]); | ||
| 152 | } | ||
| 153 | w << '}'; | ||
| 154 | |||
| 155 | LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str()); | ||
| 156 | // TODO(bunnei): Hack - ignore error | ||
| 157 | cmd_buf[1] = 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_session) { | ||
| 161 | u32* cmd_buf = Kernel::GetCommandBuffer(); | ||
| 162 | |||
| 163 | // TODO(yuriks): The kernel should be the one handling this as part of translation after | ||
| 164 | // everything else is migrated | ||
| 165 | Kernel::HLERequestContext context; | ||
| 166 | context.cmd_buf = cmd_buf; | ||
| 167 | context.session = std::move(server_session); | ||
| 168 | |||
| 169 | u32 header_code = cmd_buf[0]; | ||
| 170 | auto itr = handlers.find(header_code); | ||
| 171 | const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second; | ||
| 172 | if (info == nullptr || info->handler_callback == nullptr) { | ||
| 173 | return ReportUnimplementedFunction(cmd_buf, info); | ||
| 174 | } | ||
| 175 | |||
| 176 | LOG_TRACE(Service, "%s", | ||
| 177 | MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf).c_str()); | ||
| 178 | handler_invoker(this, info->handler_callback, context); | ||
| 179 | } | ||
| 180 | |||
| 181 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 116 | // Module interface | 182 | // Module interface |
| 117 | 183 | ||
| 184 | // TODO(yuriks): Move to kernel | ||
| 185 | void AddNamedPort(std::string name, SharedPtr<ClientPort> port) { | ||
| 186 | g_kernel_named_ports.emplace(std::move(name), std::move(port)); | ||
| 187 | } | ||
| 188 | |||
| 118 | static void AddNamedPort(Interface* interface_) { | 189 | static void AddNamedPort(Interface* interface_) { |
| 119 | auto ports = | 190 | SharedPtr<ServerPort> server_port; |
| 120 | Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), | 191 | SharedPtr<ClientPort> client_port; |
| 121 | std::shared_ptr<Interface>(interface_)); | 192 | std::tie(server_port, client_port) = |
| 122 | auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); | 193 | ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); |
| 123 | g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); | 194 | |
| 195 | server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); | ||
| 196 | AddNamedPort(interface_->GetPortName(), std::move(client_port)); | ||
| 124 | } | 197 | } |
| 125 | 198 | ||
| 126 | void AddService(Interface* interface_) { | 199 | void AddService(Interface* interface_) { |
| 127 | auto ports = | 200 | auto server_port = |
| 128 | Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), | 201 | SM::g_service_manager |
| 129 | std::shared_ptr<Interface>(interface_)); | 202 | ->RegisterService(interface_->GetPortName(), interface_->GetMaxSessions()) |
| 130 | auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); | 203 | .MoveFrom(); |
| 131 | g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); | 204 | server_port->SetHleHandler(std::shared_ptr<Interface>(interface_)); |
| 132 | } | 205 | } |
| 133 | 206 | ||
| 134 | /// Initialize ServiceManager | 207 | /// Initialize ServiceManager |
| 135 | void Init() { | 208 | void Init() { |
| 136 | AddNamedPort(new SRV::SRV); | 209 | SM::g_service_manager = std::make_shared<SM::ServiceManager>(); |
| 210 | SM::ServiceManager::InstallInterfaces(SM::g_service_manager); | ||
| 211 | |||
| 137 | AddNamedPort(new ERR::ERR_F); | 212 | AddNamedPort(new ERR::ERR_F); |
| 138 | 213 | ||
| 139 | FS::ArchiveInit(); | 214 | FS::ArchiveInit(); |
| @@ -194,7 +269,7 @@ void Shutdown() { | |||
| 194 | AC::Shutdown(); | 269 | AC::Shutdown(); |
| 195 | FS::ArchiveShutdown(); | 270 | FS::ArchiveShutdown(); |
| 196 | 271 | ||
| 197 | g_srv_services.clear(); | 272 | SM::g_service_manager = nullptr; |
| 198 | g_kernel_named_ports.clear(); | 273 | g_kernel_named_ports.clear(); |
| 199 | LOG_DEBUG(Service, "shutdown OK"); | 274 | LOG_DEBUG(Service, "shutdown OK"); |
| 200 | } | 275 | } |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index e6a5f1417..281ff99bb 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -8,70 +8,38 @@ | |||
| 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; | ||
| 21 | class ServerPort; | ||
| 20 | class ServerSession; | 22 | class ServerSession; |
| 21 | } | 23 | } |
| 22 | 24 | ||
| 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 24 | // Namespace Service | ||
| 25 | |||
| 26 | namespace Service { | 25 | namespace Service { |
| 27 | 26 | ||
| 27 | namespace SM { | ||
| 28 | class ServiceManager; | ||
| 29 | } | ||
| 30 | |||
| 28 | static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) | 31 | static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) |
| 29 | /// Arbitrary default number of maximum connections to an HLE service. | 32 | /// Arbitrary default number of maximum connections to an HLE service. |
| 30 | static const u32 DefaultMaxSessions = 10; | 33 | static const u32 DefaultMaxSessions = 10; |
| 31 | 34 | ||
| 32 | /** | 35 | /** |
| 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 | 36 | * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a |
| 72 | * table mapping header ids to handler functions. | 37 | * table mapping header ids to handler functions. |
| 38 | * | ||
| 39 | * @deprecated Use ServiceFramework for new services instead. It allows services to be stateful and | ||
| 40 | * is more extensible going forward. | ||
| 73 | */ | 41 | */ |
| 74 | class Interface : public SessionRequestHandler { | 42 | class Interface : public Kernel::SessionRequestHandler { |
| 75 | public: | 43 | public: |
| 76 | /** | 44 | /** |
| 77 | * Creates an HLE interface with the specified max sessions. | 45 | * Creates an HLE interface with the specified max sessions. |
| @@ -141,6 +109,146 @@ private: | |||
| 141 | boost::container::flat_map<u32, FunctionInfo> m_functions; | 109 | boost::container::flat_map<u32, FunctionInfo> m_functions; |
| 142 | }; | 110 | }; |
| 143 | 111 | ||
| 112 | /** | ||
| 113 | * This is an non-templated base of ServiceFramework to reduce code bloat and compilation times, it | ||
| 114 | * is not meant to be used directly. | ||
| 115 | * | ||
| 116 | * @see ServiceFramework | ||
| 117 | */ | ||
| 118 | class ServiceFrameworkBase : public Kernel::SessionRequestHandler { | ||
| 119 | public: | ||
| 120 | /// Returns the string identifier used to connect to the service. | ||
| 121 | std::string GetServiceName() const { | ||
| 122 | return service_name; | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * Returns the maximum number of sessions that can be connected to this service at the same | ||
| 127 | * time. | ||
| 128 | */ | ||
| 129 | u32 GetMaxSessions() const { | ||
| 130 | return max_sessions; | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Creates a port pair and registers this service with the given ServiceManager. | ||
| 134 | void InstallAsService(SM::ServiceManager& service_manager); | ||
| 135 | /// Creates a port pair and registers it on the kernel's global port registry. | ||
| 136 | void InstallAsNamedPort(); | ||
| 137 | |||
| 138 | void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; | ||
| 139 | |||
| 140 | protected: | ||
| 141 | /// Member-function pointer type of SyncRequest handlers. | ||
| 142 | template <typename Self> | ||
| 143 | using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); | ||
| 144 | |||
| 145 | private: | ||
| 146 | template <typename T> | ||
| 147 | friend class ServiceFramework; | ||
| 148 | |||
| 149 | struct FunctionInfoBase { | ||
| 150 | u32 expected_header; | ||
| 151 | HandlerFnP<ServiceFrameworkBase> handler_callback; | ||
| 152 | const char* name; | ||
| 153 | }; | ||
| 154 | |||
| 155 | using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, | ||
| 156 | Kernel::HLERequestContext& ctx); | ||
| 157 | |||
| 158 | ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); | ||
| 159 | ~ServiceFrameworkBase(); | ||
| 160 | |||
| 161 | void RegisterHandlersBase(const FunctionInfoBase* functions, size_t n); | ||
| 162 | void ReportUnimplementedFunction(u32* cmd_buf, const FunctionInfoBase* info); | ||
| 163 | |||
| 164 | /// Identifier string used to connect to the service. | ||
| 165 | std::string service_name; | ||
| 166 | /// Maximum number of concurrent sessions that this service can handle. | ||
| 167 | u32 max_sessions; | ||
| 168 | |||
| 169 | /** | ||
| 170 | * Port where incoming connections will be received. Only created when InstallAsService() or | ||
| 171 | * InstallAsNamedPort() are called. | ||
| 172 | */ | ||
| 173 | Kernel::SharedPtr<Kernel::ServerPort> port; | ||
| 174 | |||
| 175 | /// Function used to safely up-cast pointers to the derived class before invoking a handler. | ||
| 176 | InvokerFn* handler_invoker; | ||
| 177 | boost::container::flat_map<u32, FunctionInfoBase> handlers; | ||
| 178 | }; | ||
| 179 | |||
| 180 | /** | ||
| 181 | * Framework for implementing HLE services. Dispatches on the header id of incoming SyncRequests | ||
| 182 | * based on a table mapping header ids to handler functions. Service implementations should inherit | ||
| 183 | * from ServiceFramework using the CRTP (`class Foo : public ServiceFramework<Foo> { ... };`) and | ||
| 184 | * populate it with handlers by calling #RegisterHandlers. | ||
| 185 | * | ||
| 186 | * In order to avoid duplicating code in the binary and exposing too many implementation details in | ||
| 187 | * the header, this class is split into a non-templated base (ServiceFrameworkBase) and a template | ||
| 188 | * deriving from it (ServiceFramework). The functions in this class will mostly only erase the type | ||
| 189 | * of the passed in function pointers and then delegate the actual work to the implementation in the | ||
| 190 | * base class. | ||
| 191 | */ | ||
| 192 | template <typename Self> | ||
| 193 | class ServiceFramework : public ServiceFrameworkBase { | ||
| 194 | protected: | ||
| 195 | /// Contains information about a request type which is handled by the service. | ||
| 196 | struct FunctionInfo : FunctionInfoBase { | ||
| 197 | // TODO(yuriks): This function could be constexpr, but clang is the only compiler that | ||
| 198 | // doesn't emit an ICE or a wrong diagnostic because of the static_cast. | ||
| 199 | |||
| 200 | /** | ||
| 201 | * Constructs a FunctionInfo for a function. | ||
| 202 | * | ||
| 203 | * @param expected_header request header in the command buffer which will trigger dispatch | ||
| 204 | * to this handler | ||
| 205 | * @param handler_callback member function in this service which will be called to handle | ||
| 206 | * the request | ||
| 207 | * @param name human-friendly name for the request. Used mostly for logging purposes. | ||
| 208 | */ | ||
| 209 | FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name) | ||
| 210 | : FunctionInfoBase{ | ||
| 211 | expected_header, | ||
| 212 | // Type-erase member function pointer by casting it down to the base class. | ||
| 213 | static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {} | ||
| 214 | }; | ||
| 215 | |||
| 216 | /** | ||
| 217 | * Initializes the handler with no functions installed. | ||
| 218 | * @param max_sessions Maximum number of sessions that can be | ||
| 219 | * connected to this service at the same time. | ||
| 220 | */ | ||
| 221 | ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) | ||
| 222 | : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} | ||
| 223 | |||
| 224 | /// Registers handlers in the service. | ||
| 225 | template <size_t N> | ||
| 226 | void RegisterHandlers(const FunctionInfo (&functions)[N]) { | ||
| 227 | RegisterHandlers(functions, N); | ||
| 228 | } | ||
| 229 | |||
| 230 | /** | ||
| 231 | * Registers handlers in the service. Usually prefer using the other RegisterHandlers | ||
| 232 | * overload in order to avoid needing to specify the array size. | ||
| 233 | */ | ||
| 234 | void RegisterHandlers(const FunctionInfo* functions, size_t n) { | ||
| 235 | RegisterHandlersBase(functions, n); | ||
| 236 | } | ||
| 237 | |||
| 238 | private: | ||
| 239 | /** | ||
| 240 | * This function is used to allow invocation of pointers to handlers stored in the base class | ||
| 241 | * without needing to expose the type of this derived class. Pointers-to-member may require a | ||
| 242 | * fixup when being up or downcast, and thus code that does that needs to know the concrete type | ||
| 243 | * of the derived class in order to invoke one of it's functions through a pointer. | ||
| 244 | */ | ||
| 245 | static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, | ||
| 246 | Kernel::HLERequestContext& ctx) { | ||
| 247 | // Cast back up to our original types and call the member function | ||
| 248 | (static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx); | ||
| 249 | } | ||
| 250 | }; | ||
| 251 | |||
| 144 | /// Initialize ServiceManager | 252 | /// Initialize ServiceManager |
| 145 | void Init(); | 253 | void Init(); |
| 146 | 254 | ||
| @@ -149,9 +257,9 @@ void Shutdown(); | |||
| 149 | 257 | ||
| 150 | /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. | 258 | /// 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; | 259 | 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 | 260 | ||
| 261 | /// Adds a port to the named port table | ||
| 262 | void AddNamedPort(std::string name, Kernel::SharedPtr<Kernel::ClientPort> port); | ||
| 155 | /// Adds a service to the services table | 263 | /// Adds a service to the services table |
| 156 | void AddService(Interface* interface_); | 264 | void AddService(Interface* interface_); |
| 157 | 265 | ||
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp new file mode 100644 index 000000000..5e7fc68f9 --- /dev/null +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -0,0 +1,69 @@ | |||
| 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 "common/assert.h" | ||
| 7 | #include "core/hle/kernel/client_port.h" | ||
| 8 | #include "core/hle/kernel/client_session.h" | ||
| 9 | #include "core/hle/kernel/server_port.h" | ||
| 10 | #include "core/hle/result.h" | ||
| 11 | #include "core/hle/service/sm/sm.h" | ||
| 12 | #include "core/hle/service/sm/srv.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace SM { | ||
| 16 | |||
| 17 | static ResultCode ValidateServiceName(const std::string& name) { | ||
| 18 | if (name.size() <= 0 || name.size() > 8) { | ||
| 19 | return ERR_INVALID_NAME_SIZE; | ||
| 20 | } | ||
| 21 | if (name.find('\0') != std::string::npos) { | ||
| 22 | return ERR_NAME_CONTAINS_NUL; | ||
| 23 | } | ||
| 24 | return RESULT_SUCCESS; | ||
| 25 | } | ||
| 26 | |||
| 27 | void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) { | ||
| 28 | ASSERT(self->srv_interface.expired()); | ||
| 29 | |||
| 30 | auto srv = std::make_shared<SRV>(self); | ||
| 31 | srv->InstallAsNamedPort(); | ||
| 32 | self->srv_interface = srv; | ||
| 33 | } | ||
| 34 | |||
| 35 | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService( | ||
| 36 | std::string name, unsigned int max_sessions) { | ||
| 37 | |||
| 38 | CASCADE_CODE(ValidateServiceName(name)); | ||
| 39 | Kernel::SharedPtr<Kernel::ServerPort> server_port; | ||
| 40 | Kernel::SharedPtr<Kernel::ClientPort> client_port; | ||
| 41 | std::tie(server_port, client_port) = Kernel::ServerPort::CreatePortPair(max_sessions, name); | ||
| 42 | |||
| 43 | registered_services.emplace(std::move(name), std::move(client_port)); | ||
| 44 | return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); | ||
| 45 | } | ||
| 46 | |||
| 47 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( | ||
| 48 | const std::string& name) { | ||
| 49 | |||
| 50 | CASCADE_CODE(ValidateServiceName(name)); | ||
| 51 | auto it = registered_services.find(name); | ||
| 52 | if (it == registered_services.end()) { | ||
| 53 | return ERR_SERVICE_NOT_REGISTERED; | ||
| 54 | } | ||
| 55 | |||
| 56 | return MakeResult<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); | ||
| 57 | } | ||
| 58 | |||
| 59 | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService( | ||
| 60 | const std::string& name) { | ||
| 61 | |||
| 62 | CASCADE_RESULT(auto client_port, GetServicePort(name)); | ||
| 63 | return client_port->Connect(); | ||
| 64 | } | ||
| 65 | |||
| 66 | std::shared_ptr<ServiceManager> g_service_manager; | ||
| 67 | |||
| 68 | } // namespace SM | ||
| 69 | } // 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..8f0dbf2db --- /dev/null +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -0,0 +1,55 @@ | |||
| 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 | class SRV; | ||
| 24 | |||
| 25 | constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(1, ErrorModule::SRV, ErrorSummary::WouldBlock, | ||
| 26 | ErrorLevel::Temporary); // 0xD0406401 | ||
| 27 | constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(2, ErrorModule::SRV, ErrorSummary::WouldBlock, | ||
| 28 | ErrorLevel::Temporary); // 0xD0406402 | ||
| 29 | constexpr ResultCode ERR_INVALID_NAME_SIZE(5, ErrorModule::SRV, ErrorSummary::WrongArgument, | ||
| 30 | ErrorLevel::Permanent); // 0xD9006405 | ||
| 31 | constexpr ResultCode ERR_ACCESS_DENIED(6, ErrorModule::SRV, ErrorSummary::InvalidArgument, | ||
| 32 | ErrorLevel::Permanent); // 0xD8E06406 | ||
| 33 | constexpr ResultCode ERR_NAME_CONTAINS_NUL(7, ErrorModule::SRV, ErrorSummary::WrongArgument, | ||
| 34 | ErrorLevel::Permanent); // 0xD9006407 | ||
| 35 | |||
| 36 | class ServiceManager { | ||
| 37 | public: | ||
| 38 | static void InstallInterfaces(std::shared_ptr<ServiceManager> self); | ||
| 39 | |||
| 40 | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, | ||
| 41 | unsigned int max_sessions); | ||
| 42 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); | ||
| 43 | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); | ||
| 44 | |||
| 45 | private: | ||
| 46 | std::weak_ptr<SRV> srv_interface; | ||
| 47 | |||
| 48 | /// Map of registered services, retrieved using GetServicePort or ConnectToService. | ||
| 49 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services; | ||
| 50 | }; | ||
| 51 | |||
| 52 | extern std::shared_ptr<ServiceManager> g_service_manager; | ||
| 53 | |||
| 54 | } // namespace SM | ||
| 55 | } // namespace Service | ||
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp new file mode 100644 index 000000000..b8b62b068 --- /dev/null +++ b/src/core/hle/service/sm/srv.cpp | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <tuple> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/ipc.h" | ||
| 10 | #include "core/hle/kernel/client_port.h" | ||
| 11 | #include "core/hle/kernel/client_session.h" | ||
| 12 | #include "core/hle/kernel/handle_table.h" | ||
| 13 | #include "core/hle/kernel/semaphore.h" | ||
| 14 | #include "core/hle/kernel/server_session.h" | ||
| 15 | #include "core/hle/service/sm/sm.h" | ||
| 16 | #include "core/hle/service/sm/srv.h" | ||
| 17 | |||
| 18 | namespace Service { | ||
| 19 | namespace SM { | ||
| 20 | |||
| 21 | constexpr int MAX_PENDING_NOTIFICATIONS = 16; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * SRV::RegisterClient service function | ||
| 25 | * Inputs: | ||
| 26 | * 0: 0x00010002 | ||
| 27 | * 1: ProcessId Header (must be 0x20) | ||
| 28 | * Outputs: | ||
| 29 | * 0: 0x00010040 | ||
| 30 | * 1: ResultCode | ||
| 31 | */ | ||
| 32 | void SRV::RegisterClient(Kernel::HLERequestContext& ctx) { | ||
| 33 | u32* cmd_buff = ctx.CommandBuffer(); | ||
| 34 | |||
| 35 | if (cmd_buff[1] != IPC::CallingPidDesc()) { | ||
| 36 | cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 | ||
| 37 | cmd_buff[1] = IPC::ERR_INVALID_BUFFER_DESCRIPTOR.raw; | ||
| 38 | return; | ||
| 39 | } | ||
| 40 | cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); // 0x10040 | ||
| 41 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 42 | LOG_WARNING(Service_SRV, "(STUBBED) called"); | ||
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * SRV::EnableNotification service function | ||
| 47 | * Inputs: | ||
| 48 | * 0: 0x00020000 | ||
| 49 | * Outputs: | ||
| 50 | * 0: 0x00020042 | ||
| 51 | * 1: ResultCode | ||
| 52 | * 2: Translation descriptor: 0x20 | ||
| 53 | * 3: Handle to semaphore signaled on process notification | ||
| 54 | */ | ||
| 55 | void SRV::EnableNotification(Kernel::HLERequestContext& ctx) { | ||
| 56 | u32* cmd_buff = ctx.CommandBuffer(); | ||
| 57 | |||
| 58 | notification_semaphore = | ||
| 59 | Kernel::Semaphore::Create(0, MAX_PENDING_NOTIFICATIONS, "SRV:Notification").Unwrap(); | ||
| 60 | |||
| 61 | cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 | ||
| 62 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 63 | cmd_buff[2] = IPC::CopyHandleDesc(1); | ||
| 64 | cmd_buff[3] = Kernel::g_handle_table.Create(notification_semaphore).MoveFrom(); | ||
| 65 | LOG_WARNING(Service_SRV, "(STUBBED) called"); | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * SRV::GetServiceHandle service function | ||
| 70 | * Inputs: | ||
| 71 | * 0: 0x00050100 | ||
| 72 | * 1-2: 8-byte UTF-8 service name | ||
| 73 | * 3: Name length | ||
| 74 | * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) | ||
| 75 | * Outputs: | ||
| 76 | * 1: ResultCode | ||
| 77 | * 3: Service handle | ||
| 78 | */ | ||
| 79 | void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { | ||
| 80 | ResultCode res = RESULT_SUCCESS; | ||
| 81 | u32* cmd_buff = ctx.CommandBuffer(); | ||
| 82 | |||
| 83 | size_t name_len = cmd_buff[3]; | ||
| 84 | if (name_len > Service::kMaxPortSize) { | ||
| 85 | cmd_buff[1] = ERR_INVALID_NAME_SIZE.raw; | ||
| 86 | LOG_ERROR(Service_SRV, "called name_len=0x%X, failed with code=0x%08X", name_len, | ||
| 87 | cmd_buff[1]); | ||
| 88 | return; | ||
| 89 | } | ||
| 90 | std::string name(reinterpret_cast<const char*>(&cmd_buff[1]), name_len); | ||
| 91 | bool return_port_on_failure = (cmd_buff[4] & 1) == 0; | ||
| 92 | |||
| 93 | // TODO(yuriks): Permission checks go here | ||
| 94 | |||
| 95 | auto client_port = service_manager->GetServicePort(name); | ||
| 96 | if (client_port.Failed()) { | ||
| 97 | cmd_buff[1] = client_port.Code().raw; | ||
| 98 | LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), | ||
| 99 | cmd_buff[1]); | ||
| 100 | return; | ||
| 101 | } | ||
| 102 | |||
| 103 | auto session = client_port.Unwrap()->Connect(); | ||
| 104 | cmd_buff[1] = session.Code().raw; | ||
| 105 | if (session.Succeeded()) { | ||
| 106 | cmd_buff[3] = Kernel::g_handle_table.Create(session.MoveFrom()).MoveFrom(); | ||
| 107 | LOG_DEBUG(Service_SRV, "called service=%s, session handle=0x%08X", name.c_str(), | ||
| 108 | cmd_buff[3]); | ||
| 109 | } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED && return_port_on_failure) { | ||
| 110 | cmd_buff[1] = ERR_MAX_CONNECTIONS_REACHED.raw; | ||
| 111 | cmd_buff[3] = Kernel::g_handle_table.Create(client_port.MoveFrom()).MoveFrom(); | ||
| 112 | LOG_WARNING(Service_SRV, "called service=%s, *port* handle=0x%08X", name.c_str(), | ||
| 113 | cmd_buff[3]); | ||
| 114 | } else { | ||
| 115 | LOG_ERROR(Service_SRV, "called service=%s, failed with code=0x%08X", name.c_str(), | ||
| 116 | cmd_buff[1]); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | /** | ||
| 121 | * SRV::Subscribe service function | ||
| 122 | * Inputs: | ||
| 123 | * 0: 0x00090040 | ||
| 124 | * 1: Notification ID | ||
| 125 | * Outputs: | ||
| 126 | * 0: 0x00090040 | ||
| 127 | * 1: ResultCode | ||
| 128 | */ | ||
| 129 | void SRV::Subscribe(Kernel::HLERequestContext& ctx) { | ||
| 130 | u32* cmd_buff = ctx.CommandBuffer(); | ||
| 131 | |||
| 132 | u32 notification_id = cmd_buff[1]; | ||
| 133 | |||
| 134 | cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 | ||
| 135 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 136 | LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * SRV::Unsubscribe service function | ||
| 141 | * Inputs: | ||
| 142 | * 0: 0x000A0040 | ||
| 143 | * 1: Notification ID | ||
| 144 | * Outputs: | ||
| 145 | * 0: 0x000A0040 | ||
| 146 | * 1: ResultCode | ||
| 147 | */ | ||
| 148 | void SRV::Unsubscribe(Kernel::HLERequestContext& ctx) { | ||
| 149 | u32* cmd_buff = ctx.CommandBuffer(); | ||
| 150 | |||
| 151 | u32 notification_id = cmd_buff[1]; | ||
| 152 | |||
| 153 | cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 | ||
| 154 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 155 | LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); | ||
| 156 | } | ||
| 157 | |||
| 158 | /** | ||
| 159 | * SRV::PublishToSubscriber service function | ||
| 160 | * Inputs: | ||
| 161 | * 0: 0x000C0080 | ||
| 162 | * 1: Notification ID | ||
| 163 | * 2: Flags (bit0: only fire if not fired, bit1: report errors) | ||
| 164 | * Outputs: | ||
| 165 | * 0: 0x000C0040 | ||
| 166 | * 1: ResultCode | ||
| 167 | */ | ||
| 168 | void SRV::PublishToSubscriber(Kernel::HLERequestContext& ctx) { | ||
| 169 | u32* cmd_buff = ctx.CommandBuffer(); | ||
| 170 | |||
| 171 | u32 notification_id = cmd_buff[1]; | ||
| 172 | u8 flags = cmd_buff[2] & 0xFF; | ||
| 173 | |||
| 174 | cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 | ||
| 175 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 176 | LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, | ||
| 177 | flags); | ||
| 178 | } | ||
| 179 | |||
| 180 | SRV::SRV(std::shared_ptr<ServiceManager> service_manager) | ||
| 181 | : ServiceFramework("srv:", 4), service_manager(std::move(service_manager)) { | ||
| 182 | static const FunctionInfo functions[] = { | ||
| 183 | {0x00010002, &SRV::RegisterClient, "RegisterClient"}, | ||
| 184 | {0x00020000, &SRV::EnableNotification, "EnableNotification"}, | ||
| 185 | {0x00030100, nullptr, "RegisterService"}, | ||
| 186 | {0x000400C0, nullptr, "UnregisterService"}, | ||
| 187 | {0x00050100, &SRV::GetServiceHandle, "GetServiceHandle"}, | ||
| 188 | {0x000600C2, nullptr, "RegisterPort"}, | ||
| 189 | {0x000700C0, nullptr, "UnregisterPort"}, | ||
| 190 | {0x00080100, nullptr, "GetPort"}, | ||
| 191 | {0x00090040, &SRV::Subscribe, "Subscribe"}, | ||
| 192 | {0x000A0040, &SRV::Unsubscribe, "Unsubscribe"}, | ||
| 193 | {0x000B0000, nullptr, "ReceiveNotification"}, | ||
| 194 | {0x000C0080, &SRV::PublishToSubscriber, "PublishToSubscriber"}, | ||
| 195 | {0x000D0040, nullptr, "PublishAndGetSubscriber"}, | ||
| 196 | {0x000E00C0, nullptr, "IsServiceRegistered"}, | ||
| 197 | }; | ||
| 198 | RegisterHandlers(functions); | ||
| 199 | } | ||
| 200 | |||
| 201 | SRV::~SRV() = default; | ||
| 202 | |||
| 203 | } // namespace SM | ||
| 204 | } // namespace Service | ||
diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h new file mode 100644 index 000000000..75cca5184 --- /dev/null +++ b/src/core/hle/service/sm/srv.h | |||
| @@ -0,0 +1,37 @@ | |||
| 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 "core/hle/kernel/kernel.h" | ||
| 8 | #include "core/hle/service/service.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class HLERequestContext; | ||
| 12 | class Semaphore; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service { | ||
| 16 | namespace SM { | ||
| 17 | |||
| 18 | /// Interface to "srv:" service | ||
| 19 | class SRV final : public ServiceFramework<SRV> { | ||
| 20 | public: | ||
| 21 | explicit SRV(std::shared_ptr<ServiceManager> service_manager); | ||
| 22 | ~SRV(); | ||
| 23 | |||
| 24 | private: | ||
| 25 | void RegisterClient(Kernel::HLERequestContext& ctx); | ||
| 26 | void EnableNotification(Kernel::HLERequestContext& ctx); | ||
| 27 | void GetServiceHandle(Kernel::HLERequestContext& ctx); | ||
| 28 | void Subscribe(Kernel::HLERequestContext& ctx); | ||
| 29 | void Unsubscribe(Kernel::HLERequestContext& ctx); | ||
| 30 | void PublishToSubscriber(Kernel::HLERequestContext& ctx); | ||
| 31 | |||
| 32 | std::shared_ptr<ServiceManager> service_manager; | ||
| 33 | Kernel::SharedPtr<Kernel::Semaphore> notification_semaphore; | ||
| 34 | }; | ||
| 35 | |||
| 36 | } // namespace SM | ||
| 37 | } // 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/srv.cpp b/src/core/hle/service/srv.cpp deleted file mode 100644 index 3bd787147..000000000 --- a/src/core/hle/service/srv.cpp +++ /dev/null | |||
| @@ -1,190 +0,0 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <tuple> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/kernel/client_session.h" | ||
| 10 | #include "core/hle/kernel/event.h" | ||
| 11 | #include "core/hle/kernel/server_session.h" | ||
| 12 | #include "core/hle/service/srv.h" | ||
| 13 | |||
| 14 | namespace Service { | ||
| 15 | namespace SRV { | ||
| 16 | |||
| 17 | static Kernel::SharedPtr<Kernel::Event> event_handle; | ||
| 18 | |||
| 19 | /** | ||
| 20 | * SRV::RegisterClient service function | ||
| 21 | * Inputs: | ||
| 22 | * 0: 0x00010002 | ||
| 23 | * 1: ProcessId Header (must be 0x20) | ||
| 24 | * Outputs: | ||
| 25 | * 0: 0x00010040 | ||
| 26 | * 1: ResultCode | ||
| 27 | */ | ||
| 28 | static void RegisterClient(Interface* self) { | ||
| 29 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 30 | |||
| 31 | if (cmd_buff[1] != IPC::CallingPidDesc()) { | ||
| 32 | cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); // 0x40 | ||
| 33 | cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, | ||
| 34 | ErrorSummary::WrongArgument, ErrorLevel::Permanent) | ||
| 35 | .raw; | ||
| 36 | return; | ||
| 37 | } | ||
| 38 | cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); // 0x10040 | ||
| 39 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 40 | LOG_WARNING(Service_SRV, "(STUBBED) called"); | ||
| 41 | } | ||
| 42 | |||
| 43 | /** | ||
| 44 | * SRV::EnableNotification service function | ||
| 45 | * Inputs: | ||
| 46 | * 0: 0x00020000 | ||
| 47 | * Outputs: | ||
| 48 | * 0: 0x00020042 | ||
| 49 | * 1: ResultCode | ||
| 50 | * 2: Translation descriptor: 0x20 | ||
| 51 | * 3: Handle to semaphore signaled on process notification | ||
| 52 | */ | ||
| 53 | static void EnableNotification(Interface* self) { | ||
| 54 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 55 | |||
| 56 | // TODO(bunnei): Change to a semaphore once these have been implemented | ||
| 57 | event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); | ||
| 58 | event_handle->Clear(); | ||
| 59 | |||
| 60 | cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 | ||
| 61 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 62 | cmd_buff[2] = IPC::CopyHandleDesc(1); | ||
| 63 | cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); | ||
| 64 | LOG_WARNING(Service_SRV, "(STUBBED) called"); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * SRV::GetServiceHandle service function | ||
| 69 | * Inputs: | ||
| 70 | * 0: 0x00050100 | ||
| 71 | * 1-2: 8-byte UTF-8 service name | ||
| 72 | * 3: Name length | ||
| 73 | * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) | ||
| 74 | * Outputs: | ||
| 75 | * 1: ResultCode | ||
| 76 | * 3: Service handle | ||
| 77 | */ | ||
| 78 | static void GetServiceHandle(Interface* self) { | ||
| 79 | ResultCode res = RESULT_SUCCESS; | ||
| 80 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 81 | |||
| 82 | std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); | ||
| 83 | auto it = Service::g_srv_services.find(port_name); | ||
| 84 | |||
| 85 | if (it != Service::g_srv_services.end()) { | ||
| 86 | auto client_port = it->second; | ||
| 87 | |||
| 88 | auto client_session = client_port->Connect(); | ||
| 89 | res = client_session.Code(); | ||
| 90 | |||
| 91 | if (client_session.Succeeded()) { | ||
| 92 | // Return the client session | ||
| 93 | cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); | ||
| 94 | } | ||
| 95 | LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); | ||
| 96 | } else { | ||
| 97 | LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); | ||
| 98 | res = UnimplementedFunction(ErrorModule::SRV); | ||
| 99 | } | ||
| 100 | cmd_buff[1] = res.raw; | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * SRV::Subscribe service function | ||
| 105 | * Inputs: | ||
| 106 | * 0: 0x00090040 | ||
| 107 | * 1: Notification ID | ||
| 108 | * Outputs: | ||
| 109 | * 0: 0x00090040 | ||
| 110 | * 1: ResultCode | ||
| 111 | */ | ||
| 112 | static void Subscribe(Interface* self) { | ||
| 113 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 114 | |||
| 115 | u32 notification_id = cmd_buff[1]; | ||
| 116 | |||
| 117 | cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 | ||
| 118 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 119 | LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * SRV::Unsubscribe service function | ||
| 124 | * Inputs: | ||
| 125 | * 0: 0x000A0040 | ||
| 126 | * 1: Notification ID | ||
| 127 | * Outputs: | ||
| 128 | * 0: 0x000A0040 | ||
| 129 | * 1: ResultCode | ||
| 130 | */ | ||
| 131 | static void Unsubscribe(Interface* self) { | ||
| 132 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 133 | |||
| 134 | u32 notification_id = cmd_buff[1]; | ||
| 135 | |||
| 136 | cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 | ||
| 137 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 138 | LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * SRV::PublishToSubscriber service function | ||
| 143 | * Inputs: | ||
| 144 | * 0: 0x000C0080 | ||
| 145 | * 1: Notification ID | ||
| 146 | * 2: Flags (bit0: only fire if not fired, bit1: report errors) | ||
| 147 | * Outputs: | ||
| 148 | * 0: 0x000C0040 | ||
| 149 | * 1: ResultCode | ||
| 150 | */ | ||
| 151 | static void PublishToSubscriber(Interface* self) { | ||
| 152 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 153 | |||
| 154 | u32 notification_id = cmd_buff[1]; | ||
| 155 | u8 flags = cmd_buff[2] & 0xFF; | ||
| 156 | |||
| 157 | cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 | ||
| 158 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | ||
| 159 | LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, | ||
| 160 | flags); | ||
| 161 | } | ||
| 162 | |||
| 163 | const Interface::FunctionInfo FunctionTable[] = { | ||
| 164 | {0x00010002, RegisterClient, "RegisterClient"}, | ||
| 165 | {0x00020000, EnableNotification, "EnableNotification"}, | ||
| 166 | {0x00030100, nullptr, "RegisterService"}, | ||
| 167 | {0x000400C0, nullptr, "UnregisterService"}, | ||
| 168 | {0x00050100, GetServiceHandle, "GetServiceHandle"}, | ||
| 169 | {0x000600C2, nullptr, "RegisterPort"}, | ||
| 170 | {0x000700C0, nullptr, "UnregisterPort"}, | ||
| 171 | {0x00080100, nullptr, "GetPort"}, | ||
| 172 | {0x00090040, Subscribe, "Subscribe"}, | ||
| 173 | {0x000A0040, Unsubscribe, "Unsubscribe"}, | ||
| 174 | {0x000B0000, nullptr, "ReceiveNotification"}, | ||
| 175 | {0x000C0080, PublishToSubscriber, "PublishToSubscriber"}, | ||
| 176 | {0x000D0040, nullptr, "PublishAndGetSubscriber"}, | ||
| 177 | {0x000E00C0, nullptr, "IsServiceRegistered"}, | ||
| 178 | }; | ||
| 179 | |||
| 180 | SRV::SRV() { | ||
| 181 | Register(FunctionTable); | ||
| 182 | event_handle = nullptr; | ||
| 183 | } | ||
| 184 | |||
| 185 | SRV::~SRV() { | ||
| 186 | event_handle = nullptr; | ||
| 187 | } | ||
| 188 | |||
| 189 | } // namespace SRV | ||
| 190 | } // namespace Service | ||
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h deleted file mode 100644 index d3a9de879..000000000 --- a/src/core/hle/service/srv.h +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service { | ||
| 10 | namespace SRV { | ||
| 11 | |||
| 12 | /// Interface to "srv:" service | ||
| 13 | class SRV final : public Interface { | ||
| 14 | public: | ||
| 15 | SRV(); | ||
| 16 | ~SRV() override; | ||
| 17 | |||
| 18 | std::string GetPortName() const override { | ||
| 19 | return "srv:"; | ||
| 20 | } | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace SRV | ||
| 24 | } // namespace Service | ||
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 8538cfc9d..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" |
| @@ -14,7 +15,9 @@ | |||
| 14 | #include "core/hle/kernel/address_arbiter.h" | 15 | #include "core/hle/kernel/address_arbiter.h" |
| 15 | #include "core/hle/kernel/client_port.h" | 16 | #include "core/hle/kernel/client_port.h" |
| 16 | #include "core/hle/kernel/client_session.h" | 17 | #include "core/hle/kernel/client_session.h" |
| 18 | #include "core/hle/kernel/errors.h" | ||
| 17 | #include "core/hle/kernel/event.h" | 19 | #include "core/hle/kernel/event.h" |
| 20 | #include "core/hle/kernel/handle_table.h" | ||
| 18 | #include "core/hle/kernel/memory.h" | 21 | #include "core/hle/kernel/memory.h" |
| 19 | #include "core/hle/kernel/mutex.h" | 22 | #include "core/hle/kernel/mutex.h" |
| 20 | #include "core/hle/kernel/process.h" | 23 | #include "core/hle/kernel/process.h" |
| @@ -26,6 +29,7 @@ | |||
| 26 | #include "core/hle/kernel/thread.h" | 29 | #include "core/hle/kernel/thread.h" |
| 27 | #include "core/hle/kernel/timer.h" | 30 | #include "core/hle/kernel/timer.h" |
| 28 | #include "core/hle/kernel/vm_manager.h" | 31 | #include "core/hle/kernel/vm_manager.h" |
| 32 | #include "core/hle/kernel/wait_object.h" | ||
| 29 | #include "core/hle/result.h" | 33 | #include "core/hle/result.h" |
| 30 | #include "core/hle/service/service.h" | 34 | #include "core/hle/service/service.h" |
| 31 | 35 | ||
| @@ -37,25 +41,6 @@ using Kernel::ERR_INVALID_HANDLE; | |||
| 37 | 41 | ||
| 38 | namespace SVC { | 42 | namespace SVC { |
| 39 | 43 | ||
| 40 | const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, | ||
| 41 | ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA | ||
| 42 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, | ||
| 43 | ErrorSummary::InvalidArgument, | ||
| 44 | ErrorLevel::Usage); // 0xE0E0181E | ||
| 45 | |||
| 46 | const ResultCode ERR_SYNC_TIMEOUT(ErrorDescription::Timeout, ErrorModule::OS, | ||
| 47 | ErrorSummary::StatusChanged, ErrorLevel::Info); | ||
| 48 | |||
| 49 | const ResultCode ERR_MISALIGNED_ADDRESS{// 0xE0E01BF1 | ||
| 50 | ErrorDescription::MisalignedAddress, ErrorModule::OS, | ||
| 51 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 52 | const ResultCode ERR_MISALIGNED_SIZE{// 0xE0E01BF2 | ||
| 53 | ErrorDescription::MisalignedSize, ErrorModule::OS, | ||
| 54 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 55 | const ResultCode ERR_INVALID_COMBINATION{// 0xE0E01BEE | ||
| 56 | ErrorDescription::InvalidCombination, ErrorModule::OS, | ||
| 57 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 58 | |||
| 59 | enum ControlMemoryOperation { | 44 | enum ControlMemoryOperation { |
| 60 | MEMOP_FREE = 1, | 45 | MEMOP_FREE = 1, |
| 61 | MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel | 46 | MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel |
| @@ -195,8 +180,7 @@ static ResultCode MapMemoryBlock(Kernel::Handle handle, u32 addr, u32 permission | |||
| 195 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); | 180 | LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); |
| 196 | } | 181 | } |
| 197 | 182 | ||
| 198 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, | 183 | return Kernel::ERR_INVALID_COMBINATION; |
| 199 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 200 | } | 184 | } |
| 201 | 185 | ||
| 202 | static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) { | 186 | static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) { |
| @@ -216,16 +200,16 @@ static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) { | |||
| 216 | /// Connect to an OS service given the port name, returns the handle to the port to out | 200 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 217 | static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) { | 201 | static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) { |
| 218 | if (port_name == nullptr) | 202 | if (port_name == nullptr) |
| 219 | return ERR_NOT_FOUND; | 203 | return Kernel::ERR_NOT_FOUND; |
| 220 | if (std::strlen(port_name) > 11) | 204 | if (std::strlen(port_name) > 11) |
| 221 | return ERR_PORT_NAME_TOO_LONG; | 205 | return Kernel::ERR_PORT_NAME_TOO_LONG; |
| 222 | 206 | ||
| 223 | LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); | 207 | LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); |
| 224 | 208 | ||
| 225 | auto it = Service::g_kernel_named_ports.find(port_name); | 209 | auto it = Service::g_kernel_named_ports.find(port_name); |
| 226 | if (it == Service::g_kernel_named_ports.end()) { | 210 | if (it == Service::g_kernel_named_ports.end()) { |
| 227 | LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name); | 211 | LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name); |
| 228 | return ERR_NOT_FOUND; | 212 | return Kernel::ERR_NOT_FOUND; |
| 229 | } | 213 | } |
| 230 | 214 | ||
| 231 | auto client_port = it->second; | 215 | auto client_port = it->second; |
| @@ -263,7 +247,7 @@ static ResultCode CloseHandle(Kernel::Handle handle) { | |||
| 263 | 247 | ||
| 264 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | 248 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds |
| 265 | static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) { | 249 | static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) { |
| 266 | auto object = Kernel::g_handle_table.GetWaitObject(handle); | 250 | auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle); |
| 267 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | 251 | Kernel::Thread* thread = Kernel::GetCurrentThread(); |
| 268 | 252 | ||
| 269 | if (object == nullptr) | 253 | if (object == nullptr) |
| @@ -275,7 +259,7 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) | |||
| 275 | if (object->ShouldWait(thread)) { | 259 | if (object->ShouldWait(thread)) { |
| 276 | 260 | ||
| 277 | if (nano_seconds == 0) | 261 | if (nano_seconds == 0) |
| 278 | return ERR_SYNC_TIMEOUT; | 262 | return Kernel::RESULT_TIMEOUT; |
| 279 | 263 | ||
| 280 | thread->wait_objects = {object}; | 264 | thread->wait_objects = {object}; |
| 281 | object->AddWaitingThread(thread); | 265 | object->AddWaitingThread(thread); |
| @@ -289,7 +273,7 @@ static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) | |||
| 289 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread | 273 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread |
| 290 | // resumes due to a signal in its wait objects. | 274 | // resumes due to a signal in its wait objects. |
| 291 | // Otherwise we retain the default value of timeout. | 275 | // Otherwise we retain the default value of timeout. |
| 292 | return ERR_SYNC_TIMEOUT; | 276 | return Kernel::RESULT_TIMEOUT; |
| 293 | } | 277 | } |
| 294 | 278 | ||
| 295 | object->Acquire(thread); | 279 | object->Acquire(thread); |
| @@ -304,8 +288,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha | |||
| 304 | 288 | ||
| 305 | // Check if 'handles' is invalid | 289 | // Check if 'handles' is invalid |
| 306 | if (handles == nullptr) | 290 | if (handles == nullptr) |
| 307 | return ResultCode(ErrorDescription::InvalidPointer, ErrorModule::Kernel, | 291 | return Kernel::ERR_INVALID_POINTER; |
| 308 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 309 | 292 | ||
| 310 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If | 293 | // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If |
| 311 | // this happens, the running application will crash. | 294 | // this happens, the running application will crash. |
| @@ -313,14 +296,13 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha | |||
| 313 | 296 | ||
| 314 | // Check if 'handle_count' is invalid | 297 | // Check if 'handle_count' is invalid |
| 315 | if (handle_count < 0) | 298 | if (handle_count < 0) |
| 316 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, | 299 | return Kernel::ERR_OUT_OF_RANGE; |
| 317 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 318 | 300 | ||
| 319 | using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>; | 301 | using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>; |
| 320 | std::vector<ObjectPtr> objects(handle_count); | 302 | std::vector<ObjectPtr> objects(handle_count); |
| 321 | 303 | ||
| 322 | for (int i = 0; i < handle_count; ++i) { | 304 | for (int i = 0; i < handle_count; ++i) { |
| 323 | auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); | 305 | auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]); |
| 324 | if (object == nullptr) | 306 | if (object == nullptr) |
| 325 | return ERR_INVALID_HANDLE; | 307 | return ERR_INVALID_HANDLE; |
| 326 | objects[i] = object; | 308 | objects[i] = object; |
| @@ -344,7 +326,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha | |||
| 344 | // If a timeout value of 0 was provided, just return the Timeout error code instead of | 326 | // If a timeout value of 0 was provided, just return the Timeout error code instead of |
| 345 | // suspending the thread. | 327 | // suspending the thread. |
| 346 | if (nano_seconds == 0) | 328 | if (nano_seconds == 0) |
| 347 | return ERR_SYNC_TIMEOUT; | 329 | return Kernel::RESULT_TIMEOUT; |
| 348 | 330 | ||
| 349 | // Put the thread to sleep | 331 | // Put the thread to sleep |
| 350 | thread->status = THREADSTATUS_WAIT_SYNCH_ALL; | 332 | thread->status = THREADSTATUS_WAIT_SYNCH_ALL; |
| @@ -365,7 +347,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha | |||
| 365 | *out = -1; | 347 | *out = -1; |
| 366 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to | 348 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to |
| 367 | // a signal in one of its wait objects. | 349 | // a signal in one of its wait objects. |
| 368 | return ERR_SYNC_TIMEOUT; | 350 | return Kernel::RESULT_TIMEOUT; |
| 369 | } else { | 351 | } else { |
| 370 | // Find the first object that is acquirable in the provided list of objects | 352 | // Find the first object that is acquirable in the provided list of objects |
| 371 | auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { | 353 | auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { |
| @@ -385,7 +367,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha | |||
| 385 | // If a timeout value of 0 was provided, just return the Timeout error code instead of | 367 | // If a timeout value of 0 was provided, just return the Timeout error code instead of |
| 386 | // suspending the thread. | 368 | // suspending the thread. |
| 387 | if (nano_seconds == 0) | 369 | if (nano_seconds == 0) |
| 388 | return ERR_SYNC_TIMEOUT; | 370 | return Kernel::RESULT_TIMEOUT; |
| 389 | 371 | ||
| 390 | // Put the thread to sleep | 372 | // Put the thread to sleep |
| 391 | thread->status = THREADSTATUS_WAIT_SYNCH_ANY; | 373 | thread->status = THREADSTATUS_WAIT_SYNCH_ANY; |
| @@ -411,7 +393,7 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha | |||
| 411 | // Otherwise we retain the default value of timeout, and -1 in the out parameter | 393 | // Otherwise we retain the default value of timeout, and -1 in the out parameter |
| 412 | thread->wait_set_output = true; | 394 | thread->wait_set_output = true; |
| 413 | *out = -1; | 395 | *out = -1; |
| 414 | return ERR_SYNC_TIMEOUT; | 396 | return Kernel::RESULT_TIMEOUT; |
| 415 | } | 397 | } |
| 416 | } | 398 | } |
| 417 | 399 | ||
| @@ -520,22 +502,20 @@ static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resour | |||
| 520 | } | 502 | } |
| 521 | 503 | ||
| 522 | /// Creates a new thread | 504 | /// Creates a new thread |
| 523 | static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 entry_point, u32 arg, | 505 | static ResultCode CreateThread(Kernel::Handle* out_handle, u32 priority, u32 entry_point, u32 arg, |
| 524 | u32 stack_top, s32 processor_id) { | 506 | u32 stack_top, s32 processor_id) { |
| 525 | using Kernel::Thread; | 507 | using Kernel::Thread; |
| 526 | 508 | ||
| 527 | std::string name = Common::StringFromFormat("unknown-%08" PRIX32, entry_point); | 509 | std::string name = Common::StringFromFormat("unknown-%08" PRIX32, entry_point); |
| 528 | 510 | ||
| 529 | if (priority > THREADPRIO_LOWEST) { | 511 | if (priority > THREADPRIO_LOWEST) { |
| 530 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, | 512 | return Kernel::ERR_OUT_OF_RANGE; |
| 531 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 532 | } | 513 | } |
| 533 | 514 | ||
| 534 | using Kernel::ResourceLimit; | 515 | using Kernel::ResourceLimit; |
| 535 | Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit; | 516 | Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit; |
| 536 | if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) { | 517 | if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) { |
| 537 | return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::OS, | 518 | return Kernel::ERR_NOT_AUTHORIZED; |
| 538 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 539 | } | 519 | } |
| 540 | 520 | ||
| 541 | switch (processor_id) { | 521 | switch (processor_id) { |
| @@ -605,8 +585,7 @@ static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) { | |||
| 605 | /// Sets the priority for the specified thread | 585 | /// Sets the priority for the specified thread |
| 606 | static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) { | 586 | static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) { |
| 607 | if (priority > THREADPRIO_LOWEST) { | 587 | if (priority > THREADPRIO_LOWEST) { |
| 608 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, | 588 | return Kernel::ERR_OUT_OF_RANGE; |
| 609 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 610 | } | 589 | } |
| 611 | 590 | ||
| 612 | SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); | 591 | SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); |
| @@ -618,8 +597,7 @@ static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) { | |||
| 618 | // the one from the thread owner's resource limit. | 597 | // the one from the thread owner's resource limit. |
| 619 | Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit; | 598 | Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit; |
| 620 | if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) { | 599 | if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) { |
| 621 | return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::OS, | 600 | return Kernel::ERR_NOT_AUTHORIZED; |
| 622 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 623 | } | 601 | } |
| 624 | 602 | ||
| 625 | thread->SetPriority(priority); | 603 | thread->SetPriority(priority); |
| @@ -743,8 +721,7 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf | |||
| 743 | auto vma = process->vm_manager.FindVMA(addr); | 721 | auto vma = process->vm_manager.FindVMA(addr); |
| 744 | 722 | ||
| 745 | if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) | 723 | if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) |
| 746 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, | 724 | return Kernel::ERR_INVALID_ADDRESS; |
| 747 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 748 | 725 | ||
| 749 | memory_info->base_address = vma->second.base; | 726 | memory_info->base_address = vma->second.base; |
| 750 | memory_info->permission = static_cast<u32>(vma->second.permissions); | 727 | memory_info->permission = static_cast<u32>(vma->second.permissions); |
| @@ -842,8 +819,7 @@ static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) { | |||
| 842 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); | 819 | LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); |
| 843 | 820 | ||
| 844 | if (initial < 0 || interval < 0) { | 821 | if (initial < 0 || interval < 0) { |
| 845 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, | 822 | return Kernel::ERR_OUT_OF_RANGE_KERNEL; |
| 846 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 847 | } | 823 | } |
| 848 | 824 | ||
| 849 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | 825 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); |
| @@ -902,8 +878,7 @@ static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 si | |||
| 902 | using Kernel::SharedMemory; | 878 | using Kernel::SharedMemory; |
| 903 | 879 | ||
| 904 | if (size % Memory::PAGE_SIZE != 0) | 880 | if (size % Memory::PAGE_SIZE != 0) |
| 905 | return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, | 881 | return Kernel::ERR_MISALIGNED_SIZE; |
| 906 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 907 | 882 | ||
| 908 | SharedPtr<SharedMemory> shared_memory = nullptr; | 883 | SharedPtr<SharedMemory> shared_memory = nullptr; |
| 909 | 884 | ||
| @@ -924,16 +899,14 @@ static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 si | |||
| 924 | 899 | ||
| 925 | if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) || | 900 | if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) || |
| 926 | !VerifyPermissions(static_cast<MemoryPermission>(other_permission))) | 901 | !VerifyPermissions(static_cast<MemoryPermission>(other_permission))) |
| 927 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, | 902 | return Kernel::ERR_INVALID_COMBINATION; |
| 928 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 929 | 903 | ||
| 930 | // TODO(Subv): Processes with memory type APPLICATION are not allowed | 904 | // TODO(Subv): Processes with memory type APPLICATION are not allowed |
| 931 | // to create memory blocks with addr = 0, any attempts to do so | 905 | // to create memory blocks with addr = 0, any attempts to do so |
| 932 | // should return error 0xD92007EA. | 906 | // should return error 0xD92007EA. |
| 933 | if ((addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) && | 907 | if ((addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) && |
| 934 | addr != 0) { | 908 | addr != 0) { |
| 935 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, | 909 | return Kernel::ERR_INVALID_ADDRESS; |
| 936 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 937 | } | 910 | } |
| 938 | 911 | ||
| 939 | // When trying to create a memory block with address = 0, | 912 | // When trying to create a memory block with address = 0, |
| @@ -1035,7 +1008,7 @@ static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 ty | |||
| 1035 | *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; | 1008 | *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; |
| 1036 | if (*out % Memory::PAGE_SIZE != 0) { | 1009 | if (*out % Memory::PAGE_SIZE != 0) { |
| 1037 | LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); | 1010 | LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); |
| 1038 | return ERR_MISALIGNED_SIZE; | 1011 | return Kernel::ERR_MISALIGNED_SIZE; |
| 1039 | } | 1012 | } |
| 1040 | break; | 1013 | break; |
| 1041 | case 1: | 1014 | case 1: |
| @@ -1051,19 +1024,15 @@ static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 ty | |||
| 1051 | case 20: | 1024 | case 20: |
| 1052 | *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase(); | 1025 | *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase(); |
| 1053 | break; | 1026 | break; |
| 1027 | case 21: | ||
| 1028 | case 22: | ||
| 1029 | case 23: | ||
| 1030 | // These return a different error value than higher invalid values | ||
| 1031 | LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); | ||
| 1032 | return Kernel::ERR_NOT_IMPLEMENTED; | ||
| 1054 | default: | 1033 | default: |
| 1055 | LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); | 1034 | LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); |
| 1056 | 1035 | return Kernel::ERR_INVALID_ENUM_VALUE; | |
| 1057 | if (type >= 21 && type <= 23) { | ||
| 1058 | return ResultCode( // 0xE0E01BF4 | ||
| 1059 | ErrorDescription::NotImplemented, ErrorModule::OS, ErrorSummary::InvalidArgument, | ||
| 1060 | ErrorLevel::Usage); | ||
| 1061 | } else { | ||
| 1062 | return ResultCode( // 0xD8E007ED | ||
| 1063 | ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, | ||
| 1064 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 1065 | } | ||
| 1066 | break; | ||
| 1067 | } | 1036 | } |
| 1068 | 1037 | ||
| 1069 | return RESULT_SUCCESS; | 1038 | return RESULT_SUCCESS; |
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/core/settings.cpp b/src/core/settings.cpp index d2e7c6b97..d4f0429d1 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include "core/gdbstub/gdbstub.h" | 6 | #include "core/gdbstub/gdbstub.h" |
| 7 | #include "core/hle/service/hid/hid.h" | 7 | #include "core/hle/service/hid/hid.h" |
| 8 | #include "core/hle/service/ir/ir.h" | 8 | #include "core/hle/service/ir/ir.h" |
| 9 | #include "settings.h" | 9 | #include "core/settings.h" |
| 10 | #include "video_core/video_core.h" | 10 | #include "video_core/video_core.h" |
| 11 | 11 | ||
| 12 | #include "core/frontend/emu_window.h" | 12 | #include "core/frontend/emu_window.h" |
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp index 276a5b288..55b3b5efc 100644 --- a/src/core/tracer/recorder.cpp +++ b/src/core/tracer/recorder.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/file_util.h" | 7 | #include "common/file_util.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "recorder.h" | 9 | #include "core/tracer/recorder.h" |
| 10 | 10 | ||
| 11 | namespace CiTrace { | 11 | namespace CiTrace { |
| 12 | 12 | ||
diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h index aea363b95..39e6ec4fd 100644 --- a/src/core/tracer/recorder.h +++ b/src/core/tracer/recorder.h | |||
| @@ -8,8 +8,8 @@ | |||
| 8 | #include <unordered_map> | 8 | #include <unordered_map> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include <boost/crc.hpp> | 10 | #include <boost/crc.hpp> |
| 11 | #include "citrace.h" | ||
| 12 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/tracer/citrace.h" | ||
| 13 | 13 | ||
| 14 | namespace CiTrace { | 14 | namespace CiTrace { |
| 15 | 15 | ||
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index cfe5caaa3..e3e36ada7 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -13,15 +13,14 @@ 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}) |
| 20 | 19 | ||
| 21 | add_library(input_common STATIC ${SRCS} ${HEADERS}) | 20 | add_library(input_common STATIC ${SRCS} ${HEADERS}) |
| 22 | target_link_libraries(input_common common core) | 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 ${SDL2_LIBRARY}) | 24 | target_link_libraries(input_common PRIVATE SDL2) |
| 26 | set_property(TARGET input_common APPEND PROPERTY COMPILE_DEFINITIONS 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 d1144ba77..00d7c636a 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt | |||
| @@ -10,10 +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 core video_core audio_core common) | 14 | target_link_libraries(tests PRIVATE common core) |
| 17 | target_link_libraries(tests ${PLATFORM_LIBRARIES} Threads::Threads) | 15 | target_link_libraries(tests PRIVATE glad) # To support linker work-around |
| 16 | target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads) | ||
| 18 | 17 | ||
| 19 | 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 e00b88f71..0961a3251 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -79,13 +79,14 @@ endif() | |||
| 79 | create_directory_groups(${SRCS} ${HEADERS}) | 79 | 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 glad) | 82 | target_link_libraries(video_core PUBLIC common core) |
| 83 | target_link_libraries(video_core PRIVATE glad nihstro-headers) | ||
| 84 | |||
| 83 | if (ARCHITECTURE_x86_64) | 85 | if (ARCHITECTURE_x86_64) |
| 84 | target_link_libraries(video_core xbyak) | 86 | target_link_libraries(video_core PRIVATE xbyak) |
| 85 | endif() | 87 | endif() |
| 86 | 88 | ||
| 87 | if (PNG_FOUND) | 89 | if (PNG_FOUND) |
| 88 | target_link_libraries(video_core ${PNG_LIBRARIES}) | 90 | target_link_libraries(video_core PRIVATE PNG::PNG) |
| 89 | include_directories(${PNG_INCLUDE_DIRS}) | 91 | target_compile_definitions(video_core PRIVATE HAVE_PNG) |
| 90 | add_definitions(${PNG_DEFINITIONS}) | ||
| 91 | 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/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 456443e86..8b717e43d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -561,20 +561,16 @@ RasterizerCacheOpenGL::GetFramebufferSurfaces( | |||
| 561 | color_params.is_tiled = depth_params.is_tiled = true; | 561 | color_params.is_tiled = depth_params.is_tiled = true; |
| 562 | 562 | ||
| 563 | // Set the internal resolution, assume the same scaling factor for top and bottom screens | 563 | // Set the internal resolution, assume the same scaling factor for top and bottom screens |
| 564 | const Layout::FramebufferLayout& layout = VideoCore::g_emu_window->GetFramebufferLayout(); | 564 | float resolution_scale_factor = Settings::values.resolution_factor; |
| 565 | if (Settings::values.resolution_factor == 0.0f) { | 565 | if (resolution_scale_factor == 0.0f) { |
| 566 | // Auto - scale resolution to the window size | 566 | // Auto - scale resolution to the window size |
| 567 | color_params.res_scale_width = depth_params.res_scale_width = | 567 | resolution_scale_factor = VideoCore::g_emu_window->GetFramebufferLayout().GetScalingRatio(); |
| 568 | (float)layout.top_screen.GetWidth() / VideoCore::kScreenTopWidth; | ||
| 569 | color_params.res_scale_height = depth_params.res_scale_height = | ||
| 570 | (float)layout.top_screen.GetHeight() / VideoCore::kScreenTopHeight; | ||
| 571 | } else { | ||
| 572 | // Otherwise, scale the resolution by the specified factor | ||
| 573 | color_params.res_scale_width = Settings::values.resolution_factor; | ||
| 574 | depth_params.res_scale_width = Settings::values.resolution_factor; | ||
| 575 | color_params.res_scale_height = Settings::values.resolution_factor; | ||
| 576 | depth_params.res_scale_height = Settings::values.resolution_factor; | ||
| 577 | } | 568 | } |
| 569 | // Scale the resolution by the specified factor | ||
| 570 | color_params.res_scale_width = resolution_scale_factor; | ||
| 571 | depth_params.res_scale_width = resolution_scale_factor; | ||
| 572 | color_params.res_scale_height = resolution_scale_factor; | ||
| 573 | depth_params.res_scale_height = resolution_scale_factor; | ||
| 578 | 574 | ||
| 579 | color_params.addr = config.GetColorBufferPhysicalAddress(); | 575 | color_params.addr = config.GetColorBufferPhysicalAddress(); |
| 580 | color_params.pixel_format = CachedSurface::PixelFormatFromColorFormat(config.color_format); | 576 | color_params.pixel_format = CachedSurface::PixelFormatFromColorFormat(config.color_format); |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3eeb47d33..db53710aa 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -152,12 +152,40 @@ static bool IsPassThroughTevStage(const TevStageConfig& stage) { | |||
| 152 | stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); | 152 | stage.GetColorMultiplier() == 1 && stage.GetAlphaMultiplier() == 1); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | static std::string TexCoord(const PicaShaderConfig& config, int texture_unit) { | 155 | static std::string SampleTexture(const PicaShaderConfig& config, unsigned texture_unit) { |
| 156 | if (texture_unit == 2 && config.state.texture2_use_coord1) { | 156 | const auto& state = config.state; |
| 157 | return "texcoord[1]"; | 157 | switch (texture_unit) { |
| 158 | case 0: | ||
| 159 | // Only unit 0 respects the texturing type | ||
| 160 | switch (state.texture0_type) { | ||
| 161 | case TexturingRegs::TextureConfig::Texture2D: | ||
| 162 | return "texture(tex[0], texcoord[0])"; | ||
| 163 | case TexturingRegs::TextureConfig::Projection2D: | ||
| 164 | return "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; | ||
| 165 | default: | ||
| 166 | LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", | ||
| 167 | static_cast<int>(state.texture0_type)); | ||
| 168 | UNIMPLEMENTED(); | ||
| 169 | return "texture(tex[0], texcoord[0])"; | ||
| 170 | } | ||
| 171 | case 1: | ||
| 172 | return "texture(tex[1], texcoord[1])"; | ||
| 173 | case 2: | ||
| 174 | if (state.texture2_use_coord1) | ||
| 175 | return "texture(tex[2], texcoord[1])"; | ||
| 176 | else | ||
| 177 | return "texture(tex[2], texcoord[2])"; | ||
| 178 | case 3: | ||
| 179 | if (state.proctex.enable) { | ||
| 180 | return "ProcTex()"; | ||
| 181 | } else { | ||
| 182 | LOG_ERROR(Render_OpenGL, "Using Texture3 without enabling it"); | ||
| 183 | return "vec4(0.0)"; | ||
| 184 | } | ||
| 185 | default: | ||
| 186 | UNREACHABLE(); | ||
| 187 | return ""; | ||
| 158 | } | 188 | } |
| 159 | |||
| 160 | return "texcoord[" + std::to_string(texture_unit) + "]"; | ||
| 161 | } | 189 | } |
| 162 | 190 | ||
| 163 | /// Writes the specified TEV stage source component(s) | 191 | /// Writes the specified TEV stage source component(s) |
| @@ -176,35 +204,16 @@ static void AppendSource(std::string& out, const PicaShaderConfig& config, | |||
| 176 | out += "secondary_fragment_color"; | 204 | out += "secondary_fragment_color"; |
| 177 | break; | 205 | break; |
| 178 | case Source::Texture0: | 206 | case Source::Texture0: |
| 179 | // Only unit 0 respects the texturing type (according to 3DBrew) | 207 | out += SampleTexture(config, 0); |
| 180 | switch (state.texture0_type) { | ||
| 181 | case TexturingRegs::TextureConfig::Texture2D: | ||
| 182 | out += "texture(tex[0], texcoord[0])"; | ||
| 183 | break; | ||
| 184 | case TexturingRegs::TextureConfig::Projection2D: | ||
| 185 | out += "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; | ||
| 186 | break; | ||
| 187 | default: | ||
| 188 | out += "texture(tex[0], texcoord[0])"; | ||
| 189 | LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", | ||
| 190 | static_cast<int>(state.texture0_type)); | ||
| 191 | UNIMPLEMENTED(); | ||
| 192 | break; | ||
| 193 | } | ||
| 194 | break; | 208 | break; |
| 195 | case Source::Texture1: | 209 | case Source::Texture1: |
| 196 | out += "texture(tex[1], texcoord[1])"; | 210 | out += SampleTexture(config, 1); |
| 197 | break; | 211 | break; |
| 198 | case Source::Texture2: | 212 | case Source::Texture2: |
| 199 | out += "texture(tex[2], " + TexCoord(config, 2) + ")"; | 213 | out += SampleTexture(config, 2); |
| 200 | break; | 214 | break; |
| 201 | case Source::Texture3: | 215 | case Source::Texture3: |
| 202 | if (config.state.proctex.enable) { | 216 | out += SampleTexture(config, 3); |
| 203 | out += "ProcTex()"; | ||
| 204 | } else { | ||
| 205 | LOG_ERROR(Render_OpenGL, "Using Texture3 without enabling it"); | ||
| 206 | out += "vec4(0.0)"; | ||
| 207 | } | ||
| 208 | break; | 217 | break; |
| 209 | case Source::PreviousBuffer: | 218 | case Source::PreviousBuffer: |
| 210 | out += "combiner_buffer"; | 219 | out += "combiner_buffer"; |
| @@ -515,18 +524,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 515 | if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) { | 524 | if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) { |
| 516 | // Bump mapping is enabled using a normal map, read perturbation vector from the selected | 525 | // Bump mapping is enabled using a normal map, read perturbation vector from the selected |
| 517 | // texture | 526 | // texture |
| 518 | if (lighting.bump_selector == 3) { | 527 | out += "vec3 surface_normal = 2.0 * (" + SampleTexture(config, lighting.bump_selector) + |
| 519 | if (config.state.proctex.enable) { | 528 | ").rgb - 1.0;\n"; |
| 520 | out += "vec3 surface_normal = 2.0 * ProcTex().rgb - 1.0;\n"; | ||
| 521 | } else { | ||
| 522 | LOG_ERROR(Render_OpenGL, "Using Texture3 without enabling it"); | ||
| 523 | out += "vec3 surface_normal = vec3(-1.0);\n"; | ||
| 524 | } | ||
| 525 | } else { | ||
| 526 | std::string bump_selector = std::to_string(lighting.bump_selector); | ||
| 527 | out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], " + | ||
| 528 | TexCoord(config, lighting.bump_selector) + ").rgb - 1.0;\n"; | ||
| 529 | } | ||
| 530 | 529 | ||
| 531 | // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher | 530 | // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher |
| 532 | // precision result | 531 | // precision result |
| @@ -545,8 +544,8 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) { | |||
| 545 | } | 544 | } |
| 546 | 545 | ||
| 547 | // Rotate the surface-local normal by the interpolated normal quaternion to convert it to | 546 | // Rotate the surface-local normal by the interpolated normal quaternion to convert it to |
| 548 | // eyespace | 547 | // eyespace. |
| 549 | out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n"; | 548 | out += "vec3 normal = quaternion_rotate(normalize(normquat), surface_normal);\n"; |
| 550 | 549 | ||
| 551 | // Gets the index into the specified lookup table for specular lighting | 550 | // Gets the index into the specified lookup table for specular lighting |
| 552 | auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input, | 551 | auto GetLutIndex = [&lighting](unsigned light_num, LightingRegs::LightingLutInput input, |
| @@ -1030,7 +1029,9 @@ uniform sampler1D proctex_diff_lut; | |||
| 1030 | // Rotate the vector v by the quaternion q | 1029 | // Rotate the vector v by the quaternion q |
| 1031 | vec3 quaternion_rotate(vec4 q, vec3 v) { | 1030 | vec3 quaternion_rotate(vec4 q, vec3 v) { |
| 1032 | return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); | 1031 | return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); |
| 1033 | })"; | 1032 | } |
| 1033 | |||
| 1034 | )"; | ||
| 1034 | 1035 | ||
| 1035 | if (config.state.proctex.enable) | 1036 | if (config.state.proctex.enable) |
| 1036 | AppendProcTexSampler(out, config); | 1037 | AppendProcTexSampler(out, config); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index e19375466..d90c776f9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -94,14 +94,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons | |||
| 94 | return matrix; | 94 | return matrix; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /// RendererOpenGL constructor | 97 | RendererOpenGL::RendererOpenGL() = default; |
| 98 | RendererOpenGL::RendererOpenGL() { | 98 | RendererOpenGL::~RendererOpenGL() = default; |
| 99 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); | ||
| 100 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; | ||
| 101 | } | ||
| 102 | |||
| 103 | /// RendererOpenGL destructor | ||
| 104 | RendererOpenGL::~RendererOpenGL() {} | ||
| 105 | 99 | ||
| 106 | /// Swap buffers (render frame) | 100 | /// Swap buffers (render frame) |
| 107 | void RendererOpenGL::SwapBuffers() { | 101 | void RendererOpenGL::SwapBuffers() { |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 87c556cff..0b4f69e8f 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -68,9 +68,6 @@ private: | |||
| 68 | 68 | ||
| 69 | EmuWindow* render_window; ///< Handle to render window | 69 | EmuWindow* render_window; ///< Handle to render window |
| 70 | 70 | ||
| 71 | int resolution_width; ///< Current resolution width | ||
| 72 | int resolution_height; ///< Current resolution height | ||
| 73 | |||
| 74 | OpenGLState state; | 71 | OpenGLState state; |
| 75 | 72 | ||
| 76 | // OpenGL object IDs | 73 | // OpenGL object IDs |
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 | ||
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 4aba19ca0..94e0867f0 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -15,21 +15,6 @@ class RendererBase; | |||
| 15 | 15 | ||
| 16 | namespace VideoCore { | 16 | namespace VideoCore { |
| 17 | 17 | ||
| 18 | // 3DS Video Constants | ||
| 19 | // ------------------- | ||
| 20 | |||
| 21 | // NOTE: The LCDs actually rotate the image 90 degrees when displaying. Because of that the | ||
| 22 | // framebuffers in video memory are stored in column-major order and rendered sideways, causing | ||
| 23 | // the widths and heights of the framebuffers read by the LCD to be switched compared to the | ||
| 24 | // heights and widths of the screens listed here. | ||
| 25 | static const int kScreenTopWidth = 400; ///< 3DS top screen width | ||
| 26 | static const int kScreenTopHeight = 240; ///< 3DS top screen height | ||
| 27 | static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width | ||
| 28 | static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height | ||
| 29 | |||
| 30 | // Video core renderer | ||
| 31 | // --------------------- | ||
| 32 | |||
| 33 | extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin | 18 | extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin |
| 34 | extern EmuWindow* g_emu_window; ///< Emu window | 19 | extern EmuWindow* g_emu_window; ///< Emu window |
| 35 | 20 | ||