Kernel: Fix multiprocessing on x86_64

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

View File

@ -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 .global sys_fork_trampoline
sys_fork_trampoline: sys_fork_trampoline:
pushq %rbx pushq %rbx

View File

@ -34,23 +34,6 @@
popq %rax popq %rax
.endm .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: isr_stub:
pushaq pushaq
@ -78,6 +61,15 @@ irq_stub:
addq $16, %rsp addq $16, %rsp
iretq 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 .macro isr n
.global isr\n .global isr\n
isr\n: isr\n:
@ -166,31 +158,4 @@ irq 28
irq 29 irq 29
irq 30 irq 30
irq 31 irq 31
irq 32
.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

View File

@ -9,6 +9,7 @@
constexpr uint8_t IRQ_VECTOR_BASE = 0x20; 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 namespace Kernel
{ {

View File

@ -12,7 +12,6 @@ namespace Kernel
public: public:
static BAN::ErrorOr<void> initialize(); static BAN::ErrorOr<void> initialize();
static Scheduler& get(); static Scheduler& get();
static bool is_started();
[[noreturn]] void start(); [[noreturn]] void start();

View File

@ -10,7 +10,7 @@
#include <kernel/Timer/PIT.h> #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 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 namespace Kernel
{ {
@ -329,8 +329,10 @@ done:
return; 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); Processor::enter_interrupt(interrupt_stack, interrupt_registers);
Scheduler::get().irq_reschedule(); Scheduler::get().irq_reschedule();
Processor::leave_interrupt(); Processor::leave_interrupt();
@ -346,8 +348,6 @@ done:
asm volatile("cli; 1: hlt; jmp 1b"); asm volatile("cli; 1: hlt; jmp 1b");
} }
ASSERT(irq != IRQ_IPI);
if (!InterruptController::get().is_in_service(irq)) if (!InterruptController::get().is_in_service(irq))
dprintln("spurious irq 0x{2H}", irq); dprintln("spurious irq 0x{2H}", irq);
else else
@ -355,6 +355,8 @@ done:
InterruptController::get().eoi(irq); InterruptController::get().eoi(irq);
if (auto* handler = s_interruptables[irq]) if (auto* handler = s_interruptables[irq])
handler->handle_irq(); handler->handle_irq();
else if (irq == IRQ_IPI)
Scheduler::get().yield();
else else
dprintln("no handler for irq 0x{2H}", irq); dprintln("no handler for irq 0x{2H}", irq);
} }
@ -400,8 +402,8 @@ done:
IRQ_LIST_X IRQ_LIST_X
#undef X #undef X
extern "C" void asm_reschedule_handler(); extern "C" void asm_yield_handler();
extern "C" void syscall_asm(); extern "C" void asm_syscall_handler();
IDT* IDT::create() IDT* IDT::create()
{ {
@ -418,9 +420,9 @@ done:
IRQ_LIST_X IRQ_LIST_X
#undef 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; return idt;
} }

View File

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

View File

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

View File

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