diff options
Diffstat (limited to '')
38 files changed, 394 insertions, 147 deletions
diff --git a/src/common/fs/file.h b/src/common/fs/file.h index 209f9664b..50e270c5b 100644 --- a/src/common/fs/file.h +++ b/src/common/fs/file.h @@ -117,7 +117,7 @@ template <typename Path> } #endif -class IOFile final : NonCopyable { +class IOFile final { public: IOFile(); @@ -142,7 +142,10 @@ public: FileType type = FileType::BinaryFile, FileShareFlag flag = FileShareFlag::ShareReadOnly); - virtual ~IOFile(); + ~IOFile(); + + IOFile(const IOFile&) = delete; + IOFile& operator=(const IOFile&) = delete; IOFile(IOFile&& other) noexcept; IOFile& operator=(IOFile&& other) noexcept; @@ -441,8 +444,8 @@ public: private: std::filesystem::path file_path; - FileAccessMode file_access_mode; - FileType file_type; + FileAccessMode file_access_mode{}; + FileType file_type{}; std::FILE* file = nullptr; }; diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 9a0151736..689e3ceb5 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -65,9 +65,6 @@ public: /// Step CPU by one instruction virtual void Step() = 0; - /// Exits execution from a callback, the callback must rewind the stack - virtual void ExceptionalExit() = 0; - /// Clear all instruction cache virtual void ClearInstructionCache() = 0; @@ -159,8 +156,6 @@ public: */ virtual void SetTPIDR_EL0(u64 value) = 0; - virtual void ChangeProcessorID(std::size_t new_core_id) = 0; - virtual void SaveContext(ThreadContext32& ctx) = 0; virtual void SaveContext(ThreadContext64& ctx) = 0; virtual void LoadContext(const ThreadContext32& ctx) = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 93d43e22e..e5b78210a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -4,9 +4,9 @@ #include <cinttypes> #include <memory> -#include <dynarmic/A32/a32.h> -#include <dynarmic/A32/config.h> -#include <dynarmic/A32/context.h> +#include <dynarmic/interface/A32/a32.h> +#include <dynarmic/interface/A32/config.h> +#include <dynarmic/interface/A32/context.h> #include "common/assert.h" #include "common/logging/log.h" #include "common/page_table.h" @@ -78,7 +78,9 @@ public: } void CallSVC(u32 swi) override { - Kernel::Svc::Call(parent.system, swi); + parent.svc_called = true; + parent.svc_swi = swi; + parent.jit->HaltExecution(); } void AddTicks(u64 ticks) override { @@ -187,11 +189,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* } void ARM_Dynarmic_32::Run() { - jit->Run(); -} - -void ARM_Dynarmic_32::ExceptionalExit() { - jit->ExceptionalExit(); + while (true) { + jit->Run(); + if (!svc_called) { + break; + } + svc_called = false; + Kernel::Svc::Call(system, svc_swi); + if (shutdown) { + break; + } + } } void ARM_Dynarmic_32::Step() { @@ -255,10 +263,6 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { cp15->uprw = static_cast<u32>(value); } -void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) { - jit->ChangeProcessorID(new_core_id); -} - void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { Dynarmic::A32::Context context; jit->SaveContext(context); @@ -279,6 +283,7 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { void ARM_Dynarmic_32::PrepareReschedule() { jit->HaltExecution(); + shutdown = true; } void ARM_Dynarmic_32::ClearInstructionCache() { diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 42778c02c..063605b46 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -7,9 +7,9 @@ #include <memory> #include <unordered_map> -#include <dynarmic/A32/a32.h> -#include <dynarmic/A64/a64.h> -#include <dynarmic/exclusive_monitor.h> +#include <dynarmic/interface/A32/a32.h> +#include <dynarmic/interface/A64/a64.h> +#include <dynarmic/interface/exclusive_monitor.h> #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" @@ -42,13 +42,11 @@ public: u32 GetPSTATE() const override; void SetPSTATE(u32 pstate) override; void Run() override; - void ExceptionalExit() override; void Step() override; VAddr GetTlsAddress() const override; void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorID(std::size_t new_core_id) override; bool IsInThumbMode() const { return (GetPSTATE() & 0x20) != 0; @@ -83,6 +81,12 @@ private: std::size_t core_index; DynarmicExclusiveMonitor& exclusive_monitor; std::shared_ptr<Dynarmic::A32::Jit> jit; + + // SVC callback + u32 svc_swi{}; + bool svc_called{}; + + bool shutdown{}; }; } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 08fa85904..dd439f55e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -4,8 +4,8 @@ #include <cinttypes> #include <memory> -#include <dynarmic/A64/a64.h> -#include <dynarmic/A64/config.h> +#include <dynarmic/interface/A64/a64.h> +#include <dynarmic/interface/A64/config.h> #include "common/assert.h" #include "common/logging/log.h" #include "common/page_table.h" @@ -102,7 +102,9 @@ public: } void CallSVC(u32 swi) override { - Kernel::Svc::Call(parent.system, swi); + parent.svc_called = true; + parent.svc_swi = swi; + parent.jit->HaltExecution(); } void AddTicks(u64 ticks) override { @@ -227,11 +229,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* } void ARM_Dynarmic_64::Run() { - jit->Run(); -} - -void ARM_Dynarmic_64::ExceptionalExit() { - jit->ExceptionalExit(); + while (true) { + jit->Run(); + if (!svc_called) { + break; + } + svc_called = false; + Kernel::Svc::Call(system, svc_swi); + if (shutdown) { + break; + } + } } void ARM_Dynarmic_64::Step() { @@ -296,10 +304,6 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } -void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) { - jit->ChangeProcessorID(new_core_id); -} - void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); @@ -324,6 +328,7 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { void ARM_Dynarmic_64::PrepareReschedule() { jit->HaltExecution(); + shutdown = true; } void ARM_Dynarmic_64::ClearInstructionCache() { diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index b81fbcc66..0c4e46c64 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -7,7 +7,7 @@ #include <memory> #include <unordered_map> -#include <dynarmic/A64/a64.h> +#include <dynarmic/interface/A64/a64.h> #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" @@ -40,12 +40,10 @@ public: void SetPSTATE(u32 pstate) override; void Run() override; void Step() override; - void ExceptionalExit() override; VAddr GetTlsAddress() const override; void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorID(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override {} void SaveContext(ThreadContext64& ctx) override; @@ -76,6 +74,12 @@ private: DynarmicExclusiveMonitor& exclusive_monitor; std::shared_ptr<Dynarmic::A64::Jit> jit; + + // SVC callback + u32 svc_swi{}; + bool svc_called{}; + + bool shutdown{}; }; } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 8597beddf..7c7ede79e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -7,7 +7,7 @@ #include <memory> #include <optional> -#include <dynarmic/A32/coprocessor.h> +#include <dynarmic/interface/A32/coprocessor.h> #include "common/common_types.h" namespace Core { diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/arm_exclusive_monitor.h index f9f056a59..73d41f223 100644 --- a/src/core/arm/dynarmic/arm_exclusive_monitor.h +++ b/src/core/arm/dynarmic/arm_exclusive_monitor.h @@ -7,7 +7,7 @@ #include <memory> #include <unordered_map> -#include <dynarmic/exclusive_monitor.h> +#include <dynarmic/interface/exclusive_monitor.h> #include "common/common_types.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 8501156e8..f2fff3b01 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -22,7 +22,7 @@ class KClientPort final : public KSynchronizationObject { public: explicit KClientPort(KernelCore& kernel_); - virtual ~KClientPort() override; + ~KClientPort() override; void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_); void OnSessionFinalized(); @@ -49,8 +49,8 @@ public: bool IsServerClosed() const; // Overridden virtual functions. - virtual void Destroy() override; - virtual bool IsSignaled() const override; + void Destroy() override; + bool IsSignaled() const override; ResultCode CreateSession(KClientSession** out); diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h index 720a8c243..b11d5b4e3 100644 --- a/src/core/hle/kernel/k_client_session.h +++ b/src/core/hle/kernel/k_client_session.h @@ -34,7 +34,7 @@ class KClientSession final public: explicit KClientSession(KernelCore& kernel_); - virtual ~KClientSession(); + ~KClientSession() override; void Initialize(KSession* parent_, std::string&& name_) { // Set member variables. @@ -42,7 +42,7 @@ public: name = std::move(name_); } - virtual void Destroy() override; + void Destroy() override; static void PostDestroy([[maybe_unused]] uintptr_t arg) {} KSession* GetParent() const { diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h index 9a59ffb70..3d3ec99e2 100644 --- a/src/core/hle/kernel/k_event.h +++ b/src/core/hle/kernel/k_event.h @@ -20,23 +20,21 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj public: explicit KEvent(KernelCore& kernel_); - virtual ~KEvent(); + ~KEvent() override; void Initialize(std::string&& name); - virtual void Finalize() override; + void Finalize() override; - virtual bool IsInitialized() const override { + bool IsInitialized() const override { return initialized; } - virtual uintptr_t GetPostDestroyArgument() const override { + uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(owner); } - static void PostDestroy(uintptr_t arg); - - virtual KProcess* GetOwner() const override { + KProcess* GetOwner() const override { return owner; } @@ -48,6 +46,8 @@ public: return writable_event; } + static void PostDestroy(uintptr_t arg); + private: KReadableEvent readable_event; KWritableEvent writable_event; diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h index 960f1f3a3..4018ea2df 100644 --- a/src/core/hle/kernel/k_port.h +++ b/src/core/hle/kernel/k_port.h @@ -22,7 +22,7 @@ class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjec public: explicit KPort(KernelCore& kernel_); - virtual ~KPort(); + ~KPort() override; static void PostDestroy([[maybe_unused]] uintptr_t arg) {} @@ -59,7 +59,6 @@ private: ServerClosed = 3, }; -private: KServerPort server; KClientPort client; State state{State::Invalid}; diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 123d71cd3..c0656b9af 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -331,19 +331,19 @@ public: void LoadModule(CodeSet code_set, VAddr base_addr); - virtual bool IsInitialized() const override { + bool IsInitialized() const override { return is_initialized; } static void PostDestroy([[maybe_unused]] uintptr_t arg) {} - virtual void Finalize(); + void Finalize() override; - virtual u64 GetId() const override final { + u64 GetId() const override { return GetProcessID(); } - virtual bool IsSignaled() const override; + bool IsSignaled() const override; void PinCurrentThread(); void UnpinCurrentThread(); diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h index 33cd1dd3e..b2850ac7b 100644 --- a/src/core/hle/kernel/k_readable_event.h +++ b/src/core/hle/kernel/k_readable_event.h @@ -31,8 +31,8 @@ public: return parent; } - virtual bool IsSignaled() const override; - virtual void Destroy() override; + bool IsSignaled() const override; + void Destroy() override; ResultCode Signal(); ResultCode Clear(); diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h index 0debbbb51..fab6005ff 100644 --- a/src/core/hle/kernel/k_resource_limit.h +++ b/src/core/hle/kernel/k_resource_limit.h @@ -37,10 +37,10 @@ class KResourceLimit final public: explicit KResourceLimit(KernelCore& kernel_); - virtual ~KResourceLimit(); + ~KResourceLimit() override; void Initialize(const Core::Timing::CoreTiming* core_timing_); - virtual void Finalize() override; + void Finalize() override; s64 GetLimitValue(LimitableResource which) const; s64 GetCurrentValue(LimitableResource which) const; diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 2f82fbcd6..6a7d80d03 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -659,7 +659,6 @@ void KScheduler::Unload(KThread* thread) { if (thread) { if (thread->IsCallingSvc()) { - system.ArmInterface(core_id).ExceptionalExit(); thread->ClearIsCallingSvc(); } if (!thread->IsTerminationRequested()) { diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index d1a757ec3..55481d63f 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -25,12 +25,9 @@ class SessionRequestHandler; class KServerPort final : public KSynchronizationObject { KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject); -private: - using SessionList = boost::intrusive::list<KServerSession>; - public: explicit KServerPort(KernelCore& kernel_); - virtual ~KServerPort() override; + ~KServerPort() override; void Initialize(KPort* parent_, std::string&& name_); @@ -63,13 +60,14 @@ public: bool IsLight() const; // Overridden virtual functions. - virtual void Destroy() override; - virtual bool IsSignaled() const override; + void Destroy() override; + bool IsSignaled() const override; private: + using SessionList = boost::intrusive::list<KServerSession>; + void CleanupSessions(); -private: SessionList session_list; SessionRequestHandlerPtr session_handler; KPort* parent{}; diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index dd4de2904..27b757ad2 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -42,9 +42,9 @@ class KServerSession final : public KSynchronizationObject, public: explicit KServerSession(KernelCore& kernel_); - virtual ~KServerSession() override; + ~KServerSession() override; - virtual void Destroy() override; + void Destroy() override; void Initialize(KSession* parent_, std::string&& name_); @@ -56,7 +56,7 @@ public: return parent; } - virtual bool IsSignaled() const override; + bool IsSignaled() const override; void OnClientClosed(); diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index a981fd1f6..4ddd080d2 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -18,17 +18,17 @@ class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAut public: explicit KSession(KernelCore& kernel_); - virtual ~KSession() override; + ~KSession() override; void Initialize(KClientPort* port_, const std::string& name_); - virtual void Finalize() override; + void Finalize() override; - virtual bool IsInitialized() const override { + bool IsInitialized() const override { return initialized; } - virtual uintptr_t GetPostDestroyArgument() const override { + uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(process); } @@ -78,7 +78,6 @@ private: ServerClosed = 3, }; -private: void SetState(State state) { atomic_state = static_cast<u8>(state); } @@ -87,7 +86,6 @@ private: return static_cast<State>(atomic_state.load(std::memory_order_relaxed)); } -private: KServerSession server; KClientSession client; std::atomic<std::underlying_type_t<State>> atomic_state{ diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 553a56327..e9815f90b 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -68,9 +68,9 @@ public: return device_memory->GetPointer(physical_address + offset); } - virtual void Finalize() override; + void Finalize() override; - virtual bool IsInitialized() const override { + bool IsInitialized() const override { return is_initialized; } static void PostDestroy([[maybe_unused]] uintptr_t arg) {} diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index 81d472a3e..0ad74b0a0 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -4,34 +4,213 @@ #pragma once +#include <atomic> + +#include "common/assert.h" +#include "common/common_types.h" + namespace Kernel { class KernelCore; -/// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate -/// these with new/delete, but this can be re-implemented later to allocate these in emulated -/// memory. +namespace impl { + +class KSlabHeapImpl final : NonCopyable { +public: + struct Node { + Node* next{}; + }; + + constexpr KSlabHeapImpl() = default; + + void Initialize(std::size_t size) { + ASSERT(head == nullptr); + obj_size = size; + } + + constexpr std::size_t GetObjectSize() const { + return obj_size; + } + + Node* GetHead() const { + return head; + } + + void* Allocate() { + Node* ret = head.load(); + + do { + if (ret == nullptr) { + break; + } + } while (!head.compare_exchange_weak(ret, ret->next)); + + return ret; + } + + void Free(void* obj) { + Node* node = static_cast<Node*>(obj); + + Node* cur_head = head.load(); + do { + node->next = cur_head; + } while (!head.compare_exchange_weak(cur_head, node)); + } + +private: + std::atomic<Node*> head{}; + std::size_t obj_size{}; +}; + +} // namespace impl + +class KSlabHeapBase : NonCopyable { +public: + constexpr KSlabHeapBase() = default; + + constexpr bool Contains(uintptr_t addr) const { + return start <= addr && addr < end; + } + + constexpr std::size_t GetSlabHeapSize() const { + return (end - start) / GetObjectSize(); + } + + constexpr std::size_t GetObjectSize() const { + return impl.GetObjectSize(); + } + + constexpr uintptr_t GetSlabHeapAddress() const { + return start; + } + + std::size_t GetObjectIndexImpl(const void* obj) const { + return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize(); + } + + std::size_t GetPeakIndex() const { + return GetObjectIndexImpl(reinterpret_cast<const void*>(peak)); + } + + void* AllocateImpl() { + return impl.Allocate(); + } + + void FreeImpl(void* obj) { + // Don't allow freeing an object that wasn't allocated from this heap + ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); + + impl.Free(obj); + } + + void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { + // Ensure we don't initialize a slab using null memory + ASSERT(memory != nullptr); + + // Initialize the base allocator + impl.Initialize(obj_size); + + // Set our tracking variables + const std::size_t num_obj = (memory_size / obj_size); + start = reinterpret_cast<uintptr_t>(memory); + end = start + num_obj * obj_size; + peak = start; + + // Free the objects + u8* cur = reinterpret_cast<u8*>(end); + + for (std::size_t i{}; i < num_obj; i++) { + cur -= obj_size; + impl.Free(cur); + } + } + +private: + using Impl = impl::KSlabHeapImpl; + + Impl impl; + uintptr_t peak{}; + uintptr_t start{}; + uintptr_t end{}; +}; template <typename T> -class KSlabHeap final : NonCopyable { +class KSlabHeap final : public KSlabHeapBase { public: - KSlabHeap() = default; + enum class AllocationType { + Host, + Guest, + }; - void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) { - // Placeholder that should initialize the backing slab heap implementation. + explicit constexpr KSlabHeap(AllocationType allocation_type_ = AllocationType::Host) + : KSlabHeapBase(), allocation_type{allocation_type_} {} + + void Initialize(void* memory, std::size_t memory_size) { + if (allocation_type == AllocationType::Guest) { + InitializeImpl(sizeof(T), memory, memory_size); + } } T* Allocate() { - return new T(); + switch (allocation_type) { + case AllocationType::Host: + // Fallback for cases where we do not yet support allocating guest memory from the slab + // heap, such as for kernel memory regions. + return new T; + + case AllocationType::Guest: + T* obj = static_cast<T*>(AllocateImpl()); + if (obj != nullptr) { + new (obj) T(); + } + return obj; + } + + UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type); + return nullptr; } T* AllocateWithKernel(KernelCore& kernel) { - return new T(kernel); + switch (allocation_type) { + case AllocationType::Host: + // Fallback for cases where we do not yet support allocating guest memory from the slab + // heap, such as for kernel memory regions. + return new T(kernel); + + case AllocationType::Guest: + T* obj = static_cast<T*>(AllocateImpl()); + if (obj != nullptr) { + new (obj) T(kernel); + } + return obj; + } + + UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type); + return nullptr; } void Free(T* obj) { - delete obj; + switch (allocation_type) { + case AllocationType::Host: + // Fallback for cases where we do not yet support allocating guest memory from the slab + // heap, such as for kernel memory regions. + delete obj; + return; + + case AllocationType::Guest: + FreeImpl(obj); + return; + } + + UNREACHABLE_MSG("Invalid AllocationType {}", allocation_type); } + + constexpr std::size_t GetObjectIndex(const T* obj) const { + return GetObjectIndexImpl(obj); + } + +private: + const AllocationType allocation_type; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index a41dd1220..3d4ce1fbc 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h @@ -29,7 +29,7 @@ public: KSynchronizationObject** objects, const s32 num_objects, s64 timeout); - virtual void Finalize() override; + void Finalize() override; [[nodiscard]] virtual bool IsSignaled() const = 0; @@ -37,7 +37,7 @@ public: protected: explicit KSynchronizationObject(KernelCore& kernel); - virtual ~KSynchronizationObject(); + ~KSynchronizationObject() override; virtual void OnFinalizeSynchronizationObject() {} diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index e3f08f256..3cf43d290 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -168,13 +168,13 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0, sizeof(StackParameters)); - // Setup the TLS, if needed. - if (type == ThreadType::User) { - tls_address = owner->CreateTLSRegion(); - } - // Set parent, if relevant. if (owner != nullptr) { + // Setup the TLS, if needed. + if (type == ThreadType::User) { + tls_address = owner->CreateTLSRegion(); + } + parent = owner; parent->Open(); parent->IncrementThreadCount(); diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 4abfc2b49..01eebb165 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -358,21 +358,21 @@ public: return termination_requested || GetRawState() == ThreadState::Terminated; } - [[nodiscard]] virtual u64 GetId() const override final { + [[nodiscard]] u64 GetId() const override { return this->GetThreadID(); } - [[nodiscard]] virtual bool IsInitialized() const override { + [[nodiscard]] bool IsInitialized() const override { return initialized; } - [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override { + [[nodiscard]] uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0); } - virtual void Finalize() override; + void Finalize() override; - [[nodiscard]] virtual bool IsSignaled() const override; + [[nodiscard]] bool IsSignaled() const override; static void PostDestroy(uintptr_t arg); diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index c2d0f1eaf..31029a5c2 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -27,23 +27,23 @@ class KTransferMemory final public: explicit KTransferMemory(KernelCore& kernel_); - virtual ~KTransferMemory() override; + ~KTransferMemory() override; ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_); - virtual void Finalize() override; + void Finalize() override; - virtual bool IsInitialized() const override { + bool IsInitialized() const override { return is_initialized; } - virtual uintptr_t GetPostDestroyArgument() const override { + uintptr_t GetPostDestroyArgument() const override { return reinterpret_cast<uintptr_t>(owner); } static void PostDestroy(uintptr_t arg); - KProcess* GetOwner() const { + KProcess* GetOwner() const override { return owner; } diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h index 607b0eadb..858d982c4 100644 --- a/src/core/hle/kernel/k_writable_event.h +++ b/src/core/hle/kernel/k_writable_event.h @@ -21,7 +21,7 @@ public: explicit KWritableEvent(KernelCore& kernel_); ~KWritableEvent() override; - virtual void Destroy() override; + void Destroy() override; static void PostDestroy([[maybe_unused]] uintptr_t arg) {} diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8b55df82e..0ffb78d51 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -258,7 +258,7 @@ struct KernelCore::Impl { KAutoObject::Create(thread.get()); ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); - return std::move(thread); + return thread; }; thread_local auto thread = make_thread(); @@ -620,7 +620,8 @@ struct KernelCore::Impl { void InitializePageSlab() { // Allocate slab heaps - user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); + user_slab_heap_pages = + std::make_unique<KSlabHeap<Page>>(KSlabHeap<Page>::AllocationType::Guest); // TODO(ameerj): This should be derived, not hardcoded within the kernel constexpr u64 user_slab_heap_size{0x3de000}; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 49c17fd14..df0fe1c8e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -1770,7 +1770,7 @@ public: {232, nullptr, "GetIrSensorState"}, {233, nullptr, "GetXcdHandleForNpadWithIrSensor"}, {301, nullptr, "ActivateNpadSystem"}, - {303, nullptr, "ApplyNpadSystemCommonPolicy"}, + {303, &HidSys::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"}, {304, nullptr, "EnableAssigningSingleOnSlSrPress"}, {305, nullptr, "DisableAssigningSingleOnSlSrPress"}, {306, nullptr, "GetLastActiveNpad"}, @@ -1949,6 +1949,15 @@ public: RegisterHandlers(functions); } + +private: + void ApplyNpadSystemCommonPolicy(Kernel::HLERequestContext& ctx) { + // We already do this for homebrew so we can just stub it out + LOG_WARNING(Service_HID, "called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } }; class HidTmp final : public ServiceFramework<HidTmp> { diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index de971041f..9e6b87960 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -596,7 +596,7 @@ void BufferCache<P>::PopAsyncFlushes() { runtime.CopyBuffer(download_staging.buffer, slot_buffers[buffer_id], copies); } runtime.Finish(); - for (const auto [copy, buffer_id] : downloads) { + for (const auto& [copy, buffer_id] : downloads) { const Buffer& buffer = slot_buffers[buffer_id]; const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; // Undo the modified offset @@ -606,7 +606,7 @@ void BufferCache<P>::PopAsyncFlushes() { } } else { const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy); - for (const auto [copy, buffer_id] : downloads) { + for (const auto& [copy, buffer_id] : downloads) { Buffer& buffer = slot_buffers[buffer_id]; buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size)); const VAddr cpu_addr = buffer.CpuAddr() + copy.src_offset; diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp index 62d84c0f8..6decd2546 100644 --- a/src/video_core/rasterizer_accelerated.cpp +++ b/src/video_core/rasterizer_accelerated.cpp @@ -18,10 +18,10 @@ RasterizerAccelerated::~RasterizerAccelerated() = default; void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { const auto page_end = Common::DivCeil(addr + size, Core::Memory::PAGE_SIZE); for (auto page = addr >> Core::Memory::PAGE_BITS; page != page_end; ++page) { - auto& count = cached_pages.at(page >> 3).Count(page); + auto& count = cached_pages.at(page >> 2).Count(page); if (delta > 0) { - ASSERT_MSG(count < UINT8_MAX, "Count may overflow!"); + ASSERT_MSG(count < UINT16_MAX, "Count may overflow!"); } else if (delta < 0) { ASSERT_MSG(count > 0, "Count may underflow!"); } else { @@ -29,7 +29,7 @@ void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int del } // Adds or subtracts 1, as count is a unsigned 8-bit value - count += static_cast<u8>(delta); + count += static_cast<u16>(delta); // Assume delta is either -1 or 1 if (count == 0) { diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h index 9227a4adc..ea879bfdd 100644 --- a/src/video_core/rasterizer_accelerated.h +++ b/src/video_core/rasterizer_accelerated.h @@ -29,20 +29,20 @@ private: public: CacheEntry() = default; - std::atomic_uint8_t& Count(std::size_t page) { - return values[page & 7]; + std::atomic_uint16_t& Count(std::size_t page) { + return values[page & 3]; } - const std::atomic_uint8_t& Count(std::size_t page) const { - return values[page & 7]; + const std::atomic_uint16_t& Count(std::size_t page) const { + return values[page & 3]; } private: - std::array<std::atomic_uint8_t, 8> values{}; + std::array<std::atomic_uint16_t, 4> values{}; }; static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!"); - std::array<CacheEntry, 0x800000> cached_pages; + std::array<CacheEntry, 0x1000000> cached_pages; Core::Memory::Memory& cpu_memory; }; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index cc0790e07..634fe66a5 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -4,6 +4,12 @@ set(CMAKE_AUTOUIC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) +# Set the RPATH for Qt Libraries +# This must be done before the `yuzu` target is created +if (YUZU_USE_BUNDLED_QT AND (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")) + set(CMAKE_BUILD_RPATH "${CMAKE_BINARY_DIR}/bin/lib/") +endif() + add_executable(yuzu Info.plist about_dialog.cpp @@ -278,11 +284,14 @@ if(UNIX AND NOT APPLE) install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() -if (MSVC) +if (YUZU_USE_BUNDLED_QT) include(CopyYuzuQt5Deps) + copy_yuzu_Qt5_deps(yuzu) +endif() + +if (MSVC) include(CopyYuzuSDLDeps) include(CopyYuzuFFmpegDeps) - copy_yuzu_Qt5_deps(yuzu) copy_yuzu_SDL_deps(yuzu) copy_yuzu_FFmpeg_deps(yuzu) endif() diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 3ad40d2b3..6028135c5 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <QAbstractButton> +#include <QDialogButtonBox> #include <QHash> #include <QListWidgetItem> +#include <QPushButton> #include <QSignalBlocker> #include "common/settings.h" #include "core/core.h" @@ -31,6 +34,12 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, &ConfigureDialog::UpdateVisibleTabs); + if (Core::System::GetInstance().IsPoweredOn()) { + QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply); + connect(apply_button, &QAbstractButton::clicked, this, + &ConfigureDialog::HandleApplyButtonClicked); + } + adjustSize(); ui->selectorList->setCurrentRow(0); } @@ -80,6 +89,11 @@ void ConfigureDialog::RetranslateUI() { ui->tabWidget->setCurrentIndex(old_index); } +void ConfigureDialog::HandleApplyButtonClicked() { + UISettings::values.configuration_applied = true; + ApplyConfiguration(); +} + Q_DECLARE_METATYPE(QList<QWidget*>); void ConfigureDialog::PopulateSelectionList() { diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 570c3b941..abe019635 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -35,9 +35,10 @@ signals: private: void changeEvent(QEvent* event) override; - void RetranslateUI(); + void HandleApplyButtonClicked(); + void SetConfiguration(); void UpdateVisibleTabs(); void PopulateSelectionList(); diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 3e13bd438..d89f1ad4b 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -6,9 +6,12 @@ #include <memory> #include <utility> +#include <QAbstractButton> #include <QCheckBox> +#include <QDialogButtonBox> #include <QHeaderView> #include <QMenu> +#include <QPushButton> #include <QStandardItemModel> #include <QString> #include <QTimer> @@ -42,6 +45,12 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id) scene = new QGraphicsScene; ui->icon_view->setScene(scene); + if (Core::System::GetInstance().IsPoweredOn()) { + QPushButton* apply_button = ui->buttonBox->addButton(QDialogButtonBox::Apply); + connect(apply_button, &QAbstractButton::clicked, this, + &ConfigurePerGame::HandleApplyButtonClicked); + } + LoadConfiguration(); } @@ -74,6 +83,11 @@ void ConfigurePerGame::RetranslateUI() { ui->retranslateUi(this); } +void ConfigurePerGame::HandleApplyButtonClicked() { + UISettings::values.configuration_applied = true; + ApplyConfiguration(); +} + void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file) { this->file = std::move(file); LoadConfiguration(); diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index 5f9a08cef..f6e6ab7c4 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -39,6 +39,8 @@ private: void changeEvent(QEvent* event) override; void RetranslateUI(); + void HandleApplyButtonClicked(); + void LoadConfiguration(); std::unique_ptr<Ui::ConfigurePerGame> ui; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 37ef62967..0f0e228b0 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2587,12 +2587,12 @@ void GMainWindow::OnConfigure() { &GMainWindow::OnLanguageChanged); const auto result = configure_dialog.exec(); - if (result != QDialog::Accepted) { + if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { return; + } else if (result == QDialog::Accepted) { + configure_dialog.ApplyConfiguration(); + controller_dialog->refreshConfiguration(); } - - configure_dialog.ApplyConfiguration(); - controller_dialog->refreshConfiguration(); InitializeHotkeys(); if (UISettings::values.theme != old_theme) { UpdateUITheme(); @@ -2607,6 +2607,8 @@ void GMainWindow::OnConfigure() { game_list->PopulateAsync(UISettings::values.game_dirs); } + UISettings::values.configuration_applied = false; + config->Save(); if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { @@ -2636,23 +2638,27 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file ConfigurePerGame dialog(this, title_id); dialog.LoadFromFile(v_file); const auto result = dialog.exec(); - if (result == QDialog::Accepted) { + + if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { + Settings::RestoreGlobalState(system.IsPoweredOn()); + return; + } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); + } - const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false); - if (reload) { - game_list->PopulateAsync(UISettings::values.game_dirs); - } + const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false); + if (reload) { + game_list->PopulateAsync(UISettings::values.game_dirs); + } - // Do not cause the global config to write local settings into the config file - const bool is_powered_on = system.IsPoweredOn(); - Settings::RestoreGlobalState(is_powered_on); + // Do not cause the global config to write local settings into the config file + const bool is_powered_on = system.IsPoweredOn(); + Settings::RestoreGlobalState(is_powered_on); - if (!is_powered_on) { - config->Save(); - } - } else { - Settings::RestoreGlobalState(system.IsPoweredOn()); + UISettings::values.configuration_applied = false; + + if (!is_powered_on) { + config->Save(); } } diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 5ba00b8c8..49122ec32 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -95,6 +95,8 @@ struct Values { uint8_t row_2_text_id; std::atomic_bool is_game_list_reload_pending{false}; bool cache_game_list; + + bool configuration_applied; }; extern Values values; |