Index: firmware/stub/tpm_lite_stub.c |
diff --git a/firmware/stub/tpm_lite_stub.c b/firmware/stub/tpm_lite_stub.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ee1cbf13664c1d7b2e9d1b353cd3fca65f0d7b65 |
--- /dev/null |
+++ b/firmware/stub/tpm_lite_stub.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. |
+ * |
+ * Stub implementations of utility functions which call their linux-specific |
+ * equivalents. |
+ */ |
+ |
+#define _STUB_IMPLEMENTATION_ |
+#include "tlcl.h" |
+#include "tlcl_internal.h" |
+#include "utility.h" |
+ |
+#include <errno.h> |
+#include <fcntl.h> |
+#include <stdarg.h> |
+#include <stdio.h> |
+#include <string.h> |
+#include <sys/time.h> |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <unistd.h> |
+#include <tss/tcs.h> |
+#include "tpmextras.h" |
+#define TPM_DEVICE_PATH "/dev/tpm0" |
+ |
+/* TODO: these functions should pass errors back rather than returning void */ |
+/* TODO: if the only callers to these are just wrappers, should just |
+ * remove the wrappers and call us directly. */ |
+ |
+ |
+/* The file descriptor for the TPM device. |
+ */ |
+static int tpm_fd = -1; |
+ |
+ |
+/* Print |n| bytes from array |a|, with newlines. |
+ */ |
+POSSIBLY_UNUSED static void PrintBytes(uint8_t* a, int n) { |
+ int i; |
+ for (i = 0; i < n; i++) { |
+ VBDEBUG(("%02x ", a[i])); |
+ if ((i + 1) % 16 == 0) { |
+ VBDEBUG(("\n")); |
+ } |
+ } |
+ if (i % 16 != 0) { |
+ VBDEBUG(("\n")); |
+ } |
+} |
+ |
+ |
+/* Executes a command on the TPM. |
+ */ |
+static void TpmExecute(const uint8_t *in, const uint32_t in_len, |
+ uint8_t *out, uint32_t *pout_len) { |
+ uint8_t response[TPM_MAX_COMMAND_SIZE]; |
+ if (in_len <= 0) { |
+ error("invalid command length %d\n", in_len); |
+ } else if (tpm_fd < 0) { |
+ error("the TPM device was not opened. Forgot to call TlclLibInit?\n"); |
+ } else { |
+ int n = write(tpm_fd, in, in_len); |
+ if (n != in_len) { |
+ error("write failure to TPM device: %s\n", strerror(errno)); |
+ } |
+ n = read(tpm_fd, response, sizeof(response)); |
+ if (n == 0) { |
+ error("null read from TPM device\n"); |
+ } else if (n < 0) { |
+ error("read failure from TPM device: %s\n", strerror(errno)); |
+ } else { |
+ if (n > *pout_len) { |
+ error("TPM response too long for output buffer\n"); |
+ } else { |
+ *pout_len = n; |
+ Memcpy(out, response, n); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+/* Gets the tag field of a TPM command. |
+ */ |
+POSSIBLY_UNUSED static INLINE int TpmTag(uint8_t* buffer) { |
+ uint16_t tag; |
+ FromTpmUint16(buffer, &tag); |
+ return (int) tag; |
+} |
+ |
+ |
+/* Gets the size field of a TPM command. |
+ */ |
+POSSIBLY_UNUSED static INLINE int TpmResponseSize(const uint8_t* buffer) { |
+ uint32_t size; |
+ FromTpmUint32(buffer + sizeof(uint16_t), &size); |
+ return (int) size; |
+} |
+ |
+ |
+void TlclStubInit(void) { |
+ TlclOpenDevice(); |
+} |
+ |
+ |
+void TlclCloseDevice(void) { |
+ close(tpm_fd); |
+ tpm_fd = -1; |
+} |
+ |
+ |
+void TlclOpenDevice(void) { |
+ if (tpm_fd >= 0) |
+ return; /* Already open */ |
+ |
+ tpm_fd = open(TPM_DEVICE_PATH, O_RDWR); |
+ if (tpm_fd < 0) { |
+ error("cannot open TPM device %s: %s\n", TPM_DEVICE_PATH, strerror(errno)); |
+ } |
+} |
+ |
+ |
+void TlclStubSendReceive(uint8_t* request, int request_length, |
+ uint8_t* response, int max_length) { |
+ /* |
+ * In a real firmware implementation, this function should contain |
+ * the equivalent API call for the firmware TPM driver which takes a |
+ * raw sequence of bytes as input command and a pointer to the |
+ * output buffer for putting in the results. |
+ * |
+ * For EFI firmwares, this can make use of the EFI TPM driver as |
+ * follows (based on page 16, of TCG EFI Protocol Specs Version 1.20 |
+ * availaible from the TCG website): |
+ * |
+ * EFI_STATUS status; |
+ * status = TcgProtocol->EFI_TCG_PASS_THROUGH_TO_TPM(TpmCommandSize(request), |
+ * request, |
+ * max_length, |
+ * response); |
+ * // Error checking depending on the value of the status above |
+ */ |
+ uint32_t response_length = max_length; |
+ int tag, response_tag; |
+ |
+ struct timeval before, after; |
+ gettimeofday(&before, NULL); |
+ TpmExecute(request, request_length, response, &response_length); |
+ gettimeofday(&after, NULL); |
+ |
+#ifdef VBOOT_DEBUG |
+ { |
+ int x = request_length; |
+ int y = response_length; |
+ VBDEBUG(("request (%d bytes): ", x)); |
+ PrintBytes(request, 10); |
+ PrintBytes(request + 10, x - 10); |
+ VBDEBUG(("response (%d bytes): ", y)); |
+ PrintBytes(response, 10); |
+ PrintBytes(response + 10, y - 10); |
+ VBDEBUG(("execution time: %dms\n", |
+ (int) ((after.tv_sec - before.tv_sec) * 1000 + |
+ (after.tv_usec - before.tv_usec) / 1000))); |
+ } |
+#endif |
+ |
+ /* 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 == TpmResponseSize(response)); |
+} |