summaryrefslogtreecommitdiff
path: root/cgpt/cgpt_common.c
diff options
context:
space:
mode:
authorNam T. Nguyen <namnguyen@chromium.org>2014-10-24 13:20:39 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-13 18:29:09 +0000
commit6ee52d9a929d00e871e7316240b54f381146fbc6 (patch)
treeca403414469d9364d144a67e63f8f439874802e3 /cgpt/cgpt_common.c
parent43e0a9ed6c0b332631442fcf581e7456d62e4532 (diff)
downloadvboot-6ee52d9a929d00e871e7316240b54f381146fbc6.tar.gz
vboot: cgpt: Support writing GPT structs to NOR flash
This CL allows the GPT headers and partition entry arrays to be stored in a NOR flash device. Instead of treating both the NOR and NAND devices as one (in a sandwich way), this CL writes and reads the GPT structs independently of the actual device that houses the partitions. Therefore, the first usable LBA of the partitions will be at 0, and the last usable LBA is at the end of the NAND. +------------------------+ | NOR houses GPT structs | +------------------------+ | 0 | Index into v v +------------------------+ | NAND houses partitions | +------------------------+ Note that the "my_lba", "alternate_lba", "entries_lba" in the GPT headers are no longer meaningful. Consumers of cgptlib will have to set "stored_on_device" to either GPT_STORED_ON_DEVICE or GPT_STORED_OFF_DEVICE, and "gpt_drive_sectors" to the number of 512-byte sectors available to store GPT structs. The NOR read and write operations are done by "flashrom". BUG=chromium:425677 BRANCH=none TEST=unittest TEST=build with DEBUG, cgpt create/add/show on a stumpy-moblab Change-Id: I083b3c94da3b0bb3da1a7b10c6969774080a2afd Reviewed-on: https://chromium-review.googlesource.com/226800 Reviewed-by: Nam Nguyen <namnguyen@chromium.org> Commit-Queue: Nam Nguyen <namnguyen@chromium.org> Tested-by: Nam Nguyen <namnguyen@chromium.org>
Diffstat (limited to 'cgpt/cgpt_common.c')
-rw-r--r--cgpt/cgpt_common.c72
1 files changed, 53 insertions, 19 deletions
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index 3900cf33..43312fe6 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -9,6 +9,8 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <linux/major.h>
+#include <mtd/mtd-user.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -75,7 +77,6 @@ int Load(struct drive *drive, uint8_t **buf,
const uint64_t sector_count) {
int count; /* byte count to read */
int nread;
- int fd = drive->fd;
require(buf);
if (!sector_count || !sector_bytes) {
@@ -93,12 +94,12 @@ int Load(struct drive *drive, uint8_t **buf,
*buf = malloc(count);
require(*buf);
- if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET)) {
- Error("Can't lseek: %s\n", strerror(errno));
+ if (-1 == drive->seek(drive, sector * sector_bytes, SEEK_SET)) {
+ Error("Can't seek: %s\n", strerror(errno));
goto error_free;
}
- nread = read(fd, *buf, count);
+ nread = drive->read(drive, *buf, count);
if (nread < count) {
Error("Can't read enough: %d, not %d\n", nread, count);
goto error_free;
@@ -114,10 +115,10 @@ error_free:
int ReadPMBR(struct drive *drive) {
- if (-1 == lseek(drive->fd, 0, SEEK_SET))
+ if (-1 == drive->seek(drive, 0, SEEK_SET))
return CGPT_FAILED;
- int nread = read(drive->fd, &drive->pmbr, sizeof(struct pmbr));
+ int nread = drive->read(drive, &drive->pmbr, sizeof(struct pmbr));
if (nread != sizeof(struct pmbr))
return CGPT_FAILED;
@@ -125,10 +126,10 @@ int ReadPMBR(struct drive *drive) {
}
int WritePMBR(struct drive *drive) {
- if (-1 == lseek(drive->fd, 0, SEEK_SET))
+ if (-1 == drive->seek(drive, 0, SEEK_SET))
return CGPT_FAILED;
- int nwrote = write(drive->fd, &drive->pmbr, sizeof(struct pmbr));
+ int nwrote = drive->write(drive, &drive->pmbr, sizeof(struct pmbr));
if (nwrote != sizeof(struct pmbr))
return CGPT_FAILED;
@@ -141,15 +142,14 @@ int Save(struct drive *drive, const uint8_t *buf,
const uint64_t sector_count) {
int count; /* byte count to write */
int nwrote;
- int fd = drive->fd;
require(buf);
count = sector_bytes * sector_count;
- if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
+ if (-1 == drive->seek(drive, sector * sector_bytes, SEEK_SET))
return CGPT_FAILED;
- nwrote = write(fd, buf, count);
+ nwrote = drive->write(drive, buf, count);
if (nwrote < count)
return CGPT_FAILED;
@@ -320,6 +320,11 @@ static int GptLoad(struct drive *drive, uint32_t sector_bytes) {
}
drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
+ /* TODO(namnguyen): Remove this and totally trust gpt_drive_sectors. */
+ if (drive->gpt.stored_on_device == GPT_STORED_ON_DEVICE) {
+ drive->gpt.gpt_drive_sectors = drive->gpt.drive_sectors;
+ } /* Else, we trust gpt.gpt_drive_sectors. */
+
// Read the data.
if (CGPT_OK != Load(drive, &drive->gpt.primary_header,
GPT_PMBR_SECTORS,
@@ -328,13 +333,14 @@ static int GptLoad(struct drive *drive, uint32_t sector_bytes) {
return -1;
}
if (CGPT_OK != Load(drive, &drive->gpt.secondary_header,
- drive->gpt.drive_sectors - GPT_PMBR_SECTORS,
+ drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS,
drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
Error("Cannot read secondary GPT header\n");
return -1;
}
GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header;
- if (CheckHeader(primary_header, 0, drive->gpt.drive_sectors) == 0) {
+ if (CheckHeader(primary_header, 0, drive->gpt.drive_sectors,
+ drive->gpt.stored_on_device) == 0) {
if (CGPT_OK != Load(drive, &drive->gpt.primary_entries,
primary_header->entries_lba,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
@@ -345,7 +351,8 @@ static int GptLoad(struct drive *drive, uint32_t sector_bytes) {
Warning("Primary GPT header is invalid\n");
}
GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
- if (CheckHeader(secondary_header, 1, drive->gpt.drive_sectors) == 0) {
+ if (CheckHeader(secondary_header, 1, drive->gpt.drive_sectors,
+ drive->gpt.stored_on_device) == 0) {
if (CGPT_OK != Load(drive, &drive->gpt.secondary_entries,
secondary_header->entries_lba,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
@@ -371,7 +378,7 @@ static int GptSave(struct drive *drive) {
if (drive->gpt.modified & GPT_MODIFIED_HEADER2) {
if(CGPT_OK != Save(drive, drive->gpt.secondary_header,
- drive->gpt.drive_sectors - GPT_PMBR_SECTORS,
+ drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS,
drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
errors++;
Error("Cannot write secondary header: %s\n", strerror(errno));
@@ -427,6 +434,7 @@ int DriveOpen(const char *drive_path, struct drive *drive, int mode) {
// Clear struct for proper error handling.
memset(drive, 0, sizeof(struct drive));
+ drive->gpt.stored_on_device = GPT_STORED_ON_DEVICE;
if (TryInitMtd(drive_path)) {
is_mtd = 1;
@@ -438,11 +446,37 @@ int DriveOpen(const char *drive_path, struct drive *drive, int mode) {
return CGPT_FAILED;
}
+ drive->seek = FileSeek;
+ drive->read = FileRead;
+ drive->write = FileWrite;
+ drive->sync = FileSync;
+ drive->close = FileClose;
if (fstat(drive->fd, &stat) == -1) {
Error("Can't fstat %s: %s\n", drive_path, strerror(errno));
goto error_close;
}
- if ((stat.st_mode & S_IFMT) != S_IFREG) {
+ if (major(stat.st_rdev) == MTD_CHAR_MAJOR) {
+ mtd_info_t mtd_info;
+ if (ioctl(drive->fd, MEMGETINFO, &mtd_info) != 0) {
+ Error("Can't get the size of the MTD device\n");
+ goto error_close;
+ }
+ drive->size = mtd_info.size;
+
+ if (FlashInit(drive) != 0) {
+ Error("Can't obtain NOR flash info with flashrom\n");
+ goto error_close;
+ }
+
+ sector_bytes = 512;
+ drive->gpt.stored_on_device = GPT_STORED_OFF_DEVICE;
+ drive->gpt.gpt_drive_sectors = drive->flash_size / sector_bytes;
+ drive->seek = FlashSeek;
+ drive->read = FlashRead;
+ drive->write = FlashWrite;
+ drive->sync = FlashSync;
+ drive->close = FlashClose;
+ } else if ((stat.st_mode & S_IFMT) != S_IFREG) {
if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
Error("Can't read drive size from %s: %s\n", drive_path,
strerror(errno));
@@ -501,9 +535,9 @@ int DriveClose(struct drive *drive, int update_as_needed) {
// Sync early! Only sync file descriptor here, and leave the whole system sync
// outside cgpt because whole system sync would trigger tons of disk accesses
// and timeout tests.
- fsync(drive->fd);
+ drive->sync(drive);
- close(drive->fd);
+ drive->close(drive);
return errors ? CGPT_FAILED : CGPT_OK;
}
@@ -1173,7 +1207,7 @@ uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) {
}
} else if (valid_headers == MASK_PRIMARY) {
memcpy(secondary_header, primary_header, sizeof(GptHeader));
- secondary_header->my_lba = gpt->drive_sectors - 1; /* the last sector */
+ secondary_header->my_lba = gpt->gpt_drive_sectors - 1; /* the last sector */
secondary_header->alternate_lba = primary_header->my_lba;
secondary_header->entries_lba = secondary_header->my_lba -
GPT_ENTRIES_SECTORS;