Clock trait (#596)

* adds generic Env parameters

* adds Clock type to Env

* use new Clock

* TockTimer improvements

* new Clock interface

* addressed comments

* renames constants to milliseconds, other style fixes

* removes all cargo fmt artifacts
This commit is contained in:
kaczmarczyck
2023-02-28 17:35:42 +01:00
committed by GitHub
parent 963549f9bb
commit 73c60d8740
31 changed files with 1163 additions and 1463 deletions

118
src/env/tock/clock.rs vendored Normal file
View File

@@ -0,0 +1,118 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::api::clock::Clock;
use libtock_drivers::timer::{get_clock_frequency, get_ticks};
/// 56-bits timestamp (valid for 70k+ years)
#[derive(Clone, Copy, Debug, Default, PartialOrd, Ord, PartialEq, Eq)]
struct Timestamp {
epoch: usize, // 32-bits
tick: usize, // 24-bits (32kHz)
}
impl Timestamp {
/// Adds (potentially more than 24 bit of) ticks to this timestamp.
pub fn add_ticks(&mut self, ticks: usize) {
// Saturating should never happen, but it fails gracefully.
let sum = self.tick.saturating_add(ticks);
self.epoch += sum >> 24;
self.tick = sum & 0xff_ffff;
}
}
#[derive(Default)]
pub struct TockTimer {
deadline: Timestamp,
}
/// Clock that produces timers through Tock syscalls.
///
/// To guarantee correctness, you have to call any of its functions at least once per full tick
/// counter wrap. In our case, 24 bit ticks with a 32 kHz frequency wrap after 512 seconds. If you
/// can't guarantee to regularly create or check timers, call tickle at least every 8 minutes.
#[derive(Default)]
pub struct TockClock {
now: Timestamp,
}
impl TockClock {
/// Elapses timers before the clock wraps.
///
/// Call this regularly to timeout reliably despite wrapping clock ticks.
pub fn tickle(&mut self) {
let cur_tick = get_ticks().ok().unwrap();
if cur_tick < self.now.tick {
self.now.epoch += 1;
}
self.now.tick = cur_tick;
}
}
impl Clock for TockClock {
type Timer = TockTimer;
fn make_timer(&mut self, milliseconds: usize) -> Self::Timer {
self.tickle();
let clock_frequency = get_clock_frequency().ok().unwrap();
let delta_tick = match milliseconds.checked_mul(clock_frequency) {
Some(x) => x / 1000,
// All CTAP timeouts are multiples of 100 so far. Worst case we timeout too early.
None => (milliseconds / 100).saturating_mul(clock_frequency / 10),
};
let mut deadline = self.now;
deadline.add_ticks(delta_tick);
Self::Timer { deadline }
}
fn is_elapsed(&mut self, timer: &Self::Timer) -> bool {
self.tickle();
self.now >= timer.deadline
}
#[cfg(feature = "debug_ctap")]
fn timestamp_us(&mut self) -> usize {
let clock_frequency = get_clock_frequency().ok().unwrap();
let total_ticks = 0x100_0000u64 * self.now.epoch as u64 + self.now.tick as u64;
(total_ticks.wrapping_mul(1_000_000u64) / clock_frequency as u64) as usize
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_timestamp_add_ticks() {
let mut timestamp = Timestamp::default();
timestamp.add_ticks(1);
let expected = Timestamp { epoch: 0, tick: 1 };
assert_eq!(timestamp, expected);
timestamp.add_ticks(0xff_ffff);
let expected = Timestamp { epoch: 1, tick: 0 };
assert_eq!(timestamp, expected);
timestamp.add_ticks(0x100_0000);
let expected = Timestamp { epoch: 2, tick: 0 };
assert_eq!(timestamp, expected);
timestamp.add_ticks(0x1ff_ffff);
let expected = Timestamp {
epoch: 3,
tick: 0xff_ffff,
};
assert_eq!(timestamp, expected);
timestamp.add_ticks(1);
let expected = Timestamp { epoch: 4, tick: 0 };
assert_eq!(timestamp, expected);
}
}

29
src/env/tock/mod.rs vendored
View File

@@ -19,12 +19,10 @@ use crate::api::customization::{CustomizationImpl, DEFAULT_CUSTOMIZATION};
use crate::api::firmware_protection::FirmwareProtection;
use crate::api::user_presence::{UserPresence, UserPresenceError, UserPresenceResult};
use crate::api::{attestation_store, key_store};
use crate::clock::{ClockInt, KEEPALIVE_DELAY_MS};
use crate::env::Env;
use clock::TockClock;
use core::cell::Cell;
use core::sync::atomic::{AtomicBool, Ordering};
use embedded_time::duration::Milliseconds;
use embedded_time::fixed_point::FixedPoint;
use libtock_core::result::{CommandError, EALREADY};
use libtock_drivers::buttons::{self, ButtonState};
use libtock_drivers::console::Console;
@@ -35,6 +33,7 @@ use libtock_drivers::{crp, led, timer};
use persistent_store::{StorageResult, Store};
use rng256::TockRng256;
mod clock;
mod storage;
pub struct TockHidConnection {
@@ -42,14 +41,10 @@ pub struct TockHidConnection {
}
impl HidConnection for TockHidConnection {
fn send_and_maybe_recv(
&mut self,
buf: &mut [u8; 64],
timeout: Milliseconds<ClockInt>,
) -> SendOrRecvResult {
fn send_and_maybe_recv(&mut self, buf: &mut [u8; 64], timeout_ms: usize) -> SendOrRecvResult {
match usb_ctap_hid::send_or_recv_with_timeout(
buf,
timer::Duration::from_ms(timeout.integer() as isize),
Duration::from_ms(timeout_ms as isize),
self.endpoint,
) {
Ok(usb_ctap_hid::SendOrRecvStatus::Timeout) => Ok(SendOrRecvStatus::Timeout),
@@ -70,6 +65,7 @@ pub struct TockEnv {
#[cfg(feature = "vendor_hid")]
vendor_connection: TockHidConnection,
blink_pattern: usize,
clock: TockClock,
}
impl TockEnv {
@@ -95,6 +91,7 @@ impl TockEnv {
endpoint: UsbEndpoint::VendorHid,
},
blink_pattern: 0,
clock: TockClock::default(),
}
}
}
@@ -115,8 +112,9 @@ impl UserPresence for TockEnv {
fn check_init(&mut self) {
self.blink_pattern = 0;
}
fn wait_with_timeout(&mut self, timeout: Milliseconds<ClockInt>) -> UserPresenceResult {
if timeout.integer() == 0 {
fn wait_with_timeout(&mut self, timeout_ms: usize) -> UserPresenceResult {
if timeout_ms == 0 {
return Err(UserPresenceError::Timeout);
}
blink_leds(self.blink_pattern);
@@ -141,7 +139,7 @@ impl UserPresence for TockEnv {
});
let mut keepalive = keepalive_callback.init().flex_unwrap();
let keepalive_alarm = keepalive
.set_alarm(timer::Duration::from_ms(timeout.integer() as isize))
.set_alarm(Duration::from_ms(timeout_ms as isize))
.flex_unwrap();
// Wait for a button touch or an alarm.
@@ -224,6 +222,7 @@ impl Env for TockEnv {
type Storage = TockStorage;
type KeyStore = Self;
type AttestationStore = Self;
type Clock = TockClock;
type UpgradeStorage = TockUpgradeStorage;
type FirmwareProtection = Self;
type Write = Console;
@@ -250,6 +249,10 @@ impl Env for TockEnv {
self
}
fn clock(&mut self) -> &mut Self::Clock {
&mut self.clock
}
fn upgrade_storage(&mut self) -> Option<&mut Self::UpgradeStorage> {
self.upgrade_storage.as_mut()
}
@@ -324,5 +327,3 @@ pub fn switch_off_leds() {
led::get(l).flex_unwrap().off().flex_unwrap();
}
}
pub const KEEPALIVE_DELAY_TOCK: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS as isize);