Skip to main content

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_INVALID, zx_handle_t, zx_status_t};
19use zx::{
20    BootTimeline, Clock, ClockDetails, ClockTransformation, ClockUpdate, Duration, Instant, Job,
21    NullableHandle, Process, Rights, Status, Thread, Timeline, Unowned, Vmar,
22};
23
24// TODO(https://fxbug.dev/42139436): Document these.
25#[allow(missing_docs)]
26unsafe extern "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 `fuchsia.logger.LogSink` channel handle.
154    ///
155    /// Equivalent to PA_LOG_SINK.
156    LogSink = 0x3D,
157
158    /// A Handle to a resource object. Used by devcoordinator and devhosts.
159    ///
160    /// Equivalent to PA_RESOURCE.
161    Resource = 0x3F,
162
163    /// A Handle to a clock object representing UTC.  Used by runtimes to gain
164    /// access to UTC time.
165    ///
166    /// Equivalent to PA_CLOCK_UTC.
167    ClockUtc = 0x40,
168
169    /// A Handle to an MMIO resource object.
170    ///
171    /// Equivalent to PA_MMIO_RESOURCE.
172    MmioResource = 0x50,
173
174    /// A Handle to an IRQ resource object.
175    ///
176    /// Equivalent to PA_IRQ_RESOURCE.
177    IrqResource = 0x51,
178
179    /// A Handle to an IO Port resource object.
180    ///
181    /// Equivalent to PA_IOPORT_RESOURCE.
182    IoportResource = 0x52,
183
184    /// A Handle to an SMC resource object.
185    ///
186    /// Equivalent to PA_SMC_RESOURCE.
187    SmcResource = 0x53,
188
189    /// A Handle to the System resource object.
190    ///
191    /// Equivalent to PA_SYSTEM_RESOURCE.
192    SystemResource = 0x54,
193
194    /// A handle type with user-defined meaning.
195    ///
196    /// Equivalent to PA_USER0.
197    User0 = 0xF0,
198
199    /// A handle type with user-defined meaning.
200    ///
201    /// Equivalent to PA_USER1.
202    User1 = 0xF1,
203
204    /// A handle type with user-defined meaning.
205    ///
206    /// Equivalent to PA_USER2.
207    User2 = 0xF2,
208}
209
210/// Metadata information for a handle in a processargs message. Contains a handle type and an
211/// unsigned 16-bit value, whose meaning is handle type dependent.
212#[derive(Debug, Copy, Clone, Eq, PartialEq)]
213pub struct HandleInfo {
214    htype: HandleType,
215    arg: u16,
216}
217
218impl HandleInfo {
219    /// Create a handle info struct from a handle type and an argument.
220    ///
221    /// For example, a `HandleInfo::new(HandleType::FileDescriptor, 32)` identifies
222    /// the respective handle as file descriptor 32.
223    ///
224    /// Corresponds to PA_HND in processargs.h.
225    pub const fn new(htype: HandleType, arg: u16) -> Self {
226        HandleInfo { htype, arg }
227    }
228
229    /// Returns the handle type for this handle info struct.
230    #[inline(always)]
231    pub fn handle_type(&self) -> HandleType {
232        self.htype
233    }
234
235    /// Returns the argument for this handle info struct.
236    #[inline(always)]
237    pub fn arg(&self) -> u16 {
238        self.arg
239    }
240
241    /// Convert the handle info into a raw u32 value for FFI purposes.
242    pub const fn as_raw(&self) -> u32 {
243        ((self.htype as u32) & 0xFF) | (self.arg as u32) << 16
244    }
245}
246
247/// An implementation of the From trait to create a [HandleInfo] from a [HandleType] with an argument
248/// of 0.
249impl From<HandleType> for HandleInfo {
250    fn from(ty: HandleType) -> Self {
251        Self::new(ty, 0)
252    }
253}
254
255/// Possible errors when converting a raw u32 to a HandleInfo with the  TryFrom<u32> impl on
256/// HandleInfo.
257#[derive(Error, Debug)]
258pub enum HandleInfoError {
259    /// Unknown handle type.
260    #[error("Unknown handle type for HandleInfo: {:#x?}", _0)]
261    UnknownHandleType(u32),
262
263    /// Otherwise invalid raw value, like reserved bytes being non-zero.
264    #[error("Invalid value for HandleInfo: {:#x?}", _0)]
265    InvalidHandleInfo(u32),
266}
267
268impl TryFrom<u32> for HandleInfo {
269    type Error = HandleInfoError;
270
271    /// Attempt to convert a u32 to a handle ID value. Can fail if the value represents an
272    /// unknown handle type or is otherwise invalid.
273    ///
274    /// Useful to convert existing handle info values received through FIDL APIs, e.g. from a
275    /// client that creates them using the PA_HND macro in processargs.h from C/C++.
276    fn try_from(value: u32) -> Result<HandleInfo, HandleInfoError> {
277        // 2nd byte should be zero, it is currently unused.
278        if value & 0xFF00 != 0 {
279            return Err(HandleInfoError::InvalidHandleInfo(value));
280        }
281
282        let htype = HandleType::from_u8((value & 0xFF) as u8)
283            .ok_or(HandleInfoError::UnknownHandleType(value))?;
284        Ok(HandleInfo::new(htype, (value >> 16) as u16))
285    }
286}
287
288/// Removes the handle of type `HandleType` from the list of handles received at startup.
289///
290/// This function will return `Some` at-most once per handle type.
291/// This function will return `None` if the requested type was not received at
292/// startup or if the handle with the provided type was already taken.
293pub fn take_startup_handle(info: HandleInfo) -> Option<NullableHandle> {
294    unsafe {
295        let raw = zx_take_startup_handle(info.as_raw());
296        if raw == ZX_HANDLE_INVALID { None } else { Some(NullableHandle::from_raw(raw)) }
297    }
298}
299
300/// Provides temporary scoped access to the current thread's handle.
301///
302/// Callers who need to store a thread handle or to send it to another thread should duplicate the
303/// handle to ensure it can outlive the current thread.
304pub fn with_thread_self<F, R>(f: F) -> R
305where
306    F: for<'a> FnOnce(&Thread) -> R,
307{
308    // SAFETY: The handle returned by zx_thread_self() is guaranteed to be valid for the duration of
309    // the calling thread's execution and by creating this on our stack we prevent it from outliving
310    // this thread.
311    let thread = unsafe { Unowned::from_raw_handle(zx_thread_self()) };
312    f(&thread)
313}
314
315/// Get a reference to the handle of the current process.
316pub fn process_self() -> Unowned<'static, Process> {
317    unsafe {
318        // zx_process_self() doesn't work correctly in jobs where multiple processes share
319        // the portion of their address space for global variables. Use thrd_get_zx_process() to
320        // return the correct value in that context. See https://fxbug.dev/42083701 for background.
321        let handle = thrd_get_zx_process();
322        Unowned::from_raw_handle(handle)
323    }
324}
325
326/// Get a reference to the handle of the current address space.
327pub fn vmar_root_self() -> Unowned<'static, Vmar> {
328    unsafe {
329        let handle = zx_vmar_root_self();
330        Unowned::from_raw_handle(handle)
331    }
332}
333
334/// Get a reference to the fuchsia.ldsvc.Loader channel.
335pub fn loader_svc() -> Result<NullableHandle, Status> {
336    unsafe {
337        let mut handle: zx_handle_t = 0;
338        let status = dl_clone_loader_service(&mut handle);
339        Status::ok(status)?;
340        Ok(NullableHandle::from_raw(handle))
341    }
342}
343
344/// Get a reference to the default `Job` provided to the process on startup.
345///
346/// This typically refers to the `Job` that is the immediate parent of the current
347/// process.
348///
349/// If the current process was launched as a Fuchsia Component, this `Job`
350/// will begin with no child processes other than the current process.
351pub fn job_default() -> Unowned<'static, Job> {
352    unsafe {
353        let handle = zx_job_default();
354        Unowned::from_raw_handle(handle)
355    }
356}
357
358/// Marker type for the UTC timeline.
359#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
360pub struct UtcTimeline;
361impl Timeline for UtcTimeline {}
362
363/// A UTC timestamp, measured in nanoseconds since Jan 1 1970.
364pub type UtcInstant = Instant<UtcTimeline>;
365
366/// A duration in the UTC timeline.
367pub type UtcDuration = Duration<UtcTimeline>;
368
369/// Special methods that are only valid for UtcDuration.
370pub trait UtcDurationExt {
371    /// Converts the reading of a duration on the UTC timeline to a reading on the boot timeline.
372    ///
373    /// This is "lossy" because durations are usually differences of
374    /// two Instants, and Boot time and UTC time mostly tick at the same rate.
375    /// However, they aren't required to tick in lock-step.
376    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline>;
377}
378
379impl UtcDurationExt for UtcDuration {
380    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline> {
381        zx::Duration::from_nanos(self.into_nanos())
382    }
383}
384
385/// Special methods that are only valid for zx::BootDuration.
386pub trait BootDurationExt {
387    /// Converts the reading of a duration on the boot timeline to a reading on the UTC timeline.
388    ///
389    /// See notes alongside [UtcDurationExt::to_boot_lossy].
390    fn to_utc_lossy(&self) -> UtcDuration;
391}
392
393impl BootDurationExt for zx::BootDuration {
394    fn to_utc_lossy(&self) -> UtcDuration {
395        zx::Duration::from_nanos(self.into_nanos())
396    }
397}
398
399/// A clock that will return UTC timestamps.
400pub type UtcClock = Clock<BootTimeline, UtcTimeline>;
401
402/// Details of a UTC clock.
403pub type UtcClockDetails = ClockDetails<BootTimeline, UtcTimeline>;
404
405/// A transformation for the UTC clock.
406pub type UtcClockTransform = ClockTransformation<BootTimeline, UtcTimeline>;
407
408/// An update for the UTC clock.
409pub type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
410
411fn utc_clock() -> Unowned<'static, UtcClock> {
412    // SAFETY: basic FFI call which returns either a valid handle or ZX_HANDLE_INVALID.
413    unsafe {
414        let handle = zx_utc_reference_get();
415        Unowned::from_raw_handle(handle)
416    }
417}
418
419/// Duplicate the UTC `Clock` registered with the runtime.
420pub fn duplicate_utc_clock_handle(rights: Rights) -> Result<UtcClock, Status> {
421    utc_clock().duplicate(rights)
422}
423
424/// Swaps the current process-global UTC clock with `new_clock`, returning
425/// the old clock on success.
426/// If `new_clock` is a valid handle but does not have the ZX_RIGHT_READ right,
427/// an error is returned and `new_clock` is dropped.
428pub fn swap_utc_clock_handle(new_clock: UtcClock) -> Result<UtcClock, Status> {
429    Ok(unsafe {
430        let mut prev_handle = ZX_HANDLE_INVALID;
431        Status::ok(zx_utc_reference_swap(new_clock.into_raw(), &mut prev_handle))?;
432        NullableHandle::from_raw(prev_handle)
433    }
434    .into())
435}
436
437/// SUBTLE, read the detailed documentation before using this function.
438///
439/// Reads time from the UTC `Clock` registered with the runtime.
440///
441/// # Subtleties
442///
443/// If you intend to use this timestamp in any user-facing capacity, you must
444/// ensure that a sensible thing is displayed to the user. Specifically:
445///
446/// * If you want to display the value, make sure to first check whether the
447///   UTC clock is even started. If not started, Fuchsia's UTC will [continuously
448///   indicate backstop time][bt]. This is a Fuchsia-only behavior, disregarding
449///   this behavior may present a confusing outcome to your user.
450/// * If you want to use this value in arithmetic calculations, never roll your
451///   own, especially if you are combining values from different timelines.
452/// * If you must use this value in arithmetic calculations and must combine
453///   values from different timelines, doublecheck that you are using the correct
454///   other timeline.
455/// * If in the end, you want to format the value as user readable date-time,
456///   never roll your own. Use the ICU library or equivalent chronological
457///   library of your choice.
458/// * **In testing only.** Due to above peculiarities, we often provide fake
459///   UTC clocks to test fixtures. This does not happen automatically, you must
460///   configure your test fixture to do this. When reading UTC time in a test
461///   especially if you want to compare across components, doublecheck that all
462///   components are using the same UTC clock by koid.
463///
464/// # Checking whether the clock is started
465///
466/// You can check this property in a few ways:
467///
468/// * You can call `utc_clock().get_details()`, which will return a `UtcClockDetails`.
469///   You can check that the clock rates reported are not zero. Requires
470///   `zx::Rights::INSPECT` on the clock handle for `get_details()`.
471/// * You can call `utc_clock().read()`, which will return an `UtcInstant` value.
472///   If the clock is not started, this will return a value that is exactly the
473///   value of UTC backstop time. This is more straightforward but requires you
474///   to read the clock and its details, which is more work than you may want.
475///
476/// # Panics
477///
478/// Panics if there is no UTC clock registered with the runtime or the registered handle does not
479/// have the required rights.
480///
481/// [bt]: https://fuchsia.dev/fuchsia-src/concepts/kernel/time/utc/behavior
482#[inline]
483pub fn utc_time() -> UtcInstant {
484    utc_clock().read().expect("Failed to read UTC clock")
485}
486
487#[cfg(test)]
488mod tests {
489    use super::*;
490
491    #[test]
492    fn handle_id() {
493        let mut randbuf = [0; 2];
494        for type_val in 0..0xFF {
495            if let Some(htype) = HandleType::from_u8(type_val as u8) {
496                zx::cprng_draw(&mut randbuf);
497                let arg = u16::from_le_bytes(randbuf);
498
499                let info = HandleInfo::new(htype, arg);
500                assert_eq!(info.handle_type(), htype);
501                assert_eq!(info.arg(), arg);
502
503                let info = HandleInfo::from(htype);
504                assert_eq!(info.handle_type(), htype);
505                assert_eq!(info.arg(), 0);
506            }
507        }
508    }
509
510    #[test]
511    fn handle_id_raw() {
512        assert_eq!(HandleInfo::new(HandleType::ProcessSelf, 0).as_raw(), 0x00000001);
513        assert_eq!(HandleInfo::new(HandleType::DirectoryRequest, 0).as_raw(), 0x0000003B);
514        assert_eq!(HandleInfo::new(HandleType::LdsvcLoader, 0xABCD).as_raw(), 0xABCD0010);
515        assert_eq!(HandleInfo::new(HandleType::User0, 0x1).as_raw(), 0x000100F0);
516        assert_eq!(HandleInfo::new(HandleType::User1, 0xABCD).as_raw(), 0xABCD00F1);
517        assert_eq!(HandleInfo::new(HandleType::User2, 0xFFFF).as_raw(), 0xFFFF00F2);
518    }
519
520    #[test]
521    fn handle_id_from_u32() {
522        assert_eq!(
523            HandleInfo::try_from(0x00000002).unwrap(),
524            HandleInfo::new(HandleType::ThreadSelf, 0)
525        );
526        assert_eq!(
527            HandleInfo::try_from(0x00040030).unwrap(),
528            HandleInfo::new(HandleType::FileDescriptor, 4)
529        );
530        assert_eq!(
531            HandleInfo::try_from(0x501C00F2).unwrap(),
532            HandleInfo::new(HandleType::User2, 0x501C)
533        );
534
535        // Non-zero unused byte
536        assert!(HandleInfo::try_from(0x00001100).is_err());
537        assert!(HandleInfo::try_from(0x00010101).is_err());
538        // Unknown handle type
539        assert!(HandleInfo::try_from(0x00000000).is_err());
540        assert!(HandleInfo::try_from(0x00000006).is_err());
541    }
542
543    #[test]
544    fn read_utc_time() {
545        utc_time();
546    }
547
548    #[test]
549    fn get_loader_svc() {
550        loader_svc().unwrap();
551    }
552}