Compare commits

...

6 Commits

Author SHA1 Message Date
lizzie 1439a8041b fx 2026-05-19 07:53:59 +00:00
lizzie 6c3ea34293 fixup the stupid boost map 2026-05-19 07:08:37 +00:00
lizzie bca75e8c21 Trigger Build 2026-05-19 07:08:37 +00:00
lizzie 7572632afa fuckery2 2026-05-19 07:08:37 +00:00
lizzie 641a430463 no move constructor? 2026-05-19 07:08:36 +00:00
lizzie 60328b0bd9 [core/hle/service/nvdrv] fix Nvmap storage being pointer-unstable due to ankerl maps
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-05-19 07:08:36 +00:00
5 changed files with 119 additions and 183 deletions
+61 -106
View File
@@ -25,42 +25,33 @@ NvMap::Handle::Handle(u64 size_, Id id_)
flags.raw = 0; flags.raw = 0;
} }
NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, NvCore::SessionId pSessionId) {
NvCore::SessionId pSessionId) {
std::scoped_lock lock(mutex);
// Handles cannot be allocated twice // Handles cannot be allocated twice
if (allocated) { if (allocated) {
return NvResult::AccessDenied; return NvResult::AccessDenied;
} }
flags = pFlags; flags = pFlags;
kind = pKind; kind = pKind;
align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign;
session_id = pSessionId; session_id = pSessionId;
// This flag is only applicable for handles with an address passed // This flag is only applicable for handles with an address passed
if (pAddress) { if (pAddress) {
flags.keep_uncached_after_free.Assign(0); flags.keep_uncached_after_free.Assign(0);
} else { } else {
LOG_CRITICAL(Service_NVDRV, LOG_CRITICAL(Service_NVDRV, "Mapping nvmap handles without a CPU side address is unimplemented!");
"Mapping nvmap handles without a CPU side address is unimplemented!");
} }
size = Common::AlignUp(size, YUZU_PAGESIZE); size = Common::AlignUp(size, YUZU_PAGESIZE);
aligned_size = Common::AlignUp(size, align); aligned_size = Common::AlignUp(size, align);
address = pAddress; address = pAddress;
allocated = true; allocated = true;
return NvResult::Success; return NvResult::Success;
} }
NvResult NvMap::Handle::Duplicate(bool internal_session) { NvResult NvMap::Handle::Duplicate(bool internal_session) {
std::scoped_lock lock(mutex);
// Unallocated handles cannot be duplicated as duplication requires memory accounting (in HOS) // Unallocated handles cannot be duplicated as duplication requires memory accounting (in HOS)
if (!allocated) [[unlikely]] { if (!allocated) [[unlikely]] {
return NvResult::BadValue; return NvResult::BadValue;
} }
// If we internally use FromId the duplication tracking of handles won't work accurately due to // If we internally use FromId the duplication tracking of handles won't work accurately due to
// us not implementing per-process handle refs. // us not implementing per-process handle refs.
if (internal_session) { if (internal_session) {
@@ -68,16 +59,14 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) {
} else { } else {
dupes++; dupes++;
} }
return NvResult::Success; return NvResult::Success;
} }
NvMap::NvMap(Container& core_, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, core{core_} {} NvMap::NvMap(Container& core_, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, core{core_} {}
void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) { void NvMap::AddHandle(Handle&& handle_description) {
std::scoped_lock lock(handles_lock); std::scoped_lock l(handles_lock);
handles.insert_or_assign(handle_description.id, std::move(handle_description));
handles.emplace(handle_description->id, std::move(handle_description));
} }
void NvMap::UnmapHandle(Handle& handle_description) { void NvMap::UnmapHandle(Handle& handle_description) {
@@ -116,57 +105,48 @@ void NvMap::UnmapHandle(Handle& handle_description) {
bool NvMap::TryRemoveHandle(const Handle& handle_description) { bool NvMap::TryRemoveHandle(const Handle& handle_description) {
// No dupes left, we can remove from handle map // No dupes left, we can remove from handle map
if (handle_description.dupes == 0 && handle_description.internal_dupes == 0) { if (handle_description.dupes == 0 && handle_description.internal_dupes == 0) {
std::scoped_lock lock(handles_lock); std::scoped_lock l(handles_lock);
auto it = handles.find(handle_description.id);
auto it{handles.find(handle_description.id)};
if (it != handles.end()) { if (it != handles.end()) {
handles.erase(it); handles.erase(it);
} }
return true; return true;
} else { } else {
return false; return false;
} }
} }
NvResult NvMap::CreateHandle(u64 size, std::shared_ptr<NvMap::Handle>& result_out) { NvResult NvMap::CreateHandle(u64 size, Handle::Id& out_handle) {
if (!size) [[unlikely]] { if (!Common::AlignUp(size, YUZU_PAGESIZE)) {
return NvResult::BadValue; return NvResult::BadValue;
} }
u32 id = next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed);
u32 id{next_handle_id.fetch_add(HandleIdIncrement, std::memory_order_relaxed)}; AddHandle(Handle(size, id));
auto handle_description{std::make_shared<Handle>(size, id)}; out_handle = id;
AddHandle(handle_description);
result_out = handle_description;
return NvResult::Success; return NvResult::Success;
} }
std::shared_ptr<NvMap::Handle> NvMap::GetHandle(Handle::Id handle) { std::optional<std::reference_wrapper<NvMap::Handle>> NvMap::GetHandle(Handle::Id handle) {
std::scoped_lock lock(handles_lock); if (auto const it = handles.find(handle); it != handles.end())
try { return {it->second};
return handles.at(handle); return std::nullopt;
} catch (std::out_of_range&) {
return nullptr;
}
} }
DAddr NvMap::GetHandleAddress(Handle::Id handle) { DAddr NvMap::GetHandleAddress(Handle::Id handle) {
std::scoped_lock lock(handles_lock); if (auto const it = handles.find(handle); it != handles.end())
try { return it->second.d_address;
return handles.at(handle)->d_address; return 0;
} catch (std::out_of_range&) {
return 0;
}
} }
DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) { DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
auto handle_description{GetHandle(handle)}; std::scoped_lock lock(handles_lock);
if (!handle_description) [[unlikely]] { auto o = GetHandle(handle);
if (!o) [[unlikely]] {
return 0; return 0;
} }
std::scoped_lock lock(handle_description->mutex); auto handle_description = &o->get();
const auto map_low_area = [&] { const auto map_low_area = [&] {
if (handle_description->pin_virt_address == 0) { if (handle_description->pin_virt_address == 0) {
u32 address = host1x.Allocator().Allocate(u32(handle_description->aligned_size)); u32 address = host1x.Allocator().Allocate(u32(handle_description->aligned_size));
@@ -180,17 +160,15 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
{ {
// Lock now to prevent our queue entry from being removed for allocation in-between the // Lock now to prevent our queue entry from being removed for allocation in-between the
// following check and erase // following check and erase
std::scoped_lock queueLock(unmap_queue_lock); std::scoped_lock ql(unmap_queue_lock);
if (handle_description->unmap_queue_entry) { if (handle_description->unmap_queue_entry) {
unmap_queue.erase(*handle_description->unmap_queue_entry); unmap_queue.erase(*handle_description->unmap_queue_entry);
handle_description->unmap_queue_entry.reset(); handle_description->unmap_queue_entry.reset();
if (low_area_pin) { if (low_area_pin) {
map_low_area(); map_low_area();
handle_description->pins++; handle_description->pins++;
return static_cast<DAddr>(handle_description->pin_virt_address); return DAddr(handle_description->pin_virt_address);
} }
handle_description->pins++; handle_description->pins++;
return handle_description->d_address; return handle_description->d_address;
} }
@@ -211,12 +189,11 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
while ((address = smmu.Allocate(aligned_up)) == 0) { while ((address = smmu.Allocate(aligned_up)) == 0) {
// Free handles until the allocation succeeds // Free handles until the allocation succeeds
std::scoped_lock queueLock(unmap_queue_lock); std::scoped_lock queueLock(unmap_queue_lock);
if (auto freeHandleDesc{unmap_queue.front()}) { if (auto free_handle = handles.find(unmap_queue.front()); free_handle != handles.end()) {
// Handles in the unmap queue are guaranteed not to be pinned so don't bother // Handles in the unmap queue are guaranteed not to be pinned so don't bother
// checking if they are before unmapping // checking if they are before unmapping
std::scoped_lock freeLock(freeHandleDesc->mutex);
if (handle_description->d_address) if (handle_description->d_address)
UnmapHandle(*freeHandleDesc); UnmapHandle(free_handle->second);
} else { } else {
LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!");
} }
@@ -234,51 +211,44 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
handle_description->pins++; handle_description->pins++;
if (low_area_pin) { if (low_area_pin) {
return static_cast<DAddr>(handle_description->pin_virt_address); return DAddr(handle_description->pin_virt_address);
} }
return handle_description->d_address; return handle_description->d_address;
} }
void NvMap::UnpinHandle(Handle::Id handle) { void NvMap::UnpinHandle(Handle::Id handle) {
auto handle_description{GetHandle(handle)}; std::scoped_lock lock(handles_lock);
if (!handle_description) { if (auto o = GetHandle(handle); o) {
return; auto handle_description = &o->get();
} if (--handle_description->pins < 0) {
LOG_WARNING(Service_NVDRV, "Pin count imbalance detected!");
std::scoped_lock lock(handle_description->mutex); } else if (!handle_description->pins) {
if (--handle_description->pins < 0) { std::scoped_lock ql(unmap_queue_lock);
LOG_WARNING(Service_NVDRV, "Pin count imbalance detected!"); // Add to the unmap queue allowing this handle's memory to be freed if needed
} else if (!handle_description->pins) { unmap_queue.push_back(handle);
std::scoped_lock queueLock(unmap_queue_lock); handle_description->unmap_queue_entry = std::prev(unmap_queue.end());
}
// Add to the unmap queue allowing this handle's memory to be freed if needed
unmap_queue.push_back(handle_description);
handle_description->unmap_queue_entry = std::prev(unmap_queue.end());
} }
} }
void NvMap::DuplicateHandle(Handle::Id handle, bool internal_session) { void NvMap::DuplicateHandle(Handle::Id handle, bool internal_session) {
auto handle_description{GetHandle(handle)}; std::scoped_lock lock(handles_lock);
if (!handle_description) { auto o = GetHandle(handle);
if (!o) {
LOG_CRITICAL(Service_NVDRV, "Unregistered handle!"); LOG_CRITICAL(Service_NVDRV, "Unregistered handle!");
return; return;
} }
auto result = o->get().Duplicate(internal_session);
auto result = handle_description->Duplicate(internal_session);
if (result != NvResult::Success) { if (result != NvResult::Success) {
LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!"); LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!");
} }
} }
std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool internal_session) { std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool internal_session) {
std::weak_ptr<Handle> hWeak{GetHandle(handle)}; // We use a weak ptr here so we can tell when the handle has been freed and report that back to guest
FreeInfo freeInfo; std::scoped_lock lock(handles_lock);
if (auto o = GetHandle(handle); o) {
// We use a weak ptr here so we can tell when the handle has been freed and report that back to auto handle_description = &o->get();
// guest
if (auto handle_description = hWeak.lock()) {
std::scoped_lock lock(handle_description->mutex);
if (internal_session) { if (internal_session) {
if (--handle_description->internal_dupes < 0) if (--handle_description->internal_dupes < 0)
LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!"); LOG_WARNING(Service_NVDRV, "Internal duplicate count imbalance detected!");
@@ -288,25 +258,25 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna
} else if (handle_description->dupes == 0) { } else if (handle_description->dupes == 0) {
// Force unmap the handle // Force unmap the handle
if (handle_description->d_address) { if (handle_description->d_address) {
std::scoped_lock queueLock(unmap_queue_lock); std::scoped_lock ql(unmap_queue_lock);
UnmapHandle(*handle_description); UnmapHandle(*handle_description);
} }
handle_description->pins = 0; handle_description->pins = 0;
} }
} }
// Try to remove the shared ptr to the handle from the map, if nothing else is using the // Try to remove the shared ptr to the handle from the map, if nothing else is using the
// handle then it will now be freed when `handle_description` goes out of scope // handle then it will now be freed when `handle_description` goes out of scope
if (TryRemoveHandle(*handle_description)) { if (TryRemoveHandle(*handle_description)) {
LOG_DEBUG(Service_NVDRV, "Removed nvmap handle: {}", handle); LOG_DEBUG(Service_NVDRV, "Removed nvmap handle: {}", handle);
} else { } else {
LOG_DEBUG(Service_NVDRV, LOG_DEBUG(Service_NVDRV, "Tried to free nvmap handle: {} but didn't as it still has duplicates", handle);
"Tried to free nvmap handle: {} but didn't as it still has duplicates",
handle);
} }
// // If the handle hasn't been freed from memory, mark that
freeInfo = { // if (!hWeak.expired()) {
// LOG_DEBUG(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle);
// freeInfo.can_unlock = false;
// }
return FreeInfo{
.address = handle_description->address, .address = handle_description->address,
.size = handle_description->size, .size = handle_description->size,
.was_uncached = handle_description->flags.map_uncached.Value() != 0, .was_uncached = handle_description->flags.map_uncached.Value() != 0,
@@ -315,30 +285,15 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna
} else { } else {
return std::nullopt; return std::nullopt;
} }
// If the handle hasn't been freed from memory, mark that
if (!hWeak.expired()) {
LOG_DEBUG(Service_NVDRV, "nvmap handle: {} wasn't freed as it is still in use", handle);
freeInfo.can_unlock = false;
}
return freeInfo;
} }
void NvMap::UnmapAllHandles(NvCore::SessionId session_id) { void NvMap::UnmapAllHandles(NvCore::SessionId session_id) {
auto handles_copy = [&] { std::scoped_lock lk{handles_lock};
std::scoped_lock lk{handles_lock}; for (auto it = handles.begin(); it != handles.end(); ++it) {
return handles; if (it->second.session_id.id != session_id.id || it->second.dupes <= 0) {
}(); continue;
for (auto& [id, handle] : handles_copy) {
{
std::scoped_lock lk{handle->mutex};
if (handle->session_id.id != session_id.id || handle->dupes <= 0) {
continue;
}
} }
FreeHandle(id, false); FreeHandle(it->first, false);
} }
} }
+30 -44
View File
@@ -12,6 +12,11 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional> #include <optional>
#if BOOST_VERSION >= 109000
#include <boost/unordered/unordered_node_map.hpp>
#else
#include <unordered_map>
#endif
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
#include <assert.h> #include <assert.h>
@@ -31,54 +36,36 @@ class Host1x;
namespace Service::Nvidia::NvCore { namespace Service::Nvidia::NvCore {
class Container; class Container;
/** /// @brief The nvmap core class holds the global state for nvmap and provides methods to manage handles
* @brief The nvmap core class holds the global state for nvmap and provides methods to manage
* handles
*/
class NvMap { class NvMap {
public: public:
/** /// @brief A handle to a contiguous block of memory in an application's address space
* @brief A handle to a contiguous block of memory in an application's address space
*/
struct Handle { struct Handle {
std::mutex mutex; using Id = u32;
std::optional<typename std::list<Handle::Id>::iterator> unmap_queue_entry{};
u64 align{}; //!< The alignment to use when pinning the handle onto the SMMU u64 align{}; //!< The alignment to use when pinning the handle onto the SMMU
u64 size; //!< Page-aligned size of the memory the handle refers to u64 size; //!< Page-aligned size of the memory the handle refers to
u64 aligned_size; //!< `align`-aligned size of the memory the handle refers to u64 aligned_size; //!< `align`-aligned size of the memory the handle refers to
u64 orig_size; //!< Original unaligned size of the memory this handle refers to u64 orig_size; //!< Original unaligned size of the memory this handle refers to
DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds to, this can also be in the nvdrv tmem
VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, this can also be in the nvdrv tmem
s64 pins{};
s32 dupes{1}; //!< How many guest references there are to this handle s32 dupes{1}; //!< How many guest references there are to this handle
s32 internal_dupes{0}; //!< How many emulator-internal references there are to this handle s32 internal_dupes{0}; //!< How many emulator-internal references there are to this handle
using Id = u32;
Id id; //!< A globally unique identifier for this handle Id id; //!< A globally unique identifier for this handle
s64 pins{};
u32 pin_virt_address{}; u32 pin_virt_address{};
std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{};
union Flags { union Flags {
u32 raw; u32 raw;
BitField<0, 1, u32> map_uncached; //!< If the handle should be mapped as uncached BitField<0, 1, u32> map_uncached; //!< If the handle should be mapped as uncached
BitField<2, 1, u32> keep_uncached_after_free; //!< Only applicable when the handle was BitField<2, 1, u32> keep_uncached_after_free; //!< Only applicable when the handle was allocated with a fixed address
//!< allocated with a fixed address BitField<4, 1, u32> _unk0_; //!< Passed to IOVMM for pins
BitField<4, 1, u32> _unk0_; //!< Passed to IOVMM for pins
} flags{}; } flags{};
static_assert(sizeof(Flags) == sizeof(u32)); static_assert(sizeof(Flags) == sizeof(u32));
VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to,
//!< this can also be in the nvdrv tmem
bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC
//!< call
u8 kind{}; //!< Used for memory compression
bool allocated{}; //!< If the handle has been allocated with `Alloc`
bool in_heap{};
NvCore::SessionId session_id{}; NvCore::SessionId session_id{};
u8 kind{}; //!< Used for memory compression
DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds bool allocated : 1 = false; //!< If the handle has been allocated with `Alloc`
//!< to, this can also be in the nvdrv tmem bool in_heap : 1 = false;
bool is_shared_mem_mapped : 1 = false; //!< If this nvmap has been mapped with the MapSharedMem IPC < call
Handle(u64 size, Id id); Handle(u64 size, Id id);
@@ -123,9 +110,9 @@ public:
/** /**
* @brief Creates an unallocated handle of the given size * @brief Creates an unallocated handle of the given size
*/ */
[[nodiscard]] NvResult CreateHandle(u64 size, std::shared_ptr<NvMap::Handle>& result_out); [[nodiscard]] NvResult CreateHandle(u64 size, Handle::Id& out_handle);
std::shared_ptr<Handle> GetHandle(Handle::Id handle); std::optional<std::reference_wrapper<Handle>> GetHandle(Handle::Id handle);
DAddr GetHandleAddress(Handle::Id handle); DAddr GetHandleAddress(Handle::Id handle);
@@ -157,20 +144,21 @@ public:
void UnmapAllHandles(NvCore::SessionId session_id); void UnmapAllHandles(NvCore::SessionId session_id);
private: std::list<Handle::Id> unmap_queue{};
std::list<std::shared_ptr<Handle>> unmap_queue{}; /// Main owning map of handles
#if BOOST_VERSION >= 109000
boost::unordered_node_map<Handle::Id, Handle> handles{};
#else
std::unordered_map<Handle::Id, Handle> handles{};
#endif
std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue` std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue`
ankerl::unordered_dense::map<Handle::Id, std::shared_ptr<Handle>>
handles{}; //!< Main owning map of handles
std::mutex handles_lock; //!< Protects access to `handles` std::mutex handles_lock; //!< Protects access to `handles`
static constexpr u32 HandleIdIncrement{4}; //!< Each new handle ID is an increment of 4 from the previous
static constexpr u32 HandleIdIncrement{
4}; //!< Each new handle ID is an increment of 4 from the previous
std::atomic<u32> next_handle_id{HandleIdIncrement}; std::atomic<u32> next_handle_id{HandleIdIncrement};
Tegra::Host1x::Host1x& host1x; Tegra::Host1x::Host1x& host1x;
Container& core;
void AddHandle(std::shared_ptr<Handle> handle); void AddHandle(Handle&& handle);
/** /**
* @brief Unmaps and frees the SMMU memory region a handle is mapped to * @brief Unmaps and frees the SMMU memory region a handle is mapped to
@@ -184,7 +172,5 @@ private:
* @return If the handle was removed from the map * @return If the handle was removed from the map
*/ */
bool TryRemoveHandle(const Handle& handle_description); bool TryRemoveHandle(const Handle& handle_description);
Container& core;
}; };
} // namespace Service::Nvidia::NvCore } // namespace Service::Nvidia::NvCore
@@ -329,10 +329,11 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
} }
} }
auto handle{nvmap.GetHandle(params.handle)}; auto o = nvmap.GetHandle(params.handle);
if (!handle) { if (!o) {
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle = &o->get();
DAddr device_address = DAddr(nvmap.PinHandle(params.handle, false) + params.buffer_offset); DAddr device_address = DAddr(nvmap.PinHandle(params.handle, false) + params.buffer_offset);
u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; u64 size{params.mapping_size ? params.mapping_size : handle->orig_size};
@@ -103,17 +103,13 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
for (std::size_t i = 0; i < syncpt_increments.size(); i++) { for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i]; const SyncptIncr& syncpt_incr = syncpt_increments[i];
fence_thresholds[i] = fence_thresholds[i] = syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
} }
for (const auto& cmd_buffer : command_buffers) { for (const auto& cmd_buffer : command_buffers) {
const auto object = nvmap.GetHandle(cmd_buffer.memory_id); const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
Core::Memory::CpuGuestMemory<Tegra::ChCommandHeader, Core::Memory::CpuGuestMemory<Tegra::ChCommandHeader, Core::Memory::GuestMemoryFlags::SafeRead> cmdlist(session->process->GetMemory(), object->get().address + cmd_buffer.offset, cmd_buffer.word_count);
Core::Memory::GuestMemoryFlags::SafeRead>
cmdlist(session->process->GetMemory(), object->address + cmd_buffer.offset,
cmd_buffer.word_count);
host1x.PushEntries(fd, std::move(cmdlist)); host1x.PushEntries(fd, std::move(cmdlist));
} }
+23 -25
View File
@@ -83,17 +83,14 @@ void nvmap::OnClose(DeviceFD fd) {
NvResult nvmap::IocCreate(IocCreateParams& params) { NvResult nvmap::IocCreate(IocCreateParams& params) {
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
std::shared_ptr<NvCore::NvMap::Handle> handle_description{}; NvCore::NvMap::Handle handle_description(0, 0);
auto result = // Orig size is the unaligned size, set the handle to that
file.CreateHandle(Common::AlignUp(params.size, YUZU_PAGESIZE), handle_description); auto result = file.CreateHandle(params.size, params.handle);
if (result != NvResult::Success) { if (result != NvResult::Success) {
LOG_CRITICAL(Service_NVDRV, "Failed to create Object"); LOG_CRITICAL(Service_NVDRV, "Failed to create Object");
return result; return result;
} }
handle_description->orig_size = params.size; // Orig size is the unaligned size LOG_DEBUG(Service_NVDRV, "handle: {}, size: {:#X}", params.handle, params.size);
params.handle = handle_description->id;
LOG_DEBUG(Service_NVDRV, "handle: {}, size: {:#X}", handle_description->id, params.size);
return NvResult::Success; return NvResult::Success;
} }
@@ -115,30 +112,27 @@ NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) {
params.align = YUZU_PAGESIZE; params.align = YUZU_PAGESIZE;
} }
auto handle_description{file.GetHandle(params.handle)}; std::scoped_lock lock(file.handles_lock);
if (!handle_description) { auto o = file.GetHandle(params.handle);
if (!o) {
LOG_CRITICAL(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); LOG_CRITICAL(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle_description = &o->get();
if (handle_description->allocated) { if (handle_description->allocated) {
LOG_CRITICAL(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); LOG_CRITICAL(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
return NvResult::InsufficientMemory; return NvResult::InsufficientMemory;
} }
const auto result = handle_description->Alloc(params.flags, params.align, params.kind, const auto result = handle_description->Alloc(params.flags, params.align, params.kind, params.address, sessions[fd]);
params.address, sessions[fd]);
if (result != NvResult::Success) { if (result != NvResult::Success) {
LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle);
return result; return result;
} }
bool is_out_io{}; bool is_out_io{};
auto process = container.GetSession(sessions[fd])->process; auto process = container.GetSession(sessions[fd])->process;
ASSERT(process->GetPageTable() ASSERT(process->GetPageTable().LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, handle_description->size, Kernel::KMemoryPermission::None, true, false).IsSuccess());
.LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
handle_description->size,
Kernel::KMemoryPermission::None, true, false)
.IsSuccess());
return result; return result;
} }
@@ -151,13 +145,13 @@ NvResult nvmap::IocGetId(IocGetIdParams& params) {
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle_description{file.GetHandle(params.handle)}; std::scoped_lock lock(file.handles_lock);
if (!handle_description) { auto o = file.GetHandle(params.handle);
if (!o) {
LOG_CRITICAL(Service_NVDRV, "Error!"); LOG_CRITICAL(Service_NVDRV, "Error!");
return NvResult::AccessDenied; // This will always return EPERM irrespective of if the return NvResult::AccessDenied; // This will always return EPERM irrespective of if the handle exists or not
// handle exists or not
} }
auto handle_description = &o->get();
params.id = handle_description->id; params.id = handle_description->id;
return NvResult::Success; return NvResult::Success;
} }
@@ -174,12 +168,14 @@ NvResult nvmap::IocFromId(IocFromIdParams& params) {
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle_description{file.GetHandle(params.id)}; std::scoped_lock lock(file.handles_lock);
if (!handle_description) { auto o = file.GetHandle(params.id);
if (!o) {
LOG_CRITICAL(Service_NVDRV, "Unregistered handle!"); LOG_CRITICAL(Service_NVDRV, "Unregistered handle!");
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle_description = &o->get();
auto result = handle_description->Duplicate(false); auto result = handle_description->Duplicate(false);
if (result != NvResult::Success) { if (result != NvResult::Success) {
LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!"); LOG_CRITICAL(Service_NVDRV, "Could not duplicate handle!");
@@ -199,12 +195,14 @@ NvResult nvmap::IocParam(IocParamParams& params) {
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle_description{file.GetHandle(params.handle)}; std::scoped_lock lock(file.handles_lock);
if (!handle_description) { auto o = file.GetHandle(params.handle);
if (!o) {
LOG_CRITICAL(Service_NVDRV, "Not registered handle!"); LOG_CRITICAL(Service_NVDRV, "Not registered handle!");
return NvResult::BadValue; return NvResult::BadValue;
} }
auto handle_description = &o->get();
switch (params.param) { switch (params.param) {
case HandleParameterType::Size: case HandleParameterType::Size:
params.result = static_cast<u32_le>(handle_description->orig_size); params.result = static_cast<u32_le>(handle_description->orig_size);