fuchsia_runtime/
lib.rs

1// Copyright 2019 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//! Type-safe bindings for Fuchsia-specific `libc` functionality.
6//!
7//! This crate is a minimal extension on top of the `fuchsia-zircon` crate,
8//! which provides bindings to the Zircon kernel's syscalls, but does not
9//! depend on functionality from `libc`.
10
11// AKA `libc`-granted ambient-authority crate ;)
12
13#![deny(missing_docs)]
14
15use num_derive::FromPrimitive;
16use num_traits::cast::FromPrimitive;
17use thiserror::Error;
18use zx::sys::{zx_handle_t, zx_status_t, ZX_HANDLE_INVALID};
19use zx::{
20    BootTimeline, Clock, ClockDetails, ClockTransformation, ClockUpdate, Duration, Handle,
21    HandleBased, Instant, Job, Process, Rights, Status, Thread, Timeline, Unowned, Vmar,
22};
23
24// TODO(https://fxbug.dev/42139436): Document these.
25#[allow(missing_docs)]
26extern "C" {
27    pub fn dl_clone_loader_service(out: *mut zx_handle_t) -> zx_status_t;
28    pub fn zx_take_startup_handle(hnd_info: u32) -> zx_handle_t;
29    pub fn zx_thread_self() -> zx_handle_t;
30    pub fn zx_process_self() -> zx_handle_t;
31    pub fn thrd_get_zx_process() -> zx_handle_t;
32    pub fn zx_vmar_root_self() -> zx_handle_t;
33    pub fn zx_job_default() -> zx_handle_t;
34    pub fn zx_utc_reference_get() -> zx_handle_t;
35    pub fn zx_utc_reference_swap(
36        new_handle: zx_handle_t,
37        prev_handle: *mut zx_handle_t,
38    ) -> zx_status_t;
39}
40
41/// Handle types as defined by the processargs protocol.
42///
43/// See [//zircon/system/public/zircon/processargs.h][processargs.h] for canonical definitions.
44///
45/// Short descriptions of each handle type are given, but more complete documentation may be found
46/// in the [processargs.h] header.
47///
48/// [processargs.h]: https://fuchsia.googlesource.com/fuchsia/+/HEAD/zircon/system/public/zircon/processargs.h
49#[repr(u8)]
50#[derive(FromPrimitive, Copy, Clone, Debug, Eq, PartialEq)]
51#[non_exhaustive]
52pub enum HandleType {
53    /// Handle to our own process.
54    ///
55    /// Equivalent to PA_PROC_SELF.
56    ProcessSelf = 0x01,
57
58    /// Handle to the initial thread of our own process.
59    ///
60    /// Equivalent to PA_THREAD_SELF.
61    ThreadSelf = 0x02,
62
63    /// Handle to a job object which can be used to make child processes.
64    ///
65    /// The job can be the same as the one used to create this process or it can
66    /// be different.
67    ///
68    /// Equivalent to PA_JOB_DEFAULT.
69    DefaultJob = 0x03,
70
71    /// Handle to the root of our address space.
72    ///
73    /// Equivalent to PA_VMAR_ROOT.
74    RootVmar = 0x04,
75
76    /// Handle to the VMAR used to load the initial program image.
77    ///
78    /// Equivalent to PA_VMAR_LOADED.
79    LoadedVmar = 0x05,
80
81    /// Service for loading shared libraries.
82    ///
83    /// See `fuchsia.ldsvc.Loader` for the interface definition.
84    ///
85    /// Equivalent to PA_LDSVC_LOADER.
86    LdsvcLoader = 0x10,
87
88    /// Handle to the VMO containing the vDSO ELF image.
89    ///
90    /// Equivalent to PA_VMO_VDSO.
91    VdsoVmo = 0x11,
92
93    /// Handle to the VMO used to map the initial thread's stack.
94    ///
95    /// Equivalent to PA_VMO_STACK.
96    StackVmo = 0x13,
97
98    /// Handle to the VMO for the main executable file.
99    ///
100    /// Equivalent to PA_VMO_EXECUTABLE.
101    ExecutableVmo = 0x14,
102
103    /// Used by kernel and userboot during startup.
104    ///
105    /// Equivalent to PA_VMO_BOOTDATA.
106    BootdataVmo = 0x1A,
107
108    /// Used by kernel and userboot during startup.
109    ///
110    /// Equivalent to PA_VMO_BOOTFS.
111    BootfsVmo = 0x1B,
112
113    /// Used by the kernel to export debug information as a file in bootfs.
114    ///
115    /// Equivalent to PA_VMO_KERNEL_FILE.
116    KernelFileVmo = 0x1C,
117
118    /// A Handle to a component's process' configuration VMO.
119    ///
120    /// Equivalent to PA_VMO_COMPONENT_CONFIG.
121    ComponentConfigVmo = 0x1D,
122
123    /// A handle to a fuchsia.io.Directory service to be used as a directory in the process's
124    /// namespace. Corresponds to a path in the processargs bootstrap message's namespace table
125    /// based on the argument of a HandleInfo of this type.
126    ///
127    /// Equivalent to PA_NS_DIR.
128    NamespaceDirectory = 0x20,
129
130    /// A handle which will be used as a file descriptor.
131    ///
132    /// Equivalent to PA_FD.
133    FileDescriptor = 0x30,
134
135    /// A Handle to a channel on which the process may serve the
136    /// the |fuchsia.process.Lifecycle| protocol.
137    ///
138    /// Equivalent to PA_LIFECYCLE.
139    Lifecycle = 0x3A,
140
141    /// Server endpoint for handling connections to a process's outgoing directory.
142    ///
143    /// Equivalent to PA_DIRECTORY_REQUEST.
144    DirectoryRequest = 0x3B,
145
146    /// A |fuchsia.component.sandbox/Dictionary| client endpoint where the process
147    /// may find a dictionary that it has stowed away earlier via
148    /// |fuchsia.process.Lifecycle/OnEscrow|.
149    ///
150    /// Equivalent to PA_ESCROWED_DICTIONARY.
151    EscrowedDictionary = 0x3C,
152
153    /// A Handle to a resource object. Used by devcoordinator and devhosts.
154    ///
155    /// Equivalent to PA_RESOURCE.
156    Resource = 0x3F,
157
158    /// A Handle to a clock object representing UTC.  Used by runtimes to gain
159    /// access to UTC time.
160    ///
161    /// Equivalent to PA_CLOCK_UTC.
162    ClockUtc = 0x40,
163
164    /// A Handle to an MMIO resource object.
165    ///
166    /// Equivalent to PA_MMIO_RESOURCE.
167    MmioResource = 0x50,
168
169    /// A Handle to an IRQ resource object.
170    ///
171    /// Equivalent to PA_IRQ_RESOURCE.
172    IrqResource = 0x51,
173
174    /// A Handle to an IO Port resource object.
175    ///
176    /// Equivalent to PA_IOPORT_RESOURCE.
177    IoportResource = 0x52,
178
179    /// A Handle to an SMC resource object.
180    ///
181    /// Equivalent to PA_SMC_RESOURCE.
182    SmcResource = 0x53,
183
184    /// A Handle to the System resource object.
185    ///
186    /// Equivalent to PA_SYSTEM_RESOURCE.
187    SystemResource = 0x54,
188
189    /// A handle type with user-defined meaning.
190    ///
191    /// Equivalent to PA_USER0.
192    User0 = 0xF0,
193
194    /// A handle type with user-defined meaning.
195    ///
196    /// Equivalent to PA_USER1.
197    User1 = 0xF1,
198
199    /// A handle type with user-defined meaning.
200    ///
201    /// Equivalent to PA_USER2.
202    User2 = 0xF2,
203}
204
205/// Metadata information for a handle in a processargs message. Contains a handle type and an
206/// unsigned 16-bit value, whose meaning is handle type dependent.
207#[derive(Debug, Copy, Clone, Eq, PartialEq)]
208pub struct HandleInfo {
209    htype: HandleType,
210    arg: u16,
211}
212
213impl HandleInfo {
214    /// Create a handle info struct from a handle type and an argument.
215    ///
216    /// For example, a `HandleInfo::new(HandleType::FileDescriptor, 32)` identifies
217    /// the respective handle as file descriptor 32.
218    ///
219    /// Corresponds to PA_HND in processargs.h.
220    pub const fn new(htype: HandleType, arg: u16) -> Self {
221        HandleInfo { htype, arg }
222    }
223
224    /// Returns the handle type for this handle info struct.
225    #[inline(always)]
226    pub fn handle_type(&self) -> HandleType {
227        self.htype
228    }
229
230    /// Returns the argument for this handle info struct.
231    #[inline(always)]
232    pub fn arg(&self) -> u16 {
233        self.arg
234    }
235
236    /// Convert the handle info into a raw u32 value for FFI purposes.
237    pub const fn as_raw(&self) -> u32 {
238        ((self.htype as u32) & 0xFF) | (self.arg as u32) << 16
239    }
240}
241
242/// An implementation of the From trait to create a [HandleInfo] from a [HandleType] with an argument
243/// of 0.
244impl From<HandleType> for HandleInfo {
245    fn from(ty: HandleType) -> Self {
246        Self::new(ty, 0)
247    }
248}
249
250/// Possible errors when converting a raw u32 to a HandleInfo with the  TryFrom<u32> impl on
251/// HandleInfo.
252#[derive(Error, Debug)]
253pub enum HandleInfoError {
254    /// Unknown handle type.
255    #[error("Unknown handle type for HandleInfo: {:#x?}", _0)]
256    UnknownHandleType(u32),
257
258    /// Otherwise invalid raw value, like reserved bytes being non-zero.
259    #[error("Invalid value for HandleInfo: {:#x?}", _0)]
260    InvalidHandleInfo(u32),
261}
262
263impl TryFrom<u32> for HandleInfo {
264    type Error = HandleInfoError;
265
266    /// Attempt to convert a u32 to a handle ID value. Can fail if the value represents an
267    /// unknown handle type or is otherwise invalid.
268    ///
269    /// Useful to convert existing handle info values received through FIDL APIs, e.g. from a
270    /// client that creates them using the PA_HND macro in processargs.h from C/C++.
271    fn try_from(value: u32) -> Result<HandleInfo, HandleInfoError> {
272        // 2nd byte should be zero, it is currently unused.
273        if value & 0xFF00 != 0 {
274            return Err(HandleInfoError::InvalidHandleInfo(value));
275        }
276
277        let htype = HandleType::from_u8((value & 0xFF) as u8)
278            .ok_or(HandleInfoError::UnknownHandleType(value))?;
279        Ok(HandleInfo::new(htype, (value >> 16) as u16))
280    }
281}
282
283/// Removes the handle of type `HandleType` from the list of handles received at startup.
284///
285/// This function will return `Some` at-most once per handle type.
286/// This function will return `None` if the requested type was not received at
287/// startup or if the handle with the provided type was already taken.
288pub fn take_startup_handle(info: HandleInfo) -> Option<Handle> {
289    unsafe {
290        let raw = zx_take_startup_handle(info.as_raw());
291        if raw == ZX_HANDLE_INVALID {
292            None
293        } else {
294            Some(Handle::from_raw(raw))
295        }
296    }
297}
298
299/// Provides temporary scoped access to the current thread's handle.
300///
301/// Callers who need to store a thread handle or to send it to another thread should duplicate the
302/// handle to ensure it can outlive the current thread.
303pub fn with_thread_self<F, R>(f: F) -> R
304where
305    F: for<'a> FnOnce(&Thread) -> R,
306{
307    // SAFETY: The handle returned by zx_thread_self() is guaranteed to be valid for the duration of
308    // the calling thread's execution and by creating this on our stack we prevent it from outliving
309    // this thread.
310    let thread = unsafe { Unowned::from_raw_handle(zx_thread_self()) };
311    f(&thread)
312}
313
314/// Get a reference to the handle of the current process.
315pub fn process_self() -> Unowned<'static, Process> {
316    unsafe {
317        // zx_process_self() doesn't work correctly in jobs where multiple processes share
318        // the portion of their address space for global variables. Use thrd_get_zx_process() to
319        // return the correct value in that context. See https://fxbug.dev/42083701 for background.
320        let handle = thrd_get_zx_process();
321        Unowned::from_raw_handle(handle)
322    }
323}
324
325/// Get a reference to the handle of the current address space.
326pub fn vmar_root_self() -> Unowned<'static, Vmar> {
327    unsafe {
328        let handle = zx_vmar_root_self();
329        Unowned::from_raw_handle(handle)
330    }
331}
332
333/// Get a reference to the fuchsia.ldsvc.Loader channel.
334pub fn loader_svc() -> Result<Handle, Status> {
335    unsafe {
336        let mut handle: zx_handle_t = 0;
337        let status = dl_clone_loader_service(&mut handle);
338        Status::ok(status)?;
339        Ok(Handle::from_raw(handle))
340    }
341}
342
343/// Get a reference to the default `Job` provided to the process on startup.
344///
345/// This typically refers to the `Job` that is the immediate parent of the current
346/// process.
347///
348/// If the current process was launched as a Fuchsia Component, this `Job`
349/// will begin with no child processes other than the current process.
350pub fn job_default() -> Unowned<'static, Job> {
351    unsafe {
352        let handle = zx_job_default();
353        Unowned::from_raw_handle(handle)
354    }
355}
356
357/// Marker type for the UTC timeline.
358#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
359pub struct UtcTimeline;
360impl Timeline for UtcTimeline {}
361
362/// A UTC timestamp, measured in nanoseconds since Jan 1 1970.
363pub type UtcInstant = Instant<UtcTimeline>;
364
365/// A duration in the UTC timeline.
366pub type UtcDuration = Duration<UtcTimeline>;
367
368/// Special methods that are only valid for UtcDuration.
369pub trait UtcDurationExt {
370    /// Converts the reading of a duration on the UTC timeline to a reading on the boot timeline.
371    ///
372    /// This is "lossy" because durations are usually differences of
373    /// two Instants, and Boot time and UTC time mostly tick at the same rate.
374    /// However, they aren't required to tick in lock-step.
375    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline>;
376}
377
378impl UtcDurationExt for UtcDuration {
379    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline> {
380        zx::Duration::from_nanos(self.into_nanos())
381    }
382}
383
384/// Special methods that are only valid for zx::BootDuration.
385pub trait BootDurationExt {
386    /// Converts the reading of a duration on the boot timeline to a reading on the UTC timeline.
387    ///
388    /// See notes alongside [UtcDurationExt::to_boot_lossy].
389    fn to_utc_lossy(&self) -> UtcDuration;
390}
391
392impl BootDurationExt for zx::BootDuration {
393    fn to_utc_lossy(&self) -> UtcDuration {
394        zx::Duration::from_nanos(self.into_nanos())
395    }
396}
397
398/// A clock that will return UTC timestamps.
399pub type UtcClock = Clock<BootTimeline, UtcTimeline>;
400
401/// Details of a UTC clock.
402pub type UtcClockDetails = ClockDetails<BootTimeline, UtcTimeline>;
403
404/// A transformation for the UTC clock.
405pub type UtcClockTransform = ClockTransformation<BootTimeline, UtcTimeline>;
406
407/// An update for the UTC clock.
408pub type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
409
410fn utc_clock() -> Unowned<'static, UtcClock> {
411    // SAFETY: basic FFI call which returns either a valid handle or ZX_HANDLE_INVALID.
412    unsafe {
413        let handle = zx_utc_reference_get();
414        Unowned::from_raw_handle(handle)
415    }
416}
417
418/// Duplicate the UTC `Clock` registered with the runtime.
419pub fn duplicate_utc_clock_handle(rights: Rights) -> Result<UtcClock, Status> {
420    utc_clock().duplicate(rights)
421}
422
423/// Swaps the current process-global UTC clock with `new_clock`, returning
424/// the old clock on success.
425/// If `new_clock` is a valid handle but does not have the ZX_RIGHT_READ right,
426/// an error is returned and `new_clock` is dropped.
427pub fn swap_utc_clock_handle(new_clock: UtcClock) -> Result<UtcClock, Status> {
428    Ok(unsafe {
429        let mut prev_handle = ZX_HANDLE_INVALID;
430        Status::ok(zx_utc_reference_swap(new_clock.into_raw(), &mut prev_handle))?;
431        Handle::from_raw(prev_handle)
432    }
433    .into())
434}
435
436/// SUBTLE, read the detailed documentation before using this function.
437///
438/// Reads time from the UTC `Clock` registered with the runtime.
439///
440/// # Subtleties
441///
442/// If you intend to use this timestamp in any user-facing capacity, you must
443/// ensure that a sensible thing is displayed to the user. Specifically:
444///
445/// * If you want to display the value, make sure to first check whether the
446///   UTC clock is even started. If not started, Fuchsia's UTC will [continuously
447///   indicate backstop time][bt]. This is a Fuchsia-only behavior, disregarding
448///   this behavior may present a confusing outcome to your user.
449/// * If you want to use this value in arithmetic calculations, never roll your
450///   own, especially if you are combining values from different timelines.
451/// * If you must use this value in arithmetic calculations and must combine
452///   values from different timelines, doublecheck that you are using the correct
453///   other timeline.
454/// * If in the end, you want to format the value as user readable date-time,
455///   never roll your own. Use the ICU library or equivalent chronological
456///   library of your choice.
457/// * **In testing only.** Due to above peculiarities, we often provide fake
458///   UTC clocks to test fixtures. This does not happen automatically, you must
459///   configure your test fixture to do this. When reading UTC time in a test
460///   especially if you want to compare across components, doublecheck that all
461///   components are using the same UTC clock by koid.
462///
463/// # Checking whether the clock is started
464///
465/// You can check this property in a few ways:
466///
467/// * You can call `utc_clock().get_details()`, which will return a `UtcClockDetails`.
468///   You can check that the clock rates reported are not zero. Requires
469///   `zx::Rights::INSPECT` on the clock handle for `get_details()`.
470/// * You can call `utc_clock().read()`, which will return an `UtcInstant` value.
471///   If the clock is not started, this will return a value that is exactly the
472///   value of UTC backstop time. This is more straightforward but requires you
473///   to read the clock and its details, which is more work than you may want.
474///
475/// # Panics
476///
477/// Panics if there is no UTC clock registered with the runtime or the registered handle does not
478/// have the required rights.
479///
480/// [bt]: https://fuchsia.dev/fuchsia-src/concepts/kernel/time/utc/behavior
481#[inline]
482pub fn utc_time() -> UtcInstant {
483    utc_clock().read().expect("Failed to read UTC clock")
484}
485
486#[cfg(test)]
487mod tests {
488    use super::*;
489
490    #[test]
491    fn handle_id() {
492        let mut randbuf = [0; 2];
493        for type_val in 0..0xFF {
494            if let Some(htype) = HandleType::from_u8(type_val as u8) {
495                zx::cprng_draw(&mut randbuf);
496                let arg = u16::from_le_bytes(randbuf);
497
498                let info = HandleInfo::new(htype, arg);
499                assert_eq!(info.handle_type(), htype);
500                assert_eq!(info.arg(), arg);
501
502                let info = HandleInfo::from(htype);
503                assert_eq!(info.handle_type(), htype);
504                assert_eq!(info.arg(), 0);
505            }
506        }
507    }
508
509    #[test]
510    fn handle_id_raw() {
511        assert_eq!(HandleInfo::new(HandleType::ProcessSelf, 0).as_raw(), 0x00000001);
512        assert_eq!(HandleInfo::new(HandleType::DirectoryRequest, 0).as_raw(), 0x0000003B);
513        assert_eq!(HandleInfo::new(HandleType::LdsvcLoader, 0xABCD).as_raw(), 0xABCD0010);
514        assert_eq!(HandleInfo::new(HandleType::User0, 0x1).as_raw(), 0x000100F0);
515        assert_eq!(HandleInfo::new(HandleType::User1, 0xABCD).as_raw(), 0xABCD00F1);
516        assert_eq!(HandleInfo::new(HandleType::User2, 0xFFFF).as_raw(), 0xFFFF00F2);
517    }
518
519    #[test]
520    fn handle_id_from_u32() {
521        assert_eq!(
522            HandleInfo::try_from(0x00000002).unwrap(),
523            HandleInfo::new(HandleType::ThreadSelf, 0)
524        );
525        assert_eq!(
526            HandleInfo::try_from(0x00040030).unwrap(),
527            HandleInfo::new(HandleType::FileDescriptor, 4)
528        );
529        assert_eq!(
530            HandleInfo::try_from(0x501C00F2).unwrap(),
531            HandleInfo::new(HandleType::User2, 0x501C)
532        );
533
534        // Non-zero unused byte
535        assert!(HandleInfo::try_from(0x00001100).is_err());
536        assert!(HandleInfo::try_from(0x00010101).is_err());
537        // Unknown handle type
538        assert!(HandleInfo::try_from(0x00000000).is_err());
539        assert!(HandleInfo::try_from(0x00000006).is_err());
540    }
541
542    #[test]
543    fn read_utc_time() {
544        utc_time();
545    }
546
547    #[test]
548    fn get_loader_svc() {
549        loader_svc().unwrap();
550    }
551}