From f8c01418b1736b47df7b062989d793d6ae36ebeb Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 3 Apr 2024 14:21:55 +0300 Subject: [PATCH] Kernel: Fix multiprocessing on x86_64 I did not even start APs after initializing them... :D --- kernel/arch/x86_64/Syscall.S | 46 ++++++++++++++++++++++++++ kernel/arch/x86_64/interrupts.S | 55 ++++++------------------------- kernel/include/kernel/IDT.h | 3 +- kernel/include/kernel/Scheduler.h | 1 - kernel/kernel/IDT.cpp | 18 +++++----- kernel/kernel/Scheduler.cpp | 29 ++++++++-------- kernel/kernel/Thread.cpp | 2 +- kernel/kernel/kernel.cpp | 8 +++-- 8 files changed, 88 insertions(+), 74 deletions(-) diff --git a/kernel/arch/x86_64/Syscall.S b/kernel/arch/x86_64/Syscall.S index 91cc85fd..878e24c6 100644 --- a/kernel/arch/x86_64/Syscall.S +++ b/kernel/arch/x86_64/Syscall.S @@ -1,3 +1,49 @@ +// arguments in RAX, RBX, RCX, RDX, RSI, RDI +// System V ABI: RDI, RSI, RDX, RCX, R8, R9 +.global asm_syscall_handler +asm_syscall_handler: + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rdi + pushq %rsi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + movq %rsi, %r8 + movq %rdi, %r9 + movq %rax, %rdi + movq %rbx, %rsi + xchgq %rcx, %rdx + leaq 112(%rsp), %rbx + pushq %rbx + call cpp_syscall_handler + addq $8, %rsp + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rbp + popq %rsi + popq %rdi + popq %rdx + popq %rcx + popq %rbx + iretq + + .global sys_fork_trampoline sys_fork_trampoline: pushq %rbx diff --git a/kernel/arch/x86_64/interrupts.S b/kernel/arch/x86_64/interrupts.S index 7d3e5f4d..3d01e09b 100644 --- a/kernel/arch/x86_64/interrupts.S +++ b/kernel/arch/x86_64/interrupts.S @@ -34,23 +34,6 @@ popq %rax .endm -.macro popaq_no_rax - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %r11 - popq %r10 - popq %r9 - popq %r8 - popq %rdi - popq %rsi - popq %rbp - popq %rbx - popq %rdx - popq %rcx -.endm - isr_stub: pushaq @@ -78,6 +61,15 @@ irq_stub: addq $16, %rsp iretq +.global asm_yield_handler +asm_yield_handler: + pushaq + leaq 120(%rsp), %rdi # interrupt stack ptr + movq %rsp, %rsi # interrupt register ptr + call cpp_yield_handler + popaq + iretq + .macro isr n .global isr\n isr\n: @@ -166,31 +158,4 @@ irq 28 irq 29 irq 30 irq 31 - -.global asm_reschedule_handler -asm_reschedule_handler: - pushaq - leaq 120(%rsp), %rdi # interrupt stack ptr - movq %rsp, %rsi # interrupt register ptr - call cpp_reschedule_handler - popaq - iretq - -// arguments in RAX, RBX, RCX, RDX, RSI, RDI -// System V ABI: RDI, RSI, RDX, RCX, R8, R9 -.global syscall_asm -syscall_asm: - pushaq - movq %rsi, %r8 - movq %rdi, %r9 - movq %rax, %rdi - movq %rbx, %rsi - xchgq %rcx, %rdx - movq %rsp, %rbx - addq $120, %rbx - pushq %rbx - call cpp_syscall_handler - addq $8, %rsp - popaq_no_rax - addq $8, %rsp - iretq +irq 32 diff --git a/kernel/include/kernel/IDT.h b/kernel/include/kernel/IDT.h index 1c8b9db4..c66b223b 100644 --- a/kernel/include/kernel/IDT.h +++ b/kernel/include/kernel/IDT.h @@ -8,7 +8,8 @@ #include constexpr uint8_t IRQ_VECTOR_BASE = 0x20; -constexpr uint8_t IRQ_IPI = 32; +constexpr uint8_t IRQ_IPI = 32; +constexpr uint8_t IRQ_YIELD = 33; namespace Kernel { diff --git a/kernel/include/kernel/Scheduler.h b/kernel/include/kernel/Scheduler.h index 2784d269..bd0a75ed 100644 --- a/kernel/include/kernel/Scheduler.h +++ b/kernel/include/kernel/Scheduler.h @@ -12,7 +12,6 @@ namespace Kernel public: static BAN::ErrorOr initialize(); static Scheduler& get(); - static bool is_started(); [[noreturn]] void start(); diff --git a/kernel/kernel/IDT.cpp b/kernel/kernel/IDT.cpp index 434aef33..20900ee3 100644 --- a/kernel/kernel/IDT.cpp +++ b/kernel/kernel/IDT.cpp @@ -10,7 +10,7 @@ #include #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; } diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 5f8aa573..bd67ba4b 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -12,7 +12,6 @@ namespace Kernel { static Scheduler* s_instance = nullptr; - static BAN::Atomic s_started { false }; BAN::ErrorOr 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 diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 12fd4589..443531ed 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -265,7 +265,7 @@ namespace Kernel m_interrupt_stack.ip = reinterpret_cast(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; diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index c9f85c8f..0bfc7fba 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -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(); }