Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 405f4d35 authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge "bootloader_message: Add helpers for handling IBootControl MergeStatus."

parents 6105aa1a cf8427af
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -62,5 +62,28 @@ class BootControl {
  unsigned int current_slot_ = 0;
};

// Helper functions to write the Virtual A/B merge status message. These are
// separate because BootControl uses bootloader_control_ab in vendor space,
// whereas the Virtual A/B merge status is in system space. A HAL might not
// use bootloader_control_ab, but may want to use the AOSP method of maintaining
// the merge status.

// If the Virtual A/B message has not yet been initialized, then initialize it.
// This should be called when the BootControl HAL first loads.
//
// If the Virtual A/B message in misc was already initialized, true is returned.
// If initialization was attempted, but failed, false is returned, and the HAL
// should fail to load.
bool InitMiscVirtualAbMessageIfNeeded();

// Save the current merge status as well as the current slot.
bool SetMiscVirtualAbMergeStatus(unsigned int current_slot,
                                 android::hardware::boot::V1_1::MergeStatus status);

// Return the current merge status. If the saved status is SNAPSHOTTED but the
// slot hasn't changed, the status returned will be NONE.
bool GetMiscVirtualAbMergeStatus(unsigned int current_slot,
                                 android::hardware::boot::V1_1::MergeStatus* status);

}  // namespace bootable
}  // namespace android
+71 −9
Original line number Diff line number Diff line
@@ -232,6 +232,10 @@ bool BootControl::Init() {
    UpdateAndSaveBootloaderControl(device.c_str(), &boot_ctrl);
  }

  if (!InitMiscVirtualAbMessageIfNeeded()) {
    return false;
  }

  num_slots_ = boot_ctrl.nb_slot;
  return true;
}
@@ -335,18 +339,15 @@ bool BootControl::IsValidSlot(unsigned int slot) {
}

bool BootControl::SetSnapshotMergeStatus(MergeStatus status) {
  bootloader_control bootctrl;
  if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;

  bootctrl.merge_status = (unsigned int)status;
  return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
  return SetMiscVirtualAbMergeStatus(current_slot_, status);
}

MergeStatus BootControl::GetSnapshotMergeStatus() {
  bootloader_control bootctrl;
  if (!LoadBootloaderControl(misc_device_, &bootctrl)) return MergeStatus::UNKNOWN;

  return (MergeStatus)bootctrl.merge_status;
  MergeStatus status;
  if (!GetMiscVirtualAbMergeStatus(current_slot_, &status)) {
    return MergeStatus::UNKNOWN;
  }
  return status;
}

const char* BootControl::GetSuffix(unsigned int slot) {
@@ -356,5 +357,66 @@ const char* BootControl::GetSuffix(unsigned int slot) {
  return kSlotSuffixes[slot];
}

bool InitMiscVirtualAbMessageIfNeeded() {
  std::string err;
  misc_virtual_ab_message message;
  if (!ReadMiscVirtualAbMessage(&message, &err)) {
    LOG(ERROR) << "Could not read merge status: " << err;
    return false;
  }

  if (message.version == MISC_VIRTUAL_AB_MESSAGE_VERSION) {
    // Already initialized.
    return true;
  }

  message = {};
  message.version = MISC_VIRTUAL_AB_MESSAGE_VERSION;
  if (!WriteMiscVirtualAbMessage(message, &err)) {
    LOG(ERROR) << "Could not write merge status: " << err;
    return false;
  }
  return true;
}

bool SetMiscVirtualAbMergeStatus(unsigned int current_slot,
                                 android::hardware::boot::V1_1::MergeStatus status) {
  std::string err;
  misc_virtual_ab_message message;

  if (!ReadMiscVirtualAbMessage(&message, &err)) {
    LOG(ERROR) << "Could not read merge status: " << err;
    return false;
  }

  message.merge_status = static_cast<uint8_t>(status);
  message.source_slot = current_slot;
  if (!WriteMiscVirtualAbMessage(message, &err)) {
    LOG(ERROR) << "Could not write merge status: " << err;
    return false;
  }
  return true;
}

bool GetMiscVirtualAbMergeStatus(unsigned int current_slot,
                                 android::hardware::boot::V1_1::MergeStatus* status) {
  std::string err;
  misc_virtual_ab_message message;

  if (!ReadMiscVirtualAbMessage(&message, &err)) {
    LOG(ERROR) << "Could not read merge status: " << err;
    return false;
  }

  // If the slot reverted after having created a snapshot, then the snapshot will
  // be thrown away at boot. Thus we don't count this as being in a snapshotted
  // state.
  *status = static_cast<MergeStatus>(message.merge_status);
  if (*status == MergeStatus::SNAPSHOTTED && current_slot == message.source_slot) {
    *status = MergeStatus::NONE;
  }
  return true;
}

}  // namespace bootable
}  // namespace android
+43 −0
Original line number Diff line number Diff line
@@ -292,6 +292,49 @@ bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset,
                              err);
}

static bool ValidateSystemSpaceRegion(size_t offset, size_t size, std::string* err) {
  if (size <= SYSTEM_SPACE_SIZE_IN_MISC && offset <= (SYSTEM_SPACE_SIZE_IN_MISC - size)) {
    return true;
  }
  *err = android::base::StringPrintf("Out of bound access (offset %zu size %zu)", offset, size);
  return false;
}

static bool ReadMiscPartitionSystemSpace(void* data, size_t size, size_t offset, std::string* err) {
  if (!ValidateSystemSpaceRegion(offset, size, err)) {
    return false;
  }
  auto misc_blk_device = get_misc_blk_device(err);
  if (misc_blk_device.empty()) {
    return false;
  }
  return read_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
                             err);
}

static bool WriteMiscPartitionSystemSpace(const void* data, size_t size, size_t offset,
                                          std::string* err) {
  if (!ValidateSystemSpaceRegion(offset, size, err)) {
    return false;
  }
  auto misc_blk_device = get_misc_blk_device(err);
  if (misc_blk_device.empty()) {
    return false;
  }
  return write_misc_partition(data, size, misc_blk_device, SYSTEM_SPACE_OFFSET_IN_MISC + offset,
                              err);
}

bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err) {
  return ReadMiscPartitionSystemSpace(message, sizeof(*message),
                                      offsetof(misc_system_space_layout, virtual_ab_message), err);
}

bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err) {
  return WriteMiscPartitionSystemSpace(&message, sizeof(message),
                                       offsetof(misc_system_space_layout, virtual_ab_message), err);
}

extern "C" bool write_reboot_bootloader(void) {
  std::string err;
  return write_reboot_bootloader(&err);
+26 −0
Original line number Diff line number Diff line
@@ -185,6 +185,28 @@ static_assert(sizeof(struct bootloader_control) ==
              "struct bootloader_control has wrong size");
#endif

// Holds Virtual A/B merge status information. Current version is 1. New fields
// must be added to the end.
struct misc_virtual_ab_message {
  uint8_t version;
  uint8_t merge_status;  // IBootControl 1.1, MergeStatus enum.
  uint8_t source_slot;   // Slot number when merge_status was written.
  uint8_t reserved[61];
} __attribute__((packed));

#define MISC_VIRTUAL_AB_MESSAGE_VERSION 1

#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
static_assert(sizeof(struct misc_virtual_ab_message) == 64,
              "struct misc_virtual_ab_message has wrong size");
#endif

// This struct is not meant to be used directly, rather, it is to make
// computation of offsets easier. New fields must be added to the end.
struct misc_system_space_layout {
  misc_virtual_ab_message virtual_ab_message;
} __attribute__((packed));

#ifdef __cplusplus

#include <string>
@@ -247,6 +269,10 @@ bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::s
// offset is in relative to the start of the vendor space.
bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err);

// Read or write the Virtual A/B message from system space in /misc.
bool ReadMiscVirtualAbMessage(misc_virtual_ab_message* message, std::string* err);
bool WriteMiscVirtualAbMessage(const misc_virtual_ab_message& message, std::string* err);

#else

#include <stdbool.h>