capsules_extra/
hmac.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//! HMAC (Hash-based Message Authentication Code).
6//!
7//! Usage
8//! -----
9//!
10//! ```rust,ignore
11//! let hmac = &earlgrey::hmac::HMAC;
12//!
13//! let mux_hmac = static_init!(MuxHmac<'static, lowrisc::hmac::Hmac>, MuxHmac::new(hmac));
14//! digest::Digest::set_client(&earlgrey::hmac::HMAC, mux_hmac);
15//!
16//! let virtual_hmac_user = static_init!(
17//!     VirtualMuxHmac<'static, lowrisc::hmac::Hmac>,
18//!     VirtualMuxHmac::new(mux_hmac)
19//! );
20//! let hmac = static_init!(
21//!     capsules::hmac::HmacDriver<'static, VirtualMuxHmac<'static, lowrisc::hmac::Hmac>>,
22//!     capsules::hmac::HmacDriver::new(
23//!         virtual_hmac_user,
24//!         board_kernel.create_grant(&memory_allocation_cap),
25//!     )
26//! );
27//! digest::Digest::set_client(virtual_hmac_user, hmac);
28//! ```
29
30use capsules_core::driver;
31use kernel::errorcode::into_statuscode;
32/// Syscall driver number.
33pub const DRIVER_NUM: usize = driver::NUM::Hmac as usize;
34
35/// Ids for read-only allow buffers
36mod ro_allow {
37    pub const KEY: usize = 0;
38    pub const DATA: usize = 1;
39    pub const COMPARE: usize = 2;
40    /// The number of allow buffers the kernel stores for this grant
41    pub const COUNT: u8 = 3;
42}
43
44/// Ids for read-write allow buffers
45mod rw_allow {
46    pub const DEST: usize = 2;
47    /// The number of allow buffers the kernel stores for this grant
48    pub const COUNT: u8 = 3;
49}
50
51use core::cell::Cell;
52
53use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
54use kernel::hil::digest;
55use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
56use kernel::syscall::{CommandReturn, SyscallDriver};
57use kernel::utilities::cells::{OptionalCell, TakeCell};
58use kernel::utilities::leasable_buffer::SubSlice;
59use kernel::utilities::leasable_buffer::SubSliceMut;
60use kernel::{ErrorCode, ProcessId};
61
62enum ShaOperation {
63    Sha256,
64    Sha384,
65    Sha512,
66}
67
68// Temporary buffer to copy the keys from userspace into
69//
70// Needs to be able to accommodate the largest key sizes, e.g. 512
71const TMP_KEY_BUFFER_SIZE: usize = 512 / 8;
72
73pub struct HmacDriver<'a, H: digest::Digest<'a, L>, const L: usize> {
74    hmac: &'a H,
75
76    active: Cell<bool>,
77
78    apps: Grant<
79        App,
80        UpcallCount<1>,
81        AllowRoCount<{ ro_allow::COUNT }>,
82        AllowRwCount<{ rw_allow::COUNT }>,
83    >,
84    processid: OptionalCell<ProcessId>,
85
86    data_buffer: TakeCell<'static, [u8]>,
87    data_copied: Cell<usize>,
88    dest_buffer: TakeCell<'static, [u8; L]>,
89}
90
91impl<
92        'a,
93        H: digest::Digest<'a, L> + digest::HmacSha256 + digest::HmacSha384 + digest::HmacSha512,
94        const L: usize,
95    > HmacDriver<'a, H, L>
96{
97    pub fn new(
98        hmac: &'a H,
99        data_buffer: &'static mut [u8],
100        dest_buffer: &'static mut [u8; L],
101        grant: Grant<
102            App,
103            UpcallCount<1>,
104            AllowRoCount<{ ro_allow::COUNT }>,
105            AllowRwCount<{ rw_allow::COUNT }>,
106        >,
107    ) -> HmacDriver<'a, H, L> {
108        HmacDriver {
109            hmac,
110            active: Cell::new(false),
111            apps: grant,
112            processid: OptionalCell::empty(),
113            data_buffer: TakeCell::new(data_buffer),
114            data_copied: Cell::new(0),
115            dest_buffer: TakeCell::new(dest_buffer),
116        }
117    }
118
119    fn run(&self) -> Result<(), ErrorCode> {
120        self.processid.map_or(Err(ErrorCode::RESERVE), |processid| {
121            self.apps
122                .enter(processid, |app, kernel_data| {
123                    kernel_data
124                        .get_readonly_processbuffer(ro_allow::KEY)
125                        .and_then(|key| {
126                            key.enter(|k| {
127                                if let Some(op) = &app.sha_operation {
128                                    let mut tmp_key_buffer: [u8; TMP_KEY_BUFFER_SIZE] =
129                                        [0; TMP_KEY_BUFFER_SIZE];
130                                    let key_len = core::cmp::min(k.len(), TMP_KEY_BUFFER_SIZE);
131                                    k[..key_len].copy_to_slice(&mut tmp_key_buffer[..key_len]);
132
133                                    match op {
134                                        ShaOperation::Sha256 => self
135                                            .hmac
136                                            .set_mode_hmacsha256(&tmp_key_buffer[..key_len]),
137                                        ShaOperation::Sha384 => self
138                                            .hmac
139                                            .set_mode_hmacsha384(&tmp_key_buffer[..key_len]),
140                                        ShaOperation::Sha512 => self
141                                            .hmac
142                                            .set_mode_hmacsha512(&tmp_key_buffer[..key_len]),
143                                    }
144                                } else {
145                                    Err(ErrorCode::INVAL)
146                                }
147                            })
148                        })
149                        .unwrap_or(Err(ErrorCode::RESERVE))?;
150
151                    kernel_data
152                        .get_readonly_processbuffer(ro_allow::DATA)
153                        .and_then(|data| {
154                            data.enter(|data| {
155                                let mut static_buffer_len = 0;
156                                self.data_buffer.map(|buf| {
157                                    // Determine the size of the static buffer we have
158                                    static_buffer_len = buf.len();
159
160                                    if static_buffer_len > data.len() {
161                                        static_buffer_len = data.len()
162                                    }
163
164                                    self.data_copied.set(static_buffer_len);
165
166                                    // Copy the data into the static buffer
167                                    data[..static_buffer_len]
168                                        .copy_to_slice(&mut buf[..static_buffer_len]);
169                                });
170
171                                // Add the data from the static buffer to the HMAC
172                                let mut lease_buf = SubSliceMut::new(
173                                    self.data_buffer.take().ok_or(ErrorCode::RESERVE)?,
174                                );
175                                lease_buf.slice(0..static_buffer_len);
176                                if let Err(e) = self.hmac.add_mut_data(lease_buf) {
177                                    self.data_buffer.replace(e.1.take());
178                                    return Err(e.0);
179                                }
180                                Ok(())
181                            })
182                        })
183                        .unwrap_or(Err(ErrorCode::RESERVE))
184                })
185                .unwrap_or_else(|err| Err(err.into()))
186        })
187    }
188
189    fn calculate_digest(&self) -> Result<(), ErrorCode> {
190        self.data_copied.set(0);
191
192        if let Err(e) = self
193            .hmac
194            .run(self.dest_buffer.take().ok_or(ErrorCode::RESERVE)?)
195        {
196            // Error, clear the processid and data
197            self.hmac.clear_data();
198            self.processid.clear();
199            self.dest_buffer.replace(e.1);
200
201            return Err(e.0);
202        }
203
204        Ok(())
205    }
206
207    fn verify_digest(&self) -> Result<(), ErrorCode> {
208        self.data_copied.set(0);
209
210        if let Err(e) = self
211            .hmac
212            .verify(self.dest_buffer.take().ok_or(ErrorCode::RESERVE)?)
213        {
214            // Error, clear the processid and data
215            self.hmac.clear_data();
216            self.processid.clear();
217            self.dest_buffer.replace(e.1);
218
219            return Err(e.0);
220        }
221
222        Ok(())
223    }
224
225    fn check_queue(&self) {
226        for appiter in self.apps.iter() {
227            let started_command = appiter.enter(|app, _| {
228                // If an app is already running let it complete
229                if self.processid.is_some() {
230                    return true;
231                }
232
233                // If this app has a pending command let's use it.
234                app.pending_run_app.take().is_some_and(|processid| {
235                    // Mark this driver as being in use.
236                    self.processid.set(processid);
237                    // Actually make the buzz happen.
238                    self.run() == Ok(())
239                })
240            });
241            if started_command {
242                break;
243            }
244        }
245    }
246}
247
248impl<
249        'a,
250        H: digest::Digest<'a, L> + digest::HmacSha256 + digest::HmacSha384 + digest::HmacSha512,
251        const L: usize,
252    > digest::ClientData<L> for HmacDriver<'a, H, L>
253{
254    // Because data needs to be copied from a userspace buffer into a kernel (RAM) one,
255    // we always pass mut data; this callback should never be invoked.
256    fn add_data_done(&self, _result: Result<(), ErrorCode>, _data: SubSlice<'static, u8>) {}
257
258    fn add_mut_data_done(&self, _result: Result<(), ErrorCode>, data: SubSliceMut<'static, u8>) {
259        self.processid.map(move |id| {
260            self.apps
261                .enter(id, move |app, kernel_data| {
262                    let mut data_len = 0;
263                    let mut exit = false;
264                    let mut static_buffer_len = 0;
265
266                    self.data_buffer.replace(data.take());
267
268                    self.data_buffer.map(|buf| {
269                        let ret = kernel_data
270                            .get_readonly_processbuffer(ro_allow::DATA)
271                            .and_then(|data| {
272                                data.enter(|data| {
273                                    // Determine the size of the static buffer we have
274                                    static_buffer_len = buf.len();
275                                    // Determine how much data we have already copied
276                                    let copied_data = self.data_copied.get();
277
278                                    data_len = data.len();
279
280                                    if data_len > copied_data {
281                                        let remaining_data = &data[copied_data..];
282                                        let remaining_len = data_len - copied_data;
283
284                                        if remaining_len < static_buffer_len {
285                                            remaining_data.copy_to_slice(&mut buf[..remaining_len]);
286                                        } else {
287                                            remaining_data[..static_buffer_len].copy_to_slice(buf);
288                                        }
289                                    }
290                                    Ok(())
291                                })
292                            })
293                            .unwrap_or(Err(ErrorCode::RESERVE));
294
295                        if ret == Err(ErrorCode::RESERVE) {
296                            // No data buffer, clear the processid and data
297                            self.hmac.clear_data();
298                            self.processid.clear();
299                            exit = true;
300                        }
301                    });
302
303                    if exit {
304                        return;
305                    }
306
307                    if static_buffer_len > 0 {
308                        let copied_data = self.data_copied.get();
309
310                        if data_len > copied_data {
311                            // Update the amount of data copied
312                            self.data_copied.set(copied_data + static_buffer_len);
313
314                            let mut lease_buf = SubSliceMut::new(self.data_buffer.take().unwrap());
315
316                            // Add the data from the static buffer to the HMAC
317                            if data_len < (copied_data + static_buffer_len) {
318                                lease_buf.slice(..(data_len - copied_data))
319                            }
320
321                            if self.hmac.add_mut_data(lease_buf).is_err() {
322                                // Error, clear the processid and data
323                                self.hmac.clear_data();
324                                self.processid.clear();
325                                return;
326                            }
327
328                            // Return as we don't want to run the digest yet
329                            return;
330                        }
331                    }
332
333                    // If we get here we are ready to run the digest, reset the copied data
334                    if app.op.get().unwrap() == UserSpaceOp::Run {
335                        if let Err(e) = self.calculate_digest() {
336                            kernel_data
337                                .schedule_upcall(0, (into_statuscode(e.into()), 0, 0))
338                                .ok();
339                        }
340                    } else if app.op.get().unwrap() == UserSpaceOp::Verify {
341                        let _ = kernel_data
342                            .get_readonly_processbuffer(ro_allow::COMPARE)
343                            .and_then(|compare| {
344                                compare.enter(|compare| {
345                                    let mut static_buffer_len = 0;
346                                    self.dest_buffer.map(|buf| {
347                                        // Determine the size of the static buffer we have
348                                        static_buffer_len = buf.len();
349
350                                        if static_buffer_len > compare.len() {
351                                            static_buffer_len = compare.len()
352                                        }
353
354                                        self.data_copied.set(static_buffer_len);
355
356                                        // Copy the data into the static buffer
357                                        compare[..static_buffer_len]
358                                            .copy_to_slice(&mut buf[..static_buffer_len]);
359                                    });
360                                })
361                            });
362
363                        if let Err(e) = self.verify_digest() {
364                            kernel_data
365                                .schedule_upcall(1, (into_statuscode(e.into()), 0, 0))
366                                .ok();
367                        }
368                    } else {
369                        kernel_data.schedule_upcall(0, (0, 0, 0)).ok();
370                    }
371                })
372                .map_err(|err| {
373                    if err == kernel::process::Error::NoSuchApp
374                        || err == kernel::process::Error::InactiveApp
375                    {
376                        self.processid.clear();
377                    }
378                })
379        });
380
381        self.check_queue();
382    }
383}
384
385impl<
386        'a,
387        H: digest::Digest<'a, L> + digest::HmacSha256 + digest::HmacSha384 + digest::HmacSha512,
388        const L: usize,
389    > digest::ClientHash<L> for HmacDriver<'a, H, L>
390{
391    fn hash_done(&self, result: Result<(), ErrorCode>, digest: &'static mut [u8; L]) {
392        self.processid.map(|id| {
393            self.apps
394                .enter(id, |_, kernel_data| {
395                    self.hmac.clear_data();
396
397                    let pointer = digest[0] as *mut u8;
398
399                    let _ = kernel_data
400                        .get_readwrite_processbuffer(rw_allow::DEST)
401                        .and_then(|dest| {
402                            dest.mut_enter(|dest| {
403                                let len = dest.len();
404
405                                if len < L {
406                                    dest.copy_from_slice(&digest[0..len]);
407                                } else {
408                                    dest[0..L].copy_from_slice(digest);
409                                }
410                            })
411                        });
412
413                    match result {
414                        Ok(()) => kernel_data.schedule_upcall(0, (0, pointer as usize, 0)),
415                        Err(e) => kernel_data
416                            .schedule_upcall(0, (into_statuscode(e.into()), pointer as usize, 0)),
417                    }
418                    .ok();
419
420                    // Clear the current processid as it has finished running
421                    self.processid.clear();
422                })
423                .map_err(|err| {
424                    if err == kernel::process::Error::NoSuchApp
425                        || err == kernel::process::Error::InactiveApp
426                    {
427                        self.processid.clear();
428                    }
429                })
430        });
431
432        self.check_queue();
433        self.dest_buffer.replace(digest);
434    }
435}
436
437impl<
438        'a,
439        H: digest::Digest<'a, L> + digest::HmacSha256 + digest::HmacSha384 + digest::HmacSha512,
440        const L: usize,
441    > digest::ClientVerify<L> for HmacDriver<'a, H, L>
442{
443    fn verification_done(&self, result: Result<bool, ErrorCode>, compare: &'static mut [u8; L]) {
444        self.processid.map(|id| {
445            self.apps
446                .enter(id, |_app, kernel_data| {
447                    self.hmac.clear_data();
448
449                    match result {
450                        Ok(equal) => kernel_data.schedule_upcall(1, (0, equal as usize, 0)),
451                        Err(e) => kernel_data.schedule_upcall(1, (into_statuscode(e.into()), 0, 0)),
452                    }
453                    .ok();
454
455                    // Clear the current processid as it has finished running
456                    self.processid.clear();
457                })
458                .map_err(|err| {
459                    if err == kernel::process::Error::NoSuchApp
460                        || err == kernel::process::Error::InactiveApp
461                    {
462                        self.processid.clear();
463                    }
464                })
465        });
466
467        self.check_queue();
468        self.dest_buffer.replace(compare);
469    }
470}
471
472/// Specify memory regions to be used.
473///
474/// ### `allow_num`
475///
476/// - `0`: Allow a buffer for storing the key. The kernel will read from this
477///   when running This should not be changed after running `run` until the HMAC
478///   has completed
479/// - `1`: Allow a buffer for storing the buffer. The kernel will read from this
480///   when running This should not be changed after running `run` until the HMAC
481///   has completed
482/// - `2`: Allow a buffer for storing the digest. The kernel will fill this with
483///   the HMAC digest before calling the `hash_done` callback.
484impl<
485        'a,
486        H: digest::Digest<'a, L> + digest::HmacSha256 + digest::HmacSha384 + digest::HmacSha512,
487        const L: usize,
488    > SyscallDriver for HmacDriver<'a, H, L>
489{
490    // Subscribe to HmacDriver events.
491    //
492    // ### `subscribe_num`
493    //
494    // - `0`: Subscribe to interrupts from HMAC events. The callback signature
495    //   is `fn(result: u32)`
496
497    /// Setup and run the HMAC hardware
498    ///
499    /// We expect userspace to setup buffers for the key, data and digest.
500    /// These buffers must be allocated and specified to the kernel from the
501    /// above allow calls.
502    ///
503    /// We expect userspace not to change the value while running. If userspace
504    /// changes the value we have no guarantee of what is passed to the
505    /// hardware. This isn't a security issue, it will just prove the requesting
506    /// app with invalid data.
507    ///
508    /// The driver will take care of clearing data from the underlying implementation
509    /// by calling the `clear_data()` function when the `hash_complete()` callback
510    /// is called or if an error is encountered.
511    ///
512    /// ### `command_num`
513    ///
514    /// - `0`: set_algorithm
515    /// - `1`: run
516    /// - `2`: update
517    /// - `3`: finish
518    fn command(
519        &self,
520        command_num: usize,
521        data1: usize,
522        _data2: usize,
523        processid: ProcessId,
524    ) -> CommandReturn {
525        let match_or_empty_or_nonexistant = self.processid.map_or(true, |owning_app| {
526            // We have recorded that an app has ownership of the HMAC.
527
528            // If the HMAC is still active, then we need to wait for the operation
529            // to finish and the app, whether it exists or not (it may have crashed),
530            // still owns this capsule. If the HMAC is not active, then
531            // we need to verify that that application still exists, and remove
532            // it as owner if not.
533            if self.active.get() {
534                owning_app == processid
535            } else {
536                // Check the app still exists.
537                //
538                // If the `.enter()` succeeds, then the app is still valid, and
539                // we can check if the owning app matches the one that called
540                // the command. If the `.enter()` fails, then the owning app no
541                // longer exists and we return `true` to signify the
542                // "or_nonexistant" case.
543                self.apps
544                    .enter(owning_app, |_, _| owning_app == processid)
545                    .unwrap_or(true)
546            }
547        });
548
549        let app_match = self.processid.map_or(false, |owning_app| {
550            // We have recorded that an app has ownership of the HMAC.
551
552            // If the HMAC is still active, then we need to wait for the operation
553            // to finish and the app, whether it exists or not (it may have crashed),
554            // still owns this capsule. If the HMAC is not active, then
555            // we need to verify that that application still exists, and remove
556            // it as owner if not.
557            if self.active.get() {
558                owning_app == processid
559            } else {
560                // Check the app still exists.
561                //
562                // If the `.enter()` succeeds, then the app is still valid, and
563                // we can check if the owning app matches the one that called
564                // the command. If the `.enter()` fails, then the owning app no
565                // longer exists and we return `true` to signify the
566                // "or_nonexistant" case.
567                self.apps
568                    .enter(owning_app, |_, _| owning_app == processid)
569                    .unwrap_or(true)
570            }
571        });
572
573        // Try the commands where we want to start an operation *not* entered in
574        // an app grant first.
575        if match_or_empty_or_nonexistant
576            && (command_num == 1 || command_num == 2 || command_num == 4)
577        {
578            self.processid.set(processid);
579
580            let _ = self.apps.enter(processid, |app, _| {
581                if command_num == 1 {
582                    // run
583                    // Use key and data to compute hash
584                    // This will trigger a callback once the digest is generated
585                    app.op.set(Some(UserSpaceOp::Run));
586                } else if command_num == 2 {
587                    // update
588                    // Input key and data, don't compute final hash yet
589                    // This will trigger a callback once the data has been added.
590                    app.op.set(Some(UserSpaceOp::Update));
591                } else if command_num == 4 {
592                    // verify
593                    // Use key and data to compute hash and comapre it against
594                    // the digest
595                    app.op.set(Some(UserSpaceOp::Verify));
596                }
597            });
598
599            return if let Err(e) = self.run() {
600                self.hmac.clear_data();
601                self.processid.clear();
602                self.check_queue();
603                CommandReturn::failure(e)
604            } else {
605                CommandReturn::success()
606            };
607        }
608
609        self.apps
610            .enter(processid, |app, kernel_data| {
611                match command_num {
612                    // set_algorithm
613                    0 => {
614                        match data1 {
615                            // SHA256
616                            0 => {
617                                app.sha_operation = Some(ShaOperation::Sha256);
618                                CommandReturn::success()
619                            }
620                            // SHA384
621                            1 => {
622                                app.sha_operation = Some(ShaOperation::Sha384);
623                                CommandReturn::success()
624                            }
625                            // SHA512
626                            2 => {
627                                app.sha_operation = Some(ShaOperation::Sha512);
628                                CommandReturn::success()
629                            }
630                            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
631                        }
632                    }
633
634                    // run
635                    1 => {
636                        // There is an active app, so queue this request (if possible).
637                        if app.pending_run_app.is_some() {
638                            // No more room in the queue, nowhere to store this
639                            // request.
640                            CommandReturn::failure(ErrorCode::NOMEM)
641                        } else {
642                            // We can store this, so lets do it.
643                            app.pending_run_app = Some(processid);
644                            app.op.set(Some(UserSpaceOp::Run));
645                            CommandReturn::success()
646                        }
647                    }
648
649                    // update
650                    2 => {
651                        // There is an active app, so queue this request (if possible).
652                        if app.pending_run_app.is_some() {
653                            // No more room in the queue, nowhere to store this
654                            // request.
655                            CommandReturn::failure(ErrorCode::NOMEM)
656                        } else {
657                            // We can store this, so lets do it.
658                            app.pending_run_app = Some(processid);
659                            app.op.set(Some(UserSpaceOp::Update));
660                            CommandReturn::success()
661                        }
662                    }
663
664                    // finish
665                    // Compute final hash yet, useful after a update command
666                    3 => {
667                        if app_match {
668                            if let Err(e) = self.calculate_digest() {
669                                kernel_data
670                                    .schedule_upcall(
671                                        0,
672                                        (kernel::errorcode::into_statuscode(e.into()), 0, 0),
673                                    )
674                                    .ok();
675                            }
676                            CommandReturn::success()
677                        } else {
678                            // We don't queue this request, the user has to call
679                            // `update` first.
680                            CommandReturn::failure(ErrorCode::OFF)
681                        }
682                    }
683
684                    // verify
685                    4 => {
686                        // There is an active app, so queue this request (if possible).
687                        if app.pending_run_app.is_some() {
688                            // No more room in the queue, nowhere to store this
689                            // request.
690                            CommandReturn::failure(ErrorCode::NOMEM)
691                        } else {
692                            // We can store this, so lets do it.
693                            app.pending_run_app = Some(processid);
694                            app.op.set(Some(UserSpaceOp::Verify));
695                            CommandReturn::success()
696                        }
697                    }
698
699                    // verify_finish
700                    // Use key and data to compute hash and compare it against
701                    // the digest, useful after a update command
702                    5 => {
703                        if app_match {
704                            let _ = kernel_data
705                                .get_readonly_processbuffer(ro_allow::COMPARE)
706                                .and_then(|compare| {
707                                    compare.enter(|compare| {
708                                        let mut static_buffer_len = 0;
709                                        self.dest_buffer.map(|buf| {
710                                            // Determine the size of the static buffer we have
711                                            static_buffer_len = buf.len();
712
713                                            if static_buffer_len > compare.len() {
714                                                static_buffer_len = compare.len()
715                                            }
716
717                                            self.data_copied.set(static_buffer_len);
718
719                                            // Copy the data into the static buffer
720                                            compare[..static_buffer_len]
721                                                .copy_to_slice(&mut buf[..static_buffer_len]);
722                                        });
723                                    })
724                                });
725
726                            if let Err(e) = self.verify_digest() {
727                                kernel_data
728                                    .schedule_upcall(1, (into_statuscode(e.into()), 0, 0))
729                                    .ok();
730                            }
731                            CommandReturn::success()
732                        } else {
733                            // We don't queue this request, the user has to call
734                            // `update` first.
735                            CommandReturn::failure(ErrorCode::OFF)
736                        }
737                    }
738
739                    // default
740                    _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
741                }
742            })
743            .unwrap_or_else(|err| err.into())
744    }
745
746    fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
747        self.apps.enter(processid, |_, _| {})
748    }
749}
750
751#[derive(Copy, Clone, PartialEq)]
752enum UserSpaceOp {
753    Run,
754    Update,
755    Verify,
756}
757
758#[derive(Default)]
759pub struct App {
760    pending_run_app: Option<ProcessId>,
761    sha_operation: Option<ShaOperation>,
762    op: Cell<Option<UserSpaceOp>>,
763}