@@ -20,17 +20,19 @@ pub mod resource;
20
20
21
21
use crate :: {
22
22
AcpiError ,
23
- AcpiTables ,
24
23
AmlTable ,
25
24
Handle ,
26
25
Handler ,
27
26
PhysicalMapping ,
27
+ platform:: AcpiPlatform ,
28
+ registers:: { FixedRegisters , Pm1ControlBit } ,
28
29
sdt:: { SdtHeader , facs:: Facs , fadt:: Fadt } ,
29
30
} ;
30
31
use alloc:: {
31
32
boxed:: Box ,
32
33
collections:: btree_map:: BTreeMap ,
33
34
string:: { String , ToString } ,
35
+ sync:: Arc ,
34
36
vec,
35
37
vec:: Vec ,
36
38
} ;
70
72
region_handlers : Spinlock < BTreeMap < RegionSpace , Box < dyn RegionHandler > > > ,
71
73
72
74
global_lock_mutex : Handle ,
75
+ registers : Arc < FixedRegisters < H > > ,
73
76
facs : PhysicalMapping < H , Facs > ,
74
77
}
75
78
85
88
{
86
89
/// Construct a new `Interpreter`. This does not load any tables - if you have an `AcpiTables`
87
90
/// 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 > {
89
97
info ! ( "Initializing AML interpreter v{}" , env!( "CARGO_PKG_VERSION" ) ) ;
90
98
91
99
let global_lock_mutex = handler. create_mutex ( ) ;
@@ -98,13 +106,14 @@ where
98
106
dsdt_revision,
99
107
region_handlers : Spinlock :: new ( BTreeMap :: new ( ) ) ,
100
108
global_lock_mutex,
109
+ registers,
101
110
facs,
102
111
}
103
112
}
104
113
105
114
/// Construct a new `Interpreter` with the given set of ACPI tables. This will automatically
106
115
/// 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 > {
108
117
fn load_table ( interpreter : & Interpreter < impl Handler > , table : AmlTable ) -> Result < ( ) , AcpiError > {
109
118
let mapping = unsafe {
110
119
interpreter. handler . map_physical_region :: < SdtHeader > ( table. phys_address , table. length as usize )
@@ -119,16 +128,17 @@ where
119
128
Ok ( ( ) )
120
129
}
121
130
131
+ let registers = platform. registers . clone ( ) ;
122
132
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 > ( ) ) }
125
135
} ;
126
136
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) ;
129
139
load_table ( & interpreter, dsdt) ?;
130
140
131
- for ssdt in tables. ssdts ( ) {
141
+ for ssdt in platform . tables . ssdts ( ) {
132
142
load_table ( & interpreter, ssdt) ?;
133
143
}
134
144
@@ -267,6 +277,88 @@ where
267
277
info ! ( "Initialized {} devices" , num_devices_initialized) ;
268
278
}
269
279
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
+
270
362
fn do_execute_method ( & self , mut context : MethodContext ) -> Result < WrappedObject , AmlError > {
271
363
/*
272
364
* This is the main loop that executes operations. Every op is handled at the top-level of
@@ -630,16 +722,27 @@ where
630
722
let timeout = context. next_u16 ( ) ?;
631
723
632
724
// 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
+
634
731
context. retire_op ( op) ;
635
732
}
636
733
Opcode :: Release => {
637
734
let [ Argument :: Object ( mutex) ] = & op. arguments [ ..] else { panic ! ( ) } ;
638
735
let Object :: Mutex { mutex, sync_level } = * * mutex else {
639
736
Err ( AmlError :: InvalidOperationOnObject { op : Operation :: Release , typ : mutex. typ ( ) } ) ?
640
737
} ;
738
+
641
739
// 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
+
643
746
context. retire_op ( op) ;
644
747
}
645
748
Opcode :: InternalMethodCall => {
0 commit comments