@@ -8,7 +8,7 @@ use vm_memory::GuestMemoryError;
88use crate :: Vm ;
99use crate :: devices:: acpi:: vmclock:: VmClock ;
1010use crate :: devices:: acpi:: vmgenid:: VmGenId ;
11- use crate :: vstate:: resources :: ResourceAllocator ;
11+ use crate :: vstate:: memory :: GuestMemoryMmap ;
1212
1313#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
1414pub enum ACPIDeviceError {
@@ -23,40 +23,70 @@ pub enum ACPIDeviceError {
2323#[ derive( Debug ) ]
2424pub struct ACPIDeviceManager {
2525 /// VMGenID device
26- pub vmgenid : VmGenId ,
26+ pub vmgenid : Option < VmGenId > ,
2727 /// VMclock device
28- pub vmclock : VmClock ,
28+ pub vmclock : Option < VmClock > ,
2929}
3030
3131impl ACPIDeviceManager {
3232 /// Create a new ACPIDeviceManager object
33- pub fn new ( resource_allocator : & mut ResourceAllocator ) -> Self {
33+ pub fn new ( ) -> Self {
34+ // Although both VMGenID and VMClock devices are always present, they should be instantiated
35+ // when they are attached to preserve the existing ordering of GSI allocation.
3436 ACPIDeviceManager {
35- vmgenid : VmGenId :: new ( resource_allocator ) ,
36- vmclock : VmClock :: new ( resource_allocator ) ,
37+ vmgenid : None ,
38+ vmclock : None ,
3739 }
3840 }
3941
40- pub fn attach_vmgenid ( & self , vm : & Vm ) -> Result < ( ) , ACPIDeviceError > {
41- vm. register_irq ( & self . vmgenid . interrupt_evt , self . vmgenid . gsi ) ?;
42- self . vmgenid . activate ( vm. guest_memory ( ) ) ?;
42+ pub fn attach_vmgenid ( & mut self , vm : & Vm ) {
43+ self . vmgenid = Some ( VmGenId :: new ( & mut vm. resource_allocator ( ) ) ) ;
44+ }
45+
46+ pub fn attach_vmclock ( & mut self , vm : & Vm ) {
47+ self . vmclock = Some ( VmClock :: new ( & mut vm. resource_allocator ( ) ) ) ;
48+ }
49+
50+ pub fn vmgenid ( & self ) -> & VmGenId {
51+ self . vmgenid . as_ref ( ) . expect ( "Missing VMGenID device" )
52+ }
53+
54+ pub fn vmclock ( & self ) -> & VmClock {
55+ self . vmclock . as_ref ( ) . expect ( "Missing VMClock device" )
56+ }
57+
58+ pub fn activate_vmgenid ( & self , vm : & Vm ) -> Result < ( ) , ACPIDeviceError > {
59+ vm. register_irq ( & self . vmgenid ( ) . interrupt_evt , self . vmgenid ( ) . gsi ) ?;
60+ self . vmgenid ( ) . activate ( vm. guest_memory ( ) ) ?;
61+ Ok ( ( ) )
62+ }
63+
64+ pub fn activate_vmclock ( & self , vm : & Vm ) -> Result < ( ) , ACPIDeviceError > {
65+ vm. register_irq ( & self . vmclock ( ) . interrupt_evt , self . vmclock ( ) . gsi ) ?;
66+ self . vmclock ( ) . activate ( vm. guest_memory ( ) ) ?;
4367 Ok ( ( ) )
4468 }
4569
46- pub fn attach_vmclock ( & self , vm : & Vm ) -> Result < ( ) , ACPIDeviceError > {
47- vm. register_irq ( & self . vmclock . interrupt_evt , self . vmclock . gsi ) ?;
48- self . vmclock . activate ( vm. guest_memory ( ) ) ?;
70+ pub fn do_post_restore_vmgenid ( & self ) -> Result < ( ) , ACPIDeviceError > {
71+ self . vmgenid ( ) . do_post_restore ( ) ?;
4972 Ok ( ( ) )
5073 }
74+
75+ pub fn do_post_restore_vmclock ( & mut self , mem : & GuestMemoryMmap ) {
76+ self . vmclock
77+ . as_mut ( )
78+ . expect ( "Missing VMClock device" )
79+ . do_post_restore ( mem) ;
80+ }
5181}
5282
5383#[ cfg( target_arch = "x86_64" ) ]
5484impl Aml for ACPIDeviceManager {
5585 fn append_aml_bytes ( & self , v : & mut Vec < u8 > ) -> Result < ( ) , aml:: AmlError > {
5686 // AML for [`VmGenId`] device.
57- self . vmgenid . append_aml_bytes ( v) ?;
87+ self . vmgenid ( ) . append_aml_bytes ( v) ?;
5888 // AML for [`VmClock`] device.
59- self . vmclock . append_aml_bytes ( v) ?;
89+ self . vmclock ( ) . append_aml_bytes ( v) ?;
6090
6191 // Create the AML for the GED interrupt handler
6292 aml:: Device :: new (
@@ -66,8 +96,8 @@ impl Aml for ACPIDeviceManager {
6696 & aml:: Name :: new(
6797 "_CRS" . try_into( ) ?,
6898 & aml:: ResourceTemplate :: new( vec![
69- & aml:: Interrupt :: new( true , true , false , false , self . vmgenid. gsi) ,
70- & aml:: Interrupt :: new( true , true , false , false , self . vmclock. gsi) ,
99+ & aml:: Interrupt :: new( true , true , false , false , self . vmgenid( ) . gsi) ,
100+ & aml:: Interrupt :: new( true , true , false , false , self . vmclock( ) . gsi) ,
71101 ] ) ,
72102 ) ?,
73103 // We know that the maximum IRQ number fits in a u8. We have up to
@@ -81,15 +111,15 @@ impl Aml for ACPIDeviceManager {
81111 vec![
82112 & aml:: If :: new(
83113 #[ allow( clippy:: cast_possible_truncation) ]
84- & aml:: Equal :: new( & aml:: Arg ( 0 ) , & ( self . vmgenid. gsi as u8 ) ) ,
114+ & aml:: Equal :: new( & aml:: Arg ( 0 ) , & ( self . vmgenid( ) . gsi as u8 ) ) ,
85115 vec![ & aml:: Notify :: new(
86116 & aml:: Path :: new( "\\ _SB_.VGEN" ) ?,
87117 & 0x80usize ,
88118 ) ] ,
89119 ) ,
90120 & aml:: If :: new(
91121 #[ allow( clippy:: cast_possible_truncation) ]
92- & aml:: Equal :: new( & aml:: Arg ( 0 ) , & ( self . vmclock. gsi as u8 ) ) ,
122+ & aml:: Equal :: new( & aml:: Arg ( 0 ) , & ( self . vmclock( ) . gsi as u8 ) ) ,
93123 vec![ & aml:: Notify :: new(
94124 & aml:: Path :: new( "\\ _SB_.VCLK" ) ?,
95125 & 0x80usize ,
0 commit comments