Additional cases for the test suite, and more commands added to TLCL
to support the new cases.

Review URL: http://codereview.chromium.org/1056001
diff --git a/src/include/tlcl.h b/src/include/tlcl.h
index 30c7350..e0b5626 100644
--- a/src/include/tlcl.h
+++ b/src/include/tlcl.h
@@ -26,6 +26,7 @@
 
 /* Outputs an error message and quits the program.
  */
+POSSIBLY_UNUSED
 static void error(const char *format, ...) {
   va_list ap;
   va_start(ap, format);
@@ -99,4 +100,20 @@
  */
 int TlclIsOwned(void);
 
+/* Issues a ForceClear.
+ */
+void TlclForceClear(void);
+
+/* Issues a PhysicalEnable.
+ */
+void TlclPhysicalEnable(void);
+
+/* Issues a PhysicalSetDeactivated.  Pass 0 to activate.  Returns result code.
+ */
+int TlclPhysicalSetDeactivated(uint8_t flag);
+
+/* Gets some permanent flags of interest.  (Add more here as needed.)
+ */
+int TlclGetFlags(uint8_t* disable, uint8_t* deactivated);
+
 #endif  /* TPM_LITE_TLCL_H_ */
diff --git a/src/testsuite/Makefile b/src/testsuite/Makefile
index 0211af5..0858671 100644
--- a/src/testsuite/Makefile
+++ b/src/testsuite/Makefile
@@ -23,7 +23,7 @@
 CFLAGS += -Werror -Wall
 #CFLAGS += -pedantic -ansi
 
-TESTS = tpmtest_readonly
+TESTS = tpmtest_readonly tpmtest_clear tpmtest_writelimit tpmtest_lock
 
 all: $(TESTS)
 
diff --git a/src/testsuite/clear.c b/src/testsuite/clear.c
new file mode 100644
index 0000000..0042ed6
--- /dev/null
+++ b/src/testsuite/clear.c
@@ -0,0 +1,45 @@
+/* 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.
+ */
+
+/* Testing: ownership testing code, ForceClear, and nvram write limit.
+ */
+
+#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
+
+int main(void) {
+  int owned;
+
+  TlclLibinit();
+
+#if !USE_TPM_EMULATOR
+  /* The emulator does these itself. */
+  TlclStartup();
+  TlclSelftestfull();
+#endif
+
+  TlclAssertPhysicalPresence();
+
+  owned = TlclIsOwned();
+  printf("tpm is %sowned\n", owned?  "" : "NOT ");
+  if (owned) {
+    TlclForceClear();
+    printf("tpm was cleared\n");
+  }
+
+  return 0;
+}
diff --git a/src/testsuite/lock.c b/src/testsuite/lock.c
new file mode 100644
index 0000000..9b7cf75
--- /dev/null
+++ b/src/testsuite/lock.c
@@ -0,0 +1,31 @@
+/* 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.
+ */
+
+/* Test of locking, to see if locks count as writes.  (They should.)
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <tss/tcs.h>
+
+#include "tlcl.h"
+
+#define INDEX0 0xda70
+
+
+int main(void) {
+  TlclLibinit();
+
+  TlclStartup();
+  TlclSelftestfull();
+
+  TlclAssertPhysicalPresence();
+
+  TlclWriteLock(INDEX0);
+
+  printf("Locked 0x%x\n", INDEX0);
+  exit(0);
+}
diff --git a/src/testsuite/writelimit.c b/src/testsuite/writelimit.c
new file mode 100644
index 0000000..b2a251a
--- /dev/null
+++ b/src/testsuite/writelimit.c
@@ -0,0 +1,60 @@
+/* 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.
+ */
+
+/* Test of recovery when we hit the NVRAM write limit for an unowned TPM.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <tss/tcs.h>
+
+#include "tlcl.h"
+
+#define INDEX0 0xda70
+#define TPM_MAX_NV_WRITES_NOOWNER 64
+
+int main(void) {
+  int i;
+  uint32_t result;
+  uint8_t disable, deactivated;  /* the TPM specs use these exact names */
+
+  TlclLibinit();
+
+  TlclStartup();
+  TlclSelftestfull();
+
+  TlclAssertPhysicalPresence();
+
+  result = TlclGetFlags(&disable, &deactivated);
+  printf("disable is %d, deactivated is %d\n", disable, deactivated);
+  
+  if (disable || deactivated) {
+    TlclPhysicalEnable();
+    (void) TlclPhysicalSetDeactivated(0);
+    printf("TPM will be active after next reboot\n");
+    exit(0);
+  }
+
+  for (i = 0; i < TPM_MAX_NV_WRITES_NOOWNER + 2; i++) {
+    printf("writing %d\n", i);
+    if ((result = TlclWrite(INDEX0, (uint8_t*)&i, sizeof(i))) != TPM_SUCCESS) {
+      switch (result) {
+      case TPM_E_MAXNVWRITES:
+        printf("Max NV writes exceeded - forcing clear\n");
+        TlclForceClear();
+        printf("Please reboot and run this program again\n");
+        exit(0);
+      default:
+        error("unexpected error code %d (0x%x)\n");
+      }
+    }
+  }
+
+  /* Done for now.
+   */
+  printf("Test completed successfully\n");
+  exit(0);
+}
diff --git a/src/tlcl/generator.c b/src/tlcl/generator.c
index 1e48481..a1bc46b 100644
--- a/src/tlcl/generator.c
+++ b/src/tlcl/generator.c
@@ -204,6 +204,47 @@
   return cmd;  
 }
 
+Command* BuildForceClearCommand(void) {
+  int size = kTpmRequestHeaderLength;
+  Command* cmd = newCommand(TPM_ORD_ForceClear, size);
+  cmd->name = "tpm_forceclear_cmd";
+  return cmd;  
+}
+
+Command* BuildPhysicalEnableCommand(void) {
+  int size = kTpmRequestHeaderLength;
+  Command* cmd = newCommand(TPM_ORD_PhysicalEnable, size);
+  cmd->name = "tpm_physicalenable_cmd";
+  return cmd;  
+}
+
+Command* BuildPhysicalSetDeactivatedCommand(void) {
+  int size = kTpmRequestHeaderLength + sizeof(uint8_t);
+  Command* cmd = newCommand(TPM_ORD_PhysicalSetDeactivated, size);
+  cmd->name = "tpm_physicalsetdeactivated_cmd";
+  AddVisibleField(cmd, "deactivated", kTpmRequestHeaderLength);
+  return cmd;  
+}
+
+Command* BuildGetCapabilityCommand(void) {
+  int size = (kTpmRequestHeaderLength +
+              sizeof(TPM_CAPABILITY_AREA) +   /* capArea */
+              sizeof(uint32_t) +              /* subCapSize */
+              sizeof(uint32_t));               /* subCap */
+    
+  Command* cmd = newCommand(TPM_ORD_GetCapability, size);
+  cmd->name = "tpm_getcapability_cmd";
+  AddInitializedField(cmd, kTpmRequestHeaderLength,
+                      sizeof(TPM_CAPABILITY_AREA), TPM_CAP_FLAG);
+  AddInitializedField(cmd, kTpmRequestHeaderLength +
+                      sizeof(TPM_CAPABILITY_AREA),
+                      sizeof(uint32_t), sizeof(uint32_t));
+  AddInitializedField(cmd, kTpmRequestHeaderLength +
+                      sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t),
+                      sizeof(uint32_t), TPM_CAP_FLAG_PERMANENT);
+  return cmd;  
+}
+
 /* Output the fields of a structure.
  */
 void OutputFields(Field* fld) {
@@ -307,6 +348,10 @@
   BuildStartupCommand,
   BuildSelftestfullCommand,
   BuildReadPubekCommand,
+  BuildForceClearCommand,
+  BuildPhysicalEnableCommand,
+  BuildPhysicalSetDeactivatedCommand,
+  BuildGetCapabilityCommand,
 };
 
 static void FreeFields(Field* fld) {
diff --git a/src/tlcl/tlcl.c b/src/tlcl/tlcl.c
index 22d3613..7dc800b 100644
--- a/src/tlcl/tlcl.c
+++ b/src/tlcl/tlcl.c
@@ -150,9 +150,11 @@
     printf("response (%d bytes): ", y);
     PrintBytes(response, 10);
     PrintBytes(response + 10, y - 10);
+#if !USE_TPM_EMULATOR
     printf("execution time: %dms\n",
            (int) ((after.tv_sec - before.tv_sec) * 1000 +
                   (after.tv_usec - before.tv_usec) / 1000));
+#endif
   }
 
   /* sanity checks */
@@ -273,3 +275,48 @@
   result = TpmReturnCode(response);
   return (result != TPM_SUCCESS);
 }
+
+void TlclForceClear(void) {
+  uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+  uint32_t result;
+  SendReceive(tpm_forceclear_cmd.buffer, response, sizeof(response));
+  result = TpmReturnCode(response);
+  if (result != TPM_SUCCESS) {
+    warning("ForceClear failed with code %d (0x%x)\n", result, result);
+  }
+}
+
+void TlclPhysicalEnable(void) {
+  Send(tpm_physicalenable_cmd.buffer);
+}
+
+int TlclPhysicalSetDeactivated(uint8_t flag) {
+  uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+  uint32_t result;
+  *((uint8_t*)tpm_physicalsetdeactivated_cmd.deactivated) = flag;
+  SendReceive(tpm_physicalsetdeactivated_cmd.buffer,
+              response, sizeof(response));
+  result = TpmReturnCode(response);
+  return result;
+}
+
+int TlclGetFlags(uint8_t* disable, uint8_t* deactivated) {
+  
+  uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
+  TPM_PERMANENT_FLAGS* pflags;
+  uint32_t result;
+  uint32_t size;
+
+  SendReceive(tpm_getcapability_cmd.buffer, response, sizeof(response));
+  result = TpmReturnCode(response);
+  if (result != TPM_SUCCESS) {
+    return result;
+  }
+  FromTpmUint32(response + kTpmResponseHeaderLength, &size);
+  assert(size == sizeof(TPM_PERMANENT_FLAGS));
+  pflags =
+    (TPM_PERMANENT_FLAGS*) (response + kTpmResponseHeaderLength + sizeof(size));
+  *disable = pflags->disable;
+  *deactivated = pflags->deactivated;
+  return result;
+}