summaryrefslogtreecommitdiff
path: root/bootctrl/BootControlShared.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bootctrl/BootControlShared.cpp')
-rw-r--r--bootctrl/BootControlShared.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/bootctrl/BootControlShared.cpp b/bootctrl/BootControlShared.cpp
new file mode 100644
index 0000000..193ddea
--- /dev/null
+++ b/bootctrl/BootControlShared.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bootcontrolhal"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <bootloader_message/bootloader_message.h>
+
+#include "BootControlShared.h"
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_1 {
+namespace implementation {
+
+using android::base::unique_fd;
+using android::hardware::boot::V1_1::MergeStatus;
+
+constexpr off_t kBootloaderControlOffset = offsetof(bootloader_message_ab, slot_suffix);
+
+static uint32_t CRC32(const uint8_t *buf, size_t size) {
+ static uint32_t crc_table[256];
+
+ // Compute the CRC-32 table only once.
+ if (!crc_table[1]) {
+ for (uint32_t i = 0; i < 256; ++i) {
+ uint32_t crc = i;
+ for (uint32_t j = 0; j < 8; ++j) {
+ uint32_t mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ crc_table[i] = crc;
+ }
+ }
+
+ uint32_t ret = -1;
+ for (size_t i = 0; i < size; ++i) {
+ ret = (ret >> 8) ^ crc_table[(ret ^ buf[i]) & 0xFF];
+ }
+
+ return ~ret;
+}
+
+uint32_t ComputeChecksum(const bootloader_control *boot_ctrl) {
+ return CRC32(reinterpret_cast<const uint8_t *>(boot_ctrl),
+ offsetof(bootloader_control, crc32_le));
+}
+
+static bool LoadUpdateState(const std::string &misc_device, bootloader_control *buffer) {
+ unique_fd fd(open(misc_device.c_str(), O_RDONLY));
+ if (fd < 0) {
+ PLOG(ERROR) << "failed to open " << misc_device;
+ return false;
+ }
+ if (lseek(fd, kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) {
+ PLOG(ERROR) << "failed to lseek " << misc_device;
+ return false;
+ }
+ if (!android::base::ReadFully(fd, buffer, sizeof(bootloader_control))) {
+ PLOG(ERROR) << "failed to read " << misc_device;
+ return false;
+ }
+ return true;
+}
+
+static bool SaveUpdateState(const std::string &misc_device, bootloader_control *buffer) {
+ unique_fd fd(open(misc_device.c_str(), O_WRONLY | O_SYNC));
+ if (fd < 0) {
+ PLOG(ERROR) << "failed to open " << misc_device;
+ return false;
+ }
+ if (lseek(fd, kBootloaderControlOffset, SEEK_SET) != kBootloaderControlOffset) {
+ PLOG(ERROR) << "failed to lseek " << misc_device;
+ return false;
+ }
+
+ buffer->crc32_le = ComputeChecksum(buffer);
+ if (!android::base::WriteFully(fd, buffer, sizeof(bootloader_control))) {
+ PLOG(ERROR) << "failed to write " << misc_device;
+ return false;
+ }
+ return true;
+}
+
+BootControlShared::BootControlShared() {
+ std::string err;
+ misc_device_ = get_bootloader_message_blk_device(&err);
+ if (misc_device_.empty()) {
+ LOG(FATAL) << "Unable to locate misc device: " << err;
+ }
+
+ bootloader_control control;
+ if (!LoadUpdateState(misc_device_, &control)) {
+ LOG(FATAL) << "Unable to read update state from misc partition";
+ }
+ uint32_t computed_crc32 = ComputeChecksum(&control);
+
+ bool initialize = false;
+ if (computed_crc32 != control.crc32_le) {
+ LOG(WARNING) << "Invalid boot control found, expected CRC32 0x" << std::hex
+ << computed_crc32 << " but found 0x" << std::hex << control.crc32_le;
+ initialize = true;
+ } else if (control.magic != BOOT_CTRL_MAGIC) {
+ LOG(WARNING) << "Invalid boot control magic, " << std::hex << control.magic;
+ initialize = true;
+ }
+ if (initialize) {
+ LOG(WARNING) << "Re-initializing misc.";
+
+ // We only use the |merge_status| field of this structure.
+ memset(&control, 0, sizeof(control));
+ control.magic = BOOT_CTRL_MAGIC;
+ control.version = BOOT_CTRL_VERSION;
+ control.merge_status = static_cast<uint8_t>(MergeStatus::NONE);
+ SaveUpdateState(misc_device_, &control);
+ }
+}
+
+Return<bool> BootControlShared::setSnapshotMergeStatus(MergeStatus status) {
+ bootloader_control control;
+ if (!LoadUpdateState(misc_device_, &control)) {
+ return false;
+ }
+ control.merge_status = static_cast<uint8_t>(status);
+ return SaveUpdateState(misc_device_, &control);
+}
+
+Return<MergeStatus> BootControlShared::getSnapshotMergeStatus() {
+ bootloader_control control;
+ if (!LoadUpdateState(misc_device_, &control)) {
+ return MergeStatus::UNKNOWN;
+ }
+ return static_cast<MergeStatus>(control.merge_status);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace boot
+} // namespace hardware
+} // namespace android