mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
kern: implement SvcCreateThread, SvcStartThread
This commit is contained in:
parent
9503aae522
commit
7f4c6ae9e7
5 changed files with 95 additions and 6 deletions
|
@ -66,6 +66,14 @@ namespace ams::kern::arch::arm64 {
|
||||||
|
|
||||||
static void FpuContextSwitchHandler(KThread *thread);
|
static void FpuContextSwitchHandler(KThread *thread);
|
||||||
|
|
||||||
|
u32 GetFpcr() const { return this->fpcr; }
|
||||||
|
u32 GetFpsr() const { return this->fpsr; }
|
||||||
|
|
||||||
|
void SetFpcr(u32 v) { this->fpcr = v; }
|
||||||
|
void SetFpsr(u32 v) { this->fpsr = v; }
|
||||||
|
|
||||||
|
void CloneFpuStatus();
|
||||||
|
|
||||||
/* TODO: More methods (especially FPU management) */
|
/* TODO: More methods (especially FPU management) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace ams::kern {
|
||||||
size_t system_resource_num_pages{};
|
size_t system_resource_num_pages{};
|
||||||
size_t memory_release_hint{};
|
size_t memory_release_hint{};
|
||||||
State state{};
|
State state{};
|
||||||
KLightLock lock{};
|
KLightLock state_lock{};
|
||||||
KLightLock list_lock{};
|
KLightLock list_lock{};
|
||||||
KConditionVariable cond_var{};
|
KConditionVariable cond_var{};
|
||||||
KAddressArbiter address_arbiter{};
|
KAddressArbiter address_arbiter{};
|
||||||
|
@ -133,8 +133,11 @@ namespace ams::kern {
|
||||||
constexpr u64 GetCoreMask() const { return this->capabilities.GetCoreMask(); }
|
constexpr u64 GetCoreMask() const { return this->capabilities.GetCoreMask(); }
|
||||||
constexpr u64 GetPriorityMask() const { return this->capabilities.GetPriorityMask(); }
|
constexpr u64 GetPriorityMask() const { return this->capabilities.GetPriorityMask(); }
|
||||||
|
|
||||||
|
constexpr s32 GetIdealCoreId() const { return this->ideal_core_id; }
|
||||||
constexpr void SetIdealCoreId(s32 core_id) { this->ideal_core_id = core_id; }
|
constexpr void SetIdealCoreId(s32 core_id) { this->ideal_core_id = core_id; }
|
||||||
|
|
||||||
|
constexpr bool CheckThreadPriority(s32 prio) const { return ((1ul << prio) & this->GetPriorityMask()) != 0; }
|
||||||
|
|
||||||
constexpr bool Is64Bit() const { return this->flags & ams::svc::CreateProcessFlag_Is64Bit; }
|
constexpr bool Is64Bit() const { return this->flags & ams::svc::CreateProcessFlag_Is64Bit; }
|
||||||
|
|
||||||
constexpr KProcessAddress GetEntryPoint() const { return this->code_address; }
|
constexpr KProcessAddress GetEntryPoint() const { return this->code_address; }
|
||||||
|
@ -159,6 +162,9 @@ namespace ams::kern {
|
||||||
void ReleaseResource(ams::svc::LimitableResource which, s64 value);
|
void ReleaseResource(ams::svc::LimitableResource which, s64 value);
|
||||||
void ReleaseResource(ams::svc::LimitableResource which, s64 value, s64 hint);
|
void ReleaseResource(ams::svc::LimitableResource which, s64 value, s64 hint);
|
||||||
|
|
||||||
|
constexpr KLightLock &GetStateLock() { return this->state_lock; }
|
||||||
|
constexpr KLightLock &GetListLock() { return this->list_lock; }
|
||||||
|
|
||||||
constexpr KProcessPageTable &GetPageTable() { return this->page_table; }
|
constexpr KProcessPageTable &GetPageTable() { return this->page_table; }
|
||||||
constexpr const KProcessPageTable &GetPageTable() const { return this->page_table; }
|
constexpr const KProcessPageTable &GetPageTable() const { return this->page_table; }
|
||||||
|
|
||||||
|
|
|
@ -173,4 +173,19 @@ namespace ams::kern::arch::arm64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KThreadContext::CloneFpuStatus() {
|
||||||
|
u64 pcr, psr;
|
||||||
|
cpu::InstructionMemoryBarrier();
|
||||||
|
if (IsFpuEnabled()) {
|
||||||
|
__asm__ __volatile__("mrs %[pcr], fpcr" : [pcr]"=r"(pcr) :: "memory");
|
||||||
|
__asm__ __volatile__("mrs %[psr], fpsr" : [psr]"=r"(psr) :: "memory");
|
||||||
|
} else {
|
||||||
|
pcr = GetCurrentThread().GetContext().GetFpcr();
|
||||||
|
psr = GetCurrentThread().GetContext().GetFpsr();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->SetFpcr(pcr);
|
||||||
|
this->SetFpsr(psr);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ namespace ams::kern {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
|
||||||
/* Lock ourselves, to prevent concurrent access. */
|
/* Lock ourselves, to prevent concurrent access. */
|
||||||
KScopedLightLock lk(this->lock);
|
KScopedLightLock lk(this->state_lock);
|
||||||
|
|
||||||
/* Validate that we're in a state where we can initialize. */
|
/* Validate that we're in a state where we can initialize. */
|
||||||
const auto state = this->state;
|
const auto state = this->state;
|
||||||
|
|
|
@ -21,6 +21,66 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr bool IsValidCoreId(int32_t core_id) {
|
||||||
|
return (0 <= core_id && core_id < static_cast<int32_t>(cpu::NumCores));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CreateThread(ams::svc::Handle *out, ams::svc::ThreadFunc f, uintptr_t arg, uintptr_t stack_bottom, int32_t priority, int32_t core_id) {
|
||||||
|
/* Adjust core id, if it's the default magic. */
|
||||||
|
KProcess &process = GetCurrentProcess();
|
||||||
|
if (core_id == ams::svc::IdealCoreUseProcessValue) {
|
||||||
|
core_id = process.GetIdealCoreId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate arguments. */
|
||||||
|
R_UNLESS(IsValidCoreId(core_id), svc::ResultInvalidCoreId());
|
||||||
|
R_UNLESS(((1ul << core_id) & process.GetCoreMask()) != 0, svc::ResultInvalidCoreId());
|
||||||
|
|
||||||
|
R_UNLESS(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority, svc::ResultInvalidPriority());
|
||||||
|
R_UNLESS(process.CheckThreadPriority(priority), svc::ResultInvalidPriority());
|
||||||
|
|
||||||
|
/* Reserve a new session from the process resource limit (waiting up to 100ms). */
|
||||||
|
KScopedResourceReservation thread_reservation(std::addressof(process), ams::svc::LimitableResource_ThreadCountMax, 1, KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromMilliSeconds(100)));
|
||||||
|
R_UNLESS(thread_reservation.Succeeded(), svc::ResultLimitReached());
|
||||||
|
|
||||||
|
/* Create the thread. */
|
||||||
|
KScopedAutoObject thread = KThread::Create();
|
||||||
|
R_UNLESS(thread.IsNotNull(), svc::ResultOutOfResource());
|
||||||
|
|
||||||
|
/* Initialize the thread. */
|
||||||
|
{
|
||||||
|
KScopedLightLock lk(process.GetStateLock());
|
||||||
|
R_TRY(KThread::InitializeUserThread(thread.GetPointerUnsafe(), reinterpret_cast<KThreadFunction>(static_cast<uintptr_t>(f)), arg, stack_bottom, priority, core_id, std::addressof(process)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Commit the thread reservation. */
|
||||||
|
thread_reservation.Commit();
|
||||||
|
|
||||||
|
/* Clone the current fpu status to the new thread. */
|
||||||
|
thread->GetContext().CloneFpuStatus();
|
||||||
|
|
||||||
|
/* Register the new thread. */
|
||||||
|
R_TRY(KThread::Register(thread.GetPointerUnsafe()));
|
||||||
|
|
||||||
|
/* Add the thread to the handle table. */
|
||||||
|
R_TRY(process.GetHandleTable().Add(out, thread.GetPointerUnsafe()));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result StartThread(ams::svc::Handle thread_handle) {
|
||||||
|
/* Get the thread from its handle. */
|
||||||
|
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle);
|
||||||
|
R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
|
/* Try to start the thread. */
|
||||||
|
R_TRY(thread->Run());
|
||||||
|
|
||||||
|
/* If we succeeded, persist a reference to the thread. */
|
||||||
|
thread->Open();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
Result GetThreadPriority(int32_t *out_priority, ams::svc::Handle thread_handle) {
|
Result GetThreadPriority(int32_t *out_priority, ams::svc::Handle thread_handle) {
|
||||||
/* Get the thread from its handle. */
|
/* Get the thread from its handle. */
|
||||||
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle);
|
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(thread_handle);
|
||||||
|
@ -46,11 +106,11 @@ namespace ams::kern::svc {
|
||||||
/* ============================= 64 ABI ============================= */
|
/* ============================= 64 ABI ============================= */
|
||||||
|
|
||||||
Result CreateThread64(ams::svc::Handle *out_handle, ams::svc::ThreadFunc func, ams::svc::Address arg, ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) {
|
Result CreateThread64(ams::svc::Handle *out_handle, ams::svc::ThreadFunc func, ams::svc::Address arg, ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcCreateThread64 was called.");
|
return CreateThread(out_handle, func, arg, stack_bottom, priority, core_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result StartThread64(ams::svc::Handle thread_handle) {
|
Result StartThread64(ams::svc::Handle thread_handle) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcStartThread64 was called.");
|
return StartThread(thread_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExitThread64() {
|
void ExitThread64() {
|
||||||
|
@ -100,11 +160,11 @@ namespace ams::kern::svc {
|
||||||
/* ============================= 64From32 ABI ============================= */
|
/* ============================= 64From32 ABI ============================= */
|
||||||
|
|
||||||
Result CreateThread64From32(ams::svc::Handle *out_handle, ams::svc::ThreadFunc func, ams::svc::Address arg, ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) {
|
Result CreateThread64From32(ams::svc::Handle *out_handle, ams::svc::ThreadFunc func, ams::svc::Address arg, ams::svc::Address stack_bottom, int32_t priority, int32_t core_id) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcCreateThread64From32 was called.");
|
return CreateThread(out_handle, func, arg, stack_bottom, priority, core_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result StartThread64From32(ams::svc::Handle thread_handle) {
|
Result StartThread64From32(ams::svc::Handle thread_handle) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcStartThread64From32 was called.");
|
return StartThread(thread_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExitThread64From32() {
|
void ExitThread64From32() {
|
||||||
|
|
Loading…
Reference in a new issue