Skip to content

Commit

Permalink
alarm: compute unshifted dt from expiration
Browse files Browse the repository at this point in the history
Computing unshifted dt independently of unshifted reference can lead to
too low of a final expiration if reference and dt from userspace both have low-order
bits. Instead, compute unshifted dt by first computing the expected
expirtion, and right-shifting it to make sure the final reference + dt
expires at or after the expected expiration.
  • Loading branch information
alevy committed Oct 15, 2024
1 parent 339edb7 commit b5b3a37
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions capsules/core/src/alarm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,20 @@ impl<'a, A: Alarm<'a>> AlarmDriver<'a, A> {
(Some(userspace_reference_unshifted), false) => {
// We have a userspace reference and timer is (less than) 32
// bit. Simply set to unshifted values:

// TODO(alevy): clean up, this is correct, but a
// hack. Should be done more generally than just for
// this branch.
let expiration_shifted = reference_u32.unwrap().wrapping_add(dt_u32);
let expiration_unshifted = if expiration_shifted & ((1 << A::Ticks::u32_padding()) - 1) != 0 {
(expiration_shifted >> A::Ticks::u32_padding()) + 1
} else {
expiration_shifted >> A::Ticks::u32_padding()
};

let dt_unshifted = expiration_unshifted.wrapping_sub(userspace_reference_unshifted);


Expiration {
reference: A::Ticks::from(userspace_reference_unshifted),
dt: A::Ticks::from(dt_unshifted),
Expand Down Expand Up @@ -877,6 +891,58 @@ mod test {
);
}

#[test]
fn test_rearm_24bit_left_justified_ref_low_bits_basic() {
let mut expiration = None;

assert!(Ticks24::u32_padding() == 8);

let armed_time =
AlarmDriver::<MockAlarm<Ticks24, Freq10MHz>>::rearm_u32_left_justified_expiration(
// Current time:
Ticks24::from(0_u32),
// Userspace-provided reference:
Some(1_u32),
// Left-justified `dt` value:
3_u32,
// Reference to the `Option<Expiration>`, also used
// to update the counter of armed alarms:
&mut expiration,
);

let expiration = expiration.unwrap();

assert_eq!(armed_time, 1 << 8);
assert_eq!(expiration.reference.into_u32(), 0);
assert_eq!(expiration.dt.into_u32(), 1);
}

#[test]
fn test_rearm_24bit_left_justified_ref_low_bits_max_int() {
let mut expiration = None;

assert!(Ticks24::u32_padding() == 8);

let armed_time =
AlarmDriver::<MockAlarm<Ticks24, Freq10MHz>>::rearm_u32_left_justified_expiration(
// Current time:
Ticks24::from(6_u32),
// Userspace-provided reference:
Some(Ticks24::from(5_u32).into_u32_left_justified() - 43),
// Left-justified `dt` value:
Ticks24::from(2_u32).into_u32_left_justified() + 43,
// Reference to the `Option<Expiration>`, also used
// to update the counter of armed alarms:
&mut expiration,
);

let expiration = expiration.unwrap();

assert_eq!(armed_time, 7 << 8);
assert_eq!(expiration.reference.into_u32(), 4);
assert_eq!(expiration.dt, Ticks24::from(3));
}

#[test]
fn test_rearm_32bit_left_justified_noref_basic() {
let mut expiration = Some(Expiration {
Expand Down

0 comments on commit b5b3a37

Please sign in to comment.