OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. | 2 * Copyright (C) 2010 Google Inc. |
3 * | 3 * |
4 * This program is free software; you can redistribute it and/or | 4 * This program is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU General Public License | 5 * modify it under the terms of the GNU General Public License |
6 * as published by the Free Software Foundation; either version 2 | 6 * as published by the Free Software Foundation; either version 2 |
7 * of the License, or (at your option) any later version. | 7 * of the License, or (at your option) any later version. |
8 * | 8 * |
9 * This program is distributed in the hope that it will be useful, | 9 * This program is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with this program; if not, write to the Free Software | 15 * along with this program; if not, write to the Free Software |
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
17 * | 17 * |
18 */ | 18 */ |
19 #include <assert.h> | 19 #include <assert.h> |
20 #include <errno.h> | 20 #include <errno.h> |
| 21 #include <getopt.h> |
21 #include <inttypes.h> | 22 #include <inttypes.h> |
22 #include <stdio.h> | 23 #include <stdio.h> |
23 #include <stdlib.h> | 24 #include <stdlib.h> |
24 #include <string.h> | 25 #include <string.h> |
25 #include <getopt.h> | 26 #include <uuid/uuid.h> |
26 #include "lib/flashrom.h" | 27 #include "lib/flashrom.h" |
27 #include "lib/fmap.h" | 28 #include "lib/fmap.h" |
28 #include "lib/lib_vpd.h" | 29 #include "lib/lib_vpd.h" |
29 #include "lib/lib_smbios.h" | 30 #include "lib/lib_smbios.h" |
30 #include "lib/vpd.h" | 31 #include "lib/vpd.h" |
31 #include "lib/vpd_tables.h" | 32 #include "lib/vpd_tables.h" |
32 | 33 |
33 /* The buffer length. Right now the VPD partition size on flash is 128KB. */ | 34 /* The buffer length. Right now the VPD partition size on flash is 128KB. */ |
34 #define BUF_LEN (128 * 1024) | 35 #define BUF_LEN (128 * 1024) |
35 | 36 |
36 static uint8_t flashrom_tmp_file[] = "/tmp/vpd.flashrom.XXXXXX"; | 37 static uint8_t flashrom_tmp_file[] = "/tmp/vpd.flashrom.XXXXXX"; |
37 | 38 |
38 /* 2 containers: | 39 /* 2 containers: |
39 * file: stores decoded pairs from file. | 40 * file: stores decoded pairs from file. |
40 * argument: stores parsed pairs from command arguments. | 41 * argument: stores parsed pairs from command arguments. |
41 */ | 42 */ |
42 struct PairContainer file; | 43 struct PairContainer file; |
43 struct PairContainer argument; | 44 struct PairContainer argument; |
44 | 45 |
45 /* The current padding length value. | 46 /* The current padding length value. |
46 * Default: VPD_AS_LONG_AS | 47 * Default: VPD_AS_LONG_AS |
47 */ | 48 */ |
48 int pad_value_len = VPD_AS_LONG_AS; | 49 int pad_value_len = VPD_AS_LONG_AS; |
49 | 50 |
50 /* The output buffer */ | 51 /* The output buffer */ |
51 unsigned char buf[BUF_LEN]; | 52 unsigned char buf[BUF_LEN]; |
52 int buf_len = 0; | 53 int buf_len = 0; |
53 int max_buf_len = sizeof(buf); | 54 int max_buf_len = sizeof(buf); |
54 | 55 |
55 /* The EPS base address is used to fill the EPS table entry. */ | 56 /* The EPS base address used to fill the EPS table entry. |
56 uint32_t eps_base = GOOGLE_VPD_2_0_EPS_BASE; | 57 * If the VPD partition can be found in fmap, this points to the starting |
| 58 * offset of VPD partition. If not found, this is used to be the base address |
| 59 * to increase SPD and VPD 2.0 offset fields. |
| 60 * |
| 61 * User can overwrite this by -E argument. |
| 62 */ |
| 63 uint32_t eps_base = GOOGLE_EPS_BASE; |
57 | 64 |
58 /* the fmap name of VPD. */ | 65 /* the fmap name of VPD. */ |
59 uint8_t fmap_vpd_area_name[FMAP_STRLEN] = "RO VPD"; | 66 uint8_t fmap_vpd_area_name[FMAP_STRLEN] = "RO VPD"; |
| 67 |
60 /* If found_vpd, replace the VPD partition when saveFile(). | 68 /* If found_vpd, replace the VPD partition when saveFile(). |
61 * If not found, always create new file when saveFlie(). */ | 69 * If not found, always create new file when saveFlie(). */ |
62 int found_vpd = 0; | 70 int found_vpd = 0; |
63 /* The VPD offset and size in buf[] */ | 71 |
64 off_t vpd_offset = 0, vpd_size = 0; | 72 /* The VPD partition offset and size in buf[]. The whole partition includes: |
| 73 * |
| 74 * SMBIOS EPS |
| 75 * SMBIOS tables[] |
| 76 * SPD |
| 77 * VPD 2.0 data |
| 78 * |
| 79 * For those offset values below, ABSENT means not presented in buffer. |
| 80 */ |
| 81 off_t vpd_offset = 0, vpd_size; /* The whole partition */ |
| 82 /* Below offset are related to vpd_offset and assume positive. |
| 83 * Those are used in saveFile() to write back data. */ |
| 84 off_t eps_offset = 0; /* EPS's starting address. Tables[] is following. */ |
| 85 off_t spd_offset = GOOGLE_SPD_OFFSET; /* SPD address .*/ |
| 86 off_t vpd_2_0_offset = GOOGLE_VPD_2_0_OFFSET; /* VPD 2.0 data address. */ |
| 87 |
| 88 /* This points to the SPD data if it is availiable when loadFile(). |
| 89 * The memory is allocated in loadFile(), will be used in saveFile(), |
| 90 * and freed at end of main(). */ |
| 91 uint8_t *spd_data = NULL; |
| 92 int32_t spd_len = 256; /* max value for DDR3 */ |
65 | 93 |
66 /* for debug purpose */ | 94 /* for debug purpose */ |
67 void dumpBuf() { | 95 void dumpBuf() { |
68 int i; | 96 int i; |
69 for(i = 0; i < buf_len; ++i) { | 97 for(i = 0; i < buf_len; ++i) { |
70 printf("%02x ", buf[i]); | 98 printf("%02x ", buf[i]); |
71 if ((i % 16) == 15) printf("\n"); | 99 if ((i % 16) == 15) printf("\n"); |
72 } | 100 } |
73 } | 101 } |
74 | 102 |
75 | 103 |
76 /* Given the offset of blob block (related to the first byte of EPS) and | 104 /* Given the offset of blob block (related to the first byte of EPS) and |
77 * the size of blob, the is function generates an SMBIOS ESP. | 105 * the size of blob, the is function generates an SMBIOS ESP. |
78 */ | 106 */ |
79 int buildEpsAndTables( | 107 int buildEpsAndTables( |
80 const int offset_blob, | |
81 const int size_blob, | 108 const int size_blob, |
82 const int max_buf_len, | 109 const int max_buf_len, |
83 unsigned char *buf, | 110 unsigned char *buf, |
84 int *generated) { | 111 int *generated) { |
85 struct vpd_entry *eps; | 112 struct vpd_entry *eps; |
86 unsigned char *table = NULL; /* the structure table */ | 113 unsigned char *table = NULL; /* the structure table */ |
87 int table_len = 0; | 114 int table_len = 0; |
88 int num_structures = 0; | 115 int num_structures = 0; |
89 int retval = VPD_OK; | 116 int retval = VPD_OK; |
90 | 117 |
91 assert(buf); | 118 assert(buf); |
92 assert(generated); | 119 assert(generated); |
93 | 120 |
94 buf += *generated; | 121 buf += *generated; |
95 | 122 |
96 /* Generate type 241 */ | 123 /* Generate type 241 - SPD data */ |
97 table_len = vpd_append_type241(0, &table, table_len, | 124 table_len = vpd_append_type241(0, &table, table_len, |
| 125 GOOGLE_SPD_UUID, |
| 126 eps_base + GOOGLE_SPD_OFFSET, |
| 127 spd_len, /* Max length for DDR3 */ |
| 128 GOOGLE_SPD_VENDOR, |
| 129 GOOGLE_SPD_DESCRIPTION, |
| 130 GOOGLE_SPD_VARIANT); |
| 131 if (table_len < 0) { |
| 132 retval = VPD_FAIL; |
| 133 goto error_1; |
| 134 } |
| 135 num_structures++; |
| 136 |
| 137 /* Generate type 241 - VPD 2.0 */ |
| 138 table_len = vpd_append_type241(1, &table, table_len, |
98 GOOGLE_VPD_2_0_UUID, | 139 GOOGLE_VPD_2_0_UUID, |
99 eps_base + offset_blob, | 140 eps_base + GOOGLE_VPD_2_0_OFFSET, |
100 size_blob, | 141 size_blob, |
101 GOOGLE_VPD_2_0_VENDOR, | 142 GOOGLE_VPD_2_0_VENDOR, |
102 GOOGLE_VPD_2_0_DESCRIPTION, | 143 GOOGLE_VPD_2_0_DESCRIPTION, |
103 GOOGLE_VPD_2_0_VARIANT); | 144 GOOGLE_VPD_2_0_VARIANT); |
104 if (table_len < 0) { | 145 if (table_len < 0) { |
105 retval = VPD_FAIL; | 146 retval = VPD_FAIL; |
106 goto error_1; | 147 goto error_1; |
107 } | 148 } |
108 num_structures++; | 149 num_structures++; |
109 | 150 |
110 /* Generate type 127 */ | 151 /* Generate type 127 */ |
111 table_len = vpd_append_type127(1, &table, table_len); | 152 table_len = vpd_append_type127(2, &table, table_len); |
112 if (table_len < 0) { | 153 if (table_len < 0) { |
113 retval = VPD_FAIL; | 154 retval = VPD_FAIL; |
114 goto error_1; | 155 goto error_1; |
115 } | 156 } |
116 num_structures++; | 157 num_structures++; |
117 | 158 |
118 /* Generate EPS */ | 159 /* Generate EPS */ |
119 eps = vpd_create_eps(table_len, num_structures, eps_base); | 160 eps = vpd_create_eps(table_len, num_structures, eps_base); |
120 if ((*generated + eps->entry_length) > max_buf_len) { | 161 if ((*generated + eps->entry_length) > max_buf_len) { |
121 retval = VPD_FAIL; | 162 retval = VPD_FAIL; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 int overwrite_it) { | 212 int overwrite_it) { |
172 FILE *fp; | 213 FILE *fp; |
173 int file_size; | 214 int file_size; |
174 uint8_t *read_buf; | 215 uint8_t *read_buf; |
175 off_t sig_offset; | 216 off_t sig_offset; |
176 struct fmap *fmap; | 217 struct fmap *fmap; |
177 uint8_t *vpd_buf; | 218 uint8_t *vpd_buf; |
178 struct vpd_entry *eps; | 219 struct vpd_entry *eps; |
179 struct vpd_header *header; | 220 struct vpd_header *header; |
180 struct vpd_table_binary_blob_pointer *data; | 221 struct vpd_table_binary_blob_pointer *data; |
| 222 uint8_t spd_uuid[16], vpd_2_0_uuid[16]; |
| 223 int expected_handle = 0; |
| 224 int table_len; |
181 int index; | 225 int index; |
182 int retval = 0; | 226 int retval = 0; |
183 | 227 |
184 if (!(fp = fopen(filename, "r"))) { | 228 if (!(fp = fopen(filename, "r"))) { |
185 fprintf(stderr, "* File [%s] cannot be opened for read. Ignored.\n", | 229 fprintf(stderr, "[WARN] File [%s] cannot be opened for read. Ignored.\n", |
186 filename); | 230 filename); |
187 return 0; | 231 return 0; |
188 } | 232 } |
189 /* get file size */ | 233 /* get file size */ |
190 fseek(fp, 0, SEEK_END); | 234 fseek(fp, 0, SEEK_END); |
191 file_size = ftell(fp); | 235 file_size = ftell(fp); |
192 | 236 |
193 /* read file content */ | 237 /* read file content */ |
194 fseek(fp, 0, SEEK_SET); | 238 fseek(fp, 0, SEEK_SET); |
195 read_buf = malloc(file_size); | 239 read_buf = malloc(file_size); |
196 assert(read_buf); | 240 assert(read_buf); |
197 if (file_size != fread(read_buf, 1, file_size, fp)) { | 241 if (file_size != fread(read_buf, 1, file_size, fp)) { |
198 fprintf(stderr, "Reading file [%s] failed.\n", filename); | 242 fprintf(stderr, "Reading file [%s] failed.\n", filename); |
199 retval = 1; | 243 retval = 1; |
200 goto teardown; | 244 goto teardown; |
201 } | 245 } |
202 fclose(fp); | 246 fclose(fp); |
203 | 247 |
204 /* scan the file and find out the VPD partition. */ | 248 /* scan the file and find out the VPD partition. */ |
205 sig_offset = fmapFind(read_buf, file_size); | 249 sig_offset = fmapFind(read_buf, file_size); |
206 if (-1 == sig_offset) { | 250 if (-1 == sig_offset) { |
207 /* FMAP signature is not found, assume it is pure VPD content. */ | 251 /* FMAP signature is not found, assume it is pure VPD partition. */ |
208 vpd_buf = read_buf; | 252 vpd_buf = read_buf; |
209 eps = (struct vpd_entry *)vpd_buf; | 253 eps = (struct vpd_entry *)vpd_buf; |
210 | 254 |
211 /* In overwrite mode, ignore all existing data. */ | 255 /* In overwrite mode, ignore all existing data. */ |
212 if (overwrite_it) { | 256 if (overwrite_it) { |
213 retval = 0; | 257 retval = 0; |
214 goto teardown; | 258 goto teardown; |
215 } | 259 } |
216 } else { | 260 } else { |
217 int i; | 261 int i; |
218 | 262 |
219 fmap = (struct fmap *)&read_buf[sig_offset]; | 263 fmap = (struct fmap *)&read_buf[sig_offset]; |
220 for(i = 0; i < fmap->nareas; i++) { | 264 for(i = 0; i < fmap->nareas; i++) { |
221 fmapNormalizeAreaName(fmap->areas[i].name); | 265 fmapNormalizeAreaName(fmap->areas[i].name); |
222 } | 266 } |
223 | 267 |
224 if (FMAP_OK == fmapGetArea(fmap_vpd_area_name, fmap, | 268 if (FMAP_OK == fmapGetArea(fmap_vpd_area_name, fmap, |
225 &vpd_offset, &vpd_size)) { | 269 &vpd_offset, &vpd_size)) { |
226 fprintf(stderr, | 270 found_vpd = 1; /* Mark found here then saveFile() knows where to |
227 "FMAP and area are found, eps_base changed from 0x%x to 0x%lx\n", | 271 * write back (vpd_offset, vpd_size). */ |
228 eps_base, vpd_offset); | |
229 eps_base = vpd_offset; | 272 eps_base = vpd_offset; |
230 vpd_buf = &read_buf[vpd_offset]; | 273 vpd_buf = &read_buf[vpd_offset]; |
231 eps = (struct vpd_entry *)vpd_buf; | 274 eps = (struct vpd_entry *)vpd_buf; |
232 | 275 |
233 /* In overwrite mode, the VPD content is erased before reading. */ | 276 /* In overwrite mode, the VPD content is erased before reading. */ |
234 if (overwrite_it) { | 277 if (overwrite_it) { |
235 memset(vpd_buf, 0xff, vpd_size); | 278 retval = 0; |
| 279 goto teardown; |
236 } | 280 } |
237 } else { | 281 } else { |
238 fprintf(stderr, "The VPD partition [%s] is not found.\n", | 282 fprintf(stderr, "The VPD partition [%s] is not found.\n", |
239 fmap_vpd_area_name); | 283 fmap_vpd_area_name); |
240 retval = 1; | 284 retval = 1; |
241 goto teardown; | 285 goto teardown; |
242 } | 286 } |
| 287 } |
| 288 /* Now, vpd_buf points to the VPD partition in buffer. |
| 289 * eps points to the EPS structure, which is usually equal to vpd_buf. */ |
| 290 eps_offset = (uint8_t*)eps - vpd_buf; |
243 | 291 |
244 /* jump if the VPD partition is not recognized. */ | 292 /* jump if the VPD partition is not recognized. */ |
245 if (memcmp(VPD_ENTRY_MAGIC, eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { | 293 if (memcmp(VPD_ENTRY_MAGIC, eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { |
246 /* But OKAY if the VPD partition is all-FF, which is un-used. */ | 294 /* But OKAY if the VPD partition is all-FF, which is un-used. */ |
247 if (memcmp("\xff\xff\xff\xff", eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { | 295 if (memcmp("\xff\xff\xff\xff", eps, sizeof(VPD_ENTRY_MAGIC) - 1)) { |
248 fprintf(stderr, "FMAP found, but SMBIOS signature is not matched.\n"); | 296 fprintf(stderr, "SMBIOS signature is not matched.\n"); |
249 fprintf(stderr, "You may use -O to overwrite the data.\n"); | 297 fprintf(stderr, "You may use -O to overwrite the data.\n"); |
| 298 retval = 1; |
| 299 goto teardown; |
| 300 } |
| 301 /* TODO(yjlou): need more EPS sanity checks here. */ |
| 302 } |
| 303 /* EPS is done above. Parse structure tables below. */ |
| 304 /* Get the first type 241 blob, at the tail of EPS. */ |
| 305 header = (struct vpd_header*)(((uint8_t*)eps) + eps->entry_length); |
| 306 data = (struct vpd_table_binary_blob_pointer *) |
| 307 ((uint8_t *)header + sizeof(*header)); |
| 308 |
| 309 /* TODO(yjlou): Re-factor the parsing code to support more SMBIOS entries. |
| 310 * The current code only supports 2 combinations: |
| 311 * 1. Type 241 (SPD) + Type 241 (VPD 2.0) + Type 127 |
| 312 * 2. Type 241 (VPD 2.0) + Type 127 |
| 313 */ |
| 314 |
| 315 /* Now header points to the first SMBIOS entry, and data points to the |
| 316 * first BBP entry. The first entry could be SPD data. We don't care. */ |
| 317 if (header->handle != expected_handle) { |
| 318 fprintf(stderr, "The first handle value must be 0, but is %d.\n", |
| 319 header->handle); |
| 320 retval = 1; |
| 321 goto teardown; |
| 322 } |
| 323 if (header->type != VPD_TYPE_BINARY_BLOB_POINTER) { |
| 324 fprintf(stderr, "Expect first entry is type Binary Blob Pointer (241)," |
| 325 " but actually is %d\n", header->type); |
| 326 fprintf(stderr, "You may use -O to overwrite the data.\n"); |
| 327 retval = 1; |
| 328 goto teardown; |
| 329 } |
| 330 uuid_parse(GOOGLE_SPD_UUID, spd_uuid); |
| 331 if (!memcmp(data->uuid, spd_uuid, sizeof(data->uuid))) { |
| 332 ++expected_handle; |
| 333 spd_offset = data->offset - eps_base; |
| 334 spd_len = data->size; |
| 335 if (vpd_offset + spd_offset + spd_len >= file_size) { |
| 336 fprintf(stderr, "[ERROR] SPD offset in BBP is not correct.\n" |
| 337 " vpd=0x%x spd=0x%x len=0x%x file_size=0x%x\n" |
| 338 " If this file is VPD partition only, try to\n" |
| 339 " use -E to adjust offset values.\n", |
| 340 (uint32_t)vpd_offset, (uint32_t)spd_offset, |
| 341 spd_len, file_size); |
| 342 retval = 1; |
| 343 goto teardown; |
| 344 } |
| 345 if (!(spd_data = malloc(spd_len))) { |
| 346 fprintf(stderr, "spd_data: malloc(%d bytes) failed.\n", spd_len); |
| 347 retval = 1; |
| 348 goto teardown; |
| 349 } |
| 350 memcpy(spd_data, &read_buf[vpd_offset + spd_offset], spd_len); |
| 351 |
| 352 /* move to next table */ |
| 353 if ((table_len = vpd_type241_size(header)) < 0) { |
| 354 fprintf(stderr, "[ERROR] Cannot get type 241 structure table length.\n"); |
| 355 retval = 1; |
| 356 goto teardown; |
| 357 } |
| 358 header = (struct vpd_header*)((uint8_t*)header + table_len); |
| 359 data = (struct vpd_table_binary_blob_pointer *) |
| 360 ((uint8_t *)header + sizeof(*header)); |
| 361 } |
| 362 |
| 363 /* The 2nd could be VPD 2.0 data or End Of Table. */ |
| 364 if (header->handle != expected_handle) { |
| 365 fprintf(stderr, "The second handle value must be 1, but is %d.\n", |
| 366 header->handle); |
| 367 retval = 1; |
| 368 goto teardown; |
| 369 } |
| 370 uuid_parse(GOOGLE_VPD_2_0_UUID, vpd_2_0_uuid); |
| 371 if (header->type == VPD_TYPE_BINARY_BLOB_POINTER && |
| 372 !memcmp(data->uuid, vpd_2_0_uuid, sizeof(data->uuid))) { |
| 373 ++expected_handle; |
| 374 |
| 375 /* iterate all pairs */ |
| 376 for (index = data->offset - eps_base; /* skip the EPS */ |
| 377 vpd_buf[index] != VPD_TYPE_TERMINATOR && |
| 378 vpd_buf[index] != VPD_TYPE_IMPLICIT_TERMINATOR;) { |
| 379 if (VPD_OK != decodeVpdString(file_size, vpd_buf, container, &index)) { |
| 380 fprintf(stderr, "decodeVpdString() error.\n"); |
250 retval = 1; | 381 retval = 1; |
251 goto teardown; | 382 goto teardown; |
252 } | 383 } |
253 } | 384 } |
254 | 385 |
255 /* mark the VPD is found, so that saveFile() knows where to overwrite | 386 /* move to next table */ |
256 * (vpd_offset, vpd_size). */ | 387 if ((table_len = vpd_type241_size(header)) < 0) { |
257 found_vpd = 1; | 388 fprintf(stderr, "[ERROR] Cannot get type 241 structure table length.\n"); |
258 } | |
259 | |
260 /* Get type 241 blob */ | |
261 header = (struct vpd_header*)(((uint8_t*)eps) + eps->entry_length); | |
262 data = (struct vpd_table_binary_blob_pointer *) | |
263 ((uint8_t *)header + sizeof(*header)); | |
264 | |
265 /* iterate all pairs */ | |
266 for (index = data->offset - eps_base; /* skip the EPS */ | |
267 vpd_buf[index] != VPD_TYPE_TERMINATOR && | |
268 vpd_buf[index] != VPD_TYPE_IMPLICIT_TERMINATOR;) { | |
269 if (VPD_OK != decodeVpdString(file_size, vpd_buf, container, &index)) { | |
270 fprintf(stderr, "decodeVpdString() error.\n"); | |
271 retval = 1; | 389 retval = 1; |
272 goto teardown; | 390 goto teardown; |
273 } | 391 } |
| 392 header = (struct vpd_header*)((uint8_t*)header + table_len); |
| 393 data = (struct vpd_table_binary_blob_pointer *) |
| 394 ((uint8_t *)header + sizeof(*header)); |
| 395 } else { |
| 396 fprintf(stderr, "[WARN] no VPD 2.0 BBP is found, ignored.\n"); |
| 397 retval = 0; |
| 398 goto teardown; |
| 399 } |
| 400 |
| 401 if (header->type != VPD_TYPE_END) { |
| 402 fprintf(stderr, "[WARN] we expect the last one is type 127. Ignored.\n"); |
274 } | 403 } |
275 | 404 |
276 teardown: | 405 teardown: |
277 free(read_buf); | 406 free(read_buf); |
278 | 407 |
279 return retval; | 408 return retval; |
280 } | 409 } |
281 | 410 |
282 | 411 |
283 int saveFile(const struct PairContainer *container, const char *filename) { | 412 int saveFile(const struct PairContainer *container, const char *filename) { |
284 FILE *fp; | 413 FILE *fp; |
285 unsigned char eps[1024]; | 414 unsigned char eps[1024]; |
286 int eps_len = 0; | 415 int eps_len = 0; |
287 int retval = 0; | 416 int retval = 0; |
288 | 417 |
| 418 memset(eps, 0, sizeof(eps)); |
| 419 |
289 /* encode into buffer */ | 420 /* encode into buffer */ |
290 if (VPD_OK != encodeContainer(&file, max_buf_len, buf, &buf_len)) { | 421 if (VPD_OK != encodeContainer(&file, max_buf_len, buf, &buf_len)) { |
291 fprintf(stderr, "encodeContainer() error.\n"); | 422 fprintf(stderr, "encodeContainer() error.\n"); |
292 retval = 1; | 423 retval = 1; |
293 goto teardown; | 424 goto teardown; |
294 } | 425 } |
295 if (VPD_OK != encodeVpdTerminator(max_buf_len, buf, &buf_len)) { | 426 if (VPD_OK != encodeVpdTerminator(max_buf_len, buf, &buf_len)) { |
296 fprintf(stderr, "Out of space for terminator.\n"); | 427 fprintf(stderr, "Out of space for terminator.\n"); |
297 retval = 1; | 428 retval = 1; |
298 goto teardown; | 429 goto teardown; |
299 } | 430 } |
300 | 431 |
301 if (VPD_OK != buildEpsAndTables(GOOGLE_VPD_2_0_OFFSET, buf_len, | 432 if (VPD_OK != buildEpsAndTables(buf_len, sizeof(eps), eps, &eps_len)) { |
302 sizeof(eps), eps, &eps_len)) { | |
303 fprintf(stderr, "Cannot build EPS.\n"); | 433 fprintf(stderr, "Cannot build EPS.\n"); |
304 retval = 1; | 434 retval = 1; |
305 goto teardown; | 435 goto teardown; |
306 } | 436 } |
307 assert(eps_len <= GOOGLE_VPD_2_0_OFFSET); | 437 assert(eps_len <= GOOGLE_SPD_OFFSET); |
308 eps_len = GOOGLE_VPD_2_0_OFFSET; | |
309 | 438 |
| 439 /* Write data in the following order: |
| 440 * 1. EPS |
| 441 * 2. SPD |
| 442 * 3. VPD 2.0 |
| 443 */ |
310 if (found_vpd) { | 444 if (found_vpd) { |
311 /* We found VPD in file, which means file is existed. | 445 /* We found VPD partition in -f file, which means file is existed. |
312 * Instead of truncating the whole file, open to write partial. */ | 446 * Instead of truncating the whole file, open to write partial. */ |
313 if (!(fp = fopen(filename, "r+"))) { | 447 if (!(fp = fopen(filename, "r+"))) { |
314 fprintf(stderr, "File [%s] cannot be opened for write.\n", filename); | 448 fprintf(stderr, "File [%s] cannot be opened for write.\n", filename); |
315 retval = 1; | 449 retval = 1; |
316 goto teardown; | 450 goto teardown; |
317 } | 451 } |
318 /* Move file cursor to VPD section */ | |
319 if (fseek(fp, vpd_offset, SEEK_SET)) { | |
320 fprintf(stderr,"fseek(0x%lx) error: %s\n", vpd_offset, strerror(errno)); | |
321 retval = 1; | |
322 goto teardown; | |
323 } | |
324 } else { | 452 } else { |
325 /* VPD is not found, which means the file is pure VPD data. | 453 /* VPD is not found, which means the file is pure VPD data. |
326 * Always creates the new file and overwrites the original content. */ | 454 * Always creates the new file and overwrites the original content. */ |
327 if (!(fp = fopen(filename, "w+"))) { | 455 if (!(fp = fopen(filename, "w+"))) { |
328 fprintf(stderr, "File [%s] cannot be opened for write.\n", filename); | 456 fprintf(stderr, "File [%s] cannot be opened for write.\n", filename); |
329 retval = 1; | 457 retval = 1; |
330 goto teardown; | 458 goto teardown; |
331 } | 459 } |
332 } | 460 } |
| 461 |
| 462 /* write EPS */ |
| 463 fseek(fp, vpd_offset + eps_offset, SEEK_SET); |
333 if (fwrite(eps, eps_len, 1, fp) != 1) { | 464 if (fwrite(eps, eps_len, 1, fp) != 1) { |
334 fprintf(stderr, "fwrite(EPS) error (%s)\n", strerror(errno)); | 465 fprintf(stderr, "fwrite(EPS) error (%s)\n", strerror(errno)); |
335 retval = 1; | 466 retval = 1; |
336 goto teardown; | 467 goto teardown; |
337 } | 468 } |
| 469 |
| 470 /* write SPD */ |
| 471 if (spd_data) { |
| 472 fseek(fp, vpd_offset + spd_offset, SEEK_SET); |
| 473 if (fwrite(spd_data, spd_len, 1, fp) != 1) { |
| 474 fprintf(stderr, "fwrite(SPD) error (%s)\n", strerror(errno)); |
| 475 retval = 1; |
| 476 goto teardown; |
| 477 } |
| 478 } |
| 479 |
| 480 /* write VPD 2.0 */ |
| 481 fseek(fp, vpd_offset + vpd_2_0_offset, SEEK_SET); |
338 if (fwrite(buf, buf_len, 1, fp) != 1) { | 482 if (fwrite(buf, buf_len, 1, fp) != 1) { |
339 fprintf(stderr, "fwrite(VPD) error (%s)\n", strerror(errno)); | 483 fprintf(stderr, "fwrite(VPD 2.0) error (%s)\n", strerror(errno)); |
340 retval = 1; | 484 retval = 1; |
341 goto teardown; | 485 goto teardown; |
342 } | 486 } |
343 fclose(fp); | 487 fclose(fp); |
344 | 488 |
345 teardown: | 489 teardown: |
346 return retval; | 490 return retval; |
347 } | 491 } |
348 | 492 |
349 | 493 |
350 static void usage(const char *progname) { | 494 static void usage(const char *progname) { |
351 printf("Chrome OS VPD 2.0 utility --\n"); | 495 printf("Chrome OS VPD 2.0 utility --\n"); |
352 #ifdef VPD_VERSION | 496 #ifdef VPD_VERSION |
353 printf("%s\n", VPD_VERSION); | 497 printf("%s\n", VPD_VERSION); |
354 #endif | 498 #endif |
355 printf("\n"); | 499 printf("\n"); |
356 printf("Usage: %s [OPTION] ...\n", progname); | 500 printf("Usage: %s [OPTION] ...\n", progname); |
357 printf(" OPTIONs include:\n"); | 501 printf(" OPTIONs include:\n"); |
358 printf(" -h This help page and version.\n"); | 502 printf(" -h This help page and version.\n"); |
359 printf(" -f <filename> The output file name.\n"); | 503 printf(" -f <filename> The output file name.\n"); |
360 printf(" -E <address> EPS base address (default:0x240000).\n"); | 504 printf(" -E <address> EPS base address (default:0x240000).\n"); |
361 printf(" -s <key=value> To add/change a string value.\n"); | 505 printf(" -s <key=value> To add/change a string value.\n"); |
362 printf(" -p <pad length> Pad if length is shorter.\n"); | 506 printf(" -p <pad length> Pad if length is shorter.\n"); |
363 printf(" -i <partition> Specify VPD partition name in fmap.\n"); | 507 printf(" -i <partition> Specify VPD partition name in fmap.\n"); |
364 printf(" -l List content in the file.\n"); | 508 printf(" -l List content in the file.\n"); |
365 printf(" -O Overwrite current VPD partition.\n"); | 509 printf(" -O Overwrite and re-format VPD partition.\n"); |
366 printf("\n"); | 510 printf("\n"); |
367 } | 511 } |
368 | 512 |
369 int main(int argc, char *argv[]) { | 513 int main(int argc, char *argv[]) { |
370 int opt; | 514 int opt; |
371 int option_index = 0; | 515 int option_index = 0; |
372 int retval = 0; | 516 int retval = 0; |
373 const char *optstring = "hf:E:s:p:i:lO"; | 517 const char *optstring = "hf:E:s:p:i:lO"; |
374 static struct option long_options[] = { | 518 static struct option long_options[] = { |
375 {"help", 0, 0, 'h'}, | 519 {"help", 0, 0, 'h'}, |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 if (write_back_to_flash) { | 657 if (write_back_to_flash) { |
514 if (FLASHROM_OK != flashromPartialWrite(filename, vpd_offset, vpd_size)) { | 658 if (FLASHROM_OK != flashromPartialWrite(filename, vpd_offset, vpd_size)) { |
515 fprintf(stderr, "flashromPartialWrite() error.\n"); | 659 fprintf(stderr, "flashromPartialWrite() error.\n"); |
516 retval = 1; | 660 retval = 1; |
517 goto teardown; | 661 goto teardown; |
518 } | 662 } |
519 } | 663 } |
520 } | 664 } |
521 | 665 |
522 teardown: | 666 teardown: |
| 667 if (spd_data) free(spd_data); |
523 if (filename) free(filename); | 668 if (filename) free(filename); |
524 destroyContainer(&file); | 669 destroyContainer(&file); |
525 destroyContainer(&argument); | 670 destroyContainer(&argument); |
526 | 671 |
527 return retval; | 672 return retval; |
528 } | 673 } |
OLD | NEW |