Startup additional cores
All checks were successful
Build / build (push) Successful in 1m15s

This commit is contained in:
Mathieu Strypsteen 2024-12-10 20:38:36 +01:00
parent b9ab8da576
commit 392572ea80
10 changed files with 119 additions and 39 deletions

28
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "acpi" name = "acpi"
@ -49,9 +49,9 @@ checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.70.1" version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cexpr", "cexpr",
@ -64,7 +64,7 @@ dependencies = [
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn 2.0.89", "syn 2.0.90",
] ]
[[package]] [[package]]
@ -228,15 +228,15 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.164" version = "0.2.168"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.8.5" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets", "windows-targets",
@ -314,7 +314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn 2.0.89", "syn 2.0.90",
] ]
[[package]] [[package]]
@ -401,9 +401,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "1.1.0" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
@ -448,9 +448,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.89" version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -496,7 +496,7 @@ checksum = "9b24e77d3fc1e617051e630f99da24bcae6328abab37b8f9216bb68d06804f9a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.89", "syn 2.0.90",
] ]
[[package]] [[package]]

View file

@ -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_cache_disable(cache_disable as u64);
table.entries_phys[table_i].set_present(1); 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 mut current_pml4 = CURRENT_PML4.lock();
let page = get_page(current_pml4.as_mut().unwrap(), address); let page = get_page(current_pml4.as_mut().unwrap(), address);
assert!(page.is_some(), "Page isn't mapped"); assert!(page.is_some(), "Page isn't mapped");
@ -149,7 +149,7 @@ fn unmap(address: u64) {
None => {} 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!(virt_start % 0x1000, 0);
assert_eq!(phys_start % 0x1000, 0); assert_eq!(phys_start % 0x1000, 0);
assert_eq!(size % 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; size = phys_end - phys_start;
let virt_start = find_free_virt_range(KERNEL_MAPPINGS_START, KERNEL_MAPPINGS_END, size); let virt_start = find_free_virt_range(KERNEL_MAPPINGS_START, KERNEL_MAPPINGS_END, size);
let cache_disable = !write_combining; 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 virt_start + phys_offset
} }
pub unsafe fn unmap_physical(address: u64, size: u64) { 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 start = address / 0x1000 * 0x1000;
let size = end - start; let size = end - start;
for i in 0..size / 0x1000 { 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) { 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(); let mut frames_vec = PHYSICAL_FRAMES.lock();
*frames_vec = Some(bitvec![u64, Lsb0; 1; memory_size as usize]); *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 i in loader_struct.available_memory {
for j in 0..i.page_count { for j in 0..i.page_count {
let page = i.initial_page + j; 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_start;
let text_end; let text_end;

View file

@ -0,0 +1,5 @@
.text
.global ap_trampoline
ap_trampoline:
hlt

View file

@ -25,7 +25,16 @@ use kernel_common::{
use log::{error, info}; use log::{error, info};
use misc::display::{display_print, setup_display}; use misc::display::{display_print, setup_display};
use spin::Mutex; 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 cpu;
mod misc; mod misc;
@ -50,6 +59,7 @@ static LOADER_STRUCT: Mutex<LoaderStruct> = Mutex::new(LoaderStruct {
}); });
global_asm!(include_str!("cpu/boot.s"), options(att_syntax)); global_asm!(include_str!("cpu/boot.s"), options(att_syntax));
global_asm!(include_str!("cpu/trampoline.s"), options(att_syntax));
#[no_mangle] #[no_mangle]
extern "C" fn early_main(temp_loader_struct: *const LoaderStruct) -> ! { extern "C" fn early_main(temp_loader_struct: *const LoaderStruct) -> ! {
@ -90,6 +100,7 @@ fn main() {
assert_eq!(status, AE_OK); assert_eq!(status, AE_OK);
status = unsafe { AcpiInitializeObjects(ACPI_FULL_INITIALIZATION) }; status = unsafe { AcpiInitializeObjects(ACPI_FULL_INITIALIZATION) };
assert_eq!(status, AE_OK); assert_eq!(status, AE_OK);
start_aps();
} }
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {

View file

@ -1,6 +1,6 @@
use core::{ use core::{
ptr::null_mut, ptr::null_mut,
sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering}, sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
}; };
use bitfield::bitfield; use bitfield::bitfield;
@ -12,8 +12,8 @@ use crate::{
struct IOAPIC { struct IOAPIC {
address: AtomicPtr<u32>, address: AtomicPtr<u32>,
start_gsi: AtomicU32, start_gsi: AtomicUsize,
end_gsi: AtomicU32, end_gsi: AtomicUsize,
} }
bitfield! { bitfield! {
struct RedirectionEntry(u64); struct RedirectionEntry(u64);
@ -29,8 +29,8 @@ bitfield! {
} }
const EMPTY_IOAPIC: IOAPIC = IOAPIC { const EMPTY_IOAPIC: IOAPIC = IOAPIC {
address: AtomicPtr::new(null_mut()), address: AtomicPtr::new(null_mut()),
start_gsi: AtomicU32::new(0), start_gsi: AtomicUsize::new(0),
end_gsi: AtomicU32::new(0), end_gsi: AtomicUsize::new(0),
}; };
const REGISTER_VERSION: u8 = 1; const REGISTER_VERSION: u8 = 1;
const REGISTER_REDIRECTION: u8 = 0x10; 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 { 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 { if gsi >= IOAPICS[i].start_gsi.load(Ordering::SeqCst) as usize && gsi < IOAPICS[i].end_gsi.load(Ordering::SeqCst) as usize {
return i; 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()) { pub fn register_irq_handler(vector: usize, handler: fn()) {
assert!(ISR_HANDLERS.lock()[vector].is_none()); assert!(ISR_HANDLERS.lock()[vector].is_none());
ISR_HANDLERS.lock()[vector] = Some(handler); 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 start = IOAPICS[i].start_gsi.load(Ordering::SeqCst);
let end = IOAPICS[i].end_gsi.load(Ordering::SeqCst); let end = IOAPICS[i].end_gsi.load(Ordering::SeqCst);
for j in start..end { 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 address = unsafe { map_physical(phys, 0x14, false) as *mut u32 };
let next_id = NEXT_IOAPIC_ID.fetch_add(1, Ordering::SeqCst); let next_id = NEXT_IOAPIC_ID.fetch_add(1, Ordering::SeqCst);
IOAPICS[next_id].address.store(address, Ordering::SeqCst); IOAPICS[next_id].address.store(address, Ordering::SeqCst);
IOAPICS[next_id].start_gsi.store(gsi_base, 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); IOAPICS[next_id].end_gsi.store(gsi_base + max_ints, Ordering::SeqCst);
assert!(gsi_base + max_ints < 128); assert!(gsi_base + max_ints < 128);
for i in gsi_base..gsi_base + max_ints { for i in gsi_base..gsi_base + max_ints {

View file

@ -1,23 +1,43 @@
use core::{ use core::{
ptr::null_mut, ptr::{copy, null_mut},
sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize, Ordering}, 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; use super::hpet::sleep;
extern "C" {
fn ap_trampoline();
}
struct LAPIC {
lapic_id: AtomicUsize,
present: AtomicBool,
}
const REGISTER_ID: usize = 8; const REGISTER_ID: usize = 8;
const REGISTER_EOI: usize = 0x2c; const REGISTER_EOI: usize = 0x2c;
const REGISTER_SPURIOUS_INT: usize = 0x3c; 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_LVT: usize = 0xc8;
const REGISTER_TIMER_INITIAL_COUNT: usize = 0xe0; const REGISTER_TIMER_INITIAL_COUNT: usize = 0xe0;
const REGISTER_TIMER_CURRENT_COUNT: usize = 0xe4; const REGISTER_TIMER_CURRENT_COUNT: usize = 0xe4;
const REGISTER_TIMER_DIVIDE: usize = 0xf8; 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<u32> = AtomicPtr::new(null_mut()); static ADDRESS: AtomicPtr<u32> = 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 TICKS_PER_MS: AtomicUsize = AtomicUsize::new(0);
static NEXT_LAPIC_ID: AtomicUsize = AtomicUsize::new(0);
pub fn send_eoi() { pub fn send_eoi() {
let address = ADDRESS.load(Ordering::SeqCst); 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 }; let address = unsafe { map_physical(phys, 0x400, false) as *mut u32 };
ADDRESS.store(address, Ordering::SeqCst); ADDRESS.store(address, Ordering::SeqCst);
unsafe { 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); address.add(REGISTER_SPURIOUS_INT).write_volatile(0x1ff);
} }
send_eoi(); send_eoi();
@ -46,6 +66,13 @@ fn calibrate_timer() {
address.add(REGISTER_TIMER_INITIAL_COUNT).write_volatile(0); 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() { pub fn schedule_timer_interrupt() {
let address = ADDRESS.load(Ordering::SeqCst); let address = ADDRESS.load(Ordering::SeqCst);
unsafe { unsafe {
@ -62,3 +89,28 @@ pub fn setup_lapic_timer() {
address.add(REGISTER_TIMER_LVT).write_volatile(254); 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);
}
}

View file

@ -7,7 +7,7 @@ use kernel_common::instructions::sti;
use super::{ use super::{
early_acpi::EarlyACPIHandler, early_acpi::EarlyACPIHandler,
ioapic::{set_irq_override, setup_ioapic}, ioapic::{set_irq_override, setup_ioapic},
lapic::setup_lapic, lapic::{add_lapic, setup_lapic},
}; };
pub fn parse_madt(tables: &AcpiTables<EarlyACPIHandler>) { pub fn parse_madt(tables: &AcpiTables<EarlyACPIHandler>) {
@ -17,11 +17,16 @@ pub fn parse_madt(tables: &AcpiTables<EarlyACPIHandler>) {
if let MadtEntry::LocalApicAddressOverride(lapic_override) = i { if let MadtEntry::LocalApicAddressOverride(lapic_override) = i {
lapic_address = lapic_override.local_apic_address; 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); setup_lapic(lapic_address);
for i in madt.entries() { for i in madt.entries() {
if let MadtEntry::IoApic(ioapic) = i { 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() { for i in madt.entries() {

@ -1 +1 @@
Subproject commit 993a25704ac18784b44c1af75cb54abec5141981 Subproject commit 437f7e1a0039d227d3952677c3f9f5ad9c814395

View file

@ -5,4 +5,4 @@ edition = "2021"
license = "BSD-3-Clause-acpica" license = "BSD-3-Clause-acpica"
[build-dependencies] [build-dependencies]
bindgen = "0.70.1" bindgen = "0.71.0"

View file

@ -2,4 +2,4 @@
# shellcheck disable=SC2068 # shellcheck disable=SC2068
set -euo pipefail set -euo pipefail
./build.sh ./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 $@