diff options
Diffstat (limited to 'src/core')
52 files changed, 581 insertions, 350 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 988356c65..8ccb2d5f0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -217,6 +217,7 @@ add_library(core STATIC      hle/service/audio/audren_u.h      hle/service/audio/codecctl.cpp      hle/service/audio/codecctl.h +    hle/service/audio/errors.h      hle/service/audio/hwopus.cpp      hle/service/audio/hwopus.h      hle/service/bcat/bcat.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index ab7181a05..eba2177d1 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -36,7 +36,8 @@  #include "frontend/applets/software_keyboard.h"  #include "frontend/applets/web_browser.h"  #include "video_core/debug_utils/debug_utils.h" -#include "video_core/gpu.h" +#include "video_core/gpu_asynch.h" +#include "video_core/gpu_synch.h"  #include "video_core/renderer_base.h"  #include "video_core/video_core.h" @@ -78,6 +79,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,      return vfs->OpenFile(path, FileSys::Mode::Read);  }  struct System::Impl { +    explicit Impl(System& system) : kernel{system} {}      Cpu& CurrentCpuCore() {          return cpu_core_manager.GetCurrentCore(); @@ -95,7 +97,7 @@ struct System::Impl {          LOG_DEBUG(HW_Memory, "initialized OK");          core_timing.Initialize(); -        kernel.Initialize(core_timing); +        kernel.Initialize();          const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(              std::chrono::system_clock::now().time_since_epoch()); @@ -128,10 +130,16 @@ struct System::Impl {              return ResultStatus::ErrorVideoCore;          } -        gpu_core = std::make_unique<Tegra::GPU>(system, renderer->Rasterizer()); +        is_powered_on = true; + +        if (Settings::values.use_asynchronous_gpu_emulation) { +            gpu_core = std::make_unique<VideoCommon::GPUAsynch>(system, *renderer); +        } else { +            gpu_core = std::make_unique<VideoCommon::GPUSynch>(system, *renderer); +        }          cpu_core_manager.Initialize(system); -        is_powered_on = true; +          LOG_DEBUG(Core, "Initialized OK");          // Reset counters and set time origin to current frame @@ -182,13 +190,13 @@ struct System::Impl {      void Shutdown() {          // Log last frame performance stats -        auto perf_results = GetAndResetPerfStats(); -        Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed", -                             perf_results.emulation_speed * 100.0); -        Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", -                             perf_results.game_fps); -        Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", -                             perf_results.frametime * 1000.0); +        const auto perf_results = GetAndResetPerfStats(); +        telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed", +                                    perf_results.emulation_speed * 100.0); +        telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", +                                    perf_results.game_fps); +        telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", +                                    perf_results.frametime * 1000.0);          is_powered_on = false; @@ -265,7 +273,7 @@ struct System::Impl {      Core::FrameLimiter frame_limiter;  }; -System::System() : impl{std::make_unique<Impl>()} {} +System::System() : impl{std::make_unique<Impl>(*this)} {}  System::~System() = default;  Cpu& System::CurrentCpuCore() { diff --git a/src/core/core.h b/src/core/core.h index d720013f7..ba76a41d8 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -293,10 +293,6 @@ inline ARM_Interface& CurrentArmInterface() {      return System::GetInstance().CurrentArmInterface();  } -inline TelemetrySession& Telemetry() { -    return System::GetInstance().TelemetrySession(); -} -  inline Kernel::Process* CurrentProcess() {      return System::GetInstance().CurrentProcess();  } diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 9dd493efb..e29afd630 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -67,7 +67,7 @@ static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigne              framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right);  } -std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { +std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) const {      new_x = std::max(new_x, framebuffer_layout.screen.left);      new_x = std::min(new_x, framebuffer_layout.screen.right - 1); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 7006a37b3..d0bcb4660 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -166,7 +166,7 @@ private:      /**       * Clip the provided coordinates to be inside the touchscreen area.       */ -    std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); +    std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y) const;  };  } // namespace Core::Frontend diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index f8662d193..a1357179f 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -12,12 +12,12 @@ namespace Layout {  // Finds the largest size subrectangle contained in window area that is confined to the aspect ratio  template <class T> -static MathUtil::Rectangle<T> maxRectangle(MathUtil::Rectangle<T> window_area, -                                           float screen_aspect_ratio) { +static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area, +                                         float screen_aspect_ratio) {      float scale = std::min(static_cast<float>(window_area.GetWidth()),                             window_area.GetHeight() / screen_aspect_ratio); -    return MathUtil::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)), -                                  static_cast<T>(std::round(scale * screen_aspect_ratio))}; +    return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)), +                                static_cast<T>(std::round(scale * screen_aspect_ratio))};  }  FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) { @@ -29,8 +29,8 @@ FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {      const float emulation_aspect_ratio{static_cast<float>(ScreenUndocked::Height) /                                         ScreenUndocked::Width}; -    MathUtil::Rectangle<unsigned> screen_window_area{0, 0, width, height}; -    MathUtil::Rectangle<unsigned> screen = maxRectangle(screen_window_area, emulation_aspect_ratio); +    Common::Rectangle<unsigned> screen_window_area{0, 0, width, height}; +    Common::Rectangle<unsigned> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);      float window_aspect_ratio = static_cast<float>(height) / width; diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index e06647794..c2c63d08c 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -16,7 +16,7 @@ struct FramebufferLayout {      unsigned width{ScreenUndocked::Width};      unsigned height{ScreenUndocked::Height}; -    MathUtil::Rectangle<unsigned> screen; +    Common::Rectangle<unsigned> screen;      /**       * Returns the ration of pixel size of the screen, compared to the native size of the undocked diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 16fdcd376..7c11d7546 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -124,7 +124,7 @@ using AnalogDevice = InputDevice<std::tuple<float, float>>;   *   Orientation is determined by right-hand rule.   *   Units: deg/sec   */ -using MotionDevice = InputDevice<std::tuple<Math::Vec3<float>, Math::Vec3<float>>>; +using MotionDevice = InputDevice<std::tuple<Common::Vec3<float>, Common::Vec3<float>>>;  /**   * A touch device is an input device that returns a tuple of two floats and a bool. The floats are diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index ed84197b3..455d1f346 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -4,10 +4,10 @@  #pragma once +#include "common/bit_field.h" +#include "common/common_funcs.h"  #include "common/common_types.h"  #include "common/swap.h" -#include "core/hle/kernel/errors.h" -#include "core/memory.h"  namespace IPC { diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 90f276ee8..079283830 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -350,7 +350,7 @@ public:      template <class T>      std::shared_ptr<T> PopIpcInterface() {          ASSERT(context->Session()->IsDomain()); -        ASSERT(context->GetDomainMessageHeader()->input_object_count > 0); +        ASSERT(context->GetDomainMessageHeader().input_object_count > 0);          return context->GetDomainRequestHandler<T>(Pop<u32>() - 1);      }  }; diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index a250d088d..9780a7849 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -9,6 +9,7 @@  #include "common/common_types.h"  #include "core/core.h"  #include "core/core_cpu.h" +#include "core/hle/kernel/address_arbiter.h"  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/object.h"  #include "core/hle/kernel/process.h" @@ -17,58 +18,16 @@  #include "core/hle/result.h"  #include "core/memory.h" -namespace Kernel::AddressArbiter { - -// Performs actual address waiting logic. -static ResultCode WaitForAddress(VAddr address, s64 timeout) { -    SharedPtr<Thread> current_thread = GetCurrentThread(); -    current_thread->SetArbiterWaitAddress(address); -    current_thread->SetStatus(ThreadStatus::WaitArb); -    current_thread->InvalidateWakeupCallback(); - -    current_thread->WakeAfterDelay(timeout); - -    Core::System::GetInstance().CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); -    return RESULT_TIMEOUT; -} - -// Gets the threads waiting on an address. -static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) { -    const auto RetrieveWaitingThreads = [](std::size_t core_index, -                                           std::vector<SharedPtr<Thread>>& waiting_threads, -                                           VAddr arb_addr) { -        const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); -        const auto& thread_list = scheduler.GetThreadList(); - -        for (const auto& thread : thread_list) { -            if (thread->GetArbiterWaitAddress() == arb_addr) -                waiting_threads.push_back(thread); -        } -    }; - -    // Retrieve all threads that are waiting for this address. -    std::vector<SharedPtr<Thread>> threads; -    RetrieveWaitingThreads(0, threads, address); -    RetrieveWaitingThreads(1, threads, address); -    RetrieveWaitingThreads(2, threads, address); -    RetrieveWaitingThreads(3, threads, address); - -    // Sort them by priority, such that the highest priority ones come first. -    std::sort(threads.begin(), threads.end(), -              [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { -                  return lhs->GetPriority() < rhs->GetPriority(); -              }); - -    return threads; -} - +namespace Kernel { +namespace {  // Wake up num_to_wake (or all) threads in a vector. -static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { +void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) {      // Only process up to 'target' threads, unless 'target' is <= 0, in which case process      // them all.      std::size_t last = waiting_threads.size(); -    if (num_to_wake > 0) +    if (num_to_wake > 0) {          last = num_to_wake; +    }      // Signal the waiting threads.      for (std::size_t i = 0; i < last; i++) { @@ -78,42 +37,41 @@ static void WakeThreads(std::vector<SharedPtr<Thread>>& waiting_threads, s32 num          waiting_threads[i]->ResumeFromWait();      }  } +} // Anonymous namespace -// Signals an address being waited on. -ResultCode SignalToAddress(VAddr address, s32 num_to_wake) { -    std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); +AddressArbiter::AddressArbiter(Core::System& system) : system{system} {} +AddressArbiter::~AddressArbiter() = default; +ResultCode AddressArbiter::SignalToAddress(VAddr address, s32 num_to_wake) { +    const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);      WakeThreads(waiting_threads, num_to_wake);      return RESULT_SUCCESS;  } -// Signals an address being waited on and increments its value if equal to the value argument. -ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { +ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, +                                                              s32 num_to_wake) {      // Ensure that we can write to the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE;      } -    if (static_cast<s32>(Memory::Read32(address)) == value) { -        Memory::Write32(address, static_cast<u32>(value + 1)); -    } else { +    if (static_cast<s32>(Memory::Read32(address)) != value) {          return ERR_INVALID_STATE;      } +    Memory::Write32(address, static_cast<u32>(value + 1));      return SignalToAddress(address, num_to_wake);  } -// Signals an address being waited on and modifies its value based on waiting thread count if equal -// to the value argument. -ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, -                                                         s32 num_to_wake) { +ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, +                                                                         s32 num_to_wake) {      // Ensure that we can write to the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE;      }      // Get threads waiting on the address. -    std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); +    const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address);      // Determine the modified value depending on the waiting count.      s32 updated_value; @@ -125,31 +83,31 @@ ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 valu          updated_value = value;      } -    if (static_cast<s32>(Memory::Read32(address)) == value) { -        Memory::Write32(address, static_cast<u32>(updated_value)); -    } else { +    if (static_cast<s32>(Memory::Read32(address)) != value) {          return ERR_INVALID_STATE;      } +    Memory::Write32(address, static_cast<u32>(updated_value));      WakeThreads(waiting_threads, num_to_wake);      return RESULT_SUCCESS;  } -// Waits on an address if the value passed is less than the argument value, optionally decrementing. -ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { +ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, +                                                    bool should_decrement) {      // Ensure that we can read the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE;      } -    s32 cur_value = static_cast<s32>(Memory::Read32(address)); -    if (cur_value < value) { -        if (should_decrement) { -            Memory::Write32(address, static_cast<u32>(cur_value - 1)); -        } -    } else { +    const s32 cur_value = static_cast<s32>(Memory::Read32(address)); +    if (cur_value >= value) {          return ERR_INVALID_STATE;      } + +    if (should_decrement) { +        Memory::Write32(address, static_cast<u32>(cur_value - 1)); +    } +      // Short-circuit without rescheduling, if timeout is zero.      if (timeout == 0) {          return RESULT_TIMEOUT; @@ -158,8 +116,7 @@ ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool      return WaitForAddress(address, timeout);  } -// Waits on an address if the value passed is equal to the argument value. -ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { +ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {      // Ensure that we can read the address.      if (!Memory::IsValidVirtualAddress(address)) {          return ERR_INVALID_ADDRESS_STATE; @@ -175,4 +132,46 @@ ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {      return WaitForAddress(address, timeout);  } -} // namespace Kernel::AddressArbiter + +ResultCode AddressArbiter::WaitForAddress(VAddr address, s64 timeout) { +    SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); +    current_thread->SetArbiterWaitAddress(address); +    current_thread->SetStatus(ThreadStatus::WaitArb); +    current_thread->InvalidateWakeupCallback(); + +    current_thread->WakeAfterDelay(timeout); + +    system.CpuCore(current_thread->GetProcessorID()).PrepareReschedule(); +    return RESULT_TIMEOUT; +} + +std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const { +    const auto RetrieveWaitingThreads = [this](std::size_t core_index, +                                               std::vector<SharedPtr<Thread>>& waiting_threads, +                                               VAddr arb_addr) { +        const auto& scheduler = system.Scheduler(core_index); +        const auto& thread_list = scheduler.GetThreadList(); + +        for (const auto& thread : thread_list) { +            if (thread->GetArbiterWaitAddress() == arb_addr) { +                waiting_threads.push_back(thread); +            } +        } +    }; + +    // Retrieve all threads that are waiting for this address. +    std::vector<SharedPtr<Thread>> threads; +    RetrieveWaitingThreads(0, threads, address); +    RetrieveWaitingThreads(1, threads, address); +    RetrieveWaitingThreads(2, threads, address); +    RetrieveWaitingThreads(3, threads, address); + +    // Sort them by priority, such that the highest priority ones come first. +    std::sort(threads.begin(), threads.end(), +              [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { +                  return lhs->GetPriority() < rhs->GetPriority(); +              }); + +    return threads; +} +} // namespace Kernel diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index b58f21bec..e0c36f2e3 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -5,28 +5,68 @@  #pragma once  #include "common/common_types.h" +#include "core/hle/kernel/address_arbiter.h"  union ResultCode; -namespace Kernel::AddressArbiter { +namespace Core { +class System; +} -enum class ArbitrationType { -    WaitIfLessThan = 0, -    DecrementAndWaitIfLessThan = 1, -    WaitIfEqual = 2, -}; +namespace Kernel { -enum class SignalType { -    Signal = 0, -    IncrementAndSignalIfEqual = 1, -    ModifyByWaitingCountAndSignalIfEqual = 2, -}; +class Thread; + +class AddressArbiter { +public: +    enum class ArbitrationType { +        WaitIfLessThan = 0, +        DecrementAndWaitIfLessThan = 1, +        WaitIfEqual = 2, +    }; + +    enum class SignalType { +        Signal = 0, +        IncrementAndSignalIfEqual = 1, +        ModifyByWaitingCountAndSignalIfEqual = 2, +    }; + +    explicit AddressArbiter(Core::System& system); +    ~AddressArbiter(); + +    AddressArbiter(const AddressArbiter&) = delete; +    AddressArbiter& operator=(const AddressArbiter&) = delete; + +    AddressArbiter(AddressArbiter&&) = default; +    AddressArbiter& operator=(AddressArbiter&&) = delete; -ResultCode SignalToAddress(VAddr address, s32 num_to_wake); -ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); -ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); +    /// Signals an address being waited on. +    ResultCode SignalToAddress(VAddr address, s32 num_to_wake); -ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); -ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); +    /// Signals an address being waited on and increments its value if equal to the value argument. +    ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); + +    /// Signals an address being waited on and modifies its value based on waiting thread count if +    /// equal to the value argument. +    ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, +                                                             s32 num_to_wake); + +    /// Waits on an address if the value passed is less than the argument value, +    /// optionally decrementing. +    ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, +                                        bool should_decrement); + +    /// Waits on an address if the value passed is equal to the argument value. +    ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); + +private: +    // Waits on the given address with a timeout in nanoseconds +    ResultCode WaitForAddress(VAddr address, s64 timeout); + +    // Gets the threads waiting on an address. +    std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; + +    Core::System& system; +}; -} // namespace Kernel::AddressArbiter +} // namespace Kernel diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 704e82824..c17baa50a 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -17,21 +17,11 @@ ClientSession::~ClientSession() {      // This destructor will be called automatically when the last ClientSession handle is closed by      // the emulated application. -    // Local references to ServerSession and SessionRequestHandler are necessary to guarantee they +    // A local reference to the ServerSession is necessary to guarantee it      // will be kept alive until after ClientDisconnected() returns.      SharedPtr<ServerSession> server = parent->server;      if (server) { -        std::shared_ptr<SessionRequestHandler> hle_handler = server->hle_handler; -        if (hle_handler) -            hle_handler->ClientDisconnected(server); - -        // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set -        // their WaitSynchronization result to 0xC920181A. - -        // Clean up the list of client threads with pending requests, they are unneeded now that the -        // client endpoint is closed. -        server->pending_requesting_threads.clear(); -        server->currently_handling = nullptr; +        server->ClientDisconnected();      }      parent->client = nullptr; diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 4c18de69c..b1f39aad7 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -36,14 +36,15 @@ public:      ResultCode SendSyncRequest(SharedPtr<Thread> thread); -    std::string name; ///< Name of client port (optional) +private: +    explicit ClientSession(KernelCore& kernel); +    ~ClientSession() override;      /// The parent session, which links to the server endpoint.      std::shared_ptr<Session> parent; -private: -    explicit ClientSession(KernelCore& kernel); -    ~ClientSession() override; +    /// Name of the client session (optional) +    std::string name;  };  } // namespace Kernel diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index d17eb0cb6..8097b3863 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -14,6 +14,7 @@ constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};  constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};  constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};  constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; +constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};  constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};  constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};  constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index c8acde5b1..bdfaa977f 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -14,32 +14,47 @@  namespace Kernel {  namespace {  constexpr u16 GetSlot(Handle handle) { -    return handle >> 15; +    return static_cast<u16>(handle >> 15);  }  constexpr u16 GetGeneration(Handle handle) { -    return handle & 0x7FFF; +    return static_cast<u16>(handle & 0x7FFF);  }  } // Anonymous namespace  HandleTable::HandleTable() { -    next_generation = 1;      Clear();  }  HandleTable::~HandleTable() = default; +ResultCode HandleTable::SetSize(s32 handle_table_size) { +    if (static_cast<u32>(handle_table_size) > MAX_COUNT) { +        return ERR_OUT_OF_MEMORY; +    } + +    // Values less than or equal to zero indicate to use the maximum allowable +    // size for the handle table in the actual kernel, so we ignore the given +    // value in that case, since we assume this by default unless this function +    // is called. +    if (handle_table_size > 0) { +        table_size = static_cast<u16>(handle_table_size); +    } + +    return RESULT_SUCCESS; +} +  ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {      DEBUG_ASSERT(obj != nullptr); -    u16 slot = next_free_slot; -    if (slot >= generations.size()) { +    const u16 slot = next_free_slot; +    if (slot >= table_size) {          LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");          return ERR_HANDLE_TABLE_FULL;      }      next_free_slot = generations[slot]; -    u16 generation = next_generation++; +    const u16 generation = next_generation++;      // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.      // Horizon OS uses zero to represent an invalid handle, so skip to 1. @@ -64,10 +79,11 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {  }  ResultCode HandleTable::Close(Handle handle) { -    if (!IsValid(handle)) +    if (!IsValid(handle)) {          return ERR_INVALID_HANDLE; +    } -    u16 slot = GetSlot(handle); +    const u16 slot = GetSlot(handle);      objects[slot] = nullptr; @@ -77,10 +93,10 @@ ResultCode HandleTable::Close(Handle handle) {  }  bool HandleTable::IsValid(Handle handle) const { -    std::size_t slot = GetSlot(handle); -    u16 generation = GetGeneration(handle); +    const std::size_t slot = GetSlot(handle); +    const u16 generation = GetGeneration(handle); -    return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; +    return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;  }  SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { @@ -97,7 +113,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {  }  void HandleTable::Clear() { -    for (u16 i = 0; i < MAX_COUNT; ++i) { +    for (u16 i = 0; i < table_size; ++i) {          generations[i] = i + 1;          objects[i] = nullptr;      } diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 89a3bc740..44901391b 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -50,6 +50,20 @@ public:      ~HandleTable();      /** +     * Sets the number of handles that may be in use at one time +     * for this handle table. +     * +     * @param handle_table_size The desired size to limit the handle table to. +     * +     * @returns an error code indicating if initialization was successful. +     *          If initialization was not successful, then ERR_OUT_OF_MEMORY +     *          will be returned. +     * +     * @pre handle_table_size must be within the range [0, 1024] +     */ +    ResultCode SetSize(s32 handle_table_size); + +    /**       * Allocates a handle for the given object.       * @return The created Handle or one of the following errors:       *           - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. @@ -104,13 +118,20 @@ private:      std::array<u16, MAX_COUNT> generations;      /** +     * The limited size of the handle table. This can be specified by process +     * capabilities in order to restrict the overall number of handles that +     * can be created in a process instance +     */ +    u16 table_size = static_cast<u16>(MAX_COUNT); + +    /**       * Global counter of the number of created handles. Stored in `generations` when a handle is       * created, and wraps around to 1 when it hits 0x8000.       */ -    u16 next_generation; +    u16 next_generation = 1;      /// Head of the free slots linked list. -    u16 next_free_slot; +    u16 next_free_slot = 0;  };  } // namespace Kernel diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 5dd855db8..fe710eb6e 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -86,7 +86,7 @@ HLERequestContext::~HLERequestContext() = default;  void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf,                                             bool incoming) {      IPC::RequestParser rp(src_cmdbuf); -    command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); +    command_header = rp.PopRaw<IPC::CommandHeader>();      if (command_header->type == IPC::CommandType::Close) {          // Close does not populate the rest of the IPC header @@ -95,8 +95,7 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_      // If handle descriptor is present, add size of it      if (command_header->enable_handle_descriptor) { -        handle_descriptor_header = -            std::make_shared<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); +        handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();          if (handle_descriptor_header->send_current_pid) {              rp.Skip(2, false);          } @@ -140,16 +139,15 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_          // If this is an incoming message, only CommandType "Request" has a domain header          // All outgoing domain messages have the domain header, if only incoming has it          if (incoming || domain_message_header) { -            domain_message_header = -                std::make_shared<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>()); +            domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();          } else { -            if (Session()->IsDomain()) +            if (Session()->IsDomain()) {                  LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); +            }          }      } -    data_payload_header = -        std::make_shared<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); +    data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>();      data_payload_offset = rp.GetCurrentOffset(); @@ -264,11 +262,11 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {          // Write the domain objects to the command buffer, these go after the raw untranslated data.          // TODO(Subv): This completely ignores C buffers.          std::size_t domain_offset = size - domain_message_header->num_objects; -        auto& request_handlers = server_session->domain_request_handlers; -        for (auto& object : domain_objects) { -            request_handlers.emplace_back(object); -            dst_cmdbuf[domain_offset++] = static_cast<u32_le>(request_handlers.size()); +        for (const auto& object : domain_objects) { +            server_session->AppendDomainRequestHandler(object); +            dst_cmdbuf[domain_offset++] = +                static_cast<u32_le>(server_session->NumDomainRequestHandlers());          }      } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index cb1c5aff3..2bdd9f02c 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -6,6 +6,7 @@  #include <array>  #include <memory> +#include <optional>  #include <string>  #include <type_traits>  #include <vector> @@ -15,6 +16,8 @@  #include "core/hle/ipc.h"  #include "core/hle/kernel/object.h" +union ResultCode; +  namespace Service {  class ServiceFrameworkBase;  } @@ -166,12 +169,12 @@ public:          return buffer_c_desciptors;      } -    const IPC::DomainMessageHeader* GetDomainMessageHeader() const { -        return domain_message_header.get(); +    const IPC::DomainMessageHeader& GetDomainMessageHeader() const { +        return domain_message_header.value();      }      bool HasDomainMessageHeader() const { -        return domain_message_header != nullptr; +        return domain_message_header.has_value();      }      /// Helper function to read a buffer using the appropriate buffer descriptor @@ -208,14 +211,12 @@ public:      template <typename T>      SharedPtr<T> GetCopyObject(std::size_t index) { -        ASSERT(index < copy_objects.size()); -        return DynamicObjectCast<T>(copy_objects[index]); +        return DynamicObjectCast<T>(copy_objects.at(index));      }      template <typename T>      SharedPtr<T> GetMoveObject(std::size_t index) { -        ASSERT(index < move_objects.size()); -        return DynamicObjectCast<T>(move_objects[index]); +        return DynamicObjectCast<T>(move_objects.at(index));      }      void AddMoveObject(SharedPtr<Object> object) { @@ -232,7 +233,7 @@ public:      template <typename T>      std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { -        return std::static_pointer_cast<T>(domain_request_handlers[index]); +        return std::static_pointer_cast<T>(domain_request_handlers.at(index));      }      void SetDomainRequestHandlers( @@ -272,10 +273,10 @@ private:      boost::container::small_vector<SharedPtr<Object>, 8> copy_objects;      boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; -    std::shared_ptr<IPC::CommandHeader> command_header; -    std::shared_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; -    std::shared_ptr<IPC::DataPayloadHeader> data_payload_header; -    std::shared_ptr<IPC::DomainMessageHeader> domain_message_header; +    std::optional<IPC::CommandHeader> command_header; +    std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; +    std::optional<IPC::DataPayloadHeader> data_payload_header; +    std::optional<IPC::DomainMessageHeader> domain_message_header;      std::vector<IPC::BufferDescriptorX> buffer_x_desciptors;      std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors;      std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index dd749eed4..04ea9349e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -12,6 +12,7 @@  #include "core/core.h"  #include "core/core_timing.h" +#include "core/hle/kernel/address_arbiter.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/kernel.h" @@ -86,11 +87,13 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_  }  struct KernelCore::Impl { -    void Initialize(KernelCore& kernel, Core::Timing::CoreTiming& core_timing) { +    explicit Impl(Core::System& system) : address_arbiter{system}, system{system} {} + +    void Initialize(KernelCore& kernel) {          Shutdown();          InitializeSystemResourceLimit(kernel); -        InitializeThreads(core_timing); +        InitializeThreads();      }      void Shutdown() { @@ -122,9 +125,9 @@ struct KernelCore::Impl {          ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());      } -    void InitializeThreads(Core::Timing::CoreTiming& core_timing) { +    void InitializeThreads() {          thread_wakeup_event_type = -            core_timing.RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); +            system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);      }      std::atomic<u32> next_object_id{0}; @@ -135,6 +138,8 @@ struct KernelCore::Impl {      std::vector<SharedPtr<Process>> process_list;      Process* current_process = nullptr; +    Kernel::AddressArbiter address_arbiter; +      SharedPtr<ResourceLimit> system_resource_limit;      Core::Timing::EventType* thread_wakeup_event_type = nullptr; @@ -145,15 +150,18 @@ struct KernelCore::Impl {      /// Map of named ports managed by the kernel, which can be retrieved using      /// the ConnectToPort SVC.      NamedPortTable named_ports; + +    // System context +    Core::System& system;  }; -KernelCore::KernelCore() : impl{std::make_unique<Impl>()} {} +KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system)} {}  KernelCore::~KernelCore() {      Shutdown();  } -void KernelCore::Initialize(Core::Timing::CoreTiming& core_timing) { -    impl->Initialize(*this, core_timing); +void KernelCore::Initialize() { +    impl->Initialize(*this);  }  void KernelCore::Shutdown() { @@ -184,6 +192,14 @@ const Process* KernelCore::CurrentProcess() const {      return impl->current_process;  } +AddressArbiter& KernelCore::AddressArbiter() { +    return impl->address_arbiter; +} + +const AddressArbiter& KernelCore::AddressArbiter() const { +    return impl->address_arbiter; +} +  void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) {      impl->named_ports.emplace(std::move(name), std::move(port));  } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 154bced42..4d292aca9 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,6 +11,10 @@  template <typename T>  class ResultVal; +namespace Core { +class System; +} +  namespace Core::Timing {  class CoreTiming;  struct EventType; @@ -18,6 +22,7 @@ struct EventType;  namespace Kernel { +class AddressArbiter;  class ClientPort;  class HandleTable;  class Process; @@ -30,7 +35,14 @@ private:      using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>;  public: -    KernelCore(); +    /// Constructs an instance of the kernel using the given System +    /// instance as a context for any necessary system-related state, +    /// such as threads, CPU core state, etc. +    /// +    /// @post After execution of the constructor, the provided System +    ///       object *must* outlive the kernel instance itself. +    /// +    explicit KernelCore(Core::System& system);      ~KernelCore();      KernelCore(const KernelCore&) = delete; @@ -40,11 +52,7 @@ public:      KernelCore& operator=(KernelCore&&) = delete;      /// Resets the kernel to a clean slate for use. -    /// -    /// @param core_timing CoreTiming instance used to create any necessary -    ///                    kernel-specific callback events. -    /// -    void Initialize(Core::Timing::CoreTiming& core_timing); +    void Initialize();      /// Clears all resources in use by the kernel instance.      void Shutdown(); @@ -67,6 +75,12 @@ public:      /// Retrieves a const pointer to the current process.      const Process* CurrentProcess() const; +    /// Provides a reference to the kernel's address arbiter. +    Kernel::AddressArbiter& AddressArbiter(); + +    /// Provides a const reference to the kernel's address arbiter. +    const Kernel::AddressArbiter& AddressArbiter() const; +      /// Adds a port to the named port table      void AddNamedPort(std::string name, SharedPtr<ClientPort> port); diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c5aa19afa..8009150e0 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -99,7 +99,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {      vm_manager.Reset(metadata.GetAddressSpaceType());      const auto& caps = metadata.GetKernelCapabilities(); -    return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); +    const auto capability_init_result = +        capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); +    if (capability_init_result.IsError()) { +        return capability_init_result; +    } + +    return handle_table.SetSize(capabilities.GetHandleTableSize());  }  void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 3a2164b25..583e35b79 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -96,7 +96,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() {      interrupt_capabilities.set();      // Allow using the maximum possible amount of handles -    handle_table_size = static_cast<u32>(HandleTable::MAX_COUNT); +    handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT);      // Allow all debugging capabilities.      is_debuggable = true; @@ -337,7 +337,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {          return ERR_RESERVED_VALUE;      } -    handle_table_size = (flags >> 16) & 0x3FF; +    handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);      return RESULT_SUCCESS;  } diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h index fbc8812a3..5cdd80747 100644 --- a/src/core/hle/kernel/process_capability.h +++ b/src/core/hle/kernel/process_capability.h @@ -156,7 +156,7 @@ public:      }      /// Gets the number of total allowable handles for the process' handle table. -    u32 GetHandleTableSize() const { +    s32 GetHandleTableSize() const {          return handle_table_size;      } @@ -252,7 +252,7 @@ private:      u64 core_mask = 0;      u64 priority_mask = 0; -    u32 handle_table_size = 0; +    s32 handle_table_size = 0;      u32 kernel_version = 0;      ProgramType program_type = ProgramType::SysModule; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 027434f92..4d8a337a7 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -63,42 +63,71 @@ void ServerSession::Acquire(Thread* thread) {      pending_requesting_threads.pop_back();  } +void ServerSession::ClientDisconnected() { +    // We keep a shared pointer to the hle handler to keep it alive throughout +    // the call to ClientDisconnected, as ClientDisconnected invalidates the +    // hle_handler member itself during the course of the function executing. +    std::shared_ptr<SessionRequestHandler> handler = hle_handler; +    if (handler) { +        // Note that after this returns, this server session's hle_handler is +        // invalidated (set to null). +        handler->ClientDisconnected(this); +    } + +    // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set +    // their WaitSynchronization result to 0xC920181A. + +    // Clean up the list of client threads with pending requests, they are unneeded now that the +    // client endpoint is closed. +    pending_requesting_threads.clear(); +    currently_handling = nullptr; +} + +void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { +    domain_request_handlers.push_back(std::move(handler)); +} + +std::size_t ServerSession::NumDomainRequestHandlers() const { +    return domain_request_handlers.size(); +} +  ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { -    auto* const domain_message_header = context.GetDomainMessageHeader(); -    if (domain_message_header) { -        // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs -        context.SetDomainRequestHandlers(domain_request_handlers); - -        // If there is a DomainMessageHeader, then this is CommandType "Request" -        const u32 object_id{context.GetDomainMessageHeader()->object_id}; -        switch (domain_message_header->command) { -        case IPC::DomainMessageHeader::CommandType::SendMessage: -            if (object_id > domain_request_handlers.size()) { -                LOG_CRITICAL(IPC, -                             "object_id {} is too big! This probably means a recent service call " -                             "to {} needed to return a new interface!", -                             object_id, name); -                UNREACHABLE(); -                return RESULT_SUCCESS; // Ignore error if asserts are off -            } -            return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); - -        case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { -            LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - -            domain_request_handlers[object_id - 1] = nullptr; - -            IPC::ResponseBuilder rb{context, 2}; -            rb.Push(RESULT_SUCCESS); -            return RESULT_SUCCESS; -        } +    if (!context.HasDomainMessageHeader()) { +        return RESULT_SUCCESS; +    } + +    // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs +    context.SetDomainRequestHandlers(domain_request_handlers); + +    // If there is a DomainMessageHeader, then this is CommandType "Request" +    const auto& domain_message_header = context.GetDomainMessageHeader(); +    const u32 object_id{domain_message_header.object_id}; +    switch (domain_message_header.command) { +    case IPC::DomainMessageHeader::CommandType::SendMessage: +        if (object_id > domain_request_handlers.size()) { +            LOG_CRITICAL(IPC, +                         "object_id {} is too big! This probably means a recent service call " +                         "to {} needed to return a new interface!", +                         object_id, name); +            UNREACHABLE(); +            return RESULT_SUCCESS; // Ignore error if asserts are off          } +        return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); -        LOG_CRITICAL(IPC, "Unknown domain command={}", -                     static_cast<int>(domain_message_header->command.Value())); -        ASSERT(false); +    case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { +        LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); + +        domain_request_handlers[object_id - 1] = nullptr; + +        IPC::ResponseBuilder rb{context, 2}; +        rb.Push(RESULT_SUCCESS); +        return RESULT_SUCCESS; +    }      } +    LOG_CRITICAL(IPC, "Unknown domain command={}", +                 static_cast<int>(domain_message_header.command.Value())); +    ASSERT(false);      return RESULT_SUCCESS;  } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index e0e9d64c8..aea4ccfeb 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -46,6 +46,14 @@ public:          return HANDLE_TYPE;      } +    Session* GetParent() { +        return parent.get(); +    } + +    const Session* GetParent() const { +        return parent.get(); +    } +      using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;      /** @@ -78,23 +86,16 @@ public:      void Acquire(Thread* thread) override; -    std::string name;                ///< The name of this session (optional) -    std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint. -    std::shared_ptr<SessionRequestHandler> -        hle_handler; ///< This session's HLE request handler (applicable when not a domain) +    /// Called when a client disconnection occurs. +    void ClientDisconnected(); -    /// This is the list of domain request handlers (after conversion to a domain) -    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; - -    /// List of threads that are pending a response after a sync request. This list is processed in -    /// a LIFO manner, thus, the last request will be dispatched first. -    /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. -    std::vector<SharedPtr<Thread>> pending_requesting_threads; +    /// Adds a new domain request handler to the collection of request handlers within +    /// this ServerSession instance. +    void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); -    /// Thread whose request is currently being handled. A request is considered "handled" when a -    /// response is sent via svcReplyAndReceive. -    /// TODO(Subv): Find a better name for this. -    SharedPtr<Thread> currently_handling; +    /// Retrieves the total number of domain request handlers that have been +    /// appended to this ServerSession instance. +    std::size_t NumDomainRequestHandlers() const;      /// Returns true if the session has been converted to a domain, otherwise False      bool IsDomain() const { @@ -129,8 +130,30 @@ private:      /// object handle.      ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); +    /// The parent session, which links to the client endpoint. +    std::shared_ptr<Session> parent; + +    /// This session's HLE request handler (applicable when not a domain) +    std::shared_ptr<SessionRequestHandler> hle_handler; + +    /// This is the list of domain request handlers (after conversion to a domain) +    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + +    /// List of threads that are pending a response after a sync request. This list is processed in +    /// a LIFO manner, thus, the last request will be dispatched first. +    /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. +    std::vector<SharedPtr<Thread>> pending_requesting_threads; + +    /// Thread whose request is currently being handled. A request is considered "handled" when a +    /// response is sent via svcReplyAndReceive. +    /// TODO(Subv): Find a better name for this. +    SharedPtr<Thread> currently_handling; +      /// When set to True, converts the session to a domain at the end of the command      bool convert_to_domain{}; + +    /// The name of this session (optional) +    std::string name;  };  } // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 22d0c1dd5..62861da36 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -6,7 +6,6 @@  #include "common/assert.h"  #include "common/logging/log.h" -#include "core/core.h"  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/shared_memory.h" @@ -34,8 +33,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_          shared_memory->backing_block_offset = 0;          // Refresh the address mappings for the current process. -        if (Core::CurrentProcess() != nullptr) { -            Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings( +        if (kernel.CurrentProcess() != nullptr) { +            kernel.CurrentProcess()->VMManager().RefreshMemoryBlockMappings(                  shared_memory->backing_block.get());          }      } else { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c5d399bab..7f5c0cc86 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -20,6 +20,7 @@  #include "core/hle/kernel/address_arbiter.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/errors.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/mutex.h" @@ -47,23 +48,6 @@ constexpr bool IsValidAddressRange(VAddr address, u64 size) {      return address + size > address;  } -// Checks if a given address range lies within a larger address range. -constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin, -                                    VAddr address_range_end) { -    const VAddr end_address = address + size - 1; -    return address_range_begin <= address && end_address <= address_range_end - 1; -} - -bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) { -    return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(), -                                vm.GetAddressSpaceEndAddress()); -} - -bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) { -    return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(), -                                vm.GetNewMapRegionEndAddress()); -} -  // 8 GiB  constexpr u64 MAIN_MEMORY_SIZE = 0x200000000; @@ -105,14 +89,14 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add          return ERR_INVALID_ADDRESS_STATE;      } -    if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { +    if (!vm_manager.IsWithinAddressSpace(src_addr, size)) {          LOG_ERROR(Kernel_SVC,                    "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",                    src_addr, size);          return ERR_INVALID_ADDRESS_STATE;      } -    if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { +    if (!vm_manager.IsWithinNewMapRegion(dst_addr, size)) {          LOG_ERROR(Kernel_SVC,                    "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}",                    dst_addr, size); @@ -238,7 +222,7 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {      auto* const current_process = Core::CurrentProcess();      auto& vm_manager = current_process->VMManager(); -    if (!IsInsideAddressSpace(vm_manager, addr, size)) { +    if (!vm_manager.IsWithinAddressSpace(addr, size)) {          LOG_ERROR(Kernel_SVC,                    "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,                    size); @@ -299,7 +283,7 @@ static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attr      }      auto& vm_manager = Core::CurrentProcess()->VMManager(); -    if (!IsInsideAddressSpace(vm_manager, address, size)) { +    if (!vm_manager.IsWithinAddressSpace(address, size)) {          LOG_ERROR(Kernel_SVC,                    "Given address (0x{:016X}) is outside the bounds of the address space.", address);          return ERR_INVALID_ADDRESS_STATE; @@ -1495,13 +1479,14 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout          return ERR_INVALID_ADDRESS;      } +    auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();      switch (static_cast<AddressArbiter::ArbitrationType>(type)) {      case AddressArbiter::ArbitrationType::WaitIfLessThan: -        return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); +        return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, false);      case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: -        return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); +        return address_arbiter.WaitForAddressIfLessThan(address, value, timeout, true);      case AddressArbiter::ArbitrationType::WaitIfEqual: -        return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); +        return address_arbiter.WaitForAddressIfEqual(address, value, timeout);      default:          LOG_ERROR(Kernel_SVC,                    "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " @@ -1526,13 +1511,14 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to          return ERR_INVALID_ADDRESS;      } +    auto& address_arbiter = Core::System::GetInstance().Kernel().AddressArbiter();      switch (static_cast<AddressArbiter::SignalType>(type)) {      case AddressArbiter::SignalType::Signal: -        return AddressArbiter::SignalToAddress(address, num_to_wake); +        return address_arbiter.SignalToAddress(address, num_to_wake);      case AddressArbiter::SignalType::IncrementAndSignalIfEqual: -        return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); +        return address_arbiter.IncrementAndSignalToAddressIfEqual(address, value, num_to_wake);      case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: -        return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, +        return address_arbiter.ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,                                                                               num_to_wake);      default:          LOG_ERROR(Kernel_SVC, diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6661e2130..eb54d6651 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -184,8 +184,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name          return ERR_INVALID_PROCESSOR_ID;      } -    // TODO(yuriks): Other checks, returning 0xD9001BEA -      if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {          LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);          // TODO (bunnei): Find the correct error code to use here diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 10ad94aa6..05c59af34 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -17,8 +17,8 @@  #include "core/memory_setup.h"  namespace Kernel { - -static const char* GetMemoryStateName(MemoryState state) { +namespace { +const char* GetMemoryStateName(MemoryState state) {      static constexpr const char* names[] = {          "Unmapped",         "Io",          "Normal",           "CodeStatic", @@ -35,6 +35,14 @@ static const char* GetMemoryStateName(MemoryState state) {      return names[ToSvcMemoryState(state)];  } +// Checks if a given address range lies within a larger address range. +constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin, +                                    VAddr address_range_end) { +    const VAddr end_address = address + size - 1; +    return address_range_begin <= address && end_address <= address_range_end - 1; +} +} // Anonymous namespace +  bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {      ASSERT(base + size == next.base);      if (permissions != next.permissions || state != next.state || attribute != next.attribute || @@ -249,8 +257,7 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p  }  ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { -    if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || -        target + size < target) { +    if (!IsWithinHeapRegion(target, size)) {          return ERR_INVALID_ADDRESS;      } @@ -285,8 +292,7 @@ ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission p  }  ResultCode VMManager::HeapFree(VAddr target, u64 size) { -    if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() || -        target + size < target) { +    if (!IsWithinHeapRegion(target, size)) {          return ERR_INVALID_ADDRESS;      } @@ -706,6 +712,11 @@ u64 VMManager::GetAddressSpaceWidth() const {      return address_space_width;  } +bool VMManager::IsWithinAddressSpace(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetAddressSpaceBaseAddress(), +                                GetAddressSpaceEndAddress()); +} +  VAddr VMManager::GetASLRRegionBaseAddress() const {      return aslr_region_base;  } @@ -750,6 +761,11 @@ u64 VMManager::GetCodeRegionSize() const {      return code_region_end - code_region_base;  } +bool VMManager::IsWithinCodeRegion(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetCodeRegionBaseAddress(), +                                GetCodeRegionEndAddress()); +} +  VAddr VMManager::GetHeapRegionBaseAddress() const {      return heap_region_base;  } @@ -762,6 +778,11 @@ u64 VMManager::GetHeapRegionSize() const {      return heap_region_end - heap_region_base;  } +bool VMManager::IsWithinHeapRegion(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetHeapRegionBaseAddress(), +                                GetHeapRegionEndAddress()); +} +  VAddr VMManager::GetMapRegionBaseAddress() const {      return map_region_base;  } @@ -774,6 +795,10 @@ u64 VMManager::GetMapRegionSize() const {      return map_region_end - map_region_base;  } +bool VMManager::IsWithinMapRegion(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetMapRegionBaseAddress(), GetMapRegionEndAddress()); +} +  VAddr VMManager::GetNewMapRegionBaseAddress() const {      return new_map_region_base;  } @@ -786,6 +811,11 @@ u64 VMManager::GetNewMapRegionSize() const {      return new_map_region_end - new_map_region_base;  } +bool VMManager::IsWithinNewMapRegion(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetNewMapRegionBaseAddress(), +                                GetNewMapRegionEndAddress()); +} +  VAddr VMManager::GetTLSIORegionBaseAddress() const {      return tls_io_region_base;  } @@ -798,4 +828,9 @@ u64 VMManager::GetTLSIORegionSize() const {      return tls_io_region_end - tls_io_region_base;  } +bool VMManager::IsWithinTLSIORegion(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetTLSIORegionBaseAddress(), +                                GetTLSIORegionEndAddress()); +} +  } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 6091533bc..88e0b3c02 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -432,18 +432,21 @@ public:      /// Gets the address space width in bits.      u64 GetAddressSpaceWidth() const; +    /// Determines whether or not the given address range lies within the address space. +    bool IsWithinAddressSpace(VAddr address, u64 size) const; +      /// Gets the base address of the ASLR region.      VAddr GetASLRRegionBaseAddress() const;      /// Gets the end address of the ASLR region.      VAddr GetASLRRegionEndAddress() const; -    /// Determines whether or not the specified address range is within the ASLR region. -    bool IsWithinASLRRegion(VAddr address, u64 size) const; -      /// Gets the size of the ASLR region      u64 GetASLRRegionSize() const; +    /// Determines whether or not the specified address range is within the ASLR region. +    bool IsWithinASLRRegion(VAddr address, u64 size) const; +      /// Gets the base address of the code region.      VAddr GetCodeRegionBaseAddress() const; @@ -453,6 +456,9 @@ public:      /// Gets the total size of the code region in bytes.      u64 GetCodeRegionSize() const; +    /// Determines whether or not the specified range is within the code region. +    bool IsWithinCodeRegion(VAddr address, u64 size) const; +      /// Gets the base address of the heap region.      VAddr GetHeapRegionBaseAddress() const; @@ -462,6 +468,9 @@ public:      /// Gets the total size of the heap region in bytes.      u64 GetHeapRegionSize() const; +    /// Determines whether or not the specified range is within the heap region. +    bool IsWithinHeapRegion(VAddr address, u64 size) const; +      /// Gets the base address of the map region.      VAddr GetMapRegionBaseAddress() const; @@ -471,6 +480,9 @@ public:      /// Gets the total size of the map region in bytes.      u64 GetMapRegionSize() const; +    /// Determines whether or not the specified range is within the map region. +    bool IsWithinMapRegion(VAddr address, u64 size) const; +      /// Gets the base address of the new map region.      VAddr GetNewMapRegionBaseAddress() const; @@ -480,6 +492,9 @@ public:      /// Gets the total size of the new map region in bytes.      u64 GetNewMapRegionSize() const; +    /// Determines whether or not the given address range is within the new map region +    bool IsWithinNewMapRegion(VAddr address, u64 size) const; +      /// Gets the base address of the TLS IO region.      VAddr GetTLSIORegionBaseAddress() const; @@ -489,6 +504,9 @@ public:      /// Gets the total size of the TLS IO region in bytes.      u64 GetTLSIORegionSize() const; +    /// Determines if the given address range is within the TLS IO region. +    bool IsWithinTLSIORegion(VAddr address, u64 size) const; +      /// Each VMManager has its own page table, which is set as the main one when the owning process      /// is scheduled.      Memory::PageTable page_table; diff --git a/src/core/hle/result.h b/src/core/hle/result.h index bfb77cc31..1ed144481 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -8,7 +8,6 @@  #include <utility>  #include "common/assert.h"  #include "common/bit_field.h" -#include "common/common_funcs.h"  #include "common/common_types.h"  // All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index f255f74b5..8c5bd6059 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -7,6 +7,7 @@  #include "common/string_util.h"  #include "core/core.h"  #include "core/frontend/applets/software_keyboard.h" +#include "core/hle/result.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/am/applets/software_keyboard.h" diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index efd5753a1..b93a30d28 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -9,10 +9,13 @@  #include <vector>  #include "common/common_funcs.h" +#include "common/common_types.h"  #include "common/swap.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/am/applets/applets.h" +union ResultCode; +  namespace Service::AM::Applets {  enum class KeysetDisable : u32 { diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 6831c0735..21f5e64c7 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -18,17 +18,11 @@  #include "core/hle/kernel/readable_event.h"  #include "core/hle/kernel/writable_event.h"  #include "core/hle/service/audio/audout_u.h" +#include "core/hle/service/audio/errors.h"  #include "core/memory.h"  namespace Service::Audio { -namespace ErrCodes { -enum { -    ErrorUnknown = 2, -    BufferCountExceeded = 8, -}; -} -  constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};  constexpr int DefaultSampleRate{48000}; @@ -100,7 +94,7 @@ private:          if (stream->IsPlaying()) {              IPC::ResponseBuilder rb{ctx, 2}; -            rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown)); +            rb.Push(ERR_OPERATION_FAILED);              return;          } @@ -113,7 +107,9 @@ private:      void StopAudioOut(Kernel::HLERequestContext& ctx) {          LOG_DEBUG(Service_Audio, "called"); -        audio_core.StopStream(stream); +        if (stream->IsPlaying()) { +            audio_core.StopStream(stream); +        }          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); @@ -143,7 +139,8 @@ private:          if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {              IPC::ResponseBuilder rb{ctx, 2}; -            rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded)); +            rb.Push(ERR_BUFFER_COUNT_EXCEEDED); +            return;          }          IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 7e0cc64a8..c9de10a24 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -17,6 +17,7 @@  #include "core/hle/kernel/readable_event.h"  #include "core/hle/kernel/writable_event.h"  #include "core/hle/service/audio/audren_u.h" +#include "core/hle/service/audio/errors.h"  namespace Service::Audio { @@ -37,7 +38,7 @@ public:              {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},              {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},              {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"}, -            {11, nullptr, "ExecuteAudioRendererRendering"}, +            {11, &IAudioRenderer::ExecuteAudioRendererRendering, "ExecuteAudioRendererRendering"},          };          // clang-format on          RegisterHandlers(functions); @@ -138,6 +139,17 @@ private:          rb.Push(rendering_time_limit_percent);      } +    void ExecuteAudioRendererRendering(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_Audio, "called"); + +        // This service command currently only reports an unsupported operation +        // error code, or aborts. Given that, we just always return an error +        // code in this case. + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(ERR_NOT_SUPPORTED); +    } +      Kernel::EventPair system_event;      std::unique_ptr<AudioCore::AudioRenderer> renderer;      u32 rendering_time_limit_percent = 100; @@ -235,7 +247,7 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {          {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},          {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},          {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"}, -        {3, nullptr, "OpenAudioRendererAuto"}, +        {3, &AudRenU::OpenAudioRendererAuto, "OpenAudioRendererAuto"},          {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},      };      // clang-format on @@ -248,12 +260,7 @@ AudRenU::~AudRenU() = default;  void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_Audio, "called"); -    IPC::RequestParser rp{ctx}; -    auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); -    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - -    rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); +    OpenAudioRendererImpl(ctx);  }  void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { @@ -262,20 +269,20 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_Audio, "called");      u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); -    buffer_sz += params.unknown_c * 1024; -    buffer_sz += 0x940 * (params.unknown_c + 1); +    buffer_sz += params.submix_count * 1024; +    buffer_sz += 0x940 * (params.submix_count + 1);      buffer_sz += 0x3F0 * params.voice_count; -    buffer_sz += Common::AlignUp(8 * (params.unknown_c + 1), 0x10); +    buffer_sz += Common::AlignUp(8 * (params.submix_count + 1), 0x10);      buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10); -    buffer_sz += -        Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) * -                            (params.mix_buffer_count + 6), -                        0x40); +    buffer_sz += Common::AlignUp( +        (0x3C0 * (params.sink_count + params.submix_count) + 4 * params.sample_count) * +            (params.mix_buffer_count + 6), +        0x40);      if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { -        u32 count = params.unknown_c + 1; +        const u32 count = params.submix_count + 1;          u64 node_count = Common::AlignUp(count, 0x40); -        u64 node_state_buffer_sz = +        const u64 node_state_buffer_sz =              4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8);          u64 edge_matrix_buffer_sz = 0;          node_count = Common::AlignUp(count * count, 0x40); @@ -289,19 +296,19 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {      buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50;      if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) { -        buffer_sz += 0xE0 * params.unknown_2c; +        buffer_sz += 0xE0 * params.num_splitter_send_channels;          buffer_sz += 0x20 * params.splitter_count; -        buffer_sz += Common::AlignUp(4 * params.unknown_2c, 0x10); +        buffer_sz += Common::AlignUp(4 * params.num_splitter_send_channels, 0x10);      }      buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count;      u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count +                      ((params.voice_count * 256) | 0x40); -    if (params.unknown_1c >= 1) { +    if (params.performance_frame_count >= 1) {          output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count +                                        16 * params.voice_count + 16) +                                       0x658) * -                                            (params.unknown_1c + 1) + +                                            (params.performance_frame_count + 1) +                                          0xc0,                                      0x40) +                      output_sz; @@ -325,6 +332,12 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {      rb.PushIpcInterface<Audio::IAudioDevice>();  } +void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_Audio, "called"); + +    OpenAudioRendererImpl(ctx); +} +  void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {      LOG_WARNING(Service_Audio, "(STUBBED) called"); @@ -335,6 +348,15 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c                                                  // based on the current revision  } +void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<IAudioRenderer>(params); +} +  bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {      u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap      switch (feature) { diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h index 3d63388fb..e55d25973 100644 --- a/src/core/hle/service/audio/audren_u.h +++ b/src/core/hle/service/audio/audren_u.h @@ -21,8 +21,11 @@ private:      void OpenAudioRenderer(Kernel::HLERequestContext& ctx);      void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);      void GetAudioDeviceService(Kernel::HLERequestContext& ctx); +    void OpenAudioRendererAuto(Kernel::HLERequestContext& ctx);      void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx); +    void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); +      enum class AudioFeatures : u32 {          Splitter,      }; diff --git a/src/core/hle/service/audio/errors.h b/src/core/hle/service/audio/errors.h new file mode 100644 index 000000000..6f8c09bcf --- /dev/null +++ b/src/core/hle/service/audio/errors.h @@ -0,0 +1,15 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Service::Audio { + +constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::Audio, 2}; +constexpr ResultCode ERR_BUFFER_COUNT_EXCEEDED{ErrorModule::Audio, 8}; +constexpr ResultCode ERR_NOT_SUPPORTED{ErrorModule::Audio, 513}; + +} // namespace Service::Audio diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 6d897c842..7cc58db4c 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -15,7 +15,7 @@ namespace Kernel {  class SharedMemory;  } -namespace SM { +namespace Service::SM {  class ServiceManager;  } diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 21ccfe1f8..20c7c39aa 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -23,7 +23,7 @@ u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, std::vector  void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,                          u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, -                        const MathUtil::Rectangle<int>& crop_rect) { +                        const Common::Rectangle<int>& crop_rect) {      VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);      LOG_TRACE(Service,                "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", @@ -36,7 +36,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3      auto& instance = Core::System::GetInstance();      instance.GetPerfStats().EndGameFrame(); -    instance.Renderer().SwapBuffers(framebuffer); +    instance.GPU().SwapBuffers(framebuffer);  }  } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index a45086e45..ace71169f 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -25,7 +25,7 @@ public:      /// Performs a screen flip, drawing the buffer pointed to by the handle.      void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,                NVFlinger::BufferQueue::BufferTransformFlags transform, -              const MathUtil::Rectangle<int>& crop_rect); +              const Common::Rectangle<int>& crop_rect);  private:      std::shared_ptr<nvmap> nvmap_dev; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 466db7ccd..a34b9e753 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -178,7 +178,7 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou      auto& gpu = system_instance.GPU();      auto cpu_addr = gpu.MemoryManager().GpuToCpuAddress(params.offset);      ASSERT(cpu_addr); -    system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(*cpu_addr, itr->second.size); +    gpu.FlushAndInvalidateRegion(*cpu_addr, itr->second.size);      params.offset = gpu.MemoryManager().UnmapBuffer(params.offset, itr->second.size); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 0a650f36c..8ce7bc7a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -136,16 +136,6 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<      return 0;  } -static void PushGPUEntries(Tegra::CommandList&& entries) { -    if (entries.empty()) { -        return; -    } - -    auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()}; -    dma_pusher.Push(std::move(entries)); -    dma_pusher.DispatchCalls(); -} -  u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {      if (input.size() < sizeof(IoctlSubmitGpfifo)) {          UNIMPLEMENTED(); @@ -163,7 +153,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp      std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],                  params.num_entries * sizeof(Tegra::CommandListHeader)); -    PushGPUEntries(std::move(entries)); +    Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries));      params.fence_out.id = 0;      params.fence_out.value = 0; @@ -184,7 +174,7 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)      Memory::ReadBlock(params.address, entries.data(),                        params.num_entries * sizeof(Tegra::CommandListHeader)); -    PushGPUEntries(std::move(entries)); +    Core::System::GetInstance().GPU().PushGPUEntries(std::move(entries));      params.fence_out.id = 0;      params.fence_out.value = 0; diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index fc07d9bb8..4d150fc71 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -63,7 +63,7 @@ const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {  }  void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, -                              const MathUtil::Rectangle<int>& crop_rect) { +                              const Common::Rectangle<int>& crop_rect) {      auto itr = std::find_if(queue.begin(), queue.end(),                              [&](const Buffer& buffer) { return buffer.slot == slot; });      ASSERT(itr != queue.end()); diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index ab90d591e..e1ccb6171 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -67,14 +67,14 @@ public:          Status status = Status::Free;          IGBPBuffer igbp_buffer;          BufferTransformFlags transform; -        MathUtil::Rectangle<int> crop_rect; +        Common::Rectangle<int> crop_rect;      };      void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);      std::optional<u32> DequeueBuffer(u32 width, u32 height);      const IGBPBuffer& RequestBuffer(u32 slot) const;      void QueueBuffer(u32 slot, BufferTransformFlags transform, -                     const MathUtil::Rectangle<int>& crop_rect); +                     const Common::Rectangle<int>& crop_rect);      std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();      void ReleaseBuffer(u32 slot);      u32 Query(QueryType type); diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 56f31e2ac..fc496b654 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -186,7 +186,7 @@ void NVFlinger::Compose() {              // There was no queued buffer to draw, render previous frame              system_instance.GetPerfStats().EndGameFrame(); -            system_instance.Renderer().SwapBuffers({}); +            system_instance.GPU().SwapBuffers({});              continue;          } diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 74da4d5e6..e9ee73710 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -30,7 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};      rb.Push(RESULT_SUCCESS); -    Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; +    Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client};      rb.PushMoveObjects(session);      LOG_DEBUG(Service, "session={}", session->GetObjectId()); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 74384a24d..a975767bb 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -420,7 +420,7 @@ public:          u32_le fence_is_valid;          std::array<Fence, 2> fences; -        MathUtil::Rectangle<int> GetCropRect() const { +        Common::Rectangle<int> GetCropRect() const {              return {crop_left, crop_top, crop_right, crop_bottom};          }      }; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index e9166dbd9..6591c45d2 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -71,15 +71,20 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa                                   FlushMode::FlushAndInvalidate);      VAddr end = base + size; -    while (base != end) { -        ASSERT_MSG(base < page_table.pointers.size(), "out of range mapping at {:016X}", base); +    ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", +               base + page_table.pointers.size()); -        page_table.attributes[base] = type; -        page_table.pointers[base] = memory; +    std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type); -        base += 1; -        if (memory != nullptr) +    if (memory == nullptr) { +        std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end, memory); +    } else { +        while (base != end) { +            page_table.pointers[base] = memory; + +            base += 1;              memory += PAGE_SIZE; +        }      }  } @@ -166,9 +171,6 @@ T Read(const VAddr vaddr) {          return value;      } -    // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); -      PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];      switch (type) {      case PageType::Unmapped: @@ -199,9 +201,6 @@ void Write(const VAddr vaddr, const T data) {          return;      } -    // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state -    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); -      PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];      switch (type) {      case PageType::Unmapped: @@ -357,16 +356,16 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {          const VAddr overlap_end = std::min(end, region_end);          const VAddr overlap_size = overlap_end - overlap_start; -        auto& rasterizer = system_instance.Renderer().Rasterizer(); +        auto& gpu = system_instance.GPU();          switch (mode) {          case FlushMode::Flush: -            rasterizer.FlushRegion(overlap_start, overlap_size); +            gpu.FlushRegion(overlap_start, overlap_size);              break;          case FlushMode::Invalidate: -            rasterizer.InvalidateRegion(overlap_start, overlap_size); +            gpu.InvalidateRegion(overlap_start, overlap_size);              break;          case FlushMode::FlushAndInvalidate: -            rasterizer.FlushAndInvalidateRegion(overlap_start, overlap_size); +            gpu.FlushAndInvalidateRegion(overlap_start, overlap_size);              break;          }      }; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2e232e1e7..6dd3139cc 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -91,7 +91,10 @@ void LogSettings() {      LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);      LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit);      LogSetting("Renderer_FrameLimit", Settings::values.frame_limit); +    LogSetting("Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache);      LogSetting("Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation); +    LogSetting("Renderer_UseAsynchronousGpuEmulation", +               Settings::values.use_asynchronous_gpu_emulation);      LogSetting("Audio_OutputEngine", Settings::values.sink_id);      LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);      LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); diff --git a/src/core/settings.h b/src/core/settings.h index 7e76e0466..cdfb2f742 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -393,6 +393,7 @@ struct Values {      u16 frame_limit;      bool use_disk_shader_cache;      bool use_accurate_gpu_emulation; +    bool use_asynchronous_gpu_emulation;      float bg_red;      float bg_green; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 58dfcc4df..e1db06811 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -162,6 +162,8 @@ TelemetrySession::TelemetrySession() {               Settings::values.use_disk_shader_cache);      AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateGpuEmulation",               Settings::values.use_accurate_gpu_emulation); +    AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAsynchronousGpuEmulation", +             Settings::values.use_asynchronous_gpu_emulation);      AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode",               Settings::values.use_docked_mode);  } | 
