kern: skeleton enough types to init KCoreLocalRegion in main()

This commit is contained in:
Michael Scire 2020-01-29 14:26:24 -08:00
parent ad0d2faa6c
commit 981bb1f15d
24 changed files with 1066 additions and 33 deletions

View file

@ -37,9 +37,13 @@
#include "mesosphere/kern_k_memory_layout.hpp"
/* Core functionality. */
#include "mesosphere/kern_select_interrupts.hpp"
#include "mesosphere/kern_select_interrupt_manager.hpp"
#include "mesosphere/kern_k_spin_lock.hpp"
#include "mesosphere/kern_k_page_heap.hpp"
#include "mesosphere/kern_k_memory_manager.hpp"
#include "mesosphere/kern_k_interrupt_task_manager.hpp"
#include "mesosphere/kern_k_core_local_region.hpp"
#include "mesosphere/kern_kernel.hpp"
/* Supervisor Calls. */
#include "mesosphere/kern_svc.hpp"

View file

@ -0,0 +1,33 @@
/*
* 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_select_cpu.hpp>
#include <mesosphere/kern_k_hardware_timer_base.hpp>
namespace ams::kern::arm64 {
class KHardwareTimer : public KHardwareTimerBase {
public:
static constexpr s32 InterruptId = 30; /* Nintendo uses the non-secure timer interrupt. */
public:
constexpr KHardwareTimer() : KHardwareTimerBase() { /* ... */ }
virtual void DoTask() override;
/* TODO: Actually implement more of KHardwareTimer, */
};
}

View file

@ -0,0 +1,122 @@
/*
* 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 <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
namespace ams::kern::arm64 {
struct GicDistributor {
u32 ctlr;
u32 typer;
u32 iidr;
u32 reserved_0x0c;
u32 statusr;
u32 reserved_0x14[3];
u32 impldef_0x20[8];
u32 setspi_nsr;
u32 reserved_0x44;
u32 clrspi_nsr;
u32 reserved_0x4c;
u32 setspi_sr;
u32 reserved_0x54;
u32 clrspi_sr;
u32 reserved_0x5c[9];
u32 igroupr[32];
u32 isenabler[32];
u32 icenabler[32];
u32 ispendr[32];
u32 icpendr[32];
u32 isactiver[32];
u32 icactiver[32];
u8 ipriorityr[1020];
u32 _0x7fc;
u8 itargetsr[1020];
u32 _0xbfc;
u32 icfgr[64];
u32 igrpmodr[32];
u32 _0xd80[32];
u32 nsacr[64];
u32 sgir;
u32 _0xf04[3];
u32 cpendsgir[4];
u32 spendsgir[4];
u32 reserved_0xf30[52];
};
static_assert(std::is_pod<GicDistributor>::value);
static_assert(sizeof(GicDistributor) == 0x1000);
struct GicController {
u32 ctlr;
u32 pmr;
u32 bpr;
u32 iar;
u32 eoir;
u32 rpr;
u32 hppir;
u32 abpr;
u32 aiar;
u32 aeoir;
u32 ahppir;
u32 statusr;
u32 reserved_30[4];
u32 impldef_40[36];
u32 apr[4];
u32 nsapr[4];
u32 reserved_f0[3];
u32 iidr;
u32 reserved_100[960];
u32 dir;
u32 _0x1004[1023];
};
static_assert(std::is_pod<GicController>::value);
static_assert(sizeof(GicController) == 0x2000);
struct KInterruptController {
NON_COPYABLE(KInterruptController);
NON_MOVEABLE(KInterruptController);
public:
static constexpr size_t NumLocalInterrupts = 32;
static constexpr size_t NumGlobalInterrupts = 988;
static constexpr size_t NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts;
public:
struct LocalState {
u32 local_isenabler[NumLocalInterrupts / 32];
u32 local_ipriorityr[NumLocalInterrupts / 4];
u32 local_targetsr[NumLocalInterrupts / 4];
u32 local_icfgr[NumLocalInterrupts / 16];
};
struct GlobalState {
u32 global_isenabler[NumGlobalInterrupts / 32];
u32 global_ipriorityr[NumGlobalInterrupts / 4];
u32 global_targetsr[NumGlobalInterrupts / 4];
u32 global_icfgr[NumGlobalInterrupts / 16];
};
private:
static inline volatile GicDistributor *s_gicd;
static inline volatile GicController *s_gicc;
static inline u32 s_mask[cpu::NumCores];
private:
volatile GicDistributor *gicd;
volatile GicController *gicc;
public:
KInterruptController() { /* Don't initialize anything -- this will be taken care of by ::Initialize() */ }
/* TODO: Actually implement KInterruptController functionality. */
};
}

View file

@ -0,0 +1,82 @@
/*
* 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 <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_spin_lock.hpp>
#include <mesosphere/kern_k_interrupt_task.hpp>
#include <mesosphere/kern_select_interrupt_controller.hpp>
namespace ams::kern::arm64 {
class KInterruptManager {
NON_COPYABLE(KInterruptManager);
NON_MOVEABLE(KInterruptManager);
private:
struct KCoreLocalInterruptEntry {
KInterruptHandler *handler;
bool manually_cleared;
bool needs_clear;
u8 priority;
};
struct KGlobalInterruptEntry {
KInterruptHandler *handler;
bool manually_cleared;
bool needs_clear;
};
private:
static inline KSpinLock s_lock;
static inline KGlobalInterruptEntry s_global_interrupts[KInterruptController::NumGlobalInterrupts];
static inline KInterruptController::GlobalState s_global_state;
static inline bool s_global_state_saved;
private:
KCoreLocalInterruptEntry core_local_interrupts[KInterruptController::NumLocalInterrupts];
KInterruptController interrupt_controller;
KInterruptController::LocalState local_state;
bool local_state_saved;
public:
KInterruptManager() : local_state_saved(false) { /* Leave things mostly uninitalized. We'll call ::Initialize() later. */ }
/* TODO: Actually implement KInterruptManager functionality. */
public:
static ALWAYS_INLINE u32 DisableInterrupts() {
u64 intr_state;
__asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
__asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"(intr_state | 0x80));
return intr_state;
}
static ALWAYS_INLINE u32 EnableInterrupts() {
u64 intr_state;
__asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
__asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"(intr_state & 0x7F));
return intr_state;
}
static ALWAYS_INLINE void RestoreInterrupts(u32 intr_state) {
u64 cur_state;
__asm__ __volatile__("mrs %[cur_state], daif" : [cur_state]"=r"(cur_state));
__asm__ __volatile__("msr daif, %[intr_state]" :: [intr_state]"r"((cur_state & 0x7F) | (intr_state & 0x80)));
}
static ALWAYS_INLINE bool AreInterruptsEnabled() {
u64 intr_state;
__asm__ __volatile__("mrs %[intr_state], daif" : [intr_state]"=r"(intr_state));
return (intr_state & 0x80) == 0;
}
};
}

View file

@ -0,0 +1,111 @@
/*
* 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 <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
namespace ams::kern::arm64 {
class KNotAlignedSpinLock {
private:
u32 packed_tickets;
public:
constexpr KNotAlignedSpinLock() : packed_tickets(0) { /* ... */ }
void Lock() {
u32 tmp0, tmp1;
__asm__ __volatile__(
" prfm pstl1keep, %[packed_tickets]\n"
"loop1:\n"
" ldaxr %w[tmp0], %[packed_tickets]\n"
" add %w[tmp0], %w[tmp0], #0x10000\n"
" stxr %w[tmp1], %w[tmp0], %[packed_tickets]\n"
" cbnz %w[tmp1], loop1\n"
" \n"
" and %w[tmp1], %w[tmp0], #0xFFFF\n"
" cmp %w[tmp1], %w[tmp0], lsr #16\n"
" b.eq done"
" sevl\n"
"loop2:\n"
" wfe\n"
" ldaxrh %w[tmp1], %[packed_tickets]\n"
" cmp %w[tmp1], %w[tmp0], lsr #16\n"
" b.ne loop2\n"
"done:\n"
: [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [packed_tickets]"+Q"(this->packed_tickets)
:
: "cc", "memory"
);
}
void Unlock() {
const u32 value = this->packed_tickets + 1;
__asm__ __volatile__(
" stlrh %w[value], %[packed_tickets]\n"
: [packed_tickets]"+Q"(this->packed_tickets)
: [value]"r"(value)
: "memory"
);
}
};
static_assert(sizeof(KNotAlignedSpinLock) == sizeof(u32));
class KAlignedSpinLock {
private:
alignas(cpu::DataCacheLineSize) u16 current_ticket;
alignas(cpu::DataCacheLineSize) u16 next_ticket;
public:
constexpr KAlignedSpinLock() : current_ticket(0), next_ticket(0) { /* ... */ }
void Lock() {
u32 tmp0, tmp1, got_lock;
__asm__ __volatile__(
" prfm pstl1keep, %[next_ticket]\n"
"loop1:\n"
" ldaxrh %w[tmp0], %[next_ticket]\n"
" add %w[tmp1], %w[tmp0], #0x1\n"
" stxrh %w[got_lock], %w[tmp1], %[next_ticket]\n"
" cbnz %w[got_lock], loop1\n"
" \n"
" sevl\n"
"loop2:\n"
" wfe\n"
" ldaxrh %w[tmp1], %[current_ticket]\n"
" cmp %w[tmp1], %w[tmp0]\n"
" b.ne loop2\n"
: [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [got_lock]"=&r"(got_lock), [next_ticket]"+Q"(this->next_ticket)
: [current_ticket]"Q"(this->current_ticket)
: "cc", "memory"
);
}
void Unlock() {
const u32 value = this->current_ticket + 1;
__asm__ __volatile__(
" stlrh %w[value], %[current_ticket]\n"
: [current_ticket]"+Q"(this->current_ticket)
: [value]"r"(value)
: "memory"
);
}
};
static_assert(sizeof(KAlignedSpinLock) == 2 * cpu::DataCacheLineSize);
using KSpinLock = KAlignedSpinLock;
}

View file

@ -0,0 +1,61 @@
/*
* 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 <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_current_context.hpp>
#include <mesosphere/kern_k_scheduler.hpp>
#include <mesosphere/kern_k_interrupt_task_manager.hpp>
#include <mesosphere/kern_select_interrupt_manager.hpp>
#include <mesosphere/kern_select_hardware_timer.hpp>
#include <mesosphere/kern_k_memory_manager.hpp>
namespace ams::kern {
struct KCoreLocalContext {
KCurrentContext current;
KScheduler scheduler;
KInterruptTaskManager interrupt_task_manager;
KInterruptManager interrupt_manager;
KHardwareTimer hardware_timer;
/* Everything after this point is for debugging. */
/* Retail kernel doesn't even consistently update these fields. */
u64 num_sw_interrupts;
u64 num_hw_interrupts;
std::atomic<u64> num_svc;
u64 num_process_switches;
u64 num_thread_switches;
u64 num_fpu_switches;
u64 num_scheduler_updates;
u64 num_invoked_scheduler_updates;
std::atomic<u64> num_specific_svc[0x80];
u32 perf_counters[6];
};
static_assert(sizeof(KCoreLocalContext) < KMemoryManager::PageSize);
struct KCoreLocalPage {
KCoreLocalContext context;
u8 padding[KMemoryManager::PageSize - sizeof(KCoreLocalContext)];
};
static_assert(sizeof(KCoreLocalPage) == KMemoryManager::PageSize);
struct KCoreLocalRegion {
KCoreLocalPage current;
KCoreLocalPage absolute[cpu::NumCores];
};
static_assert(sizeof(KCoreLocalRegion) == KMemoryManager::PageSize * (1 + cpu::NumCores));
}

View file

@ -0,0 +1,89 @@
/*
* 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_select_cpu.hpp>
namespace ams::kern {
class KThread;
class KProcess;
class KScheduler;
class KInterruptTaskManager;
struct KCurrentContext {
KThread *current_thread;
KProcess *current_process;
KScheduler *scheduler;
KInterruptTaskManager *interrupt_task_manager;
s32 core_id;
void *exception_stack_bottom;
};
static_assert(std::is_pod<KCurrentContext>::value);
static_assert(sizeof(KCurrentContext) <= cpu::DataCacheLineSize);
namespace impl {
ALWAYS_INLINE KCurrentContext &GetCurrentContext() {
return *reinterpret_cast<KCurrentContext *>(cpu::GetCoreLocalRegionAddress());
}
}
ALWAYS_INLINE KThread *GetCurrentThreadPointer() {
return impl::GetCurrentContext().current_thread;
}
ALWAYS_INLINE KThread &GetCurrentThread() {
return *GetCurrentThreadPointer();
}
ALWAYS_INLINE KProcess *GetCurrentProcessPointer() {
return impl::GetCurrentContext().current_process;
}
ALWAYS_INLINE KProcess &GetCurrentProcess() {
return *GetCurrentProcessPointer();
}
ALWAYS_INLINE KScheduler *GetCurrentSchedulerPointer() {
return impl::GetCurrentContext().scheduler;
}
ALWAYS_INLINE KScheduler &GetCurrentScheduler() {
return *GetCurrentSchedulerPointer();
}
ALWAYS_INLINE KInterruptTaskManager *GetCurrentInterruptTaskManagerPointer() {
return impl::GetCurrentContext().interrupt_task_manager;
}
ALWAYS_INLINE KInterruptTaskManager &GetCurrentInterruptTaskManager() {
return *GetCurrentInterruptTaskManagerPointer();
}
ALWAYS_INLINE s32 GetCurrentCoreId() {
return impl::GetCurrentContext().core_id;
}
ALWAYS_INLINE void SetCurrentThread(KThread *new_thread) {
impl::GetCurrentContext().current_thread = new_thread;
}
ALWAYS_INLINE void SetCurrentProcess(KProcess *new_process) {
impl::GetCurrentContext().current_process = new_process;
}
}

View file

@ -0,0 +1,41 @@
/*
* 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_k_spin_lock.hpp>
#include <mesosphere/kern_k_interrupt_task.hpp>
#include <mesosphere/kern_k_timer_task.hpp>
#include <mesosphere/kern_select_interrupt_manager.hpp>
namespace ams::kern {
class KHardwareTimerBase : public KInterruptTask {
private:
using TimerTaskTree = util::IntrusiveRedBlackTreeBaseTraits<KTimerTask>::TreeType<KTimerTask>;
private:
KSpinLock lock;
TimerTaskTree task_tree;
KTimerTask *next_task;
public:
constexpr KHardwareTimerBase() : lock(), task_tree(), next_task(nullptr) { /* ... */ }
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) override { return this; }
protected:
KSpinLock &GetLock() { return this->lock; }
/* TODO: Actually implement more of KHardwareTimerBase */
};
}

View file

@ -0,0 +1,44 @@
/*
* 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
namespace ams::kern {
class KInterruptTask;
class KInterruptHandler {
public:
virtual KInterruptTask *OnInterrupt(s32 interrupt_id) = 0;
};
class KInterruptTask : public KInterruptHandler {
private:
KInterruptTask *next_task;
public:
constexpr ALWAYS_INLINE KInterruptTask() : next_task(nullptr) { /* ... */ }
ALWAYS_INLINE KInterruptTask *GetNextTask() const {
return this->next_task;
}
ALWAYS_INLINE void SetNextTask(KInterruptTask *t) {
this->next_task = t;
}
virtual void DoTask() = 0;
};
}

View file

@ -0,0 +1,46 @@
/*
* 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_k_interrupt_task.hpp>
namespace ams::kern {
class KThread;
class KInterruptTaskManager {
private:
class TaskQueue {
private:
KInterruptTask *head;
KInterruptTask *tail;
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; }
void Enqueue(KInterruptTask *task);
void Dequeue();
};
private:
TaskQueue task_queue;
KThread *thread;
public:
/* TODO: Actually implement KInterruptTaskManager. This is a placeholder. */
};
}

View file

@ -402,6 +402,18 @@ namespace ams::kern {
return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_KernelMiscMainStack, static_cast<u32>(core_id))->GetEndAddress();
}
static NOINLINE KVirtualAddress GetIdleStackTopAddress(s32 core_id) {
return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_KernelMiscIdleStack, static_cast<u32>(core_id))->GetEndAddress();
}
static NOINLINE KVirtualAddress GetExceptionStackBottomAddress(s32 core_id) {
return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_KernelMiscExceptionStack, static_cast<u32>(core_id))->GetAddress();
}
static NOINLINE KVirtualAddress GetCoreLocalRegionAddress() {
return GetVirtualMemoryBlockTree().FindFirstBlockByTypeAttr(KMemoryRegionType_CoreLocal)->GetAddress();
}
static void InitializeLinearMemoryBlockTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start);
};

View file

@ -0,0 +1,45 @@
/*
* 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_k_thread.hpp>
namespace ams::kern {
class KScheduler {
NON_COPYABLE(KScheduler);
NON_MOVEABLE(KScheduler);
public:
struct SchedulingState {
std::atomic<bool> needs_scheduling;
bool interrupt_task_thread_runnable;
bool should_count_idle;
u64 idle_count;
KThread *highest_priority_thread;
void *idle_thread_stack;
};
private:
SchedulingState state;
bool is_active;
s32 core_id;
KThread *prev_thread;
u64 last_context_switch_time;
KThread *idle_thread;
public:
KScheduler();
/* TODO: Actually implement KScheduler. This is a placeholder. */
};
}

View file

@ -0,0 +1,74 @@
/*
* 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 <vapours.hpp>
#include "kern_panic.hpp"
#if defined(ATMOSPHERE_ARCH_ARM64)
#include <mesosphere/arch/arm64/kern_k_spin_lock.hpp>
namespace ams::kern {
using ams::kern::arm64::KAlignedSpinLock;
using ams::kern::arm64::KNotAlignedSpinLock;
using ams::kern::arm64::KSpinLock;
}
#else
#error "Unknown architecture for KInterruptManager"
#endif
namespace ams::kern {
class KScopedSpinLock {
private:
KSpinLock *lock_ptr;
public:
explicit ALWAYS_INLINE KScopedSpinLock(KSpinLock *l) : lock_ptr(l) {
this->lock_ptr->Lock();
}
ALWAYS_INLINE ~KScopedSpinLock() {
this->lock_ptr->Unlock();
}
};
class KScopedAlignedSpinLock {
private:
KAlignedSpinLock *lock_ptr;
public:
explicit ALWAYS_INLINE KScopedAlignedSpinLock(KAlignedSpinLock *l) : lock_ptr(l) {
this->lock_ptr->Lock();
}
ALWAYS_INLINE ~KScopedAlignedSpinLock() {
this->lock_ptr->Unlock();
}
};
class KScopedNotAlignedSpinLock {
private:
KNotAlignedSpinLock *lock_ptr;
public:
explicit ALWAYS_INLINE KScopedNotAlignedSpinLock(KNotAlignedSpinLock *l) : lock_ptr(l) {
this->lock_ptr->Lock();
}
ALWAYS_INLINE ~KScopedNotAlignedSpinLock() {
this->lock_ptr->Unlock();
}
};
}

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
namespace ams::kern {
class KThread {
/* TODO: This should be a KAutoObject, and this is a placeholder definition. */
};
}

View file

@ -0,0 +1,47 @@
/*
* 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 <vapours.hpp>
namespace ams::kern {
class KTimerTask : public util::IntrusiveRedBlackTreeBaseNode<KTimerTask> {
private:
s64 time;
public:
static constexpr ALWAYS_INLINE int Compare(const KTimerTask &lhs, const KTimerTask &rhs) {
if (lhs.GetTime() < rhs.GetTime()) {
return -1;
} else {
return 1;
}
}
public:
constexpr ALWAYS_INLINE KTimerTask() : time(0) { /* ... */ }
constexpr ALWAYS_INLINE void SetTime(s64 t) {
this->time = t;
}
constexpr ALWAYS_INLINE s64 GetTime() const {
return this->time;
}
virtual void OnTimer() = 0;
};
}

View file

@ -0,0 +1,40 @@
/*
* 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_k_typed_address.hpp>
#include <mesosphere/kern_k_memory_layout.hpp>
#include <mesosphere/kern_k_memory_manager.hpp>
#include <mesosphere/kern_k_core_local_region.hpp>
namespace ams::kern {
class Kernel {
public:
enum class State : u8 {
Invalid = 0,
Initializing = 1,
Initialized = 2,
};
private:
static inline State s_state = State::Invalid;
public:
static void Initialize(s32 core_id);
static ALWAYS_INLINE State GetState() { return s_state; }
static ALWAYS_INLINE void SetState(State state) { s_state = state; }
};
}

View file

@ -0,0 +1,31 @@
/*
* 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 <vapours.hpp>
#include "kern_panic.hpp"
#if defined(ATMOSPHERE_ARCH_ARM64)
#include <mesosphere/arch/arm64/kern_k_hardware_timer.hpp>
namespace ams::kern {
using ams::kern::arm64::KHardwareTimer;
}
#else
#error "Unknown architecture for KHardwareTimer"
#endif

View file

@ -0,0 +1,31 @@
/*
* 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 <vapours.hpp>
#include "kern_panic.hpp"
#if defined(ATMOSPHERE_ARCH_ARM64)
#include <mesosphere/arch/arm64/kern_k_interrupt_controller.hpp>
namespace ams::kern {
using ams::kern::arm64::KInterruptController;
}
#else
#error "Unknown architecture for KInterruptController"
#endif

View file

@ -17,26 +17,42 @@
#include <vapours.hpp>
#include "kern_panic.hpp"
namespace ams::kern {
#if defined(ATMOSPHERE_ARCH_ARM64)
/* TODO: Actually select between architecture-specific interrupt code. */
#include <mesosphere/arch/arm64/kern_k_interrupt_manager.hpp>
namespace ams::kern {
using ams::kern::arm64::KInterruptManager;
}
#else
#error "Unknown architecture for KInterruptManager"
#endif
namespace ams::kern {
/* Enable or disable interrupts for the lifetime of an object. */
class KScopedInterruptDisable {
NON_COPYABLE(KScopedInterruptDisable);
NON_MOVEABLE(KScopedInterruptDisable);
private:
u32 prev_intr_state;
public:
KScopedInterruptDisable();
~KScopedInterruptDisable();
ALWAYS_INLINE KScopedInterruptDisable() : prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ }
~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(prev_intr_state); }
};
class KScopedInterruptEnable {
NON_COPYABLE(KScopedInterruptEnable);
NON_MOVEABLE(KScopedInterruptEnable);
private:
u32 prev_intr_state;
public:
KScopedInterruptEnable();
~KScopedInterruptEnable();
ALWAYS_INLINE KScopedInterruptEnable() : prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ }
~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(prev_intr_state); }
};
}

View file

@ -0,0 +1,24 @@
/*
* 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/>.
*/
#include <mesosphere.hpp>
namespace ams::kern::arm64 {
void KHardwareTimer::DoTask() {
/* TODO: Actually implement this. */
}
}

View file

@ -17,20 +17,24 @@
namespace ams::kern {
inline KScopedInterruptDisable::KScopedInterruptDisable() {
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
void KInterruptTaskManager::TaskQueue::Enqueue(KInterruptTask *task) {
/* Insert the task into the queue. */
if (this->tail != nullptr) {
this->tail->SetNextTask(task);
} else {
this->head = task;
}
this->tail = task;
}
inline KScopedInterruptDisable::~KScopedInterruptDisable() {
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
}
inline KScopedInterruptEnable::KScopedInterruptEnable() {
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
}
inline KScopedInterruptEnable::~KScopedInterruptEnable() {
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
void KInterruptTaskManager::TaskQueue::Dequeue() {
if (this->head == this->tail) {
this->head = nullptr;
this->tail = nullptr;
} else {
this->head = this->head->GetNextTask();
}
}
}

View file

@ -17,20 +17,15 @@
namespace ams::kern {
WEAK_SYMBOL KScopedInterruptDisable::KScopedInterruptDisable() {
/* TODO: Disable interrupts. */
}
WEAK_SYMBOL KScopedInterruptDisable::~KScopedInterruptDisable() {
/* TODO: un-disable interrupts. */
}
WEAK_SYMBOL KScopedInterruptEnable::KScopedInterruptEnable() {
/* TODO: Enable interrupts. */
}
WEAK_SYMBOL KScopedInterruptEnable::~KScopedInterruptEnable() {
/* TODO: un-enable interrupts. */
KScheduler::KScheduler()
: is_active(false), core_id(0), prev_thread(nullptr), last_context_switch_time(0), idle_thread(nullptr)
{
this->state.needs_scheduling = true;
this->state.interrupt_task_thread_runnable = false;
this->state.should_count_idle = false;
this->state.idle_count = 0;
this->state.idle_thread_stack = nullptr;
this->state.highest_priority_thread = nullptr;
}
}

View file

@ -0,0 +1,49 @@
/*
* 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/>.
*/
#include <mesosphere.hpp>
namespace ams::kern {
NOINLINE void Kernel::Initialize(s32 core_id) {
/* Construct the core local region object in place. */
KCoreLocalContext *clc = GetPointer<KCoreLocalContext>(KMemoryLayout::GetCoreLocalRegionAddress());
new (clc) KCoreLocalContext;
/* Set the core local region address into the global register. */
cpu::SetCoreLocalRegionAddress(reinterpret_cast<uintptr_t>(clc));
/* Initialize current context. */
clc->current.current_thread = nullptr;
clc->current.current_process = nullptr;
clc->current.scheduler = std::addressof(clc->scheduler);
clc->current.interrupt_task_manager = std::addressof(clc->interrupt_task_manager);
clc->current.core_id = core_id;
clc->current.exception_stack_bottom = GetVoidPointer(KMemoryLayout::GetExceptionStackBottomAddress(core_id));
/* Clear debugging counters. */
clc->num_sw_interrupts = 0;
clc->num_hw_interrupts = 0;
clc->num_svc = 0;
clc->num_process_switches = 0;
clc->num_thread_switches = 0;
clc->num_fpu_switches = 0;
for (size_t i = 0; i < util::size(clc->perf_counters); i++) {
clc->perf_counters[i] = 0;
}
}
}

View file

@ -18,7 +18,14 @@
namespace ams::kern {
NORETURN void HorizonKernelMain(s32 core_id) {
/* Setup the Core Local Region, and note that we're initializing. */
Kernel::Initialize(core_id);
Kernel::SetState(Kernel::State::Initializing);
/* Ensure that all cores get to this point before proceeding. */
cpu::SynchronizeAllCores();
/* TODO: Implement more of Main() */
while (true) { /* ... */ }
}