Index: host/lib/crossystem.c |
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c |
index 70f39ddb2f098e70438372d59d3852ca6cd5c8e3..9428ba526431fcef33ac2242cc3059cd7dc07ccc 100644 |
--- a/host/lib/crossystem.c |
+++ b/host/lib/crossystem.c |
@@ -63,6 +63,7 @@ |
#define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW" |
#define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP" |
#define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO" |
+#define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV" |
/* Base name for GPIO files */ |
#define GPIO_BASE_PATH "/sys/class/gpio" |
@@ -276,6 +277,104 @@ int VbSetCmosRebootField(uint8_t mask, int value) { |
return 0; |
} |
+ |
+/* Read an integer property from VbNvStorage. |
+ * |
+ * Returns the parameter value, or -1 if error. */ |
+int VbGetNvStorage(VbNvParam param) { |
+ FILE* f; |
+ VbNvContext vnc; |
+ int offs; |
+ uint32_t value; |
+ int retval; |
+ |
+ /* Get the byte offset from VBNV */ |
+ offs = ReadFileInt(ACPI_VBNV_PATH ".0"); |
+ if (offs == -1) |
+ return -1; |
+ if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1")) |
+ return -1; /* NV storage block is too small */ |
+ |
+ /* TODO: locking around NV access */ |
+ f = fopen(NVRAM_PATH, "rb"); |
+ if (!f) |
+ return -1; |
+ |
+ if (0 != fseek(f, offs, SEEK_SET) || |
+ 1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) { |
+ fclose(f); |
+ return -1; |
+ } |
+ |
+ fclose(f); |
+ |
+ if (0 != VbNvSetup(&vnc)) |
+ return -1; |
+ retval = VbNvGet(&vnc, param, &value); |
+ if (0 != VbNvTeardown(&vnc)) |
+ return -1; |
+ if (0 != retval) |
+ return -1; |
+ |
+ /* TODO: If vnc.raw_changed, attempt to reopen NVRAM for write and |
+ * save the new defaults. If we're able to, log. */ |
+ /* TODO: release lock */ |
+ |
+ return (int)value; |
+} |
+ |
+ |
+/* Write an integer property to VbNvStorage. |
+ * |
+ * Returns 0 if success, -1 if error. */ |
+int VbSetNvStorage(VbNvParam param, int value) { |
+ FILE* f; |
+ VbNvContext vnc; |
+ int offs; |
+ int retval = -1; |
+ int i; |
+ |
+ /* Get the byte offset from VBNV */ |
+ offs = ReadFileInt(ACPI_VBNV_PATH ".0"); |
+ if (offs == -1) |
+ return -1; |
+ if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1")) |
+ return -1; /* NV storage block is too small */ |
+ |
+ /* TODO: locking around NV access */ |
+ f = fopen(NVRAM_PATH, "w+b"); |
+ if (!f) |
+ return -1; |
+ |
+ if (0 != fseek(f, offs, SEEK_SET) || |
+ 1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) { |
+ goto VbSetNvCleanup; |
+ } |
+ |
+ if (0 != VbNvSetup(&vnc)) |
+ goto VbSetNvCleanup; |
+ i = VbNvSet(&vnc, param, (uint32_t)value); |
+ if (0 != VbNvTeardown(&vnc)) |
+ goto VbSetNvCleanup; |
+ if (0 != i) |
+ goto VbSetNvCleanup; |
+ |
+ if (vnc.raw_changed) { |
+ if (0 != fseek(f, offs, SEEK_SET) || |
+ 1 != fwrite(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) |
+ goto VbSetNvCleanup; |
+ } |
+ |
+ /* Success */ |
+ retval = 0; |
+ |
+VbSetNvCleanup: |
+ fclose(f); |
+ /* TODO: release lock */ |
+ return retval; |
+} |
+ |
+ |
/* Read the recovery reason. Returns the reason code or -1 if error. */ |
int VbGetRecoveryReason(void) { |
int value; |
@@ -385,13 +484,20 @@ int VbGetSystemPropertyInt(const char* name) { |
} else if (!strcasecmp(name,"savedmem_size")) { |
return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00100000); |
} |
- /* NV storage values for older H2C BIOS */ |
+ /* NV storage values. If unable to get from NV storage, fall back to the |
+ * CMOS reboot field used by older BIOS. */ |
else if (!strcasecmp(name,"recovery_request")) { |
- value = VbGetCmosRebootField(CMOSRF_RECOVERY); |
+ value = VbGetNvStorage(VBNV_RECOVERY_REQUEST); |
+ if (-1 == value) |
+ value = VbGetCmosRebootField(CMOSRF_RECOVERY); |
} else if (!strcasecmp(name,"dbg_reset")) { |
- value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); |
+ value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE); |
+ if (-1 == value) |
+ value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET); |
} else if (!strcasecmp(name,"fwb_tries")) { |
- value = VbGetCmosRebootField(CMOSRF_TRY_B); |
+ value = VbGetNvStorage(VBNV_TRY_B_COUNT); |
+ if (-1 == value) |
+ value = VbGetCmosRebootField(CMOSRF_TRY_B); |
} |
/* Other parameters */ |
else if (!strcasecmp(name,"recovery_reason")) { |
@@ -452,12 +558,19 @@ const char* VbGetSystemPropertyString(const char* name, char* dest, int size) { |
* Returns 0 if success, -1 if error. */ |
int VbSetSystemPropertyInt(const char* name, int value) { |
- /* NV storage values for older H2C BIOS */ |
+ /* NV storage values. If unable to get from NV storage, fall back to the |
+ * CMOS reboot field used by older BIOS. */ |
if (!strcasecmp(name,"recovery_request")) { |
+ if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value)) |
+ return 0; |
return VbSetCmosRebootField(CMOSRF_RECOVERY, value); |
} else if (!strcasecmp(name,"dbg_reset")) { |
- return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); |
+ if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value)) |
+ return 0; |
+ return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value); |
} else if (!strcasecmp(name,"fwb_tries")) { |
+ if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value)) |
+ return 0; |
return VbSetCmosRebootField(CMOSRF_TRY_B, value); |
} |