kern: implement thread pinning/SvcSynchronizePreemptionState

This commit is contained in:
Michael Scire 2020-07-27 17:32:04 -07:00 committed by SciresM
parent b1f38be3ae
commit 787964f7e7
10 changed files with 230 additions and 19 deletions

View file

@ -221,6 +221,12 @@ namespace ams::kern {
data[id / BitsPerWord] &= ~(1ul << (id % BitsPerWord));
}
static constexpr ALWAYS_INLINE bool GetSvcAllowedImpl(u8 *data, u32 id) {
constexpr size_t BitsPerWord = BITSIZEOF(*data);
MESOSPHERE_ASSERT(id < svc::SvcId_Count);
return (data[id / BitsPerWord] & (1ul << (id % BitsPerWord))) != 0;
}
bool SetSvcAllowed(u32 id) {
if (id < BITSIZEOF(this->svc_access_flags)) {
SetSvcAllowedImpl(this->svc_access_flags, id);
@ -266,16 +272,46 @@ namespace ams::kern {
ALWAYS_INLINE void CopySvcPermissionsTo(KThread::StackParameters &sp) const {
static_assert(sizeof(svc_access_flags) == sizeof(sp.svc_permission));
/* Copy permissions. */
std::memcpy(sp.svc_permission, this->svc_access_flags, sizeof(this->svc_access_flags));
/* Clear specific SVCs based on our state. */
ClearSvcAllowedImpl(sp.svc_permission, svc::SvcId_ReturnFromException);
ClearSvcAllowedImpl(sp.svc_permission, svc::SvcId_SynchronizePreemptionState);
if (sp.is_preemption_state_pinned) {
if (sp.is_pinned) {
ClearSvcAllowedImpl(sp.svc_permission, svc::SvcId_GetInfo);
}
}
ALWAYS_INLINE void CopyPinnedSvcPermissionsTo(KThread::StackParameters &sp) const {
static_assert(sizeof(svc_access_flags) == sizeof(sp.svc_permission));
/* Clear all permissions. */
std::memset(sp.svc_permission, 0, sizeof(this->svc_access_flags));
/* Set specific SVCs based on our state. */
SetSvcAllowedImpl(sp.svc_permission, svc::SvcId_SynchronizePreemptionState);
if (GetSvcAllowedImpl(sp.svc_permission, svc::SvcId_ReturnFromException)) {
SetSvcAllowedImpl(sp.svc_permission, svc::SvcId_ReturnFromException);
SetSvcAllowedImpl(sp.svc_permission, svc::SvcId_GetInfo);
}
}
ALWAYS_INLINE void CopyUnpinnedSvcPermissionsTo(KThread::StackParameters &sp) const {
static_assert(sizeof(svc_access_flags) == sizeof(sp.svc_permission));
/* Get whether we have access to return from exception. */
const bool return_from_exception = GetSvcAllowedImpl(sp.svc_permission, svc::SvcId_ReturnFromException);
/* Copy permissions. */
std::memcpy(sp.svc_permission, this->svc_access_flags, sizeof(this->svc_access_flags));
/* Clear/Set specific SVCs based on our state. */
ClearSvcAllowedImpl(sp.svc_permission, svc::SvcId_ReturnFromException);
ClearSvcAllowedImpl(sp.svc_permission, svc::SvcId_SynchronizePreemptionState);
if (return_from_exception) {
SetSvcAllowedImpl(sp.svc_permission, svc::SvcId_ReturnFromException);
}
}
constexpr bool IsPermittedInterrupt(u32 id) const {
constexpr size_t BitsPerWord = BITSIZEOF(this->irq_access_flags[0]);
if (id < BITSIZEOF(this->irq_access_flags)) {

View file

@ -204,10 +204,32 @@ namespace ams::kern {
return this->pinned_threads[core_id];
}
void PinThread(s32 core_id, KThread *thread) {
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
MESOSPHERE_ASSERT(thread != nullptr);
MESOSPHERE_ASSERT(this->pinned_threads[core_id] == nullptr);
this->pinned_threads[core_id] = thread;
}
void UnpinThread(s32 core_id, KThread *thread) {
MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast<s32>(cpu::NumCores));
MESOSPHERE_ASSERT(thread != nullptr);
MESOSPHERE_ASSERT(this->pinned_threads[core_id] == thread);
this->pinned_threads[core_id] = nullptr;
}
void CopySvcPermissionsTo(KThread::StackParameters &sp) {
this->capabilities.CopySvcPermissionsTo(sp);
}
void CopyPinnedSvcPermissionsTo(KThread::StackParameters &sp) {
this->capabilities.CopyPinnedSvcPermissionsTo(sp);
}
void CopyUnpinnedSvcPermissionsTo(KThread::StackParameters &sp) {
this->capabilities.CopyUnpinnedSvcPermissionsTo(sp);
}
constexpr KResourceLimit *GetResourceLimit() const { return this->resource_limit; }
bool ReserveResource(ams::svc::LimitableResource which, s64 value);

View file

@ -131,6 +131,9 @@ namespace ams::kern {
static NOINLINE void ClearPreviousThread(KThread *thread);
static NOINLINE void PinCurrentThread(KProcess *cur_process);
static NOINLINE void UnpinCurrentThread(KProcess *cur_process);
static NOINLINE void OnThreadStateChanged(KThread *thread, KThread::ThreadState old_state);
static NOINLINE void OnThreadPriorityChanged(KThread *thread, s32 old_priority);
static NOINLINE void OnThreadAffinityMaskChanged(KThread *thread, const KAffinityMask &old_affinity, s32 old_core);

View file

@ -87,7 +87,7 @@ namespace ams::kern {
u8 current_svc_id;
bool is_calling_svc;
bool is_in_exception_handler;
bool is_preemption_state_pinned;
bool is_pinned;
s32 disable_count;
KThreadContext *context;
};
@ -171,7 +171,7 @@ namespace ams::kern {
using ConditionVariableThreadTree = ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
WaiterList waiter_list{};
WaiterList paused_waiter_list{};
WaiterList pinned_waiter_list{};
KThread *lock_owner{};
ConditionVariableThreadTree *condvar_tree{};
uintptr_t debug_params[3]{};
@ -249,6 +249,9 @@ namespace ams::kern {
this->GetStackParameters().disable_count--;
}
void Pin();
void Unpin();
NOINLINE void DisableCoreMigration();
NOINLINE void EnableCoreMigration();
@ -281,7 +284,7 @@ namespace ams::kern {
ALWAYS_INLINE bool HasDpc() const {
MESOSPHERE_ASSERT_THIS();
return this->GetDpc() != 0;;
return this->GetDpc() != 0;
}
private:
void Suspend();