Compare commits

...

28 Commits

Author SHA1 Message Date
yuzubot
6a3c15f6e1 Android #174 2023-12-28 00:57:01 +00:00
yuzubot
b057a0295d Merge PR 12487 2023-12-28 00:57:01 +00:00
yuzubot
b7ad90dc18 Merge PR 12479 2023-12-28 00:57:01 +00:00
yuzubot
f2737fa6d4 Merge PR 12466 2023-12-28 00:57:01 +00:00
liamwhite
12178c694a Merge pull request #12455 from liamwhite/end-wait
kernel: use simple mutex for object list container
2023-12-26 11:46:19 -05:00
liamwhite
de1e5584b3 Merge pull request #12465 from liamwhite/proper-handle-table
service: fetch objects from the client handle table
2023-12-26 11:46:11 -05:00
liamwhite
1559984f77 Merge pull request #12471 from FearlessTobi/port-7146
Port citra-emu/citra#7146: "assert/logging: Stop the logging thread and flush the backends before crashing"
2023-12-26 11:46:04 -05:00
liamwhite
467ac4fdfe Merge pull request #12472 from FearlessTobi/port-7239
Port citra-emu/citra#7239: "common: Miscellaneous cleanups"
2023-12-26 11:45:57 -05:00
liamwhite
69b7100dac Merge pull request #12449 from liamwhite/debug-utils
renderer_vulkan: skip SetObjectNameEXT on unsupported driver
2023-12-26 11:45:39 -05:00
liamwhite
14dc41d4b3 Merge pull request #12448 from liamwhite/format-assert
renderer_vulkan: demote format assert to error log
2023-12-26 11:45:33 -05:00
liamwhite
ad049f13aa Merge pull request #12415 from ameerj/ogl-draw-auto
gl_rasterizer: Implement DrawTransformFeedback macro
2023-12-26 11:45:25 -05:00
FearlessTobi
4f569fd568 assert/logging: Stop the logging thread and flush the backends before crashing
Co-Authored-By: SachinVin <26602104+SachinVin@users.noreply.github.com>
2023-12-26 10:35:14 +01:00
FearlessTobi
553dac2ae0 ring_buffer: Use feature macro
Co-Authored-By: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-12-25 14:10:40 +01:00
FearlessTobi
96abe0d7d3 main: Remove unused enum
Co-Authored-By: GPUCode <47210458+GPUCode@users.noreply.github.com>
2023-12-25 14:10:05 +01:00
Liam
47e44a6693 am/jit: reference memory instance from context 2023-12-24 19:36:42 -05:00
Liam
cf8c7d4ed3 kernel: remove unecessary process member from handle table 2023-12-24 19:23:03 -05:00
Liam
5165ed9efd service: fetch objects from the client handle table 2023-12-24 19:20:43 -05:00
Fernando S
05e3db3ac9 Merge pull request #12394 from liamwhite/per-process-memory
general: properly support multiple memory instances
2023-12-24 16:23:14 +01:00
Liam
e3491a9ee8 kernel: use simple mutex for object list container 2023-12-23 16:26:07 -05:00
Liam
6a1ddc5028 renderer_vulkan: skip SetObjectNameEXT on unsupported driver 2023-12-23 11:08:02 -05:00
Liam
b1d4804c07 renderer_vulkan: demote format assert to error log 2023-12-23 11:04:02 -05:00
Liam
c57ae803a6 kernel: fix resource limit imbalance 2023-12-22 21:52:49 -05:00
Liam
db7b2bc8f1 kernel: restrict nce to applications 2023-12-22 21:52:49 -05:00
Liam
31bf57a310 general: properly support multiple memory instances 2023-12-22 21:52:49 -05:00
Liam
cae675343c k_server_session: remove scratch buffer usage in favor of direct copy 2023-12-22 21:52:49 -05:00
Liam
35501ba41c k_server_session: process for guest servers 2023-12-22 21:52:49 -05:00
Liam
419055e484 kernel: instantiate memory separately for each guest process 2023-12-22 21:52:49 -05:00
Ameer J
bbc0ed118d gl_rasterizer: Implement DrawTransformFeedback macro 2023-12-19 19:54:57 -05:00
85 changed files with 2389 additions and 851 deletions

View File

@@ -1,3 +1,14 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12466](https://github.com/yuzu-emu/yuzu//pull/12466) | [`adb2af0a2`](https://github.com/yuzu-emu/yuzu//pull/12466/files) | core: track separate heap allocation for linux | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12479](https://github.com/yuzu-emu/yuzu//pull/12479) | [`20e040723`](https://github.com/yuzu-emu/yuzu//pull/12479/files) | video_core: Fix buffer_row_length for linear compressed textures | [GPUCode](https://github.com/GPUCode/) | Yes |
| [12487](https://github.com/yuzu-emu/yuzu//pull/12487) | [`d0c60605a`](https://github.com/yuzu-emu/yuzu//pull/12487/files) | shader_recompiler: use default value for clip distances array | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!-- <!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later

View File

@@ -64,6 +64,8 @@ add_library(common STATIC
fs/path_util.cpp fs/path_util.cpp
fs/path_util.h fs/path_util.h
hash.h hash.h
heap_tracker.cpp
heap_tracker.h
hex_util.cpp hex_util.cpp
hex_util.h hex_util.h
host_memory.cpp host_memory.cpp

View File

@@ -3,16 +3,19 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/logging/backend.h"
#include "common/settings.h" #include "common/settings.h"
void assert_fail_impl() { void assert_fail_impl() {
if (Settings::values.use_debug_asserts) { if (Settings::values.use_debug_asserts) {
Common::Log::Stop();
Crash(); Crash();
} }
} }
[[noreturn]] void unreachable_impl() { [[noreturn]] void unreachable_impl() {
Common::Log::Stop();
Crash(); Crash();
throw std::runtime_error("Unreachable code"); throw std::runtime_error("Unreachable code");
} }

281
src/common/heap_tracker.cpp Normal file
View File

@@ -0,0 +1,281 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include <vector>
#include "common/heap_tracker.h"
#include "common/logging/log.h"
namespace Common {
namespace {
s64 GetMaxPermissibleResidentMapCount() {
// Default value.
s64 value = 65530;
// Try to read how many mappings we can make.
std::ifstream s("/proc/sys/vm/max_map_count");
s >> value;
// Print, for debug.
LOG_INFO(HW_Memory, "Current maximum map count: {}", value);
// Allow 20000 maps for other code and to account for split inaccuracy.
return std::max<s64>(value - 20000, 0);
}
} // namespace
HeapTracker::HeapTracker(Common::HostMemory& buffer)
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
HeapTracker::~HeapTracker() = default;
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
MemoryPermission perm, bool is_separate_heap) {
// When mapping other memory, map pages immediately.
if (!is_separate_heap) {
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
return;
}
{
// We are mapping part of a separate heap.
std::scoped_lock lk{m_lock};
auto* const map = new SeparateHeapMap{
.vaddr = virtual_offset,
.paddr = host_offset,
.size = length,
.tick = m_tick++,
.perm = perm,
.is_resident = false,
};
// Insert into mappings.
m_map_count++;
m_mappings.insert(*map);
}
// Finally, map.
this->DeferredMapSeparateHeap(virtual_offset);
}
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
// If this is a separate heap...
if (is_separate_heap) {
std::scoped_lock lk{m_lock};
const SeparateHeapMap key{
.vaddr = virtual_offset,
};
// Split at the boundaries of the region we are removing.
this->SplitHeapMapLocked(virtual_offset);
this->SplitHeapMapLocked(virtual_offset + size);
// Erase all mappings in range.
auto it = m_mappings.find(key);
while (it != m_mappings.end() && it->vaddr < virtual_offset + size) {
// Get underlying item.
auto* const item = std::addressof(*it);
// If resident, erase from resident map.
if (item->is_resident) {
ASSERT(--m_resident_map_count >= 0);
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
}
// Erase from map.
ASSERT(--m_map_count >= 0);
it = m_mappings.erase(it);
// Free the item.
delete item;
}
}
// Unmap pages.
m_buffer.Unmap(virtual_offset, size, false);
}
void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission perm) {
// Ensure no rebuild occurs while reprotecting.
std::shared_lock lk{m_rebuild_lock};
// Split at the boundaries of the region we are reprotecting.
this->SplitHeapMap(virtual_offset, size);
// Declare tracking variables.
const VAddr end = virtual_offset + size;
VAddr cur = virtual_offset;
while (cur < end) {
VAddr next = cur;
bool should_protect = false;
{
std::scoped_lock lk2{m_lock};
const SeparateHeapMap key{
.vaddr = next,
};
// Try to get the next mapping corresponding to this address.
const auto it = m_mappings.nfind(key);
if (it == m_mappings.end()) {
// There are no separate heap mappings remaining.
next = end;
should_protect = true;
} else if (it->vaddr == cur) {
// We are in range.
// Update permission bits.
it->perm = perm;
// Determine next address and whether we should protect.
next = cur + it->size;
should_protect = it->is_resident;
} else /* if (it->vaddr > cur) */ {
// We weren't in range, but there is a block coming up that will be.
next = it->vaddr;
should_protect = true;
}
}
// Clamp to end.
next = std::min(next, end);
// Reprotect, if we need to.
if (should_protect) {
m_buffer.Protect(cur, next - cur, perm);
}
// Advance.
cur = next;
}
}
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
if (m_buffer.IsInVirtualRange(fault_address)) {
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
}
return false;
}
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
bool rebuild_required = false;
{
std::scoped_lock lk{m_lock};
// Check to ensure this was a non-resident separate heap mapping.
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
if (it == m_mappings.end() || it->is_resident) {
return false;
}
// Update tick before possible rebuild.
it->tick = m_tick++;
// Check if we need to rebuild.
if (m_resident_map_count > m_max_resident_map_count) {
rebuild_required = true;
}
// Map the area.
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
// This map is now resident.
it->is_resident = true;
m_resident_map_count++;
m_resident_mappings.insert(*it);
}
if (rebuild_required) {
// A rebuild was required, so perform it now.
this->RebuildSeparateHeapAddressSpace();
}
return true;
}
void HeapTracker::RebuildSeparateHeapAddressSpace() {
std::scoped_lock lk{m_rebuild_lock, m_lock};
ASSERT(!m_resident_mappings.empty());
// Dump half of the mappings.
//
// Despite being worse in theory, this has proven to be better in practice than more
// regularly dumping a smaller amount, because it significantly reduces average case
// lock contention.
const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
const size_t evict_count = m_resident_map_count - desired_count;
auto it = m_resident_mappings.begin();
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
// Unmark and unmap.
it->is_resident = false;
m_buffer.Unmap(it->vaddr, it->size, false);
// Advance.
ASSERT(--m_resident_map_count >= 0);
it = m_resident_mappings.erase(it);
}
}
void HeapTracker::SplitHeapMap(VAddr offset, size_t size) {
std::scoped_lock lk{m_lock};
this->SplitHeapMapLocked(offset);
this->SplitHeapMapLocked(offset + size);
}
void HeapTracker::SplitHeapMapLocked(VAddr offset) {
const auto it = this->GetNearestHeapMapLocked(offset);
if (it == m_mappings.end() || it->vaddr == offset) {
// Not contained or no split required.
return;
}
// Cache the original values.
auto* const left = std::addressof(*it);
const size_t orig_size = left->size;
// Adjust the left map.
const size_t left_size = offset - left->vaddr;
left->size = left_size;
// Create the new right map.
auto* const right = new SeparateHeapMap{
.vaddr = left->vaddr + left_size,
.paddr = left->paddr + left_size,
.size = orig_size - left_size,
.tick = left->tick,
.perm = left->perm,
.is_resident = left->is_resident,
};
// Insert the new right map.
m_map_count++;
m_mappings.insert(*right);
// If resident, also insert into resident map.
if (right->is_resident) {
m_resident_map_count++;
m_resident_mappings.insert(*right);
}
}
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
const SeparateHeapMap key{
.vaddr = offset,
};
return m_mappings.find(key);
}
} // namespace Common

98
src/common/heap_tracker.h Normal file
View File

@@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <mutex>
#include <set>
#include <shared_mutex>
#include "common/host_memory.h"
#include "common/intrusive_red_black_tree.h"
namespace Common {
struct SeparateHeapMap {
Common::IntrusiveRedBlackTreeNode addr_node{};
Common::IntrusiveRedBlackTreeNode tick_node{};
VAddr vaddr{};
PAddr paddr{};
size_t size{};
size_t tick{};
MemoryPermission perm{};
bool is_resident{};
};
struct SeparateHeapMapAddrComparator {
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
if (lhs.vaddr < rhs.vaddr) {
return -1;
} else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) {
return 0;
} else {
return 1;
}
}
};
struct SeparateHeapMapTickComparator {
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
if (lhs.tick < rhs.tick) {
return -1;
} else if (lhs.tick > rhs.tick) {
return 1;
} else {
return SeparateHeapMapAddrComparator::Compare(lhs, rhs);
}
}
};
class HeapTracker {
public:
explicit HeapTracker(Common::HostMemory& buffer);
~HeapTracker();
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm,
bool is_separate_heap);
void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap);
void Protect(size_t virtual_offset, size_t length, MemoryPermission perm);
u8* VirtualBasePointer() {
return m_buffer.VirtualBasePointer();
}
bool DeferredMapSeparateHeap(u8* fault_address);
bool DeferredMapSeparateHeap(size_t virtual_offset);
private:
using AddrTreeTraits =
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>;
using AddrTree = AddrTreeTraits::TreeType<SeparateHeapMapAddrComparator>;
using TickTreeTraits =
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>;
using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>;
AddrTree m_mappings{};
TickTree m_resident_mappings{};
private:
void SplitHeapMap(VAddr offset, size_t size);
void SplitHeapMapLocked(VAddr offset);
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
void RebuildSeparateHeapAddressSpace();
private:
Common::HostMemory& m_buffer;
const s64 m_max_resident_map_count;
std::shared_mutex m_rebuild_lock{};
std::mutex m_lock{};
s64 m_map_count{};
s64 m_resident_map_count{};
size_t m_tick{};
};
} // namespace Common

View File

@@ -679,7 +679,7 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
MemoryPermission perms) { MemoryPermission perms, bool separate_heap) {
ASSERT(virtual_offset % PageAlignment == 0); ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(host_offset % PageAlignment == 0); ASSERT(host_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
@@ -691,7 +691,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms); impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
} }
void HostMemory::Unmap(size_t virtual_offset, size_t length) { void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap) {
ASSERT(virtual_offset % PageAlignment == 0); ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size); ASSERT(virtual_offset + length <= virtual_size);
@@ -701,14 +701,16 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) {
impl->Unmap(virtual_offset + virtual_base_offset, length); impl->Unmap(virtual_offset + virtual_base_offset, length);
} }
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write, void HostMemory::Protect(size_t virtual_offset, size_t length, MemoryPermission perm) {
bool execute) {
ASSERT(virtual_offset % PageAlignment == 0); ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size); ASSERT(virtual_offset + length <= virtual_size);
if (length == 0 || !virtual_base || !impl) { if (length == 0 || !virtual_base || !impl) {
return; return;
} }
const bool read = True(perm & MemoryPermission::Read);
const bool write = True(perm & MemoryPermission::Write);
const bool execute = True(perm & MemoryPermission::Execute);
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
} }

View File

@@ -40,11 +40,12 @@ public:
HostMemory(HostMemory&& other) noexcept; HostMemory(HostMemory&& other) noexcept;
HostMemory& operator=(HostMemory&& other) noexcept; HostMemory& operator=(HostMemory&& other) noexcept;
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms); void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms,
bool separate_heap);
void Unmap(size_t virtual_offset, size_t length); void Unmap(size_t virtual_offset, size_t length, bool separate_heap);
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false); void Protect(size_t virtual_offset, size_t length, MemoryPermission perms);
void EnableDirectMappedAddress(); void EnableDirectMappedAddress();
@@ -64,6 +65,10 @@ public:
return virtual_base; return virtual_base;
} }
bool IsInVirtualRange(void* address) const noexcept {
return address >= virtual_base && address < virtual_base + virtual_size;
}
private: private:
size_t backing_size{}; size_t backing_size{};
size_t virtual_size{}; size_t virtual_size{};

View File

@@ -208,6 +208,10 @@ public:
instance->StartBackendThread(); instance->StartBackendThread();
} }
static void Stop() {
instance->StopBackendThread();
}
Impl(const Impl&) = delete; Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete; Impl& operator=(const Impl&) = delete;
@@ -259,6 +263,15 @@ private:
}); });
} }
void StopBackendThread() {
backend_thread.request_stop();
if (backend_thread.joinable()) {
backend_thread.join();
}
ForEachBackend([](Backend& backend) { backend.Flush(); });
}
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string&& message) const { const char* function, std::string&& message) const {
using std::chrono::duration_cast; using std::chrono::duration_cast;
@@ -313,6 +326,10 @@ void Start() {
Impl::Start(); Impl::Start();
} }
void Stop() {
Impl::Stop();
}
void DisableLoggingInTests() { void DisableLoggingInTests() {
initialization_in_progress_suppress_logging = true; initialization_in_progress_suppress_logging = true;
} }

View File

@@ -14,6 +14,9 @@ void Initialize();
void Start(); void Start();
/// Explicitly stops the logger thread and flushes the buffers
void Stop();
void DisableLoggingInTests(); void DisableLoggingInTests();
/** /**

View File

@@ -103,7 +103,7 @@ private:
// Having them on the same cache-line would result in false-sharing between them. // Having them on the same cache-line would result in false-sharing between them.
// TODO: Remove this ifdef whenever clang and GCC support // TODO: Remove this ifdef whenever clang and GCC support
// std::hardware_destructive_interference_size. // std::hardware_destructive_interference_size.
#if defined(_MSC_VER) && _MSC_VER >= 1911 #ifdef __cpp_lib_hardware_interference_size
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
#else #else

View File

@@ -978,6 +978,7 @@ endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.cpp
arm/dynarmic/arm_dynarmic.h arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h arm/dynarmic/arm_dynarmic_64.h

View File

@@ -9,7 +9,7 @@
namespace Core { namespace Core {
void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const { void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
Kernel::Svc::ThreadContext ctx; Kernel::Svc::ThreadContext ctx;
this->GetContext(ctx); this->GetContext(ctx);

View File

@@ -95,7 +95,7 @@ public:
virtual void SignalInterrupt(Kernel::KThread* thread) = 0; virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
// Stack trace generation. // Stack trace generation.
void LogBacktrace(const Kernel::KProcess* process) const; void LogBacktrace(Kernel::KProcess* process) const;
// Debug functionality. // Debug functionality.
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;

View File

@@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
0x7100000000ULL, 0x7100000000ULL,
}; };
void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) { void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
auto modules = FindModules(process); auto modules = FindModules(process);
const bool is_64 = process->Is64Bit(); const bool is_64 = process->Is64Bit();
@@ -118,7 +118,7 @@ void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<Backtrace
} }
} }
std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out; std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory(); auto& memory = process->GetMemory();
@@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
return out; return out;
} }
std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out; std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory(); auto& memory = process->GetMemory();
@@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
} // namespace } // namespace
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) { std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
const auto* process = thread->GetOwnerProcess(); auto* process = thread->GetOwnerProcess();
if (process->Is64Bit()) { if (process->Is64Bit()) {
return GetNameFromThreadType64(process->GetMemory(), *thread); return GetNameFromThreadType64(process->GetMemory(), *thread);
} else { } else {
@@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
return cur_addr - 1; return cur_addr - 1;
} }
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
Loader::AppLoader::Modules modules; Loader::AppLoader::Modules modules;
auto& page_table = process->GetPageTable(); auto& page_table = process->GetPageTable();
@@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
return modules; return modules;
} }
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) { Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) {
// Do we have any loaded executable sections? // Do we have any loaded executable sections?
auto modules = FindModules(process); auto modules = FindModules(process);
@@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres
} }
} }
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
if (process->Is64Bit()) { if (process->Is64Bit()) {
return GetAArch64Backtrace(process, ctx); return GetAArch64Backtrace(process, ctx);

View File

@@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
std::string_view GetThreadWaitReason(const Kernel::KThread* thread); std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
std::string GetThreadState(const Kernel::KThread* thread); std::string GetThreadState(const Kernel::KThread* thread);
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process); Loader::AppLoader::Modules FindModules(Kernel::KProcess* process);
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base); Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process); Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process);
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size); void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
@@ -28,7 +28,7 @@ struct BacktraceEntry {
std::string name; std::string name;
}; };
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx); const Kernel::Svc::ThreadContext& ctx);
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread); std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);

View File

@@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef __linux__
#include "common/signal_chain.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/hle/kernel/k_process.h"
#include "core/memory.h"
namespace Core {
namespace {
thread_local Core::Memory::Memory* g_current_memory{};
std::once_flag g_registered{};
struct sigaction g_old_segv {};
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
return;
}
return g_old_segv.sa_sigaction(sig, info, ctx);
}
} // namespace
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
g_current_memory = std::addressof(process->GetMemory());
}
ScopedJitExecution::~ScopedJitExecution() {
g_current_memory = nullptr;
}
void ScopedJitExecution::RegisterHandler() {
std::call_once(g_registered, [] {
struct sigaction sa {};
sa.sa_sigaction = &HandleSigSegv;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
});
}
} // namespace Core
#endif

View File

@@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
return static_cast<HaltReason>(hr); return static_cast<HaltReason>(hr);
} }
#ifdef __linux__
class ScopedJitExecution {
public:
explicit ScopedJitExecution(Kernel::KProcess* process);
~ScopedJitExecution();
static void RegisterHandler();
};
#else
class ScopedJitExecution {
public:
explicit ScopedJitExecution(Kernel::KProcess* process) {}
~ScopedJitExecution() {}
static void RegisterHandler() {}
};
#endif
} // namespace Core } // namespace Core

View File

@@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public: public:
explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process) explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()), : m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled || m_check_memory_access{m_debugger_enabled ||
@@ -169,7 +169,7 @@ public:
ArmDynarmic32& m_parent; ArmDynarmic32& m_parent;
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
const Kernel::KProcess* m_process{}; Kernel::KProcess* m_process{};
const bool m_debugger_enabled{}; const bool m_debugger_enabled{};
const bool m_check_memory_access{}; const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U; static constexpr u64 MinimumRunCycles = 10000U;
@@ -331,11 +331,15 @@ bool ArmDynarmic32::IsInThumbMode() const {
} }
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) { HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState(); m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Run()); return TranslateHaltReason(m_jit->Run());
} }
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) { HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState(); m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Step()); return TranslateHaltReason(m_jit->Step());
} }
@@ -370,13 +374,14 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context); this->SetContext(m_breakpoint_context);
} }
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)), m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} { m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl(); auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
m_jit = MakeJit(&page_table_impl); m_jit = MakeJit(&page_table_impl);
ScopedJitExecution::RegisterHandler();
} }
ArmDynarmic32::~ArmDynarmic32() = default; ArmDynarmic32::~ArmDynarmic32() = default;

View File

@@ -20,7 +20,7 @@ class System;
class ArmDynarmic32 final : public ArmInterface { class ArmDynarmic32 final : public ArmInterface {
public: public:
ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic32() override; ~ArmDynarmic32() override;

View File

@@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public: public:
explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process) explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()), : m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled || m_check_memory_access{m_debugger_enabled ||
@@ -216,7 +216,7 @@ public:
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
u64 m_tpidrro_el0{}; u64 m_tpidrro_el0{};
u64 m_tpidr_el0{}; u64 m_tpidr_el0{};
const Kernel::KProcess* m_process{}; Kernel::KProcess* m_process{};
const bool m_debugger_enabled{}; const bool m_debugger_enabled{};
const bool m_check_memory_access{}; const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U; static constexpr u64 MinimumRunCycles = 10000U;
@@ -362,11 +362,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
} }
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) { HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState(); m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Run()); return TranslateHaltReason(m_jit->Run());
} }
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) { HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
ScopedJitExecution sj(thread->GetOwnerProcess());
m_jit->ClearExclusiveState(); m_jit->ClearExclusiveState();
return TranslateHaltReason(m_jit->Step()); return TranslateHaltReason(m_jit->Step());
} }
@@ -399,13 +403,14 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context); this->SetContext(m_breakpoint_context);
} }
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} { m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
auto& page_table = process->GetPageTable().GetBasePageTable(); auto& page_table = process->GetPageTable().GetBasePageTable();
auto& page_table_impl = page_table.GetImpl(); auto& page_table_impl = page_table.GetImpl();
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth()); m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
ScopedJitExecution::RegisterHandler();
} }
ArmDynarmic64::~ArmDynarmic64() = default; ArmDynarmic64::~ArmDynarmic64() = default;

View File

@@ -25,7 +25,7 @@ class System;
class ArmDynarmic64 final : public ArmInterface { class ArmDynarmic64 final : public ArmInterface {
public: public:
ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic64() override; ~ArmDynarmic64() override;

View File

@@ -28,7 +28,6 @@
#include "core/file_sys/savedata_factory.h" #include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
@@ -130,11 +129,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl { struct System::Impl {
explicit Impl(System& system) explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{}, reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
time_manager{system}, gpu_dirty_memory_write_manager{} {
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
}
void Initialize(System& system) { void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>(); device_memory = std::make_unique<Core::DeviceMemory>();
@@ -241,17 +237,17 @@ struct System::Impl {
debugger = std::make_unique<Debugger>(system, port); debugger = std::make_unique<Debugger>(system, port);
} }
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { void InitializeKernel(System& system) {
LOG_DEBUG(Core, "initialized OK"); LOG_DEBUG(Core, "initialized OK");
// Setting changes may require a full system reinitialization (e.g., disabling multicore). // Setting changes may require a full system reinitialization (e.g., disabling multicore).
ReinitializeIfNecessary(system); ReinitializeIfNecessary(system);
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
kernel.Initialize(); kernel.Initialize();
cpu_manager.Initialize(); cpu_manager.Initialize();
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
/// Reset all glue registrations /// Reset all glue registrations
arp_manager.ResetAll(); arp_manager.ResetAll();
@@ -300,17 +296,9 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader; return SystemResultStatus::ErrorGetLoader;
} }
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; InitializeKernel(system);
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); // Create the application process.
// Create the process.
auto main_process = Kernel::KProcess::Create(system.Kernel()); auto main_process = Kernel::KProcess::Create(system.Kernel());
Kernel::KProcess::Register(system.Kernel(), main_process); Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.AppendNewProcess(main_process); kernel.AppendNewProcess(main_process);
@@ -323,7 +311,18 @@ struct System::Impl {
return static_cast<SystemResultStatus>( return static_cast<SystemResultStatus>(
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
} }
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
AddGlueRegistrationForProcess(*app_loader, *main_process); AddGlueRegistrationForProcess(*app_loader, *main_process);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Initialize cheat engine // Initialize cheat engine
if (cheat_engine) { if (cheat_engine) {
@@ -426,7 +425,6 @@ struct System::Impl {
cpu_manager.Shutdown(); cpu_manager.Shutdown();
debugger.reset(); debugger.reset();
kernel.Shutdown(); kernel.Shutdown();
memory.Reset();
Network::RestartSocketOperations(); Network::RestartSocketOperations();
if (auto room_member = room_network.GetRoomMember().lock()) { if (auto room_member = room_network.GetRoomMember().lock()) {
@@ -507,7 +505,6 @@ struct System::Impl {
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core; std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
std::unique_ptr<Core::DeviceMemory> device_memory; std::unique_ptr<Core::DeviceMemory> device_memory;
std::unique_ptr<AudioCore::AudioCore> audio_core; std::unique_ptr<AudioCore::AudioCore> audio_core;
Core::Memory::Memory memory;
Core::HID::HIDCore hid_core; Core::HID::HIDCore hid_core;
Network::RoomNetwork room_network; Network::RoomNetwork room_network;
@@ -567,9 +564,6 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_write_manager{};
std::deque<std::vector<u8>> user_channel; std::deque<std::vector<u8>> user_channel;
}; };
@@ -652,29 +646,12 @@ void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index); impl->kernel.PrepareReschedule(core_index);
} }
Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
/// Provides a constant reference to the current gou dirty memory manager.
const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
size_t System::GetCurrentHostThreadID() const { size_t System::GetCurrentHostThreadID() const {
return impl->kernel.GetCurrentHostThreadID(); return impl->kernel.GetCurrentHostThreadID();
} }
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
for (auto& manager : impl->gpu_dirty_memory_write_manager) { return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
manager.Gather(callback);
}
} }
PerfStatsResults System::GetAndResetPerfStats() { PerfStatsResults System::GetAndResetPerfStats() {
@@ -723,20 +700,12 @@ const Kernel::KProcess* System::ApplicationProcess() const {
return impl->kernel.ApplicationProcess(); return impl->kernel.ApplicationProcess();
} }
ExclusiveMonitor& System::Monitor() {
return impl->kernel.GetExclusiveMonitor();
}
const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
}
Memory::Memory& System::ApplicationMemory() { Memory::Memory& System::ApplicationMemory() {
return impl->memory; return impl->kernel.ApplicationProcess()->GetMemory();
} }
const Core::Memory::Memory& System::ApplicationMemory() const { const Core::Memory::Memory& System::ApplicationMemory() const {
return impl->memory; return impl->kernel.ApplicationProcess()->GetMemory();
} }
Tegra::GPU& System::GPU() { Tegra::GPU& System::GPU() {

View File

@@ -116,7 +116,6 @@ class CpuManager;
class Debugger; class Debugger;
class DeviceMemory; class DeviceMemory;
class ExclusiveMonitor; class ExclusiveMonitor;
class GPUDirtyMemoryManager;
class PerfStats; class PerfStats;
class Reporter; class Reporter;
class SpeedLimiter; class SpeedLimiter;
@@ -225,12 +224,6 @@ public:
/// Prepare the core emulation for a reschedule /// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index); void PrepareReschedule(u32 core_index);
/// Provides a reference to the gou dirty memory manager.
[[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
/// Provides a constant reference to the current gou dirty memory manager.
[[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
[[nodiscard]] size_t GetCurrentHostThreadID() const; [[nodiscard]] size_t GetCurrentHostThreadID() const;
@@ -250,12 +243,6 @@ public:
/// Gets a const reference to the underlying CPU manager /// Gets a const reference to the underlying CPU manager
[[nodiscard]] const CpuManager& GetCpuManager() const; [[nodiscard]] const CpuManager& GetCpuManager() const;
/// Gets a reference to the exclusive monitor
[[nodiscard]] ExclusiveMonitor& Monitor();
/// Gets a constant reference to the exclusive monitor
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance. /// Gets a mutable reference to the system memory instance.
[[nodiscard]] Core::Memory::Memory& ApplicationMemory(); [[nodiscard]] Core::Memory::Memory& ApplicationMemory();

View File

@@ -166,6 +166,10 @@ u32 ProgramMetadata::GetSystemResourceSize() const {
return npdm_header.system_resource_size; return npdm_header.system_resource_size;
} }
PoolPartition ProgramMetadata::GetPoolPartition() const {
return acid_header.pool_partition;
}
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
return aci_kernel_capabilities; return aci_kernel_capabilities;
} }
@@ -201,7 +205,7 @@ void ProgramMetadata::Print() const {
// Begin ACID printing (potential perms, signed) // Begin ACID printing (potential perms, signed)
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO"); LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);

View File

@@ -34,6 +34,13 @@ enum class ProgramFilePermission : u64 {
Everything = 1ULL << 63, Everything = 1ULL << 63,
}; };
enum class PoolPartition : u32 {
Application = 0,
Applet = 1,
System = 2,
SystemNonSecure = 3,
};
/** /**
* Helper which implements an interface to parse Program Description Metadata (NPDM) * Helper which implements an interface to parse Program Description Metadata (NPDM)
* Data can either be loaded from a file path or with data and an offset into it. * Data can either be loaded from a file path or with data and an offset into it.
@@ -72,6 +79,7 @@ public:
u64 GetTitleID() const; u64 GetTitleID() const;
u64 GetFilesystemPermissions() const; u64 GetFilesystemPermissions() const;
u32 GetSystemResourceSize() const; u32 GetSystemResourceSize() const;
PoolPartition GetPoolPartition() const;
const KernelCapabilityDescriptors& GetKernelCapabilities() const; const KernelCapabilityDescriptors& GetKernelCapabilities() const;
const std::array<u8, 0x10>& GetName() const { const std::array<u8, 0x10>& GetName() const {
return npdm_header.application_name; return npdm_header.application_name;
@@ -116,8 +124,9 @@ private:
union { union {
u32 flags; u32 flags;
BitField<0, 1, u32> is_retail; BitField<0, 1, u32> production_flag;
BitField<1, 31, u32> flags_unk; BitField<1, 1, u32> unqualified_approval;
BitField<2, 4, PoolPartition> pool_partition;
}; };
u64_le title_id_min; u64_le title_id_min;
u64_le title_id_max; u64_le title_id_max;

View File

@@ -4,6 +4,7 @@
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
@@ -26,9 +27,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
return true; return true;
} }
bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) { bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) {
auto& monitor = system.Monitor(); auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = kernel.CurrentPhysicalCoreIndex();
// NOTE: If scheduler lock is not held here, interrupt disable is required. // NOTE: If scheduler lock is not held here, interrupt disable is required.
// KScopedInterruptDisable di; // KScopedInterruptDisable di;
@@ -66,10 +67,10 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
return true; return true;
} }
bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value, bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value,
s32 new_value) { s32 new_value) {
auto& monitor = system.Monitor(); auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = kernel.CurrentPhysicalCoreIndex();
// NOTE: If scheduler lock is not held here, interrupt disable is required. // NOTE: If scheduler lock is not held here, interrupt disable is required.
// KScopedInterruptDisable di; // KScopedInterruptDisable di;
@@ -159,7 +160,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
// Check the userspace value. // Check the userspace value.
s32 user_value{}; s32 user_value{};
R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1), R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1),
ResultInvalidCurrentMemory); ResultInvalidCurrentMemory);
R_UNLESS(user_value == value, ResultInvalidState); R_UNLESS(user_value == value, ResultInvalidState);
@@ -219,7 +220,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
s32 user_value{}; s32 user_value{};
bool succeeded{}; bool succeeded{};
if (value != new_value) { if (value != new_value) {
succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value); succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value);
} else { } else {
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
} }
@@ -262,7 +263,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
s32 user_value{}; s32 user_value{};
bool succeeded{}; bool succeeded{};
if (decrement) { if (decrement) {
succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value); succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value);
} else { } else {
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
} }

View File

@@ -8,19 +8,22 @@
namespace Kernel { namespace Kernel {
void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) { void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
KScopedLightLock lk(m_lock); // KScopedInterruptDisable di;
KScopedSpinLock lk(m_lock);
m_object_list.insert_unique(*obj); m_object_list.insert_unique(*obj);
} }
void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) { void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
KScopedLightLock lk(m_lock); // KScopedInterruptDisable di;
KScopedSpinLock lk(m_lock);
m_object_list.erase(*obj); m_object_list.erase(*obj);
} }
size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) { size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
KScopedLightLock lk(m_lock); // KScopedInterruptDisable di;
KScopedSpinLock lk(m_lock);
return std::count_if(m_object_list.begin(), m_object_list.end(), return std::count_if(m_object_list.begin(), m_object_list.end(),
[&](const auto& obj) { return obj.GetOwner() == owner; }); [&](const auto& obj) { return obj.GetOwner() == owner; });

View File

@@ -7,7 +7,7 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_spin_lock.h"
namespace Kernel { namespace Kernel {
@@ -21,32 +21,7 @@ public:
using ListType = boost::intrusive::rbtree<KAutoObjectWithList>; using ListType = boost::intrusive::rbtree<KAutoObjectWithList>;
class ListAccessor : public KScopedLightLock { KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(), m_object_list() {}
public:
explicit ListAccessor(KAutoObjectWithListContainer* container)
: KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
explicit ListAccessor(KAutoObjectWithListContainer& container)
: KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
typename ListType::iterator begin() const {
return m_list.begin();
}
typename ListType::iterator end() const {
return m_list.end();
}
typename ListType::iterator find(typename ListType::const_reference ref) const {
return m_list.find(ref);
}
private:
ListType& m_list;
};
friend class ListAccessor;
KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
void Initialize() {} void Initialize() {}
void Finalize() {} void Finalize() {}
@@ -56,7 +31,7 @@ public:
size_t GetOwnedCount(KProcess* owner); size_t GetOwnedCount(KProcess* owner);
private: private:
KLightLock m_lock; KSpinLock m_lock;
ListType m_object_list; ListType m_object_list;
}; };

View File

@@ -58,9 +58,8 @@ Result KClientPort::CreateSession(KClientSession** out) {
KSession* session{}; KSession* session{};
// Reserve a new session from the resource limit. // Reserve a new session from the resource limit.
//! FIXME: we are reserving this from the wrong resource limit! KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
KScopedResourceReservation session_reservation( LimitableResource::SessionCountMax);
m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
// Allocate a session normally. // Allocate a session normally.

View File

@@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
return true; return true;
} }
bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero, bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero,
u32 new_orr_mask) { u32 new_orr_mask) {
auto& monitor = system.Monitor(); auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = kernel.CurrentPhysicalCoreIndex();
u32 expected{}; u32 expected{};
@@ -208,7 +208,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true; can_access = true;
if (can_access) [[likely]] { if (can_access) [[likely]] {
UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag, UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask); Svc::HandleWaitMask);
} }
} }

View File

@@ -90,8 +90,7 @@ public:
// Handle pseudo-handles. // Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) { if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) { if (handle == Svc::PseudoHandle::CurrentProcess) {
//! FIXME: this is the wrong process! auto* const cur_process = GetCurrentProcessPointer(m_kernel);
auto* const cur_process = m_kernel.ApplicationProcess();
ASSERT(cur_process != nullptr); ASSERT(cur_process != nullptr);
return cur_process; return cur_process;
} }

View File

@@ -434,7 +434,7 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
void KPageTableBase::Finalize() { void KPageTableBase::Finalize() {
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
if (Settings::IsFastmemEnabled()) { if (Settings::IsFastmemEnabled()) {
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size); m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
} }
}; };
@@ -5243,7 +5243,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
// Unmap. // Unmap.
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, R_ASSERT(this->Operate(updater.GetPageList(), cur_address,
cur_pages, 0, false, unmap_properties, cur_pages, 0, false, unmap_properties,
OperationType::Unmap, true)); OperationType::UnmapPhysical, true));
} }
// Check if we're done. // Check if we're done.
@@ -5326,7 +5326,7 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
// Map the papges. // Map the papges.
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages,
cur_pg, map_properties, cur_pg, map_properties,
OperationType::MapFirstGroup, false)); OperationType::MapFirstGroupPhysical, false));
} }
} }
@@ -5480,7 +5480,7 @@ Result KPageTableBase::UnmapPhysicalMemory(KProcessAddress address, size_t size)
// Unmap. // Unmap.
R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false, R_ASSERT(this->Operate(updater.GetPageList(), cur_address, cur_pages, 0, false,
unmap_properties, OperationType::Unmap, false)); unmap_properties, OperationType::UnmapPhysical, false));
} }
// Check if we're done. // Check if we're done.
@@ -5655,7 +5655,10 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
// or free them to the page list, and so it goes unused (along with page properties). // or free them to the page list, and so it goes unused (along with page properties).
switch (operation) { switch (operation) {
case OperationType::Unmap: { case OperationType::Unmap:
case OperationType::UnmapPhysical: {
const bool separate_heap = operation == OperationType::UnmapPhysical;
// Ensure that any pages we track are closed on exit. // Ensure that any pages we track are closed on exit.
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
@@ -5664,7 +5667,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
this->MakePageGroup(pages_to_close, virt_addr, num_pages); this->MakePageGroup(pages_to_close, virt_addr, num_pages);
// Unmap. // Unmap.
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize); m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
R_SUCCEED(); R_SUCCEED();
} }
@@ -5672,7 +5675,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
ASSERT(virt_addr != 0); ASSERT(virt_addr != 0);
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize)); ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr, m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
ConvertToMemoryPermission(properties.perm)); ConvertToMemoryPermission(properties.perm), false);
// Open references to pages, if we should. // Open references to pages, if we should.
if (this->IsHeapPhysicalAddress(phys_addr)) { if (this->IsHeapPhysicalAddress(phys_addr)) {
@@ -5711,16 +5714,19 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
switch (operation) { switch (operation) {
case OperationType::MapGroup: case OperationType::MapGroup:
case OperationType::MapFirstGroup: { case OperationType::MapFirstGroup:
case OperationType::MapFirstGroupPhysical: {
const bool separate_heap = operation == OperationType::MapFirstGroupPhysical;
// We want to maintain a new reference to every page in the group. // We want to maintain a new reference to every page in the group.
KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup); KScopedPageGroup spg(page_group, operation == OperationType::MapGroup);
for (const auto& node : page_group) { for (const auto& node : page_group) {
const size_t size{node.GetNumPages() * PageSize}; const size_t size{node.GetNumPages() * PageSize};
// Map the pages. // Map the pages.
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(), m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
ConvertToMemoryPermission(properties.perm)); ConvertToMemoryPermission(properties.perm), separate_heap);
virt_addr += size; virt_addr += size;
} }

View File

@@ -104,6 +104,9 @@ protected:
ChangePermissionsAndRefresh = 5, ChangePermissionsAndRefresh = 5,
ChangePermissionsAndRefreshAndFlush = 6, ChangePermissionsAndRefreshAndFlush = 6,
Separate = 7, Separate = 7,
MapFirstGroupPhysical = 65000,
UnmapPhysical = 65001,
}; };
static constexpr size_t MaxPhysicalMapAlignment = 1_GiB; static constexpr size_t MaxPhysicalMapAlignment = 1_GiB;

View File

@@ -306,12 +306,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
params.code_address, params.code_num_pages * PageSize, params.code_address, params.code_num_pages * PageSize,
m_system_resource, res_limit, this->GetMemory(), 0)); m_system_resource, res_limit, m_memory, 0));
} }
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {
m_page_table.Finalize(); m_page_table.Finalize();
}; };
// Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
KMemoryState::Code), KMemoryState::Code),
@@ -399,12 +403,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
params.code_address, code_size, m_system_resource, res_limit, params.code_address, code_size, m_system_resource, res_limit,
this->GetMemory(), aslr_space_start)); m_memory, aslr_space_start));
} }
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {
m_page_table.Finalize(); m_page_table.Finalize();
}; };
// Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
@@ -1094,8 +1102,7 @@ void KProcess::UnpinThread(KThread* thread) {
Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids,
s32 max_out_count) { s32 max_out_count) {
// TODO: use current memory reference auto& memory = this->GetMemory();
auto& memory = m_kernel.System().ApplicationMemory();
// Lock the list. // Lock the list.
KScopedLightLock lk(m_list_lock); KScopedLightLock lk(m_list_lock);
@@ -1128,14 +1135,15 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
KProcess::KProcess(KernelCore& kernel) KProcess::KProcess(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
m_handle_table{kernel} {} m_handle_table{kernel}, m_dirty_memory_managers{},
m_exclusive_monitor{}, m_memory{kernel.System()} {}
KProcess::~KProcess() = default; KProcess::~KProcess() = default;
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
KProcessAddress aslr_space_start, bool is_hbl) { KProcessAddress aslr_space_start, bool is_hbl) {
// Create a resource limit for the process. // Create a resource limit for the process.
const auto physical_memory_size = const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application); const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
auto* res_limit = auto* res_limit =
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
@@ -1146,8 +1154,10 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
Svc::CreateProcessFlag flag{}; Svc::CreateProcessFlag flag{};
u64 code_address{}; u64 code_address{};
// We are an application. // Determine if we are an application.
flag |= Svc::CreateProcessFlag::IsApplication; if (pool == KMemoryManager::Pool::Application) {
flag |= Svc::CreateProcessFlag::IsApplication;
}
// If we are 64-bit, create as such. // If we are 64-bit, create as such.
if (metadata.Is64BitProgram()) { if (metadata.Is64BitProgram()) {
@@ -1196,8 +1206,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
std::memcpy(params.name.data(), name.data(), sizeof(params.name)); std::memcpy(params.name.data(), name.data(), sizeof(params.name));
// Initialize for application process. // Initialize for application process.
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool,
KMemoryManager::Pool::Application, aslr_space_start)); aslr_space_start));
// Assign remaining properties. // Assign remaining properties.
m_is_hbl = is_hbl; m_is_hbl = is_hbl;
@@ -1223,22 +1233,25 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
#ifdef HAS_NCE #ifdef HAS_NCE
if (Settings::IsNceEnabled()) { if (this->IsApplication() && Settings::IsNceEnabled()) {
auto& buffer = m_kernel.System().DeviceMemory().buffer; auto& buffer = m_kernel.System().DeviceMemory().buffer;
const auto& code = code_set.CodeSegment(); const auto& code = code_set.CodeSegment();
const auto& patch = code_set.PatchSegment(); const auto& patch = code_set.PatchSegment();
buffer.Protect(GetInteger(base_addr + code.addr), code.size, true, true, true); buffer.Protect(GetInteger(base_addr + code.addr), code.size,
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, true, true, true); Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
buffer.Protect(GetInteger(base_addr + patch.addr), patch.size,
Common::MemoryPermission::Read | Common::MemoryPermission::Execute);
ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None); ReprotectSegment(code_set.PatchSegment(), Svc::MemoryPermission::None);
} }
#endif #endif
} }
void KProcess::InitializeInterfaces() { void KProcess::InitializeInterfaces() {
this->GetMemory().SetCurrentPageTable(*this); m_exclusive_monitor =
Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
#ifdef HAS_NCE #ifdef HAS_NCE
if (this->Is64Bit() && Settings::IsNceEnabled()) { if (this->IsApplication() && Settings::IsNceEnabled()) {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
} }
@@ -1248,13 +1261,13 @@ void KProcess::InitializeInterfaces() {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>( m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
m_kernel.System(), m_kernel.IsMulticore(), this, m_kernel.System(), m_kernel.IsMulticore(), this,
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
} }
} else { } else {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>( m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
m_kernel.System(), m_kernel.IsMulticore(), this, m_kernel.System(), m_kernel.IsMulticore(), this,
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
} }
} }
} }
@@ -1305,9 +1318,10 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
return true; return true;
} }
Core::Memory::Memory& KProcess::GetMemory() const { void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
// TODO: per-process memory for (auto& manager : m_dirty_memory_managers) {
return m_kernel.System().ApplicationMemory(); manager.Gather(callback);
}
} }
} // namespace Kernel } // namespace Kernel

View File

@@ -7,6 +7,7 @@
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/file_sys/program_metadata.h" #include "core/file_sys/program_metadata.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/code_set.h" #include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_capabilities.h" #include "core/hle/kernel/k_capabilities.h"
@@ -17,6 +18,7 @@
#include "core/hle/kernel/k_system_resource.h" #include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_local_page.h" #include "core/hle/kernel/k_thread_local_page.h"
#include "core/memory.h"
namespace Kernel { namespace Kernel {
@@ -126,6 +128,9 @@ private:
#ifdef HAS_NCE #ifdef HAS_NCE
std::unordered_map<u64, u64> m_post_handlers{}; std::unordered_map<u64, u64> m_post_handlers{};
#endif #endif
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
Core::Memory::Memory m_memory;
private: private:
Result StartTermination(); Result StartTermination();
@@ -502,7 +507,15 @@ public:
void InitializeInterfaces(); void InitializeInterfaces();
Core::Memory::Memory& GetMemory() const; Core::Memory::Memory& GetMemory() {
return m_memory;
}
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
Core::ExclusiveMonitor& GetExclusiveMonitor() const {
return *m_exclusive_monitor;
}
public: public:
// Overridden parent functions. // Overridden parent functions.

File diff suppressed because it is too large Load Diff

View File

@@ -49,14 +49,21 @@ public:
bool IsSignaled() const override; bool IsSignaled() const override;
void OnClientClosed(); void OnClientClosed();
/// TODO: flesh these out to match the real kernel
Result OnRequest(KSessionRequest* request); Result OnRequest(KSessionRequest* request);
Result SendReply(bool is_hle = false); Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size,
Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, KPhysicalAddress server_message_paddr, bool is_hle = false);
Result ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size,
KPhysicalAddress server_message_paddr,
std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
std::weak_ptr<Service::SessionRequestManager> manager = {}); std::weak_ptr<Service::SessionRequestManager> manager = {});
Result SendReplyHLE() { Result SendReplyHLE() {
return SendReply(true); R_RETURN(this->SendReply(0, 0, 0, true));
}
Result ReceiveRequestHLE(std::shared_ptr<Service::HLERequestContext>* out_context,
std::weak_ptr<Service::SessionRequestManager> manager) {
R_RETURN(this->ReceiveRequest(0, 0, 0, out_context, manager));
} }
private: private:

View File

@@ -33,8 +33,7 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
m_name = name; m_name = name;
// Set our owner process. // Set our owner process.
//! FIXME: this is the wrong process! m_process = GetCurrentProcessPointer(m_kernel);
m_process = m_kernel.ApplicationProcess();
m_process->Open(); m_process->Open();
// Set our port. // Set our port.

View File

@@ -1422,8 +1422,7 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
} }
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) { Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
// TODO: per-process memory return GetCurrentProcess(kernel).GetMemory();
return kernel.System().ApplicationMemory();
} }
KScopedDisableDispatch::~KScopedDisableDispatch() { KScopedDisableDispatch::~KScopedDisableDispatch() {

View File

@@ -314,11 +314,7 @@ public:
m_current_core_id = core; m_current_core_id = core;
} }
KProcess* GetOwnerProcess() { KProcess* GetOwnerProcess() const {
return m_parent;
}
const KProcess* GetOwnerProcess() const {
return m_parent; return m_parent;
} }

View File

@@ -5,6 +5,7 @@
#include <optional> #include <optional>
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_page_group.h" #include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/slab_helpers.h" #include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_types.h" #include "core/hle/kernel/svc_types.h"

View File

@@ -68,8 +68,6 @@ struct KernelCore::Impl {
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
global_handle_table->Initialize(KHandleTable::MaxTableSize);
is_phantom_mode_for_singlecore = false; is_phantom_mode_for_singlecore = false;
@@ -121,13 +119,8 @@ struct KernelCore::Impl {
next_user_process_id = KProcess::ProcessIdMin; next_user_process_id = KProcess::ProcessIdMin;
next_thread_id = 1; next_thread_id = 1;
global_handle_table->Finalize();
global_handle_table.reset();
preemption_event = nullptr; preemption_event = nullptr;
exclusive_monitor.reset();
// Cleanup persistent kernel objects // Cleanup persistent kernel objects
auto CleanupObject = [](KAutoObject* obj) { auto CleanupObject = [](KAutoObject* obj) {
if (obj) { if (obj) {
@@ -191,8 +184,6 @@ struct KernelCore::Impl {
} }
void InitializePhysicalCores() { void InitializePhysicalCores() {
exclusive_monitor =
Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
const s32 core{static_cast<s32>(i)}; const s32 core{static_cast<s32>(i)};
@@ -791,10 +782,6 @@ struct KernelCore::Impl {
std::shared_ptr<Core::Timing::EventType> preemption_event; std::shared_ptr<Core::Timing::EventType> preemption_event;
// This is the kernel's handle table or supervisor handle table which
// stores all the objects in place.
std::unique_ptr<KHandleTable> global_handle_table;
std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
std::unique_ptr<KObjectNameGlobalData> object_name_global_data; std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
@@ -805,7 +792,6 @@ struct KernelCore::Impl {
std::mutex server_lock; std::mutex server_lock;
std::vector<std::unique_ptr<Service::ServerManager>> server_managers; std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
@@ -882,10 +868,6 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
return impl->system_resource_limit; return impl->system_resource_limit;
} }
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
return impl->global_handle_table->GetObject<KThread>(handle);
}
void KernelCore::AppendNewProcess(KProcess* process) { void KernelCore::AppendNewProcess(KProcess* process) {
impl->process_list.push_back(process); impl->process_list.push_back(process);
} }
@@ -959,14 +941,6 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
return *impl->hardware_timer; return *impl->hardware_timer;
} }
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
return *impl->exclusive_monitor;
}
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
return *impl->exclusive_monitor;
}
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
return *impl->global_object_list_container; return *impl->global_object_list_container;
} }
@@ -1030,14 +1004,6 @@ u64 KernelCore::CreateNewUserProcessID() {
return impl->next_user_process_id++; return impl->next_user_process_id++;
} }
KHandleTable& KernelCore::GlobalHandleTable() {
return *impl->global_handle_table;
}
const KHandleTable& KernelCore::GlobalHandleTable() const {
return *impl->global_handle_table;
}
void KernelCore::RegisterCoreThread(std::size_t core_id) { void KernelCore::RegisterCoreThread(std::size_t core_id) {
impl->RegisterCoreThread(core_id); impl->RegisterCoreThread(core_id);
} }

View File

@@ -116,9 +116,6 @@ public:
/// Retrieves a shared pointer to the system resource limit instance. /// Retrieves a shared pointer to the system resource limit instance.
KResourceLimit* GetSystemResourceLimit(); KResourceLimit* GetSystemResourceLimit();
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes. /// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(KProcess* process); void AppendNewProcess(KProcess* process);
@@ -170,10 +167,6 @@ public:
/// Stops execution of 'id' core, in order to reschedule a new thread. /// Stops execution of 'id' core, in order to reschedule a new thread.
void PrepareReschedule(std::size_t id); void PrepareReschedule(std::size_t id);
Core::ExclusiveMonitor& GetExclusiveMonitor();
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
KAutoObjectWithListContainer& ObjectListContainer(); KAutoObjectWithListContainer& ObjectListContainer();
const KAutoObjectWithListContainer& ObjectListContainer() const; const KAutoObjectWithListContainer& ObjectListContainer() const;

View File

@@ -18,13 +18,13 @@ public:
static constexpr inline u64 NullTag = 0; static constexpr inline u64 NullTag = 0;
public: public:
enum class ReceiveListCountType : u32 { enum ReceiveListCountType : u32 {
None = 0, ReceiveListCountType_None = 0,
ToMessageBuffer = 1, ReceiveListCountType_ToMessageBuffer = 1,
ToSingleBuffer = 2, ReceiveListCountType_ToSingleBuffer = 2,
CountOffset = 2, ReceiveListCountType_CountOffset = 2,
CountMax = 13, ReceiveListCountType_CountMax = 13,
}; };
private: private:
@@ -591,16 +591,16 @@ public:
// Add the size of the receive list. // Add the size of the receive list.
const auto count = hdr.GetReceiveListCount(); const auto count = hdr.GetReceiveListCount();
switch (count) { switch (count) {
case MessageHeader::ReceiveListCountType::None: case MessageHeader::ReceiveListCountType_None:
break; break;
case MessageHeader::ReceiveListCountType::ToMessageBuffer: case MessageHeader::ReceiveListCountType_ToMessageBuffer:
break; break;
case MessageHeader::ReceiveListCountType::ToSingleBuffer: case MessageHeader::ReceiveListCountType_ToSingleBuffer:
msg_size += ReceiveListEntry::GetDataSize(); msg_size += ReceiveListEntry::GetDataSize();
break; break;
default: default:
msg_size += (static_cast<s32>(count) - msg_size += (static_cast<s32>(count) -
static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) * static_cast<s32>(MessageHeader::ReceiveListCountType_CountOffset)) *
ReceiveListEntry::GetDataSize(); ReceiveListEntry::GetDataSize();
break; break;
} }

View File

@@ -118,7 +118,6 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED(); R_SUCCEED();
case InfoType::IsApplication: case InfoType::IsApplication:
LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
*result = process->IsApplication(); *result = process->IsApplication();
R_SUCCEED(); R_SUCCEED();

View File

@@ -48,8 +48,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
}; };
// Send the reply. // Send the reply.
R_TRY(session->SendReply()); R_TRY(session->SendReply(message, buffer_size, message_paddr));
// R_TRY(session->SendReply(message, buffer_size, message_paddr));
} }
// Receive a message. // Receive a message.
@@ -85,8 +84,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
if (R_SUCCEEDED(result)) { if (R_SUCCEEDED(result)) {
KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
if (session != nullptr) { if (session != nullptr) {
// result = session->ReceiveRequest(message, buffer_size, message_paddr); result = session->ReceiveRequest(message, buffer_size, message_paddr);
result = session->ReceiveRequest();
if (ResultNotFound == result) { if (ResultNotFound == result) {
continue; continue;
} }

View File

@@ -38,7 +38,9 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126}; constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131}; constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132}; constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258};
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259}; constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260};
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519}; constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
} // namespace Kernel } // namespace Kernel

View File

@@ -1513,8 +1513,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
return; return;
} }
auto transfer_mem = auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) { if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1524,8 +1523,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx)
} }
std::vector<u8> memory(transfer_mem->GetSize()); std::vector<u8> memory(transfer_mem->GetSize());
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
memory.size());
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@@ -1547,8 +1545,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
return; return;
} }
auto transfer_mem = auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) { if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1558,8 +1555,7 @@ void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
} }
std::vector<u8> memory(transfer_mem->GetSize()); std::vector<u8> memory(transfer_mem->GetSize());
system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
memory.size());
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);

View File

@@ -454,10 +454,8 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
return; return;
} }
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()}; auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
auto transfer_memory{
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
const auto session_id{impl->GetSessionId()}; const auto session_id{impl->GetSessionId()};
if (session_id == -1) { if (session_id == -1) {

View File

@@ -278,9 +278,7 @@ void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
auto params = rp.PopRaw<OpusParameters>(); auto params = rp.PopRaw<OpusParameters>();
auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_size{rp.Pop<u32>()};
auto transfer_memory_handle{ctx.GetCopyHandle(0)}; auto transfer_memory_handle{ctx.GetCopyHandle(0)};
auto transfer_memory{ auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
transfer_memory_handle)};
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
params.sample_rate, params.channel_count, transfer_memory_size); params.sample_rate, params.channel_count, transfer_memory_size);
@@ -323,9 +321,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_size{rp.Pop<u32>()};
auto transfer_memory_handle{ctx.GetCopyHandle(0)}; auto transfer_memory_handle{ctx.GetCopyHandle(0)};
auto transfer_memory{ auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
transfer_memory_handle)};
LOG_DEBUG(Service_Audio, LOG_DEBUG(Service_Audio,
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
@@ -374,9 +370,7 @@ void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
auto params = rp.PopRaw<OpusParametersEx>(); auto params = rp.PopRaw<OpusParametersEx>();
auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_size{rp.Pop<u32>()};
auto transfer_memory_handle{ctx.GetCopyHandle(0)}; auto transfer_memory_handle{ctx.GetCopyHandle(0)};
auto transfer_memory{ auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
transfer_memory_handle)};
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
params.sample_rate, params.channel_count, transfer_memory_size); params.sample_rate, params.channel_count, transfer_memory_size);
@@ -414,9 +408,7 @@ void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
auto transfer_memory_size{rp.Pop<u32>()}; auto transfer_memory_size{rp.Pop<u32>()};
auto transfer_memory_handle{ctx.GetCopyHandle(0)}; auto transfer_memory_handle{ctx.GetCopyHandle(0)};
auto transfer_memory{ auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
transfer_memory_handle)};
LOG_DEBUG(Service_Audio, LOG_DEBUG(Service_Audio,
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "

View File

@@ -89,7 +89,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F
crash_report += fmt::format(" ESR: {:016x}\n", info.esr); crash_report += fmt::format(" ESR: {:016x}\n", info.esr);
crash_report += fmt::format(" FAR: {:016x}\n", info.far); crash_report += fmt::format(" FAR: {:016x}\n", info.far);
crash_report += "\nBacktrace:\n"; crash_report += "\nBacktrace:\n";
for (size_t i = 0; i < info.backtrace_size; i++) { for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); i++) {
crash_report += crash_report +=
fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]); fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
} }

View File

@@ -1850,8 +1850,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( auto t_mem_1 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_1_handle);
t_mem_1_handle);
if (t_mem_1.IsNull()) { if (t_mem_1.IsNull()) {
LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
@@ -1860,8 +1859,7 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
return; return;
} }
auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( auto t_mem_2 = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_2_handle);
t_mem_2_handle);
if (t_mem_2.IsNull()) { if (t_mem_2.IsNull()) {
LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
@@ -2142,8 +2140,7 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes"); ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
t_mem_handle);
if (t_mem.IsNull()) { if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);

View File

@@ -448,8 +448,7 @@ void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes"); ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
t_mem_handle);
if (t_mem.IsNull()) { if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);

View File

@@ -197,8 +197,7 @@ void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)}; const auto t_mem_handle{ctx.GetCopyHandle(0)};
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
t_mem_handle);
if (t_mem.IsNull()) { if (t_mem.IsNull()) {
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle); LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
@@ -444,8 +443,7 @@ void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)}; const auto t_mem_handle{ctx.GetCopyHandle(0)};
auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
t_mem_handle);
LOG_INFO(Service_IRS, LOG_INFO(Service_IRS,
"called, npad_type={}, npad_id={}, transfer_memory_size={}, " "called, npad_type={}, npad_id={}, transfer_memory_size={}, "

View File

@@ -146,10 +146,7 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
HLERequestContext::~HLERequestContext() = default; HLERequestContext::~HLERequestContext() = default;
void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
bool incoming) {
client_handle_table = &process.GetHandleTable();
IPC::RequestParser rp(src_cmdbuf); IPC::RequestParser rp(src_cmdbuf);
command_header = rp.PopRaw<IPC::CommandHeader>(); command_header = rp.PopRaw<IPC::CommandHeader>();
@@ -162,7 +159,7 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
if (command_header->enable_handle_descriptor) { if (command_header->enable_handle_descriptor) {
handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
if (handle_descriptor_header->send_current_pid) { if (handle_descriptor_header->send_current_pid) {
pid = process.GetProcessId(); pid = thread->GetOwnerProcess()->GetProcessId();
rp.Skip(2, false); rp.Skip(2, false);
} }
if (incoming) { if (incoming) {
@@ -270,9 +267,10 @@ void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* sr
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
} }
Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, Result HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf) {
u32_le* src_cmdbuf) { client_handle_table = &thread->GetOwnerProcess()->GetHandleTable();
ParseCommandBuffer(process, src_cmdbuf, true);
ParseCommandBuffer(src_cmdbuf, true);
if (command_header->IsCloseCommand()) { if (command_header->IsCloseCommand()) {
// Close does not populate the rest of the IPC header // Close does not populate the rest of the IPC header
@@ -284,9 +282,9 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& pr
return ResultSuccess; return ResultSuccess;
} }
Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) { Result HLERequestContext::WriteToOutgoingCommandBuffer() {
auto current_offset = handles_offset; auto current_offset = handles_offset;
auto& owner_process = *requesting_thread.GetOwnerProcess(); auto& owner_process = *thread->GetOwnerProcess();
auto& handle_table = owner_process.GetHandleTable(); auto& handle_table = owner_process.GetHandleTable();
for (auto& object : outgoing_copy_objects) { for (auto& object : outgoing_copy_objects) {
@@ -319,7 +317,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti
} }
// Copy the translated command buffer back into the thread's command buffer area. // Copy the translated command buffer back into the thread's command buffer area.
memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32)); memory.WriteBlock(thread->GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
return ResultSuccess; return ResultSuccess;
} }

View File

@@ -17,6 +17,7 @@
#include "common/concepts.h" #include "common/concepts.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/hle/ipc.h" #include "core/hle/ipc.h"
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_common.h"
union Result; union Result;
@@ -196,10 +197,10 @@ public:
} }
/// Populates this context with data from the requesting process/thread. /// Populates this context with data from the requesting process/thread.
Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf); Result PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf);
/// Writes data from this context back to the requesting process/thread. /// Writes data from this context back to the requesting process/thread.
Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread); Result WriteToOutgoingCommandBuffer();
[[nodiscard]] u32_le GetHipcCommand() const { [[nodiscard]] u32_le GetHipcCommand() const {
return command; return command;
@@ -359,8 +360,17 @@ public:
return *thread; return *thread;
} }
Kernel::KHandleTable& GetClientHandleTable() { [[nodiscard]] Core::Memory::Memory& GetMemory() const {
return *client_handle_table; return memory;
}
template <typename T>
Kernel::KScopedAutoObject<T> GetObjectFromHandle(u32 handle) {
auto obj = client_handle_table->GetObjectForIpc(handle, thread);
if (obj.IsNotNull()) {
return obj->DynamicCast<T*>();
}
return nullptr;
} }
[[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
@@ -378,7 +388,7 @@ public:
private: private:
friend class IPC::ResponseBuilder; friend class IPC::ResponseBuilder;
void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming); void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
Kernel::KServerSession* server_session{}; Kernel::KServerSession* server_session{};

View File

@@ -151,8 +151,8 @@ public:
if (manager->IsDomain()) { if (manager->IsDomain()) {
context->AddDomainObject(std::move(iface)); context->AddDomainObject(std::move(iface));
} else { } else {
kernel.ApplicationProcess()->GetResourceLimit()->Reserve( ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve(
Kernel::LimitableResource::SessionCountMax, 1); Kernel::LimitableResource::SessionCountMax, 1));
auto* session = Kernel::KSession::Create(kernel); auto* session = Kernel::KSession::Create(kernel);
session->Initialize(nullptr, 0); session->Initialize(nullptr, 0);

View File

@@ -26,7 +26,7 @@ public:
explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx,
CodeRange user_ro) CodeRange user_ro)
: ServiceFramework{system_, "IJitEnvironment"}, process{&process_}, : ServiceFramework{system_, "IJitEnvironment"}, process{&process_},
context{system_.ApplicationMemory()} { context{process->GetMemory()} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &IJitEnvironment::GenerateCode, "GenerateCode"}, {0, &IJitEnvironment::GenerateCode, "GenerateCode"},
@@ -188,7 +188,7 @@ public:
return; return;
} }
auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)}; auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)};
if (tmem.IsNull()) { if (tmem.IsNull()) {
LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle");
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@@ -356,11 +356,7 @@ public:
return; return;
} }
// Fetch using the handle table for the application process here, auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)};
// since we are not multiprocess yet.
const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
if (process.IsNull()) { if (process.IsNull()) {
LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@@ -368,7 +364,7 @@ public:
return; return;
} }
auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)}; auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)};
if (rx_mem.IsNull()) { if (rx_mem.IsNull()) {
LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@@ -376,7 +372,7 @@ public:
return; return;
} }
auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)}; auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)};
if (ro_mem.IsNull()) { if (ro_mem.IsNull()) {
LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};

View File

@@ -651,10 +651,9 @@ private:
void RegisterProcessHandle(HLERequestContext& ctx) { void RegisterProcessHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "(called)"); LOG_DEBUG(Service_LDR, "(called)");
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
auto client_pid = ctx.GetPID(); auto client_pid = ctx.GetPID();
auto result = interface.RegisterProcessHandle(client_pid, auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe());
process_h->DynamicCast<Kernel::KProcess*>());
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);
@@ -671,12 +670,11 @@ private:
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
auto params = rp.PopRaw<InputParameters>(); auto params = rp.PopRaw<InputParameters>();
auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
auto client_pid = ctx.GetPID(); auto client_pid = ctx.GetPID();
auto result = auto result = interface.RegisterProcessModuleInfo(
interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size, client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe());
process_h->DynamicCast<Kernel::KProcess*>());
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);

View File

@@ -47,7 +47,7 @@ ServerManager::~ServerManager() {
m_stopped.Wait(); m_stopped.Wait();
m_threads.clear(); m_threads.clear();
// Clean up ports. // Clean up server ports.
for (const auto& [port, handler] : m_ports) { for (const auto& [port, handler] : m_ports) {
port->Close(); port->Close();
} }
@@ -97,22 +97,15 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
u32 max_sessions) { u32 max_sessions) {
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
// Add the new server to sm:. // Add the new server to sm: and get the moved server port.
ASSERT(R_SUCCEEDED( Kernel::KServerPort* server_port{};
m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory))); R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name,
max_sessions, handler_factory));
// Get the registered port.
Kernel::KPort* port{};
ASSERT(
R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name)));
// Open a new reference to the server port.
port->GetServerPort().Open();
// Begin tracking the server port. // Begin tracking the server port.
{ {
std::scoped_lock ll{m_list_mutex}; std::scoped_lock ll{m_list_mutex};
m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); m_ports.emplace(server_port, std::move(handler_factory));
} }
// Signal the wakeup event. // Signal the wakeup event.
@@ -372,7 +365,7 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
// Try to receive a message. // Try to receive a message.
std::shared_ptr<HLERequestContext> context; std::shared_ptr<HLERequestContext> context;
rc = session->ReceiveRequest(&context, manager); rc = session->ReceiveRequestHLE(&context, manager);
// If the session has been closed, we're done. // If the session has been closed, we're done.
if (rc == Kernel::ResultSessionClosed) { if (rc == Kernel::ResultSessionClosed) {

View File

@@ -203,7 +203,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
// If emulation was shutdown, we are closing service threads, do not write the response back to // If emulation was shutdown, we are closing service threads, do not write the response back to
// memory that may be shutting down as well. // memory that may be shutting down as well.
if (system.IsPoweredOn()) { if (system.IsPoweredOn()) {
ctx.WriteToOutgoingCommandBuffer(ctx.GetThread()); ctx.WriteToOutgoingCommandBuffer();
} }
return result; return result;

View File

@@ -507,6 +507,14 @@ void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void SET_SYS::GetDebugModeFlag(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
}
void SET_SYS::GetQuestFlag(HLERequestContext& ctx) { void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called"); LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -926,7 +934,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
{59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"},
{60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"},
{61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"},
{62, nullptr, "GetDebugModeFlag"}, {62, &SET_SYS::GetDebugModeFlag, "GetDebugModeFlag"},
{63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
{64, nullptr, "SetPrimaryAlbumStorage"}, {64, nullptr, "SetPrimaryAlbumStorage"},
{65, nullptr, "GetUsb30EnableFlag"}, {65, nullptr, "GetUsb30EnableFlag"},
@@ -1143,6 +1151,8 @@ void SET_SYS::StoreSettings() {
} }
void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) { void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) {
Common::SetCurrentThreadName("SettingsStore");
while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) {
std::scoped_lock l{m_save_needed_mutex}; std::scoped_lock l{m_save_needed_mutex};
if (!std::exchange(m_save_needed, false)) { if (!std::exchange(m_save_needed, false)) {

View File

@@ -98,6 +98,7 @@ private:
void GetSettingsItemValue(HLERequestContext& ctx); void GetSettingsItemValue(HLERequestContext& ctx);
void GetTvSettings(HLERequestContext& ctx); void GetTvSettings(HLERequestContext& ctx);
void SetTvSettings(HLERequestContext& ctx); void SetTvSettings(HLERequestContext& ctx);
void GetDebugModeFlag(HLERequestContext& ctx);
void GetQuestFlag(HLERequestContext& ctx); void GetQuestFlag(HLERequestContext& ctx);
void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); void GetDeviceTimeZoneLocationName(HLERequestContext& ctx);
void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); void SetDeviceTimeZoneLocationName(HLERequestContext& ctx);

View File

@@ -29,8 +29,7 @@ ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {
ServiceManager::~ServiceManager() { ServiceManager::~ServiceManager() {
for (auto& [name, port] : service_ports) { for (auto& [name, port] : service_ports) {
port->GetClientPort().Close(); port->Close();
port->GetServerPort().Close();
} }
if (deferral_event) { if (deferral_event) {
@@ -50,8 +49,8 @@ static Result ValidateServiceName(const std::string& name) {
return ResultSuccess; return ResultSuccess;
} }
Result ServiceManager::RegisterService(std::string name, u32 max_sessions, Result ServiceManager::RegisterService(Kernel::KServerPort** out_server_port, std::string name,
SessionRequestHandlerFactory handler) { u32 max_sessions, SessionRequestHandlerFactory handler) {
R_TRY(ValidateServiceName(name)); R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock}; std::scoped_lock lk{lock};
@@ -66,13 +65,17 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
// Register the port. // Register the port.
Kernel::KPort::Register(kernel, port); Kernel::KPort::Register(kernel, port);
service_ports.emplace(name, port); service_ports.emplace(name, std::addressof(port->GetClientPort()));
registered_services.emplace(name, handler); registered_services.emplace(name, handler);
if (deferral_event) { if (deferral_event) {
deferral_event->Signal(); deferral_event->Signal();
} }
return ResultSuccess; // Set our output.
*out_server_port = std::addressof(port->GetServerPort());
// We succeeded.
R_SUCCEED();
} }
Result ServiceManager::UnregisterService(const std::string& name) { Result ServiceManager::UnregisterService(const std::string& name) {
@@ -91,7 +94,8 @@ Result ServiceManager::UnregisterService(const std::string& name) {
return ResultSuccess; return ResultSuccess;
} }
Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) { Result ServiceManager::GetServicePort(Kernel::KClientPort** out_client_port,
const std::string& name) {
R_TRY(ValidateServiceName(name)); R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock}; std::scoped_lock lk{lock};
@@ -101,7 +105,7 @@ Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::strin
return Service::SM::ResultNotRegistered; return Service::SM::ResultNotRegistered;
} }
*out_port = it->second; *out_client_port = it->second;
return ResultSuccess; return ResultSuccess;
} }
@@ -172,8 +176,8 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
std::string name(PopServiceName(rp)); std::string name(PopServiceName(rp));
// Find the named port. // Find the named port.
Kernel::KPort* port{}; Kernel::KClientPort* client_port{};
auto port_result = service_manager.GetServicePort(&port, name); auto port_result = service_manager.GetServicePort(&client_port, name);
if (port_result == Service::SM::ResultInvalidServiceName) { if (port_result == Service::SM::ResultInvalidServiceName) {
LOG_ERROR(Service_SM, "Invalid service name '{}'", name); LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
return Service::SM::ResultInvalidServiceName; return Service::SM::ResultInvalidServiceName;
@@ -187,7 +191,7 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
// Create a new session. // Create a new session.
Kernel::KClientSession* session{}; Kernel::KClientSession* session{};
if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) { if (const auto result = client_port->CreateSession(&session); result.IsError()) {
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
return result; return result;
} }
@@ -221,7 +225,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
max_session_count, is_light); max_session_count, is_light);
if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr); Kernel::KServerPort* server_port{};
if (const auto result = service_manager.RegisterService(std::addressof(server_port), name,
max_session_count, nullptr);
result.IsError()) { result.IsError()) {
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw); LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@@ -229,13 +235,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
return; return;
} }
auto* port = Kernel::KPort::Create(kernel);
port->Initialize(ServerSessionCountMax, is_light, 0);
SCOPE_EXIT({ port->GetClientPort().Close(); });
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushMoveObjects(port->GetServerPort()); rb.PushMoveObjects(server_port);
} }
void SM::UnregisterService(HLERequestContext& ctx) { void SM::UnregisterService(HLERequestContext& ctx) {

View File

@@ -56,10 +56,10 @@ public:
explicit ServiceManager(Kernel::KernelCore& kernel_); explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager(); ~ServiceManager();
Result RegisterService(std::string name, u32 max_sessions, Result RegisterService(Kernel::KServerPort** out_server_port, std::string name,
SessionRequestHandlerFactory handler_factory); u32 max_sessions, SessionRequestHandlerFactory handler_factory);
Result UnregisterService(const std::string& name); Result UnregisterService(const std::string& name);
Result GetServicePort(Kernel::KPort** out_port, const std::string& name); Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
template <Common::DerivedFrom<SessionRequestHandler> T> template <Common::DerivedFrom<SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const { std::shared_ptr<T> GetService(const std::string& service_name) const {
@@ -84,7 +84,7 @@ private:
/// Map of registered services, retrieved using GetServicePort. /// Map of registered services, retrieved using GetServicePort.
std::mutex lock; std::mutex lock;
std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services; std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services;
std::unordered_map<std::string, Kernel::KPort*> service_ports; std::unordered_map<std::string, Kernel::KClientPort*> service_ports;
/// Kernel context /// Kernel context
Kernel::KernelCore& kernel; Kernel::KernelCore& kernel;

View File

@@ -28,7 +28,6 @@ void Controller::ConvertCurrentObjectToDomain(HLERequestContext& ctx) {
void Controller::CloneCurrentObject(HLERequestContext& ctx) { void Controller::CloneCurrentObject(HLERequestContext& ctx) {
LOG_DEBUG(Service, "called"); LOG_DEBUG(Service, "called");
auto& process = *ctx.GetThread().GetOwnerProcess();
auto session_manager = ctx.GetManager(); auto session_manager = ctx.GetManager();
// FIXME: this is duplicated from the SVC, it should just call it instead // FIXME: this is duplicated from the SVC, it should just call it instead
@@ -36,11 +35,11 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
// Reserve a new session from the process resource limit. // Reserve a new session from the process resource limit.
Kernel::KScopedResourceReservation session_reservation( Kernel::KScopedResourceReservation session_reservation(
&process, Kernel::LimitableResource::SessionCountMax); Kernel::GetCurrentProcessPointer(kernel), Kernel::LimitableResource::SessionCountMax);
ASSERT(session_reservation.Succeeded()); ASSERT(session_reservation.Succeeded());
// Create the session. // Create the session.
Kernel::KSession* session = Kernel::KSession::Create(system.Kernel()); Kernel::KSession* session = Kernel::KSession::Create(kernel);
ASSERT(session != nullptr); ASSERT(session != nullptr);
// Initialize the session. // Initialize the session.
@@ -50,7 +49,7 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
session_reservation.Commit(); session_reservation.Commit();
// Register the session. // Register the session.
Kernel::KSession::Register(system.Kernel(), session); Kernel::KSession::Register(kernel, session);
// Register with server manager. // Register with server manager.
session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), session_manager->GetServerManager().RegisterSession(&session->GetServerSession(),

View File

@@ -129,9 +129,10 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
} }
metadata.Print(); metadata.Print();
// Enable NCE only for programs with 39-bit address space. // Enable NCE only for applications with 39-bit address space.
const bool is_39bit = const bool is_39bit =
metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit; metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit;
const bool is_application = metadata.GetPoolPartition() == FileSys::PoolPartition::Application;
Settings::SetNceEnabled(is_39bit); Settings::SetNceEnabled(is_39bit);
const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2",
@@ -147,7 +148,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* {
#ifdef HAS_NCE #ifdef HAS_NCE
if (Settings::IsNceEnabled()) { if (is_application && Settings::IsNceEnabled()) {
return &module_patchers[i]; return &module_patchers[i];
} }
#endif #endif
@@ -175,7 +176,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Enable direct memory mapping in case of NCE. // Enable direct memory mapping in case of NCE.
const u64 fastmem_base = [&]() -> size_t { const u64 fastmem_base = [&]() -> size_t {
if (Settings::IsNceEnabled()) { if (is_application && Settings::IsNceEnabled()) {
auto& buffer = system.DeviceMemory().buffer; auto& buffer = system.DeviceMemory().buffer;
buffer.EnableDirectMappedAddress(); buffer.EnableDirectMappedAddress();
return reinterpret_cast<u64>(buffer.VirtualBasePointer()); return reinterpret_cast<u64>(buffer.VirtualBasePointer());

View File

@@ -10,6 +10,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/atomic_ops.h" #include "common/atomic_ops.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/heap_tracker.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/page_table.h" #include "common/page_table.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
@@ -45,11 +46,25 @@ struct Memory::Impl {
void SetCurrentPageTable(Kernel::KProcess& process) { void SetCurrentPageTable(Kernel::KProcess& process) {
current_page_table = &process.GetPageTable().GetImpl(); current_page_table = &process.GetPageTable().GetImpl();
current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
if (std::addressof(process) == system.ApplicationProcess() &&
Settings::IsFastmemEnabled()) {
current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
} else {
current_page_table->fastmem_arena = nullptr;
}
#ifdef __linux__
heap_tracker.emplace(system.DeviceMemory().buffer);
buffer = std::addressof(*heap_tracker);
#else
buffer = std::addressof(system.DeviceMemory().buffer);
#endif
} }
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target, Common::MemoryPermission perms) { Common::PhysicalAddress target, Common::MemoryPermission perms,
bool separate_heap) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}",
@@ -57,20 +72,21 @@ struct Memory::Impl {
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target, MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
Common::PageType::Memory); Common::PageType::Memory);
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
system.DeviceMemory().buffer.Map(GetInteger(base), buffer->Map(GetInteger(base), GetInteger(target) - DramMemoryMap::Base, size, perms,
GetInteger(target) - DramMemoryMap::Base, size, perms); separate_heap);
} }
} }
void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
bool separate_heap) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0,
Common::PageType::Unmapped); Common::PageType::Unmapped);
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
system.DeviceMemory().buffer.Unmap(GetInteger(base), size); buffer->Unmap(GetInteger(base), size, separate_heap);
} }
} }
@@ -79,17 +95,7 @@ struct Memory::Impl {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr); ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr);
if (!Settings::IsFastmemEnabled()) { if (!current_page_table->fastmem_arena) {
return;
}
const bool is_r = True(perms & Common::MemoryPermission::Read);
const bool is_w = True(perms & Common::MemoryPermission::Write);
const bool is_x =
True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled();
if (!current_page_table) {
system.DeviceMemory().buffer.Protect(vaddr, size, is_r, is_w, is_x);
return; return;
} }
@@ -101,8 +107,7 @@ struct Memory::Impl {
switch (page_type) { switch (page_type) {
case Common::PageType::RasterizerCachedMemory: case Common::PageType::RasterizerCachedMemory:
if (protect_bytes > 0) { if (protect_bytes > 0) {
system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, buffer->Protect(protect_begin, protect_bytes, perms);
is_x);
protect_bytes = 0; protect_bytes = 0;
} }
break; break;
@@ -115,7 +120,7 @@ struct Memory::Impl {
} }
if (protect_bytes > 0) { if (protect_bytes > 0) {
system.DeviceMemory().buffer.Protect(protect_begin, protect_bytes, is_r, is_w, is_x); buffer->Protect(protect_begin, protect_bytes, perms);
} }
} }
@@ -239,7 +244,7 @@ struct Memory::Impl {
bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped, bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped,
auto on_memory, auto on_rasterizer, auto increment) { auto on_memory, auto on_rasterizer, auto increment) {
const auto& page_table = system.ApplicationProcess()->GetPageTable().GetImpl(); const auto& page_table = *current_page_table;
std::size_t remaining_size = size; std::size_t remaining_size = size;
std::size_t page_index = addr >> YUZU_PAGEBITS; std::size_t page_index = addr >> YUZU_PAGEBITS;
std::size_t page_offset = addr & YUZU_PAGEMASK; std::size_t page_offset = addr & YUZU_PAGEMASK;
@@ -484,8 +489,10 @@ struct Memory::Impl {
return; return;
} }
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug); const auto perm{debug ? Common::MemoryPermission{}
: Common::MemoryPermission::ReadWrite};
buffer->Protect(vaddr, size, perm);
} }
// Iterate over a contiguous CPU address space, marking/unmarking the region. // Iterate over a contiguous CPU address space, marking/unmarking the region.
@@ -541,10 +548,15 @@ struct Memory::Impl {
return; return;
} }
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
const bool is_read_enable = Common::MemoryPermission perm{};
!Settings::values.use_reactive_flushing.GetValue() || !cached; if (!Settings::values.use_reactive_flushing.GetValue() || !cached) {
system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); perm |= Common::MemoryPermission::Read;
}
if (!cached) {
perm |= Common::MemoryPermission::Write;
}
buffer->Protect(vaddr, size, perm);
} }
// Iterate over a contiguous CPU address space, which corresponds to the specified GPU // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
@@ -855,6 +867,13 @@ struct Memory::Impl {
std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
std::mutex sys_core_guard; std::mutex sys_core_guard;
std::optional<Common::HeapTracker> heap_tracker;
#ifdef __linux__
Common::HeapTracker* buffer{};
#else
Common::HostMemory* buffer{};
#endif
}; };
Memory::Memory(Core::System& system_) : system{system_} { Memory::Memory(Core::System& system_) : system{system_} {
@@ -872,12 +891,14 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process) {
} }
void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target, Common::MemoryPermission perms) { Common::PhysicalAddress target, Common::MemoryPermission perms,
impl->MapMemoryRegion(page_table, base, size, target, perms); bool separate_heap) {
impl->MapMemoryRegion(page_table, base, size, target, perms, separate_heap);
} }
void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
impl->UnmapRegion(page_table, base, size); bool separate_heap) {
impl->UnmapRegion(page_table, base, size, separate_heap);
} }
void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress vaddr, u64 size, void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress vaddr, u64 size,
@@ -886,8 +907,7 @@ void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress
} }
bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
const Kernel::KProcess& process = *system.ApplicationProcess(); const auto& page_table = *impl->current_page_table;
const auto& page_table = process.GetPageTable().GetImpl();
const size_t page = vaddr >> YUZU_PAGEBITS; const size_t page = vaddr >> YUZU_PAGEBITS;
if (page >= page_table.pointers.size()) { if (page >= page_table.pointers.size()) {
return false; return false;
@@ -1048,7 +1068,9 @@ void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) {
} }
bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
bool mapped = true; [[maybe_unused]] bool mapped = true;
[[maybe_unused]] bool rasterizer = false;
u8* const ptr = impl->GetPointerImpl( u8* const ptr = impl->GetPointerImpl(
GetInteger(vaddr), GetInteger(vaddr),
[&] { [&] {
@@ -1056,8 +1078,26 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
GetInteger(vaddr)); GetInteger(vaddr));
mapped = false; mapped = false;
}, },
[&] { impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size); }); [&] {
impl->system.GPU().InvalidateRegion(GetInteger(vaddr), size);
rasterizer = true;
});
#ifdef __linux__
if (!rasterizer && mapped) {
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
}
#endif
return mapped && ptr != nullptr; return mapped && ptr != nullptr;
} }
bool Memory::InvalidateSeparateHeap(void* fault_address) {
#ifdef __linux__
return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address));
#else
return false;
#endif
}
} // namespace Core::Memory } // namespace Core::Memory

View File

@@ -86,7 +86,8 @@ public:
* @param perms The permissions to map the memory with. * @param perms The permissions to map the memory with.
*/ */
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target, Common::MemoryPermission perms); Common::PhysicalAddress target, Common::MemoryPermission perms,
bool separate_heap);
/** /**
* Unmaps a region of the emulated process address space. * Unmaps a region of the emulated process address space.
@@ -95,7 +96,8 @@ public:
* @param base The address to begin unmapping at. * @param base The address to begin unmapping at.
* @param size The amount of bytes to unmap. * @param size The amount of bytes to unmap.
*/ */
void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size); void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
bool separate_heap);
/** /**
* Protects a region of the emulated process address space with the new permissions. * Protects a region of the emulated process address space with the new permissions.
@@ -486,6 +488,7 @@ public:
void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size); void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size);
bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
bool InvalidateSeparateHeap(void* fault_address);
void FlushRegion(Common::ProcessAddress dest_addr, size_t size); void FlushRegion(Common::ProcessAddress dest_addr, size_t size);
private: private:

View File

@@ -96,9 +96,9 @@ Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
} }
Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin,
spv::StorageClass storage_class) { spv::StorageClass storage_class, std::optional<Id> initializer = std::nullopt) {
const Id pointer_type{ctx.TypePointer(storage_class, type)}; const Id pointer_type{ctx.TypePointer(storage_class, type)};
const Id id{ctx.AddGlobalVariable(pointer_type, storage_class)}; const Id id{ctx.AddGlobalVariable(pointer_type, storage_class, initializer)};
if (builtin) { if (builtin) {
ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin); ctx.Decorate(id, spv::Decoration::BuiltIn, *builtin);
} }
@@ -144,11 +144,12 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
} }
Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations, Id DefineOutput(EmitContext& ctx, Id type, std::optional<u32> invocations,
std::optional<spv::BuiltIn> builtin = std::nullopt) { std::optional<spv::BuiltIn> builtin = std::nullopt,
std::optional<Id> initializer = std::nullopt) {
if (invocations && ctx.stage == Stage::TessellationControl) { if (invocations && ctx.stage == Stage::TessellationControl) {
type = ctx.TypeArray(type, ctx.Const(*invocations)); type = ctx.TypeArray(type, ctx.Const(*invocations));
} }
return DefineVariable(ctx, type, builtin, spv::StorageClass::Output); return DefineVariable(ctx, type, builtin, spv::StorageClass::Output, initializer);
} }
void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) { void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invocations) {
@@ -811,10 +812,14 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
labels.push_back(OpLabel()); labels.push_back(OpLabel());
} }
if (info.stores.ClipDistances()) { if (info.stores.ClipDistances()) {
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2); if (profile.max_user_clip_distances >= 4) {
labels.push_back(OpLabel()); literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance0) >> 2);
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2); labels.push_back(OpLabel());
labels.push_back(OpLabel()); }
if (profile.max_user_clip_distances >= 8) {
literals.push_back(static_cast<u32>(IR::Attribute::ClipDistance4) >> 2);
labels.push_back(OpLabel());
}
} }
OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone);
OpSwitch(compare_index, default_label, literals, labels); OpSwitch(compare_index, default_label, literals, labels);
@@ -843,17 +848,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
++label_index; ++label_index;
} }
if (info.stores.ClipDistances()) { if (info.stores.ClipDistances()) {
AddLabel(labels[label_index]); if (profile.max_user_clip_distances >= 4) {
const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)}; AddLabel(labels[label_index]);
OpStore(pointer, store_value); const Id pointer{OpAccessChain(output_f32, clip_distances, masked_index)};
OpReturn(); OpStore(pointer, store_value);
++label_index; OpReturn();
AddLabel(labels[label_index]); ++label_index;
const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))}; }
const Id pointer2{OpAccessChain(output_f32, clip_distances, fixed_index)}; if (profile.max_user_clip_distances >= 8) {
OpStore(pointer2, store_value); AddLabel(labels[label_index]);
OpReturn(); const Id fixed_index{OpIAdd(U32[1], masked_index, Const(4U))};
++label_index; const Id pointer{OpAccessChain(output_f32, clip_distances, fixed_index)};
OpStore(pointer, store_value);
OpReturn();
++label_index;
}
} }
AddLabel(end_block); AddLabel(end_block);
OpUnreachable(); OpUnreachable();
@@ -1532,9 +1541,16 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
if (stage == Stage::Fragment) { if (stage == Stage::Fragment) {
throw NotImplementedException("Storing ClipDistance in fragment stage"); throw NotImplementedException("Storing ClipDistance in fragment stage");
} }
const Id type{TypeArray( if (profile.max_user_clip_distances > 0) {
F32[1], Const(std::min(info.used_clip_distances, profile.max_user_clip_distances)))}; const u32 used{std::min(profile.max_user_clip_distances, 8u)};
clip_distances = DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance); const std::array<Id, 8> zero{f32_zero_value, f32_zero_value, f32_zero_value,
f32_zero_value, f32_zero_value, f32_zero_value,
f32_zero_value, f32_zero_value};
const Id type{TypeArray(F32[1], Const(used))};
const Id initializer{ConstantComposite(type, std::span(zero).subspan(0, used))};
clip_distances =
DefineOutput(*this, type, invocations, spv::BuiltIn::ClipDistance, initializer);
}
} }
if (info.stores[IR::Attribute::Layer] && if (info.stores[IR::Attribute::Layer] &&
(profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) { (profile.support_viewport_index_layer_non_geometry || stage == Stage::Geometry)) {

View File

@@ -12,6 +12,7 @@ using namespace Common::Literals;
static constexpr size_t VIRTUAL_SIZE = 1ULL << 39; static constexpr size_t VIRTUAL_SIZE = 1ULL << 39;
static constexpr size_t BACKING_SIZE = 4_GiB; static constexpr size_t BACKING_SIZE = 4_GiB;
static constexpr auto PERMS = Common::MemoryPermission::ReadWrite; static constexpr auto PERMS = Common::MemoryPermission::ReadWrite;
static constexpr auto HEAP = false;
TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
{ HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); } { HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); }
@@ -20,7 +21,7 @@ TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
TEST_CASE("HostMemory: Simple map", "[common]") { TEST_CASE("HostMemory: Simple map", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x8000, 0x1000, PERMS); mem.Map(0x5000, 0x8000, 0x1000, PERMS, HEAP);
volatile u8* const data = mem.VirtualBasePointer() + 0x5000; volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
data[0] = 50; data[0] = 50;
@@ -29,8 +30,8 @@ TEST_CASE("HostMemory: Simple map", "[common]") {
TEST_CASE("HostMemory: Simple mirror map", "[common]") { TEST_CASE("HostMemory: Simple mirror map", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x3000, 0x2000, PERMS); mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
mem.Map(0x8000, 0x4000, 0x1000, PERMS); mem.Map(0x8000, 0x4000, 0x1000, PERMS, HEAP);
volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000; volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000;
volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000; volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000;
@@ -40,116 +41,116 @@ TEST_CASE("HostMemory: Simple mirror map", "[common]") {
TEST_CASE("HostMemory: Simple unmap", "[common]") { TEST_CASE("HostMemory: Simple unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x3000, 0x2000, PERMS); mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
volatile u8* const data = mem.VirtualBasePointer() + 0x5000; volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
data[75] = 50; data[75] = 50;
REQUIRE(data[75] == 50); REQUIRE(data[75] == 50);
mem.Unmap(0x5000, 0x2000); mem.Unmap(0x5000, 0x2000, HEAP);
} }
TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { TEST_CASE("HostMemory: Simple unmap and remap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x3000, 0x2000, PERMS); mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
volatile u8* const data = mem.VirtualBasePointer() + 0x5000; volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
data[0] = 50; data[0] = 50;
REQUIRE(data[0] == 50); REQUIRE(data[0] == 50);
mem.Unmap(0x5000, 0x2000); mem.Unmap(0x5000, 0x2000, HEAP);
mem.Map(0x5000, 0x3000, 0x2000, PERMS); mem.Map(0x5000, 0x3000, 0x2000, PERMS, HEAP);
REQUIRE(data[0] == 50); REQUIRE(data[0] == 50);
mem.Map(0x7000, 0x2000, 0x5000, PERMS); mem.Map(0x7000, 0x2000, 0x5000, PERMS, HEAP);
REQUIRE(data[0x3000] == 50); REQUIRE(data[0x3000] == 50);
} }
TEST_CASE("HostMemory: Nieche allocation", "[common]") { TEST_CASE("HostMemory: Nieche allocation", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x20000, PERMS); mem.Map(0x0000, 0, 0x20000, PERMS, HEAP);
mem.Unmap(0x0000, 0x4000); mem.Unmap(0x0000, 0x4000, HEAP);
mem.Map(0x1000, 0, 0x2000, PERMS); mem.Map(0x1000, 0, 0x2000, PERMS, HEAP);
mem.Map(0x3000, 0, 0x1000, PERMS); mem.Map(0x3000, 0, 0x1000, PERMS, HEAP);
mem.Map(0, 0, 0x1000, PERMS); mem.Map(0, 0, 0x1000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Full unmap", "[common]") { TEST_CASE("HostMemory: Full unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x8000, 0, 0x4000, PERMS); mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
mem.Unmap(0x8000, 0x4000); mem.Unmap(0x8000, 0x4000, HEAP);
mem.Map(0x6000, 0, 0x16000, PERMS); mem.Map(0x6000, 0, 0x16000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") { TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x4000, PERMS); mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
mem.Unmap(0x2000, 0x4000); mem.Unmap(0x2000, 0x4000, HEAP);
mem.Map(0x2000, 0x80000, 0x4000, PERMS); mem.Map(0x2000, 0x80000, 0x4000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") { TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x8000, 0, 0x4000, PERMS); mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
mem.Unmap(0x6000, 0x4000); mem.Unmap(0x6000, 0x4000, HEAP);
mem.Map(0x8000, 0, 0x2000, PERMS); mem.Map(0x8000, 0, 0x2000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") { TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x4000, PERMS); mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
mem.Map(0x4000, 0, 0x1b000, PERMS); mem.Map(0x4000, 0, 0x1b000, PERMS, HEAP);
mem.Unmap(0x3000, 0x1c000); mem.Unmap(0x3000, 0x1c000, HEAP);
mem.Map(0x3000, 0, 0x20000, PERMS); mem.Map(0x3000, 0, 0x20000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Unmap between placeholders", "[common]") { TEST_CASE("HostMemory: Unmap between placeholders", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x4000, PERMS); mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
mem.Map(0x4000, 0, 0x4000, PERMS); mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
mem.Unmap(0x2000, 0x4000); mem.Unmap(0x2000, 0x4000, HEAP);
mem.Map(0x2000, 0, 0x4000, PERMS); mem.Map(0x2000, 0, 0x4000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Unmap to origin", "[common]") { TEST_CASE("HostMemory: Unmap to origin", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0, 0x4000, PERMS); mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
mem.Map(0x8000, 0, 0x4000, PERMS); mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
mem.Unmap(0x4000, 0x4000); mem.Unmap(0x4000, 0x4000, HEAP);
mem.Map(0, 0, 0x4000, PERMS); mem.Map(0, 0, 0x4000, PERMS, HEAP);
mem.Map(0x4000, 0, 0x4000, PERMS); mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Unmap to right", "[common]") { TEST_CASE("HostMemory: Unmap to right", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0, 0x4000, PERMS); mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
mem.Map(0x8000, 0, 0x4000, PERMS); mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
mem.Unmap(0x8000, 0x4000); mem.Unmap(0x8000, 0x4000, HEAP);
mem.Map(0x8000, 0, 0x4000, PERMS); mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
} }
TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x4000, PERMS); mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x1000] = 17; ptr[0x1000] = 17;
mem.Unmap(0x6000, 0x2000); mem.Unmap(0x6000, 0x2000, HEAP);
REQUIRE(ptr[0x1000] == 17); REQUIRE(ptr[0x1000] == 17);
} }
TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x4000, PERMS); mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x3000] = 19; ptr[0x3000] = 19;
ptr[0x3fff] = 12; ptr[0x3fff] = 12;
mem.Unmap(0x4000, 0x2000); mem.Unmap(0x4000, 0x2000, HEAP);
REQUIRE(ptr[0x3000] == 19); REQUIRE(ptr[0x3000] == 19);
REQUIRE(ptr[0x3fff] == 12); REQUIRE(ptr[0x3fff] == 12);
@@ -157,13 +158,13 @@ TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") {
TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x4000, PERMS); mem.Map(0x4000, 0x10000, 0x4000, PERMS, HEAP);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x0000] = 19; ptr[0x0000] = 19;
ptr[0x3fff] = 12; ptr[0x3fff] = 12;
mem.Unmap(0x1000, 0x2000); mem.Unmap(0x1000, 0x2000, HEAP);
REQUIRE(ptr[0x0000] == 19); REQUIRE(ptr[0x0000] == 19);
REQUIRE(ptr[0x3fff] == 12); REQUIRE(ptr[0x3fff] == 12);
@@ -171,14 +172,14 @@ TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") {
TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") { TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x2000, PERMS); mem.Map(0x4000, 0x10000, 0x2000, PERMS, HEAP);
mem.Map(0x6000, 0x20000, 0x2000, PERMS); mem.Map(0x6000, 0x20000, 0x2000, PERMS, HEAP);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x0000] = 19; ptr[0x0000] = 19;
ptr[0x3fff] = 12; ptr[0x3fff] = 12;
mem.Unmap(0x5000, 0x2000); mem.Unmap(0x5000, 0x2000, HEAP);
REQUIRE(ptr[0x0000] == 19); REQUIRE(ptr[0x0000] == 19);
REQUIRE(ptr[0x3fff] == 12); REQUIRE(ptr[0x3fff] == 12);

View File

@@ -327,12 +327,13 @@ public:
explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {}
void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override { void Execute(const std::vector<u32>& parameters, [[maybe_unused]] u32 method) override {
const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback();
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU); auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0] & 0xFFFFU);
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) {
Fallback(parameters); Fallback(parameters);
return; return;
} }
auto& params = maxwell3d.draw_manager->GetIndirectParams(); auto& params = maxwell3d.draw_manager->GetIndirectParams();
params.is_byte_count = true; params.is_byte_count = true;
params.is_indexed = false; params.is_indexed = false;
@@ -503,6 +504,8 @@ public:
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true);
maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)), maxwell3d.CallMethod(static_cast<size_t>(MAXWELL3D_REG_INDEX(inline_data)),
regs.transform_feedback.controls[0].stride, true); regs.transform_feedback.controls[0].stride, true);
maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address());
} }
}; };

View File

@@ -173,5 +173,13 @@ public:
virtual void BindChannel(Tegra::Control::ChannelState& channel) {} virtual void BindChannel(Tegra::Control::ChannelState& channel) {}
virtual void ReleaseChannel(s32 channel_id) {} virtual void ReleaseChannel(s32 channel_id) {}
/// Register the address as a Transform Feedback Object
virtual void RegisterTransformFeedback(GPUVAddr tfb_object_addr) {}
/// Returns true when the rasterizer has Draw Transform Feedback capabilities
virtual bool HasDrawTransformFeedback() {
return false;
}
}; };
} // namespace VideoCore } // namespace VideoCore

View File

@@ -376,4 +376,15 @@ void BufferCacheRuntime::BindImageBuffer(Buffer& buffer, u32 offset, u32 size, P
*image_handles++ = buffer.View(offset, size, format); *image_handles++ = buffer.View(offset, size, format);
} }
void BufferCacheRuntime::BindTransformFeedbackObject(GPUVAddr tfb_object_addr) {
OGLTransformFeedback& tfb_object = tfb_objects[tfb_object_addr];
tfb_object.Create();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfb_object.handle);
}
GLuint BufferCacheRuntime::GetTransformFeedbackObject(GPUVAddr tfb_object_addr) {
ASSERT(tfb_objects.contains(tfb_object_addr));
return tfb_objects[tfb_object_addr].handle;
}
} // namespace OpenGL } // namespace OpenGL

View File

@@ -5,6 +5,7 @@
#include <array> #include <array>
#include <span> #include <span>
#include <unordered_map>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/buffer_cache/buffer_cache_base.h" #include "video_core/buffer_cache/buffer_cache_base.h"
@@ -121,6 +122,9 @@ public:
void BindImageBuffer(Buffer& buffer, u32 offset, u32 size, void BindImageBuffer(Buffer& buffer, u32 offset, u32 size,
VideoCore::Surface::PixelFormat format); VideoCore::Surface::PixelFormat format);
void BindTransformFeedbackObject(GPUVAddr tfb_object_addr);
GLuint GetTransformFeedbackObject(GPUVAddr tfb_object_addr);
u64 GetDeviceMemoryUsage() const; u64 GetDeviceMemoryUsage() const;
void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) { void BindFastUniformBuffer(size_t stage, u32 binding_index, u32 size) {
@@ -233,6 +237,7 @@ private:
u32 index_buffer_offset = 0; u32 index_buffer_offset = 0;
u64 device_access_memory; u64 device_access_memory;
std::unordered_map<GPUVAddr, OGLTransformFeedback> tfb_objects;
}; };
struct BufferCacheParams { struct BufferCacheParams {

View File

@@ -309,6 +309,13 @@ void RasterizerOpenGL::DrawIndirect() {
const auto& params = maxwell3d->draw_manager->GetIndirectParams(); const auto& params = maxwell3d->draw_manager->GetIndirectParams();
buffer_cache.SetDrawIndirect(&params); buffer_cache.SetDrawIndirect(&params);
PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) { PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) {
if (params.is_byte_count) {
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
const GLuint tfb_object =
buffer_cache_runtime.GetTransformFeedbackObject(tfb_object_base_addr);
glDrawTransformFeedback(primitive_mode, tfb_object);
return;
}
const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer(); const auto [buffer, offset] = buffer_cache.GetDrawIndirectBuffer();
const GLvoid* const gl_offset = const GLvoid* const gl_offset =
reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset)); reinterpret_cast<const GLvoid*>(static_cast<uintptr_t>(offset));
@@ -1371,6 +1378,10 @@ void RasterizerOpenGL::ReleaseChannel(s32 channel_id) {
query_cache.EraseChannel(channel_id); query_cache.EraseChannel(channel_id);
} }
void RasterizerOpenGL::RegisterTransformFeedback(GPUVAddr tfb_object_addr) {
buffer_cache_runtime.BindTransformFeedbackObject(tfb_object_addr);
}
AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_) AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_)
: buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {} : buffer_cache{buffer_cache_}, texture_cache{texture_cache_} {}

View File

@@ -139,6 +139,12 @@ public:
void ReleaseChannel(s32 channel_id) override; void ReleaseChannel(s32 channel_id) override;
void RegisterTransformFeedback(GPUVAddr tfb_object_addr) override;
bool HasDrawTransformFeedback() override {
return true;
}
private: private:
static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_TEXTURES = 192;
static constexpr size_t MAX_IMAGES = 48; static constexpr size_t MAX_IMAGES = 48;

View File

@@ -207,4 +207,21 @@ void OGLQuery::Release() {
handle = 0; handle = 0;
} }
void OGLTransformFeedback::Create() {
if (handle != 0)
return;
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
glCreateTransformFeedbacks(1, &handle);
}
void OGLTransformFeedback::Release() {
if (handle == 0)
return;
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
glDeleteTransformFeedbacks(1, &handle);
handle = 0;
}
} // namespace OpenGL } // namespace OpenGL

View File

@@ -323,4 +323,31 @@ public:
GLuint handle = 0; GLuint handle = 0;
}; };
class OGLTransformFeedback final {
public:
YUZU_NON_COPYABLE(OGLTransformFeedback);
OGLTransformFeedback() = default;
OGLTransformFeedback(OGLTransformFeedback&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
~OGLTransformFeedback() {
Release();
}
OGLTransformFeedback& operator=(OGLTransformFeedback&& o) noexcept {
Release();
handle = std::exchange(o.handle, 0);
return *this;
}
/// Creates a new internal OpenGL resource and stores the handle
void Create();
/// Deletes the internal OpenGL resource
void Release();
GLuint handle = 0;
};
} // namespace OpenGL } // namespace OpenGL

View File

@@ -60,66 +60,72 @@ u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
} }
template <auto decompress, PixelFormat pixel_format> template <auto decompress, PixelFormat pixel_format>
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent, void DecompressBlocks(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
bool is_signed = false) { bool is_signed = false) {
const u32 out_bpp = ConvertedBytesPerBlock(pixel_format); const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
const u32 block_width = std::min(extent.width, BLOCK_SIZE); const u32 block_size = BlockSize(pixel_format);
const u32 block_height = std::min(extent.height, BLOCK_SIZE); const u32 width = copy.image_extent.width;
const u32 pitch = extent.width * out_bpp; const u32 height = copy.image_extent.height * copy.image_subresource.num_layers;
const u32 depth = copy.image_extent.depth;
const u32 block_width = std::min(width, BLOCK_SIZE);
const u32 block_height = std::min(height, BLOCK_SIZE);
const u32 pitch = width * out_bpp;
size_t input_offset = 0; size_t input_offset = 0;
size_t output_offset = 0; size_t output_offset = 0;
for (u32 slice = 0; slice < extent.depth; ++slice) { for (u32 slice = 0; slice < depth; ++slice) {
for (u32 y = 0; y < extent.height; y += block_height) { for (u32 y = 0; y < height; y += block_height) {
size_t row_offset = 0; size_t src_offset = input_offset;
for (u32 x = 0; x < extent.width; size_t dst_offset = output_offset;
x += block_width, row_offset += block_width * out_bpp) { for (u32 x = 0; x < width; x += block_width) {
const u8* src = input.data() + input_offset; const u8* src = input.data() + src_offset;
u8* const dst = output.data() + output_offset + row_offset; u8* const dst = output.data() + dst_offset;
if constexpr (IsSigned(pixel_format)) { if constexpr (IsSigned(pixel_format)) {
decompress(src, dst, x, y, extent.width, extent.height, is_signed); decompress(src, dst, x, y, width, height, is_signed);
} else { } else {
decompress(src, dst, x, y, extent.width, extent.height); decompress(src, dst, x, y, width, height);
} }
input_offset += BlockSize(pixel_format); src_offset += block_size;
dst_offset += block_width * out_bpp;
} }
input_offset += copy.buffer_row_length * block_size / block_width;
output_offset += block_height * pitch; output_offset += block_height * pitch;
} }
} }
} }
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
VideoCore::Surface::PixelFormat pixel_format) { VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) { switch (pixel_format) {
case PixelFormat::BC1_RGBA_UNORM: case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC1_RGBA_SRGB: case PixelFormat::BC1_RGBA_SRGB:
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent); DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, copy);
break; break;
case PixelFormat::BC2_UNORM: case PixelFormat::BC2_UNORM:
case PixelFormat::BC2_SRGB: case PixelFormat::BC2_SRGB:
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent); DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, copy);
break; break;
case PixelFormat::BC3_UNORM: case PixelFormat::BC3_UNORM:
case PixelFormat::BC3_SRGB: case PixelFormat::BC3_SRGB:
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent); DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, copy);
break; break;
case PixelFormat::BC4_SNORM: case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM: case PixelFormat::BC4_UNORM:
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>( DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
input, output, extent, pixel_format == PixelFormat::BC4_SNORM); input, output, copy, pixel_format == PixelFormat::BC4_SNORM);
break; break;
case PixelFormat::BC5_SNORM: case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM: case PixelFormat::BC5_UNORM:
DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>( DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
input, output, extent, pixel_format == PixelFormat::BC5_SNORM); input, output, copy, pixel_format == PixelFormat::BC5_SNORM);
break; break;
case PixelFormat::BC6H_SFLOAT: case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT: case PixelFormat::BC6H_UFLOAT:
DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>( DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT); input, output, copy, pixel_format == PixelFormat::BC6H_SFLOAT);
break; break;
case PixelFormat::BC7_SRGB: case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM: case PixelFormat::BC7_UNORM:
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent); DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, copy);
break; break;
default: default:
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format); LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);

View File

@@ -13,7 +13,7 @@ namespace VideoCommon {
[[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format); [[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent, void DecompressBCn(std::span<const u8> input, std::span<u8> output, BufferImageCopy& copy,
VideoCore::Surface::PixelFormat pixel_format); VideoCore::Surface::PixelFormat pixel_format);
} // namespace VideoCommon } // namespace VideoCommon

View File

@@ -837,6 +837,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
std::span<u8> output) { std::span<u8> output) {
const size_t guest_size_bytes = input.size_bytes(); const size_t guest_size_bytes = input.size_bytes();
const u32 bpp_log2 = BytesPerBlockLog2(info.format); const u32 bpp_log2 = BytesPerBlockLog2(info.format);
const Extent2D tile_size = DefaultBlockSize(info.format);
const Extent3D size = info.size; const Extent3D size = info.size;
if (info.type == ImageType::Linear) { if (info.type == ImageType::Linear) {
@@ -847,7 +848,7 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
return {{ return {{
.buffer_offset = 0, .buffer_offset = 0,
.buffer_size = guest_size_bytes, .buffer_size = guest_size_bytes,
.buffer_row_length = info.pitch >> bpp_log2, .buffer_row_length = info.pitch * tile_size.width >> bpp_log2,
.buffer_image_height = size.height, .buffer_image_height = size.height,
.image_subresource = .image_subresource =
{ {
@@ -862,7 +863,6 @@ boost::container::small_vector<BufferImageCopy, 16> UnswizzleImage(Tegra::Memory
const LevelInfo level_info = MakeLevelInfo(info); const LevelInfo level_info = MakeLevelInfo(info);
const s32 num_layers = info.resources.layers; const s32 num_layers = info.resources.layers;
const s32 num_levels = info.resources.levels; const s32 num_levels = info.resources.levels;
const Extent2D tile_size = DefaultBlockSize(info.format);
const std::array level_sizes = CalculateLevelSizes(level_info, num_levels); const std::array level_sizes = CalculateLevelSizes(level_info, num_levels);
const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing); const Extent2D gob = GobSize(bpp_log2, info.block.height, info.tile_width_spacing);
const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels); const u32 layer_size = CalculateLevelBytes(level_sizes, num_levels);
@@ -926,8 +926,6 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
const auto input_offset = input.subspan(copy.buffer_offset); const auto input_offset = input.subspan(copy.buffer_offset);
copy.buffer_offset = output_offset; copy.buffer_offset = output_offset;
copy.buffer_row_length = mip_size.width;
copy.buffer_image_height = mip_size.height;
const auto recompression_setting = Settings::values.astc_recompression.GetValue(); const auto recompression_setting = Settings::values.astc_recompression.GetValue();
const bool astc = IsPixelFormatASTC(info.format); const bool astc = IsPixelFormatASTC(info.format);
@@ -972,16 +970,14 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
bpp_div; bpp_div;
output_offset += static_cast<u32>(copy.buffer_size); output_offset += static_cast<u32>(copy.buffer_size);
} else { } else {
const Extent3D image_extent{ DecompressBCn(input_offset, output.subspan(output_offset), copy, info.format);
.width = copy.image_extent.width,
.height = copy.image_extent.height * copy.image_subresource.num_layers,
.depth = copy.image_extent.depth,
};
DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
output_offset += copy.image_extent.width * copy.image_extent.height * output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_subresource.num_layers * copy.image_subresource.num_layers *
ConvertedBytesPerBlock(info.format); ConvertedBytesPerBlock(info.format);
} }
copy.buffer_row_length = mip_size.width;
copy.buffer_image_height = mip_size.height;
} }
} }

View File

@@ -755,10 +755,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
// The wanted format is not supported by hardware, search for alternatives // The wanted format is not supported by hardware, search for alternatives
const VkFormat* alternatives = GetFormatAlternatives(wanted_format); const VkFormat* alternatives = GetFormatAlternatives(wanted_format);
if (alternatives == nullptr) { if (alternatives == nullptr) {
ASSERT_MSG(false, LOG_ERROR(Render_Vulkan,
"Format={} with usage={} and type={} has no defined alternatives and host " "Format={} with usage={} and type={} has no defined alternatives and host "
"hardware does not support it", "hardware does not support it",
wanted_format, wanted_usage, format_type); wanted_format, wanted_usage, format_type);
return wanted_format; return wanted_format;
} }
@@ -774,10 +774,10 @@ VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags
} }
// No alternatives found, panic // No alternatives found, panic
ASSERT_MSG(false, LOG_ERROR(Render_Vulkan,
"Format={} with usage={} and type={} is not supported by the host hardware and " "Format={} with usage={} and type={} is not supported by the host hardware and "
"doesn't support any of the alternatives", "doesn't support any of the alternatives",
wanted_format, wanted_usage, format_type); wanted_format, wanted_usage, format_type);
return wanted_format; return wanted_format;
} }

View File

@@ -246,7 +246,9 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec
.objectHandle = reinterpret_cast<u64>(handle), .objectHandle = reinterpret_cast<u64>(handle),
.pObjectName = name, .pObjectName = name,
}; };
Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); if (dld->vkSetDebugUtilsObjectNameEXT) {
Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
}
} }
} // Anonymous namespace } // Anonymous namespace

View File

@@ -168,14 +168,6 @@ class GMainWindow : public QMainWindow {
/// Max number of recently loaded items to keep track of /// Max number of recently loaded items to keep track of
static const int max_recent_files_item = 10; static const int max_recent_files_item = 10;
// TODO: Make use of this!
enum {
UI_IDLE,
UI_EMU_BOOTING,
UI_EMU_RUNNING,
UI_EMU_STOPPING,
};
enum { enum {
CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES,
CREATE_SHORTCUT_MSGBOX_SUCCESS, CREATE_SHORTCUT_MSGBOX_SUCCESS,