OLD | NEW |
1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 */ | 4 */ |
5 | 5 |
6 #include <stdio.h> | 6 #include <stdio.h> |
7 #include <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include "host_common.h" | 9 #include "host_common.h" |
10 | 10 |
11 #include "crossystem.h" | 11 #include "crossystem.h" |
12 #include "utility.h" | 12 #include "utility.h" |
13 #include "vboot_common.h" | 13 #include "vboot_common.h" |
14 #include "vboot_nvstorage.h" | 14 #include "vboot_nvstorage.h" |
15 | 15 |
16 /* ACPI constants from Chrome OS Main Processor Firmware Spec */ | 16 /* ACPI constants from Chrome OS Main Processor Firmware Spec */ |
17 /* GPIO signal types */ | 17 /* GPIO signal types */ |
18 #define GPIO_SIGNAL_TYPE_RECOVERY 1 | 18 #define GPIO_SIGNAL_TYPE_RECOVERY 1 |
19 #define GPIO_SIGNAL_TYPE_DEV 2 | 19 #define GPIO_SIGNAL_TYPE_DEV 2 |
20 #define GPIO_SIGNAL_TYPE_WP 3 | 20 #define GPIO_SIGNAL_TYPE_WP 3 |
21 /* CHSW bitflags */ | 21 /* CHSW bitflags */ |
22 #define CHSW_RECOVERY_BOOT 0x00000002 | 22 #define CHSW_RECOVERY_BOOT 0x00000002 |
23 #define CHSW_RECOVERY_EC_BOOT 0x00000004 | 23 #define CHSW_RECOVERY_EC_BOOT 0x00000004 |
24 #define CHSW_DEV_BOOT 0x00000020 | 24 #define CHSW_DEV_BOOT 0x00000020 |
25 #define CHSW_WP_BOOT 0x00000200 | 25 #define CHSW_WP_BOOT 0x00000200 |
26 /* CMOS reboot field bitflags */ | 26 /* CMOS reboot field bitflags */ |
27 #define CMOSRF_RECOVERY 0x80 | 27 #define CMOSRF_RECOVERY 0x80 |
28 #define CMOSRF_DEBUG_RESET 0x40 | 28 #define CMOSRF_DEBUG_RESET 0x40 |
29 #define CMOSRF_TRY_B 0x20 | 29 #define CMOSRF_TRY_B 0x20 |
| 30 /* Boot reasons from BINF.0, from early H2C firmware */ |
| 31 /* Unknown */ |
| 32 #define BINF0_UNKNOWN 0 |
| 33 /* Normal boot to Chrome OS */ |
| 34 #define BINF0_NORMAL 1 |
| 35 /* Developer mode boot (developer mode warning displayed) */ |
| 36 #define BINF0_DEVELOPER 2 |
| 37 /* Recovery initiated by user, using recovery button */ |
| 38 #define BINF0_RECOVERY_BUTTON 3 |
| 39 /* Recovery initiated by user pressing a key at developer mode warning |
| 40 * screen */ |
| 41 #define BINF0_RECOVERY_DEV_SCREEN_KEY 4 |
| 42 /* Recovery caused by BIOS failed signature check (neither rewritable |
| 43 * firmware was valid) */ |
| 44 #define BINF0_RECOVERY_RW_FW_BAD 5 |
| 45 /* Recovery caused by no OS kernel detected */ |
| 46 #define BINF0_RECOVERY_NO_OS 6 |
| 47 /* Recovery caused by OS kernel failed signature check */ |
| 48 #define BINF0_RECOVERY_BAD_OS 7 |
| 49 /* Recovery initiated by OS */ |
| 50 #define BINF0_RECOVERY_OS_INITIATED 8 |
| 51 /* OS-initiated S3 diagnostic path (debug mode boot) */ |
| 52 #define BINF0_S3_DIAGNOSTIC_PATH 9 |
| 53 /* S3 resume failed */ |
| 54 #define BINF0_S3_RESUME_FAILED 10 |
| 55 /* Recovery caused by TPM error */ |
| 56 #define BINF0_RECOVERY_TPM_ERROR 11 |
30 | 57 |
31 /* Base name for ACPI files */ | 58 /* Base name for ACPI files */ |
32 #define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi" | 59 #define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi" |
33 /* Paths for frequently used ACPI files */ | 60 /* Paths for frequently used ACPI files */ |
| 61 #define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF" |
34 #define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV" | 62 #define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV" |
35 #define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW" | 63 #define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW" |
36 #define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO" | 64 #define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO" |
37 | 65 |
38 /* Base name for GPIO files */ | 66 /* Base name for GPIO files */ |
39 #define GPIO_BASE_PATH "/sys/class/gpio" | 67 #define GPIO_BASE_PATH "/sys/class/gpio" |
40 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export" | 68 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export" |
41 | 69 |
42 /* Base name for NVRAM file */ | 70 /* Base name for NVRAM file */ |
43 #define NVRAM_PATH "/dev/nvram" | 71 #define NVRAM_PATH "/dev/nvram" |
44 | 72 |
| 73 |
| 74 /* Copy up to dest_size-1 characters from src to dest, ensuring null |
| 75 termination (which strncpy() doesn't do). Returns the destination |
| 76 string. */ |
| 77 char* StrCopy(char* dest, const char* src, int dest_size) { |
| 78 strncpy(dest, src, dest_size); |
| 79 dest[dest_size - 1] = '\0'; |
| 80 return dest; |
| 81 } |
| 82 |
| 83 |
45 /* Read a string from a file. Passed the destination, dest size, and | 84 /* Read a string from a file. Passed the destination, dest size, and |
46 * filename to read. | 85 * filename to read. |
47 * | 86 * |
48 * Returns the destination, or NULL if error. */ | 87 * Returns the destination, or NULL if error. */ |
49 char* ReadFileString(char* dest, int size, const char* filename) { | 88 char* ReadFileString(char* dest, int size, const char* filename) { |
50 char* got; | 89 char* got; |
51 FILE* f; | 90 FILE* f; |
52 | 91 |
53 f = fopen(filename, "rt"); | 92 f = fopen(filename, "rt"); |
54 if (!f) | 93 if (!f) |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 if (0 != fseek(f, chnv, SEEK_SET) || EOF == (fputc(nvbyte, f))) { | 268 if (0 != fseek(f, chnv, SEEK_SET) || EOF == (fputc(nvbyte, f))) { |
230 fclose(f); | 269 fclose(f); |
231 return -1; | 270 return -1; |
232 } | 271 } |
233 | 272 |
234 /* Success */ | 273 /* Success */ |
235 fclose(f); | 274 fclose(f); |
236 return 0; | 275 return 0; |
237 } | 276 } |
238 | 277 |
| 278 /* Read the recovery reason. Returns the reason code or -1 if error. */ |
| 279 int VbGetRecoveryReason(void) { |
| 280 int value; |
| 281 |
| 282 /* Try reading type from BINF.4 */ |
| 283 value = ReadFileInt(ACPI_BINF_PATH ".4"); |
| 284 if (-1 != value) |
| 285 return value; |
| 286 |
| 287 /* Fall back to BINF.0 for legacy systems like Mario. */ |
| 288 switch(ReadFileInt(ACPI_BINF_PATH ".0")) { |
| 289 case BINF0_NORMAL: |
| 290 case BINF0_DEVELOPER: |
| 291 return VBNV_RECOVERY_NOT_REQUESTED; |
| 292 case BINF0_RECOVERY_BUTTON: |
| 293 return VBNV_RECOVERY_RO_MANUAL; |
| 294 case BINF0_RECOVERY_DEV_SCREEN_KEY: |
| 295 return VBNV_RECOVERY_RW_DEV_SCREEN; |
| 296 case BINF0_RECOVERY_RW_FW_BAD: |
| 297 case BINF0_RECOVERY_NO_OS: |
| 298 return VBNV_RECOVERY_RW_NO_OS; |
| 299 case BINF0_RECOVERY_BAD_OS: |
| 300 return VBNV_RECOVERY_RW_INVALID_OS; |
| 301 case BINF0_RECOVERY_OS_INITIATED: |
| 302 return VBNV_RECOVERY_LEGACY; |
| 303 default: |
| 304 /* Other values don't map cleanly to firmware type. */ |
| 305 return -1; |
| 306 } |
| 307 } |
| 308 |
| 309 |
| 310 /* Read the active main firmware type into the destination buffer. |
| 311 * Passed the destination and its size. Returns the destination, or |
| 312 * NULL if error. */ |
| 313 const char* VbReadMainFwType(char* dest, int size) { |
| 314 |
| 315 /* Try reading type from BINF.3 */ |
| 316 switch(ReadFileInt(ACPI_BINF_PATH ".3")) { |
| 317 case 0: |
| 318 return StrCopy(dest, "recovery", size); |
| 319 case 1: |
| 320 return StrCopy(dest, "normal", size); |
| 321 case 2: |
| 322 return StrCopy(dest, "developer", size); |
| 323 } |
| 324 |
| 325 /* Fall back to BINF.0 for legacy systems like Mario. */ |
| 326 switch(ReadFileInt(ACPI_BINF_PATH ".0")) { |
| 327 case -1: |
| 328 /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS |
| 329 * firmware. */ |
| 330 return StrCopy(dest, "nonchrome", size); |
| 331 case BINF0_NORMAL: |
| 332 return StrCopy(dest, "normal", size); |
| 333 case BINF0_DEVELOPER: |
| 334 return StrCopy(dest, "developer", size); |
| 335 case BINF0_RECOVERY_BUTTON: |
| 336 case BINF0_RECOVERY_DEV_SCREEN_KEY: |
| 337 case BINF0_RECOVERY_RW_FW_BAD: |
| 338 case BINF0_RECOVERY_NO_OS: |
| 339 case BINF0_RECOVERY_BAD_OS: |
| 340 case BINF0_RECOVERY_OS_INITIATED: |
| 341 case BINF0_RECOVERY_TPM_ERROR: |
| 342 /* Assorted flavors of recovery boot reason. */ |
| 343 return StrCopy(dest, "recovery", size); |
| 344 default: |
| 345 /* Other values don't map cleanly to firmware type. */ |
| 346 return NULL; |
| 347 } |
| 348 } |
| 349 |
| 350 |
| 351 |
239 /* Read a system property integer. | 352 /* Read a system property integer. |
240 * | 353 * |
241 * Returns the property value, or -1 if error. */ | 354 * Returns the property value, or -1 if error. */ |
242 int VbGetSystemPropertyInt(const char* name) { | 355 int VbGetSystemPropertyInt(const char* name) { |
243 int value = -1; | 356 int value = -1; |
244 | 357 |
245 /* Switch positions */ | 358 /* Switch positions */ |
246 if (!strcasecmp(name,"devsw_cur")) { | 359 if (!strcasecmp(name,"devsw_cur")) { |
247 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV); | 360 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV); |
248 } else if (!strcasecmp(name,"devsw_boot")) { | 361 } else if (!strcasecmp(name,"devsw_boot")) { |
249 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT); | 362 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT); |
250 } else if (!strcasecmp(name,"recoverysw_cur")) { | 363 } else if (!strcasecmp(name,"recoverysw_cur")) { |
251 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY); | 364 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY); |
252 } else if (!strcasecmp(name,"recoverysw_boot")) { | 365 } else if (!strcasecmp(name,"recoverysw_boot")) { |
253 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT); | 366 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT); |
254 } else if (!strcasecmp(name,"recoverysw_ec_boot")) { | 367 } else if (!strcasecmp(name,"recoverysw_ec_boot")) { |
255 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT); | 368 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT); |
256 } else if (!strcasecmp(name,"wpsw_cur")) { | 369 } else if (!strcasecmp(name,"wpsw_cur")) { |
257 value = ReadGpio(GPIO_SIGNAL_TYPE_WP); | 370 value = ReadGpio(GPIO_SIGNAL_TYPE_WP); |
258 if (-1 != value && FwidStartsWith("Mario.")) | 371 if (-1 != value && FwidStartsWith("Mario.")) |
259 value = 1 - value; /* Mario reports this backwards */ | 372 value = 1 - value; /* Mario reports this backwards */ |
260 } else if (!strcasecmp(name,"wpsw_boot")) { | 373 } else if (!strcasecmp(name,"wpsw_boot")) { |
261 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT); | 374 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT); |
262 if (-1 != value && FwidStartsWith("Mario.")) | 375 if (-1 != value && FwidStartsWith("Mario.")) |
263 value = 1 - value; /* Mario reports this backwards */ | 376 value = 1 - value; /* Mario reports this backwards */ |
264 } | 377 } |
| 378 /* Saved memory is at a fixed location for all H2C BIOS. If the CHSW |
| 379 * path exists in sysfs, it's a H2C BIOS. */ |
| 380 else if (!strcasecmp(name,"savedmem_base")) { |
| 381 return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00F00000); |
| 382 } else if (!strcasecmp(name,"savedmem_size")) { |
| 383 return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00100000); |
| 384 } |
265 /* NV storage values for older H2C BIOS */ | 385 /* NV storage values for older H2C BIOS */ |
266 else if (!strcasecmp(name,"recovery_request")) { | 386 else if (!strcasecmp(name,"recovery_request")) { |
267 value = VbGetCmosRebootField(CMOSRF_RECOVERY); | 387 value = VbGetCmosRebootField(CMOSRF_RECOVERY); |
268 } else if (!strcasecmp(name,"dbg_reset")) { | 388 } else if (!strcasecmp(name,"dbg_reset")) { |
269 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); | 389 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); |
270 } else if (!strcasecmp(name,"fwb_tries")) { | 390 } else if (!strcasecmp(name,"fwb_tries")) { |
271 value = VbGetCmosRebootField(CMOSRF_TRY_B); | 391 value = VbGetCmosRebootField(CMOSRF_TRY_B); |
272 } | 392 } |
| 393 /* Other parameters */ |
| 394 else if (!strcasecmp(name,"recovery_reason")) { |
| 395 return VbGetRecoveryReason(); |
| 396 } |
273 | 397 |
274 /* TODO: remaining properties from spec */ | 398 /* TODO: implement the following properties: |
| 399 * nvram_cleared |
| 400 */ |
275 | 401 |
276 return value; | 402 return value; |
277 } | 403 } |
278 | 404 |
279 | 405 |
280 /* Read a system property string into a destination buffer of the specified | 406 /* Read a system property string into a destination buffer of the specified |
281 * size. | 407 * size. |
282 * | 408 * |
283 * Returns the passed buffer, or NULL if error. */ | 409 * Returns the passed buffer, or NULL if error. */ |
284 const char* VbGetSystemPropertyString(const char* name, char* dest, int size) { | 410 const char* VbGetSystemPropertyString(const char* name, char* dest, int size) { |
285 | 411 |
286 if (!strcasecmp(name,"hwid")) { | 412 if (!strcasecmp(name,"hwid")) { |
287 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID"); | 413 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID"); |
288 } else if (!strcasecmp(name,"fwid")) { | 414 } else if (!strcasecmp(name,"fwid")) { |
289 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID"); | 415 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID"); |
290 } else if (!strcasecmp(name,"ro_fwid")) { | 416 } else if (!strcasecmp(name,"ro_fwid")) { |
291 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID"); | 417 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID"); |
| 418 } else if (!strcasecmp(name,"mainfw_act")) { |
| 419 switch(ReadFileInt(ACPI_BINF_PATH ".1")) { |
| 420 case 0: |
| 421 return StrCopy(dest, "recovery", size); |
| 422 case 1: |
| 423 return StrCopy(dest, "A", size); |
| 424 case 2: |
| 425 return StrCopy(dest, "B", size); |
| 426 default: |
| 427 return NULL; |
| 428 } |
| 429 } else if (!strcasecmp(name,"mainfw_type")) { |
| 430 return VbReadMainFwType(dest, size); |
| 431 } else if (!strcasecmp(name,"ecfw_act")) { |
| 432 switch(ReadFileInt(ACPI_BINF_PATH ".2")) { |
| 433 case 0: |
| 434 return StrCopy(dest, "RO", size); |
| 435 case 1: |
| 436 return StrCopy(dest, "RW", size); |
| 437 default: |
| 438 return NULL; |
| 439 } |
292 } else | 440 } else |
293 return NULL; | 441 return NULL; |
294 | |
295 /* TODO: remaining properties from spec */ | |
296 } | 442 } |
297 | 443 |
298 | 444 |
299 /* Set a system property integer. | 445 /* Set a system property integer. |
300 * | 446 * |
301 * Returns 0 if success, -1 if error. */ | 447 * Returns 0 if success, -1 if error. */ |
302 int VbSetSystemPropertyInt(const char* name, int value) { | 448 int VbSetSystemPropertyInt(const char* name, int value) { |
303 | 449 |
304 /* NV storage values for older H2C BIOS */ | 450 /* NV storage values for older H2C BIOS */ |
305 if (!strcasecmp(name,"recovery_request")) { | 451 if (!strcasecmp(name,"recovery_request")) { |
306 return VbSetCmosRebootField(CMOSRF_RECOVERY, value); | 452 return VbSetCmosRebootField(CMOSRF_RECOVERY, value); |
307 } else if (!strcasecmp(name,"dbg_reset")) { | 453 } else if (!strcasecmp(name,"dbg_reset")) { |
308 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); | 454 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); |
309 } else if (!strcasecmp(name,"fwb_tries")) { | 455 } else if (!strcasecmp(name,"fwb_tries")) { |
310 return VbSetCmosRebootField(CMOSRF_TRY_B, value); | 456 return VbSetCmosRebootField(CMOSRF_TRY_B, value); |
311 } | 457 } |
312 | 458 |
| 459 /* TODO: implement the following: |
| 460 * nvram_cleared |
| 461 */ |
| 462 |
313 return -1; | 463 return -1; |
314 } | 464 } |
315 | 465 |
316 | 466 |
317 /* Set a system property string. | 467 /* Set a system property string. |
318 * | 468 * |
319 * Returns 0 if success, -1 if error. */ | 469 * Returns 0 if success, -1 if error. */ |
320 int VbSetSystemPropertyString(const char* name, const char* value) { | 470 int VbSetSystemPropertyString(const char* name, const char* value) { |
321 | 471 |
322 /* TODO: support setting */ | 472 /* TODO: support setting */ |
323 return -1; | 473 return -1; |
324 } | 474 } |
OLD | NEW |