@@ -20,17 +20,19 @@ pub mod resource;
2020
2121use crate :: {
2222 AcpiError ,
23- AcpiTables ,
2423 AmlTable ,
2524 Handle ,
2625 Handler ,
2726 PhysicalMapping ,
27+ platform:: AcpiPlatform ,
28+ registers:: { FixedRegisters , Pm1ControlBit } ,
2829 sdt:: { SdtHeader , facs:: Facs , fadt:: Fadt } ,
2930} ;
3031use alloc:: {
3132 boxed:: Box ,
3233 collections:: btree_map:: BTreeMap ,
3334 string:: { String , ToString } ,
35+ sync:: Arc ,
3436 vec,
3537 vec:: Vec ,
3638} ;
7072 region_handlers : Spinlock < BTreeMap < RegionSpace , Box < dyn RegionHandler > > > ,
7173
7274 global_lock_mutex : Handle ,
75+ registers : Arc < FixedRegisters < H > > ,
7376 facs : PhysicalMapping < H , Facs > ,
7477}
7578
8588{
8689 /// Construct a new `Interpreter`. This does not load any tables - if you have an `AcpiTables`
8790 /// already, use [`Interpreter::new_from_tables`] instead.
88- pub fn new ( handler : H , dsdt_revision : u8 , facs : PhysicalMapping < H , Facs > ) -> Interpreter < H > {
91+ pub fn new (
92+ handler : H ,
93+ dsdt_revision : u8 ,
94+ registers : Arc < FixedRegisters < H > > ,
95+ facs : PhysicalMapping < H , Facs > ,
96+ ) -> Interpreter < H > {
8997 info ! ( "Initializing AML interpreter v{}" , env!( "CARGO_PKG_VERSION" ) ) ;
9098
9199 let global_lock_mutex = handler. create_mutex ( ) ;
@@ -98,13 +106,14 @@ where
98106 dsdt_revision,
99107 region_handlers : Spinlock :: new ( BTreeMap :: new ( ) ) ,
100108 global_lock_mutex,
109+ registers,
101110 facs,
102111 }
103112 }
104113
105114 /// Construct a new `Interpreter` with the given set of ACPI tables. This will automatically
106115 /// load the DSDT and any SSDTs in the supplied [`AcpiTables`].
107- pub fn new_from_tables ( handler : H , tables : & AcpiTables < H > ) -> Result < Interpreter < H > , AcpiError > {
116+ pub fn new_from_platform ( platform : & AcpiPlatform < H > ) -> Result < Interpreter < H > , AcpiError > {
108117 fn load_table ( interpreter : & Interpreter < impl Handler > , table : AmlTable ) -> Result < ( ) , AcpiError > {
109118 let mapping = unsafe {
110119 interpreter. handler . map_physical_region :: < SdtHeader > ( table. phys_address , table. length as usize )
@@ -119,16 +128,17 @@ where
119128 Ok ( ( ) )
120129 }
121130
131+ let registers = platform. registers . clone ( ) ;
122132 let facs = {
123- let fadt = tables. find_table :: < Fadt > ( ) . unwrap ( ) ;
124- unsafe { handler. map_physical_region ( fadt. facs_address ( ) ?, mem:: size_of :: < Facs > ( ) ) }
133+ let fadt = platform . tables . find_table :: < Fadt > ( ) . unwrap ( ) ;
134+ unsafe { platform . handler . map_physical_region ( fadt. facs_address ( ) ?, mem:: size_of :: < Facs > ( ) ) }
125135 } ;
126136
127- let dsdt = tables. dsdt ( ) ?;
128- let interpreter = Interpreter :: new ( handler, dsdt. revision , facs) ;
137+ let dsdt = platform . tables . dsdt ( ) ?;
138+ let interpreter = Interpreter :: new ( platform . handler . clone ( ) , dsdt. revision , registers , facs) ;
129139 load_table ( & interpreter, dsdt) ?;
130140
131- for ssdt in tables. ssdts ( ) {
141+ for ssdt in platform . tables . ssdts ( ) {
132142 load_table ( & interpreter, ssdt) ?;
133143 }
134144
@@ -267,6 +277,88 @@ where
267277 info ! ( "Initialized {} devices" , num_devices_initialized) ;
268278 }
269279
280+ pub fn acquire_global_lock ( & self , timeout : u16 ) -> Result < ( ) , AmlError > {
281+ self . handler . acquire ( self . global_lock_mutex , timeout) ?;
282+
283+ // Now we've acquired the AML-side mutex, acquire the hardware side
284+ // TODO: count the number of times we have to go round this loop / enforce a timeout?
285+ loop {
286+ if self . try_do_acquire_firmware_lock ( ) {
287+ break Ok ( ( ) ) ;
288+ } else {
289+ /*
290+ * The lock is owned by the firmware. We have set the pending bit - we now need to
291+ * wait for the firmware to signal it has released the lock.
292+ *
293+ * TODO: this should wait for an interrupt from the firmware. That needs more infra
294+ * so for now let's just spin round and try and acquire it again...
295+ */
296+ self . handler . release ( self . global_lock_mutex ) ;
297+ continue ;
298+ }
299+ }
300+ }
301+
302+ /// Attempt to acquire the firmware lock, setting the owned bit if the lock is free. If the
303+ /// lock is not free, sets the pending bit to instruct the firmware to alert us when we can
304+ /// attempt to take ownership of the lock again. Returns `true` if we now have ownership of the
305+ /// lock, and `false` if we need to wait for firmware to release it.
306+ fn try_do_acquire_firmware_lock ( & self ) -> bool {
307+ loop {
308+ let global_lock = self . facs . global_lock . load ( Ordering :: Relaxed ) ;
309+ let is_owned = global_lock. get_bit ( 1 ) ;
310+
311+ /*
312+ * Compute the new value: either the lock is already owned, and we need to set the
313+ * pending bit and wait, or we can acquire ownership of the lock now. Either way, we
314+ * unconditionally set the owned bit and set the pending bit if the lock is already
315+ * owned.
316+ */
317+ let mut new_value = global_lock;
318+ new_value. set_bit ( 0 , is_owned) ;
319+ new_value. set_bit ( 1 , true ) ;
320+
321+ if self
322+ . facs
323+ . global_lock
324+ . compare_exchange ( global_lock, new_value, Ordering :: AcqRel , Ordering :: Acquire )
325+ . is_ok ( )
326+ {
327+ break !is_owned;
328+ }
329+ }
330+ }
331+
332+ pub fn release_global_lock ( & self ) -> Result < ( ) , AmlError > {
333+ let is_pending = self . do_release_firmware_lock ( ) ;
334+ if is_pending {
335+ self . registers . pm1_control_registers . set_bit ( Pm1ControlBit :: GlobalLockRelease , true ) . unwrap ( ) ;
336+ }
337+ Ok ( ( ) )
338+ }
339+
340+ /// Atomically release the owned and pending bits of the global lock. Returns whether the
341+ /// pending bit was set (this means the firmware is waiting to acquire the lock, and should be
342+ /// informed we're finished with it).
343+ fn do_release_firmware_lock ( & self ) -> bool {
344+ loop {
345+ let global_lock = self . facs . global_lock . load ( Ordering :: Relaxed ) ;
346+ let is_pending = global_lock. get_bit ( 0 ) ;
347+ let mut new_value = global_lock;
348+ new_value. set_bit ( 0 , false ) ;
349+ new_value. set_bit ( 1 , false ) ;
350+
351+ if self
352+ . facs
353+ . global_lock
354+ . compare_exchange ( global_lock, new_value, Ordering :: AcqRel , Ordering :: Acquire )
355+ . is_ok ( )
356+ {
357+ break is_pending;
358+ }
359+ }
360+ }
361+
270362 fn do_execute_method ( & self , mut context : MethodContext ) -> Result < WrappedObject , AmlError > {
271363 /*
272364 * This is the main loop that executes operations. Every op is handled at the top-level of
@@ -630,16 +722,27 @@ where
630722 let timeout = context. next_u16 ( ) ?;
631723
632724 // TODO: should we do something with the sync level??
633- self . handler . acquire ( mutex, timeout) ?;
725+ if mutex == self . global_lock_mutex {
726+ self . acquire_global_lock ( timeout) ?;
727+ } else {
728+ self . handler . acquire ( mutex, timeout) ?;
729+ }
730+
634731 context. retire_op ( op) ;
635732 }
636733 Opcode :: Release => {
637734 let [ Argument :: Object ( mutex) ] = & op. arguments [ ..] else { panic ! ( ) } ;
638735 let Object :: Mutex { mutex, sync_level } = * * mutex else {
639736 Err ( AmlError :: InvalidOperationOnObject { op : Operation :: Release , typ : mutex. typ ( ) } ) ?
640737 } ;
738+
641739 // TODO: should we do something with the sync level??
642- self . handler . release ( mutex) ;
740+ if mutex == self . global_lock_mutex {
741+ self . release_global_lock ( ) ?;
742+ } else {
743+ self . handler . release ( mutex) ;
744+ }
745+
643746 context. retire_op ( op) ;
644747 }
645748 Opcode :: InternalMethodCall => {
0 commit comments