From 392572ea8070f1593d586122576c88930c735e8b Mon Sep 17 00:00:00 2001 From: Mathieu Strypsteen Date: Tue, 10 Dec 2024 20:38:36 +0100 Subject: [PATCH] Startup additional cores --- Cargo.lock | 28 ++++++++--------- kernel/src/cpu/paging.rs | 17 +++++++--- kernel/src/cpu/trampoline.s | 5 +++ kernel/src/main.rs | 13 +++++++- kernel/src/sys/ioapic.rs | 18 +++++------ kernel/src/sys/lapic.rs | 62 ++++++++++++++++++++++++++++++++++--- kernel/src/sys/madt.rs | 9 ++++-- lib/acpica | 2 +- lib/acpica-rs/Cargo.toml | 2 +- qemu.sh | 2 +- 10 files changed, 119 insertions(+), 39 deletions(-) create mode 100644 kernel/src/cpu/trampoline.s diff --git a/Cargo.lock b/Cargo.lock index 1aa88d9..a13823d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "acpi" @@ -49,9 +49,9 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] name = "bindgen" -version = "0.70.1" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ "bitflags", "cexpr", @@ -64,7 +64,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -228,15 +228,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.164" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets", @@ -314,7 +314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -401,9 +401,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "scopeguard" @@ -448,9 +448,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.89" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -496,7 +496,7 @@ checksum = "9b24e77d3fc1e617051e630f99da24bcae6328abab37b8f9216bb68d06804f9a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] diff --git a/kernel/src/cpu/paging.rs b/kernel/src/cpu/paging.rs index 1136a78..750c182 100644 --- a/kernel/src/cpu/paging.rs +++ b/kernel/src/cpu/paging.rs @@ -136,7 +136,7 @@ fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec table.entries_phys[table_i].set_cache_disable(cache_disable as u64); table.entries_phys[table_i].set_present(1); } -fn unmap(address: u64) { +pub unsafe fn unmap(address: u64) { let mut current_pml4 = CURRENT_PML4.lock(); let page = get_page(current_pml4.as_mut().unwrap(), address); assert!(page.is_some(), "Page isn't mapped"); @@ -149,7 +149,7 @@ fn unmap(address: u64) { None => {} } } -fn map_range(virt_start: u64, phys_start: u64, size: u64, user: bool, write: bool, exec: bool, cache_disable: bool) { +pub unsafe fn map_range(virt_start: u64, phys_start: u64, size: u64, user: bool, write: bool, exec: bool, cache_disable: bool) { assert_eq!(virt_start % 0x1000, 0); assert_eq!(phys_start % 0x1000, 0); assert_eq!(size % 0x1000, 0); @@ -166,7 +166,9 @@ pub unsafe fn map_physical(phys: u64, mut size: u64, write_combining: bool) -> u size = phys_end - phys_start; let virt_start = find_free_virt_range(KERNEL_MAPPINGS_START, KERNEL_MAPPINGS_END, size); let cache_disable = !write_combining; - map_range(virt_start, phys_start, size, false, true, false, cache_disable); + unsafe { + map_range(virt_start, phys_start, size, false, true, false, cache_disable); + } virt_start + phys_offset } pub unsafe fn unmap_physical(address: u64, size: u64) { @@ -174,7 +176,9 @@ pub unsafe fn unmap_physical(address: u64, size: u64) { let start = address / 0x1000 * 0x1000; let size = end - start; for i in 0..size / 0x1000 { - unmap(start + i * 0x1000); + unsafe { + unmap(start + i * 0x1000); + } } } pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64, heap_start: u64) { @@ -189,12 +193,15 @@ pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64, heap_start: u { let mut frames_vec = PHYSICAL_FRAMES.lock(); *frames_vec = Some(bitvec![u64, Lsb0; 1; memory_size as usize]); + let frames_vec = frames_vec.as_mut().unwrap(); for i in loader_struct.available_memory { for j in 0..i.page_count { let page = i.initial_page + j; - frames_vec.as_mut().unwrap().set(page as usize, false); + frames_vec.set(page as usize, false); } } + assert!(!frames_vec.get(1).unwrap()); + frames_vec.set(1, true); } let text_start; let text_end; diff --git a/kernel/src/cpu/trampoline.s b/kernel/src/cpu/trampoline.s new file mode 100644 index 0000000..8bb33f7 --- /dev/null +++ b/kernel/src/cpu/trampoline.s @@ -0,0 +1,5 @@ +.text + +.global ap_trampoline +ap_trampoline: + hlt diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 8e737cd..2a11d4b 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -25,7 +25,16 @@ use kernel_common::{ use log::{error, info}; use misc::display::{display_print, setup_display}; use spin::Mutex; -use sys::{acpica_osl::AE_OK, early_acpi::EarlyACPIHandler, hpet::setup_hpet, lapic::setup_lapic_timer, madt::parse_madt, pic::disable_pic, sync::LOCKS_HELD, task::setup_multitasking}; +use sys::{ + acpica_osl::AE_OK, + early_acpi::EarlyACPIHandler, + hpet::setup_hpet, + lapic::{setup_lapic_timer, start_aps}, + madt::parse_madt, + pic::disable_pic, + sync::LOCKS_HELD, + task::setup_multitasking, +}; mod cpu; mod misc; @@ -50,6 +59,7 @@ static LOADER_STRUCT: Mutex = Mutex::new(LoaderStruct { }); global_asm!(include_str!("cpu/boot.s"), options(att_syntax)); +global_asm!(include_str!("cpu/trampoline.s"), options(att_syntax)); #[no_mangle] extern "C" fn early_main(temp_loader_struct: *const LoaderStruct) -> ! { @@ -90,6 +100,7 @@ fn main() { assert_eq!(status, AE_OK); status = unsafe { AcpiInitializeObjects(ACPI_FULL_INITIALIZATION) }; assert_eq!(status, AE_OK); + start_aps(); } #[panic_handler] fn panic(info: &PanicInfo) -> ! { diff --git a/kernel/src/sys/ioapic.rs b/kernel/src/sys/ioapic.rs index 4fa680f..c76086c 100644 --- a/kernel/src/sys/ioapic.rs +++ b/kernel/src/sys/ioapic.rs @@ -1,6 +1,6 @@ use core::{ ptr::null_mut, - sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering}, + sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, }; use bitfield::bitfield; @@ -12,8 +12,8 @@ use crate::{ struct IOAPIC { address: AtomicPtr, - start_gsi: AtomicU32, - end_gsi: AtomicU32, + start_gsi: AtomicUsize, + end_gsi: AtomicUsize, } bitfield! { struct RedirectionEntry(u64); @@ -29,8 +29,8 @@ bitfield! { } const EMPTY_IOAPIC: IOAPIC = IOAPIC { address: AtomicPtr::new(null_mut()), - start_gsi: AtomicU32::new(0), - end_gsi: AtomicU32::new(0), + start_gsi: AtomicUsize::new(0), + end_gsi: AtomicUsize::new(0), }; const REGISTER_VERSION: u8 = 1; const REGISTER_REDIRECTION: u8 = 0x10; @@ -51,7 +51,7 @@ fn write_register(apic_i: usize, reg_i: u8, val: u32) { } } fn get_apic_for_gsi(gsi: usize) -> usize { - for i in 0..32 { + for i in 0..NEXT_IOAPIC_ID.load(Ordering::SeqCst) { if gsi >= IOAPICS[i].start_gsi.load(Ordering::SeqCst) as usize && gsi < IOAPICS[i].end_gsi.load(Ordering::SeqCst) as usize { return i; } @@ -81,7 +81,7 @@ pub fn set_irq_override(gsi: usize, vector: usize, polarity: u8, trigger: u8) { pub fn register_irq_handler(vector: usize, handler: fn()) { assert!(ISR_HANDLERS.lock()[vector].is_none()); ISR_HANDLERS.lock()[vector] = Some(handler); - for i in 0..32 { + for i in 0..NEXT_IOAPIC_ID.load(Ordering::SeqCst) { let start = IOAPICS[i].start_gsi.load(Ordering::SeqCst); let end = IOAPICS[i].end_gsi.load(Ordering::SeqCst); for j in start..end { @@ -93,12 +93,12 @@ pub fn register_irq_handler(vector: usize, handler: fn()) { } } } -pub fn setup_ioapic(phys: u64, gsi_base: u32) { +pub fn setup_ioapic(phys: u64, gsi_base: usize) { let address = unsafe { map_physical(phys, 0x14, false) as *mut u32 }; let next_id = NEXT_IOAPIC_ID.fetch_add(1, Ordering::SeqCst); IOAPICS[next_id].address.store(address, Ordering::SeqCst); IOAPICS[next_id].start_gsi.store(gsi_base, Ordering::SeqCst); - let max_ints = (read_register(next_id, REGISTER_VERSION) >> 16) & 0xff; + let max_ints = (read_register(next_id, REGISTER_VERSION) >> 16) as usize & 0xff; IOAPICS[next_id].end_gsi.store(gsi_base + max_ints, Ordering::SeqCst); assert!(gsi_base + max_ints < 128); for i in gsi_base..gsi_base + max_ints { diff --git a/kernel/src/sys/lapic.rs b/kernel/src/sys/lapic.rs index 83e078e..d8276b3 100644 --- a/kernel/src/sys/lapic.rs +++ b/kernel/src/sys/lapic.rs @@ -1,23 +1,43 @@ use core::{ - ptr::null_mut, - sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize, Ordering}, + ptr::{copy, null_mut}, + sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}, }; -use crate::cpu::paging::map_physical; +use crate::cpu::paging::{map_physical, map_range, unmap}; use super::hpet::sleep; +extern "C" { + fn ap_trampoline(); +} + +struct LAPIC { + lapic_id: AtomicUsize, + present: AtomicBool, +} + const REGISTER_ID: usize = 8; const REGISTER_EOI: usize = 0x2c; const REGISTER_SPURIOUS_INT: usize = 0x3c; +const REGISTER_ICR_1: usize = 0xc0; +const REGISTER_ICR_2: usize = 0xc4; const REGISTER_TIMER_LVT: usize = 0xc8; const REGISTER_TIMER_INITIAL_COUNT: usize = 0xe0; const REGISTER_TIMER_CURRENT_COUNT: usize = 0xe4; const REGISTER_TIMER_DIVIDE: usize = 0xf8; +const IPI_INIT: u32 = 0x500; +const IPI_STARTUP: u32 = 0x600; + +const EMPTY_LAPIC: LAPIC = LAPIC { + lapic_id: AtomicUsize::new(0), + present: AtomicBool::new(false), +}; static ADDRESS: AtomicPtr = AtomicPtr::new(null_mut()); -pub static BSP_LAPIC_ID: AtomicU8 = AtomicU8::new(0); +pub static BSP_LAPIC_ID: AtomicUsize = AtomicUsize::new(0); +static LAPICS: [LAPIC; 256] = [EMPTY_LAPIC; 256]; static TICKS_PER_MS: AtomicUsize = AtomicUsize::new(0); +static NEXT_LAPIC_ID: AtomicUsize = AtomicUsize::new(0); pub fn send_eoi() { let address = ADDRESS.load(Ordering::SeqCst); @@ -29,7 +49,7 @@ pub fn setup_lapic(phys: u64) { let address = unsafe { map_physical(phys, 0x400, false) as *mut u32 }; ADDRESS.store(address, Ordering::SeqCst); unsafe { - BSP_LAPIC_ID.store(address.add(REGISTER_ID).read_volatile() as u8, Ordering::SeqCst); + BSP_LAPIC_ID.store(address.add(REGISTER_ID).read_volatile() as usize, Ordering::SeqCst); address.add(REGISTER_SPURIOUS_INT).write_volatile(0x1ff); } send_eoi(); @@ -46,6 +66,13 @@ fn calibrate_timer() { address.add(REGISTER_TIMER_INITIAL_COUNT).write_volatile(0); } } +fn send_ipi(lapic_id: usize, data: u32) { + let address = ADDRESS.load(Ordering::SeqCst); + unsafe { + address.add(REGISTER_ICR_2).write_volatile((lapic_id << 24) as u32); + address.add(REGISTER_ICR_1).write_volatile(data); + } +} pub fn schedule_timer_interrupt() { let address = ADDRESS.load(Ordering::SeqCst); unsafe { @@ -62,3 +89,28 @@ pub fn setup_lapic_timer() { address.add(REGISTER_TIMER_LVT).write_volatile(254); } } +pub fn add_lapic(lapic_id: usize) { + let next_id = NEXT_LAPIC_ID.fetch_add(1, Ordering::SeqCst); + LAPICS[next_id].lapic_id.store(lapic_id, Ordering::SeqCst); + LAPICS[next_id].present.store(true, Ordering::SeqCst); +} +pub fn start_aps() { + unsafe { + map_range(0x1000, 0x1000, 0x1000, false, true, false, false); + let dest_ptr = 0x1000 as *mut u8; + let src_ptr = ap_trampoline as *const u8; + copy(src_ptr, dest_ptr, 0x1000); + } + for i in 0..NEXT_LAPIC_ID.load(Ordering::SeqCst) { + let lapic_id = LAPICS[i].lapic_id.load(Ordering::SeqCst); + if lapic_id == BSP_LAPIC_ID.load(Ordering::SeqCst) { + continue; + } + send_ipi(lapic_id, IPI_INIT); + sleep(10000); + send_ipi(lapic_id, IPI_STARTUP | 1); + } + unsafe { + unmap(0x1000); + } +} diff --git a/kernel/src/sys/madt.rs b/kernel/src/sys/madt.rs index 68814ff..33f5f7c 100644 --- a/kernel/src/sys/madt.rs +++ b/kernel/src/sys/madt.rs @@ -7,7 +7,7 @@ use kernel_common::instructions::sti; use super::{ early_acpi::EarlyACPIHandler, ioapic::{set_irq_override, setup_ioapic}, - lapic::setup_lapic, + lapic::{add_lapic, setup_lapic}, }; pub fn parse_madt(tables: &AcpiTables) { @@ -17,11 +17,16 @@ pub fn parse_madt(tables: &AcpiTables) { if let MadtEntry::LocalApicAddressOverride(lapic_override) = i { lapic_address = lapic_override.local_apic_address; } + if let MadtEntry::LocalApic(lapic) = i { + if lapic.flags & 1 == 1 || lapic.flags & 2 == 2 { + add_lapic(lapic.apic_id as usize); + } + } } setup_lapic(lapic_address); for i in madt.entries() { if let MadtEntry::IoApic(ioapic) = i { - setup_ioapic(ioapic.io_apic_address as u64, ioapic.global_system_interrupt_base); + setup_ioapic(ioapic.io_apic_address as u64, ioapic.global_system_interrupt_base as usize); } } for i in madt.entries() { diff --git a/lib/acpica b/lib/acpica index 993a257..437f7e1 160000 --- a/lib/acpica +++ b/lib/acpica @@ -1 +1 @@ -Subproject commit 993a25704ac18784b44c1af75cb54abec5141981 +Subproject commit 437f7e1a0039d227d3952677c3f9f5ad9c814395 diff --git a/lib/acpica-rs/Cargo.toml b/lib/acpica-rs/Cargo.toml index 753c4f3..9adc0f3 100644 --- a/lib/acpica-rs/Cargo.toml +++ b/lib/acpica-rs/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" license = "BSD-3-Clause-acpica" [build-dependencies] -bindgen = "0.70.1" +bindgen = "0.71.0" diff --git a/qemu.sh b/qemu.sh index b287118..71378ce 100755 --- a/qemu.sh +++ b/qemu.sh @@ -2,4 +2,4 @@ # shellcheck disable=SC2068 set -euo pipefail ./build.sh -qemu-system-x86_64 -M q35 -accel kvm -cpu qemu64,rdrand,smap,smep -m 256M -L /usr/share/OVMF -bios OVMF_CODE.fd -drive file=img/os.img,format=raw $@ +qemu-system-x86_64 -M q35 -accel kvm -cpu qemu64,rdrand,smap,smep -smp 4 -m 256M -L /usr/share/OVMF -bios OVMF_CODE.fd -drive file=img/os.img,format=raw $@