hle: kernel: Recode implementation of KThread to be more accurate.
This commit is contained in:
parent
1470338458
commit
cdd14b03e5
14 changed files with 1583 additions and 806 deletions
|
@ -351,7 +351,8 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
|
|||
session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
|
||||
}
|
||||
|
||||
return thread->GetSignalingResult();
|
||||
KSynchronizationObject* dummy{};
|
||||
return thread->GetWaitResult(std::addressof(dummy));
|
||||
}
|
||||
|
||||
static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
||||
|
@ -359,27 +360,26 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
|
|||
}
|
||||
|
||||
/// Get the ID for the specified thread.
|
||||
static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) {
|
||||
static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
|
||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
*thread_id = thread->GetThreadID();
|
||||
// Get the thread's id.
|
||||
*out_thread_id = thread->GetThreadID();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high,
|
||||
Handle thread_handle) {
|
||||
u64 thread_id{};
|
||||
const ResultCode result{GetThreadId(system, &thread_id, thread_handle)};
|
||||
static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low,
|
||||
u32* out_thread_id_high, Handle thread_handle) {
|
||||
u64 out_thread_id{};
|
||||
const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)};
|
||||
|
||||
*thread_id_low = static_cast<u32>(thread_id >> 32);
|
||||
*thread_id_high = static_cast<u32>(thread_id & std::numeric_limits<u32>::max());
|
||||
*out_thread_id_low = static_cast<u32>(out_thread_id >> 32);
|
||||
*out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -473,15 +473,13 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u
|
|||
static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) {
|
||||
LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
thread->CancelWait();
|
||||
// Cancel the thread's wait.
|
||||
thread->WaitCancel();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -630,7 +628,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
|||
handle_debug_buffer(info1, info2);
|
||||
|
||||
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
||||
const auto thread_processor_id = current_thread->GetProcessorID();
|
||||
const auto thread_processor_id = current_thread->GetActiveCore();
|
||||
system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
|
||||
}
|
||||
}
|
||||
|
@ -888,7 +886,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
|
|||
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
|
||||
u64 out_ticks = 0;
|
||||
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
||||
const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
|
||||
const u64 thread_ticks = current_thread->GetCpuTime();
|
||||
|
||||
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
|
||||
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
|
||||
|
@ -1025,127 +1023,109 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
|
|||
return UnmapPhysicalMemory(system, addr, size);
|
||||
}
|
||||
|
||||
/// Sets the thread activity
|
||||
static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity);
|
||||
if (activity > static_cast<u32>(ThreadActivity::Paused)) {
|
||||
return ERR_INVALID_ENUM_VALUE;
|
||||
constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
|
||||
switch (thread_activity) {
|
||||
case Svc::ThreadActivity::Runnable:
|
||||
case Svc::ThreadActivity::Paused:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* current_process = system.Kernel().CurrentProcess();
|
||||
const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (thread->GetOwnerProcess() != current_process) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"The current process does not own the current thread, thread_handle={:08X} "
|
||||
"thread_pid={}, "
|
||||
"current_process_pid={}",
|
||||
handle, thread->GetOwnerProcess()->GetProcessID(),
|
||||
current_process->GetProcessID());
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
|
||||
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
|
||||
return ERR_BUSY;
|
||||
}
|
||||
|
||||
return thread->SetActivity(static_cast<ThreadActivity>(activity));
|
||||
}
|
||||
|
||||
static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) {
|
||||
return SetThreadActivity(system, handle, activity);
|
||||
/// Sets the thread activity
|
||||
static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
|
||||
Svc::ThreadActivity thread_activity) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
|
||||
thread_activity);
|
||||
|
||||
// Validate the activity.
|
||||
R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue);
|
||||
|
||||
// Get the thread from its handle.
|
||||
auto& kernel = system.Kernel();
|
||||
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
// Check that the activity is being set on a non-current thread for the current process.
|
||||
R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle);
|
||||
R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy);
|
||||
|
||||
// Set the activity.
|
||||
R_TRY(thread->SetActivity(thread_activity));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle,
|
||||
Svc::ThreadActivity thread_activity) {
|
||||
return SetThreadActivity(system, thread_handle, thread_activity);
|
||||
}
|
||||
|
||||
/// Gets the thread context
|
||||
static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
|
||||
static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
|
||||
thread_handle);
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto* current_process = system.Kernel().CurrentProcess();
|
||||
const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
const std::shared_ptr<KThread> thread =
|
||||
current_process->GetHandleTable().Get<KThread>(thread_handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
if (thread->GetOwnerProcess() != current_process) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"The current process does not own the current thread, thread_handle={:08X} "
|
||||
"thread_pid={}, "
|
||||
"current_process_pid={}",
|
||||
handle, thread->GetOwnerProcess()->GetProcessID(),
|
||||
current_process->GetProcessID());
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
// Require the handle be to a non-current thread in the current process.
|
||||
R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle);
|
||||
R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(),
|
||||
Svc::ResultBusy);
|
||||
|
||||
if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
|
||||
LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
|
||||
return ERR_BUSY;
|
||||
}
|
||||
// Get the thread context.
|
||||
std::vector<u8> context;
|
||||
R_TRY(thread->GetThreadContext3(context));
|
||||
|
||||
Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64();
|
||||
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||
ctx.pstate &= 0xFF0FFE20;
|
||||
// Copy the thread context to user space.
|
||||
system.Memory().WriteBlock(out_context, context.data(), context.size());
|
||||
|
||||
// If 64-bit, we can just write the context registers directly and we're good.
|
||||
// However, if 32-bit, we have to ensure some registers are zeroed out.
|
||||
if (!current_process->Is64BitProcess()) {
|
||||
std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
|
||||
std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
|
||||
}
|
||||
|
||||
system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) {
|
||||
return GetThreadContext(system, thread_context, handle);
|
||||
static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) {
|
||||
return GetThreadContext(system, out_context, thread_handle);
|
||||
}
|
||||
|
||||
/// Gets the priority for the specified thread
|
||||
static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) {
|
||||
static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
||||
if (!thread) {
|
||||
*priority = 0;
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
*priority = thread->GetPriority();
|
||||
// Get the thread's priority.
|
||||
*out_priority = thread->GetPriority();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) {
|
||||
return GetThreadPriority(system, priority, handle);
|
||||
static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) {
|
||||
return GetThreadPriority(system, out_priority, handle);
|
||||
}
|
||||
|
||||
/// Sets the priority for the specified thread
|
||||
static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
if (priority > Svc::LowestThreadPriority) {
|
||||
LOG_ERROR(Kernel_SVC, "An invalid priority was specified {} for thread_handle={:08X}",
|
||||
priority, handle);
|
||||
return ERR_INVALID_THREAD_PRIORITY;
|
||||
}
|
||||
// Validate the priority.
|
||||
R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
|
||||
Svc::ResultInvalidPriority);
|
||||
|
||||
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||
|
||||
std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
// Set the thread priority.
|
||||
thread->SetBasePriority(priority);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1436,7 +1416,7 @@ static void ExitProcess(Core::System& system) {
|
|||
current_process->PrepareForTermination();
|
||||
|
||||
// Kill the current thread
|
||||
system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop();
|
||||
system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit();
|
||||
}
|
||||
|
||||
static void ExitProcess32(Core::System& system) {
|
||||
|
@ -1500,17 +1480,15 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p
|
|||
static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
ASSERT(thread->GetState() == ThreadState::Initialized);
|
||||
// Try to start the thread.
|
||||
R_TRY(thread->Run());
|
||||
|
||||
return thread->Start();
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode StartThread32(Core::System& system, Handle thread_handle) {
|
||||
|
@ -1523,7 +1501,7 @@ static void ExitThread(Core::System& system) {
|
|||
|
||||
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
||||
system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread));
|
||||
current_thread->Stop();
|
||||
current_thread->Exit();
|
||||
}
|
||||
|
||||
static void ExitThread32(Core::System& system) {
|
||||
|
@ -1532,34 +1510,28 @@ static void ExitThread32(Core::System& system) {
|
|||
|
||||
/// Sleep the current thread
|
||||
static void SleepThread(Core::System& system, s64 nanoseconds) {
|
||||
auto& kernel = system.Kernel();
|
||||
const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
|
||||
|
||||
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
|
||||
|
||||
enum class SleepType : s64 {
|
||||
YieldWithoutCoreMigration = 0,
|
||||
YieldWithCoreMigration = -1,
|
||||
YieldAndWaitForLoadBalancing = -2,
|
||||
};
|
||||
// When the input tick is positive, sleep.
|
||||
if (nanoseconds > 0) {
|
||||
// Convert the timeout from nanoseconds to ticks.
|
||||
// NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
|
||||
|
||||
auto& scheduler = *system.Kernel().CurrentScheduler();
|
||||
if (nanoseconds <= 0) {
|
||||
switch (static_cast<SleepType>(nanoseconds)) {
|
||||
case SleepType::YieldWithoutCoreMigration: {
|
||||
scheduler.YieldWithoutCoreMigration();
|
||||
break;
|
||||
}
|
||||
case SleepType::YieldWithCoreMigration: {
|
||||
scheduler.YieldWithCoreMigration();
|
||||
break;
|
||||
}
|
||||
case SleepType::YieldAndWaitForLoadBalancing: {
|
||||
scheduler.YieldToAnyThread();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
||||
}
|
||||
// Sleep.
|
||||
// NOTE: Nintendo does not check the result of this sleep.
|
||||
static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds));
|
||||
} else if (yield_type == Svc::YieldType::WithoutCoreMigration) {
|
||||
KScheduler::YieldWithoutCoreMigration(kernel);
|
||||
} else if (yield_type == Svc::YieldType::WithCoreMigration) {
|
||||
KScheduler::YieldWithCoreMigration(kernel);
|
||||
} else if (yield_type == Svc::YieldType::ToAnyThread) {
|
||||
KScheduler::YieldToAnyThread(kernel);
|
||||
} else {
|
||||
scheduler.GetCurrentThread()->Sleep(nanoseconds);
|
||||
// Nintendo does nothing at all if an otherwise invalid value is passed.
|
||||
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1822,95 +1794,72 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u
|
|||
return CreateTransferMemory(system, handle, addr, size, permissions);
|
||||
}
|
||||
|
||||
static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core,
|
||||
u64* mask) {
|
||||
static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
|
||||
u64* out_affinity_mask) {
|
||||
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
|
||||
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
*core = 0;
|
||||
*mask = 0;
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
*core = thread->GetIdealCore();
|
||||
*mask = thread->GetAffinityMask().GetAffinityMask();
|
||||
// Get the core mask.
|
||||
R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core,
|
||||
u32* mask_low, u32* mask_high) {
|
||||
u64 mask{};
|
||||
const auto result = GetThreadCoreMask(system, thread_handle, core, &mask);
|
||||
*mask_high = static_cast<u32>(mask >> 32);
|
||||
*mask_low = static_cast<u32>(mask);
|
||||
static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id,
|
||||
u32* out_affinity_mask_low, u32* out_affinity_mask_high) {
|
||||
u64 out_affinity_mask{};
|
||||
const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask);
|
||||
*out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32);
|
||||
*out_affinity_mask_low = static_cast<u32>(out_affinity_mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
|
||||
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
|
||||
u64 affinity_mask) {
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}",
|
||||
thread_handle, core, affinity_mask);
|
||||
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}",
|
||||
thread_handle, core_id, affinity_mask);
|
||||
|
||||
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||
const auto& current_process = *system.Kernel().CurrentProcess();
|
||||
|
||||
if (core == static_cast<u32>(Svc::IdealCoreUseProcessValue)) {
|
||||
const u8 ideal_cpu_core = current_process->GetIdealCoreId();
|
||||
|
||||
ASSERT(ideal_cpu_core != static_cast<u8>(Svc::IdealCoreUseProcessValue));
|
||||
|
||||
// Set the target CPU to the ideal core specified by the process.
|
||||
core = ideal_cpu_core;
|
||||
affinity_mask = 1ULL << core;
|
||||
// Determine the core id/affinity mask.
|
||||
if (core_id == Svc::IdealCoreUseProcessValue) {
|
||||
core_id = current_process.GetIdealCoreId();
|
||||
affinity_mask = (1ULL << core_id);
|
||||
} else {
|
||||
const u64 core_mask = current_process->GetCoreMask();
|
||||
// Validate the affinity mask.
|
||||
const u64 process_core_mask = current_process.GetCoreMask();
|
||||
R_UNLESS((affinity_mask | process_core_mask) == process_core_mask,
|
||||
Svc::ResultInvalidCoreId);
|
||||
R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination);
|
||||
|
||||
if ((core_mask | affinity_mask) != core_mask) {
|
||||
LOG_ERROR(
|
||||
Kernel_SVC,
|
||||
"Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})",
|
||||
core_mask, affinity_mask);
|
||||
return ERR_INVALID_PROCESSOR_ID;
|
||||
}
|
||||
|
||||
if (affinity_mask == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero.");
|
||||
return ERR_INVALID_COMBINATION;
|
||||
}
|
||||
|
||||
if (core < Core::Hardware::NUM_CPU_CORES) {
|
||||
if ((affinity_mask & (1ULL << core)) == 0) {
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Core is not enabled for the current mask, core={}, mask={:016X}", core,
|
||||
affinity_mask);
|
||||
return ERR_INVALID_COMBINATION;
|
||||
}
|
||||
} else if (core != static_cast<u32>(Svc::IdealCoreDontCare) &&
|
||||
core != static_cast<u32>(Svc::IdealCoreNoUpdate)) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core);
|
||||
return ERR_INVALID_PROCESSOR_ID;
|
||||
// Validate the core id.
|
||||
if (IsValidCoreId(core_id)) {
|
||||
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination);
|
||||
} else {
|
||||
R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare,
|
||||
Svc::ResultInvalidCoreId);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& handle_table = current_process->GetHandleTable();
|
||||
// Get the thread from its handle.
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
|
||||
if (!thread) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
|
||||
thread_handle);
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
R_UNLESS(thread, Svc::ResultInvalidHandle);
|
||||
|
||||
return thread->SetCoreAndAffinityMask(core, affinity_mask);
|
||||
// Set the core mask.
|
||||
R_TRY(thread->SetCoreMask(core_id, affinity_mask));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core,
|
||||
static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id,
|
||||
u32 affinity_mask_low, u32 affinity_mask_high) {
|
||||
const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
|
||||
return SetThreadCoreMask(system, thread_handle, core, affinity_mask);
|
||||
return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
|
||||
}
|
||||
|
||||
static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
|
||||
|
@ -2474,7 +2423,7 @@ void Call(Core::System& system, u32 immediate) {
|
|||
kernel.EnterSVCProfile();
|
||||
|
||||
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
|
||||
thread->SetContinuousOnSVC(true);
|
||||
thread->SetIsCallingSvc();
|
||||
|
||||
const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
|
||||
: GetSVCInfo32(immediate);
|
||||
|
@ -2490,7 +2439,7 @@ void Call(Core::System& system, u32 immediate) {
|
|||
|
||||
kernel.ExitSVCProfile();
|
||||
|
||||
if (!thread->IsContinuousOnSVC()) {
|
||||
if (!thread->IsCallingSvc()) {
|
||||
auto* host_context = thread->GetHostContext().get();
|
||||
host_context->Rewind();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue