1 /* Copyright 2012 The ChromiumOS Authors
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 <fcntl.h>
10 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
11 #include <linux/nvram.h>
12 #include <linux/version.h>
13 #endif
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <sys/ioctl.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/utsname.h>
22 #include <unistd.h>
23
24 #include "crossystem_arch.h"
25 #include "crossystem.h"
26 #include "crossystem_vbnv.h"
27 #include "host_common.h"
28 #include "vboot_struct.h"
29
30 /* ACPI constants from Chrome OS Main Processor Firmware Spec */
31 /* Boot reasons from BINF.0, from early H2C firmware */
32 /* Unknown */
33 #define BINF0_UNKNOWN 0
34 /* Normal boot to Chrome OS */
35 #define BINF0_NORMAL 1
36 /* Developer mode boot (developer mode warning displayed) */
37 #define BINF0_DEVELOPER 2
38 /* Recovery initiated by user, using recovery button */
39 #define BINF0_RECOVERY_BUTTON 3
40 /* Recovery initiated by user pressing a key at developer mode warning
41 * screen */
42 #define BINF0_RECOVERY_DEV_SCREEN_KEY 4
43 /* Recovery caused by BIOS failed signature check (neither rewritable
44 * firmware was valid) */
45 #define BINF0_RECOVERY_RW_FW_BAD 5
46 /* Recovery caused by no OS kernel detected */
47 #define BINF0_RECOVERY_NO_OS 6
48 /* Recovery caused by OS kernel failed signature check */
49 #define BINF0_RECOVERY_BAD_OS 7
50 /* Recovery initiated by OS */
51 #define BINF0_RECOVERY_OS_INITIATED 8
52 /* OS-initiated S3 diagnostic path (debug mode boot) */
53 #define BINF0_S3_DIAGNOSTIC_PATH 9
54 /* S3 resume failed */
55 #define BINF0_S3_RESUME_FAILED 10
56 /* Recovery caused by TPM error */
57 #define BINF0_RECOVERY_TPM_ERROR 11
58 /* CHSW bitflags */
59 #define CHSW_RECOVERY_BOOT 0x00000002
60 #define CHSW_RECOVERY_EC_BOOT 0x00000004
61 #define CHSW_DEV_BOOT 0x00000020
62 /* CMOS reboot field bitflags */
63 #define CMOSRF_RECOVERY 0x80
64 #define CMOSRF_DEBUG_RESET 0x40
65 #define CMOSRF_TRY_B 0x20
66 /* GPIO signal types */
67 #define GPIO_SIGNAL_TYPE_RECOVERY 1
68 #define GPIO_SIGNAL_TYPE_DEPRECATED_DEV 2 /* Deprecated; see chromium:942901 */
69 #define GPIO_SIGNAL_TYPE_WP 3
70 #define GPIO_SIGNAL_TYPE_PHASE_ENFORCEMENT 4
71
72 /* Base name for GPIO files */
73 #define GPIO_BASE_PATH "/sys/class/gpio"
74 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
75
76 /* Base for SMBIOS information files */
77 #define SMBIOS_BASE_PATH "/sys/class/dmi/id"
78 #define SMBIOS_PRODUCT_VERSION_PATH SMBIOS_BASE_PATH "/product_version"
79
80 /* Filename for NVRAM file */
81 #define NVRAM_PATH "/dev/nvram"
82
83 /* Filename for legacy firmware update tries */
84 #define NEED_FWUPDATE_PATH "/mnt/stateful_partition/.need_firmware_update"
85
86 /* Filenames for PCI Vendor and Device IDs */
87 #define PCI_VENDOR_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/vendor"
88 #define PCI_DEVICE_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/device"
89
90 typedef struct {
91 unsigned int base;
92 unsigned int uid;
93 } Basemapping;
94
VbFixCmosChecksum(FILE * file)95 static void VbFixCmosChecksum(FILE* file)
96 {
97 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
98 int fd = fileno(file);
99 ioctl(fd, NVRAM_SETCKS);
100 #endif
101 }
102
103
104 /*
105 * Get ChromeOS ACPI sysfs path.
106 *
107 * Note: the returned pointer should be passed to free(3) to release
108 * the allocated storage when it is no longer needed.
109 */
GetAcpiSysfsPath(const char * name)110 static char* GetAcpiSysfsPath(const char* name)
111 {
112 /*
113 * TODO: revert the legacy driver path lookup once all ChromeOS kernels
114 * switch to use CHROMEOS_ACPI.
115 */
116 static const char* legacy_driver_path = "/sys/devices/platform/chromeos_acpi";
117 static const char* legacy_fw_path = "/sys/devices/platform/GGL0001:00";
118 static const char* current_path = "/sys/devices/platform/GOOG0016:00";
119 char* path;
120 struct stat fs;
121 int ret;
122
123 if (stat(legacy_driver_path, &fs) == 0 && S_ISDIR(fs.st_mode))
124 ret = asprintf(&path, "%s/%s", legacy_driver_path, name);
125 else if (stat(legacy_fw_path, &fs) == 0 && S_ISDIR(fs.st_mode))
126 ret = asprintf(&path, "%s/%s", legacy_fw_path, name);
127 else
128 ret = asprintf(&path, "%s/%s", current_path, name);
129
130 return ret == -1 ? NULL : path;
131 }
132
133
ReadAcpiSysfsString(char * dest,int size,const char * name)134 static char* ReadAcpiSysfsString(char* dest, int size, const char* name)
135 {
136 char* path;
137 char* ret;
138
139 path = GetAcpiSysfsPath(name);
140 if (!path)
141 return NULL;
142
143 ret = ReadFileFirstLine(dest, size, path);
144 free(path);
145 return ret;
146 }
147
148
ReadAcpiSysfsInt(const char * name,unsigned * value)149 static int ReadAcpiSysfsInt(const char* name, unsigned* value)
150 {
151 char* path;
152 int ret;
153
154 path = GetAcpiSysfsPath(name);
155 if (!path)
156 return -1;
157
158 ret = ReadFileInt(path, value);
159 free(path);
160 return ret;
161 }
162
163
ReadAcpiSysfsBit(const char * name,int bitmask)164 static int ReadAcpiSysfsBit(const char* name, int bitmask)
165 {
166 char* path;
167 int ret;
168
169 path = GetAcpiSysfsPath(name);
170 if (!path)
171 return -1;
172
173 ret = ReadFileBit(path, bitmask);
174 free(path);
175 return ret;
176 }
177
178
VbCmosRead(unsigned offs,size_t size,void * ptr)179 static int VbCmosRead(unsigned offs, size_t size, void *ptr)
180 {
181 size_t res;
182 FILE* f;
183
184 f = fopen(NVRAM_PATH, "rb");
185 if (!f)
186 return -1;
187
188 if (0 != fseek(f, offs, SEEK_SET)) {
189 fclose(f);
190 return -1;
191 }
192
193 res = fread(ptr, size, 1, f);
194 if (1 != res && errno == EIO && ferror(f)) {
195 VbFixCmosChecksum(f);
196 res = fread(ptr, size, 1, f);
197 }
198
199 fclose(f);
200 return (1 == res) ? 0 : -1;
201 }
202
203
VbCmosWrite(unsigned offs,size_t size,const void * ptr)204 static int VbCmosWrite(unsigned offs, size_t size, const void *ptr)
205 {
206 size_t res;
207 FILE* f;
208
209 f = fopen(NVRAM_PATH, "w+b");
210 if (!f)
211 return -1;
212
213 if (0 != fseek(f, offs, SEEK_SET)) {
214 fclose(f);
215 return -1;
216 }
217
218 res = fwrite(ptr, size, 1, f);
219 if (1 != res && errno == EIO && ferror(f)) {
220 VbFixCmosChecksum(f);
221 res = fwrite(ptr, size, 1, f);
222 }
223
224 fclose(f);
225 return (1 == res) ? 0 : -1;
226 }
227
228
vb2_read_nv_storage(struct vb2_context * ctx)229 int vb2_read_nv_storage(struct vb2_context *ctx)
230 {
231 unsigned offs, blksz;
232 unsigned expectsz = vb2_nv_get_size(ctx);
233
234 /* Get the byte offset from VBNV */
235 if (ReadAcpiSysfsInt("VBNV.0", &offs) < 0)
236 return -1;
237 if (ReadAcpiSysfsInt("VBNV.1", &blksz) < 0)
238 return -1;
239 if (expectsz > blksz)
240 return -1; /* NV storage block is too small */
241
242 if (0 != VbCmosRead(offs, expectsz, ctx->nvdata))
243 return -1;
244
245 return 0;
246 }
247
248
vb2_write_nv_storage(struct vb2_context * ctx)249 int vb2_write_nv_storage(struct vb2_context *ctx)
250 {
251 unsigned offs, blksz;
252 unsigned expectsz = vb2_nv_get_size(ctx);
253
254 if (!(ctx->flags & VB2_CONTEXT_NVDATA_CHANGED))
255 return 0; /* Nothing changed, so no need to write */
256
257 /* Get the byte offset from VBNV */
258 if (ReadAcpiSysfsInt("VBNV.0", &offs) < 0)
259 return -1;
260 if (ReadAcpiSysfsInt("VBNV.1", &blksz) < 0)
261 return -1;
262 if (expectsz > blksz)
263 return -1; /* NV storage block is too small */
264
265 if (0 != VbCmosWrite(offs, expectsz, ctx->nvdata))
266 return -1;
267
268 /* Also attempt to write using flashrom if using vboot2 */
269 VbSharedDataHeader *sh = VbSharedDataRead();
270 if (sh) {
271 if (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2)
272 vb2_write_nv_storage_flashrom(ctx);
273 free(sh);
274 }
275
276 return 0;
277 }
278
279
280 /*
281 * Get buffer data from ACPI.
282 *
283 * Buffer data is expected to be represented by a file which is a text dump of
284 * the buffer, representing each byte by two hex numbers, space and newline
285 * separated.
286 *
287 * On success, stores the amount of data read in bytes to *buffer_size; on
288 * erros, sets *buffer_size=0.
289 *
290 * Input - ACPI file name to get data from.
291 *
292 * Output: a pointer to AcpiBuffer structure containing the binary
293 * representation of the data. The caller is responsible for
294 * deallocating the pointer, this will take care of both the structure
295 * and the buffer. Null in case of error.
296 */
VbGetBuffer(const char * filename,int * buffer_size)297 static uint8_t* VbGetBuffer(const char* filename, int* buffer_size)
298 {
299 FILE* f = NULL;
300 char* file_buffer = NULL;
301 uint8_t* output_buffer = NULL;
302 uint8_t* return_value = NULL;
303
304 /* Assume error until proven otherwise */
305 if (buffer_size)
306 *buffer_size = 0;
307
308 do {
309 struct stat fs;
310 uint8_t* output_ptr;
311 int rv, i, real_size;
312 int parsed_size = 0;
313
314 int fd = open(filename, O_RDONLY);
315 if (fd == -1)
316 break;
317
318 rv = fstat(fd, &fs);
319 if (rv || !S_ISREG(fs.st_mode)) {
320 close(fd);
321 break;
322 }
323
324 f = fdopen(fd, "r");
325 if (!f) {
326 close(fd);
327 break;
328 }
329
330 file_buffer = malloc(fs.st_size + 1);
331 if (!file_buffer)
332 break;
333
334 real_size = fread(file_buffer, 1, fs.st_size, f);
335 if (!real_size)
336 break;
337 file_buffer[real_size] = '\0';
338
339 /* Each byte in the output will replace two characters and a
340 * space in the input, so the output size does not exceed input
341 * side/3 (a little less if account for newline characters). */
342 output_buffer = malloc(real_size/3);
343 if (!output_buffer)
344 break;
345 output_ptr = output_buffer;
346
347 /* process the file contents */
348 for (i = 0; i < real_size; i++) {
349 char* base, *end;
350
351 base = file_buffer + i;
352
353 if (!isxdigit(*base))
354 continue;
355
356 output_ptr[parsed_size++] =
357 strtol(base, &end, 16) & 0xff;
358
359 if ((end - base) != 2)
360 /* Input file format error */
361 break;
362
363 /* skip the second character and the following space */
364 i += 2;
365 }
366
367 if (i == real_size) {
368 /* all is well */
369 return_value = output_buffer;
370 output_buffer = NULL; /* prevent it from deallocating */
371 if (buffer_size)
372 *buffer_size = parsed_size;
373 }
374 } while (0);
375
376 /* wrap up */
377 if (f)
378 fclose(f);
379
380 if (file_buffer)
381 free(file_buffer);
382
383 if (output_buffer)
384 free(output_buffer);
385
386 return return_value;
387 }
388
389
VbSharedDataRead(void)390 VbSharedDataHeader* VbSharedDataRead(void)
391 {
392 VbSharedDataHeader* sh;
393 int got_size = 0;
394 int expect_size;
395 char* path;
396
397 path = GetAcpiSysfsPath("VDAT");
398 if (!path)
399 return NULL;
400
401 sh = (VbSharedDataHeader*)VbGetBuffer(path, &got_size);
402 free(path);
403 if (!sh)
404 return NULL;
405
406 /* Make sure the size is sufficient for the struct version we got.
407 * Check supported old versions first. */
408 if (1 == sh->struct_version)
409 expect_size = VB_SHARED_DATA_HEADER_SIZE_V1;
410 else {
411 /* There'd better be enough data for the current header size. */
412 expect_size = sizeof(VbSharedDataHeader);
413 }
414
415 if (got_size < expect_size) {
416 free(sh);
417 return NULL;
418 }
419 if (sh->data_size > got_size)
420 sh->data_size = got_size; /* Truncated read */
421
422 return sh;
423 }
424
425
426 /* Read the CMOS reboot field in NVRAM.
427 *
428 * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */
VbGetCmosRebootField(uint8_t mask)429 static int VbGetCmosRebootField(uint8_t mask)
430 {
431 unsigned chnv;
432 uint8_t nvbyte;
433
434 /* Get the byte offset from CHNV */
435 if (ReadAcpiSysfsInt("CHNV", &chnv) < 0)
436 return -1;
437
438 if (0 != VbCmosRead(chnv, 1, &nvbyte))
439 return -1;
440
441 return (nvbyte & mask ? 1 : 0);
442 }
443
444
445 /* Write the CMOS reboot field in NVRAM.
446 *
447 * Sets (value=0) or clears (value!=0) the mask in the byte.
448 *
449 * Returns 0 if success, or -1 if error. */
VbSetCmosRebootField(uint8_t mask,int value)450 static int VbSetCmosRebootField(uint8_t mask, int value)
451 {
452 unsigned chnv;
453 uint8_t nvbyte;
454
455 /* Get the byte offset from CHNV */
456 if (ReadAcpiSysfsInt("CHNV", &chnv) < 0)
457 return -1;
458
459 if (0 != VbCmosRead(chnv, 1, &nvbyte))
460 return -1;
461
462 /* Set/clear the mask */
463 if (value)
464 nvbyte |= mask;
465 else
466 nvbyte &= ~mask;
467
468 /* Write the byte back */
469 if (0 != VbCmosWrite(chnv, 1, &nvbyte))
470 return -1;
471
472 /* Success */
473 return 0;
474 }
475
476
477 /* Read the active main firmware type into the destination buffer.
478 * Passed the destination and its size. Returns the destination, or
479 * NULL if error. */
VbReadMainFwType(char * dest,int size)480 static const char* VbReadMainFwType(char* dest, int size)
481 {
482 unsigned value;
483
484 /* Try reading type from BINF.3 */
485 if (ReadAcpiSysfsInt("BINF.3", &value) == 0) {
486 switch(value) {
487 case BINF3_LEGACY:
488 return StrCopy(dest, "legacy", size);
489 case BINF3_NETBOOT:
490 return StrCopy(dest, "netboot", size);
491 case BINF3_RECOVERY:
492 return StrCopy(dest, "recovery", size);
493 case BINF3_NORMAL:
494 return StrCopy(dest, "normal", size);
495 case BINF3_DEVELOPER:
496 return StrCopy(dest, "developer", size);
497 default:
498 break; /* Fall through to legacy handling */
499 }
500 }
501
502 /* Fall back to BINF.0 for legacy systems like Mario. */
503 if (ReadAcpiSysfsInt("BINF.0", &value) < 0)
504 /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS
505 * firmware. */
506 return StrCopy(dest, "nonchrome", size);
507
508 switch(value) {
509 case BINF0_NORMAL:
510 return StrCopy(dest, "normal", size);
511 case BINF0_DEVELOPER:
512 return StrCopy(dest, "developer", size);
513 case BINF0_RECOVERY_BUTTON:
514 case BINF0_RECOVERY_DEV_SCREEN_KEY:
515 case BINF0_RECOVERY_RW_FW_BAD:
516 case BINF0_RECOVERY_NO_OS:
517 case BINF0_RECOVERY_BAD_OS:
518 case BINF0_RECOVERY_OS_INITIATED:
519 case BINF0_RECOVERY_TPM_ERROR:
520 /* Assorted flavors of recovery boot reason. */
521 return StrCopy(dest, "recovery", size);
522 default:
523 /* Other values don't map cleanly to firmware type. */
524 return NULL;
525 }
526 }
527
528
529 /* Read the recovery reason. Returns the reason code or -1 if error. */
VbGetRecoveryReason(void)530 static vb2_error_t VbGetRecoveryReason(void)
531 {
532 unsigned value;
533
534 /* Try reading type from BINF.4 */
535 if (ReadAcpiSysfsInt("BINF.4", &value) == 0)
536 return value;
537
538 /* Fall back to BINF.0 for legacy systems like Mario. */
539 if (ReadAcpiSysfsInt("BINF.0", &value) < 0)
540 return -1;
541 switch(value) {
542 case BINF0_NORMAL:
543 case BINF0_DEVELOPER:
544 return VB2_RECOVERY_NOT_REQUESTED;
545 case BINF0_RECOVERY_BUTTON:
546 return VB2_RECOVERY_RO_MANUAL;
547 case BINF0_RECOVERY_RW_FW_BAD:
548 return VB2_RECOVERY_RO_INVALID_RW;
549 case BINF0_RECOVERY_NO_OS:
550 return VB2_RECOVERY_RW_NO_KERNEL;
551 case BINF0_RECOVERY_BAD_OS:
552 return VB2_RECOVERY_RW_INVALID_OS;
553 case BINF0_RECOVERY_OS_INITIATED:
554 return VB2_RECOVERY_LEGACY;
555 default:
556 /* Other values don't map cleanly to firmware type. */
557 return -1;
558 }
559 }
560
561 /* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/,
562 * but <N> and <M> may differ by some offset <O>. To determine that constant,
563 * we look for a directory named /sys/class/gpio/gpiochip<O>/. If there's not
564 * exactly one match for that, we're SOL.
565 */
FindGpioChipOffset(unsigned * gpio_num,unsigned * offset,const char * name)566 static int FindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
567 const char *name)
568 {
569 DIR *dir;
570 struct dirent *ent;
571 int match = 0;
572
573 dir = opendir(GPIO_BASE_PATH);
574 if (!dir) {
575 return 0;
576 }
577
578 while (0 != (ent = readdir(dir))) {
579 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) {
580 match++;
581 }
582 }
583
584 closedir(dir);
585 return (1 == match);
586 }
587
588 /* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/,
589 * but <N> and <M> may differ by some offset <O>. To determine that constant,
590 * we look for a directory named /sys/class/gpio/gpiochip<O>/ and check for
591 * a 'label' file inside of it to find the expected the controller name.
592 */
FindGpioChipOffsetByLabel(unsigned * gpio_num,unsigned * offset,const char * name)593 static int FindGpioChipOffsetByLabel(unsigned *gpio_num, unsigned *offset,
594 const char *name)
595 {
596 DIR *dir;
597 struct dirent *ent;
598 char filename[128];
599 char chiplabel[128];
600 int match = 0;
601 unsigned controller_offset = 0;
602
603 dir = opendir(GPIO_BASE_PATH);
604 if (!dir) {
605 return 0;
606 }
607
608 while (0 != (ent = readdir(dir))) {
609 if (1 == sscanf(ent->d_name, "gpiochip%u",
610 &controller_offset)) {
611 /*
612 * Read the file at gpiochip<O>/label to get the
613 * identifier for this bank of GPIOs.
614 */
615 snprintf(filename, sizeof(filename),
616 "%s/gpiochip%u/label",
617 GPIO_BASE_PATH, controller_offset);
618 if (ReadFileFirstLine(chiplabel, sizeof(chiplabel),
619 filename)) {
620 if (!strncasecmp(chiplabel, name,
621 strlen(name))) {
622 /*
623 * Store offset when chip label is
624 * matched.
625 */
626 *offset = controller_offset;
627 match++;
628 }
629 }
630 }
631 }
632
633 closedir(dir);
634 return (1 == match);
635 }
636
FindGpioChipOffsetByNumber(unsigned * gpio_num,unsigned * offset,Basemapping * data)637 static int FindGpioChipOffsetByNumber(unsigned *gpio_num, unsigned *offset,
638 Basemapping *data)
639 {
640 DIR *dir;
641 struct dirent *ent;
642 int match = 0;
643
644 /* Obtain relative GPIO number.
645 * The assumption here is the Basemapping
646 * table is arranged in decreasing order of
647 * base address and ends with 0.
648 * A UID with value 0 indicates an invalid range
649 * and causes an early return to avoid the directory
650 * opening code below.
651 */
652 do {
653 if (*gpio_num >= data->base) {
654 *gpio_num -= data->base;
655 break;
656 }
657 data++;
658 } while (1);
659
660 if (data->uid == 0) {
661 return 0;
662 }
663
664 dir = opendir(GPIO_BASE_PATH);
665 if (!dir) {
666 return 0;
667 }
668
669 while (0 != (ent = readdir(dir))) {
670 /* For every gpiochip entry determine uid. */
671 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) {
672 char uid_file[128];
673 unsigned uid_value;
674 snprintf(uid_file, sizeof(uid_file),
675 "%s/gpiochip%u/device/firmware_node/uid",
676 GPIO_BASE_PATH, *offset);
677 if (ReadFileInt(uid_file, &uid_value) < 0)
678 continue;
679 if (data->uid == uid_value) {
680 match++;
681 break;
682 }
683 }
684 }
685
686 closedir(dir);
687 return (1 == match);
688 }
689
690
691 /* Braswell has 4 sets of GPIO banks. It is expected the firmware exposes each
692 * bank of gpios using a UID in ACPI. Furthermore the gpio number exposed is
693 * relative to the bank. e.g. gpio MF_ISH_GPIO_4 in the bank specified by UID 3
694 * would be encoded as 0x10016.
695 *
696 * UID | Bank Offset
697 * ----+------------
698 * 1 | 0x0000
699 * 2 | 0x8000
700 * 3 | 0x10000
701 * 4 | 0x18000
702 */
BraswellFindGpioChipOffset(unsigned * gpio_num,unsigned * offset,const char * name)703 static int BraswellFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
704 const char *name)
705 {
706 int ret;
707 struct utsname host;
708 unsigned int maj, min;
709 int gpe = 0;
710 static Basemapping data[]={
711 {0x20000, 0},
712 {0x18000, 4},
713 {0x10000, 3},
714 {0x08000, 2},
715 {0x00000, 1}};
716
717 /*
718 * This quirk addresses b:143174998 and is required on kernels >= 4.16
719 * when GPIO numbering has changed with an upstream commit:
720 * 03c4749dd6c7ff948a0ce59a44a1b97c015353c2
721 * "gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation".
722 * With that change gpio ACPI/Linux kernel 1:1 mapping was introduced which
723 * made mismatch for gpio number and backward compatibility for user-space.
724 * Details on review commit review
725 * https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2153155
726 */
727
728 /*
729 * Here we are addressing particular wpsw_cur pin which is connected to
730 * East Community GPIO chip (uid == 3, base == 0x10000). In this case there
731 * is only one gap between 11 and 15 (0..11 15..26). For now crosssystem
732 * is not checking pins in other gpio banks, but it is worth to mention that
733 * there are gaps as well.
734 */
735 if (*gpio_num >= 0x10000 && *gpio_num < 0x18000)
736 gpe = 1;
737
738 ret = FindGpioChipOffsetByNumber(gpio_num, offset, data);
739 if (!ret || !gpe)
740 return ret;
741
742 if (uname(&host) == 0) {
743 if (sscanf(host.release, "%u.%u.", &maj, &min) == 2) {
744 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
745 if (KERNEL_VERSION(maj, min, 0) >= KERNEL_VERSION(4, 16, 0) &&
746 *offset > 11)
747 *offset += 3;
748 #endif
749 } else {
750 printf("Couldn't retrieve kernel version!\n");
751 ret = 0;
752 }
753 } else {
754 perror("uname");
755 ret = 0;
756 }
757
758 return ret;
759 }
760
761 /* BayTrail has 3 sets of GPIO banks. It is expected the firmware exposes
762 * each bank of gpios using a UID in ACPI. Furthermore the gpio number exposed
763 * is relative to the bank. e.g. gpio 6 in the bank specified by UID 3 would
764 * be encoded as 0x2006.
765 * UID | Bank Offset
766 * ----+------------
767 * 1 | 0x0000
768 * 2 | 0x1000
769 * 3 | 0x2000
770 */
BayTrailFindGpioChipOffset(unsigned * gpio_num,unsigned * offset,const char * name)771 static int BayTrailFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
772 const char *name)
773 {
774 static Basemapping data[]={
775 {0x3000, 0},
776 {0x2000, 3},
777 {0x1000, 2},
778 {0x0000, 1}};
779
780 return FindGpioChipOffsetByNumber(gpio_num, offset, data);
781 }
782
783 struct GpioChipset {
784 const char *name;
785 int (*ChipOffsetAndGpioNumber)(unsigned *gpio_num,
786 unsigned *chip_offset,
787 const char *name);
788 };
789
790 static const struct GpioChipset chipsets_supported[] = {
791 { "AMD0030", FindGpioChipOffset },
792 { "NM10", FindGpioChipOffset },
793 { "CougarPoint", FindGpioChipOffset },
794 { "PantherPoint", FindGpioChipOffset },
795 { "LynxPoint", FindGpioChipOffset },
796 { "PCH-LP", FindGpioChipOffset },
797 { "INT3437:00", FindGpioChipOffsetByLabel },
798 { "INT344B:00", FindGpioChipOffsetByLabel },
799 /* INT3452 are for Apollolake */
800 { "INT3452:00", FindGpioChipOffsetByLabel },
801 { "INT3452:01", FindGpioChipOffsetByLabel },
802 { "INT3452:02", FindGpioChipOffsetByLabel },
803 { "INT3452:03", FindGpioChipOffsetByLabel },
804 { "INT3455:00", FindGpioChipOffsetByLabel },
805 { "INT34BB:00", FindGpioChipOffsetByLabel },
806 { "INT34C8:00", FindGpioChipOffsetByLabel },
807 { "INT34C5:00", FindGpioChipOffsetByLabel },
808 /* INTC105x are for Alderlake */
809 { "INTC1055:00", FindGpioChipOffsetByLabel },
810 { "INTC1056:00", FindGpioChipOffsetByLabel },
811 { "INTC1057:00", FindGpioChipOffsetByLabel },
812 /* INTC108x are for Meteor Lake */
813 { "INTC1083:00", FindGpioChipOffsetByLabel },
814 /* INTC10Bx are for Panther Lake */
815 { "INTC10BC:00", FindGpioChipOffsetByLabel },
816 /* INT3453 are for GLK */
817 { "INT3453:00", FindGpioChipOffsetByLabel },
818 { "INT3453:01", FindGpioChipOffsetByLabel },
819 { "INT3453:02", FindGpioChipOffsetByLabel },
820 { "INT3453:03", FindGpioChipOffsetByLabel },
821 { "BayTrail", BayTrailFindGpioChipOffset },
822 { "Braswell", BraswellFindGpioChipOffset },
823 { NULL },
824 };
825
FindChipset(const char * name)826 static const struct GpioChipset *FindChipset(const char *name)
827 {
828 const struct GpioChipset *chipset = &chipsets_supported[0];
829
830 while (chipset->name != NULL) {
831 if (!strcmp(name, chipset->name))
832 return chipset;
833 chipset++;
834 }
835 return NULL;
836 }
837
838 /* Read a GPIO of the specified signal type (see ACPI GPIO SignalType).
839 *
840 * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */
ReadGpio(unsigned signal_type)841 static int ReadGpio(unsigned signal_type)
842 {
843 char name[256];
844 int index = 0;
845 unsigned gpio_type;
846 unsigned active_high;
847 unsigned controller_num;
848 unsigned controller_offset = 0;
849 char controller_name[128];
850 unsigned value;
851 const struct GpioChipset *chipset;
852 char base_path[128];
853 char* path;
854
855 path = GetAcpiSysfsPath("GPIO");
856 if (!path)
857 return -1;
858 strncpy(base_path, path, sizeof(base_path) - 1);
859 base_path[sizeof(base_path) - 1] = 0;
860 free(path);
861
862 /* Scan GPIO.* to find a matching signal type */
863 for (index = 0; ; index++) {
864 snprintf(name, sizeof(name), "%s.%d/GPIO.0", base_path, index);
865 if (ReadFileInt(name, &gpio_type) < 0)
866 return -1; /* Ran out of GPIOs before finding a match */
867 if (gpio_type == signal_type)
868 break;
869 }
870
871 /* Read attributes and controller info for the GPIO */
872 snprintf(name, sizeof(name), "%s.%d/GPIO.1", base_path, index);
873 if (ReadFileInt(name, &active_high) < 0)
874 return -1;
875 snprintf(name, sizeof(name), "%s.%d/GPIO.2", base_path, index);
876 if (ReadFileInt(name, &controller_num) < 0)
877 return -1;
878 /* Do not attempt to read GPIO that is set to -1 in ACPI */
879 if (controller_num == 0xFFFFFFFF)
880 return -1;
881
882 /* Check for chipsets we recognize. */
883 snprintf(name, sizeof(name), "%s.%d/GPIO.3", base_path, index);
884 if (!ReadFileFirstLine(controller_name, sizeof(controller_name), name))
885 return -1;
886 chipset = FindChipset(controller_name);
887 if (chipset == NULL)
888 return -1;
889
890 /* Modify GPIO number by driver's offset */
891 if (!chipset->ChipOffsetAndGpioNumber(&controller_num,
892 &controller_offset,
893 chipset->name))
894 return -1;
895 controller_offset += controller_num;
896
897 /* Try reading the GPIO value */
898 snprintf(name, sizeof(name), "%s/gpio%d/value",
899 GPIO_BASE_PATH, controller_offset);
900 if (ReadFileInt(name, &value) < 0) {
901 /* Try exporting the GPIO */
902 FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
903 if (!f)
904 return -1;
905 fprintf(f, "%u", controller_offset);
906 fclose(f);
907
908 /* Try re-reading the GPIO value */
909 if (ReadFileInt(name, &value) < 0)
910 return -1;
911 }
912
913 /* Normalize the value read from the kernel in case it is not always
914 * 1. */
915 value = value ? 1 : 0;
916
917 /* Compare the GPIO value with the active value and return 1 if
918 * match. */
919 return (value == active_high ? 1 : 0);
920 }
921
GetBoardId(void)922 static int GetBoardId(void)
923 {
924 /*
925 * Can't use vb2_read_file here, as it expects to be able to
926 * seek to the end of the file to tell the size, and the sysfs
927 * SMBIOS implementation will seek to offset 4096.
928 */
929 int board_id = -1;
930 FILE *f = fopen(SMBIOS_PRODUCT_VERSION_PATH, "r");
931
932 if (!f)
933 return -1;
934
935 if (fscanf(f, "rev%d\n", &board_id) != 1)
936 board_id = -1;
937
938 fclose(f);
939 return board_id;
940 }
941
VbGetArchPropertyInt(const char * name)942 int VbGetArchPropertyInt(const char* name)
943 {
944 int value = -1;
945
946 /* Switch positions */
947 if (!strcasecmp(name,"devsw_cur")) {
948 /* Systems with virtual developer switches return at-boot
949 * value */
950 value = VbGetSystemPropertyInt("devsw_boot");
951 } else if (!strcasecmp(name,"recoverysw_cur")) {
952 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY);
953 } else if (!strcasecmp(name,"wpsw_cur")) {
954 value = ReadGpio(GPIO_SIGNAL_TYPE_WP);
955 } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
956 value = ReadAcpiSysfsBit("CHSW", CHSW_RECOVERY_EC_BOOT);
957 } else if (!strcasecmp(name,"phase_enforcement")) {
958 value = ReadGpio(GPIO_SIGNAL_TYPE_PHASE_ENFORCEMENT);
959 }
960
961 /* Fields for old systems which don't have VbSharedData */
962 if (VbSharedDataVersion() < 2) {
963 if (!strcasecmp(name,"recovery_reason")) {
964 value = VbGetRecoveryReason();
965 } else if (!strcasecmp(name,"devsw_boot")) {
966 value = ReadAcpiSysfsBit("CHSW", CHSW_DEV_BOOT);
967 } else if (!strcasecmp(name,"recoverysw_boot")) {
968 value = ReadAcpiSysfsBit("CHSW", CHSW_RECOVERY_BOOT);
969 }
970 }
971
972 /* NV storage values. If unable to get from NV storage, fall back to
973 * the CMOS reboot field used by older BIOS (e.g. Mario). */
974 if (!strcasecmp(name,"recovery_request")) {
975 value = vb2_get_nv_storage(VB2_NV_RECOVERY_REQUEST);
976 if (-1 == value)
977 value = VbGetCmosRebootField(CMOSRF_RECOVERY);
978 } else if (!strcasecmp(name,"dbg_reset")) {
979 value = vb2_get_nv_storage(VB2_NV_DEBUG_RESET_MODE);
980 if (-1 == value)
981 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET);
982 }
983
984 /* Firmware update tries is now stored in the kernel field. On
985 * older systems where it's not, it was stored in a file in the
986 * stateful partition. */
987 if (!strcasecmp(name,"fwupdate_tries")) {
988 unsigned fwupdate_value;
989 if (-1 != vb2_get_nv_storage(VB2_NV_KERNEL_FIELD))
990 return -1; /* NvStorage supported; fail through
991 * arch-specific implementation to normal
992 * implementation. */
993 /* Read value from file; missing file means value=0. */
994 if (ReadFileInt(NEED_FWUPDATE_PATH, &fwupdate_value) < 0)
995 value = 0;
996 else
997 value = (int)fwupdate_value;
998 }
999
1000 if (!strcasecmp(name, "board_id"))
1001 return GetBoardId();
1002
1003 return value;
1004 }
1005
1006
VbGetArchPropertyString(const char * name,char * dest,size_t size)1007 const char* VbGetArchPropertyString(const char* name, char* dest,
1008 size_t size)
1009 {
1010 unsigned value;
1011
1012 if (!strcasecmp(name,"arch")) {
1013 return StrCopy(dest, "x86", size);
1014 } else if (!strcasecmp(name,"hwid")) {
1015 return ReadAcpiSysfsString(dest, size, "HWID");
1016 } else if (!strcasecmp(name,"fwid")) {
1017 return ReadAcpiSysfsString(dest, size, "FWID");
1018 } else if (!strcasecmp(name,"ro_fwid")) {
1019 return ReadAcpiSysfsString(dest, size, "FRID");
1020 } else if (!strcasecmp(name,"mainfw_act")) {
1021 if (ReadAcpiSysfsInt("BINF.1", &value) < 0)
1022 return NULL;
1023 switch(value) {
1024 case 0:
1025 return StrCopy(dest, "recovery", size);
1026 case 1:
1027 return StrCopy(dest, "A", size);
1028 case 2:
1029 return StrCopy(dest, "B", size);
1030 default:
1031 return NULL;
1032 }
1033 } else if (!strcasecmp(name,"mainfw_type")) {
1034 return VbReadMainFwType(dest, size);
1035 } else if (!strcasecmp(name,"ecfw_act")) {
1036 if (ReadAcpiSysfsInt("BINF.2", &value) < 0)
1037 return NULL;
1038 switch(value) {
1039 case 0:
1040 return StrCopy(dest, "RO", size);
1041 case 1:
1042 return StrCopy(dest, "RW", size);
1043 default:
1044 return NULL;
1045 }
1046 }
1047
1048 return NULL;
1049 }
1050
1051
VbSetArchPropertyInt(const char * name,int value)1052 int VbSetArchPropertyInt(const char* name, int value)
1053 {
1054 /* NV storage values. If unable to get from NV storage, fall back to
1055 * the CMOS reboot field used by older BIOS. */
1056 if (!strcasecmp(name,"recovery_request")) {
1057 if (0 == vb2_set_nv_storage(VB2_NV_RECOVERY_REQUEST, value))
1058 return 0;
1059 return VbSetCmosRebootField(CMOSRF_RECOVERY, value);
1060 } else if (!strcasecmp(name,"dbg_reset")) {
1061 if (0 == vb2_set_nv_storage(VB2_NV_DEBUG_RESET_MODE, value))
1062 return 0;
1063 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value);
1064 }
1065 /* Firmware update tries is now stored in the kernel field. On
1066 * older systems where it's not, it was stored in a file in the
1067 * stateful partition. */
1068 else if (!strcasecmp(name,"fwupdate_tries")) {
1069 if (-1 != vb2_get_nv_storage(VB2_NV_KERNEL_FIELD))
1070 return -1; /* NvStorage supported; fail through
1071 * arch-specific implementation to normal
1072 * implementation */
1073
1074 if (value) {
1075 char buf[32];
1076 snprintf(buf, sizeof(buf), "%d", value);
1077 return WriteFile(NEED_FWUPDATE_PATH, buf, strlen(buf));
1078 } else {
1079 /* No update tries, so remove file if it exists. */
1080 unlink(NEED_FWUPDATE_PATH);
1081 return 0;
1082 }
1083 }
1084
1085 return -1;
1086 }
1087
VbSetArchPropertyString(const char * name,const char * value)1088 int VbSetArchPropertyString(const char* name, const char* value)
1089 {
1090 /* If there were settable architecture-dependent string properties,
1091 * they'd be here. */
1092 return -1;
1093 }
1094