Compare commits

...

2 Commits

Author SHA1 Message Date
Bananymous 7ef751ba95 Kernel: Fix multiprocessor for i686
i686 is now actually ran with multiple processors.
2024-04-03 14:42:17 +03:00
Bananymous f8c01418b1 Kernel: Fix multiprocessing on x86_64
I did not even start APs after initializing them... :D
2024-04-03 14:21:55 +03:00
10 changed files with 153 additions and 124 deletions

View File

@ -1,3 +1,57 @@
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
.global asm_syscall_handler
asm_syscall_handler:
# save segment registers
pushw %ds
pushw %es
pushw %fs
pushw %gs
# save general purpose registers
pushl %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
# align stack and push arguments
pushl %esp
addl $32, (%esp)
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
# load kernel segments
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw $0x28, %ax
movw %ax, %gs
call cpp_syscall_handler
addl $28, %esp
# restore general purpose registers
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
# restore segment registers
popw %gs
popw %fs
popw %es
popw %ds
iret
.global sys_fork_trampoline .global sys_fork_trampoline
sys_fork_trampoline: sys_fork_trampoline:
pushl %ebp pushl %ebp

View File

@ -24,22 +24,6 @@
popw %gs popw %gs
.endm .endm
.macro pop_userspace_skip_eax
popl %edi
popl %esi
popl %ebp
addl $4, %esp
popl %ebx
popl %edx
popl %ecx
addl $4, %esp
popw %ds
popw %es
popw %fs
popw %gs
.endm
isr_stub: isr_stub:
push_userspace push_userspace
load_kernel_segments load_kernel_segments
@ -81,46 +65,21 @@ irq_stub:
addl $8, %esp addl $8, %esp
iret iret
.global asm_reschedule_handler .global asm_yield_handler
asm_reschedule_handler: asm_yield_handler:
push_userspace # This can only be called from kernel, so no segment saving is needed
load_kernel_segments pushal
movl %esp, %eax # interrupt registers ptr movl %esp, %eax # interrupt registers ptr
leal 40(%esp), %ebx # interrupt stack ptr leal 32(%esp), %ebx # interrupt stack ptr
subl $12, %esp subl $4, %esp
pushl %eax pushl %eax
pushl %ebx pushl %ebx
call cpp_reschedule_handler call cpp_yield_handler
addl $20, %esp addl $12, %esp
pop_userspace popal
iret
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
.global syscall_asm
syscall_asm:
push_userspace
subl $8, %esp
pushl %esp
addl $48, (%esp)
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
load_kernel_segments
call cpp_syscall_handler
addl $36, %esp
pop_userspace_skip_eax
iret iret
.macro isr n .macro isr n
@ -211,3 +170,4 @@ irq 28
irq 29 irq 29
irq 30 irq 30
irq 31 irq 31
irq 32

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

@ -8,7 +8,8 @@
#include <stdint.h> #include <stdint.h>
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,11 @@ 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));
ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
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 +349,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 +356,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 +403,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 +421,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();
} }