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