RFC-0260: Kernel Boot Time Support

RFC-0260: Kernel Boot Time Support
StatusAccepted
Areas
  • Kernel
Description

Enumerates the Zircon API changes needed to support the boot timeline.

Issues
Gerrit change
Authors
Reviewers
Date submitted (year-month-day)2024-06-14
Date reviewed (year-month-day)2024-09-25

Problem Statement

The Monotonic Clock Suspension and the Boot Timeline RFC stated that Fuchsia must provide a boot timeline that reports the amount of time elapsed since boot, including any time spent in suspend-to-idle. That RFC mentioned that there would need to be kernel changes but did not specify exactly what those were.

Summary

This RFC describes the syscalls and API changes needed to support the boot timeline in the Zircon kernel.

Stakeholders

Facilitator: jamesr@google.com

Reviewers:

  • adamperry@google.com
  • andresoportus@google.com
  • fmil@google.com
  • gkalsi@google.com
  • harshanv@google.com
  • johngro@google.com
  • maniscalco@google.com
  • mcgrathr@google.com
  • miguelfrde@google.com
  • tgales@google.com
  • tmandry@google.com

Socialization:

This RFC was socialized as a set of several documents that each discussed various portions of the design. These documents were sent to and iterated on by the kernel team and by various people across the org.

Requirements

The kernel MUST support:

  1. Reading the current value of the boot timeline.
  2. Creating custom clocks using the boot timeline as the reference timeline.
  3. Creating timers on the boot timeline, though timers that can wake the system are explicitly left for a future RFC.
  4. Reporting the timestamp of log messages and crashlogs in the boot timeline.

Note that we do not plan to support other time related syscalls, such as object or port waits, on the boot timeline, as we have not identified a motivating use case to do so. We will revisit this decision in future RFCs if a use case arises.

Design

Introducing New Time Type Aliases in the Zircon API

Zircon has several types for representing time today:

  1. zx_time_t: Represents a point in time in nanoseconds. Generally this point is sampled from the monotonic timeline, but not always; zx_clock_read, for example, also returns a zx_time_t but is not on the monotonic timeline.
  2. zx_duration_t: Represents either an amount of time or a distance between two points in time. This quantity has no concrete association with a timeline, but is always in units of nanoseconds.
  3. zx_ticks_t: Represents either a point or a duration of time in platform specific ticks.

These are all aliases of int64_t, which means that the compiler provides no type checking for any of these entities. They exist solely to improve the readability of code. Reusing these types for the boot timeline would significantly degrade the readability of code working with timestamps, as developers would not be able to easily differentiate between timestamps on different timelines.

Therefore, new type aliases will be introduced with the following structure:

zx_<kind>_<timeline>_[units_]t

where:

  • kind is either instant or duration.
  • timeline is either mono or boot.
  • units is either ticks or omitted, in which case the unit is understood to be nanoseconds. The vast majority of code uses time in nanoseconds, so this omission makes the common case a bit easier to type.

Most existing uses of zx_time_t will be migrated to use zx_instant_mono_t, and most existing uses of zx_duration_t will be migrated to use zx_duration_mono_t. Uses of zx_ticks_t will be evaluated and migrated on a case-by-case basis.

The existing aliases will not be removed, and will be used when an ambiguous type is required (for example, zx_clock_read will still return zx_time_t). It is the aim of the kernel team to remove these ambiguous types in the long term, but the exact nature of how that happens is out of scope and left to future RFCs.

Userspace Types for Time

While the new type aliases for time described in the preceding section will improve code clarity and readability in the Zircon APIs, they do not provide compiler-enforced type safety. This type safety will instead be provided by the userspace syscall wrapper libraries found in the Rust bindings for Zircon and the C++ libzx library, both of which will need to be extended with the syscalls introduced in and modified by this RFC. Userspace code should prefer to use these libraries whenever possible.

Appropriate APIs for strong typing need careful design work in each language to be idiomatic and easy to use in practice. This won't be rushed and its completion for each language won't be required for the completion of the type migration in the C API detailed in the preceding section.

Reading the Current Boot Time

Two syscalls will be introduced to allow usermode to read the current value of the boot timeline:

zx_instant_boot_t zx_clock_get_boot(void);
zx_instant_boot_ticks_t zx_ticks_get_boot(void);

The first will report the time in nanoseconds, and the second will report the time in platform ticks. This mirrors the corresponding syscalls on the monotonic timeline.

Note that the ratio of ticks to seconds will be the same for the monotonic and the boot timelines, meaning that the result of zx_ticks_per_second can be used to convert the results of both zx_ticks_get and zx_ticks_get_boot to seconds.

Creating Custom Clocks

Usermode clocks are created using the zx_clock_create syscall. The syscall already accepts an options parameter, meaning we do not need to change the function signature.

Instead, a new options flag called ZX_CLOCK_OPT_BOOT will be introduced that instructs the newly created clock to use the boot timeline as its reference timeline.

The timeline property of clocks (monotonic and boot) will be immutable, meaning that a clock cannot switch timelines once created.

Renaming Fields in zx_clock_details

The zx_clock_details_v1_t struct contains two fields that store the transformation from the monotonic timeline to the clock's synthetic timeline:

typedef struct zx_clock_details_v1 {
  // other fields
  zx_clock_transformation_t ticks_to_synthetic;
  zx_clock_transformation_t mono_to_synthetic;
  // other fields
} zx_clock_details_v1_t;

These fields will be renamed to highlight the fact that they will now store the transformation from the reference timeline to the clock's synthetic timeline:

typedef struct zx_clock_details_v1 {
  // other fields
  zx_clock_transformation_t reference_ticks_to_synthetic;
  zx_clock_transformation_t reference_to_synthetic;
  // other fields
} zx_clock_details_v1_t;

A quick scan of the code base shows very few users of these fields, and none of those users are outside of fuchsia.git. Therefore, an in-place rename should be relatively straightforward.

Creating Boot Timers

Usermode timers are created using the zx_timer_create syscall. This syscall conveniently accepts a clock_id parameter that dictates the timeline the timer should operate on.

Thus, a new clock_id value called ZX_CLOCK_BOOT will be introduced that instructs the newly created timer to operate on the boot timeline.

Similar to clocks, the timeline property of timers will be immutable, meaning that a timer cannot switch timelines once created.

Note that zx_timer_set will be reused to set boot timers. Because this syscall takes as input both monotonic and boot deadlines, its parameter type will remain zx_time_t.

Adding the clock_id to zx_info_timer_t

Users can call zx_object_get_info with the ZX_INFO_TIMER topic to get information about a timer handle. The resulting zx_info_timer_t struct will be modified to include the clock_id the timer was created with.

Normally, this would require some struct evolution, but in this case the struct already has 4 bytes of padding, which is just enough space to hold our clock_id, which is stored as a 4 byte zx_clock_t.

Updating timestamps in Zircon structures

There are several timestamps in Zircon structures that report monotonic time today, but should switch to using boot time once it is available.

Note that timestamps that continue to report monotonic time will not be changed functionally but will have their types updated to zx_instant_mono_t as described in the type alias section above.

zx_log_record_t Timestamps

zx_log_record_t is a struct exposed by Zircon that describes the structure of a message in the debuglog. This struct contains a timestamp field that is a zx_time_t and is a point on ZX_CLOCK_MONOTONIC. This will be updated to be a zx_instant_boot_t and therefore will be a point on ZX_CLOCK_BOOT.

Crashlog Uptime Timestamp

The crashlog currently reports an uptime field that utilizes monotonic time. Seeing as monotonic time does not include periods of suspension, this should be modified to use boot time and its type should be updated to zx_instant_boot_t.

Implementation

The changes to the kernel API will be implemented first, with each category of change (reading time, clocks, timers, etc.) separated into different CLs.

These changes (which should be relatively small) will be followed by slightly larger changes to add boot time support to our Rust and C++ syscall wrapper libraries. These changes will proceed in two phases:

  1. Phase 1 will add support for the syscalls added or modified by this RFC. This will require some modification of the types used, but this phase will focus mainly on functional changes.
  2. Phase 2 will add more robust type enforcement for time types. This will be done after Phase 1 as it may take longer to iron out the precise type structure needed in each language.

Performance

The syscall modifications needed to support boot time are purely additive, and therefore should not change any existing performance characteristics of the system.

Similarly, updating the timestamp field of various structures in Zircon to use the boot timeline should have no impact on performance, as computing the boot time is no more expensive than computing the monotonic time.

Ergonomics

Users of the time syscalls and types may have to be aware of the fact that there are now multiple timelines supported by the kernel. However, most programs should be able to just use monotonic time.

Backwards Compatibility

Except for the semantic change to the timeline of the log record timestamp, these changes are source and binary backwards compatible.

However, many pieces of existing code may need to switch from using the monotonic timeline to the boot timeline to preserve correctness. Please refer to the Monotonic Clock Suspension and the Boot Timeline RFC for more information on how we plan to handle this.

Security considerations

We do not anticipate any security ramifications from this proposal. For more information on why this is the case, please refer to the security section of the Monotonic Clock Suspension and the Boot Timeline RFC.

Privacy considerations

This proposal does not impact system privacy, since adding boot time support to the kernel does not involve any sort of data collection.

Testing

The core tests will be modified to exercise both the new syscalls and the modifications to the existing syscalls.

Documentation

All of the Zircon API modifications described above will need to be documented. Concretely, this means:

  1. Documenting all of the new type aliases and updating the docs for the existing type aliases.
  2. Documenting the newly added syscalls.
  3. Documenting the new flags added to existing syscalls.
  4. Documenting the timeline of the various timestamps that were updated.

In addition, we should update our clock documentation on fuchsia.dev to highlight how zx_time_t is not tethered to a particular timeline.

Prior art and references