xref: /aosp_15_r20/bootable/libbootloader/gbl/libabr/src/c_staticlib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This file provides C interface wrappers of libabr APIs.
16 
17 #![cfg_attr(not(test), no_std)]
18 
19 use abr::{
20     get_and_clear_one_shot_flag, get_boot_slot, get_slot_info, get_slot_last_marked_active,
21     mark_slot_active, mark_slot_successful, mark_slot_unbootable, set_one_shot_bootloader,
22     set_one_shot_recovery, AbrData, AbrSlotData, Ops, SlotIndex, SlotInfo as AbrSlotInfo,
23     SlotState, ABR_DATA_SIZE,
24 };
25 use core::{
26     ffi::{c_char, c_uint, c_void},
27     fmt::Write,
28 };
29 use liberror::{Error, Result};
30 
31 pub mod utils;
32 
33 pub const ABR_RESULT_OK: c_uint = 0;
34 pub const ABR_RESULT_ERR_IO: c_uint = 1;
35 pub const ABR_RESULT_ERR_INVALID_DATA: c_uint = 2;
36 pub const ABR_RESULT_ERR_UNSUPPORTED_VERSION: c_uint = 3;
37 
38 // ABR system dependencies.
39 //
40 // These correspond to the definitions in Fuchsia upstream header
41 // "src/firmware/lib/abr/include/lib/abr/sysdeps.h", which will eventually migrate over.
42 extern "C" {
43     /// Prints out a NULL-terminated string.
AbrPrint(message: *const c_char)44     pub fn AbrPrint(message: *const c_char);
45 
46     /// Aborts the program or reboots the device if |abort| is not implemented.
AbrAbort()47     pub fn AbrAbort();
48 }
49 
50 /// A helper to print an ASCII character via `AbrPrint()`.
abr_print_ascii_char(ch: u8)51 fn abr_print_ascii_char(ch: u8) {
52     let s = [ch, 0];
53     // SAFETY:
54     // * `s` is a valid buffer
55     // * `s` is for input only and will not be retained by the function.
56     unsafe { AbrPrint(s.as_ptr() as _) }
57 }
58 
59 /// A helper structure that implements formatted write using `AbrPrint()`.
60 struct AbrPrintSysdeps {}
61 
62 impl Write for AbrPrintSysdeps {
write_str(&mut self, s: &str) -> core::fmt::Result63     fn write_str(&mut self, s: &str) -> core::fmt::Result {
64         if s.is_ascii() {
65             s.as_bytes().iter().for_each(|v| abr_print_ascii_char(*v));
66         }
67         Ok(())
68     }
69 }
70 
71 /// A panic handler is needed when building as a static library. We simply call into
72 /// the AbrAbort() system dependency.
73 #[cfg(not(test))]
74 #[panic_handler]
panic(panic: &core::panic::PanicInfo<'_>) -> !75 fn panic(panic: &core::panic::PanicInfo<'_>) -> ! {
76     write!(AbrPrintSysdeps {}, "libabr panics! {}", panic).unwrap();
77     // SAFETY: Call to external C function. The function simply aborts/reboots the system.
78     unsafe { AbrAbort() };
79     unreachable!()
80 }
81 
82 /// This corresponds to the `AbrOps` C definition in Fuchsia upstream header
83 /// "src/firmware/lib/abr/include/lib/abr/ops.h", which will eventually migrate over.
84 ///
85 /// typedef struct AbrOps {
86 ///     void* context;
87 ///     bool (*read_abr_metadata)(void* context, size_t size, uint8_t* buffer);
88 ///     bool (*write_abr_metadata)(void* context, const uint8_t* buffer, size_t size);
89 ///     bool (*read_abr_metadata_custom)(void* context, AbrSlotData* a_slot_data,
90 ///                                      AbrSlotData* b_slot_data, uint8_t* one_shot_flags);
91 ///     bool (*write_abr_metadata_custom)(void* context, const AbrSlotData* a_slot_data,
92 ///                                       const AbrSlotData* b_slot_data, uint8_t one_shot_flags);
93 /// } AbrOps;
94 #[repr(C)]
95 #[derive(Debug, Copy, Clone)]
96 pub struct AbrOps {
97     pub context: *mut c_void,
98     pub read_abr_metadata:
99         Option<unsafe extern "C" fn(context: *mut c_void, size: usize, buffer: *mut u8) -> bool>,
100     pub write_abr_metadata:
101         Option<unsafe extern "C" fn(context: *mut c_void, buffer: *const u8, size: usize) -> bool>,
102     pub read_abr_metadata_custom: Option<
103         unsafe extern "C" fn(
104             context: *mut c_void,
105             a_slot_data: *mut AbrSlotData,
106             b_slot_data: *mut AbrSlotData,
107             one_shot_flags: *mut u8,
108         ) -> bool,
109     >,
110     pub write_abr_metadata_custom: Option<
111         unsafe extern "C" fn(
112             context: *mut c_void,
113             a_slot_data: *const AbrSlotData,
114             b_slot_data: *const AbrSlotData,
115             one_shot_flags: u8,
116         ) -> bool,
117     >,
118 }
119 
120 /// `AbrOpsSafe` wraps a reference to `AbrOps` and is created by an unsafe constructor that
121 /// establishes necessary safety invariants on `AbrOps`.
122 struct AbrOpsSafe<'a> {
123     ops: &'a AbrOps,
124     log: AbrPrintSysdeps,
125 }
126 
127 impl<'a> AbrOpsSafe<'a> {
128     /// Creates a new instance from a reference to `AbrOps`.
129     ///
130     /// # Safety
131     ///
132     /// * Caller must make sure that `ops.context` is either not used, or points to a valid and
133     ///   correct type of value needed by `ops.read_abr_metadata`, `ops.write_abr_metadata`,
134     ///   `ops.read_abr_metadata_custom` and `ops.write_abr_metadata_custom`.
new(ops: &'a AbrOps) -> Self135     unsafe fn new(ops: &'a AbrOps) -> Self {
136         Self { ops, log: AbrPrintSysdeps {} }
137     }
138 }
139 
140 type AbrSlotIndex = c_uint;
141 
142 impl Ops for AbrOpsSafe<'_> {
read_abr_metadata(&mut self, out: &mut [u8]) -> Result<()>143     fn read_abr_metadata(&mut self, out: &mut [u8]) -> Result<()> {
144         if let Some(f) = self.ops.read_abr_metadata.as_ref() {
145             // SAFETY:
146             // * By safety requirement of `AbrOpsSafe::new()`, `self.ops.context` is either unused,
147             //   or a valid pointer to a correct type of object used by
148             //   `self.ops.write_abr_metadata`.
149             // * `out` is a valid buffer
150             // * `out` is for reading data only and will not be retained by the function.
151             match unsafe { f(self.ops.context, out.len(), out.as_mut_ptr() as _) } {
152                 false => Err(Error::Other(Some("read_abr_metadata() failed"))),
153                 _ => Ok(()),
154             }
155         } else if let Some(f) = self.ops.read_abr_metadata_custom.as_ref() {
156             let mut data: AbrData = Default::default();
157             // SAFETY:
158             // * By safety requirement of `AbrOpsSafe::new()`, `self.ops.context` is either unused,
159             //   or a valid pointer to a correct type of object used by
160             //   `self.ops.read_abr_metadata_custom`.
161             // * Pointers to `slot_a`, `slot_b` and `one_shot_flags` are a valid memory locations.
162             // * `slot_a`, `slot_b` and `one_shot_flags` are for output and will not be retained by
163             //   the function.
164             match unsafe {
165                 f(
166                     self.ops.context,
167                     &mut data.slot_data[SlotIndex::A as usize],
168                     &mut data.slot_data[SlotIndex::B as usize],
169                     &mut data.one_shot_flags,
170                 )
171             } {
172                 false => Err(Error::Other(Some("read_abr_metadata_custom() failed"))),
173                 _ => Ok(out[..ABR_DATA_SIZE].clone_from_slice(&data.serialize())),
174             }
175         } else {
176             Err(Error::NotImplemented)
177         }
178     }
179 
write_abr_metadata(&mut self, data: &mut [u8]) -> Result<()>180     fn write_abr_metadata(&mut self, data: &mut [u8]) -> Result<()> {
181         if let Some(f) = self.ops.write_abr_metadata.as_ref() {
182             // SAFETY:
183             // * By safety requirement of `AbrOpsSafe::new()`, `self.ops.context` is either unused,
184             //   or a valid pointer to a correct type of object used by
185             //   `self.ops.write_abr_metadata`.
186             // * `data` is a valid buffer.
187             // * `data` is for input only and will not be retained by the function.
188             match unsafe { f(self.ops.context, data.as_ptr() as _, data.len()) } {
189                 false => Err(Error::Other(Some("write_abr_metadata() failed"))),
190                 _ => Ok(()),
191             }
192         } else if let Some(f) = self.ops.write_abr_metadata_custom.as_ref() {
193             let mut abr_data = [0u8; ABR_DATA_SIZE];
194             abr_data.clone_from_slice(
195                 data.get(..ABR_DATA_SIZE).ok_or(Error::BufferTooSmall(Some(ABR_DATA_SIZE)))?,
196             );
197             let abr_data = AbrData::deserialize(&mut abr_data).unwrap();
198             // SAFETY:
199             // * By safety requirement of `AbrOpsSafe::new()`, `self.ops.context` is either unused,
200             //   or a valid pointer to a correct type of object used by
201             //   `self.ops.write_abr_metadata_custom`.
202             // * Pointers to `slot_a` and `slot_b` are a valid memory locations.
203             // * `slot_a` and `slot_b` are for input and will not be retained by the function.
204             match unsafe {
205                 f(
206                     self.ops.context,
207                     &abr_data.slot_data[SlotIndex::A as usize],
208                     &abr_data.slot_data[SlotIndex::B as usize],
209                     abr_data.one_shot_flags,
210                 )
211             } {
212                 false => Err(Error::Other(Some("read_abr_metadata_custom() failed"))),
213                 _ => Ok(()),
214             }
215         } else {
216             Err(Error::NotImplemented)
217         }
218     }
219 
console(&mut self) -> Option<&mut dyn core::fmt::Write>220     fn console(&mut self) -> Option<&mut dyn core::fmt::Write> {
221         Some(&mut self.log)
222     }
223 }
224 
225 /// A helper that extracts the return value and maps the result to an integer A/B/R result code.
unpack_result<T: Into<O>, O>(res: Result<T>, val: &mut O) -> c_uint226 fn unpack_result<T: Into<O>, O>(res: Result<T>, val: &mut O) -> c_uint {
227     match res {
228         Err(e) => match e {
229             Error::BadMagic | Error::BadChecksum | Error::InvalidInput => {
230                 ABR_RESULT_ERR_INVALID_DATA
231             }
232             Error::UnsupportedVersion => ABR_RESULT_ERR_UNSUPPORTED_VERSION,
233             _ => ABR_RESULT_ERR_IO,
234         },
235         Ok(v) => {
236             *val = v.into();
237             ABR_RESULT_OK
238         }
239     }
240 }
241 
242 /// C interface wrapper of `abr::get_boot_slot()`
243 ///
244 /// # Safety
245 ///
246 /// * Caller must make sure to pass a valid pointer for `abr_ops`.
247 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
248 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
249 /// * Caller must make sure to pass either a NULL or valid pointer for `is_slot_marked_successful`.
250 #[no_mangle]
251 #[allow(non_snake_case)]
AbrGetBootSlot( abr_ops: *const AbrOps, update_metadata: bool, is_slot_marked_successful: *mut bool, ) -> AbrSlotIndex252 pub unsafe extern "C" fn AbrGetBootSlot(
253     abr_ops: *const AbrOps,
254     update_metadata: bool,
255     is_slot_marked_successful: *mut bool,
256 ) -> AbrSlotIndex {
257     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
258     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
259     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
260     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
261 
262     let (slot_index, successful) = get_boot_slot(&mut abr_ops, update_metadata);
263     // SAFETY: function safety requires `out_slot` to be a valid pointer or `NULL`.
264     match unsafe { is_slot_marked_successful.as_mut() } {
265         Some(v) => *v = successful,
266         _ => {}
267     };
268     slot_index.into()
269 }
270 
271 // NULL terminated strings for slot suffixes.
272 const SLOT_A_SUFFIX: &[u8] = b"_a\0";
273 const SLOT_B_SUFFIX: &[u8] = b"_b\0";
274 const SLOT_R_SUFFIX: &[u8] = b"_r\0";
275 const SLOT_SUFFIX_INVALID: &[u8] = b"\0";
276 
277 /// C interface for getting slot suffix.
278 #[no_mangle]
279 #[allow(non_snake_case)]
AbrGetSlotSuffix(slot_index: AbrSlotIndex) -> *const c_char280 pub extern "C" fn AbrGetSlotSuffix(slot_index: AbrSlotIndex) -> *const c_char {
281     match slot_index.try_into() {
282         Ok(SlotIndex::A) => &SLOT_A_SUFFIX,
283         Ok(SlotIndex::B) => &SLOT_B_SUFFIX,
284         Ok(SlotIndex::R) => &SLOT_R_SUFFIX,
285         Err(_) => &SLOT_SUFFIX_INVALID,
286     }
287     .as_ptr() as _
288 }
289 
290 /// C interface wrapper of `abr::mark_slot_active()`
291 ///
292 /// # Safety
293 ///
294 /// * Caller must make sure to pass a valid pointer for `abr_ops`.
295 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
296 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
297 #[no_mangle]
298 #[allow(non_snake_case)]
AbrMarkSlotActive( abr_ops: *const AbrOps, slot_index: AbrSlotIndex, ) -> c_uint299 pub unsafe extern "C" fn AbrMarkSlotActive(
300     abr_ops: *const AbrOps,
301     slot_index: AbrSlotIndex,
302 ) -> c_uint {
303     let slot_index = match slot_index.try_into() {
304         Ok(v) => v,
305         Err(_) => return ABR_RESULT_ERR_INVALID_DATA,
306     };
307 
308     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
309     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
310     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
311     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
312 
313     unpack_result(mark_slot_active(&mut abr_ops, slot_index), &mut ())
314 }
315 
316 /// C interface wrapper of `abr::get_slot_last_marked_active()`
317 ///
318 /// # Safety
319 ///
320 /// * Caller must make sure to pass a valid pointer for `abr_ops` and `out_slot`.
321 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
322 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
323 #[no_mangle]
324 #[allow(non_snake_case)]
AbrGetSlotLastMarkedActive( abr_ops: *const AbrOps, out_slot: *mut AbrSlotIndex, ) -> c_uint325 pub unsafe extern "C" fn AbrGetSlotLastMarkedActive(
326     abr_ops: *const AbrOps,
327     out_slot: *mut AbrSlotIndex,
328 ) -> c_uint {
329     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
330     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
331     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
332     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
333     // SAFETY: function safety requires `out_slot` to be a valid pointer.
334     let out_slot = unsafe { out_slot.as_mut() }.unwrap();
335 
336     unpack_result(get_slot_last_marked_active(&mut abr_ops), out_slot)
337 }
338 
339 /// C interface wrapper of `abr::mark_slot_unbootable()`
340 ///
341 /// # Safety
342 ///
343 /// * Caller must make sure to pass a valid pointer for `abr_ops`.
344 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
345 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
346 #[no_mangle]
347 #[allow(non_snake_case)]
AbrMarkSlotUnbootable( abr_ops: *const AbrOps, slot_index: AbrSlotIndex, ) -> c_uint348 pub unsafe extern "C" fn AbrMarkSlotUnbootable(
349     abr_ops: *const AbrOps,
350     slot_index: AbrSlotIndex,
351 ) -> c_uint {
352     let slot_index = match slot_index.try_into() {
353         Ok(v) => v,
354         Err(_) => return ABR_RESULT_ERR_INVALID_DATA,
355     };
356 
357     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
358     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
359     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
360     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
361 
362     unpack_result(mark_slot_unbootable(&mut abr_ops, slot_index), &mut ())
363 }
364 
365 /// C interface wrapper of `abr::mark_slot_successful()`
366 ///
367 /// # Safety
368 ///
369 /// * Caller must make sure to pass a valid pointer for `abr_ops`.
370 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
371 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
372 #[no_mangle]
373 #[allow(non_snake_case)]
AbrMarkSlotSuccessful( abr_ops: *const AbrOps, slot_index: AbrSlotIndex, ) -> c_uint374 pub unsafe extern "C" fn AbrMarkSlotSuccessful(
375     abr_ops: *const AbrOps,
376     slot_index: AbrSlotIndex,
377 ) -> c_uint {
378     let slot_index = match slot_index.try_into() {
379         Ok(v) => v,
380         Err(_) => return ABR_RESULT_ERR_INVALID_DATA,
381     };
382 
383     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
384     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
385     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
386     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
387 
388     unpack_result(mark_slot_successful(&mut abr_ops, slot_index), &mut ())
389 }
390 
391 /// `SlotInfo` contains the current state of a A/B/R slot.
392 ///
393 /// TODO(b/338243123): Detailed documentation is available in Fuchsia upstream header
394 /// "src/firmware/lib/abr/include/lib/abr/abr.h", which will migrate to the GBL repo.
395 #[repr(C)]
396 #[derive(Debug, Copy, Clone)]
397 pub struct SlotInfo {
398     /// Whether the slot is expected to be bootable.
399     pub is_bootable: bool,
400     /// Whether the slot is the highest priority A/B slot.
401     pub is_active: bool,
402     /// Whether the slot is currently marked successful.
403     pub is_marked_successful: bool,
404     /// If not marked successful, this represents the number of attempts left for booting this slot.
405     pub num_tries_remaining: u8,
406 }
407 
408 impl From<AbrSlotInfo> for SlotInfo {
from(val: abr::SlotInfo) -> Self409     fn from(val: abr::SlotInfo) -> Self {
410         let is_marked_successful = matches!(val.state, SlotState::Successful);
411         let num_tries_remaining = match val.state {
412             SlotState::Bootable(v) => v,
413             _ => 0,
414         };
415         Self {
416             is_bootable: is_marked_successful || num_tries_remaining > 0,
417             is_active: val.is_active,
418             is_marked_successful,
419             num_tries_remaining,
420         }
421     }
422 }
423 
424 /// C interface wrapper of `abr::get_slot_info()`
425 ///
426 /// # Safety
427 ///
428 /// * Caller must make sure to pass a valid pointer for `abr_ops` and 'info'.
429 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
430 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
431 #[no_mangle]
432 #[allow(non_snake_case)]
AbrGetSlotInfo( abr_ops: *const AbrOps, slot_index: AbrSlotIndex, info: *mut SlotInfo, ) -> c_uint433 pub unsafe extern "C" fn AbrGetSlotInfo(
434     abr_ops: *const AbrOps,
435     slot_index: AbrSlotIndex,
436     info: *mut SlotInfo,
437 ) -> c_uint {
438     let slot_index = match slot_index.try_into() {
439         Ok(v) => v,
440         Err(_) => return ABR_RESULT_ERR_INVALID_DATA,
441     };
442 
443     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
444     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
445     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
446     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
447     // SAFETY: function safety requires `info` to be a valid pointer.
448     let info = unsafe { info.as_mut() }.unwrap();
449 
450     unpack_result(get_slot_info(&mut abr_ops, slot_index).map(|v| SlotInfo::from(v)), info)
451 }
452 
453 /// C interface wrapper of `abr::set_one_shot_recovery()`
454 ///
455 /// # Safety
456 ///
457 /// * Caller must make sure to pass a valid pointer for `abr_ops`.
458 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
459 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
460 #[no_mangle]
461 #[allow(non_snake_case)]
AbrSetOneShotRecovery(abr_ops: *const AbrOps, enable: bool) -> c_uint462 pub unsafe extern "C" fn AbrSetOneShotRecovery(abr_ops: *const AbrOps, enable: bool) -> c_uint {
463     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
464     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
465     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
466     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
467 
468     unpack_result(set_one_shot_recovery(&mut abr_ops, enable), &mut ())
469 }
470 
471 /// C interface wrapper of `abr::set_one_shot_bootloader()`
472 ///
473 /// # Safety
474 ///
475 /// * Caller must make sure to pass a valid pointer for `abr_ops`.
476 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
477 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
478 #[no_mangle]
479 #[allow(non_snake_case)]
AbrSetOneShotBootloader(abr_ops: *const AbrOps, enable: bool) -> c_uint480 pub unsafe extern "C" fn AbrSetOneShotBootloader(abr_ops: *const AbrOps, enable: bool) -> c_uint {
481     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
482     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
483     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
484     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
485 
486     unpack_result(set_one_shot_bootloader(&mut abr_ops, enable), &mut ())
487 }
488 
489 /// Gets and clears the one shot flag.
490 ///
491 /// # Safety
492 ///
493 /// * Caller must make sure to pass a valid pointer for `abr_ops` and `flags`.
494 /// * Caller must make sure that `abr_ops.context` is either not used, or points to a valid and
495 ///   correct type of value needed by `abr_ops.read_abr_metadata` and `abr_ops.write_abr_metadata`.
496 #[no_mangle]
497 #[allow(non_snake_case)]
AbrGetAndClearOneShotFlags( abr_ops: *const AbrOps, flags: *mut c_uint, ) -> c_uint498 pub unsafe extern "C" fn AbrGetAndClearOneShotFlags(
499     abr_ops: *const AbrOps,
500     flags: *mut c_uint,
501 ) -> c_uint {
502     // SAFETY: function safety requires `abr_ops` to be a valid pointer.
503     let abr_ops = unsafe { abr_ops.as_ref() }.unwrap();
504     // SAFETY: function safety requires `abr_ops.context` to be valid for `AbrOpsSafe::new`.
505     let mut abr_ops = unsafe { AbrOpsSafe::new(abr_ops) };
506     // SAFETY: function safety requires `flags` to be a valid pointer.
507     let flags = unsafe { flags.as_mut() }.unwrap();
508 
509     unpack_result(get_and_clear_one_shot_flag(&mut abr_ops), flags)
510 }
511 
512 // Needed because of no-std environment in static lib build.
513 #[cfg(not(test))]
514 #[no_mangle]
rust_eh_personality()515 pub extern "C" fn rust_eh_personality() {}
516