@@ -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,14 +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
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) ;
252
257
}
253
258
254
259
#[ cfg( not( feature = "acpi" ) ) ]
@@ -290,23 +295,7 @@ fn detect_from_acpi() -> Result<PhysAddr, ()> {
290
295
let ioapic_record = unsafe { & * ( current_address as * const IoApicRecord ) } ;
291
296
debug ! ( "Found I/O APIC record: {}" , ioapic_record) ;
292
297
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 ( ) ) ) ;
310
299
}
311
300
_ => {
312
301
// Just ignore other entries for now.
@@ -400,17 +389,7 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
400
389
warn ! ( "No MP table entries! Guess IO-APIC!" ) ;
401
390
let default_address = PhysAddr ( 0xFEC0_0000 ) ;
402
391
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) ;
414
393
} else {
415
394
// entries starts directly after the config table
416
395
addr += mem:: size_of :: < ApicConfigTable > ( ) ;
@@ -428,25 +407,10 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
428
407
// IO-APIC entry
429
408
2 => {
430
409
let io_entry: & ApicIoEntry = unsafe { & * ( addr as * const ApicIoEntry ) } ;
431
- let ioapic = io_entry. addr ;
410
+ let ioapic = PhysAddr ( io_entry. addr . into ( ) ) ;
432
411
info ! ( "Found IOAPIC at 0x{:x}" , ioapic) ;
433
412
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) ;
450
414
451
415
addr += mem:: size_of :: < ApicIoEntry > ( ) ;
452
416
}
@@ -463,43 +427,23 @@ fn detect_from_mp() -> Result<PhysAddr, ()> {
463
427
fn default_apic ( ) -> PhysAddr {
464
428
warn ! ( "Try to use default APIC address" ) ;
465
429
466
- let default_address = PhysAddr ( 0xFEC0_0000 ) ;
430
+ let default_address = PhysAddr ( 0xFEE0_0000 ) ;
467
431
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) ;
474
433
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
481
435
}
482
436
483
437
fn detect_from_uhyve ( ) -> Result < PhysAddr , ( ) > {
484
438
if env:: is_uhyve ( ) {
485
- let default_address = PhysAddr ( 0xFEC0_0000 ) ;
439
+ let default_address = PhysAddr ( 0xFEE0_0000 ) ;
486
440
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) ;
498
442
499
- return Ok ( PhysAddr ( 0xFEE0_0000 ) ) ;
443
+ Ok ( default_address)
444
+ } else {
445
+ Err ( ( ) )
500
446
}
501
-
502
- Err ( ( ) )
503
447
}
504
448
505
449
#[ no_mangle]
@@ -508,11 +452,6 @@ pub extern "C" fn eoi() {
508
452
}
509
453
510
454
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
-
516
455
// Detect CPUs and APICs.
517
456
let local_apic_physical_address = detect_from_uhyve ( )
518
457
. or_else ( |_| detect_from_acpi ( ) )
@@ -524,17 +463,16 @@ pub fn init() {
524
463
if !processor:: supports_x2apic ( ) {
525
464
// We use the traditional xAPIC mode available on all x86-64 CPUs.
526
465
// 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
+ ) ;
533
472
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) ;
538
476
}
539
477
540
478
// Set gates to ISRs for the APIC interrupts we are going to enable.
@@ -654,14 +592,14 @@ fn calibrate_timer() {
654
592
655
593
// Save the difference of the initial value and current value as the result of the calibration
656
594
// 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" ,
663
602
) ;
664
- }
665
603
}
666
604
667
605
fn __set_oneshot_timer ( wakeup_time : Option < u64 > ) {
@@ -691,7 +629,7 @@ fn __set_oneshot_timer(wakeup_time: Option<u64>) {
691
629
1
692
630
} ;
693
631
let init_count = cmp:: min (
694
- unsafe { CALIBRATED_COUNTER_VALUE } * ticks,
632
+ CALIBRATED_COUNTER_VALUE . get ( ) . unwrap ( ) * ticks,
695
633
u64:: from ( u32:: MAX ) ,
696
634
) ;
697
635
@@ -790,7 +728,7 @@ pub fn boot_application_processors() {
790
728
}
791
729
792
730
// 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 ( ) ;
794
732
let core_id = core_id ( ) ;
795
733
796
734
for ( core_id_to_boot, & apic_id) in apic_ids. iter ( ) . enumerate ( ) {
@@ -848,7 +786,7 @@ pub fn boot_application_processors() {
848
786
#[ cfg( feature = "smp" ) ]
849
787
pub fn ipi_tlb_flush ( ) {
850
788
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 ( ) ;
852
790
let core_id = core_id ( ) ;
853
791
854
792
// 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) {
879
817
#[ cfg( feature = "smp" ) ]
880
818
if core_id_to_wakeup != core_id ( ) {
881
819
without_interrupts ( || {
882
- let apic_ids = unsafe { CPU_LOCAL_APIC_IDS . as_ref ( ) . unwrap ( ) } ;
820
+ let apic_ids = CPU_LOCAL_APIC_IDS . lock ( ) ;
883
821
let local_apic_id = apic_ids[ core_id_to_wakeup as usize ] ;
884
822
let destination = u64:: from ( local_apic_id) << 32 ;
885
823
local_apic_write (
@@ -896,7 +834,7 @@ pub fn wakeup_core(core_id_to_wakeup: CoreId) {
896
834
/// Translate the x2APIC MSR into an xAPIC memory address.
897
835
#[ inline]
898
836
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 )
900
838
}
901
839
902
840
fn local_apic_read ( x2apic_msr : u32 ) -> u32 {
@@ -910,9 +848,9 @@ fn local_apic_read(x2apic_msr: u32) -> u32 {
910
848
911
849
fn ioapic_write ( reg : u32 , value : u32 ) {
912
850
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) ;
914
852
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 > ( ) ,
916
854
value,
917
855
) ;
918
856
}
@@ -922,9 +860,10 @@ fn ioapic_read(reg: u32) -> u32 {
922
860
let value;
923
861
924
862
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
+ ) ;
928
867
}
929
868
930
869
value
@@ -964,7 +903,9 @@ fn local_apic_write(x2apic_msr: u32, value: u64) {
964
903
// Instead of a single 64-bit ICR register, xAPIC has two 32-bit registers (ICR1 and ICR2).
965
904
// There is a gap between them and the destination field in ICR2 is also 8 bits instead of 32 bits.
966
905
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
+ } ;
968
909
* icr2 = destination;
969
910
970
911
// The remaining data without the destination will now be written into ICR1.
0 commit comments