From 458da8a94877677f086f06cdeecf959ec4283a33 Mon Sep 17 00:00:00 2001 From: Kelebek1 Date: Sat, 16 Jul 2022 23:48:45 +0100 Subject: Project Andio --- src/audio_core/renderer/memory/address_info.h | 125 +++++++++++ .../renderer/memory/memory_pool_info.cpp | 61 ++++++ src/audio_core/renderer/memory/memory_pool_info.h | 170 ++++++++++++++ src/audio_core/renderer/memory/pool_mapper.cpp | 243 +++++++++++++++++++++ src/audio_core/renderer/memory/pool_mapper.h | 179 +++++++++++++++ 5 files changed, 778 insertions(+) create mode 100644 src/audio_core/renderer/memory/address_info.h create mode 100644 src/audio_core/renderer/memory/memory_pool_info.cpp create mode 100644 src/audio_core/renderer/memory/memory_pool_info.h create mode 100644 src/audio_core/renderer/memory/pool_mapper.cpp create mode 100644 src/audio_core/renderer/memory/pool_mapper.h (limited to 'src/audio_core/renderer/memory') diff --git a/src/audio_core/renderer/memory/address_info.h b/src/audio_core/renderer/memory/address_info.h new file mode 100644 index 000000000..4cfefea8e --- /dev/null +++ b/src/audio_core/renderer/memory/address_info.h @@ -0,0 +1,125 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "audio_core/renderer/memory/memory_pool_info.h" +#include "common/common_types.h" + +namespace AudioCore::AudioRenderer { + +/** + * Represents a region of mapped or unmapped memory. + */ +class AddressInfo { +public: + AddressInfo() = default; + AddressInfo(CpuAddr cpu_address_, u64 size_) : cpu_address{cpu_address_}, size{size_} {} + + /** + * Setup a new AddressInfo. + * + * @param cpu_address - The CPU address of this region. + * @param size - The size of this region. + */ + void Setup(CpuAddr cpu_address_, u64 size_) { + cpu_address = cpu_address_; + size = size_; + memory_pool = nullptr; + dsp_address = 0; + } + + /** + * Get the CPU address. + * + * @return The CpuAddr address + */ + CpuAddr GetCpuAddr() const { + return cpu_address; + } + + /** + * Assign this region to a memory pool. + * + * @param memory_pool_ - Memory pool to assign. + * @return The CpuAddr address of this region. + */ + void SetPool(MemoryPoolInfo* memory_pool_) { + memory_pool = memory_pool_; + } + + /** + * Get the size of this region. + * + * @return The size of this region. + */ + u64 GetSize() const { + return size; + } + + /** + * Get the ADSP address for this region. + * + * @return The ADSP address for this region. + */ + CpuAddr GetForceMappedDspAddr() const { + return dsp_address; + } + + /** + * Set the ADSP address for this region. + * + * @param dsp_addr - The new ADSP address for this region. + */ + void SetForceMappedDspAddr(CpuAddr dsp_addr) { + dsp_address = dsp_addr; + } + + /** + * Check whether this region has an active memory pool. + * + * @return True if this region has a mapped memory pool, otherwise false. + */ + bool HasMappedMemoryPool() const { + return memory_pool != nullptr && memory_pool->GetDspAddress() != 0; + } + + /** + * Check whether this region is mapped to the ADSP. + * + * @return True if this region is mapped, otherwise false. + */ + bool IsMapped() const { + return HasMappedMemoryPool() || dsp_address != 0; + } + + /** + * Get a usable reference to this region of memory. + * + * @param mark_in_use - Whether this region should be marked as being in use. + * @return A valid memory address if valid, otherwise 0. + */ + CpuAddr GetReference(bool mark_in_use) { + if (!HasMappedMemoryPool()) { + return dsp_address; + } + + if (mark_in_use) { + memory_pool->SetUsed(true); + } + + return memory_pool->Translate(cpu_address, size); + } + +private: + /// CPU address of this region + CpuAddr cpu_address; + /// Size of this region + u64 size; + /// The memory this region is mapped to + MemoryPoolInfo* memory_pool; + /// ADSP address of this region + CpuAddr dsp_address; +}; + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/memory/memory_pool_info.cpp b/src/audio_core/renderer/memory/memory_pool_info.cpp new file mode 100644 index 000000000..9b7824af1 --- /dev/null +++ b/src/audio_core/renderer/memory/memory_pool_info.cpp @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "audio_core/renderer/memory/memory_pool_info.h" + +namespace AudioCore::AudioRenderer { + +CpuAddr MemoryPoolInfo::GetCpuAddress() const { + return cpu_address; +} + +CpuAddr MemoryPoolInfo::GetDspAddress() const { + return dsp_address; +} + +u64 MemoryPoolInfo::GetSize() const { + return size; +} + +MemoryPoolInfo::Location MemoryPoolInfo::GetLocation() const { + return location; +} + +void MemoryPoolInfo::SetCpuAddress(const CpuAddr address, const u64 size_) { + cpu_address = address; + size = size_; +} + +void MemoryPoolInfo::SetDspAddress(const CpuAddr address) { + dsp_address = address; +} + +bool MemoryPoolInfo::Contains(const CpuAddr address_, const u64 size_) const { + return cpu_address <= address_ && (address_ + size_) <= (cpu_address + size); +} + +bool MemoryPoolInfo::IsMapped() const { + return dsp_address != 0; +} + +CpuAddr MemoryPoolInfo::Translate(const CpuAddr address, const u64 size_) const { + if (!Contains(address, size_)) { + return 0; + } + + if (!IsMapped()) { + return 0; + } + + return dsp_address + (address - cpu_address); +} + +void MemoryPoolInfo::SetUsed(const bool used) { + in_use = used; +} + +bool MemoryPoolInfo::IsUsed() const { + return in_use; +} + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/memory/memory_pool_info.h b/src/audio_core/renderer/memory/memory_pool_info.h new file mode 100644 index 000000000..537a466ec --- /dev/null +++ b/src/audio_core/renderer/memory/memory_pool_info.h @@ -0,0 +1,170 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "audio_core/common/common.h" +#include "common/common_types.h" + +namespace AudioCore::AudioRenderer { +/** + * CPU pools are mapped in user memory with the supplied process_handle (see PoolMapper). + */ +class MemoryPoolInfo { +public: + /** + * The location of this pool. + * CPU pools are mapped in user memory with the supplied process_handle (see PoolMapper). + * DSP pools are mapped in the current process sysmodule. + */ + enum class Location { + CPU = 1, + DSP = 2, + }; + + /** + * Current state of the pool + */ + enum class State { + Invalid, + Aquired, + RequestDetach, + Detached, + RequestAttach, + Attached, + Released, + }; + + /** + * Result code for updating the pool (See InfoUpdater::Update) + */ + enum class ResultState { + Success, + BadParam, + MapFailed, + InUse, + }; + + /** + * Input parameters coming from the game which are used to update current pools + * (See InfoUpdater::Update) + */ + struct InParameter { + /* 0x00 */ u64 address; + /* 0x08 */ u64 size; + /* 0x10 */ State state; + /* 0x14 */ bool in_use; + /* 0x18 */ char unk18[0x8]; + }; + static_assert(sizeof(InParameter) == 0x20, "MemoryPoolInfo::InParameter has the wrong size!"); + + /** + * Output status sent back to the game on update (See InfoUpdater::Update) + */ + struct OutStatus { + /* 0x00 */ State state; + /* 0x04 */ char unk04[0xC]; + }; + static_assert(sizeof(OutStatus) == 0x10, "MemoryPoolInfo::OutStatus has the wrong size!"); + + MemoryPoolInfo() = default; + MemoryPoolInfo(Location location_) : location{location_} {} + + /** + * Get the CPU address for this pool. + * + * @return The CPU address of this pool. + */ + CpuAddr GetCpuAddress() const; + + /** + * Get the DSP address for this pool. + * + * @return The DSP address of this pool. + */ + CpuAddr GetDspAddress() const; + + /** + * Get the size of this pool. + * + * @return The size of this pool. + */ + u64 GetSize() const; + + /** + * Get the location of this pool. + * + * @return The location for the pool (see MemoryPoolInfo::Location). + */ + Location GetLocation() const; + + /** + * Set the CPU address for this pool. + * + * @param address - The new CPU address for this pool. + * @param size - The new size for this pool. + */ + void SetCpuAddress(CpuAddr address, u64 size); + + /** + * Set the DSP address for this pool. + * + * @param address - The new DSP address for this pool. + */ + void SetDspAddress(CpuAddr address); + + /** + * Check whether the pool contains a given range. + * + * @param address - The buffer address to look for. + * @param size - The size of the given buffer. + * @return True if the range is within this pool, otherwise false. + */ + bool Contains(CpuAddr address, u64 size) const; + + /** + * Check whether this pool is mapped, which is when the dsp address is set. + * + * @return True if the pool is mapped, otherwise false. + */ + bool IsMapped() const; + + /** + * Translates a given CPU range into a relative offset for the DSP. + * + * @param address - The buffer address to look for. + * @param size - The size of the given buffer. + * @return Pointer to the DSP-mapped memory. + */ + CpuAddr Translate(CpuAddr address, u64 size) const; + + /** + * Set or unset whether this memory pool is in use. + * + * @param used - Use state for this pool. + */ + void SetUsed(bool used); + + /** + * Get whether this pool is in use. + * + * @return True if in use, otherwise false. + */ + bool IsUsed() const; + +private: + /// Base address for the CPU-side memory + CpuAddr cpu_address{}; + /// Base address for the DSP-side memory + CpuAddr dsp_address{}; + /// Size of this pool + u64 size{}; + /// Location of this pool, either CPU or DSP + Location location{Location::DSP}; + /// If this pool is in use + bool in_use{}; +}; + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/memory/pool_mapper.cpp b/src/audio_core/renderer/memory/pool_mapper.cpp new file mode 100644 index 000000000..2baf2ce08 --- /dev/null +++ b/src/audio_core/renderer/memory/pool_mapper.cpp @@ -0,0 +1,243 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "audio_core/renderer/memory/address_info.h" +#include "audio_core/renderer/memory/pool_mapper.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace AudioCore::AudioRenderer { + +PoolMapper::PoolMapper(u32 process_handle_, bool force_map_) + : process_handle{process_handle_}, force_map{force_map_} {} + +PoolMapper::PoolMapper(u32 process_handle_, std::span pool_infos_, u32 pool_count_, + bool force_map_) + : process_handle{process_handle_}, pool_infos{pool_infos_.data()}, + pool_count{pool_count_}, force_map{force_map_} {} + +void PoolMapper::ClearUseState(std::span pools, const u32 count) { + for (u32 i = 0; i < count; i++) { + pools[i].SetUsed(false); + } +} + +MemoryPoolInfo* PoolMapper::FindMemoryPool(MemoryPoolInfo* pools, const u64 count, + const CpuAddr address, const u64 size) const { + auto pool{pools}; + for (u64 i = 0; i < count; i++, pool++) { + if (pool->Contains(address, size)) { + return pool; + } + } + return nullptr; +} + +MemoryPoolInfo* PoolMapper::FindMemoryPool(const CpuAddr address, const u64 size) const { + auto pool{pool_infos}; + for (u64 i = 0; i < pool_count; i++, pool++) { + if (pool->Contains(address, size)) { + return pool; + } + } + return nullptr; +} + +bool PoolMapper::FillDspAddr(AddressInfo& address_info, MemoryPoolInfo* pools, + const u32 count) const { + if (address_info.GetCpuAddr() == 0) { + address_info.SetPool(nullptr); + return false; + } + + auto found_pool{ + FindMemoryPool(pools, count, address_info.GetCpuAddr(), address_info.GetSize())}; + if (found_pool != nullptr) { + address_info.SetPool(found_pool); + return true; + } + + if (force_map) { + address_info.SetForceMappedDspAddr(address_info.GetCpuAddr()); + } else { + address_info.SetPool(nullptr); + } + + return false; +} + +bool PoolMapper::FillDspAddr(AddressInfo& address_info) const { + if (address_info.GetCpuAddr() == 0) { + address_info.SetPool(nullptr); + return false; + } + + auto found_pool{FindMemoryPool(address_info.GetCpuAddr(), address_info.GetSize())}; + if (found_pool != nullptr) { + address_info.SetPool(found_pool); + return true; + } + + if (force_map) { + address_info.SetForceMappedDspAddr(address_info.GetCpuAddr()); + } else { + address_info.SetPool(nullptr); + } + + return false; +} + +bool PoolMapper::TryAttachBuffer(BehaviorInfo::ErrorInfo& error_info, AddressInfo& address_info, + const CpuAddr address, const u64 size) const { + address_info.Setup(address, size); + + if (!FillDspAddr(address_info)) { + error_info.error_code = Service::Audio::ERR_POOL_MAPPING_FAILED; + error_info.address = address; + return force_map; + } + + error_info.error_code = ResultSuccess; + error_info.address = CpuAddr(0); + return true; +} + +bool PoolMapper::IsForceMapEnabled() const { + return force_map; +} + +u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { + switch (pool->GetLocation()) { + case MemoryPoolInfo::Location::CPU: + return process_handle; + case MemoryPoolInfo::Location::DSP: + return Kernel::Svc::CurrentProcess; + } + LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!"); + return Kernel::Svc::CurrentProcess; +} + +bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, + [[maybe_unused]] const u64 size) const { + // nn::audio::dsp::MapUserPointer(handle, cpu_addr, size); + return true; +} + +bool PoolMapper::Map(MemoryPoolInfo& pool) const { + switch (pool.GetLocation()) { + case MemoryPoolInfo::Location::CPU: + // Map with process_handle + pool.SetDspAddress(pool.GetCpuAddress()); + return true; + case MemoryPoolInfo::Location::DSP: + // Map with Kernel::Svc::CurrentProcess + pool.SetDspAddress(pool.GetCpuAddress()); + return true; + default: + LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location={}!", + static_cast(pool.GetLocation())); + return false; + } +} + +bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, + [[maybe_unused]] const u64 size) const { + // nn::audio::dsp::UnmapUserPointer(handle, cpu_addr, size); + return true; +} + +bool PoolMapper::Unmap(MemoryPoolInfo& pool) const { + [[maybe_unused]] u32 handle{0}; + + switch (pool.GetLocation()) { + case MemoryPoolInfo::Location::CPU: + handle = process_handle; + break; + case MemoryPoolInfo::Location::DSP: + handle = Kernel::Svc::CurrentProcess; + break; + } + // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size); + pool.SetCpuAddress(0, 0); + pool.SetDspAddress(0); + return true; +} + +void PoolMapper::ForceUnmapPointer(const AddressInfo& address_info) const { + if (force_map) { + [[maybe_unused]] auto found_pool{ + FindMemoryPool(address_info.GetCpuAddr(), address_info.GetSize())}; + // nn::audio::dsp::UnmapUserPointer(this->processHandle, address_info.GetCpuAddr(), 0); + } +} + +MemoryPoolInfo::ResultState PoolMapper::Update(MemoryPoolInfo& pool, + const MemoryPoolInfo::InParameter& in_params, + MemoryPoolInfo::OutStatus& out_params) const { + if (in_params.state != MemoryPoolInfo::State::RequestAttach && + in_params.state != MemoryPoolInfo::State::RequestDetach) { + return MemoryPoolInfo::ResultState::Success; + } + + if (in_params.address == 0 || in_params.size == 0 || !Common::Is4KBAligned(in_params.address) || + !Common::Is4KBAligned(in_params.size)) { + return MemoryPoolInfo::ResultState::BadParam; + } + + switch (in_params.state) { + case MemoryPoolInfo::State::RequestAttach: + pool.SetCpuAddress(in_params.address, in_params.size); + + Map(pool); + + if (pool.IsMapped()) { + out_params.state = MemoryPoolInfo::State::Attached; + return MemoryPoolInfo::ResultState::Success; + } + pool.SetCpuAddress(0, 0); + return MemoryPoolInfo::ResultState::MapFailed; + + case MemoryPoolInfo::State::RequestDetach: + if (pool.GetCpuAddress() != in_params.address || pool.GetSize() != in_params.size) { + return MemoryPoolInfo::ResultState::BadParam; + } + + if (pool.IsUsed()) { + return MemoryPoolInfo::ResultState::InUse; + } + + Unmap(pool); + + pool.SetCpuAddress(0, 0); + pool.SetDspAddress(0); + out_params.state = MemoryPoolInfo::State::Detached; + return MemoryPoolInfo::ResultState::Success; + + default: + LOG_ERROR(Service_Audio, "Invalid MemoryPoolInfo::State!"); + break; + } + + return MemoryPoolInfo::ResultState::Success; +} + +bool PoolMapper::InitializeSystemPool(MemoryPoolInfo& pool, const u8* memory, + const u64 size_) const { + switch (pool.GetLocation()) { + case MemoryPoolInfo::Location::CPU: + return false; + case MemoryPoolInfo::Location::DSP: + pool.SetCpuAddress(reinterpret_cast(memory), size_); + if (Map(Kernel::Svc::CurrentProcess, reinterpret_cast(memory), size_)) { + pool.SetDspAddress(pool.GetCpuAddress()); + return true; + } + return false; + default: + LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location={}!", + static_cast(pool.GetLocation())); + return false; + } +} + +} // namespace AudioCore::AudioRenderer diff --git a/src/audio_core/renderer/memory/pool_mapper.h b/src/audio_core/renderer/memory/pool_mapper.h new file mode 100644 index 000000000..9a691da7a --- /dev/null +++ b/src/audio_core/renderer/memory/pool_mapper.h @@ -0,0 +1,179 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "audio_core/renderer/behavior/behavior_info.h" +#include "audio_core/renderer/memory/memory_pool_info.h" +#include "common/common_types.h" +#include "core/hle/service/audio/errors.h" + +namespace AudioCore::AudioRenderer { +class AddressInfo; + +/** + * Utility functions for managing MemoryPoolInfos + */ +class PoolMapper { +public: + explicit PoolMapper(u32 process_handle, bool force_map); + explicit PoolMapper(u32 process_handle, std::span pool_infos, u32 pool_count, + bool force_map); + + /** + * Clear the usage state for all given pools. + * + * @param pools - The memory pools to clear. + * @param count - The number of pools. + */ + static void ClearUseState(std::span pools, u32 count); + + /** + * Find the memory pool containing the given address and size from a given list of pools. + * + * @param pools - The memory pools to search within. + * @param count - The number of pools. + * @param address - The address of the region to find. + * @param size - The size of the region to find. + * @return Pointer to the memory pool if found, otherwise nullptr. + */ + MemoryPoolInfo* FindMemoryPool(MemoryPoolInfo* pools, u64 count, CpuAddr address, + u64 size) const; + + /** + * Find the memory pool containing the given address and size from the PoolMapper's memory pool. + * + * @param address - The address of the region to find. + * @param size - The size of the region to find. + * @return Pointer to the memory pool if found, otherwise nullptr. + */ + MemoryPoolInfo* FindMemoryPool(CpuAddr address, u64 size) const; + + /** + * Set the PoolMapper's memory pool to one in the given list of pools, which contains + * address_info. + * + * @param address_info - The expected region to find within pools. + * @param pools - The list of pools to search within. + * @param count - The number of pools given. + * @return True if successfully mapped, otherwise false. + */ + bool FillDspAddr(AddressInfo& address_info, MemoryPoolInfo* pools, u32 count) const; + + /** + * Set the PoolMapper's memory pool to the one containing address_info. + * + * @param address_info - The address to find the memory pool for. + * @return True if successfully mapped, otherwise false. + */ + bool FillDspAddr(AddressInfo& address_info) const; + + /** + * Try to attach a {address, size} region to the given address_info, and map it. Fills in the + * given error_info and address_info. + * + * @param error_info - Output error info. + * @param address_info - Output address info, initialized with the given {address, size} and + * attempted to map. + * @param address - Address of the region to map. + * @param size - Size of the region to map. + * @return True if successfully attached, otherwise false. + */ + bool TryAttachBuffer(BehaviorInfo::ErrorInfo& error_info, AddressInfo& address_info, + CpuAddr address, u64 size) const; + + /** + * Return whether force mapping is enabled. + * + * @return True if force mapping is enabled, otherwise false. + */ + bool IsForceMapEnabled() const; + + /** + * Get the process handle, depending on location. + * + * @param pool - The pool to check the location of. + * @return CurrentProcessHandle if location == DSP, + * the PoolMapper's process_handle if location == CPU + */ + u32 GetProcessHandle(const MemoryPoolInfo* pool) const; + + /** + * Map the given region with the given handle. This is a no-op. + * + * @param handle - The process handle to map to. + * @param cpu_addr - Address to map. + * @param size - Size to map. + * @return True if successfully mapped, otherwise false. + */ + bool Map(u32 handle, CpuAddr cpu_addr, u64 size) const; + + /** + * Map the given memory pool. + * + * @param pool - The pool to map. + * @return True if successfully mapped, otherwise false. + */ + bool Map(MemoryPoolInfo& pool) const; + + /** + * Unmap the given region with the given handle. + * + * @param handle - The process handle to unmap to. + * @param cpu_addr - Address to unmap. + * @param size - Size to unmap. + * @return True if successfully unmapped, otherwise false. + */ + bool Unmap(u32 handle, CpuAddr cpu_addr, u64 size) const; + + /** + * Unmap the given memory pool. + * + * @param pool - The pool to unmap. + * @return True if successfully unmapped, otherwise false. + */ + bool Unmap(MemoryPoolInfo& pool) const; + + /** + * Forcibly unmap the given region. + * + * @param address_info - The region to unmap. + */ + void ForceUnmapPointer(const AddressInfo& address_info) const; + + /** + * Update the given memory pool. + * + * @param pool - Pool to update. + * @param in_params - Input parameters for the update. + * @param out_params - Output parameters for the update. + * @return The result of the update. See MemoryPoolInfo::ResultState + */ + MemoryPoolInfo::ResultState Update(MemoryPoolInfo& pool, + const MemoryPoolInfo::InParameter& in_params, + MemoryPoolInfo::OutStatus& out_params) const; + + /** + * Initialize the PoolMapper's memory pool. + * + * @param pool - Input pool to initialize. + * @param memory - Pointer to the memory region for the pool. + * @param size - Size of the memory region for the pool. + * @return True if initialized successfully, otherwise false. + */ + bool InitializeSystemPool(MemoryPoolInfo& pool, const u8* memory, u64 size) const; + +private: + /// Process handle for this mapper, used when location == CPU + u32 process_handle; + /// List of memory pools assigned to this mapper + MemoryPoolInfo* pool_infos{}; + /// The number of pools + u64 pool_count{}; + /// Is forced mapping enabled + bool force_map; +}; + +} // namespace AudioCore::AudioRenderer -- cgit v1.2.3