Skip to content

Commit c44c211

Browse files
bors[bot]mkroening
andauthored
Merge #646
646: APIC: Replace static mut r=stlankes a=mkroening Co-authored-by: Martin Kröning <mkroening@posteo.net>
2 parents 60fc624 + d50f9d2 commit c44c211

File tree

1 file changed

+59
-118
lines changed

1 file changed

+59
-118
lines changed

src/arch/x86_64/kernel/apic.rs

Lines changed: 59 additions & 118 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,14 +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
247+
}
248+
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}",);
253+
254+
let mut flags = PageTableEntryFlags::empty();
255+
flags.device().writable().execute_disable();
256+
paging::map::<BasePageSize>(ioapic_address, phys_addr, 1, flags);
252257
}
253258

254259
#[cfg(not(feature = "acpi"))]
@@ -290,23 +295,7 @@ fn detect_from_acpi() -> Result<PhysAddr, ()> {
290295
let ioapic_record = unsafe { &*(current_address as *const IoApicRecord) };
291296
debug!("Found I/O APIC record: {}", ioapic_record);
292297

293-
unsafe {
294-
IOAPIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
295-
let record_addr = ioapic_record.address;
296-
debug!(
297-
"Mapping IOAPIC at {:#X} to virtual address {:#X}",
298-
record_addr, IOAPIC_ADDRESS
299-
);
300-
301-
let mut flags = PageTableEntryFlags::empty();
302-
flags.device().writable().execute_disable();
303-
paging::map::<BasePageSize>(
304-
IOAPIC_ADDRESS,
305-
PhysAddr(record_addr.into()),
306-
1,
307-
flags,
308-
);
309-
}
298+
init_ioapic_address(PhysAddr(ioapic_record.address.into()));
310299
}
311300
_ => {
312301
// Just ignore other entries for now.
@@ -400,17 +389,7 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
400389
warn!("No MP table entries! Guess IO-APIC!");
401390
let default_address = PhysAddr(0xFEC0_0000);
402391

403-
unsafe {
404-
IOAPIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
405-
debug!(
406-
"Mapping IOAPIC at {:#X} to virtual address {:#X}",
407-
default_address, IOAPIC_ADDRESS
408-
);
409-
410-
let mut flags = PageTableEntryFlags::empty();
411-
flags.device().writable().execute_disable();
412-
paging::map::<BasePageSize>(IOAPIC_ADDRESS, default_address, 1, flags);
413-
}
392+
init_ioapic_address(default_address);
414393
} else {
415394
// entries starts directly after the config table
416395
addr += mem::size_of::<ApicConfigTable>();
@@ -428,25 +407,10 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
428407
// IO-APIC entry
429408
2 => {
430409
let io_entry: &ApicIoEntry = unsafe { &*(addr as *const ApicIoEntry) };
431-
let ioapic = io_entry.addr;
410+
let ioapic = PhysAddr(io_entry.addr.into());
432411
info!("Found IOAPIC at 0x{:x}", ioapic);
433412

434-
unsafe {
435-
IOAPIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
436-
debug!(
437-
"Mapping IOAPIC at {:#X} to virtual address {:#X}",
438-
ioapic, IOAPIC_ADDRESS
439-
);
440-
441-
let mut flags = PageTableEntryFlags::empty();
442-
flags.device().writable().execute_disable();
443-
paging::map::<BasePageSize>(
444-
IOAPIC_ADDRESS,
445-
PhysAddr(ioapic as u64),
446-
1,
447-
flags,
448-
);
449-
}
413+
init_ioapic_address(ioapic);
450414

451415
addr += mem::size_of::<ApicIoEntry>();
452416
}
@@ -463,43 +427,23 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
463427
fn default_apic() -> PhysAddr {
464428
warn!("Try to use default APIC address");
465429

466-
let default_address = PhysAddr(0xFEC0_0000);
430+
let default_address = PhysAddr(0xFEE0_0000);
467431

468-
unsafe {
469-
IOAPIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
470-
debug!(
471-
"Mapping IOAPIC at {:#X} to virtual address {:#X}",
472-
default_address, IOAPIC_ADDRESS
473-
);
432+
init_ioapic_address(default_address);
474433

475-
let mut flags = PageTableEntryFlags::empty();
476-
flags.device().writable().execute_disable();
477-
paging::map::<BasePageSize>(IOAPIC_ADDRESS, default_address, 1, flags);
478-
}
479-
480-
PhysAddr(0xFEE0_0000)
434+
default_address
481435
}
482436

483437
fn detect_from_uhyve() -> Result<PhysAddr, ()> {
484438
if env::is_uhyve() {
485-
let default_address = PhysAddr(0xFEC0_0000);
439+
let default_address = PhysAddr(0xFEE0_0000);
486440

487-
unsafe {
488-
IOAPIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
489-
debug!(
490-
"Mapping IOAPIC at {:#X} to virtual address {:#X}",
491-
default_address, IOAPIC_ADDRESS
492-
);
493-
494-
let mut flags = PageTableEntryFlags::empty();
495-
flags.device().writable().execute_disable();
496-
paging::map::<BasePageSize>(IOAPIC_ADDRESS, default_address, 1, flags);
497-
}
441+
init_ioapic_address(default_address);
498442

499-
return Ok(PhysAddr(0xFEE0_0000));
443+
Ok(default_address)
444+
} else {
445+
Err(())
500446
}
501-
502-
Err(())
503447
}
504448

505449
#[no_mangle]
@@ -508,11 +452,6 @@ pub extern "C" fn eoi() {
508452
}
509453

510454
pub fn init() {
511-
// Initialize an empty vector for the Local APIC IDs of all CPUs.
512-
unsafe {
513-
CPU_LOCAL_APIC_IDS = Some(Vec::new());
514-
}
515-
516455
// Detect CPUs and APICs.
517456
let local_apic_physical_address = detect_from_uhyve()
518457
.or_else(|_| detect_from_acpi())
@@ -524,17 +463,16 @@ pub fn init() {
524463
if !processor::supports_x2apic() {
525464
// We use the traditional xAPIC mode available on all x86-64 CPUs.
526465
// It uses a mapped page for communication.
527-
unsafe {
528-
LOCAL_APIC_ADDRESS = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
529-
debug!(
530-
"Mapping Local APIC at {:#X} to virtual address {:#X}",
531-
local_apic_physical_address, LOCAL_APIC_ADDRESS
532-
);
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+
);
533472

534-
let mut flags = PageTableEntryFlags::empty();
535-
flags.device().writable().execute_disable();
536-
paging::map::<BasePageSize>(LOCAL_APIC_ADDRESS, local_apic_physical_address, 1, flags);
537-
}
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);
538476
}
539477

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

655593
// Save the difference of the initial value and current value as the result of the calibration
656594
// and re-enable interrupts.
657-
unsafe {
658-
CALIBRATED_COUNTER_VALUE =
659-
(u64::from(u32::MAX - local_apic_read(IA32_X2APIC_CUR_COUNT))) / microseconds;
660-
debug!(
661-
"Calibrated APIC Timer with a counter value of {} for 1 microsecond",
662-
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",
663602
);
664-
}
665603
}
666604

667605
fn __set_oneshot_timer(wakeup_time: Option<u64>) {
@@ -691,7 +629,7 @@ fn __set_oneshot_timer(wakeup_time: Option<u64>) {
691629
1
692630
};
693631
let init_count = cmp::min(
694-
unsafe { CALIBRATED_COUNTER_VALUE } * ticks,
632+
CALIBRATED_COUNTER_VALUE.get().unwrap() * ticks,
695633
u64::from(u32::MAX),
696634
);
697635

@@ -790,7 +728,7 @@ pub fn boot_application_processors() {
790728
}
791729

792730
// Now wake up each application processor.
793-
let apic_ids = unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap() };
731+
let apic_ids = CPU_LOCAL_APIC_IDS.lock();
794732
let core_id = core_id();
795733

796734
for (core_id_to_boot, &apic_id) in apic_ids.iter().enumerate() {
@@ -848,7 +786,7 @@ pub fn boot_application_processors() {
848786
#[cfg(feature = "smp")]
849787
pub fn ipi_tlb_flush() {
850788
if arch::get_processor_count() > 1 {
851-
let apic_ids = unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap() };
789+
let apic_ids = CPU_LOCAL_APIC_IDS.lock();
852790
let core_id = core_id();
853791

854792
// Ensure that all memory operations have completed before issuing a TLB flush.
@@ -879,7 +817,7 @@ pub fn wakeup_core(core_id_to_wakeup: CoreId) {
879817
#[cfg(feature = "smp")]
880818
if core_id_to_wakeup != core_id() {
881819
without_interrupts(|| {
882-
let apic_ids = unsafe { CPU_LOCAL_APIC_IDS.as_ref().unwrap() };
820+
let apic_ids = CPU_LOCAL_APIC_IDS.lock();
883821
let local_apic_id = apic_ids[core_id_to_wakeup as usize];
884822
let destination = u64::from(local_apic_id) << 32;
885823
local_apic_write(
@@ -896,7 +834,7 @@ pub fn wakeup_core(core_id_to_wakeup: CoreId) {
896834
/// Translate the x2APIC MSR into an xAPIC memory address.
897835
#[inline]
898836
fn translate_x2apic_msr_to_xapic_address(x2apic_msr: u32) -> VirtAddr {
899-
unsafe { LOCAL_APIC_ADDRESS + ((x2apic_msr as u64 & 0xFF) << 4) }
837+
*LOCAL_APIC_ADDRESS.get().unwrap() + ((x2apic_msr as u64 & 0xFF) << 4)
900838
}
901839

902840
fn local_apic_read(x2apic_msr: u32) -> u32 {
@@ -910,9 +848,9 @@ fn local_apic_read(x2apic_msr: u32) -> u32 {
910848

911849
fn ioapic_write(reg: u32, value: u32) {
912850
unsafe {
913-
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);
914852
core::ptr::write_volatile(
915-
(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>(),
916854
value,
917855
);
918856
}
@@ -922,9 +860,10 @@ fn ioapic_read(reg: u32) -> u32 {
922860
let value;
923861

924862
unsafe {
925-
core::ptr::write_volatile(IOAPIC_ADDRESS.as_mut_ptr::<u32>(), reg);
926-
value =
927-
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+
);
928867
}
929868

930869
value
@@ -964,7 +903,9 @@ fn local_apic_write(x2apic_msr: u32, value: u64) {
964903
// Instead of a single 64-bit ICR register, xAPIC has two 32-bit registers (ICR1 and ICR2).
965904
// There is a gap between them and the destination field in ICR2 is also 8 bits instead of 32 bits.
966905
let destination = ((value >> 8) & 0xFF00_0000) as u32;
967-
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+
};
968909
*icr2 = destination;
969910

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

0 commit comments

Comments
 (0)