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}
35
36/// Handle types as defined by the processargs protocol.
37///
38/// See [//zircon/system/public/zircon/processargs.h][processargs.h] for canonical definitions.
39///
40/// Short descriptions of each handle type are given, but more complete documentation may be found
41/// in the [processargs.h] header.
42///
43/// [processargs.h]: https://fuchsia.googlesource.com/fuchsia/+/HEAD/zircon/system/public/zircon/processargs.h
44#[repr(u8)]
45#[derive(FromPrimitive, Copy, Clone, Debug, Eq, PartialEq)]
46#[non_exhaustive]
47pub enum HandleType {
48    /// Handle to our own process.
49    ///
50    /// Equivalent to PA_PROC_SELF.
51    ProcessSelf = 0x01,
52
53    /// Handle to the initial thread of our own process.
54    ///
55    /// Equivalent to PA_THREAD_SELF.
56    ThreadSelf = 0x02,
57
58    /// Handle to a job object which can be used to make child processes.
59    ///
60    /// The job can be the same as the one used to create this process or it can
61    /// be different.
62    ///
63    /// Equivalent to PA_JOB_DEFAULT.
64    DefaultJob = 0x03,
65
66    /// Handle to the root of our address space.
67    ///
68    /// Equivalent to PA_VMAR_ROOT.
69    RootVmar = 0x04,
70
71    /// Handle to the VMAR used to load the initial program image.
72    ///
73    /// Equivalent to PA_VMAR_LOADED.
74    LoadedVmar = 0x05,
75
76    /// Service for loading shared libraries.
77    ///
78    /// See `fuchsia.ldsvc.Loader` for the interface definition.
79    ///
80    /// Equivalent to PA_LDSVC_LOADER.
81    LdsvcLoader = 0x10,
82
83    /// Handle to the VMO containing the vDSO ELF image.
84    ///
85    /// Equivalent to PA_VMO_VDSO.
86    VdsoVmo = 0x11,
87
88    /// Handle to the VMO used to map the initial thread's stack.
89    ///
90    /// Equivalent to PA_VMO_STACK.
91    StackVmo = 0x13,
92
93    /// Handle to the VMO for the main executable file.
94    ///
95    /// Equivalent to PA_VMO_EXECUTABLE.
96    ExecutableVmo = 0x14,
97
98    /// Used by kernel and userboot during startup.
99    ///
100    /// Equivalent to PA_VMO_BOOTDATA.
101    BootdataVmo = 0x1A,
102
103    /// Used by kernel and userboot during startup.
104    ///
105    /// Equivalent to PA_VMO_BOOTFS.
106    BootfsVmo = 0x1B,
107
108    /// Used by the kernel to export debug information as a file in bootfs.
109    ///
110    /// Equivalent to PA_VMO_KERNEL_FILE.
111    KernelFileVmo = 0x1C,
112
113    /// A Handle to a component's process' configuration VMO.
114    ///
115    /// Equivalent to PA_VMO_COMPONENT_CONFIG.
116    ComponentConfigVmo = 0x1D,
117
118    /// A handle to a fuchsia.io.Directory service to be used as a directory in the process's
119    /// namespace. Corresponds to a path in the processargs bootstrap message's namespace table
120    /// based on the argument of a HandleInfo of this type.
121    ///
122    /// Equivalent to PA_NS_DIR.
123    NamespaceDirectory = 0x20,
124
125    /// A handle which will be used as a file descriptor.
126    ///
127    /// Equivalent to PA_FD.
128    FileDescriptor = 0x30,
129
130    /// A Handle to a channel on which the process may serve the
131    /// the |fuchsia.process.Lifecycle| protocol.
132    ///
133    /// Equivalent to PA_LIFECYCLE.
134    Lifecycle = 0x3A,
135
136    /// Server endpoint for handling connections to a process's outgoing directory.
137    ///
138    /// Equivalent to PA_DIRECTORY_REQUEST.
139    DirectoryRequest = 0x3B,
140
141    /// A |fuchsia.component.sandbox/Dictionary| client endpoint where the process
142    /// may find a dictionary that it has stowed away earlier via
143    /// |fuchsia.process.Lifecycle/OnEscrow|.
144    ///
145    /// Equivalent to PA_ESCROWED_DICTIONARY.
146    EscrowedDictionary = 0x3C,
147
148    /// A `fuchsia.logger.LogSink` channel handle.
149    ///
150    /// Equivalent to PA_LOG_SINK.
151    LogSink = 0x3D,
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<NullableHandle> {
289    unsafe {
290        let raw = zx_take_startup_handle(info.as_raw());
291        if raw == ZX_HANDLE_INVALID { None } else { Some(NullableHandle::from_raw(raw)) }
292    }
293}
294
295/// Provides temporary scoped access to the current thread's handle.
296///
297/// Callers who need to store a thread handle or to send it to another thread should duplicate the
298/// handle to ensure it can outlive the current thread.
299pub fn with_thread_self<F, R>(f: F) -> R
300where
301    F: for<'a> FnOnce(&Thread) -> R,
302{
303    // SAFETY: The handle returned by zx_thread_self() is guaranteed to be valid for the duration of
304    // the calling thread's execution and by creating this on our stack we prevent it from outliving
305    // this thread.
306    let thread = unsafe { Unowned::from_raw_handle(zx_thread_self()) };
307    f(&thread)
308}
309
310/// Get a reference to the handle of the current process.
311pub fn process_self() -> Unowned<'static, Process> {
312    unsafe {
313        // zx_process_self() doesn't work correctly in jobs where multiple processes share
314        // the portion of their address space for global variables. Use thrd_get_zx_process() to
315        // return the correct value in that context. See https://fxbug.dev/42083701 for background.
316        let handle = thrd_get_zx_process();
317        Unowned::from_raw_handle(handle)
318    }
319}
320
321/// Get a reference to the handle of the current address space.
322pub fn vmar_root_self() -> Unowned<'static, Vmar> {
323    unsafe {
324        let handle = zx_vmar_root_self();
325        Unowned::from_raw_handle(handle)
326    }
327}
328
329/// Get a reference to the fuchsia.ldsvc.Loader channel.
330pub fn loader_svc() -> Result<NullableHandle, Status> {
331    unsafe {
332        let mut handle: zx_handle_t = 0;
333        let status = dl_clone_loader_service(&mut handle);
334        Status::ok(status)?;
335        Ok(NullableHandle::from_raw(handle))
336    }
337}
338
339/// Get a reference to the default `Job` provided to the process on startup.
340///
341/// This typically refers to the `Job` that is the immediate parent of the current
342/// process.
343///
344/// If the current process was launched as a Fuchsia Component, this `Job`
345/// will begin with no child processes other than the current process.
346pub fn job_default() -> Unowned<'static, Job> {
347    unsafe {
348        let handle = zx_job_default();
349        Unowned::from_raw_handle(handle)
350    }
351}
352
353/// Marker type for the UTC timeline.
354#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
355pub struct UtcTimeline;
356impl Timeline for UtcTimeline {}
357
358/// A UTC timestamp, measured in nanoseconds since Jan 1 1970.
359pub type UtcInstant = Instant<UtcTimeline>;
360
361/// A duration in the UTC timeline.
362pub type UtcDuration = Duration<UtcTimeline>;
363
364/// Special methods that are only valid for UtcDuration.
365pub trait UtcDurationExt {
366    /// Converts the reading of a duration on the UTC timeline to a reading on the boot timeline.
367    ///
368    /// This is "lossy" because durations are usually differences of
369    /// two Instants, and Boot time and UTC time mostly tick at the same rate.
370    /// However, they aren't required to tick in lock-step.
371    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline>;
372}
373
374impl UtcDurationExt for UtcDuration {
375    fn to_boot_lossy(&self) -> zx::Duration<BootTimeline> {
376        zx::Duration::from_nanos(self.into_nanos())
377    }
378}
379
380/// Special methods that are only valid for zx::BootDuration.
381pub trait BootDurationExt {
382    /// Converts the reading of a duration on the boot timeline to a reading on the UTC timeline.
383    ///
384    /// See notes alongside [UtcDurationExt::to_boot_lossy].
385    fn to_utc_lossy(&self) -> UtcDuration;
386}
387
388impl BootDurationExt for zx::BootDuration {
389    fn to_utc_lossy(&self) -> UtcDuration {
390        zx::Duration::from_nanos(self.into_nanos())
391    }
392}
393
394/// A clock that will return UTC timestamps.
395pub type UtcClock = Clock<BootTimeline, UtcTimeline>;
396
397/// Details of a UTC clock.
398pub type UtcClockDetails = ClockDetails<BootTimeline, UtcTimeline>;
399
400/// A transformation for the UTC clock.
401pub type UtcClockTransform = ClockTransformation<BootTimeline, UtcTimeline>;
402
403/// An update for the UTC clock.
404pub type UtcClockUpdate = ClockUpdate<BootTimeline, UtcTimeline>;
405
406fn utc_clock() -> Unowned<'static, UtcClock> {
407    zx_libc::utc::reference_get()
408}
409
410/// Duplicate the UTC `Clock` registered with the runtime.
411pub fn duplicate_utc_clock_handle(rights: Rights) -> Result<UtcClock, Status> {
412    utc_clock().duplicate_handle(rights)
413}
414
415/// Swaps the current process-global UTC clock with `new_clock`, returning
416/// the old clock on success.
417/// If `new_clock` is a valid handle but does not have the ZX_RIGHT_READ right,
418/// an error is returned and `new_clock` is dropped.
419pub fn swap_utc_clock_handle(new_clock: UtcClock) -> Result<UtcClock, Status> {
420    zx_libc::utc::reference_swap(new_clock)
421}
422
423/// SUBTLE, read the detailed documentation before using this function.
424///
425/// Reads time from the UTC `Clock` registered with the runtime.
426///
427/// # Subtleties
428///
429/// If you intend to use this timestamp in any user-facing capacity, you must
430/// ensure that a sensible thing is displayed to the user. Specifically:
431///
432/// * If you want to display the value, make sure to first check whether the
433///   UTC clock is even started. If not started, Fuchsia's UTC will [continuously
434///   indicate backstop time][bt]. This is a Fuchsia-only behavior, disregarding
435///   this behavior may present a confusing outcome to your user.
436/// * If you want to use this value in arithmetic calculations, never roll your
437///   own, especially if you are combining values from different timelines.
438/// * If you must use this value in arithmetic calculations and must combine
439///   values from different timelines, doublecheck that you are using the correct
440///   other timeline.
441/// * If in the end, you want to format the value as user readable date-time,
442///   never roll your own. Use the ICU library or equivalent chronological
443///   library of your choice.
444/// * **In testing only.** Due to above peculiarities, we often provide fake
445///   UTC clocks to test fixtures. This does not happen automatically, you must
446///   configure your test fixture to do this. When reading UTC time in a test
447///   especially if you want to compare across components, doublecheck that all
448///   components are using the same UTC clock by koid.
449///
450/// # Checking whether the clock is started
451///
452/// You can check this property in a few ways:
453///
454/// * You can call `utc_clock().get_details()`, which will return a `UtcClockDetails`.
455///   You can check that the clock rates reported are not zero. Requires
456///   `zx::Rights::INSPECT` on the clock handle for `get_details()`.
457/// * You can call `utc_clock().read()`, which will return an `UtcInstant` value.
458///   If the clock is not started, this will return a value that is exactly the
459///   value of UTC backstop time. This is more straightforward but requires you
460///   to read the clock and its details, which is more work than you may want.
461///
462/// # Panics
463///
464/// Panics if there is no UTC clock registered with the runtime or the registered handle does not
465/// have the required rights.
466///
467/// [bt]: https://fuchsia.dev/fuchsia-src/concepts/kernel/time/utc/behavior
468#[inline]
469pub fn utc_time() -> UtcInstant {
470    utc_clock().read().expect("Failed to read UTC clock")
471}
472
473#[cfg(test)]
474mod tests {
475    use super::*;
476
477    #[test]
478    fn handle_id() {
479        let mut randbuf = [0; 2];
480        for type_val in 0..0xFF {
481            if let Some(htype) = HandleType::from_u8(type_val as u8) {
482                zx::cprng_draw(&mut randbuf);
483                let arg = u16::from_le_bytes(randbuf);
484
485                let info = HandleInfo::new(htype, arg);
486                assert_eq!(info.handle_type(), htype);
487                assert_eq!(info.arg(), arg);
488
489                let info = HandleInfo::from(htype);
490                assert_eq!(info.handle_type(), htype);
491                assert_eq!(info.arg(), 0);
492            }
493        }
494    }
495
496    #[test]
497    fn handle_id_raw() {
498        assert_eq!(HandleInfo::new(HandleType::ProcessSelf, 0).as_raw(), 0x00000001);
499        assert_eq!(HandleInfo::new(HandleType::DirectoryRequest, 0).as_raw(), 0x0000003B);
500        assert_eq!(HandleInfo::new(HandleType::LdsvcLoader, 0xABCD).as_raw(), 0xABCD0010);
501        assert_eq!(HandleInfo::new(HandleType::User0, 0x1).as_raw(), 0x000100F0);
502        assert_eq!(HandleInfo::new(HandleType::User1, 0xABCD).as_raw(), 0xABCD00F1);
503        assert_eq!(HandleInfo::new(HandleType::User2, 0xFFFF).as_raw(), 0xFFFF00F2);
504    }
505
506    #[test]
507    fn handle_id_from_u32() {
508        assert_eq!(
509            HandleInfo::try_from(0x00000002).unwrap(),
510            HandleInfo::new(HandleType::ThreadSelf, 0)
511        );
512        assert_eq!(
513            HandleInfo::try_from(0x00040030).unwrap(),
514            HandleInfo::new(HandleType::FileDescriptor, 4)
515        );
516        assert_eq!(
517            HandleInfo::try_from(0x501C00F2).unwrap(),
518            HandleInfo::new(HandleType::User2, 0x501C)
519        );
520
521        // Non-zero unused byte
522        assert!(HandleInfo::try_from(0x00001100).is_err());
523        assert!(HandleInfo::try_from(0x00010101).is_err());
524        // Unknown handle type
525        assert!(HandleInfo::try_from(0x00000000).is_err());
526        assert!(HandleInfo::try_from(0x00000006).is_err());
527    }
528
529    #[test]
530    fn read_utc_time() {
531        utc_time();
532    }
533
534    #[test]
535    fn get_loader_svc() {
536        loader_svc().unwrap();
537    }
538}