Skip to content

Commit 9650986

Browse files
committed
Implement Wait, Signal, and Reset opcodes for event synchronization
1 parent 806093c commit 9650986

File tree

2 files changed

+95
-6
lines changed

2 files changed

+95
-6
lines changed

src/aml/mod.rs

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,91 @@ where
464464
context.contribute_arg(Argument::Object(result));
465465
context.retire_op(op);
466466
}
467+
Opcode::Reset => {
468+
let [Argument::Object(sync_object)] = &op.arguments[..] else {
469+
panic!();
470+
};
471+
let sync_object = sync_object.clone().unwrap_reference();
472+
473+
if let Object::Event(ref counter) = *sync_object {
474+
counter.store(0, Ordering::Release);
475+
} else {
476+
return Err(AmlError::InvalidOperationOnObject {
477+
op: Operation::ResetEvent,
478+
typ: sync_object.typ(),
479+
});
480+
}
481+
}
482+
Opcode::Signal => {
483+
let [Argument::Object(sync_object)] = &op.arguments[..] else {
484+
panic!();
485+
};
486+
let sync_object = sync_object.clone().unwrap_reference();
487+
488+
if let Object::Event(ref counter) = *sync_object {
489+
counter.fetch_add(1, Ordering::AcqRel);
490+
} else {
491+
return Err(AmlError::InvalidOperationOnObject {
492+
op: Operation::SignalEvent,
493+
typ: sync_object.typ(),
494+
});
495+
}
496+
}
497+
Opcode::Wait => {
498+
let [Argument::Object(sync_object), Argument::Object(timeout)] = &op.arguments[..] else {
499+
panic!();
500+
};
501+
let sync_object = sync_object.clone().unwrap_reference();
502+
let timeout = u64::min(timeout.as_integer()?, 0xffff);
503+
504+
if let Object::Event(ref counter) = *sync_object {
505+
/*
506+
* `Wait` returns a non-zero value if a timeout occurs and the event
507+
* was not signaled, and zero if it was. Timeout is specified in
508+
* milliseconds, should relinquish processor control (we use
509+
* `Handler::sleep` to do so) and a value of `0xffff` specifies that
510+
* the operation should wait indefinitely.
511+
*/
512+
let mut remaining_sleep = timeout;
513+
let mut timed_out = true;
514+
515+
'signaled: while remaining_sleep > 0 {
516+
loop {
517+
/*
518+
* Try to decrement the counter. If it's zero after a load, we
519+
* haven't been signalled and should wait for a bit. If it's
520+
* non-zero, we were signalled and should stop waiting.
521+
*/
522+
let value = counter.load(Ordering::Acquire);
523+
if value == 0 {
524+
break;
525+
}
526+
if counter
527+
.compare_exchange(value, value - 1, Ordering::AcqRel, Ordering::Acquire)
528+
.is_ok()
529+
{
530+
timed_out = false;
531+
break 'signaled;
532+
}
533+
}
534+
535+
let to_sleep = u64::min(timeout, 10);
536+
if timeout < 0xffff {
537+
remaining_sleep -= to_sleep
538+
}
539+
self.handler.sleep(to_sleep);
540+
}
541+
542+
context.contribute_arg(Argument::Object(
543+
Object::Integer(if timed_out { u64::MAX } else { 0 }).wrap(),
544+
));
545+
} else {
546+
return Err(AmlError::InvalidOperationOnObject {
547+
op: Operation::WaitEvent,
548+
typ: sync_object.typ(),
549+
});
550+
}
551+
}
467552
Opcode::FromBCD => self.do_from_bcd(&mut context, op)?,
468553
Opcode::ToBCD => self.do_to_bcd(&mut context, op)?,
469554
Opcode::Name => {
@@ -1158,9 +1243,9 @@ where
11581243
Opcode::Sleep => context.start_in_flight_op(OpInFlight::new(Opcode::Sleep, 1)),
11591244
Opcode::Acquire => context.start_in_flight_op(OpInFlight::new(opcode, 1)),
11601245
Opcode::Release => context.start_in_flight_op(OpInFlight::new(opcode, 1)),
1161-
Opcode::Signal => todo!(),
1162-
Opcode::Wait => todo!(),
1163-
Opcode::Reset => todo!(),
1246+
Opcode::Signal => context.start_in_flight_op(OpInFlight::new(opcode, 1)),
1247+
Opcode::Wait => context.start_in_flight_op(OpInFlight::new(opcode, 2)),
1248+
Opcode::Reset => context.start_in_flight_op(OpInFlight::new(opcode, 1)),
11641249
Opcode::Notify => todo!(),
11651250
Opcode::FromBCD | Opcode::ToBCD => context.start_in_flight_op(OpInFlight::new(opcode, 2)),
11661251
Opcode::Revision => {
@@ -3033,6 +3118,10 @@ pub enum Operation {
30333118
LogicalOp,
30343119
DecodePrt,
30353120
ParseResource,
3121+
3122+
ResetEvent,
3123+
SignalEvent,
3124+
WaitEvent,
30363125
}
30373126

30383127
#[derive(Clone, PartialEq, Debug)]

src/aml/object.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::aml::{AmlError, Handle, Operation, op_region::OpRegion};
22
use alloc::{borrow::Cow, string::String, sync::Arc, vec::Vec};
33
use bit_field::BitField;
4-
use core::{cell::UnsafeCell, fmt, ops};
4+
use core::{cell::UnsafeCell, fmt, ops, sync::atomic::AtomicU64};
55

66
type NativeMethod = dyn Fn(&[WrappedObject]) -> Result<WrappedObject, AmlError>;
77

@@ -11,7 +11,7 @@ pub enum Object {
1111
Buffer(Vec<u8>),
1212
BufferField { buffer: WrappedObject, offset: usize, length: usize },
1313
Device,
14-
Event,
14+
Event(Arc<AtomicU64>),
1515
FieldUnit(FieldUnit),
1616
Integer(u64),
1717
Method { code: Vec<u8>, flags: MethodFlags },
@@ -48,7 +48,7 @@ impl fmt::Display for Object {
4848
write!(f, "BufferField {{ offset: {offset}, length: {length} }}")
4949
}
5050
Object::Device => write!(f, "Device"),
51-
Object::Event => write!(f, "Event"),
51+
Object::Event(counter) => write!(f, "Event({counter:?})"),
5252
// TODO: include fields
5353
Object::FieldUnit(_) => write!(f, "FieldUnit"),
5454
Object::Integer(value) => write!(f, "Integer({value})"),

0 commit comments

Comments
 (0)