xref: /aosp_15_r20/external/vboot_reference/host/arch/x86/lib/crossystem_arch.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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