summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/arm_interface.cpp32
-rw-r--r--src/core/arm/arm_interface.h1
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp72
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp45
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h2
-rw-r--r--src/core/core_timing.cpp85
-rw-r--r--src/core/core_timing.h25
-rw-r--r--src/core/cpu_manager.cpp55
-rw-r--r--src/core/cpu_manager.h21
-rw-r--r--src/core/debugger/gdbstub_arch.cpp8
-rw-r--r--src/core/hardware_interrupt_manager.cpp5
-rw-r--r--src/core/hid/hid_types.h1
-rw-r--r--src/core/hle/kernel/k_code_memory.h6
-rw-r--r--src/core/hle/kernel/k_process.cpp2
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp7
-rw-r--r--src/core/hle/kernel/k_scheduler.h6
-rw-r--r--src/core/hle/kernel/k_thread.cpp34
-rw-r--r--src/core/hle/kernel/k_thread.h3
-rw-r--r--src/core/hle/kernel/kernel.cpp9
-rw-r--r--src/core/hle/kernel/time_manager.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp38
-rw-r--r--src/core/hle/service/hid/controllers/npad.h3
-rw-r--r--src/core/hle/service/hid/errors.h3
-rw-r--r--src/core/hle/service/hid/hid.cpp116
-rw-r--r--src/core/hle/service/hid/hidbus.cpp16
-rw-r--r--src/core/hle/service/nifm/nifm.cpp42
-rw-r--r--src/core/hle/service/nvflinger/binder.h1
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/hle/service/ptm/psm.cpp122
-rw-r--r--src/core/hle/service/ptm/psm.h31
-rw-r--r--src/core/hle/service/ptm/ptm.cpp18
-rw-r--r--src/core/hle/service/ptm/ptm.h18
-rw-r--r--src/core/hle/service/ptm/ts.cpp41
-rw-r--r--src/core/hle/service/ptm/ts.h25
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/memory/cheat_engine.cpp8
-rw-r--r--src/core/tools/freezer.cpp4
39 files changed, 622 insertions, 326 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d9357138f..11d554bad 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -605,6 +605,10 @@ add_library(core STATIC
hle/service/psc/psc.h
hle/service/ptm/psm.cpp
hle/service/ptm/psm.h
+ hle/service/ptm/ptm.cpp
+ hle/service/ptm/ptm.h
+ hle/service/ptm/ts.cpp
+ hle/service/ptm/ts.h
hle/service/kernel_helpers.cpp
hle/service/kernel_helpers.h
hle/service/service.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 8e095cdcd..cef79b245 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -1,6 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef _MSC_VER
+#include <cxxabi.h>
+#endif
+
#include <map>
#include <optional>
#include "common/bit_field.h"
@@ -68,8 +72,19 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
if (symbol_set != symbols.end()) {
const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
if (symbol.has_value()) {
+#ifdef _MSC_VER
// TODO(DarkLordZach): Add demangling of symbol names.
entry.name = *symbol;
+#else
+ int status{-1};
+ char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)};
+ if (status == 0 && demangled != nullptr) {
+ entry.name = demangled;
+ std::free(demangled);
+ } else {
+ entry.name = *symbol;
+ }
+#endif
}
}
}
@@ -119,16 +134,23 @@ void ARM_Interface::Run() {
}
system.ExitDynarmicProfile();
- // Notify the debugger and go to sleep if a breakpoint was hit.
- if (Has(hr, breakpoint)) {
+ // Notify the debugger and go to sleep if a breakpoint was hit,
+ // or if the thread is unable to continue for any reason.
+ if (Has(hr, breakpoint) || Has(hr, no_execute)) {
RewindBreakpointInstruction();
- system.GetDebugger().NotifyThreadStopped(current_thread);
- current_thread->RequestSuspend(SuspendType::Debug);
+ if (system.DebuggerEnabled()) {
+ system.GetDebugger().NotifyThreadStopped(current_thread);
+ }
+ current_thread->RequestSuspend(Kernel::SuspendType::Debug);
break;
}
+
+ // Notify the debugger and go to sleep if a watchpoint was hit.
if (Has(hr, watchpoint)) {
RewindBreakpointInstruction();
- system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
+ if (system.DebuggerEnabled()) {
+ system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
+ }
current_thread->RequestSuspend(SuspendType::Debug);
break;
}
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 4e431e27a..8a066ed91 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -204,6 +204,7 @@ public:
static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5;
+ static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6;
protected:
/// System context that this ARM interface is running under.
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 8c90c8be0..a780cf800 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -48,6 +48,12 @@ public:
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
return memory.Read64(vaddr);
}
+ std::optional<u32> MemoryReadCode(u32 vaddr) override {
+ if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
+ return std::nullopt;
+ }
+ return memory.Read32(vaddr);
+ }
void MemoryWrite8(u32 vaddr, u8 value) override {
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
@@ -89,21 +95,28 @@ public:
void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
parent.LogBacktrace();
- UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc,
- MemoryReadCode(pc));
+ LOG_ERROR(Core_ARM,
+ "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
+ num_instructions, memory.Read32(pc));
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
- if (debugger_enabled) {
- parent.SaveContext(parent.breakpoint_context);
- parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);
+ switch (exception) {
+ case Dynarmic::A32::Exception::NoExecuteFault:
+ LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc);
+ ReturnException(pc, ARM_Interface::no_execute);
return;
- }
+ default:
+ if (debugger_enabled) {
+ ReturnException(pc, ARM_Interface::breakpoint);
+ return;
+ }
- parent.LogBacktrace();
- LOG_CRITICAL(Core_ARM,
- "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
- exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
+ parent.LogBacktrace();
+ LOG_CRITICAL(Core_ARM,
+ "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
+ exception, pc, memory.Read32(pc), parent.IsInThumbMode());
+ }
}
void CallSVC(u32 swi) override {
@@ -141,15 +154,20 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
- parent.SaveContext(parent.breakpoint_context);
- parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
parent.halted_watchpoint = match;
+ ReturnException(parent.jit.load()->Regs()[15], ARM_Interface::watchpoint);
return false;
}
return true;
}
+ void ReturnException(u32 pc, Dynarmic::HaltReason hr) {
+ parent.SaveContext(parent.breakpoint_context);
+ parent.breakpoint_context.cpu_registers[15] = pc;
+ parent.jit.load()->HaltExecution(hr);
+ }
+
ARM_Dynarmic_32& parent;
Core::Memory::Memory& memory;
std::size_t num_interpreted_instructions{};
@@ -409,18 +427,38 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
- u64 sp, u64 lr) {
- // No way to get accurate stack traces in A32 yet
- return {};
+ u64 fp, u64 lr, u64 pc) {
+ std::vector<BacktraceEntry> out;
+ auto& memory = system.Memory();
+
+ out.push_back({"", 0, pc, 0, ""});
+
+ // fp (= r11) points to the last frame record.
+ // Frame records are two words long:
+ // fp+0 : pointer to previous frame record
+ // fp+4 : value of lr for frame
+ while (true) {
+ out.push_back({"", 0, lr, 0, ""});
+ if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
+ break;
+ }
+ lr = memory.Read32(fp + 4);
+ fp = memory.Read32(fp);
+ }
+
+ SymbolicateBacktrace(system, out);
+
+ return out;
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext(
System& system, const ThreadContext32& ctx) {
- return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]);
+ const auto& reg = ctx.cpu_registers;
+ return GetBacktrace(system, reg[11], reg[14], reg[15]);
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const {
- return GetBacktrace(system, GetReg(13), GetReg(14));
+ return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15));
}
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index fcbe24f0c..346e9abf8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -78,7 +78,7 @@ protected:
private:
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
- static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr);
+ static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 4370ca294..1a75312a4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -52,6 +52,12 @@ public:
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
}
+ std::optional<u32> MemoryReadCode(u64 vaddr) override {
+ if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
+ return std::nullopt;
+ }
+ return memory.Read32(vaddr);
+ }
void MemoryWrite8(u64 vaddr, u8 value) override {
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
@@ -105,7 +111,7 @@ public:
parent.LogBacktrace();
LOG_ERROR(Core_ARM,
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
- num_instructions, MemoryReadCode(pc));
+ num_instructions, memory.Read32(pc));
}
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
@@ -138,16 +144,19 @@ public:
case Dynarmic::A64::Exception::SendEventLocal:
case Dynarmic::A64::Exception::Yield:
return;
+ case Dynarmic::A64::Exception::NoExecuteFault:
+ LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);
+ ReturnException(pc, ARM_Interface::no_execute);
+ return;
default:
if (debugger_enabled) {
- parent.SaveContext(parent.breakpoint_context);
- parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);
+ ReturnException(pc, ARM_Interface::breakpoint);
return;
}
parent.LogBacktrace();
- ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
- static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
+ LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
+ static_cast<std::size_t>(exception), pc, memory.Read32(pc));
}
}
@@ -188,15 +197,20 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
- parent.SaveContext(parent.breakpoint_context);
- parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
parent.halted_watchpoint = match;
+ ReturnException(parent.jit.load()->GetPC(), ARM_Interface::watchpoint);
return false;
}
return true;
}
+ void ReturnException(u64 pc, Dynarmic::HaltReason hr) {
+ parent.SaveContext(parent.breakpoint_context);
+ parent.breakpoint_context.pc = pc;
+ parent.jit.load()->HaltExecution(hr);
+ }
+
ARM_Dynarmic_64& parent;
Core::Memory::Memory& memory;
u64 tpidrro_el0 = 0;
@@ -480,22 +494,22 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
- u64 fp, u64 lr) {
+ u64 fp, u64 lr, u64 pc) {
std::vector<BacktraceEntry> out;
auto& memory = system.Memory();
- // fp (= r29) points to the last frame record.
- // Note that this is the frame record for the *previous* frame, not the current one.
- // Note we need to subtract 4 from our last read to get the proper address
+ out.push_back({"", 0, pc, 0, ""});
+
+ // fp (= x29) points to the previous frame record.
// Frame records are two words long:
// fp+0 : pointer to previous frame record
// fp+8 : value of lr for frame
while (true) {
out.push_back({"", 0, lr, 0, ""});
- if (!fp) {
+ if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
break;
}
- lr = memory.Read64(fp + 8) - 4;
+ lr = memory.Read64(fp + 8);
fp = memory.Read64(fp);
}
@@ -506,11 +520,12 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext(
System& system, const ThreadContext64& ctx) {
- return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]);
+ const auto& reg = ctx.cpu_registers;
+ return GetBacktrace(system, reg[29], reg[30], ctx.pc);
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const {
- return GetBacktrace(system, GetReg(29), GetReg(30));
+ return GetBacktrace(system, GetReg(29), GetReg(30), GetPC());
}
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 71dbaac5e..c77a83ad7 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -73,7 +73,7 @@ private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
- static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr);
+ static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 140578069..5425637f5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -22,10 +22,11 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
}
struct CoreTiming::Event {
- u64 time;
+ s64 time;
u64 fifo_order;
std::uintptr_t user_data;
std::weak_ptr<EventType> type;
+ s64 reschedule_time;
// Sort by time, unless the times are the same, in which case sort by
// the order added to the queue
@@ -58,15 +59,11 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
event_fifo_id = 0;
shutting_down = false;
ticks = 0;
- const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
+ const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
+ -> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) {
- const auto hardware_concurrency = std::thread::hardware_concurrency();
- size_t id = 0;
- worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
- if (hardware_concurrency > 8) {
- worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
- }
+ worker_threads.emplace_back(ThreadEntry, std::ref(*this), 0);
}
}
@@ -81,6 +78,7 @@ void CoreTiming::Shutdown() {
thread.join();
}
worker_threads.clear();
+ pause_callbacks.clear();
ClearPendingEvents();
has_started = false;
}
@@ -98,6 +96,14 @@ void CoreTiming::Pause(bool is_paused_) {
}
}
paused_state.store(is_paused_, std::memory_order_relaxed);
+
+ if (!is_paused_) {
+ pause_end_time = GetGlobalTimeNs().count();
+ }
+
+ for (auto& cb : pause_callbacks) {
+ cb(is_paused_);
+ }
}
void CoreTiming::SyncPause(bool is_paused_) {
@@ -121,6 +127,14 @@ void CoreTiming::SyncPause(bool is_paused_) {
wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
}
}
+
+ if (!is_paused_) {
+ pause_end_time = GetGlobalTimeNs().count();
+ }
+
+ for (auto& cb : pause_callbacks) {
+ cb(is_paused_);
+ }
}
bool CoreTiming::IsRunning() const {
@@ -134,12 +148,30 @@ bool CoreTiming::HasPendingEvents() const {
void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
const std::shared_ptr<EventType>& event_type,
- std::uintptr_t user_data) {
+ std::uintptr_t user_data, bool absolute_time) {
std::unique_lock main_lock(event_mutex);
- const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
+ const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
- event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type});
+ event_queue.emplace_back(Event{next_time.count(), event_fifo_id++, user_data, event_type, 0});
+ pending_events.fetch_add(1, std::memory_order_relaxed);
+
+ std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
+
+ if (is_multicore) {
+ event_cv.notify_one();
+ }
+}
+
+void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
+ std::chrono::nanoseconds resched_time,
+ const std::shared_ptr<EventType>& event_type,
+ std::uintptr_t user_data, bool absolute_time) {
+ std::unique_lock main_lock(event_mutex);
+ const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
+
+ event_queue.emplace_back(
+ Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()});
pending_events.fetch_add(1, std::memory_order_relaxed);
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
@@ -218,6 +250,11 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
}
}
+void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
+ std::unique_lock main_lock(event_mutex);
+ pause_callbacks.emplace_back(std::move(callback));
+}
+
std::optional<s64> CoreTiming::Advance() {
global_timer = GetGlobalTimeNs().count();
@@ -228,17 +265,31 @@ std::optional<s64> CoreTiming::Advance() {
event_queue.pop_back();
if (const auto event_type{evt.type.lock()}) {
- sequence_mutex.lock();
event_mutex.unlock();
- event_type->guard.lock();
- sequence_mutex.unlock();
- const s64 delay = static_cast<s64>(GetGlobalTimeNs().count() - evt.time);
- event_type->callback(evt.user_data, std::chrono::nanoseconds{delay});
- event_type->guard.unlock();
+ const auto new_schedule_time{event_type->callback(
+ evt.user_data, evt.time,
+ std::chrono::nanoseconds{GetGlobalTimeNs().count() - evt.time})};
event_mutex.lock();
pending_events.fetch_sub(1, std::memory_order_relaxed);
+
+ if (evt.reschedule_time != 0) {
+ // If this event was scheduled into a pause, its time now is going to be way behind.
+ // Re-set this event to continue from the end of the pause.
+ auto next_time{evt.time + evt.reschedule_time};
+ if (evt.time < pause_end_time) {
+ next_time = pause_end_time + evt.reschedule_time;
+ }
+
+ const auto next_schedule_time{new_schedule_time.has_value()
+ ? new_schedule_time.value().count()
+ : evt.reschedule_time};
+ event_queue.emplace_back(
+ Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time});
+ pending_events.fetch_add(1, std::memory_order_relaxed);
+ std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
+ }
}
global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index a86553e08..09b6ed81a 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -20,8 +20,9 @@
namespace Core::Timing {
/// A callback that may be scheduled for a particular core timing event.
-using TimedCallback =
- std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>;
+using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
+ std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
+using PauseCallback = std::function<void(bool paused)>;
/// Contains the characteristics of a particular event.
struct EventType {
@@ -32,7 +33,6 @@ struct EventType {
TimedCallback callback;
/// A pointer to the name of the event.
const std::string name;
- mutable std::mutex guard;
};
/**
@@ -94,7 +94,15 @@ public:
/// Schedules an event in core timing
void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
- const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0);
+ const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0,
+ bool absolute_time = false);
+
+ /// Schedules an event which will automatically re-schedule itself with the given time, until
+ /// unscheduled
+ void ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
+ std::chrono::nanoseconds resched_time,
+ const std::shared_ptr<EventType>& event_type,
+ std::uintptr_t user_data = 0, bool absolute_time = false);
void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
@@ -126,6 +134,9 @@ public:
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
std::optional<s64> Advance();
+ /// Register a callback function to be called when coretiming pauses.
+ void RegisterPauseCallback(PauseCallback&& callback);
+
private:
struct Event;
@@ -137,7 +148,7 @@ private:
std::unique_ptr<Common::WallClock> clock;
- u64 global_timer = 0;
+ s64 global_timer = 0;
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
@@ -157,17 +168,19 @@ private:
std::condition_variable wait_pause_cv;
std::condition_variable wait_signal_cv;
mutable std::mutex event_mutex;
- mutable std::mutex sequence_mutex;
std::atomic<bool> paused_state{};
bool is_paused{};
bool shutting_down{};
bool is_multicore{};
size_t pause_count{};
+ s64 pause_end_time{};
/// Cycle timing
u64 ticks{};
s64 downcount{};
+
+ std::vector<PauseCallback> pause_callbacks{};
};
/// Creates a core timing event with the given name and callback.
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index fd6928105..37d3d83b9 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -41,51 +41,32 @@ void CpuManager::Shutdown() {
}
}
-std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
- return GuestThreadFunction;
-}
-
-std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
- return IdleThreadFunction;
-}
-
-std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
- return ShutdownThreadFunction;
-}
-
-void CpuManager::GuestThreadFunction(void* cpu_manager_) {
- CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
- if (cpu_manager->is_multicore) {
- cpu_manager->MultiCoreRunGuestThread();
+void CpuManager::GuestThreadFunction() {
+ if (is_multicore) {
+ MultiCoreRunGuestThread();
} else {
- cpu_manager->SingleCoreRunGuestThread();
+ SingleCoreRunGuestThread();
}
}
-void CpuManager::GuestRewindFunction(void* cpu_manager_) {
- CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
- if (cpu_manager->is_multicore) {
- cpu_manager->MultiCoreRunGuestLoop();
+void CpuManager::GuestRewindFunction() {
+ if (is_multicore) {
+ MultiCoreRunGuestLoop();
} else {
- cpu_manager->SingleCoreRunGuestLoop();
+ SingleCoreRunGuestLoop();
}
}
-void CpuManager::IdleThreadFunction(void* cpu_manager_) {
- CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
- if (cpu_manager->is_multicore) {
- cpu_manager->MultiCoreRunIdleThread();
+void CpuManager::IdleThreadFunction() {
+ if (is_multicore) {
+ MultiCoreRunIdleThread();
} else {
- cpu_manager->SingleCoreRunIdleThread();
+ SingleCoreRunIdleThread();
}
}
-void CpuManager::ShutdownThreadFunction(void* cpu_manager) {
- static_cast<CpuManager*>(cpu_manager)->ShutdownThread();
-}
-
-void* CpuManager::GetStartFuncParameter() {
- return this;
+void CpuManager::ShutdownThreadFunction() {
+ ShutdownThread();
}
///////////////////////////////////////////////////////////////////////////////
@@ -97,7 +78,7 @@ void CpuManager::MultiCoreRunGuestThread() {
kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
auto& host_context = thread->GetHostContext();
- host_context->SetRewindPoint(GuestRewindFunction, this);
+ host_context->SetRewindPoint([this] { GuestRewindFunction(); });
MultiCoreRunGuestLoop();
}
@@ -134,7 +115,7 @@ void CpuManager::SingleCoreRunGuestThread() {
kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
auto& host_context = thread->GetHostContext();
- host_context->SetRewindPoint(GuestRewindFunction, this);
+ host_context->SetRewindPoint([this] { GuestRewindFunction(); });
SingleCoreRunGuestLoop();
}
@@ -194,7 +175,9 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
{
auto& scheduler = system.Kernel().Scheduler(current_core);
scheduler.Reload(scheduler.GetSchedulerCurrentThread());
- idle_count = 0;
+ if (!scheduler.IsIdle()) {
+ idle_count = 0;
+ }
}
}
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index f0751fc58..76dc58ee1 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -50,10 +50,15 @@ public:
void Initialize();
void Shutdown();
- static std::function<void(void*)> GetGuestThreadStartFunc();
- static std::function<void(void*)> GetIdleThreadStartFunc();
- static std::function<void(void*)> GetShutdownThreadStartFunc();
- void* GetStartFuncParameter();
+ std::function<void()> GetGuestThreadStartFunc() {
+ return [this] { GuestThreadFunction(); };
+ }
+ std::function<void()> GetIdleThreadStartFunc() {
+ return [this] { IdleThreadFunction(); };
+ }
+ std::function<void()> GetShutdownThreadStartFunc() {
+ return [this] { ShutdownThreadFunction(); };
+ }
void PreemptSingleCore(bool from_running_enviroment = true);
@@ -62,10 +67,10 @@ public:
}
private:
- static void GuestThreadFunction(void* cpu_manager);
- static void GuestRewindFunction(void* cpu_manager);
- static void IdleThreadFunction(void* cpu_manager);
- static void ShutdownThreadFunction(void* cpu_manager);
+ void GuestThreadFunction();
+ void GuestRewindFunction();
+ void IdleThreadFunction();
+ void ShutdownThreadFunction();
void MultiCoreRunGuestThread();
void MultiCoreRunGuestLoop();
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
index 750c353b9..4bef09bd7 100644
--- a/src/core/debugger/gdbstub_arch.cpp
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -191,8 +191,10 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
const auto& gprs{context.cpu_registers};
const auto& fprs{context.vector_registers};
- if (id <= SP_REGISTER) {
+ if (id < SP_REGISTER) {
return ValueToHex(gprs[id]);
+ } else if (id == SP_REGISTER) {
+ return ValueToHex(context.sp);
} else if (id == PC_REGISTER) {
return ValueToHex(context.pc);
} else if (id == PSTATE_REGISTER) {
@@ -215,8 +217,10 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
auto& context{thread->GetContext64()};
- if (id <= SP_REGISTER) {
+ if (id < SP_REGISTER) {
context.cpu_registers[id] = HexToValue<u64>(value);
+ } else if (id == SP_REGISTER) {
+ context.sp = HexToValue<u64>(value);
} else if (id == PC_REGISTER) {
context.pc = HexToValue<u64>(value);
} else if (id == PSTATE_REGISTER) {
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index d2d968a76..d08cc3315 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,11 +11,14 @@ namespace Core::Hardware {
InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
gpu_interrupt_event = Core::Timing::CreateEvent(
- "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) {
+ "GPUInterrupt",
+ [this](std::uintptr_t message, u64 time,
+ std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
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);
+ return std::nullopt;
});
}
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 9f76f9bcb..e49223016 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -272,6 +272,7 @@ enum class VibrationDeviceType : u32 {
Unknown = 0,
LinearResonantActuator = 1,
GcErm = 2,
+ N64 = 3,
};
// This is nn::hid::VibrationGcErmCommand
diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h
index 2410f74a3..2e7e1436a 100644
--- a/src/core/hle/kernel/k_code_memory.h
+++ b/src/core/hle/kernel/k_code_memory.h
@@ -30,19 +30,19 @@ public:
explicit KCodeMemory(KernelCore& kernel_);
Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
- void Finalize();
+ void Finalize() override;
Result Map(VAddr address, size_t size);
Result Unmap(VAddr address, size_t size);
Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
Result UnmapFromOwner(VAddr address, size_t size);
- bool IsInitialized() const {
+ bool IsInitialized() const override {
return m_is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
- KProcess* GetOwner() const {
+ KProcess* GetOwner() const override {
return m_owner;
}
VAddr GetSourceAddress() const {
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 183c693e3..b662788b3 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -161,7 +161,7 @@ bool KProcess::ReleaseUserException(KThread* thread) {
std::addressof(num_waiters),
reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
next != nullptr) {
- next->SetState(ThreadState::Runnable);
+ next->EndWait(ResultSuccess);
}
KScheduler::SetSchedulerUpdateNeeded(kernel);
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index d586b3f5c..d599d2bcb 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -622,7 +622,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
}
KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
- switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
+ switch_fiber = std::make_shared<Common::Fiber>([this] { SwitchToCurrent(); });
state.needs_scheduling.store(true);
state.interrupt_task_thread_runnable = false;
state.should_count_idle = false;
@@ -778,11 +778,6 @@ void KScheduler::ScheduleImpl() {
next_scheduler.SwitchContextStep2();
}
-void KScheduler::OnSwitch(void* this_scheduler) {
- KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
- sched->SwitchToCurrent();
-}
-
void KScheduler::SwitchToCurrent() {
while (true) {
{
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 3f90656ee..6a4760eca 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -55,6 +55,11 @@ public:
return idle_thread;
}
+ /// Returns true if the scheduler is idle
+ [[nodiscard]] bool IsIdle() const {
+ return GetSchedulerCurrentThread() == idle_thread;
+ }
+
/// Gets the timestamp for the last context switch in ticks.
[[nodiscard]] u64 GetLastContextSwitchTicks() const;
@@ -165,7 +170,6 @@ private:
*/
void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
- static void OnSwitch(void* this_scheduler);
void SwitchToCurrent();
KThread* prev_thread{};
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 8d7faa662..90de86770 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -246,14 +246,12 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
- ThreadType type, std::function<void(void*)>&& init_func,
- void* init_func_parameter) {
+ ThreadType type, std::function<void()>&& init_func) {
// Initialize the thread.
R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
// Initialize emulation parameters.
- thread->host_context =
- std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
+ thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
thread->is_single_core = !Settings::values.use_multi_core.GetValue();
return ResultSuccess;
@@ -265,15 +263,13 @@ Result KThread::InitializeDummyThread(KThread* thread) {
Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
- Core::CpuManager::GetIdleThreadStartFunc(),
- system.GetCpuManager().GetStartFuncParameter());
+ system.GetCpuManager().GetIdleThreadStartFunc());
}
Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
KThreadFunction func, uintptr_t arg, s32 virt_core) {
return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
- Core::CpuManager::GetShutdownThreadStartFunc(),
- system.GetCpuManager().GetStartFuncParameter());
+ system.GetCpuManager().GetShutdownThreadStartFunc());
}
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
@@ -281,8 +277,7 @@ Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThr
KProcess* owner) {
system.Kernel().GlobalSchedulerContext().AddThread(thread);
return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
- ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
- system.GetCpuManager().GetStartFuncParameter());
+ ThreadType::User, system.GetCpuManager().GetGuestThreadStartFunc());
}
void KThread::PostDestroy(uintptr_t arg) {
@@ -313,14 +308,20 @@ void KThread::Finalize() {
auto it = waiter_list.begin();
while (it != waiter_list.end()) {
- // Clear the lock owner
- it->SetLockOwner(nullptr);
+ // Get the thread.
+ KThread* const waiter = std::addressof(*it);
+
+ // The thread shouldn't be a kernel waiter.
+ ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
+
+ // Clear the lock owner.
+ waiter->SetLockOwner(nullptr);
// Erase the waiter from our list.
it = waiter_list.erase(it);
// Cancel the thread's wait.
- it->CancelWait(ResultInvalidState, true);
+ waiter->CancelWait(ResultInvalidState, true);
}
}
@@ -485,9 +486,7 @@ void KThread::Unpin() {
// Resume any threads that began waiting on us while we were pinned.
for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) {
- if (it->GetState() == ThreadState::Waiting) {
- it->SetState(ThreadState::Runnable);
- }
+ it->EndWait(ResultSuccess);
}
}
@@ -882,6 +881,7 @@ void KThread::AddWaiterImpl(KThread* thread) {
// Keep track of how many kernel waiters we have.
if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters++) >= 0);
+ KScheduler::SetSchedulerUpdateNeeded(kernel);
}
// Insert the waiter.
@@ -895,6 +895,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
// Keep track of how many kernel waiters we have.
if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters--) > 0);
+ KScheduler::SetSchedulerUpdateNeeded(kernel);
}
// Remove the waiter.
@@ -970,6 +971,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
// Keep track of how many kernel waiters we have.
if (IsKernelAddressKey(thread->GetAddressKey())) {
ASSERT((num_kernel_waiters--) > 0);
+ KScheduler::SetSchedulerUpdateNeeded(kernel);
}
it = waiter_list.erase(it);
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 94c4cd1c8..28cd7ecb0 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -729,8 +729,7 @@ private:
[[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func,
uintptr_t arg, VAddr user_stack_top, s32 prio,
s32 core, KProcess* owner, ThreadType type,
- std::function<void(void*)>&& init_func,
- void* init_func_parameter);
+ std::function<void()>&& init_func);
static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0009193be..7307cf262 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -234,17 +234,18 @@ struct KernelCore::Impl {
void InitializePreemption(KernelCore& kernel) {
preemption_event = Core::Timing::CreateEvent(
- "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
+ "PreemptionCallback",
+ [this, &kernel](std::uintptr_t, s64 time,
+ std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
{
KScopedSchedulerLock lock(kernel);
global_scheduler_context->PreemptThreads();
}
- const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
- system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
+ return std::nullopt;
});
const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)};
- system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
+ system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event);
}
void InitializeShutdownThreads() {
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 2724c3782..5ee72c432 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -11,15 +11,17 @@
namespace Kernel {
TimeManager::TimeManager(Core::System& system_) : system{system_} {
- time_manager_event_type =
- Core::Timing::CreateEvent("Kernel::TimeManagerCallback",
- [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
- KThread* thread = reinterpret_cast<KThread*>(thread_handle);
- {
- KScopedSchedulerLock sl(system.Kernel());
- thread->OnTimer();
- }
- });
+ time_manager_event_type = Core::Timing::CreateEvent(
+ "Kernel::TimeManagerCallback",
+ [this](std::uintptr_t thread_handle, s64 time,
+ std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
+ KThread* thread = reinterpret_cast<KThread*>(thread_handle);
+ {
+ KScopedSchedulerLock sl(system.Kernel());
+ thread->OnTimer();
+ }
+ return std::nullopt;
+ });
}
void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index c08b0a5dc..3c28dee76 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -49,28 +49,41 @@ bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) {
}
}
-bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
+Result Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
- return npad_id && npad_type && device_index;
+
+ if (!npad_type) {
+ return VibrationInvalidStyleIndex;
+ }
+ if (!npad_id) {
+ return VibrationInvalidNpadId;
+ }
+ if (!device_index) {
+ return VibrationDeviceIndexOutOfRange;
+ }
+
+ return ResultSuccess;
}
Result Controller_NPad::VerifyValidSixAxisSensorHandle(
const Core::HID::SixAxisSensorHandle& device_handle) {
const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
+ const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
+ const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
+
if (!npad_id) {
return InvalidNpadId;
}
- const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
if (!device_index) {
return NpadDeviceIndexOutOfRange;
}
// This doesn't get validated on nnsdk
- const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
if (!npad_type) {
return NpadInvalidHandle;
}
+
return ResultSuccess;
}
@@ -705,6 +718,11 @@ Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const {
}
void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
+ if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) {
+ ASSERT_MSG(false, "Activation mode should be always None, Single or Dual");
+ return;
+ }
+
handheld_activation_mode = activation_mode;
}
@@ -820,11 +838,11 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
const auto now = steady_clock::now();
- // Filter out non-zero vibrations that are within 10ms of each other.
+ // Filter out non-zero vibrations that are within 15ms of each other.
if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
duration_cast<milliseconds>(
now - controller.vibration[device_index].last_vibration_timepoint) <
- milliseconds(10)) {
+ milliseconds(15)) {
return false;
}
@@ -840,7 +858,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
void Controller_NPad::VibrateController(
const Core::HID::VibrationDeviceHandle& vibration_device_handle,
const Core::HID::VibrationValue& vibration_value) {
- if (!IsDeviceHandleValid(vibration_device_handle)) {
+ if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return;
}
@@ -903,7 +921,7 @@ void Controller_NPad::VibrateControllers(
Core::HID::VibrationValue Controller_NPad::GetLastVibration(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
- if (!IsDeviceHandleValid(vibration_device_handle)) {
+ if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return {};
}
@@ -914,7 +932,7 @@ Core::HID::VibrationValue Controller_NPad::GetLastVibration(
void Controller_NPad::InitializeVibrationDevice(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
- if (!IsDeviceHandleValid(vibration_device_handle)) {
+ if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return;
}
@@ -941,7 +959,7 @@ void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
bool Controller_NPad::IsVibrationDeviceMounted(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
- if (!IsDeviceHandleValid(vibration_device_handle)) {
+ if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
return false;
}
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 8b54724ed..1a589cca2 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -81,6 +81,7 @@ public:
Dual = 0,
Single = 1,
None = 2,
+ MaxActivationMode = 3,
};
// This is nn::hid::NpadCommunicationMode
@@ -196,7 +197,7 @@ public:
Core::HID::NpadButton GetAndResetPressState();
static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
- static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
+ static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
static Result VerifyValidSixAxisSensorHandle(
const Core::HID::SixAxisSensorHandle& device_handle);
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 615c23b84..46282f42e 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -9,6 +9,9 @@ namespace Service::HID {
constexpr Result NpadInvalidHandle{ErrorModule::HID, 100};
constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
+constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122};
+constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123};
+constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124};
constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423};
constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index dc5d0366d..89bb12442 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -74,26 +74,34 @@ IAppletResource::IAppletResource(Core::System& system_,
// Register update callbacks
pad_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback",
- [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateControllers(user_data, ns_late);
+ return std::nullopt;
});
mouse_keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdateMouseKeyboardCallback",
- [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateMouseKeyboard(user_data, ns_late);
+ return std::nullopt;
});
motion_update_event = Core::Timing::CreateEvent(
"HID::UpdateMotionCallback",
- [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateMotion(user_data, ns_late);
+ return std::nullopt;
});
- system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
- system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event);
- system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
+ system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event);
+ system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
+ mouse_keyboard_update_event);
+ system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
+ motion_update_event);
system.HIDCore().ReloadInputDevices();
}
@@ -135,13 +143,6 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
}
controller->OnUpdate(core_timing);
}
-
- // If ns_late is higher than the update rate ignore the delay
- if (ns_late > pad_update_ns) {
- ns_late = {};
- }
-
- core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
}
void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
@@ -150,26 +151,12 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
-
- // If ns_late is higher than the update rate ignore the delay
- if (ns_late > mouse_keyboard_update_ns) {
- ns_late = {};
- }
-
- core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event);
}
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
-
- // If ns_late is higher than the update rate ignore the delay
- if (ns_late > motion_update_ns) {
- ns_late = {};
- }
-
- core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
}
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
@@ -778,7 +765,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
bool is_at_rest{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
+ controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -786,7 +773,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
+ rb.Push(ResultSuccess);
rb.Push(is_at_rest);
}
@@ -803,8 +790,8 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
bool is_firmware_available{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.IsFirmwareUpdateAvailableForSixAxisSensor(
- parameters.sixaxis_handle, is_firmware_available);
+ controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
+ is_firmware_available);
LOG_WARNING(
Service_HID,
@@ -813,7 +800,7 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
+ rb.Push(ResultSuccess);
rb.Push(is_firmware_available);
}
@@ -1083,13 +1070,13 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.DisconnectNpad(parameters.npad_id);
+ controller.DisconnectNpad(parameters.npad_id);
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
+ rb.Push(ResultSuccess);
}
void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
@@ -1165,15 +1152,14 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
- Controller_NPad::NpadJoyAssignmentMode::Single);
+ controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
+ Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
+ rb.Push(ResultSuccess);
}
void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
@@ -1189,15 +1175,15 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
- Controller_NPad::NpadJoyAssignmentMode::Single);
+ controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
+ Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id,
parameters.npad_joy_device_type);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
+ rb.Push(ResultSuccess);
}
void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
@@ -1212,14 +1198,13 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetNpadMode(parameters.npad_id, {},
- Controller_NPad::NpadJoyAssignmentMode::Dual);
+ controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
+ rb.Push(ResultSuccess);
}
void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
@@ -1412,8 +1397,11 @@ void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
+ const auto& controller =
+ GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
Core::HID::VibrationDeviceInfo vibration_device_info;
+ bool check_device_index = false;
switch (vibration_device_handle.npad_type) {
case Core::HID::NpadStyleIndex::ProController:
@@ -1421,34 +1409,46 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:
case Core::HID::NpadStyleIndex::JoyconRight:
- default:
vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
+ check_device_index = true;
break;
case Core::HID::NpadStyleIndex::GameCube:
vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
break;
- case Core::HID::NpadStyleIndex::Pokeball:
+ case Core::HID::NpadStyleIndex::N64:
+ vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
+ break;
+ default:
vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
break;
}
- switch (vibration_device_handle.device_index) {
- case Core::HID::DeviceIndex::Left:
- vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
- break;
- case Core::HID::DeviceIndex::Right:
- vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
- break;
- case Core::HID::DeviceIndex::None:
- default:
- ASSERT_MSG(false, "DeviceIndex should never be None!");
- vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
- break;
+ vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
+ if (check_device_index) {
+ switch (vibration_device_handle.device_index) {
+ case Core::HID::DeviceIndex::Left:
+ vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
+ break;
+ case Core::HID::DeviceIndex::Right:
+ vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
+ break;
+ case Core::HID::DeviceIndex::None:
+ default:
+ ASSERT_MSG(false, "DeviceIndex should never be None!");
+ break;
+ }
}
LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
vibration_device_info.type, vibration_device_info.position);
+ const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushRaw(vibration_device_info);
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index fa6153b4c..e5e50845f 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -50,12 +50,15 @@ HidBus::HidBus(Core::System& system_)
// Register update callbacks
hidbus_update_event = Core::Timing::CreateEvent(
"Hidbus::UpdateCallback",
- [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
UpdateHidbus(user_data, ns_late);
+ return std::nullopt;
});
- system_.CoreTiming().ScheduleEvent(hidbus_update_ns, hidbus_update_event);
+ system_.CoreTiming().ScheduleLoopingEvent(hidbus_update_ns, hidbus_update_ns,
+ hidbus_update_event);
}
HidBus::~HidBus() {
@@ -63,8 +66,6 @@ HidBus::~HidBus() {
}
void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
- auto& core_timing = system.CoreTiming();
-
if (is_hidbus_enabled) {
for (std::size_t i = 0; i < devices.size(); ++i) {
if (!devices[i].is_device_initializated) {
@@ -82,13 +83,6 @@ void HidBus::UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_
sizeof(HidbusStatusManagerEntry));
}
}
-
- // If ns_late is higher than the update rate ignore the delay
- if (ns_late > hidbus_update_ns) {
- ns_late = {};
- }
-
- core_timing.ScheduleEvent(hidbus_update_ns - ns_late, hidbus_update_event);
}
std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) const {
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 0310ce883..7055ea93e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -30,6 +30,19 @@ enum class RequestState : u32 {
Connected = 3,
};
+enum class InternetConnectionType : u8 {
+ WiFi = 1,
+ Ethernet = 2,
+};
+
+enum class InternetConnectionStatus : u8 {
+ ConnectingUnknown1,
+ ConnectingUnknown2,
+ ConnectingUnknown3,
+ ConnectingUnknown4,
+ Connected,
+};
+
struct IpAddressSetting {
bool is_automatic{};
Network::IPv4Address current_address{};
@@ -271,6 +284,7 @@ private:
rb.Push(ResultSuccess);
rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
}
+
void CreateScanRequest(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@@ -279,6 +293,7 @@ private:
rb.Push(ResultSuccess);
rb.PushIpcInterface<IScanRequest>(system);
}
+
void CreateRequest(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@@ -287,6 +302,7 @@ private:
rb.Push(ResultSuccess);
rb.PushIpcInterface<IRequest>(system);
}
+
void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -335,12 +351,14 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
+
void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
+
void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -354,6 +372,7 @@ private:
rb.Push(ResultSuccess);
rb.PushRaw(*ipv4);
}
+
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@@ -369,6 +388,7 @@ private:
rb.PushIpcInterface<INetworkProfile>(system);
rb.PushRaw<u128>(uuid);
}
+
void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -405,6 +425,7 @@ private:
rb.Push(ResultSuccess);
rb.PushRaw<IpConfigInfo>(ip_config_info);
}
+
void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -412,6 +433,24 @@ private:
rb.Push(ResultSuccess);
rb.Push<u8>(0);
}
+
+ void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
+ struct Output {
+ InternetConnectionType type{InternetConnectionType::WiFi};
+ u8 wifi_strength{3};
+ InternetConnectionStatus state{InternetConnectionStatus::Connected};
+ };
+ static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
+
+ constexpr Output out{};
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(out);
+ }
+
void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -423,6 +462,7 @@ private:
rb.Push<u8>(0);
}
}
+
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -456,7 +496,7 @@ IGeneralService::IGeneralService(Core::System& system_)
{15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"},
{16, nullptr, "SetWirelessCommunicationEnabled"},
{17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
- {18, nullptr, "GetInternetConnectionStatus"},
+ {18, &IGeneralService::GetInternetConnectionStatus, "GetInternetConnectionStatus"},
{19, nullptr, "SetEthernetCommunicationEnabled"},
{20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
{21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h
index 21aaa40cd..157333ff8 100644
--- a/src/core/hle/service/nvflinger/binder.h
+++ b/src/core/hle/service/nvflinger/binder.h
@@ -34,6 +34,7 @@ enum class TransactionId {
class IBinder {
public:
+ virtual ~IBinder() = default;
virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code,
u32 flags) = 0;
virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 2b2985a2d..5f69c8c2c 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -67,21 +67,20 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
// Schedule the screen composition events
composition_event = Core::Timing::CreateEvent(
- "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
+ "ScreenComposition",
+ [this](std::uintptr_t, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto lock_guard = Lock();
Compose();
- const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
- const auto ticks_delta = ticks - ns_late;
- const auto future_ns = std::max(std::chrono::nanoseconds::zero(), ticks_delta);
-
- this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
+ return std::max(std::chrono::nanoseconds::zero(),
+ std::chrono::nanoseconds(GetNextTicks()) - ns_late);
});
if (system.IsMulticore()) {
vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
} else {
- system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
+ system.CoreTiming().ScheduleLoopingEvent(frame_ns, frame_ns, composition_event);
}
}
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 9e0eb6ac0..2c31e9485 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -9,10 +9,8 @@
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/ptm/psm.h"
-#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
-namespace Service::PSM {
+namespace Service::PTM {
class IPsmSession final : public ServiceFramework<IPsmSession> {
public:
@@ -57,7 +55,7 @@ public:
private:
void BindStateChangeEvent(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_PSM, "called");
+ LOG_DEBUG(Service_PTM, "called");
should_signal = true;
@@ -67,7 +65,7 @@ private:
}
void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_PSM, "called");
+ LOG_DEBUG(Service_PTM, "called");
should_signal = false;
@@ -78,7 +76,7 @@ private:
void SetChargerTypeChangeEventEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto state = rp.Pop<bool>();
- LOG_DEBUG(Service_PSM, "called, state={}", state);
+ LOG_DEBUG(Service_PTM, "called, state={}", state);
should_signal_charger_type = state;
@@ -89,7 +87,7 @@ private:
void SetPowerSupplyChangeEventEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto state = rp.Pop<bool>();
- LOG_DEBUG(Service_PSM, "called, state={}", state);
+ LOG_DEBUG(Service_PTM, "called, state={}", state);
should_signal_power_supply = state;
@@ -100,7 +98,7 @@ private:
void SetBatteryVoltageStateChangeEventEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto state = rp.Pop<bool>();
- LOG_DEBUG(Service_PSM, "called, state={}", state);
+ LOG_DEBUG(Service_PTM, "called, state={}", state);
should_signal_battery_voltage = state;
@@ -117,76 +115,58 @@ private:
Kernel::KEvent* state_change_event;
};
-class PSM final : public ServiceFramework<PSM> {
-public:
- explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
- {1, &PSM::GetChargerType, "GetChargerType"},
- {2, nullptr, "EnableBatteryCharging"},
- {3, nullptr, "DisableBatteryCharging"},
- {4, nullptr, "IsBatteryChargingEnabled"},
- {5, nullptr, "AcquireControllerPowerSupply"},
- {6, nullptr, "ReleaseControllerPowerSupply"},
- {7, &PSM::OpenSession, "OpenSession"},
- {8, nullptr, "EnableEnoughPowerChargeEmulation"},
- {9, nullptr, "DisableEnoughPowerChargeEmulation"},
- {10, nullptr, "EnableFastBatteryCharging"},
- {11, nullptr, "DisableFastBatteryCharging"},
- {12, nullptr, "GetBatteryVoltageState"},
- {13, nullptr, "GetRawBatteryChargePercentage"},
- {14, nullptr, "IsEnoughPowerSupplied"},
- {15, nullptr, "GetBatteryAgePercentage"},
- {16, nullptr, "GetBatteryChargeInfoEvent"},
- {17, nullptr, "GetBatteryChargeInfoFields"},
- {18, nullptr, "GetBatteryChargeCalibratedEvent"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
- ~PSM() override = default;
-
-private:
- void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_PSM, "called");
+PSM::PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
+ {1, &PSM::GetChargerType, "GetChargerType"},
+ {2, nullptr, "EnableBatteryCharging"},
+ {3, nullptr, "DisableBatteryCharging"},
+ {4, nullptr, "IsBatteryChargingEnabled"},
+ {5, nullptr, "AcquireControllerPowerSupply"},
+ {6, nullptr, "ReleaseControllerPowerSupply"},
+ {7, &PSM::OpenSession, "OpenSession"},
+ {8, nullptr, "EnableEnoughPowerChargeEmulation"},
+ {9, nullptr, "DisableEnoughPowerChargeEmulation"},
+ {10, nullptr, "EnableFastBatteryCharging"},
+ {11, nullptr, "DisableFastBatteryCharging"},
+ {12, nullptr, "GetBatteryVoltageState"},
+ {13, nullptr, "GetRawBatteryChargePercentage"},
+ {14, nullptr, "IsEnoughPowerSupplied"},
+ {15, nullptr, "GetBatteryAgePercentage"},
+ {16, nullptr, "GetBatteryChargeInfoEvent"},
+ {17, nullptr, "GetBatteryChargeInfoFields"},
+ {18, nullptr, "GetBatteryChargeCalibratedEvent"},
+ };
+ // clang-format on
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(battery_charge_percentage);
- }
+ RegisterHandlers(functions);
+}
- void GetChargerType(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_PSM, "called");
+PSM::~PSM() = default;
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(charger_type);
- }
+void PSM::GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PTM, "called");
- void OpenSession(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_PSM, "called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u32>(battery_charge_percentage);
+}
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IPsmSession>(system);
- }
+void PSM::GetChargerType(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PTM, "called");
- enum class ChargerType : u32 {
- Unplugged = 0,
- RegularCharger = 1,
- LowPowerCharger = 2,
- Unknown = 3,
- };
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(charger_type);
+}
- u32 battery_charge_percentage{100}; // 100%
- ChargerType charger_type{ChargerType::RegularCharger};
-};
+void PSM::OpenSession(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PTM, "called");
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<PSM>(system)->InstallAsService(sm);
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IPsmSession>(system);
}
-} // namespace Service::PSM
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h
index 94a1044db..f674ba8bc 100644
--- a/src/core/hle/service/ptm/psm.h
+++ b/src/core/hle/service/ptm/psm.h
@@ -3,16 +3,29 @@
#pragma once
-namespace Core {
-class System;
-}
+#include "core/hle/service/service.h"
-namespace Service::SM {
-class ServiceManager;
-}
+namespace Service::PTM {
-namespace Service::PSM {
+class PSM final : public ServiceFramework<PSM> {
+public:
+ explicit PSM(Core::System& system_);
+ ~PSM() override;
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+private:
+ enum class ChargerType : u32 {
+ Unplugged = 0,
+ RegularCharger = 1,
+ LowPowerCharger = 2,
+ Unknown = 3,
+ };
-} // namespace Service::PSM
+ void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx);
+ void GetChargerType(Kernel::HLERequestContext& ctx);
+ void OpenSession(Kernel::HLERequestContext& ctx);
+
+ u32 battery_charge_percentage{100};
+ ChargerType charger_type{ChargerType::RegularCharger};
+};
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
new file mode 100644
index 000000000..4bea995c6
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <memory>
+
+#include "core/core.h"
+#include "core/hle/service/ptm/psm.h"
+#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ptm/ts.h"
+
+namespace Service::PTM {
+
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
+ std::make_shared<PSM>(system)->InstallAsService(sm);
+ std::make_shared<TS>(system)->InstallAsService(sm);
+}
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
new file mode 100644
index 000000000..06224a24e
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm.h
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+namespace Core {
+class System;
+}
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::PTM {
+
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.cpp b/src/core/hle/service/ptm/ts.cpp
new file mode 100644
index 000000000..65c3f135f
--- /dev/null
+++ b/src/core/hle/service/ptm/ts.cpp
@@ -0,0 +1,41 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <memory>
+
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ptm/ts.h"
+
+namespace Service::PTM {
+
+TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetTemperatureRange"},
+ {1, &TS::GetTemperature, "GetTemperature"},
+ {2, nullptr, "SetMeasurementMode"},
+ {3, nullptr, "GetTemperatureMilliC"},
+ {4, nullptr, "OpenSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+TS::~TS() = default;
+
+void TS::GetTemperature(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto location{rp.PopEnum<Location>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called. location={}", location);
+
+ const s32 temperature = location == Location::Internal ? 35 : 20;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(temperature);
+}
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.h b/src/core/hle/service/ptm/ts.h
new file mode 100644
index 000000000..39a734ef7
--- /dev/null
+++ b/src/core/hle/service/ptm/ts.h
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PTM {
+
+class TS final : public ServiceFramework<TS> {
+public:
+ explicit TS(Core::System& system_);
+ ~TS() override;
+
+private:
+ enum class Location : u8 {
+ Internal,
+ External,
+ };
+
+ void GetTemperature(Kernel::HLERequestContext& ctx);
+};
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 318009e4f..c64291e7f 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -58,7 +58,7 @@
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/psc/psc.h"
-#include "core/hle/service/ptm/psm.h"
+#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings.h"
#include "core/hle/service/sm/sm.h"
@@ -287,7 +287,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
PlayReport::InstallInterfaces(*sm, system);
PM::InstallInterfaces(system);
PSC::InstallInterfaces(*sm, system);
- PSM::InstallInterfaces(*sm, system);
+ PTM::InstallInterfaces(*sm, system);
Set::InstallInterfaces(*sm, system);
Sockets::InstallInterfaces(*sm, system);
SPL::InstallInterfaces(*sm, system);
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 5f71f0ff5..ffdbacc18 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -184,10 +184,12 @@ CheatEngine::~CheatEngine() {
void CheatEngine::Initialize() {
event = Core::Timing::CreateEvent(
"CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
- [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
FrameCallback(user_data, ns_late);
+ return std::nullopt;
});
- core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
+ core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event);
metadata.process_id = system.CurrentProcess()->GetProcessID();
metadata.title_id = system.GetCurrentProcessProgramID();
@@ -237,8 +239,6 @@ void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late
MICROPROFILE_SCOPE(Cheat_Engine);
vm.Execute(metadata);
-
- core_timing.ScheduleEvent(CHEAT_ENGINE_NS - ns_late, event);
}
} // namespace Core::Memory
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 5cc99fbe4..98ebbbf32 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -53,8 +53,10 @@ Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& m
: core_timing{core_timing_}, memory{memory_} {
event = Core::Timing::CreateEvent(
"MemoryFreezer::FrameCallback",
- [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
FrameCallback(user_data, ns_late);
+ return std::nullopt;
});
core_timing.ScheduleEvent(memory_freezer_ns, event);
}