blob: 2de0909c0c4ba288282e9dd1e930928a24aa5539 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.paver;
using fuchsia.hardware.block;
using fuchsia.hardware.block.volume;
using fuchsia.io;
using fuchsia.mem;
using zx;
/// Describes the version of an asset.
type Configuration = strict enum {
A = 1;
B = 2;
RECOVERY = 3;
};
/// Describes assets which may be updated. Each asset has 3 versions, each tied to a particular
/// configuration.
type Asset = strict enum {
/// Zircon Boot Image (ZBI) containing the kernel image as well as bootfs.
KERNEL = 1;
/// Metadata used for verified boot purposes.
VERIFIED_BOOT_METADATA = 2;
};
/// Set of states configuration may be in.
type ConfigurationStatus = strict enum {
/// Bootable and health checked.
HEALTHY = 1;
/// Bootable but not yet marked healthy.
PENDING = 2;
/// Unbootable.
UNBOOTABLE = 3;
};
type ReadInfo = struct {
/// Offset into VMO where read data starts.
offset zx.off;
/// Size of read data.
size uint64;
};
type ReadResult = strict union {
/// Error encountered while reading data.
1: err zx.status;
/// End of file reached.
2: eof bool;
/// Information about location of successfully read data within pre-registered VMO.
3: info ReadInfo;
};
type WriteFirmwareResult = strict union {
/// The result status if a write was attempted.
1: status zx.status;
/// True if a write was not attempted due to unsupported firmware. This could
/// be either unsupported content type or unsupported A/B configuration.
///
/// Callers must not treat this as a fatal error, but instead ignore it and
/// continue to update the device. This is important to be able to add new
/// items to an update package without breaking updates on older devices.
2: unsupported bool;
};
/// Protocol for streaming the FVM payload.
protocol PayloadStream {
/// Registers a VMO to stream into.
///
/// This can be called once per PayloadStream.
/// Any subsequent calls will return ZX_ERR_ALREADY_BOUND.
RegisterVmo(resource struct {
vmo zx.handle:VMO;
}) -> (struct {
status zx.status;
});
/// Reads data into the pre-registered vmo.
ReadData() -> (struct {
result ReadResult;
});
};
@discoverable
protocol Paver {
/// Attempts to auto-discover the data sink where assets and volumes will get paved to.
/// On devices with GPT, the partition must have a valid FVM partition in order for
/// auto-discovery to find it. If multiple devices are found suitable, error is returned.
///
/// `data_sink` will be closed on error, with an epitaph provided on failure reason.
FindDataSink(resource struct {
data_sink server_end:DataSink;
});
/// Provide a block device to use as a data sink. Assets and volumes will be paved to
/// partitions within this block device.
///
/// It assumes that channel backing `block_device` also implements `fuchsia.io.Node` for now.
///
/// `data_sink` will be closed on error, with an epitaph provided on failure reason.
UseBlockDevice(resource struct {
block_device client_end:fuchsia.hardware.block.Block;
data_sink server_end:DynamicDataSink;
});
/// Attempts to auto-discover the boot manager.
///
/// `boot_manager` will be closed on error, with an epitaph provided on failure reason.
/// ZX_ERR_NOT_SUPPORTED indicates lack of support and configuration A is always booted from.
FindBootManager(resource struct {
boot_manager server_end:BootManager;
});
/// Find Sysconfig service.
FindSysconfig(resource struct {
sysconfig server_end:Sysconfig;
});
};
/// Protocol for reading and writing boot partitions.
///
/// A note on DataSink.Flush() (and BootManager.Flush() coming after):
///
/// Some platforms may implement the Flush() fidl interface of DataSink/BootManager. For these
/// platforms, the update of some system images and A/B configuration is not persisted to storage
/// immediately and only buffered internally when the write fidl interfaces return. The data is
/// guaranteed to be persisted only after the Flush() interfaces are called.
///
/// If not implemented, Flush() is no-op and system images and A/B configuration will be persisted
/// to storage immediately after the write fidl interfaces return.
///
/// For all platforms, it is guaranteed that if DataSink.Flush() is implemented, BootManager.Flush()
/// is implemented as well. Therefore, in the context of system update, both of the following update
/// sequences are safe in the sense that, new A/B configuration will not be persisted to storage
/// before new system images.
/// DataSink.Write[...]() --> DataSink.Flush() --> BootManager.Set[...]() --> BootManager.Flush()
/// DataSink.Write[...]() --> BootManager.Set[...]() --> DataSink.Flush() --> BootManager.Flush()
protocol DataSink {
/// Reads partition corresponding to `configuration` and `asset` into a
/// vmo and returns it.
ReadAsset(struct {
configuration Configuration;
asset Asset;
}) -> (resource struct {
asset fuchsia.mem.Buffer;
}) error zx.status;
/// Writes partition corresponding to `configuration` and `asset` with data from `payload`.
/// `payload` may need to be resized to the partition size, so the provided vmo must have
/// been created with `ZX_VMO_RESIZABLE` or must be a child VMO that was created with
/// `ZX_VMO_CHILD_RESIZABLE`. Will zero out rest of the partition if `payload` is smaller
/// than the size of the partition being written.
///
///
/// Returns `ZX_ERR_INVALID_ARGS` if `configuration` specifies active configuration.
WriteAsset(resource struct {
configuration Configuration;
asset Asset;
payload fuchsia.mem.Buffer;
}) -> (struct {
status zx.status;
});
/// Writes firmware data from `payload`.
///
/// `configuration` represents the A/B/R configuration. For platforms that do not support
/// firmware A/B/R, the parameter will be ignored by the underlying device-specific logic .
///
/// `type` is a device-specific string identifying the payload contents,
/// used to select the proper paving logic. For example, a device with
/// multiple bootloader stages might send them as separate calls to
/// `WriteFirmware()`, differentiated by `type`. An empty string
/// indicates the default type.
///
/// `payload` may need to be resized to the partition size, so the provided
/// vmo must have been created with `ZX_VMO_RESIZABLE` or must be a child
/// VMO that was created with `ZX_VMO_CHILD_RESIZABLE`.
WriteFirmware(resource struct {
configuration Configuration;
type string:256;
payload fuchsia.mem.Buffer;
}) -> (struct {
result WriteFirmwareResult;
});
/// Writes FVM with data from streamed via `payload`. This potentially affects all
/// configurations.
WriteVolumes(resource struct {
payload client_end:PayloadStream;
}) -> (struct {
status zx.status;
});
// TODO(fxbug.dev/45606): transition users to `WriteFirmware()` and delete this.
/// Writes bootloader partition with data from `payload`.
///
/// `payload` may need to be resized to the partition size, so the provided vmo must have
/// been created with `ZX_VMO_RESIZABLE` or must be a child VMO that was created with
/// `ZX_VMO_CHILD_RESIZABLE`.
@deprecated
WriteBootloader(resource struct {
payload fuchsia.mem.Buffer;
}) -> (struct {
status zx.status;
});
/// Writes /data/`filename` with data from `payload`. Overwrites file if it already exists.
WriteDataFile(resource struct {
filename string:fuchsia.io.MAX_PATH;
payload fuchsia.mem.Buffer;
}) -> (struct {
status zx.status;
});
/// Wipes the FVM partition from the device. Should not be confused with factory reset, which
/// is less intrusive. The result is that the default FVM volumes are re-created, but empty.
///
/// Notable use cases include recovering from corrupted FVM as well as setting device to a
/// "clean" state for automation.
///
/// If `block_device` is not provided, the paver will perform a search for the the FVM.
/// If multiple block devices have valid GPT, `block_device` can be provided to specify
/// which one to target. It assumed that channel backing `block_device` also implements
/// `fuchsia.io.Node` for now.
///
/// On success, returns a channel to the initialized FVM volume.
WipeVolume() -> (resource struct {
volume client_end:fuchsia.hardware.block.volume.VolumeManager;
}) error zx.status;
/// Flush all previously buffered writes to persistent storage.
Flush() -> (struct {
status zx.status;
});
};
/// Specialized DataSink with dynamic partition tables.
protocol DynamicDataSink {
compose DataSink;
/// Initializes partitions on given block device.
InitializePartitionTables() -> (struct {
status zx.status;
});
/// Wipes all entries from the partition table of the specified block device.
/// Currently only supported on devices with a GPT.
///
/// *WARNING*: This API may destructively remove non-fuchsia maintained partitions from
/// the block device.
WipePartitionTables() -> (struct {
status zx.status;
});
};
/// Protocol for managing boot configurations.
///
/// All functions will first check the A/B/R metadata and reset it to
/// the default state if it's invalid.
/// The new configuration is not guaranteed to persist to storage before Flush() is called.
protocol BootManager {
/// Queries the configuration the system is currently running.
///
/// Returns `ZX_ERR_NOT_SUPPORTED` if the `zvb.current_slot` boot argument cannot be read
/// or is an unexpected value.
QueryCurrentConfiguration() -> (struct {
configuration Configuration;
}) error zx.status;
/// Queries the configuration which will be used as the default boot choice on a normal cold
/// boot, which may differ from the currently running configuration. `Configuration::RECOVERY`
/// should never be active.
///
/// Returns `ZX_ERR_NOT_SUPPORTED` if `Configuration.RECOVERY` is active.
QueryActiveConfiguration() -> (struct {
configuration Configuration;
}) error zx.status;
/// Queries the configuration that was last explicitly marked as active by
/// SetConfigurationActive(). The result is not affected by the current status of the slot.
///
/// A newly updated slot is typically marked as active immediately. Therefore this interface
/// can be used as a way to identify the newest slot.
///
/// Returns `ZX_ERR_IO` if fail to load abr metadata. Returns `ZX_ERR_INTERNAL` if invalid
/// slot index is returned by libabr routine.
QueryConfigurationLastSetActive() -> (struct {
configuration Configuration;
}) error zx.status;
/// Queries status of `configuration`.
///
/// Returns `ZX_ERR_INVALID_ARGS` if `Configuration.RECOVERY` is passed in via `configuration`.
QueryConfigurationStatus(struct {
configuration Configuration;
}) -> (struct {
status ConfigurationStatus;
}) error zx.status;
/// Updates persistent metadata identifying which configuration should be selected as 'primary'
/// for booting purposes. Should only be called after `KERNEL` as well as optional
/// `VERIFIED_BOOT_METADATA` assets for specified `configuration` were written successfully.
///
/// Returns `ZX_ERR_INVALID_ARGS` if `Configuration.RECOVERY` is passed in via `configuration`.
SetConfigurationActive(struct {
configuration Configuration;
}) -> (struct {
status zx.status;
});
/// Updates persistent metadata identifying whether `configuration` is bootable.
/// Should only be called in the following situations:
/// * Before `KERNEL` as well as optional `VERIFIED_BOOT_METADATA` assets for specified
/// `configuration` are written.
/// * After successfully booting from a new configuration and marking it healthy. This method
/// would be then called on the old configuration.
/// * After "successfully" booting from a new configuration, but encountering an unrecoverable
/// error during health check. This method would be then called on the new configuration.
///
/// If the configuration is unbootable, no action is taken.
///
/// Returns `ZX_ERR_INVALID_ARGS` if `Configuration.RECOVERY` is passed in via `configuration`.
SetConfigurationUnbootable(struct {
configuration Configuration;
}) -> (struct {
status zx.status;
});
/// Updates persistent metadata to mark a [`fuchsia.paver/Configuration`]
/// as successful.
///
/// This function is typically used by the OS update system after having
/// confirmed that the configuration works as intended and the "rollback to
/// previous slot" logic is not needed anymore.
///
/// Compatibility between the newly successful configuration and the other
/// configuration is unknown. Even if the other configuration was
/// successful at one point, it may no longer be. This function adds a
/// success mark to the given configuration but also removes any success
/// mark on the other.
///
/// If `configuration` is unbootable or is
/// [`fuchsia.paver/Configuration.RECOVERY`], `response` will be
/// `ZX_ERR_INVALID_ARGS`.
///
/// + request `configuration` the `Configuration` to mark as healthy. Must
/// not be `RECOVERY`.
/// - response `status` a zx_status value indicating success or failure.
SetConfigurationHealthy(struct {
configuration Configuration;
}) -> (struct {
status zx.status;
});
/// Flush all previously buffered writes to persistent storage.
Flush() -> (struct {
status zx.status;
});
};
/// Protocol that provides access to sysconfig-data sub-partition in sysconfig partition.
/// The main user of the protocol are pkg-solver and system update-checker, which need to
/// read/write sysconfig-data channel.
protocol Sysconfig {
/// Read from the sub-partition
Read() -> (resource struct {
data fuchsia.mem.Buffer;
}) error zx.status;
/// Writes to the sub-partition
Write(resource struct {
payload fuchsia.mem.Buffer;
}) -> (struct {
status zx.status;
});
/// Get sub-partition size.
GetPartitionSize() -> (struct {
size uint64;
}) error zx.status;
/// Flush all previously buffered data to persistent storage.
Flush() -> (struct {
status zx.status;
});
/// Wipe all data in the sub-partition (write 0 to all bytes).
Wipe() -> (struct {
status zx.status;
});
};