Kernel: Fix multiprocessing on x86_64

I did not even start APs after initializing them... :D
This commit is contained in:
2024-04-03 14:21:55 +03:00
parent 731330c6b5
commit f8c01418b1
8 changed files with 88 additions and 74 deletions

View File

@@ -10,7 +10,7 @@
#include <kernel/Timer/PIT.h>
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) X(32)
namespace Kernel
{
@@ -329,8 +329,10 @@ done:
return;
}
extern "C" void cpp_reschedule_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
{
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD));
Processor::enter_interrupt(interrupt_stack, interrupt_registers);
Scheduler::get().irq_reschedule();
Processor::leave_interrupt();
@@ -346,8 +348,6 @@ done:
asm volatile("cli; 1: hlt; jmp 1b");
}
ASSERT(irq != IRQ_IPI);
if (!InterruptController::get().is_in_service(irq))
dprintln("spurious irq 0x{2H}", irq);
else
@@ -355,6 +355,8 @@ done:
InterruptController::get().eoi(irq);
if (auto* handler = s_interruptables[irq])
handler->handle_irq();
else if (irq == IRQ_IPI)
Scheduler::get().yield();
else
dprintln("no handler for irq 0x{2H}", irq);
}
@@ -400,8 +402,8 @@ done:
IRQ_LIST_X
#undef X
extern "C" void asm_reschedule_handler();
extern "C" void syscall_asm();
extern "C" void asm_yield_handler();
extern "C" void asm_syscall_handler();
IDT* IDT::create()
{
@@ -418,9 +420,9 @@ done:
IRQ_LIST_X
#undef X
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_IPI, asm_reschedule_handler);
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_YIELD, asm_yield_handler);
idt->register_syscall_handler(0x80, syscall_asm);
idt->register_syscall_handler(0x80, asm_syscall_handler);
return idt;
}

View File

@@ -12,7 +12,6 @@ namespace Kernel
{
static Scheduler* s_instance = nullptr;
static BAN::Atomic<bool> s_started { false };
BAN::ErrorOr<void> Scheduler::initialize()
{
@@ -33,13 +32,12 @@ namespace Kernel
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
ASSERT(!m_active_threads.empty());
yield();
ASSERT_NOT_REACHED();
}
bool Scheduler::is_started()
{
return s_started;
// broadcast ipi (yield) for each processor
InterruptController::get().broadcast_ipi();
yield();
ASSERT_NOT_REACHED();
}
Thread& Scheduler::current_thread()
@@ -122,20 +120,21 @@ namespace Kernel
void Scheduler::timer_reschedule()
{
// Broadcast IPI to all other processors for them
// to perform reschedule
InterruptController::get().broadcast_ipi();
{
SpinLockGuard _(m_lock);
m_blocking_threads.remove_with_wake_time(m_active_threads, SystemTimer::get().ms_since_boot());
}
// Broadcast IPI to all other processors for them
// to perform reschedule
InterruptController::get().broadcast_ipi();
yield();
}
void Scheduler::yield()
{
ASSERT(!m_lock.current_processor_has_lock());
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
@@ -143,24 +142,24 @@ namespace Kernel
asm volatile(
"movq %%rsp, %%rcx;"
"movq %[load_sp], %%rsp;"
"int %[ipi];"
"int %[yield];"
"movq %%rcx, %%rsp;"
// NOTE: This is offset by 2 pointers since interrupt without PL change
// does not push SP and SS. This allows accessing "whole" interrupt stack.
:: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)),
[ipi]"i"(IRQ_VECTOR_BASE + IRQ_IPI)
[yield]"i"(IRQ_VECTOR_BASE + IRQ_YIELD)
: "memory", "rcx"
);
#elif ARCH(i686)
asm volatile(
"movl %%esp, %%ecx;"
"movl %[load_sp], %%esp;"
"int %[ipi];"
"int %[yield];"
"movl %%ecx, %%esp;"
// NOTE: This is offset by 2 pointers since interrupt without PL change
// does not push SP and SS. This allows accessing "whole" interrupt stack.
:: [load_sp]"r"(Processor::current_stack_top() - 2 * sizeof(uintptr_t)),
[ipi]"i"(IRQ_VECTOR_BASE + IRQ_IPI)
[yield]"i"(IRQ_VECTOR_BASE + IRQ_YIELD)
: "memory", "ecx"
);
#else

View File

@@ -265,7 +265,7 @@ namespace Kernel
m_interrupt_stack.ip = reinterpret_cast<vaddr_t>(start_kernel_thread);
m_interrupt_stack.cs = 0x08;
m_interrupt_stack.flags = 0x202;
m_interrupt_stack.flags = 0x002;
m_interrupt_stack.sp = kernel_stack_top() - 4 * sizeof(uintptr_t);
m_interrupt_stack.ss = 0x10;

View File

@@ -218,7 +218,9 @@ extern "C" void ap_main()
dprintln("ap{} initialized", Processor::current_id());
while (!Scheduler::is_started())
__builtin_ia32_pause();
Scheduler::get().start();
// wait until scheduler is started and we get irq for reschedule
Processor::set_interrupt_state(InterruptState::Enabled);
while (true)
asm volatile("hlt");
ASSERT_NOT_REACHED();
}