starnix_types/
futex_address.rs

1// Copyright 2024 The Fuchsia Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// A FutexAddress is a more limited form of UserAddress. FutexAddress values must be aligned
6// to a 4 byte boundary and must be within the restricted address space range.
7
8use starnix_uapi::errors::{Errno, error};
9use starnix_uapi::restricted_aspace::RESTRICTED_ASPACE_RANGE;
10use starnix_uapi::user_address::UserAddress;
11use std::fmt;
12use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
13use zx::sys::zx_vaddr_t;
14
15#[derive(
16    Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, IntoBytes, KnownLayout, FromBytes, Immutable,
17)]
18#[repr(transparent)]
19pub struct FutexAddress(zx_vaddr_t);
20
21impl FutexAddress {
22    pub fn ptr(&self) -> zx_vaddr_t {
23        self.0
24    }
25}
26
27impl TryFrom<usize> for FutexAddress {
28    type Error = Errno;
29
30    fn try_from(value: usize) -> Result<Self, Errno> {
31        // Futex addresses must be aligned to a 4 byte boundary.
32        if value % 4 != 0 {
33            return error!(EINVAL);
34        }
35        // Futex addresses cannot be outside of the restricted address space range.
36        if !RESTRICTED_ASPACE_RANGE.contains(&value) {
37            return error!(EFAULT);
38        }
39        Ok(FutexAddress(value))
40    }
41}
42
43impl TryFrom<UserAddress> for FutexAddress {
44    type Error = Errno;
45
46    fn try_from(value: UserAddress) -> Result<Self, Errno> {
47        value.ptr().try_into()
48    }
49}
50
51impl Into<UserAddress> for FutexAddress {
52    fn into(self) -> UserAddress {
53        UserAddress::const_from(self.ptr() as u64)
54    }
55}
56
57impl fmt::Display for FutexAddress {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        write!(f, "{:#x}", self.0)
60    }
61}
62
63impl fmt::Debug for FutexAddress {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        f.debug_tuple("FutexAddress").field(&format_args!("{:#x}", self.0)).finish()
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use starnix_uapi::restricted_aspace::RESTRICTED_ASPACE_HIGHEST_ADDRESS;
73
74    #[::fuchsia::test]
75    fn test_misaligned_address() {
76        let result = FutexAddress::try_from(3);
77        assert!(result.is_err());
78    }
79
80    #[::fuchsia::test]
81    fn test_normal_mode_address() {
82        let result = FutexAddress::try_from(RESTRICTED_ASPACE_HIGHEST_ADDRESS);
83        assert!(result.is_err());
84    }
85
86    #[::fuchsia::test]
87    fn test_maximal_address() {
88        let result = FutexAddress::try_from(usize::max_value());
89        assert!(result.is_err());
90    }
91
92    #[::fuchsia::test]
93    fn test_regular_restricted_address() {
94        // This address is a valid restricted mode address on every architecture.
95        let result = FutexAddress::try_from(2 * 1 << 20);
96        assert!(result.is_ok());
97        assert_eq!(result.unwrap().ptr(), 2 * 1 << 20);
98    }
99}