mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-04 00:28:51 -04:00
kern: Implement exception vector ASM
This commit is contained in:
parent
e330b6187f
commit
919b8124dc
26 changed files with 1497 additions and 60 deletions
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) */
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue