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}