mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 18:58:40 +00:00
fix: added stability for SMP on Tiger Lake processors
This commit is contained in:
parent
85c93cbcfa
commit
9c2096f737
10 changed files with 84 additions and 20 deletions
|
|
@ -18,7 +18,7 @@ process_jump_usermode:
|
||||||
|
|
||||||
; Build the IRETQ stack frame
|
; Build the IRETQ stack frame
|
||||||
; 1. SS (User Data Segment)
|
; 1. SS (User Data Segment)
|
||||||
push 0x23
|
push 0x1B
|
||||||
|
|
||||||
; 2. RSP (User Stack)
|
; 2. RSP (User Stack)
|
||||||
push rsi
|
push rsi
|
||||||
|
|
@ -27,7 +27,7 @@ process_jump_usermode:
|
||||||
push 0x202
|
push 0x202
|
||||||
|
|
||||||
; 4. CS (User Code Segment)
|
; 4. CS (User Code Segment)
|
||||||
push 0x1B
|
push 0x23
|
||||||
|
|
||||||
; 5. RIP (Entry Point)
|
; 5. RIP (Entry Point)
|
||||||
push rdi
|
push rdi
|
||||||
|
|
@ -40,6 +40,12 @@ process_jump_usermode:
|
||||||
global context_switch_to
|
global context_switch_to
|
||||||
context_switch_to:
|
context_switch_to:
|
||||||
mov rsp, rdi
|
mov rsp, rdi
|
||||||
|
mov rcx, [rsp + 8192]
|
||||||
|
xor ecx, ecx
|
||||||
|
xgetbv
|
||||||
|
xrstor [rsp]
|
||||||
|
add rsp, 8192
|
||||||
|
add rsp, rcx
|
||||||
|
|
||||||
pop r15
|
pop r15
|
||||||
pop r14
|
pop r14
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,17 @@
|
||||||
|
|
||||||
#include "../drivers/ACPI/acpi.h"
|
#include "../drivers/ACPI/acpi.h"
|
||||||
|
|
||||||
void memset(void *dest, int val, size_t len) {
|
void *memset(void *dest, int val, size_t len) {
|
||||||
unsigned char *ptr = (unsigned char *)dest;
|
unsigned char *ptr = (unsigned char *)dest;
|
||||||
while (len-- > 0) *ptr++ = (unsigned char)val;
|
while (len-- > 0) *ptr++ = (unsigned char)val;
|
||||||
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memcpy(void *dest, const void *src, size_t len) {
|
void *memcpy(void *dest, const void *src, size_t len) {
|
||||||
unsigned char *d = (unsigned char *)dest;
|
unsigned char *d = (unsigned char *)dest;
|
||||||
const unsigned char *s = (const unsigned char *)src;
|
const unsigned char *s = (const unsigned char *)src;
|
||||||
while (len-- > 0) *d++ = *s++;
|
while (len-- > 0) *d++ = *s++;
|
||||||
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
int memcmp(const void *str1, const void *str2, size_t count) {
|
int memcmp(const void *str1, const void *str2, size_t count) {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
// Kernel string utilities
|
// Kernel string utilities
|
||||||
void *memmove(void *dest, const void *src, uint64_t n);
|
void *memmove(void *dest, const void *src, uint64_t n);
|
||||||
void memset(void *dest, int val, size_t len);
|
void *memset(void *dest, int val, size_t len);
|
||||||
void memcpy(void *dest, const void *src, size_t len);
|
void *memcpy(void *dest, const void *src, size_t len);
|
||||||
int memcmp (const void *str1, const void *str2, size_t count);
|
int memcmp (const void *str1, const void *str2, size_t count);
|
||||||
size_t strlen(const char *str);
|
size_t strlen(const char *str);
|
||||||
int strcmp(const char *s1, const char *s2);
|
int strcmp(const char *s1, const char *s2);
|
||||||
|
|
|
||||||
|
|
@ -493,16 +493,23 @@ void kmain(void) {
|
||||||
serial_write_hex(current_rsp);
|
serial_write_hex(current_rsp);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
|
serial_write("[DBG] before graphics_init_fonts\n");
|
||||||
graphics_init_fonts();
|
graphics_init_fonts();
|
||||||
|
serial_write("[DBG] after graphics_init_fonts\n");
|
||||||
|
|
||||||
asm("cli");
|
serial_write("[DBG] before ps2_init\n");
|
||||||
ps2_init();
|
ps2_init();
|
||||||
asm("sti");
|
serial_write("[DBG] after ps2_init\n");
|
||||||
|
asm("sti"); // Enable interrupts
|
||||||
|
|
||||||
|
serial_write("[DBG] before keymap_init\n");
|
||||||
keymap_init();
|
keymap_init();
|
||||||
serial_write("[INIT] Keymap initialized");
|
serial_write("[DBG] after keymap_init\n");
|
||||||
|
serial_write("[INIT] Keymap initialized\n");
|
||||||
|
|
||||||
|
serial_write("[DBG] before lapic_init\n");
|
||||||
lapic_init();
|
lapic_init();
|
||||||
|
serial_write("[DBG] after lapic_init\n");
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#include "input/keyboard.h"
|
#include "input/keyboard.h"
|
||||||
#include "input/keymap.h"
|
#include "input/keymap.h"
|
||||||
|
|
||||||
|
extern void serial_write(const char *s);
|
||||||
|
extern void serial_write_num(uint32_t n);
|
||||||
extern void serial_print(const char *s);
|
extern void serial_print(const char *s);
|
||||||
extern void serial_print_hex(uint64_t n);
|
extern void serial_print_hex(uint64_t n);
|
||||||
|
|
||||||
|
|
@ -25,6 +27,12 @@ uint64_t timer_handler(registers_t *regs) {
|
||||||
|
|
||||||
extern void k_beep_process(void);
|
extern void k_beep_process(void);
|
||||||
k_beep_process();
|
k_beep_process();
|
||||||
|
|
||||||
|
if (kernel_ticks % 100 == 0) {
|
||||||
|
serial_write("[TIMER] Heartbeat: ");
|
||||||
|
serial_write_num((uint32_t)kernel_ticks);
|
||||||
|
serial_write(" ticks\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outb(0x20, 0x20);
|
outb(0x20, 0x20);
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "lapic.h"
|
#include "lapic.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "spinlock.h"
|
||||||
|
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
// LAPIC is at physical 0xFEE00000. Access via HHDM.
|
// LAPIC is at physical 0xFEE00000. Access via HHDM.
|
||||||
static volatile uint32_t *lapic_base = 0;
|
static volatile uint32_t *lapic_base = 0;
|
||||||
|
static spinlock_t lapic_lock = SPINLOCK_INIT;
|
||||||
|
|
||||||
// LAPIC register offsets (byte offsets, divided by 4 for uint32_t* indexing)
|
// LAPIC register offsets (byte offsets, divided by 4 for uint32_t* indexing)
|
||||||
#define LAPIC_ID (0x020 / 4)
|
#define LAPIC_ID (0x020 / 4)
|
||||||
|
|
@ -41,14 +43,27 @@ void lapic_send_ipi_all(void) {
|
||||||
if (!lapic_base) return;
|
if (!lapic_base) return;
|
||||||
|
|
||||||
// Send IPI to all excluding self
|
// Send IPI to all excluding self
|
||||||
// ICR format:
|
// ICR format:
|
||||||
// bits 7:0 = vector (IPI_SCHED_VECTOR = 0x41)
|
// bits 7:0 = vector (IPI_SCHED_VECTOR = 0x41)
|
||||||
// bits 10:8 = delivery mode (000 = Fixed)
|
// bits 10:8 = delivery mode (000 = Fixed)
|
||||||
// bit 11 = destination mode (0 = Physical)
|
// bit 11 = destination mode (0 = Physical)
|
||||||
// bit 14 = level (1 = Assert)
|
// bit 14 = level: 0 = Edge
|
||||||
// bits 19:18 = destination shorthand (11 = All Excluding Self)
|
// bits 19:18 = destination shorthand (11 = All Excluding Self)
|
||||||
uint32_t icr_low = IPI_SCHED_VECTOR | (0b11 << 18) | (1 << 14);
|
uint32_t icr_low = IPI_SCHED_VECTOR | (0b11 << 18);
|
||||||
|
|
||||||
// Writing ICR_LOW triggers the IPI send
|
uint64_t rflags = spinlock_acquire_irqsave(&lapic_lock);
|
||||||
lapic_base[LAPIC_ICR_LOW] = icr_low;
|
lapic_base[LAPIC_ICR_LOW] = icr_low;
|
||||||
|
while (lapic_base[LAPIC_ICR_LOW] & (1 << 12)) {}
|
||||||
|
spinlock_release_irqrestore(&lapic_lock, rflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_send_ipi(uint32_t lapic_id, uint8_t vector) {
|
||||||
|
if (!lapic_base) return;
|
||||||
|
uint32_t icr_low = (uint32_t)vector;
|
||||||
|
|
||||||
|
uint64_t rflags = spinlock_acquire_irqsave(&lapic_lock);
|
||||||
|
lapic_base[LAPIC_ICR_HIGH] = (lapic_id << 24);
|
||||||
|
lapic_base[LAPIC_ICR_LOW] = icr_low;
|
||||||
|
while (lapic_base[LAPIC_ICR_LOW] & (1 << 12)) {}
|
||||||
|
spinlock_release_irqrestore(&lapic_lock, rflags);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,7 @@ void lapic_eoi(void);
|
||||||
// Send a scheduling IPI to all APs (excludes self)
|
// Send a scheduling IPI to all APs (excludes self)
|
||||||
void lapic_send_ipi_all(void);
|
void lapic_send_ipi_all(void);
|
||||||
|
|
||||||
|
// Send a targeted IPI to a specific LAPIC ID
|
||||||
|
void lapic_send_ipi(uint32_t lapic_id, uint8_t vector);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
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);
|
||||||
|
extern void serial_write_num(uint32_t n);
|
||||||
|
|
||||||
#define MAX_PROCESSES 16
|
#define MAX_PROCESSES 16
|
||||||
#define MAX_CPUS_SCHED 32
|
#define MAX_CPUS_SCHED 32
|
||||||
|
|
@ -507,7 +508,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str, bool t
|
||||||
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)
|
// Assign to a CPU core via round-robin across APs (if SMP is active)
|
||||||
uint32_t cpu_count = smp_cpu_count();
|
uint32_t cpu_count = smp_cpu_count();
|
||||||
if (cpu_count > 1) {
|
if (cpu_count > 1) {
|
||||||
new_proc->cpu_affinity = next_cpu_assign;
|
new_proc->cpu_affinity = next_cpu_assign;
|
||||||
|
|
@ -517,15 +518,29 @@ process_t* process_create_elf(const char* filepath, const char* args_str, bool t
|
||||||
new_proc->cpu_affinity = 0;
|
new_proc->cpu_affinity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to linked list (Critical Section)
|
|
||||||
rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
||||||
new_proc->next = current_process[0]->next;
|
uint32_t target_cpu = new_proc->cpu_affinity;
|
||||||
current_process[0]->next = new_proc;
|
process_t *target_head = current_process[target_cpu];
|
||||||
|
if (target_head) {
|
||||||
|
new_proc->next = target_head->next;
|
||||||
|
target_head->next = new_proc;
|
||||||
|
} else {
|
||||||
|
new_proc->next = new_proc;
|
||||||
|
current_process[target_cpu] = new_proc;
|
||||||
|
}
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
|
|
||||||
serial_write("[PROC] Exec: ");
|
serial_write("[PROC] Exec: ");
|
||||||
serial_write(filepath);
|
serial_write(filepath);
|
||||||
|
serial_write(" on CPU ");
|
||||||
|
serial_write_num(new_proc->cpu_affinity);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
uint32_t target_lapic = smp_get_lapic_id(new_proc->cpu_affinity);
|
||||||
|
if (target_lapic != 0xFF) {
|
||||||
|
lapic_send_ipi(target_lapic, IPI_SCHED_VECTOR);
|
||||||
|
}
|
||||||
|
|
||||||
return new_proc;
|
return new_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ static void ap_entry(struct limine_smp_info *info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_init_bsp(void) {
|
void smp_init_bsp(void) {
|
||||||
static cpu_state_t bsp_state_static = {0};
|
static cpu_state_t bsp_state_static __attribute__((aligned(64))) = {0};
|
||||||
bsp_state_static.cpu_id = 0;
|
bsp_state_static.cpu_id = 0;
|
||||||
bsp_lapic_id = read_lapic_id();
|
bsp_lapic_id = read_lapic_id();
|
||||||
bsp_state_static.lapic_id = bsp_lapic_id;
|
bsp_state_static.lapic_id = bsp_lapic_id;
|
||||||
|
|
@ -138,7 +138,7 @@ void smp_init_bsp(void) {
|
||||||
uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
if (!smp_resp || smp_resp->cpu_count <= 1) {
|
if (!smp_resp || smp_resp->cpu_count <= 1) {
|
||||||
total_cpus = 1;
|
total_cpus = 1;
|
||||||
cpu_states = (cpu_state_t *)kmalloc(sizeof(cpu_state_t));
|
cpu_states = (cpu_state_t *)kmalloc_aligned(sizeof(cpu_state_t), 64);
|
||||||
if (!cpu_states) return 1;
|
if (!cpu_states) return 1;
|
||||||
extern void mem_memset(void *, int, size_t);
|
extern void mem_memset(void *, int, size_t);
|
||||||
mem_memset(cpu_states, 0, sizeof(cpu_state_t));
|
mem_memset(cpu_states, 0, sizeof(cpu_state_t));
|
||||||
|
|
@ -158,7 +158,7 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
serial_write_num(bsp_lapic_id);
|
serial_write_num(bsp_lapic_id);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
cpu_states = (cpu_state_t *)kmalloc(total_cpus * sizeof(cpu_state_t));
|
cpu_states = (cpu_state_t *)kmalloc_aligned(total_cpus * sizeof(cpu_state_t), 64);
|
||||||
if (!cpu_states) {
|
if (!cpu_states) {
|
||||||
serial_write("[SMP] ERROR: Failed to allocate CPU state array!\n");
|
serial_write("[SMP] ERROR: Failed to allocate CPU state array!\n");
|
||||||
total_cpus = 1;
|
total_cpus = 1;
|
||||||
|
|
@ -231,3 +231,8 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
|
|
||||||
return online_count;
|
return online_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t smp_get_lapic_id(uint32_t cpu_id) {
|
||||||
|
if (cpu_id >= total_cpus || !cpu_states) return 0xFF;
|
||||||
|
return cpu_states[cpu_id].lapic_id;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ typedef struct cpu_state {
|
||||||
volatile bool online;
|
volatile bool online;
|
||||||
uint64_t user_rsp_scratch;
|
uint64_t user_rsp_scratch;
|
||||||
uint64_t kernel_syscall_stack;
|
uint64_t kernel_syscall_stack;
|
||||||
|
uint8_t xsave_area[8192] __attribute__((aligned(64)));
|
||||||
} cpu_state_t;
|
} cpu_state_t;
|
||||||
|
|
||||||
void smp_init_bsp(void);
|
void smp_init_bsp(void);
|
||||||
|
|
@ -31,4 +32,6 @@ uint32_t smp_cpu_count(void);
|
||||||
|
|
||||||
cpu_state_t *smp_get_cpu(uint32_t cpu_id);
|
cpu_state_t *smp_get_cpu(uint32_t cpu_id);
|
||||||
|
|
||||||
|
uint32_t smp_get_lapic_id(uint32_t cpu_id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue