1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 10:07:43 +00:00
serenity/Kernel/Arch/aarch64/Processor.h
Andreas Kling 94b514b981 Kernel: Add MAX_CPU_COUNT global constant
Instead of just hard-coding the x86 Processor array to size 64,
we now use a named constant that you can also reference elsewhere. :^)
2022-11-19 15:39:30 +01:00

275 lines
6.6 KiB
C++

/*
* Copyright (c) 2018-2021, James Mintram <me@jamesrm.com>
* Copyright (c) 2022, Timon Kruiper <timonkruiper@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Array.h>
#include <AK/Concepts.h>
#include <AK/Function.h>
#include <AK/Types.h>
#include <Kernel/Arch/ProcessorSpecificDataID.h>
#include <Kernel/Arch/aarch64/Registers.h>
#include <Kernel/VirtualAddress.h>
namespace Kernel {
namespace Memory {
class PageDirectory;
};
class Thread;
class Processor;
// FIXME This needs to go behind some sort of platform abstraction
// it is used between Thread and Processor.
struct [[gnu::aligned(16)]] FPUState
{
u8 buffer[512];
};
// FIXME: Remove this once we support SMP in aarch64
extern Processor* g_current_processor;
constexpr size_t MAX_CPU_COUNT = 1;
class Processor {
void* m_processor_specific_data[static_cast<size_t>(ProcessorSpecificDataID::__Count)];
public:
void initialize(u32 cpu);
template<typename T>
T* get_specific()
{
return static_cast<T*>(m_processor_specific_data[static_cast<size_t>(T::processor_specific_data_id())]);
}
void set_specific(ProcessorSpecificDataID specific_id, void* ptr)
{
m_processor_specific_data[static_cast<size_t>(specific_id)] = ptr;
}
void idle_begin() const
{
TODO_AARCH64();
}
void idle_end() const
{
TODO_AARCH64();
}
ALWAYS_INLINE static void pause()
{
TODO_AARCH64();
}
ALWAYS_INLINE static void wait_check()
{
TODO_AARCH64();
}
ALWAYS_INLINE u8 physical_address_bit_width() const
{
TODO_AARCH64();
return 0;
}
ALWAYS_INLINE u8 virtual_address_bit_width() const
{
TODO_AARCH64();
return 0;
}
ALWAYS_INLINE static bool is_initialized()
{
return false;
}
static void flush_tlb_local(VirtualAddress vaddr, size_t page_count);
static void flush_tlb(Memory::PageDirectory const*, VirtualAddress, size_t);
ALWAYS_INLINE u32 id() const
{
// NOTE: This variant should only be used when iterating over all
// Processor instances, or when it's guaranteed that the thread
// cannot move to another processor in between calling Processor::current
// and Processor::get_id, or if this fact is not important.
// All other cases should use Processor::id instead!
return 0;
}
// FIXME: When aarch64 supports multiple cores, return the correct core id here.
ALWAYS_INLINE static u32 current_id()
{
return 0;
}
ALWAYS_INLINE void set_idle_thread(Thread& idle_thread)
{
m_idle_thread = &idle_thread;
}
ALWAYS_INLINE static Thread* current_thread()
{
return current().m_current_thread;
}
ALWAYS_INLINE bool has_nx() const
{
return true;
}
ALWAYS_INLINE bool has_pat() const
{
return false;
}
ALWAYS_INLINE static FlatPtr current_in_irq()
{
return current().m_in_irq;
}
ALWAYS_INLINE static u64 read_cpu_counter()
{
TODO_AARCH64();
return 0;
}
ALWAYS_INLINE static bool are_interrupts_enabled()
{
auto daif = Aarch64::DAIF::read();
return !daif.I;
}
ALWAYS_INLINE static void enable_interrupts()
{
Aarch64::DAIF::clear_I();
}
ALWAYS_INLINE static void disable_interrupts()
{
Aarch64::DAIF::set_I();
}
void check_invoke_scheduler();
void invoke_scheduler_async() { m_invoke_scheduler_async = true; }
ALWAYS_INLINE static bool current_in_scheduler()
{
auto current_processor = current();
return current_processor.m_in_scheduler;
}
ALWAYS_INLINE static void set_current_in_scheduler(bool value)
{
current().m_in_scheduler = value;
}
// FIXME: Share the critical functions with x86/Processor.h
ALWAYS_INLINE static void enter_critical()
{
auto current_processor = current();
current_processor.m_in_critical = current_processor.in_critical() + 1;
}
ALWAYS_INLINE static void leave_critical()
{
auto current_processor = current();
current_processor.m_in_critical = current_processor.in_critical() - 1;
}
static u32 clear_critical();
ALWAYS_INLINE static void restore_critical(u32 prev_critical)
{
(void)prev_critical;
TODO_AARCH64();
}
ALWAYS_INLINE static u32 in_critical()
{
return current().m_in_critical;
}
ALWAYS_INLINE static void verify_no_spinlocks_held()
{
VERIFY(!Processor::in_critical());
}
ALWAYS_INLINE static FPUState const& clean_fpu_state() { TODO_AARCH64(); }
ALWAYS_INLINE static void set_current_thread(Thread& current_thread)
{
current().m_current_thread = &current_thread;
}
ALWAYS_INLINE static Thread* idle_thread()
{
return current().m_idle_thread;
}
ALWAYS_INLINE static Processor& current()
{
return *g_current_processor;
}
template<IteratorFunction<Processor&> Callback>
static inline IterationDecision for_each(Callback)
{
TODO_AARCH64();
}
template<VoidFunction<Processor&> Callback>
static inline IterationDecision for_each(Callback)
{
TODO_AARCH64();
}
u64 time_spent_idle() const
{
TODO_AARCH64();
}
static u32 count()
{
TODO_AARCH64();
}
// FIXME: Move this into generic Processor class, when there is such a class.
ALWAYS_INLINE static bool is_bootstrap_processor()
{
return Processor::current_id() == 0;
}
static void deferred_call_queue(Function<void()> /* callback */)
{
TODO_AARCH64();
}
static u32 smp_wake_n_idle_processors(u32 wake_count);
[[noreturn]] static void halt();
[[noreturn]] void initialize_context_switching(Thread& initial_thread);
NEVER_INLINE void switch_context(Thread*& from_thread, Thread*& to_thread);
[[noreturn]] static void assume_context(Thread& thread, FlatPtr flags);
FlatPtr init_context(Thread& thread, bool leave_crit);
static ErrorOr<Vector<FlatPtr, 32>> capture_stack_trace(Thread& thread, size_t max_frames = 0);
private:
Thread* m_current_thread;
Thread* m_idle_thread;
u32 m_in_critical { 0 };
// FIXME: Once there is code in place to differentiate IRQs from synchronous exceptions (syscalls),
// this member should be incremented. Also this member shouldn't be a FlatPtr.
FlatPtr m_in_irq { 0 };
bool m_in_scheduler { false };
bool m_invoke_scheduler_async { false };
};
}