Clean up exported Mtd* functions

A lot of functions were added some time ago, nominally to support keeping
the firmware in an MTD device that wasn't formatted with the GPT headers.
That work was never completed, so these functions aren't used anywhere.

We may want to resurrect this work at some future point. Until then, this CL
just moves some of the functions into an "unused" file.

BUG=chromium:231567
BRANCH=ToT
TEST=manual

All tests pass, all firmware and external repos build.

Change-Id: I420dd52d1cea0418cedf2f8e834c61145915f20c
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/207037
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Bill Richardson
2014-06-23 17:48:33 -07:00
committed by chrome-internal-fetch
parent 782990277a
commit 18e03706df
12 changed files with 325 additions and 305 deletions

View File

@@ -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;
}