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.
9 #include <linux/nvram.h>
14 #include <sys/ioctl.h>
16 #include <sys/types.h>
19 #include "crossystem.h"
20 #include "crossystem_arch.h"
21 #include "crossystem_vbnv.h"
22 #include "host_common.h"
24 #include "vboot_common.h"
25 #include "vboot_nvstorage.h"
26 #include "vboot_struct.h"
29 /* ACPI constants from Chrome OS Main Processor Firmware Spec */
30 /* Boot reasons from BINF.0, from early H2C firmware */
32 #define BINF0_UNKNOWN 0
33 /* Normal boot to Chrome OS */
34 #define BINF0_NORMAL 1
35 /* Developer mode boot (developer mode warning displayed) */
36 #define BINF0_DEVELOPER 2
37 /* Recovery initiated by user, using recovery button */
38 #define BINF0_RECOVERY_BUTTON 3
39 /* Recovery initiated by user pressing a key at developer mode warning
41 #define BINF0_RECOVERY_DEV_SCREEN_KEY 4
42 /* Recovery caused by BIOS failed signature check (neither rewritable
43 * firmware was valid) */
44 #define BINF0_RECOVERY_RW_FW_BAD 5
45 /* Recovery caused by no OS kernel detected */
46 #define BINF0_RECOVERY_NO_OS 6
47 /* Recovery caused by OS kernel failed signature check */
48 #define BINF0_RECOVERY_BAD_OS 7
49 /* Recovery initiated by OS */
50 #define BINF0_RECOVERY_OS_INITIATED 8
51 /* OS-initiated S3 diagnostic path (debug mode boot) */
52 #define BINF0_S3_DIAGNOSTIC_PATH 9
53 /* S3 resume failed */
54 #define BINF0_S3_RESUME_FAILED 10
55 /* Recovery caused by TPM error */
56 #define BINF0_RECOVERY_TPM_ERROR 11
58 #define CHSW_RECOVERY_BOOT 0x00000002
59 #define CHSW_RECOVERY_EC_BOOT 0x00000004
60 #define CHSW_DEV_BOOT 0x00000020
61 #define CHSW_WP_BOOT 0x00000200
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_DEV 2
69 #define GPIO_SIGNAL_TYPE_WP 3
71 /* Base name for ACPI files */
72 #define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi"
73 /* Paths for frequently used ACPI files */
74 #define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF"
75 #define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV"
76 #define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW"
77 #define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP"
78 #define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO"
79 #define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV"
80 #define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT"
82 /* Base name for GPIO files */
83 #define GPIO_BASE_PATH "/sys/class/gpio"
84 #define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
86 /* Filename for NVRAM file */
87 #define NVRAM_PATH "/dev/nvram"
89 /* Filename for legacy firmware update tries */
90 #define NEED_FWUPDATE_PATH "/mnt/stateful_partition/.need_firmware_update"
92 /* Filenames for PCI Vendor and Device IDs */
93 #define PCI_VENDOR_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/vendor"
94 #define PCI_DEVICE_ID_PATH "/sys/bus/pci/devices/0000:00:00.0/device"
101 static void VbFixCmosChecksum(FILE* file) {
102 int fd = fileno(file);
103 ioctl(fd, NVRAM_SETCKS);
107 static int VbCmosRead(unsigned offs, size_t size, void *ptr) {
111 f = fopen(NVRAM_PATH, "rb");
115 if (0 != fseek(f, offs, SEEK_SET)) {
120 res = fread(ptr, size, 1, f);
121 if (1 != res && errno == EIO && ferror(f)) {
122 VbFixCmosChecksum(f);
123 res = fread(ptr, size, 1, f);
127 return (1 == res) ? 0 : -1;
131 static int VbCmosWrite(unsigned offs, size_t size, const void *ptr) {
135 f = fopen(NVRAM_PATH, "w+b");
139 if (0 != fseek(f, offs, SEEK_SET)) {
144 res = fwrite(ptr, size, 1, f);
145 if (1 != res && errno == EIO && ferror(f)) {
146 VbFixCmosChecksum(f);
147 res = fwrite(ptr, size, 1, f);
151 return (1 == res) ? 0 : -1;
155 int VbReadNvStorage(VbNvContext* vnc) {
156 unsigned offs, blksz;
158 /* Get the byte offset from VBNV */
159 if (ReadFileInt(ACPI_VBNV_PATH ".0", &offs) < 0)
161 if (ReadFileInt(ACPI_VBNV_PATH ".1", &blksz) < 0)
163 if (VBNV_BLOCK_SIZE > blksz)
164 return -1; /* NV storage block is too small */
166 if (0 != VbCmosRead(offs, VBNV_BLOCK_SIZE, vnc->raw))
173 int VbWriteNvStorage(VbNvContext* vnc) {
174 unsigned offs, blksz;
175 VbSharedDataHeader *sh = VbSharedDataRead();
177 if (!vnc->raw_changed)
178 return 0; /* Nothing changed, so no need to write */
180 /* Get the byte offset from VBNV */
181 if (ReadFileInt(ACPI_VBNV_PATH ".0", &offs) < 0)
183 if (ReadFileInt(ACPI_VBNV_PATH ".1", &blksz) < 0)
185 if (VBNV_BLOCK_SIZE > blksz)
186 return -1; /* NV storage block is too small */
188 if (0 != VbCmosWrite(offs, VBNV_BLOCK_SIZE, vnc->raw))
191 /* Also attempt to write using mosys if using vboot2 */
192 if (sh && (sh->flags & VBSD_BOOT_FIRMWARE_VBOOT2))
193 VbWriteNvStorage_mosys(vnc);
200 * Get buffer data from ACPI.
202 * Buffer data is expected to be represented by a file which is a text dump of
203 * the buffer, representing each byte by two hex numbers, space and newline
206 * On success, stores the amount of data read in bytes to *buffer_size; on
207 * erros, sets *buffer_size=0.
209 * Input - ACPI file name to get data from.
211 * Output: a pointer to AcpiBuffer structure containing the binary
212 * representation of the data. The caller is responsible for
213 * deallocating the pointer, this will take care of both the structure
214 * and the buffer. Null in case of error.
216 static uint8_t* VbGetBuffer(const char* filename, int* buffer_size) {
218 char* file_buffer = NULL;
219 uint8_t* output_buffer = NULL;
220 uint8_t* return_value = NULL;
222 /* Assume error until proven otherwise */
229 int rv, i, real_size;
232 rv = stat(filename, &fs);
233 if (rv || !S_ISREG(fs.st_mode))
236 f = fopen(filename, "r");
240 file_buffer = malloc(fs.st_size + 1);
244 real_size = fread(file_buffer, 1, fs.st_size, f);
247 file_buffer[real_size] = '\0';
249 /* Each byte in the output will replace two characters and a space
250 * in the input, so the output size does not exceed input side/3
251 * (a little less if account for newline characters). */
252 output_buffer = malloc(real_size/3);
255 output_ptr = output_buffer;
257 /* process the file contents */
258 for (i = 0; i < real_size; i++) {
261 base = file_buffer + i;
263 if (!isxdigit(*base))
266 output_ptr[parsed_size++] = strtol(base, &end, 16) & 0xff;
268 if ((end - base) != 2)
269 /* Input file format error */
272 i += 2; /* skip the second character and the following space */
275 if (i == real_size) {
277 return_value = output_buffer;
278 output_buffer = NULL; /* prevent it from deallocating */
280 *buffer_size = parsed_size;
298 VbSharedDataHeader* VbSharedDataRead(void) {
299 VbSharedDataHeader* sh;
303 sh = (VbSharedDataHeader*)VbGetBuffer(ACPI_VDAT_PATH, &got_size);
307 /* Make sure the size is sufficient for the struct version we got.
308 * Check supported old versions first. */
309 if (1 == sh->struct_version)
310 expect_size = VB_SHARED_DATA_HEADER_SIZE_V1;
312 /* There'd better be enough data for the current header size. */
313 expect_size = sizeof(VbSharedDataHeader);
316 if (got_size < expect_size) {
320 if (sh->data_size > got_size)
321 sh->data_size = got_size; /* Truncated read */
327 /* Read the CMOS reboot field in NVRAM.
329 * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */
330 static int VbGetCmosRebootField(uint8_t mask) {
334 /* Get the byte offset from CHNV */
335 if (ReadFileInt(ACPI_CHNV_PATH, &chnv) < 0)
338 if (0 != VbCmosRead(chnv, 1, &nvbyte))
341 return (nvbyte & mask ? 1 : 0);
345 /* Write the CMOS reboot field in NVRAM.
347 * Sets (value=0) or clears (value!=0) the mask in the byte.
349 * Returns 0 if success, or -1 if error. */
350 static int VbSetCmosRebootField(uint8_t mask, int value) {
354 /* Get the byte offset from CHNV */
355 if (ReadFileInt(ACPI_CHNV_PATH, &chnv) < 0)
358 if (0 != VbCmosRead(chnv, 1, &nvbyte))
361 /* Set/clear the mask */
367 /* Write the byte back */
368 if (0 != VbCmosWrite(chnv, 1, &nvbyte))
376 /* Read the active main firmware type into the destination buffer.
377 * Passed the destination and its size. Returns the destination, or
379 static const char* VbReadMainFwType(char* dest, int size) {
382 /* Try reading type from BINF.3 */
383 if (ReadFileInt(ACPI_BINF_PATH ".3", &value) == 0) {
386 return StrCopy(dest, "netboot", size);
388 return StrCopy(dest, "recovery", size);
390 return StrCopy(dest, "normal", size);
391 case BINF3_DEVELOPER:
392 return StrCopy(dest, "developer", size);
394 break; /* Fall through to legacy handling */
398 /* Fall back to BINF.0 for legacy systems like Mario. */
399 if (ReadFileInt(ACPI_BINF_PATH ".0", &value) < 0)
400 /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS
402 return StrCopy(dest, "nonchrome", size);
406 return StrCopy(dest, "normal", size);
407 case BINF0_DEVELOPER:
408 return StrCopy(dest, "developer", size);
409 case BINF0_RECOVERY_BUTTON:
410 case BINF0_RECOVERY_DEV_SCREEN_KEY:
411 case BINF0_RECOVERY_RW_FW_BAD:
412 case BINF0_RECOVERY_NO_OS:
413 case BINF0_RECOVERY_BAD_OS:
414 case BINF0_RECOVERY_OS_INITIATED:
415 case BINF0_RECOVERY_TPM_ERROR:
416 /* Assorted flavors of recovery boot reason. */
417 return StrCopy(dest, "recovery", size);
419 /* Other values don't map cleanly to firmware type. */
425 /* Read the recovery reason. Returns the reason code or -1 if error. */
426 static int VbGetRecoveryReason(void) {
429 /* Try reading type from BINF.4 */
430 if (ReadFileInt(ACPI_BINF_PATH ".4", &value) == 0)
433 /* Fall back to BINF.0 for legacy systems like Mario. */
434 if (ReadFileInt(ACPI_BINF_PATH ".0", &value) < 0)
438 case BINF0_DEVELOPER:
439 return VBNV_RECOVERY_NOT_REQUESTED;
440 case BINF0_RECOVERY_BUTTON:
441 return VBNV_RECOVERY_RO_MANUAL;
442 case BINF0_RECOVERY_DEV_SCREEN_KEY:
443 return VBNV_RECOVERY_RW_DEV_SCREEN;
444 case BINF0_RECOVERY_RW_FW_BAD:
445 return VBNV_RECOVERY_RO_INVALID_RW;
446 case BINF0_RECOVERY_NO_OS:
447 return VBNV_RECOVERY_RW_NO_OS;
448 case BINF0_RECOVERY_BAD_OS:
449 return VBNV_RECOVERY_RW_INVALID_OS;
450 case BINF0_RECOVERY_OS_INITIATED:
451 return VBNV_RECOVERY_LEGACY;
453 /* Other values don't map cleanly to firmware type. */
458 /* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/,
459 * but <N> and <M> may differ by some offset <O>. To determine that constant,
460 * we look for a directory named /sys/class/gpio/gpiochip<O>/. If there's not
461 * exactly one match for that, we're SOL.
463 static int FindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
469 dir = opendir(GPIO_BASE_PATH);
474 while(0 != (ent = readdir(dir))) {
475 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) {
484 /* Physical GPIO number <N> may be accessed through /sys/class/gpio/gpio<M>/,
485 * but <N> and <M> may differ by some offset <O>. To determine that constant,
486 * we look for a directory named /sys/class/gpio/gpiochip<O>/ and check for
487 * a 'label' file inside of it to find the expected the controller name.
489 static int FindGpioChipOffsetByLabel(unsigned *gpio_num, unsigned *offset,
496 unsigned controller_offset = 0;
498 dir = opendir(GPIO_BASE_PATH);
503 while(0 != (ent = readdir(dir))) {
504 if (1 == sscanf(ent->d_name, "gpiochip%u", &controller_offset)) {
506 * Read the file at gpiochip<O>/label to get the identifier
507 * for this bank of GPIOs.
509 snprintf(filename, sizeof(filename), "%s/gpiochip%u/label",
510 GPIO_BASE_PATH, controller_offset);
511 if (ReadFileString(chiplabel, sizeof(chiplabel), filename)) {
512 if (!strncasecmp(chiplabel, name, strlen(name))) {
514 * Store offset when chip label is matched.
516 *offset = controller_offset;
527 static int FindGpioChipOffsetByNumber(unsigned *gpio_num, unsigned *offset,
533 /* Obtain relative GPIO number.
534 * The assumption here is the Basemapping
535 * table is arranged in decreasing order of
536 * base address and ends with 0.
537 * A UID with value 0 indicates an invalid range
538 * and causes an early return to avoid the directory
539 * opening code below.
542 if (*gpio_num >= data->base) {
543 *gpio_num -= data->base;
549 if (data->uid == 0) {
553 dir = opendir(GPIO_BASE_PATH);
558 while(0 != (ent = readdir(dir))) {
559 /* For every gpiochip entry determine uid. */
560 if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) {
563 snprintf(uid_file, sizeof(uid_file),
564 "%s/gpiochip%u/device/firmware_node/uid", GPIO_BASE_PATH,
566 if (ReadFileInt(uid_file, &uid_value) < 0)
568 if (data->uid == uid_value) {
580 /* Braswell has 4 sets of GPIO banks. It is expected the firmware exposes
581 * each bank of gpios using a UID in ACPI. Furthermore the gpio number exposed
582 * is relative to the bank. e.g. gpio MF_ISH_GPIO_4 in the bank specified by UID 3
583 * would be encoded as 0x10016.
591 static int BraswellFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
593 static Basemapping data[]={
600 return FindGpioChipOffsetByNumber(gpio_num, offset, data);
603 /* BayTrail has 3 sets of GPIO banks. It is expected the firmware exposes
604 * each bank of gpios using a UID in ACPI. Furthermore the gpio number exposed
605 * is relative to the bank. e.g. gpio 6 in the bank specified by UID 3 would
606 * be encoded as 0x2006.
613 static int BayTrailFindGpioChipOffset(unsigned *gpio_num, unsigned *offset,
615 static Basemapping data[]={
621 return FindGpioChipOffsetByNumber(gpio_num, offset, data);
626 int (*ChipOffsetAndGpioNumber)(unsigned *gpio_num, unsigned *chip_offset,
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 { "INT344B:00", FindGpioChipOffsetByLabel },
638 { "INT3452:00", FindGpioChipOffsetByLabel }, /* INT3452 are for Apollolake */
639 { "INT3452:01", FindGpioChipOffsetByLabel },
640 { "INT3452:02", FindGpioChipOffsetByLabel },
641 { "INT3452:03", FindGpioChipOffsetByLabel },
642 { "BayTrail", BayTrailFindGpioChipOffset },
643 { "Braswell", BraswellFindGpioChipOffset },
647 static const struct GpioChipset *FindChipset(const char *name) {
648 const struct GpioChipset *chipset = &chipsets_supported[0];
650 while (chipset->name != NULL) {
651 if (!strcmp(name, chipset->name))
658 /* Read a GPIO of the specified signal type (see ACPI GPIO SignalType).
660 * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */
661 static int ReadGpio(unsigned signal_type) {
665 unsigned active_high;
666 unsigned controller_num;
667 unsigned controller_offset = 0;
668 char controller_name[128];
670 const struct GpioChipset *chipset;
672 /* Scan GPIO.* to find a matching signal type */
673 for (index = 0; ; index++) {
674 snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH, index);
675 if (ReadFileInt(name, &gpio_type) < 0)
676 return -1; /* Ran out of GPIOs before finding a match */
677 if (gpio_type == signal_type)
681 /* Read attributes and controller info for the GPIO */
682 snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index);
683 if (ReadFileInt(name, &active_high) < 0)
685 snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index);
686 if (ReadFileInt(name, &controller_num) < 0)
688 /* Do not attempt to read GPIO that is set to -1 in ACPI */
689 if (controller_num == 0xFFFFFFFF)
692 /* Check for chipsets we recognize. */
693 snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index);
694 if (!ReadFileString(controller_name, sizeof(controller_name), name))
696 chipset = FindChipset(controller_name);
700 /* Modify GPIO number by driver's offset */
701 if (!chipset->ChipOffsetAndGpioNumber(&controller_num, &controller_offset,
704 controller_offset += controller_num;
706 /* Try reading the GPIO value */
707 snprintf(name, sizeof(name), "%s/gpio%d/value",
708 GPIO_BASE_PATH, controller_offset);
709 if (ReadFileInt(name, &value) < 0) {
710 /* Try exporting the GPIO */
711 FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
714 fprintf(f, "%u", controller_offset);
717 /* Try re-reading the GPIO value */
718 if (ReadFileInt(name, &value) < 0)
722 /* Normalize the value read from the kernel in case it is not always 1. */
723 value = value ? 1 : 0;
725 /* Compare the GPIO value with the active value and return 1 if match. */
726 return (value == active_high ? 1 : 0);
730 int VbGetArchPropertyInt(const char* name) {
733 /* Values from ACPI */
734 if (!strcasecmp(name,"fmap_base")) {
736 if (ReadFileInt(ACPI_FMAP_PATH, &fmap_base) < 0)
739 value = (int)fmap_base;
742 /* Switch positions */
743 if (!strcasecmp(name,"devsw_cur")) {
744 /* Systems with virtual developer switches return at-boot value */
745 int flags = VbGetSystemPropertyInt("vdat_flags");
746 if ((flags != -1) && (flags & VBSD_HONOR_VIRT_DEV_SWITCH))
747 value = VbGetSystemPropertyInt("devsw_boot");
749 value = ReadGpio(GPIO_SIGNAL_TYPE_DEV);
750 } else if (!strcasecmp(name,"recoverysw_cur")) {
751 value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY);
752 } else if (!strcasecmp(name,"wpsw_cur")) {
753 value = ReadGpio(GPIO_SIGNAL_TYPE_WP);
754 if (-1 != value && FwidStartsWith("Mario."))
755 value = 1 - value; /* Mario reports this backwards */
756 } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
757 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT);
760 /* Fields for old systems which don't have VbSharedData */
761 if (VbSharedDataVersion() < 2) {
762 if (!strcasecmp(name,"recovery_reason")) {
763 value = VbGetRecoveryReason();
764 } else if (!strcasecmp(name,"devsw_boot")) {
765 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT);
766 } else if (!strcasecmp(name,"recoverysw_boot")) {
767 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT);
768 } else if (!strcasecmp(name,"wpsw_boot")) {
769 value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT);
770 if (-1 != value && FwidStartsWith("Mario."))
771 value = 1 - value; /* Mario reports this backwards */
775 /* NV storage values. If unable to get from NV storage, fall back to the
776 * CMOS reboot field used by older BIOS (e.g. Mario). */
777 if (!strcasecmp(name,"recovery_request")) {
778 value = VbGetNvStorage(VBNV_RECOVERY_REQUEST);
780 value = VbGetCmosRebootField(CMOSRF_RECOVERY);
781 } else if (!strcasecmp(name,"dbg_reset")) {
782 value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE);
784 value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET);
785 } else if (!strcasecmp(name,"fwb_tries")) {
786 value = VbGetNvStorage(VBNV_TRY_B_COUNT);
788 value = VbGetCmosRebootField(CMOSRF_TRY_B);
791 /* Firmware update tries is now stored in the kernel field. On
792 * older systems where it's not, it was stored in a file in the
793 * stateful partition. */
794 if (!strcasecmp(name,"fwupdate_tries")) {
795 unsigned fwupdate_value;
796 if (-1 != VbGetNvStorage(VBNV_KERNEL_FIELD))
797 return -1; /* NvStorage supported; fail through arch-specific
798 * implementation to normal implementation. */
799 /* Read value from file; missing file means value=0. */
800 if (ReadFileInt(NEED_FWUPDATE_PATH, &fwupdate_value) < 0)
803 value = (int)fwupdate_value;
806 /* Detect if the host is a VM. If there is no HWID and the firmware type
807 * is "nonchrome", then assume it is a VM. If HWID is present, it is a
808 * baremetal Chrome OS machine. Other cases are errors. */
809 if (!strcasecmp(name,"inside_vm")) {
810 char hwid[VB_MAX_STRING_PROPERTY];
811 if (!VbGetArchPropertyString("hwid", hwid, sizeof(hwid))) {
812 char fwtype_buf[VB_MAX_STRING_PROPERTY];
813 const char *fwtype = VbGetArchPropertyString("mainfw_type", fwtype_buf,
815 if (fwtype && !strcasecmp(fwtype,"nonchrome")) {
827 const char* VbGetArchPropertyString(const char* name, char* dest,
831 if (!strcasecmp(name,"arch")) {
832 return StrCopy(dest, "x86", size);
833 } else if (!strcasecmp(name,"hwid")) {
834 return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID");
835 } else if (!strcasecmp(name,"fwid")) {
836 return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID");
837 } else if (!strcasecmp(name,"ro_fwid")) {
838 return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID");
839 } else if (!strcasecmp(name,"mainfw_act")) {
840 if (ReadFileInt(ACPI_BINF_PATH ".1", &value) < 0)
844 return StrCopy(dest, "recovery", size);
846 return StrCopy(dest, "A", size);
848 return StrCopy(dest, "B", size);
852 } else if (!strcasecmp(name,"mainfw_type")) {
853 return VbReadMainFwType(dest, size);
854 } else if (!strcasecmp(name,"ecfw_act")) {
855 if (ReadFileInt(ACPI_BINF_PATH ".2", &value) < 0)
859 return StrCopy(dest, "RO", size);
861 return StrCopy(dest, "RW", size);
871 int VbSetArchPropertyInt(const char* name, int value) {
872 /* NV storage values. If unable to get from NV storage, fall back to the
873 * CMOS reboot field used by older BIOS. */
874 if (!strcasecmp(name,"recovery_request")) {
875 if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value))
877 return VbSetCmosRebootField(CMOSRF_RECOVERY, value);
878 } else if (!strcasecmp(name,"dbg_reset")) {
879 if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value))
881 return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value);
882 } else if (!strcasecmp(name,"fwb_tries")) {
883 if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value))
885 return VbSetCmosRebootField(CMOSRF_TRY_B, value);
887 /* Firmware update tries is now stored in the kernel field. On
888 * older systems where it's not, it was stored in a file in the
889 * stateful partition. */
890 else if (!strcasecmp(name,"fwupdate_tries")) {
891 if (-1 != VbGetNvStorage(VBNV_KERNEL_FIELD))
892 return -1; /* NvStorage supported; fail through arch-specific
893 * implementation to normal implementation */
897 snprintf(buf, sizeof(buf), "%d", value);
898 return WriteFile(NEED_FWUPDATE_PATH, buf, strlen(buf));
900 /* No update tries, so remove file if it exists. */
901 unlink(NEED_FWUPDATE_PATH);
910 int VbSetArchPropertyString(const char* name, const char* value) {
911 /* If there were settable architecture-dependent string properties,