mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 17:33:23 +00:00
Initialize local APICs on every processors
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
425027677b
commit
326ec09169
@ -150,7 +150,7 @@ fn send_startup_to_all_aps() {
|
|||||||
(AP_BOOT_START_PA / PAGE_SIZE) as u8,
|
(AP_BOOT_START_PA / PAGE_SIZE) as u8,
|
||||||
);
|
);
|
||||||
// SAFETY: we are sending startup IPI to all APs.
|
// 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() {
|
fn send_init_to_all_aps() {
|
||||||
@ -165,7 +165,7 @@ fn send_init_to_all_aps() {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
// SAFETY: we are sending init IPI to all APs.
|
// 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() {
|
fn send_init_deassert() {
|
||||||
@ -180,7 +180,7 @@ fn send_init_deassert() {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
// SAFETY: we are sending deassert IPI to all APs.
|
// 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.
|
/// Spin wait approximately `c` cycles.
|
||||||
|
@ -173,7 +173,7 @@ pub(crate) unsafe fn send_ipi(cpu_id: u32, irq_num: u8) {
|
|||||||
apic::DeliveryMode::Fixed,
|
apic::DeliveryMode::Fixed,
|
||||||
irq_num,
|
irq_num,
|
||||||
);
|
);
|
||||||
apic::borrow(|apic| {
|
apic::with_borrow(|apic| {
|
||||||
apic.send_ipi(icr);
|
apic.send_ipi(icr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub mod x2apic;
|
|||||||
pub mod xapic;
|
pub mod xapic;
|
||||||
|
|
||||||
cpu_local! {
|
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();
|
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
|
/// local APIC instance. During the execution of the closure, the interrupts
|
||||||
/// are guaranteed to be disabled.
|
/// 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:
|
/// Example:
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use ostd::arch::x86::kernel::apic;
|
/// use ostd::arch::x86::kernel::apic;
|
||||||
///
|
///
|
||||||
/// let ticks = apic::borrow(|apic| {
|
/// let ticks = apic::with_borrow(|apic| {
|
||||||
/// let ticks = apic.timer_current_count();
|
/// let ticks = apic.timer_current_count();
|
||||||
/// apic.set_timer_init_count(0);
|
/// apic.set_timer_init_count(0);
|
||||||
/// ticks
|
/// 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 irq_guard = crate::trap::disable_local();
|
||||||
let apic_guard = APIC_INSTANCE.get_with(&irq_guard);
|
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 it is not initialized, lazily initialize it.
|
||||||
if !apic_guard.is_completed() {
|
let apic_ref = if let Some(apic_ref) = apic_init_ref.as_mut() {
|
||||||
apic_guard.call_once(|| match APIC_TYPE.get().unwrap() {
|
apic_ref
|
||||||
|
} else {
|
||||||
|
*apic_init_ref = Some(match APIC_TYPE.get().unwrap() {
|
||||||
ApicType::XApic => {
|
ApicType::XApic => {
|
||||||
let mut xapic = xapic::XApic::new().unwrap();
|
let mut xapic = xapic::XApic::new().unwrap();
|
||||||
xapic.enable();
|
xapic.enable();
|
||||||
@ -51,7 +57,7 @@ pub fn borrow<R>(f: impl FnOnce(&mut (dyn Apic + 'static)) -> R) -> R {
|
|||||||
version & 0xff,
|
version & 0xff,
|
||||||
(version >> 16) & 0xff
|
(version >> 16) & 0xff
|
||||||
);
|
);
|
||||||
RefCell::new(Box::new(xapic))
|
Box::new(xapic)
|
||||||
}
|
}
|
||||||
ApicType::X2Apic => {
|
ApicType::X2Apic => {
|
||||||
let mut x2apic = x2apic::X2Apic::new().unwrap();
|
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 & 0xff,
|
||||||
(version >> 16) & 0xff
|
(version >> 16) & 0xff
|
||||||
);
|
);
|
||||||
RefCell::new(Box::new(x2apic))
|
Box::new(x2apic)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let apic_cell = apic_guard.get().unwrap();
|
apic_init_ref.as_mut().unwrap()
|
||||||
let mut apic_ref = apic_cell.borrow_mut();
|
};
|
||||||
|
|
||||||
let ret = f.call_once((apic_ref.as_mut(),));
|
let ret = f.call_once((apic_ref.as_mut(),));
|
||||||
|
|
||||||
|
@ -108,10 +108,21 @@ pub(crate) fn init_on_bsp() {
|
|||||||
kernel::pic::init();
|
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) {
|
pub(crate) fn interrupts_ack(irq_number: usize) {
|
||||||
if !cpu::CpuException::is_cpu_exception(irq_number as u16) {
|
if !cpu::CpuException::is_cpu_exception(irq_number as u16) {
|
||||||
kernel::pic::ack();
|
kernel::pic::ack();
|
||||||
kernel::apic::borrow(|apic| {
|
kernel::apic::with_borrow(|apic| {
|
||||||
apic.eoi();
|
apic.eoi();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ fn is_tsc_deadline_mode_supported() -> bool {
|
|||||||
fn init_tsc_mode() -> IrqLine {
|
fn init_tsc_mode() -> IrqLine {
|
||||||
let timer_irq = IrqLine::alloc().unwrap();
|
let timer_irq = IrqLine::alloc().unwrap();
|
||||||
// Enable tsc deadline mode
|
// Enable tsc deadline mode
|
||||||
apic::borrow(|apic| {
|
apic::with_borrow(|apic| {
|
||||||
apic.set_lvt_timer(timer_irq.num() as u64 | (1 << 18));
|
apic.set_lvt_timer(timer_irq.num() as u64 | (1 << 18));
|
||||||
});
|
});
|
||||||
let tsc_step = TSC_FREQ.load(Ordering::Relaxed) / TIMER_FREQ;
|
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());
|
super::pit::enable_ioapic_line(irq.clone());
|
||||||
|
|
||||||
// Set APIC timer count
|
// Set APIC timer count
|
||||||
apic::borrow(|apic| {
|
apic::with_borrow(|apic| {
|
||||||
apic.set_timer_div_config(DivideConfig::Divide64);
|
apic.set_timer_div_config(DivideConfig::Divide64);
|
||||||
apic.set_timer_init_count(0xFFFF_FFFF);
|
apic.set_timer_init_count(0xFFFF_FFFF);
|
||||||
});
|
});
|
||||||
@ -99,7 +99,7 @@ fn init_periodic_mode() -> IrqLine {
|
|||||||
// Init APIC Timer
|
// Init APIC Timer
|
||||||
let timer_irq = IrqLine::alloc().unwrap();
|
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_timer_init_count(INIT_COUNT.load(Ordering::Relaxed));
|
||||||
apic.set_lvt_timer(timer_irq.num() as u64 | (1 << 17));
|
apic.set_lvt_timer(timer_irq.num() as u64 | (1 << 17));
|
||||||
apic.set_timer_div_config(DivideConfig::Divide64);
|
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) < CALLBACK_TIMES || IS_FINISH.load(Ordering::Acquire) {
|
||||||
if IN_TIME.load(Ordering::Relaxed) == 0 {
|
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);
|
APIC_FIRST_COUNT.store(0xFFFF_FFFF - remain_ticks, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
IN_TIME.fetch_add(1, Ordering::Relaxed);
|
IN_TIME.fetch_add(1, Ordering::Relaxed);
|
||||||
@ -124,7 +124,7 @@ fn init_periodic_mode() -> IrqLine {
|
|||||||
|
|
||||||
// Stop PIT and APIC Timer
|
// Stop PIT and APIC Timer
|
||||||
super::pit::disable_ioapic_line();
|
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();
|
let remain_ticks = apic.timer_current_count();
|
||||||
apic.set_timer_init_count(0);
|
apic.set_timer_init_count(0);
|
||||||
remain_ticks
|
remain_ticks
|
||||||
|
@ -123,6 +123,13 @@ fn ap_early_entry(local_apic_id: u32) -> ! {
|
|||||||
unsafe {
|
unsafe {
|
||||||
trapframe::init();
|
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();
|
crate::arch::irq::enable_local();
|
||||||
|
|
||||||
// SAFETY: this function is only called once on this AP.
|
// SAFETY: this function is only called once on this AP.
|
||||||
|
Reference in New Issue
Block a user