Home | History | Annotate | Download | only in lib
      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