Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Unified Diff: vpd.c

Issue 6628052: Supports SPD in VPD partition. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/vpd.git@master
Patch Set: refine the logic to next structure table. refine type 241 parameters. Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/lib_smbios.c ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: vpd.c
diff --git a/vpd.c b/vpd.c
index c1397ae5eddde520bf88755dfb3a32f024d3b190..45fbc1d66d319feb170e26c6ff25190a28961725 100644
--- a/vpd.c
+++ b/vpd.c
@@ -18,11 +18,12 @@
*/
#include <assert.h>
#include <errno.h>
+#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <getopt.h>
+#include <uuid/uuid.h>
#include "lib/flashrom.h"
#include "lib/fmap.h"
#include "lib/lib_vpd.h"
@@ -52,16 +53,43 @@ unsigned char buf[BUF_LEN];
int buf_len = 0;
int max_buf_len = sizeof(buf);
-/* The EPS base address is used to fill the EPS table entry. */
-uint32_t eps_base = GOOGLE_VPD_2_0_EPS_BASE;
+/* The EPS base address used to fill the EPS table entry.
+ * If the VPD partition can be found in fmap, this points to the starting
+ * offset of VPD partition. If not found, this is used to be the base address
+ * to increase SPD and VPD 2.0 offset fields.
+ *
+ * User can overwrite this by -E argument.
+ */
+uint32_t eps_base = GOOGLE_EPS_BASE;
/* the fmap name of VPD. */
uint8_t fmap_vpd_area_name[FMAP_STRLEN] = "RO VPD";
+
/* If found_vpd, replace the VPD partition when saveFile().
* If not found, always create new file when saveFlie(). */
int found_vpd = 0;
-/* The VPD offset and size in buf[] */
-off_t vpd_offset = 0, vpd_size = 0;
+
+/* The VPD partition offset and size in buf[]. The whole partition includes:
+ *
+ * SMBIOS EPS
+ * SMBIOS tables[]
+ * SPD
+ * VPD 2.0 data
+ *
+ * For those offset values below, ABSENT means not presented in buffer.
+ */
+off_t vpd_offset = 0, vpd_size; /* The whole partition */
+/* Below offset are related to vpd_offset and assume positive.
+ * Those are used in saveFile() to write back data. */
+off_t eps_offset = 0; /* EPS's starting address. Tables[] is following. */
+off_t spd_offset = GOOGLE_SPD_OFFSET; /* SPD address .*/
+off_t vpd_2_0_offset = GOOGLE_VPD_2_0_OFFSET; /* VPD 2.0 data address. */
+
+/* This points to the SPD data if it is availiable when loadFile().
+ * The memory is allocated in loadFile(), will be used in saveFile(),
+ * and freed at end of main(). */
+uint8_t *spd_data = NULL;
+int32_t spd_len = 256; /* max value for DDR3 */
/* for debug purpose */
void dumpBuf() {
@@ -77,7 +105,6 @@ void dumpBuf() {
* the size of blob, the is function generates an SMBIOS ESP.
*/
int buildEpsAndTables(
- const int offset_blob,
const int size_blob,
const int max_buf_len,
unsigned char *buf,
@@ -93,10 +120,24 @@ int buildEpsAndTables(
buf += *generated;
- /* Generate type 241 */
+ /* Generate type 241 - SPD data */
table_len = vpd_append_type241(0, &table, table_len,
+ GOOGLE_SPD_UUID,
+ eps_base + GOOGLE_SPD_OFFSET,
+ spd_len, /* Max length for DDR3 */
+ GOOGLE_SPD_VENDOR,
+ GOOGLE_SPD_DESCRIPTION,
+ GOOGLE_SPD_VARIANT);
+ if (table_len < 0) {
+ retval = VPD_FAIL;
+ goto error_1;
+ }
+ num_structures++;
+
+ /* Generate type 241 - VPD 2.0 */
+ table_len = vpd_append_type241(1, &table, table_len,
GOOGLE_VPD_2_0_UUID,
- eps_base + offset_blob,
+ eps_base + GOOGLE_VPD_2_0_OFFSET,
size_blob,
GOOGLE_VPD_2_0_VENDOR,
GOOGLE_VPD_2_0_DESCRIPTION,
@@ -108,7 +149,7 @@ int buildEpsAndTables(
num_structures++;
/* Generate type 127 */
- table_len = vpd_append_type127(1, &table, table_len);
+ table_len = vpd_append_type127(2, &table, table_len);
if (table_len < 0) {
retval = VPD_FAIL;
goto error_1;
@@ -178,11 +219,14 @@ int loadFile(const char *filename, struct PairContainer *container,
struct vpd_entry *eps;
struct vpd_header *header;
struct vpd_table_binary_blob_pointer *data;
+ uint8_t spd_uuid[16], vpd_2_0_uuid[16];
+ int expected_handle = 0;
+ int table_len;
int index;
int retval = 0;
if (!(fp = fopen(filename, "r"))) {
- fprintf(stderr, "* File [%s] cannot be opened for read. Ignored.\n",
+ fprintf(stderr, "[WARN] File [%s] cannot be opened for read. Ignored.\n",
filename);
return 0;
}
@@ -204,7 +248,7 @@ int loadFile(const char *filename, struct PairContainer *container,
/* scan the file and find out the VPD partition. */
sig_offset = fmapFind(read_buf, file_size);
if (-1 == sig_offset) {
- /* FMAP signature is not found, assume it is pure VPD content. */
+ /* FMAP signature is not found, assume it is pure VPD partition. */
vpd_buf = read_buf;
eps = (struct vpd_entry *)vpd_buf;
@@ -223,16 +267,16 @@ int loadFile(const char *filename, struct PairContainer *container,
if (FMAP_OK == fmapGetArea(fmap_vpd_area_name, fmap,
&vpd_offset, &vpd_size)) {
- fprintf(stderr,
- "FMAP and area are found, eps_base changed from 0x%x to 0x%lx\n",
- eps_base, vpd_offset);
+ found_vpd = 1; /* Mark found here then saveFile() knows where to
+ * write back (vpd_offset, vpd_size). */
eps_base = vpd_offset;
vpd_buf = &read_buf[vpd_offset];
eps = (struct vpd_entry *)vpd_buf;
/* In overwrite mode, the VPD content is erased before reading. */
if (overwrite_it) {
- memset(vpd_buf, 0xff, vpd_size);
+ retval = 0;
+ goto teardown;
}
} else {
fprintf(stderr, "The VPD partition [%s] is not found.\n",
@@ -240,37 +284,122 @@ int loadFile(const char *filename, struct PairContainer *container,
retval = 1;
goto teardown;
}
-
- /* jump if the VPD partition is not recognized. */
- if (memcmp(VPD_ENTRY_MAGIC, eps, sizeof(VPD_ENTRY_MAGIC) - 1)) {
- /* But OKAY if the VPD partition is all-FF, which is un-used. */
- if (memcmp("\xff\xff\xff\xff", eps, sizeof(VPD_ENTRY_MAGIC) - 1)) {
- fprintf(stderr, "FMAP found, but SMBIOS signature is not matched.\n");
- fprintf(stderr, "You may use -O to overwrite the data.\n");
- retval = 1;
- goto teardown;
- }
+ }
+ /* Now, vpd_buf points to the VPD partition in buffer.
+ * eps points to the EPS structure, which is usually equal to vpd_buf. */
+ eps_offset = (uint8_t*)eps - vpd_buf;
+
+ /* jump if the VPD partition is not recognized. */
+ if (memcmp(VPD_ENTRY_MAGIC, eps, sizeof(VPD_ENTRY_MAGIC) - 1)) {
+ /* But OKAY if the VPD partition is all-FF, which is un-used. */
+ if (memcmp("\xff\xff\xff\xff", eps, sizeof(VPD_ENTRY_MAGIC) - 1)) {
+ fprintf(stderr, "SMBIOS signature is not matched.\n");
+ fprintf(stderr, "You may use -O to overwrite the data.\n");
+ retval = 1;
+ goto teardown;
}
-
- /* mark the VPD is found, so that saveFile() knows where to overwrite
- * (vpd_offset, vpd_size). */
- found_vpd = 1;
+ /* TODO(yjlou): need more EPS sanity checks here. */
}
-
- /* Get type 241 blob */
+ /* EPS is done above. Parse structure tables below. */
+ /* Get the first type 241 blob, at the tail of EPS. */
header = (struct vpd_header*)(((uint8_t*)eps) + eps->entry_length);
data = (struct vpd_table_binary_blob_pointer *)
((uint8_t *)header + sizeof(*header));
- /* iterate all pairs */
- for (index = data->offset - eps_base; /* skip the EPS */
- vpd_buf[index] != VPD_TYPE_TERMINATOR &&
- vpd_buf[index] != VPD_TYPE_IMPLICIT_TERMINATOR;) {
- if (VPD_OK != decodeVpdString(file_size, vpd_buf, container, &index)) {
- fprintf(stderr, "decodeVpdString() error.\n");
+ /* TODO(yjlou): Re-factor the parsing code to support more SMBIOS entries.
+ * The current code only supports 2 combinations:
+ * 1. Type 241 (SPD) + Type 241 (VPD 2.0) + Type 127
+ * 2. Type 241 (VPD 2.0) + Type 127
+ */
+
+ /* Now header points to the first SMBIOS entry, and data points to the
+ * first BBP entry. The first entry could be SPD data. We don't care. */
+ if (header->handle != expected_handle) {
+ fprintf(stderr, "The first handle value must be 0, but is %d.\n",
+ header->handle);
+ retval = 1;
+ goto teardown;
+ }
+ if (header->type != VPD_TYPE_BINARY_BLOB_POINTER) {
+ fprintf(stderr, "Expect first entry is type Binary Blob Pointer (241),"
+ " but actually is %d\n", header->type);
+ fprintf(stderr, "You may use -O to overwrite the data.\n");
+ retval = 1;
+ goto teardown;
+ }
+ uuid_parse(GOOGLE_SPD_UUID, spd_uuid);
+ if (!memcmp(data->uuid, spd_uuid, sizeof(data->uuid))) {
+ ++expected_handle;
+ spd_offset = data->offset - eps_base;
+ spd_len = data->size;
+ if (vpd_offset + spd_offset + spd_len >= file_size) {
+ fprintf(stderr, "[ERROR] SPD offset in BBP is not correct.\n"
+ " vpd=0x%x spd=0x%x len=0x%x file_size=0x%x\n"
+ " If this file is VPD partition only, try to\n"
+ " use -E to adjust offset values.\n",
+ (uint32_t)vpd_offset, (uint32_t)spd_offset,
+ spd_len, file_size);
retval = 1;
goto teardown;
}
+ if (!(spd_data = malloc(spd_len))) {
+ fprintf(stderr, "spd_data: malloc(%d bytes) failed.\n", spd_len);
+ retval = 1;
+ goto teardown;
+ }
+ memcpy(spd_data, &read_buf[vpd_offset + spd_offset], spd_len);
+
+ /* move to next table */
+ if ((table_len = vpd_type241_size(header)) < 0) {
+ fprintf(stderr, "[ERROR] Cannot get type 241 structure table length.\n");
+ retval = 1;
+ goto teardown;
+ }
+ header = (struct vpd_header*)((uint8_t*)header + table_len);
+ data = (struct vpd_table_binary_blob_pointer *)
+ ((uint8_t *)header + sizeof(*header));
+ }
+
+ /* The 2nd could be VPD 2.0 data or End Of Table. */
+ if (header->handle != expected_handle) {
+ fprintf(stderr, "The second handle value must be 1, but is %d.\n",
+ header->handle);
+ retval = 1;
+ goto teardown;
+ }
+ uuid_parse(GOOGLE_VPD_2_0_UUID, vpd_2_0_uuid);
+ if (header->type == VPD_TYPE_BINARY_BLOB_POINTER &&
+ !memcmp(data->uuid, vpd_2_0_uuid, sizeof(data->uuid))) {
+ ++expected_handle;
+
+ /* iterate all pairs */
+ for (index = data->offset - eps_base; /* skip the EPS */
+ vpd_buf[index] != VPD_TYPE_TERMINATOR &&
+ vpd_buf[index] != VPD_TYPE_IMPLICIT_TERMINATOR;) {
+ if (VPD_OK != decodeVpdString(file_size, vpd_buf, container, &index)) {
+ fprintf(stderr, "decodeVpdString() error.\n");
+ retval = 1;
+ goto teardown;
+ }
+ }
+
+ /* move to next table */
+ if ((table_len = vpd_type241_size(header)) < 0) {
+ fprintf(stderr, "[ERROR] Cannot get type 241 structure table length.\n");
+ retval = 1;
+ goto teardown;
+ }
+ header = (struct vpd_header*)((uint8_t*)header + table_len);
+ data = (struct vpd_table_binary_blob_pointer *)
+ ((uint8_t *)header + sizeof(*header));
+ } else {
+ fprintf(stderr, "[WARN] no VPD 2.0 BBP is found, ignored.\n");
+ retval = 0;
+ goto teardown;
+ }
+
+ if (header->type != VPD_TYPE_END) {
+ fprintf(stderr, "[WARN] we expect the last one is type 127. Ignored.\n");
}
teardown:
@@ -286,6 +415,8 @@ int saveFile(const struct PairContainer *container, const char *filename) {
int eps_len = 0;
int retval = 0;
+ memset(eps, 0, sizeof(eps));
+
/* encode into buffer */
if (VPD_OK != encodeContainer(&file, max_buf_len, buf, &buf_len)) {
fprintf(stderr, "encodeContainer() error.\n");
@@ -298,29 +429,26 @@ int saveFile(const struct PairContainer *container, const char *filename) {
goto teardown;
}
- if (VPD_OK != buildEpsAndTables(GOOGLE_VPD_2_0_OFFSET, buf_len,
- sizeof(eps), eps, &eps_len)) {
+ if (VPD_OK != buildEpsAndTables(buf_len, sizeof(eps), eps, &eps_len)) {
fprintf(stderr, "Cannot build EPS.\n");
retval = 1;
goto teardown;
}
- assert(eps_len <= GOOGLE_VPD_2_0_OFFSET);
- eps_len = GOOGLE_VPD_2_0_OFFSET;
+ assert(eps_len <= GOOGLE_SPD_OFFSET);
+ /* Write data in the following order:
+ * 1. EPS
+ * 2. SPD
+ * 3. VPD 2.0
+ */
if (found_vpd) {
- /* We found VPD in file, which means file is existed.
+ /* We found VPD partition in -f file, which means file is existed.
* Instead of truncating the whole file, open to write partial. */
if (!(fp = fopen(filename, "r+"))) {
fprintf(stderr, "File [%s] cannot be opened for write.\n", filename);
retval = 1;
goto teardown;
}
- /* Move file cursor to VPD section */
- if (fseek(fp, vpd_offset, SEEK_SET)) {
- fprintf(stderr,"fseek(0x%lx) error: %s\n", vpd_offset, strerror(errno));
- retval = 1;
- goto teardown;
- }
} else {
/* VPD is not found, which means the file is pure VPD data.
* Always creates the new file and overwrites the original content. */
@@ -330,13 +458,29 @@ int saveFile(const struct PairContainer *container, const char *filename) {
goto teardown;
}
}
+
+ /* write EPS */
+ fseek(fp, vpd_offset + eps_offset, SEEK_SET);
if (fwrite(eps, eps_len, 1, fp) != 1) {
fprintf(stderr, "fwrite(EPS) error (%s)\n", strerror(errno));
retval = 1;
goto teardown;
}
+
+ /* write SPD */
+ if (spd_data) {
+ fseek(fp, vpd_offset + spd_offset, SEEK_SET);
+ if (fwrite(spd_data, spd_len, 1, fp) != 1) {
+ fprintf(stderr, "fwrite(SPD) error (%s)\n", strerror(errno));
+ retval = 1;
+ goto teardown;
+ }
+ }
+
+ /* write VPD 2.0 */
+ fseek(fp, vpd_offset + vpd_2_0_offset, SEEK_SET);
if (fwrite(buf, buf_len, 1, fp) != 1) {
- fprintf(stderr, "fwrite(VPD) error (%s)\n", strerror(errno));
+ fprintf(stderr, "fwrite(VPD 2.0) error (%s)\n", strerror(errno));
retval = 1;
goto teardown;
}
@@ -362,7 +506,7 @@ static void usage(const char *progname) {
printf(" -p <pad length> Pad if length is shorter.\n");
printf(" -i <partition> Specify VPD partition name in fmap.\n");
printf(" -l List content in the file.\n");
- printf(" -O Overwrite current VPD partition.\n");
+ printf(" -O Overwrite and re-format VPD partition.\n");
printf("\n");
}
@@ -520,6 +664,7 @@ int main(int argc, char *argv[]) {
}
teardown:
+ if (spd_data) free(spd_data);
if (filename) free(filename);
destroyContainer(&file);
destroyContainer(&argument);
« no previous file with comments | « lib/lib_smbios.c ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698