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
sys_fork_trampoline:
pushl %ebp

View File

@ -24,22 +24,6 @@
popw %gs
.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:
push_userspace
load_kernel_segments
@ -81,46 +65,21 @@ irq_stub:
addl $8, %esp
iret
.global asm_reschedule_handler
asm_reschedule_handler:
push_userspace
load_kernel_segments
.global asm_yield_handler
asm_yield_handler:
# This can only be called from kernel, so no segment saving is needed
pushal
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 %ebx
call cpp_reschedule_handler
addl $20, %esp
call cpp_yield_handler
addl $12, %esp
pop_userspace
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
popal
iret
.macro isr n
@ -211,3 +170,4 @@ irq 28
irq 29
irq 30
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
sys_fork_trampoline:
pushq %rbx

View File

@ -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

View File

@ -8,7 +8,8 @@
#include <stdint.h>
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
{

View File

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

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,11 @@ 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));
ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
Processor::enter_interrupt(interrupt_stack, interrupt_registers);
Scheduler::get().irq_reschedule();
Processor::leave_interrupt();
@ -346,8 +349,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 +356,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 +403,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 +421,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();
}