diff --git a/include/menix/system/arch.h b/include/menix/system/arch.h index 4998b17..a106d77 100644 --- a/include/menix/system/arch.h +++ b/include/menix/system/arch.h @@ -15,28 +15,28 @@ #ifdef ARCH_HAS_DYNAMIC_PAGE_SIZE extern usize arch_page_size; #else -#define arch_page_size ((usize)(0x1000)) +#define arch_page_size ((usize)(ARCH_DEFAULT_PAGE_SIZE)) #endif // CPU-local information. -typedef struct [[gnu::aligned(arch_page_size)]] Cpu +typedef struct [[gnu::aligned(ARCH_DEFAULT_PAGE_SIZE)]] CpuInfo { - usize id; // Unique ID of this CPU. - usize kernel_stack; // Stack pointer for the kernel. - usize user_stack; // Stack pointer for the user space. - struct Thread* thread; // Current thread running on this CPU. - usize ticks_active; // The amount of ticks the running thread has been active. - bool is_present; // If the CPU is present. - InterruptFn irq_handlers[256]; // IRQ handlers. - void* irq_data[256]; // IRQ context to pass along. + usize id; // Unique ID of this CPU. + usize kernel_stack; // Stack pointer for the kernel. + usize user_stack; // Stack pointer for the user space. + struct Thread* thread; // Current thread running on this CPU. + usize ticks_active; // The amount of ticks the running thread has been active. + bool is_present; // If the CPU is present. #ifdef __x86_64__ - Gdt gdt; - TaskStateSegment tss; - u32 lapic_id; // Local APIC ID. - usize fpu_size; // Size of the FPU in bytes. - void (*fpu_save)(void* dst); // Function to call when saving the FPU state. - void (*fpu_restore)(void* dst); // Function to call when restoring the FPU state. + Gdt gdt; // Global Descriptor Table. + TaskStateSegment tss; // Task state segment. + IdtCallbackFn idt_callbacks[IDT_SIZE]; // IDT handlers. + Irq idt_to_irq_map[IDT_SIZE]; // ISR to IRQ mapping. + u32 lapic_id; // Local APIC ID. + usize fpu_size; // Size of the FPU in bytes. + void (*fpu_save)(void* dst); // Function to call when saving the FPU state. + void (*fpu_restore)(void* dst); // Function to call when restoring the FPU state. #elif defined(__riscv) && (__riscv_xlen == 64) u32 hart_id; // Hart CPU ID. #endif @@ -65,7 +65,8 @@ bool arch_stop_cpu(usize id); // Writes all registers to the current output stream. void arch_dump_registers(Context* regs); -// Gets processor metadata. +// Gets processor local information. +// ! Extremely unsafe to call directly, 99% of the time you want to call sch_acquire_percpu()! CpuInfo* arch_current_cpu(); typedef enum : usize diff --git a/include/menix/system/interrupts.h b/include/menix/system/interrupts.h index 6e5beaa..b410751 100644 --- a/include/menix/system/interrupts.h +++ b/include/menix/system/interrupts.h @@ -1,19 +1,50 @@ -// Function prototypes for interrupts +// Interrupt handling #pragma once #include +#include +typedef usize Irq; typedef struct Context Context; -typedef Context* (*InterruptFn)(usize isr, Context* regs, void* priv); -// Handler called by the processor. -Context* int_handler(usize isr, Context* regs); +typedef enum +{ + IrqIgnored = 0, // Interrupt was not handled. + IrqHandled = (1 << 0), // Handler completed the IRQ work. + IrqWake = (1 << 1), // Handler wants to wake up the handler thread. +} IrqStatus; -// Registers a new IRQ handler. Automatically selects optimal IRQ placement. -// You can also pass an additional parameter for context passed to the handler. -// Returns `true` upon success. -bool irq_allocate_handler(InterruptFn handler, void* data); +typedef enum +{ + IrqFlags_None = 0, +} IrqFlags; -// Internal function to register an interrupt handler at a specific ISR index on the current CPU. -bool isr_register_handler(usize cpu, usize idx, InterruptFn handler, void* data); +// An IRQ handler callback. +typedef IrqStatus (*IrqHandlerFn)(Irq irq, void* context); + +typedef struct IrqAction +{ + struct IrqAction* next; // Next action in the list. + Irq irq; // The IRQ number. + IrqFlags flags; // Flags for this action. + IrqHandlerFn handler; // Called directly to handle the IRQ. + IrqHandlerFn worker; // Function to call in a worker thread, if woken up by the handler. + struct Thread* thread; // The thread to execute the worker function on. + const char* name; // Name of the IRQ. + void* context; // A generic context to pass to the handler. +} IrqAction; + +extern IrqAction* irq_actions; + +// Platform independent handler that runs the given IRQ. To be called by architecture specific interrupt handlers. +void irq_generic_handler(Irq irq); + +// Registers a new IRQ handler. Automatically selects optimal CPU placement. +// Returns true upon success. +// `handler`: The main interrupt handler. Must not be NULL. +// `thread_handler`: The threaded handler. Optional. +// `flags`: Flags to control how this IRQ handler behaves. +// `name`: Name of this IRQ. +// `data`: Context to pass to the IRQ on invocation. +bool irq_allocate(IrqHandlerFn handler, IrqHandlerFn thread_handler, IrqFlags flags, const char* name, void* data); diff --git a/include/menix/system/sch/process.h b/include/menix/system/sch/process.h index 04fa218..56e89ca 100644 --- a/include/menix/system/sch/process.h +++ b/include/menix/system/sch/process.h @@ -57,6 +57,9 @@ typedef struct Process #define PROC_USER_INTERP_BASE 0x0000060000000000 +// The kernel process. +extern Process* proc_kernel; + // Creates a new process. Returns a reference to the newly created process. // `name`: Name of the process. // `state`: Which state the process should be initialized with. diff --git a/include/menix/system/sch/scheduler.h b/include/menix/system/sch/scheduler.h index f59d395..bae5919 100644 --- a/include/menix/system/sch/scheduler.h +++ b/include/menix/system/sch/scheduler.h @@ -7,12 +7,16 @@ extern Process* proc_list; extern Process* hanging_proc_list; - extern Thread* thread_list; extern Thread* hanging_thread_list; - extern Thread* sleeping_thread_list; +// Halts preemption of the current thread by the scheduler. +void sch_stop_preemption(); + +// Continues preemption of the current thread. +void sch_start_preemption(); + // Initializes the scheduler. void sch_init(VirtAddr entry_point); diff --git a/include/menix/system/sch/thread.h b/include/menix/system/sch/thread.h index 0aaa8a4..7f65387 100644 --- a/include/menix/system/sch/thread.h +++ b/include/menix/system/sch/thread.h @@ -49,7 +49,10 @@ void thread_set_errno(usize errno); // Creates a new thread in a process. // `parent`: The parent process of the new thread. -Thread* thread_create(Process* parent); +Thread* thread_new(Process* parent); + +// Creates a new kernel thread. +Thread* thread_create_kernel(Process* parent, VirtAddr start); // Sets up the context of a user thread. // `target`: The thread to set up. diff --git a/kernel/arch/x86_64/include/apic.h b/kernel/arch/x86_64/include/apic.h index 2ea7212..abf8174 100644 --- a/kernel/arch/x86_64/include/apic.h +++ b/kernel/arch/x86_64/include/apic.h @@ -32,4 +32,4 @@ void lapic_write(u32 register, u32 value); usize lapic_get_id(); // Handles an interrupt triggered by the timer. -Context* timer_handler(usize isr, Context* regs, void* data); +Context* timer_handler(usize isr, Context* regs); diff --git a/kernel/arch/x86_64/include/bits/arch.h b/kernel/arch/x86_64/include/bits/arch.h index 7cff0f5..1b9416d 100644 --- a/kernel/arch/x86_64/include/bits/arch.h +++ b/kernel/arch/x86_64/include/bits/arch.h @@ -5,6 +5,7 @@ #include #include +#include #include // CPUID Leaf 1 ECX diff --git a/kernel/arch/x86_64/include/bits/arch_defs.h b/kernel/arch/x86_64/include/bits/arch_defs.h index 3cd431e..d8eecc0 100644 --- a/kernel/arch/x86_64/include/bits/arch_defs.h +++ b/kernel/arch/x86_64/include/bits/arch_defs.h @@ -1,4 +1,4 @@ #pragma once -#define ARCH_BITS 64 -#define ARCH_MAX_PAGE_SIZE 0x1000 +#define ARCH_BITS 64 +#define ARCH_DEFAULT_PAGE_SIZE 0x1000 diff --git a/kernel/arch/x86_64/include/idt.h b/kernel/arch/x86_64/include/idt.h index 1764eb2..f7a68f3 100644 --- a/kernel/arch/x86_64/include/idt.h +++ b/kernel/arch/x86_64/include/idt.h @@ -6,7 +6,7 @@ #include -#define IDT_MAX_SIZE 256 +#define IDT_SIZE 256 #define IDT_GATE_INT 0xE #define IDT_GATE_TRAP 0xF #define IDT_TYPE(priv, gate) ((1 << 7) | (((priv) & 0x3) << 0x5) | ((gate) & 0xF)) @@ -16,7 +16,7 @@ typedef struct [[gnu::packed]] { u16 base_0_15; u16 selector; -#if ARCH_BITS >= 64 +#ifdef __x86_64__ Bits ist:2; Bits reserved:6; #else @@ -24,7 +24,7 @@ typedef struct [[gnu::packed]] #endif u8 type; u16 base_16_31; -#if ARCH_BITS >= 64 +#ifdef __x86_64__ u32 base_32_63; u32 reserved2; #endif @@ -41,6 +41,9 @@ typedef struct [[gnu::packed]] static_assert(sizeof(IdtRegister) == 10); +typedef struct Context Context; +typedef Context* (*IdtCallbackFn)(usize isr, Context* regs); + // Install the Interrupt Descriptor Table. void idt_init(); diff --git a/kernel/arch/x86_64/include/interrupts.h b/kernel/arch/x86_64/include/interrupts.h index 82dbf9f..16d7b42 100644 --- a/kernel/arch/x86_64/include/interrupts.h +++ b/kernel/arch/x86_64/include/interrupts.h @@ -2,7 +2,7 @@ #include -Context* interrupt_debug_handler(usize isr, Context* regs, void* data); -Context* interrupt_ud_handler(usize isr, Context* regs, void* data); -Context* interrupt_pf_handler(usize isr, Context* regs, void* data); -Context* syscall_handler(usize isr, Context* regs, void* data); +Context* interrupt_debug_handler(usize isr, Context* regs); +Context* interrupt_ud_handler(usize isr, Context* regs); +Context* interrupt_pf_handler(usize isr, Context* regs); +Context* syscall_handler(usize isr, Context* regs); diff --git a/kernel/arch/x86_64/memory/vm.c b/kernel/arch/x86_64/memory/vm.c index bff8168..1aaa6c5 100644 --- a/kernel/arch/x86_64/memory/vm.c +++ b/kernel/arch/x86_64/memory/vm.c @@ -439,10 +439,12 @@ Context* interrupt_pf_handler(usize isr, Context* regs, void* data) panic(); } + CpuInfo* info = arch_current_cpu(); + // TODO: Handle user page fault. - if (arch_current_cpu()) + if (info) { - Process* proc = arch_current_cpu()->thread->parent; + Process* proc = info->thread->parent; // If nothing can make the process recover, we have to put it out of its misery. proc_kill(proc, true); diff --git a/kernel/arch/x86_64/sch/thread.c b/kernel/arch/x86_64/sch/thread.c index 4533a6f..f59f38e 100644 --- a/kernel/arch/x86_64/sch/thread.c +++ b/kernel/arch/x86_64/sch/thread.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -77,7 +78,8 @@ void thread_arch_setup(Thread* target, VirtAddr start, bool is_user, VirtAddr st void thread_arch_destroy(Thread* thread) { kfree((void*)(thread->kernel_stack - VM_KERNEL_STACK_SIZE)); - pm_free(thread->saved_fpu - pm_get_phys_base(), ROUND_UP(arch_current_cpu()->fpu_size, arch_page_size)); + CpuInfo* info = arch_current_cpu(); + pm_free(thread->saved_fpu - pm_get_phys_base(), ROUND_UP(info->fpu_size, arch_page_size)); } void thread_arch_fork(Thread* forked, Thread* original) @@ -85,11 +87,12 @@ void thread_arch_fork(Thread* forked, Thread* original) forked->fs_base = original->fs_base; forked->gs_base = original->gs_base; + CpuInfo* cpu = arch_current_cpu(); + // Allocate FPU memory. - PhysAddr fpu_pages = pm_alloc(ROUND_UP(arch_current_cpu()->fpu_size, vm_get_page_size(VMLevel_Small))); + PhysAddr fpu_pages = pm_alloc(ROUND_UP(cpu->fpu_size, vm_get_page_size(VMLevel_Small))); forked->saved_fpu = pm_get_phys_base() + fpu_pages; - - memcpy(forked->saved_fpu, original->saved_fpu, arch_current_cpu()->fpu_size); + memcpy(forked->saved_fpu, original->saved_fpu, cpu->fpu_size); // Return SYSCALL_OK(0) to the forked syscall process. forked->registers.rax = 0; diff --git a/kernel/arch/x86_64/system/apic.c b/kernel/arch/x86_64/system/apic.c index 5ade81e..75e2838 100644 --- a/kernel/arch/x86_64/system/apic.c +++ b/kernel/arch/x86_64/system/apic.c @@ -12,6 +12,8 @@ #include #include +#include "menix/util/log.h" + static PhysAddr lapic_addr = 0; static bool has_x2apic = 0; u32 apic_ticks_in_10ms = 0; @@ -70,6 +72,7 @@ void lapic_init(usize cpu_id) else { // TODO + print_error("x86_64: No X2APIC found, this is currently unsupported!\n"); return; } @@ -115,7 +118,7 @@ void apic_send_eoi() lapic_write(0xB0, 0); } -Context* timer_handler(usize isr, Context* regs, void* data) +Context* timer_handler(usize isr, Context* regs) { Context* new_context = sch_reschedule(regs); apic_send_eoi(); diff --git a/kernel/arch/x86_64/system/arch.s b/kernel/arch/x86_64/system/arch.s index 4f82579..2987503 100644 --- a/kernel/arch/x86_64/system/arch.s +++ b/kernel/arch/x86_64/system/arch.s @@ -90,8 +90,8 @@ arch_int_\+: mov $\+, %rdi /* Load the ISR as first argument */ mov %rsp, %rsi /* Load the Context* as second argument. */ xor %rbp, %rbp - .extern int_handler - call int_handler + .extern idt_dispatcher + call idt_dispatcher mov %rax, %rsp /* int_handler returns a pointer to the new context. */ pop_all_regs swapgs_if_necessary diff --git a/kernel/arch/x86_64/system/idt.c b/kernel/arch/x86_64/system/idt.c index c822c02..98d38f5 100644 --- a/kernel/arch/x86_64/system/idt.c +++ b/kernel/arch/x86_64/system/idt.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -12,7 +13,7 @@ #include #include -[[gnu::aligned(0x1000)]] static IdtDesc idt_table[IDT_MAX_SIZE]; +[[gnu::aligned(0x1000)]] static IdtDesc idt_table[IDT_SIZE]; [[gnu::aligned(0x10)]] static IdtRegister idtr; void idt_set(u8 idx, void* handler, u8 type_attr) @@ -31,27 +32,56 @@ void idt_set(u8 idx, void* handler, u8 type_attr) #endif } +// Directly called by the IDT handler. +// Referenced by arch.s +Context* idt_dispatcher(usize isr, Context* regs) +{ + CpuInfo* cpu = arch_current_cpu(); + + Context* result = regs; + // If the IDT slot is occupied, call that function directly. + if (likely(cpu->idt_callbacks[isr])) + result = cpu->idt_callbacks[isr](isr, regs); + // If it is not, call the generic handler instead. + else + irq_generic_handler(cpu->idt_to_irq_map[isr]); + + return result; +} + +// Deliberately does nothing. +static Context* idt_noop(usize isr, Context* regs) +{ + return regs; +} + void idt_reload() { - const usize cpu = arch_current_cpu()->id; + sch_stop_preemption(); - // Set IRQ handlers for known ISRs (Exceptions, timer, syscall) on this core. - isr_register_handler(cpu, 0x3, interrupt_debug_handler, NULL); - isr_register_handler(cpu, 0x6, interrupt_ud_handler, NULL); - isr_register_handler(cpu, 0xE, interrupt_pf_handler, NULL); - isr_register_handler(cpu, INT_TIMER, timer_handler, NULL); - isr_register_handler(cpu, INT_SYSCALL, syscall_handler, NULL); + CpuInfo* cpu = arch_current_cpu(); + + // Set known ISRs (Exceptions, timer, syscall) on this core. + for (usize i = 0; i < 32; i++) + cpu->idt_callbacks[i] = idt_noop; // Exceptions + cpu->idt_callbacks[0x3] = interrupt_debug_handler; + cpu->idt_callbacks[0x6] = interrupt_ud_handler; + cpu->idt_callbacks[0xE] = interrupt_pf_handler; + cpu->idt_callbacks[INT_TIMER] = timer_handler; + cpu->idt_callbacks[INT_SYSCALL] = syscall_handler; idtr.limit = sizeof(idt_table) - 1; // Limit is the last entry, not total size. idtr.base = idt_table; asm volatile("lidt %0" ::"m"(idtr)); + + sch_start_preemption(); } -extern void* arch_int_table[IDT_MAX_SIZE]; +extern void* arch_int_table[IDT_SIZE]; void idt_init() { - for (usize i = 0; i < IDT_MAX_SIZE; i++) + for (usize i = 0; i < IDT_SIZE; i++) { idt_set(i, arch_int_table[i], IDT_TYPE(0, IDT_GATE_INT)); } diff --git a/kernel/arch/x86_64/system/interrupts.c b/kernel/arch/x86_64/system/interrupts.c index 5b42179..2cf1a6d 100644 --- a/kernel/arch/x86_64/system/interrupts.c +++ b/kernel/arch/x86_64/system/interrupts.c @@ -8,7 +8,7 @@ #include #include -Context* interrupt_ud_handler(usize isr, Context* regs, void* data) +Context* interrupt_ud_handler(usize isr, Context* regs) { // Make sure we're in user mode, otherwise we have to crash. print_log("Invalid opcode at 0x%zx on core %zu!\n", regs->rip, arch_current_cpu()->id); @@ -19,7 +19,7 @@ Context* interrupt_ud_handler(usize isr, Context* regs, void* data) return regs; } -Context* interrupt_debug_handler(usize isr, Context* regs, void* data) +Context* interrupt_debug_handler(usize isr, Context* regs) { // We use this exception just to print the current registers, so no abort. arch_dump_registers(regs); @@ -28,7 +28,7 @@ Context* interrupt_debug_handler(usize isr, Context* regs, void* data) } // Handles the syscall interrupt. Also referenced by system/arch.s -Context* syscall_handler(usize isr, Context* regs, void* data) +Context* syscall_handler(usize isr, Context* regs) { // Save the registers. CpuInfo* const core = arch_current_cpu(); diff --git a/kernel/main.c b/kernel/main.c index efd1874..6b7f344 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -37,6 +37,8 @@ static BootInfo* info; module_load_kernel_syms(info->kernel_file); + sch_init((VirtAddr)kernel_main); + // Initialize virtual file system. vfs_init(); @@ -69,7 +71,6 @@ static BootInfo* info; module_init(); print_log("boot: Initialization complete, handing over to scheduler.\n"); - sch_init((VirtAddr)kernel_main); while (true) sch_arch_invoke(); diff --git a/kernel/syscall/fstat.c b/kernel/syscall/fstat.c index bdffb66..b7f4edd 100644 --- a/kernel/syscall/fstat.c +++ b/kernel/syscall/fstat.c @@ -1,5 +1,6 @@ #include #include +#include SYSCALL_IMPL(fstat, int fd, VirtAddr path, int flags, VirtAddr buf) { @@ -14,14 +15,18 @@ SYSCALL_IMPL(fstat, int fd, VirtAddr path, int flags, VirtAddr buf) { FileDescriptor* file_desc = fd_get(process, fd); if (file_desc == NULL) + { return SYSCALL_ERR(EBADF); + } node = file_desc->node; } else { if (path == 0) + { return SYSCALL_ERR(EINVAL); + } char* kernel_path = kmalloc(PATH_MAX); vm_user_read(process, kernel_path, path, PATH_MAX); @@ -31,7 +36,9 @@ SYSCALL_IMPL(fstat, int fd, VirtAddr path, int flags, VirtAddr buf) } if (node == NULL) + { return SYSCALL_ERR(ENOENT); + } vm_user_write(process, buf, &node->handle->stat, sizeof(struct stat)); diff --git a/kernel/system/CMakeLists.txt b/kernel/system/CMakeLists.txt index 709e315..169a104 100644 --- a/kernel/system/CMakeLists.txt +++ b/kernel/system/CMakeLists.txt @@ -3,7 +3,6 @@ target_sources(menix PUBLIC device.c elf.c - interrupts.c module.c logger.c ) @@ -11,6 +10,7 @@ target_sources(menix PUBLIC add_subdirectory(acpi) add_subdirectory(bus) add_subdirectory(dst) +add_subdirectory(irq) add_subdirectory(net) add_subdirectory(sch) add_subdirectory(time) diff --git a/kernel/system/acpi/uacpi_interface.c b/kernel/system/acpi/uacpi_interface.c index 74650e8..5738315 100644 --- a/kernel/system/acpi/uacpi_interface.c +++ b/kernel/system/acpi/uacpi_interface.c @@ -288,13 +288,6 @@ uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request*) return UACPI_STATUS_UNIMPLEMENTED; } -static Context* irq_handler_wrapper(usize isr, Context* context, void* data) -{ - void** frame = (void**)data; - ((uacpi_interrupt_handler)frame[0])(frame[1]); - return context; -} - uacpi_status uacpi_kernel_install_interrupt_handler(uacpi_u32 irq, uacpi_interrupt_handler handler, uacpi_handle ctx, uacpi_handle* out_irq_handle) { @@ -302,7 +295,7 @@ uacpi_status uacpi_kernel_install_interrupt_handler(uacpi_u32 irq, uacpi_interru context[0] = handler; context[1] = ctx; - isr_register_handler(arch_current_cpu()->id, irq + 32, irq_handler_wrapper, context); + // isr_register_handler(arch_current_cpu()->id, irq + 32, irq_handler_wrapper, context); *out_irq_handle = context; return UACPI_STATUS_OK; } diff --git a/kernel/system/interrupts.c b/kernel/system/interrupts.c deleted file mode 100644 index bcb7e44..0000000 --- a/kernel/system/interrupts.c +++ /dev/null @@ -1,73 +0,0 @@ -// Interrupt service routines - -#include -#include -#include -#include -#include -#include -#include -#include - -Context* int_handler(usize isr, Context* regs) -{ - const CpuInfo* current = arch_current_cpu(); - // If we have a handler for this interrupt, call it. - if (isr < ARRAY_SIZE(current->irq_handlers) && current->irq_handlers[isr]) - { - Context* result = current->irq_handlers[isr](isr, regs, current->irq_data[isr]); - return result; - } - - // If unhandled and caused by the user, terminate the process with SIGILL. - if (current->thread && current->thread->is_user) - { - Process* proc = current->thread->parent; - print_log("Unhandled interrupt %zu caused by user program! Terminating PID %i!\n", isr, proc->id); - arch_dump_registers(regs); - proc_kill(proc, true); - return sch_reschedule(regs); - } - - // Disable spinlocks so we have a chance of displaying a message. - // In this state everything could be broken anyways. - spin_use(false); - - // Exception was not caused by the user and is not handled, abort. - print_log("Unhandled interrupt %zu in kernel mode!\n", isr); - - ktrace(regs); - panic(); -} - -bool isr_register_handler(usize cpu, usize idx, InterruptFn handler, void* data) -{ - asm_interrupt_disable(); - if (cpu >= ARRAY_SIZE(per_cpu_data) || idx >= ARRAY_SIZE(per_cpu_data[cpu].irq_handlers)) - { - arch_log("Failed to register a handler for ISR %zu! Out of bounds.\n", idx); - return false; - } - - per_cpu_data[cpu].irq_handlers[idx] = handler; - per_cpu_data[cpu].irq_data[idx] = data; - arch_log("Registered handler 0x%p for interrupt %zu on CPU %zu!\n", handler, idx, cpu); - return true; -} - -bool irq_allocate_handler(InterruptFn handler, void* data) -{ - // Find a CPU with free interrupt vector. - usize cpu = 0; - usize idx = 0; - for (; cpu < ARRAY_SIZE(per_cpu_data); cpu++) - { - for (; idx < ARRAY_SIZE(per_cpu_data[cpu].irq_handlers); idx++) - { - if (per_cpu_data[cpu].irq_handlers[idx] == NULL) - break; - } - } - - return isr_register_handler(cpu, idx, handler, data); -} diff --git a/kernel/system/irq/CMakeLists.txt b/kernel/system/irq/CMakeLists.txt new file mode 100644 index 0000000..c8bbc3d --- /dev/null +++ b/kernel/system/irq/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(menix PUBLIC + alloc.c + handle.c +) \ No newline at end of file diff --git a/kernel/system/irq/alloc.c b/kernel/system/irq/alloc.c new file mode 100644 index 0000000..41598de --- /dev/null +++ b/kernel/system/irq/alloc.c @@ -0,0 +1,62 @@ +// Interrupt service routines + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static SpinLock irq_alloc_lock = {0}; +static Irq irq_counter = 0; +IrqAction* irq_actions = NULL; + +// Find the next free slot in the irq_actions list. +static void add_irq(IrqAction* target) +{ + if (target == NULL) + return; + + IrqAction* cur = irq_actions; + + if (cur == NULL) + { + irq_actions = target; + return; + } + + if (cur == target) + return; + + while (cur->next) + cur = cur->next; + + cur->next = target; +} + +bool irq_allocate(IrqHandlerFn handler, IrqHandlerFn thread_handler, IrqFlags flags, const char* name, void* data) +{ + spin_lock(&irq_alloc_lock); + + // TODO: Allocate an interrupt line on the CPU. + + IrqAction* action = kzalloc(sizeof(IrqAction)); + action->irq = irq_counter++; + action->flags = flags; + action->handler = handler; + action->worker = thread_handler; + action->name = name; + action->context = data; + + action->thread = thread_new(proc_kernel); + thread_arch_setup(action->thread, 0, false, 0); + + add_irq(action); + + spin_unlock(&irq_alloc_lock); + return true; +} diff --git a/kernel/system/irq/handle.c b/kernel/system/irq/handle.c new file mode 100644 index 0000000..9f8dae7 --- /dev/null +++ b/kernel/system/irq/handle.c @@ -0,0 +1,8 @@ +#include + +#include "menix/util/log.h" + +void irq_generic_handler(Irq irq) +{ + print_log("irq_generic_handler, %zu", irq); +} diff --git a/kernel/system/sch/core.c b/kernel/system/sch/core.c index 34f9ad4..5889774 100644 --- a/kernel/system/sch/core.c +++ b/kernel/system/sch/core.c @@ -5,6 +5,7 @@ #include #include #include +#include #include Process* proc_list = NULL; @@ -17,10 +18,18 @@ Thread* sleeping_thread_list = NULL; void sch_init(VirtAddr entry_point) { // Create the first process for kernel tasks (PID 0). - Process* kernel_proc = proc_create("kernel", ProcessState_Ready, false, NULL); - Thread* kernel_thread = thread_create(kernel_proc); - thread_arch_setup(kernel_thread, entry_point, false, 0); - sch_arch_invoke(); + proc_kernel = proc_create("kernel", ProcessState_Ready, false, NULL); + thread_create_kernel(proc_kernel, entry_point); +} + +void sch_start_preemption() +{ + // TODO +} + +void sch_stop_preemption() +{ + // TODO } Thread* sch_next(Thread* list) diff --git a/kernel/system/sch/proc.c b/kernel/system/sch/proc.c index 7f62e0c..c8c8b2c 100644 --- a/kernel/system/sch/proc.c +++ b/kernel/system/sch/proc.c @@ -24,6 +24,8 @@ static usize pid_counter = 0; ProcessList dead_processes; +Process* proc_kernel = NULL; + Process* proc_create(const char* name, ProcessState state, bool is_user, Process* parent) { spin_lock(&proc_lock); @@ -135,7 +137,7 @@ bool proc_create_elf(const char* name, const char* path, char** argv, char** env proc->working_dir = node->parent; proc->map_base = VM_USER_MAP_BASE; - Thread* thread = thread_create(proc); + Thread* thread = thread_new(proc); proc->elf_info = info; thread_setup(thread, entry_point, argv, envp, is_user); diff --git a/kernel/system/sch/thread.c b/kernel/system/sch/thread.c index 601d168..9d70982 100644 --- a/kernel/system/sch/thread.c +++ b/kernel/system/sch/thread.c @@ -24,7 +24,7 @@ void thread_set_errno(usize errno) t->errno = errno; } -Thread* thread_create(Process* parent) +Thread* thread_new(Process* parent) { spin_lock(&thread_lock); @@ -46,6 +46,16 @@ Thread* thread_create(Process* parent) return thread; } +Thread* thread_create_kernel(Process* parent, VirtAddr start) +{ + print_log("thread: Creating new kernel thread for process \"%s\"\n", parent->name); + Thread* result = thread_new(parent); + + thread_arch_setup(result, start, false, 0); + + return result; +} + void thread_setup(Thread* target, VirtAddr start, char** argv, char** envp, bool is_user) { kassert(argv != NULL, "argv can't be null!");