blob: 5c791b8eb8c8cc85f0be238c47c69c73542e3108 [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2017-2019 Linaro LTD
2// Copyright (c) 2017-2019 JUUL Labs
Salome Thirot6fdbf552021-05-14 16:46:14 +01003// Copyright (c) 2019-2021 Arm Limited
David Browne2acfae2020-01-21 16:45:01 -07004//
5// SPDX-License-Identifier: Apache-2.0
6
7//! Interface wrappers to C API entering to the bootloader
David Brownde7729e2017-01-09 10:41:35 -07008
David Brown65de6d12019-01-02 11:38:38 -07009use crate::area::AreaDesc;
David Brown76101572019-02-28 11:29:03 -070010use simflash::SimMultiFlash;
David Brown65de6d12019-01-02 11:38:38 -070011use crate::api;
David Brownde7729e2017-01-09 10:41:35 -070012
David Brownc423ac42021-06-04 13:47:34 -060013/// The result of an invocation of `boot_go`. This is intentionally opaque so that we can provide
14/// accessors for everything we need from this.
15#[derive(Debug)]
David Brown6d47d422021-06-04 14:41:33 -060016pub enum BootGoResult {
17 /// This run was stopped by the flash simulation mechanism.
18 Stopped,
19 /// The bootloader ran to completion with the following data.
20 Normal {
21 result: i32,
22 asserts: u8,
David Brownd82de8c2021-06-04 15:08:25 -060023
24 resp: api::BootRsp,
David Brown6d47d422021-06-04 14:41:33 -060025 },
David Brownc423ac42021-06-04 13:47:34 -060026}
27
28impl BootGoResult {
29 /// Was this run interrupted.
30 pub fn interrupted(&self) -> bool {
David Brown6d47d422021-06-04 14:41:33 -060031 matches!(self, BootGoResult::Stopped)
David Brownc423ac42021-06-04 13:47:34 -060032 }
33
34 /// Was this boot run successful (returned 0)
35 pub fn success(&self) -> bool {
David Brown6d47d422021-06-04 14:41:33 -060036 matches!(self, BootGoResult::Normal { result: 0, .. })
David Brownc423ac42021-06-04 13:47:34 -060037 }
38
39 /// Success, but also no asserts.
40 pub fn success_no_asserts(&self) -> bool {
David Brown6d47d422021-06-04 14:41:33 -060041 matches!(self, BootGoResult::Normal {
42 result: 0,
43 asserts: 0,
David Brownd82de8c2021-06-04 15:08:25 -060044 ..
David Brown6d47d422021-06-04 14:41:33 -060045 })
David Brownc423ac42021-06-04 13:47:34 -060046 }
47
David Brown6d47d422021-06-04 14:41:33 -060048 /// Get the asserts count. An interrupted run will be considered to have no asserts.
David Brownc423ac42021-06-04 13:47:34 -060049 pub fn asserts(&self) -> u8 {
David Brown6d47d422021-06-04 14:41:33 -060050 match self {
51 BootGoResult::Normal { asserts, .. } => *asserts,
52 _ => 0,
53 }
David Brownc423ac42021-06-04 13:47:34 -060054 }
David Brownd82de8c2021-06-04 15:08:25 -060055
56 /// Retrieve the 'resp' field that is filled in.
57 pub fn resp(&self) -> Option<&api::BootRsp> {
58 match self {
59 BootGoResult::Normal { resp, .. } => Some(resp),
60 _ => None,
61 }
62 }
David Brownc423ac42021-06-04 13:47:34 -060063}
64
David Brownde7729e2017-01-09 10:41:35 -070065/// Invoke the bootloader on this flash device.
David Brown76101572019-02-28 11:29:03 -070066pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
David Brownc423ac42021-06-04 13:47:34 -060067 counter: Option<&mut i32>, catch_asserts: bool) -> BootGoResult {
David Brown7cc45262021-03-10 05:13:44 -070068 for (&dev_id, flash) in multiflash.iter_mut() {
69 api::set_flash(dev_id, flash);
Fabio Utzig8000e322019-08-05 08:14:32 -030070 }
71 let mut sim_ctx = api::CSimContext {
72 flash_counter: match counter {
David Brownee61c832017-11-06 11:13:25 -070073 None => 0,
74 Some(ref c) => **c as libc::c_int
Fabio Utzig8000e322019-08-05 08:14:32 -030075 },
76 jumped: 0,
77 c_asserts: 0,
78 c_catch_asserts: if catch_asserts { 1 } else { 0 },
79 boot_jmpbuf: [0; 16],
80 };
David Brownd216b202021-06-04 10:14:33 -060081 let mut rsp = api::BootRsp {
82 br_hdr: std::ptr::null(),
83 flash_dev_id: 0,
84 image_off: 0,
85 };
Fabio Utzig8000e322019-08-05 08:14:32 -030086 let result = unsafe {
David Brownd216b202021-06-04 10:14:33 -060087 raw::invoke_boot_go(&mut sim_ctx as *mut _, &areadesc.get_c() as *const _,
88 &mut rsp as *mut _) as i32
Fabio Utzig8000e322019-08-05 08:14:32 -030089 };
90 let asserts = sim_ctx.c_asserts;
David Brown8608c532021-03-10 05:18:11 -070091 if let Some(c) = counter {
92 *c = sim_ctx.flash_counter;
93 }
David Brown7cc45262021-03-10 05:13:44 -070094 for &dev_id in multiflash.keys() {
95 api::clear_flash(dev_id);
96 }
David Brown6d47d422021-06-04 14:41:33 -060097 if result == -0x13579 {
98 BootGoResult::Stopped
99 } else {
David Brownd82de8c2021-06-04 15:08:25 -0600100 BootGoResult::Normal { result, asserts, resp: rsp }
David Brown6d47d422021-06-04 14:41:33 -0600101 }
David Brownde7729e2017-01-09 10:41:35 -0700102}
103
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300104pub fn boot_trailer_sz(align: u32) -> u32 {
Christopher Collins2adef702019-05-22 14:37:31 -0700105 unsafe { raw::boot_trailer_sz(align) }
David Brownde7729e2017-01-09 10:41:35 -0700106}
107
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300108pub fn boot_status_sz(align: u32) -> u32 {
109 unsafe { raw::boot_status_sz(align) }
110}
111
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300112pub fn boot_magic_sz() -> usize {
David Brown2b8a6952019-10-01 16:14:53 -0600113 unsafe { raw::boot_magic_sz() as usize }
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300114}
115
116pub fn boot_max_align() -> usize {
David Browne0bb1f92019-10-01 15:57:01 -0600117 unsafe { raw::boot_max_align() as usize }
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300118}
119
Fabio Utzig1e48b912018-09-18 09:04:18 -0300120pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
121 unsafe {
122 let mut encbuf: [u8; 256] = [0; 256];
123 if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
124 seckey.as_ptr(), seckey.len() as u32,
125 encbuf.as_mut_ptr()) == 0 {
126 return Ok(encbuf);
127 }
David Brownc20bbb22021-03-10 05:19:14 -0700128 Err("Failed to encrypt buffer")
Fabio Utzig1e48b912018-09-18 09:04:18 -0300129 }
130}
131
Salome Thirot6fdbf552021-05-14 16:46:14 +0100132pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
Fabio Utzig1e48b912018-09-18 09:04:18 -0300133 unsafe {
Salome Thirot6fdbf552021-05-14 16:46:14 +0100134 let mut encbuf = vec![0u8; 24];
135 if keylen == 32 {
136 encbuf = vec![0u8; 40];
137 }
Fabio Utzig1e48b912018-09-18 09:04:18 -0300138 if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
139 return Ok(encbuf);
140 }
David Brownc20bbb22021-03-10 05:19:14 -0700141 Err("Failed to encrypt buffer")
Fabio Utzig1e48b912018-09-18 09:04:18 -0300142 }
143}
144
David Brownde7729e2017-01-09 10:41:35 -0700145mod raw {
David Brown65de6d12019-01-02 11:38:38 -0700146 use crate::area::CAreaDesc;
David Brownd216b202021-06-04 10:14:33 -0600147 use crate::api::{BootRsp, CSimContext};
David Brownde7729e2017-01-09 10:41:35 -0700148
149 extern "C" {
150 // This generates a warning about `CAreaDesc` not being foreign safe. There doesn't appear to
151 // be any way to get rid of this warning. See https://github.com/rust-lang/rust/issues/34798
152 // for information and tracking.
David Brownd216b202021-06-04 10:14:33 -0600153 pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
154 rsp: *mut BootRsp) -> libc::c_int;
David Brownde7729e2017-01-09 10:41:35 -0700155
Fabio Utzig3fbbdac2019-12-19 15:18:23 -0300156 pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
157 pub fn boot_status_sz(min_write_sz: u32) -> u32;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300158
David Brown2b8a6952019-10-01 16:14:53 -0600159 pub fn boot_magic_sz() -> u32;
David Browne0bb1f92019-10-01 15:57:01 -0600160 pub fn boot_max_align() -> u32;
Fabio Utzig92be3fb2017-12-05 08:52:53 -0200161
Fabio Utzig1e48b912018-09-18 09:04:18 -0300162 pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
163 seckey: *const u8, seckey_len: libc::c_uint,
164 encbuf: *mut u8) -> libc::c_int;
165
166 pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
167 encbuf: *mut u8) -> libc::c_int;
David Brownde7729e2017-01-09 10:41:35 -0700168 }
169}