diff options
140 files changed, 2465 insertions, 1260 deletions
diff --git a/.gitignore b/.gitignore index 659736ff5..5e4a6eef9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ # Build directory -build/ +[Bb]uild/ doc-build/ # Generated source files src/common/scm_rev.cpp + +# Project/editor files +*.swp +.idea/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb1067c92..82b66be75 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,27 +24,36 @@ Citra is a brand new project, so we have a great opportunity to keep things clea ### Indentation/Whitespace Style Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. +### Comments +* For regular comments, use C++ style (`//`) comments, even for multi-line ones. +* For doc-comments (Doxygen comments), use `/// ` if it's a single line, else use the `/**` `*/` style featured in the example. Start the text on the second line, not the first containing `/**`. + ```cpp namespace Example { // Namespace contents are not indented - + // Declare globals at the top int g_foo = 0; char* g_some_pointer; // Notice the position of the * - + +/// A colorful enum. enum SomeEnum { - COLOR_RED, - COLOR_GREEN, - COLOR_BLUE + COLOR_RED, ///< The color of fire. + COLOR_GREEN, ///< The color of grass. + COLOR_BLUE ///< Not actually the color of water. }; - + +/** + * Very important struct that does a lot of stuff. + * Note that the asterisks are indented by one space. + */ struct Position { int x, y; }; - + // Use "typename" rather than "class" here, just to be consistent -template +template void FooBar() { int some_array[] = { 5, @@ -52,29 +61,29 @@ void FooBar() { 7, 42 }; - + if (note == the_space_after_the_if) { CallAfunction(); } else { // Use a space after the // when commenting } - + // Comment directly above code when possible if (some_condition) single_statement(); - + // Place a single space after the for loop semicolons for (int i = 0; i != 25; ++i) { // This is how we write loops } - + DoStuff(this, function, call, takes, up, multiple, lines, like, this); - + if (this || condition_takes_up_multiple && lines && like && this || everything || alright || then) { } - + switch (var) { // No indentation for case label case 1: { @@ -85,18 +94,18 @@ void FooBar() { case 3: DoSomething(var); return; - + default: // Yes, even break for the last case break; } - + std::vector you_can_declare, a_few, variables, like_this; } - + } ``` diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 41b62ac16..f2aeb510e 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -23,7 +23,7 @@ int __cdecl main(int argc, char **argv) { } Config config; - + if (!Settings::values.enable_log) LogManager::Shutdown(); diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp index 0c774bbc5..697bf4693 100644 --- a/src/citra/emu_window/emu_window_glfw.cpp +++ b/src/citra/emu_window/emu_window_glfw.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include <GLFW/glfw3.h> + #include "common/common.h" #include "video_core/video_core.h" @@ -10,22 +12,21 @@ #include "citra/emu_window/emu_window_glfw.h" +EmuWindow_GLFW* EmuWindow_GLFW::GetEmuWindow(GLFWwindow* win) { + return static_cast<EmuWindow_GLFW*>(glfwGetWindowUserPointer(win)); +} + /// Called by GLFW when a key event occurs void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) { - if (!VideoCore::g_emu_window) { - return; - } - - int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id; + int keyboard_id = GetEmuWindow(win)->keyboard_id; if (action == GLFW_PRESS) { EmuWindow::KeyPressed({key, keyboard_id}); - } - - if (action == GLFW_RELEASE) { + } else if (action == GLFW_RELEASE) { EmuWindow::KeyReleased({key, keyboard_id}); } + HID_User::PadUpdateComplete(); } @@ -34,15 +35,36 @@ const bool EmuWindow_GLFW::IsOpen() { return glfwWindowShouldClose(m_render_window) == 0; } +void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) { + _dbg_assert_(GUI, width > 0); + _dbg_assert_(GUI, height > 0); + + GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height)); +} + +void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) { + _dbg_assert_(GUI, width > 0); + _dbg_assert_(GUI, height > 0); + + // NOTE: GLFW provides no proper way to set a minimal window size. + // Hence, we just ignore the corresponding EmuWindow hint. + + GetEmuWindow(win)->NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(width, height)); +} + /// EmuWindow_GLFW constructor EmuWindow_GLFW::EmuWindow_GLFW() { keyboard_id = KeyMap::NewDeviceId(); ReloadSetKeymaps(); + glfwSetErrorCallback([](int error, const char *desc){ + ERROR_LOG(GUI, "GLFW 0x%08x: %s", error, desc); + }); + // Initialize the window if(glfwInit() != GL_TRUE) { - printf("Failed to initialize GLFW! Exiting..."); + ERROR_LOG(GUI, "Failed to initialize GLFW! Exiting..."); exit(1); } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -50,19 +72,31 @@ EmuWindow_GLFW::EmuWindow_GLFW() { // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, - (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), - m_window_title.c_str(), NULL, NULL); + + std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); + m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, + (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), + window_title.c_str(), NULL, NULL); if (m_render_window == NULL) { - printf("Failed to create GLFW window! Exiting..."); + ERROR_LOG(GUI, "Failed to create GLFW window! Exiting..."); exit(1); } - - // Setup callbacks + glfwSetWindowUserPointer(m_render_window, this); + + // Notify base interface about window state + int width, height; + glfwGetFramebufferSize(m_render_window, &width, &height); + OnFramebufferResizeEvent(m_render_window, width, height); + + glfwGetWindowSize(m_render_window, &width, &height); + OnClientAreaResizeEvent(m_render_window, width, height); + + // Setup callbacks glfwSetKeyCallback(m_render_window, OnKeyEvent); + glfwSetFramebufferSizeCallback(m_render_window, OnFramebufferResizeEvent); + glfwSetWindowSizeCallback(m_render_window, OnClientAreaResizeEvent); DoneCurrent(); } @@ -110,3 +144,15 @@ void EmuWindow_GLFW::ReloadSetKeymaps() { KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); } + +void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { + std::pair<int,int> current_size; + glfwGetWindowSize(m_render_window, ¤t_size.first, ¤t_size.second); + + _dbg_assert_(GUI, (int)minimal_size.first > 0 && (int)minimal_size.second > 0); + int new_width = std::max(current_size.first, (int)minimal_size.first); + int new_height = std::max(current_size.second, (int)minimal_size.second); + + if (current_size != std::make_pair(new_width, new_height)) + glfwSetWindowSize(m_render_window, new_width, new_height); +} diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h index 7c3072145..5b04e87bb 100644 --- a/src/citra/emu_window/emu_window_glfw.h +++ b/src/citra/emu_window/emu_window_glfw.h @@ -4,10 +4,10 @@ #pragma once -#include <GLFW/glfw3.h> - #include "common/emu_window.h" +struct GLFWwindow; + class EmuWindow_GLFW : public EmuWindow { public: EmuWindow_GLFW(); @@ -16,12 +16,12 @@ public: /// Swap buffers to display the next frame void SwapBuffers() override; - /// Polls window events - void PollEvents() override; + /// Polls window events + void PollEvents() override; /// Makes the graphics context current for the caller thread void MakeCurrent() override; - + /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread void DoneCurrent() override; @@ -30,9 +30,17 @@ public: /// Whether the window is still open, and a close request hasn't yet been sent const bool IsOpen(); + static void OnClientAreaResizeEvent(GLFWwindow* win, int width, int height); + + static void OnFramebufferResizeEvent(GLFWwindow* win, int width, int height); + void ReloadSetKeymaps() override; private: + void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override; + + static EmuWindow_GLFW* GetEmuWindow(GLFWwindow* win); + GLFWwindow* m_render_window; ///< Internal GLFW render window /// Device id of keyboard for use with KeyMap diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 20824692d..9bf079919 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -2,6 +2,12 @@ #include <QKeyEvent> #include <QApplication> +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +// Required for screen DPI information +#include <QScreen> +#include <QWindow> +#endif + #include "common/common.h" #include "bootmanager.hxx" @@ -17,7 +23,7 @@ #define APP_TITLE APP_NAME " " APP_VERSION #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" -EmuThread::EmuThread(GRenderWindow* render_window) : +EmuThread::EmuThread(GRenderWindow* render_window) : filename(""), exec_cpu_step(false), cpu_running(false), stop_run(false), render_window(render_window) { @@ -36,7 +42,7 @@ void EmuThread::run() if (cpu_running) { Core::RunLoop(); - } + } else if (exec_cpu_step) { exec_cpu_step = false; @@ -82,20 +88,20 @@ void EmuThread::Stop() class GGLWidgetInternal : public QGLWidget { public: - GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(fmt, parent) - { - parent_ = parent; + GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) + : QGLWidget(fmt, parent), parent(parent) { } - void paintEvent(QPaintEvent* ev) override - { + void paintEvent(QPaintEvent* ev) override { } + void resizeEvent(QResizeEvent* ev) override { - parent_->SetClientAreaWidth(size().width()); - parent_->SetClientAreaHeight(size().height()); + parent->OnClientAreaResized(ev->size().width(), ev->size().height()); + parent->OnFramebufferSizeChanged(); } + private: - GRenderWindow* parent_; + GRenderWindow* parent; }; EmuThread& GRenderWindow::GetEmuThread() @@ -105,6 +111,9 @@ EmuThread& GRenderWindow::GetEmuThread() GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0) { + std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); + setWindowTitle(QString::fromStdString(window_title)); + keyboard_id = KeyMap::NewDeviceId(); ReloadSetKeymaps(); @@ -114,16 +123,25 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this fmt.setProfile(QGLFormat::CoreProfile); // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X fmt.setOption(QGL::NoDeprecatedFunctions); - + child = new GGLWidgetInternal(fmt, this); QBoxLayout* layout = new QHBoxLayout(this); resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); layout->addWidget(child); layout->setMargin(0); setLayout(layout); - QObject::connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext())); + connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext())); + + OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); + + OnFramebufferSizeChanged(); + NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(child->width(), child->height())); BackupGeometry(); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + connect(this->windowHandle(), SIGNAL(screenChanged(QScreen*)), this, SLOT(OnFramebufferSizeChanged())); +#endif } void GRenderWindow::moveContext() @@ -166,14 +184,28 @@ void GRenderWindow::DoneCurrent() } void GRenderWindow::PollEvents() { - // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title - // from the main thread, but this should probably be in an event handler... - /* - static char title[128]; - sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(), - video_core::g_renderer->current_fps()); - setWindowTitle(title); - */ +} + +// On Qt 5.0+, this correctly gets the size of the framebuffer (pixels). +// +// Older versions get the window size (density independent pixels), +// and hence, do not support DPI scaling ("retina" displays). +// The result will be a viewport that is smaller than the extent of the window. +void GRenderWindow::OnFramebufferSizeChanged() +{ + // Screen changes potentially incur a change in screen DPI, hence we should update the framebuffer size +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + // windowHandle() might not be accessible until the window is displayed to screen. + auto pixel_ratio = windowHandle() ? (windowHandle()->screen()->devicePixelRatio()) : 1.0; + + unsigned width = child->QPaintDevice::width() * pixel_ratio; + unsigned height = child->QPaintDevice::height() * pixel_ratio; +#else + unsigned width = child->QPaintDevice::width(); + unsigned height = child->QPaintDevice::height(); +#endif + + NotifyFramebufferSizeChanged(std::make_pair(width, height)); } void GRenderWindow::BackupGeometry() @@ -236,3 +268,11 @@ void GRenderWindow::ReloadSetKeymaps() KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); } +void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) +{ + NotifyClientAreaSizeChanged(std::make_pair(width, height)); +} + +void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { + setMinimumSize(minimal_size.first, minimal_size.second); +} diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index f8afc403e..5f69f15ea 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -1,12 +1,16 @@ +#include <atomic> + #include <QThread> #include <QGLWidget> -#include <atomic> + #include "common/common.h" #include "common/emu_window.h" -class GRenderWindow; +class QScreen; class QKeyEvent; +class GRenderWindow; + class EmuThread : public QThread { Q_OBJECT @@ -14,7 +18,7 @@ class EmuThread : public QThread public: /** * Set image filename - * + * * @param filename * @warning Only call when not running! */ @@ -74,7 +78,7 @@ private: signals: /** * Emitted when CPU when we've finished processing a single Gekko instruction - * + * * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false)) * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) */ @@ -100,7 +104,7 @@ public: void BackupGeometry(); void RestoreGeometry(); void restoreGeometry(const QByteArray& geometry); // overridden - QByteArray saveGeometry(); // overridden + QByteArray saveGeometry(); // overridden EmuThread& GetEmuThread(); @@ -109,10 +113,16 @@ public: void ReloadSetKeymaps() override; + void OnClientAreaResized(unsigned width, unsigned height); + + void OnFramebufferSizeChanged(); + public slots: - void moveContext(); + void moveContext(); // overridden private: + void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override; + QGLWidget* child; EmuThread emu_thread; diff --git a/src/citra_qt/config/controller_config_util.cpp b/src/citra_qt/config/controller_config_util.cpp index c5426570b..aee3f8616 100644 --- a/src/citra_qt/config/controller_config_util.cpp +++ b/src/citra_qt/config/controller_config_util.cpp @@ -48,7 +48,7 @@ void GKeyConfigButton::OnActivePortChanged(const common::Config::ControllerPort& else if (config.keys.key_code[id] == Qt::Key_Control) text = tr("Control"); else if (config.keys.key_code[id] == Qt::Key_Alt) text = tr("Alt"); else if (config.keys.key_code[id] == Qt::Key_Meta) text = tr("Meta"); - setText(text); + setText(text); } void GKeyConfigButton::OnClicked() @@ -118,4 +118,4 @@ GButtonConfigGroup::GButtonConfigGroup(const QString& name, common::Config::Cont setLayout(layout); } -*/
\ No newline at end of file +*/ diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 77fb0c9ed..895851be3 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -28,7 +28,7 @@ void CallstackWidget::OnCPUStepped() u32 sp = app_core->GetReg(13); //stack pointer u32 addr, ret_addr, call_addr, func_addr; - + int counter = 0; for (int addr = 0x10000000; addr >= sp; addr -= 4) { @@ -55,7 +55,7 @@ void CallstackWidget::OnCPUStepped() callstack_model->setItem(counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg(ret_addr, 8, 16, QLatin1Char('0')))); callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg(call_addr, 8, 16, QLatin1Char('0')))); - + name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; callstack_model->setItem(counter, 3, new QStandardItem(QString("%1_%2").arg(QString::fromStdString(name)) .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); @@ -63,4 +63,4 @@ void CallstackWidget::OnCPUStepped() counter++; } } -}
\ No newline at end of file +} diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index 96ceed480..ed17ee4b4 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp @@ -46,18 +46,18 @@ void RegistersWidget::OnCPUStepped() CSPR->setText(1, QString("0x%1").arg(app_core->GetCPSR(), 8, 16, QLatin1Char('0'))); CSPR->child(0)->setText(1, QString("b%1").arg(app_core->GetCPSR() & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode - CSPR->child(1)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 5) & 0x1)); // T - State - CSPR->child(2)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 6) & 0x1)); // F - FIQ disable - CSPR->child(3)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 7) & 0x1)); // I - IRQ disable - CSPR->child(4)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 8) & 0x1)); // A - Imprecise abort - CSPR->child(5)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 9) & 0x1)); // E - Data endianess - CSPR->child(6)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 10) & 0x3F)); // IT - If-Then state (DNM) - CSPR->child(7)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 16) & 0xF)); // GE - Greater-than-or-Equal - CSPR->child(8)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 20) & 0xF)); // DNM - Do not modify - CSPR->child(9)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 24) & 0x1)); // J - Java state - CSPR->child(10)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 27) & 0x1)); // Q - Sticky overflow - CSPR->child(11)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 28) & 0x1)); // V - Overflow - CSPR->child(12)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 29) & 0x1)); // C - Carry/Borrow/Extend - CSPR->child(13)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 30) & 0x1)); // Z - Zero - CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than + CSPR->child(1)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 5) & 0x1)); // T - State + CSPR->child(2)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 6) & 0x1)); // F - FIQ disable + CSPR->child(3)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 7) & 0x1)); // I - IRQ disable + CSPR->child(4)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 8) & 0x1)); // A - Imprecise abort + CSPR->child(5)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 9) & 0x1)); // E - Data endianess + CSPR->child(6)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 10) & 0x3F)); // IT - If-Then state (DNM) + CSPR->child(7)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 16) & 0xF)); // GE - Greater-than-or-Equal + CSPR->child(8)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 20) & 0xF)); // DNM - Do not modify + CSPR->child(9)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 24) & 0x1)); // J - Java state + CSPR->child(10)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 27) & 0x1)); // Q - Sticky overflow + CSPR->child(11)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 28) & 0x1)); // V - Overflow + CSPR->child(12)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 29) & 0x1)); // C - Carry/Borrow/Extend + CSPR->child(13)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 30) & 0x1)); // Z - Zero + CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than } diff --git a/src/citra_qt/debugger/registers.hxx b/src/citra_qt/debugger/registers.hxx index 9645feb2a..4cca957ce 100644 --- a/src/citra_qt/debugger/registers.hxx +++ b/src/citra_qt/debugger/registers.hxx @@ -16,10 +16,10 @@ public slots: void OnCPUStepped(); private: - Ui::ARMRegisters cpu_regs_ui; + Ui::ARMRegisters cpu_regs_ui; - QTreeWidget* tree; - - QTreeWidgetItem* registers; - QTreeWidgetItem* CSPR; + QTreeWidget* tree; + + QTreeWidgetItem* registers; + QTreeWidgetItem* CSPR; }; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 9a4e36adf..d5554d917 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -117,7 +117,8 @@ GMainWindow::GMainWindow() connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile())); connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); - setWindowTitle(render_window->GetWindowTitle().c_str()); + std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); + setWindowTitle(window_title.c_str()); show(); diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h index dc8ac1fd9..609784076 100644 --- a/src/common/chunk_file.h +++ b/src/common/chunk_file.h @@ -51,7 +51,7 @@ public: PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { } ~PointerWrapSection(); - + bool operator == (const int &v) const { return ver_ == v; } bool operator != (const int &v) const { return ver_ != v; } bool operator <= (const int &v) const { return ver_ <= v; } @@ -196,7 +196,7 @@ public: } (*ptr) += size; } - + template<class K, class T> void Do(std::map<K, T *> &x) { @@ -364,7 +364,7 @@ public: if (vec_size > 0) DoArray(&x[0], vec_size); } - + // Store deques. template<class T> void Do(std::deque<T *> &x) @@ -481,11 +481,11 @@ public: } // Store strings. - void Do(std::string &x) + void Do(std::string &x) { int stringLen = (int)x.length() + 1; Do(stringLen); - + switch (mode) { case MODE_READ: x = (char*)*ptr; break; case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; @@ -495,7 +495,7 @@ public: (*ptr) += stringLen; } - void Do(std::wstring &x) + void Do(std::wstring &x) { int stringLen = sizeof(wchar_t)*((int)x.length() + 1); Do(stringLen); @@ -534,7 +534,7 @@ public: void Do(T &x) { DoHelper<T>::Do(this, x); } - + template<class T> void DoPOD(T &x) { DoHelper<T>::Do(this, x); diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index c18afe119..d84ec4c42 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -17,7 +17,7 @@ template<> struct CompileTimeAssert<true> {}; #define b2(x) ( (x) | ( (x) >> 1) ) #define b4(x) ( b2(x) | ( b2(x) >> 2) ) #define b8(x) ( b4(x) | ( b4(x) >> 4) ) -#define b16(x) ( b8(x) | ( b8(x) >> 8) ) +#define b16(x) ( b8(x) | ( b8(x) >> 8) ) #define b32(x) (b16(x) | (b16(x) >>16) ) #define ROUND_UP_POW2(x) (b32(x - 1) + 1) @@ -79,12 +79,12 @@ inline u64 _rotr64(u64 x, unsigned int shift){ #define unlink _unlink #define snprintf _snprintf #define vscprintf _vscprintf - + // Locale Cross-Compatibility #define locale_t _locale_t #define freelocale _free_locale #define newlocale(mask, locale, base) _create_locale(mask, locale) - + #define LC_GLOBAL_LOCALE ((locale_t)-1) #define LC_ALL_MASK LC_ALL #define LC_COLLATE_MASK LC_COLLATE @@ -92,7 +92,7 @@ inline u64 _rotr64(u64 x, unsigned int shift){ #define LC_MONETARY_MASK LC_MONETARY #define LC_NUMERIC_MASK LC_NUMERIC #define LC_TIME_MASK LC_TIME - + inline locale_t uselocale(locale_t new_locale) { // Retrieve the current per thread locale setting @@ -168,8 +168,8 @@ inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);} inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} #elif _M_ARM -inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} -inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} +inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} +inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} #elif __linux__ inline u16 swap16(u16 _data) {return bswap_16(_data);} @@ -226,7 +226,7 @@ template <typename T> inline T FromBigEndian(T data) { //static_assert(std::is_arithmetic<T>::value, "function only makes sense with arithmetic types"); - + swap<sizeof(data)>(reinterpret_cast<u8*>(&data)); return data; } diff --git a/src/common/common_types.h b/src/common/common_types.h index 7ce6b2240..fcc8b9a4e 100644 --- a/src/common/common_types.h +++ b/src/common/common_types.h @@ -22,7 +22,7 @@ * http://code.google.com/p/gekko-gc-emu/ */ -#pragma once +#pragma once #include <cmath> #include <cstdint> @@ -45,8 +45,8 @@ typedef double f64; ///< 64-bit floating point /// Union for fast 16-bit type casting union t16 { - u8 _u8[2]; ///< 8-bit unsigned char(s) - u16 _u16; ///< 16-bit unsigned shorts(s) + u8 _u8[2]; ///< 8-bit unsigned char(s) + u16 _u16; ///< 16-bit unsigned shorts(s) }; /// Union for fast 32-bit type casting diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp index 53f20d754..d7f27c358 100644 --- a/src/common/console_listener.cpp +++ b/src/common/console_listener.cpp @@ -86,7 +86,7 @@ bool ConsoleListener::IsOpen() /* LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are - dependent on each other, that's the reason for the additional checks. + dependent on each other, that's the reason for the additional checks. */ void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) { @@ -225,7 +225,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool BytesWritten += cAttrWritten; coordScreen = GetCoordinates(BytesWritten, LBufWidth); - } + } const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; COORD Coo = GetCoordinates(OldCursor, LBufWidth); @@ -296,23 +296,23 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) } // Clear console screen void ConsoleListener::ClearScreen(bool Cursor) -{ +{ #if defined(_WIN32) - COORD coordScreen = { 0, 0 }; - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; + COORD coordScreen = { 0, 0 }; + DWORD cCharsWritten; + CONSOLE_SCREEN_BUFFER_INFO csbi; + DWORD dwConSize; - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - GetConsoleScreenBufferInfo(hConsole, &csbi); + GetConsoleScreenBufferInfo(hConsole, &csbi); dwConSize = csbi.dwSize.X * csbi.dwSize.Y; // Write space to the entire console - FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); - GetConsoleScreenBufferInfo(hConsole, &csbi); + FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); + GetConsoleScreenBufferInfo(hConsole, &csbi); FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); // Reset cursor - if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); + if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); #endif } diff --git a/src/common/emu_window.h b/src/common/emu_window.h index 4d09acb8b..4cb94fed1 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h @@ -9,17 +9,33 @@ #include "common/string_util.h" #include "common/key_map.h" -// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, -// QGLWidget, GLFW, etc...) +/** + * Abstraction class used to provide an interface between emulation code and the frontend + * (e.g. SDL, QGLWidget, GLFW, etc...). + * + * Design notes on the interaction between EmuWindow and the emulation core: + * - Generally, decisions on anything visible to the user should be left up to the GUI. + * For example, the emulation core should not try to dictate some window title or size. + * This stuff is not the core's business and only causes problems with regards to thread-safety + * anyway. + * - Under certain circumstances, it may be desirable for the core to politely request the GUI + * to set e.g. a minimum window size. However, the GUI should always be free to ignore any + * such hints. + * - EmuWindow may expose some of its state as read-only to the emulation core, however care + * should be taken to make sure the provided information is self-consistent. This requires + * some sort of synchronization (most of this is still a TODO). + * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please + * re-read the upper points again and think about it if you don't see this. + */ class EmuWindow { - public: - /// Data structure to store an emuwindow configuration + /// Data structure to store emuwindow configuration struct WindowConfig { bool fullscreen; int res_width; int res_height; + std::pair<unsigned,unsigned> min_client_area_size; }; /// Swap buffers to display the next frame @@ -42,52 +58,96 @@ public: /// Signals a key release action to the HID module static void KeyReleased(KeyMap::HostDeviceKey key); - WindowConfig GetConfig() const { - return m_config; + /** + * Returns currently active configuration. + * @note Accesses to the returned object need not be consistent because it may be modified in another thread + */ + const WindowConfig& GetActiveConfig() const { + return active_config; } + /** + * Requests the internal configuration to be replaced by the specified argument at some point in the future. + * @note This method is thread-safe, because it delays configuration changes to the GUI event loop. Hence there is no guarantee on when the requested configuration will be active. + */ void SetConfig(const WindowConfig& val) { - m_config = val; - } - - int GetClientAreaWidth() const { - return m_client_area_width; + config = val; } - void SetClientAreaWidth(const int val) { - m_client_area_width = val; + /** + * Gets the framebuffer size in pixels. + * @note This method is thread-safe + */ + const std::pair<unsigned,unsigned> GetFramebufferSize() const { + return framebuffer_size; } - int GetClientAreaHeight() const { - return m_client_area_height; + /** + * Gets window client area width in logical coordinates. + * @note For high-DPI systems, this is smaller than the framebuffer size. + * @note This method is thread-safe + */ + std::pair<unsigned,unsigned> GetClientAreaSize() const { + return std::make_pair(client_area_width, client_area_height); } - void SetClientAreaHeight(const int val) { - m_client_area_height = val; +protected: + EmuWindow() + { + // TODO: Find a better place to set this. + config.min_client_area_size = std::make_pair(400u, 480u); + active_config = config; } + virtual ~EmuWindow() {} - std::string GetWindowTitle() const { - return m_window_title; + /** + * Processes any pending configuration changes from the last SetConfig call. + * This method invokes OnMinimalClientAreaChangeRequest if the corresponding configuration + * field changed. + * @note Implementations will usually want to call this from the GUI thread. + * @todo Actually call this in existing implementations. + */ + void ProcessConfigurationChanges() { + // TODO: For proper thread safety, we should eventually implement a proper + // multiple-writer/single-reader queue... + + if (config.min_client_area_size != active_config.min_client_area_size) { + OnMinimalClientAreaChangeRequest(config.min_client_area_size); + config.min_client_area_size = active_config.min_client_area_size; + } } - - void SetWindowTitle(std::string val) { - m_window_title = val; + + /** + * Update internal framebuffer size with the given parameter. + * @note EmuWindow implementations will usually use this in window resize event handlers. + */ + void NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) { + framebuffer_size = size; } -protected: - EmuWindow(): - m_client_area_width(640), - m_client_area_height(480), - m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc)) - {} - virtual ~EmuWindow() {} + /** + * Update internal client area size with the given parameter. + * @note EmuWindow implementations will usually use this in window resize event handlers. + */ + void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) { + client_area_width = size.first; + client_area_height = size.second; + } - std::string m_window_title; ///< Current window title, should be used by window impl. +private: + /** + * Handler called when the minimal client area was requested to be changed via SetConfig. + * For the request to be honored, EmuWindow implementations will usually reimplement this function. + */ + virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { + // By default, ignore this request and do nothing. + } - int m_client_area_width; ///< Current client width, should be set by window impl. - int m_client_area_height; ///< Current client height, should be set by window impl. + std::pair<unsigned,unsigned> framebuffer_size; -private: - WindowConfig m_config; ///< Internal configuration + unsigned client_area_width; ///< Current client width, should be set by window impl. + unsigned client_area_height; ///< Current client height, should be set by window impl. + WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges) + WindowConfig active_config; ///< Internal active configuration }; diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp index 9cd0398ed..bf61ac1d1 100644 --- a/src/common/extended_trace.cpp +++ b/src/common/extended_trace.cpp @@ -29,7 +29,7 @@ using namespace std; void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) { #if defined(UNICODE)||defined(_UNICODE) - ULONG index = 0; + ULONG index = 0; PCSTR lpAct = lpszIn; for( ; ; lpAct++ ) @@ -37,7 +37,7 @@ void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) lpszOut[index++] = (TCHAR)(*lpAct); if ( *lpAct == 0 ) break; - } + } #else // This is trivial :) strcpy( lpszOut, lpszIn ); @@ -101,7 +101,7 @@ BOOL InitSymInfo( PCSTR lpszInitialSymbolPath ) CHAR lpszSymbolPath[BUFFERSIZE]; DWORD symOptions = SymGetOptions(); - symOptions |= SYMOPT_LOAD_LINES; + symOptions |= SYMOPT_LOAD_LINES; symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions ); InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); @@ -153,15 +153,15 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L #ifndef _M_X64 DWORD dwDisp = 0; if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) -#else +#else //makes it compile but hell im not sure if this works... DWORD64 dwDisp = 0; if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) #endif { // Make the symbol readable for humans - UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, - UNDNAME_COMPLETE | + UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, + UNDNAME_COMPLETE | UNDNAME_NO_THISTYPE | UNDNAME_NO_SPECIAL_SYMS | UNDNAME_NO_MEMBER_TYPE | @@ -219,7 +219,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L _tcscat( lpszSymbol, lpszParsed ); ret = TRUE; - } + } GlobalFree( pSym ); return ret; @@ -325,14 +325,14 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) PrintFunctionAndSourceInfo(file, callStack); - for( ULONG index = 0; ; index++ ) + for( ULONG index = 0; ; index++ ) { bResult = StackWalk( IMAGE_FILE_MACHINE_I386, hProcess, hThread, &callStack, - NULL, + NULL, NULL, SymFunctionTableAccess, SymGetModuleBase, @@ -341,7 +341,7 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) if ( index == 0 ) continue; - if( !bResult || callStack.AddrFrame.Offset == 0 ) + if( !bResult || callStack.AddrFrame.Offset == 0 ) break; PrintFunctionAndSourceInfo(file, callStack); @@ -382,14 +382,14 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, PrintFunctionAndSourceInfo(file, callStack); - for( ULONG index = 0; ; index++ ) + for( ULONG index = 0; ; index++ ) { bResult = StackWalk( IMAGE_FILE_MACHINE_I386, hProcess, hThread, &callStack, - NULL, + NULL, NULL, SymFunctionTableAccess, SymGetModuleBase, @@ -398,7 +398,7 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, if ( index == 0 ) continue; - if( !bResult || callStack.AddrFrame.Offset == 0 ) + if( !bResult || callStack.AddrFrame.Offset == 0 ) break; PrintFunctionAndSourceInfo(file, callStack); diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h index 78a8f561d..2c18285d4 100644 --- a/src/common/fifo_queue.h +++ b/src/common/fifo_queue.h @@ -45,7 +45,7 @@ public: // create the element, add it to the queue m_write_ptr->current = new T(std::forward<Arg>(t)); // set the next pointer to a new element ptr - // then advance the write pointer + // then advance the write pointer m_write_ptr = m_write_ptr->next = new ElementPtr(); Common::AtomicIncrement(m_size); } diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp index 63580f688..bfb54ce72 100644 --- a/src/common/file_search.cpp +++ b/src/common/file_search.cpp @@ -43,7 +43,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string& bool bkeepLooping = true; while (bkeepLooping) - { + { if (findData.cFileName[0] != '.') { std::string strFilename; diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 35da07306..b6dec838c 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -88,7 +88,7 @@ bool IsDirectory(const std::string &filename) #endif if (result < 0) { - WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", + WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", filename.c_str(), GetLastErrorMsg()); return false; } @@ -102,7 +102,7 @@ bool Delete(const std::string &filename) { INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); - // Return true because we care about the file no + // Return true because we care about the file no // being there, not the actual delete. if (!Exists(filename)) { @@ -120,13 +120,13 @@ bool Delete(const std::string &filename) #ifdef _WIN32 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) { - WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", + WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg()); return false; } #else if (unlink(filename.c_str()) == -1) { - WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", + WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", filename.c_str(), GetLastErrorMsg()); return false; } @@ -232,28 +232,28 @@ bool DeleteDir(const std::string &filename) return false; } -// renames file srcFilename to destFilename, returns true on success +// renames file srcFilename to destFilename, returns true on success bool Rename(const std::string &srcFilename, const std::string &destFilename) { - INFO_LOG(COMMON, "Rename: %s --> %s", + INFO_LOG(COMMON, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str()); if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) return true; - ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", + ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); return false; } -// copies file srcFilename to destFilename, returns true on success +// copies file srcFilename to destFilename, returns true on success bool Copy(const std::string &srcFilename, const std::string &destFilename) { - INFO_LOG(COMMON, "Copy: %s --> %s", + INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) return true; - ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", + ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); return false; #else @@ -267,7 +267,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) FILE *input = fopen(srcFilename.c_str(), "rb"); if (!input) { - ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", + ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); return false; } @@ -277,7 +277,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) if (!output) { fclose(input); - ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", + ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); return false; } @@ -291,8 +291,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) { if (ferror(input) != 0) { - ERROR_LOG(COMMON, - "Copy: failed reading from source, %s --> %s: %s", + ERROR_LOG(COMMON, + "Copy: failed reading from source, %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); goto bail; } @@ -302,8 +302,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) int wnum = fwrite(buffer, sizeof(char), rnum, output); if (wnum != rnum) { - ERROR_LOG(COMMON, - "Copy: failed writing to output, %s --> %s: %s", + ERROR_LOG(COMMON, + "Copy: failed writing to output, %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); goto bail; } @@ -335,7 +335,7 @@ u64 GetSize(const std::string &filename) WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); return 0; } - + struct stat64 buf; #ifdef _WIN32 if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0) @@ -384,10 +384,10 @@ u64 GetSize(FILE *f) return size; } -// creates an empty file filename, returns true on success +// creates an empty file filename, returns true on success bool CreateEmptyFile(const std::string &filename) { - INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); + INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); if (!FileUtil::IOFile(filename, "wb")) { @@ -437,7 +437,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) #endif // check for "." and ".." if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && + ((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0'))) continue; entry.virtualName = virtualName; @@ -452,14 +452,14 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) foundEntries += (u32)entry.size; } else - { // is a file + { // is a file entry.isDirectory = false; entry.size = GetSize(entry.physicalName.c_str()); } ++foundEntries; // Push into the tree - parentEntry.children.push_back(entry); -#ifdef _WIN32 + parentEntry.children.push_back(entry); +#ifdef _WIN32 } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); #else @@ -504,7 +504,7 @@ bool DeleteDirRecursively(const std::string &directory) // check for "." and ".." if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || - ((virtualName[0] == '.') && (virtualName[1] == '.') && + ((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0'))) continue; @@ -540,7 +540,7 @@ bool DeleteDirRecursively(const std::string &directory) closedir(dirp); #endif FileUtil::DeleteDir(directory); - + return true; } @@ -585,7 +585,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) std::string GetCurrentDir() { char *dir; - // Get the current working directory (getcwd uses malloc) + // Get the current working directory (getcwd uses malloc) if (!(dir = __getcwd(NULL, 0))) { ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", @@ -604,7 +604,7 @@ bool SetCurrentDir(const std::string &directory) } #if defined(__APPLE__) -std::string GetBundleDirectory() +std::string GetBundleDirectory() { CFURLRef BundleRef; char AppBundlePath[MAXPATHLEN]; @@ -666,8 +666,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; else - paths[D_USER_IDX] = std::string(getenv("HOME") ? - getenv("HOME") : getenv("PWD") ? + paths[D_USER_IDX] = std::string(getenv("HOME") ? + getenv("HOME") : getenv("PWD") ? getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; #endif @@ -749,7 +749,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; } } - + return paths[DirIDX]; } @@ -762,7 +762,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new // if (!FileUtil::Exists(dir)) // dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; //#endif -// +// // return dir; //} diff --git a/src/common/file_util.h b/src/common/file_util.h index 173ce6623..72b80be8a 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -16,33 +16,33 @@ // User directory indices for GetUserPath enum { - D_USER_IDX, - D_ROOT_IDX, - D_CONFIG_IDX, - D_GAMECONFIG_IDX, - D_MAPS_IDX, - D_CACHE_IDX, - D_SHADERCACHE_IDX, - D_SHADERS_IDX, - D_STATESAVES_IDX, - D_SCREENSHOTS_IDX, - D_SDMC_IDX, - D_HIRESTEXTURES_IDX, - D_DUMP_IDX, - D_DUMPFRAMES_IDX, - D_DUMPAUDIO_IDX, - D_DUMPTEXTURES_IDX, - D_DUMPDSP_IDX, - D_LOGS_IDX, - D_SYSCONF_IDX, - F_EMUCONFIG_IDX, - F_DEBUGGERCONFIG_IDX, - F_LOGGERCONFIG_IDX, - F_MAINLOG_IDX, - F_RAMDUMP_IDX, - F_ARAMDUMP_IDX, - F_SYSCONF_IDX, - NUM_PATH_INDICES + D_USER_IDX, + D_ROOT_IDX, + D_CONFIG_IDX, + D_GAMECONFIG_IDX, + D_MAPS_IDX, + D_CACHE_IDX, + D_SHADERCACHE_IDX, + D_SHADERS_IDX, + D_STATESAVES_IDX, + D_SCREENSHOTS_IDX, + D_SDMC_IDX, + D_HIRESTEXTURES_IDX, + D_DUMP_IDX, + D_DUMPFRAMES_IDX, + D_DUMPAUDIO_IDX, + D_DUMPTEXTURES_IDX, + D_DUMPDSP_IDX, + D_LOGS_IDX, + D_SYSCONF_IDX, + F_EMUCONFIG_IDX, + F_DEBUGGERCONFIG_IDX, + F_LOGGERCONFIG_IDX, + F_MAINLOG_IDX, + F_RAMDUMP_IDX, + F_ARAMDUMP_IDX, + F_SYSCONF_IDX, + NUM_PATH_INDICES }; namespace FileUtil @@ -51,11 +51,11 @@ namespace FileUtil // FileSystem tree node/ struct FSTEntry { - bool isDirectory; - u64 size; // file length or number of entries from children - std::string physicalName; // name on disk - std::string virtualName; // name in FST names table - std::vector<FSTEntry> children; + bool isDirectory; + u64 size; // file length or number of entries from children + std::string physicalName; // name on disk + std::string virtualName; // name in FST names table + std::vector<FSTEntry> children; }; // Returns true if file filename exists @@ -148,86 +148,86 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam class IOFile : public NonCopyable { public: - IOFile(); - IOFile(std::FILE* file); - IOFile(const std::string& filename, const char openmode[]); + IOFile(); + IOFile(std::FILE* file); + IOFile(const std::string& filename, const char openmode[]); - ~IOFile(); + ~IOFile(); - IOFile(IOFile&& other); - IOFile& operator=(IOFile&& other); + IOFile(IOFile&& other); + IOFile& operator=(IOFile&& other); - void Swap(IOFile& other); + void Swap(IOFile& other); - bool Open(const std::string& filename, const char openmode[]); - bool Close(); + bool Open(const std::string& filename, const char openmode[]); + bool Close(); - template <typename T> - size_t ReadArray(T* data, size_t length) - { - if (!IsOpen()) { - m_good = false; - return -1; - } + template <typename T> + size_t ReadArray(T* data, size_t length) + { + if (!IsOpen()) { + m_good = false; + return -1; + } - size_t items_read = std::fread(data, sizeof(T), length, m_file); - if (items_read != length) - m_good = false; + size_t items_read = std::fread(data, sizeof(T), length, m_file); + if (items_read != length) + m_good = false; - return items_read; - } + return items_read; + } - template <typename T> - size_t WriteArray(const T* data, size_t length) - { - if (!IsOpen()) { - m_good = false; - return -1; - } + template <typename T> + size_t WriteArray(const T* data, size_t length) + { + if (!IsOpen()) { + m_good = false; + return -1; + } - size_t items_written = std::fwrite(data, sizeof(T), length, m_file); - if (items_written != length) - m_good = false; + size_t items_written = std::fwrite(data, sizeof(T), length, m_file); + if (items_written != length) + m_good = false; - return items_written; - } + return items_written; + } - size_t ReadBytes(void* data, size_t length) - { - return ReadArray(reinterpret_cast<char*>(data), length); - } + size_t ReadBytes(void* data, size_t length) + { + return ReadArray(reinterpret_cast<char*>(data), length); + } - size_t WriteBytes(const void* data, size_t length) - { - return WriteArray(reinterpret_cast<const char*>(data), length); - } + size_t WriteBytes(const void* data, size_t length) + { + return WriteArray(reinterpret_cast<const char*>(data), length); + } - bool IsOpen() { return NULL != m_file; } + bool IsOpen() { return NULL != m_file; } - // m_good is set to false when a read, write or other function fails - bool IsGood() { return m_good; } - operator void*() { return m_good ? m_file : NULL; } + // m_good is set to false when a read, write or other function fails + bool IsGood() { return m_good; } + operator void*() { return m_good ? m_file : NULL; } - std::FILE* ReleaseHandle(); + std::FILE* ReleaseHandle(); - std::FILE* GetHandle() { return m_file; } + std::FILE* GetHandle() { return m_file; } - void SetHandle(std::FILE* file); + void SetHandle(std::FILE* file); - bool Seek(s64 off, int origin); - u64 Tell(); - u64 GetSize(); - bool Resize(u64 size); - bool Flush(); + bool Seek(s64 off, int origin); + u64 Tell(); + u64 GetSize(); + bool Resize(u64 size); + bool Flush(); - // clear error state - void Clear() { m_good = true; std::clearerr(m_file); } + // clear error state + void Clear() { m_good = true; std::clearerr(m_file); } - std::FILE* m_file; - bool m_good; + std::FILE* m_file; + bool m_good; private: - IOFile(IOFile&); - IOFile& operator=(IOFile& other); + IOFile(IOFile&); + IOFile& operator=(IOFile& other); }; } // namespace @@ -237,8 +237,8 @@ template <typename T> void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) { #ifdef _WIN32 - fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); + fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); #else - fstream.open(filename.c_str(), openmode); + fstream.open(filename.c_str(), openmode); #endif } diff --git a/src/common/hash.cpp b/src/common/hash.cpp index d2ebc7341..2ddcfe6b7 100644 --- a/src/common/hash.cpp +++ b/src/common/hash.cpp @@ -115,15 +115,15 @@ inline u64 getblock(const u64 * p, int i) inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2) { - k1 *= c1; - k1 = _rotl64(k1,23); + k1 *= c1; + k1 = _rotl64(k1,23); k1 *= c2; h1 ^= k1; h1 += h2; h2 = _rotl64(h2,41); - k2 *= c2; + k2 *= c2; k2 = _rotl64(k2,23); k2 *= c1; h2 ^= k2; @@ -250,7 +250,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples) } -/* +/* * NOTE: This hash function is used for custom texture loading/dumping, so * it should not be changed, which would require all custom textures to be * recalculated for their new hash values. If the hashing function is @@ -273,7 +273,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) u64 k = data[0]; data+=Step; k *= m; - k ^= k >> r; + k ^= k >> r; k *= m; h ^= k; h *= m; @@ -292,13 +292,13 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) case 1: h ^= u64(data2[0]); h *= m; }; - + h ^= h >> r; h *= m; h ^= h >> r; return h; -} +} #else // CRC32 hash using the SSE4.2 instruction u64 GetCRC32(const u8 *src, int len, u32 samples) @@ -351,15 +351,15 @@ inline u32 fmix32(u32 h) inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2) { - k1 *= c1; - k1 = _rotl(k1,11); + k1 *= c1; + k1 = _rotl(k1,11); k1 *= c2; h1 ^= k1; h1 += h2; h2 = _rotl(h2,17); - k2 *= c2; + k2 *= c2; k2 = _rotl(k2,11); k2 *= c1; h2 ^= k2; @@ -405,7 +405,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples) //---------- // tail - + const u8 * tail = (const u8*)(data + nblocks*8); u32 k1 = 0; @@ -439,7 +439,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples) out[0] = h1; out[1] = h2; - + return *((u64 *)&out); } @@ -463,11 +463,11 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) { u64 k = data[0]; data+=Step; - k *= m; - k ^= k >> r; + k *= m; + k ^= k >> r; k *= m; h ^= k; - h *= m; + h *= m; } const u8 * data2 = (const u8*)end; @@ -483,7 +483,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples) case 1: h ^= u64(data2[0]); h *= m; }; - + h ^= h >> r; h *= m; h ^= h >> r; diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h index 96dce3155..f4263f72a 100644 --- a/src/common/linear_disk_cache.h +++ b/src/common/linear_disk_cache.h @@ -64,7 +64,7 @@ public: m_file.seekg(0, std::ios::beg); std::fstream::pos_type start_pos = m_file.tellg(); std::streamoff file_size = end_pos - start_pos; - + if (m_file.is_open() && ValidateHeader()) { // good header, read some key/value pairs @@ -87,7 +87,7 @@ public: // read key/value and pass to reader if (Read(&key) && - Read(value, value_size) && + Read(value, value_size) && Read(&entry_number) && entry_number == m_num_entries+1) { @@ -115,7 +115,7 @@ public: WriteHeader(); return 0; } - + void Sync() { m_file.flush(); diff --git a/src/common/log.h b/src/common/log.h index bfd73f8a5..14ad98c08 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -11,7 +11,7 @@ enum { OS_LEVEL, // Printed by the emulated operating system NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports. - ERROR_LEVEL, // Critical errors + ERROR_LEVEL, // Critical errors WARNING_LEVEL, // Something is suspicious. INFO_LEVEL, // General information. DEBUG_LEVEL, // Detailed debugging - might make things slow. @@ -46,7 +46,7 @@ enum LOG_TYPE { MEMMAP, MEMCARD_MANAGER, OSREPORT, - PAD, + PAD, PROCESSORINTERFACE, PIXELENGINE, SERIALINTERFACE, @@ -69,6 +69,7 @@ enum LOG_TYPE { HW, TIME, NETPLAY, + GUI, NUMBER_OF_LOGS // Must be last }; @@ -88,7 +89,7 @@ enum LOG_LEVELS { } // namespace -void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line, +void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line, const char* function, const char* fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 6, 7))) diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 4d590d98f..2ef7d98c0 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -7,9 +7,8 @@ #include "common/log_manager.h" #include "common/console_listener.h" #include "common/timer.h" -#include "common/thread.h" -void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, +void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, const char* function, const char* fmt, ...) { va_list args; @@ -75,6 +74,7 @@ LogManager::LogManager() m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); + m_Log[LogTypes::GUI] = new LogContainer("GUI", "GUI"); m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str()); m_consoleLog = new ConsoleListener(); @@ -111,7 +111,7 @@ LogManager::~LogManager() delete m_debuggerLog; } -void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, +void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, const char* function, const char *fmt, va_list args) { char temp[MAX_MSGLEN]; @@ -124,11 +124,11 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); static const char level_to_char[7] = "ONEWID"; - sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, + sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, level_to_char[(int)level], log->GetShortName(), function, temp); - + #ifdef ANDROID - Host_SysMessage(msg); + Host_SysMessage(msg); #endif log->Trigger(level, msg); } diff --git a/src/common/log_manager.h b/src/common/log_manager.h index de1d16ee5..baefc4ba8 100644 --- a/src/common/log_manager.h +++ b/src/common/log_manager.h @@ -54,7 +54,7 @@ class LogContainer { public: LogContainer(const char* shortName, const char* fullName, bool enable = false); - + const char* GetShortName() const { return m_shortName; } const char* GetFullName() const { return m_fullName; } @@ -98,7 +98,7 @@ public: static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; } - void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, + void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, const char* function, const char *fmt, va_list args); void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp index ab0e6b75c..3613e82a6 100644 --- a/src/common/math_util.cpp +++ b/src/common/math_util.cpp @@ -18,7 +18,7 @@ u32 ClassifyDouble(double dvalue) value.d = dvalue; u64 sign = value.i & DOUBLE_SIGN; u64 exp = value.i & DOUBLE_EXP; - if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) + if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) { // Nice normalized number. return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; @@ -58,7 +58,7 @@ u32 ClassifyFloat(float fvalue) value.f = fvalue; u32 sign = value.i & FLOAT_SIGN; u32 exp = value.i & FLOAT_EXP; - if (exp > FLOAT_ZERO && exp < FLOAT_EXP) + if (exp > FLOAT_ZERO && exp < FLOAT_EXP) { // Nice normalized number. return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; @@ -77,13 +77,13 @@ u32 ClassifyFloat(float fvalue) // Denormalized number. return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; } - } - else if (exp) + } + else if (exp) { // Infinite return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else + } + else { //Zero return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; @@ -143,7 +143,7 @@ void Matrix33::RotateY(Matrix33 &mtx, float rad) mtx.data[0] = c; mtx.data[2] = s; mtx.data[4] = 1; - mtx.data[6] = -s; + mtx.data[6] = -s; mtx.data[8] = c; } diff --git a/src/common/math_util.h b/src/common/math_util.h index b32e7bb14..b10a25c13 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h @@ -7,6 +7,7 @@ #include "common/common.h" #include <algorithm> +#include <type_traits> #include <vector> namespace MathUtil @@ -109,11 +110,11 @@ struct Rectangle Rectangle(T theLeft, T theTop, T theRight, T theBottom) : left(theLeft), top(theTop), right(theRight), bottom(theBottom) { } - + bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } - T GetWidth() const { return abs(right - left); } - T GetHeight() const { return abs(bottom - top); } + T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); } + T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); } // If the rectangle is in a coordinate system with a lower-left origin, use // this Clamp. @@ -127,7 +128,7 @@ struct Rectangle // If the rectangle is in a coordinate system with an upper-left origin, // use this Clamp. - void ClampUL(T x1, T y1, T x2, T y2) + void ClampUL(T x1, T y1, T x2, T y2) { if (left < x1) left = x1; if (right > x2) right = x2; diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp index 40d9c03a2..67dbaf509 100644 --- a/src/common/mem_arena.cpp +++ b/src/common/mem_arena.cpp @@ -38,7 +38,7 @@ void* globalbase = NULL; // Hopefully this ABI will never change... -#define ASHMEM_DEVICE "/dev/ashmem" +#define ASHMEM_DEVICE "/dev/ashmem" /* * ashmem_create_region - creates a new ashmem region and returns the file @@ -272,11 +272,11 @@ u8* MemArena::Find4GBBase() // yeah, this could also be done in like two bitwise ops... -#define SKIP(a_flags, b_flags) -// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) -// continue; -// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) -// continue; +#define SKIP(a_flags, b_flags) +//if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) +// continue; +//if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) +// continue; static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { // OK, we know where to find free space. Now grab it! diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index bab7d9f7a..b6f66e4e1 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp @@ -47,7 +47,7 @@ void* AllocateExecutableMemory(size_t size, bool low) // printf("Mapped executable memory at %p (size %ld)\n", ptr, // (unsigned long)size); - + #ifdef _WIN32 if (ptr == nullptr) { @@ -55,7 +55,7 @@ void* AllocateExecutableMemory(size_t size, bool low) if (ptr == MAP_FAILED) { ptr = nullptr; -#endif +#endif PanicAlert("Failed to allocate executable memory"); } #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) @@ -127,11 +127,11 @@ void FreeMemoryPages(void* ptr, size_t size) if (ptr) { #ifdef _WIN32 - + if (!VirtualFree(ptr, 0, MEM_RELEASE)) PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); ptr = NULL; // Is this our responsibility? - + #else munmap(ptr, size); #endif diff --git a/src/common/msg_handler.h b/src/common/msg_handler.h index 7c5319ec3..9bfdf950e 100644 --- a/src/common/msg_handler.h +++ b/src/common/msg_handler.h @@ -15,7 +15,7 @@ enum MSG_TYPE CRITICAL }; -typedef bool (*MsgAlertHandler)(const char* caption, const char* text, +typedef bool (*MsgAlertHandler)(const char* caption, const char* text, bool yes_no, int Style); typedef std::string (*StringTranslator)(const char* text); @@ -31,29 +31,29 @@ void SetEnableAlert(bool enable); #ifndef GEKKO #ifdef _WIN32 - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) + #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) + #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) + #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) + #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) + #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) + #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) + #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) + #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) + #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) + #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) #else - #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) + #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) + #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) + #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) + #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) + #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) // Use these macros (that do the same thing) if the message should be translated. - #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) - #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) - #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) - #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) - #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) + #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) + #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) + #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) + #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) + #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) #endif #else // GEKKO diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 54943d306..dcec9275f 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -121,11 +121,11 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces) { std::ostringstream oss; oss << std::setfill('0') << std::hex; - + for (int line = 0; size; ++data, --size) { oss << std::setw(2) << (int)*data; - + if (line_len == ++line) { oss << '\n'; @@ -168,7 +168,7 @@ bool TryParse(const std::string &str, u32 *const output) errno = 0; unsigned long value = strtoul(str.c_str(), &endptr, 0); - + if (!endptr || *endptr) return false; @@ -294,7 +294,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st //#include <string> //#include <assert.h> -const char HEX2DEC[256] = +const char HEX2DEC[256] = { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, @@ -327,7 +327,7 @@ std::string UriDecode(const std::string & sSrc) const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); const size_t SRC_LEN = sSrc.length(); const unsigned char * const SRC_END = pSrc + SRC_LEN; - const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' + const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' char * const pStart = new char[SRC_LEN]; char * pEnd = pStart; @@ -394,7 +394,7 @@ std::string UriEncode(const std::string & sSrc) for (; pSrc < SRC_END; ++pSrc) { - if (SAFE[*pSrc]) + if (SAFE[*pSrc]) *pEnd++ = *pSrc; else { @@ -518,9 +518,9 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& out_buffer.resize(out_buffer_size - dst_bytes); out_buffer.swap(result); - + iconv_close(conv_desc); - + return result; } @@ -576,7 +576,7 @@ std::u16string UTF8ToUTF16(const std::string& input) out_buffer.swap(result); iconv_close(conv_desc); - + return result; } diff --git a/src/common/string_util.h b/src/common/string_util.h index 787a5663f..ae5bbadad 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -63,7 +63,7 @@ template <typename N> static bool TryParse(const std::string &str, N *const output) { std::istringstream iss(str); - + N tmp = 0; if (iss >> tmp) { diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp index d61f4c0c6..63ad6218b 100644 --- a/src/common/symbols.cpp +++ b/src/common/symbols.cpp @@ -31,7 +31,7 @@ namespace Symbols { TSymbolsMap::iterator foundSymbolItr; TSymbol symbol; - + foundSymbolItr = g_symbols.find(_address); if (foundSymbolItr != g_symbols.end()) { @@ -44,7 +44,7 @@ namespace Symbols { return GetSymbol(_address).name; } - + void Remove(u32 _address) { g_symbols.erase(_address); diff --git a/src/common/symbols.h b/src/common/symbols.h index b13a8001a..4560f5240 100644 --- a/src/common/symbols.h +++ b/src/common/symbols.h @@ -33,5 +33,5 @@ namespace Symbols const std::string GetName(u32 _address); void Remove(u32 _address); void Clear(); -}; +} diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 60d8ed075..dc153ba71 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -25,7 +25,7 @@ int CurrentThreadId() return 0; #endif } - + #ifdef _WIN32 void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) @@ -52,7 +52,7 @@ void SwitchCurrentThread() // Sets the debugger-visible name of the current thread. // Uses undocumented (actually, it is now documented) trick. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp - + // This is implemented much nicer in upcoming msvc++, see: // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx void SetCurrentThreadName(const char* szThreadName) @@ -81,7 +81,7 @@ void SetCurrentThreadName(const char* szThreadName) __except(EXCEPTION_CONTINUE_EXECUTION) {} } - + #else // !WIN32, so must be POSIX threads void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) diff --git a/src/common/thread.h b/src/common/thread.h index f7ace21b4..be9b5cbe2 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -30,13 +30,13 @@ int CurrentThreadId(); void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); void SetCurrentThreadAffinity(u32 mask); - + class Event { public: Event() : is_set(false) - {}; + {} void Set() { @@ -135,7 +135,7 @@ private: const size_t m_count; volatile size_t m_waiting; }; - + void SleepCurrentThread(int ms); void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms @@ -146,7 +146,7 @@ inline void YieldCPU() { std::this_thread::yield(); } - + void SetCurrentThreadName(const char *name); - + } // namespace Common diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h index 4a89572f6..59efbce4c 100644 --- a/src/common/thread_queue_list.h +++ b/src/common/thread_queue_list.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -12,7 +12,7 @@ template<class IdType> struct ThreadQueueList { // Number of queues (number of priority levels starting at 0.) static const int NUM_QUEUES = 128; - + // Initial number of threads a single queue can handle. static const int INITIAL_CAPACITY = 32; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f41d52e80..48241c3d4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -31,17 +31,24 @@ set(SRCS hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/service/ac_u.cpp + hle/service/am_net.cpp hle/service/apt_u.cpp + hle/service/boss_u.cpp + hle/service/cfg_i.cpp hle/service/cfg_u.cpp + hle/service/csnd_snd.cpp hle/service/dsp_dsp.cpp hle/service/err_f.cpp hle/service/fs_user.cpp hle/service/frd_u.cpp hle/service/gsp_gpu.cpp hle/service/hid_user.cpp + hle/service/ir_rst.cpp + hle/service/ir_u.cpp hle/service/mic_u.cpp hle/service/ndm_u.cpp hle/service/nwm_uds.cpp + hle/service/pm_app.cpp hle/service/ptm_u.cpp hle/service/service.cpp hle/service/soc_u.cpp @@ -102,23 +109,31 @@ set(HEADERS hle/kernel/shared_memory.h hle/kernel/thread.h hle/service/ac_u.h + hle/service/am_net.h hle/service/apt_u.h + hle/service/boss_u.h + hle/service/cfg_i.h hle/service/cfg_u.h + hle/service/csnd_snd.h hle/service/dsp_dsp.h hle/service/err_f.h hle/service/fs_user.h hle/service/frd_u.h hle/service/gsp_gpu.h hle/service/hid_user.h + hle/service/ir_rst.h + hle/service/ir_u.h hle/service/mic_u.h hle/service/ndm_u.h hle/service/nwm_uds.h + hle/service/pm_app.h hle/service/ptm_u.h hle/service/service.h hle/service/soc_u.h hle/service/srv.h hle/service/ssl_c.h hle/config_mem.h + hle/result.h hle/function_wrappers.h hle/hle.h hle/svc.h diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 4b93d3313..3ae528562 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -63,7 +63,7 @@ public: * Get the current CPSR register * @return Returns the value of the CPSR register */ - virtual u32 GetCPSR() const = 0; + virtual u32 GetCPSR() const = 0; /** * Set the current CPSR register @@ -98,7 +98,7 @@ public: } protected: - + /** * Executes the given number of instructions * @param num_instructions Number of instructions to executes diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp index 0f384ad3e..55278474b 100644 --- a/src/core/arm/disassembler/load_symbol_map.cpp +++ b/src/core/arm/disassembler/load_symbol_map.cpp @@ -22,8 +22,8 @@ void LoadSymbolMap(std::string filename) { while (std::getline(infile, line)) { std::istringstream iss(line); - if (!(iss >> address_str >> size >> function_name)) { - break; // Error parsing + if (!(iss >> address_str >> size >> function_name)) { + break; // Error parsing } u32 address = std::stoul(address_str, nullptr, 16); diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index a3ed3e31e..6c8ea211e 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "core/arm/skyeye_common/armcpu.h" #include "core/arm/skyeye_common/armemu.h" @@ -113,7 +113,7 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) { state->NumInstrsToExecute = num_instructions; // Dyncom only breaks on instruction dispatch. This only happens on every instruction when - // executing one instruction at a time. Otherwise, if a block is being executed, more + // executing one instruction at a time. Otherwise, if a block is being executed, more // instructions may actually be executed than specified. ticks += InterpreterMainLoop(state.get()); } diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 1f8cd3a3a..51eea41ed 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -19,7 +19,7 @@ public: /** * Set the Program Counter to an address - * @param addr Address to set PC to + * @param pc Address to set PC to */ void SetPC(u32 pc) override; diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index f899e2e8a..233cd3e3a 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -26,7 +26,7 @@ #define CITRA_IGNORE_EXIT(x) #include <algorithm> -#include <map> +#include <unordered_map> #include <stdio.h> #include <assert.h> #include <cstdio> @@ -94,9 +94,8 @@ typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper); /* exclusive memory access */ static int exclusive_detect(ARMul_State* state, ARMword addr){ - int i; #if 0 - for(i = 0; i < 128; i++){ + for(int i = 0; i < 128; i++){ if(state->exclusive_tag_array[i] == addr) return 0; } @@ -108,9 +107,8 @@ static int exclusive_detect(ARMul_State* state, ARMword addr){ } static void add_exclusive_addr(ARMul_State* state, ARMword addr){ - int i; #if 0 - for(i = 0; i < 128; i++){ + for(int i = 0; i < 128; i++){ if(state->exclusive_tag_array[i] == 0xffffffff){ state->exclusive_tag_array[i] = addr; //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr); @@ -3309,9 +3307,8 @@ const transop_fp_t arm_instruction_trans[] = { INTERPRETER_TRANSLATE(blx_1_thumb) }; -typedef map<unsigned int, int> bb_map; -bb_map CreamCache[65536]; -bb_map ProfileCache[65536]; +typedef std::unordered_map<u32, int> bb_map; +bb_map CreamCache; //#define USE_DUMMY_CACHE @@ -3319,14 +3316,12 @@ bb_map ProfileCache[65536]; unsigned int DummyCache[0x100000]; #endif -#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536) void insert_bb(unsigned int addr, int start) { #ifdef USE_DUMMY_CACHE DummyCache[addr] = start; #else -// CreamCache[addr] = start; - CreamCache[HASH(addr)][addr] = start; + CreamCache[addr] = start; #endif } @@ -3341,8 +3336,8 @@ int find_bb(unsigned int addr, int &start) } else ret = -1; #else - bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr); - if (it != CreamCache[HASH(addr)].end()) { + bb_map::const_iterator it = CreamCache.find(addr); + if (it != CreamCache.end()) { start = static_cast<int>(it->second); ret = 0; #if HYBRID_MODE @@ -3473,30 +3468,15 @@ void flush_bb(uint32_t addr) uint32_t start; addr &= 0xfffff000; - for (int i = 0; i < 65536; i ++) { - for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) { - start = static_cast<uint32_t>(it->first); - //start = (start >> 12) << 12; - start &= 0xfffff000; - if (start == addr) { - //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); - CreamCache[i].erase(it ++); - } else - ++it; - } - } - - for (int i = 0; i < 65536; i ++) { - for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) { - start = static_cast<uint32_t>(it->first); - //start = (start >> 12) << 12; - start &= 0xfffff000; - if (start == addr) { - //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); - ProfileCache[i].erase(it ++); - } else - ++it; - } + for (it = CreamCache.begin(); it != CreamCache.end(); ) { + start = static_cast<uint32_t>(it->first); + //start = (start >> 12) << 12; + start &= 0xfffff000; + if (start == addr) { + //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); + CreamCache.erase(it++); + } else + ++it; } //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr); diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h index c65eb23f7..3a2462f55 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.h +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index ed4415082..e2aa5ce92 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "core/arm/interpreter/arm_interpreter.h" @@ -24,7 +24,7 @@ ARM_Interpreter::ARM_Interpreter() { state->lateabtSig = LOW; // Reset the core to initial state - ARMul_CoProInit(state); + ARMul_CoProInit(state); ARMul_Reset(state); state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext state->Emulate = 3; diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index ceb1be438..ed53d997c 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -18,7 +18,7 @@ public: /** * Set the Program Counter to an address - * @param addr Address to set PC to + * @param pc Address to set PC to */ void SetPC(u32 pc) override; diff --git a/src/core/arm/skyeye_common/armcpu.h b/src/core/arm/skyeye_common/armcpu.h index 3a029f0e7..2b756c5bc 100644 --- a/src/core/arm/skyeye_common/armcpu.h +++ b/src/core/arm/skyeye_common/armcpu.h @@ -24,8 +24,6 @@ #include <stddef.h> #include <stdio.h> -#include "common/thread.h" - #include "core/arm/skyeye_common/armdefs.h" typedef struct ARM_CPU_State_s { diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 8e71948c6..8343aaa01 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -799,22 +799,24 @@ pascal void SpinCursor (short increment); /* copied from CursorCtl.h */ #include "list.h" #include "tb.h" */ -#define EQ 0 -#define NE 1 -#define CS 2 -#define CC 3 -#define MI 4 -#define PL 5 -#define VS 6 -#define VC 7 -#define HI 8 -#define LS 9 -#define GE 10 -#define LT 11 -#define GT 12 -#define LE 13 -#define AL 14 -#define NV 15 +enum ConditionCode { + EQ = 0, + NE = 1, + CS = 2, + CC = 3, + MI = 4, + PL = 5, + VS = 6, + VC = 7, + HI = 8, + LS = 9, + GE = 10, + LT = 11, + GT = 12, + LE = 13, + AL = 14, + NV = 15, +}; #ifndef NFLAG #define NFLAG state->NFlag diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h index c0f0270fe..075fc7e9e 100644 --- a/src/core/arm/skyeye_common/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h @@ -25,24 +25,6 @@ #define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__) -/* Condition code values. */ -#define EQ 0 -#define NE 1 -#define CS 2 -#define CC 3 -#define MI 4 -#define PL 5 -#define VS 6 -#define VC 7 -#define HI 8 -#define LS 9 -#define GE 10 -#define LT 11 -#define GT 12 -#define LE 13 -#define AL 14 -#define NV 15 - /* Shift Opcodes. */ #define LSL 0 #define LSR 1 diff --git a/src/core/core.cpp b/src/core/core.cpp index 25c78d33c..865898b24 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -16,10 +16,10 @@ namespace Core { -u64 g_last_ticks = 0; ///< Last CPU ticks -ARM_Disasm* g_disasm = nullptr; ///< ARM disassembler -ARM_Interface* g_app_core = nullptr; ///< ARM11 application core -ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core +static u64 last_ticks = 0; ///< Last CPU ticks +static ARM_Disasm* disasm = nullptr; ///< ARM disassembler +ARM_Interface* g_app_core = nullptr; ///< ARM11 application core +ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core /// Run the core CPU loop void RunLoop(int tight_loop) { @@ -49,7 +49,7 @@ void Stop() { int Init() { NOTICE_LOG(MASTER_LOG, "initialized OK"); - g_disasm = new ARM_Disasm(); + disasm = new ARM_Disasm(); g_sys_core = new ARM_Interpreter(); switch (Settings::values.cpu_core) { @@ -62,13 +62,13 @@ int Init() { break; } - g_last_ticks = Core::g_app_core->GetTicks(); + last_ticks = Core::g_app_core->GetTicks(); return 0; } void Shutdown() { - delete g_disasm; + delete disasm; delete g_app_core; delete g_sys_core; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 0116cb376..558c6cbf7 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -41,7 +41,7 @@ struct BaseEvent s64 time; u64 userdata; int type; - // Event *next; + // Event *next; }; typedef LinkedListItem<BaseEvent> Event; @@ -249,7 +249,7 @@ void AddEventToQueue(Event* ne) // This must be run ONLY from within the cpu thread // cyclesIntoFuture may be VERY inaccurate if called from anything else -// than Advance +// than Advance void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata) { Event *ne = GetNewEvent(); @@ -469,8 +469,8 @@ void ProcessFifoWaitEvents() { if (first->time <= globalTimer) { - // LOG(TIMER, "[Scheduler] %s (%lld, %lld) ", - // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time); + //LOG(TIMER, "[Scheduler] %s (%lld, %lld) ", + // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time); Event* evt = first; first = first->next; event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time)); @@ -516,23 +516,23 @@ void Advance() //currentMIPS->downcount = slicelength; //if (Common::AtomicLoadAcquire(hasTsEvents)) - // MoveEvents(); + // MoveEvents(); //ProcessFifoWaitEvents(); //if (!first) //{ - // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000"); - // currentMIPS->downcount += 10000; + // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000"); + // currentMIPS->downcount += 10000; //} //else //{ - // slicelength = (int)(first->time - globalTimer); - // if (slicelength > MAX_SLICE_LENGTH) - // slicelength = MAX_SLICE_LENGTH; - // currentMIPS->downcount = slicelength; + // slicelength = (int)(first->time - globalTimer); + // if (slicelength > MAX_SLICE_LENGTH) + // slicelength = MAX_SLICE_LENGTH; + // currentMIPS->downcount = slicelength; //} //if (advanceCallback) - // advanceCallback(cyclesExecuted); + // advanceCallback(cyclesExecuted); } void LogPendingEvents() @@ -550,20 +550,20 @@ void Idle(int maxIdle) ERROR_LOG(TIME, "Unimplemented function!"); //int cyclesDown = currentMIPS->downcount; //if (maxIdle != 0 && cyclesDown > maxIdle) - // cyclesDown = maxIdle; + // cyclesDown = maxIdle; //if (first && cyclesDown > 0) //{ - // int cyclesExecuted = slicelength - currentMIPS->downcount; - // int cyclesNextEvent = (int) (first->time - globalTimer); - - // if (cyclesNextEvent < cyclesExecuted + cyclesDown) - // { - // cyclesDown = cyclesNextEvent - cyclesExecuted; - // // Now, now... no time machines, please. - // if (cyclesDown < 0) - // cyclesDown = 0; - // } + // int cyclesExecuted = slicelength - currentMIPS->downcount; + // int cyclesNextEvent = (int) (first->time - globalTimer); + + // if (cyclesNextEvent < cyclesExecuted + cyclesDown) + // { + // cyclesDown = cyclesNextEvent - cyclesExecuted; + // // Now, now... no time machines, please. + // if (cyclesDown < 0) + // cyclesDown = 0; + // } //} //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f)); @@ -571,7 +571,7 @@ void Idle(int maxIdle) //idledCycles += cyclesDown; //currentMIPS->downcount -= cyclesDown; //if (currentMIPS->downcount == 0) - // currentMIPS->downcount = -1; + // currentMIPS->downcount = -1; } std::string GetScheduledEventsSummary() @@ -623,4 +623,4 @@ void DoState(PointerWrap &p) p.Do(idledCycles); } -} // namespace +} // namespace diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 09fdf7a90..b197cf40c 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -106,4 +106,4 @@ void SetClockFrequencyMHz(int cpuMhz); int GetClockFrequencyMHz(); extern int slicelength; -}; // namespace +} // namespace diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h index 38145eed8..c2426a153 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive.h @@ -67,6 +67,8 @@ public: u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. break; } + default: + break; } } @@ -74,6 +76,35 @@ public: return type; } + /** + * Gets the string representation of the path for debugging + * @return String representation of the path for debugging + */ + const std::string DebugStr() const { + switch (GetType()) { + case Invalid: + return "[Invalid]"; + case Empty: + return "[Empty]"; + case Binary: + { + std::stringstream res; + res << "[Binary: "; + for (unsigned byte : binary) + res << std::hex << std::setw(2) << std::setfill('0') << byte; + res << ']'; + return res.str(); + } + case Char: + return "[Char: " + AsString() + ']'; + case Wchar: + return "[Wchar: " + AsString() + ']'; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!"); + return {}; + } + } + const std::string AsString() const { switch (GetType()) { case Char: @@ -153,21 +184,35 @@ public: * @param mode Mode to open the file with * @return Opened file, or nullptr */ - virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0; + virtual std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const = 0; + + /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Whether the file could be deleted + */ + virtual bool DeleteFile(const FileSys::Path& path) const = 0; + + /** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be deleted + */ + virtual bool DeleteDirectory(const FileSys::Path& path) const = 0; /** * Create a directory specified by its path * @param path Path relative to the archive * @return Whether the directory could be created */ - virtual bool CreateDirectory(const std::string& path) const = 0; + virtual bool CreateDirectory(const Path& path) const = 0; /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr */ - virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0; + virtual std::unique_ptr<Directory> OpenDirectory(const Path& path) const = 0; /** * Read data from the archive @@ -193,7 +238,7 @@ public: * @return Size of the archive in bytes */ virtual size_t GetSize() const = 0; - + /** * Set the size of the archive in bytes */ diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index cc759faa8..53dc57954 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -29,26 +29,46 @@ Archive_RomFS::~Archive_RomFS() { * @param mode Mode to open the file with * @return Opened file, or nullptr */ -std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const { +std::unique_ptr<File> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { return std::unique_ptr<File>(new File_RomFS); } /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Whether the file could be deleted + */ +bool Archive_RomFS::DeleteFile(const FileSys::Path& path) const { + ERROR_LOG(FILESYS, "Attempted to delete a file from ROMFS."); + return false; +} + +/** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be deleted + */ +bool Archive_RomFS::DeleteDirectory(const FileSys::Path& path) const { + ERROR_LOG(FILESYS, "Attempted to delete a directory from ROMFS."); + return false; +} + +/** * Create a directory specified by its path * @param path Path relative to the archive * @return Whether the directory could be created */ -bool Archive_RomFS::CreateDirectory(const std::string& path) const { +bool Archive_RomFS::CreateDirectory(const Path& path) const { ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS."); return false; -}; +} /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr */ -std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const { +std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const Path& path) const { return std::unique_ptr<Directory>(new Directory_RomFS); } diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index ae2344e82..0649dde99 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -26,7 +26,7 @@ public: * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) * @return IdCode of the archive */ - IdCode GetIdCode() const override { return IdCode::RomFS; }; + IdCode GetIdCode() const override { return IdCode::RomFS; } /** * Open a file specified by its path, using the specified mode @@ -34,21 +34,35 @@ public: * @param mode Mode to open the file with * @return Opened file, or nullptr */ - std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; + std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; + + /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Whether the file could be deleted + */ + bool DeleteFile(const FileSys::Path& path) const override; + + /** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be deleted + */ + bool DeleteDirectory(const FileSys::Path& path) const override; /** * Create a directory specified by its path * @param path Path relative to the archive * @return Whether the directory could be created */ - bool CreateDirectory(const std::string& path) const override; + bool CreateDirectory(const Path& path) const override; /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr */ - std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; + std::unique_ptr<Directory> OpenDirectory(const Path& path) const override; /** * Read data from the archive @@ -74,7 +88,7 @@ public: * @return Size of the archive in bytes */ size_t GetSize() const override; - + /** * Set the size of the archive in bytes */ diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 66931e93e..789212b17 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -49,8 +49,8 @@ bool Archive_SDMC::Initialize() { * @param mode Mode to open the file with * @return Opened file, or nullptr */ -std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { - DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode); +std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { + DEBUG_LOG(FILESYS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex); File_SDMC* file = new File_SDMC(this, path, mode); if (!file->Open()) return nullptr; @@ -58,12 +58,30 @@ std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode } /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Whether the file could be deleted + */ +bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const { + return FileUtil::Delete(GetMountPoint() + path.AsString()); +} + +/** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be deleted + */ +bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const { + return FileUtil::DeleteDir(GetMountPoint() + path.AsString()); +} + +/** * Create a directory specified by its path * @param path Path relative to the archive * @return Whether the directory could be created */ -bool Archive_SDMC::CreateDirectory(const std::string& path) const { - return FileUtil::CreateDir(GetMountPoint() + path); +bool Archive_SDMC::CreateDirectory(const Path& path) const { + return FileUtil::CreateDir(GetMountPoint() + path.AsString()); } /** @@ -71,8 +89,8 @@ bool Archive_SDMC::CreateDirectory(const std::string& path) const { * @param path Path relative to the archive * @return Opened directory, or nullptr */ -std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const { - DEBUG_LOG(FILESYS, "called path=%s", path.c_str()); +std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const { + DEBUG_LOG(FILESYS, "called path=%s", path.DebugStr().c_str()); Directory_SDMC* directory = new Directory_SDMC(this, path); return std::unique_ptr<Directory>(directory); } diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 0e059b635..74ce29c0d 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -30,7 +30,7 @@ public: * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) * @return IdCode of the archive */ - IdCode GetIdCode() const override { return IdCode::SDMC; }; + IdCode GetIdCode() const override { return IdCode::SDMC; } /** * Open a file specified by its path, using the specified mode @@ -38,21 +38,35 @@ public: * @param mode Mode to open the file with * @return Opened file, or nullptr */ - std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; + std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; + + /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Whether the file could be deleted + */ + bool DeleteFile(const FileSys::Path& path) const override; + + /** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be deleted + */ + bool DeleteDirectory(const FileSys::Path& path) const override; /** * Create a directory specified by its path * @param path Path relative to the archive * @return Whether the directory could be created */ - bool CreateDirectory(const std::string& path) const override; + bool CreateDirectory(const Path& path) const override; /** * Open a directory specified by its path * @param path Path relative to the archive * @return Opened directory, or nullptr */ - std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; + std::unique_ptr<Directory> OpenDirectory(const Path& path) const override; /** * Read data from the archive diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp index fd558def9..60a197ce9 100644 --- a/src/core/file_sys/directory_sdmc.cpp +++ b/src/core/file_sys/directory_sdmc.cpp @@ -15,11 +15,11 @@ namespace FileSys { -Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& path) { +Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) { // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass // the root directory we set while opening the archive. // For example, opening /../../usr/bin can give the emulated program your installed programs. - std::string absolute_path = archive->GetMountPoint() + path; + std::string absolute_path = archive->GetMountPoint() + path.AsString(); FileUtil::ScanDirectoryTree(absolute_path, directory); children_iterator = directory.children.begin(); } @@ -45,7 +45,7 @@ u32 Directory_SDMC::Read(const u32 count, Entry* entries) { WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); // TODO(Link Mauve): use a proper conversion to UTF-16. - for (int j = 0; j < FILENAME_LENGTH; ++j) { + for (size_t j = 0; j < FILENAME_LENGTH; ++j) { entry.filename[j] = filename[j]; if (!filename[j]) break; diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h index cb8d32fda..4520d0401 100644 --- a/src/core/file_sys/directory_sdmc.h +++ b/src/core/file_sys/directory_sdmc.h @@ -19,7 +19,7 @@ namespace FileSys { class Directory_SDMC final : public Directory { public: Directory_SDMC(); - Directory_SDMC(const Archive_SDMC* archive, const std::string& path); + Directory_SDMC(const Archive_SDMC* archive, const Path& path); ~Directory_SDMC() override; /** diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp index 26204392c..a4b90670a 100644 --- a/src/core/file_sys/file_sdmc.cpp +++ b/src/core/file_sys/file_sdmc.cpp @@ -15,11 +15,11 @@ namespace FileSys { -File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode) { +File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) { // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass // the root directory we set while opening the archive. // For example, opening /../../etc/passwd can give the emulated program your users list. - this->path = archive->GetMountPoint() + path; + this->path = archive->GetMountPoint() + path.AsString(); this->mode.hex = mode.hex; } diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h index df032f7c0..80b445968 100644 --- a/src/core/file_sys/file_sdmc.h +++ b/src/core/file_sys/file_sdmc.h @@ -19,7 +19,7 @@ namespace FileSys { class File_SDMC final : public File { public: File_SDMC(); - File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode); + File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode); ~File_SDMC() override; /** diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index a45e61427..c7cf5b1d3 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "common/common_types.h" diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp index 1eb33eb86..e34229a57 100644 --- a/src/core/hle/coprocessor.cpp +++ b/src/core/hle/coprocessor.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "core/hle/coprocessor.h" #include "core/hle/hle.h" diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 55eaf0621..3dbe25037 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -50,7 +50,7 @@ template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){ template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { s32 param_1 = 0; - s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), + s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))); Core::g_app_core->SetReg(1, (u32)param_1); FuncReturn(retval); @@ -103,7 +103,7 @@ template<s32 func(void*)> void Wrap() { } template<s32 func(s64*, u32, void*, s32)> void Wrap(){ - FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), + FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), (s32)PARAM(3))); } diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index b03894ad7..b8ac186f6 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <vector> @@ -20,7 +20,7 @@ bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a n const FunctionDef* GetSVCInfo(u32 opcode) { u32 func_num = opcode & 0xFFFFFF; // 8 bits if (func_num > 0xFF) { - ERROR_LOG(HLE,"unknown svc=0x%02X", func_num); + ERROR_LOG(HLE,"unknown svc=0x%02X", func_num); return nullptr; } return &g_module_db[0].func_table[func_num]; @@ -58,7 +58,7 @@ void RegisterAllModules() { void Init() { Service::Init(); - + RegisterAllModules(); NOTICE_LOG(HLE, "initialized OK"); diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index bf4d84575..4ab258c69 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 2b21657da..db571b895 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -25,22 +25,17 @@ public: std::string name; ///< Name of address arbiter object (optional) - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::OS); } }; //////////////////////////////////////////////////////////////////////////////////////////////////// /// Arbitrate an address -Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { +ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { switch (type) { // Signal thread(s) waiting for arbitrate address... @@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va default: ERROR_LOG(KERNEL, "unknown type=%d", type); - return -1; + return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage); } - return 0; + return RESULT_SUCCESS; } /// Create an address arbiter diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index a483fe466..8a5fb10b4 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -11,7 +11,7 @@ // Address arbiters are an underlying kernel synchronization object that can be created/used via // supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR // applications use them as an underlying mechanism to implement thread-safe barriers, events, and -// semphores. +// semphores. //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -28,7 +28,7 @@ enum class ArbitrationType : u32 { }; /// Arbitrate an address -Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); +ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); /// Create an address arbiter Handle CreateAddressArbiter(const std::string& name = "Unknown"); diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 764082d71..e273444c9 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp @@ -9,8 +9,9 @@ #include "core/file_sys/archive.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/directory.h" -#include "core/hle/service/service.h" #include "core/hle/kernel/archive.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -51,15 +52,10 @@ public: std::string name; ///< Name of archive (optional) FileSys::Archive* backend; ///< Archive backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); - + switch (cmd) { // Read from archive... case FileCommand::Read: @@ -99,7 +95,6 @@ public: case FileCommand::Close: { DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_object_pool.Destroy<Archive>(GetHandle()); CloseArchive(backend->GetIdCode()); break; } @@ -107,42 +102,32 @@ public: default: { ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - return -1; + return UnimplementedFunction(ErrorModule::FS); } } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; class File : public Object { public: std::string GetTypeName() const override { return "File"; } - std::string GetName() const override { return path; } + std::string GetName() const override { return path.DebugStr(); } static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } Kernel::HandleType GetHandleType() const override { return HandleType::File; } - std::string path; ///< Path of the file + FileSys::Path path; ///< Path of the file std::unique_ptr<FileSys::File> backend; ///< File backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -184,7 +169,8 @@ public: case FileCommand::SetSize: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); + DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", + GetTypeName().c_str(), GetName().c_str(), size); backend->SetSize(size); break; } @@ -199,42 +185,33 @@ public: // Unknown command... default: ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. - return -1; + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; class Directory : public Object { public: std::string GetTypeName() const override { return "Directory"; } - std::string GetName() const override { return path; } + std::string GetName() const override { return path.DebugStr(); } static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } - std::string path; ///< Path of the directory + FileSys::Path path; ///< Path of the directory std::unique_ptr<FileSys::Directory> backend; ///< File backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); switch (cmd) { @@ -244,8 +221,9 @@ public: { u32 count = cmd_buff[1]; u32 address = cmd_buff[3]; - FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); - DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); + auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); + DEBUG_LOG(KERNEL, "Read %s %s: count=%d", + GetTypeName().c_str(), GetName().c_str(), count); // Number of entries actually read cmd_buff[2] = backend->Read(count, entries); @@ -262,22 +240,18 @@ public: // Unknown command... default: ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. - return -1; + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; @@ -285,108 +259,124 @@ public: std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode -/** - * Opens an archive - * @param id_code IdCode of the archive to open - * @return Handle to archive if it exists, otherwise a null handle (0) - */ -Handle OpenArchive(FileSys::Archive::IdCode id_code) { +ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) { auto itr = g_archive_map.find(id_code); if (itr == g_archive_map.end()) { - return 0; + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); } - return itr->second; + + return MakeResult<Handle>(itr->second); } -/** - * Closes an archive - * @param id_code IdCode of the archive to open - * @return Result of operation, 0 on success, otherwise error code - */ -Result CloseArchive(FileSys::Archive::IdCode id_code) { - if (1 != g_archive_map.erase(id_code)) { - ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code); - return -1; +ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { + auto itr = g_archive_map.find(id_code); + if (itr == g_archive_map.end()) { + ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); + return InvalidHandle(ErrorModule::FS); } INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); - return 0; + return RESULT_SUCCESS; } /** * Mounts an archive * @param archive Pointer to the archive to mount - * @return Result of operation, 0 on success, otherwise error code */ -Result MountArchive(Archive* archive) { +ResultCode MountArchive(Archive* archive) { FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); - if (0 != OpenArchive(id_code)) { + ResultVal<Handle> archive_handle = OpenArchive(id_code); + if (archive_handle.Succeeded()) { ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); - return -1; + return archive_handle.Code(); } g_archive_map[id_code] = archive->GetHandle(); INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); - return 0; + return RESULT_SUCCESS; } -/** - * Creates an Archive - * @param handle Handle to newly created archive object - * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Newly created Archive object - */ -Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) { +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { Archive* archive = new Archive; - handle = Kernel::g_object_pool.Create(archive); + Handle handle = Kernel::g_object_pool.Create(archive); archive->name = name; archive->backend = backend; - MountArchive(archive); + ResultCode result = MountArchive(archive); + if (result.IsError()) { + return result; + } - return archive; + return RESULT_SUCCESS; } -/** - * Creates an Archive - * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Handle to newly created Archive object - */ -Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { - Handle handle; - CreateArchive(handle, backend, name); - return handle; -} +ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { + // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create + // the archive file handles at app loading, and then keep them persistent throughout execution. + // Archives file handles are just reused and not actually freed until emulation shut down. + // Verify if real hardware works this way, or if new handles are created each time + if (path.GetType() == FileSys::Binary) + // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend + // design. While the functionally of this is OK, our implementation decision to separate + // normal files from archive file pointers is very likely wrong. + // See https://github.com/citra-emu/citra/issues/205 + return MakeResult<Handle>(archive_handle); -/** - * Open a File from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the File inside of the Archive - * @param mode Mode under which to open the File - * @return Opened File object - */ -Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) { File* file = new File; Handle handle = Kernel::g_object_pool.Create(file); - Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } file->path = path; file->backend = archive->backend->OpenFile(path, mode); - if (!file->backend) + if (!file->backend) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); + } + + return MakeResult<Handle>(handle); +} + +/** + * Delete a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->DeleteFile(path)) return 0; + return -1; +} - return handle; +/** + * Delete a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->DeleteDirectory(path)) + return 0; + return -1; } /** * Create a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return Opened Directory object + * @return Whether creation succeeded */ -Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { +Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); if (archive == nullptr) return -1; @@ -401,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path * @param path Path to the Directory inside of the Archive * @return Opened Directory object */ -Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { +ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { Directory* directory = new Directory; Handle handle = Kernel::g_object_pool.Create(directory); - Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } directory->path = path; directory->backend = archive->backend->OpenDirectory(path); - return handle; + return MakeResult<Handle>(handle); } /// Initialize archives diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h index 0230996b6..6fc4f0f25 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/kernel/archive.h @@ -6,8 +6,9 @@ #include "common/common_types.h" -#include "core/hle/kernel/kernel.h" #include "core/file_sys/archive.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -17,33 +18,47 @@ namespace Kernel { /** * Opens an archive * @param id_code IdCode of the archive to open - * @return Handle to archive if it exists, otherwise a null handle (0) + * @return Handle to the opened archive */ -Handle OpenArchive(FileSys::Archive::IdCode id_code); +ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code); /** * Closes an archive * @param id_code IdCode of the archive to open - * @return true if it worked fine */ -Result CloseArchive(FileSys::Archive::IdCode id_code); +ResultCode CloseArchive(FileSys::Archive::IdCode id_code); /** * Creates an Archive * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Handle to newly created Archive object + * @param name Name of Archive */ -Handle CreateArchive(FileSys::Archive* backend, const std::string& name); +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); /** * Open a File from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the File inside of the Archive * @param mode Mode under which to open the File - * @return Opened File object + * @return Handle to the opened File object + */ +ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); + +/** + * Delete a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path); + +/** + * Delete a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded */ -Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode); +Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); /** * Create a Directory from an Archive @@ -51,15 +66,15 @@ Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const * @param path Path to the Directory inside of the Archive * @return Whether creation of directory succeeded */ -Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name); +Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); /** * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return Opened Directory object + * @return Handle to the opened File object */ -Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name); +ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); /// Initialize archives void ArchiveInit(); diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 45ed79be8..288080209 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <map> #include <algorithm> @@ -30,13 +30,8 @@ public: std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event std::string name; ///< Name of event (optional) - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { - *wait = locked; + ResultVal<bool> WaitSynchronization() override { + bool wait = locked; if (locked) { Handle thread = GetCurrentThreadHandle(); if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { @@ -47,7 +42,7 @@ public: if (reset_type != RESETTYPE_STICKY && !permanent_locked) { locked = true; } - return 0; + return MakeResult<bool>(wait); } }; @@ -57,12 +52,12 @@ public: * @param permanent_locked Boolean permanent locked value to set event * @return Result of operation, 0 on success, otherwise error code */ -Result SetPermanentLock(Handle handle, const bool permanent_locked) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); evt->permanent_locked = permanent_locked; - return 0; + return RESULT_SUCCESS; } /** @@ -71,14 +66,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) { * @param locked Boolean locked value to set event * @return Result of operation, 0 on success, otherwise error code */ -Result SetEventLocked(const Handle handle, const bool locked) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode SetEventLocked(const Handle handle, const bool locked) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!evt->permanent_locked) { evt->locked = locked; } - return 0; + return RESULT_SUCCESS; } /** @@ -86,16 +81,16 @@ Result SetEventLocked(const Handle handle, const bool locked) { * @param handle Handle to event to signal * @return Result of operation, 0 on success, otherwise error code */ -Result SignalEvent(const Handle handle) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode SignalEvent(const Handle handle) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); // Resume threads waiting for event to signal bool event_caught = false; for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { ResumeThreadFromWait( evt->waiting_threads[i]); - // If any thread is signalled awake by this event, assume the event was "caught" and reset + // If any thread is signalled awake by this event, assume the event was "caught" and reset // the event. This will result in the next thread waiting on the event to block. Otherwise, // the event will not be reset, and the next thread to call WaitSynchronization on it will // not block. Not sure if this is correct behavior, but it seems to work. @@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) { if (!evt->permanent_locked) { evt->locked = event_caught; } - return 0; + return RESULT_SUCCESS; } /** @@ -114,14 +109,14 @@ Result SignalEvent(const Handle handle) { * @param handle Handle to event to clear * @return Result of operation, 0 on success, otherwise error code */ -Result ClearEvent(Handle handle) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode ClearEvent(Handle handle) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!evt->permanent_locked) { evt->locked = true; } - return 0; + return RESULT_SUCCESS; } /** diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index c39b33180..73aec4e79 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -15,31 +15,27 @@ namespace Kernel { * Changes whether an event is locked or not * @param handle Handle to event to change * @param locked Boolean locked value to set event - * @return Result of operation, 0 on success, otherwise error code */ -Result SetEventLocked(const Handle handle, const bool locked); +ResultCode SetEventLocked(const Handle handle, const bool locked); /** * Hackish function to set an events permanent lock state, used to pass through synch blocks * @param handle Handle to event to change * @param permanent_locked Boolean permanent locked value to set event - * @return Result of operation, 0 on success, otherwise error code */ -Result SetPermanentLock(Handle handle, const bool permanent_locked); +ResultCode SetPermanentLock(Handle handle, const bool permanent_locked); /** * Signals an event * @param handle Handle to event to signal - * @return Result of operation, 0 on success, otherwise error code */ -Result SignalEvent(const Handle handle); +ResultCode SignalEvent(const Handle handle); /** * Clears an event * @param handle Handle to event to clear - * @return Result of operation, 0 on success, otherwise error code */ -Result ClearEvent(Handle handle); +ResultCode ClearEvent(Handle handle); /** * Creates an event diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 88cbc1af5..018000abd 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "common/common.h" @@ -68,7 +68,7 @@ void ObjectPool::List() { for (int i = 0; i < MAX_COUNT; i++) { if (occupied[i]) { if (pool[i]) { - INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), + INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), pool[i]->GetName().c_str()); } } @@ -110,7 +110,7 @@ void Shutdown() { */ bool LoadExec(u32 entry_point) { Init(); - + Core::g_app_core->SetPC(entry_point); // 0x30 is the typical main thread priority I've seen used so far diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 867d1b89c..8d3937ce8 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -1,12 +1,13 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once #include <array> #include <string> #include "common/common.h" +#include "core/hle/result.h" typedef u32 Handle; typedef s32 Result; @@ -34,7 +35,7 @@ enum class HandleType : u32 { Archive = 12, Directory = 13, }; - + enum { DEFAULT_STACK_SIZE = 0x4000, }; @@ -52,21 +53,19 @@ public: virtual Kernel::HandleType GetHandleType() const = 0; /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code + * Synchronize kernel object. + * @return True if the current thread should wait as a result of the sync */ - virtual Result SyncRequest(bool* wait) { + virtual ResultVal<bool> SyncRequest() { ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); - return -1; + return UnimplementedFunction(ErrorModule::Kernel); } /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code + * Wait for kernel object to synchronize. + * @return True if the current thread should wait as a result of the wait */ - virtual Result WaitSynchronization(bool* wait) = 0; + virtual ResultVal<bool> WaitSynchronization() = 0; }; class ObjectPool : NonCopyable { @@ -80,38 +79,29 @@ public: static Object* CreateByIDType(int type); template <class T> - u32 Destroy(Handle handle) { - u32 error; - if (Get<T>(handle, error)) { + void Destroy(Handle handle) { + if (Get<T>(handle)) { occupied[handle - HANDLE_OFFSET] = false; delete pool[handle - HANDLE_OFFSET]; } - return error; - }; + } bool IsValid(Handle handle); template <class T> - T* Get(Handle handle, u32& outError) { + T* Get(Handle handle) { if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { - // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP - if (handle != 0 && (u32)handle != 0x80020001) { + if (handle != 0) { WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); } - outError = 0;//T::GetMissingErrorCode(); - return 0; + return nullptr; } else { - // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, - // it just acted as a static case and everything worked. This means that we will never - // see the Wrong type object error below, but we'll just have to live with that danger. - T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]); - if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) { + Object* t = pool[handle - HANDLE_OFFSET]; + if (t->GetHandleType() != T::GetStaticHandleType()) { WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); - outError = 0;//T::GetMissingErrorCode(); - return 0; + return nullptr; } - outError = 0;//SCE_KERNEL_ERROR_OK; - return t; + return static_cast<T*>(t); } } @@ -139,7 +129,7 @@ public: } bool GetIDType(Handle handle, HandleType* type) const { - if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || + if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || !occupied[handle - HANDLE_OFFSET]) { ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); return false; @@ -155,7 +145,7 @@ public: int GetCount(); private: - + enum { MAX_COUNT = 0x1000, HANDLE_OFFSET = 0x100, diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index fcfd061ac..d07e9761b 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <map> #include <vector> @@ -27,31 +27,20 @@ public: std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex std::string name; ///< Name of mutex (optional) - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { // TODO(bunnei): ImplementMe locked = true; - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe - *wait = locked; - + bool wait = locked; if (locked) { Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); } - return 0; + return MakeResult<bool>(wait); } }; @@ -99,35 +88,36 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { bool ReleaseMutex(Mutex* mutex) { MutexEraseLock(mutex); - bool woke_threads = false; // Find the next waiting thread for the mutex... - while (!woke_threads && !mutex->waiting_threads.empty()) { + while (!mutex->waiting_threads.empty()) { std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); - woke_threads |= ReleaseMutexForThread(mutex, *iter); + ReleaseMutexForThread(mutex, *iter); mutex->waiting_threads.erase(iter); } + // Reset mutex lock thread handle, nothing is waiting - if (!woke_threads) { - mutex->locked = false; - mutex->lock_thread = -1; - } - return woke_threads; + mutex->locked = false; + mutex->lock_thread = -1; + + return true; } /** * Releases a mutex * @param handle Handle to mutex to release */ -Result ReleaseMutex(Handle handle) { - Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); - - _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!"); +ResultCode ReleaseMutex(Handle handle) { + Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle); + if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!ReleaseMutex(mutex)) { - return -1; + // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure + // what error condition this is supposed to be signaling. + return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, + ErrorSummary::NothingHappened, ErrorLevel::Temporary); } - return 0; + return RESULT_SUCCESS; } /** diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 7d7b5137e..155449f95 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -13,9 +13,8 @@ namespace Kernel { /** * Releases a mutex * @param handle Handle to mutex to release - * @return Result of operation, 0 on success, otherwise error code */ -Result ReleaseMutex(Handle handle); +ResultCode ReleaseMutex(Handle handle); /** * Creates a mutex diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index f538c6550..cfcc0e0b7 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "common/common.h" @@ -16,15 +16,10 @@ public: static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::OS); } u32 base_address; ///< Address of shared memory block in RAM @@ -48,11 +43,6 @@ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { return shared_memory; } -/** - * Creates a shared memory object - * @param name Optional name of shared memory object - * @return Handle of newly created shared memory object - */ Handle CreateSharedMemory(const std::string& name) { Handle handle; CreateSharedMemory(handle, name); @@ -67,39 +57,36 @@ Handle CreateSharedMemory(const std::string& name) { * @param other_permissions Memory block map other permissions (specified by SVC field) * @return Result of operation, 0 on success, otherwise error code */ -Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, +ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, MemoryPermission other_permissions) { if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", handle, address); - return -1; + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, + ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } - SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); - _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); + SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); + if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); shared_memory->base_address = address; shared_memory->permissions = permissions; shared_memory->other_permissions = other_permissions; - return 0; + return RESULT_SUCCESS; } -/** - * Gets a pointer to the shared memory block - * @param handle Shared memory block handle - * @param offset Offset from the start of the shared memory block to get pointer - * @return Pointer to the shared memory block from the specified offset - */ -u8* GetSharedMemoryPointer(Handle handle, u32 offset) { - SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); - _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); +ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { + SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); + if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); if (0 != shared_memory->base_address) - return Memory::GetPointer(shared_memory->base_address + offset); + return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); - return nullptr; + // TODO(yuriks): Verify error code. + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, + ErrorSummary::InvalidState, ErrorLevel::Permanent); } } // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 5312b8854..304cf5b67 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -32,9 +32,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown"); * @param address Address in system memory to map shared memory block to * @param permissions Memory block map permissions (specified by SVC field) * @param other_permissions Memory block map other permissions (specified by SVC field) - * @return Result of operation, 0 on success, otherwise error code */ -Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, +ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, MemoryPermission other_permissions); /** @@ -43,6 +42,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, * @param offset Offset from the start of the shared memory block to get pointer * @return Pointer to the shared memory block from the specified offset */ -u8* GetSharedMemoryPointer(Handle handle, u32 offset); +ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); } // namespace diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e15590c49..f59795901 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <algorithm> #include <list> @@ -11,10 +11,11 @@ #include "common/thread_queue_list.h" #include "core/core.h" -#include "core/mem_map.h" #include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" +#include "core/hle/result.h" +#include "core/mem_map.h" namespace Kernel { @@ -33,21 +34,17 @@ public: inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { - if (status != THREADSTATUS_DORMANT) { + ResultVal<bool> WaitSynchronization() override { + const bool wait = status != THREADSTATUS_DORMANT; + if (wait) { Handle thread = GetCurrentThreadHandle(); if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { waiting_threads.push_back(thread); } WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); - *wait = true; } - return 0; + + return MakeResult<bool>(wait); } ThreadContext context; @@ -71,17 +68,17 @@ public: }; // Lists all thread ids that aren't deleted/etc. -std::vector<Handle> g_thread_queue; +static std::vector<Handle> thread_queue; // Lists only ready thread ids. -Common::ThreadQueueList<Handle> g_thread_ready_queue; +static Common::ThreadQueueList<Handle> thread_ready_queue; -Handle g_current_thread_handle; -Thread* g_current_thread; +static Handle current_thread_handle; +static Thread* current_thread; /// Gets the current thread inline Thread* GetCurrentThread() { - return g_current_thread; + return current_thread; } /// Gets the current thread handle @@ -91,8 +88,8 @@ Handle GetCurrentThreadHandle() { /// Sets the current thread inline void SetCurrentThread(Thread* t) { - g_current_thread = t; - g_current_thread_handle = t->GetHandle(); + current_thread = t; + current_thread_handle = t->GetHandle(); } /// Saves the current CPU context @@ -113,7 +110,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { t->context.pc = t->context.reg_15 = t->entry_point; t->context.sp = t->stack_top; t->context.cpsr = 0x1F; // Usermode - + // TODO(bunnei): This instructs the CPU core to start the execution as if it is "resuming" a // thread. This is somewhat Sky-Eye specific, and should be re-architected in the future to be // agnostic of the CPU core. @@ -131,40 +128,35 @@ void ChangeReadyState(Thread* t, bool ready) { Handle handle = t->GetHandle(); if (t->IsReady()) { if (!ready) { - g_thread_ready_queue.remove(t->current_priority, handle); + thread_ready_queue.remove(t->current_priority, handle); } } else if (ready) { if (t->IsRunning()) { - g_thread_ready_queue.push_front(t->current_priority, handle); + thread_ready_queue.push_front(t->current_priority, handle); } else { - g_thread_ready_queue.push_back(t->current_priority, handle); + thread_ready_queue.push_back(t->current_priority, handle); } t->status = THREADSTATUS_READY; } } /// Verify that a thread has not been released from waiting -inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { - Thread* thread = g_object_pool.GetFast<Thread>(handle); - _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); - - if (type != thread->wait_type || wait_handle != thread->wait_handle) - return false; - - return true; +inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { + _dbg_assert_(KERNEL, thread != nullptr); + return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting()); } /// Stops the current thread -void StopThread(Handle handle, const char* reason) { - Thread* thread = g_object_pool.GetFast<Thread>(handle); - _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); - +ResultCode StopThread(Handle handle, const char* reason) { + Thread* thread = g_object_pool.Get<Thread>(handle); + if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); + ChangeReadyState(thread, false); thread->status = THREADSTATUS_DORMANT; - for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { - const Handle waiting_thread = thread->waiting_threads[i]; + for (Handle waiting_handle : thread->waiting_threads) { + Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { - ResumeThreadFromWait(waiting_thread); + ResumeThreadFromWait(waiting_handle); } } thread->waiting_threads.clear(); @@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) { // Stopped threads are never waiting. thread->wait_type = WAITTYPE_NONE; thread->wait_handle = 0; + + return RESULT_SUCCESS; } /// Changes a threads state @@ -181,7 +175,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { } ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); t->status = new_status; - + if (new_status == THREADSTATUS_WAIT) { if (t->wait_type == WAITTYPE_NONE) { ERROR_LOG(KERNEL, "Waittype none not allowed"); @@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { s32 priority = THREADPRIO_LOWEST; // Iterate through threads, find highest priority thread that is waiting to be arbitrated... - for (const auto& handle : g_thread_queue) { + for (Handle handle : thread_queue) { + Thread* thread = g_object_pool.Get<Thread>(handle); // TODO(bunnei): Verify arbiter address... - if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) + if (!VerifyWait(thread, WAITTYPE_ARB, arbiter)) continue; - Thread* thread = g_object_pool.GetFast<Thread>(handle); + if (thread == nullptr) + continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. if(thread->current_priority <= priority) { highest_priority_thread = handle; priority = thread->current_priority; @@ -216,12 +212,13 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { /// Arbitrate all threads currently waiting void ArbitrateAllThreads(u32 arbiter, u32 address) { - + // Iterate through threads, find highest priority thread that is waiting to be arbitrated... - for (const auto& handle : g_thread_queue) { + for (Handle handle : thread_queue) { + Thread* thread = g_object_pool.Get<Thread>(handle); // TODO(bunnei): Verify arbiter address... - if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) + if (VerifyWait(thread, WAITTYPE_ARB, arbiter)) ResumeThreadFromWait(handle); } } @@ -238,11 +235,11 @@ void CallThread(Thread* t) { /// Switches CPU context to that of the specified thread void SwitchContext(Thread* t) { Thread* cur = GetCurrentThread(); - + // Save context for current thread if (cur) { SaveContext(cur->context); - + if (cur->IsRunning()) { ChangeReadyState(cur, true); } @@ -263,16 +260,16 @@ void SwitchContext(Thread* t) { Thread* NextThread() { Handle next; Thread* cur = GetCurrentThread(); - + if (cur && cur->IsRunning()) { - next = g_thread_ready_queue.pop_first_better(cur->current_priority); + next = thread_ready_queue.pop_first_better(cur->current_priority); } else { - next = g_thread_ready_queue.pop_first(); + next = thread_ready_queue.pop_first(); } if (next == 0) { return nullptr; } - return Kernel::g_object_pool.GetFast<Thread>(next); + return Kernel::g_object_pool.Get<Thread>(next); } /** @@ -289,8 +286,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle) { - u32 error; - Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error); + Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); if (thread) { thread->status &= ~THREADSTATUS_WAIT; if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { @@ -306,9 +302,9 @@ void DebugThreadQueue() { return; } INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); - for (u32 i = 0; i < g_thread_queue.size(); i++) { - Handle handle = g_thread_queue[i]; - s32 priority = g_thread_ready_queue.contains(handle); + for (u32 i = 0; i < thread_queue.size(); i++) { + Handle handle = thread_queue[i]; + s32 priority = thread_ready_queue.contains(handle); if (priority != -1) { INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); } @@ -319,15 +315,15 @@ void DebugThreadQueue() { Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { - _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), + _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), "CreateThread priority=%d, outside of allowable range!", priority) Thread* thread = new Thread; handle = Kernel::g_object_pool.Create(thread); - g_thread_queue.push_back(handle); - g_thread_ready_queue.prepare(priority); + thread_queue.push_back(handle); + thread_ready_queue.prepare(priority); thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; @@ -351,7 +347,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 return -1; } if ((u32)stack_size < 0x200) { - ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, + ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, stack_size); return -1; } @@ -368,7 +364,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 return -1; } Handle handle; - Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, + Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, stack_size); ResetThread(thread, arg, 0); @@ -378,19 +374,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 } /// Get the priority of the thread specified by handle -u32 GetThreadPriority(const Handle handle) { - Thread* thread = g_object_pool.GetFast<Thread>(handle); - _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); - return thread->current_priority; +ResultVal<u32> GetThreadPriority(const Handle handle) { + Thread* thread = g_object_pool.Get<Thread>(handle); + if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); + + return MakeResult<u32>(thread->current_priority); } /// Set the priority of the thread specified by handle -Result SetThreadPriority(Handle handle, s32 priority) { +ResultCode SetThreadPriority(Handle handle, s32 priority) { Thread* thread = nullptr; if (!handle) { thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? } else { - thread = g_object_pool.GetFast<Thread>(handle); + thread = g_object_pool.Get<Thread>(handle); + if (thread == nullptr) { + return InvalidHandle(ErrorModule::Kernel); + } } _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); @@ -405,37 +405,37 @@ Result SetThreadPriority(Handle handle, s32 priority) { // Change thread priority s32 old = thread->current_priority; - g_thread_ready_queue.remove(old, handle); + thread_ready_queue.remove(old, handle); thread->current_priority = priority; - g_thread_ready_queue.prepare(thread->current_priority); + thread_ready_queue.prepare(thread->current_priority); // Change thread status to "ready" and push to ready queue if (thread->IsRunning()) { thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; } if (thread->IsReady()) { - g_thread_ready_queue.push_back(thread->current_priority, handle); + thread_ready_queue.push_back(thread->current_priority, handle); } - return 0; + return RESULT_SUCCESS; } /// Sets up the primary application thread Handle SetupMainThread(s32 priority, int stack_size) { Handle handle; - + // Initialize new "main" thread - Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, + Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); - + ResetThread(thread, 0, 0); - + // If running another thread already, set it to "ready" state Thread* cur = GetCurrentThread(); if (cur && cur->IsRunning()) { ChangeReadyState(cur, true); } - + // Run new "main" thread SetCurrentThread(thread); thread->status = THREADSTATUS_RUNNING; @@ -452,12 +452,12 @@ void Reschedule() { HLE::g_reschedule = false; if (next > 0) { INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); - + SwitchContext(next); // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. - // This results in the current thread yielding on a VBLANK once, and then it will be + // This results in the current thread yielding on a VBLANK once, and then it will be // immediately placed back in the queue for execution. if (prev->wait_type == WAITTYPE_VBLANK) { ResumeThreadFromWait(prev->GetHandle()); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 39fa38b75..ce63a70d3 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -1,11 +1,12 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" enum ThreadPriority { THREADPRIO_HIGHEST = 0, ///< Highest thread priority @@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); void Reschedule(); /// Stops the current thread -void StopThread(Handle thread, const char* reason); +ResultCode StopThread(Handle thread, const char* reason); /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle); @@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa void WaitThread_Synchronization(); /// Get the priority of the thread specified by handle -u32 GetThreadPriority(const Handle handle); +ResultVal<u32> GetThreadPriority(const Handle handle); /// Set the priority of the thread specified by handle -Result SetThreadPriority(Handle handle, s32 priority); +ResultCode SetThreadPriority(Handle handle, s32 priority); /// Initialize threading void ThreadingInit(); diff --git a/src/core/hle/result.h b/src/core/hle/result.h new file mode 100644 index 000000000..15c4a2677 --- /dev/null +++ b/src/core/hle/result.h @@ -0,0 +1,400 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <cassert> +#include <cstddef> +#include <type_traits> +#include <utility> + +#include "common/common_types.h" +#include "common/bit_field.h" + +// All the constants in this file come from http://3dbrew.org/wiki/Error_codes + +/// Detailed description of the error. This listing is likely incomplete. +enum class ErrorDescription : u32 { + Success = 0, + InvalidSection = 1000, + TooLarge = 1001, + NotAuthorized = 1002, + AlreadyDone = 1003, + InvalidSize = 1004, + InvalidEnumValue = 1005, + InvalidCombination = 1006, + NoData = 1007, + Busy = 1008, + MisalignedAddress = 1009, + MisalignedSize = 1010, + OutOfMemory = 1011, + NotImplemented = 1012, + InvalidAddress = 1013, + InvalidPointer = 1014, + InvalidHandle = 1015, + NotInitialized = 1016, + AlreadyInitialized = 1017, + NotFound = 1018, + CancelRequested = 1019, + AlreadyExists = 1020, + OutOfRange = 1021, + Timeout = 1022, + InvalidResultValue = 1023, +}; + +/** + * Identifies the module which caused the error. Error codes can be propagated through a call + * chain, meaning that this doesn't always correspond to the module where the API call made is + * contained. + */ +enum class ErrorModule : u32 { + Common = 0, + Kernel = 1, + Util = 2, + FileServer = 3, + LoaderServer = 4, + TCB = 5, + OS = 6, + DBG = 7, + DMNT = 8, + PDN = 9, + GX = 10, + I2C = 11, + GPIO = 12, + DD = 13, + CODEC = 14, + SPI = 15, + PXI = 16, + FS = 17, + DI = 18, + HID = 19, + CAM = 20, + PI = 21, + PM = 22, + PM_LOW = 23, + FSI = 24, + SRV = 25, + NDM = 26, + NWM = 27, + SOC = 28, + LDR = 29, + ACC = 30, + RomFS = 31, + AM = 32, + HIO = 33, + Updater = 34, + MIC = 35, + FND = 36, + MP = 37, + MPWL = 38, + AC = 39, + HTTP = 40, + DSP = 41, + SND = 42, + DLP = 43, + HIO_LOW = 44, + CSND = 45, + SSL = 46, + AM_LOW = 47, + NEX = 48, + Friends = 49, + RDT = 50, + Applet = 51, + NIM = 52, + PTM = 53, + MIDI = 54, + MC = 55, + SWC = 56, + FatFS = 57, + NGC = 58, + CARD = 59, + CARDNOR = 60, + SDMC = 61, + BOSS = 62, + DBM = 63, + Config = 64, + PS = 65, + CEC = 66, + IR = 67, + UDS = 68, + PL = 69, + CUP = 70, + Gyroscope = 71, + MCU = 72, + NS = 73, + News = 74, + RO_1 = 75, + GD = 76, + CardSPI = 77, + EC = 78, + RO_2 = 79, + WebBrowser = 80, + Test = 81, + ENC = 82, + PIA = 83, + + Application = 254, + InvalidResult = 255 +}; + +/// A less specific error cause. +enum class ErrorSummary : u32 { + Success = 0, + NothingHappened = 1, + WouldBlock = 2, + OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to + ///< execute the operation. + NotFound = 4, ///< A file or resource was not found. + InvalidState = 5, + NotSupported = 6, ///< The operation is not supported or not implemented. + InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime + ///< context. (Invalid handle, out-of-bounds pointer or size, etc.) + WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use + ///< with the function. (E.g. Invalid enum value) + Canceled = 9, + StatusChanged = 10, + Internal = 11, + + InvalidResult = 63 +}; + +/// The severity of the error. +enum class ErrorLevel : u32 { + Success = 0, + Info = 1, + + Status = 25, + Temporary = 26, + Permanent = 27, + Usage = 28, + Reinitialize = 29, + Reset = 30, + Fatal = 31 +}; + +/// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields. +union ResultCode { + u32 raw; + + BitField<0, 10, ErrorDescription> description; + BitField<10, 8, ErrorModule> module; + + BitField<21, 6, ErrorSummary> summary; + BitField<27, 5, ErrorLevel> level; + + // The last bit of `level` is checked by apps and the kernel to determine if a result code is an error + BitField<31, 1, u32> is_error; + + explicit ResultCode(u32 raw) : raw(raw) {} + ResultCode(ErrorDescription description_, ErrorModule module_, + ErrorSummary summary_, ErrorLevel level_) : raw(0) { + description = description_; + module = module_; + summary = summary_; + level = level_; + } + + ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; } + + bool IsSuccess() const { + return is_error == 0; + } + + bool IsError() const { + return is_error == 1; + } +}; + +inline bool operator==(const ResultCode a, const ResultCode b) { + return a.raw == b.raw; +} + +inline bool operator!=(const ResultCode a, const ResultCode b) { + return a.raw != b.raw; +} + +// Convenience functions for creating some common kinds of errors: + +/// The default success `ResultCode`. +const ResultCode RESULT_SUCCESS(0); + +/// Might be returned instead of a dummy success for unimplemented APIs. +inline ResultCode UnimplementedFunction(ErrorModule module) { + return ResultCode(ErrorDescription::NotImplemented, module, + ErrorSummary::NotSupported, ErrorLevel::Permanent); +} +/// Returned when a function is passed an invalid handle. +inline ResultCode InvalidHandle(ErrorModule module) { + return ResultCode(ErrorDescription::InvalidHandle, module, + ErrorSummary::InvalidArgument, ErrorLevel::Permanent); +} + +/** + * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, + * also holds a result of type `T`. If the code is an error code then trying to access the inner + * value fails, thus ensuring that the ResultCode of functions is always checked properly before + * their return value is used. It is similar in concept to the `std::optional` type + * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in + * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html). + * + * An example of how it could be used: + * \code + * ResultVal<int> Frobnicate(float strength) { + * if (strength < 0.f || strength > 1.0f) { + * // Can't frobnicate too weakly or too strongly + * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common, + * ErrorSummary::InvalidArgument, ErrorLevel::Permanent); + * } else { + * // Frobnicated! Give caller a cookie + * return MakeResult<int>(42); + * } + * } + * \endcode + * + * \code + * ResultVal<int> frob_result = Frobnicate(0.75f); + * if (frob_result) { + * // Frobbed ok + * printf("My cookie is %d\n", *frob_result); + * } else { + * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex); + * } + * \endcode + */ +template <typename T> +class ResultVal { +public: + /// Constructs an empty `ResultVal` with the given error code. The code must not be a success code. + ResultVal(ResultCode error_code = ResultCode(-1)) + : result_code(error_code) + { + assert(error_code.IsError()); + UpdateDebugPtr(); + } + + /** + * Similar to the non-member function `MakeResult`, with the exception that you can manually + * specify the success code. `success_code` must not be an error code. + */ + template <typename... Args> + static ResultVal WithCode(ResultCode success_code, Args&&... args) { + ResultVal<T> result; + result.emplace(success_code, std::forward<Args>(args)...); + return result; + } + + ResultVal(const ResultVal& o) + : result_code(o.result_code) + { + if (!o.empty()) { + new (&storage) T(*o.GetPointer()); + } + UpdateDebugPtr(); + } + + ResultVal(ResultVal&& o) + : result_code(o.result_code) + { + if (!o.empty()) { + new (&storage) T(std::move(*o.GetPointer())); + } + UpdateDebugPtr(); + } + + ~ResultVal() { + if (!empty()) { + GetPointer()->~T(); + } + } + + ResultVal& operator=(const ResultVal& o) { + if (*this) { + if (o) { + *GetPointer() = *o.GetPointer(); + } else { + GetPointer()->~T(); + } + } else { + if (o) { + new (&storage) T(*o.GetPointer()); + } + } + result_code = o.result_code; + UpdateDebugPtr(); + + return *this; + } + + /** + * Replaces the current result with a new constructed result value in-place. The code must not + * be an error code. + */ + template <typename... Args> + void emplace(ResultCode success_code, Args&&... args) { + assert(success_code.IsSuccess()); + if (!empty()) { + GetPointer()->~T(); + } + new (&storage) T(std::forward<Args>(args)...); + result_code = success_code; + UpdateDebugPtr(); + } + + /// Returns true if the `ResultVal` contains an error code and no value. + bool empty() const { return result_code.IsError(); } + + /// Returns true if the `ResultVal` contains a return value. + bool Succeeded() const { return result_code.IsSuccess(); } + /// Returns true if the `ResultVal` contains an error code and no value. + bool Failed() const { return empty(); } + + ResultCode Code() const { return result_code; } + + const T& operator* () const { return *GetPointer(); } + T& operator* () { return *GetPointer(); } + const T* operator->() const { return GetPointer(); } + T* operator->() { return GetPointer(); } + + /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. + template <typename U> + T ValueOr(U&& value) const { + return !empty() ? *GetPointer() : std::move(value); + } + +private: + typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; + + StorageType storage; + ResultCode result_code; +#if _DEBUG + // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the + // need to cast `storage` to a pointer or pay attention to `result_code`. + const T* debug_ptr; +#endif + + void UpdateDebugPtr() { +#if _DEBUG + debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage)); +#endif + } + + const T* GetPointer() const { + assert(!empty()); + return static_cast<const T*>(static_cast<const void*>(&storage)); + } + + T* GetPointer() { + assert(!empty()); + return static_cast<T*>(static_cast<void*>(&storage)); + } +}; + +/** + * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct + * `T` with and creates a success `ResultVal` contained the constructed value. + */ +template <typename T, typename... Args> +ResultVal<T> MakeResult(Args&&... args) { + return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); +} diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp index b39603bdf..9af96f6b8 100644 --- a/src/core/hle/service/ac_u.cpp +++ b/src/core/hle/service/ac_u.cpp @@ -22,12 +22,12 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000E0042, nullptr, "GetCurrentAPInfo"}, {0x00100042, nullptr, "GetCurrentNZoneInfo"}, {0x00110042, nullptr, "GetNZoneApNumService"}, - {0x00240042, nullptr, "AddDenyApType "}, - {0x00270002, nullptr, "GetInfraPriority "}, + {0x00240042, nullptr, "AddDenyApType"}, + {0x00270002, nullptr, "GetInfraPriority"}, {0x002D0082, nullptr, "SetRequestEulaVersion"}, {0x00300004, nullptr, "RegisterDisconnectEvent"}, {0x003C0042, nullptr, "GetAPSSIDList"}, - {0x003E0042, nullptr, "IsConnected "}, + {0x003E0042, nullptr, "IsConnected"}, {0x00400042, nullptr, "SetClientVersion"}, }; diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h index 3c5958d27..c91b28353 100644 --- a/src/core/hle/service/ac_u.h +++ b/src/core/hle/service/ac_u.h @@ -9,7 +9,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace AC_U -// socket service "ac:u" +// socket service "ac:u" namespace AC_U { @@ -21,7 +21,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "ac:u"; } }; diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am_net.cpp new file mode 100644 index 000000000..403cac353 --- /dev/null +++ b/src/core/hle/service/am_net.cpp @@ -0,0 +1,47 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/am_net.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace AM_NET + +namespace AM_NET { + +const Interface::FunctionInfo FunctionTable[] = { + {0x08010000, nullptr, "OpenTicket"}, + {0x08020002, nullptr, "TicketAbortInstall"}, + {0x08030002, nullptr, "TicketFinalizeInstall"}, + {0x08040100, nullptr, "InstallTitleBegin"}, + {0x08050000, nullptr, "InstallTitleAbort"}, + {0x080600C0, nullptr, "InstallTitleResume"}, + {0x08070000, nullptr, "InstallTitleAbortTMD"}, + {0x08080000, nullptr, "InstallTitleFinish"}, + {0x080A0000, nullptr, "OpenTMD"}, + {0x080B0002, nullptr, "TMDAbortInstall"}, + {0x080C0042, nullptr, "TMDFinalizeInstall"}, + {0x080E0040, nullptr, "OpenContentCreate"}, + {0x080F0002, nullptr, "ContentAbortInstall"}, + {0x08100040, nullptr, "OpenContentResume"}, + {0x08120002, nullptr, "ContentFinalizeInstall"}, + {0x08130000, nullptr, "GetTotalContents"}, + {0x08140042, nullptr, "GetContentIndexes"}, + {0x08150044, nullptr, "GetContentsInfo"}, + {0x08190108, nullptr, "Unknown"}, + {0x081B00C2, nullptr, "InstallTitlesFinish"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h new file mode 100644 index 000000000..4816e1697 --- /dev/null +++ b/src/core/hle/service/am_net.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace AM_NET + +namespace AM_NET { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "am:net"; + } +}; + +} // namespace diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp index 4f41ec5f4..4bb05ce40 100644 --- a/src/core/hle/service/apt_u.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -27,7 +27,7 @@ enum class SignalType : u32 { void Initialize(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); - + cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle @@ -168,7 +168,7 @@ void AppletUtility(Service::Interface* self) { cmd_buff[1] = 0; // No error WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " - "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, + "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr); } diff --git a/src/core/hle/service/apt_u.h b/src/core/hle/service/apt_u.h index 5af39e085..306730400 100644 --- a/src/core/hle/service/apt_u.h +++ b/src/core/hle/service/apt_u.h @@ -13,8 +13,8 @@ namespace APT_U { // Application and title launching service. These services handle signaling for home/power button as // well. Only one session for either APT service can be open at a time, normally processes close the -// service handle immediately once finished using the service. The commands for APT:U and APT:S are -// exactly the same, however certain commands are only accessible with APT:S(NS module will call +// service handle immediately once finished using the service. The commands for APT:U and APT:S are +// exactly the same, however certain commands are only accessible with APT:S(NS module will call // svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. /// Interface to "APT:U" service diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp new file mode 100644 index 000000000..b2ff4a756 --- /dev/null +++ b/src/core/hle/service/boss_u.cpp @@ -0,0 +1,28 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/boss_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace BOSS_U + +namespace BOSS_U { + + const Interface::FunctionInfo FunctionTable[] = { + {0x00020100, nullptr, "GetStorageInfo"}, + }; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Interface class + + Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + } + + Interface::~Interface() { + } + +} // namespace diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h new file mode 100644 index 000000000..af39b8e65 --- /dev/null +++ b/src/core/hle/service/boss_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace BOSS_U + +namespace BOSS_U { + + class Interface : public Service::Interface { + public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "boss:U"; + } + }; + +} // namespace diff --git a/src/core/hle/service/cfg_i.cpp b/src/core/hle/service/cfg_i.cpp new file mode 100644 index 000000000..88d13d459 --- /dev/null +++ b/src/core/hle/service/cfg_i.cpp @@ -0,0 +1,59 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/cfg_i.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CFG_I + +namespace CFG_I { + +const Interface::FunctionInfo FunctionTable[] = { + {0x04010082, nullptr, "GetConfigInfoBlk8"}, + {0x04020082, nullptr, "GetConfigInfoBlk4"}, + {0x04030000, nullptr, "UpdateConfigNANDSavegame"}, + {0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, + {0x04050000, nullptr, "GetLocalFriendCodeSeed"}, + {0x04060000, nullptr, "SecureInfoGetRegion"}, + {0x04070000, nullptr, "SecureInfoGetByte101"}, + {0x04080042, nullptr, "SecureInfoGetSerialNo"}, + {0x04090000, nullptr, "UpdateConfigBlk00040003"}, + {0x08010082, nullptr, "GetConfigInfoBlk8"}, + {0x08020082, nullptr, "GetConfigInfoBlk4"}, + {0x08030000, nullptr, "UpdateConfigNANDSavegame"}, + {0x080400C2, nullptr, "CreateConfigInfoBlk"}, + {0x08050000, nullptr, "DeleteConfigNANDSavefile"}, + {0x08060000, nullptr, "FormatConfig"}, + {0x08070000, nullptr, "Unknown"}, + {0x08080000, nullptr, "UpdateConfigBlk1"}, + {0x08090000, nullptr, "UpdateConfigBlk2"}, + {0x080A0000, nullptr, "UpdateConfigBlk3"}, + {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"}, + {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"}, + {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"}, + {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"}, + {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"}, + {0x08100000, nullptr, "GetLocalFriendCodeSeed"}, + {0x08110084, nullptr, "SetSecureInfo"}, + {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"}, + {0x08130000, nullptr, "VerifySigSecureInfo"}, + {0x08140042, nullptr, "SecureInfoGetData"}, + {0x08150042, nullptr, "SecureInfoGetSignature"}, + {0x08160000, nullptr, "SecureInfoGetRegion"}, + {0x08170000, nullptr, "SecureInfoGetByte101"}, + {0x08180042, nullptr, "SecureInfoGetSerialNo"}, +}; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/cfg_i.h b/src/core/hle/service/cfg_i.h new file mode 100644 index 000000000..fe343c968 --- /dev/null +++ b/src/core/hle/service/cfg_i.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CFG_I + +namespace CFG_I { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "cfg:i"; + } +}; + +} // namespace diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h index 7525bd7c6..8075d19a8 100644 --- a/src/core/hle/service/cfg_u.h +++ b/src/core/hle/service/cfg_u.h @@ -19,7 +19,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "cfg:u"; } }; diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp new file mode 100644 index 000000000..6e59a9bf3 --- /dev/null +++ b/src/core/hle/service/csnd_snd.cpp @@ -0,0 +1,39 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/csnd_snd.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CSND_SND + +namespace CSND_SND { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010140, nullptr, "Initialize"}, + {0x00020000, nullptr, "Shutdown"}, + {0x00030040, nullptr, "Unknown"}, + {0x00040080, nullptr, "Unknown"}, + {0x00050000, nullptr, "Unknown"}, + {0x00060000, nullptr, "Unknown"}, + {0x00070000, nullptr, "Unknown"}, + {0x00080040, nullptr, "Unknown"}, + {0x00090082, nullptr, "FlushDCache"}, + {0x000A0082, nullptr, "StoreDCache"}, + {0x000B0082, nullptr, "InvalidateDCache"}, + {0x000C0000, nullptr, "Unknown"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h new file mode 100644 index 000000000..31cc85b07 --- /dev/null +++ b/src/core/hle/service/csnd_snd.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CSND_SND + +namespace CSND_SND { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "csnd:SND"; + } +}; + +} // namespace diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 9e84ac938..bbcf26f61 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -26,12 +26,12 @@ const Interface::FunctionInfo FunctionTable[] = { {0x001100C2, nullptr, "LoadComponent"}, {0x00120000, nullptr, "UnloadComponent"}, {0x00130082, nullptr, "FlushDataCache"}, - {0x00140082, nullptr, "InvalidateDCache "}, + {0x00140082, nullptr, "InvalidateDCache"}, {0x00150082, nullptr, "RegisterInterruptEvents"}, {0x00160000, nullptr, "GetSemaphoreEventHandle"}, {0x00170040, nullptr, "SetSemaphoreMask"}, {0x00180040, nullptr, "GetPhysicalAddress"}, - {0x00190040, nullptr, "GetVirtualAddress" }, + {0x00190040, nullptr, "GetVirtualAddress"}, {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, {0x001C0082, nullptr, "SetIirFilterEQ"}, diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h index c439ed266..c4ce44245 100644 --- a/src/core/hle/service/dsp_dsp.h +++ b/src/core/hle/service/dsp_dsp.h @@ -19,7 +19,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "dsp:DSP"; } }; diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp index 917b2f8ca..785c351e9 100644 --- a/src/core/hle/service/err_f.cpp +++ b/src/core/hle/service/err_f.cpp @@ -20,8 +20,8 @@ namespace ERR_F { Interface::Interface() { Register(FunctionTable, ARRAY_SIZE(FunctionTable)); } - + Interface::~Interface() { } - + } // namespace diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h index 5da663267..6d7141c1b 100644 --- a/src/core/hle/service/err_f.h +++ b/src/core/hle/service/err_f.h @@ -19,9 +19,9 @@ namespace ERR_F { * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "err:f"; } }; - + } // namespace diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h index 9df8a815a..4020c6664 100644 --- a/src/core/hle/service/frd_u.h +++ b/src/core/hle/service/frd_u.h @@ -19,7 +19,7 @@ namespace FRD_U { * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "frd:u"; } }; diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp index 9dc83291d..34af78cb9 100644 --- a/src/core/hle/service/fs_user.cpp +++ b/src/core/hle/service/fs_user.cpp @@ -4,31 +4,45 @@ #include "common/common.h" -#include "fs_user.h" #include "common/string_util.h" -#include "core/settings.h" #include "core/hle/kernel/archive.h" +#include "core/hle/kernel/archive.h" +#include "core/hle/result.h" +#include "core/hle/service/fs_user.h" +#include "core/settings.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace FS_User namespace FS_User { -// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it -// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make -// sure we don't mislead the application into thinking something worked. - -void Initialize(Service::Interface* self) { +static void Initialize(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per // http://3dbrew.org/wiki/FS:Initialize#Request - cmd_buff[1] = 0; + cmd_buff[1] = RESULT_SUCCESS.raw; DEBUG_LOG(KERNEL, "called"); } -void OpenFile(Service::Interface* self) { +/** + * FS_User::OpenFile service function + * Inputs: + * 1 : Transaction + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Low path type + * 5 : Low path size + * 6 : Open flags + * 7 : Attributes + * 8 : (LowPathSize << 14) | 2 + * 9 : Low path data pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : File handle + */ +static void OpenFile(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to @@ -39,36 +53,41 @@ void OpenFile(Service::Interface* self) { FileSys::Mode mode; mode.hex = cmd_buff[6]; u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. u32 filename_ptr = cmd_buff[9]; - FileSys::Path file_path(filename_type, filename_size, filename_ptr); - std::string file_string; - switch (file_path.GetType()) { - case FileSys::Char: - case FileSys::Wchar: - file_string = file_path.AsString(); - break; - default: - WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); - return; - } - DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", - filename_type, filename_size, mode, attributes, file_string.c_str()); + DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); - if (handle) { - cmd_buff[1] = 0; - cmd_buff[3] = handle; + ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + cmd_buff[3] = *handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); - // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. - cmd_buff[1] = -1; + ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); } DEBUG_LOG(KERNEL, "called"); } -void OpenFileDirectly(Service::Interface* self) { +/** + * FS_User::OpenFileDirectly service function + * Inputs: + * 1 : Transaction + * 2 : Archive ID + * 3 : Archive low path type + * 4 : Archive low path size + * 5 : File low path type + * 6 : File low path size + * 7 : Flags + * 8 : Attributes + * 9 : (ArchiveLowPathSize << 14) | 0x802 + * 10 : Archive low path + * 11 : (FileLowPathSize << 14) | 2 + * 12 : File low path + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : File handle + */ +static void OpenFileDirectly(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); @@ -80,55 +99,103 @@ void OpenFileDirectly(Service::Interface* self) { u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. u32 archivename_ptr = cmd_buff[10]; u32 filename_ptr = cmd_buff[12]; + FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); + FileSys::Path file_path(filename_type, filename_size, filename_ptr); - DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d", - archivename_type, archivename_size, filename_type, filename_size, mode, attributes); + DEBUG_LOG(KERNEL, "archive_path=%s file_path=%s, mode=%u attributes=%d", + archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); - if (archivename_type != FileSys::Empty) { + if (archive_path.GetType() != FileSys::Empty) { ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); - cmd_buff[1] = -1; + cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; return; } - // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it. - Handle archive_handle = Kernel::OpenArchive(archive_id); - if (archive_handle) { - cmd_buff[1] = 0; - // cmd_buff[2] isn't used according to 3dmoo's implementation. - cmd_buff[3] = archive_handle; - } else { + // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it + // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? + ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id); + cmd_buff[1] = archive_handle.Code().raw; + if (archive_handle.Failed()) { ERROR_LOG(KERNEL, "failed to get a handle for archive"); - // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. - cmd_buff[1] = -1; - return; - } - - FileSys::Path file_path(filename_type, filename_size, filename_ptr); - std::string file_string; - switch (file_path.GetType()) { - case FileSys::Char: - case FileSys::Wchar: - file_string = file_path.AsString(); - break; - default: - WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); return; } + // cmd_buff[2] isn't used according to 3dmoo's implementation. + cmd_buff[3] = *archive_handle; - Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); - if (handle) { - cmd_buff[1] = 0; - cmd_buff[3] = handle; + ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + cmd_buff[3] = *handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); - // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. - cmd_buff[1] = -1; + ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); } DEBUG_LOG(KERNEL, "called"); } /* + * FS_User::DeleteFile service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : File path string type + * 5 : File path string size + * 7 : File path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void DeleteFile(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast<Handle>(cmd_buff[3]); + auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); + u32 filename_size = cmd_buff[5]; + u32 filename_ptr = cmd_buff[7]; + + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", + filename_type, filename_size, file_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path); + + DEBUG_LOG(KERNEL, "called"); +} + +/* + * FS_User::DeleteDirectory service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Directory path string type + * 5 : Directory path string size + * 7 : Directory path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void DeleteDirectory(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast<Handle>(cmd_buff[3]); + auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); + u32 dirname_size = cmd_buff[5]; + u32 dirname_ptr = cmd_buff[7]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", + dirname_type, dirname_size, dir_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path); + + DEBUG_LOG(KERNEL, "called"); +} + +/* * FS_User::CreateDirectory service function * Inputs: * 2 : Archive handle lower word @@ -139,7 +206,7 @@ void OpenFileDirectly(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -void CreateDirectory(Service::Interface* self) { +static void CreateDirectory(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to @@ -150,25 +217,15 @@ void CreateDirectory(Service::Interface* self) { u32 dirname_ptr = cmd_buff[8]; FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); - std::string dir_string; - switch (dir_path.GetType()) { - case FileSys::Char: - case FileSys::Wchar: - dir_string = dir_path.AsString(); - break; - default: - cmd_buff[1] = -1; - return; - } - DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string); + cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path); DEBUG_LOG(KERNEL, "called"); } -void OpenDirectory(Service::Interface* self) { +static void OpenDirectory(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to @@ -179,57 +236,57 @@ void OpenDirectory(Service::Interface* self) { u32 dirname_ptr = cmd_buff[6]; FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); - std::string dir_string; - switch (dir_path.GetType()) { - case FileSys::Char: - case FileSys::Wchar: - dir_string = dir_path.AsString(); - break; - default: - cmd_buff[1] = -1; - return; - } - DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string); - if (handle) { - cmd_buff[1] = 0; - cmd_buff[3] = handle; + ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + cmd_buff[3] = *handle; } else { - ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str()); - // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. - cmd_buff[1] = -1; + ERROR_LOG(KERNEL, "failed to get a handle for directory"); } DEBUG_LOG(KERNEL, "called"); } -void OpenArchive(Service::Interface* self) { +/** + * FS_User::OpenArchive service function + * Inputs: + * 1 : Archive ID + * 2 : Archive low path type + * 3 : Archive low path size + * 4 : (LowPathSize << 14) | 2 + * 5 : Archive low path + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Archive handle lower word (unused) + * 3 : Archive handle upper word (same as file handle) + */ +static void OpenArchive(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); - auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); + auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); - u32 archivename_size = cmd_buff[3]; - u32 archivename_ptr = cmd_buff[5]; + u32 archivename_size = cmd_buff[3]; + u32 archivename_ptr = cmd_buff[5]; + FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); - DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size); + DEBUG_LOG(KERNEL, "archive_path=%s", archive_path.DebugStr().c_str()); - if (archivename_type != FileSys::Empty) { + if (archive_path.GetType() != FileSys::Empty) { ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); - cmd_buff[1] = -1; + cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; return; } - Handle handle = Kernel::OpenArchive(archive_id); - if (handle) { - cmd_buff[1] = 0; + ResultVal<Handle> handle = Kernel::OpenArchive(archive_id); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { // cmd_buff[2] isn't used according to 3dmoo's implementation. - cmd_buff[3] = handle; + cmd_buff[3] = *handle; } else { ERROR_LOG(KERNEL, "failed to get a handle for archive"); - // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. - cmd_buff[1] = -1; } DEBUG_LOG(KERNEL, "called"); @@ -241,12 +298,12 @@ void OpenArchive(Service::Interface* self) { * 1 : Result of function, 0 on success, otherwise error code * 2 : Whether the Sdmc could be detected */ -void IsSdmcDetected(Service::Interface* self) { +static void IsSdmcDetected(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); cmd_buff[1] = 0; cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; - + DEBUG_LOG(KERNEL, "called"); } @@ -256,9 +313,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x08010002, Initialize, "Initialize"}, {0x080201C2, OpenFile, "OpenFile"}, {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, - {0x08040142, nullptr, "DeleteFile"}, + {0x08040142, DeleteFile, "DeleteFile"}, {0x08050244, nullptr, "RenameFile"}, - {0x08060142, nullptr, "DeleteDirectory"}, + {0x08060142, DeleteDirectory, "DeleteDirectory"}, {0x08070142, nullptr, "DeleteDirectoryRecursively"}, {0x08080202, nullptr, "CreateFile"}, {0x08090182, CreateDirectory, "CreateDirectory"}, diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 6119e6300..de1bd3f61 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -28,31 +28,26 @@ u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1 /// Gets a pointer to a thread command buffer in GSP shared memory static inline u8* GetCommandBuffer(u32 thread_id) { - if (0 == g_shared_memory) - return nullptr; - - return Kernel::GetSharedMemoryPointer(g_shared_memory, - 0x800 + (thread_id * sizeof(CommandBuffer))); + ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer))); + return ptr.ValueOr(nullptr); } static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { - if (0 == g_shared_memory) - return nullptr; - _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); // For each thread there are two FrameBufferUpdate fields u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); - return (FrameBufferUpdate*)Kernel::GetSharedMemoryPointer(g_shared_memory, offset); + ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset); + return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); } /// Gets a pointer to the interrupt relay queue for a given thread index static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { - return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory, - sizeof(InterruptRelayQueue) * thread_id); + ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id); + return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); } -void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { +static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { // TODO: Return proper error codes if (base_address + size_in_bytes >= 0x420000) { ERROR_LOG(GPU, "Write address out of range! (address=0x%08x, size=0x%08x)", @@ -76,7 +71,7 @@ void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { } /// Write a GSP GPU hardware register -void WriteHWRegs(Service::Interface* self) { +static void WriteHWRegs(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; @@ -87,7 +82,7 @@ void WriteHWRegs(Service::Interface* self) { } /// Read a GSP GPU hardware register -void ReadHWRegs(Service::Interface* self) { +static void ReadHWRegs(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; @@ -115,7 +110,7 @@ void ReadHWRegs(Service::Interface* self) { } } -void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { +static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { u32 base_address = 0x400000; if (info.active_fb == 0) { WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_left1), 4, &info.address_left); @@ -140,7 +135,7 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { * Outputs: * 1: Result code */ -void SetBufferSwap(Service::Interface* self) { +static void SetBufferSwap(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 screen_id = cmd_buff[1]; FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2]; @@ -159,7 +154,7 @@ void SetBufferSwap(Service::Interface* self) { * 2 : Thread index into GSP command buffer * 4 : Handle to GSP shared memory */ -void RegisterInterruptRelayQueue(Service::Interface* self) { +static void RegisterInterruptRelayQueue(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; g_interrupt_event = cmd_buff[3]; @@ -202,7 +197,7 @@ void SignalInterrupt(InterruptId interrupt_id) { } /// Executes the next GSP command -void ExecuteCommand(const Command& command, u32 thread_id) { +static void ExecuteCommand(const Command& command, u32 thread_id) { // Utility function to convert register ID to address auto WriteGPURegister = [](u32 id, u32 data) { GPU::Write<u32>(0x1EF00000 + 4 * id, data); @@ -308,7 +303,7 @@ void ExecuteCommand(const Command& command, u32 thread_id) { } /// This triggers handling of the GX command written to the command buffer in shared memory. -void TriggerCmdReqQueue(Service::Interface* self) { +static void TriggerCmdReqQueue(Service::Interface* self) { // Iterate through each thread's command queue... for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) { diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp index 0eb32ba4a..d29de1a52 100644 --- a/src/core/hle/service/hid_user.cpp +++ b/src/core/hle/service/hid_user.cpp @@ -34,10 +34,7 @@ static s16 next_circle_y = 0; * Gets a pointer to the PadData structure inside HID shared memory */ static inline PadData* GetPadData() { - if (0 == shared_mem) - return nullptr; - - return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0)); + return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr)); } /** @@ -47,7 +44,7 @@ static inline PadData* GetPadData() { * * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. */ -void UpdateNextCirclePadState() { +static void UpdateNextCirclePadState() { static const s16 max_value = 0x9C; next_circle_x = next_state.circle_left ? -max_value : 0x0; next_circle_x += next_state.circle_right ? max_value : 0x0; @@ -155,7 +152,7 @@ void PadUpdateComplete() { * 7 : Gyroscope event * 8 : Event signaled by HID_User */ -void GetIPCHandles(Service::Interface* self) { +static void GetIPCHandles(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); cmd_buff[1] = 0; // No error diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid_user.h index 9f6c4d5ed..5ed97085d 100644 --- a/src/core/hle/service/hid_user.h +++ b/src/core/hle/service/hid_user.h @@ -15,7 +15,7 @@ namespace HID_User { -/** +/** * Structure of a Pad controller state. */ struct PadState { diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp new file mode 100644 index 000000000..be15db231 --- /dev/null +++ b/src/core/hle/service/ir_rst.cpp @@ -0,0 +1,36 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ir_rst.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace IR_RST + +namespace IR_RST { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "GetHandles"}, + {0x00020080, nullptr, "Initialize"}, + {0x00030000, nullptr, "Shutdown"}, + {0x00040000, nullptr, "Unknown"}, + {0x00050000, nullptr, "Unknown"}, + {0x00060000, nullptr, "Unknown"}, + {0x00070080, nullptr, "Unknown"}, + {0x00080000, nullptr, "Unknown"}, + {0x00090000, nullptr, "Unknown"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ir_rst.h b/src/core/hle/service/ir_rst.h new file mode 100644 index 000000000..73effd7e3 --- /dev/null +++ b/src/core/hle/service/ir_rst.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace IR_RST + +namespace IR_RST { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "ir:rst"; + } +}; + +} // namespace diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir_u.cpp new file mode 100644 index 000000000..aa9db6f6d --- /dev/null +++ b/src/core/hle/service/ir_u.cpp @@ -0,0 +1,45 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ir_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace IR_U + +namespace IR_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "Initialize"}, + {0x00020000, nullptr, "Shutdown"}, + {0x00030042, nullptr, "StartSendTransfer"}, + {0x00040000, nullptr, "WaitSendTransfer"}, + {0x000500C2, nullptr, "StartRecvTransfer"}, + {0x00060000, nullptr, "WaitRecvTransfer"}, + {0x00070080, nullptr, "GetRecvTransferCount"}, + {0x00080000, nullptr, "GetSendState"}, + {0x00090040, nullptr, "SetBitRate"}, + {0x000A0000, nullptr, "GetBitRate"}, + {0x000B0040, nullptr, "SetIRLEDState"}, + {0x000C0000, nullptr, "GetIRLEDRecvState"}, + {0x000D0000, nullptr, "GetSendFinishedEvent"}, + {0x000E0000, nullptr, "GetRecvFinishedEvent"}, + {0x000F0000, nullptr, "GetTransferState"}, + {0x00100000, nullptr, "GetErrorStatus"}, + {0x00110040, nullptr, "SetSleepModeActive"}, + {0x00120040, nullptr, "SetSleepModeState"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ir_u.h b/src/core/hle/service/ir_u.h new file mode 100644 index 000000000..86d98d079 --- /dev/null +++ b/src/core/hle/service/ir_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace IR_U + +namespace IR_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "ir:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp index 58051f133..d6f30e9ae 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic_u.cpp @@ -27,7 +27,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000D0040, nullptr, "SetClamp"}, {0x000E0000, nullptr, "GetClamp"}, {0x000F0040, nullptr, "unknown_input1"}, - {0x00100040, nullptr, "unknown_input2"}, + {0x00100040, nullptr, "unknown_input2"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h index 72ba048ef..2a495f3a9 100644 --- a/src/core/hle/service/mic_u.h +++ b/src/core/hle/service/mic_u.h @@ -21,7 +21,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "mic:u"; } }; diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h index a956ca812..69d2c2002 100644 --- a/src/core/hle/service/nwm_uds.h +++ b/src/core/hle/service/nwm_uds.h @@ -21,7 +21,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "nwm:UDS"; } }; diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp new file mode 100644 index 000000000..90e9b1bfa --- /dev/null +++ b/src/core/hle/service/pm_app.cpp @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/pm_app.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace PM_APP + +namespace PM_APP { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010140, nullptr, "LaunchTitle"}, + {0x00020082, nullptr, "LaunchFIRMSetParams"}, + {0x00030080, nullptr, "TerminateProcesse"}, + {0x00040100, nullptr, "TerminateProcessTID"}, + {0x000500C0, nullptr, "TerminateProcessTID_unknown"}, + {0x00070042, nullptr, "GetFIRMLaunchParams"}, + {0x00080100, nullptr, "GetTitleExheaderFlags"}, + {0x00090042, nullptr, "SetFIRMLaunchParams"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h new file mode 100644 index 000000000..28c38f582 --- /dev/null +++ b/src/core/hle/service/pm_app.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace PM_APP + +namespace PM_APP { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "pm:app"; + } +}; + +} // namespace diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp index f6a14d509..d9122dbbc 100644 --- a/src/core/hle/service/ptm_u.cpp +++ b/src/core/hle/service/ptm_u.cpp @@ -17,13 +17,13 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00030000, nullptr, "GetRtcAlarm"}, {0x00040000, nullptr, "CancelRtcAlarm"}, {0x00050000, nullptr, "GetAdapterState"}, - {0x00060000, nullptr, "GetShellState "}, + {0x00060000, nullptr, "GetShellState"}, {0x00070000, nullptr, "GetBatteryLevel"}, {0x00080000, nullptr, "GetBatteryChargeState"}, {0x00090000, nullptr, "GetPedometerState"}, {0x000A0042, nullptr, "GetStepHistoryEntry"}, - {0x000B00C2, nullptr, "GetStepHistory "}, - {0x000C0000, nullptr, "GetTotalStepCount "}, + {0x000B00C2, nullptr, "GetStepHistory"}, + {0x000C0000, nullptr, "GetTotalStepCount"}, {0x000D0040, nullptr, "SetPedometerRecordingMode"}, {0x000E0000, nullptr, "GetPedometerRecordingMode"}, {0x000F0084, nullptr, "GetStepHistoryAll"}, diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h index 82749fa39..f8d9f57be 100644 --- a/src/core/hle/service/ptm_u.h +++ b/src/core/hle/service/ptm_u.h @@ -21,7 +21,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "ptm:u"; } }; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index bb0f80e98..fed2268a0 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -7,17 +7,24 @@ #include "core/hle/service/service.h" #include "core/hle/service/ac_u.h" +#include "core/hle/service/am_net.h" #include "core/hle/service/apt_u.h" +#include "core/hle/service/boss_u.h" +#include "core/hle/service/cfg_i.h" #include "core/hle/service/cfg_u.h" +#include "core/hle/service/csnd_snd.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" #include "core/hle/service/fs_user.h" #include "core/hle/service/frd_u.h" #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/hid_user.h" +#include "core/hle/service/ir_rst.h" +#include "core/hle/service/ir_u.h" #include "core/hle/service/mic_u.h" #include "core/hle/service/ndm_u.h" #include "core/hle/service/nwm_uds.h" +#include "core/hle/service/pm_app.h" #include "core/hle/service/ptm_u.h" #include "core/hle/service/soc_u.h" #include "core/hle/service/srv.h" @@ -55,7 +62,7 @@ void Manager::DeleteService(const std::string& port_name) { /// Get a Service Interface from its Handle Interface* Manager::FetchFromHandle(Handle handle) { - return Kernel::g_object_pool.GetFast<Interface>(handle); + return Kernel::g_object_pool.Get<Interface>(handle); } /// Get a Service Interface from its port @@ -74,20 +81,27 @@ Interface* Manager::FetchFromPortName(const std::string& port_name) { /// Initialize ServiceManager void Init() { g_manager = new Manager; - + g_manager->AddService(new SRV::Interface); g_manager->AddService(new AC_U::Interface); + g_manager->AddService(new AM_NET::Interface); g_manager->AddService(new APT_U::Interface); + g_manager->AddService(new BOSS_U::Interface); + g_manager->AddService(new CFG_I::Interface); g_manager->AddService(new CFG_U::Interface); + g_manager->AddService(new CSND_SND::Interface); g_manager->AddService(new DSP_DSP::Interface); g_manager->AddService(new ERR_F::Interface); g_manager->AddService(new FRD_U::Interface); g_manager->AddService(new FS_User::Interface); g_manager->AddService(new GSP_GPU::Interface); g_manager->AddService(new HID_User::Interface); + g_manager->AddService(new IR_RST::Interface); + g_manager->AddService(new IR_U::Interface); g_manager->AddService(new MIC_U::Interface); g_manager->AddService(new NDM_U::Interface); g_manager->AddService(new NWM_UDS::Interface); + g_manager->AddService(new PM_APP::Interface); g_manager->AddService(new PTM_U::Interface); g_manager->AddService(new SOC_U::Interface); g_manager->AddService(new SSL_C::Interface); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 2f5a866c9..20e7fb4d3 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -38,7 +38,7 @@ class Manager; class Interface : public Kernel::Object { friend class Manager; public: - + std::string GetName() const override { return GetPortName(); } std::string GetTypeName() const override { return GetPortName(); } @@ -75,48 +75,38 @@ public: m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); } - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); if (itr == m_functions.end()) { - ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X", + ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X", GetPortName().c_str(), cmd_buff[0]); // TODO(bunnei): Hack - ignore error u32* cmd_buff = Service::GetCommandBuffer(); cmd_buff[1] = 0; - return 0; + return MakeResult<bool>(false); } if (itr->second.func == nullptr) { - ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", + ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", GetPortName().c_str(), itr->second.name.c_str()); // TODO(bunnei): Hack - ignore error u32* cmd_buff = Service::GetCommandBuffer(); cmd_buff[1] = 0; - return 0; - } + return MakeResult<bool>(false); + } itr->second.func(this); - return 0; // TODO: Implement return from actual function + return MakeResult<bool>(false); // TODO: Implement return from actual function } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "unimplemented function"); - return 0; + return UnimplementedFunction(ErrorModule::OS); } protected: diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h index e27a2b1fe..d5590a683 100644 --- a/src/core/hle/service/soc_u.h +++ b/src/core/hle/service/soc_u.h @@ -19,7 +19,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "soc:U"; } }; diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 6c02a43d9..0e7fa9e3b 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -11,9 +11,9 @@ namespace SRV { -Handle g_event_handle = 0; +static Handle g_event_handle = 0; -void Initialize(Service::Interface* self) { +static void Initialize(Service::Interface* self) { DEBUG_LOG(OSHLE, "called"); u32* cmd_buff = Service::GetCommandBuffer(); @@ -21,7 +21,7 @@ void Initialize(Service::Interface* self) { cmd_buff[1] = 0; // No error } -void GetProcSemaphore(Service::Interface* self) { +static void GetProcSemaphore(Service::Interface* self) { DEBUG_LOG(OSHLE, "called"); u32* cmd_buff = Service::GetCommandBuffer(); @@ -34,8 +34,8 @@ void GetProcSemaphore(Service::Interface* self) { cmd_buff[3] = g_event_handle; } -void GetServiceHandle(Service::Interface* self) { - Result res = 0; +static void GetServiceHandle(Service::Interface* self) { + ResultCode res = RESULT_SUCCESS; u32* cmd_buff = Service::GetCommandBuffer(); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); @@ -46,9 +46,9 @@ void GetServiceHandle(Service::Interface* self) { DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); } else { ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); - res = -1; + res = UnimplementedFunction(ErrorModule::SRV); } - cmd_buff[1] = res; + cmd_buff[1] = res.raw; } const Interface::FunctionInfo FunctionTable[] = { diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 1eda36c53..43a3cbe03 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <map> @@ -16,6 +16,7 @@ #include "core/hle/kernel/thread.h" #include "core/hle/function_wrappers.h" +#include "core/hle/result.h" #include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -29,8 +30,8 @@ enum ControlMemoryOperation { }; /// Map application or GSP heap memory -Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { - DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", +static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { + DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", operation, addr0, addr1, size, permissions); switch (operation) { @@ -53,8 +54,8 @@ Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 siz } /// Maps a memory block to specified address -Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { - DEBUG_LOG(SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", +static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { + DEBUG_LOG(SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", handle, addr, permissions, other_permissions); Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions); @@ -63,7 +64,7 @@ Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permis case Kernel::MemoryPermission::Write: case Kernel::MemoryPermission::ReadWrite: case Kernel::MemoryPermission::DontCare: - Kernel::MapSharedMemory(handle, addr, permissions_type, + Kernel::MapSharedMemory(handle, addr, permissions_type, static_cast<Kernel::MemoryPermission>(other_permissions)); break; default: @@ -73,7 +74,7 @@ Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permis } /// Connect to an OS service given the port name, returns the handle to the port to out -Result ConnectToPort(Handle* out, const char* port_name) { +static Result ConnectToPort(Handle* out, const char* port_name) { Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); DEBUG_LOG(SVC, "called port_name=%s", port_name); @@ -85,78 +86,83 @@ Result ConnectToPort(Handle* out, const char* port_name) { } /// Synchronize to an OS service -Result SendSyncRequest(Handle handle) { +static Result SendSyncRequest(Handle handle) { + // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object, + // so we are forced to use GetFast and manually verify the handle. + if (!Kernel::g_object_pool.IsValid(handle)) { + return InvalidHandle(ErrorModule::Kernel).raw; + } Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); - bool wait = false; - Result res = object->SyncRequest(&wait); - if (wait) { + ResultVal<bool> wait = object->SyncRequest(); + if (wait.Succeeded() && *wait) { Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? } - return res; + return wait.Code().raw; } /// Close a handle -Result CloseHandle(Handle handle) { +static Result CloseHandle(Handle handle) { // ImplementMe ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); return 0; } /// Wait for a handle to synchronize, timeout after the specified nanoseconds -Result WaitSynchronization1(Handle handle, s64 nano_seconds) { +static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { // TODO(bunnei): Do something with nano_seconds, currently ignoring this - bool wait = false; bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated + if (!Kernel::g_object_pool.IsValid(handle)) { + return InvalidHandle(ErrorModule::Kernel).raw; + } Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); + _dbg_assert_(KERNEL, object != nullptr); - DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), + DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); - - Result res = object->WaitSynchronization(&wait); + ResultVal<bool> wait = object->WaitSynchronization(); // Check for next thread to schedule - if (wait) { + if (wait.Succeeded() && *wait) { HLE::Reschedule(__func__); - return 0; } - return res; + return wait.Code().raw; } /// Wait for the given handles to synchronize, timeout after the specified nanoseconds -Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, +static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { // TODO(bunnei): Do something with nano_seconds, currently ignoring this bool unlock_all = true; bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated - DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", + DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", handle_count, (wait_all ? "true" : "false"), nano_seconds); // Iterate through each handle, synchronize kernel object for (s32 i = 0; i < handle_count; i++) { - bool wait = false; + if (!Kernel::g_object_pool.IsValid(handles[i])) { + return InvalidHandle(ErrorModule::Kernel).raw; + } Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); - _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object " - "is nullptr!", handles[i]); - - DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), + DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), object->GetName().c_str()); - Result res = object->WaitSynchronization(&wait); + // TODO(yuriks): Verify how the real function behaves when an error happens here + ResultVal<bool> wait_result = object->WaitSynchronization(); + bool wait = wait_result.Succeeded() && *wait_result; if (!wait && !wait_all) { *out = i; - return 0; + return RESULT_SUCCESS.raw; } else { unlock_all = false; } @@ -164,17 +170,17 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa if (wait_all && unlock_all) { *out = handle_count; - return 0; + return RESULT_SUCCESS.raw; } // Check for next thread to schedule HLE::Reschedule(__func__); - return 0; + return RESULT_SUCCESS.raw; } /// Create an address arbiter (to allocate access to shared resources) -Result CreateAddressArbiter(u32* arbiter) { +static Result CreateAddressArbiter(u32* arbiter) { DEBUG_LOG(SVC, "called"); Handle handle = Kernel::CreateAddressArbiter(); *arbiter = handle; @@ -182,20 +188,22 @@ Result CreateAddressArbiter(u32* arbiter) { } /// Arbitrate address -Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { - return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address, - value); +static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { + DEBUG_LOG(SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter, + address, type, value); + return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), + address, value).raw; } /// Used to output a message on a debug hardware unit - does nothing on a retail unit -void OutputDebugString(const char* string) { +static void OutputDebugString(const char* string) { OS_LOG(SVC, "%s", string); } /// Get resource limit -Result GetResourceLimit(Handle* resource_limit, Handle process) { +static Result GetResourceLimit(Handle* resource_limit, Handle process) { // With regards to proceess values: - // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for + // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for // the current KThread. *resource_limit = 0xDEADBEEF; ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process); @@ -203,7 +211,7 @@ Result GetResourceLimit(Handle* resource_limit, Handle process) { } /// Get resource limit current values -Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, +static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, s32 name_count) { ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", resource_limit, names, name_count); @@ -212,7 +220,7 @@ Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* n } /// Creates a new thread -Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { +static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { std::string name; if (Symbols::HasSymbol(entry_point)) { TSymbol symbol = Symbols::GetSymbol(entry_point); @@ -227,14 +235,14 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p Core::g_app_core->SetReg(1, thread); DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " - "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, + "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, name.c_str(), arg, stack_top, priority, processor_id, thread); - + return 0; } /// Called when a thread exits -u32 ExitThread() { +static u32 ExitThread() { Handle thread = Kernel::GetCurrentThreadHandle(); DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C @@ -245,54 +253,56 @@ u32 ExitThread() { } /// Gets the priority for the specified thread -Result GetThreadPriority(s32* priority, Handle handle) { - *priority = Kernel::GetThreadPriority(handle); - return 0; +static Result GetThreadPriority(s32* priority, Handle handle) { + ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle); + if (priority_result.Succeeded()) { + *priority = *priority_result; + } + return priority_result.Code().raw; } /// Sets the priority for the specified thread -Result SetThreadPriority(Handle handle, s32 priority) { - return Kernel::SetThreadPriority(handle, priority); +static Result SetThreadPriority(Handle handle, s32 priority) { + return Kernel::SetThreadPriority(handle, priority).raw; } /// Create a mutex -Result CreateMutex(Handle* mutex, u32 initial_locked) { +static Result CreateMutex(Handle* mutex, u32 initial_locked) { *mutex = Kernel::CreateMutex((initial_locked != 0)); - DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X", + DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X", initial_locked ? "true" : "false", *mutex); return 0; } /// Release a mutex -Result ReleaseMutex(Handle handle) { +static Result ReleaseMutex(Handle handle) { DEBUG_LOG(SVC, "called handle=0x%08X", handle); - _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); - Kernel::ReleaseMutex(handle); - return 0; + ResultCode res = Kernel::ReleaseMutex(handle); + return res.raw; } /// Get current thread ID -Result GetThreadId(u32* thread_id, Handle thread) { +static Result GetThreadId(u32* thread_id, Handle thread) { ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread); return 0; } /// Query memory -Result QueryMemory(void* info, void* out, u32 addr) { +static Result QueryMemory(void* info, void* out, u32 addr) { ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); return 0; } /// Create an event -Result CreateEvent(Handle* evt, u32 reset_type) { +static Result CreateEvent(Handle* evt, u32 reset_type) { *evt = Kernel::CreateEvent((ResetType)reset_type); - DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X", + DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, *evt); return 0; } /// Duplicates a kernel handle -Result DuplicateHandle(Handle* out, Handle handle) { +static Result DuplicateHandle(Handle* out, Handle handle) { DEBUG_LOG(SVC, "called handle=0x%08X", handle); // Translate kernel handles -> real handles @@ -301,7 +311,7 @@ Result DuplicateHandle(Handle* out, Handle handle) { } _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), "(UNIMPLEMENTED) process handle duplication!"); - + // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate. *out = handle; @@ -309,26 +319,27 @@ Result DuplicateHandle(Handle* out, Handle handle) { } /// Signals an event -Result SignalEvent(Handle evt) { - Result res = Kernel::SignalEvent(evt); +static Result SignalEvent(Handle evt) { DEBUG_LOG(SVC, "called event=0x%08X", evt); - return res; + return Kernel::SignalEvent(evt).raw; } /// Clears an event -Result ClearEvent(Handle evt) { - Result res = Kernel::ClearEvent(evt); +static Result ClearEvent(Handle evt) { DEBUG_LOG(SVC, "called event=0x%08X", evt); - return res; + return Kernel::ClearEvent(evt).raw; } /// Sleep the current thread -void SleepThread(s64 nanoseconds) { +static void SleepThread(s64 nanoseconds) { DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); + + // Check for next thread to schedule + HLE::Reschedule(__func__); } /// This returns the total CPU ticks elapsed since the CPU was powered-on -s64 GetSystemTick() { +static s64 GetSystemTick() { return (s64)Core::g_app_core->GetTicks(); } diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h index 1d125faf6..6be393d0b 100644 --- a/src/core/hle/svc.h +++ b/src/core/hle/svc.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 3ad801c63..af5e1b39b 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -49,7 +49,7 @@ inline void Write(u32 addr, const T data) { // Writes other than u32 are untested, so I'd rather have them abort than silently fail if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { - ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr); return; } @@ -140,8 +140,8 @@ inline void Write(u32 addr, const T data) { DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", config.output_height * config.output_width * 4, - config.GetPhysicalInputAddress(), config.input_width, config.input_height, - config.GetPhysicalOutputAddress(), config.output_width, config.output_height, + config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height, + config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height, config.output_format.Value()); } break; diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index 33f75c50a..ea001673a 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -39,7 +39,7 @@ enum { template <typename T> inline void Read(T &var, const u32 addr) { switch (addr & 0xFFFFF000) { - + // TODO(bunnei): What is the virtual address of NDMA? // case VADDR_NDMA: // NDMA::Read(var, addr); @@ -57,9 +57,9 @@ inline void Read(T &var, const u32 addr) { template <typename T> inline void Write(u32 addr, const T data) { switch (addr & 0xFFFFF000) { - + // TODO(bunnei): What is the virtual address of NDMA? - // case VADDR_NDMA + // case VADDR_NDMA // NDMA::Write(addr, data); // break; @@ -68,7 +68,7 @@ inline void Write(u32 addr, const T data) { break; default: - ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr); } } diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp index e29a773f1..593e5de30 100644 --- a/src/core/hw/ndma.cpp +++ b/src/core/hw/ndma.cpp @@ -15,7 +15,7 @@ inline void Read(T &var, const u32 addr) { template <typename T> inline void Write(u32 addr, const T data) { - ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr); } // Explicitly instantiate template functions because we aren't defining this in the header: diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 389d5a8c9..63d2496ed 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -273,13 +273,13 @@ bool ElfReader::LoadInto(u32 vaddr) { for (int i = 0; i < header->e_phnum; i++) { Elf32_Phdr *p = segments + i; - INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, + INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); if (p->p_type == PT_LOAD) { segment_addr[i] = base_addr + p->p_vaddr; memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); - INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], + INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], p->p_memsz); } } diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 1e5501e6d..343bb7523 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -24,7 +24,7 @@ static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes) * @param size Size of compressed buffer * @return Size of decompressed buffer */ -u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) { +static u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) { u32 offset_size = *(u32*)(buffer + size - 4); return offset_size + size; } @@ -37,7 +37,7 @@ u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) { * @param decompressed_size Size of decompressed buffer * @return True on success, otherwise false */ -bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) { +static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) { u8* footer = compressed + compressed_size - 8; u32 buffer_top_and_bottom = *(u32*)footer; u32 out = decompressed_size; @@ -118,7 +118,7 @@ AppLoader_NCCH::~AppLoader_NCCH() { * @return ResultStatus result of function */ ResultStatus AppLoader_NCCH::LoadExec() const { - if (!is_loaded) + if (!is_loaded) return ResultStatus::ErrorNotLoaded; std::vector<u8> code; @@ -185,7 +185,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& return ResultStatus::Error; } return ResultStatus::ErrorNotUsed; -} +} /** * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) @@ -210,7 +210,7 @@ ResultStatus AppLoader_NCCH::Load() { file.Seek(ncch_offset, 0); file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); } - + // Verify we are loading the correct file type... if (0 != memcmp(&ncch_header.magic, "NCCH", 4)) return ResultStatus::ErrorInvalidFormat; diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index f40a258b7..03116add8 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -215,7 +215,7 @@ private: u32 entry_point; u32 ncch_offset; // Offset to NCCH header, can be 0 or after NCSD header u32 exefs_offset; - + NCCH_Header ncch_header; ExeFs_Header exefs_header; ExHeader_Header exheader_header; diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index cf12f24d9..74a93b1d9 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp @@ -11,38 +11,38 @@ namespace Memory { -u8* g_base = NULL; ///< The base pointer to the auto-mirrored arena. +u8* g_base = nullptr; ///< The base pointer to the auto-mirrored arena. -MemArena g_arena; ///< The MemArena class +static MemArena arena; ///< The MemArena class -u8* g_exefs_code = NULL; ///< ExeFS:/.code is loaded here -u8* g_system_mem = NULL; ///< System memory -u8* g_heap = NULL; ///< Application heap (main memory) -u8* g_heap_gsp = NULL; ///< GSP heap (main memory) -u8* g_vram = NULL; ///< Video memory (VRAM) pointer -u8* g_shared_mem = NULL; ///< Shared memory -u8* g_kernel_mem; ///< Kernel memory +u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here +u8* g_system_mem = nullptr; ///< System memory +u8* g_heap = nullptr; ///< Application heap (main memory) +u8* g_heap_gsp = nullptr; ///< GSP heap (main memory) +u8* g_vram = nullptr; ///< Video memory (VRAM) pointer +u8* g_shared_mem = nullptr; ///< Shared memory +u8* g_kernel_mem; ///< Kernel memory -u8* g_physical_bootrom = NULL; ///< Bootrom physical memory -u8* g_uncached_bootrom = NULL; +static u8* physical_bootrom = nullptr; ///< Bootrom physical memory +static u8* uncached_bootrom = nullptr; -u8* g_physical_exefs_code = NULL; ///< Phsical ExeFS:/.code is loaded here -u8* g_physical_system_mem = NULL; ///< System physical memory -u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM) -u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory -u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) -u8* g_physical_shared_mem = NULL; ///< Physical shared memory -u8* g_physical_kernel_mem; ///< Kernel memory +static u8* physical_exefs_code = nullptr; ///< Phsical ExeFS:/.code is loaded here +static u8* physical_system_mem = nullptr; ///< System physical memory +static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM) +static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory +static u8* physical_vram = nullptr; ///< Video physical memory (VRAM) +static u8* physical_shared_mem = nullptr; ///< Physical shared memory +static u8* physical_kernel_mem; ///< Kernel memory // We don't declare the IO region in here since its handled by other means. static MemoryView g_views[] = { - {&g_exefs_code, &g_physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0}, - {&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, - {&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, - {&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, - {&g_system_mem, &g_physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0}, - {&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, - {&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, + {&g_exefs_code, &physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0}, + {&g_vram, &physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, + {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, + {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, + {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0}, + {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, + {&g_heap_gsp, &physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, }; /*static MemoryView views[] = @@ -69,18 +69,18 @@ void Init() { g_views[i].size = FCRAM_SIZE; } - g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena); + g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena); NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap, - g_physical_fcram); + physical_fcram); } void Shutdown() { u32 flags = 0; - MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena); + MemoryMap_Shutdown(g_views, kNumMemViews, flags, &arena); - g_arena.ReleaseSpace(); - g_base = NULL; + arena.ReleaseSpace(); + g_base = nullptr; NOTICE_LOG(MEMMAP, "shutdown OK"); } diff --git a/src/core/mem_map.h b/src/core/mem_map.h index eed445046..a58c59244 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -147,6 +147,7 @@ u32 Read16_ZX(VAddr addr); void Write8(VAddr addr, u8 data); void Write16(VAddr addr, u16 data); void Write32(VAddr addr, u32 data); +void Write64(VAddr addr, u64 data); void WriteBlock(VAddr addr, const u8* data, size_t size); @@ -156,7 +157,7 @@ u8* GetPointer(VAddr virtual_address); * Maps a block of memory on the heap * @param size Size of block in bytes * @param operation Memory map operation type - * @param flags Memory allocation flags + * @param permissions Memory allocation permissions */ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions); diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 90951812b..e8747840c 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -12,9 +12,9 @@ namespace Memory { -std::map<u32, MemoryBlock> g_heap_map; -std::map<u32, MemoryBlock> g_heap_gsp_map; -std::map<u32, MemoryBlock> g_shared_map; +static std::map<u32, MemoryBlock> heap_map; +static std::map<u32, MemoryBlock> heap_gsp_map; +static std::map<u32, MemoryBlock> shared_map; /// Convert a physical address to virtual address VAddr PhysicalToVirtualAddress(const PAddr addr) { @@ -92,7 +92,7 @@ inline void Read(T &var, const VAddr vaddr) { var = *((const T*)&g_vram[vaddr & VRAM_MASK]); } else { - ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); + ERROR_LOG(MEMMAP, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr); } } @@ -141,7 +141,7 @@ inline void Write(const VAddr vaddr, const T data) { // Error out... } else { - ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); + ERROR_LOG(MEMMAP, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, vaddr); } } @@ -194,11 +194,11 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { block.operation = operation; block.permissions = permissions; - if (g_heap_map.size() > 0) { - const MemoryBlock last_block = g_heap_map.rbegin()->second; + if (heap_map.size() > 0) { + const MemoryBlock last_block = heap_map.rbegin()->second; block.address = last_block.address + last_block.size; } - g_heap_map[block.GetVirtualAddress()] = block; + heap_map[block.GetVirtualAddress()] = block; return block.GetVirtualAddress(); } @@ -217,11 +217,11 @@ u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) { block.operation = operation; block.permissions = permissions; - if (g_heap_gsp_map.size() > 0) { - const MemoryBlock last_block = g_heap_gsp_map.rbegin()->second; + if (heap_gsp_map.size() > 0) { + const MemoryBlock last_block = heap_gsp_map.rbegin()->second; block.address = last_block.address + last_block.size; } - g_heap_gsp_map[block.GetVirtualAddress()] = block; + heap_gsp_map[block.GetVirtualAddress()] = block; return block.GetVirtualAddress(); } diff --git a/src/core/system.h b/src/core/system.h index 8f8ddf87b..2bc2edc75 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -11,16 +11,16 @@ namespace System { // State of the full emulator -typedef enum { - STATE_NULL = 0, ///< System is in null state, nothing initialized - STATE_IDLE, ///< System is in an initialized state, but not running - STATE_RUNNING, ///< System is running - STATE_LOADING, ///< System is loading a ROM - STATE_HALTED, ///< System is halted (error) - STATE_STALLED, ///< System is stalled (unused) - STATE_DEBUG, ///< System is in a special debug mode (unused) - STATE_DIE ///< System is shutting down -} State; +enum State { + STATE_NULL = 0, ///< System is in null state, nothing initialized + STATE_IDLE, ///< System is in an initialized state, but not running + STATE_RUNNING, ///< System is running + STATE_LOADING, ///< System is loading a ROM + STATE_HALTED, ///< System is halted (error) + STATE_STALLED, ///< System is stalled (unused) + STATE_DEBUG, ///< System is in a special debug mode (unused) + STATE_DIE ///< System is shutting down +}; extern volatile State g_state; @@ -30,4 +30,4 @@ void RunLoopFor(int cycles); void RunLoopUntil(u64 global_cycles); void Shutdown(); -}; +} diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 22b8e9950..275b06b7c 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -318,9 +318,9 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { return; #ifndef HAVE_PNG - return; + return; #else - if (!data) + if (!data) return; // Write data to file diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index 8b1499bf2..b1558cfae 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h @@ -41,7 +41,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data // Utility class to log Pica commands. struct PicaTrace { struct Write : public std::pair<u32,u32> { - Write(u32 id, u32 value) : std::pair<u32,u32>(id, value) {} + Write(u32 id, u32 value) : std::pair<u32,u32>(id, value) {} u32& Id() { return first; } const u32& Id() const { return first; } diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index f1dbc9d17..bce402b88 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -25,7 +25,7 @@ public: /// Swap buffers (render frame) virtual void SwapBuffers() = 0; - /** + /** * Set the emulator window to use for renderer * @param window EmuWindow handle to emulator window to use for rendering */ diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 8483f79be..abbb4c2cb 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -191,7 +191,8 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x * Draws the emulated screens to the emulator window. */ void RendererOpenGL::DrawScreens() { - glViewport(0, 0, resolution_width, resolution_height); + auto viewport_extent = GetViewportExtent(); + glViewport(viewport_extent.left, viewport_extent.top, viewport_extent.GetWidth(), viewport_extent.GetHeight()); // TODO: Or bottom? glClear(GL_COLOR_BUFFER_BIT); glUseProgram(program_id); @@ -228,6 +229,34 @@ void RendererOpenGL::SetWindow(EmuWindow* window) { render_window = window; } +MathUtil::Rectangle<unsigned> RendererOpenGL::GetViewportExtent() { + unsigned framebuffer_width; + unsigned framebuffer_height; + std::tie(framebuffer_width, framebuffer_height) = render_window->GetFramebufferSize(); + + float window_aspect_ratio = static_cast<float>(framebuffer_height) / framebuffer_width; + float emulation_aspect_ratio = static_cast<float>(resolution_height) / resolution_width; + + MathUtil::Rectangle<unsigned> viewport_extent; + if (window_aspect_ratio > emulation_aspect_ratio) { + // Window is narrower than the emulation content => apply borders to the top and bottom + unsigned viewport_height = emulation_aspect_ratio * framebuffer_width; + viewport_extent.left = 0; + viewport_extent.top = (framebuffer_height - viewport_height) / 2; + viewport_extent.right = viewport_extent.left + framebuffer_width; + viewport_extent.bottom = viewport_extent.top + viewport_height; + } else { + // Otherwise, apply borders to the left and right sides of the window. + unsigned viewport_width = framebuffer_height / emulation_aspect_ratio; + viewport_extent.left = (framebuffer_width - viewport_width) / 2; + viewport_extent.top = 0; + viewport_extent.right = viewport_extent.left + viewport_width; + viewport_extent.bottom = viewport_extent.top + framebuffer_height; + } + + return viewport_extent; +} + /// Initialize the renderer void RendererOpenGL::Init() { render_window->MakeCurrent(); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index eed201a95..7fdcec731 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -4,13 +4,15 @@ #pragma once +#include <array> + #include "generated/gl_3_2_core.h" -#include "common/common.h" +#include "common/math_util.h" + #include "core/hw/gpu.h" -#include "video_core/renderer_base.h" -#include <array> +#include "video_core/renderer_base.h" class EmuWindow; @@ -52,6 +54,9 @@ private: static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, const TextureInfo& texture); + /// Computes the viewport rectangle + MathUtil::Rectangle<unsigned> GetViewportExtent(); + EmuWindow* render_window; ///< Handle to render window u32 last_mode; ///< Last render mode diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp index c1848f923..f1156a493 100644 --- a/src/video_core/utils.cpp +++ b/src/video_core/utils.cpp @@ -20,7 +20,7 @@ namespace VideoCore { void DumpTGA(std::string filename, short width, short height, u8* raw_data) { TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0}; FILE* fout = fopen(filename.c_str(), "wb"); - + fwrite(&hdr, sizeof(TGAHeader), 1, fout); for (int y = 0; y < height; y++) { @@ -30,7 +30,7 @@ void DumpTGA(std::string filename, short width, short height, u8* raw_data) { putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r } } - + fclose(fout); } } // namespace diff --git a/src/video_core/utils.h b/src/video_core/utils.h index 9cb3d4d43..21380a908 100644 --- a/src/video_core/utils.h +++ b/src/video_core/utils.h @@ -12,24 +12,24 @@ namespace FormatPrecision { /// Adjust RGBA8 color with RGBA6 precision static inline u32 rgba8_with_rgba6(u32 src) { - u32 color = src; - color &= 0xFCFCFCFC; - color |= (color >> 6) & 0x03030303; - return color; + u32 color = src; + color &= 0xFCFCFCFC; + color |= (color >> 6) & 0x03030303; + return color; } /// Adjust RGBA8 color with RGB565 precision static inline u32 rgba8_with_rgb565(u32 src) { - u32 color = (src & 0xF8FCF8); - color |= (color >> 5) & 0x070007; - color |= (color >> 6) & 0x000300; - color |= 0xFF000000; - return color; + u32 color = (src & 0xF8FCF8); + color |= (color >> 5) & 0x070007; + color |= (color >> 6) & 0x000300; + color |= 0xFF000000; + return color; } /// Adjust Z24 depth value with Z16 precision static inline u32 z24_with_z16(u32 src) { - return (src & 0xFFFF00) | (src >> 16); + return (src & 0xFFFF00) | (src >> 16); } } // namespace diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h index 607a8e803..bfb6fb6e3 100644 --- a/src/video_core/vertex_shader.h +++ b/src/video_core/vertex_shader.h @@ -141,7 +141,7 @@ union Instruction { return BitFieldType::Value(); else if (GetRegisterType() == Temporary) return BitFieldType::Value() - 0x10; - else if (GetRegisterType() == FloatUniform) + else // if (GetRegisterType() == FloatUniform) return BitFieldType::Value() - 0x20; } |