xref: /aosp_15_r20/external/crosvm/base/src/sys/linux/ioctl.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2017 The ChromiumOS 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 //! Macros and wrapper functions for dealing with ioctls.
6 
7 // Allow missing safety comments because this file provides just thin helper functions for
8 // `libc::ioctl`. Their safety follows `libc::ioctl`'s safety.
9 #![allow(clippy::missing_safety_doc)]
10 
11 use std::os::raw::c_int;
12 use std::os::raw::c_uint;
13 use std::os::raw::c_ulong;
14 use std::os::raw::c_void;
15 
16 use crate::descriptor::AsRawDescriptor;
17 
18 /// Raw macro to declare the expression that calculates an ioctl number
19 #[macro_export]
20 macro_rules! ioctl_expr {
21     ($dir:expr, $ty:expr, $nr:expr, $size:expr) => {
22         ((($dir as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_DIRSHIFT)
23             | (($ty as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_TYPESHIFT)
24             | (($nr as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_NRSHIFT)
25             | (($size as $crate::linux::IoctlNr) << $crate::linux::ioctl::_IOC_SIZESHIFT))
26     };
27 }
28 
29 /// Raw macro to declare a constant or a function that returns an ioctl number.
30 #[macro_export]
31 macro_rules! ioctl_ioc_nr {
32     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr) => {
33         #[allow(non_snake_case)]
34         /// Constant ioctl request number.
35         pub const $name: $crate::linux::IoctlNr = $crate::ioctl_expr!($dir, $ty, $nr, $size);
36     };
37     ($name:ident, $dir:expr, $ty:expr, $nr:expr, $size:expr, $($v:ident),+) => {
38         #[allow(non_snake_case)]
39         /// Generates ioctl request number.
40         pub const fn $name($($v: ::std::os::raw::c_uint),+) -> $crate::linux::IoctlNr {
41             $crate::ioctl_expr!($dir, $ty, $nr, $size)
42         }
43     };
44 }
45 
46 /// Declare an ioctl that transfers no data.
47 #[macro_export]
48 macro_rules! ioctl_io_nr {
49     ($name:ident, $ty:expr, $nr:expr) => {
50         $crate::ioctl_ioc_nr!($name, $crate::linux::ioctl::_IOC_NONE, $ty, $nr, 0);
51     };
52     ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
53         $crate::ioctl_ioc_nr!($name, $crate::linux::ioctl::_IOC_NONE, $ty, $nr, 0, $($v),+);
54     };
55 }
56 
57 /// Declare an ioctl that reads data.
58 #[macro_export]
59 macro_rules! ioctl_ior_nr {
60     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
61         $crate::ioctl_ioc_nr!(
62             $name,
63             $crate::linux::ioctl::_IOC_READ,
64             $ty,
65             $nr,
66             ::std::mem::size_of::<$size>() as u32
67         );
68     };
69     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
70         $crate::ioctl_ioc_nr!(
71             $name,
72             $crate::linux::ioctl::_IOC_READ,
73             $ty,
74             $nr,
75             ::std::mem::size_of::<$size>() as u32,
76             $($v),+
77         );
78     };
79 }
80 
81 /// Declare an ioctl that writes data.
82 #[macro_export]
83 macro_rules! ioctl_iow_nr {
84     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
85         $crate::ioctl_ioc_nr!(
86             $name,
87             $crate::linux::ioctl::_IOC_WRITE,
88             $ty,
89             $nr,
90             ::std::mem::size_of::<$size>() as u32
91         );
92     };
93     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
94         $crate::ioctl_ioc_nr!(
95             $name,
96             $crate::linux::ioctl::_IOC_WRITE,
97             $ty,
98             $nr,
99             ::std::mem::size_of::<$size>() as u32,
100             $($v),+
101         );
102     };
103 }
104 
105 /// Declare an ioctl that reads and writes data.
106 #[macro_export]
107 macro_rules! ioctl_iowr_nr {
108     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
109         $crate::ioctl_ioc_nr!(
110             $name,
111             $crate::linux::ioctl::_IOC_READ | $crate::linux::ioctl::_IOC_WRITE,
112             $ty,
113             $nr,
114             ::std::mem::size_of::<$size>() as u32
115         );
116     };
117     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
118         $crate::ioctl_ioc_nr!(
119             $name,
120             $crate::linux::ioctl::_IOC_READ | $crate::linux::ioctl::_IOC_WRITE,
121             $ty,
122             $nr,
123             ::std::mem::size_of::<$size>() as u32,
124             $($v),+
125         );
126     };
127 }
128 
129 pub const _IOC_NRBITS: c_uint = 8;
130 pub const _IOC_TYPEBITS: c_uint = 8;
131 pub const _IOC_SIZEBITS: c_uint = 14;
132 pub const _IOC_DIRBITS: c_uint = 2;
133 pub const _IOC_NRMASK: c_uint = 255;
134 pub const _IOC_TYPEMASK: c_uint = 255;
135 pub const _IOC_SIZEMASK: c_uint = 16383;
136 pub const _IOC_DIRMASK: c_uint = 3;
137 pub const _IOC_NRSHIFT: c_uint = 0;
138 pub const _IOC_TYPESHIFT: c_uint = 8;
139 pub const _IOC_SIZESHIFT: c_uint = 16;
140 pub const _IOC_DIRSHIFT: c_uint = 30;
141 pub const _IOC_NONE: c_uint = 0;
142 pub const _IOC_WRITE: c_uint = 1;
143 pub const _IOC_READ: c_uint = 2;
144 pub const IOC_IN: c_uint = 1_073_741_824;
145 pub const IOC_OUT: c_uint = 2_147_483_648;
146 pub const IOC_INOUT: c_uint = 3_221_225_472;
147 pub const IOCSIZE_MASK: c_uint = 1_073_676_288;
148 pub const IOCSIZE_SHIFT: c_uint = 16;
149 
150 #[cfg(any(target_os = "android", target_env = "musl"))]
151 pub type IoctlNr = c_int;
152 #[cfg(not(any(target_os = "android", target_env = "musl")))]
153 pub type IoctlNr = c_ulong;
154 
155 /// Run an ioctl with no arguments.
156 /// # Safety
157 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int158 pub unsafe fn ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int {
159     libc::ioctl(descriptor.as_raw_descriptor(), nr, 0)
160 }
161 
162 /// Run an ioctl with a single value argument.
163 /// # Safety
164 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_val(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: c_ulong) -> c_int165 pub unsafe fn ioctl_with_val(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: c_ulong) -> c_int {
166     libc::ioctl(descriptor.as_raw_descriptor(), nr, arg)
167 }
168 
169 /// Run an ioctl with an immutable reference.
170 /// # Safety
171 ///
172 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_ref<T>(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &T) -> c_int173 pub unsafe fn ioctl_with_ref<T>(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &T) -> c_int {
174     libc::ioctl(
175         descriptor.as_raw_descriptor(),
176         nr,
177         arg as *const T as *const c_void,
178     )
179 }
180 
181 /// Run an ioctl with a mutable reference.
182 /// # Safety
183 ///
184 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_mut_ref<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &mut T, ) -> c_int185 pub unsafe fn ioctl_with_mut_ref<T>(
186     descriptor: &dyn AsRawDescriptor,
187     nr: IoctlNr,
188     arg: &mut T,
189 ) -> c_int {
190     libc::ioctl(
191         descriptor.as_raw_descriptor(),
192         nr,
193         arg as *mut T as *mut c_void,
194     )
195 }
196 
197 /// Run an ioctl with a raw pointer.
198 /// # Safety
199 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_ptr<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *const T, ) -> c_int200 pub unsafe fn ioctl_with_ptr<T>(
201     descriptor: &dyn AsRawDescriptor,
202     nr: IoctlNr,
203     arg: *const T,
204 ) -> c_int {
205     libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *const c_void)
206 }
207 
208 /// Run an ioctl with a mutable raw pointer.
209 /// # Safety
210 /// The caller is responsible for determining the safety of the particular ioctl.
ioctl_with_mut_ptr<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *mut T, ) -> c_int211 pub unsafe fn ioctl_with_mut_ptr<T>(
212     descriptor: &dyn AsRawDescriptor,
213     nr: IoctlNr,
214     arg: *mut T,
215 ) -> c_int {
216     libc::ioctl(descriptor.as_raw_descriptor(), nr, arg as *mut c_void)
217 }
218 #[cfg(test)]
219 mod tests {
220     const TUNTAP: ::std::os::raw::c_uint = 0x54;
221     const VHOST: ::std::os::raw::c_uint = 0xaf;
222     const EVDEV: ::std::os::raw::c_uint = 0x45;
223 
224     ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01);
225     ioctl_ior_nr!(TUNGETFEATURES, TUNTAP, 0xcf, ::std::os::raw::c_uint);
226     ioctl_iow_nr!(TUNSETQUEUE, TUNTAP, 0xd9, ::std::os::raw::c_int);
227     ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, ::std::os::raw::c_int);
228 
229     ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, [u8; 128], evt);
230     ioctl_io_nr!(FAKE_IOCTL_2_ARG, EVDEV, 0x01 + x + y, x, y);
231 
232     #[test]
ioctl_macros()233     fn ioctl_macros() {
234         assert_eq!(0x0000af01, VHOST_SET_OWNER);
235         assert_eq!(0x800454cf, TUNGETFEATURES);
236         assert_eq!(0x400454d9, TUNSETQUEUE);
237         assert_eq!(0xc004af12, VHOST_GET_VRING_BASE);
238 
239         assert_eq!(0x80804522, EVIOCGBIT(2));
240         assert_eq!(0x00004509, FAKE_IOCTL_2_ARG(3, 5));
241     }
242 }
243