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 
VbFixCmosChecksum(FILE * file)117 static void VbFixCmosChecksum(FILE* file) {
118   int fd = fileno(file);
119   ioctl(fd, NVRAM_SETCKS);
120 }
121 
122 
VbCmosRead(unsigned offs,size_t size,void * ptr)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 
VbCmosWrite(unsigned offs,size_t size,const void * ptr)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 
VbReadNvStorage(VbNvContext * vnc)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 
VbWriteNvStorage(VbNvContext * vnc)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  */
VbGetBuffer(const char * filename,int * buffer_size)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 
VbSharedDataRead(void)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. */
VbGetCmosRebootField(uint8_t mask)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. */
VbSetCmosRebootField(uint8_t mask,int value)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. */
VbReadMainFwType(char * dest,int size)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. */
VbGetRecoveryReason(void)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  */
ReadPlatformFamilyString(char * dest,int size)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  */
FindGpioChipOffset(unsigned * gpio_num,unsigned * offset,const char * name)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  */
FindGpioChipOffsetByLabel(unsigned * gpio_num,unsigned * offset,const char * name)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  */
BayTrailFindGpioChipOffset(unsigned * gpio_num,unsigned * offset,const char * name)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 
FindChipset(const char * name)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. */
ReadGpio(unsigned signal_type)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 
VbGetArchPropertyInt(const char * name)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 
VbGetArchPropertyString(const char * name,char * dest,size_t size)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 
VbSetArchPropertyInt(const char * name,int value)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 
VbSetArchPropertyString(const char * name,const char * value)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