Initialize local APICs on every processors

This commit is contained in:
Zhang Junyang
2024-08-30 15:53:16 +08:00
committed by Tate, Hongliang Tian
parent 425027677b
commit 326ec09169
6 changed files with 43 additions and 20 deletions

View File

@ -150,7 +150,7 @@ fn send_startup_to_all_aps() {
(AP_BOOT_START_PA / PAGE_SIZE) as u8,
);
// SAFETY: we are sending startup IPI to all APs.
apic::borrow(|apic| unsafe { apic.send_ipi(icr) });
apic::with_borrow(|apic| unsafe { apic.send_ipi(icr) });
}
fn send_init_to_all_aps() {
@ -165,7 +165,7 @@ fn send_init_to_all_aps() {
0,
);
// SAFETY: we are sending init IPI to all APs.
apic::borrow(|apic| unsafe { apic.send_ipi(icr) });
apic::with_borrow(|apic| unsafe { apic.send_ipi(icr) });
}
fn send_init_deassert() {
@ -180,7 +180,7 @@ fn send_init_deassert() {
0,
);
// SAFETY: we are sending deassert IPI to all APs.
apic::borrow(|apic| unsafe { apic.send_ipi(icr) });
apic::with_borrow(|apic| unsafe { apic.send_ipi(icr) });
}
/// Spin wait approximately `c` cycles.

View File

@ -173,7 +173,7 @@ pub(crate) unsafe fn send_ipi(cpu_id: u32, irq_num: u8) {
apic::DeliveryMode::Fixed,
irq_num,
);
apic::borrow(|apic| {
apic::with_borrow(|apic| {
apic.send_ipi(icr);
});
}

View File

@ -13,7 +13,7 @@ pub mod x2apic;
pub mod xapic;
cpu_local! {
static APIC_INSTANCE: Once<RefCell<Box<dyn Apic + 'static>>> = Once::new();
static APIC_INSTANCE: RefCell<Option<Box<dyn Apic + 'static>>> = RefCell::new(None);
}
static APIC_TYPE: Once<ApicType> = Once::new();
@ -24,23 +24,29 @@ static APIC_TYPE: Once<ApicType> = Once::new();
/// local APIC instance. During the execution of the closure, the interrupts
/// are guaranteed to be disabled.
///
/// This function also lazily initializes the Local APIC instance. It does
/// enable the Local APIC if it is not enabled.
///
/// Example:
/// ```rust
/// use ostd::arch::x86::kernel::apic;
///
/// let ticks = apic::borrow(|apic| {
/// let ticks = apic::with_borrow(|apic| {
/// let ticks = apic.timer_current_count();
/// apic.set_timer_init_count(0);
/// ticks
/// });
/// ```
pub fn borrow<R>(f: impl FnOnce(&mut (dyn Apic + 'static)) -> R) -> R {
pub fn with_borrow<R>(f: impl FnOnce(&mut (dyn Apic + 'static)) -> R) -> R {
let irq_guard = crate::trap::disable_local();
let apic_guard = APIC_INSTANCE.get_with(&irq_guard);
let mut apic_init_ref = apic_guard.borrow_mut();
// If it is not initialized, lazily initialize it.
if !apic_guard.is_completed() {
apic_guard.call_once(|| match APIC_TYPE.get().unwrap() {
let apic_ref = if let Some(apic_ref) = apic_init_ref.as_mut() {
apic_ref
} else {
*apic_init_ref = Some(match APIC_TYPE.get().unwrap() {
ApicType::XApic => {
let mut xapic = xapic::XApic::new().unwrap();
xapic.enable();
@ -51,7 +57,7 @@ pub fn borrow<R>(f: impl FnOnce(&mut (dyn Apic + 'static)) -> R) -> R {
version & 0xff,
(version >> 16) & 0xff
);
RefCell::new(Box::new(xapic))
Box::new(xapic)
}
ApicType::X2Apic => {
let mut x2apic = x2apic::X2Apic::new().unwrap();
@ -63,13 +69,12 @@ pub fn borrow<R>(f: impl FnOnce(&mut (dyn Apic + 'static)) -> R) -> R {
version & 0xff,
(version >> 16) & 0xff
);
RefCell::new(Box::new(x2apic))
Box::new(x2apic)
}
});
}
let apic_cell = apic_guard.get().unwrap();
let mut apic_ref = apic_cell.borrow_mut();
apic_init_ref.as_mut().unwrap()
};
let ret = f.call_once((apic_ref.as_mut(),));

View File

@ -108,10 +108,21 @@ pub(crate) fn init_on_bsp() {
kernel::pic::init();
}
/// Architecture-specific initialization on the application processor.
///
/// # Safety
///
/// This function must be called only once on each application processor.
/// And it should be called after the BSP's call to [`init_on_bsp`].
pub(crate) unsafe fn init_on_ap() {
// Trigger the initialization of the local APIC.
crate::arch::x86::kernel::apic::with_borrow(|_| {});
}
pub(crate) fn interrupts_ack(irq_number: usize) {
if !cpu::CpuException::is_cpu_exception(irq_number as u16) {
kernel::pic::ack();
kernel::apic::borrow(|apic| {
kernel::apic::with_borrow(|apic| {
apic.eoi();
});
}

View File

@ -54,7 +54,7 @@ fn is_tsc_deadline_mode_supported() -> bool {
fn init_tsc_mode() -> IrqLine {
let timer_irq = IrqLine::alloc().unwrap();
// Enable tsc deadline mode
apic::borrow(|apic| {
apic::with_borrow(|apic| {
apic.set_lvt_timer(timer_irq.num() as u64 | (1 << 18));
});
let tsc_step = TSC_FREQ.load(Ordering::Relaxed) / TIMER_FREQ;
@ -81,7 +81,7 @@ fn init_periodic_mode() -> IrqLine {
super::pit::enable_ioapic_line(irq.clone());
// Set APIC timer count
apic::borrow(|apic| {
apic::with_borrow(|apic| {
apic.set_timer_div_config(DivideConfig::Divide64);
apic.set_timer_init_count(0xFFFF_FFFF);
});
@ -99,7 +99,7 @@ fn init_periodic_mode() -> IrqLine {
// Init APIC Timer
let timer_irq = IrqLine::alloc().unwrap();
apic::borrow(|apic| {
apic::with_borrow(|apic| {
apic.set_timer_init_count(INIT_COUNT.load(Ordering::Relaxed));
apic.set_lvt_timer(timer_irq.num() as u64 | (1 << 17));
apic.set_timer_div_config(DivideConfig::Divide64);
@ -115,7 +115,7 @@ fn init_periodic_mode() -> IrqLine {
if IN_TIME.load(Ordering::Relaxed) < CALLBACK_TIMES || IS_FINISH.load(Ordering::Acquire) {
if IN_TIME.load(Ordering::Relaxed) == 0 {
let remain_ticks = apic::borrow(|apic| apic.timer_current_count());
let remain_ticks = apic::with_borrow(|apic| apic.timer_current_count());
APIC_FIRST_COUNT.store(0xFFFF_FFFF - remain_ticks, Ordering::Relaxed);
}
IN_TIME.fetch_add(1, Ordering::Relaxed);
@ -124,7 +124,7 @@ fn init_periodic_mode() -> IrqLine {
// Stop PIT and APIC Timer
super::pit::disable_ioapic_line();
let remain_ticks = apic::borrow(|apic| {
let remain_ticks = apic::with_borrow(|apic| {
let remain_ticks = apic.timer_current_count();
apic.set_timer_init_count(0);
remain_ticks

View File

@ -123,6 +123,13 @@ fn ap_early_entry(local_apic_id: u32) -> ! {
unsafe {
trapframe::init();
}
// SAFETY: this function is only called once on this AP, after the BSP has
// done the architecture-specific initialization.
unsafe {
crate::arch::init_on_ap();
}
crate::arch::irq::enable_local();
// SAFETY: this function is only called once on this AP.