mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
CHECKP: multi core scheduling
This commit is contained in:
parent
a7c3cccce7
commit
9fb307e603
9 changed files with 190 additions and 59 deletions
|
|
@ -7,9 +7,11 @@ global isr1_wrapper
|
||||||
global isr8_wrapper
|
global isr8_wrapper
|
||||||
global isr12_wrapper
|
global isr12_wrapper
|
||||||
global isr14_wrapper
|
global isr14_wrapper
|
||||||
|
global isr_sched_ipi_wrapper
|
||||||
extern timer_handler
|
extern timer_handler
|
||||||
extern keyboard_handler
|
extern keyboard_handler
|
||||||
extern mouse_handler
|
extern mouse_handler
|
||||||
|
extern sched_ipi_handler
|
||||||
extern exception_handler_c
|
extern exception_handler_c
|
||||||
|
|
||||||
; Helper to send EOI (End of Interrupt) to PIC
|
; Helper to send EOI (End of Interrupt) to PIC
|
||||||
|
|
@ -85,6 +87,9 @@ isr1_wrapper:
|
||||||
isr12_wrapper:
|
isr12_wrapper:
|
||||||
ISR_NOERRCODE mouse_handler, 44
|
ISR_NOERRCODE mouse_handler, 44
|
||||||
|
|
||||||
|
isr_sched_ipi_wrapper:
|
||||||
|
ISR_NOERRCODE sched_ipi_handler, 65
|
||||||
|
|
||||||
; Common exception macro for exceptions WITHOUT error code
|
; Common exception macro for exceptions WITHOUT error code
|
||||||
%macro EXCEPTION_NOERRCODE 1
|
%macro EXCEPTION_NOERRCODE 1
|
||||||
global exc%1_wrapper
|
global exc%1_wrapper
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include "wallpaper.h"
|
#include "wallpaper.h"
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
#include "work_queue.h"
|
#include "work_queue.h"
|
||||||
|
#include "lapic.h"
|
||||||
|
|
||||||
// --- Limine Requests ---
|
// --- Limine Requests ---
|
||||||
__attribute__((used, section(".requests")))
|
__attribute__((used, section(".requests")))
|
||||||
|
|
@ -241,6 +242,9 @@ void kmain(void) {
|
||||||
ps2_init();
|
ps2_init();
|
||||||
asm("sti");
|
asm("sti");
|
||||||
|
|
||||||
|
// Initialize LAPIC for IPI support
|
||||||
|
lapic_init();
|
||||||
|
|
||||||
// Initialize SMP — bring up all CPU cores
|
// Initialize SMP — bring up all CPU cores
|
||||||
if (smp_request.response != NULL) {
|
if (smp_request.response != NULL) {
|
||||||
uint32_t online = smp_init(smp_request.response);
|
uint32_t online = smp_init(smp_request.response);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "lapic.h"
|
||||||
|
#include "smp.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
extern void serial_print(const char *s);
|
extern void serial_print(const char *s);
|
||||||
|
|
@ -23,7 +25,14 @@ uint64_t timer_handler(registers_t *regs) {
|
||||||
|
|
||||||
outb(0x20, 0x20); // EOI after processing to prevent nested timer interrupts
|
outb(0x20, 0x20); // EOI after processing to prevent nested timer interrupts
|
||||||
extern uint64_t process_schedule(uint64_t current_rsp);
|
extern uint64_t process_schedule(uint64_t current_rsp);
|
||||||
return process_schedule((uint64_t)regs);
|
uint64_t new_rsp = process_schedule((uint64_t)regs);
|
||||||
|
|
||||||
|
// SMP: Wake AP cores to run their assigned processes
|
||||||
|
if (smp_cpu_count() > 1) {
|
||||||
|
lapic_send_ipi_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Keyboard ---
|
// --- Keyboard ---
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,10 @@ void idt_register_interrupts(void) {
|
||||||
idt_set_gate(30, exc30_wrapper, cs, 0x8E);
|
idt_set_gate(30, exc30_wrapper, cs, 0x8E);
|
||||||
idt_set_gate(31, exc31_wrapper, cs, 0x8E);
|
idt_set_gate(31, exc31_wrapper, cs, 0x8E);
|
||||||
|
|
||||||
|
// SMP: Scheduling IPI for AP cores (vector 0x41 = 65)
|
||||||
|
extern void isr_sched_ipi_wrapper(void);
|
||||||
|
idt_set_gate(0x41, isr_sched_ipi_wrapper, cs, 0x8E);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void idt_load(void) {
|
void idt_load(void) {
|
||||||
|
|
|
||||||
50
src/sys/lapic.c
Normal file
50
src/sys/lapic.c
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
|
#include "lapic.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
|
// LAPIC is at physical 0xFEE00000. Access via HHDM.
|
||||||
|
static volatile uint32_t *lapic_base = 0;
|
||||||
|
|
||||||
|
// LAPIC register offsets (byte offsets, divided by 4 for uint32_t* indexing)
|
||||||
|
#define LAPIC_ID (0x020 / 4)
|
||||||
|
#define LAPIC_EOI (0x0B0 / 4)
|
||||||
|
#define LAPIC_SVR (0x0F0 / 4)
|
||||||
|
#define LAPIC_ICR_LOW (0x300 / 4)
|
||||||
|
#define LAPIC_ICR_HIGH (0x310 / 4)
|
||||||
|
|
||||||
|
void lapic_init(void) {
|
||||||
|
extern uint64_t hhdm_offset;
|
||||||
|
lapic_base = (volatile uint32_t *)(hhdm_offset + 0xFEE00000ULL);
|
||||||
|
|
||||||
|
// Enable the LAPIC by setting the Spurious Interrupt Vector Register
|
||||||
|
// Bit 8 = APIC Software Enable, vector = 0xFF (spurious)
|
||||||
|
lapic_base[LAPIC_SVR] = 0x1FF;
|
||||||
|
|
||||||
|
serial_write("[LAPIC] Initialized at HHDM + 0xFEE00000\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_eoi(void) {
|
||||||
|
if (lapic_base) {
|
||||||
|
lapic_base[LAPIC_EOI] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_send_ipi_all(void) {
|
||||||
|
if (!lapic_base) return;
|
||||||
|
|
||||||
|
// Send IPI to all excluding self
|
||||||
|
// ICR format:
|
||||||
|
// bits 7:0 = vector (IPI_SCHED_VECTOR = 0x41)
|
||||||
|
// bits 10:8 = delivery mode (000 = Fixed)
|
||||||
|
// bit 11 = destination mode (0 = Physical)
|
||||||
|
// bit 14 = level (1 = Assert)
|
||||||
|
// bits 19:18 = destination shorthand (11 = All Excluding Self)
|
||||||
|
uint32_t icr_low = IPI_SCHED_VECTOR | (0b11 << 18) | (1 << 14);
|
||||||
|
|
||||||
|
// Writing ICR_LOW triggers the IPI send
|
||||||
|
lapic_base[LAPIC_ICR_LOW] = icr_low;
|
||||||
|
}
|
||||||
21
src/sys/lapic.h
Normal file
21
src/sys/lapic.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
|
#ifndef LAPIC_H
|
||||||
|
#define LAPIC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// IPI vector used for scheduling on APs
|
||||||
|
#define IPI_SCHED_VECTOR 0x41
|
||||||
|
|
||||||
|
// Initialize LAPIC access (maps registers via HHDM)
|
||||||
|
void lapic_init(void);
|
||||||
|
|
||||||
|
// Send End-of-Interrupt to the local APIC
|
||||||
|
void lapic_eoi(void);
|
||||||
|
|
||||||
|
// Send a scheduling IPI to all APs (excludes self)
|
||||||
|
void lapic_send_ipi_all(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -11,17 +11,21 @@
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
|
#include "smp.h"
|
||||||
|
#include "lapic.h"
|
||||||
|
|
||||||
extern void cmd_write(const char *str);
|
extern void cmd_write(const char *str);
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
#define MAX_PROCESSES 16
|
#define MAX_PROCESSES 16
|
||||||
|
#define MAX_CPUS_SCHED 32
|
||||||
process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
||||||
int process_count = 0;
|
int process_count = 0;
|
||||||
static process_t* current_process = NULL;
|
static process_t* current_process[MAX_CPUS_SCHED] = {0}; // Per-CPU
|
||||||
static uint32_t next_pid = 0;
|
static uint32_t next_pid = 0;
|
||||||
static void *free_kernel_stack_later = NULL;
|
static void *free_kernel_stack_later = NULL;
|
||||||
static spinlock_t runqueue_lock = SPINLOCK_INIT;
|
static spinlock_t runqueue_lock = SPINLOCK_INIT;
|
||||||
|
static uint32_t next_cpu_assign = 1; // Round-robin CPU assignment (start from CPU 1)
|
||||||
|
|
||||||
void process_init(void) {
|
void process_init(void) {
|
||||||
for (int i = 0; i < MAX_PROCESSES; i++) {
|
for (int i = 0; i < MAX_PROCESSES; i++) {
|
||||||
|
|
@ -49,7 +53,8 @@ void process_init(void) {
|
||||||
kernel_proc->used_memory = 32768; // Kernel stack
|
kernel_proc->used_memory = 32768; // Kernel stack
|
||||||
|
|
||||||
kernel_proc->next = kernel_proc; // Circular linked list
|
kernel_proc->next = kernel_proc; // Circular linked list
|
||||||
current_process = kernel_proc;
|
kernel_proc->cpu_affinity = 0; // Kernel always on BSP
|
||||||
|
current_process[0] = kernel_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_create(void* entry_point, bool is_user) {
|
void process_create(void* entry_point, bool is_user) {
|
||||||
|
|
@ -133,10 +138,12 @@ void process_create(void* entry_point, bool is_user) {
|
||||||
asm volatile("fninit");
|
asm volatile("fninit");
|
||||||
new_proc->fpu_initialized = true;
|
new_proc->fpu_initialized = true;
|
||||||
|
|
||||||
|
new_proc->cpu_affinity = 0; // Non-ELF processes stay on BSP
|
||||||
|
|
||||||
// Add to linked list (Critical Section)
|
// Add to linked list (Critical Section)
|
||||||
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
||||||
new_proc->next = current_process->next;
|
new_proc->next = current_process[0]->next;
|
||||||
current_process->next = new_proc;
|
current_process[0]->next = new_proc;
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,10 +323,20 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
asm volatile("fninit");
|
asm volatile("fninit");
|
||||||
new_proc->fpu_initialized = true;
|
new_proc->fpu_initialized = true;
|
||||||
|
|
||||||
|
// Assign to an AP core via round-robin (if SMP is active)
|
||||||
|
uint32_t cpu_count = smp_cpu_count();
|
||||||
|
if (cpu_count > 1) {
|
||||||
|
new_proc->cpu_affinity = next_cpu_assign;
|
||||||
|
next_cpu_assign++;
|
||||||
|
if (next_cpu_assign >= cpu_count) next_cpu_assign = 1; // Wrap, skip CPU 0
|
||||||
|
} else {
|
||||||
|
new_proc->cpu_affinity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Add to linked list (Critical Section)
|
// Add to linked list (Critical Section)
|
||||||
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
||||||
new_proc->next = current_process->next;
|
new_proc->next = current_process[0]->next;
|
||||||
current_process->next = new_proc;
|
current_process[0]->next = new_proc;
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
|
|
||||||
serial_write("[PROCESS] Spawned ELF Executable: ");
|
serial_write("[PROCESS] Spawned ELF Executable: ");
|
||||||
|
|
@ -329,7 +346,8 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* process_get_current(void) {
|
process_t* process_get_current(void) {
|
||||||
return current_process;
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
|
return current_process[cpu];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t process_schedule(uint64_t current_rsp) {
|
uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
|
|
@ -338,41 +356,54 @@ uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
free_kernel_stack_later = NULL;
|
free_kernel_stack_later = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current_process || !current_process->next || current_process == current_process->next)
|
uint32_t my_cpu = smp_this_cpu_id();
|
||||||
|
process_t *cur = current_process[my_cpu];
|
||||||
|
|
||||||
|
if (!cur || !cur->next || cur == cur->next)
|
||||||
return current_rsp;
|
return current_rsp;
|
||||||
|
|
||||||
// Save context
|
// Save context
|
||||||
current_process->rsp = current_rsp;
|
cur->rsp = current_rsp;
|
||||||
|
|
||||||
// Switch to next ready process
|
// Switch to next ready process assigned to this CPU
|
||||||
extern uint32_t wm_get_ticks(void);
|
extern uint32_t wm_get_ticks(void);
|
||||||
uint32_t now = wm_get_ticks();
|
uint32_t now = wm_get_ticks();
|
||||||
|
|
||||||
process_t *start = current_process;
|
process_t *start = cur;
|
||||||
process_t *next_proc = current_process->next;
|
process_t *next_proc = cur->next;
|
||||||
|
|
||||||
while (next_proc != start) {
|
while (next_proc != start) {
|
||||||
if (next_proc->pid == 0 || next_proc->sleep_until == 0 || next_proc->sleep_until <= now) {
|
// Only consider processes assigned to our CPU
|
||||||
break;
|
if (next_proc->cpu_affinity == my_cpu) {
|
||||||
|
if (next_proc->pid == 0 || next_proc->sleep_until == 0 || next_proc->sleep_until <= now) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next_proc = next_proc->next;
|
next_proc = next_proc->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_process = next_proc;
|
// If we didn't find a ready process for our CPU, stay on current
|
||||||
|
if (next_proc->cpu_affinity != my_cpu) {
|
||||||
|
return current_rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_process[my_cpu] = next_proc;
|
||||||
|
|
||||||
// Update Kernel Stack for User Mode interrupts and System Calls
|
// Update Kernel Stack for User Mode interrupts and System Calls
|
||||||
if (current_process->is_user && current_process->kernel_stack) {
|
if (current_process[my_cpu]->is_user && current_process[my_cpu]->kernel_stack) {
|
||||||
tss_set_stack(current_process->kernel_stack);
|
tss_set_stack_cpu(my_cpu, current_process[my_cpu]->kernel_stack);
|
||||||
extern uint64_t kernel_syscall_stack;
|
if (my_cpu == 0) {
|
||||||
kernel_syscall_stack = current_process->kernel_stack;
|
extern uint64_t kernel_syscall_stack;
|
||||||
|
kernel_syscall_stack = current_process[my_cpu]->kernel_stack;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch page table
|
// Switch page table
|
||||||
paging_switch_directory(current_process->pml4_phys);
|
paging_switch_directory(current_process[my_cpu]->pml4_phys);
|
||||||
|
|
||||||
current_process->ticks++;
|
current_process[my_cpu]->ticks++;
|
||||||
|
|
||||||
return current_process->rsp;
|
return current_process[my_cpu]->rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* process_get_by_pid(uint32_t pid) {
|
process_t* process_get_by_pid(uint32_t pid) {
|
||||||
|
|
@ -430,11 +461,12 @@ void process_terminate(process_t *to_delete) {
|
||||||
// 3. Remove current from list
|
// 3. Remove current from list
|
||||||
prev->next = to_delete->next;
|
prev->next = to_delete->next;
|
||||||
|
|
||||||
if (to_delete == current_process) {
|
// Update per-CPU current_process if this was the current on any CPU
|
||||||
current_process = to_delete->next;
|
uint32_t cpu_count = smp_cpu_count();
|
||||||
// WARNING: If this was called as a regular function and not via a task switch,
|
for (uint32_t c = 0; c < cpu_count && c < MAX_CPUS_SCHED; c++) {
|
||||||
// the stack might be in a weird state. But usually we call this via window manager
|
if (current_process[c] == to_delete) {
|
||||||
// or other external triggers.
|
current_process[c] = to_delete->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark slot as free
|
// Mark slot as free
|
||||||
|
|
@ -442,11 +474,7 @@ void process_terminate(process_t *to_delete) {
|
||||||
|
|
||||||
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
||||||
if (to_delete->kernel_stack_alloc) {
|
if (to_delete->kernel_stack_alloc) {
|
||||||
if (to_delete == current_process) {
|
kfree(to_delete->kernel_stack_alloc);
|
||||||
free_kernel_stack_later = to_delete->kernel_stack_alloc;
|
|
||||||
} else {
|
|
||||||
kfree(to_delete->kernel_stack_alloc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void paging_destroy_user_pml4_phys(uint64_t pml4_phys);
|
extern void paging_destroy_user_pml4_phys(uint64_t pml4_phys);
|
||||||
|
|
@ -464,46 +492,49 @@ void process_terminate(process_t *to_delete) {
|
||||||
uint64_t process_terminate_current(void) {
|
uint64_t process_terminate_current(void) {
|
||||||
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
||||||
|
|
||||||
if (!current_process || current_process->pid == 0) {
|
uint32_t my_cpu = smp_this_cpu_id();
|
||||||
|
process_t *cur = current_process[my_cpu];
|
||||||
|
|
||||||
|
if (!cur || cur->pid == 0) {
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_cleanup_inner(current_process);
|
process_cleanup_inner(cur);
|
||||||
|
|
||||||
// 2. Find previous process in circular list
|
// 2. Find previous process in circular list
|
||||||
process_t *prev = current_process;
|
process_t *prev = cur;
|
||||||
while (prev->next != current_process) {
|
while (prev->next != cur) {
|
||||||
prev = prev->next;
|
prev = prev->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Remove current from list
|
// 3. Remove current from list
|
||||||
process_t *to_delete = current_process;
|
process_t *to_delete = cur;
|
||||||
|
|
||||||
if (prev == current_process) {
|
if (prev == cur) {
|
||||||
// Only one process (should be kernel), cannot terminate.
|
// Only one process (should be kernel), cannot terminate.
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
return to_delete->rsp;
|
return to_delete->rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev->next = to_delete->next;
|
prev->next = to_delete->next;
|
||||||
current_process = to_delete->next;
|
current_process[my_cpu] = to_delete->next;
|
||||||
|
|
||||||
// Mark slot as free
|
// Mark slot as free
|
||||||
to_delete->pid = 0xFFFFFFFF;
|
to_delete->pid = 0xFFFFFFFF;
|
||||||
|
|
||||||
// 4. Load context for the NEXT process
|
// 4. Load context for the NEXT process
|
||||||
if (current_process->is_user && current_process->kernel_stack) {
|
if (current_process[my_cpu]->is_user && current_process[my_cpu]->kernel_stack) {
|
||||||
tss_set_stack(current_process->kernel_stack);
|
tss_set_stack_cpu(my_cpu, current_process[my_cpu]->kernel_stack);
|
||||||
extern uint64_t kernel_syscall_stack;
|
if (my_cpu == 0) {
|
||||||
kernel_syscall_stack = current_process->kernel_stack;
|
extern uint64_t kernel_syscall_stack;
|
||||||
|
kernel_syscall_stack = current_process[my_cpu]->kernel_stack;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paging_switch_directory(current_process->pml4_phys);
|
paging_switch_directory(current_process[my_cpu]->pml4_phys);
|
||||||
|
|
||||||
// 5. Actually free the memory (after switching state to avoid issues)
|
// 5. Free memory
|
||||||
// We only safely free the user stack. Immediate freeing of the current
|
|
||||||
// kernel stack is unsafe while we are still running on it.
|
|
||||||
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
||||||
|
|
||||||
extern void paging_destroy_user_pml4_phys(uint64_t pml4_phys);
|
extern void paging_destroy_user_pml4_phys(uint64_t pml4_phys);
|
||||||
|
|
@ -511,17 +542,24 @@ uint64_t process_terminate_current(void) {
|
||||||
paging_destroy_user_pml4_phys(to_delete->pml4_phys);
|
paging_destroy_user_pml4_phys(to_delete->pml4_phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear pointers to avoid double-free during slot reuse
|
|
||||||
to_delete->user_stack_alloc = NULL;
|
to_delete->user_stack_alloc = NULL;
|
||||||
free_kernel_stack_later = to_delete->kernel_stack_alloc;
|
free_kernel_stack_later = to_delete->kernel_stack_alloc;
|
||||||
to_delete->kernel_stack_alloc = NULL; // Leak the small kernel stack for safety
|
to_delete->kernel_stack_alloc = NULL;
|
||||||
to_delete->pml4_phys = 0;
|
to_delete->pml4_phys = 0;
|
||||||
|
|
||||||
uint64_t next_rsp = current_process->rsp;
|
uint64_t next_rsp = current_process[my_cpu]->rsp;
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
return next_rsp;
|
return next_rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SMP: IPI handler called on AP cores when BSP broadcasts scheduling IPI
|
||||||
|
uint64_t sched_ipi_handler(registers_t *regs) {
|
||||||
|
lapic_eoi(); // Acknowledge the IPI
|
||||||
|
|
||||||
|
// Run the scheduler for this CPU
|
||||||
|
return process_schedule((uint64_t)regs);
|
||||||
|
}
|
||||||
|
|
||||||
void process_push_gui_event(process_t *proc, gui_event_t *ev) {
|
void process_push_gui_event(process_t *proc, gui_event_t *ev) {
|
||||||
if (!proc) return;
|
if (!proc) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ typedef struct process {
|
||||||
uint64_t ticks;
|
uint64_t ticks;
|
||||||
uint64_t sleep_until;
|
uint64_t sleep_until;
|
||||||
size_t used_memory;
|
size_t used_memory;
|
||||||
|
uint32_t cpu_affinity; // Which CPU this process runs on (0 = BSP)
|
||||||
} __attribute__((aligned(16))) process_t;
|
} __attribute__((aligned(16))) process_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -70,6 +71,9 @@ uint64_t process_terminate_current(void);
|
||||||
void process_terminate(process_t *proc);
|
void process_terminate(process_t *proc);
|
||||||
process_t* process_get_by_pid(uint32_t pid);
|
process_t* process_get_by_pid(uint32_t pid);
|
||||||
|
|
||||||
|
// SMP: IPI handler for AP scheduling (called from ISR)
|
||||||
|
uint64_t sched_ipi_handler(registers_t *regs);
|
||||||
|
|
||||||
void process_push_gui_event(process_t *proc, gui_event_t *ev);
|
void process_push_gui_event(process_t *proc, gui_event_t *ev);
|
||||||
process_t* process_get_by_ui_window(void* win);
|
process_t* process_get_by_ui_window(void* win);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,16 +89,12 @@ static void ap_entry(struct limine_smp_info *info) {
|
||||||
serial_write_num(cpu_states[my_id].lapic_id);
|
serial_write_num(cpu_states[my_id].lapic_id);
|
||||||
serial_write(")\n");
|
serial_write(")\n");
|
||||||
|
|
||||||
// 8. Enable interrupts and enter idle loop
|
// 8. Enable interrupts and enter idle halt loop.
|
||||||
// APs don't handle PIC interrupts (only BSP does with legacy PIC).
|
// APs will be woken by scheduling IPIs from BSP (vector 0x41).
|
||||||
// But they WILL pick up work from the work queue.
|
// The IPI handler does context switching for this CPU's processes.
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
|
|
||||||
// Import work queue drain function
|
// Idle loop — APs halt and wait for IPI
|
||||||
extern void work_queue_drain_loop(void);
|
|
||||||
work_queue_drain_loop();
|
|
||||||
|
|
||||||
// Should never reach here
|
|
||||||
for (;;) { asm volatile("hlt"); }
|
for (;;) { asm volatile("hlt"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue