Initial code for the TPM Lightweight Command Library.

Review URL: http://codereview.chromium.org/587014
diff --git a/src/include/tlcl.h b/src/include/tlcl.h
new file mode 100644
index 0000000..e644ebe
--- /dev/null
+++ b/src/include/tlcl.h
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* TPM Lightweight Command Library.
+ *
+ * A low-level library for interfacing to TPM hardware or an emulator.
+ */
+
+#ifndef TPM_LITE_TLCL_H_
+#define TPM_LITE_TLCL_H_
+
+#include <stdint.h>
+
+/* Call this first.
+ */
+void TlclLibinit(void);
+
+/* Sends a TPM_Startup(ST_CLEAR).  Note that this is a no-op for the emulator,
+ * because it runs this command during initialization.
+ */
+void TlclStartup(void);
+
+/* Run the self test.  Note---this is synchronous.  To run this in parallel
+ * with other firmware, use ContinueSelfTest.
+ */
+void TlclSelftestfull(void);
+
+/* Defines a space with permission [perm].  [index] is the index for the space,
+ * [size] the usable data size.  Errors are ignored.
+ */
+void TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size);
+
+/* Writes [length] bytes of [data] to space at [index].  The TPM error code is
+ * returned (0 for success).
+ */
+uint32_t TlclWrite(uint32_t index, uint8_t *data, uint32_t length);
+
+/* Reads [length] bytes from space at [index] into [data].  The TPM error code
+ * is returned (0 for success).
+ */
+uint32_t TlclRead(uint32_t index, uint8_t *data, uint32_t length);
+
+/* Write-locks space at [index].
+ */
+void TlclWriteLock(uint32_t index);
+
+/* Read-locks space at [index].
+ */
+void TlclReadLock(uint32_t index);
+
+/* Asserts physical presence in software.
+ */
+void TlclAssertPhysicalPresence(void);
+
+/* Sets the nvLocked bit.
+ */
+void TlclSetNvLocked(void);
+
+#endif  /* TPM_LITE_TLCL_H_ */
diff --git a/src/testsuite/Makefile b/src/testsuite/Makefile
new file mode 100644
index 0000000..ac515b7
--- /dev/null
+++ b/src/testsuite/Makefile
@@ -0,0 +1,19 @@
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+LIBTLCL = ../tlcl/libtlcl.a
+LIBTPMEMU = ../../../../third_party/tpm-emulator/tpmemu/libtpmemu.a
+CC ?= cc
+
+readonly: readonly.o $(LIBTLCL) $(LIBTPMEMU)
+	$(CC) -g readonly.o -o readonly \
+	$(LIBTLCL) \
+	$(LIBTPMEMU) \
+	-lgmp
+
+readonly.o: readonly.c
+	cc -g -c -Werror -Wall -pedantic -ansi readonly.c -I../include
+
+clean:
+	rm -f readonly *.o *~
diff --git a/src/testsuite/readonly.c b/src/testsuite/readonly.c
new file mode 100644
index 0000000..1707d59
--- /dev/null
+++ b/src/testsuite/readonly.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* This program mimicks the TPM usage from read-only firmware.  It exercises
+ * the TPM functionality needed in the read-only firmware.  It is meant to be
+ * integrated with the rest of the read-only firmware.  It is also provided as
+ * a test.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <tss/tcs.h>
+
+#include "tlcl.h"
+
+/* These index values are used to create NVRAM spaces.  They only need to be
+ * unique.
+ */
+#define INDEX0 0xda70
+#define INDEX1 0xda71
+#define INDEX2 0xda72
+#define INDEX3 0xda73
+
+#define INDEX_INITIALIZED 0xda80
+
+/* This is called once at initialization time.  It may be called again from
+ * recovery mode to rebuild the spaces if something incomprehensible happened
+ * and the spaces are gone or messed up.  This is called after TPM_Startup and
+ * before the spaces are write-locked, so there is a chance that they can be
+ * recreated (but who knows---if anything can happen, there are plenty of ways
+ * of making this FUBAR).
+ */
+void InitializeSpaces(void) {
+  uint32_t zero = 0;
+
+  TlclSetNvLocked();  /* useful only the first time */
+
+  TlclDefineSpace(INDEX0, TPM_NV_PER_WRITE_STCLEAR, 4);
+  TlclWrite(INDEX0, (uint8_t *) &zero, 4);
+  TlclDefineSpace(INDEX1, TPM_NV_PER_WRITE_STCLEAR, 4);
+  TlclWrite(INDEX1, (uint8_t *) &zero, 4);
+  TlclDefineSpace(INDEX2, TPM_NV_PER_WRITE_STCLEAR, 4);
+  TlclWrite(INDEX2, (uint8_t *) &zero, 4);
+  TlclDefineSpace(INDEX3, TPM_NV_PER_WRITE_STCLEAR, 4);
+  TlclWrite(INDEX3, (uint8_t *) &zero, 4);
+
+  TlclDefineSpace(INDEX_INITIALIZED, TPM_NV_PER_READ_STCLEAR, 1);
+  TlclReadLock(INDEX_INITIALIZED);
+}
+
+
+void EnterRecoveryMode(void) {
+  printf("entering recovery mode");
+  exit(0);
+}
+  
+
+int main(void) {
+  uint8_t c;
+  uint32_t index_0, index_1, index_2, index_3;
+
+  TlclLibinit();
+
+#if 0
+  TlclStartup();
+  TlclSelftestfull();
+#endif
+
+  TlclAssertPhysicalPresence();
+
+  /* Checks if initialization has completed.
+   */
+  if (TlclRead(INDEX_INITIALIZED, &c, 1) != TPM_E_DISABLED_CMD) {
+    /* The initialization did not complete.
+     */
+    InitializeSpaces();
+  }
+
+  /* Checks if spaces are OK or messed up.
+   */
+  if (TlclRead(INDEX0, (uint8_t *) &index_0, sizeof(index_0)) != TPM_SUCCESS ||
+      TlclRead(INDEX1, (uint8_t *) &index_1, sizeof(index_1)) != TPM_SUCCESS ||
+      TlclRead(INDEX2, (uint8_t *) &index_2, sizeof(index_2)) != TPM_SUCCESS ||
+      TlclRead(INDEX3, (uint8_t *) &index_3, sizeof(index_3)) != TPM_SUCCESS) {
+    EnterRecoveryMode();
+  }
+
+  /* Done for now.
+   */
+  exit(0);
+}
+  
diff --git a/src/tlcl/Makefile b/src/tlcl/Makefile
new file mode 100644
index 0000000..70e9143
--- /dev/null
+++ b/src/tlcl/Makefile
@@ -0,0 +1,21 @@
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+INCLUDEDIRS = -I../include -I../../../../third_party/tpm-emulator/tpmemu
+CFLAGS += -g -Wall -Werror -ansi -pedantic $(INCLUDEDIRS)
+CC ?= cc
+
+libtlcl.a: tlcl.o 
+	ar rcs libtlcl.a tlcl.o
+
+tlcl.o: tlcl.c tlcl_internal.h ../include/tlcl.h structures.h
+
+structures.h: generator
+	./generator > structures.h
+
+generator: generator.c ../include/tlcl.h
+	$(CC) $(CFLAGS) -fpack-struct generator.c -o generator
+
+clean:
+	rm -f generator *.o *.a structures.h *~
diff --git a/src/tlcl/generator.c b/src/tlcl/generator.c
new file mode 100644
index 0000000..1906d5f
--- /dev/null
+++ b/src/tlcl/generator.c
@@ -0,0 +1,334 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* This program generates partially filled TPM datagrams and other compile-time
+ * constants (e.g. structure sizes and offsets).  Compile this file---and ONLY
+ * this file---with -fpack-struct.  We take advantage of the fact that the
+ * (packed) TPM structures layout (mostly) match the TPM request and response
+ * datagram layout.  When they don't completely match, some fixing is necessary
+ * (see PCR_SELECTION_FIX below).
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tss/tcs.h>
+
+#include "tlcl_internal.h"
+#include "tpmextras.h"
+
+/* See struct Command below.  This structure represent a field in a TPM
+ * command.  [name] is the field name.  [visible] is true if the field is
+ * modified by the run-time.  Non-visible fields are initialized at build time
+ * and remain constant.  [size] is the field size in bytes.  [value] is the
+ * fixed value of non-visible fields.
+ */
+typedef struct Field {
+  const char* name;
+  bool visible;
+  int offset;
+  int size;
+  uint32_t value;     /* large enough for all initializers */
+  struct Field* next;
+} Field;
+
+/* This structure is used to build (at build time) and manipulate (at firmware
+ * or emulation run time) buffers containing TPM datagrams.  [name] is the name
+ * of a TPM command.  [size] is the size of the command buffer in bytes, when
+ * known.  [max_size] is the maximum size allowed for variable-length commands
+ * (such as Read and Write).  [fields] is a link-list of command fields.
+ */
+typedef struct Command {
+  const char* name;
+  int size;
+  int max_size;
+  Field* fields;
+  struct Command* next;
+} Command;
+
+/* Adds a field to a command, and makes its offset visible.  The fields must be
+ * added at increasing offsets.
+ */
+static void AddVisibleField(Command* cmd, const char* name, int offset) {
+  Field* fld = (Field*) malloc(sizeof(Field));
+  if (cmd->fields != NULL) {
+    Field* fn = cmd->fields;
+    assert(offset > fn->offset);
+  }
+  fld->next = cmd->fields;
+  cmd->fields = fld;
+  fld->name = name;
+  fld->visible = true;
+  fld->offset = offset;
+}
+
+/* Adds a constant field with its value.  The fields must be added at
+ * increasing offsets.
+ */
+static void AddInitializedField(Command* cmd, int offset,
+                                int size, uint32_t value) {
+  Field* fld = (Field*) malloc(sizeof(Field));
+  fld->next = cmd->fields;
+  cmd->fields = fld;
+  fld->name = NULL;
+  fld->visible = false;
+  fld->size = size;
+  fld->offset = offset;
+  fld->value = value;
+}
+
+/* Create a structure representing a TPM command datagram.
+ */
+Command* newCommand(TPM_COMMAND_CODE code, int size) {
+  Command* cmd = (Command*) malloc(sizeof(Command));
+  cmd->size = size;
+  AddInitializedField(cmd, 0, sizeof(TPM_TAG), TPM_TAG_RQU_COMMAND);
+  AddInitializedField(cmd, sizeof(TPM_TAG), sizeof(uint32_t), size);
+  AddInitializedField(cmd, sizeof(TPM_TAG) + sizeof(uint32_t),
+                      sizeof(TPM_COMMAND_CODE), code);
+  return cmd;
+}
+
+/* The TPM_PCR_SELECTION structure in /usr/include/tss/tpm.h contains a pointer
+ * instead of an array[3] of bytes, so we need to adjust sizes and offsets
+ * accordingly.
+ */
+#define PCR_SELECTION_FIX (3 - sizeof(char *))
+
+/* BuildXXX builds TPM command XXX.
+ */
+Command* BuildDefineSpaceCommand(void) {
+  int nv_data_public = kTpmRequestHeaderLength;
+  int nv_index = nv_data_public + offsetof(TPM_NV_DATA_PUBLIC, nvIndex);
+  int nv_pcr_info_read = nv_data_public +
+    offsetof(TPM_NV_DATA_PUBLIC, pcrInfoRead);
+  /*
+   * Here we need to carefully add PCR_SELECTION_FIX (or twice that much) in
+   * all the places where the offset calculation would be wrong without it.
+   * The mismatch occurs in the TPM_PCR_SELECTION structure, and it must be
+   * accounted for in all the structures that include it, directly or
+   * indirectly.
+   */
+  int read_locality = nv_pcr_info_read +
+    offsetof(TPM_PCR_INFO_SHORT, localityAtRelease) + PCR_SELECTION_FIX;
+  int nv_pcr_info_write = nv_data_public +
+    offsetof(TPM_NV_DATA_PUBLIC, pcrInfoWrite) + PCR_SELECTION_FIX;
+  int write_locality = nv_pcr_info_write +
+    offsetof(TPM_PCR_INFO_SHORT, localityAtRelease) + PCR_SELECTION_FIX;
+  int nv_permission = nv_data_public +
+    offsetof(TPM_NV_DATA_PUBLIC, permission) + 2 * PCR_SELECTION_FIX;
+  int nv_permission_tag =
+    nv_permission + offsetof(TPM_NV_ATTRIBUTES, tag);
+  int nv_permission_attributes =
+    nv_permission + offsetof(TPM_NV_ATTRIBUTES, attributes);
+  int nv_datasize = nv_data_public +
+    offsetof(TPM_NV_DATA_PUBLIC, dataSize) + 2 * PCR_SELECTION_FIX;
+
+  int size = kTpmRequestHeaderLength + sizeof(TPM_NV_DATA_PUBLIC) +
+    2 * PCR_SELECTION_FIX + kEncAuthLength;
+  Command* cmd = newCommand(TPM_ORD_NV_DefineSpace, size);
+  cmd->name = "tpm_nv_definespace_cmd";
+
+  AddVisibleField(cmd, "index", nv_index);
+  AddVisibleField(cmd, "perm", nv_permission_attributes);
+  AddVisibleField(cmd, "size", nv_datasize);
+
+  AddInitializedField(cmd, nv_data_public, sizeof(uint16_t),
+                      TPM_TAG_NV_DATA_PUBLIC);
+  AddInitializedField(cmd, nv_pcr_info_read, sizeof(uint16_t), 3);
+  AddInitializedField(cmd, read_locality, sizeof(TPM_LOCALITY_SELECTION),
+                      TPM_ALL_LOCALITIES);
+  AddInitializedField(cmd, nv_pcr_info_write, sizeof(uint16_t), 3);
+  AddInitializedField(cmd, write_locality, sizeof(TPM_LOCALITY_SELECTION),
+                      TPM_ALL_LOCALITIES);
+  AddInitializedField(cmd, nv_permission_tag, sizeof(TPM_STRUCTURE_TAG),
+                      TPM_TAG_NV_ATTRIBUTES);
+  return cmd;
+}
+
+/* BuildXXX builds TPM command XXX.
+ */
+Command* BuildWriteCommand(void) {
+  Command* cmd = newCommand(TPM_ORD_NV_WriteValue, 0);
+  cmd->name = "tpm_nv_write_cmd";
+  cmd->max_size = TPM_LARGE_ENOUGH_COMMAND_SIZE;
+  AddVisibleField(cmd, "index", kTpmRequestHeaderLength);
+  AddVisibleField(cmd, "length", kTpmRequestHeaderLength + 8);
+  AddVisibleField(cmd, "data", kTpmRequestHeaderLength + 12);
+  return cmd;
+}
+
+Command* BuildReadCommand(void) {
+  int size = kTpmRequestHeaderLength + kTpmReadInfoLength;
+  Command* cmd = newCommand(TPM_ORD_NV_ReadValue, size);
+  cmd->name = "tpm_nv_read_cmd";
+  AddVisibleField(cmd, "index", kTpmRequestHeaderLength);
+  AddVisibleField(cmd, "length", kTpmRequestHeaderLength + 8);
+  return cmd;
+}
+
+Command* BuildPhysicalPresenceCommand(void) {
+  int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE);
+  Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size);
+  cmd->name = "tpm_physicalpresence_cmd";
+  AddInitializedField(cmd, kTpmRequestHeaderLength,
+                      sizeof(TPM_PHYSICAL_PRESENCE),
+                      TPM_PHYSICAL_PRESENCE_PRESENT);
+  return cmd;
+}
+
+Command* BuildStartupCommand(void) {
+  int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE);
+  Command* cmd = newCommand(TPM_ORD_Startup, size);
+  cmd->name = "tpm_startup_cmd";
+  AddInitializedField(cmd, kTpmRequestHeaderLength,
+                      sizeof(TPM_STARTUP_TYPE),
+                      TPM_ST_CLEAR);
+  return cmd;
+}
+
+Command* BuildSelftestfullCommand(void) {
+  int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE);
+  Command* cmd = newCommand(TPM_ORD_SelfTestFull, size);
+  cmd->name = "tpm_selftestfull_cmd";
+  return cmd;
+}
+
+/* Output the fields of a structure.
+ */
+void OutputFields(Field* fld) {
+  /*
+   * Field order is reversed.
+   */
+  if (fld != NULL) {
+    OutputFields(fld->next);
+    if (fld->visible) {
+      printf("  uint8_t* %s;\n", fld->name);
+    }
+  }
+}
+
+/* Outputs a structure initializer.
+ */
+int OutputBytes_(Command* cmd, Field* fld) {
+  int cursor = 0;
+  int i;
+  /*
+   * Field order is reversed.
+   */
+  if (fld != NULL) {
+    cursor = OutputBytes_(cmd, fld->next);
+  } else {
+    return 0;
+  }
+  if (!fld->visible) {
+    /*
+     * Catch up missing fields.
+     */
+    assert(fld->offset >= cursor);
+    for (i = 0; i < fld->offset - cursor; i++) {
+      printf("0, ");
+    }
+    cursor = fld->offset;
+    switch (fld->size) {
+    case 1:
+      printf("0x%x, ", fld->value);
+      cursor += 1;
+      break;
+    case 2:
+      printf("0x%x, 0x%x, ", fld->value >> 8, fld->value & 0xff);
+      cursor += 2;
+      break;
+    case 4:
+      printf("0x%x, 0x%x, 0x%x, 0x%x, ", fld->value >> 24,
+             (fld->value >> 16) & 0xff, 
+             (fld->value >> 8) & 0xff, 
+             fld->value & 0xff);
+      cursor += 4;
+      break;
+    default:
+      error("invalid field size %d\n", fld->size);
+      break;
+    }
+  }
+  return cursor;
+}
+
+/* Helper to output a structure initializer.
+ */
+void OutputBytes(Command* cmd) {
+  (void) OutputBytes_(cmd, cmd->fields);
+}
+
+void OutputFieldPointers(Command* cmd, Field* fld) {
+  if (fld == NULL) {
+    return;
+  } else {
+    OutputFieldPointers(cmd, fld->next);
+    if (fld->visible) {
+      printf("%s.buffer + %d, ", cmd->name, fld->offset);
+    }
+  }
+}
+
+/* Outputs the structure initializers for all commands.
+ */
+void OutputCommands(Command* cmd) {
+  if (cmd == NULL) {
+    return;
+  } else {
+    printf("struct {\n  uint8_t buffer[%d];\n",
+           cmd->size == 0 ? cmd->max_size : cmd->size);
+    OutputFields(cmd->fields);
+    printf("} %s = {{", cmd->name);
+    OutputBytes(cmd);
+    printf("},\n");
+    OutputFieldPointers(cmd, cmd->fields);
+    printf("};\n\n");
+  }
+  OutputCommands(cmd->next);
+}
+
+Command* (*builders[])(void) = {
+  BuildDefineSpaceCommand,
+  BuildWriteCommand,
+  BuildReadCommand,
+  BuildPhysicalPresenceCommand,
+  BuildStartupCommand,
+  BuildSelftestfullCommand,
+};
+
+static void FreeFields(Field* fld) {
+  if (fld != NULL) {
+    Field* next_field = fld->next;
+    free(fld);
+    FreeFields(next_field);
+  }
+}
+
+static void FreeCommands(Command* cmd) {
+  if (cmd != NULL) {
+    Command* next_command = cmd->next;
+    free(cmd);
+    FreeCommands(next_command);
+  }
+}
+
+int main(void) {
+  Command* commands = NULL;
+  int i;
+  for (i = 0; i < sizeof(builders) / sizeof(builders[0]); i++) {
+    Command* cmd = builders[i]();
+    cmd->next = commands;
+    commands = cmd;
+  }
+
+  printf("/* This file is automatically generated */\n\n");
+  OutputCommands(commands);
+  printf("const int kWriteInfoLength = %ld;\n", sizeof(TPM_WRITE_INFO));
+
+  FreeCommands(commands);
+  return 0;
+}
diff --git a/src/tlcl/tlcl.c b/src/tlcl/tlcl.c
new file mode 100644
index 0000000..916fb9f
--- /dev/null
+++ b/src/tlcl/tlcl.c
@@ -0,0 +1,178 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* A lightweight TPM command library.
+ *
+ * The general idea is that TPM commands are array of bytes whose fields are
+ * mostly compile-time constant.  The goal is to build much of the commands at
+ * compile time (or build time) and change some of the fields at run time as
+ * needed.  The code in generator.c builds structures containing the commands,
+ * as well as the offsets of the fields that need to be set at run time.
+ */
+
+#include "tlcl.h"
+
+#include <string.h>
+#include <tss/tcs.h>
+
+#include "structures.h"
+#include "tlcl_internal.h"
+#include "tpmemu.h"
+#include "tpmextras.h"
+
+/* Gets the tag field of a TPM command.
+ */
+static INLINE int TpmTag(uint8_t* buffer) {
+  uint16_t tag;
+  FromTpmUint16(buffer, &tag);
+  return (int) tag;
+}
+
+/* Sets the size field of a TPM command.
+ */
+static INLINE void SetTpmCommandSize(uint8_t* buffer, uint32_t size) {
+  ToTpmUint32(buffer + 2, size);
+}
+
+/* Gets the size field of a TPM command.
+ */
+static INLINE int TpmCommandSize(const uint8_t* buffer) {
+  uint32_t size;
+  FromTpmUint32(buffer + 2, &size);
+  return (int) size;
+}
+
+/* Gets the code field of a TPM command.
+ */
+static INLINE int TpmCommandCode(const uint8_t* buffer) {
+  uint32_t code;
+  FromTpmUint32(buffer + 6, &code);
+  return code;
+}
+
+/* Gets the code field of a TPM result.
+ */
+static INLINE int TpmReturnCode(const uint8_t* buffer) {
+  return TpmCommandCode(buffer);
+}
+
+/* Checks for errors in a TPM response.
+ */
+static void CheckResult(uint8_t* request, uint8_t* response, bool warn_only) {
+  int command = TpmCommandCode(request);
+  int result = TpmReturnCode(response);
+  if (result != TPM_SUCCESS) {
+    (warn_only? warning : error)("command 0x%x failed: 0x%x\n",
+                                 command, result);
+  }
+}
+
+/* Sends a request and receive a response.
+ */
+static void SendReceive(uint8_t* request, uint8_t* response, int max_length) {
+  uint32_t response_length = max_length;
+  int tag, response_tag;
+
+  tpmemu_execute(request, TpmCommandSize(request), response, &response_length);
+
+  /* sanity checks */
+  tag = TpmTag(request);
+  response_tag = TpmTag(response);
+  assert(
+    (tag == TPM_TAG_RQU_COMMAND &&
+     response_tag == TPM_TAG_RSP_COMMAND) ||
+    (tag == TPM_TAG_RQU_AUTH1_COMMAND &&
+     response_tag == TPM_TAG_RSP_AUTH1_COMMAND) ||
+    (tag == TPM_TAG_RQU_AUTH2_COMMAND &&
+     response_tag == TPM_TAG_RSP_AUTH2_COMMAND));
+  assert(response_length == TpmCommandSize(response));
+}
+
+/* Sends a command and checks the result for errors.  Note that this error
+ * checking is only meaningful when running in user mode.  TODO: The entire
+ * error recovery strategy in the firmware needs more work.
+ */
+static void Send(uint8_t* command) {
+  uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+  SendReceive(command, response, sizeof(response));
+  CheckResult(command, response, false);
+}
+
+
+/* Exported functions.
+ */
+
+void TlclLibinit(void) {
+  tpmemu_init();
+}
+
+void TlclStartup(void) {
+  Send(tpm_startup_cmd.buffer);
+}
+
+void TlclSelftestfull(void) {
+  Send(tpm_selftestfull_cmd.buffer);
+}
+
+void TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size) {
+  ToTpmUint32(tpm_nv_definespace_cmd.index, index);
+  ToTpmUint32(tpm_nv_definespace_cmd.perm, perm);
+  ToTpmUint32(tpm_nv_definespace_cmd.size, size);
+  Send(tpm_nv_definespace_cmd.buffer);
+}
+
+uint32_t TlclWrite(uint32_t index, uint8_t* data, uint32_t length) {
+  uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+  const int total_length =
+    kTpmRequestHeaderLength + kWriteInfoLength + length;
+
+  assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
+  SetTpmCommandSize(tpm_nv_write_cmd.buffer, total_length);
+
+  ToTpmUint32(tpm_nv_write_cmd.index, index);
+  ToTpmUint32(tpm_nv_write_cmd.length, length);
+  memcpy(tpm_nv_write_cmd.data, data, length);
+
+  SendReceive(tpm_nv_write_cmd.buffer, response, sizeof(response));
+  CheckResult(tpm_nv_write_cmd.buffer, response, true);
+
+  return TpmReturnCode(response);
+}
+
+uint32_t TlclRead(uint32_t index, uint8_t* data, uint32_t length) {
+  uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+  uint32_t result_length;
+  uint32_t result;
+
+  ToTpmUint32(tpm_nv_read_cmd.index, index);
+  ToTpmUint32(tpm_nv_read_cmd.length, length);
+
+  SendReceive(tpm_nv_read_cmd.buffer, response, sizeof(response));
+  result = TpmReturnCode(response);
+  if (result == TPM_SUCCESS && length > 0) {
+    uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength;
+    FromTpmUint32(nv_read_cursor, &result_length);
+    nv_read_cursor += sizeof(uint32_t);
+    memcpy(data, nv_read_cursor, result_length);
+  }
+
+  return result;
+}
+
+void TlclWriteLock(uint32_t index) {
+  (void) TlclWrite(index, NULL, 0);
+}
+
+void TlclReadLock(uint32_t index) {
+  (void) TlclRead(index, NULL, 0);
+}
+
+void TlclAssertPhysicalPresence(void) {
+  Send(tpm_physicalpresence_cmd.buffer);
+}
+
+void TlclSetNvLocked(void) {
+  TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0);
+}
diff --git a/src/tlcl/tlcl_internal.h b/src/tlcl/tlcl_internal.h
new file mode 100644
index 0000000..1ca71c0
--- /dev/null
+++ b/src/tlcl/tlcl_internal.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TPM_LITE_TLCL_INTERNAL_H_
+#define TPM_LITE_TLCL_INTERNAL_H_
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef int bool;
+const bool true = 1;
+const bool false = 0;
+
+#define POSSIBLY_UNUSED __attribute__((unused))
+
+#ifdef __STRICT_ANSI__
+#define INLINE
+#else
+#define INLINE inline
+#endif
+
+/*
+ * Output an error message and quit the program.
+ */
+static void error(const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  fprintf(stderr, "ERROR: ");
+  vfprintf(stderr, format, ap);
+  va_end(ap);
+  exit(1);
+}
+
+/*
+ * Output a warning and continue.
+ */
+POSSIBLY_UNUSED
+static void warning(const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  fprintf(stderr, "WARNING: ");
+  vfprintf(stderr, format, ap);
+  va_end(ap);
+  exit(1);
+}
+
+#define assert(expr) do { if (!(expr)) { \
+      error("assert fail: %s at %s:%d\n", \
+            #expr, __FILE__, __LINE__); }} while(0)
+
+/*
+ * Conversion functions.  ToTpmTYPE puts a value of type TYPE into a TPM
+ * command buffer.  FromTpmTYPE gets a value of type TYPE from a TPM command
+ * buffer into a variable.
+ */
+POSSIBLY_UNUSED
+static INLINE void ToTpmUint32(uint8_t *buffer, uint32_t x) {
+  buffer[0] = (x >> 24);
+  buffer[1] = ((x >> 16) & 0xff);
+  buffer[2] = ((x >> 8) & 0xff);
+  buffer[3] = x & 0xff;
+}
+
+/*
+ * See comment for above function.
+ */
+POSSIBLY_UNUSED
+static INLINE void FromTpmUint32(const uint8_t *buffer, uint32_t *x) {
+  *x = ((buffer[0] << 24) |
+        (buffer[1] << 16) |
+        (buffer[2] << 8) |
+        buffer[3]);
+}
+
+/*
+ * See comment for above function.
+ */
+POSSIBLY_UNUSED
+static INLINE void ToTpmUint16(uint8_t *buffer, uint16_t x) {
+  buffer[0] = (x >> 8);
+  buffer[1] = x & 0xff;
+}
+
+/*
+ * See comment for above function.
+ */
+POSSIBLY_UNUSED
+static INLINE void FromTpmUint16(const uint8_t *buffer, uint16_t *x) {
+  *x = (buffer[0] << 8) | buffer[1];
+}
+
+/*
+ * These numbers derive from adding the sizes of command fields as shown in the
+ * TPM commands manual.
+ */
+const int kTpmRequestHeaderLength = 10;
+const int kTpmResponseHeaderLength = 14;
+const int kTpmReadInfoLength = 12;
+const int kEncAuthLength = 20;
+
+#endif
diff --git a/src/tlcl/tpmextras.h b/src/tlcl/tpmextras.h
new file mode 100644
index 0000000..7f01348
--- /dev/null
+++ b/src/tlcl/tpmextras.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * TPM definitions not available in any TSS include file :-(
+ */
+
+#ifndef TPM_LITE_TPMEXTRAS_H_
+#define TPM_LITE_TPMEXTRAS_H_
+
+#include <tss/tcs.h>
+
+#define TPM_MAX_COMMAND_SIZE 4096
+#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256  /* saves space in the firmware */
+
+typedef struct tdTPM_WRITE_INFO {
+  uint32_t nvIndex;
+  uint32_t offset;
+  uint32_t dataSize;
+} TPM_WRITE_INFO;
+
+#define TPM_ALL_LOCALITIES (TPM_LOC_ZERO | TPM_LOC_ONE | TPM_LOC_TWO \
+                            | TPM_LOC_THREE | TPM_LOC_FOUR)  /* 0x1f */
+
+#define TPM_ENCAUTH_SIZE 20
+
+#endif