svc: Provide more detailed error logs for svc functions

Allows SVC calls to have much more informative information during error
cases. This also doesn't hide control flow returns from the reader.
This commit is contained in:
Lioncash 2021-02-03 22:33:27 -05:00
parent 1498a7c9a8
commit 75a60a6e22

View file

@ -368,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Get the thread's id. // Get the thread's id.
*out_thread_id = thread->GetThreadID(); *out_thread_id = thread->GetThreadID();
@ -478,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Cancel the thread's wait. // Cancel the thread's wait.
thread->WaitCancel(); thread->WaitCancel();
@ -496,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
thread_handle, address, tag); thread_handle, address, tag);
// Validate the input address. // Validate the input address.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(u32))) {
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
return ResultInvalidAddress;
}
return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
} }
@ -512,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
// Validate the input address. // Validate the input address.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC,
"Attempting to arbitrate an unlock on a kernel address (address={:08X})",
address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(u32))) {
LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
return ResultInvalidAddress;
}
return system.Kernel().CurrentProcess()->SignalToAddress(address); return system.Kernel().CurrentProcess()->SignalToAddress(address);
} }
@ -1025,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
return UnmapPhysicalMemory(system, addr, size); return UnmapPhysicalMemory(system, addr, size);
} }
constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
switch (thread_activity) {
case Svc::ThreadActivity::Runnable:
case Svc::ThreadActivity::Paused:
return true;
default:
return false;
}
}
/// Sets the thread activity /// Sets the thread activity
static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
Svc::ThreadActivity thread_activity) { ThreadActivity thread_activity) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
thread_activity); thread_activity);
// Validate the activity. // Validate the activity.
R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
};
if (!IsValidThreadActivity(thread_activity)) {
LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
thread_activity);
return ResultInvalidEnumValue;
}
// Get the thread from its handle. // Get the thread from its handle.
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Check that the activity is being set on a non-current thread for the current process. // Check that the activity is being set on a non-current thread for the current process.
R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
return ResultInvalidHandle;
}
if (thread.get() == GetCurrentThreadPointer(kernel)) {
LOG_ERROR(Kernel_SVC, "Thread is busy");
return ResultBusy;
}
// Set the activity. // Set the activity.
R_TRY(thread->SetActivity(thread_activity)); const auto set_result = thread->SetActivity(thread_activity);
if (set_result.IsError()) {
LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
return set_result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1074,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
const auto* current_process = system.Kernel().CurrentProcess(); const auto* current_process = system.Kernel().CurrentProcess();
const std::shared_ptr<KThread> thread = const std::shared_ptr<KThread> thread =
current_process->GetHandleTable().Get<KThread>(thread_handle); current_process->GetHandleTable().Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
return ResultInvalidHandle;
}
// Require the handle be to a non-current thread in the current process. // Require the handle be to a non-current thread in the current process.
R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); if (thread->GetOwnerProcess() != current_process) {
R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
Svc::ResultBusy); return ResultInvalidHandle;
}
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
LOG_ERROR(Kernel_SVC, "Current thread is busy.");
return ResultBusy;
}
// Get the thread context. // Get the thread context.
std::vector<u8> context; std::vector<u8> context;
R_TRY(thread->GetThreadContext3(context)); const auto context_result = thread->GetThreadContext3(context);
if (context_result.IsError()) {
LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
context_result.raw);
return context_result;
}
// Copy the thread context to user space. // Copy the thread context to user space.
system.Memory().WriteBlock(out_context, context.data(), context.size()); system.Memory().WriteBlock(out_context, context.data(), context.size());
@ -1102,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
return ResultInvalidHandle;
}
// Get the thread's priority. // Get the thread's priority.
*out_priority = thread->GetPriority(); *out_priority = thread->GetPriority();
@ -1118,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
LOG_TRACE(Kernel_SVC, "called"); LOG_TRACE(Kernel_SVC, "called");
// Validate the priority. // Validate the priority.
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
Svc::ResultInvalidPriority); LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
return ResultInvalidPriority;
}
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
return ResultInvalidHandle;
}
// Set the thread priority. // Set the thread priority.
thread->SetBasePriority(priority); thread->SetBasePriority(priority);
@ -1440,17 +1492,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
// Adjust core id, if it's the default magic. // Adjust core id, if it's the default magic.
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
auto& process = *kernel.CurrentProcess(); auto& process = *kernel.CurrentProcess();
if (core_id == Svc::IdealCoreUseProcessValue) { if (core_id == IdealCoreUseProcessValue) {
core_id = process.GetIdealCoreId(); core_id = process.GetIdealCoreId();
} }
// Validate arguments. // Validate arguments.
R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); if (!IsValidCoreId(core_id)) {
R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
return ResultInvalidCoreId;
}
if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
return ResultInvalidCoreId;
}
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
Svc::ResultInvalidPriority); LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); return ResultInvalidPriority;
}
if (!process.CheckThreadPriority(priority)) {
LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
return ResultInvalidPriority;
}
ASSERT(process.GetResourceLimit()->Reserve( ASSERT(process.GetResourceLimit()->Reserve(
LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
@ -1489,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Try to start the thread. // Try to start the thread.
R_TRY(thread->Run()); const auto run_result = thread->Run();
if (run_result.IsError()) {
LOG_ERROR(Kernel_SVC,
"Unable to successfuly start thread (thread handle={:08X}, result={})",
thread_handle, run_result.raw);
return run_result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1553,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
cv_key, tag, timeout_ns); cv_key, tag, timeout_ns);
// Validate input. // Validate input.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
// Convert timeout from nanoseconds to ticks. // Convert timeout from nanoseconds to ticks.
s64 timeout{}; s64 timeout{};
@ -1629,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
address, arb_type, value, timeout_ns); address, arb_type, value, timeout_ns);
// Validate input. // Validate input.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
if (!IsValidArbitrationType(arb_type)) {
LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
return ResultInvalidEnumValue;
}
// Convert timeout from nanoseconds to ticks. // Convert timeout from nanoseconds to ticks.
s64 timeout{}; s64 timeout{};
@ -1665,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
address, signal_type, value, count); address, signal_type, value, count);
// Validate input. // Validate input.
R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); if (Memory::IsKernelAddress(address)) {
R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); return ResultInvalidCurrentMemory;
}
if (!Common::IsAligned(address, sizeof(s32))) {
LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
return ResultInvalidAddress;
}
if (!IsValidSignalType(signal_type)) {
LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
return ResultInvalidEnumValue;
}
return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
count); count);
@ -1815,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Get the core mask. // Get the core mask.
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
if (result.IsError()) {
LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
return result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1846,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
} else { } else {
// Validate the affinity mask. // Validate the affinity mask.
const u64 process_core_mask = current_process.GetCoreMask(); const u64 process_core_mask = current_process.GetCoreMask();
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, if ((affinity_mask | process_core_mask) != process_core_mask) {
Svc::ResultInvalidCoreId); LOG_ERROR(Kernel_SVC,
R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); "Affinity mask does match the process core mask (affinity mask={:016X}, core "
"mask={:016X})",
affinity_mask, process_core_mask);
return ResultInvalidCoreId;
}
if (affinity_mask == 0) {
LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
return ResultInvalidCombination;
}
// Validate the core id. // Validate the core id.
if (IsValidCoreId(core_id)) { if (IsValidCoreId(core_id)) {
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); if (((1ULL << core_id) & affinity_mask) == 0) {
LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
return ResultInvalidCombination;
}
} else { } else {
R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
Svc::ResultInvalidCoreId); LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
return ResultInvalidCoreId;
}
} }
} }
// Get the thread from its handle. // Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
R_UNLESS(thread, Svc::ResultInvalidHandle); if (!thread) {
LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
return ResultInvalidHandle;
}
// Set the core mask. // Set the core mask.
R_TRY(thread->SetCoreMask(core_id, affinity_mask)); const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
if (set_result.IsError()) {
LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
return set_result;
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1884,7 +2007,10 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
// Get the writable event. // Get the writable event.
auto writable_event = handle_table.Get<KWritableEvent>(event_handle); auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
R_UNLESS(writable_event, Svc::ResultInvalidHandle); if (!writable_event) {
LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
return ResultInvalidHandle;
}
return writable_event->Signal(); return writable_event->Signal();
} }
@ -1933,7 +2059,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
// Create a new event. // Create a new event.
const auto event = KEvent::Create(kernel, "CreateEvent"); const auto event = KEvent::Create(kernel, "CreateEvent");
R_UNLESS(event != nullptr, Svc::ResultOutOfResource); if (!event) {
LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
return ResultOutOfResource;
}
// Initialize the event. // Initialize the event.
event->Initialize(); event->Initialize();