rustkey/
lib.rs

1// rusTkey, a rust crate/library that provides a development API for the tillitis TKey.
2// Copyright (C) 2024  Danny van Heumen
3// SPDX-License-Identifier: BSD-2-Clause
4
5#![no_std]
6#![deny(unused_must_use)]
7#![warn(clippy::pedantic)]
8// Note: thread-safety is guaranteed; static mutable refs allowed by default.
9#![allow(
10    dead_code,
11    clippy::identity_op,
12    clippy::needless_range_loop,
13    clippy::cast_lossless
14)]
15
16use core::ptr;
17
18#[cfg(feature = "blake2-standalone")]
19pub mod blake2s;
20
21pub const ROM_BASE: usize = 0x0000_0000;
22/// `ROM_SIZE` is not specified in tk1 memory model. Instead, this is the maximum allowed size that
23/// is made available in EBR (Embedded Block RAM) in the verilog model. See
24/// `hw/application_fpg/core/rom/rtl/rom.v` in the `tillitis-key1` repository containing the
25/// hardware, fpga and firmware content.
26///
27/// `rom.v` (verilog):
28///
29///      "Max size for the ROM is 3072 [32-bit] words, and the address is 12 bits to support ROM
30///      with this number of words."
31pub const ROM_SIZE: usize = 3072 * 4;
32pub const RAM_BASE: usize = 0x4000_0000;
33pub const RAM_SIZE: usize = 0x2_0000;
34const RESERVED_BASE: usize = 0x8000_0000;
35const MMIO_BASE: usize = 0xc000_0000;
36const MMIO_SIZE: usize = 0xffff_ffff - MMIO_BASE;
37
38pub const TK1_CPU_FREQUENCY: u32 = 18_000_000;
39
40/// The maximum possible size of an application, i.e. the size of available RAM.
41pub const APP_MAX_SIZE: usize = RAM_SIZE;
42
43const MMIO_TRNG_BASE: usize = MMIO_BASE | 0x0000_0000;
44const MMIO_TIMER_BASE: usize = MMIO_BASE | 0x0100_0000;
45const MMIO_UDS_BASE: usize = MMIO_BASE | 0x0200_0000;
46const MMIO_TOUCH_BASE: usize = MMIO_BASE | 0x0400_0000;
47const MMIO_FW_RAM_BASE: usize = MMIO_BASE | 0x1000_0000;
48const MMIO_FW_RAM_SIZE: usize = 2048;
49const MMIO_TK1_BASE: usize = MMIO_BASE | 0x3f00_0000;
50
51/// `TK1_NAME0` is the address for the first 4-byte app-name.
52pub const TK1_NAME0: *const u32 = (MMIO_TK1_BASE | 0x00) as *const u32;
53/// `TK1_NAME1` is the address for the second 4-byte app-name.
54pub const TK1_NAME1: *const u32 = (MMIO_TK1_BASE | 0x04) as *const u32;
55/// `TK1_VERSION` is the address for the app version.
56pub const TK1_VERSION: *const u32 = (MMIO_TK1_BASE | 0x08) as *const u32;
57
58pub const TK1_SWITCH_APP: *const u8 = (MMIO_TK1_BASE | 0x20) as *const u8;
59
60/// `TK1_APP_ADDR` the address to the start of the application loaded into TKey.
61pub const TK1_APP_ADDR: *const usize = (MMIO_TK1_BASE | 0x30) as *const usize;
62/// `TK1_APP_SIZE` the size of the application loaded into TKey.
63pub const TK1_APP_SIZE: *const usize = (MMIO_TK1_BASE | 0x34) as *const usize;
64
65/// `TK1_BLAKE2S_ADDR` provides the address to the `blake2s` function in TKey firmware.
66pub const TK1_BLAKE2S_ADDR: *const usize = (MMIO_TK1_BASE | 0x40) as *const usize;
67
68/// `TK1_CDI` provides access to the (application-specific) CDI value. (32 bytes, contiguous)
69pub const TK1_CDI: *const u8 = (MMIO_TK1_BASE | 0x80) as *const u8;
70
71#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
72pub enum Error {
73    /// `InvalidInput` indicates that execution failed due to bad input arguments into the function.
74    InvalidInput,
75    /// `ProtocolViolation` indicates an error that is rooted in failing to follow the established
76    /// protocol.
77    ProtocolViolation(&'static str),
78    /// `Underrun` represents a (buffer) underrun, i.e. no more data is available.
79    Underrun,
80    /// `Timeout` represents a reached deadline, i.e. the allocated time has passed.
81    Timeout,
82}
83
84/// `io` module contains basic input/output operations.
85pub mod io {
86    use core::ptr;
87
88    use crate::{timer, Error};
89
90    const MMIO_UART_BASE: usize = crate::MMIO_BASE | 0x0300_0000;
91    pub const UART_BITRATE: *mut u16 = (MMIO_UART_BASE | 0x40) as *mut u16;
92    pub const UART_DATA_BITS: *mut u8 = (MMIO_UART_BASE | 0x44) as *mut u8;
93    pub const UART_STOP_BITS: *mut u8 = (MMIO_UART_BASE | 0x48) as *mut u8;
94    pub const UART_RX_STATUS: *const u8 = (MMIO_UART_BASE | 0x80) as *const u8;
95    pub const UART_RX_DATA: *const u8 = (MMIO_UART_BASE | 0x84) as *const u8;
96    pub const UART_RX_BYTES: *const u32 = (MMIO_UART_BASE | 0x88) as *const u32;
97    pub const UART_TX_STATUS: *const u8 = (MMIO_UART_BASE | 0x100) as *const u8;
98    pub const UART_TX_DATA: *mut u8 = (MMIO_UART_BASE | 0x104) as *mut u8;
99
100    /// `configuration` returns the current I/O configuration as triple (`bitrate`, `data_bits`,
101    /// `stop_bits`).
102    ///
103    /// Note that `bitrate` here represents the value that, when dividing `TK1_CPU_FREQUENCY`,
104    /// produces the intended communication bitrate in bps.
105    pub fn configuration() -> (u16, u8, u8) {
106        (
107            unsafe { ptr::read_volatile(UART_BITRATE) },
108            unsafe { ptr::read_volatile(UART_DATA_BITS) },
109            unsafe { ptr::read_volatile(UART_STOP_BITS) },
110        )
111    }
112
113    /// Configure UART I/O communication.
114    ///
115    /// - `bitrate`: a value that cleanly divides `TK1_CPU_FREQUENCY`, default: 288 (62,500 bps)
116    /// - `data_bits`: a value in range 0-16 (excl.), default: 8.
117    /// - `stop_bits`: a value in range 0-4 (excl.), default: 1.
118    ///
119    /// # Panics
120    /// - In case illegal value is provided for any parameter.
121    pub fn configure(bitrate: u16, data_bits: u8, stop_bits: u8) {
122        assert_eq!(0, crate::TK1_CPU_FREQUENCY % u32::from(bitrate));
123        assert!(data_bits < 16);
124        assert!(stop_bits < 4);
125        unsafe {
126            ptr::write_volatile(UART_BITRATE, bitrate);
127            ptr::write_volatile(UART_DATA_BITS, data_bits);
128            ptr::write_volatile(UART_STOP_BITS, stop_bits);
129        }
130    }
131
132    /// `available` reports the number of bytes available in buffer ready to be read.
133    #[must_use]
134    pub fn available() -> usize {
135        unsafe { ptr::read_volatile(UART_RX_BYTES) as usize }
136    }
137
138    /// `wait` blocks (actively checking status) until new bytes arrive to be read.
139    pub fn wait() {
140        while unsafe { ptr::read_volatile(UART_RX_STATUS) } == 0 {}
141    }
142
143    /// `read_u8` reads a single byte.
144    #[must_use]
145    pub fn read_u8() -> u8 {
146        loop {
147            unsafe {
148                if ptr::read_volatile(UART_RX_STATUS) != 0 {
149                    return ptr::read_volatile(UART_RX_DATA);
150                }
151            }
152        }
153    }
154
155    /// `read_into` reads bytes with length of the slice into the provided slice.
156    pub fn read_into(buffer: &mut [u8]) {
157        for cell in buffer.iter_mut() {
158            *cell = read_u8();
159        }
160    }
161
162    /// `read_available` reads data that is currently available in receive-buffer into `buffer`,
163    /// up until receive-buffer is empty or `buffer` is filled.
164    /// Returns number of bytes read, possibly 0 if no bytes are available in the buffer.
165    pub fn read_available(buffer: &mut [u8]) -> usize {
166        let n = available();
167        if n == 0 {
168            return 0;
169        }
170        let n = n.min(buffer.len());
171        read_into(&mut buffer[0..n]);
172        n
173    }
174
175    /// `read_into_checked` reads to fill provided `buffer` iff sufficient data is available in
176    /// receive-buffer.
177    ///
178    /// # Errors
179    /// `Error::Underrun` in case availability of data in receive-buffer is short.
180    pub fn read_into_checked(buffer: &mut [u8]) -> Result<(), Error> {
181        if buffer.len() > available() {
182            return Err(Error::Underrun);
183        }
184        read_into(buffer);
185        Ok(())
186    }
187
188    /// `read_into_timed` receives data into `buffer` until buffer is filled or `timeout` is
189    /// reached. `timeout` is a timeout in milliseconds.
190    ///
191    /// Note: this function uses the timer, so the timer must not be in use.
192    ///
193    /// # Errors
194    /// In case of timeout before buffer is filled.
195    ///
196    /// # Panics
197    /// In case timer is already running.
198    pub fn read_into_timed(buffer: &mut [u8], timeout: u32) -> Result<(), Error> {
199        assert!(!timer::running());
200        timer::set_prescaler(timer::PRESCALE_MILLISECONDS);
201        timer::initialize(timeout);
202        timer::start();
203        let mut i = 0usize;
204        while timer::running() {
205            // Read many bytes if available, so we read the maximum amount in case of looming
206            // deadline (`timeout`). (As opposed to looping after reading a single byte.)
207            i += read_available(&mut buffer[i..]);
208            if i == buffer.len() {
209                timer::stop();
210                return Ok(());
211            }
212        }
213        Err(Error::Timeout)
214    }
215
216    /// `read_into_restricted` will attempt to read data from receive-buffer. The read amount is
217    /// either a full buffer, or whatever was available at that time. The maximum amount of time
218    /// spent on receiving data is limited by `cycles` number of iterations.
219    ///
220    /// Returns number of bytes read, from 0 to `buffer.len()`.
221    pub fn read_into_limited(buffer: &mut [u8], cycles: u32) -> usize {
222        let mut n = 0usize;
223        for _ in 0..cycles {
224            n += read_available(&mut buffer[n..]);
225            if n == buffer.len() {
226                break;
227            }
228        }
229        n
230    }
231
232    /// `read` reads N bytes.
233    #[must_use]
234    pub fn read<const N: usize>() -> [u8; N] {
235        let mut buffer = [0u8; N];
236        read_into(&mut buffer);
237        buffer
238    }
239
240    /// `read_checked` reads `N` bytes after checking for availability in the current reception
241    /// buffer.
242    ///
243    /// # Errors
244    /// `Error::Underrun` in case availability of data in receive-buffer is short.
245    pub fn read_checked<const N: usize>() -> Result<[u8; N], Error> {
246        if N > available() {
247            return Err(Error::Underrun);
248        }
249        Ok(read())
250    }
251
252    /// `read_timed` reads `N` bytes or until `timeout` (milliseconds) is reached.
253    ///
254    /// # Errors
255    /// In case timeout is reached.
256    pub fn read_timed<const N: usize>(timeout: u32) -> Result<[u8; N], Error> {
257        let mut buffer = [0u8; N];
258        read_into_timed(&mut buffer, timeout)?;
259        Ok(buffer)
260    }
261
262    /// `write_u8` writes a single byte.
263    pub fn write_u8(b: u8) {
264        loop {
265            unsafe {
266                if ptr::read_volatile(UART_TX_STATUS) != 0 {
267                    ptr::write_volatile(UART_TX_DATA, b);
268                    return;
269                }
270            }
271        }
272    }
273
274    /// `write` writes provided data.
275    pub fn write(data: &[u8]) {
276        for b in data {
277            write_u8(*b);
278        }
279    }
280}
281
282/// `frame` module contains logic for constructing frames (header and payload) according to the
283/// specified protocol.
284pub mod frame {
285    use crate::{io, Error};
286
287    pub const LENGTH_MAX: usize = 128;
288
289    /// `Endpoint` indicates the intended endpoint for a frame, as indicated in the header-byte.
290    #[derive(Clone, Copy)]
291    pub enum Endpoint {
292        Firmware = 2,
293        Software = 3,
294    }
295
296    /// `CommandLength` represents the command-length class.
297    #[derive(Clone, Copy)]
298    pub enum CommandLength {
299        Length1 = 0,
300        Length4 = 1,
301        Length32 = 2,
302        Length128 = 3,
303    }
304
305    /// `command_length` convertes command length indicator to a value.
306    #[must_use]
307    pub fn command_length(length: CommandLength) -> usize {
308        match length {
309            CommandLength::Length1 => 1,
310            CommandLength::Length4 => 4,
311            CommandLength::Length32 => 32,
312            CommandLength::Length128 => 128,
313        }
314    }
315
316    /// `create_headerbyte` creates a header-byte from individual values.
317    #[must_use]
318    pub fn create_headerbyte(id: u8, endpoint: Endpoint, status: u8, length: CommandLength) -> u8 {
319        (id & 0b0000_0011) << 5 | (endpoint as u8) << 3 | (status & 0b0000_0001) << 2 | length as u8
320    }
321
322    /// `encode_header` encodes a header into a byte.
323    #[must_use]
324    pub fn encode_header(header: &Header) -> u8 {
325        create_headerbyte(
326            header.id,
327            header.endpoint,
328            u8::from(header.error),
329            header.length,
330        )
331    }
332
333    /// `Header` is the first byte of a frame, which contains an id, endpoint, status-bit (unused in
334    /// requests, indicates error in responses), length (one of predefined request/response lengths).
335    #[derive(Clone, Copy)]
336    pub struct Header {
337        /// `id` represents an 2-bit identifier to allow distinguishing several interweaved
338        /// communication streams.
339        pub id: u8,
340        /// `endpoint` indicates whether the frame is intended for the firmware or the loaded
341        /// application. The firmware or loaded application can then reject the frame early if addressed
342        /// incorrectly.
343        pub endpoint: Endpoint,
344        /// `error`, `false` indicates a good result, or `true` to signal bad result (and consequently
345        /// no frame-body).
346        pub error: bool,
347        /// `length` indicator for one of 4 variants of frame-length: 1, 4, 32 or 128 bytes.
348        pub length: CommandLength,
349    }
350
351    /// `parse_into` parses the header-byte to reconstruct the header.
352    ///
353    /// # Errors
354    /// In case of protocol violations or otherwise illegal values.
355    ///
356    /// # Panics
357    /// In case of impossible situation, most likely indicating a bug.
358    pub fn parse_into(dst: &mut Header, headerbyte: u8) -> Result<(), Error> {
359        if headerbyte & 0b1000_0000 != 0 {
360            return Err(Error::ProtocolViolation(
361                "illegal value for reserved bit (protocol version)",
362            ));
363        }
364        if headerbyte & 0b0000_0100 != 0 {
365            return Err(Error::ProtocolViolation(
366                "illegal value for unused bit (response status)",
367            ));
368        }
369        dst.id = (headerbyte & 0b0110_0000) >> 5;
370        dst.endpoint = match (headerbyte & 0b0001_1000) >> 3 {
371            0 | 1 => return Err(Error::ProtocolViolation("illegal value for endpoint")),
372            2 => Endpoint::Firmware,
373            3 => Endpoint::Software,
374            _ => panic!("BUG: impossible value for id in frame-byte"),
375        };
376        dst.error = false;
377        dst.length = match headerbyte & 0b0000_0011 {
378            0 => CommandLength::Length1,
379            1 => CommandLength::Length4,
380            2 => CommandLength::Length32,
381            3 => CommandLength::Length128,
382            _ => panic!("BUG: impossible value for command length in frame-byte"),
383        };
384        Ok(())
385    }
386
387    /// `parse` parses the header-byte of the frame.
388    ///
389    /// # Errors
390    /// In case of protocol violation or otherwise illegal value.
391    pub fn parse(headerbyte: u8) -> Result<Header, Error> {
392        let mut header = Header {
393            id: 0,
394            endpoint: Endpoint::Firmware,
395            error: false,
396            length: CommandLength::Length1,
397        };
398        parse_into(&mut header, headerbyte)?;
399        Ok(header)
400    }
401
402    /// `read_into` reads a complete frame into header and buffer.
403    ///
404    /// # Errors
405    /// In case of protocol violation or otherwise illegal value in the header-byte.
406    pub fn read_into(header: &mut Header, buffer: &mut [u8; LENGTH_MAX]) -> Result<(), Error> {
407        let headerbyte = io::read_u8();
408        parse_into(header, headerbyte)?;
409        let length = command_length(header.length);
410        io::read_into(&mut buffer[..length]);
411        Ok(())
412    }
413
414    /// `write` writes a frame, both header and payload. Only as many bytes of payload are written,
415    /// as is specified by the length in the header, so `1`, `4`, `32` or `128` bytes. A larger
416    /// buffer may be provided, but will not be written fully.
417    ///
418    /// # Panics
419    /// Panics if provided data-buffer is smaller than length specified in the provided header.
420    pub fn write(header: &Header, data: &[u8]) {
421        let length = command_length(header.length);
422        assert!(data.len() >= length);
423        io::write_u8(encode_header(header));
424        io::write(&data[..length]);
425    }
426}
427
428/// `gpio` provides only the constants for addressing the appropriate memory region. The GPIO pins
429/// are not exposed in the ready-sold TKeys, so they are only of benefit for the unlocked versions.
430pub mod gpio {
431    use crate::MMIO_TK1_BASE;
432
433    pub const TK1_GPIO: *mut u8 = (MMIO_TK1_BASE | 0x28) as *mut u8;
434    pub const TK1_GPIO_BIT_1: u8 = 0;
435    pub const TK1_GPIO_BIT_2: u8 = 1;
436    pub const TK1_GPIO_BIT_3: u8 = 2;
437    pub const TK1_GPIO_BIT_4: u8 = 3;
438}
439
440/// `trng` is the module for the true-RNG. Note that this RNG is not guaranteed cryptographically-
441/// secure and it is recommended to mix the entropy from the TRNG with cryptographically-suitable
442/// mechanisms.
443///
444/// Entropy is produced at a rate of approximately 66.6 times per second.
445pub mod trng {
446    use core::ptr;
447
448    use crate::MMIO_TRNG_BASE;
449
450    /// `TRNG_STATUS` the address that hosts the bit indicating whether the entropy-source is ready.
451    pub const TRNG_STATUS: *const u8 = (MMIO_TRNG_BASE | 0x24) as *const u8;
452    /// `TRNG_BIT_READY` is the bit (index) that hosts the ready-indicator.
453    pub const TRNG_BIT_READY: u8 = 0;
454    /// `TRNG_FLAG_READY` is the mask value for selecting specifically the 'ready'-bit.
455    pub const TRNG_FLAG_READY: u8 = 1 << TRNG_BIT_READY;
456    /// `TRNG_ENTROPY` is the address for the TRNG entropy-source.
457    pub const TRNG_ENTROPY: *const u32 = (MMIO_TRNG_BASE | 0x80) as *const u32;
458
459    /// `ready` returns true iff new entropy is available.
460    #[must_use]
461    pub fn ready() -> bool {
462        unsafe { ptr::read_volatile(TRNG_STATUS) & TRNG_FLAG_READY != 0 }
463    }
464
465    /// `wait` waits for the entropy source to become ready. (blocking)
466    ///
467    /// Entropy is produced at a rate of approximately 66.6 times per second.
468    pub fn wait() {
469        while !ready() {}
470    }
471
472    /// `read` reads data from the TRNG entropy location, regardless of whether new entropy is
473    /// available. (Check `ready` to check availability.)
474    #[must_use]
475    pub fn read() -> u32 {
476        unsafe { ptr::read_volatile(TRNG_ENTROPY) }
477    }
478
479    /// `read_next` waits for the TRNG to become ready then reads the available entropy from the
480    /// entropy source.
481    ///
482    /// Entropy is produced at a rate of approximately 66.6 times per second.
483    #[must_use]
484    pub fn read_next() -> u32 {
485        wait();
486        read()
487    }
488
489    /// `read_bytes` reads data, as 4 bytes, from the entropy source, regardless of whether new
490    /// entropy is available. (Check `ready` for availability.)
491    #[allow(clippy::cast_possible_truncation)]
492    #[must_use]
493    pub fn read_bytes() -> [u8; 4] {
494        let v = read();
495        [v as u8, (v >> 8) as u8, (v >> 16) as u8, (v >> 24) as u8]
496    }
497
498    /// `read_bytes_next` waits for the TRNG to become ready then reads the available entropy from
499    /// the entropy source.
500    ///
501    /// Entropy is produced at a rate of approximately 66.6 times per second.
502    #[must_use]
503    pub fn read_bytes_next() -> [u8; 4] {
504        wait();
505        read_bytes()
506    }
507
508    /// `gather` reads entropy from the TRNG as it becomes ready and fills the provided buffer,
509    /// blocking as it waits for new entropy to become available. The TRNG rate of production is
510    /// about 66.6 times per second. This function should be used sparingly, if at all.
511    ///
512    /// Note: `gather` should not be used as a cryptographically-secure random-bytes generator. See
513    /// `rustkey::random`.
514    pub fn gather(buffer: &mut [u8]) {
515        for i in (0..buffer.len()).step_by(4) {
516            unsafe {
517                // loop until new entropy is available
518                while ptr::read_volatile(TRNG_STATUS) & TRNG_FLAG_READY == 0 {}
519                ptr::copy_nonoverlapping(
520                    TRNG_ENTROPY.cast::<u8>(),
521                    buffer[i..].as_mut_ptr(),
522                    4.min(buffer.len() - i),
523                );
524            }
525        }
526    }
527}
528
529/// `led` module controls the LED on the TKey.
530pub mod led {
531    use core::ptr;
532
533    use crate::{sleep, MMIO_TK1_BASE};
534
535    /// `TK1_LED` is the address for controlling the LED.
536    pub const TK1_LED: *mut u8 = (MMIO_TK1_BASE | 0x24) as *mut u8;
537    /// `TK1_LED_BIT_RED` is the bit (index) that controls the red led.
538    pub const TK1_LED_BIT_RED: u8 = 2;
539    /// `TK1_LED_BIT_GREEN` is the bit (index) that controls the green led.
540    pub const TK1_LED_BIT_GREEN: u8 = 1;
541    /// `TK1_LED_BIT_BLUE` is the bit (index) that controls the blue led.
542    pub const TK1_LED_BIT_BLUE: u8 = 0;
543
544    pub const LED_OFF: u8 = 0;
545    pub const LED_BLUE: u8 = 1 << TK1_LED_BIT_BLUE;
546    pub const LED_GREEN: u8 = 1 << TK1_LED_BIT_GREEN;
547    pub const LED_RED: u8 = 1 << TK1_LED_BIT_RED;
548    pub const LED_YELLOW: u8 = LED_RED | LED_GREEN;
549    pub const LED_PURPLE: u8 = LED_RED | LED_BLUE;
550    pub const LED_CYAN: u8 = LED_GREEN | LED_BLUE;
551    pub const LED_WHITE: u8 = LED_RED | LED_GREEN | LED_BLUE;
552
553    /// `get` gets the current LED value.
554    pub fn get() -> u8 {
555        unsafe { ptr::read_volatile(TK1_LED) & 0x7 }
556    }
557
558    /// `set` sets the LED value.
559    pub fn set(color: u8) {
560        unsafe { ptr::write_volatile(TK1_LED, color & 0x7) }
561    }
562
563    /// `change` sets the LED to a new color and returns the previous color.
564    #[must_use]
565    pub fn change(color: u8) -> u8 {
566        let prev = get();
567        set(color);
568        prev
569    }
570
571    /// `signal` performs `count` flashes uniformly between two LED-colors: `color1` and `color2`.
572    /// Afterwards, the previous LED color is restored. Blinking the LED with alternating colors,
573    /// is a simple but effective way to signal a user that is physically near the TKey device.
574    pub fn signal(count: usize, color1: u8, color2: u8) {
575        let restore = get();
576        for _ in 0..count {
577            set(color1);
578            sleep(75000);
579            set(color2);
580            sleep(75000);
581        }
582        set(restore);
583    }
584}
585
586/// `touch` represents the touch-sensor of the TKey.
587pub mod touch {
588    use core::ptr;
589
590    use crate::{led, sleep, MMIO_TOUCH_BASE};
591
592    pub const TOUCH_STATUS: *mut u8 = (MMIO_TOUCH_BASE | 0x24) as *mut u8;
593    pub const TOUCH_STATUS_BIT_EVENT: u8 = 0;
594    pub const TOUCH_STATUS_FLAG_EVENT: u8 = 1 << TOUCH_STATUS_BIT_EVENT;
595
596    /// `reset` reset any previous touch-events.
597    pub fn reset() {
598        unsafe { ptr::write_volatile(TOUCH_STATUS, 0) };
599    }
600
601    /// `touched` returns true iff sensor registered a touch-event. (Use `reset` to clear a possible
602    /// previous touch-event.)
603    pub fn touched() -> bool {
604        unsafe { ptr::read_volatile(TOUCH_STATUS) & TOUCH_STATUS_FLAG_EVENT != 0 }
605    }
606
607    /// `request` touch confirmation by initiating a (finite) loop that blinks the led and checks
608    /// the touch-sensor for confirmation. The current led-color will be restored after use.
609    ///
610    /// Returns true iff sensor is touched within the request-period, or false if no touch was
611    /// registered within this period.
612    #[must_use]
613    pub fn request(count: u16, color: u8) -> bool {
614        let restore = led::get();
615        reset();
616        for i in 0..usize::from(count) * 4 {
617            led::set(if i % 2 == 0 { led::LED_OFF } else { color });
618            if touched() {
619                led::set(restore);
620                return true;
621            }
622            sleep(if i % 4 == 0 { 200_000 } else { 100_000 });
623        }
624        led::set(restore);
625        false
626    }
627}
628
629/// `timer` module provides access to the device's countdown-timer.
630///
631/// The timer counts down from the `initial` value and the resolution is scaled using the
632/// `prescaler`. With a `prescaler` value of `0`, every clock-cycle is a timer-tick. For a timer
633/// that ticks every second, set the `prescaler` to `18_000_000` and then `initialize` the timer
634/// with however many seconds count-down is needed.
635///
636/// Note: these functions require knowledge of the current state of the timer (running/stopped),
637/// because both initial timer value and prescaler can be modified, which completely alters the
638/// interpretation of timer values, therefore it is critical to be aware of the current
639/// configuration.
640pub mod timer {
641    use core::ptr;
642
643    use crate::{MMIO_TIMER_BASE, TK1_CPU_FREQUENCY};
644
645    pub const TIMER_CTRL: *mut u32 = (MMIO_TIMER_BASE | 0x20) as *mut u32;
646    pub const TIMER_CTRL_BIT_START: u32 = 0;
647    pub const TIMER_CTRL_FLAG_START: u32 = 1 << TIMER_CTRL_BIT_START;
648    pub const TIMER_CTRL_BIT_STOP: u32 = 1;
649    pub const TIMER_CTRL_FLAG_STOP: u32 = 1 << TIMER_CTRL_BIT_STOP;
650    pub const TIMER_STATUS: *const u32 = (MMIO_TIMER_BASE | 0x24) as *mut u32;
651    pub const TIMER_STATUS_BIT_RUNNING: u32 = 0;
652    pub const TIMER_STATUS_FLAG_RUNNING: u32 = 1 << TIMER_STATUS_BIT_RUNNING;
653    pub const TIMER_PRESCALER: *mut u32 = (MMIO_TIMER_BASE | 0x28) as *mut u32;
654    pub const TIMER_TIMER: *mut u32 = (MMIO_TIMER_BASE | 0x2c) as *mut u32;
655
656    /// `PRESCALE_SECONDS` is the prescaler value that results in 1-second timer-ticks. (Given an
657    /// 18 MHz processor, a second is about 18,000,000 cycles.)
658    pub const PRESCALE_SECONDS: u32 = TK1_CPU_FREQUENCY;
659    /// `PRESCALE_MILLISECONDS` is the prescaler value that results in 0.001-second timer-ticks.
660    /// (Given an 18 MHz processor, a millisecond is about 18,000 cycles.)
661    pub const PRESCALE_MILLISECONDS: u32 = TK1_CPU_FREQUENCY / 1000;
662
663    /// `running()` indicates the current status of the timer: false if stopped, true if running.
664    #[must_use]
665    pub fn running() -> bool {
666        unsafe { ptr::read_volatile(TIMER_STATUS) & TIMER_STATUS_FLAG_RUNNING != 0 }
667    }
668
669    /// `set_prescaler` sets the prescaler. A value is `18_000_000`, i.e. gives one tick per
670    /// second given that the processor operates at 18 MHz. The prescaler can be used to scale the
671    /// timer from very high frequencies (microseconds) with low or zero prescaler, to low
672    /// frequencies (seconds) with high prescaler.
673    ///
674    /// # Panics
675    /// Panics if timer is already running.
676    pub fn set_prescaler(prescaler: u32) {
677        assert!(!running());
678        unsafe { ptr::write_volatile(TIMER_PRESCALER, prescaler) }
679    }
680
681    /// `initialize` sets the initial timer value. Only allowed if timer is not running.
682    ///
683    /// # Panics
684    /// Panics if timer is already running.
685    pub fn initialize(initial: u32) {
686        assert!(!running());
687        unsafe { ptr::write_volatile(TIMER_TIMER, initial) }
688    }
689
690    /// `current` gets the initial timer value if stopped, or the current timer value if running.
691    pub fn current() -> u32 {
692        unsafe { ptr::read_volatile(TIMER_TIMER) }
693    }
694
695    /// `start` starts the timer if stopped.
696    ///
697    /// Note: upon timer completion (counted down to `1`), the timer value resets to its initial
698    /// value.
699    ///
700    /// Repeat calls of `start()` have no effect.
701    pub fn start() {
702        unsafe { ptr::write_volatile(TIMER_CTRL, TIMER_CTRL_FLAG_START) }
703    }
704
705    /// `stop` stops the timer if started.
706    ///
707    /// Note: upon stopping the timer, the timer value is reset to its initial value.
708    ///
709    /// Repeat calls of `stop()` have no effect.
710    pub fn stop() {
711        unsafe { ptr::write_volatile(TIMER_CTRL, TIMER_CTRL_FLAG_STOP) }
712    }
713
714    /// `wait` waits until the timer has stopped.
715    pub fn wait() {
716        while running() {}
717    }
718
719    /// `wait_until` waits until the timer count-down reaches or has passed the specified value.
720    /// The timer must be running.
721    ///
722    /// # Panics
723    /// Panics if timer is not running.
724    pub fn wait_until(value: u32) {
725        assert!(running());
726        while current() > value {}
727    }
728
729    /// `wait_for` waits for a specified number of ticks of the timer to pass.
730    /// The timer must be running.
731    ///
732    /// # Panics
733    /// Panics if the timer is not running.
734    pub fn wait_for(ticks: u32) {
735        wait_until(current() - ticks);
736    }
737
738    /// `sleep` use timer to perform a timed sleep in amount of seconds. (Blocking until timer
739    /// expires.)
740    ///
741    /// This function is a utility that (re)configures the prescaler for seconds, then initiates a
742    /// timer with the specified number of seconds. The timer must be available.
743    ///
744    /// # Panics
745    /// If called when timer is already running.
746    pub fn sleep(seconds: u32) {
747        assert!(!running());
748        set_prescaler(PRESCALE_SECONDS);
749        initialize(seconds);
750        start();
751        wait();
752    }
753}
754
755/// `cpumonitor` module provides access to the CPU execution monitor.
756pub mod cpumonitor {
757    use core::ptr;
758
759    use crate::MMIO_TK1_BASE;
760
761    pub const TK1_CPU_MONITOR_CTRL: *mut u32 = (MMIO_TK1_BASE | 0x180) as *mut u32;
762    pub const TK1_CPU_MONITOR_FIRST: *mut usize = (MMIO_TK1_BASE | 0x184) as *mut usize;
763    pub const TK1_CPU_MONITOR_LAST: *mut usize = (MMIO_TK1_BASE | 0x188) as *mut usize;
764
765    /// `monitor_range` initializes the CPU execution monitor to the specified address range.
766    /// - `first`: the first (start) address for the range.
767    /// - `last`: the last address (_inclusive_) for the range.
768    ///
769    /// Note: only one CPU execution monitor can be set, and once set cannot be disabled.
770    ///
771    /// According to the developer guide, the application is loaded at the start of RAM, so
772    /// `RAM_BASE == *TK1_APP_ADDR`. Therefore, setting up the CPU execution monitor for start of
773    /// RAM, will always immediately result in cpu abort being triggered. So it seems the earliest
774    /// starting point is at `*TK1_APP_ADDR + *TK1_APP_SIZE`, and last address
775    /// `RAM_BASE + RAM_SIZE - 4`. That is, if we set the monitor for the extent of available
776    /// application RAM.
777    ///
778    /// To see CPU execution monitor in action, set the monitoring range to a range that includes
779    /// application memory (`[*TK1_APP_ADDR, *TK1_APP_ADDR+*TK1_APP_SIZE]`) and have it trigger
780    /// immediately. (This is obviously useless in practice, but does trigger the execution
781    /// monitor.)
782    ///
783    /// # Panics
784    /// - In case of incorrect input arguments, such as `first` > `last`.
785    /// - In case CPU execution monitor is set up more than once.
786    pub fn monitor_range(first: usize, last: usize) {
787        static mut AVAILABLE: bool = true;
788        assert!(first <= last);
789        unsafe {
790            assert!(AVAILABLE);
791            ptr::write_volatile(TK1_CPU_MONITOR_FIRST, first);
792            ptr::write_volatile(TK1_CPU_MONITOR_LAST, last);
793            ptr::write_volatile(TK1_CPU_MONITOR_CTRL, 1);
794            AVAILABLE = false;
795        }
796    }
797
798    /// `monitor_application_memory` sets up the CPU execution monitor to monitor all RAM memory
799    /// past the application binary code. Therefore, all memory available to the application is
800    /// monitored, regardless of how this memory is used.
801    ///
802    /// Note: only one CPU execution monitor can be set, and once set cannot be disabled.
803    ///
804    /// # Panics
805    /// - In case CPU execution monitor is set up more than once.
806    pub fn monitor_application_memory() {
807        monitor_range(
808            unsafe { *crate::TK1_APP_ADDR + *crate::TK1_APP_SIZE },
809            crate::RAM_BASE + crate::RAM_SIZE - 1,
810        );
811    }
812}
813
814/// `read_name_version` reads the name addresses and the version address.
815#[must_use]
816pub fn read_name_version() -> ([u8; 4], [u8; 4], u32) {
817    let mut name0 = [0u8; 4];
818    let mut name1 = [0u8; 4];
819    let version: u32;
820    unsafe {
821        ptr::copy_nonoverlapping(TK1_NAME0.cast::<u8>(), name0.as_mut_ptr(), 4);
822        ptr::copy_nonoverlapping(TK1_NAME1.cast::<u8>(), name1.as_mut_ptr(), 4);
823        version = ptr::read_volatile(TK1_VERSION);
824    }
825    (name0, name1, version)
826}
827
828/// `read_cdi` reads the compound device identifier (CDI).
829// TODO track <https://github.com/tillitis/tillitis-key1/pull/204> for disabling access to CDI.
830#[must_use]
831pub fn read_cdi() -> [u8; 32] {
832    let mut cdi = [0u8; 32];
833    unsafe {
834        ptr::copy_nonoverlapping(TK1_CDI, cdi.as_mut_ptr(), 32);
835    }
836    cdi
837}
838
839#[repr(C)]
840#[derive(Copy, Clone)]
841struct Blake2sContext {
842    pub b: [u8; 64],
843    pub h: [u32; 8],
844    pub t: [u32; 2],
845    pub c: usize,
846    pub outlen: usize,
847}
848
849/// `blake2s` performs a Blake2s hash calculation with immediate result.
850/// - `N`: size of resulting digest, must be larger than 0 and at most 32 bytes.
851/// - `key`: an optional key (for purpose of keyed-hash) of at most 32 bytes.
852/// - `content`: the content of which to produce the digest, of any length.
853///
854/// Returns the resulting digest, an array of size `N`.
855///
856/// `blake2s` does not expose the used context-struct. Given that stack-allocation takes minimal
857/// overhead and firmware's `blake2s` function is self-contained, the provided context is always
858/// (re)initialized and in the end finalized.
859///
860/// # Errors
861/// In case of bad input arguments.
862///
863/// # Panics
864/// In case of incorrect use, such as N too big, key length too big, etc.
865#[cfg(feature = "blake2-firmware")]
866pub fn blake2s(out: &mut [u8], key: &[u8], content: &[u8]) -> Result<(), Error> {
867    if out.is_empty() || out.len() > 32 || key.len() > 32 {
868        return Err(Error::InvalidInput);
869    }
870    let mut ctx = Blake2sContext {
871        b: [0; 64],
872        h: [0; 8],
873        t: [0; 2],
874        c: 0,
875        outlen: 0,
876    };
877    unsafe {
878        let blake2s_fw: unsafe extern "C" fn(
879            out: *mut u8,
880            outlen: usize,
881            key: *const u8,
882            keylen: usize,
883            content: *const u8,
884            contentlen: usize,
885            ctx: *mut Blake2sContext,
886        ) -> i32 = core::mem::transmute(*TK1_BLAKE2S_ADDR);
887        let ret = blake2s_fw(
888            out.as_mut_ptr(),
889            out.len(),
890            key.as_ptr(),
891            key.len(),
892            content.as_ptr(),
893            content.len(),
894            &mut ctx,
895        );
896        // `ret != 0` should be impossible given that we verify arguments before calling blake2s.
897        // However, do not let it pass unchecked. Now we at least have a way to detect unexpected
898        // incorrect use of the firmware's blake2s function.
899        assert_eq!(0, ret);
900    }
901    Ok(())
902}
903
904/// Blake2s from stand-alone implementation.
905///
906/// # Errors
907/// In case of incorrect input arguments.
908///
909/// # Panics
910/// In case of incorrect input.
911#[cfg(all(not(feature = "blake2-firmware"), feature = "blake2-standalone"))]
912pub fn blake2s(out: &mut [u8], key: &[u8], content: &[u8]) -> Result<(), Error> {
913    blake2s::blake2s(out, key, content).map_err(|e| match e {
914        blake2s::Error::InvalidInput => Error::InvalidInput,
915    })
916}
917
918/// _EXPERIMENTAL!_ `hash_firmware_rom` computes the Blake2s hash-value of the TKey firmware in ROM.
919/// The ROM is monitored for execution once the program-binary is loaded to prevent malicious
920/// activity, but it is still readable. A checksum of the firmware may be useful to determine what
921/// exact firmware is running on the device. Especially if (minor) changes are made to the
922/// (memory-mapped) API.
923///
924/// `key` must be at most 32 bytes. (see requirements of `blake2s`)
925///
926/// # Errors
927/// In case of invalid input, e.g. key.
928#[must_use = "Firmware ROM digest stored in the return value."]
929pub fn hash_firmware_rom(key: &[u8]) -> Result<[u8; 32], Error> {
930    let mut out = [0u8; 32];
931    blake2s(&mut out, key, unsafe {
932        core::slice::from_raw_parts(ROM_BASE as *const u8, ROM_SIZE)
933    })?;
934    Ok(out)
935}
936
937/// `random` produces (reasonably) cryptographically-secure (needs to be verified/proved) random
938/// bytes, using the TRNG, Blake2s and optionally seed data. If strong randomness is needed from
939/// very first use, it is recommended to contribute some `seed`-entropy to get the buffer mixed up
940/// faster.
941///
942/// `seed` input is processed in 32-byte chunks, provided as keyed input, to be mixed in with
943/// buffer. (So, for example, providing the in-memory application bytes will do more than simply
944/// calculate the hash-digest of that input.)
945///
946/// Note: `random` isn't free. Use `bench.rs` program for querying random for testing the production
947/// rate or evaluating the quality of the output.
948///
949/// The exact implementation is not fixed, but currently uses an internal buffer to maintain some
950/// buffered random data to be mixed in with other sources of entropy and seed data.
951///
952/// # Panics
953/// In case of bugs. (Should not panic.)
954// TODO provide function for some initial seeding of random? (E.g. use firmware-ROM checksum, CDI derivations, etc. to mix up some unpredictable initial buffer.)
955// TODO currently ignoring `static_mut_refs`.
956#[allow(static_mut_refs)]
957pub fn random(out: &mut [u8], seed: &[u8]) {
958    static mut BUFFER: [u8; 32] = [0u8; 32];
959    for i in (0..seed.len()).step_by(32) {
960        unsafe {
961            blake2s(
962                &mut BUFFER,
963                &seed[i..32.min(seed.len() - i)],
964                &*ptr::addr_of_mut!(BUFFER),
965            )
966            .unwrap();
967        };
968    }
969    if out.is_empty() {
970        // Allow seeding the buffer without taking any output randomness.
971        return;
972    }
973    // Assumption: don't wait for entropy status for initial randomness for key. Instead, assume
974    // that there is some randomness present. This is only for initialization.
975    let mut key: [u8; 4] = trng::read_bytes();
976    for i in (0..out.len()).step_by(32) {
977        // TRNG has low rate for entropy production, so until true-randomness is available, reuse
978        // known entropy in unpredictable way.
979        if trng::ready() {
980            // TODO this ready-case won't be touched very often, because we start out reading from the TRNG. We should probably approach this in a different way.
981            key = trng::read_bytes();
982        } else {
983            key[0] ^= unsafe { BUFFER[key[0] as usize % BUFFER.len()] };
984            key[1] ^= unsafe { BUFFER[key[1] as usize % BUFFER.len()] };
985            key[2] ^= unsafe { BUFFER[key[2] as usize % BUFFER.len()] };
986            key[3] ^= unsafe { BUFFER[key[3] as usize % BUFFER.len()] };
987        }
988        // TODO using the key for randomness, means that only 4 bytes contribute to the unpredictable next bytes. Can we make it a bit more unpredictable?
989        unsafe {
990            blake2s(&mut BUFFER, &key, &*ptr::addr_of_mut!(BUFFER)).unwrap();
991        };
992        let size = 32.min(out.len() - i);
993        // TODO should we blake2s-hash the buffer to produce output-randomness? (Avoids reconstructing internal state, even if this state is still changed before next use.)
994        out[i..i + size].copy_from_slice(unsafe { &BUFFER[..size] });
995    }
996    unsafe {
997        blake2s(
998            &mut BUFFER,
999            "ByeByeOutputBytes".as_bytes(),
1000            &*ptr::addr_of_mut!(BUFFER),
1001        )
1002        .unwrap();
1003    };
1004}
1005
1006/// `sleep` for specified number of cycles (delay by virtue of volatile writes).
1007pub fn sleep(n: usize) {
1008    let mut i = 0usize;
1009    while i < n {
1010        unsafe { ptr::write_volatile(&mut i, i + 1) };
1011    }
1012}
1013
1014/// `done` enters an infinite loop, effectively halting execution.
1015#[allow(clippy::empty_loop)]
1016pub fn done() -> ! {
1017    loop {}
1018}
1019
1020/// `abort` enters infinite loop, effectively aborting execution, with blinking red LED.
1021/// It uses 400,000 cycles for sleeps, therefore flashes at about twice as rapid as CPU halt on
1022/// illegal instruction.
1023pub fn abort() -> ! {
1024    loop {
1025        led::set(led::LED_RED);
1026        sleep(400_000);
1027        led::set(led::LED_OFF);
1028        sleep(400_000);
1029    }
1030}