@@ -11,7 +11,7 @@ use align_address::Align;
11
11
#[ cfg( feature = "smp" ) ]
12
12
use arch:: x86_64:: kernel:: core_local:: * ;
13
13
use arch:: x86_64:: kernel:: { interrupts, processor} ;
14
- use hermit_sync:: without_interrupts;
14
+ use hermit_sync:: { without_interrupts, OnceCell , SpinMutex } ;
15
15
#[ cfg( feature = "smp" ) ]
16
16
use x86:: controlregs:: * ;
17
17
use x86:: msr:: * ;
@@ -86,19 +86,16 @@ const SMP_BOOT_CODE_OFFSET_PML4: usize = SMP_BOOT_CODE_OFFSET_BOOTINFO + 0x08;
86
86
87
87
const X2APIC_ENABLE : u64 = 1 << 10 ;
88
88
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 ( ) ;
91
91
92
92
/// Stores the Local APIC IDs of all CPUs. The index equals the Core ID.
93
93
/// 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 ( ) ) ;
98
95
99
96
/// After calibration, initialize the APIC Timer with this counter value to let it fire an interrupt
100
97
/// after 1 microsecond.
101
- static mut CALIBRATED_COUNTER_VALUE : u64 = 0 ;
98
+ static CALIBRATED_COUNTER_VALUE : OnceCell < u64 > = OnceCell :: new ( ) ;
102
99
103
100
/// MP Floating Pointer Structure
104
101
#[ repr( C , packed) ]
@@ -241,25 +238,22 @@ extern "x86-interrupt" fn wakeup_handler(_stack_frame: interrupts::ExceptionStac
241
238
242
239
#[ inline]
243
240
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) ;
247
242
}
248
243
249
244
#[ cfg( feature = "smp" ) ]
250
245
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
252
247
}
253
248
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}" , ) ;
258
253
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) ;
263
257
}
264
258
265
259
#[ cfg( not( feature = "acpi" ) ) ]
@@ -301,9 +295,7 @@ fn detect_from_acpi() -> Result<PhysAddr, ()> {
301
295
let ioapic_record = unsafe { & * ( current_address as * const IoApicRecord ) } ;
302
296
debug ! ( "Found I/O APIC record: {}" , ioapic_record) ;
303
297
304
- unsafe {
305
- init_ioapic_address ( PhysAddr ( ioapic_record. address . into ( ) ) ) ;
306
- }
298
+ init_ioapic_address ( PhysAddr ( ioapic_record. address . into ( ) ) ) ;
307
299
}
308
300
_ => {
309
301
// Just ignore other entries for now.
@@ -397,9 +389,7 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
397
389
warn ! ( "No MP table entries! Guess IO-APIC!" ) ;
398
390
let default_address = PhysAddr ( 0xFEC0_0000 ) ;
399
391
400
- unsafe {
401
- init_ioapic_address ( default_address) ;
402
- }
392
+ init_ioapic_address ( default_address) ;
403
393
} else {
404
394
// entries starts directly after the config table
405
395
addr += mem:: size_of :: < ApicConfigTable > ( ) ;
@@ -420,9 +410,7 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
420
410
let ioapic = PhysAddr ( io_entry. addr . into ( ) ) ;
421
411
info ! ( "Found IOAPIC at 0x{:x}" , ioapic) ;
422
412
423
- unsafe {
424
- init_ioapic_address ( ioapic) ;
425
- }
413
+ init_ioapic_address ( ioapic) ;
426
414
427
415
addr += mem:: size_of :: < ApicIoEntry > ( ) ;
428
416
}
@@ -441,9 +429,7 @@ fn default_apic() -> PhysAddr {
441
429
442
430
let default_address = PhysAddr ( 0xFEE0_0000 ) ;
443
431
444
- unsafe {
445
- init_ioapic_address ( default_address) ;
446
- }
432
+ init_ioapic_address ( default_address) ;
447
433
448
434
default_address
449
435
}
@@ -452,9 +438,7 @@ fn detect_from_uhyve() -> Result<PhysAddr, ()> {
452
438
if env:: is_uhyve ( ) {
453
439
let default_address = PhysAddr ( 0xFEE0_0000 ) ;
454
440
455
- unsafe {
456
- init_ioapic_address ( default_address) ;
457
- }
441
+ init_ioapic_address ( default_address) ;
458
442
459
443
Ok ( default_address)
460
444
} else {
@@ -468,11 +452,6 @@ pub extern "C" fn eoi() {
468
452
}
469
453
470
454
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
-
476
455
// Detect CPUs and APICs.
477
456
let local_apic_physical_address = detect_from_uhyve ( )
478
457
. or_else ( |_| detect_from_acpi ( ) )
@@ -484,17 +463,16 @@ pub fn init() {
484
463
if !processor:: supports_x2apic ( ) {
485
464
// We use the traditional xAPIC mode available on all x86-64 CPUs.
486
465
// 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
+ ) ;
493
472
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) ;
498
476
}
499
477
500
478
// Set gates to ISRs for the APIC interrupts we are going to enable.
@@ -614,14 +592,14 @@ fn calibrate_timer() {
614
592
615
593
// Save the difference of the initial value and current value as the result of the calibration
616
594
// 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" ,
623
602
) ;
624
- }
625
603
}
626
604
627
605
fn __set_oneshot_timer ( wakeup_time : Option < u64 > ) {
@@ -651,7 +629,7 @@ fn __set_oneshot_timer(wakeup_time: Option<u64>) {
651
629
1
652
630
} ;
653
631
let init_count = cmp:: min (
654
- unsafe { CALIBRATED_COUNTER_VALUE } * ticks,
632
+ CALIBRATED_COUNTER_VALUE . get ( ) . unwrap ( ) * ticks,
655
633
u64:: from ( u32:: MAX ) ,
656
634
) ;
657
635
@@ -750,7 +728,7 @@ pub fn boot_application_processors() {
750
728
}
751
729
752
730
// 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 ( ) ;
754
732
let core_id = core_id ( ) ;
755
733
756
734
for ( core_id_to_boot, & apic_id) in apic_ids. iter ( ) . enumerate ( ) {
@@ -808,7 +786,7 @@ pub fn boot_application_processors() {
808
786
#[ cfg( feature = "smp" ) ]
809
787
pub fn ipi_tlb_flush ( ) {
810
788
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 ( ) ;
812
790
let core_id = core_id ( ) ;
813
791
814
792
// 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) {
839
817
#[ cfg( feature = "smp" ) ]
840
818
if core_id_to_wakeup != core_id ( ) {
841
819
without_interrupts ( || {
842
- let apic_ids = unsafe { CPU_LOCAL_APIC_IDS . as_ref ( ) . unwrap ( ) } ;
820
+ let apic_ids = CPU_LOCAL_APIC_IDS . lock ( ) ;
843
821
let local_apic_id = apic_ids[ core_id_to_wakeup as usize ] ;
844
822
let destination = u64:: from ( local_apic_id) << 32 ;
845
823
local_apic_write (
@@ -856,7 +834,7 @@ pub fn wakeup_core(core_id_to_wakeup: CoreId) {
856
834
/// Translate the x2APIC MSR into an xAPIC memory address.
857
835
#[ inline]
858
836
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 )
860
838
}
861
839
862
840
fn local_apic_read ( x2apic_msr : u32 ) -> u32 {
@@ -870,9 +848,9 @@ fn local_apic_read(x2apic_msr: u32) -> u32 {
870
848
871
849
fn ioapic_write ( reg : u32 , value : u32 ) {
872
850
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) ;
874
852
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 > ( ) ,
876
854
value,
877
855
) ;
878
856
}
@@ -882,9 +860,10 @@ fn ioapic_read(reg: u32) -> u32 {
882
860
let value;
883
861
884
862
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
+ ) ;
888
867
}
889
868
890
869
value
@@ -924,7 +903,9 @@ fn local_apic_write(x2apic_msr: u32, value: u64) {
924
903
// Instead of a single 64-bit ICR register, xAPIC has two 32-bit registers (ICR1 and ICR2).
925
904
// There is a gap between them and the destination field in ICR2 is also 8 bits instead of 32 bits.
926
905
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
+ } ;
928
909
* icr2 = destination;
929
910
930
911
// The remaining data without the destination will now be written into ICR1.
0 commit comments