mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
Defines MTD on-disk structures & API in mtdlib.h/c that closely mirrors the existing cgpt implementation. Currently, the disk structures do not contain guids or labels, and the number of available partition types and quantities are limited, exactly what we want to support should be decided before we ship this. Adds appropriate test coverage to the unit test library - either by modifying existing tests, or copying them and changing them accordingly. BUG=chromium:221745 TEST=added appropriate tests to the unittests BRANCH=none Change-Id: Iee19864498024c72229bc3c7811594fe762f52de Original-Change-Id: I031eca69d6c8e825b02bd0522d57e92b05eb191a Reviewed-on: https://gerrit.chromium.org/gerrit/46082 Tested-by: Albert Chaulk <achaulk@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org> Commit-Queue: Albert Chaulk <achaulk@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/48793 Reviewed-by: Albert Chaulk <achaulk@chromium.org>
169 lines
4.2 KiB
C
169 lines
4.2 KiB
C
/* 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 "sysincludes.h"
|
|
|
|
#include "cgptlib.h"
|
|
#include "cgptlib_internal.h"
|
|
#include "crc32.h"
|
|
#include "gpt.h"
|
|
#include "utility.h"
|
|
#include "vboot_api.h"
|
|
|
|
int GptInit(GptData *gpt)
|
|
{
|
|
int retval;
|
|
|
|
gpt->modified = 0;
|
|
gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
|
|
gpt->current_priority = 999;
|
|
|
|
retval = GptSanityCheck(gpt);
|
|
if (GPT_SUCCESS != retval) {
|
|
VBDEBUG(("GptInit() failed sanity check\n"));
|
|
return retval;
|
|
}
|
|
|
|
GptRepair(gpt);
|
|
return GPT_SUCCESS;
|
|
}
|
|
|
|
int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
|
|
{
|
|
GptHeader *header = (GptHeader *)gpt->primary_header;
|
|
GptEntry *entries = (GptEntry *)gpt->primary_entries;
|
|
GptEntry *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 (gpt->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) {
|
|
for (i = gpt->current_kernel + 1;
|
|
i < header->number_of_entries; i++) {
|
|
e = entries + i;
|
|
if (!IsKernelEntry(e))
|
|
continue;
|
|
VBDEBUG(("GptNextKernelEntry looking at same prio "
|
|
"partition %d\n", i+1));
|
|
VBDEBUG(("GptNextKernelEntry s%d t%d p%d\n",
|
|
GetEntrySuccessful(e), GetEntryTries(e),
|
|
GetEntryPriority(e)));
|
|
if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
|
|
continue;
|
|
if (GetEntryPriority(e) == gpt->current_priority) {
|
|
gpt->current_kernel = i;
|
|
*start_sector = e->starting_lba;
|
|
*size = e->ending_lba - e->starting_lba + 1;
|
|
VBDEBUG(("GptNextKernelEntry 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 < header->number_of_entries; i++, e++) {
|
|
int current_prio = GetEntryPriority(e);
|
|
if (!IsKernelEntry(e))
|
|
continue;
|
|
VBDEBUG(("GptNextKernelEntry looking at new prio "
|
|
"partition %d\n", i+1));
|
|
VBDEBUG(("GptNextKernelEntry s%d t%d p%d\n",
|
|
GetEntrySuccessful(e), GetEntryTries(e),
|
|
GetEntryPriority(e)));
|
|
if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
|
|
continue;
|
|
if (current_prio >= gpt->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.
|
|
*/
|
|
gpt->current_kernel = new_kernel;
|
|
gpt->current_priority = new_prio;
|
|
|
|
if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) {
|
|
VBDEBUG(("GptNextKernelEntry no more kernels\n"));
|
|
return GPT_ERROR_NO_VALID_KERNEL;
|
|
}
|
|
|
|
VBDEBUG(("GptNextKernelEntry likes partition %d\n", new_kernel + 1));
|
|
e = entries + new_kernel;
|
|
*start_sector = e->starting_lba;
|
|
*size = e->ending_lba - e->starting_lba + 1;
|
|
return GPT_SUCCESS;
|
|
}
|
|
|
|
int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type)
|
|
{
|
|
GptEntry *entries = (GptEntry *)gpt->primary_entries;
|
|
GptEntry *e = entries + gpt->current_kernel;
|
|
int modified = 0;
|
|
|
|
if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND)
|
|
return GPT_ERROR_INVALID_UPDATE_TYPE;
|
|
if (!IsKernelEntry(e))
|
|
return GPT_ERROR_INVALID_UPDATE_TYPE;
|
|
|
|
switch (update_type) {
|
|
case GPT_UPDATE_ENTRY_TRY: {
|
|
/* Used up a try */
|
|
int tries;
|
|
if (GetEntrySuccessful(e)) {
|
|
/*
|
|
* Successfully booted this partition, so tries field
|
|
* is ignored.
|
|
*/
|
|
return GPT_SUCCESS;
|
|
}
|
|
tries = GetEntryTries(e);
|
|
if (tries > 1) {
|
|
/* Still have tries left */
|
|
modified = 1;
|
|
SetEntryTries(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 (!GetEntrySuccessful(e)) {
|
|
/*
|
|
* Only clear tries and priority if the successful bit
|
|
* is not set.
|
|
*/
|
|
modified = 1;
|
|
SetEntryTries(e, 0);
|
|
SetEntryPriority(e, 0);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return GPT_ERROR_INVALID_UPDATE_TYPE;
|
|
}
|
|
|
|
if (modified) {
|
|
GptModified(gpt);
|
|
}
|
|
|
|
return GPT_SUCCESS;
|
|
}
|