Skip to main content

fake_bti/
lib.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![warn(missing_docs)]
6
7//! Fake BTI for testing without access to hardware resources
8
9use std::ops::Deref;
10use zx::sys::{zx_handle_t, zx_paddr_t};
11
12mod ffi;
13
14/// A fake BTI object which can be created without having access to hardware resources.
15#[derive(Debug)]
16pub struct FakeBti(zx::Bti);
17
18impl Deref for FakeBti {
19    type Target = zx::Bti;
20
21    fn deref(&self) -> &Self::Target {
22        &self.0
23    }
24}
25
26impl FakeBti {
27    /// All physical addresses returned by zx_bti_pin with a fake BTI will be set to this value.
28    #[inline(always)]
29    pub fn phys_addr() -> usize {
30        // SAFETY: This is just a constant with static storage.
31        unsafe { ffi::g_fake_bti_phys_addr }
32    }
33
34    /// Creates a new FakeBti.
35    pub fn create() -> Result<Self, zx::Status> {
36        let handle = {
37            let mut raw_handle = zx_handle_t::default();
38            // SAFETY: `raw_handle` is valid
39            unsafe {
40                zx::ok(ffi::fake_bti_create(&mut raw_handle))?;
41            }
42            // SAFETY: `fake_bti_create` returned a valid handle on success
43            unsafe { zx::NullableHandle::from_raw(raw_handle) }
44        };
45        Ok(Self(handle.into()))
46    }
47
48    /// Sets the paddrs used by the fake BTI.  Whenever [`zx::Bti::pin`] is called, these static
49    /// paddrs will be written out into the resulting array.  If more physical addresses are needed
50    /// than are available in paddrs, `pin` will return an error.
51    pub fn set_paddrs(&self, paddrs: &[zx_paddr_t]) {
52        // SAFETY: `paddrs` is valid
53        unsafe {
54            // OK to unwrap -- we know that `self.0` is a valid handle to a fake BTI
55            zx::ok(ffi::fake_bti_set_paddrs(self.0.raw_handle(), paddrs.as_ptr(), paddrs.len()))
56                .unwrap();
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[fuchsia::test]
66    fn create() {
67        let bti = FakeBti::create().expect("create failed");
68        let info = bti.info().expect("info failed");
69        assert!(info.minimum_contiguity > 0);
70    }
71
72    #[fuchsia::test]
73    fn pin_vmo() {
74        let bti = FakeBti::create().expect("create failed");
75        let vmo = zx::Vmo::create(16384).expect("create VMO failed");
76        let mut paddrs = [zx_paddr_t::default(); 4];
77        let _pmt = bti
78            .pin(zx::BtiOptions::PERM_READ, &vmo, 0, 16384, &mut paddrs[..])
79            .expect("pin failed");
80
81        let expected = FakeBti::phys_addr();
82        assert_eq!(paddrs, [expected, expected, expected, expected]);
83    }
84
85    #[fuchsia::test]
86    fn create_and_pin_contiguous_vmo() {
87        let bti = FakeBti::create().expect("create failed");
88        let vmo = zx::Vmo::create_contiguous(&bti, 16384, 0).expect("create contiguous VMO failed");
89        let mut paddr = [zx_paddr_t::default()];
90        let _pmt = bti
91            .pin(
92                zx::BtiOptions::PERM_READ | zx::BtiOptions::CONTIGUOUS,
93                &vmo,
94                0,
95                16384,
96                &mut paddr[..],
97            )
98            .expect("pin failed");
99
100        assert_eq!(paddr, [FakeBti::phys_addr()]);
101    }
102
103    #[fuchsia::test]
104    fn pin_with_paddrs() {
105        let bti = FakeBti::create().expect("create failed");
106        bti.set_paddrs(&[4096, 16384, 65536]);
107        let vmo = zx::Vmo::create(3 * 4096).expect("create VMO failed");
108        {
109            let mut paddrs = [zx_paddr_t::default(); 3];
110            let _pmt = bti
111                .pin(zx::BtiOptions::PERM_READ, &vmo, 0, 3 * 4096, &mut paddrs[..])
112                .expect("pin failed");
113            assert_eq!(paddrs, [4096, 16384, 65536]);
114        }
115        bti.set_paddrs(&[4096, 8192]);
116        {
117            let mut paddrs = [zx_paddr_t::default(); 2];
118            let _pmt = bti
119                .pin(zx::BtiOptions::PERM_READ, &vmo, 0, 2 * 4096, &mut paddrs[..])
120                .expect("pin failed");
121            assert_eq!(paddrs, [4096, 8192]);
122        }
123    }
124}