kern: Implement exception vector ASM

This commit is contained in:
Michael Scire 2020-02-08 02:49:32 -08:00
parent e330b6187f
commit 919b8124dc
26 changed files with 1497 additions and 60 deletions

View file

@ -15,14 +15,12 @@
*/
#pragma once
#define MESOSPHERE_BUILD_FOR_AUDITING
/* All kernel code should have access to libvapours. */
#include <vapours.hpp>
/* First, pull in core macros (panic, etc). */
#include <mesosphere/kern_panic.hpp>
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_panic.hpp>
/* Primitive types. */
#include <mesosphere/kern_k_typed_address.hpp>

View file

@ -43,6 +43,7 @@ namespace ams::kern::arm64::cpu {
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(VbarEl1, vbar_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(FarEl1, far_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(ParEl1, par_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SctlrEl1, sctlr_el1)
@ -56,6 +57,10 @@ namespace ams::kern::arm64::cpu {
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TpidrRoEl0, tpidrro_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(EsrEl1, esr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Afsr0El1, afsr0_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Afsr1El1, afsr1_el1)
#define FOR_I_IN_0_TO_15(HANDLER, ...) \
HANDLER(0, ## __VA_ARGS__) HANDLER(1, ## __VA_ARGS__) HANDLER(2, ## __VA_ARGS__) HANDLER(3, ## __VA_ARGS__) \
HANDLER(4, ## __VA_ARGS__) HANDLER(5, ## __VA_ARGS__) HANDLER(6, ## __VA_ARGS__) HANDLER(7, ## __VA_ARGS__) \
@ -139,6 +144,24 @@ namespace ams::kern::arm64::cpu {
}
};
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(ArchitecturalFeatureAccessControl) {
public:
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(ArchitecturalFeatureAccessControl, cpacr_el1)
constexpr ALWAYS_INLINE decltype(auto) SetFpEnabled(bool en) {
if (en) {
this->SetBits(20, 2, 0x3);
} else {
this->SetBits(20, 2, 0x0);
}
return *this;
}
constexpr ALWAYS_INLINE bool IsFpEnabled() {
return this->GetBits(20, 2) != 0;
}
};
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(DebugFeature) {
public:
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(DebugFeature, id_aa64dfr0_el1)

View file

@ -143,6 +143,14 @@ namespace ams::kern::arm64 {
void Initialize(s32 core_id);
void Finalize(s32 core_id);
public:
u32 GetIrq() const {
return this->gicc->iar;
}
static constexpr s32 ConvertRawIrq(u32 irq) {
return (irq == 0x3FF) ? -1 : (irq & 0x3FF);
}
void Enable(s32 irq) const {
this->gicd->isenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}

View file

@ -60,6 +60,8 @@ namespace ams::kern::arm64 {
static ALWAYS_INLINE KSpinLock &GetLock() { return s_lock; }
static ALWAYS_INLINE KGlobalInterruptEntry &GetGlobalInterruptEntry(s32 irq) { return s_global_interrupts[KInterruptController::GetGlobalInterruptIndex(irq)]; }
ALWAYS_INLINE KCoreLocalInterruptEntry &GetLocalInterruptEntry(s32 irq) { return this->core_local_interrupts[KInterruptController::GetLocalInterruptIndex(irq)]; }
bool OnHandleInterrupt();
public:
constexpr KInterruptManager() : core_local_interrupts(), interrupt_controller(), local_state(), local_state_saved(false) { /* ... */ }
NOINLINE void Initialize(s32 core_id);
@ -79,6 +81,8 @@ namespace ams::kern::arm64 {
this->interrupt_controller.SendInterProcessorInterrupt(irq);
}
static void HandleInterrupt(bool user_mode);
/* Implement more KInterruptManager functionality. */
private:
Result BindGlobal(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level);

View file

@ -62,6 +62,8 @@ namespace ams::kern::arm64 {
Result Initialize(KVirtualAddress u_pc, KVirtualAddress k_sp, KVirtualAddress u_sp, uintptr_t arg, bool is_user, bool is_64_bit, bool is_main);
Result Finalize();
static void FpuContextSwitchHandler(KThread *thread);
/* TODO: More methods (especially FPU management) */
};

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
namespace ams::kern::arm64 {
void UserspaceMemoryAccessFunctionAreaBegin();
void UserspaceMemoryAccessFunctionAreaEnd();
}

View file

@ -24,6 +24,10 @@ namespace ams::kern {
}
#if 1
#define MESOSPHERE_BUILD_FOR_AUDITING
#endif
#ifdef MESOSPHERE_BUILD_FOR_AUDITING
#define MESOSPHERE_BUILD_FOR_DEBUGGING
#endif

View file

@ -29,7 +29,7 @@ namespace ams::kern {
KScheduler *scheduler;
KInterruptTaskManager *interrupt_task_manager;
s32 core_id;
void *exception_stack_bottom;
void *exception_stack_top;
};
static_assert(std::is_pod<KCurrentContext>::value);
static_assert(sizeof(KCurrentContext) <= cpu::DataCacheLineSize);

View file

@ -29,9 +29,9 @@ namespace ams::kern {
public:
constexpr TaskQueue() : head(nullptr), tail(nullptr) { /* ... */ }
ALWAYS_INLINE KInterruptTask *GetHead() { return this->head; }
ALWAYS_INLINE bool IsEmpty() const { return this->head == nullptr; }
ALWAYS_INLINE void Clear() { this->head = nullptr; this->tail = nullptr; }
constexpr KInterruptTask *GetHead() { return this->head; }
constexpr bool IsEmpty() const { return this->head == nullptr; }
constexpr void Clear() { this->head = nullptr; this->tail = nullptr; }
void Enqueue(KInterruptTask *task);
void Dequeue();

View file

@ -439,8 +439,8 @@ namespace ams::kern {
return GetVirtualMemoryRegionTree().FindFirstRegionByTypeAttr(KMemoryRegionType_KernelMiscIdleStack, static_cast<u32>(core_id))->GetEndAddress();
}
static NOINLINE KVirtualAddress GetExceptionStackBottomAddress(s32 core_id) {
return GetVirtualMemoryRegionTree().FindFirstRegionByTypeAttr(KMemoryRegionType_KernelMiscExceptionStack, static_cast<u32>(core_id))->GetAddress();
static NOINLINE KVirtualAddress GetExceptionStackTopAddress(s32 core_id) {
return GetVirtualMemoryRegionTree().FindFirstRegionByTypeAttr(KMemoryRegionType_KernelMiscExceptionStack, static_cast<u32>(core_id))->GetEndAddress();
}
static NOINLINE KVirtualAddress GetSlabRegionAddress() {

View file

@ -32,7 +32,9 @@ namespace ams::kern {
constexpr ALWAYS_INLINE bool Is64Bit() const { /* TODO */ return true; }
ALWAYS_INLINE KThread *GetSuggestedTopThread(s32 core_id) { /* TODO */ return nullptr; }
ALWAYS_INLINE KThread *GetPreemptionStatePinnedThread(s32 core_id) { /* TODO */ return nullptr; }
void SetPreemptionState();
};
}

View file

@ -74,6 +74,14 @@ namespace ams::kern {
NOINLINE void Initialize(KThread *idle_thread);
NOINLINE void Activate();
ALWAYS_INLINE void RequestScheduleOnInterrupt() {
SetSchedulerUpdateNeeded();
if (CanSchedule()) {
this->ScheduleOnInterrupt();
}
}
private:
/* Static private API. */
static ALWAYS_INLINE bool IsSchedulerUpdateNeeded() { return s_scheduler_update_needed; }
@ -130,6 +138,11 @@ namespace ams::kern {
this->ScheduleImpl();
}
ALWAYS_INLINE void ScheduleOnInterrupt() {
KScopedDisableDispatch dd;
this->Schedule();
}
void RescheduleOtherCores(u64 cores_needing_scheduling);
ALWAYS_INLINE void RescheduleCurrentCore() {

View file

@ -202,23 +202,57 @@ namespace ams::kern {
public:
ALWAYS_INLINE s32 GetDisableDispatchCount() const {
MESOSPHERE_ASSERT_THIS();
return GetStackParameters().disable_count;
return this->GetStackParameters().disable_count;
}
ALWAYS_INLINE void DisableDispatch() {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() >= 0);
GetStackParameters().disable_count++;
this->GetStackParameters().disable_count++;
}
ALWAYS_INLINE void EnableDispatch() {
MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() > 0);
GetStackParameters().disable_count--;
this->GetStackParameters().disable_count--;
}
ALWAYS_INLINE void SetInExceptionHandler() {
MESOSPHERE_ASSERT_THIS();
this->GetStackParameters().is_in_exception_handler = true;
}
ALWAYS_INLINE void ClearInExceptionHandler() {
MESOSPHERE_ASSERT_THIS();
this->GetStackParameters().is_in_exception_handler = false;
}
ALWAYS_INLINE bool IsInExceptionHandler() const {
MESOSPHERE_ASSERT_THIS();
return this->GetStackParameters().is_in_exception_handler;
}
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
this->GetStackParameters().dpc_flags |= flag;
}
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
this->GetStackParameters().dpc_flags &= ~flag;
}
ALWAYS_INLINE u8 GetDpc() const {
return this->GetStackParameters().dpc_flags;
}
ALWAYS_INLINE bool HasDpc() const {
MESOSPHERE_ASSERT_THIS();
return this->GetDpc() != 0;;
}
private:
void Suspend();
public:
constexpr KThreadContext *GetContext() { return std::addressof(this->thread_context); }
constexpr const KThreadContext *GetContext() const { return std::addressof(this->thread_context); }
constexpr const KAffinityMask &GetAffinityMask() const { return this->affinity_mask; }
constexpr ThreadState GetState() const { return static_cast<ThreadState>(this->thread_state & ThreadState_Mask); }
constexpr ThreadState GetRawState() const { return this->thread_state; }
@ -248,6 +282,9 @@ namespace ams::kern {
constexpr KProcessAddress GetThreadLocalRegionAddress() const { return this->tls_address; }
constexpr void *GetThreadLocalRegionHeapAddress() const { return this->tls_heap_address; }
constexpr u16 GetUserPreemptionState() const { return *GetPointer<u16>(this->tls_address + 0x100); }
constexpr void SetKernelPreemptionState(u16 state) const { *GetPointer<u16>(this->tls_address + 0x100 + sizeof(u16)) = state; }
void AddCpuTime(s64 amount) {
this->cpu_time += amount;
}
@ -267,14 +304,6 @@ namespace ams::kern {
/* TODO: This is kind of a placeholder definition. */
ALWAYS_INLINE bool IsInExceptionHandler() const {
return GetStackParameters().is_in_exception_handler;
}
ALWAYS_INLINE void SetInExceptionHandler() {
GetStackParameters().is_in_exception_handler = true;
}
ALWAYS_INLINE bool IsTerminationRequested() const {
return this->termination_requested || this->GetRawState() == ThreadState_Terminated;
}

View file

@ -25,9 +25,9 @@ namespace ams::kern {
}
#ifdef MESOSPHERE_ENABLE_DEBUG_PRINT
#define MESOSPHERE_PANIC(...) ams::kern::Panic(__FILE__, __LINE__, __VA_ARGS__)
#define MESOSPHERE_PANIC(...) ::ams::kern::Panic(__FILE__, __LINE__, __VA_ARGS__)
#else
#define MESOSPHERE_PANIC(...) ams::kern::Panic()
#define MESOSPHERE_PANIC(...) ::ams::kern::Panic()
#endif
#ifdef MESOSPHERE_ENABLE_ASSERTIONS

View file

@ -15,7 +15,7 @@
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>
#include <mesosphere/svc/kern_svc_prototypes.hpp>
namespace ams::kern::svc {