diff options
Diffstat (limited to '')
153 files changed, 2434 insertions, 1499 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4f6a87b0a..7fd226050 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -170,6 +170,7 @@ add_library(core STATIC hle/kernel/server_port.h hle/kernel/server_session.cpp hle/kernel/server_session.h + hle/kernel/session.cpp hle/kernel/session.h hle/kernel/shared_memory.cpp hle/kernel/shared_memory.h @@ -509,7 +510,6 @@ add_library(core STATIC memory/dmnt_cheat_vm.h memory.cpp memory.h - memory_setup.h perf_stats.cpp perf_stats.h reporter.cpp @@ -522,6 +522,23 @@ add_library(core STATIC tools/freezer.h ) +if (MSVC) + target_compile_options(core PRIVATE + # 'expression' : signed/unsigned mismatch + /we4018 + # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) + /we4244 + # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch + /we4245 + # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /we4254 + # 'var' : conversion from 'size_t' to 'type', possible loss of data + /we4267 + # 'context' : truncation from 'type1' to 'type2' + /we4305 + ) +endif() + create_target_directory_groups(core) target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 372612c9b..7e846ddd5 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -13,7 +13,6 @@ #include "core/memory.h" namespace Core { - namespace { constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; @@ -61,15 +60,15 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size."); using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; -Symbols GetSymbols(VAddr text_offset) { - const auto mod_offset = text_offset + Memory::Read32(text_offset + 4); +Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) { + const auto mod_offset = text_offset + memory.Read32(text_offset + 4); if (mod_offset < text_offset || (mod_offset & 0b11) != 0 || - Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { + memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { return {}; } - const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset; + const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset; VAddr string_table_offset{}; VAddr symbol_table_offset{}; @@ -77,8 +76,8 @@ Symbols GetSymbols(VAddr text_offset) { VAddr dynamic_index = dynamic_offset; while (true) { - const auto tag = Memory::Read64(dynamic_index); - const auto value = Memory::Read64(dynamic_index + 0x8); + const u64 tag = memory.Read64(dynamic_index); + const u64 value = memory.Read64(dynamic_index + 0x8); dynamic_index += 0x10; if (tag == ELF_DYNAMIC_TAG_NULL) { @@ -106,11 +105,11 @@ Symbols GetSymbols(VAddr text_offset) { VAddr symbol_index = symbol_table_address; while (symbol_index < string_table_address) { ELFSymbol symbol{}; - Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); + memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol)); VAddr string_offset = string_table_address + symbol.name_index; std::string name; - for (u8 c = Memory::Read8(string_offset); c != 0; c = Memory::Read8(++string_offset)) { + for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) { name += static_cast<char>(c); } @@ -142,28 +141,28 @@ constexpr u64 SEGMENT_BASE = 0x7100000000ull; std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { std::vector<BacktraceEntry> out; + auto& memory = system.Memory(); auto fp = GetReg(29); auto lr = GetReg(30); - while (true) { out.push_back({"", 0, lr, 0}); if (!fp) { break; } - lr = Memory::Read64(fp + 8) - 4; - fp = Memory::Read64(fp); + lr = memory.Read64(fp + 8) - 4; + fp = memory.Read64(fp); } std::map<VAddr, std::string> modules; - auto& loader{System::GetInstance().GetAppLoader()}; + auto& loader{system.GetAppLoader()}; if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { return {}; } std::map<std::string, Symbols> symbols; for (const auto& module : modules) { - symbols.insert_or_assign(module.second, GetSymbols(module.first)); + symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); } for (auto& entry : out) { diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 45e94e625..47b964eb7 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -17,11 +17,13 @@ enum class VMAPermission : u8; } namespace Core { +class System; /// Generic ARMv8 CPU interface class ARM_Interface : NonCopyable { public: - virtual ~ARM_Interface() {} + explicit ARM_Interface(System& system_) : system{system_} {} + virtual ~ARM_Interface() = default; struct ThreadContext { std::array<u64, 31> cpu_registers; @@ -163,6 +165,10 @@ public: /// fp+0 : pointer to previous frame record /// fp+8 : value of lr for frame void LogBacktrace() const; + +protected: + /// System context that this ARM interface is running under. + System& system; }; } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 700c4afff..f8c7f0efd 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -28,36 +28,38 @@ public: explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} u8 MemoryRead8(u64 vaddr) override { - return Memory::Read8(vaddr); + return parent.system.Memory().Read8(vaddr); } u16 MemoryRead16(u64 vaddr) override { - return Memory::Read16(vaddr); + return parent.system.Memory().Read16(vaddr); } u32 MemoryRead32(u64 vaddr) override { - return Memory::Read32(vaddr); + return parent.system.Memory().Read32(vaddr); } u64 MemoryRead64(u64 vaddr) override { - return Memory::Read64(vaddr); + return parent.system.Memory().Read64(vaddr); } Vector MemoryRead128(u64 vaddr) override { - return {Memory::Read64(vaddr), Memory::Read64(vaddr + 8)}; + auto& memory = parent.system.Memory(); + return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; } void MemoryWrite8(u64 vaddr, u8 value) override { - Memory::Write8(vaddr, value); + parent.system.Memory().Write8(vaddr, value); } void MemoryWrite16(u64 vaddr, u16 value) override { - Memory::Write16(vaddr, value); + parent.system.Memory().Write16(vaddr, value); } void MemoryWrite32(u64 vaddr, u32 value) override { - Memory::Write32(vaddr, value); + parent.system.Memory().Write32(vaddr, value); } void MemoryWrite64(u64 vaddr, u64 value) override { - Memory::Write64(vaddr, value); + parent.system.Memory().Write64(vaddr, value); } void MemoryWrite128(u64 vaddr, Vector value) override { - Memory::Write64(vaddr, value[0]); - Memory::Write64(vaddr + 8, value[1]); + auto& memory = parent.system.Memory(); + memory.Write64(vaddr, value[0]); + memory.Write64(vaddr + 8, value[1]); } void InterpreterFallback(u64 pc, std::size_t num_instructions) override { @@ -67,7 +69,7 @@ public: ARM_Interface::ThreadContext ctx; parent.SaveContext(ctx); parent.inner_unicorn.LoadContext(ctx); - parent.inner_unicorn.ExecuteInstructions(static_cast<int>(num_instructions)); + parent.inner_unicorn.ExecuteInstructions(num_instructions); parent.inner_unicorn.SaveContext(ctx); parent.LoadContext(ctx); num_interpreted_instructions += num_instructions; @@ -171,9 +173,10 @@ void ARM_Dynarmic::Step() { ARM_Dynarmic::ARM_Dynarmic(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, - core_index{core_index}, system{system}, - exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} + : ARM_Interface{system}, + cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), inner_unicorn{system}, + core_index{core_index}, exclusive_monitor{ + dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} ARM_Dynarmic::~ARM_Dynarmic() = default; @@ -264,7 +267,9 @@ void ARM_Dynarmic::PageTableChanged(Common::PageTable& page_table, jit = MakeJit(page_table, new_address_space_size_in_bits); } -DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(std::size_t core_count) : monitor(core_count) {} +DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count) + : monitor(core_count), memory{memory_} {} + DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; void DynarmicExclusiveMonitor::SetExclusive(std::size_t core_index, VAddr addr) { @@ -277,29 +282,28 @@ void DynarmicExclusiveMonitor::ClearExclusive() { } bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) { - return monitor.DoExclusiveOperation(core_index, vaddr, 1, - [&] { Memory::Write8(vaddr, value); }); + return monitor.DoExclusiveOperation(core_index, vaddr, 1, [&] { memory.Write8(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 2, - [&] { Memory::Write16(vaddr, value); }); + [&] { memory.Write16(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 4, - [&] { Memory::Write32(vaddr, value); }); + [&] { memory.Write32(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 8, - [&] { Memory::Write64(vaddr, value); }); + [&] { memory.Write64(vaddr, value); }); } bool DynarmicExclusiveMonitor::ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) { return monitor.DoExclusiveOperation(core_index, vaddr, 16, [&] { - Memory::Write64(vaddr + 0, value[0]); - Memory::Write64(vaddr + 8, value[1]); + memory.Write64(vaddr + 0, value[0]); + memory.Write64(vaddr + 8, value[1]); }); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 504d46c68..9cd475cfb 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -12,6 +12,10 @@ #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" +namespace Memory { +class Memory; +} + namespace Core { class ARM_Dynarmic_Callbacks; @@ -58,13 +62,12 @@ private: ARM_Unicorn inner_unicorn; std::size_t core_index; - System& system; DynarmicExclusiveMonitor& exclusive_monitor; }; class DynarmicExclusiveMonitor final : public ExclusiveMonitor { public: - explicit DynarmicExclusiveMonitor(std::size_t core_count); + explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count); ~DynarmicExclusiveMonitor() override; void SetExclusive(std::size_t core_index, VAddr addr) override; @@ -79,6 +82,7 @@ public: private: friend class ARM_Dynarmic; Dynarmic::A64::ExclusiveMonitor monitor; + Memory::Memory& memory; }; } // namespace Core diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index d4f41bfc1..48182c99a 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -60,17 +60,18 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si return false; } -ARM_Unicorn::ARM_Unicorn(System& system) : system{system} { +ARM_Unicorn::ARM_Unicorn(System& system) : ARM_Interface{system} { CHECKED(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc)); auto fpv = 3 << 20; CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv)); uc_hook hook{}; - CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1)); - CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0, -1)); + CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX)); + CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0, + UINT64_MAX)); if (GDBStub::IsServerEnabled()) { - CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); + CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX)); last_bkpt_hit = false; } } @@ -154,9 +155,10 @@ void ARM_Unicorn::SetTPIDR_EL0(u64 value) { void ARM_Unicorn::Run() { if (GDBStub::IsServerEnabled()) { - ExecuteInstructions(std::max(4000000, 0)); + ExecuteInstructions(std::max(4000000U, 0U)); } else { - ExecuteInstructions(std::max(system.CoreTiming().GetDowncount(), s64{0})); + ExecuteInstructions( + std::max(std::size_t(system.CoreTiming().GetDowncount()), std::size_t{0})); } } @@ -166,7 +168,7 @@ void ARM_Unicorn::Step() { MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64)); -void ARM_Unicorn::ExecuteInstructions(int num_instructions) { +void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { MICROPROFILE_SCOPE(ARM_Jit_Unicorn); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); system.CoreTiming().AddTicks(num_instructions); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index fe2ffd70c..3c5b155f9 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -34,7 +34,7 @@ public: void LoadContext(const ThreadContext& ctx) override; void PrepareReschedule() override; void ClearExclusiveState() override; - void ExecuteInstructions(int num_instructions); + void ExecuteInstructions(std::size_t num_instructions); void Run() override; void Step() override; void ClearInstructionCache() override; @@ -45,7 +45,6 @@ private: static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data); uc_engine* uc{}; - System& system; GDBStub::BreakpointAddress last_bkpt{}; bool last_bkpt_hit = false; }; diff --git a/src/core/core.cpp b/src/core/core.cpp index eba17218a..c45fb960c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -39,6 +39,7 @@ #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" #include "core/loader/loader.h" +#include "core/memory.h" #include "core/memory/cheat_engine.h" #include "core/perf_stats.h" #include "core/reporter.h" @@ -112,8 +113,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, } struct System::Impl { explicit Impl(System& system) - : kernel{system}, fs_controller{system}, cpu_core_manager{system}, reporter{system}, - applet_manager{system} {} + : kernel{system}, fs_controller{system}, memory{system}, + cpu_core_manager{system}, reporter{system}, applet_manager{system} {} Cpu& CurrentCpuCore() { return cpu_core_manager.GetCurrentCore(); @@ -341,7 +342,8 @@ struct System::Impl { std::unique_ptr<VideoCore::RendererBase> renderer; std::unique_ptr<Tegra::GPU> gpu_core; std::shared_ptr<Tegra::DebugContext> debug_context; - std::unique_ptr<Core::Hardware::InterruptManager> interrupt_manager; + std::unique_ptr<Hardware::InterruptManager> interrupt_manager; + Memory::Memory memory; CpuCoreManager cpu_core_manager; bool is_powered_on = false; bool exit_lock = false; @@ -498,6 +500,14 @@ const ExclusiveMonitor& System::Monitor() const { return impl->cpu_core_manager.GetExclusiveMonitor(); } +Memory::Memory& System::Memory() { + return impl->memory; +} + +const Memory::Memory& System::Memory() const { + return impl->memory; +} + Tegra::GPU& System::GPU() { return *impl->gpu_core; } diff --git a/src/core/core.h b/src/core/core.h index 984074ce3..91184e433 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -7,6 +7,7 @@ #include <cstddef> #include <memory> #include <string> +#include <vector> #include "common/common_types.h" #include "core/file_sys/vfs_types.h" @@ -85,6 +86,10 @@ namespace Core::Hardware { class InterruptManager; } +namespace Memory { +class Memory; +} + namespace Core { class ARM_Interface; @@ -224,6 +229,12 @@ public: /// Gets a constant reference to the exclusive monitor const ExclusiveMonitor& Monitor() const; + /// Gets a mutable reference to the system memory instance. + Memory::Memory& Memory(); + + /// Gets a constant reference to the system memory instance. + const Memory::Memory& Memory() const; + /// Gets a mutable reference to the GPU interface Tegra::GPU& GPU(); diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 233ea572c..cf3fe0b0b 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -66,9 +66,10 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba Cpu::~Cpu() = default; -std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { +std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor( + [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) { #ifdef ARCHITECTURE_x86_64 - return std::make_unique<DynarmicExclusiveMonitor>(num_cores); + return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores); #else // TODO(merry): Passthrough exclusive monitor return nullptr; diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index cafca8df7..78f5021a2 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -24,6 +24,10 @@ namespace Core::Timing { class CoreTiming; } +namespace Memory { +class Memory; +} + namespace Core { class ARM_Interface; @@ -86,7 +90,19 @@ public: void Shutdown(); - static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores); + /** + * Creates an exclusive monitor to handle exclusive reads/writes. + * + * @param memory The current memory subsystem that the monitor may wish + * to keep track of. + * + * @param num_cores The number of cores to assume about the CPU. + * + * @returns The constructed exclusive monitor instance, or nullptr if the current + * CPU backend is unable to use an exclusive monitor. + */ + static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, + std::size_t num_cores); private: void Reschedule(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 0e9570685..aa09fa453 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -17,11 +17,15 @@ namespace Core::Timing { constexpr int MAX_SLICE_LENGTH = 10000; +std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { + return std::make_shared<EventType>(std::move(callback), std::move(name)); +} + struct CoreTiming::Event { s64 time; u64 fifo_order; u64 userdata; - const EventType* type; + std::weak_ptr<EventType> type; // Sort by time, unless the times are the same, in which case sort by // the order added to the queue @@ -54,36 +58,15 @@ void CoreTiming::Initialize() { event_fifo_id = 0; const auto empty_timed_callback = [](u64, s64) {}; - ev_lost = RegisterEvent("_lost_event", empty_timed_callback); + ev_lost = CreateEvent("_lost_event", empty_timed_callback); } void CoreTiming::Shutdown() { ClearPendingEvents(); - UnregisterAllEvents(); -} - -EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) { - std::lock_guard guard{inner_mutex}; - // check for existing type with same name. - // we want event type names to remain unique so that we can use them for serialization. - ASSERT_MSG(event_types.find(name) == event_types.end(), - "CoreTiming Event \"{}\" is already registered. Events should only be registered " - "during Init to avoid breaking save states.", - name.c_str()); - - auto info = event_types.emplace(name, EventType{callback, nullptr}); - EventType* event_type = &info.first->second; - event_type->name = &info.first->first; - return event_type; -} - -void CoreTiming::UnregisterAllEvents() { - ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending"); - event_types.clear(); } -void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) { - ASSERT(event_type != nullptr); +void CoreTiming::ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type, + u64 userdata) { std::lock_guard guard{inner_mutex}; const s64 timeout = GetTicks() + cycles_into_future; @@ -93,13 +76,15 @@ void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_ty } event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); + std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); } -void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) { +void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) { std::lock_guard guard{inner_mutex}; + const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { - return e.type == event_type && e.userdata == userdata; + return e.type.lock().get() == event_type.get() && e.userdata == userdata; }); // Removing random items breaks the invariant so we have to re-establish it. @@ -130,10 +115,12 @@ void CoreTiming::ClearPendingEvents() { event_queue.clear(); } -void CoreTiming::RemoveEvent(const EventType* event_type) { +void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) { std::lock_guard guard{inner_mutex}; - const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), - [&](const Event& e) { return e.type == event_type; }); + + const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { + return e.type.lock().get() == event_type.get(); + }); // Removing random items breaks the invariant so we have to re-establish it. if (itr != event_queue.end()) { @@ -181,7 +168,11 @@ void CoreTiming::Advance() { std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); event_queue.pop_back(); inner_mutex.unlock(); - evt.type->callback(evt.userdata, global_timer - evt.time); + + if (auto event_type{evt.type.lock()}) { + event_type->callback(evt.userdata, global_timer - evt.time); + } + inner_mutex.lock(); } diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 3bb88c810..d50f4eb8a 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -6,11 +6,12 @@ #include <chrono> #include <functional> +#include <memory> #include <mutex> #include <optional> #include <string> -#include <unordered_map> #include <vector> + #include "common/common_types.h" #include "common/threadsafe_queue.h" @@ -21,10 +22,13 @@ using TimedCallback = std::function<void(u64 userdata, s64 cycles_late)>; /// Contains the characteristics of a particular event. struct EventType { + EventType(TimedCallback&& callback, std::string&& name) + : callback{std::move(callback)}, name{std::move(name)} {} + /// The event's callback function. TimedCallback callback; /// A pointer to the name of the event. - const std::string* name; + const std::string name; }; /** @@ -57,31 +61,17 @@ public: /// Tears down all timing related functionality. void Shutdown(); - /// Registers a core timing event with the given name and callback. - /// - /// @param name The name of the core timing event to register. - /// @param callback The callback to execute for the event. - /// - /// @returns An EventType instance representing the registered event. - /// - /// @pre The name of the event being registered must be unique among all - /// registered events. - /// - EventType* RegisterEvent(const std::string& name, TimedCallback callback); - - /// Unregisters all registered events thus far. Note: not thread unsafe - void UnregisterAllEvents(); - /// After the first Advance, the slice lengths and the downcount will be reduced whenever an /// event is scheduled earlier than the current values. /// /// Scheduling from a callback will not update the downcount until the Advance() completes. - void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0); + void ScheduleEvent(s64 cycles_into_future, const std::shared_ptr<EventType>& event_type, + u64 userdata = 0); - void UnscheduleEvent(const EventType* event_type, u64 userdata); + void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); /// We only permit one event of each type in the queue at a time. - void RemoveEvent(const EventType* event_type); + void RemoveEvent(const std::shared_ptr<EventType>& event_type); void ForceExceptionCheck(s64 cycles); @@ -148,13 +138,18 @@ private: std::vector<Event> event_queue; u64 event_fifo_id = 0; - // Stores each element separately as a linked list node so pointers to elements - // remain stable regardless of rehashes/resizing. - std::unordered_map<std::string, EventType> event_types; - - EventType* ev_lost = nullptr; + std::shared_ptr<EventType> ev_lost; std::mutex inner_mutex; }; +/// Creates a core timing event with the given name and callback. +/// +/// @param name The name of the core timing event to create. +/// @param callback The callback to execute for the event. +/// +/// @returns An EventType instance representing the created event. +/// +std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback); + } // namespace Core::Timing diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp index 8efd410bb..f04a34133 100644 --- a/src/core/cpu_core_manager.cpp +++ b/src/core/cpu_core_manager.cpp @@ -25,7 +25,7 @@ CpuCoreManager::~CpuCoreManager() = default; void CpuCoreManager::Initialize() { barrier = std::make_unique<CpuBarrier>(); - exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); + exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size()); for (std::size_t index = 0; index < cores.size(); ++index) { cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 222fc95ba..87e6a1fd3 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -22,6 +22,7 @@ #include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "core/core.h" #include "core/crypto/aes_util.h" #include "core/crypto/key_manager.h" @@ -378,8 +379,9 @@ std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save) { template <size_t size> static std::array<u8, size> operator^(const std::array<u8, size>& lhs, const std::array<u8, size>& rhs) { - std::array<u8, size> out{}; - std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(), std::bit_xor<>()); + std::array<u8, size> out; + std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(), + [](u8 lhs, u8 rhs) { return u8(lhs ^ rhs); }); return out; } @@ -396,7 +398,7 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) { while (out.size() < target_size) { out.resize(out.size() + 0x20); seed_exp[in_size + 3] = static_cast<u8>(i); - mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); + mbedtls_sha256_ret(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0); ++i; } @@ -538,7 +540,7 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { Key128 key = Common::HexStringToArray<16>(out[1]); s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key; } else { - std::transform(out[0].begin(), out[0].end(), out[0].begin(), ::tolower); + out[0] = Common::ToLower(out[0]); if (s128_file_id.find(out[0]) != s128_file_id.end()) { const auto index = s128_file_id.at(out[0]); Key128 key = Common::HexStringToArray<16>(out[1]); @@ -668,23 +670,27 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, const std::array<u8, Size>& key) { const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); std::string filename = "title.keys_autogenerated"; - if (category == KeyCategory::Standard) + if (category == KeyCategory::Standard) { filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated"; - else if (category == KeyCategory::Console) + } else if (category == KeyCategory::Console) { filename = "console.keys_autogenerated"; - const auto add_info_text = !FileUtil::Exists(yuzu_keys_dir + DIR_SEP + filename); - FileUtil::CreateFullPath(yuzu_keys_dir + DIR_SEP + filename); - std::ofstream file(yuzu_keys_dir + DIR_SEP + filename, std::ios::app); - if (!file.is_open()) + } + + const auto path = yuzu_keys_dir + DIR_SEP + filename; + const auto add_info_text = !FileUtil::Exists(path); + FileUtil::CreateFullPath(path); + FileUtil::IOFile file{path, "a"}; + if (!file.IsOpen()) { return; + } if (add_info_text) { - file - << "# This file is autogenerated by Yuzu\n" - << "# It serves to store keys that were automatically generated from the normal keys\n" - << "# If you are experiencing issues involving keys, it may help to delete this file\n"; + file.WriteString( + "# This file is autogenerated by Yuzu\n" + "# It serves to store keys that were automatically generated from the normal keys\n" + "# If you are experiencing issues involving keys, it may help to delete this file\n"); } - file << fmt::format("\n{} = {}", keyname, Common::HexToString(key)); + file.WriteString(fmt::format("\n{} = {}", keyname, Common::HexToString(key))); AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, category == KeyCategory::Title); } @@ -944,12 +950,10 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) { return; } - Key128 rsa_oaep_kek{}; - std::transform(seed3.begin(), seed3.end(), mask0.begin(), rsa_oaep_kek.begin(), - std::bit_xor<>()); - - if (rsa_oaep_kek == Key128{}) + const Key128 rsa_oaep_kek = seed3 ^ mask0; + if (rsa_oaep_kek == Key128{}) { return; + } SetKey(S128KeyType::Source, rsa_oaep_kek, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration)); diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp index 594cd82c5..d64302f2e 100644 --- a/src/core/crypto/partition_data_manager.cpp +++ b/src/core/crypto/partition_data_manager.cpp @@ -161,7 +161,7 @@ std::array<u8, key_size> FindKeyFromHex(const std::vector<u8>& binary, std::array<u8, 0x20> temp{}; for (size_t i = 0; i < binary.size() - key_size; ++i) { - mbedtls_sha256(binary.data() + i, key_size, temp.data(), 0); + mbedtls_sha256_ret(binary.data() + i, key_size, temp.data(), 0); if (temp != hash) continue; @@ -189,7 +189,7 @@ static std::array<Key128, 0x20> FindEncryptedMasterKeyFromHex(const std::vector< AESCipher<Key128> cipher(key, Mode::ECB); for (size_t i = 0; i < binary.size() - 0x10; ++i) { cipher.Transcode(binary.data() + i, dec_temp.size(), dec_temp.data(), Op::Decrypt); - mbedtls_sha256(dec_temp.data(), dec_temp.size(), temp.data(), 0); + mbedtls_sha256_ret(dec_temp.data(), dec_temp.size(), temp.data(), 0); for (size_t k = 0; k < out.size(); ++k) { if (temp == master_key_hashes[k]) { @@ -204,11 +204,12 @@ static std::array<Key128, 0x20> FindEncryptedMasterKeyFromHex(const std::vector< FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir, const std::string& name) { - auto upper = name; - std::transform(upper.begin(), upper.end(), upper.begin(), [](u8 c) { return std::toupper(c); }); + const auto upper = Common::ToUpper(name); + for (const auto& fname : {name, name + ".bin", upper, upper + ".BIN"}) { - if (dir->GetFile(fname) != nullptr) + if (dir->GetFile(fname) != nullptr) { return dir->GetFile(fname); + } } return nullptr; diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 7b5c509fb..0d73eecc9 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h @@ -15,7 +15,7 @@ namespace FileSys { -enum EntryType : u8 { +enum class EntryType : u8 { Directory = 0, File = 1, }; diff --git a/src/core/file_sys/kernel_executable.cpp b/src/core/file_sys/kernel_executable.cpp index 371300684..76313679d 100644 --- a/src/core/file_sys/kernel_executable.cpp +++ b/src/core/file_sys/kernel_executable.cpp @@ -147,7 +147,7 @@ std::vector<u32> KIP::GetKernelCapabilities() const { } s32 KIP::GetMainThreadPriority() const { - return header.main_thread_priority; + return static_cast<s32>(header.main_thread_priority); } u32 KIP::GetMainThreadStackSize() const { diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index df0ecb15c..e226e9711 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -76,7 +76,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { const auto& disabled = Settings::values.disabled_addons[title_id]; const auto update_disabled = - std::find(disabled.begin(), disabled.end(), "Update") != disabled.end(); + std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); // Game Updates const auto update_tid = GetUpdateTitleID(title_id); @@ -127,7 +127,7 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD std::vector<VirtualFile> out; out.reserve(patch_dirs.size()); for (const auto& subdir : patch_dirs) { - if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end()) + if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) continue; auto exefs_dir = subdir->GetSubdirectory("exefs"); @@ -284,12 +284,17 @@ std::vector<Memory::CheatEntry> PatchManager::CreateCheatList( return {}; } + const auto& disabled = Settings::values.disabled_addons[title_id]; auto patch_dirs = load_dir->GetSubdirectories(); std::sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); std::vector<Memory::CheatEntry> out; for (const auto& subdir : patch_dirs) { + if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) { + continue; + } + auto cheats_dir = subdir->GetSubdirectory("cheats"); if (cheats_dir != nullptr) { auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true); @@ -331,8 +336,9 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t layers.reserve(patch_dirs.size() + 1); layers_ext.reserve(patch_dirs.size() + 1); for (const auto& subdir : patch_dirs) { - if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end()) + if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) != disabled.cend()) { continue; + } auto romfs_dir = subdir->GetSubdirectory("romfs"); if (romfs_dir != nullptr) @@ -381,7 +387,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content const auto& disabled = Settings::values.disabled_addons[title_id]; const auto update_disabled = - std::find(disabled.begin(), disabled.end(), "Update") != disabled.end(); + std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); if (!update_disabled && update != nullptr) { const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); @@ -431,7 +437,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam auto [nacp, discard_icon_file] = update.GetControlMetadata(); const auto update_disabled = - std::find(disabled.begin(), disabled.end(), "Update") != disabled.end(); + std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); const auto update_label = update_disabled ? "[D] Update" : "Update"; if (nacp != nullptr) { diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 7310b3602..1d6c30962 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -52,14 +52,14 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { } void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, - u8 main_thread_prio, u8 main_thread_core, + s32 main_thread_prio, u32 main_thread_core, u32 main_thread_stack_size, u64 title_id, u64 filesystem_permissions, KernelCapabilityDescriptors capabilities) { npdm_header.has_64_bit_instructions.Assign(is_64_bit); npdm_header.address_space_type.Assign(address_space); - npdm_header.main_thread_priority = main_thread_prio; - npdm_header.main_thread_cpu = main_thread_core; + npdm_header.main_thread_priority = static_cast<u8>(main_thread_prio); + npdm_header.main_thread_cpu = static_cast<u8>(main_thread_core); npdm_header.main_stack_size = main_thread_stack_size; aci_header.title_id = title_id; aci_file_access.permissions = filesystem_permissions; diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 88ec97d85..f8759a396 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h @@ -47,8 +47,8 @@ public: Loader::ResultStatus Load(VirtualFile file); // Load from parameters instead of NPDM file, used for KIP - void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, u8 main_thread_prio, - u8 main_thread_core, u32 main_thread_stack_size, u64 title_id, + void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, s32 main_thread_prio, + u32 main_thread_core, u32 main_thread_stack_size, u64 title_id, u64 filesystem_permissions, KernelCapabilityDescriptors capabilities); bool Is64BitProgram() const; diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index ac3fbd849..6e9cf67ef 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -62,7 +62,7 @@ static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bo Common::HexToString(nca_id, second_hex_upper)); Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); + mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0); return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0], Common::HexToString(nca_id, second_hex_upper)); } @@ -141,7 +141,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const { } Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256(id.data(), id.size(), hash.data(), 0); + mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); const auto dirname = fmt::format("000000{:02X}", hash[0]); const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); @@ -165,7 +165,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const { } Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256(id.data(), id.size(), hash.data(), 0); + mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); const auto dirname = fmt::format("000000{:02X}", hash[0]); const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); @@ -603,7 +603,7 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, OptionalHeader opt_header{0, 0}; ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}}; const auto& data = nca.GetBaseFile()->ReadBytes(0x100000); - mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); + mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); memcpy(&c_rec.nca_id, &c_rec.hash, 16); const CNMT new_cnmt(header, opt_header, {c_rec}, {}); if (!RawInstallYuzuMeta(new_cnmt)) @@ -626,7 +626,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti id = *override_id; } else { const auto& data = in->ReadBytes(0x100000); - mbedtls_sha256(data.data(), data.size(), hash.data(), 0); + mbedtls_sha256_ret(data.data(), data.size(), hash.data(), 0); memcpy(id.data(), hash.data(), 16); } diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index ebbdf081e..c909d1ce4 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <memory> + #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/fsmitm_romfsbuild.h" @@ -12,7 +14,7 @@ #include "core/file_sys/vfs_vector.h" namespace FileSys { - +namespace { constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF; struct TableLocation { @@ -51,7 +53,7 @@ struct FileEntry { static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); template <typename Entry> -static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { +std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { Entry entry{}; if (file->ReadObject(&entry, offset) != sizeof(Entry)) return {}; @@ -99,6 +101,7 @@ void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file this_dir_offset = entry.first.sibling; } } +} // Anonymous namespace VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { RomFSHeader header{}; diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 1c89be8a4..2fd07ed04 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h @@ -5,10 +5,6 @@ #pragma once #include <array> -#include <map> -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/swap.h" #include "core/file_sys/vfs.h" namespace FileSys { diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 4bd2e6183..418a39a7e 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -71,12 +71,12 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, if (res == nullptr) { // TODO(DarkLordZach): Find the right error code to use here - return ResultCode(-1); + return RESULT_UNKNOWN; } const auto romfs = res->GetRomFS(); if (romfs == nullptr) { // TODO(DarkLordZach): Find the right error code to use here - return ResultCode(-1); + return RESULT_UNKNOWN; } return MakeResult<VirtualFile>(romfs); } diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index e2a7eaf7b..f3def93ab 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -90,7 +90,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space, // Return an error if the save data doesn't actually exist. if (out == nullptr) { // TODO(DarkLordZach): Find out correct error code. - return ResultCode(-1); + return RESULT_UNKNOWN; } return MakeResult<VirtualDir>(std::move(out)); @@ -111,7 +111,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, // Return an error if the save data doesn't actually exist. if (out == nullptr) { // TODO(Subv): Find out correct error code. - return ResultCode(-1); + return RESULT_UNKNOWN; } return MakeResult<VirtualDir>(std::move(out)); diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp index 8bdaa7e4a..11d1978ea 100644 --- a/src/core/file_sys/vfs_libzip.cpp +++ b/src/core/file_sys/vfs_libzip.cpp @@ -27,7 +27,7 @@ VirtualDir ExtractZIP(VirtualFile file) { std::shared_ptr<VectorVfsDirectory> out = std::make_shared<VectorVfsDirectory>(); - const auto num_entries = zip_get_num_entries(zip.get(), 0); + const auto num_entries = static_cast<std::size_t>(zip_get_num_entries(zip.get(), 0)); zip_stat_t stat{}; zip_stat_init(&stat); diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index f5f8b91c9..86e06ccb9 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -7,12 +7,13 @@ #include <cstring> #include <regex> #include <string> + #include <mbedtls/md.h> #include <mbedtls/sha256.h> -#include "common/assert.h" + #include "common/file_util.h" #include "common/hex_util.h" -#include "common/logging/log.h" +#include "common/string_util.h" #include "core/crypto/aes_util.h" #include "core/crypto/xts_encryption_layer.h" #include "core/file_sys/partition_filesystem.h" @@ -53,18 +54,15 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m return; } - std::string two_dir = match[1]; - std::string nca_id = match[2]; - std::transform(two_dir.begin(), two_dir.end(), two_dir.begin(), ::toupper); - std::transform(nca_id.begin(), nca_id.end(), nca_id.begin(), ::tolower); - + const std::string two_dir = Common::ToUpper(match[1]); + const std::string nca_id = Common::ToLower(match[2]); status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id)); } NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { Core::Crypto::SHA256Hash hash{}; - mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); + mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0); status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0], Common::HexToString(nca_id, false))); } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 20bb50868..37cb28848 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -468,7 +468,8 @@ static u8 ReadByte() { /// Calculate the checksum of the current command buffer. static u8 CalculateChecksum(const u8* buffer, std::size_t length) { - return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>())); + return static_cast<u8>(std::accumulate(buffer, buffer + length, u8{0}, + [](u8 lhs, u8 rhs) { return u8(lhs + rhs); })); } /** @@ -507,8 +508,9 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) { bp->second.len, bp->second.addr, static_cast<int>(type)); if (type == BreakpointType::Execute) { - Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + auto& system = Core::System::GetInstance(); + system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); + system.InvalidateCpuInstructionCaches(); } p.erase(addr); } @@ -968,12 +970,13 @@ static void ReadMemory() { SendReply("E01"); } - if (!Memory::IsValidVirtualAddress(addr)) { + auto& memory = Core::System::GetInstance().Memory(); + if (!memory.IsValidVirtualAddress(addr)) { return SendReply("E00"); } std::vector<u8> data(len); - Memory::ReadBlock(addr, data.data(), len); + memory.ReadBlock(addr, data.data(), len); MemToGdbHex(reply, data.data(), len); reply[len * 2] = '\0'; @@ -983,22 +986,23 @@ static void ReadMemory() { /// Modify location in memory with data received from the gdb client. static void WriteMemory() { auto start_offset = command_buffer + 1; - auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); - VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); + const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); + const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); start_offset = addr_pos + 1; - auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); - u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset)); + const auto len_pos = std::find(start_offset, command_buffer + command_length, ':'); + const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset)); - if (!Memory::IsValidVirtualAddress(addr)) { + auto& system = Core::System::GetInstance(); + auto& memory = system.Memory(); + if (!memory.IsValidVirtualAddress(addr)) { return SendReply("E00"); } std::vector<u8> data(len); - GdbHexToMem(data.data(), len_pos + 1, len); - Memory::WriteBlock(addr, data.data(), len); - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + memory.WriteBlock(addr, data.data(), len); + system.InvalidateCpuInstructionCaches(); SendReply("OK"); } @@ -1054,12 +1058,15 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { breakpoint.active = true; breakpoint.addr = addr; breakpoint.len = len; - Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); + + auto& system = Core::System::GetInstance(); + auto& memory = system.Memory(); + memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; if (type == BreakpointType::Execute) { - Memory::WriteBlock(addr, btrap.data(), btrap.size()); - Core::System::GetInstance().InvalidateCpuInstructionCaches(); + memory.WriteBlock(addr, btrap.data(), btrap.size()); + system.InvalidateCpuInstructionCaches(); } p.insert({addr, breakpoint}); diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp index c2115db2d..c629d9fa1 100644 --- a/src/core/hardware_interrupt_manager.cpp +++ b/src/core/hardware_interrupt_manager.cpp @@ -11,13 +11,12 @@ namespace Core::Hardware { InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { - gpu_interrupt_event = - system.CoreTiming().RegisterEvent("GPUInterrupt", [this](u64 message, s64) { - auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); - const u32 syncpt = static_cast<u32>(message >> 32); - const u32 value = static_cast<u32>(message); - nvdrv->SignalGPUInterruptSyncpt(syncpt, value); - }); + gpu_interrupt_event = Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, s64) { + auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); + const u32 syncpt = static_cast<u32>(message >> 32); + const u32 value = static_cast<u32>(message); + nvdrv->SignalGPUInterruptSyncpt(syncpt, value); + }); } InterruptManager::~InterruptManager() = default; diff --git a/src/core/hardware_interrupt_manager.h b/src/core/hardware_interrupt_manager.h index 494db883a..5fa306ae0 100644 --- a/src/core/hardware_interrupt_manager.h +++ b/src/core/hardware_interrupt_manager.h @@ -4,6 +4,8 @@ #pragma once +#include <memory> + #include "common/common_types.h" namespace Core { @@ -25,7 +27,7 @@ public: private: Core::System& system; - Core::Timing::EventType* gpu_interrupt_event{}; + std::shared_ptr<Core::Timing::EventType> gpu_interrupt_event; }; } // namespace Core::Hardware diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 5bb139483..0dc6a4a43 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -19,6 +19,7 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h" #include "core/hle/result.h" namespace IPC { @@ -139,10 +140,9 @@ public: context->AddDomainObject(std::move(iface)); } else { auto& kernel = Core::System::GetInstance().Kernel(); - auto [server, client] = - Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName()); - iface->ClientConnected(server); + auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName()); context->AddMoveObject(std::move(client)); + iface->ClientConnected(std::move(server)); } } @@ -203,10 +203,10 @@ public: void PushRaw(const T& value); template <typename... O> - void PushMoveObjects(Kernel::SharedPtr<O>... pointers); + void PushMoveObjects(std::shared_ptr<O>... pointers); template <typename... O> - void PushCopyObjects(Kernel::SharedPtr<O>... pointers); + void PushCopyObjects(std::shared_ptr<O>... pointers); private: u32 normal_params_size{}; @@ -298,7 +298,7 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value } template <typename... O> -inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) { +inline void ResponseBuilder::PushCopyObjects(std::shared_ptr<O>... pointers) { auto objects = {pointers...}; for (auto& object : objects) { context->AddCopyObject(std::move(object)); @@ -306,7 +306,7 @@ inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) { } template <typename... O> -inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) { +inline void ResponseBuilder::PushMoveObjects(std::shared_ptr<O>... pointers) { auto objects = {pointers...}; for (auto& object : objects) { context->AddMoveObject(std::move(object)); @@ -357,10 +357,10 @@ public: T PopRaw(); template <typename T> - Kernel::SharedPtr<T> GetMoveObject(std::size_t index); + std::shared_ptr<T> GetMoveObject(std::size_t index); template <typename T> - Kernel::SharedPtr<T> GetCopyObject(std::size_t index); + std::shared_ptr<T> GetCopyObject(std::size_t index); template <class T> std::shared_ptr<T> PopIpcInterface() { @@ -465,12 +465,12 @@ void RequestParser::Pop(First& first_value, Other&... other_values) { } template <typename T> -Kernel::SharedPtr<T> RequestParser::GetMoveObject(std::size_t index) { +std::shared_ptr<T> RequestParser::GetMoveObject(std::size_t index) { return context->GetMoveObject<T>(index); } template <typename T> -Kernel::SharedPtr<T> RequestParser::GetCopyObject(std::size_t index) { +std::shared_ptr<T> RequestParser::GetCopyObject(std::size_t index) { return context->GetCopyObject<T>(index); } diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index de0a9064e..98d07fa5b 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -21,7 +21,7 @@ namespace Kernel { namespace { // Wake up num_to_wake (or all) threads in a vector. -void WakeThreads(const std::vector<SharedPtr<Thread>>& waiting_threads, s32 num_to_wake) { +void WakeThreads(const std::vector<std::shared_ptr<Thread>>& waiting_threads, s32 num_to_wake) { auto& system = Core::System::GetInstance(); // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. @@ -59,35 +59,41 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v } ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { - const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); + const std::vector<std::shared_ptr<Thread>> waiting_threads = + GetThreadsWaitingOnAddress(address); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + auto& memory = system.Memory(); + // Ensure that we can write to the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } - if (static_cast<s32>(Memory::Read32(address)) != value) { + if (static_cast<s32>(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - Memory::Write32(address, static_cast<u32>(value + 1)); + memory.Write32(address, static_cast<u32>(value + 1)); return SignalToAddressOnly(address, num_to_wake); } ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + auto& memory = system.Memory(); + // Ensure that we can write to the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } // Get threads waiting on the address. - const std::vector<SharedPtr<Thread>> waiting_threads = GetThreadsWaitingOnAddress(address); + const std::vector<std::shared_ptr<Thread>> waiting_threads = + GetThreadsWaitingOnAddress(address); // Determine the modified value depending on the waiting count. s32 updated_value; @@ -107,11 +113,11 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a } } - if (static_cast<s32>(Memory::Read32(address)) != value) { + if (static_cast<s32>(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - Memory::Write32(address, static_cast<u32>(updated_value)); + memory.Write32(address, static_cast<u32>(updated_value)); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } @@ -132,18 +138,20 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { + auto& memory = system.Memory(); + // Ensure that we can read the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } - const s32 cur_value = static_cast<s32>(Memory::Read32(address)); + const s32 cur_value = static_cast<s32>(memory.Read32(address)); if (cur_value >= value) { return ERR_INVALID_STATE; } if (should_decrement) { - Memory::Write32(address, static_cast<u32>(cur_value - 1)); + memory.Write32(address, static_cast<u32>(cur_value - 1)); } // Short-circuit without rescheduling, if timeout is zero. @@ -155,15 +163,19 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 } ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { + auto& memory = system.Memory(); + // Ensure that we can read the address. - if (!Memory::IsValidVirtualAddress(address)) { + if (!memory.IsValidVirtualAddress(address)) { return ERR_INVALID_ADDRESS_STATE; } + // Only wait for the address if equal. - if (static_cast<s32>(Memory::Read32(address)) != value) { + if (static_cast<s32>(memory.Read32(address)) != value) { return ERR_INVALID_STATE; } - // Short-circuit without rescheduling, if timeout is zero. + + // Short-circuit without rescheduling if timeout is zero. if (timeout == 0) { return RESULT_TIMEOUT; } @@ -172,21 +184,21 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t } ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { - SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetArbiterWaitAddress(address); current_thread->SetStatus(ThreadStatus::WaitArb); current_thread->InvalidateWakeupCallback(); - current_thread->WakeAfterDelay(timeout); system.PrepareReschedule(current_thread->GetProcessorID()); return RESULT_TIMEOUT; } -std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr address) const { +std::vector<std::shared_ptr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress( + VAddr address) const { // Retrieve all threads that are waiting for this address. - std::vector<SharedPtr<Thread>> threads; + std::vector<std::shared_ptr<Thread>> threads; const auto& scheduler = system.GlobalScheduler(); const auto& thread_list = scheduler.GetThreadList(); @@ -198,7 +210,7 @@ std::vector<SharedPtr<Thread>> AddressArbiter::GetThreadsWaitingOnAddress(VAddr // Sort them by priority, such that the highest priority ones come first. std::sort(threads.begin(), threads.end(), - [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { + [](const std::shared_ptr<Thread>& lhs, const std::shared_ptr<Thread>& rhs) { return lhs->GetPriority() < rhs->GetPriority(); }); diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index ed0d0e69f..608918de5 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -72,7 +72,7 @@ private: ResultCode WaitForAddressImpl(VAddr address, s64 timeout); // Gets the threads waiting on an address. - std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; + std::vector<std::shared_ptr<Thread>> GetThreadsWaitingOnAddress(VAddr address) const; Core::System& system; }; diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 744b1697d..00bb939a0 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -9,38 +9,35 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h" namespace Kernel { ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {} ClientPort::~ClientPort() = default; -SharedPtr<ServerPort> ClientPort::GetServerPort() const { +std::shared_ptr<ServerPort> ClientPort::GetServerPort() const { return server_port; } -ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { - // Note: Threads do not wait for the server endpoint to call - // AcceptSession before returning from this call. - +ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { if (active_sessions >= max_sessions) { return ERR_MAX_CONNECTIONS_REACHED; } active_sessions++; - // Create a new session pair, let the created sessions inherit the parent port's HLE handler. - auto [server, client] = ServerSession::CreateSessionPair(kernel, server_port->GetName(), this); + auto [client, server] = Kernel::Session::Create(kernel, name); if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(server); + server_port->GetHLEHandler()->ClientConnected(std::move(server)); } else { - server_port->AppendPendingSession(server); + server_port->AppendPendingSession(std::move(server)); } // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); - return MakeResult(client); + return MakeResult(std::move(client)); } void ClientPort::ConnectionClosed() { diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 4921ad4f0..715edd18c 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -17,6 +17,9 @@ class ServerPort; class ClientPort final : public Object { public: + explicit ClientPort(KernelCore& kernel); + ~ClientPort() override; + friend class ServerPort; std::string GetTypeName() const override { return "ClientPort"; @@ -30,7 +33,7 @@ public: return HANDLE_TYPE; } - SharedPtr<ServerPort> GetServerPort() const; + std::shared_ptr<ServerPort> GetServerPort() const; /** * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's @@ -38,7 +41,7 @@ public: * waiting on it to awake. * @returns ClientSession The client endpoint of the created Session pair, or error code. */ - ResultVal<SharedPtr<ClientSession>> Connect(); + ResultVal<std::shared_ptr<ClientSession>> Connect(); /** * Signifies that a previously active connection has been closed, @@ -47,10 +50,7 @@ public: void ConnectionClosed(); private: - explicit ClientPort(KernelCore& kernel); - ~ClientPort() override; - - SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. + std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port. u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have u32 active_sessions = 0; ///< Number of currently open sessions to this port std::string name; ///< Name of client port (optional) diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index c17baa50a..4669a14ad 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -12,29 +12,44 @@ namespace Kernel { -ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} +ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} + ClientSession::~ClientSession() { // This destructor will be called automatically when the last ClientSession handle is closed by // the emulated application. - - // A local reference to the ServerSession is necessary to guarantee it - // will be kept alive until after ClientDisconnected() returns. - SharedPtr<ServerSession> server = parent->server; - if (server) { - server->ClientDisconnected(); + if (parent->Server()) { + parent->Server()->ClientDisconnected(); } +} + +bool ClientSession::ShouldWait(const Thread* thread) const { + UNIMPLEMENTED(); + return {}; +} - parent->client = nullptr; +void ClientSession::Acquire(Thread* thread) { + UNIMPLEMENTED(); } -ResultCode ClientSession::SendSyncRequest(SharedPtr<Thread> thread) { +ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name) { + std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)}; + + client_session->name = std::move(name); + client_session->parent = std::move(parent); + + return MakeResult(std::move(client_session)); +} + +ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { // Keep ServerSession alive until we're done working with it. - SharedPtr<ServerSession> server = parent->server; - if (server == nullptr) + if (!parent->Server()) { return ERR_SESSION_CLOSED_BY_REMOTE; + } // Signal the server session that new data is available - return server->HandleSyncRequest(std::move(thread)); + return parent->Server()->HandleSyncRequest(std::move(thread), memory); } } // namespace Kernel diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 09cdff588..b4289a9a8 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -6,20 +6,28 @@ #include <memory> #include <string> -#include "core/hle/kernel/object.h" + +#include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h" union ResultCode; +namespace Memory { +class Memory; +} + namespace Kernel { class KernelCore; class Session; -class ServerSession; class Thread; -class ClientSession final : public Object { +class ClientSession final : public WaitObject { public: - friend class ServerSession; + explicit ClientSession(KernelCore& kernel); + ~ClientSession() override; + + friend class Session; std::string GetTypeName() const override { return "ClientSession"; @@ -34,11 +42,16 @@ public: return HANDLE_TYPE; } - ResultCode SendSyncRequest(SharedPtr<Thread> thread); + ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); + + bool ShouldWait(const Thread* thread) const override; + + void Acquire(Thread* thread) override; private: - explicit ClientSession(KernelCore& kernel); - ~ClientSession() override; + static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name = "Unknown"); /// The parent session, which links to the server endpoint. std::shared_ptr<Session> parent; diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 2cc5d536b..e441a27fc 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -44,7 +44,7 @@ ResultCode HandleTable::SetSize(s32 handle_table_size) { return RESULT_SUCCESS; } -ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { +ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) { DEBUG_ASSERT(obj != nullptr); const u16 slot = next_free_slot; @@ -70,7 +70,7 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { } ResultVal<Handle> HandleTable::Duplicate(Handle handle) { - SharedPtr<Object> object = GetGeneric(handle); + std::shared_ptr<Object> object = GetGeneric(handle); if (object == nullptr) { LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle); return ERR_INVALID_HANDLE; @@ -99,11 +99,11 @@ bool HandleTable::IsValid(Handle handle) const { return slot < table_size && objects[slot] != nullptr && generations[slot] == generation; } -SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { +std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { - return GetCurrentThread(); + return SharedFrom(GetCurrentThread()); } else if (handle == CurrentProcess) { - return Core::System::GetInstance().CurrentProcess(); + return SharedFrom(Core::System::GetInstance().CurrentProcess()); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 44901391b..9fcb4cc15 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -68,7 +68,7 @@ public: * @return The created Handle or one of the following errors: * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded. */ - ResultVal<Handle> Create(SharedPtr<Object> obj); + ResultVal<Handle> Create(std::shared_ptr<Object> obj); /** * Returns a new handle that points to the same object as the passed in handle. @@ -92,7 +92,7 @@ public: * Looks up a handle. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. */ - SharedPtr<Object> GetGeneric(Handle handle) const; + std::shared_ptr<Object> GetGeneric(Handle handle) const; /** * Looks up a handle while verifying its type. @@ -100,7 +100,7 @@ public: * type differs from the requested one. */ template <class T> - SharedPtr<T> Get(Handle handle) const { + std::shared_ptr<T> Get(Handle handle) const { return DynamicObjectCast<T>(GetGeneric(handle)); } @@ -109,7 +109,7 @@ public: private: /// Stores the Object referenced by the handle or null if the slot is empty. - std::array<SharedPtr<Object>, MAX_COUNT> objects; + std::array<std::shared_ptr<Object>, MAX_COUNT> objects; /** * The value of `next_generation` when the handle was created, used to check for validity. For diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index a7b5849b0..2db28dcf0 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -32,23 +32,25 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) { +void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) { server_session->SetHleHandler(shared_from_this()); connected_sessions.push_back(std::move(server_session)); } -void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& server_session) { +void SessionRequestHandler::ClientDisconnected( + const std::shared_ptr<ServerSession>& server_session) { server_session->SetHleHandler(nullptr); boost::range::remove_erase(connected_sessions, server_session); } -SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( +std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, - SharedPtr<WritableEvent> writable_event) { + std::shared_ptr<WritableEvent> writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetWakeupCallback([context = *this, callback]( - ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index) mutable -> bool { + thread->SetWakeupCallback([context = *this, callback](ThreadWakeupReason reason, + std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, + std::size_t index) mutable -> bool { ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); callback(thread, context, reason); context.WriteToOutgoingCommandBuffer(*thread); @@ -72,11 +74,13 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread( thread->WakeAfterDelay(timeout); } + is_thread_waiting = true; + return writable_event; } -HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session, - SharedPtr<Thread> thread) +HLERequestContext::HLERequestContext(std::shared_ptr<Kernel::ServerSession> server_session, + std::shared_ptr<Thread> thread) : server_session(std::move(server_session)), thread(std::move(thread)) { cmd_buf[0] = 0; } @@ -212,10 +216,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { auto& owner_process = *thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); + auto& memory = Core::System::GetInstance().Memory(); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; - Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); // The header was already built in the internal command buffer. Attempt to parse it to verify // the integrity and then copy it over to the target command buffer. @@ -271,8 +276,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { } // Copy the translated command buffer back into the thread's command buffer area. - Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), - dst_cmdbuf.size() * sizeof(u32)); + memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); return RESULT_SUCCESS; } @@ -280,15 +285,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { std::vector<u8> HLERequestContext::ReadBuffer(int buffer_index) const { std::vector<u8> buffer; const bool is_buffer_a{BufferDescriptorA().size() && BufferDescriptorA()[buffer_index].Size()}; + auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_a) { buffer.resize(BufferDescriptorA()[buffer_index].Size()); - Memory::ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), - buffer.size()); + memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); } else { buffer.resize(BufferDescriptorX()[buffer_index].Size()); - Memory::ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), - buffer.size()); + memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); } return buffer; @@ -309,10 +313,11 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, size = buffer_size; // TODO(bunnei): This needs to be HW tested } + auto& memory = Core::System::GetInstance().Memory(); if (is_buffer_b) { - Memory::WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); + memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { - Memory::WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); + memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } return size; diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index ccf5e56aa..050ad8fd7 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include <functional> #include <memory> #include <optional> #include <string> @@ -60,20 +61,20 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected(SharedPtr<ServerSession> server_session); + void ClientConnected(std::shared_ptr<ServerSession> server_session); /** * Signals that a client has just disconnected from this HLE handler and releases the * associated ServerSession. * @param server_session ServerSession associated with the connection. */ - void ClientDisconnected(const SharedPtr<ServerSession>& server_session); + void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session); protected: /// List of sessions that are connected to this handler. /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list /// for the duration of the connection. - std::vector<SharedPtr<ServerSession>> connected_sessions; + std::vector<std::shared_ptr<ServerSession>> connected_sessions; }; /** @@ -97,7 +98,8 @@ protected: */ class HLERequestContext { public: - explicit HLERequestContext(SharedPtr<ServerSession> session, SharedPtr<Thread> thread); + explicit HLERequestContext(std::shared_ptr<ServerSession> session, + std::shared_ptr<Thread> thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -109,12 +111,12 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - const SharedPtr<Kernel::ServerSession>& Session() const { + const std::shared_ptr<Kernel::ServerSession>& Session() const { return server_session; } - using WakeupCallback = std::function<void(SharedPtr<Thread> thread, HLERequestContext& context, - ThreadWakeupReason reason)>; + using WakeupCallback = std::function<void( + std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; /** * Puts the specified guest thread to sleep until the returned event is signaled or until the @@ -129,9 +131,9 @@ public: * created. * @returns Event that when signaled will resume the thread and call the callback function. */ - SharedPtr<WritableEvent> SleepClientThread(const std::string& reason, u64 timeout, - WakeupCallback&& callback, - SharedPtr<WritableEvent> writable_event = nullptr); + std::shared_ptr<WritableEvent> SleepClientThread( + const std::string& reason, u64 timeout, WakeupCallback&& callback, + std::shared_ptr<WritableEvent> writable_event = nullptr); /// Populates this context with data from the requesting process/thread. ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, @@ -209,20 +211,20 @@ public: std::size_t GetWriteBufferSize(int buffer_index = 0) const; template <typename T> - SharedPtr<T> GetCopyObject(std::size_t index) { + std::shared_ptr<T> GetCopyObject(std::size_t index) { return DynamicObjectCast<T>(copy_objects.at(index)); } template <typename T> - SharedPtr<T> GetMoveObject(std::size_t index) { + std::shared_ptr<T> GetMoveObject(std::size_t index) { return DynamicObjectCast<T>(move_objects.at(index)); } - void AddMoveObject(SharedPtr<Object> object) { + void AddMoveObject(std::shared_ptr<Object> object) { move_objects.emplace_back(std::move(object)); } - void AddCopyObject(SharedPtr<Object> object) { + void AddCopyObject(std::shared_ptr<Object> object) { copy_objects.emplace_back(std::move(object)); } @@ -262,15 +264,27 @@ public: std::string Description() const; + Thread& GetThread() { + return *thread; + } + + const Thread& GetThread() const { + return *thread; + } + + bool IsThreadWaiting() const { + return is_thread_waiting; + } + private: void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; - SharedPtr<Kernel::ServerSession> server_session; - SharedPtr<Thread> thread; + std::shared_ptr<Kernel::ServerSession> server_session; + std::shared_ptr<Thread> thread; // TODO(yuriks): Check common usage of this and optimize size accordingly - boost::container::small_vector<SharedPtr<Object>, 8> move_objects; - boost::container::small_vector<SharedPtr<Object>, 8> copy_objects; + boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; + boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; std::optional<IPC::CommandHeader> command_header; @@ -288,6 +302,7 @@ private: u32_le command{}; std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + bool is_thread_waiting{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f94ac150d..1c90546a4 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -40,7 +40,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard lock{HLE::g_hle_lock}; - SharedPtr<Thread> thread = + std::shared_ptr<Thread> thread = system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); if (thread == nullptr) { LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); @@ -53,7 +53,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ thread->GetStatus() == ThreadStatus::WaitHLEEvent) { // Remove the thread from each of its waiting objects' waitlists for (const auto& object : thread->GetWaitObjects()) { - object->RemoveWaitingThread(thread.get()); + object->RemoveWaitingThread(thread); } thread->ClearWaitObjects(); @@ -64,8 +64,11 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ } else if (thread->GetStatus() == ThreadStatus::WaitMutex || thread->GetStatus() == ThreadStatus::WaitCondVar) { thread->SetMutexWaitAddress(0); - thread->SetCondVarWaitAddress(0); thread->SetWaitHandle(0); + if (thread->GetStatus() == ThreadStatus::WaitCondVar) { + thread->GetOwnerProcess()->RemoveConditionVariableThread(thread); + thread->SetCondVarWaitAddress(0); + } auto* const lock_owner = thread->GetLockOwner(); // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance @@ -136,12 +139,12 @@ struct KernelCore::Impl { void InitializeThreads() { thread_wakeup_event_type = - system.CoreTiming().RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); + Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); } void InitializePreemption() { - preemption_event = system.CoreTiming().RegisterEvent( - "PreemptionCallback", [this](u64 userdata, s64 cycles_late) { + preemption_event = + Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) { global_scheduler.PreemptThreads(); s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); system.CoreTiming().ScheduleEvent(time_interval, preemption_event); @@ -151,20 +154,31 @@ struct KernelCore::Impl { system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } + void MakeCurrentProcess(Process* process) { + current_process = process; + + if (process == nullptr) { + return; + } + + system.Memory().SetCurrentPageTable(*process); + } + std::atomic<u32> next_object_id{0}; std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; std::atomic<u64> next_thread_id{1}; // Lists all processes that exist in the current session. - std::vector<SharedPtr<Process>> process_list; + std::vector<std::shared_ptr<Process>> process_list; Process* current_process = nullptr; Kernel::GlobalScheduler global_scheduler; - SharedPtr<ResourceLimit> system_resource_limit; + std::shared_ptr<ResourceLimit> system_resource_limit; + + std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type; + std::shared_ptr<Core::Timing::EventType> preemption_event; - Core::Timing::EventType* thread_wakeup_event_type = nullptr; - Core::Timing::EventType* preemption_event = nullptr; // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, // allowing us to simply use a pool index or similar. Kernel::HandleTable thread_wakeup_callback_handle_table; @@ -190,26 +204,21 @@ void KernelCore::Shutdown() { impl->Shutdown(); } -SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { +std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const { return impl->system_resource_limit; } -SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { +std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable( + Handle handle) const { return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle); } -void KernelCore::AppendNewProcess(SharedPtr<Process> process) { +void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { impl->process_list.push_back(std::move(process)); } void KernelCore::MakeCurrentProcess(Process* process) { - impl->current_process = process; - - if (process == nullptr) { - return; - } - - Memory::SetCurrentPageTable(*process); + impl->MakeCurrentProcess(process); } Process* KernelCore::CurrentProcess() { @@ -220,7 +229,7 @@ const Process* KernelCore::CurrentProcess() const { return impl->current_process; } -const std::vector<SharedPtr<Process>>& KernelCore::GetProcessList() const { +const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const { return impl->process_list; } @@ -232,7 +241,7 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { return impl->global_scheduler; } -void KernelCore::AddNamedPort(std::string name, SharedPtr<ClientPort> port) { +void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { impl->named_ports.emplace(std::move(name), std::move(port)); } @@ -265,7 +274,7 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -Core::Timing::EventType* KernelCore::ThreadWakeupCallbackEventType() const { +const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallbackEventType() const { return impl->thread_wakeup_event_type; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c4397fc77..babb531c6 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -6,6 +6,7 @@ #include <string> #include <unordered_map> +#include <vector> #include "core/hle/kernel/object.h" namespace Core { @@ -30,7 +31,7 @@ class Thread; /// Represents a single instance of the kernel. class KernelCore { private: - using NamedPortTable = std::unordered_map<std::string, SharedPtr<ClientPort>>; + using NamedPortTable = std::unordered_map<std::string, std::shared_ptr<ClientPort>>; public: /// Constructs an instance of the kernel using the given System @@ -56,13 +57,13 @@ public: void Shutdown(); /// Retrieves a shared pointer to the system resource limit instance. - SharedPtr<ResourceLimit> GetSystemResourceLimit() const; + std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. - SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; + std::shared_ptr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; /// Adds the given shared pointer to an internal list of active processes. - void AppendNewProcess(SharedPtr<Process> process); + void AppendNewProcess(std::shared_ptr<Process> process); /// Makes the given process the new current process. void MakeCurrentProcess(Process* process); @@ -74,7 +75,7 @@ public: const Process* CurrentProcess() const; /// Retrieves the list of processes. - const std::vector<SharedPtr<Process>>& GetProcessList() const; + const std::vector<std::shared_ptr<Process>>& GetProcessList() const; /// Gets the sole instance of the global scheduler Kernel::GlobalScheduler& GlobalScheduler(); @@ -83,7 +84,7 @@ public: const Kernel::GlobalScheduler& GlobalScheduler() const; /// Adds a port to the named port table - void AddNamedPort(std::string name, SharedPtr<ClientPort> port); + void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); /// Finds a port within the named port table with the given name. NamedPortTable::iterator FindNamedPort(const std::string& name); @@ -112,7 +113,7 @@ private: u64 CreateNewThreadID(); /// Retrieves the event type used for thread wakeup callbacks. - Core::Timing::EventType* ThreadWakeupCallbackEventType() const; + const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const; /// Provides a reference to the thread wakeup callback handle table. Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 663d0f4b6..061e9bcb0 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -22,10 +22,10 @@ namespace Kernel { /// Returns the number of threads that are waiting for a mutex, and the highest priority one among /// those. -static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread( - const SharedPtr<Thread>& current_thread, VAddr mutex_addr) { +static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThread( + const std::shared_ptr<Thread>& current_thread, VAddr mutex_addr) { - SharedPtr<Thread> highest_priority_thread; + std::shared_ptr<Thread> highest_priority_thread; u32 num_waiters = 0; for (const auto& thread : current_thread->GetMutexWaitingThreads()) { @@ -45,14 +45,14 @@ static std::pair<SharedPtr<Thread>, u32> GetHighestPriorityMutexWaitingThread( } /// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. -static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_thread, - SharedPtr<Thread> new_owner) { +static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr<Thread> current_thread, + std::shared_ptr<Thread> new_owner) { const auto threads = current_thread->GetMutexWaitingThreads(); for (const auto& thread : threads) { if (thread->GetMutexWaitAddress() != mutex_addr) continue; - ASSERT(thread->GetLockOwner() == current_thread); + ASSERT(thread->GetLockOwner() == current_thread.get()); current_thread->RemoveMutexWaiter(thread); if (new_owner != thread) new_owner->AddMutexWaiter(thread); @@ -70,15 +70,16 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, } const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - Thread* const current_thread = system.CurrentScheduler().GetCurrentThread(); - SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); - SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); + std::shared_ptr<Thread> current_thread = + SharedFrom(system.CurrentScheduler().GetCurrentThread()); + std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); + std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another // thread. ASSERT(requesting_thread == current_thread); - const u32 addr_value = Memory::Read32(address); + const u32 addr_value = system.Memory().Read32(address); // If the mutex isn't being held, just return success. if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { @@ -110,12 +111,13 @@ ResultCode Mutex::Release(VAddr address) { return ERR_INVALID_ADDRESS; } - auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); + std::shared_ptr<Thread> current_thread = + SharedFrom(system.CurrentScheduler().GetCurrentThread()); auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); // There are no more threads waiting for the mutex, release it completely. if (thread == nullptr) { - Memory::Write32(address, 0); + system.Memory().Write32(address, 0); return RESULT_SUCCESS; } @@ -130,7 +132,7 @@ ResultCode Mutex::Release(VAddr address) { } // Grant the mutex to the next waiting thread and resume it. - Memory::Write32(address, mutex_value); + system.Memory().Write32(address, mutex_value); ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); thread->ResumeFromWait(); diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 10431e94c..2c571792b 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -27,6 +27,7 @@ bool Object::IsWaitable() const { case HandleType::ResourceLimit: case HandleType::ClientPort: case HandleType::ClientSession: + case HandleType::Session: return false; } diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index a6faeb83b..e3391e2af 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -5,10 +5,9 @@ #pragma once #include <atomic> +#include <memory> #include <string> -#include <boost/smart_ptr/intrusive_ptr.hpp> - #include "common/common_types.h" namespace Kernel { @@ -30,9 +29,10 @@ enum class HandleType : u32 { ServerPort, ClientSession, ServerSession, + Session, }; -class Object : NonCopyable { +class Object : NonCopyable, public std::enable_shared_from_this<Object> { public: explicit Object(KernelCore& kernel); virtual ~Object(); @@ -61,35 +61,24 @@ protected: KernelCore& kernel; private: - friend void intrusive_ptr_add_ref(Object*); - friend void intrusive_ptr_release(Object*); - - std::atomic<u32> ref_count{0}; std::atomic<u32> object_id{0}; }; -// Special functions used by boost::instrusive_ptr to do automatic ref-counting -inline void intrusive_ptr_add_ref(Object* object) { - object->ref_count.fetch_add(1, std::memory_order_relaxed); -} - -inline void intrusive_ptr_release(Object* object) { - if (object->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) { - delete object; - } -} - template <typename T> -using SharedPtr = boost::intrusive_ptr<T>; +std::shared_ptr<T> SharedFrom(T* raw) { + if (raw == nullptr) + return nullptr; + return std::static_pointer_cast<T>(raw->shared_from_this()); +} /** * Attempts to downcast the given Object pointer to a pointer to T. * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T. */ template <typename T> -inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { +inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) { if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { - return boost::static_pointer_cast<T>(object); + return std::static_pointer_cast<T>(object); } return nullptr; } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 12a900bcc..12ea4ebe3 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -38,7 +38,7 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) { auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, owner_process.GetIdealCore(), stack_top, owner_process); - SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); + std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap(); // Register 1 must be a handle to the main thread const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); @@ -100,10 +100,10 @@ private: std::bitset<num_slot_entries> is_slot_used; }; -SharedPtr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { +std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { auto& kernel = system.Kernel(); - SharedPtr<Process> process(new Process(system)); + std::shared_ptr<Process> process = std::make_shared<Process>(system); process->name = std::move(name); process->resource_limit = kernel.GetSystemResourceLimit(); process->status = ProcessStatus::Created; @@ -121,7 +121,7 @@ SharedPtr<Process> Process::Create(Core::System& system, std::string name, Proce return process; } -SharedPtr<ResourceLimit> Process::GetResourceLimit() const { +std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const { return resource_limit; } @@ -142,6 +142,49 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); } +void Process::InsertConditionVariableThread(std::shared_ptr<Thread> thread) { + VAddr cond_var_addr = thread->GetCondVarWaitAddress(); + std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; + auto it = thread_list.begin(); + while (it != thread_list.end()) { + const std::shared_ptr<Thread> current_thread = *it; + if (current_thread->GetPriority() > thread->GetPriority()) { + thread_list.insert(it, thread); + return; + } + ++it; + } + thread_list.push_back(thread); +} + +void Process::RemoveConditionVariableThread(std::shared_ptr<Thread> thread) { + VAddr cond_var_addr = thread->GetCondVarWaitAddress(); + std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; + auto it = thread_list.begin(); + while (it != thread_list.end()) { + const std::shared_ptr<Thread> current_thread = *it; + if (current_thread.get() == thread.get()) { + thread_list.erase(it); + return; + } + ++it; + } + UNREACHABLE(); +} + +std::vector<std::shared_ptr<Thread>> Process::GetConditionVariableThreads( + const VAddr cond_var_addr) { + std::vector<std::shared_ptr<Thread>> result{}; + std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr]; + auto it = thread_list.begin(); + while (it != thread_list.end()) { + std::shared_ptr<Thread> current_thread = *it; + result.push_back(current_thread); + ++it; + } + return result; +} + void Process::RegisterThread(const Thread* thread) { thread_list.push_back(thread); } @@ -197,12 +240,12 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { void Process::PrepareForTermination() { ChangeStatus(ProcessStatus::Exiting); - const auto stop_threads = [this](const std::vector<SharedPtr<Thread>>& thread_list) { + const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) { for (auto& thread : thread_list) { if (thread->GetOwnerProcess() != this) continue; - if (thread == system.CurrentScheduler().GetCurrentThread()) + if (thread.get() == system.CurrentScheduler().GetCurrentThread()) continue; // TODO(Subv): When are the other running/ready threads terminated? diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index c2df451f3..3483fa19d 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -8,6 +8,7 @@ #include <cstddef> #include <list> #include <string> +#include <unordered_map> #include <vector> #include "common/common_types.h" #include "core/hle/kernel/address_arbiter.h" @@ -61,6 +62,9 @@ enum class ProcessStatus { class Process final : public WaitObject { public: + explicit Process(Core::System& system); + ~Process() override; + enum : u64 { /// Lowest allowed process ID for a kernel initial process. InitialKIPIDMin = 1, @@ -81,7 +85,8 @@ public: static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; - static SharedPtr<Process> Create(Core::System& system, std::string name, ProcessType type); + static std::shared_ptr<Process> Create(Core::System& system, std::string name, + ProcessType type); std::string GetTypeName() const override { return "Process"; @@ -156,7 +161,7 @@ public: } /// Gets the resource limit descriptor for this process - SharedPtr<ResourceLimit> GetResourceLimit() const; + std::shared_ptr<ResourceLimit> GetResourceLimit() const; /// Gets the ideal CPU core ID for this process u8 GetIdealCore() const { @@ -232,6 +237,15 @@ public: return thread_list; } + /// Insert a thread into the condition variable wait container + void InsertConditionVariableThread(std::shared_ptr<Thread> thread); + + /// Remove a thread from the condition variable wait container + void RemoveConditionVariableThread(std::shared_ptr<Thread> thread); + + /// Obtain all condition variable threads waiting for some address + std::vector<std::shared_ptr<Thread>> GetConditionVariableThreads(VAddr cond_var_addr); + /// Registers a thread as being created under this process, /// adding it to this process' thread list. void RegisterThread(const Thread* thread); @@ -287,9 +301,6 @@ public: void FreeTLSRegion(VAddr tls_address); private: - explicit Process(Core::System& system); - ~Process() override; - /// Checks if the specified thread should wait until this process is available. bool ShouldWait(const Thread* thread) const override; @@ -328,7 +339,7 @@ private: u32 system_resource_size = 0; /// Resource limit descriptor for this process - SharedPtr<ResourceLimit> resource_limit; + std::shared_ptr<ResourceLimit> resource_limit; /// The ideal CPU core for this process, threads are scheduled on this core by default. u8 ideal_core = 0; @@ -375,6 +386,9 @@ private: /// List of threads that are running with this process as their owner. std::list<const Thread*> thread_list; + /// List of threads waiting for a condition variable + std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads; + /// System context Core::System& system; diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 173f69915..b53423462 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp @@ -16,8 +16,8 @@ constexpr std::size_t ResourceTypeToIndex(ResourceType type) { ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} ResourceLimit::~ResourceLimit() = default; -SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { - return new ResourceLimit(kernel); +std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel) { + return std::make_shared<ResourceLimit>(kernel); } s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 2613a6bb5..b5534620d 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h @@ -31,8 +31,11 @@ constexpr bool IsValidResourceType(ResourceType type) { class ResourceLimit final : public Object { public: + explicit ResourceLimit(KernelCore& kernel); + ~ResourceLimit() override; + /// Creates a resource limit object. - static SharedPtr<ResourceLimit> Create(KernelCore& kernel); + static std::shared_ptr<ResourceLimit> Create(KernelCore& kernel); std::string GetTypeName() const override { return "ResourceLimit"; @@ -76,9 +79,6 @@ public: ResultCode SetLimitValue(ResourceType resource, s64 value); private: - explicit ResourceLimit(KernelCore& kernel); - ~ResourceLimit() override; - // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create // functions // diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 0e2dbf13e..3f5192087 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -26,27 +26,27 @@ GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {} GlobalScheduler::~GlobalScheduler() = default; -void GlobalScheduler::AddThread(SharedPtr<Thread> thread) { +void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) { thread_list.push_back(std::move(thread)); } -void GlobalScheduler::RemoveThread(const Thread* thread) { +void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) { thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); } -void GlobalScheduler::UnloadThread(s32 core) { +void GlobalScheduler::UnloadThread(std::size_t core) { Scheduler& sched = system.Scheduler(core); sched.UnloadThread(); } -void GlobalScheduler::SelectThread(u32 core) { +void GlobalScheduler::SelectThread(std::size_t core) { const auto update_thread = [](Thread* thread, Scheduler& sched) { - if (thread != sched.selected_thread) { + if (thread != sched.selected_thread.get()) { if (thread == nullptr) { ++sched.idle_selection_count; } - sched.selected_thread = thread; + sched.selected_thread = SharedFrom(thread); } sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; std::atomic_thread_fence(std::memory_order_seq_cst); @@ -77,9 +77,9 @@ void GlobalScheduler::SelectThread(u32 core) { // if we got a suggested thread, select it, else do a second pass. if (winner && winner->GetPriority() > 2) { if (winner->IsRunning()) { - UnloadThread(winner->GetProcessorID()); + UnloadThread(static_cast<u32>(winner->GetProcessorID())); } - TransferToCore(winner->GetPriority(), core, winner); + TransferToCore(winner->GetPriority(), static_cast<s32>(core), winner); update_thread(winner, sched); return; } @@ -91,9 +91,9 @@ void GlobalScheduler::SelectThread(u32 core) { Thread* thread_on_core = scheduled_queue[src_core].front(); Thread* to_change = *it; if (thread_on_core->IsRunning() || to_change->IsRunning()) { - UnloadThread(src_core); + UnloadThread(static_cast<u32>(src_core)); } - TransferToCore(thread_on_core->GetPriority(), core, thread_on_core); + TransferToCore(thread_on_core->GetPriority(), static_cast<s32>(core), thread_on_core); current_thread = thread_on_core; break; } @@ -154,9 +154,9 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { if (winner != nullptr) { if (winner != yielding_thread) { if (winner->IsRunning()) { - UnloadThread(winner->GetProcessorID()); + UnloadThread(static_cast<u32>(winner->GetProcessorID())); } - TransferToCore(winner->GetPriority(), core_id, winner); + TransferToCore(winner->GetPriority(), s32(core_id), winner); } } else { winner = next_thread; @@ -196,9 +196,9 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread if (winner != nullptr) { if (winner != yielding_thread) { if (winner->IsRunning()) { - UnloadThread(winner->GetProcessorID()); + UnloadThread(static_cast<u32>(winner->GetProcessorID())); } - TransferToCore(winner->GetPriority(), core_id, winner); + TransferToCore(winner->GetPriority(), static_cast<s32>(core_id), winner); } } else { winner = yielding_thread; @@ -248,7 +248,7 @@ void GlobalScheduler::PreemptThreads() { if (winner != nullptr) { if (winner->IsRunning()) { - UnloadThread(winner->GetProcessorID()); + UnloadThread(static_cast<u32>(winner->GetProcessorID())); } TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = @@ -281,7 +281,7 @@ void GlobalScheduler::PreemptThreads() { if (winner != nullptr) { if (winner->IsRunning()) { - UnloadThread(winner->GetProcessorID()); + UnloadThread(static_cast<u32>(winner->GetProcessorID())); } TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner; @@ -292,30 +292,30 @@ void GlobalScheduler::PreemptThreads() { } } -void GlobalScheduler::Suggest(u32 priority, u32 core, Thread* thread) { +void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) { suggested_queue[core].add(thread, priority); } -void GlobalScheduler::Unsuggest(u32 priority, u32 core, Thread* thread) { +void GlobalScheduler::Unsuggest(u32 priority, std::size_t core, Thread* thread) { suggested_queue[core].remove(thread, priority); } -void GlobalScheduler::Schedule(u32 priority, u32 core, Thread* thread) { +void GlobalScheduler::Schedule(u32 priority, std::size_t core, Thread* thread) { ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority); } -void GlobalScheduler::SchedulePrepend(u32 priority, u32 core, Thread* thread) { +void GlobalScheduler::SchedulePrepend(u32 priority, std::size_t core, Thread* thread) { ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority, false); } -void GlobalScheduler::Reschedule(u32 priority, u32 core, Thread* thread) { +void GlobalScheduler::Reschedule(u32 priority, std::size_t core, Thread* thread) { scheduled_queue[core].remove(thread, priority); scheduled_queue[core].add(thread, priority); } -void GlobalScheduler::Unschedule(u32 priority, u32 core, Thread* thread) { +void GlobalScheduler::Unschedule(u32 priority, std::size_t core, Thread* thread) { scheduled_queue[core].remove(thread, priority); } @@ -327,14 +327,14 @@ void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* } thread->SetProcessorID(destination_core); if (source_core >= 0) { - Unschedule(priority, source_core, thread); + Unschedule(priority, static_cast<u32>(source_core), thread); } if (destination_core >= 0) { - Unsuggest(priority, destination_core, thread); - Schedule(priority, destination_core, thread); + Unsuggest(priority, static_cast<u32>(destination_core), thread); + Schedule(priority, static_cast<u32>(destination_core), thread); } if (source_core >= 0) { - Suggest(priority, source_core, thread); + Suggest(priority, static_cast<u32>(source_core), thread); } } @@ -357,7 +357,7 @@ void GlobalScheduler::Shutdown() { thread_list.clear(); } -Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 core_id) +Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) : system(system), cpu_core(cpu_core), core_id(core_id) {} Scheduler::~Scheduler() = default; @@ -446,7 +446,7 @@ void Scheduler::SwitchContext() { // Cancel any outstanding wakeup events for this thread new_thread->CancelWakeupTimer(); - current_thread = new_thread; + current_thread = SharedFrom(new_thread); new_thread->SetStatus(ThreadStatus::Running); new_thread->SetIsRunning(true); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f2d6311b8..3c5c21346 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -28,13 +28,13 @@ public: ~GlobalScheduler(); /// Adds a new thread to the scheduler - void AddThread(SharedPtr<Thread> thread); + void AddThread(std::shared_ptr<Thread> thread); /// Removes a thread from the scheduler - void RemoveThread(const Thread* thread); + void RemoveThread(std::shared_ptr<Thread> thread); /// Returns a list of all threads managed by the scheduler - const std::vector<SharedPtr<Thread>>& GetThreadList() const { + const std::vector<std::shared_ptr<Thread>>& GetThreadList() const { return thread_list; } @@ -42,41 +42,34 @@ public: * Add a thread to the suggested queue of a cpu core. Suggested threads may be * picked if no thread is scheduled to run on the core. */ - void Suggest(u32 priority, u32 core, Thread* thread); + void Suggest(u32 priority, std::size_t core, Thread* thread); /** * Remove a thread to the suggested queue of a cpu core. Suggested threads may be * picked if no thread is scheduled to run on the core. */ - void Unsuggest(u32 priority, u32 core, Thread* thread); + void Unsuggest(u32 priority, std::size_t core, Thread* thread); /** * Add a thread to the scheduling queue of a cpu core. The thread is added at the * back the queue in its priority level. */ - void Schedule(u32 priority, u32 core, Thread* thread); + void Schedule(u32 priority, std::size_t core, Thread* thread); /** * Add a thread to the scheduling queue of a cpu core. The thread is added at the * front the queue in its priority level. */ - void SchedulePrepend(u32 priority, u32 core, Thread* thread); + void SchedulePrepend(u32 priority, std::size_t core, Thread* thread); /// Reschedule an already scheduled thread based on a new priority - void Reschedule(u32 priority, u32 core, Thread* thread); + void Reschedule(u32 priority, std::size_t core, Thread* thread); /// Unschedules a thread. - void Unschedule(u32 priority, u32 core, Thread* thread); - - /** - * Transfers a thread into an specific core. If the destination_core is -1 - * it will be unscheduled from its source code and added into its suggested - * queue. - */ - void TransferToCore(u32 priority, s32 destination_core, Thread* thread); + void Unschedule(u32 priority, std::size_t core, Thread* thread); /// Selects a core and forces it to unload its current thread's context - void UnloadThread(s32 core); + void UnloadThread(std::size_t core); /** * Takes care of selecting the new scheduled thread in three steps: @@ -90,9 +83,9 @@ public: * 3. Third is no suggested thread is found, we do a second pass and pick a running * thread in another core and swap it with its current thread. */ - void SelectThread(u32 core); + void SelectThread(std::size_t core); - bool HaveReadyThreads(u32 core_id) const { + bool HaveReadyThreads(std::size_t core_id) const { return !scheduled_queue[core_id].empty(); } @@ -145,6 +138,13 @@ public: void Shutdown(); private: + /** + * Transfers a thread into an specific core. If the destination_core is -1 + * it will be unscheduled from its source code and added into its suggested + * queue. + */ + void TransferToCore(u32 priority, s32 destination_core, Thread* thread); + bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner); static constexpr u32 min_regular_priority = 2; @@ -157,13 +157,13 @@ private: std::array<u32, NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; /// Lists all thread ids that aren't deleted/etc. - std::vector<SharedPtr<Thread>> thread_list; + std::vector<std::shared_ptr<Thread>> thread_list; Core::System& system; }; class Scheduler final { public: - explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 core_id); + explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id); ~Scheduler(); /// Returns whether there are any threads that are ready to run. @@ -213,14 +213,14 @@ private: */ void UpdateLastContextSwitchTime(Thread* thread, Process* process); - SharedPtr<Thread> current_thread = nullptr; - SharedPtr<Thread> selected_thread = nullptr; + std::shared_ptr<Thread> current_thread = nullptr; + std::shared_ptr<Thread> selected_thread = nullptr; Core::System& system; Core::ARM_Interface& cpu_core; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; - const u32 core_id; + const std::size_t core_id; bool is_context_switch_pending = false; }; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 02e7c60e6..a4ccfa35e 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -16,7 +16,7 @@ namespace Kernel { ServerPort::ServerPort(KernelCore& kernel) : WaitObject{kernel} {} ServerPort::~ServerPort() = default; -ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { +ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { if (pending_sessions.empty()) { return ERR_NOT_FOUND; } @@ -26,7 +26,7 @@ ResultVal<SharedPtr<ServerSession>> ServerPort::Accept() { return MakeResult(std::move(session)); } -void ServerPort::AppendPendingSession(SharedPtr<ServerSession> pending_session) { +void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { pending_sessions.push_back(std::move(pending_session)); } @@ -41,8 +41,8 @@ void ServerPort::Acquire(Thread* thread) { ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions, std::string name) { - SharedPtr<ServerPort> server_port(new ServerPort(kernel)); - SharedPtr<ClientPort> client_port(new ClientPort(kernel)); + std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel); + std::shared_ptr<ClientPort> client_port = std::make_shared<ClientPort>(kernel); server_port->name = name + "_Server"; client_port->name = name + "_Client"; diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index dc88a1ebd..8be8a75ea 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -22,8 +22,11 @@ class SessionRequestHandler; class ServerPort final : public WaitObject { public: + explicit ServerPort(KernelCore& kernel); + ~ServerPort() override; + using HLEHandler = std::shared_ptr<SessionRequestHandler>; - using PortPair = std::pair<SharedPtr<ServerPort>, SharedPtr<ClientPort>>; + using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; /** * Creates a pair of ServerPort and an associated ClientPort. @@ -52,7 +55,7 @@ public: * Accepts a pending incoming connection on this port. If there are no pending sessions, will * return ERR_NO_PENDING_SESSIONS. */ - ResultVal<SharedPtr<ServerSession>> Accept(); + ResultVal<std::shared_ptr<ServerSession>> Accept(); /// Whether or not this server port has an HLE handler available. bool HasHLEHandler() const { @@ -74,17 +77,14 @@ public: /// Appends a ServerSession to the collection of ServerSessions /// waiting to be accepted by this port. - void AppendPendingSession(SharedPtr<ServerSession> pending_session); + void AppendPendingSession(std::shared_ptr<ServerSession> pending_session); bool ShouldWait(const Thread* thread) const override; void Acquire(Thread* thread) override; private: - explicit ServerPort(KernelCore& kernel); - ~ServerPort() override; - /// ServerSessions waiting to be accepted by the port - std::vector<SharedPtr<ServerSession>> pending_sessions; + std::vector<std::shared_ptr<ServerSession>> pending_sessions; /// This session's HLE request handler template (optional) /// ServerSessions created from this port inherit a reference to this handler. diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 30b2bfb5a..7825e1ec4 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -19,35 +20,32 @@ #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" #include "core/hle/kernel/thread.h" +#include "core/memory.h" namespace Kernel { ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} -ServerSession::~ServerSession() { - // This destructor will be called automatically when the last ServerSession handle is closed by - // the emulated application. +ServerSession::~ServerSession() = default; - // Decrease the port's connection count. - if (parent->port) { - parent->port->ConnectionClosed(); - } - - parent->server = nullptr; -} +ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name) { + std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; -ResultVal<SharedPtr<ServerSession>> ServerSession::Create(KernelCore& kernel, std::string name) { - SharedPtr<ServerSession> server_session(new ServerSession(kernel)); + session->request_event = Core::Timing::CreateEvent( + name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); + session->name = std::move(name); + session->parent = std::move(parent); - server_session->name = std::move(name); - server_session->parent = nullptr; - - return MakeResult(std::move(server_session)); + return MakeResult(std::move(session)); } bool ServerSession::ShouldWait(const Thread* thread) const { // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. - if (parent->client == nullptr) + if (!parent->Client()) { return false; + } + // Wait if we have no pending requests, or if we're currently handling a request. return pending_requesting_threads.empty() || currently_handling != nullptr; } @@ -69,7 +67,7 @@ void ServerSession::ClientDisconnected() { if (handler) { // Note that after this returns, this server session's hle_handler is // invalidated (set to null). - handler->ClientDisconnected(this); + handler->ClientDisconnected(SharedFrom(this)); } // Clean up the list of client threads with pending requests, they are unneeded now that the @@ -126,13 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return RESULT_SUCCESS; } -ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { - // The ServerSession received a sync request, this means that there's new data available - // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or - // similar. - Kernel::HLERequestContext context(this, thread); - u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); - context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); +ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { + u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; + std::shared_ptr<Kernel::HLERequestContext> context{ + std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))}; + + context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); + request_queue.Push(std::move(context)); + + return RESULT_SUCCESS; +} + +ResultCode ServerSession::CompleteSyncRequest() { + ASSERT(!request_queue.Empty()); + + auto& context = *request_queue.Front(); ResultCode result = RESULT_SUCCESS; // If the session has been converted to a domain, handle the domain request @@ -144,61 +150,27 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { result = hle_handler->HandleSyncRequest(context); } - if (thread->GetStatus() == ThreadStatus::Running) { - // Put the thread to sleep until the server replies, it will be awoken in - // svcReplyAndReceive for LLE servers. - thread->SetStatus(ThreadStatus::WaitIPC); - - if (hle_handler != nullptr) { - // For HLE services, we put the request threads to sleep for a short duration to - // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for - // other reasons like an async callback. The IPC overhead is needed to prevent - // starvation when a thread only does sync requests to HLE services while a - // lower-priority thread is waiting to run. - - // This delay was approximated in a homebrew application by measuring the average time - // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC - // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have - // a high variance and vary between models. - static constexpr u64 IPCDelayNanoseconds = 39000; - thread->WakeAfterDelay(IPCDelayNanoseconds); - } else { - // Add the thread to the list of threads that have issued a sync request with this - // server. - pending_requesting_threads.push_back(std::move(thread)); - } - } - - // If this ServerSession does not have an HLE implementation, just wake up the threads waiting - // on it. - WakeupAllWaitingThreads(); - - // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the - // end of the command such that only commands following this one are handled as domains if (convert_to_domain) { ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); domain_request_handlers = {hle_handler}; convert_to_domain = false; } - return result; -} - -ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel, - const std::string& name, - SharedPtr<ClientPort> port) { - auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap(); - SharedPtr<ClientSession> client_session(new ClientSession(kernel)); - client_session->name = name + "_Client"; + // Some service requests require the thread to block + if (!context.IsThreadWaiting()) { + context.GetThread().ResumeFromWait(); + context.GetThread().SetWaitSynchronizationResult(result); + } - std::shared_ptr<Session> parent(new Session); - parent->client = client_session.get(); - parent->server = server_session.get(); - parent->port = std::move(port); + request_queue.Pop(); - client_session->parent = parent; - server_session->parent = parent; + return result; +} - return std::make_pair(std::move(server_session), std::move(client_session)); +ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, + Memory::Memory& memory) { + Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); + return QueueSyncRequest(std::move(thread), memory); } + } // namespace Kernel diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 738df30f8..d6e48109e 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -9,17 +9,22 @@ #include <utility> #include <vector> -#include "core/hle/kernel/object.h" +#include "common/threadsafe_queue.h" #include "core/hle/kernel/wait_object.h" #include "core/hle/result.h" +namespace Memory { +class Memory; +} + +namespace Core::Timing { +struct EventType; +} + namespace Kernel { -class ClientPort; -class ClientSession; class HLERequestContext; class KernelCore; -class ServerSession; class Session; class SessionRequestHandler; class Thread; @@ -38,6 +43,15 @@ class Thread; */ class ServerSession final : public WaitObject { public: + explicit ServerSession(KernelCore& kernel); + ~ServerSession() override; + + friend class Session; + + static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, + std::shared_ptr<Session> parent, + std::string name = "Unknown"); + std::string GetTypeName() const override { return "ServerSession"; } @@ -59,18 +73,6 @@ public: return parent.get(); } - using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>; - - /** - * Creates a pair of ServerSession and an associated ClientSession. - * @param kernel The kernal instance to create the session pair under. - * @param name Optional name of the ports. - * @param client_port Optional The ClientPort that spawned this session. - * @return The created session tuple - */ - static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown", - SharedPtr<ClientPort> client_port = nullptr); - /** * Sets the HLE handler for the session. This handler will be called to service IPC requests * instead of the regular IPC machinery. (The regular IPC machinery is currently not @@ -82,10 +84,13 @@ public: /** * Handle a sync request from the emulated application. + * * @param thread Thread that initiated the request. + * @param memory Memory context to handle the sync request under. + * * @returns ResultCode from the operation. */ - ResultCode HandleSyncRequest(SharedPtr<Thread> thread); + ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); bool ShouldWait(const Thread* thread) const override; @@ -118,18 +123,11 @@ public: } private: - explicit ServerSession(KernelCore& kernel); - ~ServerSession() override; + /// Queues a sync request from the emulated application. + ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); - /** - * Creates a server session. The server session can have an optional HLE handler, - * which will be invoked to handle the IPC requests that this session receives. - * @param kernel The kernel instance to create this server session under. - * @param name Optional name of the server session. - * @return The created server session - */ - static ResultVal<SharedPtr<ServerSession>> Create(KernelCore& kernel, - std::string name = "Unknown"); + /// Completes a sync request from the emulated application. + ResultCode CompleteSyncRequest(); /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an /// object handle. @@ -147,18 +145,24 @@ private: /// List of threads that are pending a response after a sync request. This list is processed in /// a LIFO manner, thus, the last request will be dispatched first. /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test. - std::vector<SharedPtr<Thread>> pending_requesting_threads; + std::vector<std::shared_ptr<Thread>> pending_requesting_threads; /// Thread whose request is currently being handled. A request is considered "handled" when a /// response is sent via svcReplyAndReceive. /// TODO(Subv): Find a better name for this. - SharedPtr<Thread> currently_handling; + std::shared_ptr<Thread> currently_handling; /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; /// The name of this session (optional) std::string name; + + /// Core timing event used to schedule the service request at some point in the future + std::shared_ptr<Core::Timing::EventType> request_event; + + /// Queue of scheduled service requests + Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue; }; } // namespace Kernel diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 642914744..dee6e2b72 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp @@ -1,12 +1,36 @@ -// Copyright 2015 Citra Emulator Project +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" -#include "core/hle/kernel/thread.h" namespace Kernel { -Session::Session() {} -Session::~Session() {} +Session::Session(KernelCore& kernel) : WaitObject{kernel} {} +Session::~Session() = default; + +Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { + auto session{std::make_shared<Session>(kernel)}; + auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; + auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; + + session->name = std::move(name); + session->client = client_session; + session->server = server_session; + + return std::make_pair(std::move(client_session), std::move(server_session)); +} + +bool Session::ShouldWait(const Thread* thread) const { + UNIMPLEMENTED(); + return {}; +} + +void Session::Acquire(Thread* thread) { + UNIMPLEMENTED(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 7a551f5e4..5a9d4e9ad 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -1,27 +1,64 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2019 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once -#include "core/hle/kernel/object.h" +#include <memory> +#include <string> + +#include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h" namespace Kernel { class ClientSession; -class ClientPort; class ServerSession; /** * Parent structure to link the client and server endpoints of a session with their associated - * client port. The client port need not exist, as is the case for portless sessions like the - * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its - * corresponding field in this structure will be set to nullptr. + * client port. */ -class Session final { +class Session final : public WaitObject { public: - ClientSession* client = nullptr; ///< The client endpoint of the session. - ServerSession* server = nullptr; ///< The server endpoint of the session. - SharedPtr<ClientPort> port; ///< The port that this session is associated with (optional). + explicit Session(KernelCore& kernel); + ~Session() override; + + using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>; + + static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::Session; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + bool ShouldWait(const Thread* thread) const override; + + void Acquire(Thread* thread) override; + + std::shared_ptr<ClientSession> Client() { + if (auto result{client.lock()}) { + return result; + } + return {}; + } + + std::shared_ptr<ServerSession> Server() { + if (auto result{server.lock()}) { + return result; + } + return {}; + } + +private: + std::string name; + std::weak_ptr<ClientSession> client; + std::weak_ptr<ServerSession> server; }; + } // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index a815c4eea..afb2e3fc2 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -15,11 +15,12 @@ namespace Kernel { SharedMemory::SharedMemory(KernelCore& kernel) : Object{kernel} {} SharedMemory::~SharedMemory() = default; -SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, u64 size, - MemoryPermission permissions, - MemoryPermission other_permissions, VAddr address, - MemoryRegion region, std::string name) { - SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); +std::shared_ptr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_process, + u64 size, MemoryPermission permissions, + MemoryPermission other_permissions, + VAddr address, MemoryRegion region, + std::string name) { + std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel); shared_memory->owner_process = owner_process; shared_memory->name = std::move(name); @@ -58,10 +59,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, Process* owner_ return shared_memory; } -SharedPtr<SharedMemory> SharedMemory::CreateForApplet( +std::shared_ptr<SharedMemory> SharedMemory::CreateForApplet( KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { - SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); + std::shared_ptr<SharedMemory> shared_memory = std::make_shared<SharedMemory>(kernel); shared_memory->owner_process = nullptr; shared_memory->name = std::move(name); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 01ca6dcd2..18400a5ad 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -33,6 +33,9 @@ enum class MemoryPermission : u32 { class SharedMemory final : public Object { public: + explicit SharedMemory(KernelCore& kernel); + ~SharedMemory() override; + /** * Creates a shared memory object. * @param kernel The kernel instance to create a shared memory instance under. @@ -46,11 +49,12 @@ public: * linear heap. * @param name Optional object name, used for debugging purposes. */ - static SharedPtr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, u64 size, - MemoryPermission permissions, - MemoryPermission other_permissions, VAddr address = 0, - MemoryRegion region = MemoryRegion::BASE, - std::string name = "Unknown"); + static std::shared_ptr<SharedMemory> Create(KernelCore& kernel, Process* owner_process, + u64 size, MemoryPermission permissions, + MemoryPermission other_permissions, + VAddr address = 0, + MemoryRegion region = MemoryRegion::BASE, + std::string name = "Unknown"); /** * Creates a shared memory object from a block of memory managed by an HLE applet. @@ -63,7 +67,7 @@ public: * block. * @param name Optional object name, used for debugging purposes. */ - static SharedPtr<SharedMemory> CreateForApplet( + static std::shared_ptr<SharedMemory> CreateForApplet( KernelCore& kernel, std::shared_ptr<Kernel::PhysicalMemory> heap_block, std::size_t offset, u64 size, MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet"); @@ -130,9 +134,6 @@ public: const u8* GetPointer(std::size_t offset = 0) const; private: - explicit SharedMemory(KernelCore& kernel); - ~SharedMemory() override; - /// Backing memory for this shared memory block. std::shared_ptr<PhysicalMemory> backing_block; /// Offset into the backing block for this shared memory. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c63a9ba8b..bd25de478 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -17,6 +17,7 @@ #include "core/core.h" #include "core/core_cpu.h" #include "core/core_timing.h" +#include "core/core_timing_util.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -331,7 +332,9 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { - if (!Memory::IsValidVirtualAddress(port_name_address)) { + auto& memory = system.Memory(); + + if (!memory.IsValidVirtualAddress(port_name_address)) { LOG_ERROR(Kernel_SVC, "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", port_name_address); @@ -340,7 +343,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, static constexpr std::size_t PortNameMaxLength = 11; // Read 1 char beyond the max allowed port name to detect names that are too long. - std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); + const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1); if (port_name.size() > PortNameMaxLength) { LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength, port_name.size()); @@ -358,7 +361,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, auto client_port = it->second; - SharedPtr<ClientSession> client_session; + std::shared_ptr<ClientSession> client_session; CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session @@ -370,7 +373,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle); + std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); if (!session) { LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -378,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - system.PrepareReschedule(); + auto thread = system.CurrentScheduler().GetCurrentThread(); + thread->InvalidateWakeupCallback(); + thread->SetStatus(ThreadStatus::WaitIPC); + system.PrepareReschedule(thread->GetProcessorID()); - // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server - // responds and cause a reschedule. - return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread()); + return session->SendSyncRequest(SharedFrom(thread), system.Memory()); } /// Get the ID for the specified thread. @@ -390,7 +394,7 @@ static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle threa LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); return ERR_INVALID_HANDLE; @@ -405,13 +409,13 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Process> process = handle_table.Get<Process>(handle); + const std::shared_ptr<Process> process = handle_table.Get<Process>(handle); if (process) { *process_id = process->GetProcessID(); return RESULT_SUCCESS; } - const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); if (thread) { const Process* const owner_process = thread->GetOwnerProcess(); if (!owner_process) { @@ -430,8 +434,8 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han } /// Default thread wakeup callback for WaitSynchronization -static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index) { +static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index) { ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); if (reason == ThreadWakeupReason::Timeout) { @@ -451,7 +455,8 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", handles_address, handle_count, nano_seconds); - if (!Memory::IsValidVirtualAddress(handles_address)) { + auto& memory = system.Memory(); + if (!memory.IsValidVirtualAddress(handles_address)) { LOG_ERROR(Kernel_SVC, "Handle address is not a valid virtual address, handle_address=0x{:016X}", handles_address); @@ -473,7 +478,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); for (u64 i = 0; i < handle_count; ++i) { - const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); + const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); const auto object = handle_table.Get<WaitObject>(handle); if (object == nullptr) { @@ -505,8 +510,13 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr return RESULT_TIMEOUT; } + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + return ERR_SYNCHRONIZATION_CANCELED; + } + for (auto& object : objects) { - object->AddWaitingThread(thread); + object->AddWaitingThread(SharedFrom(thread)); } thread->SetWaitObjects(std::move(objects)); @@ -526,7 +536,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -610,13 +620,15 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { return; } + auto& memory = system.Memory(); + // This typically is an error code so we're going to assume this is the case if (sz == sizeof(u32)) { - LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr)); + LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr)); } else { // We don't know what's in here so we'll hexdump it debug_buffer.resize(sz); - Memory::ReadBlock(addr, debug_buffer.data(), sz); + memory.ReadBlock(addr, debug_buffer.data(), sz); std::string hexdump; for (std::size_t i = 0; i < debug_buffer.size(); i++) { hexdump += fmt::format("{:02X} ", debug_buffer[i]); @@ -706,7 +718,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre } std::string str(len, '\0'); - Memory::ReadBlock(address, str.data(), str.size()); + system.Memory().ReadBlock(address, str.data(), str.size()); LOG_DEBUG(Debug_Emulated, "{}", str); } @@ -935,7 +947,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha const auto& core_timing = system.CoreTiming(); const auto& scheduler = system.CurrentScheduler(); const auto* const current_thread = scheduler.GetCurrentThread(); - const bool same_thread = current_thread == thread; + const bool same_thread = current_thread == thread.get(); const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); u64 out_ticks = 0; @@ -1045,7 +1057,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act } const auto* current_process = system.Kernel().CurrentProcess(); - const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1061,7 +1073,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return ERR_INVALID_HANDLE; } - if (thread == system.CurrentScheduler().GetCurrentThread()) { + if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); return ERR_BUSY; } @@ -1077,7 +1089,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); const auto* current_process = system.Kernel().CurrentProcess(); - const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1093,7 +1105,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H return ERR_INVALID_HANDLE; } - if (thread == system.CurrentScheduler().GetCurrentThread()) { + if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); return ERR_BUSY; } @@ -1109,7 +1121,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{}); } - Memory::WriteBlock(thread_context, &ctx, sizeof(ctx)); + system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx)); return RESULT_SUCCESS; } @@ -1118,7 +1130,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle LOG_TRACE(Kernel_SVC, "called"); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1142,7 +1154,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri const auto* const current_process = system.Kernel().CurrentProcess(); - SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); + std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; @@ -1262,27 +1274,28 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add VAddr address) { LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - SharedPtr<Process> process = handle_table.Get<Process>(process_handle); + std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle); if (!process) { LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", process_handle); return ERR_INVALID_HANDLE; } + auto& memory = system.Memory(); const auto& vm_manager = process->VMManager(); const MemoryInfo memory_info = vm_manager.QueryMemory(address); - Memory::Write64(memory_info_address, memory_info.base_address); - Memory::Write64(memory_info_address + 8, memory_info.size); - Memory::Write32(memory_info_address + 16, memory_info.state); - Memory::Write32(memory_info_address + 20, memory_info.attributes); - Memory::Write32(memory_info_address + 24, memory_info.permission); - Memory::Write32(memory_info_address + 32, memory_info.ipc_ref_count); - Memory::Write32(memory_info_address + 28, memory_info.device_ref_count); - Memory::Write32(memory_info_address + 36, 0); + memory.Write64(memory_info_address, memory_info.base_address); + memory.Write64(memory_info_address + 8, memory_info.size); + memory.Write32(memory_info_address + 16, memory_info.state); + memory.Write32(memory_info_address + 20, memory_info.attributes); + memory.Write32(memory_info_address + 24, memory_info.permission); + memory.Write32(memory_info_address + 32, memory_info.ipc_ref_count); + memory.Write32(memory_info_address + 28, memory_info.device_ref_count); + memory.Write32(memory_info_address + 36, 0); // Page info appears to be currently unused by the kernel and is always set to zero. - Memory::Write32(page_info_address, 0); + memory.Write32(page_info_address, 0); return RESULT_SUCCESS; } @@ -1490,7 +1503,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e } auto& kernel = system.Kernel(); - CASCADE_RESULT(SharedPtr<Thread> thread, + CASCADE_RESULT(std::shared_ptr<Thread> thread, Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top, *current_process)); @@ -1516,7 +1529,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -1540,7 +1553,7 @@ static void ExitThread(Core::System& system) { auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->Stop(); - system.GlobalScheduler().RemoveThread(current_thread); + system.GlobalScheduler().RemoveThread(SharedFrom(current_thread)); system.PrepareReschedule(); } @@ -1612,7 +1625,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add auto* const current_process = system.Kernel().CurrentProcess(); const auto& handle_table = current_process->GetHandleTable(); - SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); ASSERT(thread); const auto release_result = current_process->GetMutex().Release(mutex_addr); @@ -1620,12 +1633,13 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return release_result; } - SharedPtr<Thread> current_thread = system.CurrentScheduler().GetCurrentThread(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); current_thread->SetCondVarWaitAddress(condition_variable_addr); current_thread->SetMutexWaitAddress(mutex_addr); current_thread->SetWaitHandle(thread_handle); current_thread->SetStatus(ThreadStatus::WaitCondVar); current_thread->InvalidateWakeupCallback(); + current_process->InsertConditionVariableThread(SharedFrom(current_thread)); current_thread->WakeAfterDelay(nano_seconds); @@ -1644,42 +1658,28 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); // Retrieve a list of all threads that are waiting for this condition variable. - std::vector<SharedPtr<Thread>> waiting_threads; - const auto& scheduler = system.GlobalScheduler(); - const auto& thread_list = scheduler.GetThreadList(); - - for (const auto& thread : thread_list) { - if (thread->GetCondVarWaitAddress() == condition_variable_addr) { - waiting_threads.push_back(thread); - } - } - - // Sort them by priority, such that the highest priority ones come first. - std::sort(waiting_threads.begin(), waiting_threads.end(), - [](const SharedPtr<Thread>& lhs, const SharedPtr<Thread>& rhs) { - return lhs->GetPriority() < rhs->GetPriority(); - }); + auto* const current_process = system.Kernel().CurrentProcess(); + std::vector<std::shared_ptr<Thread>> waiting_threads = + current_process->GetConditionVariableThreads(condition_variable_addr); - // Only process up to 'target' threads, unless 'target' is -1, in which case process + // Only process up to 'target' threads, unless 'target' is less equal 0, in which case process // them all. std::size_t last = waiting_threads.size(); - if (target != -1) + if (target > 0) last = std::min(waiting_threads.size(), static_cast<std::size_t>(target)); - // If there are no threads waiting on this condition variable, just exit - if (last == 0) - return RESULT_SUCCESS; - for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); // liberate Cond Var Thread. + current_process->RemoveConditionVariableThread(thread); thread->SetCondVarWaitAddress(0); const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); + auto& memory = system.Memory(); // Atomically read the value of the mutex. u32 mutex_val = 0; @@ -1689,7 +1689,7 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var monitor.SetExclusive(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. - mutex_val = Memory::Read32(mutex_address); + mutex_val = memory.Read32(mutex_address); if (mutex_val != 0) { update_val = mutex_val | Mutex::MutexHasWaitersFlag; @@ -1786,7 +1786,9 @@ static u64 GetSystemTick(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); auto& core_timing = system.CoreTiming(); - const u64 result{core_timing.GetTicks()}; + + // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) + const u64 result{Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks())}; // Advance time to defeat dumb games that busy-wait for the frame to end. core_timing.AddTicks(400); @@ -1975,7 +1977,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -2034,7 +2036,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, } const auto& handle_table = current_process->GetHandleTable(); - const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); + const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); @@ -2290,12 +2292,13 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes, return ERR_INVALID_ADDRESS_STATE; } + auto& memory = system.Memory(); const auto& process_list = kernel.GetProcessList(); const auto num_processes = process_list.size(); const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes); for (std::size_t i = 0; i < copy_amount; ++i) { - Memory::Write64(out_process_ids, process_list[i]->GetProcessID()); + memory.Write64(out_process_ids, process_list[i]->GetProcessID()); out_process_ids += sizeof(u64); } @@ -2329,13 +2332,14 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd return ERR_INVALID_ADDRESS_STATE; } + auto& memory = system.Memory(); const auto& thread_list = current_process->GetThreadList(); const auto num_threads = thread_list.size(); const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads); auto list_iter = thread_list.cbegin(); for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { - Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID()); + memory.Write64(out_thread_ids, (*list_iter)->GetThreadID()); out_thread_ids += sizeof(u64); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 962530d2d..e84e5ce0d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -50,7 +50,7 @@ void Thread::Stop() { // Clean up any dangling references in objects that this thread was waiting for for (auto& wait_object : wait_objects) { - wait_object->RemoveWaitingThread(this); + wait_object->RemoveWaitingThread(SharedFrom(this)); } wait_objects.clear(); @@ -77,18 +77,6 @@ void Thread::CancelWakeupTimer() { callback_handle); } -static std::optional<s32> GetNextProcessorId(u64 mask) { - for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { - if (mask & (1ULL << index)) { - if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) { - // Core is enabled and not running any threads, use this one - return index; - } - } - } - return {}; -} - void Thread::ResumeFromWait() { ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); @@ -132,8 +120,11 @@ void Thread::ResumeFromWait() { } void Thread::CancelWait() { - ASSERT(GetStatus() == ThreadStatus::WaitSynch); - ClearWaitObjects(); + if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { + is_sync_cancelled = true; + return; + } + is_sync_cancelled = false; SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); ResumeFromWait(); } @@ -156,9 +147,10 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd context.fpcr = 0x03C00000; } -ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, - u32 priority, u64 arg, s32 processor_id, - VAddr stack_top, Process& owner_process) { +ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process& owner_process) { // Check if priority is in ranged. Lowest priority -> highest priority id. if (priority > THREADPRIO_LOWEST) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); @@ -170,14 +162,14 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name return ERR_INVALID_PROCESSOR_ID; } - if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) { + auto& system = Core::System::GetInstance(); + if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) { LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); // TODO (bunnei): Find the correct error code to use here - return ResultCode(-1); + return RESULT_UNKNOWN; } - auto& system = Core::System::GetInstance(); - SharedPtr<Thread> thread(new Thread(kernel)); + std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel); thread->thread_id = kernel.CreateNewThreadID(); thread->status = ThreadStatus::Dormant; @@ -206,7 +198,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name // to initialize the context ResetThreadContext(thread->context, stack_top, entry_point, arg); - return MakeResult<SharedPtr<Thread>>(std::move(thread)); + return MakeResult<std::shared_ptr<Thread>>(std::move(thread)); } void Thread::SetPriority(u32 priority) { @@ -224,7 +216,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { context.cpu_registers[1] = output; } -s32 Thread::GetWaitObjectIndex(const WaitObject* object) const { +s32 Thread::GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const { ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1); @@ -264,8 +256,8 @@ void Thread::SetStatus(ThreadStatus new_status) { status = new_status; } -void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { - if (thread->lock_owner == this) { +void Thread::AddMutexWaiter(std::shared_ptr<Thread> thread) { + if (thread->lock_owner.get() == this) { // If the thread is already waiting for this thread to release the mutex, ensure that the // waiters list is consistent and return without doing anything. const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); @@ -285,13 +277,13 @@ void Thread::AddMutexWaiter(SharedPtr<Thread> thread) { wait_mutex_threads.begin(), wait_mutex_threads.end(), [&thread](const auto& entry) { return entry->GetPriority() > thread->GetPriority(); }); wait_mutex_threads.insert(insertion_point, thread); - thread->lock_owner = this; + thread->lock_owner = SharedFrom(this); UpdatePriority(); } -void Thread::RemoveMutexWaiter(SharedPtr<Thread> thread) { - ASSERT(thread->lock_owner == this); +void Thread::RemoveMutexWaiter(std::shared_ptr<Thread> thread) { + ASSERT(thread->lock_owner.get() == this); // Ensure that the thread is in the list of mutex waiters const auto iter = std::find(wait_mutex_threads.begin(), wait_mutex_threads.end(), thread); @@ -318,16 +310,24 @@ void Thread::UpdatePriority() { return; } + if (GetStatus() == ThreadStatus::WaitCondVar) { + owner_process->RemoveConditionVariableThread(SharedFrom(this)); + } + SetCurrentPriority(new_priority); + if (GetStatus() == ThreadStatus::WaitCondVar) { + owner_process->InsertConditionVariableThread(SharedFrom(this)); + } + if (!lock_owner) { return; } // Ensure that the thread is within the correct location in the waiting list. auto old_owner = lock_owner; - lock_owner->RemoveMutexWaiter(this); - old_owner->AddMutexWaiter(this); + lock_owner->RemoveMutexWaiter(SharedFrom(this)); + old_owner->AddMutexWaiter(SharedFrom(this)); // Recursively update the priority of the thread that depends on the priority of this one. lock_owner->UpdatePriority(); @@ -340,11 +340,11 @@ void Thread::ChangeCore(u32 core, u64 mask) { bool Thread::AllWaitObjectsReady() const { return std::none_of( wait_objects.begin(), wait_objects.end(), - [this](const SharedPtr<WaitObject>& object) { return object->ShouldWait(this); }); + [this](const std::shared_ptr<WaitObject>& object) { return object->ShouldWait(this); }); } -bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index) { +bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index) { ASSERT(wakeup_callback); return wakeup_callback(reason, std::move(thread), std::move(object), index); } @@ -401,7 +401,7 @@ void Thread::SetCurrentPriority(u32 new_priority) { ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { const auto HighestSetCore = [](u64 mask, u32 max_cores) { - for (s32 core = max_cores - 1; core >= 0; core--) { + for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) { if (((mask >> core) & 1) != 0) { return core; } @@ -425,7 +425,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { if (old_affinity_mask != new_affinity_mask) { const s32 old_core = processor_id; if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { - if (ideal_core < 0) { + if (static_cast<s32>(ideal_core) < 0) { processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES); } else { processor_id = ideal_core; @@ -447,23 +447,23 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { ThreadSchedStatus::Runnable) { // In this case the thread was running, now it's pausing/exitting if (processor_id >= 0) { - scheduler.Unschedule(current_priority, processor_id, this); + scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this); } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { - if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { - scheduler.Unsuggest(current_priority, static_cast<u32>(core), this); + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { + scheduler.Unsuggest(current_priority, core, this); } } } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) { // The thread is now set to running from being stopped if (processor_id >= 0) { - scheduler.Schedule(current_priority, processor_id, this); + scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this); } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { - if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { - scheduler.Suggest(current_priority, static_cast<u32>(core), this); + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { + scheduler.Suggest(current_priority, core, this); } } } @@ -477,11 +477,11 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } auto& scheduler = Core::System::GetInstance().GlobalScheduler(); if (processor_id >= 0) { - scheduler.Unschedule(old_priority, processor_id, this); + scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this); } for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { - if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { + if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(old_priority, core, this); } } @@ -491,14 +491,14 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { if (processor_id >= 0) { if (current_thread == this) { - scheduler.SchedulePrepend(current_priority, processor_id, this); + scheduler.SchedulePrepend(current_priority, static_cast<u32>(processor_id), this); } else { - scheduler.Schedule(current_priority, processor_id, this); + scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this); } } for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { - if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { + if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } } @@ -515,7 +515,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (((old_affinity_mask >> core) & 1) != 0) { - if (core == old_core) { + if (core == static_cast<u32>(old_core)) { scheduler.Unschedule(current_priority, core, this); } else { scheduler.Unsuggest(current_priority, core, this); @@ -525,7 +525,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (((affinity_mask >> core) & 1) != 0) { - if (core == processor_id) { + if (core == static_cast<u32>(processor_id)) { scheduler.Schedule(current_priority, core, this); } else { scheduler.Suggest(current_priority, core, this); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c9870873d..3bcf9e137 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -97,14 +97,18 @@ enum class ThreadSchedMasks : u32 { class Thread final : public WaitObject { public: - using MutexWaitingThreads = std::vector<SharedPtr<Thread>>; + explicit Thread(KernelCore& kernel); + ~Thread() override; + + using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>; using ThreadContext = Core::ARM_Interface::ThreadContext; - using ThreadWaitObjects = std::vector<SharedPtr<WaitObject>>; + using ThreadWaitObjects = std::vector<std::shared_ptr<WaitObject>>; - using WakeupCallback = std::function<bool(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index)>; + using WakeupCallback = + std::function<bool(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index)>; /** * Creates and returns a new thread. The new thread is immediately scheduled @@ -118,10 +122,10 @@ public: * @param owner_process The parent process for the thread * @return A shared pointer to the newly created thread */ - static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process& owner_process); + static ResultVal<std::shared_ptr<Thread>> Create(KernelCore& kernel, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process& owner_process); std::string GetName() const override { return name; @@ -166,10 +170,10 @@ public: void SetPriority(u32 priority); /// Adds a thread to the list of threads that are waiting for a lock held by this thread. - void AddMutexWaiter(SharedPtr<Thread> thread); + void AddMutexWaiter(std::shared_ptr<Thread> thread); /// Removes a thread from the list of threads that are waiting for a lock held by this thread. - void RemoveMutexWaiter(SharedPtr<Thread> thread); + void RemoveMutexWaiter(std::shared_ptr<Thread> thread); /// Recalculates the current priority taking into account priority inheritance. void UpdatePriority(); @@ -229,7 +233,7 @@ public: * * @param object Object to query the index of. */ - s32 GetWaitObjectIndex(const WaitObject* object) const; + s32 GetWaitObjectIndex(std::shared_ptr<WaitObject> object) const; /** * Stops a thread, invalidating it from further use @@ -320,7 +324,7 @@ public: void ClearWaitObjects() { for (const auto& waiting_object : wait_objects) { - waiting_object->RemoveWaitingThread(this); + waiting_object->RemoveWaitingThread(SharedFrom(this)); } wait_objects.clear(); } @@ -336,7 +340,7 @@ public: return lock_owner.get(); } - void SetLockOwner(SharedPtr<Thread> owner) { + void SetLockOwner(std::shared_ptr<Thread> owner) { lock_owner = std::move(owner); } @@ -390,8 +394,8 @@ public: * @pre A valid wakeup callback has been set. Violating this precondition * will cause an assertion to trigger. */ - bool InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread, - SharedPtr<WaitObject> object, std::size_t index); + bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread, + std::shared_ptr<WaitObject> object, std::size_t index); u32 GetIdealCore() const { return ideal_core; @@ -440,10 +444,15 @@ public: is_running = value; } -private: - explicit Thread(KernelCore& kernel); - ~Thread() override; + bool IsSyncCancelled() const { + return is_sync_cancelled; + } + void SetSyncCancelled(bool value) { + is_sync_cancelled = value; + } + +private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); @@ -491,7 +500,7 @@ private: MutexWaitingThreads wait_mutex_threads; /// Thread that owns the lock that this thread is waiting for. - SharedPtr<Thread> lock_owner; + std::shared_ptr<Thread> lock_owner; /// If waiting on a ConditionVariable, this is the ConditionVariable address VAddr condvar_wait_address = 0; @@ -524,6 +533,7 @@ private: u32 scheduling_state = 0; bool is_running = false; + bool is_sync_cancelled = false; std::string name; }; diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index 1113c815e..f0e73f57b 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -14,9 +14,9 @@ namespace Kernel { TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} TransferMemory::~TransferMemory() = default; -SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, u64 size, - MemoryPermission permissions) { - SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)}; +std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, + u64 size, MemoryPermission permissions) { + std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; transfer_memory->base_address = base_address; transfer_memory->memory_size = size; diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 6be9dc094..556e6c62b 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -27,10 +27,13 @@ enum class MemoryPermission : u32; /// class TransferMemory final : public Object { public: + explicit TransferMemory(KernelCore& kernel); + ~TransferMemory() override; + static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; - static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, - MemoryPermission permissions); + static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, + MemoryPermission permissions); TransferMemory(const TransferMemory&) = delete; TransferMemory& operator=(const TransferMemory&) = delete; @@ -79,9 +82,6 @@ public: ResultCode UnmapMemory(VAddr address, u64 size); private: - explicit TransferMemory(KernelCore& kernel); - ~TransferMemory() override; - /// Memory block backing this instance. std::shared_ptr<PhysicalMemory> backing_block; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index c7af87073..a9a20ef76 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -16,7 +16,6 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" -#include "core/memory_setup.h" namespace Kernel { namespace { @@ -167,7 +166,7 @@ ResultVal<VAddr> VMManager::FindFreeRegion(VAddr begin, VAddr end, u64 size) con if (vma_handle == vma_map.cend()) { // TODO(Subv): Find the correct error code here. - return ResultCode(-1); + return RESULT_UNKNOWN; } const VAddr target = std::max(begin, vma_handle->second.base); @@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre } void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { + auto& memory = system.Memory(); + switch (vma.type) { case VMAType::Free: - Memory::UnmapRegion(page_table, vma.base, vma.size); + memory.UnmapRegion(page_table, vma.base, vma.size); break; case VMAType::AllocatedMemoryBlock: - Memory::MapMemoryRegion(page_table, vma.base, vma.size, - vma.backing_block->data() + vma.offset); + memory.MapMemoryRegion(page_table, vma.base, vma.size, + vma.backing_block->data() + vma.offset); break; case VMAType::BackingMemory: - Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); + memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); break; case VMAType::MMIO: - Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); + memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); break; } } diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index c00cef062..745f2c4e8 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -18,13 +18,13 @@ namespace Kernel { WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {} WaitObject::~WaitObject() = default; -void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { +void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); if (itr == waiting_threads.end()) waiting_threads.push_back(std::move(thread)); } -void WaitObject::RemoveWaitingThread(Thread* thread) { +void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) { auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); // If a thread passed multiple handles to the same object, // the kernel might attempt to remove the thread from the object's @@ -33,7 +33,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { +std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const { Thread* candidate = nullptr; u32 candidate_priority = THREADPRIO_LOWEST + 1; @@ -64,10 +64,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() const { } } - return candidate; + return SharedFrom(candidate); } -void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { +void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { ASSERT(!ShouldWait(thread.get())); if (!thread) { @@ -83,7 +83,7 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { Acquire(thread.get()); } - const std::size_t index = thread->GetWaitObjectIndex(this); + const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this)); thread->ClearWaitObjects(); @@ -91,7 +91,8 @@ void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) { bool resume = true; if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index); + resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), + index); } if (resume) { thread->ResumeFromWait(); @@ -105,7 +106,7 @@ void WaitObject::WakeupAllWaitingThreads() { } } -const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const { +const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const { return waiting_threads; } diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 3271a30a7..f9d596db9 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -33,13 +33,13 @@ public: * Add a thread to wait on this object * @param thread Pointer to thread to add */ - void AddWaitingThread(SharedPtr<Thread> thread); + void AddWaitingThread(std::shared_ptr<Thread> thread); /** * Removes a thread from waiting on this object (e.g. if it was resumed already) * @param thread Pointer to thread to remove */ - void RemoveWaitingThread(Thread* thread); + void RemoveWaitingThread(std::shared_ptr<Thread> thread); /** * Wake up all threads waiting on this object that can be awoken, in priority order, @@ -51,24 +51,24 @@ public: * Wakes up a single thread waiting on this object. * @param thread Thread that is waiting on this object to wakeup. */ - void WakeupWaitingThread(SharedPtr<Thread> thread); + void WakeupWaitingThread(std::shared_ptr<Thread> thread); /// Obtains the highest priority thread that is ready to run from this object's waiting list. - SharedPtr<Thread> GetHighestPriorityReadyThread() const; + std::shared_ptr<Thread> GetHighestPriorityReadyThread() const; /// Get a const reference to the waiting threads list for debug use - const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const; + const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; private: /// Threads waiting for this object to become available - std::vector<SharedPtr<Thread>> waiting_threads; + std::vector<std::shared_ptr<Thread>> waiting_threads; }; // Specialization of DynamicObjectCast for WaitObjects template <> -inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { +inline std::shared_ptr<WaitObject> DynamicObjectCast<WaitObject>(std::shared_ptr<Object> object) { if (object != nullptr && object->IsWaitable()) { - return boost::static_pointer_cast<WaitObject>(object); + return std::static_pointer_cast<WaitObject>(object); } return nullptr; } diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp index c783a34ee..c9332e3e1 100644 --- a/src/core/hle/kernel/writable_event.cpp +++ b/src/core/hle/kernel/writable_event.cpp @@ -16,8 +16,8 @@ WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {} WritableEvent::~WritableEvent() = default; EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { - SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel)); - SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel)); + std::shared_ptr<WritableEvent> writable_event(new WritableEvent(kernel)); + std::shared_ptr<ReadableEvent> readable_event(new ReadableEvent(kernel)); writable_event->name = name + ":Writable"; writable_event->readable = readable_event; @@ -27,7 +27,7 @@ EventPair WritableEvent::CreateEventPair(KernelCore& kernel, std::string name) { return {std::move(readable_event), std::move(writable_event)}; } -SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const { +std::shared_ptr<ReadableEvent> WritableEvent::GetReadableEvent() const { return readable; } diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h index f46cf1dd8..afe97f3a9 100644 --- a/src/core/hle/kernel/writable_event.h +++ b/src/core/hle/kernel/writable_event.h @@ -13,8 +13,8 @@ class ReadableEvent; class WritableEvent; struct EventPair { - SharedPtr<ReadableEvent> readable; - SharedPtr<WritableEvent> writable; + std::shared_ptr<ReadableEvent> readable; + std::shared_ptr<WritableEvent> writable; }; class WritableEvent final : public Object { @@ -40,7 +40,7 @@ public: return HANDLE_TYPE; } - SharedPtr<ReadableEvent> GetReadableEvent() const; + std::shared_ptr<ReadableEvent> GetReadableEvent() const; void Signal(); void Clear(); @@ -49,7 +49,7 @@ public: private: explicit WritableEvent(KernelCore& kernel); - SharedPtr<ReadableEvent> readable; + std::shared_ptr<ReadableEvent> readable; std::string name; ///< Name of event (optional) }; diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 8a3701151..450f61fea 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -147,6 +147,14 @@ constexpr bool operator!=(const ResultCode& a, const ResultCode& b) { constexpr ResultCode RESULT_SUCCESS(0); /** + * Placeholder result code used for unknown error codes. + * + * @note This should only be used when a particular error code + * is not known yet. + */ +constexpr ResultCode RESULT_UNKNOWN(UINT32_MAX); + +/** * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, * also holds a result of type `T`. If the code is an error code then trying to access the inner * value fails, thus ensuring that the ResultCode of functions is always checked properly before @@ -183,7 +191,7 @@ class ResultVal { public: /// Constructs an empty `ResultVal` with the given error code. The code must not be a success /// code. - ResultVal(ResultCode error_code = ResultCode(-1)) : result_code(error_code) { + ResultVal(ResultCode error_code = RESULT_UNKNOWN) : result_code(error_code) { ASSERT(error_code.IsError()); } diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 0c0f7ed6e..7e3e311fb 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -84,7 +84,7 @@ protected: LOG_ERROR(Service_ACC, "Failed to get profile base and data for user={}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); // TODO(ogniK): Get actual error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Get actual error code } } @@ -98,7 +98,7 @@ protected: } else { LOG_ERROR(Service_ACC, "Failed to get profile base for user={}", user_id.Format()); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); // TODO(ogniK): Get actual error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Get actual error code } } @@ -442,7 +442,7 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex const auto user_list = profile_manager->GetAllUsers(); if (std::all_of(user_list.begin(), user_list.end(), [](const auto& user) { return user.uuid == Common::INVALID_UUID; })) { - rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find the correct error code rb.PushRaw<u128>(Common::INVALID_UUID); return; } diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 0d1663657..b941c260b 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -28,6 +28,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, {104, nullptr, "GetProfileUpdateNotifier"}, {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, + {106, nullptr, "GetProfileSyncNotifier"}, {110, nullptr, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {112, nullptr, "LoadSaveDataThumbnail"}, @@ -44,6 +45,8 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"}, {206, nullptr, "CompleteUserRegistrationForcibly"}, {210, nullptr, "CreateFloatingRegistrationRequest"}, + {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, + {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, {230, nullptr, "AuthenticateServiceAsync"}, {250, nullptr, "GetBaasAccountAdministrator"}, {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"}, diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 6520b3968..858e91dde 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -28,6 +28,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p {103, nullptr, "GetProfileUpdateNotifier"}, {104, nullptr, "CheckNetworkServiceAvailabilityAsync"}, {105, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, + {106, nullptr, "GetProfileSyncNotifier"}, {110, nullptr, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {112, nullptr, "LoadSaveDataThumbnail"}, diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 8f9986326..3e756e59e 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -31,8 +31,8 @@ struct ProfileDataRaw { static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size."); // TODO(ogniK): Get actual error codes -constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); -constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, -2); +constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, u32(-1)); +constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, u32(-2)); constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/avators/"; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index ba54b3040..95aa5d23d 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -229,7 +229,15 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { {20, nullptr, "InvalidateTransitionLayer"}, {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, {40, nullptr, "GetAppletResourceUsageInfo"}, - {41, nullptr, "SetCpuBoostModeForApplet"}, + {100, nullptr, "SetCpuBoostModeForApplet"}, + {110, nullptr, "PushToAppletBoundChannelForDebug"}, + {111, nullptr, "TryPopFromAppletBoundChannelForDebug"}, + {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"}, + {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"}, + {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"}, + {130, nullptr, "FriendInvitationSetApplicationParameter"}, + {131, nullptr, "FriendInvitationClearApplicationParameter"}, + {132, nullptr, "FriendInvitationPushApplicationParameter"}, }; // clang-format on @@ -278,10 +286,12 @@ ISelfController::ISelfController(Core::System& system, {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, {70, nullptr, "ReportMultimediaError"}, {71, nullptr, "GetCurrentIlluminanceEx"}, + {72, nullptr, "SetInputDetectionPolicy"}, {80, nullptr, "SetWirelessPriorityMode"}, {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, {100, nullptr, "SetAlbumImageTakenNotificationEnabled"}, + {110, nullptr, "SetApplicationAlbumUserData"}, {1000, nullptr, "GetDebugStorageChannel"}, }; // clang-format on @@ -531,12 +541,11 @@ AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { AppletMessageQueue::~AppletMessageQueue() = default; -const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() - const { +const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() const { return on_new_message.readable; } -const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() +const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() const { return on_operation_mode_changed.readable; } @@ -613,6 +622,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system, {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, {91, nullptr, "GetCurrentPerformanceConfiguration"}, {200, nullptr, "GetOperationModeSystemInfo"}, + {300, nullptr, "GetSettingsPlatformRegion"}, }; // clang-format on @@ -991,7 +1001,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -1027,7 +1037,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex if (transfer_mem == nullptr) { LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -1076,11 +1086,18 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, - {110, nullptr, "QueryApplicationPlayStatistics"}, + {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, + {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, {122, nullptr, "UnpopToUserChannel"}, {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, + {140, nullptr, "GetFriendInvitationStorageChannelEvent"}, + {141, nullptr, "TryPopFromFriendInvitationStorageChannel"}, + {150, nullptr, "GetNotificationStorageChannelEvent"}, + {151, nullptr, "TryPopFromNotificationStorageChannel"}, + {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, + {170, nullptr, "SetHdcpAuthenticationActivated"}, {500, nullptr, "StartContinuousRecordingFlushForDebug"}, {1000, nullptr, "CreateMovieMaker"}, {1001, nullptr, "PrepareForJit"}, @@ -1335,12 +1352,16 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { } void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + u64 new_normal_size; + u64 new_journal_size; + }; + static_assert(sizeof(Parameters) == 40); + IPC::RequestParser rp{ctx}; - const auto type{rp.PopRaw<FileSys::SaveDataType>()}; - rp.Skip(1, false); - const auto user_id{rp.PopRaw<u128>()}; - const auto new_normal_size{rp.PopRaw<u64>()}; - const auto new_journal_size{rp.PopRaw<u64>()}; + const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>(); LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " @@ -1359,10 +1380,14 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { } void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { + struct Parameters { + FileSys::SaveDataType type; + u128 user_id; + }; + static_assert(sizeof(Parameters) == 24); + IPC::RequestParser rp{ctx}; - const auto type{rp.PopRaw<FileSys::SaveDataType>()}; - rp.Skip(1, false); - const auto user_id{rp.PopRaw<u128>()}; + const auto [type, user_id] = rp.PopRaw<Parameters>(); LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), user_id[1], user_id[0]); @@ -1376,6 +1401,22 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) { rb.Push(size.journal); } +void IApplicationFunctions::QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); +} + +void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(0); +} + void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -1409,6 +1450,8 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" {30, nullptr, "GetHomeButtonWriterLockAccessor"}, {31, nullptr, "GetWriterLockAccessorEx"}, {100, nullptr, "PopRequestLaunchApplicationForDebug"}, + {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, + {200, nullptr, "LaunchDevMenu"}, }; // clang-format on diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 2ae9402a8..448817be9 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -54,8 +54,8 @@ public: explicit AppletMessageQueue(Kernel::KernelCore& kernel); ~AppletMessageQueue(); - const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; - const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; + const std::shared_ptr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; + const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; void PushMessage(AppletMessage msg); AppletMessage PopMessage(); std::size_t GetMessageCount() const; @@ -255,6 +255,8 @@ private: void InitializeApplicationCopyrightFrameBuffer(Kernel::HLERequestContext& ctx); void SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx); void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); + void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); + void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); bool launch_popped_application_specific = false; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 673ad1f7f..92f995f8f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -108,15 +108,15 @@ void AppletDataBroker::SignalStateChanged() const { state_changed_event.writable->Signal(); } -Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const { +std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const { return pop_out_data_event.readable; } -Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { +std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { return pop_interactive_out_data_event.readable; } -Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const { +std::shared_ptr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const { return state_changed_event.readable; } diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 226be88b1..16e61fc6f 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -86,9 +86,9 @@ public: void SignalStateChanged() const; - Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const; - Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const; - Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const; + std::shared_ptr<Kernel::ReadableEvent> GetNormalDataEvent() const; + std::shared_ptr<Kernel::ReadableEvent> GetInteractiveDataEvent() const; + std::shared_ptr<Kernel::ReadableEvent> GetStateChangedEvent() const; private: // Queues are named from applet's perspective diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 32283e819..5546ef6e8 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -337,7 +337,7 @@ void WebBrowser::ExecuteInternal() { void WebBrowser::InitializeShop() { if (frontend_e_commerce == nullptr) { LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -353,7 +353,7 @@ void WebBrowser::InitializeShop() { if (url == args.end()) { LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -366,7 +366,7 @@ void WebBrowser::InitializeShop() { // Less is missing info, More is malformed if (split_query.size() != 2) { LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -390,7 +390,7 @@ void WebBrowser::InitializeShop() { if (scene == shop_query.end()) { LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -406,7 +406,7 @@ void WebBrowser::InitializeShop() { const auto target = target_map.find(scene->second); if (target == target_map.end()) { LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return; } @@ -427,7 +427,7 @@ void WebBrowser::InitializeOffline() { if (args.find(WebArgTLVType::DocumentPath) == args.end() || args.find(WebArgTLVType::DocumentKind) == args.end() || args.find(WebArgTLVType::ApplicationID) == args.end()) { - status = ResultCode(-1); + status = RESULT_UNKNOWN; LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!"); } @@ -476,7 +476,7 @@ void WebBrowser::InitializeOffline() { offline_romfs = GetApplicationRomFS(system, title_id, type); if (offline_romfs == nullptr) { - status = ResultCode(-1); + status = RESULT_UNKNOWN; LOG_ERROR(Service_AM, "Failed to find offline data for request!"); } @@ -496,7 +496,7 @@ void WebBrowser::ExecuteShop() { const auto check_optional_parameter = [this](const auto& p) { if (!p.has_value()) { LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!"); - status = ResultCode(-1); + status = RESULT_UNKNOWN; return false; } diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp index f814fe2c0..d256d57c8 100644 --- a/src/core/hle/service/am/idle.cpp +++ b/src/core/hle/service/am/idle.cpp @@ -10,7 +10,7 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetAutoPowerDownEvent"}, - {1, nullptr, "Unknown1"}, + {1, nullptr, "IsAutoPowerDownRequested"}, {2, nullptr, "Unknown2"}, {3, nullptr, "SetHandlingContext"}, {4, nullptr, "LoadAndApplySettings"}, diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp index 6ab3fb906..37389ccda 100644 --- a/src/core/hle/service/am/omm.cpp +++ b/src/core/hle/service/am/omm.cpp @@ -35,6 +35,8 @@ OMM::OMM() : ServiceFramework{"omm"} { {23, nullptr, "GetHdcpState"}, {24, nullptr, "ShowCardUpdateProcessing"}, {25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"}, + {26, nullptr, "GetOperationModeSystemInfo"}, + {27, nullptr, "GetAppletFullAwakingSystemEvent"}, }; // clang-format on diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index f36ccbc49..4227a4adf 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -61,6 +61,7 @@ AOC_U::AOC_U(Core::System& system) {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, {100, nullptr, "CreateEcPurchasedEventManager"}, + {101, nullptr, "CreatePermanentEcPurchasedEventManager"}, }; // clang-format on @@ -131,7 +132,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { if (out.size() < offset) { IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find the correct error code. - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 6a01d4d29..9e08e5346 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp @@ -38,6 +38,7 @@ AudCtl::AudCtl() : ServiceFramework{"audctl"} { {24, nullptr, "GetSystemOutputMasterVolume"}, {25, nullptr, "GetAudioVolumeDataForPlayReport"}, {26, nullptr, "UpdateHeadphoneSettings"}, + {27, nullptr, "SetVolumeMappingTableForDev"}, }; // clang-format on diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 6a29377e3..4fb2cbc4b 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -43,7 +43,8 @@ public: IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, std::string&& unique_name) : ServiceFramework("IAudioOut"), audio_core(audio_core), - device_name(std::move(device_name)), audio_params(audio_params) { + device_name(std::move(device_name)), + audio_params(audio_params), main_memory{system.Memory()} { // clang-format off static const FunctionInfo functions[] = { {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, @@ -137,7 +138,7 @@ private: const u64 tag{rp.Pop<u64>()}; std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16)); - Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size); + main_memory.ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size); if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) { IPC::ResponseBuilder rb{ctx, 2}; @@ -209,6 +210,7 @@ private: /// This is the event handle used to check if the audio buffer was released Kernel::EventPair buffer_event; + Memory::Memory& main_memory; }; AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 4ea7ade6e..82a5dbf14 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -49,8 +49,9 @@ public: system_event = Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); - renderer = std::make_unique<AudioCore::AudioRenderer>( - system.CoreTiming(), audren_params, system_event.writable, instance_number); + renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(), + audren_params, system_event.writable, + instance_number); } private: diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index cb4a1160d..cb839e4a2 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -80,7 +80,7 @@ private: LOG_ERROR(Audio, "Failed to decode opus data"); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -278,7 +278,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error); IPC::ResponseBuilder rb{ctx, 2}; // TODO(ogniK): Use correct error code - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp index dec0849b8..6f5ea095a 100644 --- a/src/core/hle/service/bcat/backend/backend.cpp +++ b/src/core/hle/service/bcat/backend/backend.cpp @@ -16,7 +16,7 @@ ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, kernel, std::string("ProgressServiceBackend:UpdateEvent:").append(event_name)); } -Kernel::SharedPtr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const { +std::shared_ptr<Kernel::ReadableEvent> ProgressServiceBackend::GetEvent() const { return event.readable; } diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h index ea4b16ad0..48bbbe66f 100644 --- a/src/core/hle/service/bcat/backend/backend.h +++ b/src/core/hle/service/bcat/backend/backend.h @@ -98,7 +98,7 @@ public: private: explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name); - Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent() const; + std::shared_ptr<Kernel::ReadableEvent> GetEvent() const; DeliveryCacheProgressImpl& GetImpl(); void SignalUpdate() const; diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp index 918159e11..67e39a5c4 100644 --- a/src/core/hle/service/bcat/backend/boxcat.cpp +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -114,7 +114,7 @@ void HandleDownloadDisplayResult(const AM::Applets::AppletManager& applet_manage const auto& frontend{applet_manager.GetAppletFrontendSet()}; frontend.error->ShowCustomErrorText( - ResultCode(-1), "There was an error while attempting to use Boxcat.", + RESULT_UNKNOWN, "There was an error while attempting to use Boxcat.", DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {}); } @@ -255,7 +255,7 @@ private: using Digest = std::array<u8, 0x20>; static Digest DigestFile(std::vector<u8> bytes) { Digest out{}; - mbedtls_sha256(bytes.data(), bytes.size(), out.data(), 0); + mbedtls_sha256_ret(bytes.data(), bytes.size(), out.data(), 0); return out; } diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 6d9d1527d..7ada67130 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -46,7 +46,7 @@ u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) { BCATDigest DigestFile(const FileSys::VirtualFile& file) { BCATDigest out{}; const auto bytes = file->ReadAllBytes(); - mbedtls_md5(bytes.data(), bytes.size(), out.data()); + mbedtls_md5_ret(bytes.data(), bytes.size(), out.data()); return out; } @@ -87,7 +87,7 @@ struct DeliveryCacheDirectoryEntry { class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { public: - IDeliveryCacheProgressService(Kernel::SharedPtr<Kernel::ReadableEvent> event, + IDeliveryCacheProgressService(std::shared_ptr<Kernel::ReadableEvent> event, const DeliveryCacheProgressImpl& impl) : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { // clang-format off @@ -118,7 +118,7 @@ private: rb.Push(RESULT_SUCCESS); } - Kernel::SharedPtr<Kernel::ReadableEvent> event; + std::shared_ptr<Kernel::ReadableEvent> event; const DeliveryCacheProgressImpl& impl; }; @@ -137,14 +137,20 @@ public: {10200, nullptr, "CancelSyncDeliveryCacheRequest"}, {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"}, {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"}, + {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"}, + {20301, nullptr, "RequestSuspendDeliveryTask"}, + {20400, nullptr, "RegisterSystemApplicationDeliveryTask"}, + {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"}, {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, {30200, nullptr, "RegisterBackgroundDeliveryTask"}, {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, {30202, nullptr, "BlockDeliveryTask"}, {30203, nullptr, "UnblockDeliveryTask"}, + {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"}, {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, {90200, nullptr, "GetDeliveryList"}, {90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"}, + {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"}, {90300, nullptr, "GetPushNotificationLog"}, }; // clang-format on diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 4574d9572..40a06c9fd 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -155,6 +155,7 @@ public: {98, nullptr, "SetLeScanParameter"}, {256, nullptr, "GetIsManufacturingMode"}, {257, nullptr, "EmulateBluetoothCrash"}, + {258, nullptr, "GetBleChannelMap"}, }; // clang-format on diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp index d9b32954e..4ec8c3093 100644 --- a/src/core/hle/service/erpt/erpt.cpp +++ b/src/core/hle/service/erpt/erpt.cpp @@ -24,6 +24,8 @@ public: {6, nullptr, "SubmitMultipleCategoryContext"}, {7, nullptr, "UpdateApplicationLaunchTime"}, {8, nullptr, "ClearApplicationLaunchTime"}, + {9, nullptr, "SubmitAttachment"}, + {10, nullptr, "CreateReportWithAttachments"}, }; // clang-format on @@ -38,6 +40,7 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "OpenReport"}, {1, nullptr, "OpenManager"}, + {2, nullptr, "OpenAttachment"}, }; // clang-format on diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index f77ddd739..df00ae625 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -52,6 +52,8 @@ public: {34, nullptr, "GetEncryptedTicketSize"}, {35, nullptr, "GetEncryptedTicketData"}, {36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"}, + {37, nullptr, "OwnTicket2"}, + {38, nullptr, "OwnTicket3"}, {503, nullptr, "GetTitleKey"}, }; // clang-format on diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 11e5c56b7..102017d73 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -58,11 +58,11 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 auto file = dir->CreateFile(FileUtil::GetFilename(path)); if (file == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } if (!file->Resize(size)) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -80,7 +80,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons } if (!dir->DeleteFile(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; @@ -94,7 +94,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path)); if (new_dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -104,7 +104,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -114,7 +114,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -125,7 +125,7 @@ ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::stri if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; @@ -142,7 +142,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, return FileSys::ERROR_PATH_NOT_FOUND; if (!src->Rename(FileUtil::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -160,7 +160,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; @@ -177,7 +177,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa return FileSys::ERROR_PATH_NOT_FOUND; if (!src->Rename(FileUtil::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return RESULT_SUCCESS; } @@ -189,7 +189,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa src_path, dest_path); // TODO(DarkLordZach): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_, @@ -287,7 +287,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() if (romfs_factory == nullptr) { // TODO(bunnei): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID()); @@ -300,7 +300,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( if (romfs_factory == nullptr) { // TODO(bunnei): Find a better error code for this - return ResultCode(-1); + return RESULT_UNKNOWN; } return romfs_factory->Open(title_id, storage_id, type); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index cbd5466c1..55d62fc5e 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -256,8 +256,8 @@ public: // TODO(DarkLordZach): Verify that this is the correct behavior. // Build entry index now to save time later. - BuildEntryIndex(entries, backend->GetFiles(), FileSys::File); - BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::Directory); + BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File); + BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory); } private: @@ -391,13 +391,10 @@ public: } void RenameFile(Kernel::HLERequestContext& ctx) { - std::vector<u8> buffer; - buffer.resize(ctx.BufferDescriptorX()[0].Size()); - Memory::ReadBlock(ctx.BufferDescriptorX()[0].Address(), buffer.data(), buffer.size()); + std::vector<u8> buffer = ctx.ReadBuffer(0); const std::string src_name = Common::StringFromBuffer(buffer); - buffer.resize(ctx.BufferDescriptorX()[1].Size()); - Memory::ReadBlock(ctx.BufferDescriptorX()[1].Address(), buffer.data(), buffer.size()); + buffer = ctx.ReadBuffer(1); const std::string dst_name = Common::StringFromBuffer(buffer); LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); @@ -680,6 +677,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) {33, nullptr, "DeleteCacheStorage"}, {34, nullptr, "GetCacheStorageSize"}, {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, + {36, nullptr, "OpenHostFileSystemWithOption"}, {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, {52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"}, {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, @@ -694,11 +692,14 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, {67, nullptr, "FindSaveDataWithFilter"}, {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, + {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, + {70, nullptr, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, {80, nullptr, "OpenSaveDataMetaFile"}, {81, nullptr, "OpenSaveDataTransferManager"}, {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"}, {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, + {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, {100, nullptr, "OpenImageDirectoryFileSystem"}, {110, nullptr, "OpenContentStorageFileSystem"}, {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, @@ -756,6 +757,8 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) {1009, nullptr, "GetAndClearMemoryReportInfo"}, {1010, nullptr, "SetDataStorageRedirectTarget"}, {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"}, + {1012, nullptr, "GetFsStackUsage"}, + {1013, nullptr, "UnsetSaveDataRootPath"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, {1200, nullptr, "OpenMultiCommitManager"}, @@ -785,7 +788,7 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { static_cast<u8>(type), title_id); IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); } void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { @@ -891,7 +894,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { // TODO (bunnei): Find the right error code to use here LOG_CRITICAL(Service_FS, "no file system interface available!"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -928,7 +931,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) { "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, static_cast<u8>(storage_id)); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 1a0214f08..219176c31 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -60,6 +60,9 @@ public: {20801, nullptr, "SyncUserSetting"}, {20900, nullptr, "RequestListSummaryOverlayNotification"}, {21000, nullptr, "GetExternalApplicationCatalog"}, + {22000, nullptr, "GetReceivedFriendInvitationList"}, + {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"}, + {22010, nullptr, "GetReceivedFriendInvitationCountCache"}, {30100, nullptr, "DropFriendNewlyFlags"}, {30101, nullptr, "DeleteFriend"}, {30110, nullptr, "DropFriendNewlyFlag"}, @@ -91,6 +94,8 @@ public: {30812, nullptr, "ChangePlayLogPermission"}, {30820, nullptr, "IssueFriendCode"}, {30830, nullptr, "ClearPlayLog"}, + {30900, nullptr, "SendFriendInvitation"}, + {30910, nullptr, "ReadFriendInvitation"}, {49900, nullptr, "DeleteNetworkServiceAccountCache"}, }; // clang-format on diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 79fff517e..4d952adc0 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -501,8 +501,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, last_processed_vibration = vibrations.back(); } -Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent( - u32 npad_id) const { +std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should // be signalled at least once, and signaled after a new controller is connected? const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 16c4caa1f..931f03430 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -109,7 +109,7 @@ public: void VibrateController(const std::vector<u32>& controller_ids, const std::vector<Vibration>& vibrations); - Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; + std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; Vibration GetLastVibration() const; void AddNewController(NPadControllerType controller); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index ecc130f6c..89bf8b815 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -77,15 +77,14 @@ IAppletResource::IAppletResource(Core::System& system) GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); // Register update callbacks - auto& core_timing = system.CoreTiming(); pad_update_event = - core_timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { + Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { UpdateControllers(userdata, cycles_late); }); // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) - core_timing.ScheduleEvent(pad_update_ticks, pad_update_event); + system.CoreTiming().ScheduleEvent(pad_update_ticks, pad_update_event); ReloadInputDevices(); } @@ -215,6 +214,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, + {135, nullptr, "SetNpadCaptureButtonAssignment"}, + {136, nullptr, "ClearNpadCaptureButtonAssignment"}, {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, {201, &Hid::SendVibrationValue, "SendVibrationValue"}, {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, @@ -245,6 +246,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {404, nullptr, "HasLeftRightBattery"}, {405, nullptr, "GetNpadInterfaceType"}, {406, nullptr, "GetNpadLeftRightInterfaceType"}, + {407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"}, + {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"}, {500, nullptr, "GetPalmaConnectionHandle"}, {501, nullptr, "InitializePalma"}, {502, nullptr, "AcquirePalmaOperationCompleteEvent"}, @@ -272,8 +275,13 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {524, nullptr, "PairPalma"}, {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, {526, nullptr, "CancelWritePalmaWaveEntry"}, + {527, nullptr, "EnablePalmaBoostMode"}, + {528, nullptr, "GetPalmaBluetoothAddress"}, + {529, nullptr, "SetDisallowedPalmaConnection"}, {1000, nullptr, "SetNpadCommunicationMode"}, {1001, nullptr, "GetNpadCommunicationMode"}, + {1002, nullptr, "SetTouchScreenConfiguration"}, + {1003, nullptr, "IsFirmwareUpdateNeededForNotification"}, }; // clang-format on @@ -969,6 +977,9 @@ public: {310, nullptr, "GetMaskedSupportedNpadStyleSet"}, {311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, {312, nullptr, "SetSupportedNpadStyleSetAll"}, + {313, nullptr, "GetNpadCaptureButtonAssignment"}, + {314, nullptr, "GetAppletFooterUiType"}, + {315, nullptr, "GetAppletDetailedUiType"}, {321, nullptr, "GetUniquePadsFromNpad"}, {322, nullptr, "GetIrSensorState"}, {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, @@ -984,6 +995,8 @@ public: {513, nullptr, "EndPermitVibrationSession"}, {520, nullptr, "EnableHandheldHids"}, {521, nullptr, "DisableHandheldHids"}, + {522, nullptr, "SetJoyConRailEnabled"}, + {523, nullptr, "IsJoyConRailEnabled"}, {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, {541, nullptr, "GetPlayReportControllerUsages"}, {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, @@ -1010,6 +1023,7 @@ public: {809, nullptr, "GetUniquePadSerialNumber"}, {810, nullptr, "GetUniquePadControllerNumber"}, {811, nullptr, "GetSixAxisSensorUserCalibrationStage"}, + {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"}, {821, nullptr, "StartAnalogStickManualCalibration"}, {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"}, {823, nullptr, "CancelAnalogStickManualCalibration"}, @@ -1020,6 +1034,8 @@ public: {828, nullptr, "IsAnalogStickInReleasePosition"}, {829, nullptr, "IsAnalogStickInCircumference"}, {830, nullptr, "SetNotificationLedPattern"}, + {831, nullptr, "SetNotificationLedPatternWithTimeout"}, + {832, nullptr, "PrepareHidsForNotificationWake"}, {850, nullptr, "IsUsbFullKeyControllerEnabled"}, {851, nullptr, "EnableUsbFullKeyController"}, {852, nullptr, "IsUsbConnected"}, @@ -1049,6 +1065,13 @@ public: {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, {1133, nullptr, "StartUsbFirmwareUpdate"}, {1134, nullptr, "GetUsbFirmwareUpdateState"}, + {1150, nullptr, "SetTouchScreenMagnification"}, + {1151, nullptr, "GetTouchScreenFirmwareVersion"}, + {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, + {1153, nullptr, "GetTouchScreenDefaultConfiguration"}, + {1154, nullptr, "IsFirmwareAvailableForNotification"}, + {1155, nullptr, "SetForceHandheldStyleVibration"}, + {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, }; // clang-format on diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index f08e036a3..ad20f147c 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -67,9 +67,9 @@ private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(u64 userdata, s64 cycles_late); - Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; + std::shared_ptr<Kernel::SharedMemory> shared_mem; - Core::Timing::EventType* pad_update_event; + std::shared_ptr<Core::Timing::EventType> pad_update_event; Core::System& system; std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index eb4e898dd..8918ad6ca 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -37,7 +37,7 @@ private: void RunIrLedProcessor(Kernel::HLERequestContext& ctx); void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); - Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; + std::shared_ptr<Kernel::SharedMemory> shared_mem; const u32 device_handle{0xABCD}; Core::System& system; }; diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 499376bfc..157aeec88 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -140,9 +140,10 @@ public: rb.Push(ERROR_INVALID_SIZE); return; } + // Read NRR data from memory std::vector<u8> nrr_data(nrr_size); - Memory::ReadBlock(nrr_address, nrr_data.data(), nrr_size); + system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size); NRRHeader header; std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); @@ -291,10 +292,10 @@ public: // Read NRO data from memory std::vector<u8> nro_data(nro_size); - Memory::ReadBlock(nro_address, nro_data.data(), nro_size); + system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size); SHA256Hash hash{}; - mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0); + mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0); // NRO Hash is already loaded if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) { diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 435f2d286..346c8f899 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp @@ -17,7 +17,8 @@ namespace Service::LM { class ILogger final : public ServiceFramework<ILogger> { public: - ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) { + explicit ILogger(Manager& manager_, Memory::Memory& memory_) + : ServiceFramework("ILogger"), manager{manager_}, memory{memory_} { static const FunctionInfo functions[] = { {0, &ILogger::Log, "Log"}, {1, &ILogger::SetDestination, "SetDestination"}, @@ -35,15 +36,15 @@ private: MessageHeader header{}; VAddr addr{ctx.BufferDescriptorX()[0].Address()}; const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; - Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); + memory.ReadBlock(addr, &header, sizeof(MessageHeader)); addr += sizeof(MessageHeader); FieldMap fields; while (addr < end_addr) { - const auto field = static_cast<Field>(Memory::Read8(addr++)); - const auto length = Memory::Read8(addr++); + const auto field = static_cast<Field>(memory.Read8(addr++)); + const auto length = memory.Read8(addr++); - if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { + if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) { ++addr; } @@ -54,7 +55,7 @@ private: } std::vector<u8> data(length); - Memory::ReadBlock(addr, data.data(), length); + memory.ReadBlock(addr, data.data(), length); fields.emplace(field, std::move(data)); } @@ -74,11 +75,13 @@ private: } Manager& manager; + Memory::Memory& memory; }; class LM final : public ServiceFramework<LM> { public: - explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) { + explicit LM(Manager& manager_, Memory::Memory& memory_) + : ServiceFramework{"lm"}, manager{manager_}, memory{memory_} { // clang-format off static const FunctionInfo functions[] = { {0, &LM::OpenLogger, "OpenLogger"}, @@ -94,14 +97,16 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<ILogger>(manager); + rb.PushIpcInterface<ILogger>(manager, memory); } Manager& manager; + Memory::Memory& memory; }; void InstallInterfaces(Core::System& system) { - std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager()); + std::make_shared<LM>(system.GetLogManager(), system.Memory()) + ->InstallAsService(system.ServiceManager()); } } // namespace Service::LM diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index 0b3923ad9..a128edb43 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -50,6 +50,8 @@ public: {21, &IDatabaseService::GetIndex, "GetIndex"}, {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"}, {23, nullptr, "Convert"}, + {24, nullptr, "ConvertCoreDataToCharInfo"}, + {25, nullptr, "ConvertCharInfoToCoreData"}, }; // clang-format on @@ -242,7 +244,7 @@ private: const auto index = db.IndexOf(uuid); if (index > MAX_MIIS) { // TODO(DarkLordZach): Find a better error code - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); rb.Push(index); } else { rb.Push(RESULT_SUCCESS); @@ -268,7 +270,7 @@ private: IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : ResultCode(-1)); + rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); } void AddOrReplace(Kernel::HLERequestContext& ctx) { @@ -282,7 +284,7 @@ private: IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code - rb.Push(success ? RESULT_SUCCESS : ResultCode(-1)); + rb.Push(success ? RESULT_SUCCESS : RESULT_UNKNOWN); } void Delete(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp index b405a4b66..89e283ca5 100644 --- a/src/core/hle/service/ncm/ncm.cpp +++ b/src/core/hle/service/ncm/ncm.cpp @@ -61,7 +61,8 @@ public: {5, nullptr, "RegisterHtmlDocumentPath"}, {6, nullptr, "UnregisterHtmlDocumentPath"}, {7, nullptr, "RedirectHtmlDocumentPath"}, - {8, nullptr, ""}, + {8, nullptr, "Refresh"}, + {9, nullptr, "RefreshExcluding"}, }; // clang-format on @@ -77,6 +78,8 @@ public: {0, nullptr, "ResolveAddOnContentPath"}, {1, nullptr, "RegisterAddOnContentStorage"}, {2, nullptr, "UnregisterAllAddOnContentPath"}, + {3, nullptr, "RefreshApplicationAddOnContent"}, + {4, nullptr, "UnregisterApplicationAddOnContent"}, }; // clang-format on @@ -118,6 +121,7 @@ public: {10, nullptr, "InactivateContentStorage"}, {11, nullptr, "ActivateContentMetaDatabase"}, {12, nullptr, "InactivateContentMetaDatabase"}, + {13, nullptr, "InvalidateRightsIdCache"}, }; // clang-format on diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index ca88bf97f..b7b34ce7e 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -215,6 +215,7 @@ public: {411, nullptr, "AttachActivateEvent"}, {412, nullptr, "AttachDeactivateEvent"}, {500, nullptr, "SetNfcEnabled"}, + {510, nullptr, "OutputTestWave"}, {1000, nullptr, "ReadMifare"}, {1001, nullptr, "WriteMifare"}, {1300, nullptr, "SendCommandByPassThrough"}, diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 795d7b716..4b79eb81d 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -16,10 +16,7 @@ #include "core/hle/service/nfp/nfp_user.h" namespace Service::NFP { - namespace ErrCodes { -[[maybe_unused]] constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, - -1); // TODO(ogniK): Find the actual error code constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); } // namespace ErrCodes @@ -192,7 +189,7 @@ private: LOG_DEBUG(Service_NFP, "called"); auto nfc_event = nfp_interface.GetNFCEvent(); - if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { + if (!nfc_event->ShouldWait(&ctx.GetThread()) && !has_attached_handle) { device_state = DeviceState::TagFound; nfc_event->Clear(); } @@ -345,7 +342,7 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { return true; } -const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const { +const std::shared_ptr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const { return nfc_tag_load.readable; } diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 9718ef745..200013795 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -34,7 +34,7 @@ public: void CreateUserInterface(Kernel::HLERequestContext& ctx); bool LoadAmiibo(const std::vector<u8>& buffer); - const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const; + const std::shared_ptr<Kernel::ReadableEvent>& GetNFCEvent() const; const AmiiboFile& GetAmiiboBuffer() const; private: diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 01d557c7a..2e53b3221 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -208,6 +208,7 @@ private: IGeneralService::IGeneralService(Core::System& system) : ServiceFramework("IGeneralService"), system(system) { + // clang-format off static const FunctionInfo functions[] = { {1, &IGeneralService::GetClientId, "GetClientId"}, {2, &IGeneralService::CreateScanRequest, "CreateScanRequest"}, @@ -246,7 +247,14 @@ IGeneralService::IGeneralService(Core::System& system) {36, nullptr, "GetCurrentAccessPoint"}, {37, nullptr, "Shutdown"}, {38, nullptr, "GetAllowedChannels"}, + {39, nullptr, "NotifyApplicationSuspended"}, + {40, nullptr, "SetAcceptableNetworkTypeFlag"}, + {41, nullptr, "GetAcceptableNetworkTypeFlag"}, + {42, nullptr, "NotifyConnectionStateChanged"}, + {43, nullptr, "SetWowlDelayedWakeTime"}, }; + // clang-format on + RegisterHandlers(functions); } diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 7d6cf2070..e85f123e2 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -116,6 +116,8 @@ public: {500, nullptr, "RequestSyncTicket"}, {501, nullptr, "RequestDownloadTicket"}, {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, + {503, nullptr, "RequestSyncTicket"}, + {504, nullptr, "RequestDownloadTicketForPrepurchasedContents2"}, }; // clang-format on diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp index 8751522ca..aa171473b 100644 --- a/src/core/hle/service/npns/npns.cpp +++ b/src/core/hle/service/npns/npns.cpp @@ -44,6 +44,10 @@ public: {113, nullptr, "DestroyJid"}, {114, nullptr, "AttachJid"}, {115, nullptr, "DetachJid"}, + {120, nullptr, "CreateNotificationReceiver"}, + {151, nullptr, "GetStateWithHandover"}, + {152, nullptr, "GetStateChangeEventWithHandover"}, + {153, nullptr, "GetDropEventWithHandover"}, {201, nullptr, "RequestChangeStateForceTimed"}, {202, nullptr, "RequestChangeStateForceAsync"}, }; @@ -74,6 +78,9 @@ public: {104, nullptr, "GetStatistics"}, {111, nullptr, "GetJid"}, {120, nullptr, "CreateNotificationReceiver"}, + {151, nullptr, "GetStateWithHandover"}, + {152, nullptr, "GetStateChangeEventWithHandover"}, + {153, nullptr, "GetDropEventWithHandover"}, }; // clang-format on diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 15c156ce1..fdab3cf78 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -106,6 +106,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {96, nullptr, "AcquireApplicationLaunchInfo"}, {97, nullptr, "GetMainApplicationProgramIndex2"}, {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, + {99, nullptr, "LaunchDevMenu"}, {100, nullptr, "ResetToFactorySettings"}, {101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"}, {102, nullptr, "ResetToFactorySettingsForRefurbishment"}, @@ -130,6 +131,8 @@ IApplicationManagerInterface::IApplicationManagerInterface() {404, nullptr, "InvalidateApplicationControlCache"}, {405, nullptr, "ListApplicationControlCacheEntryInfo"}, {406, nullptr, "GetApplicationControlProperty"}, + {407, nullptr, "ListApplicationTitle"}, + {408, nullptr, "ListApplicationIcon"}, {502, nullptr, "RequestCheckGameCardRegistration"}, {503, nullptr, "RequestGameCardRegistrationGoldPoint"}, {504, nullptr, "RequestRegisterGameCard"}, @@ -138,6 +141,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {507, nullptr, "EnsureGameCardAccess"}, {508, nullptr, "GetLastGameCardMountFailureResult"}, {509, nullptr, "ListApplicationIdOnGameCard"}, + {510, nullptr, "GetGameCardPlatformRegion"}, {600, nullptr, "CountApplicationContentMeta"}, {601, nullptr, "ListApplicationContentMetaStatus"}, {602, nullptr, "ListAvailableAddOnContent"}, @@ -168,6 +172,9 @@ IApplicationManagerInterface::IApplicationManagerInterface() {910, nullptr, "HasApplicationRecord"}, {911, nullptr, "SetPreInstalledApplication"}, {912, nullptr, "ClearPreInstalledApplicationFlag"}, + {913, nullptr, "ListAllApplicationRecord"}, + {914, nullptr, "HideApplicationRecord"}, + {915, nullptr, "ShowApplicationRecord"}, {1000, nullptr, "RequestVerifyApplicationDeprecated"}, {1001, nullptr, "CorruptApplicationForDebug"}, {1002, nullptr, "RequestVerifyAddOnContentsRights"}, @@ -190,12 +197,14 @@ IApplicationManagerInterface::IApplicationManagerInterface() {1502, nullptr, "GetLastSdCardFormatUnexpectedResult"}, {1504, nullptr, "InsertSdCard"}, {1505, nullptr, "RemoveSdCard"}, + {1506, nullptr, "GetSdCardStartupStatus"}, {1600, nullptr, "GetSystemSeedForPseudoDeviceId"}, {1601, nullptr, "ResetSystemSeedForPseudoDeviceId"}, {1700, nullptr, "ListApplicationDownloadingContentMeta"}, {1701, nullptr, "GetApplicationView"}, {1702, nullptr, "GetApplicationDownloadTaskStatus"}, {1703, nullptr, "GetApplicationViewDownloadErrorContext"}, + {1704, nullptr, "GetApplicationViewWithPromotionInfo"}, {1800, nullptr, "IsNotificationSetupCompleted"}, {1801, nullptr, "GetLastNotificationInfoCount"}, {1802, nullptr, "ListLastNotificationInfo"}, @@ -223,6 +232,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {2017, nullptr, "CreateDownloadTask"}, {2018, nullptr, "GetApplicationDeliveryInfoHash"}, {2050, nullptr, "GetApplicationRightsOnClient"}, + {2051, nullptr, "InvalidateRightsIdCache"}, {2100, nullptr, "GetApplicationTerminateResult"}, {2101, nullptr, "GetRawApplicationTerminateResult"}, {2150, nullptr, "CreateRightsEnvironment"}, @@ -230,6 +240,8 @@ IApplicationManagerInterface::IApplicationManagerInterface() {2152, nullptr, "ActivateRightsEnvironment"}, {2153, nullptr, "DeactivateRightsEnvironment"}, {2154, nullptr, "ForceActivateRightsContextForExit"}, + {2155, nullptr, "UpdateRightsEnvironmentStatus"}, + {2156, nullptr, "CreateRightsEnvironmentForPreomia"}, {2160, nullptr, "AddTargetApplicationToRightsEnvironment"}, {2161, nullptr, "SetUsersToRightsEnvironment"}, {2170, nullptr, "GetRightsEnvironmentStatus"}, @@ -243,6 +255,20 @@ IApplicationManagerInterface::IApplicationManagerInterface() {2201, nullptr, "GetInstalledApplicationCopyIdentifier"}, {2250, nullptr, "RequestReportActiveELicence"}, {2300, nullptr, "ListEventLog"}, + {2350, nullptr, "PerformAutoUpdateByApplicationId"}, + {2351, nullptr, "RequestNoDownloadRightsErrorResolution"}, + {2352, nullptr, "RequestResolveNoDownloadRightsError"}, + {2400, nullptr, "GetPromotionInfo"}, + {2401, nullptr, "CountPromotionInfo"}, + {2402, nullptr, "ListPromotionInfo"}, + {2403, nullptr, "ImportPromotionJsonForDebug"}, + {2404, nullptr, "ClearPromotionInfoForDebug"}, + {2500, nullptr, "ConfirmAvailableTime"}, + {2510, nullptr, "CreateApplicationResource"}, + {2511, nullptr, "GetApplicationResource"}, + {2513, nullptr, "LaunchPreomia"}, + {2514, nullptr, "ClearTaskOfAsyncTaskManager"}, + {2800, nullptr, "GetApplicationIdOfPreomia"}, }; // clang-format on @@ -271,7 +297,7 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size); IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code for this. - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -291,7 +317,7 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC 0x4000 + control.second->GetSize()); IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find a better error code for this. - rb.Push(ResultCode(-1)); + rb.Push(RESULT_UNKNOWN); return; } @@ -463,6 +489,7 @@ IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterfa {3, nullptr, "RequestSyncRights"}, {4, nullptr, "RequestUnlinkDevice"}, {5, nullptr, "RequestRevokeAllELicense"}, + {6, nullptr, "RequestSyncRightsBasedOnAssignedELicenses"}, }; // clang-format on diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 23477315f..8da4e52c5 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -97,7 +97,7 @@ void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC); std::vector<u32> transformed_font(input.size() + 2); transformed_font[0] = Common::swap32(EXPECTED_MAGIC); - transformed_font[1] = Common::swap32(input.size() * sizeof(u32)) ^ key; + transformed_font[1] = Common::swap32(static_cast<u32>(input.size() * sizeof(u32))) ^ key; std::transform(input.begin(), input.end(), transformed_font.begin() + 2, [key](u32 in) { return in ^ key; }); std::memcpy(output.data() + offset, transformed_font.data(), @@ -141,7 +141,7 @@ struct PL_U::Impl { } /// Handle to shared memory region designated for a shared font - Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; + std::shared_ptr<Kernel::SharedMemory> shared_font_mem; /// Backing memory for the shared font data std::shared_ptr<Kernel::PhysicalMemory> shared_font; @@ -152,7 +152,7 @@ struct PL_U::Impl { PL_U::PL_U(Core::System& system) : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) { - + // clang-format off static const FunctionInfo functions[] = { {0, &PL_U::RequestLoad, "RequestLoad"}, {1, &PL_U::GetLoadState, "GetLoadState"}, @@ -160,7 +160,13 @@ PL_U::PL_U(Core::System& system) {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, + {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, + {100, nullptr, "RequestApplicationFunctionAuthorization"}, + {101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"}, + {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, + {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, }; + // clang-format on RegisterHandlers(functions); auto& fsc = system.GetFileSystemController(); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 9de0ace22..6d8bca8bb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -191,8 +191,8 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, std::memcpy(entries.data(), input2.data(), params.num_entries * sizeof(Tegra::CommandListHeader)); } else { - Memory::ReadBlock(params.address, entries.data(), - params.num_entries * sizeof(Tegra::CommandListHeader)); + system.Memory().ReadBlock(params.address, entries.data(), + params.num_entries * sizeof(Tegra::CommandListHeader)); } UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index 68d139cfb..c8ea6c661 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -61,7 +61,7 @@ void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { if (ctrl.must_delay) { ctrl.fresh_call = false; ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout, - [=](Kernel::SharedPtr<Kernel::Thread> thread, + [=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { IoctlCtrl ctrl2{ctrl}; diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index cc9cd3fd1..197c77db0 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -100,11 +100,11 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { } } -Kernel::SharedPtr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { +std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { return events_interface.events[event_id].readable; } -Kernel::SharedPtr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { +std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { return events_interface.events[event_id].writable; } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f8bb28969..d7a1bef91 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -114,9 +114,9 @@ public: void SignalSyncpt(const u32 syncpoint_id, const u32 value); - Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(u32 event_id) const; + std::shared_ptr<Kernel::ReadableEvent> GetEvent(u32 event_id) const; - Kernel::SharedPtr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; + std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; private: /// Id to use for the next open file descriptor. diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 1af11e80c..32b6f4b27 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp @@ -117,11 +117,11 @@ u32 BufferQueue::Query(QueryType type) { return 0; } -Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { +std::shared_ptr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { return buffer_wait_event.writable; } -Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const { +std::shared_ptr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const { return buffer_wait_event.readable; } diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 8f9b18547..f4bbfd945 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h @@ -93,9 +93,9 @@ public: return id; } - Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; + std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; - Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const; + std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const; private: u32 id; diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index cc9522aad..52623cf89 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -37,8 +37,8 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(4, "Null", system); // Schedule the screen composition events - composition_event = system.CoreTiming().RegisterEvent( - "ScreenComposition", [this](u64 userdata, s64 cycles_late) { + composition_event = + Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) { Compose(); const auto ticks = Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); @@ -98,7 +98,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co return layer->GetBufferQueue().GetId(); } -Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { +std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { auto* const display = FindDisplay(display_id); if (display == nullptr) { diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 5d7e3bfb8..e3cc14bdc 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -62,7 +62,7 @@ public: /// Gets the vsync event for the specified display. /// /// If an invalid display ID is provided, then nullptr is returned. - Kernel::SharedPtr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; + std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; /// Obtains a buffer queue identified by the ID. BufferQueue& FindBufferQueue(u32 id); @@ -103,7 +103,7 @@ private: u32 swap_interval = 1; /// Event that handles screen composition. - Core::Timing::EventType* composition_event; + std::shared_ptr<Core::Timing::EventType> composition_event; Core::System& system; }; diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index fe6b5f798..809eca0ab 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -16,9 +16,9 @@ constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; constexpr u64 NO_PROCESS_FOUND_PID{0}; -std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList( - const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list, - std::function<bool(const Kernel::SharedPtr<Kernel::Process>&)> predicate) { +std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList( + const std::vector<std::shared_ptr<Kernel::Process>>& process_list, + std::function<bool(const std::shared_ptr<Kernel::Process>&)> predicate) { const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); if (iter == process_list.end()) { @@ -29,7 +29,7 @@ std::optional<Kernel::SharedPtr<Kernel::Process>> SearchProcessList( } void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx, - const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list) { + const std::vector<std::shared_ptr<Kernel::Process>>& process_list) { const auto process = SearchProcessList(process_list, [](const auto& process) { return process->GetProcessID() == Kernel::Process::ProcessIDMin; }); @@ -124,7 +124,7 @@ private: class Info final : public ServiceFramework<Info> { public: - explicit Info(const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list) + explicit Info(const std::vector<std::shared_ptr<Kernel::Process>>& process_list) : ServiceFramework{"pm:info"}, process_list(process_list) { static const FunctionInfo functions[] = { {0, &Info::GetTitleId, "GetTitleId"}, @@ -154,7 +154,7 @@ private: rb.Push((*process)->GetTitleID()); } - const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list; + const std::vector<std::shared_ptr<Kernel::Process>>& process_list; }; class Shell final : public ServiceFramework<Shell> { @@ -172,7 +172,7 @@ public: {6, &Shell::GetApplicationPid, "GetApplicationPid"}, {7, nullptr, "BoostSystemMemoryResourceLimit"}, {8, nullptr, "EnableAdditionalSystemThreads"}, - {9, nullptr, "GetUnimplementedEventHandle"}, + {9, nullptr, "GetBootFinishedEventHandle"}, }; // clang-format on diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 18d895263..5eb26caf8 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -25,6 +25,7 @@ public: {10103, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::New>, "SaveReportWithUser"}, {10200, nullptr, "RequestImmediateTransmission"}, {10300, nullptr, "GetTransmissionStatus"}, + {10400, nullptr, "GetSystemSessionId"}, {20100, &PlayReport::SaveSystemReport, "SaveSystemReport"}, {20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"}, {20200, nullptr, "SetOperationMode"}, diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 7c5302017..fa5347af9 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -116,7 +116,7 @@ void ServiceFrameworkBase::InstallAsNamedPort() { port_installed = true; } -Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { +std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { ASSERT(!port_installed); auto& kernel = Core::System::GetInstance().Kernel(); @@ -186,7 +186,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType())); } - context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread()); + context.WriteToOutgoingCommandBuffer(context.GetThread()); return RESULT_SUCCESS; } @@ -201,7 +201,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); - SM::ServiceManager::InstallInterfaces(sm); + SM::ServiceManager::InstallInterfaces(sm, system.Kernel()); Account::InstallInterfaces(system); AM::InstallInterfaces(*sm, nv_flinger, system); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index aef964861..022d885b6 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -65,7 +65,7 @@ public: /// Creates a port pair and registers it on the kernel's global port registry. void InstallAsNamedPort(); /// Creates and returns an unregistered port for the service. - Kernel::SharedPtr<Kernel::ClientPort> CreatePort(); + std::shared_ptr<Kernel::ClientPort> CreatePort(); void InvokeRequest(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index b54214421..5bcc0b588 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -124,6 +124,7 @@ SET::SET() : ServiceFramework("set") { {7, nullptr, "GetKeyCodeMap"}, {8, &SET::GetQuestFlag, "GetQuestFlag"}, {9, nullptr, "GetKeyCodeMap2"}, + {10, nullptr, "GetFirmwareVersionForDebug"}, }; // clang-format on diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp index 5981c575c..1398a4a48 100644 --- a/src/core/hle/service/set/set_cal.cpp +++ b/src/core/hle/service/set/set_cal.cpp @@ -7,6 +7,7 @@ namespace Service::Set { SET_CAL::SET_CAL() : ServiceFramework("set:cal") { + // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetBluetoothBdAddress"}, {1, nullptr, "GetConfigurationId1"}, @@ -40,8 +41,18 @@ SET_CAL::SET_CAL() : ServiceFramework("set:cal") { {30, nullptr, "GetAmiiboEcqvBlsCertificate"}, {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"}, {32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"}, + {33, nullptr, "GetAnalogStickModuleTypeL"}, + {34, nullptr, "GetAnalogStickModelParameterL"}, + {35, nullptr, "GetAnalogStickFactoryCalibrationL"}, + {36, nullptr, "GetAnalogStickModuleTypeR"}, + {37, nullptr, "GetAnalogStickModelParameterR"}, + {38, nullptr, "GetAnalogStickFactoryCalibrationR"}, + {39, nullptr, "GetConsoleSixAxisSensorModuleType"}, + {40, nullptr, "GetConsoleSixAxisSensorHorizontalOffset"}, {41, nullptr, "GetBatteryVersion"}, }; + // clang-format on + RegisterHandlers(functions); } diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp index cac6af86d..565882a31 100644 --- a/src/core/hle/service/set/set_fd.cpp +++ b/src/core/hle/service/set/set_fd.cpp @@ -7,6 +7,7 @@ namespace Service::Set { SET_FD::SET_FD() : ServiceFramework("set:fd") { + // clang-format off static const FunctionInfo functions[] = { {2, nullptr, "SetSettingsItemValue"}, {3, nullptr, "ResetSettingsItemValue"}, @@ -16,7 +17,10 @@ SET_FD::SET_FD() : ServiceFramework("set:fd") { {20, nullptr, "SetWebInspectorFlag"}, {21, nullptr, "SetAllowedSslHosts"}, {22, nullptr, "SetHostFsMountPoint"}, + {23, nullptr, "SetMemoryUsageRateFlag"}, }; + // clang-format on + RegisterHandlers(functions); } diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 98d0cfdfd..b7c9ea74b 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp @@ -273,10 +273,21 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") { {171, nullptr, "SetChineseTraditionalInputMethod"}, {172, nullptr, "GetPtmCycleCountReliability"}, {173, nullptr, "SetPtmCycleCountReliability"}, + {174, nullptr, "GetHomeMenuScheme"}, {175, nullptr, "GetThemeSettings"}, {176, nullptr, "SetThemeSettings"}, {177, nullptr, "GetThemeKey"}, {178, nullptr, "SetThemeKey"}, + {179, nullptr, "GetZoomFlag"}, + {180, nullptr, "SetZoomFlag"}, + {181, nullptr, "GetT"}, + {182, nullptr, "SetT"}, + {183, nullptr, "GetPlatformRegion"}, + {184, nullptr, "SetPlatformRegion"}, + {185, nullptr, "GetHomeMenuSchemeModel"}, + {186, nullptr, "GetMemoryUsageRateFlag"}, + {187, nullptr, "GetTouchScreenMode"}, + {188, nullptr, "SetTouchScreenMode"}, }; // clang-format on diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index e9ee73710..c45b285f8 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -30,10 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client}; - rb.PushMoveObjects(session); - - LOG_DEBUG(Service, "session={}", session->GetObjectId()); + rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); } void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 142929124..88909504d 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -36,16 +36,17 @@ static ResultCode ValidateServiceName(const std::string& name) { return RESULT_SUCCESS; } -void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) { +void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, + Kernel::KernelCore& kernel) { ASSERT(self->sm_interface.expired()); - auto sm = std::make_shared<SM>(self); + auto sm = std::make_shared<SM>(self, kernel); sm->InstallAsNamedPort(); self->sm_interface = sm; self->controller_interface = std::make_unique<Controller>(); } -ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService( +ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService( std::string name, unsigned int max_sessions) { CASCADE_CODE(ValidateServiceName(name)); @@ -72,7 +73,7 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) { return RESULT_SUCCESS; } -ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( +ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); @@ -84,7 +85,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( return MakeResult(it->second); } -ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService( +ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService( const std::string& name) { CASCADE_RESULT(auto client_port, GetServicePort(name)); @@ -114,8 +115,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { std::string name(name_buf.begin(), end); - // TODO(yuriks): Permission checks go here - auto client_port = service_manager->GetServicePort(name); if (client_port.Failed()) { IPC::ResponseBuilder rb{ctx, 2}; @@ -127,14 +126,22 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { return; } - auto session = client_port.Unwrap()->Connect(); - ASSERT(session.Succeeded()); - if (session.Succeeded()) { - LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); - IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; - rb.Push(session.Code()); - rb.PushMoveObjects(std::move(session).Unwrap()); + auto [client, server] = Kernel::Session::Create(kernel, name); + + const auto& server_port = client_port.Unwrap()->GetServerPort(); + if (server_port->GetHLEHandler()) { + server_port->GetHLEHandler()->ClientConnected(server); + } else { + server_port->AppendPendingSession(server); } + + // Wake the threads waiting on the ServerPort + server_port->WakeupAllWaitingThreads(); + + LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; + rb.Push(RESULT_SUCCESS); + rb.PushMoveObjects(std::move(client)); } void SM::RegisterService(Kernel::HLERequestContext& ctx) { @@ -178,8 +185,8 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) { rb.Push(service_manager->UnregisterService(name)); } -SM::SM(std::shared_ptr<ServiceManager> service_manager) - : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { +SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel) + : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} { static const FunctionInfo functions[] = { {0x00000000, &SM::Initialize, "Initialize"}, {0x00000001, &SM::GetService, "GetService"}, diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index b9d6381b4..b06d2f103 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -18,6 +18,7 @@ namespace Kernel { class ClientPort; class ClientSession; +class KernelCore; class ServerPort; class SessionRequestHandler; } // namespace Kernel @@ -29,7 +30,7 @@ class Controller; /// Interface to "sm:" service class SM final : public ServiceFramework<SM> { public: - explicit SM(std::shared_ptr<ServiceManager> service_manager); + explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel); ~SM() override; private: @@ -39,20 +40,21 @@ private: void UnregisterService(Kernel::HLERequestContext& ctx); std::shared_ptr<ServiceManager> service_manager; + Kernel::KernelCore& kernel; }; class ServiceManager { public: - static void InstallInterfaces(std::shared_ptr<ServiceManager> self); + static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel); ServiceManager(); ~ServiceManager(); - ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, - unsigned int max_sessions); + ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name, + unsigned int max_sessions); ResultCode UnregisterService(const std::string& name); - ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); - ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); + ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); + ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); template <typename T> std::shared_ptr<T> GetService(const std::string& service_name) const { @@ -77,7 +79,7 @@ private: std::unique_ptr<Controller> controller_interface; /// Map of registered services, retrieved using GetServicePort or ConnectToService. - std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> registered_services; + std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services; }; } // namespace Service::SM diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index e6d73065e..dc70fd6fe 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp @@ -7,6 +7,7 @@ namespace Service::Sockets { NSD::NSD(const char* name) : ServiceFramework(name) { + // clang-format off static const FunctionInfo functions[] = { {10, nullptr, "GetSettingName"}, {11, nullptr, "GetEnvironmentIdentifier"}, @@ -22,10 +23,14 @@ NSD::NSD(const char* name) : ServiceFramework(name) { {42, nullptr, "GetNasApiFqdn"}, {43, nullptr, "GetNasApiFqdnEx"}, {50, nullptr, "GetCurrentSetting"}, + {51, nullptr, "WriteTestParameter"}, + {52, nullptr, "ReadTestParameter"}, {60, nullptr, "ReadSaveDataFromFsForTest"}, {61, nullptr, "WriteSaveDataToFsForTest"}, {62, nullptr, "DeleteSaveDataOfFsForTest"}, }; + // clang-format on + RegisterHandlers(functions); } diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index 65040c077..1ba8c19a0 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -13,6 +13,7 @@ namespace Service::SSL { class ISslConnection final : public ServiceFramework<ISslConnection> { public: ISslConnection() : ServiceFramework("ISslConnection") { + // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "SetSocketDescriptor"}, {1, nullptr, "SetHostName"}, @@ -40,7 +41,11 @@ public: {23, nullptr, "GetOption"}, {24, nullptr, "GetVerifyCertErrors"}, {25, nullptr, "GetCipherInfo"}, + {26, nullptr, "SetNextAlpnProto"}, + {27, nullptr, "GetNextAlpnProto"}, }; + // clang-format on + RegisterHandlers(functions); } }; diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 9565e7de5..bc74f1e1d 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -21,6 +21,7 @@ Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_me {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"}, {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, {50, nullptr, "SetStandardSteadyClockInternalOffset"}, + {51, nullptr, "GetStandardSteadyClockRtcValue"}, {100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, {101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, {102, nullptr, "GetStandardUserSystemClockInitialYear"}, diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 1b9ab8401..6ee77c5f9 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -34,12 +34,12 @@ static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, additional_info = {}; return; } - calendar_time.year = tm->tm_year + 1900; - calendar_time.month = tm->tm_mon + 1; - calendar_time.day = tm->tm_mday; - calendar_time.hour = tm->tm_hour; - calendar_time.minute = tm->tm_min; - calendar_time.second = tm->tm_sec; + calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); + calendar_time.month = static_cast<u8>(tm->tm_mon + 1); + calendar_time.day = static_cast<u8>(tm->tm_mday); + calendar_time.hour = static_cast<u8>(tm->tm_hour); + calendar_time.minute = static_cast<u8>(tm->tm_min); + calendar_time.second = static_cast<u8>(tm->tm_sec); additional_info.day_of_week = tm->tm_wday; additional_info.day_of_year = tm->tm_yday; @@ -74,15 +74,17 @@ public: ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory, ClockContextType clock_type) : ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) { + // clang-format off static const FunctionInfo functions[] = { {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, {1, nullptr, "SetCurrentTime"}, {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, {3, nullptr, "SetSystemClockContext"}, - + {4, nullptr, "GetOperationEventReadableHandle"}, }; - RegisterHandlers(functions); + // clang-format on + RegisterHandlers(functions); UpdateSharedMemoryContext(system_clock_context); } @@ -162,6 +164,7 @@ private: class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { public: ITimeZoneService() : ServiceFramework("ITimeZoneService") { + // clang-format off static const FunctionInfo functions[] = { {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, {1, nullptr, "SetDeviceLocationName"}, @@ -169,11 +172,17 @@ public: {3, nullptr, "LoadLocationNameList"}, {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, {5, nullptr, "GetTimeZoneRuleVersion"}, + {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, + {7, nullptr, "SetDeviceLocationNameWithTimeZoneRule"}, + {8, nullptr, "ParseTimeZoneBinary"}, + {20, nullptr, "GetDeviceLocationNameOperationEventReadableHandle"}, {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, }; + // clang-format on + RegisterHandlers(functions); } @@ -322,7 +331,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { if (tm == nullptr) { LOG_ERROR(Service_Time, "tm is a nullptr"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code + rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find appropriate error code return; } @@ -331,12 +340,12 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; CalendarTime calendar_time{}; - calendar_time.year = tm->tm_year + 1900; - calendar_time.month = tm->tm_mon + 1; - calendar_time.day = tm->tm_mday; - calendar_time.hour = tm->tm_hour; - calendar_time.minute = tm->tm_min; - calendar_time.second = tm->tm_sec; + calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); + calendar_time.month = static_cast<u8>(tm->tm_mon + 1); + calendar_time.day = static_cast<u8>(tm->tm_mday); + calendar_time.hour = static_cast<u8>(tm->tm_hour); + calendar_time.minute = static_cast<u8>(tm->tm_min); + calendar_time.second = static_cast<u8>(tm->tm_sec); ClockSnapshot clock_snapshot{}; clock_snapshot.system_posix_time = time_since_epoch; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index bfc81b83c..4035f5072 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -21,7 +21,7 @@ SharedMemory::SharedMemory(Core::System& system) : system(system) { SharedMemory::~SharedMemory() = default; -Kernel::SharedPtr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const { +std::shared_ptr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const { return shared_memory_holder; } diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index cb8253541..904a96430 100644 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h @@ -15,7 +15,7 @@ public: ~SharedMemory(); // Return the shared memory handle - Kernel::SharedPtr<Kernel::SharedMemory> GetSharedMemoryHolder() const; + std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const; // Set memory barriers in shared memory and update them void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint); @@ -66,7 +66,7 @@ public: static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); private: - Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_holder{}; + std::shared_ptr<Kernel::SharedMemory> shared_memory_holder{}; Core::System& system; Format shared_memory_format{}; }; diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 07033fb98..cd18c1610 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -31,7 +31,7 @@ const Layer& Display::GetLayer(std::size_t index) const { return layers.at(index); } -Kernel::SharedPtr<Kernel::ReadableEvent> Display::GetVSyncEvent() const { +std::shared_ptr<Kernel::ReadableEvent> Display::GetVSyncEvent() const { return vsync_event.readable; } diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index f56b5badc..8bb966a85 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -57,7 +57,7 @@ public: const Layer& GetLayer(std::size_t index) const; /// Gets the readable vsync event. - Kernel::SharedPtr<Kernel::ReadableEvent> GetVSyncEvent() const; + std::shared_ptr<Kernel::ReadableEvent> GetVSyncEvent() const; /// Signals the internal vsync event. void SignalVSyncEvent(); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 611cecc20..651c89dc0 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -541,8 +541,8 @@ private: } else { // Wait the current thread until a buffer becomes available ctx.SleepClientThread( - "IHOSBinderDriver::DequeueBuffer", -1, - [=](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, + "IHOSBinderDriver::DequeueBuffer", UINT64_MAX, + [=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { // Repeat TransactParcel DequeueBuffer when a buffer is available auto& buffer_queue = nv_flinger->FindBufferQueue(id); @@ -731,6 +731,7 @@ class IManagerDisplayService final : public ServiceFramework<IManagerDisplayServ public: explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { + // clang-format off static const FunctionInfo functions[] = { {200, nullptr, "AllocateProcessHeapBlock"}, {201, nullptr, "FreeProcessHeapBlock"}, @@ -766,8 +767,11 @@ public: {6008, nullptr, "StartLayerPresentationFenceWait"}, {6009, nullptr, "StopLayerPresentationFenceWait"}, {6010, nullptr, "GetLayerPresentationAllFencesExpiredEvent"}, + {6011, nullptr, "EnableLayerAutoClearTransitionBuffer"}, + {6012, nullptr, "DisableLayerAutoClearTransitionBuffer"}, {7000, nullptr, "SetContentVisibility"}, {8000, nullptr, "SetConductorLayer"}, + {8001, nullptr, "SetTimestampTracking"}, {8100, nullptr, "SetIndirectProducerFlipOffset"}, {8200, nullptr, "CreateSharedBufferStaticStorage"}, {8201, nullptr, "CreateSharedBufferTransferMemory"}, @@ -800,6 +804,8 @@ public: {8297, nullptr, "GetSharedFrameBufferContentParameter"}, {8298, nullptr, "ExpandStartupLogoOnSharedFrameBuffer"}, }; + // clang-format on + RegisterHandlers(functions); } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index fa49f3dd0..91bf07a92 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -17,529 +17,699 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" -#include "core/memory_setup.h" #include "video_core/gpu.h" namespace Memory { -static Common::PageTable* current_page_table = nullptr; +// Implementation class used to keep the specifics of the memory subsystem hidden +// from outside classes. This also allows modification to the internals of the memory +// subsystem without needing to rebuild all files that make use of the memory interface. +struct Memory::Impl { + explicit Impl(Core::System& system_) : system{system_} {} -void SetCurrentPageTable(Kernel::Process& process) { - current_page_table = &process.VMManager().page_table; + void SetCurrentPageTable(Kernel::Process& process) { + current_page_table = &process.VMManager().page_table; - const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth(); + const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth(); - auto& system = Core::System::GetInstance(); - system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width); - system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width); - system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width); - system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); -} + system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width); + system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width); + system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width); + system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); + } -static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, - Common::PageType type) { - LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, - (base + size) * PAGE_SIZE); - - // During boot, current_page_table might not be set yet, in which case we need not flush - if (Core::System::GetInstance().IsPoweredOn()) { - auto& gpu = Core::System::GetInstance().GPU(); - for (u64 i = 0; i < size; i++) { - const auto page = base + i; - if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) { - gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); - } - } + void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); + MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); } - VAddr end = base + size; - ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", - base + page_table.pointers.size()); + void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer mmio_handler) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); + MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, + Common::PageType::Special); + + const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); + const Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice, + std::move(mmio_handler)}; + page_table.special_regions.add( + std::make_pair(interval, std::set<Common::SpecialRegion>{region})); + } - std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type); + void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); + MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, + Common::PageType::Unmapped); - if (memory == nullptr) { - std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end, memory); - } else { - while (base != end) { - page_table.pointers[base] = memory; + const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); + page_table.special_regions.erase(interval); + } - base += 1; - memory += PAGE_SIZE; - } + void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer hook) { + const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); + const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)}; + page_table.special_regions.add( + std::make_pair(interval, std::set<Common::SpecialRegion>{region})); } -} -void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { - ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); - ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); - MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); -} + void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer hook) { + const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); + const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)}; + page_table.special_regions.subtract( + std::make_pair(interval, std::set<Common::SpecialRegion>{region})); + } -void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, - Common::MemoryHookPointer mmio_handler) { - ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); - ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); - MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Special); + bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { + const auto& page_table = process.VMManager().page_table; - auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); - Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice, std::move(mmio_handler)}; - page_table.special_regions.add( - std::make_pair(interval, std::set<Common::SpecialRegion>{region})); -} + const u8* const page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + return true; + } -void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { - ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); - ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); - MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Unmapped); + if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) { + return true; + } - auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); - page_table.special_regions.erase(interval); -} + if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) { + return false; + } -void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, - Common::MemoryHookPointer hook) { - auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); - Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)}; - page_table.special_regions.add( - std::make_pair(interval, std::set<Common::SpecialRegion>{region})); -} + return false; + } -void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, - Common::MemoryHookPointer hook) { - auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); - Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)}; - page_table.special_regions.subtract( - std::make_pair(interval, std::set<Common::SpecialRegion>{region})); -} + bool IsValidVirtualAddress(VAddr vaddr) const { + return IsValidVirtualAddress(*system.CurrentProcess(), vaddr); + } -/** - * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) - * using a VMA from the current process - */ -static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { - const auto& vm_manager = process.VMManager(); - - const auto it = vm_manager.FindVMA(vaddr); - DEBUG_ASSERT(vm_manager.IsValidHandle(it)); - - u8* direct_pointer = nullptr; - const auto& vma = it->second; - switch (vma.type) { - case Kernel::VMAType::AllocatedMemoryBlock: - direct_pointer = vma.backing_block->data() + vma.offset; - break; - case Kernel::VMAType::BackingMemory: - direct_pointer = vma.backing_memory; - break; - case Kernel::VMAType::Free: - return nullptr; - default: - UNREACHABLE(); + /** + * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) + * using a VMA from the current process + */ + u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { + const auto& vm_manager = process.VMManager(); + + const auto it = vm_manager.FindVMA(vaddr); + DEBUG_ASSERT(vm_manager.IsValidHandle(it)); + + u8* direct_pointer = nullptr; + const auto& vma = it->second; + switch (vma.type) { + case Kernel::VMAType::AllocatedMemoryBlock: + direct_pointer = vma.backing_block->data() + vma.offset; + break; + case Kernel::VMAType::BackingMemory: + direct_pointer = vma.backing_memory; + break; + case Kernel::VMAType::Free: + return nullptr; + default: + UNREACHABLE(); + } + + return direct_pointer + (vaddr - vma.base); } - return direct_pointer + (vaddr - vma.base); -} + /** + * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) + * using a VMA from the current process. + */ + u8* GetPointerFromVMA(VAddr vaddr) { + return GetPointerFromVMA(*system.CurrentProcess(), vaddr); + } -/** - * Gets a pointer to the exact memory at the virtual address (i.e. not page aligned) - * using a VMA from the current process. - */ -static u8* GetPointerFromVMA(VAddr vaddr) { - return GetPointerFromVMA(*Core::System::GetInstance().CurrentProcess(), vaddr); -} + u8* GetPointer(const VAddr vaddr) { + u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + return page_pointer + (vaddr & PAGE_MASK); + } -template <typename T> -T Read(const VAddr vaddr) { - const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; - if (page_pointer) { - // NOTE: Avoid adding any extra logic to this fast-path block - T value; - std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); - return value; - } - - Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; - switch (type) { - case Common::PageType::Unmapped: - LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); - return 0; - case Common::PageType::Memory: - ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); - break; - case Common::PageType::RasterizerCachedMemory: { - auto host_ptr{GetPointerFromVMA(vaddr)}; - Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T)); - T value; - std::memcpy(&value, host_ptr, sizeof(T)); - return value; - } - default: - UNREACHABLE(); - } - return {}; -} + if (current_page_table->attributes[vaddr >> PAGE_BITS] == + Common::PageType::RasterizerCachedMemory) { + return GetPointerFromVMA(vaddr); + } -template <typename T> -void Write(const VAddr vaddr, const T data) { - u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; - if (page_pointer) { - // NOTE: Avoid adding any extra logic to this fast-path block - std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); - return; - } - - Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; - switch (type) { - case Common::PageType::Unmapped: - LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, - static_cast<u32>(data), vaddr); - return; - case Common::PageType::Memory: - ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); - break; - case Common::PageType::RasterizerCachedMemory: { - auto host_ptr{GetPointerFromVMA(vaddr)}; - Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); - std::memcpy(host_ptr, &data, sizeof(T)); - break; - } - default: - UNREACHABLE(); + LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr); + return nullptr; } -} -bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { - const auto& page_table = process.VMManager().page_table; + u8 Read8(const VAddr addr) { + return Read<u8>(addr); + } - const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; - if (page_pointer) - return true; + u16 Read16(const VAddr addr) { + return Read<u16_le>(addr); + } - if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) - return true; + u32 Read32(const VAddr addr) { + return Read<u32_le>(addr); + } - if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) - return false; + u64 Read64(const VAddr addr) { + return Read<u64_le>(addr); + } - return false; -} + void Write8(const VAddr addr, const u8 data) { + Write<u8>(addr, data); + } -bool IsValidVirtualAddress(const VAddr vaddr) { - return IsValidVirtualAddress(*Core::System::GetInstance().CurrentProcess(), vaddr); -} + void Write16(const VAddr addr, const u16 data) { + Write<u16_le>(addr, data); + } -bool IsKernelVirtualAddress(const VAddr vaddr) { - return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; -} + void Write32(const VAddr addr, const u32 data) { + Write<u32_le>(addr, data); + } -u8* GetPointer(const VAddr vaddr) { - u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; - if (page_pointer) { - return page_pointer + (vaddr & PAGE_MASK); + void Write64(const VAddr addr, const u64 data) { + Write<u64_le>(addr, data); } - if (current_page_table->attributes[vaddr >> PAGE_BITS] == - Common::PageType::RasterizerCachedMemory) { - return GetPointerFromVMA(vaddr); + std::string ReadCString(VAddr vaddr, std::size_t max_length) { + std::string string; + string.reserve(max_length); + for (std::size_t i = 0; i < max_length; ++i) { + const char c = Read8(vaddr); + if (c == '\0') { + break; + } + string.push_back(c); + ++vaddr; + } + string.shrink_to_fit(); + return string; } - LOG_ERROR(HW_Memory, "Unknown GetPointer @ 0x{:016X}", vaddr); - return nullptr; -} + void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); + std::memset(dest_buffer, 0, copy_amount); + break; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); -std::string ReadCString(VAddr vaddr, std::size_t max_length) { - std::string string; - string.reserve(max_length); - for (std::size_t i = 0; i < max_length; ++i) { - char c = Read8(vaddr); - if (c == '\0') - break; - string.push_back(c); - ++vaddr; + const u8* const src_ptr = page_table.pointers[page_index] + page_offset; + std::memcpy(dest_buffer, src_ptr, copy_amount); + break; + } + case Common::PageType::RasterizerCachedMemory: { + const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); + system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); + std::memcpy(dest_buffer, host_ptr, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; + remaining_size -= copy_amount; + } } - string.shrink_to_fit(); - return string; -} -void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { - if (vaddr == 0) { - return; + void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { + ReadBlock(*system.CurrentProcess(), src_addr, dest_buffer, size); } - // Iterate over a contiguous CPU address space, which corresponds to the specified GPU address - // space, marking the region as un/cached. The region is marked un/cached at a granularity of - // CPU pages, hence why we iterate on a CPU page basis (note: GPU page size is different). This - // assumes the specified GPU address region is contiguous as well. + void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, + const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + std::size_t remaining_size = size; + std::size_t page_index = dest_addr >> PAGE_BITS; + std::size_t page_offset = dest_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); + break; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + + u8* const dest_ptr = page_table.pointers[page_index] + page_offset; + std::memcpy(dest_ptr, src_buffer, copy_amount); + break; + } + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); + std::memcpy(host_ptr, src_buffer, copy_amount); + break; + } + default: + UNREACHABLE(); + } + + page_index++; + page_offset = 0; + src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; + remaining_size -= copy_amount; + } + } - u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; - for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { - Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; + void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { + WriteBlock(*system.CurrentProcess(), dest_addr, src_buffer, size); + } - if (cached) { - // Switch page type to cached if now cached - switch (page_type) { - case Common::PageType::Unmapped: - // It is not necessary for a process to have this region mapped into its address - // space, for example, a system module need not have a VRAM mapping. + void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + std::size_t remaining_size = size; + std::size_t page_index = dest_addr >> PAGE_BITS; + std::size_t page_offset = dest_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, dest_addr, size); break; - case Common::PageType::Memory: - page_type = Common::PageType::RasterizerCachedMemory; - current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + + u8* dest_ptr = page_table.pointers[page_index] + page_offset; + std::memset(dest_ptr, 0, copy_amount); break; - case Common::PageType::RasterizerCachedMemory: - // There can be more than one GPU region mapped per CPU region, so it's common that - // this area is already marked as cached. + } + case Common::PageType::RasterizerCachedMemory: { + u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); + std::memset(host_ptr, 0, copy_amount); break; + } default: UNREACHABLE(); } - } else { - // Switch page type to uncached if now uncached - switch (page_type) { - case Common::PageType::Unmapped: - // It is not necessary for a process to have this region mapped into its address - // space, for example, a system module need not have a VRAM mapping. + + page_index++; + page_offset = 0; + remaining_size -= copy_amount; + } + } + + void ZeroBlock(const VAddr dest_addr, const std::size_t size) { + ZeroBlock(*system.CurrentProcess(), dest_addr, size); + } + + void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, + const std::size_t size) { + const auto& page_table = process.VMManager().page_table; + std::size_t remaining_size = size; + std::size_t page_index = src_addr >> PAGE_BITS; + std::size_t page_offset = src_addr & PAGE_MASK; + + while (remaining_size > 0) { + const std::size_t copy_amount = + std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); + const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); + + switch (page_table.attributes[page_index]) { + case Common::PageType::Unmapped: { + LOG_ERROR(HW_Memory, + "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", + current_vaddr, src_addr, size); + ZeroBlock(process, dest_addr, copy_amount); break; - case Common::PageType::Memory: - // There can be more than one GPU region mapped per CPU region, so it's common that - // this area is already unmarked as cached. + } + case Common::PageType::Memory: { + DEBUG_ASSERT(page_table.pointers[page_index]); + const u8* src_ptr = page_table.pointers[page_index] + page_offset; + WriteBlock(process, dest_addr, src_ptr, copy_amount); break; + } case Common::PageType::RasterizerCachedMemory: { - u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); - if (pointer == nullptr) { - // It's possible that this function has been called while updating the pagetable - // after unmapping a VMA. In that case the underlying VMA will no longer exist, - // and we should just leave the pagetable entry blank. - page_type = Common::PageType::Unmapped; - } else { - page_type = Common::PageType::Memory; - current_page_table->pointers[vaddr >> PAGE_BITS] = pointer; - } + const u8* const host_ptr = GetPointerFromVMA(process, current_vaddr); + system.GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); + WriteBlock(process, dest_addr, host_ptr, copy_amount); break; } default: UNREACHABLE(); } + + page_index++; + page_offset = 0; + dest_addr += static_cast<VAddr>(copy_amount); + src_addr += static_cast<VAddr>(copy_amount); + remaining_size -= copy_amount; } } -} -u8 Read8(const VAddr addr) { - return Read<u8>(addr); -} + void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { + return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size); + } -u16 Read16(const VAddr addr) { - return Read<u16_le>(addr); -} + void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { + if (vaddr == 0) { + return; + } -u32 Read32(const VAddr addr) { - return Read<u32_le>(addr); -} + // Iterate over a contiguous CPU address space, which corresponds to the specified GPU + // address space, marking the region as un/cached. The region is marked un/cached at a + // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size + // is different). This assumes the specified GPU address region is contiguous as well. + + u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; + for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { + Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; + + if (cached) { + // Switch page type to cached if now cached + switch (page_type) { + case Common::PageType::Unmapped: + // It is not necessary for a process to have this region mapped into its address + // space, for example, a system module need not have a VRAM mapping. + break; + case Common::PageType::Memory: + page_type = Common::PageType::RasterizerCachedMemory; + current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; + break; + case Common::PageType::RasterizerCachedMemory: + // There can be more than one GPU region mapped per CPU region, so it's common + // that this area is already marked as cached. + break; + default: + UNREACHABLE(); + } + } else { + // Switch page type to uncached if now uncached + switch (page_type) { + case Common::PageType::Unmapped: + // It is not necessary for a process to have this region mapped into its address + // space, for example, a system module need not have a VRAM mapping. + break; + case Common::PageType::Memory: + // There can be more than one GPU region mapped per CPU region, so it's common + // that this area is already unmarked as cached. + break; + case Common::PageType::RasterizerCachedMemory: { + u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK); + if (pointer == nullptr) { + // It's possible that this function has been called while updating the + // pagetable after unmapping a VMA. In that case the underlying VMA will no + // longer exist, and we should just leave the pagetable entry blank. + page_type = Common::PageType::Unmapped; + } else { + page_type = Common::PageType::Memory; + current_page_table->pointers[vaddr >> PAGE_BITS] = pointer; + } + break; + } + default: + UNREACHABLE(); + } + } + } + } -u64 Read64(const VAddr addr) { - return Read<u64_le>(addr); -} + /** + * Maps a region of pages as a specific type. + * + * @param page_table The page table to use to perform the mapping. + * @param base The base address to begin mapping at. + * @param size The total size of the range in bytes. + * @param memory The memory to map. + * @param type The page type to map the memory as. + */ + void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, + Common::PageType type) { + LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, + (base + size) * PAGE_SIZE); + + // During boot, current_page_table might not be set yet, in which case we need not flush + if (system.IsPoweredOn()) { + auto& gpu = system.GPU(); + for (u64 i = 0; i < size; i++) { + const auto page = base + i; + if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) { + gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); + } + } + } -void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, - const std::size_t size) { - const auto& page_table = process.VMManager().page_table; - - std::size_t remaining_size = size; - std::size_t page_index = src_addr >> PAGE_BITS; - std::size_t page_offset = src_addr & PAGE_MASK; - - while (remaining_size > 0) { - const std::size_t copy_amount = - std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); - const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); - - switch (page_table.attributes[page_index]) { - case Common::PageType::Unmapped: { - LOG_ERROR(HW_Memory, - "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", - current_vaddr, src_addr, size); - std::memset(dest_buffer, 0, copy_amount); - break; + const VAddr end = base + size; + ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", + base + page_table.pointers.size()); + + std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type); + + if (memory == nullptr) { + std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end, + memory); + } else { + while (base != end) { + page_table.pointers[base] = memory; + + base += 1; + memory += PAGE_SIZE; + } + } + } + + /** + * Reads a particular data type out of memory at the given virtual address. + * + * @param vaddr The virtual address to read the data type from. + * + * @tparam T The data type to read out of memory. This type *must* be + * trivially copyable, otherwise the behavior of this function + * is undefined. + * + * @returns The instance of T read from the specified virtual address. + */ + template <typename T> + T Read(const VAddr vaddr) { + const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + // NOTE: Avoid adding any extra logic to this fast-path block + T value; + std::memcpy(&value, &page_pointer[vaddr & PAGE_MASK], sizeof(T)); + return value; } - case Common::PageType::Memory: { - DEBUG_ASSERT(page_table.pointers[page_index]); - const u8* src_ptr = page_table.pointers[page_index] + page_offset; - std::memcpy(dest_buffer, src_ptr, copy_amount); + const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case Common::PageType::Unmapped: + LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); + return 0; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); break; + case Common::PageType::RasterizerCachedMemory: { + const u8* const host_ptr = GetPointerFromVMA(vaddr); + system.GPU().FlushRegion(ToCacheAddr(host_ptr), sizeof(T)); + T value; + std::memcpy(&value, host_ptr, sizeof(T)); + return value; + } + default: + UNREACHABLE(); } + return {}; + } + + /** + * Writes a particular data type to memory at the given virtual address. + * + * @param vaddr The virtual address to write the data type to. + * + * @tparam T The data type to write to memory. This type *must* be + * trivially copyable, otherwise the behavior of this function + * is undefined. + * + * @returns The instance of T write to the specified virtual address. + */ + template <typename T> + void Write(const VAddr vaddr, const T data) { + u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer != nullptr) { + // NOTE: Avoid adding any extra logic to this fast-path block + std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T)); + return; + } + + const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case Common::PageType::Unmapped: + LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, + static_cast<u32>(data), vaddr); + return; + case Common::PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); + break; case Common::PageType::RasterizerCachedMemory: { - const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; - Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); - std::memcpy(dest_buffer, host_ptr, copy_amount); + u8* const host_ptr{GetPointerFromVMA(vaddr)}; + system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); + std::memcpy(host_ptr, &data, sizeof(T)); break; } default: UNREACHABLE(); } - - page_index++; - page_offset = 0; - dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; - remaining_size -= copy_amount; } + + Common::PageTable* current_page_table = nullptr; + Core::System& system; +}; + +Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {} +Memory::~Memory() = default; + +void Memory::SetCurrentPageTable(Kernel::Process& process) { + impl->SetCurrentPageTable(process); } -void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { - ReadBlock(*Core::System::GetInstance().CurrentProcess(), src_addr, dest_buffer, size); +void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { + impl->MapMemoryRegion(page_table, base, size, target); } -void Write8(const VAddr addr, const u8 data) { - Write<u8>(addr, data); +void Memory::MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer mmio_handler) { + impl->MapIoRegion(page_table, base, size, std::move(mmio_handler)); } -void Write16(const VAddr addr, const u16 data) { - Write<u16_le>(addr, data); +void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { + impl->UnmapRegion(page_table, base, size); } -void Write32(const VAddr addr, const u32 data) { - Write<u32_le>(addr, data); +void Memory::AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer hook) { + impl->AddDebugHook(page_table, base, size, std::move(hook)); } -void Write64(const VAddr addr, const u64 data) { - Write<u64_le>(addr, data); +void Memory::RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer hook) { + impl->RemoveDebugHook(page_table, base, size, std::move(hook)); } -void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, - const std::size_t size) { - const auto& page_table = process.VMManager().page_table; - std::size_t remaining_size = size; - std::size_t page_index = dest_addr >> PAGE_BITS; - std::size_t page_offset = dest_addr & PAGE_MASK; - - while (remaining_size > 0) { - const std::size_t copy_amount = - std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); - const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); - - switch (page_table.attributes[page_index]) { - case Common::PageType::Unmapped: { - LOG_ERROR(HW_Memory, - "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", - current_vaddr, dest_addr, size); - break; - } - case Common::PageType::Memory: { - DEBUG_ASSERT(page_table.pointers[page_index]); +bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { + return impl->IsValidVirtualAddress(process, vaddr); +} - u8* dest_ptr = page_table.pointers[page_index] + page_offset; - std::memcpy(dest_ptr, src_buffer, copy_amount); - break; - } - case Common::PageType::RasterizerCachedMemory: { - const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; - Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); - std::memcpy(host_ptr, src_buffer, copy_amount); - break; - } - default: - UNREACHABLE(); - } +bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { + return impl->IsValidVirtualAddress(vaddr); +} - page_index++; - page_offset = 0; - src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; - remaining_size -= copy_amount; - } +u8* Memory::GetPointer(VAddr vaddr) { + return impl->GetPointer(vaddr); } -void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_buffer, size); +const u8* Memory::GetPointer(VAddr vaddr) const { + return impl->GetPointer(vaddr); } -void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { - const auto& page_table = process.VMManager().page_table; - std::size_t remaining_size = size; - std::size_t page_index = dest_addr >> PAGE_BITS; - std::size_t page_offset = dest_addr & PAGE_MASK; - - while (remaining_size > 0) { - const std::size_t copy_amount = - std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); - const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); - - switch (page_table.attributes[page_index]) { - case Common::PageType::Unmapped: { - LOG_ERROR(HW_Memory, - "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", - current_vaddr, dest_addr, size); - break; - } - case Common::PageType::Memory: { - DEBUG_ASSERT(page_table.pointers[page_index]); +u8 Memory::Read8(const VAddr addr) { + return impl->Read8(addr); +} - u8* dest_ptr = page_table.pointers[page_index] + page_offset; - std::memset(dest_ptr, 0, copy_amount); - break; - } - case Common::PageType::RasterizerCachedMemory: { - const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; - Core::System::GetInstance().GPU().InvalidateRegion(ToCacheAddr(host_ptr), copy_amount); - std::memset(host_ptr, 0, copy_amount); - break; - } - default: - UNREACHABLE(); - } +u16 Memory::Read16(const VAddr addr) { + return impl->Read16(addr); +} - page_index++; - page_offset = 0; - remaining_size -= copy_amount; - } +u32 Memory::Read32(const VAddr addr) { + return impl->Read32(addr); } -void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, - const std::size_t size) { - const auto& page_table = process.VMManager().page_table; - std::size_t remaining_size = size; - std::size_t page_index = src_addr >> PAGE_BITS; - std::size_t page_offset = src_addr & PAGE_MASK; - - while (remaining_size > 0) { - const std::size_t copy_amount = - std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); - const VAddr current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); - - switch (page_table.attributes[page_index]) { - case Common::PageType::Unmapped: { - LOG_ERROR(HW_Memory, - "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", - current_vaddr, src_addr, size); - ZeroBlock(process, dest_addr, copy_amount); - break; - } - case Common::PageType::Memory: { - DEBUG_ASSERT(page_table.pointers[page_index]); - const u8* src_ptr = page_table.pointers[page_index] + page_offset; - WriteBlock(process, dest_addr, src_ptr, copy_amount); - break; - } - case Common::PageType::RasterizerCachedMemory: { - const auto& host_ptr{GetPointerFromVMA(process, current_vaddr)}; - Core::System::GetInstance().GPU().FlushRegion(ToCacheAddr(host_ptr), copy_amount); - WriteBlock(process, dest_addr, host_ptr, copy_amount); - break; - } - default: - UNREACHABLE(); - } +u64 Memory::Read64(const VAddr addr) { + return impl->Read64(addr); +} - page_index++; - page_offset = 0; - dest_addr += static_cast<VAddr>(copy_amount); - src_addr += static_cast<VAddr>(copy_amount); - remaining_size -= copy_amount; - } +void Memory::Write8(VAddr addr, u8 data) { + impl->Write8(addr, data); +} + +void Memory::Write16(VAddr addr, u16 data) { + impl->Write16(addr, data); +} + +void Memory::Write32(VAddr addr, u32 data) { + impl->Write32(addr, data); +} + +void Memory::Write64(VAddr addr, u64 data) { + impl->Write64(addr, data); +} + +std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { + return impl->ReadCString(vaddr, max_length); +} + +void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, + const std::size_t size) { + impl->ReadBlock(process, src_addr, dest_buffer, size); +} + +void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) { + impl->ReadBlock(src_addr, dest_buffer, size); +} + +void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + std::size_t size) { + impl->WriteBlock(process, dest_addr, src_buffer, size); +} + +void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) { + impl->WriteBlock(dest_addr, src_buffer, size); } -void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { - CopyBlock(*Core::System::GetInstance().CurrentProcess(), dest_addr, src_addr, size); +void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { + impl->ZeroBlock(process, dest_addr, size); +} + +void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) { + impl->ZeroBlock(dest_addr, size); +} + +void Memory::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, + const std::size_t size) { + impl->CopyBlock(process, dest_addr, src_addr, size); +} + +void Memory::CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size) { + impl->CopyBlock(dest_addr, src_addr, size); +} + +void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { + impl->RasterizerMarkRegionCached(vaddr, size, cached); +} + +bool IsKernelVirtualAddress(const VAddr vaddr) { + return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; } } // namespace Memory diff --git a/src/core/memory.h b/src/core/memory.h index 09008e1dd..1428a6d60 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -5,8 +5,18 @@ #pragma once #include <cstddef> +#include <memory> #include <string> #include "common/common_types.h" +#include "common/memory_hook.h" + +namespace Common { +struct PageTable; +} + +namespace Core { +class System; +} namespace Kernel { class Process; @@ -36,41 +46,369 @@ enum : VAddr { KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE, }; -/// Changes the currently active page table to that of -/// the given process instance. -void SetCurrentPageTable(Kernel::Process& process); +/// Central class that handles all memory operations and state. +class Memory { +public: + explicit Memory(Core::System& system); + ~Memory(); -/// Determines if the given VAddr is valid for the specified process. -bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); -bool IsValidVirtualAddress(VAddr vaddr); -/// Determines if the given VAddr is a kernel address -bool IsKernelVirtualAddress(VAddr vaddr); + Memory(const Memory&) = delete; + Memory& operator=(const Memory&) = delete; -u8 Read8(VAddr addr); -u16 Read16(VAddr addr); -u32 Read32(VAddr addr); -u64 Read64(VAddr addr); + Memory(Memory&&) = default; + Memory& operator=(Memory&&) = default; -void Write8(VAddr addr, u8 data); -void Write16(VAddr addr, u16 data); -void Write32(VAddr addr, u32 data); -void Write64(VAddr addr, u64 data); + /** + * Changes the currently active page table to that of the given process instance. + * + * @param process The process to use the page table of. + */ + void SetCurrentPageTable(Kernel::Process& process); -void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size); -void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); -void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, - std::size_t size); -void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); -void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); -void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); + /** + * Maps an allocated buffer onto a region of the emulated process address space. + * + * @param page_table The page table of the emulated process. + * @param base The address to start mapping at. Must be page-aligned. + * @param size The amount of bytes to map. Must be page-aligned. + * @param target Buffer with the memory backing the mapping. Must be of length at least + * `size`. + */ + void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target); -u8* GetPointer(VAddr vaddr); + /** + * Maps a region of the emulated process address space as a IO region. + * + * @param page_table The page table of the emulated process. + * @param base The address to start mapping at. Must be page-aligned. + * @param size The amount of bytes to map. Must be page-aligned. + * @param mmio_handler The handler that backs the mapping. + */ + void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer mmio_handler); -std::string ReadCString(VAddr vaddr, std::size_t max_length); + /** + * Unmaps a region of the emulated process address space. + * + * @param page_table The page table of the emulated process. + * @param base The address to begin unmapping at. + * @param size The amount of bytes to unmap. + */ + void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); -/** - * Mark each page touching the region as cached. - */ -void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); + /** + * Adds a memory hook to intercept reads and writes to given region of memory. + * + * @param page_table The page table of the emulated process + * @param base The starting address to apply the hook to. + * @param size The size of the memory region to apply the hook to, in bytes. + * @param hook The hook to apply to the region of memory. + */ + void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer hook); + + /** + * Removes a memory hook from a given range of memory. + * + * @param page_table The page table of the emulated process. + * @param base The starting address to remove the hook from. + * @param size The size of the memory region to remove the hook from, in bytes. + * @param hook The hook to remove from the specified region of memory. + */ + void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, + Common::MemoryHookPointer hook); + + /** + * Checks whether or not the supplied address is a valid virtual + * address for the given process. + * + * @param process The emulated process to check the address against. + * @param vaddr The virtual address to check the validity of. + * + * @returns True if the given virtual address is valid, false otherwise. + */ + bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const; + + /** + * Checks whether or not the supplied address is a valid virtual + * address for the current process. + * + * @param vaddr The virtual address to check the validity of. + * + * @returns True if the given virtual address is valid, false otherwise. + */ + bool IsValidVirtualAddress(VAddr vaddr) const; + + /** + * Gets a pointer to the given address. + * + * @param vaddr Virtual address to retrieve a pointer to. + * + * @returns The pointer to the given address, if the address is valid. + * If the address is not valid, nullptr will be returned. + */ + u8* GetPointer(VAddr vaddr); + + /** + * Gets a pointer to the given address. + * + * @param vaddr Virtual address to retrieve a pointer to. + * + * @returns The pointer to the given address, if the address is valid. + * If the address is not valid, nullptr will be returned. + */ + const u8* GetPointer(VAddr vaddr) const; + + /** + * Reads an 8-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 8-bit value from. + * + * @returns the read 8-bit unsigned value. + */ + u8 Read8(VAddr addr); + + /** + * Reads a 16-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 16-bit value from. + * + * @returns the read 16-bit unsigned value. + */ + u16 Read16(VAddr addr); + + /** + * Reads a 32-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 32-bit value from. + * + * @returns the read 32-bit unsigned value. + */ + u32 Read32(VAddr addr); + + /** + * Reads a 64-bit unsigned value from the current process' address space + * at the given virtual address. + * + * @param addr The virtual address to read the 64-bit value from. + * + * @returns the read 64-bit value. + */ + u64 Read64(VAddr addr); + + /** + * Writes an 8-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 8-bit unsigned integer to. + * @param data The 8-bit unsigned integer to write to the given virtual address. + * + * @post The memory at the given virtual address contains the specified data value. + */ + void Write8(VAddr addr, u8 data); + + /** + * Writes a 16-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 16-bit unsigned integer to. + * @param data The 16-bit unsigned integer to write to the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + void Write16(VAddr addr, u16 data); + + /** + * Writes a 32-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 32-bit unsigned integer to. + * @param data The 32-bit unsigned integer to write to the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + void Write32(VAddr addr, u32 data); + + /** + * Writes a 64-bit unsigned integer to the given virtual address in + * the current process' address space. + * + * @param addr The virtual address to write the 64-bit unsigned integer to. + * @param data The 64-bit unsigned integer to write to the given virtual address. + * + * @post The memory range [addr, sizeof(data)) contains the given data value. + */ + void Write64(VAddr addr, u64 data); + + /** + * Reads a null-terminated string from the given virtual address. + * This function will continually read characters until either: + * + * - A null character ('\0') is reached. + * - max_length characters have been read. + * + * @note The final null-terminating character (if found) is not included + * in the returned string. + * + * @param vaddr The address to begin reading the string from. + * @param max_length The maximum length of the string to read in characters. + * + * @returns The read string. + */ + std::string ReadCString(VAddr vaddr, std::size_t max_length); + + /** + * Reads a contiguous block of bytes from a specified process' address space. + * + * @param process The process to read the data from. + * @param src_addr The virtual address to begin reading from. + * @param dest_buffer The buffer to place the read bytes into. + * @param size The amount of data to read, in bytes. + * + * @note If a size of 0 is specified, then this function reads nothing and + * no attempts to access memory are made at all. + * + * @pre dest_buffer must be at least size bytes in length, otherwise a + * buffer overrun will occur. + * + * @post The range [dest_buffer, size) contains the read bytes from the + * process' address space. + */ + void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, + std::size_t size); + + /** + * Reads a contiguous block of bytes from the current process' address space. + * + * @param src_addr The virtual address to begin reading from. + * @param dest_buffer The buffer to place the read bytes into. + * @param size The amount of data to read, in bytes. + * + * @note If a size of 0 is specified, then this function reads nothing and + * no attempts to access memory are made at all. + * + * @pre dest_buffer must be at least size bytes in length, otherwise a + * buffer overrun will occur. + * + * @post The range [dest_buffer, size) contains the read bytes from the + * current process' address space. + */ + void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size); + + /** + * Writes a range of bytes into a given process' address space at the specified + * virtual address. + * + * @param process The process to write data into the address space of. + * @param dest_addr The destination virtual address to begin writing the data at. + * @param src_buffer The data to write into the process' address space. + * @param size The size of the data to write, in bytes. + * + * @post The address range [dest_addr, size) in the process' address space + * contains the data that was within src_buffer. + * + * @post If an attempt is made to write into an unmapped region of memory, the writes + * will be ignored and an error will be logged. + * + * @post If a write is performed into a region of memory that is considered cached + * rasterizer memory, will cause the currently active rasterizer to be notified + * and will mark that region as invalidated to caches that the active + * graphics backend may be maintaining over the course of execution. + */ + void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, + std::size_t size); + + /** + * Writes a range of bytes into the current process' address space at the specified + * virtual address. + * + * @param dest_addr The destination virtual address to begin writing the data at. + * @param src_buffer The data to write into the current process' address space. + * @param size The size of the data to write, in bytes. + * + * @post The address range [dest_addr, size) in the current process' address space + * contains the data that was within src_buffer. + * + * @post If an attempt is made to write into an unmapped region of memory, the writes + * will be ignored and an error will be logged. + * + * @post If a write is performed into a region of memory that is considered cached + * rasterizer memory, will cause the currently active rasterizer to be notified + * and will mark that region as invalidated to caches that the active + * graphics backend may be maintaining over the course of execution. + */ + void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size); + + /** + * Fills the specified address range within a process' address space with zeroes. + * + * @param process The process that will have a portion of its memory zeroed out. + * @param dest_addr The starting virtual address of the range to zero out. + * @param size The size of the address range to zero out, in bytes. + * + * @post The range [dest_addr, size) within the process' address space is + * filled with zeroes. + */ + void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); + + /** + * Fills the specified address range within the current process' address space with zeroes. + * + * @param dest_addr The starting virtual address of the range to zero out. + * @param size The size of the address range to zero out, in bytes. + * + * @post The range [dest_addr, size) within the current process' address space is + * filled with zeroes. + */ + void ZeroBlock(VAddr dest_addr, std::size_t size); + + /** + * Copies data within a process' address space to another location within the + * same address space. + * + * @param process The process that will have data copied within its address space. + * @param dest_addr The destination virtual address to begin copying the data into. + * @param src_addr The source virtual address to begin copying the data from. + * @param size The size of the data to copy, in bytes. + * + * @post The range [dest_addr, size) within the process' address space contains the + * same data within the range [src_addr, size). + */ + void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, + std::size_t size); + + /** + * Copies data within the current process' address space to another location within the + * same address space. + * + * @param dest_addr The destination virtual address to begin copying the data into. + * @param src_addr The source virtual address to begin copying the data from. + * @param size The size of the data to copy, in bytes. + * + * @post The range [dest_addr, size) within the current process' address space + * contains the same data within the range [src_addr, size). + */ + void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); + + /** + * Marks each page within the specified address range as cached or uncached. + * + * @param vaddr The virtual address indicating the start of the address range. + * @param size The size of the address range in bytes. + * @param cached Whether or not any pages within the address range should be + * marked as cached or uncached. + */ + void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); + +private: + struct Impl; + std::unique_ptr<Impl> impl; +}; + +/// Determines if the given VAddr is a kernel address +bool IsKernelVirtualAddress(VAddr vaddr); } // namespace Memory diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 10821d452..d1e6bed93 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -20,18 +20,17 @@ namespace Memory { constexpr s64 CHEAT_ENGINE_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 12); constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF; -StandardVmCallbacks::StandardVmCallbacks(const Core::System& system, - const CheatProcessMetadata& metadata) +StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) : metadata(metadata), system(system) {} StandardVmCallbacks::~StandardVmCallbacks() = default; void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) { - ReadBlock(SanitizeAddress(address), data, size); + system.Memory().ReadBlock(SanitizeAddress(address), data, size); } void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) { - WriteBlock(SanitizeAddress(address), data, size); + system.Memory().WriteBlock(SanitizeAddress(address), data, size); } u64 StandardVmCallbacks::HidKeysDown() { @@ -186,7 +185,7 @@ CheatEngine::~CheatEngine() { } void CheatEngine::Initialize() { - event = core_timing.RegisterEvent( + event = Core::Timing::CreateEvent( "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id), [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h index 0f012e9b5..3d6b2298a 100644 --- a/src/core/memory/cheat_engine.h +++ b/src/core/memory/cheat_engine.h @@ -5,6 +5,7 @@ #pragma once #include <atomic> +#include <memory> #include <vector> #include "common/common_types.h" #include "core/memory/dmnt_cheat_types.h" @@ -23,7 +24,7 @@ namespace Memory { class StandardVmCallbacks : public DmntCheatVm::Callbacks { public: - StandardVmCallbacks(const Core::System& system, const CheatProcessMetadata& metadata); + StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata); ~StandardVmCallbacks() override; void MemoryRead(VAddr address, void* data, u64 size) override; @@ -36,7 +37,7 @@ private: VAddr SanitizeAddress(VAddr address) const; const CheatProcessMetadata& metadata; - const Core::System& system; + Core::System& system; }; // Intermediary class that parses a text file or other disk format for storing cheats into a @@ -78,7 +79,7 @@ private: std::vector<CheatEntry> cheats; std::atomic_bool is_pending_reload{false}; - Core::Timing::EventType* event{}; + std::shared_ptr<Core::Timing::EventType> event; Core::Timing::CoreTiming& core_timing; Core::System& system; }; diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h deleted file mode 100644 index 5225ee8e2..000000000 --- a/src/core/memory_setup.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" -#include "common/memory_hook.h" - -namespace Common { -struct PageTable; -} - -namespace Memory { - -/** - * Maps an allocated buffer onto a region of the emulated process address space. - * - * @param page_table The page table of the emulated process. - * @param base The address to start mapping at. Must be page-aligned. - * @param size The amount of bytes to map. Must be page-aligned. - * @param target Buffer with the memory backing the mapping. Must be of length at least `size`. - */ -void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target); - -/** - * Maps a region of the emulated process address space as a IO region. - * @param page_table The page table of the emulated process. - * @param base The address to start mapping at. Must be page-aligned. - * @param size The amount of bytes to map. Must be page-aligned. - * @param mmio_handler The handler that backs the mapping. - */ -void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, - Common::MemoryHookPointer mmio_handler); - -void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); - -void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, - Common::MemoryHookPointer hook); -void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, - Common::MemoryHookPointer hook); - -} // namespace Memory diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index d2c69d1a0..f1ae9d4df 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -81,7 +81,7 @@ double PerfStats::GetMeanFrametime() { return 0; } const double sum = std::accumulate(perf_history.begin() + IgnoreFrames, - perf_history.begin() + current_index, 0); + perf_history.begin() + current_index, 0.0); return sum / (current_index - IgnoreFrames); } diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 6f4af77fd..f95eee3b1 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -147,7 +147,7 @@ json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& s } template <bool read_value, typename DescriptorType> -json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) { +json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer, Memory::Memory& memory) { auto buffer_out = json::array(); for (const auto& desc : buffer) { auto entry = json{ @@ -157,7 +157,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) { if constexpr (read_value) { std::vector<u8> data(desc.Size()); - Memory::ReadBlock(desc.Address(), data.data(), desc.Size()); + memory.ReadBlock(desc.Address(), data.data(), desc.Size()); entry["data"] = Common::HexToString(data); } @@ -167,7 +167,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer) { return buffer_out; } -json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { +json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Memory::Memory& memory) { json out; auto cmd_buf = json::array(); @@ -177,10 +177,10 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) { out["command_buffer"] = std::move(cmd_buf); - out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA()); - out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB()); - out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC()); - out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX()); + out["buffer_descriptor_a"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorA(), memory); + out["buffer_descriptor_b"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorB(), memory); + out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC(), memory); + out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX(), memory); return out; } @@ -259,7 +259,7 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u const auto title_id = system.CurrentProcess()->GetTitleID(); auto out = GetFullDataAuto(timestamp, title_id, system); - auto function_out = GetHLERequestContextData(ctx); + auto function_out = GetHLERequestContextData(ctx, system.Memory()); function_out["command_id"] = command_id; function_out["function_name"] = name; function_out["service_name"] = service_name; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 793d102d3..320e8ad73 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -165,24 +165,20 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { Telemetry::AppendOSInfo(field_collection); // Log user configuration information - AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id); - AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching", - Settings::values.enable_audio_stretching); - AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore", - Settings::values.use_multi_core); - AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor", - Settings::values.resolution_factor); - AddField(Telemetry::FieldType::UserConfig, "Renderer_UseFrameLimit", - Settings::values.use_frame_limit); - AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", Settings::values.frame_limit); - AddField(Telemetry::FieldType::UserConfig, "Renderer_UseDiskShaderCache", - Settings::values.use_disk_shader_cache); - AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateGpuEmulation", + constexpr auto field_type = Telemetry::FieldType::UserConfig; + AddField(field_type, "Audio_SinkId", Settings::values.sink_id); + AddField(field_type, "Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); + AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core); + AddField(field_type, "Renderer_Backend", "OpenGL"); + AddField(field_type, "Renderer_ResolutionFactor", Settings::values.resolution_factor); + AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit); + AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit); + AddField(field_type, "Renderer_UseDiskShaderCache", Settings::values.use_disk_shader_cache); + AddField(field_type, "Renderer_UseAccurateGpuEmulation", Settings::values.use_accurate_gpu_emulation); - AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAsynchronousGpuEmulation", + AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", Settings::values.use_asynchronous_gpu_emulation); - AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode", - Settings::values.use_docked_mode); + AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); } bool TelemetrySession::SubmitTestcase() { diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 17f050068..55e0dbc49 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -11,40 +11,39 @@ #include "core/tools/freezer.h" namespace Tools { - namespace { constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60); -u64 MemoryReadWidth(u32 width, VAddr addr) { +u64 MemoryReadWidth(Memory::Memory& memory, u32 width, VAddr addr) { switch (width) { case 1: - return Memory::Read8(addr); + return memory.Read8(addr); case 2: - return Memory::Read16(addr); + return memory.Read16(addr); case 4: - return Memory::Read32(addr); + return memory.Read32(addr); case 8: - return Memory::Read64(addr); + return memory.Read64(addr); default: UNREACHABLE(); return 0; } } -void MemoryWriteWidth(u32 width, VAddr addr, u64 value) { +void MemoryWriteWidth(Memory::Memory& memory, u32 width, VAddr addr, u64 value) { switch (width) { case 1: - Memory::Write8(addr, static_cast<u8>(value)); + memory.Write8(addr, static_cast<u8>(value)); break; case 2: - Memory::Write16(addr, static_cast<u16>(value)); + memory.Write16(addr, static_cast<u16>(value)); break; case 4: - Memory::Write32(addr, static_cast<u32>(value)); + memory.Write32(addr, static_cast<u32>(value)); break; case 8: - Memory::Write64(addr, value); + memory.Write64(addr, value); break; default: UNREACHABLE(); @@ -53,8 +52,9 @@ void MemoryWriteWidth(u32 width, VAddr addr, u64 value) { } // Anonymous namespace -Freezer::Freezer(Core::Timing::CoreTiming& core_timing) : core_timing(core_timing) { - event = core_timing.RegisterEvent( +Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_) + : core_timing{core_timing_}, memory{memory_} { + event = Core::Timing::CreateEvent( "MemoryFreezer::FrameCallback", [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS, event); @@ -89,7 +89,7 @@ void Freezer::Clear() { u64 Freezer::Freeze(VAddr address, u32 width) { std::lock_guard lock{entries_mutex}; - const auto current_value = MemoryReadWidth(width, address); + const auto current_value = MemoryReadWidth(memory, width, address); entries.push_back({address, width, current_value}); LOG_DEBUG(Common_Memory, @@ -169,7 +169,7 @@ void Freezer::FrameCallback(u64 userdata, s64 cycles_late) { LOG_DEBUG(Common_Memory, "Enforcing memory freeze at address={:016X}, value={:016X}, width={:02X}", entry.address, entry.value, entry.width); - MemoryWriteWidth(entry.width, entry.address, entry.value); + MemoryWriteWidth(memory, entry.width, entry.address, entry.value); } core_timing.ScheduleEvent(MEMORY_FREEZER_TICKS - cycles_late, event); @@ -181,7 +181,7 @@ void Freezer::FillEntryReads() { LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values."); for (auto& entry : entries) { - entry.value = MemoryReadWidth(entry.width, entry.address); + entry.value = MemoryReadWidth(memory, entry.width, entry.address); } } diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h index b58de5472..916339c6c 100644 --- a/src/core/tools/freezer.h +++ b/src/core/tools/freezer.h @@ -5,6 +5,7 @@ #pragma once #include <atomic> +#include <memory> #include <mutex> #include <optional> #include <vector> @@ -15,6 +16,10 @@ class CoreTiming; struct EventType; } // namespace Core::Timing +namespace Memory { +class Memory; +} + namespace Tools { /** @@ -33,7 +38,7 @@ public: u64 value; }; - explicit Freezer(Core::Timing::CoreTiming& core_timing); + explicit Freezer(Core::Timing::CoreTiming& core_timing_, Memory::Memory& memory_); ~Freezer(); // Enables or disables the entire memory freezer. @@ -75,8 +80,9 @@ private: mutable std::mutex entries_mutex; std::vector<Entry> entries; - Core::Timing::EventType* event; + std::shared_ptr<Core::Timing::EventType> event; Core::Timing::CoreTiming& core_timing; + Memory::Memory& memory; }; } // namespace Tools |