diff options
Diffstat (limited to 'cgpt/cgpt_common.c')
-rw-r--r-- | cgpt/cgpt_common.c | 315 |
1 files changed, 220 insertions, 95 deletions
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c index b4f71f76..29a207a9 100644 --- a/cgpt/cgpt_common.c +++ b/cgpt/cgpt_common.c @@ -23,6 +23,7 @@ #include "cgpt.h" #include "cgptlib_internal.h" #include "crc32.h" +#include "flash_ts.h" #include "vboot_host.h" void Error(const char *format, ...) { @@ -44,24 +45,13 @@ int CheckValid(const struct drive *drive) { return CGPT_OK; } -/* Loads sectors from 'fd'. - * *buf is pointed to an allocated memory when returned, and should be - * freed by cgpt_close(). - * - * fd -- file descriptot. - * buf -- pointer to buffer pointer - * sector -- offset of starting sector (in sectors) - * sector_bytes -- bytes per sector - * sector_count -- number of sectors to load - * - * Returns CGPT_OK for successful. Aborts if any error occurs. - */ -static int Load(const int fd, uint8_t **buf, +int Load(struct drive *drive, uint8_t **buf, const uint64_t sector, const uint64_t sector_bytes, const uint64_t sector_count) { int count; /* byte count to read */ int nread; + int fd = drive->fd; require(buf); if (!sector_count || !sector_bytes) { @@ -121,22 +111,13 @@ int WritePMBR(struct drive *drive) { return CGPT_OK; } -/* Saves sectors to 'fd'. - * - * fd -- file descriptot. - * buf -- pointer to buffer - * sector -- starting sector offset - * sector_bytes -- bytes per sector - * sector_count -- number of sector to save - * - * Returns CGPT_OK for successful, CGPT_FAILED for failed. - */ -static int Save(const int fd, const uint8_t *buf, +int Save(struct drive *drive, const uint8_t *buf, const uint64_t sector, const uint64_t sector_bytes, const uint64_t sector_count) { int count; /* byte count to write */ int nwrote; + int fd = drive->fd; require(buf); count = sector_bytes * sector_count; @@ -151,6 +132,204 @@ static int Save(const int fd, const uint8_t *buf, return CGPT_OK; } +static int get_hex_char_value(char ch) { + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } + if (ch >= 'a' && ch <= 'f') { + return ch - 'a' + 10; + } + if (ch >= 'A' && ch <= 'F') { + return ch - 'A' + 10; + } + return -1; +} + +int FlashGet(const char *key, uint8_t *data, uint32_t *bufsz) { + char *hex = (char*)malloc(*bufsz * 2); + char *read; + uint32_t written = 0; + + flash_ts_get(key, hex, *bufsz * 2); + + /* Hex -> binary */ + for (read = hex; read < hex + *bufsz * 2 && *read != '\0'; read += 2) { + int c0, c1; + c0 = get_hex_char_value(read[0]); + c1 = get_hex_char_value(read[1]); + if (c0 < 0 || c1 < 0) { + free(hex); + return -1; + } + + data[written++] = (c0 << 4) + c1; + } + *bufsz = written; + free(hex); + return 0; +} + +int FlashSet(const char *key, const uint8_t *data, uint32_t bufsz) { + char *hex = (char*)malloc(bufsz * 2 + 1); + const char *hex_chars = "0123456789ABCDEF"; + int ret; + uint32_t i; + + /* Binary -> hex, we need some encoding because FTS only stores C strings */ + for (i = 0; i < bufsz; i++) { + hex[i * 2] = hex_chars[data[i] >> 4]; + hex[i * 2 + 1] = hex_chars[data[i] & 0xF]; + } + /* Buffer must be NUL-terminated. */ + hex[bufsz * 2] = '\0'; + ret = flash_ts_set(key, hex); + free(hex); + return ret; +} + +int MtdLoad(struct drive *drive, int sector_bytes) { + int ret; + uint32_t old_crc, new_crc; + uint32_t sz; + MtdData *mtd = &drive->mtd; + + mtd->sector_bytes = sector_bytes; + + ret = flash_ts_init(mtd->fts_block_offset, + mtd->fts_block_size, + mtd->flash_page_bytes, + mtd->flash_block_bytes, + mtd->sector_bytes, /* Needed for Load() and Save() */ + drive); + if (ret) + return ret; + + memset(&mtd->primary, 0, sizeof(mtd->primary)); + sz = sizeof(mtd->primary); + ret = FlashGet(MTD_DRIVE_SIGNATURE, (uint8_t *)&mtd->primary, &sz); + if (ret) + return ret; + + /* Read less than expected */ + if (sz < MTD_DRIVE_V1_SIZE) + return -1; + + if (memcmp(mtd->primary.signature, MTD_DRIVE_SIGNATURE, + sizeof(mtd->primary.signature))) { + return -1; + } + + old_crc = mtd->primary.crc32; + mtd->primary.crc32 = 0; + new_crc = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE); + mtd->primary.crc32 = old_crc; + + if (old_crc != new_crc) { + return -1; + } + + mtd->current_kernel = -1; + mtd->current_priority = 0; + mtd->modified = 0; + return 0; +} + +int MtdSave(struct drive *drive) { + MtdData *mtd = &drive->mtd; + + mtd->primary.crc32 = 0; + mtd->primary.crc32 = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE); + + return FlashSet(MTD_DRIVE_SIGNATURE, (uint8_t *)&mtd->primary, + sizeof(mtd->primary)); +} + +int GptLoad(struct drive *drive, uint32_t sector_bytes) { + drive->gpt.sector_bytes = sector_bytes; + if (drive->size % drive->gpt.sector_bytes) { + Error("Media size (%llu) is not a multiple of sector size(%d)\n", + (long long unsigned int)drive->size, drive->gpt.sector_bytes); + return -1; + } + drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes; + + // Read the data. + if (CGPT_OK != Load(drive, &drive->gpt.primary_header, + GPT_PMBR_SECTOR, + drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { + return -1; + } + if (CGPT_OK != Load(drive, &drive->gpt.secondary_header, + drive->gpt.drive_sectors - GPT_PMBR_SECTOR, + drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { + return -1; + } + if (CGPT_OK != Load(drive, &drive->gpt.primary_entries, + GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + return -1; + } + if (CGPT_OK != Load(drive, &drive->gpt.secondary_entries, + drive->gpt.drive_sectors - GPT_HEADER_SECTOR + - GPT_ENTRIES_SECTORS, + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + return -1; + } + return 0; +} + +int GptSave(struct drive *drive) { + int errors = 0; + if (drive->gpt.modified & GPT_MODIFIED_HEADER1) { + if (CGPT_OK != Save(drive, drive->gpt.primary_header, + GPT_PMBR_SECTOR, + drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { + errors++; + Error("Cannot write primary header: %s\n", strerror(errno)); + } + } + + if (drive->gpt.modified & GPT_MODIFIED_HEADER2) { + if(CGPT_OK != Save(drive, drive->gpt.secondary_header, + drive->gpt.drive_sectors - GPT_PMBR_SECTOR, + drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { + errors++; + Error("Cannot write secondary header: %s\n", strerror(errno)); + } + } + if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) { + if (CGPT_OK != Save(drive, drive->gpt.primary_entries, + GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + errors++; + Error("Cannot write primary entries: %s\n", strerror(errno)); + } + } + if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) { + if (CGPT_OK != Save(drive, drive->gpt.secondary_entries, + drive->gpt.drive_sectors - GPT_HEADER_SECTOR + - GPT_ENTRIES_SECTORS, + drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + errors++; + Error("Cannot write secondary entries: %s\n", strerror(errno)); + } + } + + if (drive->gpt.primary_header) + free(drive->gpt.primary_header); + drive->gpt.primary_header = 0; + if (drive->gpt.primary_entries) + free(drive->gpt.primary_entries); + drive->gpt.primary_entries = 0; + if (drive->gpt.secondary_header) + free(drive->gpt.secondary_header); + drive->gpt.secondary_header = 0; + if (drive->gpt.secondary_entries) + free(drive->gpt.secondary_entries); + drive->gpt.secondary_entries = 0; + return errors ? -1 : 0; +} + // Opens a block device or file, loads raw GPT data from it. // mode should be O_RDONLY or O_RDWR @@ -159,6 +338,8 @@ static int Save(const int fd, const uint8_t *buf, // Returns CGPT_OK if success and information are stored in 'drive'. */ int DriveOpen(const char *drive_path, struct drive *drive, int mode) { struct stat stat; + uint32_t sector_bytes; + int is_mtd = 0; require(drive_path); require(drive); @@ -166,6 +347,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->is_mtd = is_mtd; drive->fd = open(drive_path, mode | O_LARGEFILE | O_NOFOLLOW); if (drive->fd == -1) { Error("Can't open %s: %s\n", drive_path, strerror(errno)); @@ -181,43 +363,24 @@ int DriveOpen(const char *drive_path, struct drive *drive, int mode) { Error("Can't read drive size from %s: %s\n", drive_path, strerror(errno)); goto error_close; } - if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) { + if (ioctl(drive->fd, BLKSSZGET, §or_bytes) < 0) { Error("Can't read sector size from %s: %s\n", drive_path, strerror(errno)); goto error_close; } } else { - drive->gpt.sector_bytes = 512; /* bytes */ + sector_bytes = 512; /* bytes */ drive->size = stat.st_size; } - if (drive->size % drive->gpt.sector_bytes) { - Error("Media size (%llu) is not a multiple of sector size(%d)\n", - (long long unsigned int)drive->size, drive->gpt.sector_bytes); - goto error_close; - } - drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes; - // Read the data. - if (CGPT_OK != Load(drive->fd, &drive->gpt.primary_header, - GPT_PMBR_SECTOR, - drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { - goto error_close; - } - if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_header, - drive->gpt.drive_sectors - GPT_PMBR_SECTOR, - drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { - goto error_close; - } - if (CGPT_OK != Load(drive->fd, &drive->gpt.primary_entries, - GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { - goto error_close; - } - if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_entries, - drive->gpt.drive_sectors - GPT_HEADER_SECTOR - - GPT_ENTRIES_SECTORS, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { - goto error_close; + if (is_mtd) { + if (MtdLoad(drive, sector_bytes)) { + goto error_close; + } + } else { + if (GptLoad(drive, sector_bytes)) { + goto error_close; + } } // We just load the data. Caller must validate it. @@ -233,38 +396,13 @@ int DriveClose(struct drive *drive, int update_as_needed) { int errors = 0; if (update_as_needed) { - if (drive->gpt.modified & GPT_MODIFIED_HEADER1) { - if (CGPT_OK != Save(drive->fd, drive->gpt.primary_header, - GPT_PMBR_SECTOR, - drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { - errors++; - Error("Cannot write primary header: %s\n", strerror(errno)); - } - } - - if (drive->gpt.modified & GPT_MODIFIED_HEADER2) { - if(CGPT_OK != Save(drive->fd, drive->gpt.secondary_header, - drive->gpt.drive_sectors - GPT_PMBR_SECTOR, - drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) { - errors++; - Error("Cannot write secondary header: %s\n", strerror(errno)); - } - } - if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) { - if (CGPT_OK != Save(drive->fd, drive->gpt.primary_entries, - GPT_PMBR_SECTOR + GPT_HEADER_SECTOR, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + if (drive->is_mtd) { + if (MtdSave(drive)) { errors++; - Error("Cannot write primary entries: %s\n", strerror(errno)); } - } - if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) { - if (CGPT_OK != Save(drive->fd, drive->gpt.secondary_entries, - drive->gpt.drive_sectors - GPT_HEADER_SECTOR - - GPT_ENTRIES_SECTORS, - drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) { + } else { + if (GptSave(drive)) { errors++; - Error("Cannot write secondary entries: %s\n", strerror(errno)); } } } @@ -276,19 +414,6 @@ int DriveClose(struct drive *drive, int update_as_needed) { close(drive->fd); - if (drive->gpt.primary_header) - free(drive->gpt.primary_header); - drive->gpt.primary_header = 0; - if (drive->gpt.primary_entries) - free(drive->gpt.primary_entries); - drive->gpt.primary_entries = 0; - if (drive->gpt.secondary_header) - free(drive->gpt.secondary_header); - drive->gpt.secondary_header = 0; - if (drive->gpt.secondary_entries) - free(drive->gpt.secondary_entries); - drive->gpt.secondary_entries = 0; - return errors ? CGPT_FAILED : CGPT_OK; } |