@@ -45,18 +45,19 @@ use crate::task::{schedule, schedule_task, KernelThreadStartInfo, RunQueue, Task
4545use crate :: types:: {
4646 PAGE_SHIFT , PAGE_SHIFT_2M , PAGE_SIZE , PAGE_SIZE_2M , SVSM_TR_ATTRIBUTES , SVSM_TSS ,
4747} ;
48+ use crate :: utils:: immut_after_init:: ImmutAfterInitCell ;
4849use crate :: utils:: MemoryRegion ;
4950use alloc:: boxed:: Box ;
5051use alloc:: string:: String ;
5152use alloc:: sync:: Arc ;
5253use alloc:: vec:: Vec ;
5354use core:: arch:: asm;
54- use core:: cell:: { Cell , OnceCell , Ref , RefCell , RefMut , UnsafeCell } ;
55+ use core:: cell:: { Cell , Ref , RefCell , RefMut , UnsafeCell } ;
5556use core:: mem:: size_of;
5657use core:: ops:: Deref ;
5758use core:: ptr;
5859use core:: slice:: Iter ;
59- use core:: sync:: atomic:: { AtomicBool , AtomicU32 , Ordering } ;
60+ use core:: sync:: atomic:: { AtomicBool , AtomicU32 , AtomicU64 , Ordering } ;
6061use cpuarch:: vmsa:: VMSA ;
6162
6263// PERCPU areas virtual addresses into shared memory
@@ -163,15 +164,15 @@ impl PerCpuAreas {
163164
164165#[ derive( Debug ) ]
165166struct IstStacks {
166- double_fault_stack : Cell < Option < VirtAddr > > ,
167- double_fault_shadow_stack : Cell < Option < VirtAddr > > ,
167+ double_fault_stack : ImmutAfterInitCell < VirtAddr > ,
168+ double_fault_shadow_stack : ImmutAfterInitCell < VirtAddr > ,
168169}
169170
170171impl IstStacks {
171172 const fn new ( ) -> Self {
172173 IstStacks {
173- double_fault_stack : Cell :: new ( None ) ,
174- double_fault_shadow_stack : Cell :: new ( None ) ,
174+ double_fault_stack : ImmutAfterInitCell :: uninit ( ) ,
175+ double_fault_shadow_stack : ImmutAfterInitCell :: uninit ( ) ,
175176 }
176177 }
177178}
@@ -368,8 +369,8 @@ pub struct PerCpu {
368369 pgtbl : RefCell < Option < & ' static mut PageTable > > ,
369370 tss : X86Tss ,
370371 isst : Cell < Isst > ,
371- svsm_vmsa : OnceCell < VmsaPage > ,
372- reset_ip : Cell < u64 > ,
372+ svsm_vmsa : ImmutAfterInitCell < VmsaPage > ,
373+ reset_ip : AtomicU64 ,
373374 /// PerCpu Virtual Memory Range
374375 vm_range : VMR ,
375376 /// Address allocator for per-cpu 4k temporary mappings
@@ -382,16 +383,16 @@ pub struct PerCpu {
382383 guest_apic : RefCell < Option < LocalApic > > ,
383384
384385 /// GHCB page for this CPU.
385- ghcb : OnceCell < GhcbPage > ,
386+ ghcb : ImmutAfterInitCell < GhcbPage > ,
386387
387388 /// Hypercall input/output pages for this CPU if running under Hyper-V.
388389 hypercall_pages : RefCell < Option < ( HypercallPage , HypercallPage ) > > ,
389390
390391 /// `#HV` doorbell page for this CPU.
391- hv_doorbell : OnceCell < SharedBox < HVDoorbell > > ,
392+ hv_doorbell : ImmutAfterInitCell < SharedBox < HVDoorbell > > ,
392393
393- init_shadow_stack : Cell < Option < VirtAddr > > ,
394- context_switch_stack : Cell < Option < VirtAddr > > ,
394+ init_shadow_stack : ImmutAfterInitCell < VirtAddr > ,
395+ context_switch_stack : ImmutAfterInitCell < VirtAddr > ,
395396 ist : IstStacks ,
396397
397398 /// Stack boundaries of the currently running task.
@@ -407,8 +408,8 @@ impl PerCpu {
407408 irq_state : IrqState :: new ( ) ,
408409 tss : X86Tss :: new ( ) ,
409410 isst : Cell :: new ( Isst :: default ( ) ) ,
410- svsm_vmsa : OnceCell :: new ( ) ,
411- reset_ip : Cell :: new ( 0xffff_fff0 ) ,
411+ svsm_vmsa : ImmutAfterInitCell :: uninit ( ) ,
412+ reset_ip : AtomicU64 :: new ( 0xffff_fff0 ) ,
412413 vm_range : {
413414 let mut vmr = VMR :: new ( SVSM_PERCPU_BASE , SVSM_PERCPU_END , PTEntryFlags :: GLOBAL ) ;
414415 vmr. set_per_cpu ( true ) ;
@@ -421,11 +422,11 @@ impl PerCpu {
421422 guest_apic : RefCell :: new ( None ) ,
422423
423424 shared,
424- ghcb : OnceCell :: new ( ) ,
425+ ghcb : ImmutAfterInitCell :: uninit ( ) ,
425426 hypercall_pages : RefCell :: new ( None ) ,
426- hv_doorbell : OnceCell :: new ( ) ,
427- init_shadow_stack : Cell :: new ( None ) ,
428- context_switch_stack : Cell :: new ( None ) ,
427+ hv_doorbell : ImmutAfterInitCell :: uninit ( ) ,
428+ init_shadow_stack : ImmutAfterInitCell :: uninit ( ) ,
429+ context_switch_stack : ImmutAfterInitCell :: uninit ( ) ,
429430 ist : IstStacks :: new ( ) ,
430431 current_stack : Cell :: new ( MemoryRegion :: new ( VirtAddr :: null ( ) , 0 ) ) ,
431432 }
@@ -532,15 +533,12 @@ impl PerCpu {
532533
533534 /// Sets up the CPU-local GHCB page.
534535 pub fn setup_ghcb ( & self ) -> Result < ( ) , SvsmError > {
535- let page = GhcbPage :: new ( ) ?;
536- self . ghcb
537- . set ( page)
538- . expect ( "Attempted to reinitialize the GHCB" ) ;
536+ self . ghcb . try_init_from_fn ( GhcbPage :: new) ?;
539537 Ok ( ( ) )
540538 }
541539
542540 fn ghcb ( & self ) -> Option < & GhcbPage > {
543- self . ghcb . get ( )
541+ self . ghcb . try_get_inner ( ) . ok ( )
544542 }
545543
546544 /// Allocates hypercall input/output pages for this CPU.
@@ -560,11 +558,11 @@ impl PerCpu {
560558 }
561559
562560 pub fn hv_doorbell ( & self ) -> Option < & HVDoorbell > {
563- self . hv_doorbell . get ( ) . map ( Deref :: deref)
561+ self . hv_doorbell . try_get_inner ( ) . ok ( ) . map ( Deref :: deref)
564562 }
565563
566564 pub fn process_hv_events_if_required ( & self ) {
567- if let Some ( doorbell) = self . hv_doorbell . get ( ) {
565+ if let Ok ( doorbell) = self . hv_doorbell . try_get_inner ( ) {
568566 doorbell. process_if_required ( & self . irq_state ) ;
569567 }
570568 }
@@ -573,25 +571,30 @@ impl PerCpu {
573571 /// PerCpu structure.
574572 pub fn hv_doorbell_addr ( & self ) -> * const * const HVDoorbell {
575573 self . hv_doorbell
576- . get ( )
574+ . try_get_inner ( )
575+ . ok ( )
577576 . map ( SharedBox :: ptr_ref)
578577 . unwrap_or ( ptr:: null ( ) )
579578 }
580579
581580 pub fn get_top_of_shadow_stack ( & self ) -> Option < VirtAddr > {
582- self . init_shadow_stack . get ( )
581+ self . init_shadow_stack . try_get_inner ( ) . ok ( ) . copied ( )
583582 }
584583
585584 pub fn get_top_of_context_switch_stack ( & self ) -> Option < VirtAddr > {
586- self . context_switch_stack . get ( )
585+ self . context_switch_stack . try_get_inner ( ) . ok ( ) . copied ( )
587586 }
588587
589588 pub fn get_top_of_df_stack ( & self ) -> Option < VirtAddr > {
590- self . ist . double_fault_stack . get ( )
589+ self . ist . double_fault_stack . try_get_inner ( ) . ok ( ) . copied ( )
591590 }
592591
593592 pub fn get_top_of_df_shadow_stack ( & self ) -> Option < VirtAddr > {
594- self . ist . double_fault_shadow_stack . get ( )
593+ self . ist
594+ . double_fault_shadow_stack
595+ . try_get_inner ( )
596+ . ok ( )
597+ . copied ( )
595598 }
596599
597600 pub fn get_current_stack ( & self ) -> MemoryRegion < VirtAddr > {
@@ -651,15 +654,15 @@ impl PerCpu {
651654 }
652655
653656 fn allocate_init_shadow_stack ( & self ) -> Result < ( ) , SvsmError > {
654- let init_stack =
655- Some ( self . allocate_shadow_stack ( SVSM_SHADOW_STACKS_INIT_TASK , ShadowStackInit :: Init ) ? ) ;
656- self . init_shadow_stack . set ( init_stack ) ;
657+ self . init_shadow_stack . try_init_from_fn ( || {
658+ self . allocate_shadow_stack ( SVSM_SHADOW_STACKS_INIT_TASK , ShadowStackInit :: Init )
659+ } ) ? ;
657660 Ok ( ( ) )
658661 }
659662
660663 fn allocate_context_switch_stack ( & self ) -> Result < ( ) , SvsmError > {
661- let cs_stack = Some ( self . allocate_stack ( SVSM_CONTEXT_SWITCH_STACK ) ? ) ;
662- self . context_switch_stack . set ( cs_stack ) ;
664+ self . context_switch_stack
665+ . try_init_from_fn ( || self . allocate_stack ( SVSM_CONTEXT_SWITCH_STACK ) ) ? ;
663666 Ok ( ( ) )
664667 }
665668
@@ -672,18 +675,16 @@ impl PerCpu {
672675 }
673676
674677 fn allocate_ist_stacks ( & self ) -> Result < ( ) , SvsmError > {
675- let double_fault_stack = self . allocate_stack ( SVSM_STACK_IST_DF_BASE ) ? ;
676- self . ist . double_fault_stack . set ( Some ( double_fault_stack ) ) ;
677-
678+ self . ist
679+ . double_fault_stack
680+ . try_init_from_fn ( || self . allocate_stack ( SVSM_STACK_IST_DF_BASE ) ) ? ;
678681 Ok ( ( ) )
679682 }
680683
681684 fn allocate_isst_shadow_stacks ( & self ) -> Result < ( ) , SvsmError > {
682- let double_fault_shadow_stack =
683- self . allocate_shadow_stack ( SVSM_SHADOW_STACK_ISST_DF_BASE , ShadowStackInit :: Exception ) ?;
684- self . ist
685- . double_fault_shadow_stack
686- . set ( Some ( double_fault_shadow_stack) ) ;
685+ self . ist . double_fault_shadow_stack . try_init_from_fn ( || {
686+ self . allocate_shadow_stack ( SVSM_SHADOW_STACK_ISST_DF_BASE , ShadowStackInit :: Exception )
687+ } ) ?;
687688
688689 Ok ( ( ) )
689690 }
@@ -705,10 +706,8 @@ impl PerCpu {
705706 }
706707
707708 pub fn setup_hv_doorbell ( & self ) -> Result < ( ) , SvsmError > {
708- let doorbell = allocate_hv_doorbell_page ( current_ghcb ( ) ) ?;
709709 self . hv_doorbell
710- . set ( doorbell)
711- . expect ( "Attempted to reinitialize HV doorbell page" ) ;
710+ . try_init_from_fn ( || allocate_hv_doorbell_page ( current_ghcb ( ) ) ) ?;
712711 Ok ( ( ) )
713712 }
714713
@@ -865,7 +864,7 @@ impl PerCpu {
865864 }
866865
867866 pub fn set_reset_ip ( & self , reset_ip : u64 ) {
868- self . reset_ip . set ( reset_ip) ;
867+ self . reset_ip . store ( reset_ip, Ordering :: Relaxed ) ;
869868 }
870869
871870 /// Fill in the initial context structure for the SVSM.
@@ -908,25 +907,17 @@ impl PerCpu {
908907 /// physical address and SEV features. Returns an error if allocation
909908 /// fails of this CPU's VMSA was already initialized.
910909 pub fn alloc_svsm_vmsa ( & self , vtom : u64 , start_rip : u64 ) -> Result < ( PhysAddr , u64 ) , SvsmError > {
911- if self . svsm_vmsa . get ( ) . is_some ( ) {
912- // FIXME: add a more explicit error variant for this condition
913- return Err ( SvsmError :: Mem ) ;
914- }
915-
916- let mut vmsa = VmsaPage :: new ( RMPFlags :: VMPL1 ) ?;
917- let paddr = vmsa. paddr ( ) ;
918-
919- // Initialize VMSA
920- let context = self . get_initial_context ( start_rip) ;
921- init_svsm_vmsa ( & mut vmsa, vtom, & context) ;
922- vmsa. enable ( ) ;
923-
924- let sev_features = vmsa. sev_features ;
910+ let vmsa = self . svsm_vmsa . try_init_from_fn ( || {
911+ let mut vmsa = VmsaPage :: new ( RMPFlags :: VMPL1 ) ?;
925912
926- // We already checked that the VMSA is unset
927- self . svsm_vmsa . set ( vmsa) . unwrap ( ) ;
913+ // Initialize VMSA
914+ let context = self . get_initial_context ( start_rip) ;
915+ init_svsm_vmsa ( & mut vmsa, vtom, & context) ;
916+ vmsa. enable ( ) ;
917+ Ok :: < _ , SvsmError > ( vmsa)
918+ } ) ?;
928919
929- Ok ( ( paddr, sev_features) )
920+ Ok ( ( vmsa . paddr ( ) , vmsa . sev_features ) )
930921 }
931922
932923 fn unmap_guest_vmsa ( & self ) {
@@ -962,7 +953,11 @@ impl PerCpu {
962953 let mut vmsa = VmsaPage :: new ( RMPFlags :: GUEST_VMPL ) ?;
963954 let paddr = vmsa. paddr ( ) ;
964955
965- init_guest_vmsa ( & mut vmsa, self . reset_ip . get ( ) , use_alternate_injection) ;
956+ init_guest_vmsa (
957+ & mut vmsa,
958+ self . reset_ip . load ( Ordering :: Relaxed ) ,
959+ use_alternate_injection,
960+ ) ;
966961
967962 self . shared ( ) . update_guest_vmsa ( paddr) ;
968963 let _ = VmsaPage :: leak ( vmsa) ;
0 commit comments