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