1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <ctype.h> 7 #include <dirent.h> 8 #include <errno.h> 9 #include <linux/nvram.h> 10 #include <stddef.h> 11 #include <stdint.h> 12 #include <stdio.h> 13 #include <string.h> 14 #include <sys/ioctl.h> 15 #include <sys/stat.h> 16 #include <sys/types.h> 17 #include <unistd.h> 18 19 #include "crossystem.h" 20 #include "crossystem_arch.h" 21 #include "host_common.h" 22 #include "utility.h" 23 #include "vboot_common.h" 24 #include "vboot_nvstorage.h" 25 #include "vboot_struct.h" 26 27 28 /* ACPI constants from Chrome OS Main Processor Firmware Spec */ 29 /* Boot reasons from BINF.0, from early H2C firmware */ 30 /* Unknown */ 31 #define BINF0_UNKNOWN 0 32 /* Normal boot to Chrome OS */ 33 #define BINF0_NORMAL 1 34 /* Developer mode boot (developer mode warning displayed) */ 35 #define BINF0_DEVELOPER 2 36 /* Recovery initiated by user, using recovery button */ 37 #define BINF0_RECOVERY_BUTTON 3 38 /* Recovery initiated by user pressing a key at developer mode warning 39 * screen */ 40 #define BINF0_RECOVERY_DEV_SCREEN_KEY 4 41 /* Recovery caused by BIOS failed signature check (neither rewritable 42 * firmware was valid) */ 43 #define BINF0_RECOVERY_RW_FW_BAD 5 44 /* Recovery caused by no OS kernel detected */ 45 #define BINF0_RECOVERY_NO_OS 6 46 /* Recovery caused by OS kernel failed signature check */ 47 #define BINF0_RECOVERY_BAD_OS 7 48 /* Recovery initiated by OS */ 49 #define BINF0_RECOVERY_OS_INITIATED 8 50 /* OS-initiated S3 diagnostic path (debug mode boot) */ 51 #define BINF0_S3_DIAGNOSTIC_PATH 9 52 /* S3 resume failed */ 53 #define BINF0_S3_RESUME_FAILED 10 54 /* Recovery caused by TPM error */ 55 #define BINF0_RECOVERY_TPM_ERROR 11 56 /* CHSW bitflags */ 57 #define CHSW_RECOVERY_BOOT 0x00000002 58 #define CHSW_RECOVERY_EC_BOOT 0x00000004 59 #define CHSW_DEV_BOOT 0x00000020 60 #define CHSW_WP_BOOT 0x00000200 61 /* CMOS reboot field bitflags */ 62 #define CMOSRF_RECOVERY 0x80 63 #define CMOSRF_DEBUG_RESET 0x40 64 #define CMOSRF_TRY_B 0x20 65 /* GPIO signal types */ 66 #define GPIO_SIGNAL_TYPE_RECOVERY 1 67 #define GPIO_SIGNAL_TYPE_DEV 2 68 #define GPIO_SIGNAL_TYPE_WP 3 69 70 /* Base name for ACPI files */ 71 #define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi" 72 /* Paths for frequently used ACPI files */ 73 #define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF" 74 #define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV" 75 #define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW" 76 #define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP" 77 #define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO" 78 #define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV" 79 #define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT" 80 81 /* Base name for GPIO files */ 82 #define GPIO_BASE_PATH "/sys/class/gpio" 83 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export" 84 85 /* Filename for NVRAM file */ 86 #define NVRAM_PATH "/dev/nvram" 87 88 /* Filename for legacy firmware update tries */ 89 #define NEED_FWUPDATE_PATH "/mnt/stateful_partition/.need_firmware_update" 90 91 /* Filenames for PCI Vendor and Device IDs */ 92 #define PCI_VENDOR_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/vendor" 93 #define PCI_DEVICE_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/device" 94 95 typedef struct PlatformFamily { 96 unsigned int vendor; /* Vendor id value */ 97 unsigned int device; /* Device id value */ 98 const char* platform_string; /* String to return */ 99 } PlatformFamily; 100 101 /* Array of platform family names, terminated with a NULL entry */ 102 const PlatformFamily platform_family_array[] = { 103 {0x8086, 0xA010, "PineTrail"}, 104 {0x8086, 0x3406, "Westmere"}, 105 {0x8086, 0x0104, "SandyBridge"}, /* mobile */ 106 {0x8086, 0x0100, "SandyBridge"}, /* desktop */ 107 {0x8086, 0x0154, "IvyBridge"}, /* mobile */ 108 {0x8086, 0x0150, "IvyBridge"}, /* desktop */ 109 {0x8086, 0x0a04, "Haswell"}, /* ult */ 110 {0x8086, 0x0c04, "Haswell"}, /* mobile */ 111 {0x8086, 0x0f00, "BayTrail"}, /* mobile */ 112 {0x8086, 0x1604, "Broadwell"}, /* ult */ 113 /* Terminate with NULL entry */ 114 {0, 0, 0} 115 }; 116 117 static void VbFixCmosChecksum(FILE* file) { 118 int fd = fileno(file); 119 ioctl(fd, NVRAM_SETCKS); 120 } 121 122 123 static int VbCmosRead(unsigned offs, size_t size, void *ptr) { 124 size_t res; 125 FILE* f; 126 127 f = fopen(NVRAM_PATH, "rb"); 128 if (!f) 129 return -1; 130 131 if (0 != fseek(f, offs, SEEK_SET)) { 132 fclose(f); 133 return -1; 134 } 135 136 res = fread(ptr, size, 1, f); 137 if (1 != res && errno == EIO && ferror(f)) { 138 VbFixCmosChecksum(f); 139 res = fread(ptr, size, 1, f); 140 } 141 142 fclose(f); 143 return (1 == res) ? 0 : -1; 144 } 145 146 147 static int VbCmosWrite(unsigned offs, size_t size, const void *ptr) { 148 size_t res; 149 FILE* f; 150 151 f = fopen(NVRAM_PATH, "w+b"); 152 if (!f) 153 return -1; 154 155 if (0 != fseek(f, offs, SEEK_SET)) { 156 fclose(f); 157 return -1; 158 } 159 160 res = fwrite(ptr, size, 1, f); 161 if (1 != res && errno == EIO && ferror(f)) { 162 VbFixCmosChecksum(f); 163 res = fwrite(ptr, size, 1, f); 164 } 165 166 fclose(f); 167 return (1 == res) ? 0 : -1; 168 } 169 170 171 int VbReadNvStorage(VbNvContext* vnc) { 172 unsigned offs, blksz; 173 174 /* Get the byte offset from VBNV */ 175 if (ReadFileInt(ACPI_VBNV_PATH ".0", &offs) < 0) 176 return -1; 177 if (ReadFileInt(ACPI_VBNV_PATH ".1", &blksz) < 0) 178 return -1; 179 if (VBNV_BLOCK_SIZE > blksz) 180 return -1; /* NV storage block is too small */ 181 182 if (0 != VbCmosRead(offs, VBNV_BLOCK_SIZE, vnc->raw)) 183 return -1; 184 185 return 0; 186 } 187 188 189 int VbWriteNvStorage(VbNvContext* vnc) { 190 unsigned offs, blksz; 191 192 if (!vnc->raw_changed) 193 return 0; /* Nothing changed, so no need to write */ 194 195 /* Get the byte offset from VBNV */ 196 if (ReadFileInt(ACPI_VBNV_PATH ".0", &offs) < 0) 197 return -1; 198 if (ReadFileInt(ACPI_VBNV_PATH ".1", &blksz) < 0) 199 return -1; 200 if (VBNV_BLOCK_SIZE > blksz) 201 return -1; /* NV storage block is too small */ 202 203 if (0 != VbCmosWrite(offs, VBNV_BLOCK_SIZE, vnc->raw)) 204 return -1; 205 206 return 0; 207 } 208 209 210 /* 211 * Get buffer data from ACPI. 212 * 213 * Buffer data is expected to be represented by a file which is a text dump of 214 * the buffer, representing each byte by two hex numbers, space and newline 215 * separated. 216 * 217 * On success, stores the amount of data read in bytes to *buffer_size; on 218 * erros, sets *buffer_size=0. 219 * 220 * Input - ACPI file name to get data from. 221 * 222 * Output: a pointer to AcpiBuffer structure containing the binary 223 * representation of the data. The caller is responsible for 224 * deallocating the pointer, this will take care of both the structure 225 * and the buffer. Null in case of error. 226 */ 227 static uint8_t* VbGetBuffer(const char* filename, int* buffer_size) { 228 FILE* f = NULL; 229 char* file_buffer = NULL; 230 uint8_t* output_buffer = NULL; 231 uint8_t* return_value = NULL; 232 233 /* Assume error until proven otherwise */ 234 if (buffer_size) 235 *buffer_size = 0; 236 237 do { 238 struct stat fs; 239 uint8_t* output_ptr; 240 int rv, i, real_size; 241 int parsed_size = 0; 242 243 rv = stat(filename, &fs); 244 if (rv || !S_ISREG(fs.st_mode)) 245 break; 246 247 f = fopen(filename, "r"); 248 if (!f) 249 break; 250 251 file_buffer = malloc(fs.st_size + 1); 252 if (!file_buffer) 253 break; 254 255 real_size = fread(file_buffer, 1, fs.st_size, f); 256 if (!real_size) 257 break; 258 file_buffer[real_size] = '\0'; 259 260 /* Each byte in the output will replace two characters and a space 261 * in the input, so the output size does not exceed input side/3 262 * (a little less if account for newline characters). */ 263 output_buffer = malloc(real_size/3); 264 if (!output_buffer) 265 break; 266 output_ptr = output_buffer; 267 268 /* process the file contents */ 269 for (i = 0; i < real_size; i++) { 270 char* base, *end; 271 272 base = file_buffer + i; 273 274 if (!isxdigit(*base)) 275 continue; 276 277 output_ptr[parsed_size++] = strtol(base, &end, 16) & 0xff; 278 279 if ((end - base) != 2) 280 /* Input file format error */ 281 break; 282 283 i += 2; /* skip the second character and the following space */ 284 } 285 286 if (i == real_size) { 287 /* all is well */ 288 return_value = output_buffer; 289 output_buffer = NULL; /* prevent it from deallocating */ 290 if (buffer_size) 291 *buffer_size = parsed_size; 292 } 293 } while(0); 294 295 /* wrap up */ 296 if (f) 297 fclose(f); 298 299 if (file_buffer) 300 free(file_buffer); 301 302 if (output_buffer) 303 free(output_buffer); 304 305 return return_value; 306 } 307 308 309 VbSharedDataHeader* VbSharedDataRead(void) { 310 VbSharedDataHeader* sh; 311 int got_size = 0; 312 int expect_size; 313 314 sh = (VbSharedDataHeader*)VbGetBuffer(ACPI_VDAT_PATH, &got_size); 315 if (!sh) 316 return NULL; 317 318 /* Make sure the size is sufficient for the struct version we got. 319 * Check supported old versions first. */ 320 if (1 == sh->struct_version) 321 expect_size = VB_SHARED_DATA_HEADER_SIZE_V1; 322 else { 323 /* There'd better be enough data for the current header size. */ 324 expect_size = sizeof(VbSharedDataHeader); 325 } 326 327 if (got_size < expect_size) { 328 free(sh); 329 return NULL; 330 } 331 if (sh->data_size > got_size) 332 sh->data_size = got_size; /* Truncated read */ 333 334 return sh; 335 } 336 337 338 /* Read the CMOS reboot field in NVRAM. 339 * 340 * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */ 341 static int VbGetCmosRebootField(uint8_t mask) { 342 unsigned chnv; 343 uint8_t nvbyte; 344 345 /* Get the byte offset from CHNV */ 346 if (ReadFileInt(ACPI_CHNV_PATH, &chnv) < 0) 347 return -1; 348 349 if (0 != VbCmosRead(chnv, 1, &nvbyte)) 350 return -1; 351 352 return (nvbyte & mask ? 1 : 0); 353 } 354 355 356 /* Write the CMOS reboot field in NVRAM. 357 * 358 * Sets (value=0) or clears (value!=0) the mask in the byte. 359 * 360 * Returns 0 if success, or -1 if error. */ 361 static int VbSetCmosRebootField(uint8_t mask, int value) { 362 unsigned chnv; 363 uint8_t nvbyte; 364 365 /* Get the byte offset from CHNV */ 366 if (ReadFileInt(ACPI_CHNV_PATH, &chnv) < 0) 367 return -1; 368 369 if (0 != VbCmosRead(chnv, 1, &nvbyte)) 370 return -1; 371 372 /* Set/clear the mask */ 373 if (value) 374 nvbyte |= mask; 375 else 376 nvbyte &= ~mask; 377 378 /* Write the byte back */ 379 if (0 != VbCmosWrite(chnv, 1, &nvbyte)) 380 return -1; 381 382 /* Success */ 383 return 0; 384 } 385 386 387 /* Read the active main firmware type into the destination buffer. 388 * Passed the destination and its size. Returns the destination, or 389 * NULL if error. */ 390 static const char* VbReadMainFwType(char* dest, int size) { 391 unsigned value; 392 393 /* Try reading type from BINF.3 */ 394 if (ReadFileInt(ACPI_BINF_PATH ".3", &value) == 0) { 395 switch(value) { 396 case BINF3_NETBOOT: 397 return StrCopy(dest, "netboot", size); 398 case BINF3_RECOVERY: 399 return StrCopy(dest, "recovery", size); 400 case BINF3_NORMAL: 401 return StrCopy(dest, "normal", size); 402 case BINF3_DEVELOPER: 403 return StrCopy(dest, "developer", size); 404 default: 405 break; /* Fall through to legacy handling */ 406 } 407 } 408 409 /* Fall back to BINF.0 for legacy systems like Mario. */ 410 if (ReadFileInt(ACPI_BINF_PATH ".0", &value) < 0) 411 /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS 412 * firmware. */ 413 return StrCopy(dest, "nonchrome", size); 414 415 switch(value) { 416 case BINF0_NORMAL: 417 return StrCopy(dest, "normal", size); 418 case BINF0_DEVELOPER: 419 return StrCopy(dest, "developer", size); 420 case BINF0_RECOVERY_BUTTON: 421 case BINF0_RECOVERY_DEV_SCREEN_KEY: 422 case BINF0_RECOVERY_RW_FW_BAD: 423 case BINF0_RECOVERY_NO_OS: 424 case BINF0_RECOVERY_BAD_OS: 425 case BINF0_RECOVERY_OS_INITIATED: 426 case BINF0_RECOVERY_TPM_ERROR: 427 /* Assorted flavors of recovery boot reason. */ 428 return StrCopy(dest, "recovery", size); 429 default: 430 /* Other values don't map cleanly to firmware type. */ 431 return NULL; 432 } 433 } 434 435 436 /* Read the recovery reason. Returns the reason code or -1 if error. */ 437 static int VbGetRecoveryReason(void) { 438 unsigned value; 439 440 /* Try reading type from BINF.4 */ 441 if (ReadFileInt(ACPI_BINF_PATH ".4", &value) == 0) 442 return value; 443 444 /* Fall back to BINF.0 for legacy systems like Mario. */ 445 if (ReadFileInt(ACPI_BINF_PATH ".0", &value) < 0) 446 return -1; 447 switch(value) { 448 case BINF0_NORMAL: 449 case BINF0_DEVELOPER: 450 return VBNV_RECOVERY_NOT_REQUESTED; 451 case BINF0_RECOVERY_BUTTON: 452 return VBNV_RECOVERY_RO_MANUAL; 453 case BINF0_RECOVERY_DEV_SCREEN_KEY: 454 return VBNV_RECOVERY_RW_DEV_SCREEN; 455 case BINF0_RECOVERY_RW_FW_BAD: 456 return VBNV_RECOVERY_RO_INVALID_RW; 457 case BINF0_RECOVERY_NO_OS: 458 return VBNV_RECOVERY_RW_NO_OS; 459 case BINF0_RECOVERY_BAD_OS: 460 return VBNV_RECOVERY_RW_INVALID_OS; 461 case BINF0_RECOVERY_OS_INITIATED: 462 return VBNV_RECOVERY_LEGACY; 463 default: 464 /* Other values don't map cleanly to firmware type. */ 465 return -1; 466 } 467 } 468 469 /* Determine the platform family and return it in the dest string. 470 * This uses the PCI Bus 0, Device 0, Function 0 vendor and device id values 471 * taken from sysfs to determine the platform family. This assumes there will 472 * be a unique pair of values here for any given platform. 473 */ 474 static char* ReadPlatformFamilyString(char* dest, int size) { 475 FILE* f; 476 const PlatformFamily* p; 477 unsigned int v = 0xFFFF; 478 unsigned int d = 0xFFFF; 479 480 f = fopen(PCI_VENDOR_ID_PATH, "rt"); 481 if (!f) 482 return NULL; 483 if(fscanf(f, "0x%4x", &v) != 1) 484 return NULL; 485 fclose(f); 486 487 f = fopen(PCI_DEVICE_ID_PATH, "rt"); 488 if (!f) 489 return NULL; 490 if(fscanf(f, "0x%4x", &d) != 1) 491 return NULL; 492 fclose(f); 493 494 for (p = platform_family_array; p->vendor; p++) { 495 if((v == p->vendor) && (d == p->device)) 496 return StrCopy(dest, p->platform_string, size); 497 } 498 499 /* No recognized platform family was found */ 500 return NULL; 501 } 502 503 /* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/, 504 * but <N> and <M> may differ by some offset <O>. To determine that constant, 505 * we look for a directory named /sys/class/gpio/gpiochip<O>/. If there's not 506 * exactly one match for that, we're SOL. 507 */ 508 static int FindGpioChipOffset(unsigned *gpio_num, unsigned *offset, 509 const char *name) { 510 DIR *dir; 511 struct dirent *ent; 512 int match = 0; 513 514 dir = opendir(GPIO_BASE_PATH); 515 if (!dir) { 516 return 0; 517 } 518 519 while(0 != (ent = readdir(dir))) { 520 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { 521 match++; 522 } 523 } 524 525 closedir(dir); 526 return (1 == match); 527 } 528 529 /* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/, 530 * but <N> and <M> may differ by some offset <O>. To determine that constant, 531 * we look for a directory named /sys/class/gpio/gpiochip<O>/ and check for 532 * a 'label' file inside of it to find the expected the controller name. 533 */ 534 static int FindGpioChipOffsetByLabel(unsigned *gpio_num, unsigned *offset, 535 const char *name) { 536 DIR *dir; 537 struct dirent *ent; 538 char filename[128]; 539 char chiplabel[128]; 540 int match = 0; 541 542 dir = opendir(GPIO_BASE_PATH); 543 if (!dir) { 544 return 0; 545 } 546 547 while(0 != (ent = readdir(dir))) { 548 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { 549 /* 550 * Read the file at gpiochip<O>/label to get the identifier 551 * for this bank of GPIOs. 552 */ 553 snprintf(filename, sizeof(filename), "%s/gpiochip%u/label", 554 GPIO_BASE_PATH, *offset); 555 if (ReadFileString(chiplabel, sizeof(chiplabel), filename)) { 556 if (!strncasecmp(chiplabel, name, strlen(name))) 557 match++; 558 } 559 } 560 } 561 562 closedir(dir); 563 return (1 == match); 564 } 565 566 /* BayTrail has 3 sets of GPIO banks. It is expected the firmware exposes 567 * each bank of gpios using a UID in ACPI. Furthermore the gpio number exposed 568 * is relative to the bank. e.g. gpio 6 in the bank specified by UID 3 would 569 * be encoded as 0x2006. 570 * UID | Bank Offset 571 * ----+------------ 572 * 1 | 0x0000 573 * 2 | 0x1000 574 * 3 | 0x2000 575 */ 576 static int BayTrailFindGpioChipOffset(unsigned *gpio_num, unsigned *offset, 577 const char *name) { 578 DIR *dir; 579 struct dirent *ent; 580 unsigned expected_uid; 581 int match = 0; 582 583 /* Obtain relative GPIO number. */ 584 if (*gpio_num >= 0x2000) { 585 *gpio_num -= 0x2000; 586 expected_uid = 3; 587 } else if (*gpio_num >= 0x1000) { 588 *gpio_num -= 0x1000; 589 expected_uid = 2; 590 } else if (*gpio_num >= 0x0000) { 591 *gpio_num -= 0x0000; 592 expected_uid = 1; 593 } else { 594 return 0; 595 } 596 597 dir = opendir(GPIO_BASE_PATH); 598 if (!dir) { 599 return 0; 600 } 601 602 while(0 != (ent = readdir(dir))) { 603 /* For every gpiochip entry determine uid. */ 604 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { 605 char uid_file[128]; 606 unsigned uid_value; 607 snprintf(uid_file, sizeof(uid_file), 608 "%s/gpiochip%u/device/firmware_node/uid", GPIO_BASE_PATH, 609 *offset); 610 if (ReadFileInt(uid_file, &uid_value) < 0) 611 continue; 612 if (expected_uid == uid_value) { 613 match++; 614 break; 615 } 616 } 617 } 618 619 closedir(dir); 620 return (1 == match); 621 } 622 623 624 struct GpioChipset { 625 const char *name; 626 int (*ChipOffsetAndGpioNumber)(unsigned *gpio_num, unsigned *chip_offset, 627 const char *name); 628 }; 629 630 static const struct GpioChipset chipsets_supported[] = { 631 { "NM10", FindGpioChipOffset }, 632 { "CougarPoint", FindGpioChipOffset }, 633 { "PantherPoint", FindGpioChipOffset }, 634 { "LynxPoint", FindGpioChipOffset }, 635 { "PCH-LP", FindGpioChipOffset }, 636 { "INT3437:00", FindGpioChipOffsetByLabel }, 637 { "BayTrail", BayTrailFindGpioChipOffset }, 638 { NULL }, 639 }; 640 641 static const struct GpioChipset *FindChipset(const char *name) { 642 const struct GpioChipset *chipset = &chipsets_supported[0]; 643 644 while (chipset->name != NULL) { 645 if (!strcmp(name, chipset->name)) 646 return chipset; 647 chipset++; 648 } 649 return NULL; 650 } 651 652 /* Read a GPIO of the specified signal type (see ACPI GPIO SignalType). 653 * 654 * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */ 655 static int ReadGpio(unsigned signal_type) { 656 char name[128]; 657 int index = 0; 658 unsigned gpio_type; 659 unsigned active_high; 660 unsigned controller_num; 661 unsigned controller_offset = 0; 662 char controller_name[128]; 663 unsigned value; 664 const struct GpioChipset *chipset; 665 666 /* Scan GPIO.* to find a matching signal type */ 667 for (index = 0; ; index++) { 668 snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH, index); 669 if (ReadFileInt(name, &gpio_type) < 0) 670 return -1; /* Ran out of GPIOs before finding a match */ 671 if (gpio_type == signal_type) 672 break; 673 } 674 675 /* Read attributes and controller info for the GPIO */ 676 snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index); 677 if (ReadFileInt(name, &active_high) < 0) 678 return -1; 679 snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index); 680 if (ReadFileInt(name, &controller_num) < 0) 681 return -1; 682 /* Do not attempt to read GPIO that is set to -1 in ACPI */ 683 if (controller_num == 0xFFFFFFFF) 684 return -1; 685 686 /* Check for chipsets we recognize. */ 687 snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index); 688 if (!ReadFileString(controller_name, sizeof(controller_name), name)) 689 return -1; 690 chipset = FindChipset(controller_name); 691 if (chipset == NULL) 692 return -1; 693 694 /* Modify GPIO number by driver's offset */ 695 if (!chipset->ChipOffsetAndGpioNumber(&controller_num, &controller_offset, 696 chipset->name)) 697 return -1; 698 controller_offset += controller_num; 699 700 /* Try reading the GPIO value */ 701 snprintf(name, sizeof(name), "%s/gpio%d/value", 702 GPIO_BASE_PATH, controller_offset); 703 if (ReadFileInt(name, &value) < 0) { 704 /* Try exporting the GPIO */ 705 FILE* f = fopen(GPIO_EXPORT_PATH, "wt"); 706 if (!f) 707 return -1; 708 fprintf(f, "%u", controller_offset); 709 fclose(f); 710 711 /* Try re-reading the GPIO value */ 712 if (ReadFileInt(name, &value) < 0) 713 return -1; 714 } 715 716 /* Normalize the value read from the kernel in case it is not always 1. */ 717 value = value ? 1 : 0; 718 719 /* Compare the GPIO value with the active value and return 1 if match. */ 720 return (value == active_high ? 1 : 0); 721 } 722 723 724 int VbGetArchPropertyInt(const char* name) { 725 int value = -1; 726 727 /* Values from ACPI */ 728 if (!strcasecmp(name,"fmap_base")) { 729 unsigned fmap_base; 730 if (ReadFileInt(ACPI_FMAP_PATH, &fmap_base) < 0) 731 return -1; 732 else 733 value = (int)fmap_base; 734 } 735 736 /* Switch positions */ 737 if (!strcasecmp(name,"devsw_cur")) { 738 /* Systems with virtual developer switches return at-boot value */ 739 int flags = VbGetSystemPropertyInt("vdat_flags"); 740 if ((flags != -1) && (flags & VBSD_HONOR_VIRT_DEV_SWITCH)) 741 value = VbGetSystemPropertyInt("devsw_boot"); 742 else 743 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV); 744 } else if (!strcasecmp(name,"recoverysw_cur")) { 745 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY); 746 } else if (!strcasecmp(name,"wpsw_cur")) { 747 value = ReadGpio(GPIO_SIGNAL_TYPE_WP); 748 if (-1 != value && FwidStartsWith("Mario.")) 749 value = 1 - value; /* Mario reports this backwards */ 750 } else if (!strcasecmp(name,"recoverysw_ec_boot")) { 751 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT); 752 } 753 754 /* Fields for old systems which don't have VbSharedData */ 755 if (VbSharedDataVersion() < 2) { 756 if (!strcasecmp(name,"recovery_reason")) { 757 value = VbGetRecoveryReason(); 758 } else if (!strcasecmp(name,"devsw_boot")) { 759 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT); 760 } else if (!strcasecmp(name,"recoverysw_boot")) { 761 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT); 762 } else if (!strcasecmp(name,"wpsw_boot")) { 763 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT); 764 if (-1 != value && FwidStartsWith("Mario.")) 765 value = 1 - value; /* Mario reports this backwards */ 766 } 767 } 768 769 /* Saved memory is at a fixed location for all H2C BIOS. If the CHSW 770 * path exists in sysfs, it's a H2C BIOS. */ 771 if (!strcasecmp(name,"savedmem_base")) { 772 unsigned savedmem_base; 773 if (ReadFileInt(ACPI_CHSW_PATH, &savedmem_base) < 0) 774 return -1; 775 else 776 return 0x00F00000; 777 } else if (!strcasecmp(name,"savedmem_size")) { 778 unsigned savedmem_size; 779 if (ReadFileInt(ACPI_CHSW_PATH, &savedmem_size) < 0) 780 return -1; 781 else 782 return 0x00100000; 783 } 784 785 /* NV storage values. If unable to get from NV storage, fall back to the 786 * CMOS reboot field used by older BIOS (e.g. Mario). */ 787 if (!strcasecmp(name,"recovery_request")) { 788 value = VbGetNvStorage(VBNV_RECOVERY_REQUEST); 789 if (-1 == value) 790 value = VbGetCmosRebootField(CMOSRF_RECOVERY); 791 } else if (!strcasecmp(name,"dbg_reset")) { 792 value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE); 793 if (-1 == value) 794 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); 795 } else if (!strcasecmp(name,"fwb_tries")) { 796 value = VbGetNvStorage(VBNV_TRY_B_COUNT); 797 if (-1 == value) 798 value = VbGetCmosRebootField(CMOSRF_TRY_B); 799 } 800 801 /* Firmware update tries is now stored in the kernel field. On 802 * older systems where it's not, it was stored in a file in the 803 * stateful partition. */ 804 if (!strcasecmp(name,"fwupdate_tries")) { 805 unsigned fwupdate_value; 806 if (-1 != VbGetNvStorage(VBNV_KERNEL_FIELD)) 807 return -1; /* NvStorage supported; fail through arch-specific 808 * implementation to normal implementation. */ 809 /* Read value from file; missing file means value=0. */ 810 if (ReadFileInt(NEED_FWUPDATE_PATH, &fwupdate_value) < 0) 811 value = 0; 812 else 813 value = (int)fwupdate_value; 814 } 815 816 return value; 817 } 818 819 820 const char* VbGetArchPropertyString(const char* name, char* dest, 821 size_t size) { 822 unsigned value; 823 824 if (!strcasecmp(name,"arch")) { 825 return StrCopy(dest, "x86", size); 826 } else if (!strcasecmp(name,"hwid")) { 827 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID"); 828 } else if (!strcasecmp(name,"fwid")) { 829 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID"); 830 } else if (!strcasecmp(name,"ro_fwid")) { 831 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID"); 832 } else if (!strcasecmp(name,"mainfw_act")) { 833 if (ReadFileInt(ACPI_BINF_PATH ".1", &value) < 0) 834 return NULL; 835 switch(value) { 836 case 0: 837 return StrCopy(dest, "recovery", size); 838 case 1: 839 return StrCopy(dest, "A", size); 840 case 2: 841 return StrCopy(dest, "B", size); 842 default: 843 return NULL; 844 } 845 } else if (!strcasecmp(name,"mainfw_type")) { 846 return VbReadMainFwType(dest, size); 847 } else if (!strcasecmp(name,"ecfw_act")) { 848 if (ReadFileInt(ACPI_BINF_PATH ".2", &value) < 0) 849 return NULL; 850 switch(value) { 851 case 0: 852 return StrCopy(dest, "RO", size); 853 case 1: 854 return StrCopy(dest, "RW", size); 855 default: 856 return NULL; 857 } 858 } else if (!strcasecmp(name,"platform_family")) { 859 return ReadPlatformFamilyString(dest, size); 860 } 861 862 return NULL; 863 } 864 865 866 int VbSetArchPropertyInt(const char* name, int value) { 867 /* NV storage values. If unable to get from NV storage, fall back to the 868 * CMOS reboot field used by older BIOS. */ 869 if (!strcasecmp(name,"recovery_request")) { 870 if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value)) 871 return 0; 872 return VbSetCmosRebootField(CMOSRF_RECOVERY, value); 873 } else if (!strcasecmp(name,"dbg_reset")) { 874 if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value)) 875 return 0; 876 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); 877 } else if (!strcasecmp(name,"fwb_tries")) { 878 if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value)) 879 return 0; 880 return VbSetCmosRebootField(CMOSRF_TRY_B, value); 881 } 882 /* Firmware update tries is now stored in the kernel field. On 883 * older systems where it's not, it was stored in a file in the 884 * stateful partition. */ 885 else if (!strcasecmp(name,"fwupdate_tries")) { 886 if (-1 != VbGetNvStorage(VBNV_KERNEL_FIELD)) 887 return -1; /* NvStorage supported; fail through arch-specific 888 * implementation to normal implementation */ 889 890 if (value) { 891 char buf[32]; 892 snprintf(buf, sizeof(buf), "%d", value); 893 return WriteFile(NEED_FWUPDATE_PATH, buf, strlen(buf)); 894 } else { 895 /* No update tries, so remove file if it exists. */ 896 unlink(NEED_FWUPDATE_PATH); 897 return 0; 898 } 899 } 900 901 return -1; 902 } 903 904 905 int VbSetArchPropertyString(const char* name, const char* value) { 906 /* If there were settable architecture-dependent string properties, 907 * they'd be here. */ 908 return -1; 909 } 910