mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
It turned out that shared verified boot library fails to work properly when compiled by msc in BIOS environment. The culprit was identified as failing 64 bit logical operations by preprocessor. It is probably possible to come up with a certain compile flag set to fix the operations, but it is not easy to modify and control the BIOS compilation environment. The alternative solution is to limit the size of the field in question to 16 bits (especially since this is the only part of the attributes field which is supposed to be altered by firmware. A union is being introduced in firmware/lib/cgptlib/include/gpt.h:GptEntry to allow accessing the field both as a 64 bit entity and a top 16 bit field. All places where this field is used are being modified appropriately. tests/Makefile is being fixed to allow controlling test run from the top level directory. Tested by building everything and running tests. All tests pass. Review URL: http://codereview.chromium.org/2799019
150 lines
4.6 KiB
C
150 lines
4.6 KiB
C
/* Copyright (c) 2010 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 "cgptlib.h"
|
|
#include "cgptlib_internal.h"
|
|
#include "crc32.h"
|
|
#include "gpt.h"
|
|
#include "utility.h"
|
|
|
|
/* global types to compare against */
|
|
const Guid guid_unused = GPT_ENT_TYPE_UNUSED;
|
|
const Guid guid_chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
|
|
|
|
|
|
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)
|
|
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;
|
|
int i;
|
|
|
|
/* If we already found a kernel, continue the scan at the current
|
|
* kernel's prioity, 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;
|
|
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;
|
|
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;
|
|
if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
|
|
continue;
|
|
if (current_prio >= gpt->current_priority)
|
|
continue; /* Already returned this kernel in a previous call */
|
|
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)
|
|
return GPT_ERROR_NO_VALID_KERNEL;
|
|
|
|
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) {
|
|
GptHeader* header = (GptHeader*)gpt->primary_header;
|
|
GptEntry* entries = (GptEntry*)gpt->primary_entries;
|
|
GptEntry* e = entries + gpt->current_kernel;
|
|
uint16_t previous_attr = e->attrs.fields.gpt_att;
|
|
|
|
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))
|
|
return GPT_SUCCESS; /* Successfully booted this partition, so
|
|
* tries field is ignored. */
|
|
tries = GetEntryTries(e);
|
|
if (tries > 1) {
|
|
/* Still have tries left */
|
|
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. */
|
|
e->attrs.fields.gpt_att = previous_attr & ~(
|
|
CGPT_ATTRIBUTE_SUCCESSFUL_MASK |
|
|
CGPT_ATTRIBUTE_TRIES_MASK |
|
|
CGPT_ATTRIBUTE_PRIORITY_MASK);
|
|
break;
|
|
}
|
|
default:
|
|
return GPT_ERROR_INVALID_UPDATE_TYPE;
|
|
}
|
|
|
|
/* If no change to attributes, we're done */
|
|
if (e->attrs.fields.gpt_att == previous_attr)
|
|
return GPT_SUCCESS;
|
|
|
|
/* Update the CRCs */
|
|
header->entries_crc32 = Crc32((const uint8_t *)entries,
|
|
header->size_of_entry *
|
|
header->number_of_entries);
|
|
header->header_crc32 = HeaderCrc(header);
|
|
gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
|
|
|
|
/* Use the repair function to update the other copy of the GPT.
|
|
* This is a tad inefficient, but is much faster than the disk I/O
|
|
* to update the GPT on disk so it doesn't matter. */
|
|
gpt->valid_headers = MASK_PRIMARY;
|
|
gpt->valid_entries = MASK_PRIMARY;
|
|
GptRepair(gpt);
|
|
|
|
return GPT_SUCCESS;
|
|
}
|