Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5568763a57 | |||
| a3b12e3809 | |||
| dc47d0f624 | |||
| fcfe192e83 | |||
| bd38aefc57 | |||
| feaf010fa2 | |||
| ebecdd3a74 | |||
| a29ddcee40 | |||
| d11547024c | |||
| 6f59e2676b | |||
| 8fea7e56e5 | |||
| 58fea44eb5 | |||
| 084d7d6b01 | |||
| bd3bfe411d | |||
| 963ed37fd6 | |||
| 741da9c8bf | |||
| a0407a8e64 | |||
| 7582717c9d | |||
| ec85eac3c9 | |||
| fb4b507ba4 | |||
| 7ea78699a1 | |||
| 80ad90651e | |||
| b94739cfa7 | |||
| 89e00c442d | |||
| d796341d33 | |||
| 5282efac1b | |||
| ae83d5c6d3 | |||
| 3370546a7a | |||
| 2ff606628c | |||
| 20576ebb43 | |||
| 6f81160160 | |||
| 266e086706 | |||
| 9561a2f5b1 | |||
| bc8699a9fa | |||
| c3cc65a11e | |||
| 1f0fee33ed | |||
| de6c0defb3 | |||
| 6c659c3a16 | |||
| af022294dd | |||
| 073714a762 | |||
| 4ae75bec50 | |||
| 31527ccd25 | |||
| 268878f895 | |||
| d00b7be2d6 | |||
| 941b663352 | |||
| 708e5b027f | |||
| c33c9c76bf | |||
| 888e814130 | |||
| cad53179ed | |||
| 3c313a43fd | |||
| 45bdbf538c | |||
| 4544407af6 | |||
| 2f2e443858 | |||
| 4dd6bcd206 | |||
| 054732210e | |||
| e609bc1c6a | |||
| 422525e3fb | |||
| 2dafb27055 | |||
| 500b01076e | |||
| b43ae9d5ed | |||
| f22867efc5 | |||
| 67fa743414 | |||
| 5799fa4d7d | |||
| 499c89790b | |||
| 75bf2c20eb | |||
| 017a18f42e | |||
| 669a9a644d |
Vendored
+13
@@ -58,6 +58,19 @@ QPushButton#GPUStatusBarButton:!checked {
|
||||
color: #109010;
|
||||
}
|
||||
|
||||
QPushButton#DockingStatusBarButton {
|
||||
min-width: 0px;
|
||||
color: #000000;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
QPushButton#DockingStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
||||
|
||||
QPushButton#buttonRefreshDevices {
|
||||
min-width: 21px;
|
||||
min-height: 21px;
|
||||
|
||||
Vendored
+13
@@ -1304,6 +1304,19 @@ QPushButton#GPUStatusBarButton:!checked {
|
||||
color: #40dd40;
|
||||
}
|
||||
|
||||
QPushButton#DockingStatusBarButton {
|
||||
min-width: 0px;
|
||||
color: #ffffff;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
QPushButton#DockingStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
||||
|
||||
QPushButton#buttonRefreshDevices {
|
||||
min-width: 23px;
|
||||
min-height: 23px;
|
||||
|
||||
@@ -2207,6 +2207,19 @@ QPushButton#GPUStatusBarButton:!checked {
|
||||
color: #40dd40;
|
||||
}
|
||||
|
||||
QPushButton#DockingStatusBarButton {
|
||||
min-width: 0px;
|
||||
color: #ffffff;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
padding: 0px 3px 0px 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
QPushButton#DockingStatusBarButton:hover {
|
||||
border: 1px solid #76797C;
|
||||
}
|
||||
|
||||
QPushButton#buttonRefreshDevices {
|
||||
min-width: 19px;
|
||||
min-height: 19px;
|
||||
|
||||
Vendored
+5
@@ -40,6 +40,11 @@ target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||
add_library(microprofile INTERFACE)
|
||||
target_include_directories(microprofile INTERFACE ./microprofile)
|
||||
|
||||
# GCC bugs
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND MINGW)
|
||||
target_compile_options(microprofile INTERFACE "-Wno-array-bounds")
|
||||
endif()
|
||||
|
||||
# libusb
|
||||
if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
|
||||
add_subdirectory(libusb)
|
||||
|
||||
@@ -429,7 +429,7 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
|
||||
in_params.node_id);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
|
||||
ASSERT_MSG(false, "Unimplemented sample format={}", in_params.sample_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1312,7 +1312,7 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::s
|
||||
samples_to_read - samples_read, channel, temp_mix_offset);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
|
||||
ASSERT_MSG(false, "Unimplemented sample format={}", in_params.sample_format);
|
||||
}
|
||||
|
||||
temp_mix_offset += samples_decoded;
|
||||
|
||||
@@ -50,7 +50,7 @@ EffectBase* EffectContext::RetargetEffect(std::size_t i, EffectType effect) {
|
||||
effects[i] = std::make_unique<EffectBiquadFilter>();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unimplemented effect {}", effect);
|
||||
ASSERT_MSG(false, "Unimplemented effect {}", effect);
|
||||
effects[i] = std::make_unique<EffectStubbed>();
|
||||
}
|
||||
return GetInfo(i);
|
||||
@@ -104,7 +104,7 @@ void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
|
||||
auto& params = GetParams();
|
||||
const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data());
|
||||
if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
|
||||
UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels);
|
||||
ASSERT_MSG(false, "Invalid reverb max channel count {}", reverb_params->max_channels);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -483,7 +483,7 @@ bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) {
|
||||
// Add more work
|
||||
index_stack.push(j);
|
||||
} else if (node_state == NodeStates::State::InFound) {
|
||||
UNREACHABLE_MSG("Node start marked as found");
|
||||
ASSERT_MSG(false, "Node start marked as found");
|
||||
ResetState();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
|
||||
in_params.current_playstate = ServerPlayState::Play;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown playstate {}", voice_in.play_state);
|
||||
ASSERT_MSG(false, "Unknown playstate {}", voice_in.play_state);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
|
||||
return in_params.should_depop;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid playstate {}", in_params.current_playstate);
|
||||
ASSERT_MSG(false, "Invalid playstate {}", in_params.current_playstate);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -58,6 +58,7 @@ add_library(common STATIC
|
||||
div_ceil.h
|
||||
dynamic_library.cpp
|
||||
dynamic_library.h
|
||||
elf.h
|
||||
error.cpp
|
||||
error.h
|
||||
expected.h
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
|
||||
#include "common/settings.h"
|
||||
|
||||
void assert_handle_failure() {
|
||||
void assert_fail_impl() {
|
||||
if (Settings::values.use_debug_asserts) {
|
||||
Crash();
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void unreachable_impl() {
|
||||
Crash();
|
||||
throw std::runtime_error("Unreachable code");
|
||||
}
|
||||
|
||||
+27
-28
@@ -9,44 +9,43 @@
|
||||
// Sometimes we want to try to continue even after hitting an assert.
|
||||
// However touching this file yields a global recompilation as this header is included almost
|
||||
// everywhere. So let's just move the handling of the failed assert to a single cpp file.
|
||||
void assert_handle_failure();
|
||||
|
||||
// For asserts we'd like to keep all the junk executed when an assert happens away from the
|
||||
// important code in the function. One way of doing this is to put all the relevant code inside a
|
||||
// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
|
||||
// specify __declspec on lambda functions, so what we do instead is define a noinline wrapper
|
||||
// template that calls the lambda. This seems to generate an extra instruction at the call-site
|
||||
// compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good
|
||||
// enough for our purposes.
|
||||
template <typename Fn>
|
||||
#if defined(_MSC_VER)
|
||||
[[msvc::noinline]]
|
||||
#elif defined(__GNUC__)
|
||||
[[gnu::cold, gnu::noinline]]
|
||||
void assert_fail_impl();
|
||||
[[noreturn]] void unreachable_impl();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define YUZU_NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define YUZU_NO_INLINE __attribute__((noinline))
|
||||
#endif
|
||||
static void
|
||||
assert_noinline_call(const Fn& fn) {
|
||||
fn();
|
||||
assert_handle_failure();
|
||||
}
|
||||
|
||||
#define ASSERT(_a_) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
|
||||
([&]() YUZU_NO_INLINE { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
||||
assert_fail_impl(); \
|
||||
} \
|
||||
while (0)
|
||||
}())
|
||||
|
||||
#define ASSERT_MSG(_a_, ...) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
|
||||
([&]() YUZU_NO_INLINE { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
||||
assert_fail_impl(); \
|
||||
} \
|
||||
while (0)
|
||||
}())
|
||||
|
||||
#define UNREACHABLE() \
|
||||
do { \
|
||||
LOG_CRITICAL(Debug, "Unreachable code!"); \
|
||||
unreachable_impl(); \
|
||||
} while (0)
|
||||
|
||||
#define UNREACHABLE() assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); })
|
||||
#define UNREACHABLE_MSG(...) \
|
||||
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); })
|
||||
do { \
|
||||
LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \
|
||||
unreachable_impl(); \
|
||||
} while (0)
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4324)
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
#include <stop_token>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace Common {
|
||||
namespace mpsc {
|
||||
#if defined(__cpp_lib_hardware_interference_size)
|
||||
constexpr size_t hardware_interference_size = std::hardware_destructive_interference_size;
|
||||
#else
|
||||
constexpr size_t hardware_interference_size = 64;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
using AlignedAllocator = std::allocator<T>;
|
||||
|
||||
template <typename T>
|
||||
struct Slot {
|
||||
~Slot() noexcept {
|
||||
if (turn.test()) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void construct(Args&&... args) noexcept {
|
||||
static_assert(std::is_nothrow_constructible_v<T, Args&&...>,
|
||||
"T must be nothrow constructible with Args&&...");
|
||||
std::construct_at(reinterpret_cast<T*>(&storage), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void destroy() noexcept {
|
||||
static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible");
|
||||
std::destroy_at(reinterpret_cast<T*>(&storage));
|
||||
}
|
||||
|
||||
T&& move() noexcept {
|
||||
return reinterpret_cast<T&&>(storage);
|
||||
}
|
||||
|
||||
// Align to avoid false sharing between adjacent slots
|
||||
alignas(hardware_interference_size) std::atomic_flag turn{};
|
||||
struct aligned_store {
|
||||
struct type {
|
||||
alignas(T) unsigned char data[sizeof(T)];
|
||||
};
|
||||
};
|
||||
typename aligned_store::type storage;
|
||||
};
|
||||
|
||||
template <typename T, typename Allocator = AlignedAllocator<Slot<T>>>
|
||||
class Queue {
|
||||
public:
|
||||
explicit Queue(const size_t capacity, const Allocator& allocator = Allocator())
|
||||
: allocator_(allocator) {
|
||||
if (capacity < 1) {
|
||||
throw std::invalid_argument("capacity < 1");
|
||||
}
|
||||
// Ensure that the queue length is an integer power of 2
|
||||
// This is so that idx(i) can be a simple i & mask_ insted of i % capacity
|
||||
// https://github.com/rigtorp/MPMCQueue/pull/36
|
||||
if (!std::has_single_bit(capacity)) {
|
||||
throw std::invalid_argument("capacity must be an integer power of 2");
|
||||
}
|
||||
|
||||
mask_ = capacity - 1;
|
||||
|
||||
// Allocate one extra slot to prevent false sharing on the last slot
|
||||
slots_ = allocator_.allocate(mask_ + 2);
|
||||
// Allocators are not required to honor alignment for over-aligned types
|
||||
// (see http://eel.is/c++draft/allocator.requirements#10) so we verify
|
||||
// alignment here
|
||||
if (reinterpret_cast<uintptr_t>(slots_) % alignof(Slot<T>) != 0) {
|
||||
allocator_.deallocate(slots_, mask_ + 2);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
for (size_t i = 0; i < mask_ + 1; ++i) {
|
||||
std::construct_at(&slots_[i]);
|
||||
}
|
||||
static_assert(alignof(Slot<T>) == hardware_interference_size,
|
||||
"Slot must be aligned to cache line boundary to prevent false sharing");
|
||||
static_assert(sizeof(Slot<T>) % hardware_interference_size == 0,
|
||||
"Slot size must be a multiple of cache line size to prevent "
|
||||
"false sharing between adjacent slots");
|
||||
static_assert(sizeof(Queue) % hardware_interference_size == 0,
|
||||
"Queue size must be a multiple of cache line size to "
|
||||
"prevent false sharing between adjacent queues");
|
||||
}
|
||||
|
||||
~Queue() noexcept {
|
||||
for (size_t i = 0; i < mask_ + 1; ++i) {
|
||||
slots_[i].~Slot();
|
||||
}
|
||||
allocator_.deallocate(slots_, mask_ + 2);
|
||||
}
|
||||
|
||||
// non-copyable and non-movable
|
||||
Queue(const Queue&) = delete;
|
||||
Queue& operator=(const Queue&) = delete;
|
||||
|
||||
void Push(const T& v) noexcept {
|
||||
static_assert(std::is_nothrow_copy_constructible_v<T>,
|
||||
"T must be nothrow copy constructible");
|
||||
emplace(v);
|
||||
}
|
||||
|
||||
template <typename P, typename = std::enable_if_t<std::is_nothrow_constructible_v<T, P&&>>>
|
||||
void Push(P&& v) noexcept {
|
||||
emplace(std::forward<P>(v));
|
||||
}
|
||||
|
||||
void Pop(T& v, std::stop_token stop) noexcept {
|
||||
auto const tail = tail_.fetch_add(1);
|
||||
auto& slot = slots_[idx(tail)];
|
||||
if (false == slot.turn.test()) {
|
||||
std::unique_lock lock{cv_mutex};
|
||||
cv.wait(lock, stop, [&slot] { return slot.turn.test(); });
|
||||
}
|
||||
v = slot.move();
|
||||
slot.destroy();
|
||||
slot.turn.clear();
|
||||
slot.turn.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) noexcept {
|
||||
static_assert(std::is_nothrow_constructible_v<T, Args&&...>,
|
||||
"T must be nothrow constructible with Args&&...");
|
||||
auto const head = head_.fetch_add(1);
|
||||
auto& slot = slots_[idx(head)];
|
||||
slot.turn.wait(true);
|
||||
slot.construct(std::forward<Args>(args)...);
|
||||
slot.turn.test_and_set();
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
constexpr size_t idx(size_t i) const noexcept {
|
||||
return i & mask_;
|
||||
}
|
||||
|
||||
std::conditional_t<true, std::condition_variable_any, std::condition_variable> cv;
|
||||
std::mutex cv_mutex;
|
||||
size_t mask_;
|
||||
Slot<T>* slots_;
|
||||
[[no_unique_address]] Allocator allocator_;
|
||||
|
||||
// Align to avoid false sharing between head_ and tail_
|
||||
alignas(hardware_interference_size) std::atomic<size_t> head_{0};
|
||||
alignas(hardware_interference_size) std::atomic<size_t> tail_{0};
|
||||
|
||||
static_assert(std::is_nothrow_copy_assignable_v<T> || std::is_nothrow_move_assignable_v<T>,
|
||||
"T must be nothrow copy or move assignable");
|
||||
|
||||
static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible");
|
||||
};
|
||||
} // namespace mpsc
|
||||
|
||||
template <typename T, typename Allocator = mpsc::AlignedAllocator<mpsc::Slot<T>>>
|
||||
using MPSCQueue = mpsc::Queue<T, Allocator>;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -0,0 +1,333 @@
|
||||
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
|
||||
#include "common_types.h"
|
||||
|
||||
namespace Common {
|
||||
namespace ELF {
|
||||
|
||||
/* Type for a 16-bit quantity. */
|
||||
using Elf32_Half = u16;
|
||||
using Elf64_Half = u16;
|
||||
|
||||
/* Types for signed and unsigned 32-bit quantities. */
|
||||
using Elf32_Word = u32;
|
||||
using Elf32_Sword = s32;
|
||||
using Elf64_Word = u32;
|
||||
using Elf64_Sword = s32;
|
||||
|
||||
/* Types for signed and unsigned 64-bit quantities. */
|
||||
using Elf32_Xword = u64;
|
||||
using Elf32_Sxword = s64;
|
||||
using Elf64_Xword = u64;
|
||||
using Elf64_Sxword = s64;
|
||||
|
||||
/* Type of addresses. */
|
||||
using Elf32_Addr = u32;
|
||||
using Elf64_Addr = u64;
|
||||
|
||||
/* Type of file offsets. */
|
||||
using Elf32_Off = u32;
|
||||
using Elf64_Off = u64;
|
||||
|
||||
/* Type for section indices, which are 16-bit quantities. */
|
||||
using Elf32_Section = u16;
|
||||
using Elf64_Section = u16;
|
||||
|
||||
/* Type for version symbol information. */
|
||||
using Elf32_Versym = Elf32_Half;
|
||||
using Elf64_Versym = Elf64_Half;
|
||||
|
||||
constexpr size_t ElfIdentSize = 16;
|
||||
|
||||
/* The ELF file header. This appears at the start of every ELF file. */
|
||||
|
||||
struct Elf32_Ehdr {
|
||||
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
|
||||
Elf32_Half e_type; /* Object file type */
|
||||
Elf32_Half e_machine; /* Architecture */
|
||||
Elf32_Word e_version; /* Object file version */
|
||||
Elf32_Addr e_entry; /* Entry point virtual address */
|
||||
Elf32_Off e_phoff; /* Program header table file offset */
|
||||
Elf32_Off e_shoff; /* Section header table file offset */
|
||||
Elf32_Word e_flags; /* Processor-specific flags */
|
||||
Elf32_Half e_ehsize; /* ELF header size in bytes */
|
||||
Elf32_Half e_phentsize; /* Program header table entry size */
|
||||
Elf32_Half e_phnum; /* Program header table entry count */
|
||||
Elf32_Half e_shentsize; /* Section header table entry size */
|
||||
Elf32_Half e_shnum; /* Section header table entry count */
|
||||
Elf32_Half e_shstrndx; /* Section header string table index */
|
||||
};
|
||||
|
||||
struct Elf64_Ehdr {
|
||||
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
|
||||
Elf64_Half e_type; /* Object file type */
|
||||
Elf64_Half e_machine; /* Architecture */
|
||||
Elf64_Word e_version; /* Object file version */
|
||||
Elf64_Addr e_entry; /* Entry point virtual address */
|
||||
Elf64_Off e_phoff; /* Program header table file offset */
|
||||
Elf64_Off e_shoff; /* Section header table file offset */
|
||||
Elf64_Word e_flags; /* Processor-specific flags */
|
||||
Elf64_Half e_ehsize; /* ELF header size in bytes */
|
||||
Elf64_Half e_phentsize; /* Program header table entry size */
|
||||
Elf64_Half e_phnum; /* Program header table entry count */
|
||||
Elf64_Half e_shentsize; /* Section header table entry size */
|
||||
Elf64_Half e_shnum; /* Section header table entry count */
|
||||
Elf64_Half e_shstrndx; /* Section header string table index */
|
||||
};
|
||||
|
||||
constexpr u8 ElfClass32 = 1; /* 32-bit objects */
|
||||
constexpr u8 ElfClass64 = 2; /* 64-bit objects */
|
||||
constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */
|
||||
constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */
|
||||
constexpr u8 ElfOsAbiNone = 0; /* System V ABI */
|
||||
|
||||
constexpr u16 ElfTypeNone = 0; /* No file type */
|
||||
constexpr u16 ElfTypeRel = 0; /* Relocatable file */
|
||||
constexpr u16 ElfTypeExec = 0; /* Executable file */
|
||||
constexpr u16 ElfTypeDyn = 0; /* Shared object file */
|
||||
|
||||
constexpr u16 ElfMachineArm = 40; /* ARM */
|
||||
constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */
|
||||
|
||||
constexpr std::array<u8, ElfIdentSize> Elf32Ident{
|
||||
0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
|
||||
|
||||
constexpr std::array<u8, ElfIdentSize> Elf64Ident{
|
||||
0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
|
||||
|
||||
/* Section header. */
|
||||
|
||||
struct Elf32_Shdr {
|
||||
Elf32_Word sh_name; /* Section name (string tbl index) */
|
||||
Elf32_Word sh_type; /* Section type */
|
||||
Elf32_Word sh_flags; /* Section flags */
|
||||
Elf32_Addr sh_addr; /* Section virtual addr at execution */
|
||||
Elf32_Off sh_offset; /* Section file offset */
|
||||
Elf32_Word sh_size; /* Section size in bytes */
|
||||
Elf32_Word sh_link; /* Link to another section */
|
||||
Elf32_Word sh_info; /* Additional section information */
|
||||
Elf32_Word sh_addralign; /* Section alignment */
|
||||
Elf32_Word sh_entsize; /* Entry size if section holds table */
|
||||
};
|
||||
|
||||
struct Elf64_Shdr {
|
||||
Elf64_Word sh_name; /* Section name (string tbl index) */
|
||||
Elf64_Word sh_type; /* Section type */
|
||||
Elf64_Xword sh_flags; /* Section flags */
|
||||
Elf64_Addr sh_addr; /* Section virtual addr at execution */
|
||||
Elf64_Off sh_offset; /* Section file offset */
|
||||
Elf64_Xword sh_size; /* Section size in bytes */
|
||||
Elf64_Word sh_link; /* Link to another section */
|
||||
Elf64_Word sh_info; /* Additional section information */
|
||||
Elf64_Xword sh_addralign; /* Section alignment */
|
||||
Elf64_Xword sh_entsize; /* Entry size if section holds table */
|
||||
};
|
||||
|
||||
constexpr u32 ElfShnUndef = 0; /* Undefined section */
|
||||
|
||||
constexpr u32 ElfShtNull = 0; /* Section header table entry unused */
|
||||
constexpr u32 ElfShtProgBits = 1; /* Program data */
|
||||
constexpr u32 ElfShtSymtab = 2; /* Symbol table */
|
||||
constexpr u32 ElfShtStrtab = 3; /* String table */
|
||||
constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */
|
||||
constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */
|
||||
constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */
|
||||
constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */
|
||||
constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */
|
||||
|
||||
/* Symbol table entry. */
|
||||
|
||||
struct Elf32_Sym {
|
||||
Elf32_Word st_name; /* Symbol name (string tbl index) */
|
||||
Elf32_Addr st_value; /* Symbol value */
|
||||
Elf32_Word st_size; /* Symbol size */
|
||||
u8 st_info; /* Symbol type and binding */
|
||||
u8 st_other; /* Symbol visibility */
|
||||
Elf32_Section st_shndx; /* Section index */
|
||||
};
|
||||
|
||||
struct Elf64_Sym {
|
||||
Elf64_Word st_name; /* Symbol name (string tbl index) */
|
||||
u8 st_info; /* Symbol type and binding */
|
||||
u8 st_other; /* Symbol visibility */
|
||||
Elf64_Section st_shndx; /* Section index */
|
||||
Elf64_Addr st_value; /* Symbol value */
|
||||
Elf64_Xword st_size; /* Symbol size */
|
||||
};
|
||||
|
||||
/* How to extract and insert information held in the st_info field. */
|
||||
|
||||
static inline u8 ElfStBind(u8 st_info) {
|
||||
return st_info >> 4;
|
||||
}
|
||||
static inline u8 ElfStType(u8 st_info) {
|
||||
return st_info & 0xf;
|
||||
}
|
||||
static inline u8 ElfStInfo(u8 st_bind, u8 st_type) {
|
||||
return static_cast<u8>((st_bind << 4) + (st_type & 0xf));
|
||||
}
|
||||
|
||||
constexpr u8 ElfBindLocal = 0; /* Local symbol */
|
||||
constexpr u8 ElfBindGlobal = 1; /* Global symbol */
|
||||
constexpr u8 ElfBindWeak = 2; /* Weak symbol */
|
||||
|
||||
constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */
|
||||
constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */
|
||||
constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */
|
||||
|
||||
static inline u8 ElfStVisibility(u8 st_other) {
|
||||
return static_cast<u8>(st_other & 0x3);
|
||||
}
|
||||
|
||||
constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */
|
||||
constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */
|
||||
constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */
|
||||
constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */
|
||||
|
||||
/* Relocation table entry without addend (in section of type ShtRel). */
|
||||
|
||||
struct Elf32_Rel {
|
||||
Elf32_Addr r_offset; /* Address */
|
||||
Elf32_Word r_info; /* Relocation type and symbol index */
|
||||
};
|
||||
|
||||
/* Relocation table entry with addend (in section of type ShtRela). */
|
||||
|
||||
struct Elf32_Rela {
|
||||
Elf32_Addr r_offset; /* Address */
|
||||
Elf32_Word r_info; /* Relocation type and symbol index */
|
||||
Elf32_Sword r_addend; /* Addend */
|
||||
};
|
||||
|
||||
struct Elf64_Rela {
|
||||
Elf64_Addr r_offset; /* Address */
|
||||
Elf64_Xword r_info; /* Relocation type and symbol index */
|
||||
Elf64_Sxword r_addend; /* Addend */
|
||||
};
|
||||
|
||||
/* How to extract and insert information held in the r_info field. */
|
||||
|
||||
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
|
||||
return r_info >> 8;
|
||||
}
|
||||
static inline u8 Elf32RelType(Elf32_Word r_info) {
|
||||
return static_cast<u8>(r_info & 0xff);
|
||||
}
|
||||
static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) {
|
||||
return (sym_index << 8) + type;
|
||||
}
|
||||
static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) {
|
||||
return static_cast<u32>(r_info >> 32);
|
||||
}
|
||||
static inline u32 Elf64RelType(Elf64_Xword r_info) {
|
||||
return r_info & 0xffffffff;
|
||||
}
|
||||
static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) {
|
||||
return (static_cast<Elf64_Xword>(sym_index) << 32) + type;
|
||||
}
|
||||
|
||||
constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */
|
||||
constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */
|
||||
constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */
|
||||
constexpr u32 ElfArmRelative = 23; /* Adjust by program base */
|
||||
|
||||
constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */
|
||||
constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */
|
||||
constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */
|
||||
constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */
|
||||
|
||||
/* Program segment header. */
|
||||
|
||||
struct Elf32_Phdr {
|
||||
Elf32_Word p_type; /* Segment type */
|
||||
Elf32_Off p_offset; /* Segment file offset */
|
||||
Elf32_Addr p_vaddr; /* Segment virtual address */
|
||||
Elf32_Addr p_paddr; /* Segment physical address */
|
||||
Elf32_Word p_filesz; /* Segment size in file */
|
||||
Elf32_Word p_memsz; /* Segment size in memory */
|
||||
Elf32_Word p_flags; /* Segment flags */
|
||||
Elf32_Word p_align; /* Segment alignment */
|
||||
};
|
||||
|
||||
struct Elf64_Phdr {
|
||||
Elf64_Word p_type; /* Segment type */
|
||||
Elf64_Word p_flags; /* Segment flags */
|
||||
Elf64_Off p_offset; /* Segment file offset */
|
||||
Elf64_Addr p_vaddr; /* Segment virtual address */
|
||||
Elf64_Addr p_paddr; /* Segment physical address */
|
||||
Elf64_Xword p_filesz; /* Segment size in file */
|
||||
Elf64_Xword p_memsz; /* Segment size in memory */
|
||||
Elf64_Xword p_align; /* Segment alignment */
|
||||
};
|
||||
|
||||
/* Legal values for p_type (segment type). */
|
||||
|
||||
constexpr u32 ElfPtNull = 0; /* Program header table entry unused */
|
||||
constexpr u32 ElfPtLoad = 1; /* Loadable program segment */
|
||||
constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */
|
||||
constexpr u32 ElfPtInterp = 3; /* Program interpreter */
|
||||
constexpr u32 ElfPtNote = 4; /* Auxiliary information */
|
||||
constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */
|
||||
constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */
|
||||
|
||||
/* Legal values for p_flags (segment flags). */
|
||||
|
||||
constexpr u32 ElfPfExec = 0; /* Segment is executable */
|
||||
constexpr u32 ElfPfWrite = 1; /* Segment is writable */
|
||||
constexpr u32 ElfPfRead = 2; /* Segment is readable */
|
||||
|
||||
/* Dynamic section entry. */
|
||||
|
||||
struct Elf32_Dyn {
|
||||
Elf32_Sword d_tag; /* Dynamic entry type */
|
||||
union {
|
||||
Elf32_Word d_val; /* Integer value */
|
||||
Elf32_Addr d_ptr; /* Address value */
|
||||
} d_un;
|
||||
};
|
||||
|
||||
struct Elf64_Dyn {
|
||||
Elf64_Sxword d_tag; /* Dynamic entry type */
|
||||
union {
|
||||
Elf64_Xword d_val; /* Integer value */
|
||||
Elf64_Addr d_ptr; /* Address value */
|
||||
} d_un;
|
||||
};
|
||||
|
||||
/* Legal values for d_tag (dynamic entry type). */
|
||||
|
||||
constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */
|
||||
constexpr u32 ElfDtNeeded = 1; /* Name of needed library */
|
||||
constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */
|
||||
constexpr u32 ElfDtPltGot = 3; /* Processor defined value */
|
||||
constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */
|
||||
constexpr u32 ElfDtStrtab = 5; /* Address of string table */
|
||||
constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */
|
||||
constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */
|
||||
constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */
|
||||
constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */
|
||||
constexpr u32 ElfDtStrsz = 10; /* Size of string table */
|
||||
constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */
|
||||
constexpr u32 ElfDtInit = 12; /* Address of init function */
|
||||
constexpr u32 ElfDtFini = 13; /* Address of termination function */
|
||||
constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */
|
||||
constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */
|
||||
constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */
|
||||
constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */
|
||||
constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */
|
||||
constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */
|
||||
constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */
|
||||
constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */
|
||||
constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
|
||||
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
|
||||
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
|
||||
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
|
||||
|
||||
} // namespace ELF
|
||||
} // namespace Common
|
||||
@@ -147,7 +147,7 @@ void UpdateRescalingInfo() {
|
||||
info.down_shift = 0;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
info.up_scale = 1;
|
||||
info.down_shift = 0;
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ struct Values {
|
||||
|
||||
// Renderer
|
||||
RangedSetting<RendererBackend> renderer_backend{
|
||||
RendererBackend::OpenGL, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
|
||||
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
|
||||
BasicSetting<bool> renderer_debug{false, "debug"};
|
||||
BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"};
|
||||
BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
|
||||
|
||||
+13
-72
@@ -3,73 +3,14 @@
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/elf.h"
|
||||
#include "core/arm/symbols.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
using namespace Common::ELF;
|
||||
|
||||
namespace Core {
|
||||
namespace {
|
||||
|
||||
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
|
||||
constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
|
||||
constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
|
||||
constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
|
||||
|
||||
enum class ELFSymbolType : u8 {
|
||||
None = 0,
|
||||
Object = 1,
|
||||
Function = 2,
|
||||
Section = 3,
|
||||
File = 4,
|
||||
Common = 5,
|
||||
TLS = 6,
|
||||
};
|
||||
|
||||
enum class ELFSymbolBinding : u8 {
|
||||
Local = 0,
|
||||
Global = 1,
|
||||
Weak = 2,
|
||||
};
|
||||
|
||||
enum class ELFSymbolVisibility : u8 {
|
||||
Default = 0,
|
||||
Internal = 1,
|
||||
Hidden = 2,
|
||||
Protected = 3,
|
||||
};
|
||||
|
||||
struct ELF64Symbol {
|
||||
u32 name_index;
|
||||
union {
|
||||
u8 info;
|
||||
|
||||
BitField<0, 4, ELFSymbolType> type;
|
||||
BitField<4, 4, ELFSymbolBinding> binding;
|
||||
};
|
||||
ELFSymbolVisibility visibility;
|
||||
u16 sh_index;
|
||||
u64 value;
|
||||
u64 size;
|
||||
};
|
||||
static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size.");
|
||||
|
||||
struct ELF32Symbol {
|
||||
u32 name_index;
|
||||
u32 value;
|
||||
u32 size;
|
||||
union {
|
||||
u8 info;
|
||||
|
||||
BitField<0, 4, ELFSymbolType> type;
|
||||
BitField<4, 4, ELFSymbolBinding> binding;
|
||||
};
|
||||
ELFSymbolVisibility visibility;
|
||||
u16 sh_index;
|
||||
};
|
||||
static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size.");
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
namespace Symbols {
|
||||
|
||||
template <typename Word, typename ELFSymbol, typename ByteReader>
|
||||
@@ -110,15 +51,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
|
||||
const Word value = ReadWord(dynamic_index + sizeof(Word));
|
||||
dynamic_index += 2 * sizeof(Word);
|
||||
|
||||
if (tag == ELF_DYNAMIC_TAG_NULL) {
|
||||
if (tag == ElfDtNull) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag == ELF_DYNAMIC_TAG_STRTAB) {
|
||||
if (tag == ElfDtStrtab) {
|
||||
string_table_offset = value;
|
||||
} else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
|
||||
} else if (tag == ElfDtSymtab) {
|
||||
symbol_table_offset = value;
|
||||
} else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
|
||||
} else if (tag == ElfDtSyment) {
|
||||
symbol_entry_size = value;
|
||||
}
|
||||
}
|
||||
@@ -134,14 +75,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
|
||||
ELFSymbol symbol{};
|
||||
ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
|
||||
|
||||
VAddr string_offset = string_table_offset + symbol.name_index;
|
||||
VAddr string_offset = string_table_offset + symbol.st_name;
|
||||
std::string name;
|
||||
for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
|
||||
name += static_cast<char>(c);
|
||||
}
|
||||
|
||||
symbol_index += symbol_entry_size;
|
||||
out[name] = std::make_pair(symbol.value, symbol.size);
|
||||
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -152,9 +93,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
|
||||
[&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
|
||||
|
||||
if (is_64) {
|
||||
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
|
||||
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
|
||||
} else {
|
||||
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
|
||||
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,9 +105,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) {
|
||||
}};
|
||||
|
||||
if (is_64) {
|
||||
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
|
||||
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
|
||||
} else {
|
||||
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
|
||||
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -493,6 +493,12 @@ void System::Shutdown() {
|
||||
impl->Shutdown();
|
||||
}
|
||||
|
||||
void System::DetachDebugger() {
|
||||
if (impl->debugger) {
|
||||
impl->debugger->NotifyShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> System::StallCPU() {
|
||||
return impl->StallCPU();
|
||||
}
|
||||
|
||||
@@ -160,6 +160,9 @@ public:
|
||||
/// Shutdown the emulated system.
|
||||
void Shutdown();
|
||||
|
||||
/// Forcibly detach the debugger if it is running.
|
||||
void DetachDebugger();
|
||||
|
||||
std::unique_lock<std::mutex> StallCPU();
|
||||
void UnstallCPU();
|
||||
|
||||
|
||||
+32
-84
@@ -16,7 +16,8 @@
|
||||
|
||||
namespace Core {
|
||||
|
||||
CpuManager::CpuManager(System& system_) : system{system_} {}
|
||||
CpuManager::CpuManager(System& system_)
|
||||
: pause_barrier{std::make_unique<Common::Barrier>(1)}, system{system_} {}
|
||||
CpuManager::~CpuManager() = default;
|
||||
|
||||
void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
|
||||
@@ -30,8 +31,10 @@ void CpuManager::Initialize() {
|
||||
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||
core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
|
||||
}
|
||||
pause_barrier = std::make_unique<Common::Barrier>(Core::Hardware::NUM_CPU_CORES + 1);
|
||||
} else {
|
||||
core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0);
|
||||
pause_barrier = std::make_unique<Common::Barrier>(2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,51 +141,14 @@ void CpuManager::MultiCoreRunSuspendThread() {
|
||||
auto core = kernel.CurrentPhysicalCoreIndex();
|
||||
auto& scheduler = *kernel.CurrentScheduler();
|
||||
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
|
||||
current_thread->DisableDispatch();
|
||||
|
||||
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
|
||||
ASSERT(scheduler.ContextSwitchPending());
|
||||
ASSERT(core == kernel.CurrentPhysicalCoreIndex());
|
||||
scheduler.RescheduleCurrentCore();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::MultiCorePause(bool paused) {
|
||||
if (!paused) {
|
||||
bool all_not_barrier = false;
|
||||
while (!all_not_barrier) {
|
||||
all_not_barrier = true;
|
||||
for (const auto& data : core_data) {
|
||||
all_not_barrier &= !data.is_running.load() && data.initialized.load();
|
||||
}
|
||||
}
|
||||
for (auto& data : core_data) {
|
||||
data.enter_barrier->Set();
|
||||
}
|
||||
if (paused_state.load()) {
|
||||
bool all_barrier = false;
|
||||
while (!all_barrier) {
|
||||
all_barrier = true;
|
||||
for (const auto& data : core_data) {
|
||||
all_barrier &= data.is_paused.load() && data.initialized.load();
|
||||
}
|
||||
}
|
||||
for (auto& data : core_data) {
|
||||
data.exit_barrier->Set();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/// Wait until all cores are paused.
|
||||
bool all_barrier = false;
|
||||
while (!all_barrier) {
|
||||
all_barrier = true;
|
||||
for (const auto& data : core_data) {
|
||||
all_barrier &= data.is_paused.load() && data.initialized.load();
|
||||
}
|
||||
}
|
||||
/// Don't release the barrier
|
||||
}
|
||||
paused_state = paused;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// SingleCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -235,8 +201,9 @@ void CpuManager::SingleCoreRunSuspendThread() {
|
||||
auto core = kernel.GetCurrentHostThreadID();
|
||||
auto& scheduler = *kernel.CurrentScheduler();
|
||||
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
|
||||
current_thread->DisableDispatch();
|
||||
|
||||
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context);
|
||||
ASSERT(scheduler.ContextSwitchPending());
|
||||
ASSERT(core == kernel.GetCurrentHostThreadID());
|
||||
scheduler.RescheduleCurrentCore();
|
||||
}
|
||||
@@ -274,37 +241,21 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::SingleCorePause(bool paused) {
|
||||
if (!paused) {
|
||||
bool all_not_barrier = false;
|
||||
while (!all_not_barrier) {
|
||||
all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load();
|
||||
}
|
||||
core_data[0].enter_barrier->Set();
|
||||
if (paused_state.load()) {
|
||||
bool all_barrier = false;
|
||||
while (!all_barrier) {
|
||||
all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
|
||||
}
|
||||
core_data[0].exit_barrier->Set();
|
||||
}
|
||||
} else {
|
||||
/// Wait until all cores are paused.
|
||||
bool all_barrier = false;
|
||||
while (!all_barrier) {
|
||||
all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
|
||||
}
|
||||
/// Don't release the barrier
|
||||
}
|
||||
paused_state = paused;
|
||||
}
|
||||
|
||||
void CpuManager::Pause(bool paused) {
|
||||
if (is_multicore) {
|
||||
MultiCorePause(paused);
|
||||
} else {
|
||||
SingleCorePause(paused);
|
||||
std::scoped_lock lk{pause_lock};
|
||||
|
||||
if (pause_state == paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the new state
|
||||
pause_state.store(paused);
|
||||
|
||||
// Wake up any waiting threads
|
||||
pause_state.notify_all();
|
||||
|
||||
// Wait for all threads to successfully change state before returning
|
||||
pause_barrier->Sync();
|
||||
}
|
||||
|
||||
void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
|
||||
@@ -320,27 +271,29 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
|
||||
Common::SetCurrentThreadName(name.c_str());
|
||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
|
||||
auto& data = core_data[core];
|
||||
data.enter_barrier = std::make_unique<Common::Event>();
|
||||
data.exit_barrier = std::make_unique<Common::Event>();
|
||||
data.host_context = Common::Fiber::ThreadToFiber();
|
||||
data.is_running = false;
|
||||
data.initialized = true;
|
||||
const bool sc_sync = !is_async_gpu && !is_multicore;
|
||||
bool sc_sync_first_use = sc_sync;
|
||||
|
||||
// Cleanup
|
||||
SCOPE_EXIT({
|
||||
data.host_context->Exit();
|
||||
data.enter_barrier.reset();
|
||||
data.exit_barrier.reset();
|
||||
data.initialized = false;
|
||||
MicroProfileOnThreadExit();
|
||||
});
|
||||
|
||||
/// Running
|
||||
while (running_mode) {
|
||||
data.is_running = false;
|
||||
data.enter_barrier->Wait();
|
||||
if (pause_state.load(std::memory_order_relaxed)) {
|
||||
// Wait for caller to acknowledge pausing
|
||||
pause_barrier->Sync();
|
||||
|
||||
// Wait until unpaused
|
||||
pause_state.wait(true, std::memory_order_relaxed);
|
||||
|
||||
// Wait for caller to acknowledge unpausing
|
||||
pause_barrier->Sync();
|
||||
}
|
||||
|
||||
if (sc_sync_first_use) {
|
||||
system.GPU().ObtainContext();
|
||||
sc_sync_first_use = false;
|
||||
@@ -352,12 +305,7 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
|
||||
}
|
||||
|
||||
auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
||||
data.is_running = true;
|
||||
Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
|
||||
data.is_running = false;
|
||||
data.is_paused = true;
|
||||
data.exit_barrier->Wait();
|
||||
data.is_paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,13 +69,11 @@ private:
|
||||
void MultiCoreRunGuestLoop();
|
||||
void MultiCoreRunIdleThread();
|
||||
void MultiCoreRunSuspendThread();
|
||||
void MultiCorePause(bool paused);
|
||||
|
||||
void SingleCoreRunGuestThread();
|
||||
void SingleCoreRunGuestLoop();
|
||||
void SingleCoreRunIdleThread();
|
||||
void SingleCoreRunSuspendThread();
|
||||
void SingleCorePause(bool paused);
|
||||
|
||||
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
|
||||
|
||||
@@ -83,16 +81,13 @@ private:
|
||||
|
||||
struct CoreData {
|
||||
std::shared_ptr<Common::Fiber> host_context;
|
||||
std::unique_ptr<Common::Event> enter_barrier;
|
||||
std::unique_ptr<Common::Event> exit_barrier;
|
||||
std::atomic<bool> is_running;
|
||||
std::atomic<bool> is_paused;
|
||||
std::atomic<bool> initialized;
|
||||
std::jthread host_thread;
|
||||
};
|
||||
|
||||
std::atomic<bool> running_mode{};
|
||||
std::atomic<bool> paused_state{};
|
||||
std::atomic<bool> pause_state{};
|
||||
std::unique_ptr<Common::Barrier> pause_barrier{};
|
||||
std::mutex pause_lock{};
|
||||
|
||||
std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
|
||||
|
||||
|
||||
@@ -140,7 +140,6 @@ u64 GetSignatureTypeDataSize(SignatureType type) {
|
||||
return 0x3C;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 GetSignatureTypePaddingSize(SignatureType type) {
|
||||
@@ -155,7 +154,6 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
|
||||
return 0x40;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SignatureType Ticket::GetSignatureType() const {
|
||||
|
||||
@@ -20,15 +20,16 @@ template <typename Readable, typename Buffer, typename Callback>
|
||||
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
|
||||
static_assert(std::is_trivial_v<Buffer>);
|
||||
auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
|
||||
r.async_read_some(boost_buffer, [&](const boost::system::error_code& error, size_t bytes_read) {
|
||||
if (!error.failed()) {
|
||||
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
|
||||
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
|
||||
c(received_data);
|
||||
}
|
||||
r.async_read_some(
|
||||
boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) {
|
||||
if (!error.failed()) {
|
||||
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
|
||||
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
|
||||
c(received_data);
|
||||
}
|
||||
|
||||
AsyncReceiveInto(r, buffer, c);
|
||||
});
|
||||
AsyncReceiveInto(r, buffer, c);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Readable, typename Buffer>
|
||||
@@ -41,6 +42,16 @@ static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) {
|
||||
return received_data;
|
||||
}
|
||||
|
||||
enum class SignalType {
|
||||
Stopped,
|
||||
ShuttingDown,
|
||||
};
|
||||
|
||||
struct SignalInfo {
|
||||
SignalType type;
|
||||
Kernel::KThread* thread;
|
||||
};
|
||||
|
||||
namespace Core {
|
||||
|
||||
class DebuggerImpl : public DebuggerBackend {
|
||||
@@ -55,7 +66,7 @@ public:
|
||||
ShutdownServer();
|
||||
}
|
||||
|
||||
bool NotifyThreadStopped(Kernel::KThread* thread) {
|
||||
bool SignalDebugger(SignalInfo signal_info) {
|
||||
std::scoped_lock lk{connection_lock};
|
||||
|
||||
if (stopped) {
|
||||
@@ -63,9 +74,13 @@ public:
|
||||
// It should be ignored.
|
||||
return false;
|
||||
}
|
||||
stopped = true;
|
||||
|
||||
signal_pipe.write_some(boost::asio::buffer(&thread, sizeof(thread)));
|
||||
// Set up the state.
|
||||
stopped = true;
|
||||
info = signal_info;
|
||||
|
||||
// Write a single byte into the pipe to wake up the debug interface.
|
||||
boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped)));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -74,7 +89,7 @@ public:
|
||||
}
|
||||
|
||||
void WriteToClient(std::span<const u8> data) override {
|
||||
client_socket.write_some(boost::asio::buffer(data.data(), data.size_bytes()));
|
||||
boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes()));
|
||||
}
|
||||
|
||||
void SetActiveThread(Kernel::KThread* thread) override {
|
||||
@@ -95,7 +110,7 @@ private:
|
||||
connection_thread = std::jthread([&, port](std::stop_token stop_token) {
|
||||
try {
|
||||
// Initialize the listening socket and accept a new client.
|
||||
tcp::endpoint endpoint{boost::asio::ip::address_v4::loopback(), port};
|
||||
tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port};
|
||||
tcp::acceptor acceptor{io_context, endpoint};
|
||||
|
||||
acceptor.async_accept(client_socket, [](const auto&) {});
|
||||
@@ -123,7 +138,7 @@ private:
|
||||
Common::SetCurrentThreadName("yuzu:Debugger");
|
||||
|
||||
// Set up the client signals for new data.
|
||||
AsyncReceiveInto(signal_pipe, active_thread, [&](auto d) { PipeData(d); });
|
||||
AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); });
|
||||
AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); });
|
||||
|
||||
// Stop the emulated CPU.
|
||||
@@ -141,9 +156,28 @@ private:
|
||||
}
|
||||
|
||||
void PipeData(std::span<const u8> data) {
|
||||
AllCoreStop();
|
||||
UpdateActiveThread();
|
||||
frontend->Stopped(active_thread);
|
||||
switch (info.type) {
|
||||
case SignalType::Stopped:
|
||||
// Stop emulation.
|
||||
AllCoreStop();
|
||||
|
||||
// Notify the client.
|
||||
active_thread = info.thread;
|
||||
UpdateActiveThread();
|
||||
frontend->Stopped(active_thread);
|
||||
|
||||
break;
|
||||
case SignalType::ShuttingDown:
|
||||
frontend->ShuttingDown();
|
||||
|
||||
// Wait for emulation to shut down gracefully now.
|
||||
suspend.reset();
|
||||
signal_pipe.close();
|
||||
client_socket.shutdown(boost::asio::socket_base::shutdown_both);
|
||||
LOG_INFO(Debug_GDBStub, "Shut down server");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientData(std::span<const u8> data) {
|
||||
@@ -245,7 +279,9 @@ private:
|
||||
boost::asio::ip::tcp::socket client_socket;
|
||||
std::optional<std::unique_lock<std::mutex>> suspend;
|
||||
|
||||
SignalInfo info;
|
||||
Kernel::KThread* active_thread;
|
||||
bool pipe_data;
|
||||
bool stopped;
|
||||
|
||||
std::array<u8, 4096> client_data;
|
||||
@@ -262,7 +298,13 @@ Debugger::Debugger(Core::System& system, u16 port) {
|
||||
Debugger::~Debugger() = default;
|
||||
|
||||
bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
|
||||
return impl && impl->NotifyThreadStopped(thread);
|
||||
return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread});
|
||||
}
|
||||
|
||||
void Debugger::NotifyShutdown() {
|
||||
if (impl) {
|
||||
impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -35,6 +35,11 @@ public:
|
||||
*/
|
||||
bool NotifyThreadStopped(Kernel::KThread* thread);
|
||||
|
||||
/**
|
||||
* Notify the debugger that a shutdown is being performed now and disconnect.
|
||||
*/
|
||||
void NotifyShutdown();
|
||||
|
||||
private:
|
||||
std::unique_ptr<DebuggerImpl> impl;
|
||||
};
|
||||
|
||||
@@ -66,6 +66,11 @@ public:
|
||||
*/
|
||||
virtual void Stopped(Kernel::KThread* thread) = 0;
|
||||
|
||||
/**
|
||||
* Called when emulation is shutting down.
|
||||
*/
|
||||
virtual void ShuttingDown() = 0;
|
||||
|
||||
/**
|
||||
* Called when new data is asynchronously received on the client socket.
|
||||
* A list of actions to perform is returned.
|
||||
|
||||
@@ -106,6 +106,8 @@ GDBStub::~GDBStub() = default;
|
||||
|
||||
void GDBStub::Connected() {}
|
||||
|
||||
void GDBStub::ShuttingDown() {}
|
||||
|
||||
void GDBStub::Stopped(Kernel::KThread* thread) {
|
||||
SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP));
|
||||
}
|
||||
@@ -422,6 +424,18 @@ static std::string GetThreadState(const Kernel::KThread* thread) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string PaginateBuffer(std::string_view buffer, std::string_view request) {
|
||||
const auto amount{request.substr(request.find(',') + 1)};
|
||||
const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))};
|
||||
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
|
||||
|
||||
if (offset_val + amount_val > buffer.size()) {
|
||||
return fmt::format("l{}", buffer.substr(offset_val));
|
||||
} else {
|
||||
return fmt::format("m{}", buffer.substr(offset_val, amount_val));
|
||||
}
|
||||
}
|
||||
|
||||
void GDBStub::HandleQuery(std::string_view command) {
|
||||
if (command.starts_with("TStatus")) {
|
||||
// no tracepoint support
|
||||
@@ -430,18 +444,8 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||
SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;"
|
||||
"vContSupported+;QStartNoAckMode+");
|
||||
} else if (command.starts_with("Xfer:features:read:target.xml:")) {
|
||||
const auto offset{command.substr(30)};
|
||||
const auto amount{command.substr(command.find(',') + 1)};
|
||||
|
||||
const auto offset_val{static_cast<u64>(strtoll(offset.data(), nullptr, 16))};
|
||||
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
|
||||
const auto target_xml{arch->GetTargetXML()};
|
||||
|
||||
if (offset_val + amount_val > target_xml.size()) {
|
||||
SendReply("l" + target_xml.substr(offset_val));
|
||||
} else {
|
||||
SendReply("m" + target_xml.substr(offset_val, amount_val));
|
||||
}
|
||||
SendReply(PaginateBuffer(target_xml, command.substr(30)));
|
||||
} else if (command.starts_with("Offsets")) {
|
||||
Loader::AppLoader::Modules modules;
|
||||
system.GetAppLoader().ReadNSOModules(modules);
|
||||
@@ -454,6 +458,20 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||
SendReply(fmt::format("TextSeg={:x}",
|
||||
system.CurrentProcess()->PageTable().GetCodeRegionStart()));
|
||||
}
|
||||
} else if (command.starts_with("Xfer:libraries:read::")) {
|
||||
Loader::AppLoader::Modules modules;
|
||||
system.GetAppLoader().ReadNSOModules(modules);
|
||||
|
||||
std::string buffer;
|
||||
buffer += R"(<?xml version="1.0"?>)";
|
||||
buffer += "<library-list>";
|
||||
for (const auto& [base, name] : modules) {
|
||||
buffer += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)",
|
||||
EscapeXML(name), base);
|
||||
}
|
||||
buffer += "</library-list>";
|
||||
|
||||
SendReply(PaginateBuffer(buffer, command.substr(21)));
|
||||
} else if (command.starts_with("fThreadInfo")) {
|
||||
// beginning of list
|
||||
const auto& threads = system.GlobalSchedulerContext().GetThreadList();
|
||||
@@ -484,17 +502,7 @@ void GDBStub::HandleQuery(std::string_view command) {
|
||||
|
||||
buffer += "</threads>";
|
||||
|
||||
const auto offset{command.substr(19)};
|
||||
const auto amount{command.substr(command.find(',') + 1)};
|
||||
|
||||
const auto offset_val{static_cast<u64>(strtoll(offset.data(), nullptr, 16))};
|
||||
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
|
||||
|
||||
if (offset_val + amount_val > buffer.size()) {
|
||||
SendReply("l" + buffer.substr(offset_val));
|
||||
} else {
|
||||
SendReply("m" + buffer.substr(offset_val, amount_val));
|
||||
}
|
||||
SendReply(PaginateBuffer(buffer, command.substr(19)));
|
||||
} else if (command.starts_with("Attached")) {
|
||||
SendReply("0");
|
||||
} else if (command.starts_with("StartNoAckMode")) {
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
|
||||
void Connected() override;
|
||||
void Stopped(Kernel::KThread* thread) override;
|
||||
void ShuttingDown() override;
|
||||
std::vector<DebuggerAction> ClientData(std::span<const u8> data) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Core {
|
||||
|
||||
class GDBStubArch {
|
||||
public:
|
||||
virtual ~GDBStubArch() = default;
|
||||
virtual std::string GetTargetXML() const = 0;
|
||||
virtual std::string RegRead(const Kernel::KThread* thread, size_t id) const = 0;
|
||||
virtual void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const = 0;
|
||||
|
||||
@@ -419,7 +419,7 @@ std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type
|
||||
Core::Crypto::Mode::ECB);
|
||||
cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt);
|
||||
|
||||
Core::Crypto::Key128 out;
|
||||
Core::Crypto::Key128 out{};
|
||||
if (type == NCASectionCryptoType::XTS) {
|
||||
std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
|
||||
} else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) {
|
||||
|
||||
@@ -50,7 +50,7 @@ std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockTyp
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
UNREACHABLE_MSG("Offset could not be found in BKTR block.");
|
||||
ASSERT_MSG(false, "Offset could not be found in BKTR block.");
|
||||
return {0, 0};
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -108,7 +108,7 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
|
||||
// TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
|
||||
return ContentRecordType::HtmlDocument;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid NCAContentType={:02X}", type);
|
||||
ASSERT_MSG(false, "Invalid NCAContentType={:02X}", type);
|
||||
return ContentRecordType{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
|
||||
LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path);
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
|
||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
|
||||
controller->Connect(true);
|
||||
} else {
|
||||
UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
|
||||
ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type) {
|
||||
return handheld.get();
|
||||
case NpadIdType::Invalid:
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type);
|
||||
ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type
|
||||
return handheld.get();
|
||||
case NpadIdType::Invalid:
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid NpadIdType={}", npad_id_type);
|
||||
ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
if (index < DomainHandlerCount()) {
|
||||
domain_handlers[index] = nullptr;
|
||||
} else {
|
||||
UNREACHABLE_MSG("Unexpected handler index {}", index);
|
||||
ASSERT_MSG(false, "Unexpected handler index {}", index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
|
||||
FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP)
|
||||
// If we somehow get an invalid type, abort.
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown slab type: {}", slab_types[i]);
|
||||
ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]);
|
||||
}
|
||||
|
||||
// If we've hit the end of a gap, free it.
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual:
|
||||
return SignalAndModifyByWaitingCountIfEqual(addr, value, count);
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
case Svc::ArbitrationType::WaitIfEqual:
|
||||
return WaitIfEqual(addr, value, timeout);
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return ResultUnknown;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
|
||||
ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index]));
|
||||
return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type)
|
||||
ASSERT(IsAllowed39BitType(type));
|
||||
return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Kernel {
|
||||
class KernelCore;
|
||||
class KProcess;
|
||||
|
||||
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
|
||||
#define KERNEL_AUTOOBJECT_TRAITS_IMPL(CLASS, BASE_CLASS, ATTRIBUTE) \
|
||||
\
|
||||
private: \
|
||||
friend class ::Kernel::KClassTokenGenerator; \
|
||||
@@ -40,16 +40,19 @@ public:
|
||||
static constexpr const char* GetStaticTypeName() { \
|
||||
return TypeName; \
|
||||
} \
|
||||
virtual TypeObj GetTypeObj() const { \
|
||||
virtual TypeObj GetTypeObj() ATTRIBUTE { \
|
||||
return GetStaticTypeObj(); \
|
||||
} \
|
||||
virtual const char* GetTypeName() const { \
|
||||
virtual const char* GetTypeName() ATTRIBUTE { \
|
||||
return GetStaticTypeName(); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
constexpr bool operator!=(const TypeObj& rhs)
|
||||
|
||||
#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
|
||||
KERNEL_AUTOOBJECT_TRAITS_IMPL(CLASS, BASE_CLASS, const override)
|
||||
|
||||
class KAutoObject {
|
||||
protected:
|
||||
class TypeObj {
|
||||
@@ -82,7 +85,7 @@ protected:
|
||||
};
|
||||
|
||||
private:
|
||||
KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
|
||||
KERNEL_AUTOOBJECT_TRAITS_IMPL(KAutoObject, KAutoObject, const);
|
||||
|
||||
public:
|
||||
explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
|
||||
|
||||
@@ -49,6 +49,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
}();
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -27,23 +27,18 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr
|
||||
auto& page_table = m_owner->PageTable();
|
||||
|
||||
// Construct the page group.
|
||||
m_page_group =
|
||||
KPageLinkedList(page_table.GetPhysicalAddr(addr), Common::DivideUp(size, PageSize));
|
||||
m_page_group = {};
|
||||
|
||||
// Lock the memory.
|
||||
R_TRY(page_table.LockForCodeMemory(addr, size))
|
||||
R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size))
|
||||
|
||||
// Clear the memory.
|
||||
//
|
||||
// FIXME: this ends up clobbering address ranges outside the scope of the mapping within
|
||||
// guest memory, and is not specifically required if the guest program is correctly
|
||||
// written, so disable until this is further investigated.
|
||||
//
|
||||
// for (const auto& block : m_page_group.Nodes()) {
|
||||
// std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize());
|
||||
// }
|
||||
for (const auto& block : m_page_group.Nodes()) {
|
||||
std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize());
|
||||
}
|
||||
|
||||
// Set remaining tracking members.
|
||||
m_owner->Open();
|
||||
m_address = addr;
|
||||
m_is_initialized = true;
|
||||
m_is_owner_mapped = false;
|
||||
@@ -57,8 +52,14 @@ void KCodeMemory::Finalize() {
|
||||
// Unlock.
|
||||
if (!m_is_mapped && !m_is_owner_mapped) {
|
||||
const size_t size = m_page_group.GetNumPages() * PageSize;
|
||||
m_owner->PageTable().UnlockForCodeMemory(m_address, size);
|
||||
m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group);
|
||||
}
|
||||
|
||||
// Close the page group.
|
||||
m_page_group = {};
|
||||
|
||||
// Close our reference to our owner.
|
||||
m_owner->Close();
|
||||
}
|
||||
|
||||
ResultCode KCodeMemory::Map(VAddr address, size_t size) {
|
||||
@@ -118,7 +119,8 @@ ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermis
|
||||
k_perm = KMemoryPermission::UserReadExecute;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
// Already validated by ControlCodeMemory svc
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Map the memory.
|
||||
|
||||
@@ -29,7 +29,7 @@ constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) {
|
||||
} else if ((type | KMemoryRegionType_DramSystemNonSecurePool) == type) {
|
||||
return KMemoryManager::Pool::SystemNonSecure;
|
||||
} else {
|
||||
UNREACHABLE_MSG("InvalidMemoryRegionType for conversion to Pool");
|
||||
ASSERT_MSG(false, "InvalidMemoryRegionType for conversion to Pool");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceT
|
||||
case FileSys::ProgramAddressSpaceType::Is39Bit:
|
||||
return 39;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_
|
||||
const std::size_t needed_size{
|
||||
(alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)};
|
||||
if (alloc_size < needed_size) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return ResultOutOfMemory;
|
||||
}
|
||||
|
||||
@@ -542,6 +542,95 @@ ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size_t num_pages) {
|
||||
ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
const size_t size = num_pages * PageSize;
|
||||
const auto& pg = pg_ll.Nodes();
|
||||
const auto& memory_layout = system.Kernel().MemoryLayout();
|
||||
|
||||
// Empty groups are necessarily invalid.
|
||||
if (pg.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're going to validate that the group we'd expect is the group we see.
|
||||
auto cur_it = pg.begin();
|
||||
PAddr cur_block_address = cur_it->GetAddress();
|
||||
size_t cur_block_pages = cur_it->GetNumPages();
|
||||
|
||||
auto UpdateCurrentIterator = [&]() {
|
||||
if (cur_block_pages == 0) {
|
||||
if ((++cur_it) == pg.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cur_block_address = cur_it->GetAddress();
|
||||
cur_block_pages = cur_it->GetNumPages();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Begin traversal.
|
||||
Common::PageTable::TraversalContext context;
|
||||
Common::PageTable::TraversalEntry next_entry;
|
||||
if (!page_table_impl.BeginTraversal(next_entry, context, addr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare tracking variables.
|
||||
PAddr cur_addr = next_entry.phys_addr;
|
||||
size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
|
||||
size_t tot_size = cur_size;
|
||||
|
||||
// Iterate, comparing expected to actual.
|
||||
while (tot_size < size) {
|
||||
if (!page_table_impl.ContinueTraversal(next_entry, context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (next_entry.phys_addr != (cur_addr + cur_size)) {
|
||||
const size_t cur_pages = cur_size / PageSize;
|
||||
|
||||
if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!UpdateCurrentIterator()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cur_block_address != cur_addr || cur_block_pages < cur_pages) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cur_block_address += cur_size;
|
||||
cur_block_pages -= cur_pages;
|
||||
cur_addr = next_entry.phys_addr;
|
||||
cur_size = next_entry.block_size;
|
||||
} else {
|
||||
cur_size += next_entry.block_size;
|
||||
}
|
||||
|
||||
tot_size += next_entry.block_size;
|
||||
}
|
||||
|
||||
// Ensure we compare the right amount for the last block.
|
||||
if (tot_size > size) {
|
||||
cur_size -= (tot_size - size);
|
||||
}
|
||||
|
||||
if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!UpdateCurrentIterator()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
|
||||
KPageTable& src_page_table, VAddr src_addr) {
|
||||
KScopedLightLock lk(general_lock);
|
||||
@@ -1341,7 +1430,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
|
||||
new_state = KMemoryState::AliasCodeData;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1687,22 +1776,22 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size) {
|
||||
return this->LockMemoryAndOpen(
|
||||
nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, KMemoryPermission::UserReadWrite,
|
||||
KMemoryAttribute::All, KMemoryAttribute::None,
|
||||
out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
|
||||
KMemoryAttribute::None,
|
||||
static_cast<KMemoryPermission>(KMemoryPermission::NotMapped |
|
||||
KMemoryPermission::KernelReadWrite),
|
||||
KMemoryAttribute::Locked);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) {
|
||||
return this->UnlockMemory(addr, size, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryState::FlagCanCodeMemory, KMemoryPermission::None,
|
||||
KMemoryPermission::None, KMemoryAttribute::All,
|
||||
KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
|
||||
KMemoryAttribute::Locked, nullptr);
|
||||
ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size,
|
||||
const KPageLinkedList& pg) {
|
||||
return this->UnlockMemory(
|
||||
addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
|
||||
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All,
|
||||
KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg);
|
||||
}
|
||||
|
||||
ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) {
|
||||
@@ -1734,9 +1823,7 @@ void KPageTable::AddRegionToPages(VAddr start, std::size_t num_pages,
|
||||
VAddr addr{start};
|
||||
while (addr < start + (num_pages * PageSize)) {
|
||||
const PAddr paddr{GetPhysicalAddr(addr)};
|
||||
if (!paddr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
ASSERT(paddr != 0);
|
||||
page_linked_list.AddBlock(paddr, 1);
|
||||
addr += PageSize;
|
||||
}
|
||||
@@ -1767,7 +1854,7 @@ ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLin
|
||||
system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
addr += size;
|
||||
@@ -1798,7 +1885,7 @@ ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermiss
|
||||
case OperationType::ChangePermissionsAndRefresh:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
return ResultSuccess;
|
||||
}
|
||||
@@ -1835,7 +1922,6 @@ VAddr KPageTable::GetRegionAddress(KMemoryState state) const {
|
||||
return code_region_start;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1871,7 +1957,6 @@ std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
|
||||
return code_region_end - code_region_start;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2125,7 +2210,7 @@ ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_
|
||||
|
||||
// Check the page group.
|
||||
if (pg != nullptr) {
|
||||
UNIMPLEMENTED_MSG("PageGroup support is unimplemented!");
|
||||
R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), ResultInvalidMemoryRegion);
|
||||
}
|
||||
|
||||
// Decide on new perm and attr.
|
||||
|
||||
@@ -72,8 +72,8 @@ public:
|
||||
KMemoryPermission perm, PAddr map_addr = 0);
|
||||
ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size);
|
||||
ResultCode LockForCodeMemory(VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size);
|
||||
ResultCode LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size);
|
||||
ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageLinkedList& pg);
|
||||
ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages,
|
||||
KMemoryState state_mask, KMemoryState state,
|
||||
KMemoryPermission perm_mask, KMemoryPermission perm,
|
||||
@@ -178,6 +178,7 @@ private:
|
||||
const KPageLinkedList* pg);
|
||||
|
||||
ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages);
|
||||
bool IsValidPageGroup(const KPageLinkedList& pg, VAddr addr, size_t num_pages);
|
||||
|
||||
bool IsLockedByCurrentThread() const {
|
||||
return general_lock.IsLockedByCurrentThread();
|
||||
|
||||
@@ -60,7 +60,7 @@ ResultCode KPort::EnqueueSession(KServerSession* session) {
|
||||
if (auto session_ptr = server.GetSessionRequestHandler().lock()) {
|
||||
session_ptr->ClientConnected(server.AcceptSession());
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
|
||||
@@ -350,7 +350,7 @@ ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
// Create TLS region
|
||||
|
||||
@@ -97,13 +97,13 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co
|
||||
"object_id {} is too big! This probably means a recent service call "
|
||||
"to {} needed to return a new interface!",
|
||||
object_id, name);
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return ResultSuccess; // Ignore error if asserts are off
|
||||
}
|
||||
if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) {
|
||||
return strong_ptr->HandleSyncRequest(*this, context);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
|
||||
ASSERT_MSG(false, "KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
|
||||
break;
|
||||
}
|
||||
thread_type = type;
|
||||
|
||||
@@ -212,7 +212,9 @@ struct KernelCore::Impl {
|
||||
system_resource_limit = KResourceLimit::Create(system.Kernel());
|
||||
system_resource_limit->Initialize(&core_timing);
|
||||
|
||||
const auto [total_size, kernel_size] = memory_layout->GetTotalAndKernelMemorySizes();
|
||||
const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()};
|
||||
const auto total_size{sizes.first};
|
||||
const auto kernel_size{sizes.second};
|
||||
|
||||
// If setting the default system values fails, then something seriously wrong has occurred.
|
||||
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
|
||||
@@ -252,6 +254,7 @@ struct KernelCore::Impl {
|
||||
core_id)
|
||||
.IsSuccess());
|
||||
suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
|
||||
suspend_threads[core_id]->DisableDispatch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1073,9 +1076,6 @@ void KernelCore::Suspend(bool in_suspention) {
|
||||
impl->suspend_threads[core_id]->SetState(state);
|
||||
impl->suspend_threads[core_id]->SetWaitReasonForDebugging(
|
||||
ThreadWaitReasonForDebugging::Suspended);
|
||||
if (!should_suspend) {
|
||||
impl->suspend_threads[core_id]->DisableDispatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1876,7 +1876,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) {
|
||||
KScheduler::YieldToAnyThread(kernel);
|
||||
} else {
|
||||
// Nintendo does nothing at all if an otherwise invalid value is passed.
|
||||
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
||||
ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ ResultCode Controller::GetStatus() const {
|
||||
}
|
||||
|
||||
void Controller::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
|
||||
ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
|
||||
}
|
||||
|
||||
void Controller::Execute() {
|
||||
|
||||
@@ -156,7 +156,7 @@ ResultCode Error::GetStatus() const {
|
||||
}
|
||||
|
||||
void Error::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Unexpected interactive applet data!");
|
||||
ASSERT_MSG(false, "Unexpected interactive applet data!");
|
||||
}
|
||||
|
||||
void Error::Execute() {
|
||||
|
||||
@@ -76,7 +76,7 @@ ResultCode Auth::GetStatus() const {
|
||||
}
|
||||
|
||||
void Auth::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Unexpected interactive applet data.");
|
||||
ASSERT_MSG(false, "Unexpected interactive applet data.");
|
||||
}
|
||||
|
||||
void Auth::Execute() {
|
||||
@@ -175,7 +175,7 @@ ResultCode PhotoViewer::GetStatus() const {
|
||||
}
|
||||
|
||||
void PhotoViewer::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Unexpected interactive applet data.");
|
||||
ASSERT_MSG(false, "Unexpected interactive applet data.");
|
||||
}
|
||||
|
||||
void PhotoViewer::Execute() {
|
||||
|
||||
@@ -67,7 +67,7 @@ ResultCode MiiEdit::GetStatus() const {
|
||||
}
|
||||
|
||||
void MiiEdit::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
|
||||
ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
|
||||
}
|
||||
|
||||
void MiiEdit::Execute() {
|
||||
|
||||
@@ -44,7 +44,7 @@ ResultCode ProfileSelect::GetStatus() const {
|
||||
}
|
||||
|
||||
void ProfileSelect::ExecuteInteractive() {
|
||||
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
|
||||
ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
|
||||
}
|
||||
|
||||
void ProfileSelect::Execute() {
|
||||
|
||||
@@ -71,7 +71,7 @@ void SoftwareKeyboard::Initialize() {
|
||||
InitializeBackground(applet_mode);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid LibraryAppletMode={}", applet_mode);
|
||||
ASSERT_MSG(false, "Invalid LibraryAppletMode={}", applet_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ void WebBrowser::Initialize() {
|
||||
InitializeLobby();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -320,7 +320,7 @@ void WebBrowser::Execute() {
|
||||
ExecuteLobby();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -899,7 +899,7 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
case FileSys::SaveDataSpaceId::TemporaryStorage:
|
||||
case FileSys::SaveDataSpaceId::ProperSystem:
|
||||
case FileSys::SaveDataSpaceId::SafeMode:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
|
||||
|
||||
@@ -61,6 +61,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
}
|
||||
|
||||
last_update_timestamp = shared_memory->gesture_lifo.timestamp;
|
||||
UpdateGestureSharedMemory(gesture, time_difference);
|
||||
}
|
||||
|
||||
void Controller_Gesture::ReadTouchInput() {
|
||||
@@ -94,8 +95,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
|
||||
return false;
|
||||
}
|
||||
|
||||
void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
|
||||
GestureProperties& gesture,
|
||||
void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture,
|
||||
f32 time_difference) {
|
||||
GestureType type = GestureType::Idle;
|
||||
GestureAttribute attributes{};
|
||||
|
||||
@@ -107,8 +107,7 @@ private:
|
||||
bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference);
|
||||
|
||||
// Updates the shared memory to the next state
|
||||
void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture,
|
||||
f32 time_difference);
|
||||
void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference);
|
||||
|
||||
// Initializes new gesture
|
||||
void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes);
|
||||
|
||||
@@ -160,7 +160,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
|
||||
shared_memory->system_properties.raw = 0;
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
shared_memory->style_tag.fullkey.Assign(1);
|
||||
@@ -422,7 +422,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
libnx_state.connection_status.is_connected.Assign(1);
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::NES:
|
||||
@@ -597,7 +597,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
@@ -856,7 +856,7 @@ void Controller_NPad::VibrateController(
|
||||
}
|
||||
|
||||
if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) {
|
||||
UNREACHABLE_MSG("DeviceIndex should never be None!");
|
||||
ASSERT_MSG(false, "DeviceIndex should never be None!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1441,7 +1441,7 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
|
||||
break;
|
||||
case Core::HID::DeviceIndex::None:
|
||||
default:
|
||||
UNREACHABLE_MSG("DeviceIndex should never be None!");
|
||||
ASSERT_MSG(false, "DeviceIndex should never be None!");
|
||||
vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/hid/errors.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
|
||||
namespace Service::HID {
|
||||
@@ -38,21 +40,32 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_IRS, "called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -60,35 +73,109 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedMomentProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedClusteringProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedImageTransferProcessorConfig processor_config;
|
||||
u32 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -97,71 +184,195 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
|
||||
npad_id != Core::HID::NpadIdType::Handheld) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidNpadId);
|
||||
return;
|
||||
}
|
||||
|
||||
IrCameraHandle camera_handle{
|
||||
.npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)),
|
||||
.npad_type = Core::HID::NpadStyleIndex::None,
|
||||
};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}",
|
||||
npad_id, camera_handle.npad_id, camera_handle.npad_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<u32>(device_handle);
|
||||
rb.PushRaw(camera_handle);
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto mcu_version{rp.PopRaw<PackedMcuVersion>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
|
||||
mcu_version.minor);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
PackedFunctionLevel function_level;
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
PackedImageTransferProcessorExConfig processor_config;
|
||||
u64 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem =
|
||||
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
PackedFunctionLevel function_level;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
|
||||
parameters.function_level.function_level, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -17,6 +18,235 @@ public:
|
||||
~IRS() override;
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::IrCameraStatus
|
||||
enum IrCameraStatus : u32 {
|
||||
Available,
|
||||
Unsupported,
|
||||
Unconnected,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrCameraInternalStatus
|
||||
enum IrCameraInternalStatus : u32 {
|
||||
Stopped,
|
||||
FirmwareUpdateNeeded,
|
||||
Unkown2,
|
||||
Unkown3,
|
||||
Unkown4,
|
||||
FirmwareVersionRequested,
|
||||
FirmwareVersionIsInvalid,
|
||||
Ready,
|
||||
Setting,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::detail::StatusManager::IrSensorMode
|
||||
enum IrSensorMode : u64 {
|
||||
None,
|
||||
MomentProcessor,
|
||||
ClusteringProcessor,
|
||||
ImageTransferProcessor,
|
||||
PointingProcessorMarker,
|
||||
TeraPluginProcessor,
|
||||
IrLedProcessor,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::ImageProcessorStatus
|
||||
enum ImageProcessorStatus : u8 {
|
||||
stopped,
|
||||
running,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::ImageTransferProcessorFormat
|
||||
enum ImageTransferProcessorFormat : u8 {
|
||||
Size320x240,
|
||||
Size160x120,
|
||||
Size80x60,
|
||||
Size40x30,
|
||||
Size20x15,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringMode
|
||||
enum AdaptiveClusteringMode : u8 {
|
||||
StaticFov,
|
||||
DynamicFov,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::AdaptiveClusteringTargetDistance
|
||||
enum AdaptiveClusteringTargetDistance : u8 {
|
||||
Near,
|
||||
Middle,
|
||||
Far,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrsHandAnalysisMode
|
||||
enum IrsHandAnalysisMode : u8 {
|
||||
Silhouette,
|
||||
Image,
|
||||
SilhoueteAndImage,
|
||||
SilhuetteOnly,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrSensorFunctionLevel
|
||||
enum IrSensorFunctionLevel : u8 {
|
||||
unknown0,
|
||||
unknown1,
|
||||
unknown2,
|
||||
unknown3,
|
||||
unknown4,
|
||||
};
|
||||
|
||||
// This is nn::irsensor::IrCameraHandle
|
||||
struct IrCameraHandle {
|
||||
u8 npad_id{};
|
||||
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
|
||||
|
||||
struct IrsRect {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 width;
|
||||
s16 height;
|
||||
};
|
||||
|
||||
// This is nn::irsensor::PackedMcuVersion
|
||||
struct PackedMcuVersion {
|
||||
u16 major;
|
||||
u16 minor;
|
||||
};
|
||||
static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size");
|
||||
|
||||
// This is nn::irsensor::MomentProcessorConfig
|
||||
struct MomentProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
IrsRect window_of_interest;
|
||||
u8 preprocess;
|
||||
u8 preprocess_intensity_threshold;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
};
|
||||
static_assert(sizeof(MomentProcessorConfig) == 0x28,
|
||||
"MomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedMomentProcessorConfig
|
||||
struct PackedMomentProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 preprocess;
|
||||
u8 preprocess_intensity_threshold;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(PackedMomentProcessorConfig) == 0x20,
|
||||
"PackedMomentProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::ClusteringProcessorConfig
|
||||
struct ClusteringProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u32 light_target;
|
||||
u32 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
IrsRect window_of_interest;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
|
||||
"ClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedClusteringProcessorConfig
|
||||
struct PackedClusteringProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u32 pixel_count_min;
|
||||
u32 pixel_count_max;
|
||||
u32 object_intensity_min;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30,
|
||||
"PackedClusteringProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedImageTransferProcessorConfig
|
||||
struct PackedImageTransferProcessorConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 format;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18,
|
||||
"PackedImageTransferProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedTeraPluginProcessorConfig
|
||||
struct PackedTeraPluginProcessorConfig {
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 mode;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8,
|
||||
"PackedTeraPluginProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedPointingProcessorConfig
|
||||
struct PackedPointingProcessorConfig {
|
||||
IrsRect window_of_interest;
|
||||
PackedMcuVersion required_mcu_version;
|
||||
};
|
||||
static_assert(sizeof(PackedPointingProcessorConfig) == 0xC,
|
||||
"PackedPointingProcessorConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedFunctionLevel
|
||||
struct PackedFunctionLevel {
|
||||
IrSensorFunctionLevel function_level;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedImageTransferProcessorExConfig
|
||||
struct PackedImageTransferProcessorExConfig {
|
||||
u64 exposire_time;
|
||||
u8 light_target;
|
||||
u8 gain;
|
||||
u8 is_negative_used;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
PackedMcuVersion required_mcu_version;
|
||||
ImageTransferProcessorFormat origin_format;
|
||||
ImageTransferProcessorFormat trimming_format;
|
||||
u16 trimming_start_x;
|
||||
u16 trimming_start_y;
|
||||
u8 is_external_light_filter_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20,
|
||||
"PackedImageTransferProcessorExConfig is an invalid size");
|
||||
|
||||
// This is nn::irsensor::PackedIrLedProcessorConfig
|
||||
struct PackedIrLedProcessorConfig {
|
||||
PackedMcuVersion required_mcu_version;
|
||||
u8 light_target;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
};
|
||||
static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8,
|
||||
"PackedIrLedProcessorConfig is an invalid size");
|
||||
|
||||
void ActivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
|
||||
void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
|
||||
@@ -35,8 +265,6 @@ private:
|
||||
void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
|
||||
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
|
||||
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
|
||||
|
||||
const u32 device_handle{0xABCD};
|
||||
};
|
||||
|
||||
class IRS_SYS final : public ServiceFramework<IRS_SYS> {
|
||||
|
||||
@@ -11,10 +11,13 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/div_ceil.h"
|
||||
#include "common/elf.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/jit/jit_context.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
using namespace Common::ELF;
|
||||
|
||||
namespace Service::JIT {
|
||||
|
||||
constexpr std::array<u8, 8> SVC0_ARM64 = {
|
||||
@@ -26,25 +29,6 @@ constexpr std::array HELPER_FUNCTIONS{
|
||||
"_stop", "_resolve", "_panic", "memcpy", "memmove", "memset",
|
||||
};
|
||||
|
||||
struct Elf64_Dyn {
|
||||
u64 d_tag;
|
||||
u64 d_un;
|
||||
};
|
||||
|
||||
struct Elf64_Rela {
|
||||
u64 r_offset;
|
||||
u64 r_info;
|
||||
s64 r_addend;
|
||||
};
|
||||
|
||||
static constexpr u32 Elf64_RelaType(const Elf64_Rela* rela) {
|
||||
return static_cast<u32>(rela->r_info);
|
||||
}
|
||||
|
||||
constexpr int DT_RELA = 7; /* Address of Rela relocs */
|
||||
constexpr int DT_RELASZ = 8; /* Total size of Rela relocs */
|
||||
constexpr int R_AARCH64_RELATIVE = 1027; /* Adjust by program base. */
|
||||
|
||||
constexpr size_t STACK_ALIGN = 16;
|
||||
|
||||
class JITContextImpl;
|
||||
@@ -206,17 +190,17 @@ public:
|
||||
if (!dyn.d_tag) {
|
||||
break;
|
||||
}
|
||||
if (dyn.d_tag == DT_RELA) {
|
||||
rela_dyn = dyn.d_un;
|
||||
if (dyn.d_tag == ElfDtRela) {
|
||||
rela_dyn = dyn.d_un.d_ptr;
|
||||
}
|
||||
if (dyn.d_tag == DT_RELASZ) {
|
||||
num_rela = dyn.d_un / sizeof(Elf64_Rela);
|
||||
if (dyn.d_tag == ElfDtRelasz) {
|
||||
num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_rela; i++) {
|
||||
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
|
||||
if (Elf64_RelaType(&rela) != R_AARCH64_RELATIVE) {
|
||||
if (Elf64RelType(rela.r_info) != ElfAArch64Relative) {
|
||||
continue;
|
||||
}
|
||||
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};
|
||||
|
||||
@@ -347,7 +347,7 @@ public:
|
||||
}
|
||||
|
||||
if (!succeeded) {
|
||||
UNREACHABLE_MSG("Out of address space!");
|
||||
ASSERT_MSG(false, "Out of address space!");
|
||||
return Kernel::ResultOutOfMemory;
|
||||
}
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Commo
|
||||
u8 glasses_type{};
|
||||
while (glasses_type_start < glasses_type_info.values[glasses_type]) {
|
||||
if (++glasses_type >= glasses_type_info.values_count) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ u32 SyncpointManager::AllocateSyncpoint() {
|
||||
return syncpoint_id;
|
||||
}
|
||||
}
|
||||
UNREACHABLE_MSG("No more available syncpoints!");
|
||||
ASSERT_MSG(false, "No more available syncpoints!");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -89,14 +89,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
|
||||
|
||||
LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot);
|
||||
|
||||
// If the front buffer is still being tracked, update its slot state
|
||||
if (core->StillTracking(*front)) {
|
||||
slots[slot].acquire_called = true;
|
||||
slots[slot].needs_cleanup_on_release = false;
|
||||
slots[slot].buffer_state = BufferState::Acquired;
|
||||
slots[slot].fence = Fence::NoFence();
|
||||
}
|
||||
|
||||
// If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
|
||||
// avoid unnecessarily remapping this buffer on the consumer side.
|
||||
if (out_buffer->acquire_called) {
|
||||
@@ -139,26 +131,11 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
|
||||
++current;
|
||||
}
|
||||
|
||||
if (slots[slot].buffer_state == BufferState::Acquired) {
|
||||
slots[slot].fence = release_fence;
|
||||
slots[slot].buffer_state = BufferState::Free;
|
||||
slots[slot].buffer_state = BufferState::Free;
|
||||
|
||||
listener = core->connected_producer_listener;
|
||||
listener = core->connected_producer_listener;
|
||||
|
||||
LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot);
|
||||
} else if (slots[slot].needs_cleanup_on_release) {
|
||||
LOG_DEBUG(Service_NVFlinger, "releasing a stale buffer slot {} (state = {})", slot,
|
||||
slots[slot].buffer_state);
|
||||
|
||||
slots[slot].needs_cleanup_on_release = false;
|
||||
|
||||
return Status::StaleBufferSlot;
|
||||
} else {
|
||||
LOG_ERROR(Service_NVFlinger, "attempted to release buffer slot {} but its state was {}",
|
||||
slot, slots[slot].buffer_state);
|
||||
|
||||
return Status::BadValue;
|
||||
}
|
||||
LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot);
|
||||
|
||||
core->SignalDequeueCondition();
|
||||
}
|
||||
|
||||
@@ -84,10 +84,6 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) {
|
||||
|
||||
slots[slot].graphic_buffer.reset();
|
||||
|
||||
if (slots[slot].buffer_state == BufferState::Acquired) {
|
||||
slots[slot].needs_cleanup_on_release = true;
|
||||
}
|
||||
|
||||
slots[slot].buffer_state = BufferState::Free;
|
||||
slots[slot].frame_number = UINT32_MAX;
|
||||
slots[slot].acquire_called = false;
|
||||
|
||||
@@ -659,7 +659,7 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
|
||||
value = core->consumer_usage_bit;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return Status::BadValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ struct BufferSlot final {
|
||||
u64 frame_number{};
|
||||
Fence fence;
|
||||
bool acquire_called{};
|
||||
bool needs_cleanup_on_release{};
|
||||
bool attached_by_consumer{};
|
||||
bool is_preallocated{};
|
||||
};
|
||||
|
||||
@@ -48,12 +48,12 @@ ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system,
|
||||
}
|
||||
|
||||
ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) {
|
||||
UNREACHABLE();
|
||||
UNIMPLEMENTED();
|
||||
return ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) {
|
||||
UNREACHABLE();
|
||||
UNIMPLEMENTED();
|
||||
return ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ struct TimeManager::Impl final {
|
||||
FileSys::VirtualFile& vfs_file) {
|
||||
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
|
||||
location_name, vfs_file) != ResultSuccess) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ struct TimeManager::Impl final {
|
||||
} else {
|
||||
if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) !=
|
||||
ResultSuccess) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ struct TimeManager::Impl final {
|
||||
|
||||
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
|
||||
ResultSuccess) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ struct TimeManager::Impl final {
|
||||
Clock::SteadyClockTimePoint steady_clock_time_point) {
|
||||
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
|
||||
system_, is_automatic_correction_enabled) != ResultSuccess) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ struct TimeManager::Impl final {
|
||||
if (GetStandardLocalSystemClockCore()
|
||||
.SetCurrentTime(system_, timespan.ToSeconds())
|
||||
.IsError()) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
return value + rule.transition_time + offset;
|
||||
}
|
||||
|
||||
+16
-167
@@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/elf.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/code_set.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
@@ -13,159 +14,7 @@
|
||||
#include "core/loader/elf.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ELF Header Constants
|
||||
|
||||
// File type
|
||||
enum ElfType {
|
||||
ET_NONE = 0,
|
||||
ET_REL = 1,
|
||||
ET_EXEC = 2,
|
||||
ET_DYN = 3,
|
||||
ET_CORE = 4,
|
||||
ET_LOPROC = 0xFF00,
|
||||
ET_HIPROC = 0xFFFF,
|
||||
};
|
||||
|
||||
// Machine/Architecture
|
||||
enum ElfMachine {
|
||||
EM_NONE = 0,
|
||||
EM_M32 = 1,
|
||||
EM_SPARC = 2,
|
||||
EM_386 = 3,
|
||||
EM_68K = 4,
|
||||
EM_88K = 5,
|
||||
EM_860 = 7,
|
||||
EM_MIPS = 8
|
||||
};
|
||||
|
||||
// File version
|
||||
#define EV_NONE 0
|
||||
#define EV_CURRENT 1
|
||||
|
||||
// Identification index
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
#define EI_PAD 7
|
||||
#define EI_NIDENT 16
|
||||
|
||||
// Sections constants
|
||||
|
||||
// Section types
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
#define SHT_LOPROC 0x70000000
|
||||
#define SHT_HIPROC 0x7FFFFFFF
|
||||
#define SHT_LOUSER 0x80000000
|
||||
#define SHT_HIUSER 0xFFFFFFFF
|
||||
|
||||
// Section flags
|
||||
enum ElfSectionFlags {
|
||||
SHF_WRITE = 0x1,
|
||||
SHF_ALLOC = 0x2,
|
||||
SHF_EXECINSTR = 0x4,
|
||||
SHF_MASKPROC = 0xF0000000,
|
||||
};
|
||||
|
||||
// Segment types
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7FFFFFFF
|
||||
|
||||
// Segment flags
|
||||
#define PF_X 0x1
|
||||
#define PF_W 0x2
|
||||
#define PF_R 0x4
|
||||
#define PF_MASKPROC 0xF0000000
|
||||
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned short Elf32_Half;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef signed int Elf32_Sword;
|
||||
typedef unsigned int Elf32_Word;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ELF file header
|
||||
|
||||
struct Elf32_Ehdr {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
};
|
||||
|
||||
// Section header
|
||||
struct Elf32_Shdr {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
};
|
||||
|
||||
// Segment header
|
||||
struct Elf32_Phdr {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
};
|
||||
|
||||
// Symbol table entry
|
||||
struct Elf32_Sym {
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
};
|
||||
|
||||
// Relocation entries
|
||||
struct Elf32_Rel {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
};
|
||||
using namespace Common::ELF;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ElfReader class
|
||||
@@ -193,11 +42,11 @@ public:
|
||||
}
|
||||
|
||||
// Quick accessors
|
||||
ElfType GetType() const {
|
||||
return (ElfType)(header->e_type);
|
||||
u16 GetType() const {
|
||||
return header->e_type;
|
||||
}
|
||||
ElfMachine GetMachine() const {
|
||||
return (ElfMachine)(header->e_machine);
|
||||
u16 GetMachine() const {
|
||||
return header->e_machine;
|
||||
}
|
||||
VAddr GetEntryPoint() const {
|
||||
return entryPoint;
|
||||
@@ -220,13 +69,13 @@ public:
|
||||
const u8* GetSectionDataPtr(int section) const {
|
||||
if (section < 0 || section >= header->e_shnum)
|
||||
return nullptr;
|
||||
if (sections[section].sh_type != SHT_NOBITS)
|
||||
if (sections[section].sh_type != ElfShtNobits)
|
||||
return GetPtr(sections[section].sh_offset);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
bool IsCodeSection(int section) const {
|
||||
return sections[section].sh_type == SHT_PROGBITS;
|
||||
return sections[section].sh_type == ElfShtProgBits;
|
||||
}
|
||||
const u8* GetSegmentPtr(int segment) {
|
||||
return GetPtr(segments[segment].p_offset);
|
||||
@@ -256,7 +105,7 @@ ElfReader::ElfReader(void* ptr) {
|
||||
}
|
||||
|
||||
const char* ElfReader::GetSectionName(int section) const {
|
||||
if (sections[section].sh_type == SHT_NULL)
|
||||
if (sections[section].sh_type == ElfShtNull)
|
||||
return nullptr;
|
||||
|
||||
int name_offset = sections[section].sh_name;
|
||||
@@ -272,7 +121,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
|
||||
LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
|
||||
|
||||
// Should we relocate?
|
||||
relocate = (header->e_type != ET_EXEC);
|
||||
relocate = (header->e_type != ElfTypeExec);
|
||||
|
||||
if (relocate) {
|
||||
LOG_DEBUG(Loader, "Relocatable module");
|
||||
@@ -288,7 +137,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
|
||||
u64 total_image_size = 0;
|
||||
for (unsigned int i = 0; i < header->e_phnum; ++i) {
|
||||
const Elf32_Phdr* p = &segments[i];
|
||||
if (p->p_type == PT_LOAD) {
|
||||
if (p->p_type == ElfPtLoad) {
|
||||
total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
|
||||
}
|
||||
}
|
||||
@@ -303,14 +152,14 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
|
||||
LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
|
||||
p->p_vaddr, p->p_filesz, p->p_memsz);
|
||||
|
||||
if (p->p_type == PT_LOAD) {
|
||||
if (p->p_type == ElfPtLoad) {
|
||||
Kernel::CodeSet::Segment* codeset_segment;
|
||||
u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
|
||||
if (permission_flags == (PF_R | PF_X)) {
|
||||
u32 permission_flags = p->p_flags & (ElfPfRead | ElfPfWrite | ElfPfExec);
|
||||
if (permission_flags == (ElfPfRead | ElfPfExec)) {
|
||||
codeset_segment = &codeset.CodeSegment();
|
||||
} else if (permission_flags == (PF_R)) {
|
||||
} else if (permission_flags == (ElfPfRead)) {
|
||||
codeset_segment = &codeset.RODataSegment();
|
||||
} else if (permission_flags == (PF_R | PF_W)) {
|
||||
} else if (permission_flags == (ElfPfRead | ElfPfWrite)) {
|
||||
codeset_segment = &codeset.DataSegment();
|
||||
} else {
|
||||
LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,
|
||||
|
||||
@@ -128,11 +128,10 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
||||
|
||||
// Apply patches if necessary
|
||||
if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
|
||||
std::vector<u8> pi_header;
|
||||
pi_header.insert(pi_header.begin(), reinterpret_cast<u8*>(&nso_header),
|
||||
reinterpret_cast<u8*>(&nso_header) + sizeof(NSOHeader));
|
||||
pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(),
|
||||
program_image.data() + program_image.size());
|
||||
std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size());
|
||||
std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader));
|
||||
std::memcpy(pi_header.data() + sizeof(NSOHeader), program_image.data(),
|
||||
program_image.size());
|
||||
|
||||
pi_header = pm->PatchNSO(pi_header, nso_file.GetName());
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) {
|
||||
return memory.Read64(addr);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
[[nodiscard]] Stack Remove(Token token) const;
|
||||
|
||||
private:
|
||||
boost::container::small_vector<StackEntry, 3> entries;
|
||||
std::vector<StackEntry> entries;
|
||||
};
|
||||
|
||||
struct IndirectBranch {
|
||||
|
||||
@@ -975,13 +975,7 @@ private:
|
||||
Environment& env;
|
||||
IR::AbstractSyntaxList& syntax_list;
|
||||
bool uses_demote_to_helper{};
|
||||
|
||||
// TODO: C++20 Remove this when all compilers support constexpr std::vector
|
||||
#if __cpp_lib_constexpr_vector >= 201907
|
||||
static constexpr Flow::Block dummy_flow_block;
|
||||
#else
|
||||
const Flow::Block dummy_flow_block;
|
||||
#endif
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ void Codec::Decode() {
|
||||
vp9_hidden_frame = vp9_decoder->WasFrameHidden();
|
||||
return vp9_decoder->GetFrameBytes();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return std::vector<u8>{};
|
||||
}
|
||||
}();
|
||||
|
||||
@@ -228,7 +228,7 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
gpu.MemoryManager().WriteBlock(output_surface_chroma_address, chroma_buffer.data(),
|
||||
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
case Size::Size_11_11_10:
|
||||
return 3;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ public:
|
||||
case Size::Size_11_11_10:
|
||||
return 4;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ public:
|
||||
case Size::Size_11_11_10:
|
||||
return "11_11_10";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -296,7 +296,7 @@ public:
|
||||
case Type::Float:
|
||||
return "FLOAT";
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ public:
|
||||
case 3:
|
||||
return {x3, y3};
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return {0, 0};
|
||||
}
|
||||
}
|
||||
@@ -1193,7 +1193,7 @@ public:
|
||||
case IndexFormat::UnsignedInt:
|
||||
return 4;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ void MaxwellDMA::Launch() {
|
||||
|
||||
if (!is_src_pitch && !is_dst_pitch) {
|
||||
// If both the source and the destination are in block layout, assert.
|
||||
UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented");
|
||||
UNIMPLEMENTED_MSG("Tiled->Tiled DMA transfers are not yet implemented");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ void MaxwellDMA::ReleaseSemaphore() {
|
||||
memory_manager.Write<u64>(address + 8, system.GPU().GetTicks());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown semaphore type: {}", static_cast<u32>(type.Value()));
|
||||
ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast<u32>(type.Value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
|
||||
VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer();
|
||||
|
||||
while (!stop_token.stop_requested()) {
|
||||
CommandDataContainer next = state.queue.PopWait(stop_token);
|
||||
CommandDataContainer next;
|
||||
state.queue.Pop(next, stop_token);
|
||||
if (stop_token.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
@@ -49,7 +50,7 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
|
||||
} else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
|
||||
rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
state.signaled_fence.store(next.fence);
|
||||
if (next.block) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <thread>
|
||||
#include <variant>
|
||||
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "common/bounded_threadsafe_queue.h"
|
||||
#include "video_core/framebuffer_config.h"
|
||||
|
||||
namespace Tegra {
|
||||
@@ -96,9 +96,9 @@ struct CommandDataContainer {
|
||||
|
||||
/// Struct used to synchronize the GPU thread
|
||||
struct SynchState final {
|
||||
using CommandQueue = Common::SPSCQueue<CommandDataContainer, true>;
|
||||
using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
|
||||
std::mutex write_lock;
|
||||
CommandQueue queue;
|
||||
CommandQueue queue{512}; // size must be 2^n
|
||||
u64 last_fence{};
|
||||
std::atomic<u64> signaled_fence{};
|
||||
std::condition_variable_any cv;
|
||||
|
||||
@@ -71,7 +71,7 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||
}
|
||||
}
|
||||
if (!mid_method.has_value()) {
|
||||
UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method);
|
||||
ASSERT_MSG(false, "Macro 0x{0:x} was not uploaded", method);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,6 @@ bool MacroInterpreterImpl::EvaluateBranchCondition(Macro::BranchCondition cond,
|
||||
return value != 0;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return true;
|
||||
}
|
||||
|
||||
Macro::Opcode MacroInterpreterImpl::GetOpcode() const {
|
||||
|
||||
@@ -411,7 +411,7 @@ void MacroJITx64Impl::Compile_Branch(Macro::Opcode opcode) {
|
||||
|
||||
Xbyak::Label end;
|
||||
auto value = Compile_GetRegister(opcode.src_a, eax);
|
||||
test(value, value);
|
||||
cmp(value, 0); // test(value, value);
|
||||
if (optimizer.has_delayed_pc) {
|
||||
switch (opcode.branch_condition) {
|
||||
case Macro::BranchCondition::Zero:
|
||||
|
||||
@@ -67,7 +67,7 @@ void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
|
||||
ASSERT(it->first == gpu_addr);
|
||||
map_ranges.erase(it);
|
||||
} else {
|
||||
UNREACHABLE_MSG("Unmapping non-existent GPU address=0x{:x}", gpu_addr);
|
||||
ASSERT_MSG(false, "Unmapping non-existent GPU address=0x{:x}", gpu_addr);
|
||||
}
|
||||
const auto submapped_ranges = GetSubmappedRange(gpu_addr, size);
|
||||
|
||||
@@ -206,7 +206,7 @@ T MemoryManager::Read(GPUVAddr addr) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -219,7 +219,7 @@ void MemoryManager::Write(GPUVAddr addr, T data) {
|
||||
return;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
template u8 MemoryManager::Read<u8>(GPUVAddr addr) const;
|
||||
|
||||
@@ -48,7 +48,7 @@ GLenum Stage(size_t stage_index) {
|
||||
case 4:
|
||||
return GL_FRAGMENT_SHADER;
|
||||
}
|
||||
UNREACHABLE_MSG("{}", stage_index);
|
||||
ASSERT_MSG(false, "{}", stage_index);
|
||||
return GL_NONE;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ GLenum AssemblyStage(size_t stage_index) {
|
||||
case 4:
|
||||
return GL_FRAGMENT_PROGRAM_NV;
|
||||
}
|
||||
UNREACHABLE_MSG("{}", stage_index);
|
||||
ASSERT_MSG(false, "{}", stage_index);
|
||||
return GL_NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
|
||||
case Maxwell::TessellationPrimitive::Quads:
|
||||
return Shader::TessPrimitive::Quads;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return Shader::TessPrimitive::Triangles;
|
||||
}();
|
||||
info.tess_spacing = [&] {
|
||||
@@ -97,7 +97,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
|
||||
case Maxwell::TessellationSpacing::FractionalEven:
|
||||
return Shader::TessSpacing::FractionalEven;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return Shader::TessSpacing::Equal;
|
||||
}();
|
||||
break;
|
||||
|
||||
@@ -83,7 +83,7 @@ GLenum ImageTarget(const VideoCommon::ImageInfo& info) {
|
||||
case ImageType::Buffer:
|
||||
return GL_TEXTURE_BUFFER;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid image type={}", info.type);
|
||||
ASSERT_MSG(false, "Invalid image type={}", info.type);
|
||||
return GL_NONE;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) {
|
||||
case Shader::TextureType::Buffer:
|
||||
return GL_TEXTURE_BUFFER;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid image view type={}", type);
|
||||
ASSERT_MSG(false, "Invalid image view type={}", type);
|
||||
return GL_NONE;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ GLenum TextureMode(PixelFormat format, bool is_first) {
|
||||
case PixelFormat::S8_UINT_D24_UNORM:
|
||||
return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return GL_DEPTH_COMPONENT;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ GLint Swizzle(SwizzleSource source) {
|
||||
case SwizzleSource::OneFloat:
|
||||
return GL_ONE;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid swizzle source={}", source);
|
||||
ASSERT_MSG(false, "Invalid swizzle source={}", source);
|
||||
return GL_NONE;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ GLint ConvertA5B5G5R1_UNORM(SwizzleSource source) {
|
||||
case SwizzleSource::OneFloat:
|
||||
return GL_ONE;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid swizzle source={}", source);
|
||||
ASSERT_MSG(false, "Invalid swizzle source={}", source);
|
||||
return GL_NONE;
|
||||
}
|
||||
|
||||
@@ -381,10 +381,10 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
|
||||
glTextureStorage3D(handle, gl_num_levels, gl_internal_format, width, height, depth);
|
||||
break;
|
||||
case GL_TEXTURE_BUFFER:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid target=0x{:x}", target);
|
||||
ASSERT_MSG(false, "Invalid target=0x{:x}", target);
|
||||
break;
|
||||
}
|
||||
return texture;
|
||||
@@ -420,7 +420,7 @@ OGLTexture MakeImage(const VideoCommon::ImageInfo& info, GLenum gl_internal_form
|
||||
case Shader::ImageFormat::R32G32B32A32_UINT:
|
||||
return GL_RGBA32UI;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid image format={}", format);
|
||||
ASSERT_MSG(false, "Invalid image format={}", format);
|
||||
return GL_R32UI;
|
||||
}
|
||||
|
||||
@@ -579,7 +579,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
|
||||
} else if (IsPixelFormatBGR(dst.info.format) || IsPixelFormatBGR(src.info.format)) {
|
||||
format_conversion_pass.ConvertImage(dst, src, copies);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ void TextureCacheRuntime::AccelerateImageUpload(Image& image, const ImageBufferM
|
||||
case ImageType::Linear:
|
||||
return util_shaders.PitchUpload(image, map, swizzles);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -639,7 +639,7 @@ FormatProperties TextureCacheRuntime::FormatInfo(ImageType type, GLenum internal
|
||||
case ImageType::e3D:
|
||||
return format_properties[2].at(internal_format);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return FormatProperties{};
|
||||
}
|
||||
}
|
||||
@@ -888,7 +888,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,7 +924,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b
|
||||
depth = copy.image_extent.depth;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
}
|
||||
// Compressed formats don't have a pixel format or type
|
||||
const bool is_compressed = gl_format == GL_NONE;
|
||||
@@ -950,7 +950,7 @@ void Image::Scale(bool up_scale) {
|
||||
case SurfaceType::DepthStencil:
|
||||
return GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return GL_COLOR_ATTACHMENT0;
|
||||
}
|
||||
}();
|
||||
@@ -965,7 +965,7 @@ void Image::Scale(bool up_scale) {
|
||||
case SurfaceType::DepthStencil:
|
||||
return GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
}();
|
||||
@@ -980,7 +980,7 @@ void Image::Scale(bool up_scale) {
|
||||
case SurfaceType::DepthStencil:
|
||||
return 3;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
}();
|
||||
@@ -1045,7 +1045,7 @@ bool Image::ScaleUp(bool ignore) {
|
||||
return false;
|
||||
}
|
||||
if (info.type == ImageType::Linear) {
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
flags |= ImageFlagBits::Rescaled;
|
||||
@@ -1139,7 +1139,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case ImageViewType::Buffer:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
switch (info.type) {
|
||||
@@ -1319,7 +1319,7 @@ Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM
|
||||
buffer_bits |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
buffer_bits |= GL_DEPTH_BUFFER_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ inline GLenum IndexFormat(Maxwell::IndexFormat index_format) {
|
||||
case Maxwell::IndexFormat::UnsignedInt:
|
||||
return GL_UNSIGNED_INT;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid index_format={}", index_format);
|
||||
ASSERT_MSG(false, "Invalid index_format={}", index_format);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
|
||||
case Maxwell::PrimitiveTopology::Patches:
|
||||
return GL_PATCHES;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid topology={}", topology);
|
||||
ASSERT_MSG(false, "Invalid topology={}", topology);
|
||||
return GL_POINTS;
|
||||
}
|
||||
|
||||
@@ -271,8 +271,8 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode,
|
||||
}
|
||||
break;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid texture filter mode={} and mipmap filter mode={}", filter_mode,
|
||||
mipmap_filter_mode);
|
||||
ASSERT_MSG(false, "Invalid texture filter mode={} and mipmap filter mode={}", filter_mode,
|
||||
mipmap_filter_mode);
|
||||
return GL_NEAREST;
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ inline GLenum PolygonMode(Maxwell::PolygonMode polygon_mode) {
|
||||
case Maxwell::PolygonMode::Fill:
|
||||
return GL_FILL;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid polygon mode={}", polygon_mode);
|
||||
ASSERT_MSG(false, "Invalid polygon mode={}", polygon_mode);
|
||||
return GL_FILL;
|
||||
}
|
||||
|
||||
@@ -563,7 +563,7 @@ inline GLenum ReductionFilter(Tegra::Texture::SamplerReduction filter) {
|
||||
case Tegra::Texture::SamplerReduction::Max:
|
||||
return GL_MAX;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid reduction filter={}", static_cast<int>(filter));
|
||||
ASSERT_MSG(false, "Invalid reduction filter={}", static_cast<int>(filter));
|
||||
return GL_WEIGHTED_AVERAGE_ARB;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ const char* GetSource(GLenum source) {
|
||||
case GL_DEBUG_SOURCE_OTHER:
|
||||
return "OTHER";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return "Unknown source";
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ const char* GetType(GLenum type) {
|
||||
case GL_DEBUG_TYPE_MARKER:
|
||||
return "MARKER";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return "Unknown type";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ GLenum StoreFormat(u32 bytes_per_block) {
|
||||
case 16:
|
||||
return GL_RGBA32UI;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return GL_R8UI;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ VkFilter Filter(Tegra::Texture::TextureFilter filter) {
|
||||
case Tegra::Texture::TextureFilter::Linear:
|
||||
return VK_FILTER_LINEAR;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid sampler filter={}", filter);
|
||||
ASSERT_MSG(false, "Invalid sampler filter={}", filter);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ VkSamplerMipmapMode MipmapMode(Tegra::Texture::TextureMipmapFilter mipmap_filter
|
||||
case Tegra::Texture::TextureMipmapFilter::Linear:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid sampler mipmap mode={}", mipmap_filter);
|
||||
ASSERT_MSG(false, "Invalid sampler mipmap mode={}", mipmap_filter);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wra
|
||||
case Tegra::Texture::TextureFilter::Linear:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
@@ -744,7 +744,7 @@ VkViewportCoordinateSwizzleNV ViewportSwizzle(Maxwell::ViewportSwizzle swizzle)
|
||||
case Maxwell::ViewportSwizzle::NegativeW:
|
||||
return VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid swizzle={}", swizzle);
|
||||
ASSERT_MSG(false, "Invalid swizzle={}", swizzle);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@ VkSamplerReductionMode SamplerReduction(Tegra::Texture::SamplerReduction reducti
|
||||
case Tegra::Texture::SamplerReduction::Max:
|
||||
return VK_SAMPLER_REDUCTION_MODE_MAX_EXT;
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid sampler mode={}", static_cast<int>(reduction));
|
||||
ASSERT_MSG(false, "Invalid sampler mode={}", static_cast<int>(reduction));
|
||||
return VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT;
|
||||
}
|
||||
|
||||
@@ -780,7 +780,7 @@ VkSampleCountFlagBits MsaaMode(Tegra::Texture::MsaaMode msaa_mode) {
|
||||
case Tegra::Texture::MsaaMode::Msaa4x4:
|
||||
return VK_SAMPLE_COUNT_16_BIT;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid msaa_mode={}", static_cast<int>(msaa_mode));
|
||||
ASSERT_MSG(false, "Invalid msaa_mode={}", static_cast<int>(msaa_mode));
|
||||
return VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ size_t BytesPerIndex(VkIndexType index_type) {
|
||||
case VK_INDEX_TYPE_UINT32:
|
||||
return 4;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid index type={}", index_type);
|
||||
ASSERT_MSG(false, "Invalid index type={}", index_type);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ void BufferCacheRuntime::ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle
|
||||
std::memcpy(staging_data, MakeQuadIndices<u32>(quad, first).data(), quad_size);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
staging_data += quad_size;
|
||||
|
||||
@@ -265,7 +265,7 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
|
||||
case Tegra::Engines::Maxwell3D::Regs::IndexFormat::UnsignedInt:
|
||||
return 2;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return 2;
|
||||
}();
|
||||
const u32 input_size = num_vertices << index_shift;
|
||||
@@ -333,7 +333,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
||||
const VkImageMemoryBarrier image_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VkAccessFlags{},
|
||||
.srcAccessMask = is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VK_ACCESS_NONE,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
|
||||
@@ -174,7 +174,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
||||
case Maxwell::TessellationPrimitive::Quads:
|
||||
return Shader::TessPrimitive::Quads;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return Shader::TessPrimitive::Triangles;
|
||||
}();
|
||||
info.tess_spacing = [&] {
|
||||
@@ -187,7 +187,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
||||
case Maxwell::TessellationSpacing::FractionalEven:
|
||||
return Shader::TessSpacing::FractionalEven;
|
||||
}
|
||||
UNREACHABLE();
|
||||
ASSERT(false);
|
||||
return Shader::TessSpacing::Equal;
|
||||
}();
|
||||
break;
|
||||
|
||||
@@ -263,7 +263,7 @@ StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage
|
||||
case MemoryUsage::Download:
|
||||
return download_cache;
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid memory usage={}", usage);
|
||||
ASSERT_MSG(false, "Invalid memory usage={}", usage);
|
||||
return upload_cache;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user