Skip to content

Commit d50f9d2

Browse files
committed
APIC: Replace static mut
1 parent cf57761 commit d50f9d2

File tree

1 file changed

+49
-68
lines changed

1 file changed

+49
-68
lines changed

src/arch/x86_64/kernel/apic.rs

Lines changed: 49 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use align_address::Align;
1111
#[cfg(feature = "smp")]
1212
use arch::x86_64::kernel::core_local::*;
1313
use arch::x86_64::kernel::{interrupts, processor};
14-
use hermit_sync::without_interrupts;
14+
use hermit_sync::{without_interrupts, OnceCell, SpinMutex};
1515
#[cfg(feature = "smp")]
1616
use x86::controlregs::*;
1717
use x86::msr::*;
@@ -86,19 +86,16 @@ const SMP_BOOT_CODE_OFFSET_PML4: usize = SMP_BOOT_CODE_OFFSET_BOOTINFO + 0x08;
8686

8787
const X2APIC_ENABLE: u64 = 1 << 10;
8888

89-
static mut LOCAL_APIC_ADDRESS: VirtAddr = VirtAddr::zero();
90-
static mut IOAPIC_ADDRESS: VirtAddr = VirtAddr::zero();
89+
static LOCAL_APIC_ADDRESS: OnceCell<VirtAddr> = OnceCell::new();
90+
static IOAPIC_ADDRESS: OnceCell<VirtAddr> = OnceCell::new();
9191

9292
/// Stores the Local APIC IDs of all CPUs. The index equals the Core ID.
9393
/// Both numbers often match, but don't need to (e.g. when a core has been disabled).
94-
///
95-
/// As Rust currently implements no way of zero-initializing a global Vec in a no_std environment,
96-
/// we have to encapsulate it in an Option...
97-
static mut CPU_LOCAL_APIC_IDS: Option<Vec<u8>> = None;
94+
static CPU_LOCAL_APIC_IDS: SpinMutex<Vec<u8>> = SpinMutex::new(Vec::new());
9895

9996
/// After calibration, initialize the APIC Timer with this counter value to let it fire an interrupt
10097
/// after 1 microsecond.
101-
static mut CALIBRATED_COUNTER_VALUE: u64 = 0;
98+
static CALIBRATED_COUNTER_VALUE: OnceCell<u64> = OnceCell::new();
10299

103100
/// MP Floating Pointer Structure
104101
#[repr(C, packed)]
@@ -241,25 +238,22 @@ extern "x86-interrupt" fn wakeup_handler(_stack_frame: interrupts::ExceptionStac
241238

242239
#[inline]
243240
pub fn add_local_apic_id(id: u8) {
244-
unsafe {
245-
CPU_LOCAL_APIC_IDS.as_mut().unwrap().push(id);
246-
}
241+
CPU_LOCAL_APIC_IDS.lock().push(id);
247242
}
248243

249244
#[cfg(feature = "smp")]
250245
pub fn local_apic_id_count() -> u32 {
251-
unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap().len() as u32 }
246+
CPU_LOCAL_APIC_IDS.lock().len() as u32
252247
}
253248

254-
unsafe fn init_ioapic_address(phys_addr: PhysAddr) {
255-
unsafe {
256-
IOAPIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
257-
debug!("Mapping IOAPIC at {phys_addr:p} to virtual address {IOAPIC_ADDRESS:p}",);
249+
fn init_ioapic_address(phys_addr: PhysAddr) {
250+
let ioapic_address = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
251+
IOAPIC_ADDRESS.set(ioapic_address).unwrap();
252+
debug!("Mapping IOAPIC at {phys_addr:p} to virtual address {ioapic_address:p}",);
258253

259-
let mut flags = PageTableEntryFlags::empty();
260-
flags.device().writable().execute_disable();
261-
paging::map::<BasePageSize>(IOAPIC_ADDRESS, phys_addr, 1, flags);
262-
}
254+
let mut flags = PageTableEntryFlags::empty();
255+
flags.device().writable().execute_disable();
256+
paging::map::<BasePageSize>(ioapic_address, phys_addr, 1, flags);
263257
}
264258

265259
#[cfg(not(feature = "acpi"))]
@@ -301,9 +295,7 @@ fn detect_from_acpi() -> Result<PhysAddr, ()> {
301295
let ioapic_record = unsafe { &*(current_address as *const IoApicRecord) };
302296
debug!("Found I/O APIC record: {}", ioapic_record);
303297

304-
unsafe {
305-
init_ioapic_address(PhysAddr(ioapic_record.address.into()));
306-
}
298+
init_ioapic_address(PhysAddr(ioapic_record.address.into()));
307299
}
308300
_ => {
309301
// Just ignore other entries for now.
@@ -397,9 +389,7 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
397389
warn!("No MP table entries! Guess IO-APIC!");
398390
let default_address = PhysAddr(0xFEC0_0000);
399391

400-
unsafe {
401-
init_ioapic_address(default_address);
402-
}
392+
init_ioapic_address(default_address);
403393
} else {
404394
// entries starts directly after the config table
405395
addr += mem::size_of::<ApicConfigTable>();
@@ -420,9 +410,7 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
420410
let ioapic = PhysAddr(io_entry.addr.into());
421411
info!("Found IOAPIC at 0x{:x}", ioapic);
422412

423-
unsafe {
424-
init_ioapic_address(ioapic);
425-
}
413+
init_ioapic_address(ioapic);
426414

427415
addr += mem::size_of::<ApicIoEntry>();
428416
}
@@ -441,9 +429,7 @@ fn default_apic() -> PhysAddr {
441429

442430
let default_address = PhysAddr(0xFEE0_0000);
443431

444-
unsafe {
445-
init_ioapic_address(default_address);
446-
}
432+
init_ioapic_address(default_address);
447433

448434
default_address
449435
}
@@ -452,9 +438,7 @@ fn detect_from_uhyve() -> Result<PhysAddr, ()> {
452438
if env::is_uhyve() {
453439
let default_address = PhysAddr(0xFEE0_0000);
454440

455-
unsafe {
456-
init_ioapic_address(default_address);
457-
}
441+
init_ioapic_address(default_address);
458442

459443
Ok(default_address)
460444
} else {
@@ -468,11 +452,6 @@ pub extern "C" fn eoi() {
468452
}
469453

470454
pub fn init() {
471-
// Initialize an empty vector for the Local APIC IDs of all CPUs.
472-
unsafe {
473-
CPU_LOCAL_APIC_IDS = Some(Vec::new());
474-
}
475-
476455
// Detect CPUs and APICs.
477456
let local_apic_physical_address = detect_from_uhyve()
478457
.or_else(|_| detect_from_acpi())
@@ -484,17 +463,16 @@ pub fn init() {
484463
if !processor::supports_x2apic() {
485464
// We use the traditional xAPIC mode available on all x86-64 CPUs.
486465
// It uses a mapped page for communication.
487-
unsafe {
488-
LOCAL_APIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
489-
debug!(
490-
"Mapping Local APIC at {:#X} to virtual address {:#X}",
491-
local_apic_physical_address, LOCAL_APIC_ADDRESS
492-
);
466+
let local_apic_address = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
467+
LOCAL_APIC_ADDRESS.set(local_apic_address).unwrap();
468+
debug!(
469+
"Mapping Local APIC at {:#X} to virtual address {:#X}",
470+
local_apic_physical_address, local_apic_address
471+
);
493472

494-
let mut flags = PageTableEntryFlags::empty();
495-
flags.device().writable().execute_disable();
496-
paging::map::<BasePageSize>(LOCAL_APIC_ADDRESS, local_apic_physical_address, 1, flags);
497-
}
473+
let mut flags = PageTableEntryFlags::empty();
474+
flags.device().writable().execute_disable();
475+
paging::map::<BasePageSize>(local_apic_address, local_apic_physical_address, 1, flags);
498476
}
499477

500478
// Set gates to ISRs for the APIC interrupts we are going to enable.
@@ -614,14 +592,14 @@ fn calibrate_timer() {
614592

615593
// Save the difference of the initial value and current value as the result of the calibration
616594
// and re-enable interrupts.
617-
unsafe {
618-
CALIBRATED_COUNTER_VALUE =
619-
(u64::from(u32::MAX - local_apic_read(IA32_X2APIC_CUR_COUNT))) / microseconds;
620-
debug!(
621-
"Calibrated APIC Timer with a counter value of {} for 1 microsecond",
622-
CALIBRATED_COUNTER_VALUE
595+
let calibrated_counter_value =
596+
(u64::from(u32::MAX - local_apic_read(IA32_X2APIC_CUR_COUNT))) / microseconds;
597+
CALIBRATED_COUNTER_VALUE
598+
.set(calibrated_counter_value)
599+
.unwrap();
600+
debug!(
601+
"Calibrated APIC Timer with a counter value of {calibrated_counter_value} for 1 microsecond",
623602
);
624-
}
625603
}
626604

627605
fn __set_oneshot_timer(wakeup_time: Option<u64>) {
@@ -651,7 +629,7 @@ fn __set_oneshot_timer(wakeup_time: Option<u64>) {
651629
1
652630
};
653631
let init_count = cmp::min(
654-
unsafe { CALIBRATED_COUNTER_VALUE } * ticks,
632+
CALIBRATED_COUNTER_VALUE.get().unwrap() * ticks,
655633
u64::from(u32::MAX),
656634
);
657635

@@ -750,7 +728,7 @@ pub fn boot_application_processors() {
750728
}
751729

752730
// Now wake up each application processor.
753-
let apic_ids = unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap() };
731+
let apic_ids = CPU_LOCAL_APIC_IDS.lock();
754732
let core_id = core_id();
755733

756734
for (core_id_to_boot, &apic_id) in apic_ids.iter().enumerate() {
@@ -808,7 +786,7 @@ pub fn boot_application_processors() {
808786
#[cfg(feature = "smp")]
809787
pub fn ipi_tlb_flush() {
810788
if arch::get_processor_count() > 1 {
811-
let apic_ids = unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap() };
789+
let apic_ids = CPU_LOCAL_APIC_IDS.lock();
812790
let core_id = core_id();
813791

814792
// Ensure that all memory operations have completed before issuing a TLB flush.
@@ -839,7 +817,7 @@ pub fn wakeup_core(core_id_to_wakeup: CoreId) {
839817
#[cfg(feature = "smp")]
840818
if core_id_to_wakeup != core_id() {
841819
without_interrupts(|| {
842-
let apic_ids = unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap() };
820+
let apic_ids = CPU_LOCAL_APIC_IDS.lock();
843821
let local_apic_id = apic_ids[core_id_to_wakeup as usize];
844822
let destination = u64::from(local_apic_id) << 32;
845823
local_apic_write(
@@ -856,7 +834,7 @@ pub fn wakeup_core(core_id_to_wakeup: CoreId) {
856834
/// Translate the x2APIC MSR into an xAPIC memory address.
857835
#[inline]
858836
fn translate_x2apic_msr_to_xapic_address(x2apic_msr: u32) -> VirtAddr {
859-
unsafe { LOCAL_APIC_ADDRESS + ((x2apic_msr as u64 & 0xFF) << 4) }
837+
*LOCAL_APIC_ADDRESS.get().unwrap() + ((x2apic_msr as u64 & 0xFF) << 4)
860838
}
861839

862840
fn local_apic_read(x2apic_msr: u32) -> u32 {
@@ -870,9 +848,9 @@ fn local_apic_read(x2apic_msr: u32) -> u32 {
870848

871849
fn ioapic_write(reg: u32, value: u32) {
872850
unsafe {
873-
core::ptr::write_volatile(IOAPIC_ADDRESS.as_mut_ptr::<u32>(), reg);
851+
core::ptr::write_volatile(IOAPIC_ADDRESS.get().unwrap().as_mut_ptr::<u32>(), reg);
874852
core::ptr::write_volatile(
875-
(IOAPIC_ADDRESS + 4 * mem::size_of::<u32>()).as_mut_ptr::<u32>(),
853+
(*IOAPIC_ADDRESS.get().unwrap() + 4 * mem::size_of::<u32>()).as_mut_ptr::<u32>(),
876854
value,
877855
);
878856
}
@@ -882,9 +860,10 @@ fn ioapic_read(reg: u32) -> u32 {
882860
let value;
883861

884862
unsafe {
885-
core::ptr::write_volatile(IOAPIC_ADDRESS.as_mut_ptr::<u32>(), reg);
886-
value =
887-
core::ptr::read_volatile((IOAPIC_ADDRESS + 4 * mem::size_of::<u32>()).as_ptr::<u32>());
863+
core::ptr::write_volatile(IOAPIC_ADDRESS.get().unwrap().as_mut_ptr::<u32>(), reg);
864+
value = core::ptr::read_volatile(
865+
(*IOAPIC_ADDRESS.get().unwrap() + 4 * mem::size_of::<u32>()).as_ptr::<u32>(),
866+
);
888867
}
889868

890869
value
@@ -924,7 +903,9 @@ fn local_apic_write(x2apic_msr: u32, value: u64) {
924903
// Instead of a single 64-bit ICR register, xAPIC has two 32-bit registers (ICR1 and ICR2).
925904
// There is a gap between them and the destination field in ICR2 is also 8 bits instead of 32 bits.
926905
let destination = ((value >> 8) & 0xFF00_0000) as u32;
927-
let icr2 = unsafe { &mut *((LOCAL_APIC_ADDRESS + APIC_ICR2).as_mut_ptr::<u32>()) };
906+
let icr2 = unsafe {
907+
&mut *((*LOCAL_APIC_ADDRESS.get().unwrap() + APIC_ICR2).as_mut_ptr::<u32>())
908+
};
928909
*icr2 = destination;
929910

930911
// The remaining data without the destination will now be written into ICR1.

0 commit comments

Comments
 (0)