serenity/Kernel/Arch/x86_64/Interrupts/APIC.h
Liav A. 2bba9411ca Kernel: Use the AK SetOnce container class in various cases
We have many places in the kernel code that we have boolean flags that
are only set once, and never reset again but are checked multiple times
before and after the time they're being set, which matches the purpose
of the SetOnce class.
2024-04-26 23:46:23 -06:00

117 lines
3.2 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/SetOnce.h>
#include <AK/Types.h>
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Time/HardwareTimer.h>
namespace Kernel {
class APICTimer;
struct LocalAPIC {
u32 apic_id;
};
class APIC {
public:
static APIC& the();
static void initialize();
static bool initialized();
bool init_bsp();
void eoi();
void setup_ap_boot_environment();
void boot_aps();
void enable(u32 cpu);
void init_finished(u32 cpu);
void broadcast_ipi();
void send_ipi(u32 cpu);
static u8 spurious_interrupt_vector();
Thread* get_idle_thread(u32 cpu) const;
u32 enabled_processor_count() const { return m_processor_enabled_cnt; }
APICTimer* initialize_timers(HardwareTimerBase&);
APICTimer* get_timer() const { return m_apic_timer; }
enum class TimerMode {
OneShot,
Periodic,
TSCDeadline
};
void setup_local_timer(u32, TimerMode, bool);
u32 get_timer_current_count();
u32 get_timer_divisor();
private:
struct ICRReg {
enum DeliveryMode {
Fixed = 0x0,
LowPriority = 0x1,
SMI = 0x2,
NMI = 0x4,
INIT = 0x5,
StartUp = 0x6,
};
enum DestinationMode {
Physical = 0x0,
Logical = 0x1,
};
enum Level {
DeAssert = 0x0,
Assert = 0x1
};
enum class TriggerMode {
Edge = 0x0,
Level = 0x1,
};
enum DestinationShorthand {
NoShorthand = 0x0,
Self = 0x1,
AllIncludingSelf = 0x2,
AllExcludingSelf = 0x3,
};
u8 vector { 0 };
u32 destination { 0 };
DeliveryMode delivery_mode { DeliveryMode::Fixed };
DestinationMode destination_mode { DestinationMode::Physical };
Level level { Level::DeAssert };
TriggerMode trigger_mode { TriggerMode::Edge };
DestinationShorthand destination_short { DestinationShorthand::NoShorthand };
u32 x_low() const { return (u32)vector | (delivery_mode << 8) | (destination_mode << 11) | (level << 14) | (static_cast<u32>(trigger_mode) << 15) | (destination_short << 18); }
u32 x_high() const { return destination << 24; }
u64 x2_value() const { return ((u64)destination << 32) | x_low(); }
};
OwnPtr<Memory::Region> m_apic_base;
Vector<OwnPtr<Processor>> m_ap_processor_info;
Vector<OwnPtr<Memory::Region>> m_ap_temporary_boot_stacks;
Vector<Thread*> m_ap_idle_threads;
OwnPtr<Memory::Region> m_ap_boot_environment;
Atomic<u8> m_apic_ap_count { 0 };
Atomic<u8> m_apic_ap_continue { 0 };
u32 m_processor_cnt { 0 };
u32 m_processor_enabled_cnt { 0 };
APICTimer* m_apic_timer { nullptr };
SetOnce m_is_x2;
static PhysicalAddress get_base();
void set_base(PhysicalAddress const& base);
void write_register(u32 offset, u32 value);
u32 read_register(u32 offset);
void set_lvt(u32 offset, u8 interrupt);
void set_siv(u32 offset, u8 interrupt);
void wait_for_pending_icr();
void write_icr(ICRReg const& icr);
void do_boot_aps();
};
}