lowrisc/
virtual_otbn.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Virtualise the Accel interface to enable multiple users of an underlying
6//! Accel hardware peripheral.
7
8use crate::otbn::{Client, Otbn};
9use core::cell::Cell;
10use kernel::collections::list::{ListLink, ListNode};
11use kernel::utilities::cells::OptionalCell;
12use kernel::ErrorCode;
13
14pub struct VirtualMuxAccel<'a> {
15    mux: &'a MuxAccel<'a>,
16    next: ListLink<'a, VirtualMuxAccel<'a>>,
17    client: OptionalCell<&'a dyn Client<'a>>,
18    id: u32,
19}
20
21impl<'a> ListNode<'a, VirtualMuxAccel<'a>> for VirtualMuxAccel<'a> {
22    fn next(&self) -> &'a ListLink<VirtualMuxAccel<'a>> {
23        &self.next
24    }
25}
26
27impl<'a> VirtualMuxAccel<'a> {
28    pub fn new(mux_accel: &'a MuxAccel<'a>) -> VirtualMuxAccel<'a> {
29        let id = mux_accel.next_id.get();
30        mux_accel.next_id.set(id + 1);
31
32        VirtualMuxAccel {
33            mux: mux_accel,
34            next: ListLink::empty(),
35            client: OptionalCell::empty(),
36            id,
37        }
38    }
39
40    pub fn set_client(&'a self, client: &'a dyn Client<'a>) {
41        self.client.set(client);
42    }
43
44    pub fn load_binary(&self, input: &[u8]) -> Result<(), ErrorCode> {
45        // Check if any mux is enabled. If it isn't we enable it for us.
46        if !self.mux.running.get() {
47            self.mux.running.set(true);
48            self.mux.running_id.set(self.id);
49            self.mux.accel.load_binary(input)
50        } else if self.mux.running_id.get() == self.id {
51            self.mux.accel.load_binary(input)
52        } else {
53            Err(ErrorCode::BUSY)
54        }
55    }
56
57    pub fn load_data(&self, address: usize, data: &[u8]) -> Result<(), ErrorCode> {
58        // Check if any mux is enabled. If it isn't we enable it for us.
59        if !self.mux.running.get() {
60            self.mux.running.set(true);
61            self.mux.running_id.set(self.id);
62            self.mux.accel.load_data(address, data)
63        } else if self.mux.running_id.get() == self.id {
64            self.mux.accel.load_data(address, data)
65        } else {
66            Err(ErrorCode::BUSY)
67        }
68    }
69
70    pub fn run(
71        &self,
72        address: usize,
73        output: &'static mut [u8],
74    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
75        // Check if any mux is enabled. If it isn't we enable it for us.
76        if !self.mux.running.get() {
77            self.mux.running.set(true);
78            self.mux.running_id.set(self.id);
79            self.mux.accel.run(address, output)
80        } else if self.mux.running_id.get() == self.id {
81            self.mux.accel.run(address, output)
82        } else {
83            Err((ErrorCode::BUSY, output))
84        }
85    }
86
87    /// Disable the Accel hardware and clear the keys and any other sensitive
88    /// data
89    pub fn clear_data(&self) {
90        if self.mux.running_id.get() == self.id {
91            self.mux.running.set(false);
92            self.mux.accel.clear_data()
93        }
94    }
95}
96
97impl<'a> Client<'a> for VirtualMuxAccel<'a> {
98    fn op_done(&'a self, result: Result<(), ErrorCode>, output: &'static mut [u8]) {
99        self.client
100            .map(move |client| client.op_done(result, output));
101    }
102}
103
104/// Calling a 'set_mode*()' function from a `VirtualMuxAccel` will mark that
105/// `VirtualMuxAccel` as the one that has been enabled and running.
106///
107/// Until that Mux calls `clear_data()` it will be the only
108/// `VirtualMuxAccel` that can interact with the underlying device.
109pub struct MuxAccel<'a> {
110    accel: &'a Otbn<'a>,
111    running: Cell<bool>,
112    running_id: Cell<u32>,
113    next_id: Cell<u32>,
114}
115
116impl<'a> MuxAccel<'a> {
117    pub const fn new(accel: &'a Otbn<'a>) -> MuxAccel<'a> {
118        MuxAccel {
119            accel,
120            running: Cell::new(false),
121            running_id: Cell::new(0),
122            next_id: Cell::new(0),
123        }
124    }
125}