summaryrefslogtreecommitdiff
path: root/firmware/lib/cgptlib/mtdlib_unused.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/lib/cgptlib/mtdlib_unused.c')
-rw-r--r--firmware/lib/cgptlib/mtdlib_unused.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/firmware/lib/cgptlib/mtdlib_unused.c b/firmware/lib/cgptlib/mtdlib_unused.c
new file mode 100644
index 00000000..bf285005
--- /dev/null
+++ b/firmware/lib/cgptlib/mtdlib_unused.c
@@ -0,0 +1,284 @@
+/* Copyright (c) 2013 The Chromium OS 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 "mtdlib.h"
+#include "mtdlib_unused.h"
+
+#include "cgptlib.h"
+#include "cgptlib_internal.h"
+#include "crc32.h"
+#include "utility.h"
+#include "vboot_api.h"
+
+int MtdIsKernelEntry(const MtdDiskPartition *e) {
+ return MtdGetEntryType(e) == MTD_PARTITION_TYPE_CHROMEOS_KERNEL;
+}
+
+void MtdModified(MtdData *mtd) {
+ mtd->modified = 1;
+ mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
+}
+
+int MtdIsPartitionValid(const MtdDiskPartition *part) {
+ return MtdGetEntryType(part) != 0;
+}
+
+int MtdCheckParameters(MtdData *disk) {
+ if (disk->sector_bytes != 512) {
+ return GPT_ERROR_INVALID_SECTOR_SIZE;
+ }
+
+ /* At minimum, the disk must consist of at least one erase block */
+ if (disk->drive_sectors < disk->flash_block_bytes / disk->sector_bytes) {
+ return GPT_ERROR_INVALID_SECTOR_NUMBER;
+ }
+
+ /* Write pages must be an integer multiple of sector size */
+ if (disk->flash_page_bytes == 0 ||
+ disk->flash_page_bytes % disk->sector_bytes != 0) {
+ return GPT_ERROR_INVALID_FLASH_GEOMETRY;
+ }
+
+ /* Erase blocks must be an integer multiple of write pages */
+ if (disk->flash_block_bytes == 0 ||
+ disk->flash_block_bytes % disk->flash_page_bytes != 0) {
+ return GPT_ERROR_INVALID_FLASH_GEOMETRY;
+ }
+
+ /* Without a FTS region, why are you using MTD? */
+ if (disk->fts_block_size == 0) {
+ return GPT_ERROR_INVALID_FLASH_GEOMETRY;
+ }
+ return GPT_SUCCESS;
+}
+
+
+int MtdCheckEntries(MtdDiskPartition *entries, MtdDiskLayout *h) {
+ uint32_t i, j;
+
+ for (i = 0; i < MTD_MAX_PARTITIONS; i++) {
+ for (j = 0; j < MTD_MAX_PARTITIONS; j++) {
+ if (i != j) {
+ MtdDiskPartition *entry = entries + i;
+ MtdDiskPartition *e2 = entries + j;
+ uint64_t start, end;
+ uint64_t other_start, other_end;
+
+ if (!MtdIsPartitionValid(entry) || !MtdIsPartitionValid(e2))
+ continue;
+
+ MtdGetPartitionSize(entry, &start, &end, NULL);
+ MtdGetPartitionSize(e2, &other_start, &other_end, NULL);
+
+ if((start == 0 && end == 0) ||
+ (other_start == 0 && other_end == 0)) {
+ continue;
+ }
+
+ if (end > h->last_offset) {
+ return GPT_ERROR_OUT_OF_REGION;
+ }
+ if (start < h->first_offset) {
+ return GPT_ERROR_OUT_OF_REGION;
+ }
+ if (start > end) {
+ return GPT_ERROR_OUT_OF_REGION;
+ }
+
+ if ((start >= other_start) &&
+ (start <= other_end)) {
+ return GPT_ERROR_START_LBA_OVERLAP;
+ }
+ if ((end >= other_start) &&
+ (end <= other_end)) {
+ return GPT_ERROR_END_LBA_OVERLAP;
+ }
+ }
+ }
+ }
+ return GPT_SUCCESS;
+}
+
+int MtdSanityCheck(MtdData *disk) {
+ MtdDiskLayout *h = &disk->primary;
+ int ret;
+
+ ret = MtdCheckParameters(disk);
+ if(GPT_SUCCESS != ret)
+ return ret;
+
+ if (Memcmp(disk->primary.signature, MTD_DRIVE_SIGNATURE,
+ sizeof(disk->primary.signature))) {
+ return GPT_ERROR_INVALID_HEADERS;
+ }
+
+ if (disk->primary.first_offset > disk->primary.last_offset ||
+ disk->primary.last_offset > disk->drive_sectors * disk->sector_bytes) {
+ return GPT_ERROR_INVALID_SECTOR_NUMBER;
+ }
+
+ if (h->crc32 != MtdHeaderCrc(h)) {
+ return GPT_ERROR_CRC_CORRUPTED;
+ }
+ if (h->size < MTD_DRIVE_V1_SIZE) {
+ return GPT_ERROR_INVALID_HEADERS;
+ }
+ return MtdCheckEntries(h->partitions, h);
+}
+
+
+int MtdInit(MtdData *mtd) {
+ int ret;
+
+ mtd->modified = 0;
+ mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+ mtd->current_priority = 999;
+
+ ret = MtdSanityCheck(mtd);
+ if (GPT_SUCCESS != ret) {
+ VBDEBUG(("MtdInit() failed sanity check\n"));
+ return ret;
+ }
+
+ return GPT_SUCCESS;
+}
+
+int MtdNextKernelEntry(MtdData *mtd, uint64_t *start_sector, uint64_t *size)
+{
+ MtdDiskLayout *header = &mtd->primary;
+ MtdDiskPartition *entries = header->partitions;
+ MtdDiskPartition *e;
+ int new_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+ int new_prio = 0;
+ uint32_t i;
+
+ /*
+ * If we already found a kernel, continue the scan at the current
+ * kernel's priority, in case there is another kernel with the same
+ * priority.
+ */
+ if (mtd->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) {
+ for (i = mtd->current_kernel + 1;
+ i < MTD_MAX_PARTITIONS; i++) {
+ e = entries + i;
+ if (!MtdIsKernelEntry(e))
+ continue;
+ VBDEBUG(("MtdNextKernelEntry looking at same prio "
+ "partition %d\n", i+1));
+ VBDEBUG(("MtdNextKernelEntry s%d t%d p%d\n",
+ MtdGetEntrySuccessful(e), MtdGetEntryTries(e),
+ MtdGetEntryPriority(e)));
+ if (!(MtdGetEntrySuccessful(e) || MtdGetEntryTries(e)))
+ continue;
+ if (MtdGetEntryPriority(e) == mtd->current_priority) {
+ MtdGetPartitionSizeInSectors(e, start_sector, NULL, size);
+ mtd->current_kernel = i;
+ VBDEBUG(("MtdNextKernelEntry likes it\n"));
+ return GPT_SUCCESS;
+ }
+ }
+ }
+
+ /*
+ * We're still here, so scan for the remaining kernel with the highest
+ * priority less than the previous attempt.
+ */
+ for (i = 0, e = entries; i < MTD_MAX_PARTITIONS; i++, e++) {
+ int current_prio = MtdGetEntryPriority(e);
+ if (!MtdIsKernelEntry(e))
+ continue;
+ VBDEBUG(("MtdNextKernelEntry looking at new prio "
+ "partition %d\n", i+1));
+ VBDEBUG(("MtdNextKernelEntry s%d t%d p%d\n",
+ MtdGetEntrySuccessful(e), MtdGetEntryTries(e),
+ MtdGetEntryPriority(e)));
+ if (!(MtdGetEntrySuccessful(e) || MtdGetEntryTries(e)))
+ continue;
+ if (current_prio >= mtd->current_priority) {
+ /* Already returned this kernel in a previous call */
+ continue;
+ }
+ if (current_prio > new_prio) {
+ new_kernel = i;
+ new_prio = current_prio;
+ }
+ }
+
+ /*
+ * Save what we found. Note that if we didn't find a new kernel,
+ * new_prio will still be -1, so future calls to this function will
+ * also fail.
+ */
+ mtd->current_kernel = new_kernel;
+ mtd->current_priority = new_prio;
+
+ if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) {
+ VBDEBUG(("MtdNextKernelEntry no more kernels\n"));
+ return GPT_ERROR_NO_VALID_KERNEL;
+ }
+
+ VBDEBUG(("MtdNextKernelEntry likes partition %d\n", new_kernel + 1));
+ e = entries + new_kernel;
+ MtdGetPartitionSizeInSectors(e, start_sector, NULL, size);
+
+ return GPT_SUCCESS;
+}
+
+
+int MtdUpdateKernelEntry(MtdData *mtd, uint32_t update_type)
+{
+ MtdDiskLayout *header = &mtd->primary;
+ MtdDiskPartition *entries = header->partitions;
+ MtdDiskPartition *e = entries + mtd->current_kernel;
+ int modified = 0;
+
+ if (mtd->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND)
+ return GPT_ERROR_INVALID_UPDATE_TYPE;
+ if (!MtdIsKernelEntry(e))
+ return GPT_ERROR_INVALID_UPDATE_TYPE;
+
+ switch (update_type) {
+ case GPT_UPDATE_ENTRY_TRY: {
+ /* Used up a try */
+ int tries;
+ if (MtdGetEntrySuccessful(e)) {
+ /*
+ * Successfully booted this partition, so tries field
+ * is ignored.
+ */
+ return GPT_SUCCESS;
+ }
+ tries = MtdGetEntryTries(e);
+ if (tries > 1) {
+ /* Still have tries left */
+ modified = 1;
+ MtdSetEntryTries(e, tries - 1);
+ break;
+ }
+ /* Out of tries, so drop through and mark partition bad. */
+ }
+ case GPT_UPDATE_ENTRY_BAD: {
+ /* Giving up on this partition entirely. */
+ if (!MtdGetEntrySuccessful(e)) {
+ /*
+ * Only clear tries and priority if the successful bit
+ * is not set.
+ */
+ modified = 1;
+ MtdSetEntryTries(e, 0);
+ MtdSetEntryPriority(e, 0);
+ }
+ break;
+ }
+ default:
+ return GPT_ERROR_INVALID_UPDATE_TYPE;
+ }
+
+ if (modified) {
+ MtdModified(mtd);
+ }
+
+ return GPT_SUCCESS;
+}