Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Unified Diff: host/lib/crossystem.c

Issue 6719005: Cherry-pick vboot_reference files from TOT to support crossystem (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/vboot_reference.git@0.11.257.B
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « firmware/stub/utility_stub.c ('k') | tests/tpm_lite/timing.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: host/lib/crossystem.c
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index 04dc9756446878651dc0226ffa226e5c716fce38..5c5dec0d9541cb4304f6da6b0f5b123a960d7a7d 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -5,6 +5,10 @@
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
#include "host_common.h"
@@ -12,6 +16,7 @@
#include "utility.h"
#include "vboot_common.h"
#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
/* ACPI constants from Chrome OS Main Processor Firmware Spec */
/* GPIO signal types */
@@ -68,6 +73,7 @@
#define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP"
#define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO"
#define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV"
+#define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT"
/* Base name for GPIO files */
#define GPIO_BASE_PATH "/sys/class/gpio"
@@ -79,6 +85,31 @@
/* Filename for kernel command line */
#define KERNEL_CMDLINE_PATH "/proc/cmdline"
+/* A structure to contain buffer data retrieved from the ACPI. */
+typedef struct {
+ int buffer_size;
+ uint8_t* buffer;
+} AcpiBuffer;
+
+
+/* Fields that GetVdatString() can get */
+typedef enum VdatStringField {
+ VDAT_STRING_TIMERS = 0, /* Timer values */
+ VDAT_STRING_LOAD_FIRMWARE_DEBUG, /* LoadFirmware() debug information */
+ VDAT_STRING_LOAD_KERNEL_DEBUG /* LoadKernel() debug information */
+} VdatStringField;
+
+
+/* Fields that GetVdatInt() can get */
+typedef enum VdatIntField {
+ VDAT_INT_FLAGS = 0, /* Flags */
+ VDAT_INT_FW_VERSION_TPM, /* Current firmware version in TPM */
+ VDAT_INT_KERNEL_VERSION_TPM, /* Current kernel version in TPM */
+ VDAT_INT_TRIED_FIRMWARE_B, /* Tried firmware B due to fwb_tries */
+ VDAT_INT_KERNEL_KEY_VERIFIED /* Kernel key verified using
+ * signature, not just hash */
+} VdatIntField;
+
/* Copy up to dest_size-1 characters from src to dest, ensuring null
termination (which strncpy() doesn't do). Returns the destination
@@ -284,6 +315,97 @@ int VbSetCmosRebootField(uint8_t mask, int value) {
return 0;
}
+/*
+ * Get buffer data from ACPI.
+ *
+ * Buffer data is expected to be represented by a file which is a text dump of
+ * the buffer, representing each byte by two hex numbers, space and newline
+ * separated.
+ *
+ * Input - ACPI file name to get data from.
+ *
+ * Output: a pointer to AcpiBuffer structure containing the binary
+ * representation of the data. The caller is responsible for
+ * deallocating the pointer, this will take care of both the structure
+ * and the buffer. Null in case of error.
+ */
+
+AcpiBuffer* VbGetBuffer(const char* filename)
+{
+ FILE* f = NULL;
+ char* file_buffer = NULL;
+ AcpiBuffer* acpi_buffer = NULL;
+ AcpiBuffer* return_value = NULL;
+
+ do {
+ struct stat fs;
+ uint8_t* output_ptr;
+ int rv, i, real_size;
+
+ rv = stat(filename, &fs);
+ if (rv || !S_ISREG(fs.st_mode))
+ break;
+
+ f = fopen(filename, "r");
+ if (!f)
+ break;
+
+ file_buffer = Malloc(fs.st_size + 1);
+ if (!file_buffer)
+ break;
+
+ real_size = fread(file_buffer, 1, fs.st_size, f);
+ if (!real_size)
+ break;
+ file_buffer[real_size] = '\0';
+
+ /* Each byte in the output will replace two characters and a space
+ * in the input, so the output size does not exceed input side/3
+ * (a little less if account for newline characters). */
+ acpi_buffer = Malloc(sizeof(AcpiBuffer) + real_size/3);
+ if (!acpi_buffer)
+ break;
+ acpi_buffer->buffer = (uint8_t*)(acpi_buffer + 1);
+ acpi_buffer->buffer_size = 0;
+ output_ptr = acpi_buffer->buffer;
+
+ /* process the file contents */
+ for (i = 0; i < real_size; i++) {
+ char* base, *end;
+
+ base = file_buffer + i;
+
+ if (!isxdigit(*base))
+ continue;
+
+ output_ptr[acpi_buffer->buffer_size++] = strtol(base, &end, 16) & 0xff;
+
+ if ((end - base) != 2)
+ /* Input file format error */
+ break;
+
+ i += 2; /* skip the second character and the following space */
+ }
+
+ if (i == real_size) {
+ /* all is well */
+ return_value = acpi_buffer;
+ acpi_buffer = NULL; /* prevent it from deallocating */
+ }
+ } while(0);
+
+ /* wrap up */
+ if (f)
+ fclose(f);
+
+ if (file_buffer)
+ Free(file_buffer);
+
+ if (acpi_buffer)
+ Free(acpi_buffer);
+
+ return return_value;
+}
/* Read an integer property from VbNvStorage.
*
@@ -497,6 +619,193 @@ int VbGetCrosDebug(void) {
}
+char* GetVdatLoadFirmwareDebug(char* dest, int size,
+ const VbSharedDataHeader* sh) {
+ snprintf(dest, size,
+ "Check A result=%d\n"
+ "Check B result=%d\n"
+ "Firmware index booted=0x%02x\n"
+ "TPM combined version at start=0x%08x\n"
+ "Lowest combined version from firmware=0x%08x\n",
+ sh->check_fw_a_result,
+ sh->check_fw_b_result,
+ sh->firmware_index,
+ sh->fw_version_tpm_start,
+ sh->fw_version_lowest);
+ return dest;
+}
+
+
+#define TRUNCATED "\n(truncated)\n"
+
+char* GetVdatLoadKernelDebug(char* dest, int size,
+ const VbSharedDataHeader* sh) {
+ int used = 0;
+ int first_call_tracked = 0;
+ int call;
+
+ /* Make sure we have space for truncation warning */
+ if (size < strlen(TRUNCATED) + 1)
+ return NULL;
+ size -= strlen(TRUNCATED) + 1;
+
+ used += snprintf(
+ dest + used, size - used,
+ "Calls to LoadKernel()=%d\n",
+ sh->lk_call_count);
+ if (used > size)
+ goto LoadKernelDebugExit;
+
+ /* Report on the last calls */
+ if (sh->lk_call_count > VBSD_MAX_KERNEL_CALLS)
+ first_call_tracked = sh->lk_call_count - VBSD_MAX_KERNEL_CALLS;
+ for (call = first_call_tracked; call < sh->lk_call_count; call++) {
+ const VbSharedDataKernelCall* shc =
+ sh->lk_calls + (call & (VBSD_MAX_KERNEL_CALLS - 1));
+ int first_part_tracked = 0;
+ int part;
+
+ used += snprintf(
+ dest + used, size - used,
+ "Call %d:\n"
+ " Boot flags=0x%02x\n"
+ " Boot mode=%d\n"
+ " Test error=%d\n"
+ " Return code=%d\n"
+ " Debug flags=0x%02x\n"
+ " Drive sectors=%" PRIu64 "\n"
+ " Sector size=%d\n"
+ " Check result=%d\n"
+ " Kernel partitions found=%d\n",
+ call + 1,
+ shc->boot_flags,
+ shc->boot_mode,
+ shc->test_error_num,
+ shc->return_code,
+ shc->flags,
+ shc->sector_count,
+ shc->sector_size,
+ shc->check_result,
+ shc->kernel_parts_found);
+ if (used > size)
+ goto LoadKernelDebugExit;
+
+ /* If we found too many partitions, only prints ones where the
+ * structure has info. */
+ if (shc->kernel_parts_found > VBSD_MAX_KERNEL_PARTS)
+ first_part_tracked = shc->kernel_parts_found - VBSD_MAX_KERNEL_PARTS;
+
+ /* Report on the partitions checked */
+ for (part = first_part_tracked; part < shc->kernel_parts_found; part++) {
+ const VbSharedDataKernelPart* shp =
+ shc->parts + (part & (VBSD_MAX_KERNEL_PARTS - 1));
+
+ used += snprintf(
+ dest + used, size - used,
+ " Kernel %d:\n"
+ " GPT index=%d\n"
+ " Start sector=%" PRIu64 "\n"
+ " Sector count=%" PRIu64 "\n"
+ " Combined version=0x%08x\n"
+ " Check result=%d\n"
+ " Debug flags=0x%02x\n",
+ part + 1,
+ shp->gpt_index,
+ shp->sector_start,
+ shp->sector_count,
+ shp->combined_version,
+ shp->check_result,
+ shp->flags);
+ if (used > size)
+ goto LoadKernelDebugExit;
+ }
+ }
+
+LoadKernelDebugExit:
+
+ /* Warn if data was truncated; we left space for this above. */
+ if (used > size)
+ strcat(dest, TRUNCATED);
+
+ return dest;
+}
+
+
+char* GetVdatString(char* dest, int size, VdatStringField field)
+{
+ VbSharedDataHeader* sh;
+ AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH);
+ char* value = dest;
+ if (!ab)
+ return NULL;
+
+ sh = (VbSharedDataHeader*)ab->buffer;
+
+ switch (field) {
+ case VDAT_STRING_TIMERS:
+ snprintf(dest, size,
+ "LFS=%" PRIu64 ",%" PRIu64
+ " LF=%" PRIu64 ",%" PRIu64
+ " LK=%" PRIu64 ",%" PRIu64,
+ sh->timer_load_firmware_start_enter,
+ sh->timer_load_firmware_start_exit,
+ sh->timer_load_firmware_enter,
+ sh->timer_load_firmware_exit,
+ sh->timer_load_kernel_enter,
+ sh->timer_load_kernel_exit);
+ break;
+
+ case VDAT_STRING_LOAD_FIRMWARE_DEBUG:
+ value = GetVdatLoadFirmwareDebug(dest, size, sh);
+ break;
+
+ case VDAT_STRING_LOAD_KERNEL_DEBUG:
+ value = GetVdatLoadKernelDebug(dest, size, sh);
+ break;
+
+ default:
+ Free(ab);
+ return NULL;
+ }
+
+ Free(ab);
+ return value;
+}
+
+
+int GetVdatInt(VdatIntField field) {
+ VbSharedDataHeader* sh;
+ AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH);
+ int value = -1;
+
+ if (!ab)
+ return -1;
+
+ sh = (VbSharedDataHeader*)ab->buffer;
+
+ switch (field) {
+ case VDAT_INT_FLAGS:
+ value = (int)sh->flags;
+ break;
+ case VDAT_INT_FW_VERSION_TPM:
+ value = (int)sh->fw_version_tpm;
+ break;
+ case VDAT_INT_KERNEL_VERSION_TPM:
+ value = (int)sh->kernel_version_tpm;
+ break;
+ case VDAT_INT_TRIED_FIRMWARE_B:
+ value = (sh->flags & VBSD_FWB_TRIED ? 1 : 0);
+ break;
+ case VDAT_INT_KERNEL_KEY_VERIFIED:
+ value = (sh->flags & VBSD_KERNEL_KEY_VERIFIED ? 1 : 0);
+ break;
+ }
+
+ Free(ab);
+ return value;
+}
+
+
/* Read a system property integer.
*
* Returns the property value, or -1 if error. */
@@ -531,12 +840,14 @@ int VbGetSystemPropertyInt(const char* name) {
return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00100000);
}
/* NV storage values with no defaults for older BIOS. */
- else if (!strcasecmp(name,"tried_fwb")) {
- value = VbGetNvStorage(VBNV_TRIED_FIRMWARE_B);
- } else if (!strcasecmp(name,"kern_nv")) {
+ else if (!strcasecmp(name,"kern_nv")) {
value = VbGetNvStorage(VBNV_KERNEL_FIELD);
} else if (!strcasecmp(name,"nvram_cleared")) {
value = VbGetNvStorage(VBNV_KERNEL_SETTINGS_RESET);
+ } else if (!strcasecmp(name,"vbtest_errfunc")) {
+ value = VbGetNvStorage(VBNV_TEST_ERROR_FUNC);
+ } else if (!strcasecmp(name,"vbtest_errno")) {
+ value = VbGetNvStorage(VBNV_TEST_ERROR_NUM);
}
/* NV storage values. If unable to get from NV storage, fall back to the
* CMOS reboot field used by older BIOS. */
@@ -560,12 +871,19 @@ int VbGetSystemPropertyInt(const char* name) {
value = ReadFileInt(ACPI_FMAP_PATH);
} else if (!strcasecmp(name,"cros_debug")) {
value = VbGetCrosDebug();
+ } else if (!strcasecmp(name,"vdat_flags")) {
+ value = GetVdatInt(VDAT_INT_FLAGS);
+ } else if (!strcasecmp(name,"tpm_fwver")) {
+ value = GetVdatInt(VDAT_INT_FW_VERSION_TPM);
+ } else if (!strcasecmp(name,"tpm_kernver")) {
+ value = GetVdatInt(VDAT_INT_KERNEL_VERSION_TPM);
+ } else if (!strcasecmp(name,"tried_fwb")) {
+ value = GetVdatInt(VDAT_INT_TRIED_FIRMWARE_B);
}
return value;
}
-
/* Read a system property string into a destination buffer of the specified
* size.
*
@@ -601,7 +919,7 @@ const char* VbGetSystemPropertyString(const char* name, char* dest, int size) {
return NULL;
}
} else if (!strcasecmp(name,"kernkey_vfy")) {
- switch(VbGetNvStorage(VBNV_FW_VERIFIED_KERNEL_KEY)) {
+ switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) {
case 0:
return "hash";
case 1:
@@ -609,6 +927,12 @@ const char* VbGetSystemPropertyString(const char* name, char* dest, int size) {
default:
return NULL;
}
+ } else if (!strcasecmp(name, "vdat_timers")) {
+ return GetVdatString(dest, size, VDAT_STRING_TIMERS);
+ } else if (!strcasecmp(name, "vdat_lfdebug")) {
+ return GetVdatString(dest, size, VDAT_STRING_LOAD_FIRMWARE_DEBUG);
+ } else if (!strcasecmp(name, "vdat_lkdebug")) {
+ return GetVdatString(dest, size, VDAT_STRING_LOAD_KERNEL_DEBUG);
} else
return NULL;
}
@@ -625,6 +949,10 @@ int VbSetSystemPropertyInt(const char* name, int value) {
return VbSetNvStorage(VBNV_KERNEL_SETTINGS_RESET, 0);
} else if (!strcasecmp(name,"kern_nv")) {
return VbSetNvStorage(VBNV_KERNEL_FIELD, value);
+ } else if (!strcasecmp(name,"vbtest_errfunc")) {
+ return VbSetNvStorage(VBNV_TEST_ERROR_FUNC, value);
+ } else if (!strcasecmp(name,"vbtest_errno")) {
+ return VbSetNvStorage(VBNV_TEST_ERROR_NUM, value);
}
/* NV storage values. If unable to get from NV storage, fall back to the
* CMOS reboot field used by older BIOS. */
« no previous file with comments | « firmware/stub/utility_stub.c ('k') | tests/tpm_lite/timing.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698