diff options
28 files changed, 187 insertions, 118 deletions
| diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index ed1e93cc2..59b999935 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -3,19 +3,20 @@  // Refer to the license.txt file included.  #include <algorithm> -#include <array> +#include <atomic>  #include <chrono>  #include <climits>  #include <condition_variable>  #include <memory> +#include <mutex>  #include <thread> +#include <vector>  #ifdef _WIN32  #include <share.h> // For _SH_DENYWR  #else  #define _SH_DENYWR 0  #endif  #include "common/assert.h" -#include "common/common_funcs.h" // snprintf compatibility define  #include "common/logging/backend.h"  #include "common/logging/log.h"  #include "common/logging/text_formatter.h" @@ -48,11 +49,11 @@ public:          backends.push_back(std::move(backend));      } -    void RemoveBackend(const std::string& backend_name) { +    void RemoveBackend(std::string_view backend_name) {          std::lock_guard<std::mutex> lock(writing_mutex); -        auto it = std::remove_if(backends.begin(), backends.end(), [&backend_name](const auto& i) { -            return !strcmp(i->GetName(), backend_name.c_str()); -        }); +        const auto it = +            std::remove_if(backends.begin(), backends.end(), +                           [&backend_name](const auto& i) { return backend_name == i->GetName(); });          backends.erase(it, backends.end());      } @@ -64,10 +65,10 @@ public:          filter = f;      } -    Backend* GetBackend(const std::string& backend_name) { -        auto it = std::find_if(backends.begin(), backends.end(), [&backend_name](const auto& i) { -            return !strcmp(i->GetName(), backend_name.c_str()); -        }); +    Backend* GetBackend(std::string_view backend_name) { +        const auto it = +            std::find_if(backends.begin(), backends.end(), +                         [&backend_name](const auto& i) { return backend_name == i->GetName(); });          if (it == backends.end())              return nullptr;          return it->get(); @@ -265,11 +266,11 @@ void AddBackend(std::unique_ptr<Backend> backend) {      Impl::Instance().AddBackend(std::move(backend));  } -void RemoveBackend(const std::string& backend_name) { +void RemoveBackend(std::string_view backend_name) {      Impl::Instance().RemoveBackend(backend_name);  } -Backend* GetBackend(const std::string& backend_name) { +Backend* GetBackend(std::string_view backend_name) {      return Impl::Instance().GetBackend(backend_name);  } diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 57cdf6b2d..b3f4b9cef 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h @@ -4,10 +4,9 @@  #pragma once  #include <chrono> -#include <cstdarg>  #include <memory>  #include <string> -#include <utility> +#include <string_view>  #include "common/file_util.h"  #include "common/logging/filter.h"  #include "common/logging/log.h" @@ -106,9 +105,9 @@ private:  void AddBackend(std::unique_ptr<Backend> backend); -void RemoveBackend(const std::string& backend_name); +void RemoveBackend(std::string_view backend_name); -Backend* GetBackend(const std::string& backend_name); +Backend* GetBackend(std::string_view backend_name);  /**   * Returns the name of the passed log class as a C-string. Subclasses are separated by periods diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 6ed087beb..2dd331152 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -8,39 +8,9 @@  #include "common/string_util.h"  namespace Log { - -Filter::Filter(Level default_level) { -    ResetAll(default_level); -} - -void Filter::ResetAll(Level level) { -    class_levels.fill(level); -} - -void Filter::SetClassLevel(Class log_class, Level level) { -    class_levels[static_cast<size_t>(log_class)] = level; -} - -void Filter::ParseFilterString(const std::string& filter_str) { -    auto clause_begin = filter_str.cbegin(); -    while (clause_begin != filter_str.cend()) { -        auto clause_end = std::find(clause_begin, filter_str.cend(), ' '); - -        // If clause isn't empty -        if (clause_end != clause_begin) { -            ParseFilterRule(clause_begin, clause_end); -        } - -        if (clause_end != filter_str.cend()) { -            // Skip over the whitespace -            ++clause_end; -        } -        clause_begin = clause_end; -    } -} - +namespace {  template <typename It> -static Level GetLevelByName(const It begin, const It end) { +Level GetLevelByName(const It begin, const It end) {      for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) {          const char* level_name = GetLevelName(static_cast<Level>(i));          if (Common::ComparePartialString(begin, end, level_name)) { @@ -51,7 +21,7 @@ static Level GetLevelByName(const It begin, const It end) {  }  template <typename It> -static Class GetClassByName(const It begin, const It end) { +Class GetClassByName(const It begin, const It end) {      for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) {          const char* level_name = GetLogClassName(static_cast<Class>(i));          if (Common::ComparePartialString(begin, end, level_name)) { @@ -61,8 +31,8 @@ static Class GetClassByName(const It begin, const It end) {      return Class::Count;  } -bool Filter::ParseFilterRule(const std::string::const_iterator begin, -                             const std::string::const_iterator end) { +template <typename Iterator> +bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {      auto level_separator = std::find(begin, end, ':');      if (level_separator == end) {          LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", @@ -77,7 +47,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,      }      if (Common::ComparePartialString(begin, level_separator, "*")) { -        ResetAll(level); +        instance.ResetAll(level);          return true;      } @@ -87,9 +57,40 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,          return false;      } -    SetClassLevel(log_class, level); +    instance.SetClassLevel(log_class, level);      return true;  } +} // Anonymous namespace + +Filter::Filter(Level default_level) { +    ResetAll(default_level); +} + +void Filter::ResetAll(Level level) { +    class_levels.fill(level); +} + +void Filter::SetClassLevel(Class log_class, Level level) { +    class_levels[static_cast<size_t>(log_class)] = level; +} + +void Filter::ParseFilterString(std::string_view filter_view) { +    auto clause_begin = filter_view.cbegin(); +    while (clause_begin != filter_view.cend()) { +        auto clause_end = std::find(clause_begin, filter_view.cend(), ' '); + +        // If clause isn't empty +        if (clause_end != clause_begin) { +            ParseFilterRule(*this, clause_begin, clause_end); +        } + +        if (clause_end != filter_view.cend()) { +            // Skip over the whitespace +            ++clause_end; +        } +        clause_begin = clause_end; +    } +}  bool Filter::CheckMessage(Class log_class, Level level) const {      return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]); diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h index 2a4f7c845..d5ffc5a58 100644 --- a/src/common/logging/filter.h +++ b/src/common/logging/filter.h @@ -6,7 +6,7 @@  #include <array>  #include <cstddef> -#include <string> +#include <string_view>  #include "common/logging/log.h"  namespace Log { @@ -40,9 +40,7 @@ public:       *  - `Service:Info` -- Sets the level of Service to Info.       *  - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.       */ -    void ParseFilterString(const std::string& filter_str); -    bool ParseFilterRule(const std::string::const_iterator start, -                         const std::string::const_iterator end); +    void ParseFilterString(std::string_view filter_view);      /// Matches class/level combination against the filter, returning true if it passed.      bool CheckMessage(Class log_class, Level level) const; diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp index e0df430ab..9526ca0c6 100644 --- a/src/common/param_package.cpp +++ b/src/common/param_package.cpp @@ -3,7 +3,9 @@  // Refer to the license.txt file included.  #include <array> +#include <utility>  #include <vector> +  #include "common/logging/log.h"  #include "common/param_package.h"  #include "common/string_util.h" @@ -12,10 +14,11 @@ namespace Common {  constexpr char KEY_VALUE_SEPARATOR = ':';  constexpr char PARAM_SEPARATOR = ','; +  constexpr char ESCAPE_CHARACTER = '$'; -const std::string KEY_VALUE_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '0'}; -const std::string PARAM_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '1'}; -const std::string ESCAPE_CHARACTER_ESCAPE{ESCAPE_CHARACTER, '2'}; +constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0"; +constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1"; +constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2";  ParamPackage::ParamPackage(const std::string& serialized) {      std::vector<std::string> pairs; @@ -35,7 +38,7 @@ ParamPackage::ParamPackage(const std::string& serialized) {              part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER});          } -        Set(key_value[0], key_value[1]); +        Set(key_value[0], std::move(key_value[1]));      }  } @@ -101,16 +104,16 @@ float ParamPackage::Get(const std::string& key, float default_value) const {      }  } -void ParamPackage::Set(const std::string& key, const std::string& value) { -    data[key] = value; +void ParamPackage::Set(const std::string& key, std::string value) { +    data.insert_or_assign(key, std::move(value));  }  void ParamPackage::Set(const std::string& key, int value) { -    data[key] = std::to_string(value); +    data.insert_or_assign(key, std::to_string(value));  }  void ParamPackage::Set(const std::string& key, float value) { -    data[key] = std::to_string(value); +    data.insert_or_assign(key, std::to_string(value));  }  bool ParamPackage::Has(const std::string& key) const { diff --git a/src/common/param_package.h b/src/common/param_package.h index c4c11b221..7842cd4ef 100644 --- a/src/common/param_package.h +++ b/src/common/param_package.h @@ -28,7 +28,7 @@ public:      std::string Get(const std::string& key, const std::string& default_value) const;      int Get(const std::string& key, int default_value) const;      float Get(const std::string& key, float default_value) const; -    void Set(const std::string& key, const std::string& value); +    void Set(const std::string& key, std::string value);      void Set(const std::string& key, int value);      void Set(const std::string& key, float value);      bool Has(const std::string& key) const; diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 8416e73b0..28a99defe 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -104,6 +104,10 @@ public:      virtual void SetTlsAddress(VAddr address) = 0; +    virtual u64 GetTPIDR_EL0() const = 0; + +    virtual void SetTPIDR_EL0(u64 value) = 0; +      /**       * Saves the current CPU context       * @param ctx Thread context to save diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 3572ee7b9..df47d5ee8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -196,6 +196,14 @@ void ARM_Dynarmic::SetTlsAddress(u64 address) {      cb->tpidrro_el0 = address;  } +u64 ARM_Dynarmic::GetTPIDR_EL0() const { +    return cb->tpidr_el0; +} + +void ARM_Dynarmic::SetTPIDR_EL0(u64 value) { +    cb->tpidr_el0 = value; +} +  void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {      ctx.cpu_registers = jit->GetRegisters();      ctx.sp = jit->GetSP(); diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index ed724c3f1..a9891ac4f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -34,6 +34,8 @@ public:      void SetCPSR(u32 cpsr) override;      VAddr GetTlsAddress() const override;      void SetTlsAddress(VAddr address) override; +    void SetTPIDR_EL0(u64 value) override; +    u64 GetTPIDR_EL0() const override;      void SaveContext(ThreadContext& ctx) override;      void LoadContext(const ThreadContext& ctx) override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index d2d699e9b..44a46bf04 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -169,6 +169,16 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) {      CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));  } +u64 ARM_Unicorn::GetTPIDR_EL0() const { +    u64 value{}; +    CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value)); +    return value; +} + +void ARM_Unicorn::SetTPIDR_EL0(u64 value) { +    CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value)); +} +  void ARM_Unicorn::Run() {      if (GDBStub::IsServerEnabled()) {          ExecuteInstructions(std::max(4000000, 0)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index a78a0acf2..af7943352 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -28,6 +28,8 @@ public:      void SetCPSR(u32 cpsr) override;      VAddr GetTlsAddress() const override;      void SetTlsAddress(VAddr address) override; +    void SetTPIDR_EL0(u64 value) override; +    u64 GetTPIDR_EL0() const override;      void SaveContext(ThreadContext& ctx) override;      void LoadContext(const ThreadContext& ctx) override;      void PrepareReschedule() override; diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index a152dbd33..fea0593c7 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h @@ -20,13 +20,13 @@ enum {  constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound);  // TODO(bunnei): Replace these with correct errors for Switch OS -constexpr ResultCode ERROR_INVALID_PATH(ResultCode(-1)); -constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(ResultCode(-1)); -constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(ResultCode(-1)); -constexpr ResultCode ERROR_FILE_NOT_FOUND(ResultCode(-1)); -constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(ResultCode(-1)); -constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(ResultCode(-1)); -constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(ResultCode(-1)); -constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(ResultCode(-1)); +constexpr ResultCode ERROR_INVALID_PATH(-1); +constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1); +constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1); +constexpr ResultCode ERROR_FILE_NOT_FOUND(-1); +constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1); +constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1); +constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1); +constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1);  } // namespace FileSys diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 16c8ad90b..3f690f12a 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -42,7 +42,7 @@ bool VfsFile::WriteByte(u8 data, size_t offset) {      return Write(&data, 1, offset) == 1;  } -size_t VfsFile::WriteBytes(std::vector<u8> data, size_t offset) { +size_t VfsFile::WriteBytes(const std::vector<u8>& data, size_t offset) {      return Write(data.data(), data.size(), offset);  } diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index a5213e0cc..db3c77eac 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -59,8 +59,7 @@ struct VfsFile : NonCopyable {      // Returns the number of bytes (sizeof(T)*number_elements) read successfully.      template <typename T>      size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const { -        static_assert(std::is_trivially_copyable<T>::value, -                      "Data type must be trivially copyable."); +        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");          return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);      } @@ -69,8 +68,7 @@ struct VfsFile : NonCopyable {      // Returns the number of bytes read successfully.      template <typename T>      size_t ReadBytes(T* data, size_t size, size_t offset = 0) const { -        static_assert(std::is_trivially_copyable<T>::value, -                      "Data type must be trivially copyable."); +        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");          return Read(reinterpret_cast<u8*>(data), size, offset);      } @@ -78,8 +76,7 @@ struct VfsFile : NonCopyable {      // Returns the number of bytes read successfully (sizeof(T)).      template <typename T>      size_t ReadObject(T* data, size_t offset = 0) const { -        static_assert(std::is_trivially_copyable<T>::value, -                      "Data type must be trivially copyable."); +        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");          return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);      } @@ -88,33 +85,29 @@ struct VfsFile : NonCopyable {      virtual bool WriteByte(u8 data, size_t offset = 0);      // Writes a vector of bytes to offset in file and returns the number of bytes successfully      // written. -    virtual size_t WriteBytes(std::vector<u8> data, size_t offset = 0); +    virtual size_t WriteBytes(const std::vector<u8>& data, size_t offset = 0);      // Writes an array of type T, size number_elements to offset in file.      // Returns the number of bytes (sizeof(T)*number_elements) written successfully.      template <typename T> -    size_t WriteArray(T* data, size_t number_elements, size_t offset = 0) { -        static_assert(std::is_trivially_copyable<T>::value, -                      "Data type must be trivially copyable."); - +    size_t WriteArray(const T* data, size_t number_elements, size_t offset = 0) { +        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");          return Write(data, number_elements * sizeof(T), offset);      }      // Writes size bytes starting at memory location data to offset in file.      // Returns the number of bytes written successfully.      template <typename T> -    size_t WriteBytes(T* data, size_t size, size_t offset = 0) { -        static_assert(std::is_trivially_copyable<T>::value, -                      "Data type must be trivially copyable."); -        return Write(reinterpret_cast<u8*>(data), size, offset); +    size_t WriteBytes(const T* data, size_t size, size_t offset = 0) { +        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable."); +        return Write(reinterpret_cast<const u8*>(data), size, offset);      }      // Writes one object of type T to offset in file.      // Returns the number of bytes written successfully (sizeof(T)).      template <typename T>      size_t WriteObject(const T& data, size_t offset = 0) { -        static_assert(std::is_trivially_copyable<T>::value, -                      "Data type must be trivially copyable."); +        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");          return Write(&data, sizeof(T), offset);      } diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index 31fdd9aa1..217e02235 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp @@ -2,6 +2,7 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <algorithm>  #include <utility>  #include "core/file_sys/vfs_offset.h" @@ -75,7 +76,7 @@ bool OffsetVfsFile::WriteByte(u8 data, size_t r_offset) {      return false;  } -size_t OffsetVfsFile::WriteBytes(std::vector<u8> data, size_t r_offset) { +size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, size_t r_offset) {      return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);  } @@ -88,7 +89,7 @@ size_t OffsetVfsFile::GetOffset() const {  }  size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const { -    return std::max<size_t>(std::min<size_t>(size - r_offset, r_size), 0); +    return std::clamp(r_size, size_t{0}, size - r_offset);  }  } // namespace FileSys diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index 2e16e47eb..ded4827f5 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -28,7 +28,7 @@ struct OffsetVfsFile : public VfsFile {      std::vector<u8> ReadBytes(size_t size, size_t offset) const override;      std::vector<u8> ReadAllBytes() const override;      bool WriteByte(u8 data, size_t offset) override; -    size_t WriteBytes(std::vector<u8> data, size_t offset) override; +    size_t WriteBytes(const std::vector<u8>& data, size_t offset) override;      bool Rename(const std::string& name) override; diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 24605a273..8b5b06f31 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -175,6 +175,25 @@ public:      void Push(const First& first_value, const Other&... other_values);      /** +     * Helper function for pushing strongly-typed enumeration values. +     * +     * @tparam Enum The enumeration type to be pushed +     * +     * @param value The value to push. +     * +     * @note The underlying size of the enumeration type is the size of the +     *       data that gets pushed. e.g. "enum class SomeEnum : u16" will +     *       push a u16-sized amount of data. +     */ +    template <typename Enum> +    void PushEnum(Enum value) { +        static_assert(std::is_enum_v<Enum>, "T must be an enum type within a PushEnum call."); +        static_assert(!std::is_convertible_v<Enum, int>, +                      "enum type in PushEnum must be a strongly typed enum."); +        Push(static_cast<std::underlying_type_t<Enum>>(value)); +    } + +    /**       * @brief Copies the content of the given trivially copyable class to the buffer as a normal       * param       * @note: The input class must be correctly packed/padded to fit hardware layout. diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index f7e25cbf5..e307eec98 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -56,6 +56,8 @@ void Scheduler::SwitchContext(Thread* new_thread) {      if (previous_thread) {          previous_thread->last_running_ticks = CoreTiming::GetTicks();          cpu_core->SaveContext(previous_thread->context); +        // Save the TPIDR_EL0 system register in case it was modified. +        previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0();          if (previous_thread->status == ThreadStatus::Running) {              // This is only the case when a reschedule is triggered without the current thread @@ -87,6 +89,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {          cpu_core->LoadContext(new_thread->context);          cpu_core->SetTlsAddress(new_thread->GetTLSAddress()); +        cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0());          cpu_core->ClearExclusiveState();      } else {          current_thread = nullptr; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 53f2e861e..cd85c4b7c 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -312,6 +312,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,      thread->status = ThreadStatus::Dormant;      thread->entry_point = entry_point;      thread->stack_top = stack_top; +    thread->tpidr_el0 = 0;      thread->nominal_priority = thread->current_priority = priority;      thread->last_running_ticks = CoreTiming::GetTicks();      thread->processor_id = processor_id; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 47881ec20..6218960d2 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -183,6 +183,14 @@ public:      }      /* +     * Returns the value of the TPIDR_EL0 Read/Write system register for this thread. +     * @returns The value of the TPIDR_EL0 register. +     */ +    u64 GetTPIDR_EL0() const { +        return tpidr_el0; +    } + +    /*       * Returns the address of the current thread's command buffer, located in the TLS.       * @returns VAddr of the thread's command buffer.       */ @@ -213,6 +221,7 @@ public:      s32 processor_id;      VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread +    u64 tpidr_el0;     ///< TPIDR_EL0 read/write system register.      SharedPtr<Process> owner_process; ///< Process that owns this thread diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index 751d73f8d..ce943d829 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp @@ -20,6 +20,21 @@ public:      }  private: +    enum class PerformanceConfiguration : u32 { +        Config1 = 0x00010000, +        Config2 = 0x00010001, +        Config3 = 0x00010002, +        Config4 = 0x00020000, +        Config5 = 0x00020001, +        Config6 = 0x00020002, +        Config7 = 0x00020003, +        Config8 = 0x00020004, +        Config9 = 0x00020005, +        Config10 = 0x00020006, +        Config11 = 0x92220007, +        Config12 = 0x92220008, +    }; +      void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {          IPC::RequestParser rp{ctx}; @@ -40,7 +55,7 @@ private:          IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS); -        rb.Push<u32>(0); // Performance configuration +        rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));          LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));      } diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 19b8667ba..394963a69 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -83,16 +83,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(      VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};      for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",                                 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { -        const VAddr load_addr = next_load_addr;          const FileSys::VirtualFile module_file = dir->GetFile(module); -        if (module_file != nullptr) +        if (module_file != nullptr) { +            const VAddr load_addr = next_load_addr;              next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr); -        if (next_load_addr) {              LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);              // Register module with GDBStub              GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); -        } else { -            next_load_addr = load_addr;          }      } diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index e36483145..a003bc9e3 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -20,7 +20,11 @@ GPU::GPU() {  GPU::~GPU() = default; -const Tegra::Engines::Maxwell3D& GPU::Get3DEngine() const { +const Engines::Maxwell3D& GPU::Maxwell3D() const { +    return *maxwell_3d; +} + +Engines::Maxwell3D& GPU::Maxwell3D() {      return *maxwell_3d;  } diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 60930e997..a32148ecd 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -93,15 +93,14 @@ public:      /// Processes a command list stored at the specified address in GPU memory.      void ProcessCommandList(GPUVAddr address, u32 size); +    /// Returns a const reference to the Maxwell3D GPU engine. +    const Engines::Maxwell3D& Maxwell3D() const; +      /// Returns a reference to the Maxwell3D GPU engine. -    const Engines::Maxwell3D& Get3DEngine() const; +    Engines::Maxwell3D& Maxwell3D();      std::unique_ptr<MemoryManager> memory_manager; -    Engines::Maxwell3D& Maxwell3D() { -        return *maxwell_3d; -    } -  private:      /// Writes a single register in the engine bound to the specified subchannel      void WriteReg(u32 method, u32 subchannel, u32 value, u32 remaining_params); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index f75999557..65a2fd5e8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -634,8 +634,8 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr  u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint program,                                          u32 current_bindpoint,                                          const std::vector<GLShader::ConstBufferEntry>& entries) { -    auto& gpu = Core::System::GetInstance().GPU(); -    auto& maxwell3d = gpu.Get3DEngine(); +    const auto& gpu = Core::System::GetInstance().GPU(); +    const auto& maxwell3d = gpu.Maxwell3D();      // Reset all buffer draw state for this stage.      for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) { @@ -644,7 +644,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr      }      // Upload only the enabled buffers from the 16 constbuffers of each shader stage -    auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)]; +    const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];      for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {          const auto& used_buffer = entries[bindpoint]; @@ -700,8 +700,8 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr  u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit,                                      const std::vector<GLShader::SamplerEntry>& entries) { -    auto& gpu = Core::System::GetInstance().GPU(); -    auto& maxwell3d = gpu.Get3DEngine(); +    const auto& gpu = Core::System::GetInstance().GPU(); +    const auto& maxwell3d = gpu.Maxwell3D();      ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units),                 "Exceeded the number of active textures."); diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 1aa437f76..e81fcbbc4 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp @@ -10,8 +10,9 @@  namespace GLShader {  namespace Impl { -void SetShaderUniformBlockBinding(GLuint shader, const char* name, -                                  Maxwell3D::Regs::ShaderStage binding, size_t expected_size) { +static void SetShaderUniformBlockBinding(GLuint shader, const char* name, +                                         Maxwell3D::Regs::ShaderStage binding, +                                         size_t expected_size) {      GLuint ub_index = glGetUniformBlockIndex(shader, name);      if (ub_index != GL_INVALID_INDEX) {          GLint ub_size = 0; diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 4295c20a6..e29d551e1 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h @@ -21,7 +21,6 @@ using Tegra::Engines::Maxwell3D;  namespace Impl {  void SetShaderUniformBlockBindings(GLuint shader); -void SetShaderSamplerBindings(GLuint shader);  } // namespace Impl  /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp index 1fbca8ad0..c41ff693b 100644 --- a/src/yuzu/debugger/graphics/graphics_surface.cpp +++ b/src/yuzu/debugger/graphics/graphics_surface.cpp @@ -336,9 +336,9 @@ void GraphicsSurfaceWidget::OnUpdate() {          // TODO: Store a reference to the registers in the debug context instead of accessing them          // directly... -        auto& registers = gpu.Get3DEngine().regs; -        auto& rt = registers.rt[static_cast<size_t>(surface_source) - -                                static_cast<size_t>(Source::RenderTarget0)]; +        const auto& registers = gpu.Maxwell3D().regs; +        const auto& rt = registers.rt[static_cast<size_t>(surface_source) - +                                      static_cast<size_t>(Source::RenderTarget0)];          surface_address = rt.Address();          surface_width = rt.width; | 
