blob: cdbc5ab7ecc76eb4ef5e7668bb0121821581aec9 [file] [log] [blame]
/* Copyright 2020 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.
*/
#include "mock_zircon_boot_ops.h"
#include <fcntl.h>
#include <zircon/hw/gpt.h>
#include "src/lib/digest/digest.h"
zx::status<fbl::Span<uint8_t>> MockZirconBootOps::GetPartitionSpan(const char* part_name,
size_t offset, size_t size) {
auto part = partitions_.find(part_name);
if (part == partitions_.end()) {
return zx::error(ZX_ERR_NOT_FOUND);
}
std::vector<uint8_t>& data = part->second;
if (offset > data.size() || data.size() - offset < size) {
return zx::error(ZX_ERR_OUT_OF_RANGE);
}
return zx::ok(fbl::Span<uint8_t>(data.data() + offset, size));
}
zx::status<> MockZirconBootOps::ReadFromPartition(const char* part_name, size_t offset, size_t size,
void* out) {
auto status = GetPartitionSpan(part_name, offset, size);
if (status.is_error()) {
return status.take_error();
}
memcpy(out, status.value().data(), status.value().size_bytes());
return zx::ok();
}
zx::status<> MockZirconBootOps::WriteToPartition(const char* part_name, size_t offset, size_t size,
const void* payload) {
auto status = GetPartitionSpan(part_name, offset, size);
if (status.is_error()) {
return status.take_error();
}
auto start = static_cast<const uint8_t*>(payload);
std::copy(start, start + size, status.value().data());
return zx::ok();
}
zx::status<size_t> MockZirconBootOps::GetPartitionSize(const char* part_name) {
auto part = partitions_.find(part_name);
if (part == partitions_.end()) {
return zx::error(ZX_ERR_NOT_FOUND);
}
return zx::ok(part->second.size());
}
void MockZirconBootOps::AddPartition(const char* name, size_t size) {
partitions_[name] = std::vector<uint8_t>(size, 0);
}
void MockZirconBootOps::Boot(zbi_header_t* image, size_t capacity, AbrSlotIndex slot) {
const uint8_t* start = reinterpret_cast<const uint8_t*>(image);
booted_image_ = std::vector<uint8_t>(start, start + capacity);
booted_slot_ = slot;
}
void MockZirconBootOps::Reboot(bool force_recovery) {
// For firmware A/B/R, we assume that device boots to slot according to metadata.
AbrOps ops = GetAbrOps();
firmware_slot_ =
force_recovery == kForceRecoveryOn ? kAbrSlotIndexR : AbrGetBootSlot(&ops, false, nullptr);
}
static bool ReadAbrMetadata(void* context, size_t size, uint8_t* buffer) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(context);
return dev->ReadFromPartition(GPT_DURABLE_BOOT_NAME, 0, size, buffer).is_ok();
}
static bool WriteAbrMetadata(void* context, const uint8_t* buffer, size_t size) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(context);
return dev->WriteToPartition(GPT_DURABLE_BOOT_NAME, 0, size, buffer).is_ok();
}
AbrOps MockZirconBootOps::GetAbrOps() {
return AbrOps{
.context = this,
.read_abr_metadata = ReadAbrMetadata,
.write_abr_metadata = WriteAbrMetadata,
};
}
void MockZirconBootOps::SetAddDeviceZbiItemsMethod(
std::function<bool(zbi_header_t*, size_t, AbrSlotIndex)> method) {
add_zbi_items_ = method;
}
void MockZirconBootOps::WriteRollbackIndex(size_t location, uint64_t rollback_index) {
rollback_index_[location] = rollback_index;
}
zx::status<uint64_t> MockZirconBootOps::ReadRollbackIndex(size_t location) const {
auto iter = rollback_index_.find(location);
if (iter == rollback_index_.end()) {
return zx::error(ZX_ERR_NOT_FOUND);
}
return zx::ok(iter->second);
}
void MockZirconBootOps::SetPermanentAttributes(
const AvbAtxPermanentAttributes& permanent_attribute) {
permanent_attributes_ = permanent_attribute;
}
AvbAtxPermanentAttributes MockZirconBootOps::GetPermanentAttributes() {
return permanent_attributes_;
}
bool MockZirconBootOps::GetPartitionSize(ZirconBootOps* ops, const char* part, size_t* out) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
auto status = dev->GetPartitionSize(part);
if (status.is_error()) {
return 0;
}
*out = status.value();
return true;
}
bool MockZirconBootOps::ReadFromPartition(ZirconBootOps* ops, const char* part, size_t offset,
size_t size, void* dst, size_t* read_size) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
if (auto status = dev->ReadFromPartition(part, offset, size, static_cast<uint8_t*>(dst));
status.is_error()) {
return false;
}
*read_size = size;
return true;
}
bool MockZirconBootOps::WriteToPartition(ZirconBootOps* ops, const char* part, size_t offset,
size_t size, const void* src, size_t* write_size) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
if (auto status = dev->WriteToPartition(part, offset, size, static_cast<const uint8_t*>(src));
status.is_error()) {
return false;
}
*write_size = size;
return true;
}
bool MockZirconBootOps::GetFirmwareSlot(ZirconBootOps* ops, AbrSlotIndex* out_slot) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
*out_slot = dev->GetFirmwareSlot();
return true;
}
void MockZirconBootOps::Reboot(ZirconBootOps* ops, bool force_recovery) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
dev->Reboot(force_recovery);
}
void MockZirconBootOps::Boot(ZirconBootOps* ops, zbi_header_t* image, size_t capacity,
AbrSlotIndex slot) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
dev->Boot(image, capacity, slot);
}
bool MockZirconBootOps::AddDeviceZbiItems(ZirconBootOps* zb_ops, zbi_header_t* image,
size_t capacity, AbrSlotIndex slot) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(zb_ops->context);
return dev->add_zbi_items_(image, capacity, slot);
}
// Avb related operation
bool MockZirconBootOps::ReadRollbackIndex(ZirconBootOps* ops, size_t rollback_index_location,
uint64_t* out_rollback_index) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
auto status = dev->ReadRollbackIndex(rollback_index_location);
if (status.is_error()) {
return false;
}
*out_rollback_index = status.value();
return true;
}
bool MockZirconBootOps::WriteRollbackIndex(ZirconBootOps* ops, size_t rollback_index_location,
uint64_t rollback_index) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
dev->WriteRollbackIndex(rollback_index_location, rollback_index);
return true;
}
bool MockZirconBootOps::ReadIsDeivceLocked(ZirconBootOps* ops, bool* out_is_locked) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
*out_is_locked = dev->GetDeviceLockStatus() == MockZirconBootOps::LockStatus::kLocked;
return true;
}
bool MockZirconBootOps::ReadPermanentAttributes(ZirconBootOps* ops,
AvbAtxPermanentAttributes* attribute) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
*attribute = dev->GetPermanentAttributes();
return true;
}
bool MockZirconBootOps::ReadPermanentAttributesHash(ZirconBootOps* ops,
uint8_t hash[AVB_SHA256_DIGEST_SIZE]) {
MockZirconBootOps* dev = static_cast<MockZirconBootOps*>(ops->context);
auto attributes = dev->GetPermanentAttributes();
digest::Digest hasher;
const uint8_t* result = hasher.Hash(static_cast<void*>(&attributes), sizeof(attributes));
memcpy(hash, result, AVB_SHA256_DIGEST_SIZE);
return true;
}
ZirconBootOps MockZirconBootOps::GetZirconBootOps() {
ZirconBootOps zircon_boot_ops;
zircon_boot_ops.context = this;
zircon_boot_ops.read_from_partition = ReadFromPartition;
zircon_boot_ops.write_to_partition = WriteToPartition;
zircon_boot_ops.get_firmware_slot = GetFirmwareSlot;
zircon_boot_ops.reboot = Reboot;
zircon_boot_ops.boot = Boot;
zircon_boot_ops.add_zbi_items = AddDeviceZbiItems;
zircon_boot_ops.verified_boot_get_partition_size = nullptr;
zircon_boot_ops.verified_boot_read_rollback_index = nullptr;
zircon_boot_ops.verified_boot_write_rollback_index = nullptr;
zircon_boot_ops.verified_boot_read_is_device_locked = nullptr;
zircon_boot_ops.verified_boot_read_permanent_attributes = nullptr;
zircon_boot_ops.verified_boot_read_permanent_attributes_hash = nullptr;
return zircon_boot_ops;
}
ZirconBootOps MockZirconBootOps::GetZirconBootOpsWithAvb() {
ZirconBootOps zircon_boot_ops = GetZirconBootOps();
zircon_boot_ops.verified_boot_get_partition_size = GetPartitionSize;
zircon_boot_ops.verified_boot_read_rollback_index = ReadRollbackIndex;
zircon_boot_ops.verified_boot_write_rollback_index = WriteRollbackIndex;
zircon_boot_ops.verified_boot_read_is_device_locked = ReadIsDeivceLocked;
zircon_boot_ops.verified_boot_read_permanent_attributes = ReadPermanentAttributes;
zircon_boot_ops.verified_boot_read_permanent_attributes_hash = ReadPermanentAttributesHash;
return zircon_boot_ops;
}