Merge pull request #5872 from lioncash/svc-error

svc: Provide more detailed error logs for svc functions
This commit is contained in:
Chloe 2021-02-08 12:27:36 +11:00 committed by GitHub
commit d0a760a34a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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();