fix(smp): add per-core TSS descriptors in GDT and defer AP wakeup after kernel init
This commit is contained in:
+78
-21
@@ -1,7 +1,10 @@
|
||||
//! Global Descriptor Table (GDT) and Task State Segment (TSS) for x86_64
|
||||
//! Global Descriptor Table (GDT) and Task State Segment (TSS) for x86_64 SMP
|
||||
//! Supports up to 4 CPU Cores with dedicated TSS descriptors.
|
||||
|
||||
use core::mem::size_of;
|
||||
|
||||
pub const MAX_CPUS: usize = 4;
|
||||
|
||||
#[repr(C, packed)]
|
||||
pub struct TaskStateSegment {
|
||||
_reserved1: u32,
|
||||
@@ -40,37 +43,60 @@ struct GdtDescriptor {
|
||||
#[no_mangle]
|
||||
pub static mut TSS: TaskStateSegment = TaskStateSegment::new();
|
||||
|
||||
// 8 entries: Null, KCode, KData, UData, UCode, TSS Low, TSS High, Null
|
||||
static mut GDT: [u64; 8] = [
|
||||
#[no_mangle]
|
||||
pub static mut PER_CPU_TSS: [TaskStateSegment; MAX_CPUS] = [const { TaskStateSegment::new() }; MAX_CPUS];
|
||||
|
||||
// GDT entries:
|
||||
// 0: Null
|
||||
// 1: Kernel Code 64 (0x08)
|
||||
// 2: Kernel Data 64 (0x10)
|
||||
// 3: User Data 64 (0x18)
|
||||
// 4: User Code 64 (0x20)
|
||||
// 5,6: TSS CPU 0 (0x28)
|
||||
// 7,8: TSS CPU 1 (0x38)
|
||||
// 9,10: TSS CPU 2 (0x48)
|
||||
// 11,12: TSS CPU 3 (0x58)
|
||||
// 13,14,15: padding
|
||||
static mut GDT: [u64; 16] = [
|
||||
0x0000000000000000, // 0x00: Null
|
||||
0x00af9a000000ffff, // 0x08: Kernel Code 64 (Ring 0)
|
||||
0x00cf92000000ffff, // 0x10: Kernel Data 64 (Ring 0)
|
||||
0x00cff2000000ffff, // 0x18: User Data 64 (Ring 3)
|
||||
0x00affa000000ffff, // 0x20: User Code 64 (Ring 3)
|
||||
0x0000000000000000, // 0x28: TSS Low (populated at init)
|
||||
0x0000000000000000, // 0x30: TSS High (populated at init)
|
||||
0x0000000000000000, // 0x38: Alignment / padding
|
||||
0, 0, // 0x28: TSS CPU 0
|
||||
0, 0, // 0x38: TSS CPU 1
|
||||
0, 0, // 0x48: TSS CPU 2
|
||||
0, 0, // 0x58: TSS CPU 3
|
||||
0, 0, 0, // Padding
|
||||
];
|
||||
|
||||
pub unsafe fn init() {
|
||||
let tss_addr = core::ptr::addr_of!(TSS) as u64;
|
||||
let tss_size = (size_of::<TaskStateSegment>() - 1) as u64;
|
||||
|
||||
// Build 64-bit TSS descriptor
|
||||
let tss_low = (tss_size & 0xffff)
|
||||
| ((tss_addr & 0xffff) << 16)
|
||||
| (((tss_addr >> 16) & 0xff) << 32)
|
||||
| (0x89u64 << 40) // Present, 64-bit TSS (Available)
|
||||
| (((tss_size >> 16) & 0xf) << 48)
|
||||
| (((tss_addr >> 24) & 0xff) << 56);
|
||||
let tss_high = tss_addr >> 32;
|
||||
|
||||
let gdt_ptr = core::ptr::addr_of_mut!(GDT) as *mut u64;
|
||||
*gdt_ptr.add(5) = tss_low;
|
||||
*gdt_ptr.add(6) = tss_high;
|
||||
|
||||
// Populate TSS descriptors for all supported CPU cores
|
||||
for cpu in 0..MAX_CPUS {
|
||||
let tss_addr = if cpu == 0 {
|
||||
core::ptr::addr_of!(TSS) as u64
|
||||
} else {
|
||||
core::ptr::addr_of!(PER_CPU_TSS[cpu]) as u64
|
||||
};
|
||||
let tss_size = (size_of::<TaskStateSegment>() - 1) as u64;
|
||||
|
||||
let tss_low = (tss_size & 0xffff)
|
||||
| ((tss_addr & 0xffff) << 16)
|
||||
| (((tss_addr >> 16) & 0xff) << 32)
|
||||
| (0x89u64 << 40) // Present, 64-bit TSS (Available)
|
||||
| (((tss_size >> 16) & 0xf) << 48)
|
||||
| (((tss_addr >> 24) & 0xff) << 56);
|
||||
let tss_high = tss_addr >> 32;
|
||||
|
||||
let entry_idx = 5 + cpu * 2;
|
||||
*gdt_ptr.add(entry_idx) = tss_low;
|
||||
*gdt_ptr.add(entry_idx + 1) = tss_high;
|
||||
}
|
||||
|
||||
let descriptor = GdtDescriptor {
|
||||
limit: (size_of::<[u64; 8]>() - 1) as u16,
|
||||
limit: (size_of::<[u64; 16]>() - 1) as u16,
|
||||
base: gdt_ptr as u64,
|
||||
};
|
||||
|
||||
@@ -95,6 +121,37 @@ pub unsafe fn init() {
|
||||
);
|
||||
}
|
||||
|
||||
/// Initialize GDT and load dedicated TSS for an Application Processor (AP)
|
||||
pub unsafe fn init_ap(cpu_id: usize) {
|
||||
let gdt_ptr = core::ptr::addr_of_mut!(GDT) as *mut u64;
|
||||
let descriptor = GdtDescriptor {
|
||||
limit: (size_of::<[u64; 16]>() - 1) as u16,
|
||||
base: gdt_ptr as u64,
|
||||
};
|
||||
|
||||
let tss_sel = (0x28 + (cpu_id.min(MAX_CPUS - 1) * 16)) as u16;
|
||||
|
||||
core::arch::asm!(
|
||||
"lgdt [{0}]",
|
||||
"push 0x08",
|
||||
"lea {tmp}, [2f + rip]",
|
||||
"push {tmp}",
|
||||
"retfq",
|
||||
"2:",
|
||||
"mov ax, 0x10",
|
||||
"mov ds, ax",
|
||||
"mov es, ax",
|
||||
"mov ss, ax",
|
||||
"mov fs, ax",
|
||||
"mov gs, ax",
|
||||
"ltr {tss_sel:x}",
|
||||
in(reg) &descriptor,
|
||||
tmp = out(reg) _,
|
||||
tss_sel = in(reg) tss_sel,
|
||||
options(preserves_flags)
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn set_kernel_stack(stack_top: u64) {
|
||||
unsafe {
|
||||
|
||||
+15
-7
@@ -12,15 +12,15 @@ pub extern "C" fn ap_startup(info: *const LimineSmpInfo) -> ! {
|
||||
let cpu_id = (*info).processor_id;
|
||||
let lapic_id = (*info).lapic_id;
|
||||
|
||||
// Initialize CPU Architecture for this AP
|
||||
super::gdt::init();
|
||||
// Initialize CPU Architecture for this AP with dedicated TSS selector
|
||||
super::gdt::init_ap(cpu_id as usize);
|
||||
super::idt::init();
|
||||
super::syscall::init();
|
||||
|
||||
CORES_ONLINE.fetch_add(1, Ordering::SeqCst);
|
||||
kprintln!("[SMP] CPU Core [{}] (LAPIC ID: {}) is ONLINE and entering scheduler.", cpu_id, lapic_id);
|
||||
kprintln!("[SMP] CPU Core [{}] (LAPIC ID: {}) is ONLINE.", cpu_id, lapic_id);
|
||||
|
||||
// Enter AP idle / scheduling loop
|
||||
// AP idle loop - ready for SMP thread scheduling
|
||||
loop {
|
||||
core::arch::asm!("sti; hlt");
|
||||
}
|
||||
@@ -36,14 +36,22 @@ pub unsafe fn init() {
|
||||
|
||||
let cpu_count = (*smp_resp).cpu_count;
|
||||
let bsp_lapic_id = (*smp_resp).bsp_lapic_id;
|
||||
|
||||
kprintln!("[SMP] Detected {} CPU Core(s) (BSP LAPIC ID: {})", cpu_count, bsp_lapic_id);
|
||||
}
|
||||
|
||||
/// Wake up all secondary Application Processors after memory & scheduler are initialized
|
||||
pub unsafe fn boot_aps() {
|
||||
let smp_resp = SMP_REQUEST.response;
|
||||
if smp_resp.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
let cpu_count = (*smp_resp).cpu_count;
|
||||
let bsp_lapic_id = (*smp_resp).bsp_lapic_id;
|
||||
|
||||
// Boot all Application Processors (APs)
|
||||
for i in 0..cpu_count {
|
||||
let cpu_info = *(*smp_resp).cpus.add(i as usize);
|
||||
if (*cpu_info).lapic_id != bsp_lapic_id {
|
||||
// Write our entry trampoline to wake up the AP
|
||||
let info_mut = cpu_info as *mut LimineSmpInfo;
|
||||
(*info_mut).goto_address = Some(ap_startup);
|
||||
}
|
||||
|
||||
+6
-1
@@ -82,7 +82,12 @@ pub extern "C" fn _start() -> ! {
|
||||
// 8. Initialize Scheduler
|
||||
sched::init();
|
||||
|
||||
// 9. Inspect and Load Initial Userspace Processes
|
||||
// 9. Bring up SMP Cores (APs)
|
||||
unsafe {
|
||||
arch::smp::boot_aps();
|
||||
}
|
||||
|
||||
// 10. Inspect and Load Initial Userspace Processes
|
||||
unsafe {
|
||||
let mod_resp = MODULE_REQUEST.response;
|
||||
if !mod_resp.is_null() && (*mod_resp).module_count > 0 {
|
||||
|
||||
@@ -35,22 +35,17 @@ impl FrameAllocator {
|
||||
|
||||
let entry_count = (*memmap).entry_count as usize;
|
||||
let entries_ptr = (*memmap).entries;
|
||||
kprintln!("[PFA] entry_count={}, entries_ptr={:#018x}", entry_count, entries_ptr as u64);
|
||||
|
||||
let mut max_paddr: u64 = 0;
|
||||
for i in 0..entry_count {
|
||||
let entry = *entries_ptr.add(i);
|
||||
let end = (*entry).base + (*entry).length;
|
||||
kprintln!("[PFA] entry[{}]: base={:#x} len={:#x} type={}", i, (*entry).base, (*entry).length, (*entry).typ);
|
||||
if end > max_paddr {
|
||||
max_paddr = end;
|
||||
}
|
||||
}
|
||||
|
||||
kprintln!("[PFA] max_paddr={:#x}", max_paddr);
|
||||
self.total_frames = (max_paddr as usize) / PAGE_SIZE;
|
||||
self.bitmap_size_bytes = (self.total_frames + 7) / 8;
|
||||
kprintln!("[PFA] total_frames={}, bitmap_size={} bytes", self.total_frames, self.bitmap_size_bytes);
|
||||
|
||||
// Find a usable region large enough to place the bitmap
|
||||
let mut bitmap_paddr: u64 = 0;
|
||||
@@ -68,11 +63,8 @@ impl FrameAllocator {
|
||||
kprintln!("[FATAL] Could not find memory for PFA bitmap!");
|
||||
return;
|
||||
}
|
||||
kprintln!("[PFA] Bitmap at phys={:#x}, virt={:#x}", bitmap_paddr, bitmap_paddr + hhdm);
|
||||
|
||||
self.bitmap = (bitmap_paddr + hhdm) as *mut u8;
|
||||
core::ptr::write_bytes(self.bitmap, 0xFF, self.bitmap_size_bytes);
|
||||
kprintln!("[PFA] Bitmap zeroed OK");
|
||||
|
||||
self.free_frames = 0;
|
||||
for i in 0..entry_count {
|
||||
|
||||
Reference in New Issue
Block a user