summaryrefslogtreecommitdiff
path: root/Kernel/Arch/i386/CPU.h
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/Arch/i386/CPU.h')
-rw-r--r--Kernel/Arch/i386/CPU.h153
1 files changed, 126 insertions, 27 deletions
diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h
index 1c53a48660..60f92e6786 100644
--- a/Kernel/Arch/i386/CPU.h
+++ b/Kernel/Arch/i386/CPU.h
@@ -26,6 +26,7 @@
#pragma once
+#include <AK/Atomic.h>
#include <AK/Badge.h>
#include <AK/Noncopyable.h>
#include <AK/Vector.h>
@@ -33,7 +34,7 @@
#include <Kernel/VirtualAddress.h>
#define PAGE_SIZE 4096
-#define GENERIC_INTERRUPT_HANDLERS_COUNT 128
+#define GENERIC_INTERRUPT_HANDLERS_COUNT (256 - IRQ_VECTOR_BASE)
#define PAGE_MASK ((FlatPtr)0xfffff000u)
namespace Kernel {
@@ -276,13 +277,6 @@ void flush_idt();
void load_task_register(u16 selector);
void handle_crash(RegisterState&, const char* description, int signal, bool out_of_memory = false);
-[[noreturn]] static inline void hang()
-{
- asm volatile("cli; hlt");
- for (;;) {
- }
-}
-
#define LSW(x) ((u32)(x)&0xFFFF)
#define MSW(x) (((u32)(x) >> 16) & 0xFFFF)
#define LSB(x) ((x)&0xFF)
@@ -307,20 +301,17 @@ inline u32 cpu_flags()
inline void set_fs(u32 segment)
{
asm volatile(
- "movl %%eax, %%fs" :: "a"(segment)
- : "memory"
- );
+ "movl %%eax, %%fs" ::"a"(segment)
+ : "memory");
}
inline void set_gs(u32 segment)
{
asm volatile(
- "movl %%eax, %%gs" :: "a"(segment)
- : "memory"
- );
+ "movl %%eax, %%gs" ::"a"(segment)
+ : "memory");
}
-
inline u32 get_fs()
{
u32 fs;
@@ -532,9 +523,9 @@ u32 read_dr6();
static inline bool is_kernel_mode()
{
u32 cs;
- asm volatile (
+ asm volatile(
"movl %%cs, %[cs] \n"
- : [cs] "=g" (cs));
+ : [ cs ] "=g"(cs));
return (cs & 3) == 0;
}
@@ -624,10 +615,48 @@ struct TrapFrame;
class ProcessorInfo;
struct MemoryManagerData;
+struct ProcessorMessageEntry;
+
+struct ProcessorMessage {
+ enum Type {
+ FlushTlb,
+ Callback,
+ CallbackWithData
+ };
+ Type type;
+ volatile u32 refs; // atomic
+ union {
+ ProcessorMessage* next; // only valid while in the pool
+ struct {
+ void (*handler)();
+ } callback;
+ struct {
+ void* data;
+ void (*handler)(void*);
+ void (*free)(void*);
+ } callback_with_data;
+ struct {
+ u8* ptr;
+ size_t page_count;
+ } flush_tlb;
+ };
+
+ volatile bool async;
+
+ ProcessorMessageEntry* per_proc_entries;
+};
+
+struct ProcessorMessageEntry {
+ ProcessorMessageEntry* next;
+ ProcessorMessage* msg;
+};
class Processor {
friend class ProcessorInfo;
+ AK_MAKE_NONCOPYABLE(Processor);
+ AK_MAKE_NONMOVABLE(Processor);
+
Processor* m_self; // must be first field (%fs offset 0x0)
DescriptorTablePointer m_gdtr;
@@ -641,48 +670,85 @@ class Processor {
TSS32 m_tss;
static FPUState s_clean_fpu_state;
CPUFeature m_features;
+ static volatile u32 g_total_processors; // atomic
ProcessorInfo* m_info;
MemoryManagerData* m_mm_data;
Thread* m_current_thread;
Thread* m_idle_thread;
+ volatile ProcessorMessageEntry* m_message_queue; // atomic, LIFO
+
bool m_invoke_scheduler_async;
bool m_scheduler_initialized;
+ bool m_halt_requested;
void gdt_init();
void write_raw_gdt_entry(u16 selector, u32 low, u32 high);
void write_gdt_entry(u16 selector, Descriptor& descriptor);
static Vector<Processor*>& processors();
+ static void smp_return_to_pool(ProcessorMessage& msg);
+ static ProcessorMessage& smp_get_from_pool();
+ static void smp_cleanup_message(ProcessorMessage& msg);
+ bool smp_queue_message(ProcessorMessage& msg);
+ static void smp_broadcast_message(ProcessorMessage& msg, bool async);
+ static void smp_broadcast_halt();
+
void cpu_detect();
void cpu_setup();
String features_string() const;
public:
+ Processor() = default;
+
void early_initialize(u32 cpu);
void initialize(u32 cpu);
+ static u32 count()
+ {
+ // NOTE: because this value never changes once all APs are booted,
+ // we don't really need to do an atomic_load() on this variable
+ return g_total_processors;
+ }
+
+ ALWAYS_INLINE static void wait_check()
+ {
+ Processor::current().smp_process_pending_messages();
+ // TODO: pause
+ }
+
+ [[noreturn]] static void halt();
+
+ static void flush_entire_tlb_local()
+ {
+ write_cr3(read_cr3());
+ }
+
+ static void flush_tlb_local(VirtualAddress vaddr, size_t page_count);
+ static void flush_tlb(VirtualAddress vaddr, size_t page_count);
+
Descriptor& get_gdt_entry(u16 selector);
void flush_gdt();
const DescriptorTablePointer& get_gdtr();
static Processor& by_id(u32 cpu);
- template <typename Callback>
+ template<typename Callback>
static inline IterationDecision for_each(Callback callback)
{
auto& procs = processors();
- for (auto it = procs.begin(); it != procs.end(); ++it) {
- if (callback(**it) == IterationDecision::Break)
+ size_t count = procs.size();
+ for (size_t i = 0; i < count; i++) {
+ if (callback(*procs[i]) == IterationDecision::Break)
return IterationDecision::Break;
}
return IterationDecision::Continue;
}
-
+
ALWAYS_INLINE ProcessorInfo& info() { return *m_info; }
-
+
ALWAYS_INLINE static Processor& current()
{
return *(Processor*)read_fs_u32(0);
@@ -729,19 +795,30 @@ public:
{
return m_cpu;
}
-
+
+ ALWAYS_INLINE u32 raise_irq()
+ {
+ return m_in_irq++;
+ }
+
+ ALWAYS_INLINE void restore_irq(u32 prev_irq)
+ {
+ ASSERT(prev_irq <= m_in_irq);
+ m_in_irq = prev_irq;
+ }
+
ALWAYS_INLINE u32& in_irq()
{
return m_in_irq;
}
-
+
ALWAYS_INLINE void enter_critical(u32& prev_flags)
{
m_in_critical++;
prev_flags = cpu_flags();
cli();
}
-
+
ALWAYS_INLINE void leave_critical(u32 prev_flags)
{
ASSERT(m_in_critical > 0);
@@ -754,7 +831,7 @@ public:
else
cli();
}
-
+
ALWAYS_INLINE u32 clear_critical(u32& prev_flags, bool enable_interrupts)
{
u32 prev_crit = m_in_critical;
@@ -766,7 +843,7 @@ public:
sti();
return prev_crit;
}
-
+
ALWAYS_INLINE void restore_critical(u32 prev_crit, u32 prev_flags)
{
ASSERT(m_in_critical == 0);
@@ -784,6 +861,27 @@ public:
return s_clean_fpu_state;
}
+ static void smp_enable();
+ bool smp_process_pending_messages();
+
+ template<typename Callback>
+ static void smp_broadcast(Callback callback, bool async)
+ {
+ auto* data = new Callback(move(callback));
+ smp_broadcast(
+ [](void* data) {
+ (*reinterpret_cast<Callback*>(data))();
+ },
+ data,
+ [](void* data) {
+ delete reinterpret_cast<Callback*>(data);
+ },
+ async);
+ }
+ static void smp_broadcast(void (*callback)(), bool async);
+ static void smp_broadcast(void (*callback)(void*), void* data, void (*free_data)(void*), bool async);
+ static void smp_broadcast_flush_tlb(VirtualAddress vaddr, size_t page_count);
+
ALWAYS_INLINE bool has_feature(CPUFeature f) const
{
return (static_cast<u32>(m_features) & static_cast<u32>(f)) != 0;
@@ -793,6 +891,7 @@ public:
void invoke_scheduler_async() { m_invoke_scheduler_async = true; }
void enter_trap(TrapFrame& trap, bool raise_irq);
+
void exit_trap(TrapFrame& trap);
[[noreturn]] void initialize_context_switching(Thread& initial_thread);