Files
OpenCellular/firmware/lib/gpt_misc.c
Randall Spangler 559a110f33 vboot: use malloc and free directly
Originally, vboot1 code used VbExMalloc() and VbExFree() since it needed
to talk to EFI firmware that didn't have standard malloc() and free().
Now, coreboot and depthcharge implement them as wrappers around those
standard calls.  vboot2 code already calls them directly, so let vboot1
code do that too.

BUG=chromium:611535
BRANCH=none
TEST=make runtests; emerge-kevin coreboot depthcharge

Change-Id: I49ad0e32e38d278dc3589bfaf494bcf0e4b0a4bd
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/400905
2016-11-06 02:33:50 +00:00

244 lines
7.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"
/**
* Allocate and read GPT data from the drive.
*
* The sector_bytes and gpt_drive_sectors fields should be filled on input. The
* primary and secondary header and entries are filled on output.
*
* Returns 0 if successful, 1 if error.
*/
int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
{
uint64_t max_entries_bytes = MAX_NUMBER_OF_ENTRIES * sizeof(GptEntry);
int primary_valid = 0, secondary_valid = 0;
/* No data to be written yet */
gptdata->modified = 0;
/* This should get overwritten by GptInit() */
gptdata->ignored = 0;
/* Allocate all buffers */
gptdata->primary_header = (uint8_t *)malloc(gptdata->sector_bytes);
gptdata->secondary_header =
(uint8_t *)malloc(gptdata->sector_bytes);
gptdata->primary_entries = (uint8_t *)malloc(max_entries_bytes);
gptdata->secondary_entries = (uint8_t *)malloc(max_entries_bytes);
if (gptdata->primary_header == NULL ||
gptdata->secondary_header == NULL ||
gptdata->primary_entries == NULL ||
gptdata->secondary_entries == NULL)
return 1;
/* Read primary header from the drive, skipping the protective MBR */
if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) {
VBDEBUG(("Read error in primary GPT header\n"));
memset(gptdata->primary_header, 0, gptdata->sector_bytes);
}
/* Only read primary GPT if the primary header is valid */
GptHeader* primary_header = (GptHeader*)gptdata->primary_header;
if (0 == CheckHeader(primary_header, 0,
gptdata->streaming_drive_sectors,
gptdata->gpt_drive_sectors,
gptdata->flags)) {
primary_valid = 1;
uint64_t entries_bytes =
(uint64_t)primary_header->number_of_entries
* primary_header->size_of_entry;
uint64_t entries_sectors = entries_bytes
/ gptdata->sector_bytes;
if (0 != VbExDiskRead(disk_handle,
primary_header->entries_lba,
entries_sectors,
gptdata->primary_entries)) {
VBDEBUG(("Read error in primary GPT entries\n"));
primary_valid = 0;
}
} else {
VBDEBUG(("Primary GPT header is %s\n",
memcmp(primary_header->signature,
GPT_HEADER_SIGNATURE_IGNORED,
GPT_HEADER_SIGNATURE_SIZE)
? "invalid" : "being ignored"));
}
/* Read secondary header from the end of the drive */
if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1,
gptdata->secondary_header)) {
VBDEBUG(("Read error in secondary GPT header\n"));
memset(gptdata->secondary_header, 0, gptdata->sector_bytes);
}
/* Only read secondary GPT if the secondary header is valid */
GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header;
if (0 == CheckHeader(secondary_header, 1,
gptdata->streaming_drive_sectors,
gptdata->gpt_drive_sectors,
gptdata->flags)) {
secondary_valid = 1;
uint64_t entries_bytes =
(uint64_t)secondary_header->number_of_entries
* secondary_header->size_of_entry;
uint64_t entries_sectors = entries_bytes
/ gptdata->sector_bytes;
if (0 != VbExDiskRead(disk_handle,
secondary_header->entries_lba,
entries_sectors,
gptdata->secondary_entries)) {
VBDEBUG(("Read error in secondary GPT entries\n"));
secondary_valid = 0;
}
} else {
VBDEBUG(("Secondary GPT header is %s\n",
memcmp(secondary_header->signature,
GPT_HEADER_SIGNATURE_IGNORED,
GPT_HEADER_SIGNATURE_SIZE)
? "invalid" : "being ignored"));
}
/* Return 0 if least one GPT header was valid */
return (primary_valid || secondary_valid) ? 0 : 1;
}
/**
* Write any changes for the GPT data back to the drive, then free the buffers.
*
* Returns 0 if successful, 1 if error.
*/
int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
{
int skip_primary = 0;
GptHeader *header;
uint64_t entries_bytes, entries_sectors;
int ret = 1;
header = (GptHeader *)gptdata->primary_header;
if (!header)
header = (GptHeader *)gptdata->secondary_header;
if (!header)
return 1; /* No headers at all, so nothing to write */
entries_bytes = (uint64_t)header->number_of_entries
* header->size_of_entry;
entries_sectors = entries_bytes / gptdata->sector_bytes;
/*
* TODO(namnguyen): Preserve padding between primary GPT header and
* its entries.
*/
uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS;
if (gptdata->primary_header) {
GptHeader *h = (GptHeader *)(gptdata->primary_header);
entries_lba = h->entries_lba;
if (gptdata->ignored & MASK_PRIMARY) {
VBDEBUG(("Not updating primary GPT: "
"marked to be ignored.\n"));
skip_primary = 1;
} else if (gptdata->modified & GPT_MODIFIED_HEADER1) {
if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2,
GPT_HEADER_SIGNATURE_SIZE)) {
VBDEBUG(("Not updating primary GPT: "
"legacy mode is enabled.\n"));
skip_primary = 1;
} else {
VBDEBUG(("Updating GPT header 1\n"));
if (0 != VbExDiskWrite(disk_handle, 1, 1,
gptdata->primary_header))
goto fail;
}
}
}
if (gptdata->primary_entries && !skip_primary) {
if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
VBDEBUG(("Updating GPT entries 1\n"));
if (0 != VbExDiskWrite(disk_handle, entries_lba,
entries_sectors,
gptdata->primary_entries))
goto fail;
}
}
entries_lba = (gptdata->gpt_drive_sectors - entries_sectors -
GPT_HEADER_SECTORS);
if (gptdata->secondary_header && !(gptdata->ignored & MASK_SECONDARY)) {
GptHeader *h = (GptHeader *)(gptdata->secondary_header);
entries_lba = h->entries_lba;
if (gptdata->modified & GPT_MODIFIED_HEADER2) {
VBDEBUG(("Updating GPT header 2\n"));
if (0 != VbExDiskWrite(disk_handle,
gptdata->gpt_drive_sectors - 1, 1,
gptdata->secondary_header))
goto fail;
}
}
if (gptdata->secondary_entries && !(gptdata->ignored & MASK_SECONDARY)){
if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
VBDEBUG(("Updating GPT entries 2\n"));
if (0 != VbExDiskWrite(disk_handle,
entries_lba, entries_sectors,
gptdata->secondary_entries))
goto fail;
}
}
ret = 0;
fail:
/* Avoid leaking memory on disk write failure */
if (gptdata->primary_header)
free(gptdata->primary_header);
if (gptdata->primary_entries)
free(gptdata->primary_entries);
if (gptdata->secondary_entries)
free(gptdata->secondary_entries);
if (gptdata->secondary_header)
free(gptdata->secondary_header);
/* Success */
return ret;
}
int IsUnusedEntry(const GptEntry *e)
{
static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
return !memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
}
/*
* Func: GptGetEntrySize
* Desc: This function returns size(in lba) of a partition represented by
* given GPT entry.
*/
size_t GptGetEntrySizeLba(const GptEntry *e)
{
return (e->ending_lba - e->starting_lba + 1);
}
/*
* Func: GptGetEntrySize
* Desc: This function returns size(in bytes) of a partition represented by
* given GPT entry.
*/
size_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e)
{
return GptGetEntrySizeLba(e) * gpt->sector_bytes;
}