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}