1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 17:57:35 +00:00

Kernel: Implement software context switching and Processor structure

Moving certain globals into a new Processor structure for
each CPU allows us to eventually run an instance of the
scheduler on each CPU.
This commit is contained in:
Tom 2020-06-27 13:42:28 -06:00 committed by Andreas Kling
parent 10407061d2
commit fb41d89384
22 changed files with 1002 additions and 513 deletions

View file

@ -106,6 +106,14 @@ union [[gnu::packed]] Descriptor
TrapGate_32bit = 0xf,
};
void* get_base() const
{
u32 b = base_lo;
b |= base_hi << 16;
b |= base_hi2 << 24;
return reinterpret_cast<void*>(b);
}
void set_base(void* b)
{
base_lo = (u32)(b)&0xffff;
@ -256,8 +264,6 @@ struct RegisterState;
const DescriptorTablePointer& get_gdtr();
const DescriptorTablePointer& get_idtr();
void gdt_init();
void idt_init();
void sse_init();
void register_interrupt_handler(u8 number, void (*f)());
void register_user_callable_interrupt_handler(u8 number, void (*f)());
@ -267,12 +273,7 @@ void replace_single_handler_with_shared(GenericInterruptHandler&);
void replace_shared_handler_with_single(GenericInterruptHandler&);
void unregister_generic_interrupt_handler(u8 number, GenericInterruptHandler&);
void flush_idt();
void flush_gdt();
void load_task_register(u16 selector);
u16 gdt_alloc_entry();
void gdt_free_entry(u16);
Descriptor& get_gdt_entry(u16 selector);
void write_gdt_entry(u16 selector, Descriptor&);
void handle_crash(RegisterState&, const char* description, int signal, bool out_of_memory = false);
[[noreturn]] static inline void hang()
@ -303,6 +304,39 @@ inline u32 cpu_flags()
return flags;
}
inline void set_fs(u32 segment)
{
asm volatile(
"movl %%eax, %%fs" :: "a"(segment)
: "memory"
);
}
inline void set_gs(u32 segment)
{
asm volatile(
"movl %%eax, %%gs" :: "a"(segment)
: "memory"
);
}
inline u32 get_fs()
{
u32 fs;
asm("mov %%fs, %%eax"
: "=a"(fs));
return fs;
}
inline u32 get_gs()
{
u32 gs;
asm("mov %%gs, %%eax"
: "=a"(gs));
return gs;
}
inline u32 read_fs_u32(u32 offset)
{
u32 val;
@ -460,6 +494,9 @@ struct [[gnu::packed]] RegisterState
u32 userspace_ss;
};
#define REGISTER_STATE_SIZE (19 * 4)
static_assert(REGISTER_STATE_SIZE == sizeof(RegisterState));
struct [[gnu::aligned(16)]] FPUState
{
u8 buffer[512];
@ -492,6 +529,15 @@ u32 read_cr4();
u32 read_dr6();
static inline bool is_kernel_mode()
{
u32 cs;
asm volatile (
"movl %%cs, %[cs] \n"
: [cs] "=g" (cs));
return (cs & 3) == 0;
}
class CPUID {
public:
CPUID(u32 function) { asm volatile("cpuid"
@ -552,6 +598,94 @@ private:
SplitQword m_start;
};
class Thread;
struct TrapFrame;
#define GDT_SELECTOR_CODE0 0x08
#define GDT_SELECTOR_DATA0 0x10
#define GDT_SELECTOR_CODE3 0x18
#define GDT_SELECTOR_DATA3 0x20
#define GDT_SELECTOR_TLS 0x28
#define GDT_SELECTOR_PROC 0x30
#define GDT_SELECTOR_TSS 0x38
class Processor {
Processor* m_self; // must be first field (%fs offset 0x0)
DescriptorTablePointer m_gdtr;
Descriptor m_gdt[256];
u32 m_gdt_length;
u32 m_cpu;
u32 m_in_irq;
TSS32 m_tss;
static FPUState s_clean_fpu_state;
bool m_invoke_scheduler_async;
void gdt_init();
void write_raw_gdt_entry(u16 selector, u32 low, u32 high);
void write_gdt_entry(u16 selector, Descriptor& descriptor);
public:
void initialize(u32 cpu);
Descriptor& get_gdt_entry(u16 selector);
void flush_gdt();
const DescriptorTablePointer& get_gdtr();
ALWAYS_INLINE static Processor& current()
{
return *(Processor*)read_fs_u32(0);
}
ALWAYS_INLINE static u32 id()
{
return current().m_cpu;
}
ALWAYS_INLINE u32& in_irq()
{
return m_in_irq;
}
ALWAYS_INLINE const FPUState& clean_fpu_state() const
{
return s_clean_fpu_state;
}
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);
void switch_context(Thread* from_thread, Thread* to_thread);
[[noreturn]] static void assume_context(Thread& thread);
static u32 init_context(Thread& thread);
void set_thread_specific(u8* data, size_t len);
};
struct TrapFrame {
u32 prev_irq_level;
RegisterState* regs; // must be last
TrapFrame() = delete;
TrapFrame(const TrapFrame&) = delete;
TrapFrame(TrapFrame&&) = delete;
TrapFrame& operator=(const TrapFrame&) = delete;
TrapFrame& operator=(TrapFrame&&) = delete;
};
#define TRAP_FRAME_SIZE (2 * 4)
static_assert(TRAP_FRAME_SIZE == sizeof(TrapFrame));
extern "C" void enter_trap_no_irq(TrapFrame*);
extern "C" void enter_trap(TrapFrame*);
extern "C" void exit_trap(TrapFrame*);
class MSR {
uint32_t m_msr;
@ -583,7 +717,8 @@ public:
}
};
void cpu_setup();
void cpu_setup(u32 cpu);
extern bool g_cpu_supports_nx;
extern bool g_cpu_supports_pae;
extern bool g_cpu_supports_pge;
@ -629,6 +764,4 @@ private:
u32 m_flags;
};
extern u32 g_in_irq;
}