Add VbSharedData field parsing

R=reinauer@chromium.org
BUG=chrome-os-partner:2578
TEST=manual

crossystem vdat_timers
should show 'LFS=0,0 LF=number1,number2 LK=number3,number4'
where number1 < number2 < number3 < number4

crossystem vdat_lfdebug
run from a dev mode console, should show
'check=12,0 index=0x00 tpmver=(hex number) lowestver=(hex number)'

crossystem vdat_flags
run from a dev mode console, flags should be 0x04.

Review URL: http://codereview.chromium.org/6685068

Change-Id: Id7b958ae300d10cdcdc1b17a1bb17b7e5069166f
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index b43c502..6ba67e6 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -16,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 */
@@ -87,10 +88,23 @@
 /* A structure to contain buffer data retrieved from the ACPI. */
 typedef struct {
   int buffer_size;
-  void* buffer;
+  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 */
+} VdatStringField;
+
+
+/* Fields that GetVdatInt() can get */
+typedef enum VdatIntField {
+  VDAT_INT_FLAGS = 0  /* Flags */
+} VdatIntField;
+
+
 /* Copy up to dest_size-1 characters from src to dest, ensuring null
    termination (which strncpy() doesn't do).  Returns the destination
    string. */
@@ -319,7 +333,7 @@
 
   do {
     struct stat fs;
-    unsigned char* output_ptr;
+    uint8_t* output_ptr;
     int rv, i, real_size;
 
     rv = stat(filename, &fs);
@@ -334,23 +348,18 @@
     if (!file_buffer)
       break;
 
-
     real_size = fread(file_buffer, 1, fs.st_size, f);
     if (!real_size)
       break;
-
-    /* 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;
-
     file_buffer[real_size] = '\0';
 
-    acpi_buffer->buffer = acpi_buffer + 1;
+    /* 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;
 
@@ -604,6 +613,71 @@
 }
 
 
+char* GetVdatString(char* dest, int size, VdatStringField field)
+{
+  VbSharedDataHeader* sh;
+  AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH);
+  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:
+      snprintf(dest, size,
+               "check=%d,%d index=0x%02x tpmver=0x%x lowestver=0x%x",
+               sh->check_fw_a_result,
+               sh->check_fw_b_result,
+               sh->firmware_index,
+               sh->fw_version_tpm_start,
+               sh->fw_version_lowest);
+      break;
+
+    default:
+      Free(ab);
+      return NULL;
+  }
+
+  Free(ab);
+  return dest;
+}
+
+
+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;
+
+  }
+
+  Free(ab);
+  return value;
+}
+
+
 /* Read a system property integer.
  *
  * Returns the property value, or -1 if error. */
@@ -671,37 +745,13 @@
     value = ReadFileInt(ACPI_FMAP_PATH);
   } else if (!strcasecmp(name,"cros_debug")) {
     value = VbGetCrosDebug();
+  } else if (!strcasecmp(name,"vdat_flags")) {
+    value = GetVdatInt(VDAT_INT_FLAGS);
   }
 
   return value;
 }
 
-/* This function is just an example illustrating the use of VbGetBuffer(). It
- * converts the binary contents of the buffer into a space delimetered hex
- * string. It is expected to be replaced with a function which has knowledge
- * of the buffer data structure.
- */
-char* GetVdatBuffer(void)
-{
-  char* buffer, *src, *p;
-  int i;
-
-  AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH);
-  if (!ab)
-    return NULL;
-
-  buffer = Malloc(ab->buffer_size * 3 + 2);
-  p = buffer;
-  src = ab->buffer;
-  for (i = 0; i < ab->buffer_size; i++) {
-    snprintf(p, 4, " %2.2x", *src++);
-    p += 3;
-  }
-  *p = '\0';
-  Free(ab);
-  return buffer;
-}
-
 /* Read a system property string into a destination buffer of the specified
  * size.
  *
@@ -745,8 +795,10 @@
       default:
         return NULL;
     }
-  } else if (!strcasecmp(name, "vdat")) {
-    return GetVdatBuffer();
+  } 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
     return NULL;
 }