From mboxrd@z Thu Jan 1 00:00:00 1970 From: Matthew Fioravante Subject: Re: [PATCH mini-os enhancements for vtpm 8/8] Add 3 tpm drivers to mini-os Date: Wed, 26 Sep 2012 10:29:58 -0400 Message-ID: <50631166.5010709@jhuapl.edu> References: <50579F53.4070302@jhuapl.edu> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3681841939449735748==" Return-path: In-Reply-To: List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: George Dunlap Cc: Samuel Thibault , "xen-devel@lists.xensource.com" List-Id: xen-devel@lists.xenproject.org This is a cryptographically signed message in MIME format. --===============3681841939449735748== Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha1; boundary="------------ms090403080908030504050400" This is a cryptographically signed message in MIME format. --------------ms090403080908030504050400 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On 09/26/2012 09:25 AM, George Dunlap wrote: > On Mon, Sep 17, 2012 at 11:08 PM, Matthew Fioravante > wrote: >> This patch adds 3 new drivers to mini-os. >> >> tpmfront - paravirtualized tpm frontend driver >> tpmback - paravirtualized tpm backend driver >> tpm_tis - hardware tpm driver > Just trying to understand this -- tpmback is so that you can run a > vtpm instance in the stubdom. But what is tmpfront for? Is that for > running qemu stub domains? > > -George tpmfront and tpmback are like traditional frontend/backend paravirtualized xen drivers. vtpm-stubdom uses tpmback to talk to the linux guest. tpmfront and tpmback are also used by vtpm-stubdom and vtpmmgrdom to communicate with one another. The driver chain looks like this. linux guest [tpm_xenu] -> [tpmback] vtpm-stubdom [tpmfront]->[tpmback]vtpmmgrdom[tpm_tis]->TPM > >> Unfortunately these drivers were derived from GPL licensed linux kerne= l >> drivers so they must carry the GPL license. However, since mini-os now= >> supports conditional compilation, hopefully these drivers can be >> included into the xen tree and conditionally removed from non-gpl >> projects. By default they are disabled in the makefile. >> >> Signed off by: Matthew Fioravante matthew.fioravante@jhuapl.edu >> >> diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile >> --- a/extras/mini-os/Makefile >> +++ b/extras/mini-os/Makefile >> @@ -22,6 +22,9 @@ CONFIG_QEMU_XS_ARGS ?=3D n >> CONFIG_TEST ?=3D n >> CONFIG_PCIFRONT ?=3D n >> CONFIG_BLKFRONT ?=3D y >> +CONFIG_TPMFRONT ?=3D n >> +CONFIG_TPM_TIS ?=3D n >> +CONFIG_TPMBACK ?=3D n >> CONFIG_NETFRONT ?=3D y >> CONFIG_FBFRONT ?=3D y >> CONFIG_KBDFRONT ?=3D y >> @@ -36,6 +39,9 @@ flags-$(CONFIG_SPARSE_BSS) +=3D -DCONFIG_SPARSE_BSS >> flags-$(CONFIG_QEMU_XS_ARGS) +=3D -DCONFIG_QEMU_XS_ARGS >> flags-$(CONFIG_PCIFRONT) +=3D -DCONFIG_PCIFRONT >> flags-$(CONFIG_BLKFRONT) +=3D -DCONFIG_BLKFRONT >> +flags-$(CONFIG_TPMFRONT) +=3D -DCONFIG_TPMFRONT >> +flags-$(CONFIG_TPM_TIS) +=3D -DCONFIG_TPM_TIS >> +flags-$(CONFIG_TPMBACK) +=3D -DCONFIG_TPMBACK >> flags-$(CONFIG_NETFRONT) +=3D -DCONFIG_NETFRONT >> flags-$(CONFIG_KBDFRONT) +=3D -DCONFIG_KBDFRONT >> flags-$(CONFIG_FBFRONT) +=3D -DCONFIG_FBFRONT >> @@ -67,6 +73,9 @@ TARGET :=3D mini-os >> SUBDIRS :=3D lib xenbus console >> >> src-$(CONFIG_BLKFRONT) +=3D blkfront.c >> +src-$(CONFIG_TPMFRONT) +=3D tpmfront.c >> +src-$(CONFIG_TPM_TIS) +=3D tpm_tis.c >> +src-$(CONFIG_TPMBACK) +=3D tpmback.c >> src-y +=3D daytime.c >> src-y +=3D events.c >> src-$(CONFIG_FBFRONT) +=3D fbfront.c >> diff --git a/extras/mini-os/include/lib.h b/extras/mini-os/include/lib= =2Eh >> --- a/extras/mini-os/include/lib.h >> +++ b/extras/mini-os/include/lib.h >> @@ -142,6 +142,8 @@ enum fd_type { >> FTYPE_FB, >> FTYPE_MEM, >> FTYPE_SAVEFILE, >> + FTYPE_TPMFRONT, >> + FTYPE_TPM_TIS, >> }; >> >> LIST_HEAD(evtchn_port_list, evtchn_port_info); >> @@ -185,6 +187,20 @@ extern struct file { >> struct { >> struct consfront_dev *dev; >> } cons; >> +#ifdef CONFIG_TPMFRONT >> + struct { >> + struct tpmfront_dev *dev; >> + int respgot; >> + off_t offset; >> + } tpmfront; >> +#endif >> +#ifdef CONFIG_TPM_TIS >> + struct { >> + struct tpm_chip *dev; >> + int respgot; >> + off_t offset; >> + } tpm_tis; >> +#endif >> #ifdef CONFIG_XENBUS >> struct { >> /* To each xenbus FD is associated a queue of watch event= s >> for this >> diff --git a/extras/mini-os/include/tpm_tis.h >> b/extras/mini-os/include/tpm_tis.h >> --- /dev/null >> +++ b/extras/mini-os/include/tpm_tis.h >> @@ -0,0 +1,63 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented b= y >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This driver is free software: you can redistribute it and/or modif= y >> + * it under the terms of the GNU General Public License as published = by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * This driver is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see . >> + * >> + * Based upon the files: >> + * drivers/char/tpm/tpm_tis.c >> + * drivers/char/tpm/tpm.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporatio= n >> + */ >> +#ifndef TPM_TIS_H >> +#define TPM_TIS_H >> + >> +#include >> +#include >> + >> +#define TPM_TIS_EN_LOCL0 1 >> +#define TPM_TIS_EN_LOCL1 (1 << 1) >> +#define TPM_TIS_EN_LOCL2 (1 << 2) >> +#define TPM_TIS_EN_LOCL3 (1 << 3) >> +#define TPM_TIS_EN_LOCL4 (1 << 4) >> +#define TPM_TIS_EN_LOCLALL (TPM_TIS_EN_LOCL0 | TPM_TIS_EN_LOCL1 | >> TPM_TIS_EN_LOCL2 | TPM_TIS_EN_LOCL3 | TPM_TIS_EN_LOCL4) >> +#define TPM_TIS_LOCL_INT_TO_FLAG(x) (1 << x) >> +#define TPM_BASEADDR 0xFED40000 >> +#define TPM_PROBE_IRQ 0xFFFF >> + >> +struct tpm_chip; >> + >> +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,= >> unsigned int irq); >> +void shutdown_tpm_tis(struct tpm_chip* tpm); >> + >> +int tpm_tis_request_locality(struct tpm_chip* tpm, int locality); >> +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen, >> uint8_t** resp, size_t* resplen); >> + >> +#ifdef HAVE_LIBC >> +#include >> +#include >> +/* POSIX IO functions: >> + * use tpm_tis_open() to get a file descriptor to the tpm device >> + * use write() on the fd to send a command to the backend. You must >> + * include the entire command in a single call to write(). >> + * use read() on the fd to read the response. You can use >> + * fstat() to get the size of the response and lseek() to seek on it.= >> + */ >> +int tpm_tis_open(struct tpm_chip* tpm); >> +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count); >> +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count); >> +int tpm_tis_posix_fstat(int fd, struct stat* buf); >> +#endif >> + >> +#endif >> diff --git a/extras/mini-os/include/tpmback.h >> b/extras/mini-os/include/tpmback.h >> --- /dev/null >> +++ b/extras/mini-os/include/tpmback.h >> @@ -0,0 +1,95 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented b= y >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This driver is free software: you can redistribute it and/or modif= y >> + * it under the terms of the GNU General Public License as published = by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * This driver is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see . >> + * >> + * Based upon the files: >> + * drivers/xen/tpmbk.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporatio= n >> + */ >> +#include >> +#include >> +#include >> +#include >> +#ifndef TPMBACK_H >> +#define TPMBACK_H >> + >> +struct tpmcmd { >> + domid_t domid; /* Domid of the frontend */ >> + unsigned int handle; /* Handle of the frontend */ >> + char* uuid; /* uuid of the tpm interface - allocated >> internally, dont free it */ >> + >> + unsigned int req_len; /* Size of the command in buf - set b= y >> tpmback driver */ >> + uint8_t* req; /* tpm command bits, allocated by driver,= >> DON'T FREE IT */ >> + unsigned int resp_len; /* Size of the outgoing command, >> + you set this before passing the cmd object to >> tpmback_resp */ >> + uint8_t* resp; /* Buffer for response - YOU MUST ALLOCATE I= T, >> YOU MUST ALSO FREE IT */ >> +}; >> +typedef struct tpmcmd tpmcmd_t; >> + >> +/* Initialize the tpm backend driver >> + * @exclusive_domname - This is NULL terminated list of vtpm uuid >> strings. If this list >> + * is non-empty, then only frontend domains with vtpm >> uuid's matching >> + * entries in this list will be allowed to connect. >> + * Other connections will be immediatly closed. >> + * Set this argument to NULL to allow any vtpm to connect= =2E >> + */ >> +void init_tpmback(char** exclusive_uuids); >> +/* Shutdown tpm backend driver */ >> +void shutdown_tpmback(void); >> + >> +/* Blocks until a tpm command is sent from any front end. >> + * Returns a pointer to the tpm command to handle. >> + * Do not try to free this pointer or the req buffer >> + * This function will return NULL if the tpm backend driver >> + * is shutdown or any other error occurs */ >> +tpmcmd_t* tpmback_req_any(void); >> + >> +/* Blocks until a tpm command from the frontend at domid/handle >> + * is sent. >> + * Returns NULL if domid/handle is not connected, tpmback is >> + * shutdown or shutting down, or if there is an error >> + */ >> +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle); >> + >> +/* Send the response to the tpm command back to the frontend >> + * This function will free the tpmcmd object, but you must free the r= esp >> + * buffer yourself */ >> +void tpmback_resp(tpmcmd_t* tpmcmd); >> + >> +/* Waits for the first frontend to connect and then sets domid and >> handle appropriately. >> + * If one or more frontends are already connected, this will set domi= d >> and handle to one >> + * of them arbitrarily. The main use for this function is to wait unt= il >> a single >> + * frontend connection has occured. >> + * returns 0 on success, non-zero on failure */ >> +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int >> *handle); >> + >> +/* returns the number of frontends connected */ >> +int tpmback_num_frontends(void); >> + >> +/* Returns the uuid of the specified frontend, NULL on error */ >> +char* tpmback_get_uuid(domid_t domid, unsigned int handle); >> + >> +/* Specify a function to call when a new tpm device connects */ >> +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int)); >> + >> +/* Specify a function to call when a tpm device disconnects */ >> +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int)); >> + >> +//Not Implemented >> +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int));= >> +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)); >> + >> +#endif >> diff --git a/extras/mini-os/include/tpmfront.h >> b/extras/mini-os/include/tpmfront.h >> --- /dev/null >> +++ b/extras/mini-os/include/tpmfront.h >> @@ -0,0 +1,94 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented b= y >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This driver is free software: you can redistribute it and/or modif= y >> + * it under the terms of the GNU General Public License as published = by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * This driver is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see . >> + * >> + * Based upon the files: >> + * drivers/char/tpm/tpm_vtpm.c >> + * drivers/char/tpm/tpm_xen.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporatio= n >> + */ >> +#ifndef TPMFRONT_H >> +#define TPMFRONT_H >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +struct tpmfront_dev { >> + grant_ref_t ring_ref; >> + evtchn_port_t evtchn; >> + >> + tpmif_tx_interface_t* tx; >> + >> + void** pages; >> + >> + domid_t bedomid; >> + char* nodename; >> + char* bepath; >> + >> + XenbusState state; >> + >> + uint8_t waiting; >> + struct wait_queue_head waitq; >> + >> + uint8_t* respbuf; >> + size_t resplen; >> + >> +#ifdef HAVE_LIBC >> + int fd; >> +#endif >> + >> +}; >> + >> + >> +/*Initialize frontend */ >> +struct tpmfront_dev* init_tpmfront(const char* nodename); >> +/*Shutdown frontend */ >> +void shutdown_tpmfront(struct tpmfront_dev* dev); >> + >> +/* Send a tpm command to the backend and wait for the response >> + * >> + * @dev - frontend device >> + * @req - request buffer >> + * @reqlen - length of request buffer >> + * @resp - *resp will be set to internal response buffer, don't free >> it! Value is undefined on error >> + * @resplen - *resplen will be set to the length of the response. Val= ue >> is undefined on error >> + * >> + * returns 0 on success, non zero on failure. >> + * */ >> +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqle= n, >> uint8_t** resp, size_t* resplen); >> + >> +#ifdef HAVE_LIBC >> +#include >> +/* POSIX IO functions: >> + * use tpmfront_open() to get a file descriptor to the tpm device >> + * use write() on the fd to send a command to the backend. You must >> + * include the entire command in a single call to write(). >> + * use read() on the fd to read the response. You can use >> + * fstat() to get the size of the response and lseek() to seek on it.= >> + */ >> +int tpmfront_open(struct tpmfront_dev* dev); >> +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count); >> +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count); >> +int tpmfront_posix_fstat(int fd, struct stat* buf); >> +#endif >> + >> + >> +#endif >> diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c >> --- a/extras/mini-os/lib/sys.c >> +++ b/extras/mini-os/lib/sys.c >> @@ -27,6 +27,8 @@ >> #include >> #include >> #include >> +#include >> +#include >> #include >> #include >> >> @@ -294,6 +296,16 @@ int read(int fd, void *buf, size_t nbytes) >> return blkfront_posix_read(fd, buf, nbytes); >> } >> #endif >> +#ifdef CONFIG_TPMFRONT >> + case FTYPE_TPMFRONT: { >> + return tpmfront_posix_read(fd, buf, nbytes); >> + } >> +#endif >> +#ifdef CONFIG_TPM_TIS >> + case FTYPE_TPM_TIS: { >> + return tpm_tis_posix_read(fd, buf, nbytes); >> + } >> +#endif >> default: >> break; >> } >> @@ -330,6 +342,14 @@ int write(int fd, const void *buf, size_t nbytes)= >> case FTYPE_BLK: >> return blkfront_posix_write(fd, buf, nbytes); >> #endif >> +#ifdef CONFIG_TPMFRONT >> + case FTYPE_TPMFRONT: >> + return tpmfront_posix_write(fd, buf, nbytes); >> +#endif >> +#ifdef CONFIG_TPM_TIS >> + case FTYPE_TPM_TIS: >> + return tpm_tis_posix_write(fd, buf, nbytes); >> +#endif >> default: >> break; >> } >> @@ -341,8 +361,16 @@ int write(int fd, const void *buf, size_t nbytes)= >> off_t lseek(int fd, off_t offset, int whence) >> { >> switch(files[fd].type) { >> +#if defined(CONFIG_BLKFRONT) || defined(CONFIG_TPMFRONT) || >> defined(CONFIG_TPM_TIS) >> #ifdef CONFIG_BLKFRONT >> case FTYPE_BLK: >> +#endif >> +#ifdef CONFIG_TPMFRNT >> + case FTYPE_TPMFRONT: >> +#endif >> +#ifdef CONFIG_TPM_TIS >> + case FTYPE_TPM_TIS: >> +#endif >> switch (whence) { >> case SEEK_SET: >> files[fd].file.offset =3D offset; >> @@ -420,6 +448,18 @@ int close(int fd) >> files[fd].type =3D FTYPE_NONE; >> return 0; >> #endif >> +#ifdef CONFIG_TPMFRONT >> + case FTYPE_TPMFRONT: >> + shutdown_tpmfront(files[fd].tpmfront.dev); >> + files[fd].type =3D FTYPE_NONE; >> + return 0; >> +#endif >> +#ifdef CONFIG_TPM_TIS >> + case FTYPE_TPM_TIS: >> + shutdown_tpm_tis(files[fd].tpm_tis.dev); >> + files[fd].type =3D FTYPE_NONE; >> + return 0; >> +#endif >> #ifdef CONFIG_KBDFRONT >> case FTYPE_KBD: >> shutdown_kbdfront(files[fd].kbd.dev); >> @@ -489,6 +529,14 @@ int fstat(int fd, struct stat *buf) >> case FTYPE_BLK: >> return blkfront_posix_fstat(fd, buf); >> #endif >> +#ifdef CONFIG_TPMFRONT >> + case FTYPE_TPMFRONT: >> + return tpmfront_posix_fstat(fd, buf); >> +#endif >> +#ifdef CONFIG_TPM_TIS >> + case FTYPE_TPM_TIS: >> + return tpm_tis_posix_fstat(fd, buf); >> +#endif >> default: >> break; >> } >> diff --git a/extras/mini-os/tpm_tis.c b/extras/mini-os/tpm_tis.c >> --- /dev/null >> +++ b/extras/mini-os/tpm_tis.c >> @@ -0,0 +1,1344 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented b= y >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This driver is free software: you can redistribute it and/or modif= y >> + * it under the terms of the GNU General Public License as published = by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * This driver is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see . >> + * >> + * Based upon the files: >> + * drivers/char/tpm/tpm_tis.c >> + * drivers/char/tpm/tpm.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporatio= n >> + */ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#ifndef min >> + #define min( a, b ) ( ((a) < (b)) ? (a) : (b) ) >> +#endif >> + >> +#define TPM_HEADER_SIZE 10 >> + >> +#define TPM_BUFSIZE 2048 >> + >> +struct tpm_input_header { >> + uint16_t tag; >> + uint32_t length; >> + uint32_t ordinal; >> +}__attribute__((packed)); >> + >> +struct tpm_output_header { >> + uint16_t tag; >> + uint32_t length; >> + uint32_t return_code; >> +}__attribute__((packed)); >> + >> +struct stclear_flags_t { >> + uint16_t tag; >> + uint8_t deactivated; >> + uint8_t disableForceClear; >> + uint8_t physicalPresence; >> + uint8_t physicalPresenceLock; >> + uint8_t bGlobalLock; >> +}__attribute__((packed)); >> + >> +struct tpm_version_t { >> + uint8_t Major; >> + uint8_t Minor; >> + uint8_t revMajor; >> + uint8_t revMinor; >> +}__attribute__((packed)); >> + >> +struct tpm_version_1_2_t { >> + uint16_t tag; >> + uint8_t Major; >> + uint8_t Minor; >> + uint8_t revMajor; >> + uint8_t revMinor; >> +}__attribute__((packed)); >> + >> +struct timeout_t { >> + uint32_t a; >> + uint32_t b; >> + uint32_t c; >> + uint32_t d; >> +}__attribute__((packed)); >> + >> +struct duration_t { >> + uint32_t tpm_short; >> + uint32_t tpm_medium; >> + uint32_t tpm_long; >> +}__attribute__((packed)); >> + >> +struct permanent_flags_t { >> + uint16_t tag; >> + uint8_t disable; >> + uint8_t ownership; >> + uint8_t deactivated; >> + uint8_t readPubek; >> + uint8_t disableOwnerClear; >> + uint8_t allowMaintenance; >> + uint8_t physicalPresenceLifetimeLock; >> + uint8_t physicalPresenceHWEnable; >> + uint8_t physicalPresenceCMDEnable; >> + uint8_t CEKPUsed; >> + uint8_t TPMpost; >> + uint8_t TPMpostLock; >> + uint8_t FIPS; >> + uint8_t operator; >> + uint8_t enableRevokeEK; >> + uint8_t nvLocked; >> + uint8_t readSRKPub; >> + uint8_t tpmEstablished; >> + uint8_t maintenanceDone; >> + uint8_t disableFullDALogicInfo; >> +}__attribute__((packed)); >> + >> +typedef union { >> + struct permanent_flags_t perm_flags; >> + struct stclear_flags_t stclear_flags; >> + bool owned; >> + uint32_t num_pcrs; >> + struct tpm_version_t tpm_version; >> + struct tpm_version_1_2_t tpm_version_1_2; >> + uint32_t manufacturer_id; >> + struct timeout_t timeout; >> + struct duration_t duration; >> +} cap_t; >> + >> +struct tpm_getcap_params_in { >> + uint32_t cap; >> + uint32_t subcap_size; >> + uint32_t subcap; >> +}__attribute__((packed)); >> + >> +struct tpm_getcap_params_out { >> + uint32_t cap_size; >> + cap_t cap; >> +}__attribute__((packed)); >> + >> +struct tpm_readpubek_params_out { >> + uint8_t algorithm[4]; >> + uint8_t encscheme[2]; >> + uint8_t sigscheme[2]; >> + uint32_t paramsize; >> + uint8_t parameters[12]; /*assuming RSA*/ >> + uint32_t keysize; >> + uint8_t modulus[256]; >> + uint8_t checksum[20]; >> +}__attribute__((packed)); >> + >> +typedef union { >> + struct tpm_input_header in; >> + struct tpm_output_header out; >> +} tpm_cmd_header; >> + >> +#define TPM_DIGEST_SIZE 20 >> +struct tpm_pcrread_out { >> + uint8_t pcr_result[TPM_DIGEST_SIZE]; >> +}__attribute__((packed)); >> + >> +struct tpm_pcrread_in { >> + uint32_t pcr_idx; >> +}__attribute__((packed)); >> + >> +struct tpm_pcrextend_in { >> + uint32_t pcr_idx; >> + uint8_t hash[TPM_DIGEST_SIZE]; >> +}__attribute__((packed)); >> + >> +typedef union { >> + struct tpm_getcap_params_out getcap_out; >> + struct tpm_readpubek_params_out readpubek_out; >> + uint8_t readpubek_out_buffer[sizeof(struct >> tpm_readpubek_params_out)]; >> + struct tpm_getcap_params_in getcap_in; >> + struct tpm_pcrread_in pcrread_in; >> + struct tpm_pcrread_out pcrread_out; >> + struct tpm_pcrextend_in pcrextend_in; >> +} tpm_cmd_params; >> + >> +struct tpm_cmd_t { >> + tpm_cmd_header header; >> + tpm_cmd_params params; >> +}__attribute__((packed)); >> + >> + >> +enum tpm_duration { >> + TPM_SHORT =3D 0, >> + TPM_MEDIUM =3D 1, >> + TPM_LONG =3D 2, >> + TPM_UNDEFINED, >> +}; >> + >> +#define TPM_MAX_ORDINAL 243 >> +#define TPM_MAX_PROTECTED_ORDINAL 12 >> +#define TPM_PROTECTED_ORDINAL_MASK 0xFF >> + >> +extern const uint8_t >> tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL]; >> +extern const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL]; >> + >> +#define TPM_DIGEST_SIZE 20 >> +#define TPM_ERROR_SIZE 10 >> +#define TPM_RET_CODE_IDX 6 >> + >> +/* tpm_capabilities */ >> +#define TPM_CAP_FLAG cpu_to_be32(4) >> +#define TPM_CAP_PROP cpu_to_be32(5) >> +#define CAP_VERSION_1_1 cpu_to_be32(0x06) >> +#define CAP_VERSION_1_2 cpu_to_be32(0x1A) >> + >> +/* tpm_sub_capabilities */ >> +#define TPM_CAP_PROP_PCR cpu_to_be32(0x101) >> +#define TPM_CAP_PROP_MANUFACTURER cpu_to_be32(0x103) >> +#define TPM_CAP_FLAG_PERM cpu_to_be32(0x108) >> +#define TPM_CAP_FLAG_VOL cpu_to_be32(0x109) >> +#define TPM_CAP_PROP_OWNER cpu_to_be32(0x111) >> +#define TPM_CAP_PROP_TIS_TIMEOUT cpu_to_be32(0x115) >> +#define TPM_CAP_PROP_TIS_DURATION cpu_to_be32(0x120) >> + >> + >> +#define TPM_INTERNAL_RESULT_SIZE 200 >> +#define TPM_TAG_RQU_COMMAND cpu_to_be16(193) >> +#define TPM_ORD_GET_CAP cpu_to_be32(101) >> + >> +extern const struct tpm_input_header tpm_getcap_header; >> + >> + >> + >> +const uint8_t tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINA= L] =3D { >> + TPM_UNDEFINED, /* 0 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 5 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 10 */ >> + TPM_SHORT, >> +}; >> + >> +const uint8_t tpm_ordinal_duration[TPM_MAX_ORDINAL] =3D { >> + TPM_UNDEFINED, /* 0 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 5 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 10 */ >> + TPM_SHORT, >> + TPM_MEDIUM, >> + TPM_LONG, >> + TPM_LONG, >> + TPM_MEDIUM, /* 15 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_MEDIUM, >> + TPM_LONG, >> + TPM_SHORT, /* 20 */ >> + TPM_SHORT, >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_SHORT, /* 25 */ >> + TPM_SHORT, >> + TPM_MEDIUM, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_MEDIUM, /* 30 */ >> + TPM_LONG, >> + TPM_MEDIUM, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, /* 35 */ >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_MEDIUM, /* 40 */ >> + TPM_LONG, >> + TPM_MEDIUM, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, /* 45 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_LONG, >> + TPM_MEDIUM, /* 50 */ >> + TPM_MEDIUM, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 55 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_MEDIUM, /* 60 */ >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_MEDIUM, /* 65 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 70 */ >> + TPM_SHORT, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 75 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_LONG, /* 80 */ >> + TPM_UNDEFINED, >> + TPM_MEDIUM, >> + TPM_LONG, >> + TPM_SHORT, >> + TPM_UNDEFINED, /* 85 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 90 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_UNDEFINED, /* 95 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_MEDIUM, /* 100 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 105 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 110 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, /* 115 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_LONG, /* 120 */ >> + TPM_LONG, >> + TPM_MEDIUM, >> + TPM_UNDEFINED, >> + TPM_SHORT, >> + TPM_SHORT, /* 125 */ >> + TPM_SHORT, >> + TPM_LONG, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, /* 130 */ >> + TPM_MEDIUM, >> + TPM_UNDEFINED, >> + TPM_SHORT, >> + TPM_MEDIUM, >> + TPM_UNDEFINED, /* 135 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 140 */ >> + TPM_SHORT, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 145 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 150 */ >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_UNDEFINED, /* 155 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 160 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 165 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_LONG, /* 170 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 175 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_MEDIUM, /* 180 */ >> + TPM_SHORT, >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_MEDIUM, /* 185 */ >> + TPM_SHORT, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 190 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 195 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 200 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, >> + TPM_SHORT, /* 205 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_MEDIUM, /* 210 */ >> + TPM_UNDEFINED, >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_MEDIUM, >> + TPM_UNDEFINED, /* 215 */ >> + TPM_MEDIUM, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, >> + TPM_SHORT, /* 220 */ >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_SHORT, >> + TPM_UNDEFINED, /* 225 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 230 */ >> + TPM_LONG, >> + TPM_MEDIUM, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, /* 235 */ >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_UNDEFINED, >> + TPM_SHORT, /* 240 */ >> + TPM_UNDEFINED, >> + TPM_MEDIUM, >> +}; >> + >> +const struct tpm_input_header tpm_getcap_header =3D { >> + .tag =3D TPM_TAG_RQU_COMMAND, >> + .length =3D cpu_to_be32(22), >> + .ordinal =3D TPM_ORD_GET_CAP >> +}; >> + >> + >> +enum tis_access { >> + TPM_ACCESS_VALID =3D 0x80, >> + TPM_ACCESS_ACTIVE_LOCALITY =3D 0x20, /* (R) */ >> + TPM_ACCESS_RELINQUISH_LOCALITY =3D 0x20,/* (W) */ >> + TPM_ACCESS_REQUEST_PENDING =3D 0x04, /* (W) */ >> + TPM_ACCESS_REQUEST_USE =3D 0x02, /* (W) */ >> +}; >> + >> +enum tis_status { >> + TPM_STS_VALID =3D 0x80, /* (R) */ >> + TPM_STS_COMMAND_READY =3D 0x40, /* (R) */ >> + TPM_STS_DATA_AVAIL =3D 0x10, /* (R) */ >> + TPM_STS_DATA_EXPECT =3D 0x08, /* (R) */ >> + TPM_STS_GO =3D 0x20, /* (W) */ >> +}; >> + >> +enum tis_int_flags { >> + TPM_GLOBAL_INT_ENABLE =3D 0x80000000, >> + TPM_INTF_BURST_COUNT_STATIC =3D 0x100, >> + TPM_INTF_CMD_READY_INT =3D 0x080, >> + TPM_INTF_INT_EDGE_FALLING =3D 0x040, >> + TPM_INTF_INT_EDGE_RISING =3D 0x020, >> + TPM_INTF_INT_LEVEL_LOW =3D 0x010, >> + TPM_INTF_INT_LEVEL_HIGH =3D 0x008, >> + TPM_INTF_LOCALITY_CHANGE_INT =3D 0x004, >> + TPM_INTF_STS_VALID_INT =3D 0x002, >> + TPM_INTF_DATA_AVAIL_INT =3D 0x001, >> +}; >> + >> +enum tis_defaults { >> + TIS_MEM_BASE =3D 0xFED40000, >> + TIS_MEM_LEN =3D 0x5000, >> + TIS_SHORT_TIMEOUT =3D 750, /*ms*/ >> + TIS_LONG_TIMEOUT =3D 2000, /*2 sec */ >> +}; >> + >> +#define TPM_TIMEOUT 5 >> + >> +#define TPM_ACCESS(t, l) (((uint8_t*)t->pages[l]) += >> 0x0000) >> +#define TPM_INT_ENABLE(t, l) >> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0008)) >> +#define TPM_INT_VECTOR(t, l) (((uint8_t*)t->pages[l]) += >> 0x000C) >> +#define TPM_INT_STATUS(t, l) (((uint8_t*)t->pages[l]) += >> 0x0010) >> +#define TPM_INTF_CAPS(t, l) >> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0014)) >> +#define TPM_STS(t, l) >> ((uint8_t*)(((uint8_t*)t->pages[l]) + 0x0018)) >> +#define TPM_DATA_FIFO(t, l) (((uint8_t*)t->pages[l]) += >> 0x0024) >> + >> +#define TPM_DID_VID(t, l) >> ((uint32_t*)(((uint8_t*)t->pages[l]) + 0x0F00)) >> +#define TPM_RID(t, l) (((uint8_t*)t->pages[l]) += >> 0x0F04) >> + >> +struct tpm_chip { >> + int enabled_localities; >> + int locality; >> + unsigned long baseaddr; >> + uint8_t* pages[5]; >> + int did, vid, rid; >> + >> + uint8_t data_buffer[TPM_BUFSIZE]; >> + int data_len; >> + >> + s_time_t timeout_a, timeout_b, timeout_c, timeout_d; >> + s_time_t duration[3]; >> + >> +#ifdef HAVE_LIBC >> + int fd; >> +#endif >> + >> + unsigned int irq; >> + struct wait_queue_head read_queue; >> + struct wait_queue_head int_queue; >> +}; >> + >> + >> +static void __init_tpm_chip(struct tpm_chip* tpm) { >> + tpm->enabled_localities =3D TPM_TIS_EN_LOCLALL; >> + tpm->locality =3D -1; >> + tpm->baseaddr =3D 0; >> + tpm->pages[0] =3D tpm->pages[1] =3D tpm->pages[2] =3D tpm->pages[3= ] =3D >> tpm->pages[4] =3D NULL; >> + tpm->vid =3D 0; >> + tpm->did =3D 0; >> + tpm->irq =3D 0; >> + init_waitqueue_head(&tpm->read_queue); >> + init_waitqueue_head(&tpm->int_queue); >> + >> + tpm->data_len =3D -1; >> + >> +#ifdef HAVE_LIBC >> + tpm->fd =3D -1; >> +#endif >> +} >> + >> +/* >> + * Returns max number of nsecs to wait >> + */ >> +s_time_t tpm_calc_ordinal_duration(struct tpm_chip *chip, >> + uint32_t ordinal) >> +{ >> + int duration_idx =3D TPM_UNDEFINED; >> + s_time_t duration =3D 0; >> + >> + if (ordinal < TPM_MAX_ORDINAL) >> + duration_idx =3D tpm_ordinal_duration[ordinal]; >> + else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < >> + TPM_MAX_PROTECTED_ORDINAL) >> + duration_idx =3D >> + tpm_protected_ordinal_duration[ordinal & >> + TPM_PROTECTED_ORDINAL_MASK]; >> + >> + if (duration_idx !=3D TPM_UNDEFINED) { >> + duration =3D chip->duration[duration_idx]; >> + } >> + >> + if (duration <=3D 0) { >> + return SECONDS(120); >> + } >> + else >> + { >> + return duration; >> + } >> +} >> + >> + >> +static int locality_enabled(struct tpm_chip* tpm, int l) { >> + return tpm->enabled_localities & (1 << l); >> +} >> + >> +static int check_locality(struct tpm_chip* tpm, int l) { >> + if(locality_enabled(tpm, l) && (ioread8(TPM_ACCESS(tpm, l)) & >> + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) =3D=3D >> + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { >> + return l; >> + } >> + return -1; >> +} >> + >> +void release_locality(struct tpm_chip* tpm, int l, int force) >> +{ >> + if (locality_enabled(tpm, l) && (force || (ioread8(TPM_ACCESS(tpm,= l)) & >> + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) =3D=3D >> + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))) { >> + iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_RELINQUISH_LOCALITY); >> + } >> +} >> + >> +int tpm_tis_request_locality(struct tpm_chip* tpm, int l) { >> + >> + s_time_t stop; >> + /*Make sure locality is valid */ >> + if(!locality_enabled(tpm, l)) { >> + printk("tpm_tis_change_locality() Tried to change to locality %= d, >> but it is disabled or invalid!\n", l); >> + return -1; >> + } >> + /* Check if we already have the current locality */ >> + if(check_locality(tpm, l) >=3D 0) { >> + return tpm->locality =3D l; >> + } >> + /* Set the new locality*/ >> + iowrite8(TPM_ACCESS(tpm, l), TPM_ACCESS_REQUEST_USE); >> + >> + if(tpm->irq) { >> + /* Wait for interrupt */ >> + wait_event_deadline(tpm->int_queue, (check_locality(tpm, l) >=3D= >> 0), NOW() + tpm->timeout_a); >> + >> + /* FIXME: Handle timeout event, should return error in that cas= e */ >> + return l; >> + } else { >> + /* Wait for burstcount */ >> + stop =3D NOW() + tpm->timeout_a; >> + do { >> + if(check_locality(tpm, l) >=3D 0) { >> + return tpm->locality =3D l; >> + } >> + msleep(TPM_TIMEOUT); >> + } while(NOW() < stop); >> + } >> + >> + printk("REQ LOCALITY FAILURE\n"); >> + return -1; >> +} >> + >> +static uint8_t tpm_tis_status(struct tpm_chip* tpm) { >> + return ioread8(TPM_STS(tpm, tpm->locality)); >> +} >> + >> +/* This causes the current command to be aborted */ >> +static void tpm_tis_ready(struct tpm_chip* tpm) { >> + iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_COMMAND_READY); >> +} >> +#define tpm_tis_cancel_cmd(v) tpm_tis_ready(v) >> + >> +static int get_burstcount(struct tpm_chip* tpm) { >> + s_time_t stop; >> + int burstcnt; >> + >> + stop =3D NOW() + tpm->timeout_d; >> + do { >> + burstcnt =3D ioread8((TPM_STS(tpm, tpm->locality) + 1)); >> + burstcnt +=3D ioread8(TPM_STS(tpm, tpm->locality) + 2) << 8; >> + >> + if (burstcnt) { >> + return burstcnt; >> + } >> + msleep(TPM_TIMEOUT); >> + } while(NOW() < stop); >> + return -EBUSY; >> +} >> + >> +static int wait_for_stat(struct tpm_chip* tpm, uint8_t mask, >> + unsigned long timeout, struct wait_queue_head* queue) { >> + s_time_t stop; >> + uint8_t status; >> + >> + status =3D tpm_tis_status(tpm); >> + if((status & mask) =3D=3D mask) { >> + return 0; >> + } >> + >> + if(tpm->irq) { >> + wait_event_deadline(*queue, ((tpm_tis_status(tpm) & mask) =3D=3D= >> mask), timeout); >> + /* FIXME: Check for timeout and return -ETIME */ >> + return 0; >> + } else { >> + stop =3D NOW() + timeout; >> + do { >> + msleep(TPM_TIMEOUT); >> + status =3D tpm_tis_status(tpm); >> + if((status & mask) =3D=3D mask) >> + return 0; >> + } while( NOW() < stop); >> + } >> + return -ETIME; >> +} >> + >> +static int recv_data(struct tpm_chip* tpm, uint8_t* buf, size_t count= ) { >> + int size =3D 0; >> + int burstcnt; >> + while( size < count && >> + wait_for_stat(tpm, >> + TPM_STS_DATA_AVAIL | TPM_STS_VALID, >> + tpm->timeout_c, >> + &tpm->read_queue) >> + =3D=3D 0) { >> + burstcnt =3D get_burstcount(tpm); >> + for(; burstcnt > 0 && size < count; --burstcnt) >> + { >> + buf[size++] =3D ioread8(TPM_DATA_FIFO(tpm, tpm->locality)); >> + } >> + } >> + return size; >> +} >> + >> +int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) { >> + int size =3D 0; >> + int expected, status; >> + >> + if (count < TPM_HEADER_SIZE) { >> + size =3D -EIO; >> + goto out; >> + } >> + >> + /* read first 10 bytes, including tag, paramsize, and result */ >> + if((size =3D >> + recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { >> + printk("Error reading tpm cmd header\n"); >> + goto out; >> + } >> + >> + expected =3D be32_to_cpu(*((uint32_t*)(buf + 2))); >> + if(expected > count) { >> + size =3D -EIO; >> + goto out; >> + } >> + >> + if((size +=3D recv_data(tpm, & buf[TPM_HEADER_SIZE], >> + expected - TPM_HEADER_SIZE)) < expected) { >> + printk("Unable to read rest of tpm command size=3D%d >> expected=3D%d\n", size, expected); >> + size =3D -ETIME; >> + goto out; >> + } >> + >> + wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue)= ; >> + status =3D tpm_tis_status(tpm); >> + if(status & TPM_STS_DATA_AVAIL) { >> + printk("Error: left over data\n"); >> + size =3D -EIO; >> + goto out; >> + } >> + >> +out: >> + tpm_tis_ready(tpm); >> + release_locality(tpm, tpm->locality, 0); >> + return size; >> +} >> +int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) { >> + int rc; >> + int status, burstcnt =3D 0; >> + int count =3D 0; >> + uint32_t ordinal; >> + >> + if(tpm_tis_request_locality(tpm, tpm->locality) < 0) { >> + return -EBUSY; >> + } >> + >> + status =3D tpm_tis_status(tpm); >> + if((status & TPM_STS_COMMAND_READY) =3D=3D 0) { >> + tpm_tis_ready(tpm); >> + if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b, >> &tpm->int_queue) < 0) { >> + rc =3D -ETIME; >> + goto out_err; >> + } >> + } >> + >> + while(count < len - 1) { >> + burstcnt =3D get_burstcount(tpm); >> + for(;burstcnt > 0 && count < len -1; --burstcnt) { >> + iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]); >> + } >> + >> + wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_que= ue); >> + status =3D tpm_tis_status(tpm); >> + if((status & TPM_STS_DATA_EXPECT) =3D=3D 0) { >> + rc =3D -EIO; >> + goto out_err; >> + } >> + } >> + >> + /*Write last byte*/ >> + iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]); >> + wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue= ); >> + status =3D tpm_tis_status(tpm); >> + if((status & TPM_STS_DATA_EXPECT) !=3D 0) { >> + rc =3D -EIO; >> + goto out_err; >> + } >> + >> + /*go and do it*/ >> + iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO); >> + >> + if(tpm->irq) { >> + /*Wait for interrupt */ >> + ordinal =3D be32_to_cpu(*(buf + 6)); >> + if(wait_for_stat(tpm, >> + TPM_STS_DATA_AVAIL | TPM_STS_VALID, >> + tpm_calc_ordinal_duration(tpm, ordinal), >> + &tpm->read_queue) < 0) { >> + rc =3D -ETIME; >> + goto out_err; >> + } >> + } >> +#ifdef HAVE_LIBC >> + if(tpm->fd >=3D 0) { >> + files[tpm->fd].read =3D 0; >> + files[tpm->fd].tpm_tis.respgot =3D 0; >> + files[tpm->fd].tpm_tis.offset =3D 0; >> + } >> +#endif >> + return len; >> + >> +out_err: >> + tpm_tis_ready(tpm); >> + release_locality(tpm, tpm->locality, 0); >> + return rc; >> +} >> + >> +static void tpm_tis_irq_handler(evtchn_port_t port, struct pt_regs >> *regs, void* data) >> +{ >> + struct tpm_chip* tpm =3D data; >> + uint32_t interrupt; >> + int i; >> + >> + interrupt =3D ioread32(TPM_INT_STATUS(tpm, tpm->locality)); >> + if(interrupt =3D=3D 0) { >> + return; >> + } >> + >> + if(interrupt & TPM_INTF_DATA_AVAIL_INT) { >> + wake_up(&tpm->read_queue); >> + } >> + if(interrupt & TPM_INTF_LOCALITY_CHANGE_INT) { >> + for(i =3D 0; i < 5; ++i) { >> + if(check_locality(tpm, i) >=3D 0) { >> + break; >> + } >> + } >> + } >> + if(interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_= INT | >> + TPM_INTF_CMD_READY_INT)) { >> + wake_up(&tpm->int_queue); >> + } >> + >> + /* Clear interrupts handled with TPM_EOI */ >> + iowrite32(TPM_INT_STATUS(tpm, tpm->locality), interrupt); >> + ioread32(TPM_INT_STATUS(tpm, tpm->locality)); >> + return; >> +} >> + >> +/* >> + * Internal kernel interface to transmit TPM commands >> + */ >> +static ssize_t tpm_transmit(struct tpm_chip *chip, const uint8_t *buf= , >> + size_t bufsiz) >> +{ >> + ssize_t rc; >> + uint32_t count, ordinal; >> + s_time_t stop; >> + >> + count =3D be32_to_cpu(*((uint32_t *) (buf + 2))); >> + ordinal =3D be32_to_cpu(*((uint32_t *) (buf + 6))); >> + if (count =3D=3D 0) >> + return -ENODATA; >> + if (count > bufsiz) { >> + printk("Error: invalid count value %x %zx \n", count, bufsiz); >> + return -E2BIG; >> + } >> + >> + //down(&chip->tpm_mutex); >> + >> + if ((rc =3D tpm_tis_send(chip, (uint8_t *) buf, count)) < 0) { >> + printk("tpm_transmit: tpm_send: error %zd\n", rc); >> + goto out; >> + } >> + >> + if (chip->irq) >> + goto out_recv; >> + >> + stop =3D NOW() + tpm_calc_ordinal_duration(chip, ordinal); >> + do { >> + uint8_t status =3D tpm_tis_status(chip); >> + if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) =3D=3D >> + (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) >> + goto out_recv; >> + >> + if ((status =3D=3D TPM_STS_COMMAND_READY)) { >> + printk("TPM Error: Operation Canceled\n"); >> + rc =3D -ECANCELED; >> + goto out; >> + } >> + >> + msleep(TPM_TIMEOUT); /* CHECK */ >> + rmb(); >> + } while (NOW() < stop); >> + >> + /* Cancel the command */ >> + tpm_tis_cancel_cmd(chip); >> + printk("TPM Operation Timed out\n"); >> + rc =3D -ETIME; >> + goto out; >> + >> +out_recv: >> + if((rc =3D tpm_tis_recv(chip, (uint8_t *) buf, bufsiz)) < 0) { >> + printk("tpm_transmit: tpm_recv: error %d\n", rc); >> + } >> +out: >> + //up(&chip->tpm_mutex); >> + return rc; >> +} >> + >> +static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *= cmd, >> + int len, const char *desc) >> +{ >> + int err; >> + >> + len =3D tpm_transmit(chip,(uint8_t *) cmd, len); >> + if (len < 0) >> + return len; >> + if (len =3D=3D TPM_ERROR_SIZE) { >> + err =3D be32_to_cpu(cmd->header.out.return_code); >> + printk("A TPM error (%d) occurred %s\n", err, desc); >> + return err; >> + } >> + return 0; >> +} >> + >> +void tpm_get_timeouts(struct tpm_chip *chip) >> +{ >> + struct tpm_cmd_t tpm_cmd; >> + struct timeout_t *timeout_cap; >> + struct duration_t *duration_cap; >> + ssize_t rc; >> + uint32_t timeout; >> + >> + tpm_cmd.header.in =3D tpm_getcap_header; >> + tpm_cmd.params.getcap_in.cap =3D TPM_CAP_PROP; >> + tpm_cmd.params.getcap_in.subcap_size =3D cpu_to_be32(4); >> + tpm_cmd.params.getcap_in.subcap =3D TPM_CAP_PROP_TIS_TIMEOUT; >> + >> + if((rc =3D transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, >> + "attempting to determine the timeouts")) !=3D 0) { >> + printk("transmit failed %d\n", rc); >> + goto duration; >> + } >> + >> + if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size) >> + !=3D 4 * sizeof(uint32_t)) { >> + printk("Out len check failure %lu \n", >> be32_to_cpu(tpm_cmd.header.out.length)); >> + goto duration; >> + } >> + >> + timeout_cap =3D &tpm_cmd.params.getcap_out.cap.timeout; >> + /* Don't overwrite default if value is 0 */ >> + timeout =3D be32_to_cpu(timeout_cap->a); >> + if (timeout) >> + chip->timeout_a =3D MICROSECS(timeout); /*Convert to msec */ >> + timeout =3D be32_to_cpu(timeout_cap->b); >> + if (timeout) >> + chip->timeout_b =3D MICROSECS(timeout); /*Convert to msec */ >> + timeout =3D be32_to_cpu(timeout_cap->c); >> + if (timeout) >> + chip->timeout_c =3D MICROSECS(timeout); /*Convert to msec */ >> + timeout =3D be32_to_cpu(timeout_cap->d); >> + if (timeout) >> + chip->timeout_d =3D MICROSECS(timeout); /*Convert to msec */ >> + >> +duration: >> + tpm_cmd.header.in =3D tpm_getcap_header; >> + tpm_cmd.params.getcap_in.cap =3D TPM_CAP_PROP; >> + tpm_cmd.params.getcap_in.subcap_size =3D cpu_to_be32(4); >> + tpm_cmd.params.getcap_in.subcap =3D TPM_CAP_PROP_TIS_DURATION; >> + >> + if((rc =3D transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, >> + "attempting to determine the durations")) < 0) { >> + return; >> + } >> + >> + if (be32_to_cpu(tpm_cmd.params.getcap_out.cap_size) >> + !=3D 3 * sizeof(uint32_t)) { >> + return; >> + } >> + duration_cap =3D &tpm_cmd.params.getcap_out.cap.duration; >> + chip->duration[TPM_SHORT] =3D be32_to_cpu(duration_cap->tpm_s= hort); >> + /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets >> the above >> + * value wrong and apparently reports msecs rather than usecs= =2E >> So we >> + * fix up the resulting too-small TPM_SHORT value to make >> things work. >> + */ >> + if (chip->duration[TPM_SHORT] < 10) { >> + chip->duration[TPM_SHORT] =3D MILLISECS(chip->duration[TPM_SHO= RT]); >> + } else { >> + chip->duration[TPM_SHORT] =3D MICROSECS(chip->duration[TPM_SHO= RT]); >> + } >> + >> + chip->duration[TPM_MEDIUM] =3D >> MICROSECS(be32_to_cpu(duration_cap->tpm_medium)); >> + chip->duration[TPM_LONG] =3D >> MICROSECS(be32_to_cpu(duration_cap->tpm_long)); >> +} >> + >> + >> + >> +void tpm_continue_selftest(struct tpm_chip* chip) { >> + uint8_t data[] =3D { >> + 0, 193, /* TPM_TAG_RQU_COMMAND */ >> + 0, 0, 0, 10, /* length */ >> + 0, 0, 0, 83, /* TPM_ORD_GetCapability */ >> + }; >> + >> + tpm_transmit(chip, data, sizeof(data)); >> +} >> + >> +ssize_t tpm_getcap(struct tpm_chip *chip, uint32_t subcap_id, cap_t *= cap, >> + const char *desc) >> +{ >> + struct tpm_cmd_t tpm_cmd; >> + int rc; >> + >> + tpm_cmd.header.in =3D tpm_getcap_header; >> + if (subcap_id =3D=3D CAP_VERSION_1_1 || subcap_id =3D=3D CAP_= VERSION_1_2) { >> + tpm_cmd.params.getcap_in.cap =3D subcap_id; >> + /*subcap field not necessary */ >> + tpm_cmd.params.getcap_in.subcap_size =3D cpu_to_be32(= 0); >> + tpm_cmd.header.in.length -=3D cpu_to_be32(sizeof(uint= 32_t)); >> + } else { >> + if (subcap_id =3D=3D TPM_CAP_FLAG_PERM || >> + subcap_id =3D=3D TPM_CAP_FLAG_VOL) >> + tpm_cmd.params.getcap_in.cap =3D TPM_CAP_FLAG= ; >> + else >> + tpm_cmd.params.getcap_in.cap =3D TPM_CAP_PROP= ; >> + tpm_cmd.params.getcap_in.subcap_size =3D cpu_to_be32(= 4); >> + tpm_cmd.params.getcap_in.subcap =3D subcap_id; >> + } >> + rc =3D transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,= desc); >> + if (!rc) >> + *cap =3D tpm_cmd.params.getcap_out.cap; >> + return rc; >> +} >> + >> + >> +struct tpm_chip* init_tpm_tis(unsigned long baseaddr, int localities,= >> unsigned int irq) >> +{ >> + int i; >> + unsigned long addr; >> + struct tpm_chip* tpm =3D NULL; >> + uint32_t didvid; >> + uint32_t intfcaps; >> + uint32_t intmask; >> + >> + printk("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Init TPM TIS Drive= r =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); >> + >> + /*Sanity check the localities input */ >> + if(localities & ~TPM_TIS_EN_LOCLALL) { >> + printk("init_tpm_tis() Invalid locality specification! %X\n", >> localities); >> + goto abort_egress; >> + } >> + >> + printk("IOMEM Machine Base Address: %lX\n", baseaddr); >> + >> + /* Create the tpm data structure */ >> + tpm =3D malloc(sizeof(struct tpm_chip)); >> + __init_tpm_chip(tpm); >> + >> + /* Set the enabled localities - if 0 we leave default as all enabl= ed */ >> + if(localities !=3D 0) { >> + tpm->enabled_localities =3D localities; >> + } >> + printk("Enabled Localities: "); >> + for(i =3D 0; i < 5; ++i) { >> + if(locality_enabled(tpm, i)) { >> + printk("%d ", i); >> + } >> + } >> + printk("\n"); >> + >> + /* Set the base machine address */ >> + tpm->baseaddr =3D baseaddr; >> + >> + /* Set default timeouts */ >> + tpm->timeout_a =3D MILLISECS(TIS_SHORT_TIMEOUT); >> + tpm->timeout_b =3D MILLISECS(TIS_LONG_TIMEOUT); >> + tpm->timeout_c =3D MILLISECS(TIS_SHORT_TIMEOUT); >> + tpm->timeout_d =3D MILLISECS(TIS_SHORT_TIMEOUT); >> + >> + /*Map the mmio pages */ >> + addr =3D tpm->baseaddr; >> + for(i =3D 0; i < 5; ++i) { >> + if(locality_enabled(tpm, i)) { >> + /* Map the page in now */ >> + if((tpm->pages[i] =3D ioremap_nocache(addr, PAGE_SIZE)) =3D=3D N= ULL) { >> + printk("Unable to map iomem page a address %p\n", addr); >> + goto abort_egress; >> + } >> + >> + /* Set default locality to the first enabled one */ >> + if (tpm->locality < 0) { >> + if(tpm_tis_request_locality(tpm, i) < 0) { >> + printk("Unable to request locality %d??\n", i); >> + goto abort_egress; >> + } >> + } >> + } >> + addr +=3D PAGE_SIZE; >> + } >> + >> + >> + /* Get the vendor and device ids */ >> + didvid =3D ioread32(TPM_DID_VID(tpm, tpm->locality)); >> + tpm->did =3D didvid >> 16; >> + tpm->vid =3D didvid & 0xFFFF; >> + >> + >> + /* Get the revision id */ >> + tpm->rid =3D ioread8(TPM_RID(tpm, tpm->locality)); >> + >> + printk("1.2 TPM (device-id=3D0x%X vendor-id =3D %X rev-id =3D %X)\= n", >> tpm->did, tpm->vid, tpm->rid); >> + >> + intfcaps =3D ioread32(TPM_INTF_CAPS(tpm, tpm->locality)); >> + printk("TPM interface capabilities (0x%x):\n", intfcaps); >> + if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) >> + printk("\tBurst Count Static\n"); >> + if (intfcaps & TPM_INTF_CMD_READY_INT) >> + printk("\tCommand Ready Int Support\n"); >> + if (intfcaps & TPM_INTF_INT_EDGE_FALLING) >> + printk("\tInterrupt Edge Falling\n"); >> + if (intfcaps & TPM_INTF_INT_EDGE_RISING) >> + printk("\tInterrupt Edge Rising\n"); >> + if (intfcaps & TPM_INTF_INT_LEVEL_LOW) >> + printk("\tInterrupt Level Low\n"); >> + if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) >> + printk("\tInterrupt Level High\n"); >> + if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) >> + printk("\tLocality Change Int Support\n"); >> + if (intfcaps & TPM_INTF_STS_VALID_INT) >> + printk("\tSts Valid Int Support\n"); >> + if (intfcaps & TPM_INTF_DATA_AVAIL_INT) >> + printk("\tData Avail Int Support\n"); >> + >> + /*Interupt setup */ >> + intmask =3D ioread32(TPM_INT_ENABLE(tpm, tpm->locality)); >> + >> + intmask |=3D TPM_INTF_CMD_READY_INT >> + | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT >> + | TPM_INTF_STS_VALID_INT; >> + >> + iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask); >> + >> + /*If interupts are enabled, handle it */ >> + if(irq) { >> + if(irq !=3D TPM_PROBE_IRQ) { >> + tpm->irq =3D irq; >> + } else { >> + /*FIXME add irq probing feature later */ >> + printk("IRQ probing not implemented\n"); >> + } >> + } >> + >> + if(tpm->irq) { >> + iowrite8(TPM_INT_VECTOR(tpm, tpm->locality), tpm->irq); >> + >> + if(bind_pirq(tpm->irq, 1, tpm_tis_irq_handler, tpm) !=3D 0) { >> + printk("Unabled to request irq: %u for use\n", tpm->irq); >> + printk("Will use polling mode\n"); >> + tpm->irq =3D 0; >> + } else { >> + /* Clear all existing */ >> + iowrite32(TPM_INT_STATUS(tpm, tpm->locality), >> ioread32(TPM_INT_STATUS(tpm, tpm->locality))); >> + >> + /* Turn on interrupts */ >> + iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), intmask | >> TPM_GLOBAL_INT_ENABLE); >> + } >> + } >> + >> + tpm_get_timeouts(tpm); >> + tpm_continue_selftest(tpm); >> + >> + >> + return tpm; >> +abort_egress: >> + if(tpm !=3D NULL) { >> + shutdown_tpm_tis(tpm); >> + } >> + return NULL; >> +} >> + >> +void shutdown_tpm_tis(struct tpm_chip* tpm){ >> + int i; >> + >> + printk("Shutting down tpm_tis device\n"); >> + >> + iowrite32(TPM_INT_ENABLE(tpm, tpm->locality), ~TPM_GLOBAL_INT_ENAB= LE); >> + >> + /*Unmap all of the mmio pages */ >> + for(i =3D 0; i < 5; ++i) { >> + if(tpm->pages[i] !=3D NULL) { >> + iounmap(tpm->pages[i], PAGE_SIZE); >> + tpm->pages[i] =3D NULL; >> + } >> + } >> + free(tpm); >> + return; >> +} >> + >> + >> +int tpm_tis_cmd(struct tpm_chip* tpm, uint8_t* req, size_t reqlen, >> uint8_t** resp, size_t* resplen) >> +{ >> + if(tpm->locality < 0) { >> + printk("tpm_tis_cmd() failed! locality not set!\n"); >> + return -1; >> + } >> + if(reqlen > TPM_BUFSIZE) { >> + reqlen =3D TPM_BUFSIZE; >> + } >> + memcpy(tpm->data_buffer, req, reqlen); >> + *resplen =3D tpm_transmit(tpm, tpm->data_buffer, TPM_BUFSIZE); >> + >> + *resp =3D malloc(*resplen); >> + memcpy(*resp, tpm->data_buffer, *resplen); >> + return 0; >> +} >> + >> +#ifdef HAVE_LIBC >> +int tpm_tis_open(struct tpm_chip* tpm) >> +{ >> + /* Silently prevent multiple opens */ >> + if(tpm->fd !=3D -1) { >> + return tpm->fd; >> + } >> + >> + tpm->fd =3D alloc_fd(FTYPE_TPM_TIS); >> + printk("tpm_tis_open() -> %d\n", tpm->fd); >> + files[tpm->fd].tpm_tis.dev =3D tpm; >> + files[tpm->fd].tpm_tis.offset =3D 0; >> + files[tpm->fd].tpm_tis.respgot =3D 0; >> + return tpm->fd; >> +} >> + >> +int tpm_tis_posix_write(int fd, const uint8_t* buf, size_t count) >> +{ >> + struct tpm_chip* tpm; >> + tpm =3D files[fd].tpm_tis.dev; >> + >> + if(tpm->locality < 0) { >> + printk("tpm_tis_posix_write() failed! locality not set!\n"); >> + errno =3D EINPROGRESS; >> + return -1; >> + } >> + if(count =3D=3D 0) { >> + return 0; >> + } >> + >> + /* Return an error if we are already processing a command */ >> + if(count > TPM_BUFSIZE) { >> + count =3D TPM_BUFSIZE; >> + } >> + /* Send the command now */ >> + memcpy(tpm->data_buffer, buf, count); >> + if((tpm->data_len =3D tpm_transmit(tpm, tpm->data_buffer, >> TPM_BUFSIZE)) < 0) { >> + errno =3D EIO; >> + return -1; >> + } >> + return count; >> +} >> + >> +int tpm_tis_posix_read(int fd, uint8_t* buf, size_t count) >> +{ >> + int rc; >> + struct tpm_chip* tpm; >> + tpm =3D files[fd].tpm_tis.dev; >> + >> + if(count =3D=3D 0) { >> + return 0; >> + } >> + >> + /* If there is no tpm resp to read, return EIO */ >> + if(tpm->data_len < 0) { >> + errno =3D EIO; >> + return -1; >> + } >> + >> + >> + /* Handle EOF case */ >> + if(files[fd].tpm_tis.offset >=3D tpm->data_len) { >> + rc =3D 0; >> + } else { >> + rc =3D min(tpm->data_len - files[fd].tpm_tis.offset, count); >> + memcpy(buf, tpm->data_buffer + files[fd].tpm_tis.offset, rc); >> + } >> + files[fd].tpm_tis.offset +=3D rc; >> + /* Reset the data pending flag */ >> + return rc; >> +} >> +int tpm_tis_posix_fstat(int fd, struct stat* buf) >> +{ >> + struct tpm_chip* tpm; >> + tpm =3D files[fd].tpm_tis.dev; >> + >> + buf->st_mode =3D O_RDWR; >> + buf->st_uid =3D 0; >> + buf->st_gid =3D 0; >> + buf->st_size =3D be32_to_cpu(*((uint32_t*)(tpm->data_buffer + 2)))= ; >> + buf->st_atime =3D buf->st_mtime =3D buf->st_ctime =3D time(NULL); >> + return 0; >> +} >> + >> + >> +#endif >> diff --git a/extras/mini-os/tpmback.c b/extras/mini-os/tpmback.c >> --- /dev/null >> +++ b/extras/mini-os/tpmback.c >> @@ -0,0 +1,1114 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented b= y >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This driver is free software: you can redistribute it and/or modif= y >> + * it under the terms of the GNU General Public License as published = by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * This driver is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see . >> + * >> + * Based upon the files: >> + * drivers/xen/tpmbk.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporatio= n >> + */ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> + >> +#ifndef HAVE_LIBC >> +#define strtoul simple_strtoul >> +#endif >> + >> +//#define TPMBACK_PRINT_DEBUG >> +#ifdef TPMBACK_PRINT_DEBUG >> +#define TPMBACK_DEBUG(fmt,...) printk("Tpmback:Debug("__FILE__":%d) "= >> fmt, __LINE__, ##__VA_ARGS__) >> +#define TPMBACK_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__) >> +#else >> +#define TPMBACK_DEBUG(fmt,...) >> +#endif >> +#define TPMBACK_ERR(fmt,...) printk("Tpmback:Error " fmt, ##__VA_ARGS= __) >> +#define TPMBACK_LOG(fmt,...) printk("Tpmback:Info " fmt, ##__VA_ARGS_= _) >> + >> +#define min(a,b) (((a) < (b)) ? (a) : (b)) >> + >> +/* Default size of the tpmif array at initialization */ >> +#define DEF_ARRAY_SIZE 1 >> + >> +/* tpmif and tpmdev flags */ >> +#define TPMIF_CLOSED 1 >> +#define TPMIF_REQ_READY 2 >> + >> +struct tpmif { >> + domid_t domid; >> + unsigned int handle; >> + >> + char* fe_path; >> + char* fe_state_path; >> + >> + /* Locally bound event channel*/ >> + evtchn_port_t evtchn; >> + >> + /* Shared page */ >> + tpmif_tx_interface_t* tx; >> + >> + /* pointer to TPMIF_RX_RING_SIZE pages */ >> + void** pages; >> + >> + enum xenbus_state state; >> + enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; >> + >> + char* uuid; >> + >> + /* state flags */ >> + int flags; >> +}; >> +typedef struct tpmif tpmif_t; >> + >> +struct tpmback_dev { >> + >> + tpmif_t** tpmlist; >> + unsigned long num_tpms; >> + unsigned long num_alloc; >> + >> + struct gntmap map; >> + >> + /* True if at least one tpmif has a request to be handled */ >> + int flags; >> + >> + /* exclusive domains, see init_tpmback comment in tpmback.h */ >> + char** exclusive_uuids; >> + >> + xenbus_event_queue events; >> + >> + /* Callbacks */ >> + void (*open_callback)(domid_t, unsigned int); >> + void (*close_callback)(domid_t, unsigned int); >> + void (*suspend_callback)(domid_t, unsigned int); >> + void (*resume_callback)(domid_t, unsigned int); >> +}; >> +typedef struct tpmback_dev tpmback_dev_t; >> + >> +enum { EV_NONE, EV_NEWFE, EV_STCHNG } tpm_ev_enum; >> + >> +/* Global objects */ >> +static struct thread* eventthread =3D NULL; >> +static tpmback_dev_t gtpmdev =3D { >> + .tpmlist =3D NULL, >> + .num_tpms =3D 0, >> + .num_alloc =3D 0, >> + .flags =3D TPMIF_CLOSED, >> + .events =3D NULL, >> + .open_callback =3D NULL, >> + .close_callback =3D NULL, >> + .suspend_callback =3D NULL, >> + .resume_callback =3D NULL, >> +}; >> +struct wait_queue_head waitq; >> +int globalinit =3D 0; >> + >> +/************************************ >> + * TPMIF SORTED ARRAY FUNCTIONS >> + * tpmback_dev_t.tpmlist is a sorted array, sorted by domid and then >> handle number >> + * Duplicates are not allowed >> + * **********************************/ >> + >> +inline void tpmif_req_ready(tpmif_t* tpmif) { >> + tpmif->flags |=3D TPMIF_REQ_READY; >> + gtpmdev.flags |=3D TPMIF_REQ_READY; >> +} >> + >> +inline void tpmdev_check_req(void) { >> + int i; >> + int flags; >> + local_irq_save(flags); >> + for(i =3D 0; i < gtpmdev.num_tpms; ++i) { >> + if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) { >> + gtpmdev.flags |=3D TPMIF_REQ_READY; >> + local_irq_restore(flags); >> + return; >> + } >> + } >> + gtpmdev.flags &=3D ~TPMIF_REQ_READY; >> + local_irq_restore(flags); >> +} >> + >> +inline void tpmif_req_finished(tpmif_t* tpmif) { >> + tpmif->flags &=3D ~TPMIF_REQ_READY; >> + tpmdev_check_req(); >> +} >> + >> +int __get_tpmif_index(int st, int n, domid_t domid, unsigned int hand= le) >> +{ >> + int i =3D st + n /2; >> + tpmif_t* tmp; >> + >> + if( n <=3D 0 ) >> + return -1; >> + >> + tmp =3D gtpmdev.tpmlist[i]; >> + if(domid =3D=3D tmp->domid && tmp->handle =3D=3D handle) { >> + return i; >> + } else if ( (domid < tmp->domid) || >> + (domid =3D=3D tmp->domid && handle < tmp->handle)) { >> + return __get_tpmif_index(st, n/2, domid, handle); >> + } else { >> + return __get_tpmif_index(i + 1, n/2 - ((n +1) % 2), domid, hand= le); >> + } >> +} >> + >> +/* Returns the array index of the tpmif domid/handle. Returns -1 if n= o >> such tpmif exists */ >> +int get_tpmif_index(domid_t domid, unsigned int handle) >> +{ >> + int flags; >> + int index; >> + local_irq_save(flags); >> + index =3D __get_tpmif_index(0, gtpmdev.num_tpms, domid, handle); >> + local_irq_restore(flags); >> + return index; >> +} >> + >> +/* Returns the tpmif domid/handle or NULL if none exists */ >> +tpmif_t* get_tpmif(domid_t domid, unsigned int handle) >> +{ >> + int flags; >> + int i; >> + tpmif_t* ret; >> + local_irq_save(flags); >> + i =3D get_tpmif_index(domid, handle); >> + if (i < 0) { >> + ret =3D NULL; >> + } else { >> + ret =3D gtpmdev.tpmlist[i]; >> + } >> + local_irq_restore(flags); >> + return ret; >> +} >> + >> +/* Remove the given tpmif. Returns 0 if it was removed, -1 if it was >> not removed */ >> +int remove_tpmif(tpmif_t* tpmif) >> +{ >> + int i, j; >> + char* err; >> + int flags; >> + local_irq_save(flags); >> + >> + /* Find the index in the array if it exists */ >> + i =3D get_tpmif_index(tpmif->domid, tpmif->handle); >> + if (i < 0) { >> + goto error; >> + } >> + >> + /* Remove the interface from the list */ >> + for(j =3D i; j < gtpmdev.num_tpms - 1; ++j) { >> + gtpmdev.tpmlist[j] =3D gtpmdev.tpmlist[j+1]; >> + } >> + gtpmdev.tpmlist[j] =3D NULL; >> + --gtpmdev.num_tpms; >> + >> + /* If removed tpm was the only ready tpm, then we need to check an= d >> turn off the ready flag */ >> + tpmdev_check_req(); >> + >> + local_irq_restore(flags); >> + >> + /* Stop listening for events on this tpm interface */ >> + if((err =3D xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_pat= h, >> tpmif->fe_state_path))) { >> + TPMBACK_ERR("Unable to unwatch path token `%s' Error was %s >> Ignoring..\n", tpmif->fe_state_path, err); >> + free(err); >> + } >> + >> + return 0; >> +error: >> + local_irq_restore(flags); >> + return -1; >> +} >> + >> +/* Insert tpmif into dev->tpmlist. Returns 0 on success and non zero = on >> error. >> + * It is an error to insert a tpmif with the same domid and handle >> + * number >> + * as something already in the list */ >> +int insert_tpmif(tpmif_t* tpmif) >> +{ >> + int flags; >> + unsigned int i, j; >> + tpmif_t* tmp; >> + char* err; >> + >> + local_irq_save(flags); >> + >> + /*Check if we need to allocate more space */ >> + if (gtpmdev.num_tpms =3D=3D gtpmdev.num_alloc) { >> + gtpmdev.num_alloc *=3D 2; >> + gtpmdev.tpmlist =3D realloc(gtpmdev.tpmlist, gtpmdev.num_alloc)= ; >> + } >> + >> + /*Find where to put the new interface */ >> + for(i =3D 0; i < gtpmdev.num_tpms; ++i) >> + { >> + tmp =3D gtpmdev.tpmlist[i]; >> + if(tpmif->domid =3D=3D tmp->domid && tpmif->handle =3D=3D tmp->= handle) { >> + TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n", >> (unsigned int) tpmif->domid, tpmif->handle); >> + goto error; >> + } >> + if((tpmif->domid < tmp->domid) || >> + (tpmif->domid =3D=3D tmp->domid && tpmif->handle < tmp->handl= e)) { >> + break; >> + } >> + } >> + >> + /*Shift all the tpm pointers past i down one */ >> + for(j =3D gtpmdev.num_tpms; j > i; --j) { >> + gtpmdev.tpmlist[j] =3D gtpmdev.tpmlist[j-1]; >> + } >> + >> + /*Add the new interface */ >> + gtpmdev.tpmlist[i] =3D tpmif; >> + ++gtpmdev.num_tpms; >> + >> + /*Should not be needed, anything inserted with ready flag is >> probably an error */ >> + tpmdev_check_req(); >> + >> + local_irq_restore(flags); >> + >> + /*Listen for state changes on the new interface */ >> + if((err =3D xenbus_watch_path_token(XBT_NIL, tpmif->fe_state_path,= >> tpmif->fe_state_path, >pmdev.events))) >> + { >> + /* if we got an error here we should carefully remove the >> interface and then return */ >> + TPMBACK_ERR("Unable to watch path token `%s' Error was %s\n", >> tpmif->fe_state_path, err); >> + free(err); >> + remove_tpmif(tpmif); >> + goto error_post_irq; >> + } >> + >> + return 0; >> +error: >> + local_irq_restore(flags); >> +error_post_irq: >> + return -1; >> +} >> + >> + >> +/***************** >> + * CHANGE BACKEND STATE >> + * *****************/ >> +/*Attempts to change the backend state in xenstore >> + * returns 0 on success and non-zero on error */ >> +int tpmif_change_state(tpmif_t* tpmif, enum xenbus_state state) >> +{ >> + char path[512]; >> + char *value; >> + char *err; >> + enum xenbus_state readst; >> + TPMBACK_DEBUG("Backend state change %u/%u from=3D%d to=3D%d\n", >> (unsigned int) tpmif->domid, tpmif->handle, tpmif->state, state); >> + if (tpmif->state =3D=3D state) >> + return 0; >> + >> + snprintf(path, 512, "backend/vtpm/%u/%u/state", (unsigned int) >> tpmif->domid, tpmif->handle); >> + >> + if((err =3D xenbus_read(XBT_NIL, path, &value))) { >> + TPMBACK_ERR("Unable to read backend state %s, error was %s\n", >> path, err); >> + free(err); >> + return -1; >> + } >> + if(sscanf(value, "%d", &readst) !=3D 1) { >> + TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path); >> + free(value); >> + return -1; >> + } >> + free(value); >> + >> + /* It's possible that the backend state got updated by hotplug or >> something else behind our back */ >> + if(readst !=3D tpmif->state) { >> + TPMBACK_DEBUG("tpm interface state was %d but xenstore state wa= s >> %d!\n", tpmif->state, readst); >> + tpmif->state =3D readst; >> + } >> + >> + /*If if the state isnt changing, then we dont update xenstore b/c = we >> dont want to fire extraneous events */ >> + if(tpmif->state =3D=3D state) { >> + return 0; >> + } >> + >> + /*update xenstore*/ >> + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) >> tpmif->domid, tpmif->handle); >> + if((err =3D xenbus_printf(XBT_NIL, path, "state", "%u", state))) {= >> + TPMBACK_ERR("Error writing to xenstore %s, error was %s new >> state=3D%d\n", path, err, state); >> + free(err); >> + return -1; >> + } >> + >> + tpmif->state =3D state; >> + >> + return 0; >> +} >> +/********************************** >> + * TPMIF CREATION AND DELETION >> + * *******************************/ >> +inline tpmif_t* __init_tpmif(domid_t domid, unsigned int handle) >> +{ >> + tpmif_t* tpmif; >> + tpmif =3D malloc(sizeof(*tpmif)); >> + tpmif->domid =3D domid; >> + tpmif->handle =3D handle; >> + tpmif->fe_path =3D NULL; >> + tpmif->fe_state_path =3D NULL; >> + tpmif->state =3D XenbusStateInitialising; >> + tpmif->status =3D DISCONNECTED; >> + tpmif->tx =3D NULL; >> + tpmif->pages =3D NULL; >> + tpmif->flags =3D 0; >> + tpmif->uuid =3D NULL; >> + return tpmif; >> +} >> + >> +void __free_tpmif(tpmif_t* tpmif) >> +{ >> + if(tpmif->pages) { >> + free(tpmif->pages); >> + } >> + if(tpmif->fe_path) { >> + free(tpmif->fe_path); >> + } >> + if(tpmif->fe_state_path) { >> + free(tpmif->fe_state_path); >> + } >> + if(tpmif->uuid) { >> + free(tpmif->uuid); >> + } >> + free(tpmif); >> +} >> +/* Creates a new tpm interface, adds it to the sorted array and retur= ns it. >> + * returns NULL on error >> + * If the tpm interface already exists, it is returned*/ >> +tpmif_t* new_tpmif(domid_t domid, unsigned int handle) >> +{ >> + tpmif_t* tpmif; >> + char* err; >> + char path[512]; >> + >> + /* Make sure we haven't already created this tpm >> + * Double events can occur */ >> + if((tpmif =3D get_tpmif(domid, handle)) !=3D NULL) { >> + return tpmif; >> + } >> + >> + tpmif =3D __init_tpmif(domid, handle); >> + >> + /* Get the uuid from xenstore */ >> + snprintf(path, 512, "backend/vtpm/%u/%u/uuid", (unsigned int) domi= d, >> handle); >> + if((err =3D xenbus_read(XBT_NIL, path, &tpmif->uuid))) { >> + TPMBACK_ERR("Error reading %s, Error =3D %s\n", path, err); >> + free(err); >> + goto error; >> + } >> + >> + /* Do the exclusive uuid check now */ >> + if(gtpmdev.exclusive_uuids !=3D NULL) { >> + char** ptr; >> + >> + /* Check that its in the whitelist */ >> + for(ptr =3D gtpmdev.exclusive_uuids; *ptr !=3D NULL; ++ptr) { >> + if(!strcmp(tpmif->uuid, *ptr)) { >> + break; >> + } >> + } >> + /* If *ptr =3D=3D NULL then we went through the whole list with= out a >> match, so close the connection */ >> + if(*ptr =3D=3D NULL) { >> + tpmif_change_state(tpmif, XenbusStateClosed); >> + TPMBACK_ERR("Frontend %u/%u tried to connect with invalid >> uuid=3D%s\n", (unsigned int) domid, handle, tpmif->uuid); >> + goto error; >> + } >> + } >> + >> + /* allocate pages to be used for shared mapping */ >> + if((tpmif->pages =3D malloc(sizeof(void*) * TPMIF_TX_RING_SIZE)) =3D= =3D >> NULL) { >> + goto error; >> + } >> + memset(tpmif->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); >> + >> + if(tpmif_change_state(tpmif, XenbusStateInitWait)) { >> + goto error; >> + } >> + >> + snprintf(path, 512, "backend/vtpm/%u/%u/frontend", (unsigned int) >> domid, handle); >> + if((err =3D xenbus_read(XBT_NIL, path, &tpmif->fe_path))) { >> + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s), >> Error =3D %s", path, err); >> + free(err); >> + goto error; >> + } >> + >> + /*Set the state path */ >> + tpmif->fe_state_path =3D malloc(strlen(tpmif->fe_path) + 7); >> + strcpy(tpmif->fe_state_path, tpmif->fe_path); >> + strcat(tpmif->fe_state_path, "/state"); >> + >> + if(insert_tpmif(tpmif)) { >> + goto error; >> + } >> + TPMBACK_DEBUG("New tpmif %u/%u\n", (unsigned int) tpmif->domid, >> tpmif->handle); >> + /* Do the callback now */ >> + if(gtpmdev.open_callback) { >> + gtpmdev.open_callback(tpmif->domid, tpmif->handle); >> + } >> + return tpmif; >> +error: >> + __free_tpmif(tpmif); >> + return NULL; >> + >> +} >> + >> +/* Removes tpmif from dev->tpmlist and frees it's memory usage */ >> +void free_tpmif(tpmif_t* tpmif) >> +{ >> + char* err; >> + char path[512]; >> + TPMBACK_DEBUG("Free tpmif %u/%u\n", (unsigned int) tpmif->domid, >> tpmif->handle); >> + if(tpmif->flags & TPMIF_CLOSED) { >> + TPMBACK_ERR("Tried to free an instance twice! Theres a bug >> somewhere!\n"); >> + BUG(); >> + } >> + tpmif->flags =3D TPMIF_CLOSED; >> + >> + tpmif_change_state(tpmif, XenbusStateClosing); >> + >> + /* Unmap share page and unbind event channel */ >> + if(tpmif->status =3D=3D CONNECTED) { >> + tpmif->status =3D DISCONNECTING; >> + mask_evtchn(tpmif->evtchn); >> + >> + if(gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1)) { >> + TPMBACK_ERR("%u/%u Error occured while trying to unmap shared >> page\n", (unsigned int) tpmif->domid, tpmif->handle); >> + } >> + >> + unbind_evtchn(tpmif->evtchn); >> + } >> + tpmif->status =3D DISCONNECTED; >> + tpmif_change_state(tpmif, XenbusStateClosed); >> + >> + /* Do the callback now */ >> + if(gtpmdev.close_callback) { >> + gtpmdev.close_callback(tpmif->domid, tpmif->handle); >> + } >> + >> + /* remove from array */ >> + remove_tpmif(tpmif); >> + >> + /* Wake up anyone possibly waiting on this interface and let them >> exit */ >> + wake_up(&waitq); >> + schedule(); >> + >> + /* Remove the old xenbus entries */ >> + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) >> tpmif->domid, tpmif->handle); >> + if((err =3D xenbus_rm(XBT_NIL, path))) { >> + TPMBACK_ERR("Error cleaning up xenbus entries path=3D%s >> error=3D%s\n", path, err); >> + free(err); >> + } >> + >> + TPMBACK_LOG("Frontend %u/%u disconnected\n", (unsigned int) >> tpmif->domid, tpmif->handle); >> + >> + /* free memory */ >> + __free_tpmif(tpmif); >> + >> +} >> + >> +/********************** >> + * REMAINING TPMBACK FUNCTIONS >> + * ********************/ >> + >> +/*Event channel handler */ >> +void tpmback_handler(evtchn_port_t port, struct pt_regs *regs, void *= data) >> +{ >> + tpmif_t* tpmif =3D (tpmif_t*) data; >> + tpmif_tx_request_t* tx =3D &tpmif->tx->ring[0].req; >> + /* Throw away 0 size events, these can trigger from event channel >> unmasking */ >> + if(tx->size =3D=3D 0) >> + return; >> + >> + TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) >> tpmif->domid, tpmif->handle); >> + tpmif_req_ready(tpmif); >> + wake_up(&waitq); >> + >> +} >> + >> +/* Connect to frontend */ >> +int connect_fe(tpmif_t* tpmif) >> +{ >> + char path[512]; >> + char* err, *value; >> + uint32_t domid; >> + grant_ref_t ringref; >> + evtchn_port_t evtchn; >> + >> + /* If already connected then quit */ >> + if (tpmif->status =3D=3D CONNECTED) { >> + TPMBACK_DEBUG("%u/%u tried to connect while it was already >> connected?\n", (unsigned int) tpmif->domid, tpmif->handle); >> + return 0; >> + } >> + >> + /* Fetch the grant reference */ >> + snprintf(path, 512, "%s/ring-ref", tpmif->fe_path); >> + if((err =3D xenbus_read(XBT_NIL, path, &value))) { >> + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s) >> Error =3D %s", path, err); >> + free(err); >> + return -1; >> + } >> + if(sscanf(value, "%d", &ringref) !=3D 1) { >> + TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path); >> + free(value); >> + return -1; >> + } >> + free(value); >> + >> + >> + /* Fetch the event channel*/ >> + snprintf(path, 512, "%s/event-channel", tpmif->fe_path); >> + if((err =3D xenbus_read(XBT_NIL, path, &value))) { >> + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s) >> Error =3D %s", path, err); >> + free(err); >> + return -1; >> + } >> + if(sscanf(value, "%d", &evtchn) !=3D 1) { >> + TPMBACK_ERR("Non integer value (%s) in %s ??\n", value, path); >> + free(value); >> + return -1; >> + } >> + free(value); >> + >> + domid =3D tpmif->domid; >> + if((tpmif->tx =3D gntmap_map_grant_refs(>pmdev.map, 1, &domid, 0= , >> &ringref, PROT_READ | PROT_WRITE)) =3D=3D NULL) { >> + TPMBACK_ERR("Failed to map grant reference %u/%u\n", (unsigned >> int) tpmif->domid, tpmif->handle); >> + return -1; >> + } >> + memset(tpmif->tx, 0, PAGE_SIZE); >> + >> + /*Bind the event channel */ >> + if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler,= >> tpmif, &tpmif->evtchn))) >> + { >> + TPMBACK_ERR("%u/%u Unable to bind to interdomain event >> channel!\n", (unsigned int) tpmif->domid, tpmif->handle); >> + goto error_post_map; >> + } >> + unmask_evtchn(tpmif->evtchn); >> + >> + /* Write the ready flag and change status to connected */ >> + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) >> tpmif->domid, tpmif->handle); >> + if((err =3D xenbus_printf(XBT_NIL, path, "ready", "%u", 1))) { >> + TPMBACK_ERR("%u/%u Unable to write ready flag on connect_fe()\n= ", >> (unsigned int) tpmif->domid, tpmif->handle); >> + free(err); >> + goto error_post_evtchn; >> + } >> + tpmif->status =3D CONNECTED; >> + if((tpmif_change_state(tpmif, XenbusStateConnected))){ >> + goto error_post_evtchn; >> + } >> + >> + TPMBACK_LOG("Frontend %u/%u connected\n", (unsigned int) >> tpmif->domid, tpmif->handle); >> + >> + return 0; >> +error_post_evtchn: >> + mask_evtchn(tpmif->evtchn); >> + unbind_evtchn(tpmif->evtchn); >> +error_post_map: >> + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->tx, 1); >> + return -1; >> +} >> + >> +static int frontend_changed(tpmif_t* tpmif) >> +{ >> + int state =3D xenbus_read_integer(tpmif->fe_state_path); >> + if(state < 0) { >> + state =3D XenbusStateUnknown; >> + } >> + >> + TPMBACK_DEBUG("Frontend %u/%u state changed to %d\n", (unsigned in= t) >> tpmif->domid, tpmif->handle, state); >> + >> + switch (state) { >> + case XenbusStateInitialising: >> + case XenbusStateInitialised: >> + break; >> + >> + case XenbusStateConnected: >> + if(connect_fe(tpmif)) { >> + TPMBACK_ERR("Failed to connect to front end %u/%u\n", (unsign= ed >> int) tpmif->domid, tpmif->handle); >> + tpmif_change_state(tpmif, XenbusStateClosed); >> + return -1; >> + } >> + break; >> + >> + case XenbusStateClosing: >> + tpmif_change_state(tpmif, XenbusStateClosing); >> + break; >> + >> + case XenbusStateUnknown: /* keep it here */ >> + case XenbusStateClosed: >> + free_tpmif(tpmif); >> + break; >> + >> + default: >> + TPMBACK_DEBUG("BAD STATE CHANGE %u/%u state =3D %d for tpmif\n",= >> (unsigned int) tpmif->domid, tpmif->handle, state); >> + return -1; >> + } >> + return 0; >> +} >> + >> + >> +/* parses the string that comes out of xenbus_watch_wait_return. */ >> +static int parse_eventstr(const char* evstr, domid_t* domid, unsigned= >> int* handle) >> +{ >> + int ret; >> + char cmd[40]; >> + char* err; >> + char* value; >> + unsigned int udomid =3D 0; >> + tpmif_t* tpmif; >> + /* First check for new frontends, this occurs when >> /backend/vtpm// gets created. Note we what the sscanf t= o >> fail on the last %s */ >> + if (sscanf(evstr, "backend/vtpm/%u/%u/%40s", &udomid, handle, cmd)= >> =3D=3D 2) { >> + *domid =3D udomid; >> + /* Make sure the entry exists, if this event triggers because t= he >> entry dissapeared then ignore it */ >> + if((err =3D xenbus_read(XBT_NIL, evstr, &value))) { >> + free(err); >> + return EV_NONE; >> + } >> + free(value); >> + /* Make sure the tpmif entry does not already exist, this shoul= d >> not happen */ >> + if((tpmif =3D get_tpmif(*domid, *handle)) !=3D NULL) { >> + TPMBACK_DEBUG("Duplicate tpm entries! %u %u\n", tpmif->domid, >> tpmif->handle); >> + return EV_NONE; >> + } >> + return EV_NEWFE; >> + } else if((ret =3D sscanf(evstr, >> "/local/domain/%u/device/vtpm/%u/%40s", &udomid, handle, cmd)) =3D=3D = 3) { >> + *domid =3D udomid; >> + if (!strcmp(cmd, "state")) >> + return EV_STCHNG; >> + } >> + return EV_NONE; >> +} >> + >> +void handle_backend_event(char* evstr) { >> + tpmif_t* tpmif; >> + domid_t domid; >> + unsigned int handle; >> + int event; >> + >> + TPMBACK_DEBUG("Xenbus Event: %s\n", evstr); >> + >> + event =3D parse_eventstr(evstr, &domid, &handle); >> + >> + switch(event) { >> + case EV_NEWFE: >> + if(new_tpmif(domid, handle) =3D=3D NULL) { >> + TPMBACK_ERR("Failed to create new tpm instance %u/%u\n", >> (unsigned int) domid, handle); >> + } >> + wake_up(&waitq); >> + break; >> + case EV_STCHNG: >> + if((tpmif =3D get_tpmif(domid, handle))) { >> + frontend_changed(tpmif); >> + } else { >> + TPMBACK_DEBUG("Event Received for non-existant tpm! >> instance=3D%u/%u xenbus_event=3D%s\n", (unsigned int) domid, handle, e= vstr); >> + } >> + break; >> + } >> +} >> + >> +/* Runs through the given path and creates events recursively >> + * for all of its children. >> + * @path - xenstore path to scan */ >> +static void generate_backend_events(const char* path) >> +{ >> + char* err; >> + int i, len; >> + char **dirs; >> + char *entry; >> + >> + if((err =3D xenbus_ls(XBT_NIL, path, &dirs)) !=3D NULL) { >> + free(err); >> + return; >> + } >> + >> + for(i =3D 0; dirs[i] !=3D NULL; ++i) { >> + len =3D strlen(path) + strlen(dirs[i]) + 2; >> + entry =3D malloc(len); >> + snprintf(entry, len, "%s/%s", path, dirs[i]); >> + >> + /* Generate and handle event for the entry itself */ >> + handle_backend_event(entry); >> + >> + /* Do children */ >> + generate_backend_events(entry); >> + >> + /* Cleanup */ >> + free(entry); >> + free(dirs[i]); >> + } >> + free(dirs); >> + return; >> +} >> + >> +char* tpmback_get_uuid(domid_t domid, unsigned int handle) >> +{ >> + tpmif_t* tpmif; >> + if((tpmif =3D get_tpmif(domid, handle)) =3D=3D NULL) { >> + TPMBACK_DEBUG("get_uuid() failed, %u/%u is an invalid >> frontend\n", (unsigned int) domid, handle); >> + return NULL; >> + } >> + >> + return tpmif->uuid; >> +} >> + >> +void tpmback_set_open_callback(void (*cb)(domid_t, unsigned int)) >> +{ >> + gtpmdev.open_callback =3D cb; >> +} >> +void tpmback_set_close_callback(void (*cb)(domid_t, unsigned int)) >> +{ >> + gtpmdev.close_callback =3D cb; >> +} >> +void tpmback_set_suspend_callback(void (*cb)(domid_t, unsigned int)) >> +{ >> + gtpmdev.suspend_callback =3D cb; >> +} >> +void tpmback_set_resume_callback(void (*cb)(domid_t, unsigned int)) >> +{ >> + gtpmdev.resume_callback =3D cb; >> +} >> + >> +static void event_listener(void) >> +{ >> + const char* bepath =3D "backend/vtpm"; >> + char **path; >> + char* err; >> + >> + /* Setup the backend device watch */ >> + if((err =3D xenbus_watch_path_token(XBT_NIL, bepath, bepath, >> >pmdev.events)) !=3D NULL) { >> + TPMBACK_ERR("xenbus_watch_path_token(%s) failed with error >> %s!\n", bepath, err); >> + free(err); >> + goto egress; >> + } >> + >> + /* Check for any frontends that connected before we set the watch.= >> + * This is almost guaranteed to happen if both domains are started= >> + * immediatly one after the other. >> + * We do this by manually generating events on everything in the b= ackend >> + * path */ >> + generate_backend_events(bepath); >> + >> + /* Wait and listen for changes in frontend connections */ >> + while(1) { >> + path =3D xenbus_wait_for_watch_return(>pmdev.events); >> + >> + /*If quit flag was set then exit */ >> + if(gtpmdev.flags & TPMIF_CLOSED) { >> + TPMBACK_DEBUG("listener thread got quit event. Exiting..\n"); >> + free(path); >> + break; >> + } >> + handle_backend_event(*path); >> + free(path); >> + >> + } >> + >> + if((err =3D xenbus_unwatch_path_token(XBT_NIL, bepath, bepath)) !=3D= NULL) { >> + free(err); >> + } >> +egress: >> + return; >> +} >> + >> +void event_thread(void* p) { >> + event_listener(); >> +} >> + >> +void init_tpmback(char** exclusive_uuids) >> +{ >> + if(!globalinit) { >> + init_waitqueue_head(&waitq); >> + globalinit =3D 1; >> + } >> + printk("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Init TPM BACK =3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); >> + gtpmdev.tpmlist =3D malloc(sizeof(tpmif_t*) * DEF_ARRAY_SIZE); >> + gtpmdev.num_alloc =3D DEF_ARRAY_SIZE; >> + gtpmdev.num_tpms =3D 0; >> + gtpmdev.flags =3D 0; >> + gtpmdev.exclusive_uuids =3D exclusive_uuids; >> + >> + gtpmdev.open_callback =3D gtpmdev.close_callback =3D NULL; >> + gtpmdev.suspend_callback =3D gtpmdev.resume_callback =3D NULL; >> + >> + eventthread =3D create_thread("tpmback-listener", event_thread, NU= LL); >> + >> +} >> + >> +void shutdown_tpmback(void) >> +{ >> + /* Disable callbacks */ >> + gtpmdev.open_callback =3D gtpmdev.close_callback =3D NULL; >> + gtpmdev.suspend_callback =3D gtpmdev.resume_callback =3D NULL; >> + >> + TPMBACK_LOG("Shutting down tpm backend\n"); >> + /* Set the quit flag */ >> + gtpmdev.flags =3D TPMIF_CLOSED; >> + >> + //printk("num tpms is %d\n", gtpmdev.num_tpms); >> + /*Free all backend instances */ >> + while(gtpmdev.num_tpms) { >> + free_tpmif(gtpmdev.tpmlist[0]); >> + } >> + free(gtpmdev.tpmlist); >> + gtpmdev.tpmlist =3D NULL; >> + gtpmdev.num_alloc =3D 0; >> + >> + /* Wake up anyone possibly waiting on the device and let them exit= */ >> + wake_up(&waitq); >> + schedule(); >> +} >> + >> +inline void init_tpmcmd(tpmcmd_t* tpmcmd, domid_t domid, unsigned int= >> handle, char* uuid) >> +{ >> + tpmcmd->domid =3D domid; >> + tpmcmd->handle =3D handle; >> + tpmcmd->uuid =3D uuid; >> + tpmcmd->req =3D NULL; >> + tpmcmd->req_len =3D 0; >> + tpmcmd->resp =3D NULL; >> + tpmcmd->resp_len =3D 0; >> +} >> + >> +tpmcmd_t* get_request(tpmif_t* tpmif) { >> + tpmcmd_t* cmd; >> + tpmif_tx_request_t* tx; >> + int offset; >> + int tocopy; >> + int i; >> + uint32_t domid; >> + int flags; >> + >> + local_irq_save(flags); >> + >> + /* Allocate the cmd object to hold the data */ >> + if((cmd =3D malloc(sizeof(*cmd))) =3D=3D NULL) { >> + goto error; >> + } >> + init_tpmcmd(cmd, tpmif->domid, tpmif->handle, tpmif->uuid); >> + >> + tx =3D &tpmif->tx->ring[0].req; >> + cmd->req_len =3D tx->size; >> + /* Allocate the buffer */ >> + if(cmd->req_len) { >> + if((cmd->req =3D malloc(cmd->req_len)) =3D=3D NULL) { >> + goto error; >> + } >> + } >> + /* Copy the bits from the shared pages */ >> + offset =3D 0; >> + for(i =3D 0; i < TPMIF_TX_RING_SIZE && offset < cmd->req_len; ++i)= { >> + tx =3D &tpmif->tx->ring[i].req; >> + >> + /* Map the page with the data */ >> + domid =3D (uint32_t)tpmif->domid; >> + if((tpmif->pages[i] =3D gntmap_map_grant_refs(>pmdev.map, 1, >> &domid, 0, &tx->ref, PROT_READ)) =3D=3D NULL) { >> + TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", >> (unsigned int) tpmif->domid, tpmif->handle); >> + goto error; >> + } >> + >> + /* do the copy now */ >> + tocopy =3D min(cmd->req_len - offset, PAGE_SIZE); >> + memcpy(&cmd->req[offset], tpmif->pages[i], tocopy); >> + offset +=3D tocopy; >> + >> + /* release the page */ >> + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1);= >> + >> + } >> + >> +#ifdef TPMBACK_PRINT_DEBUG >> + TPMBACK_DEBUG("Received Tpm Command from %u/%u of size %u", >> (unsigned int) tpmif->domid, tpmif->handle, cmd->req_len); >> + for(i =3D 0; i < cmd->req_len; ++i) { >> + if (!(i % 30)) { >> + TPMBACK_DEBUG_MORE("\n"); >> + } >> + TPMBACK_DEBUG_MORE("%02hhX ", cmd->req[i]); >> + } >> + TPMBACK_DEBUG_MORE("\n\n"); >> +#endif >> + >> + local_irq_restore(flags); >> + return cmd; >> +error: >> + if(cmd !=3D NULL) { >> + if (cmd->req !=3D NULL) { >> + free(cmd->req); >> + cmd->req =3D NULL; >> + } >> + free(cmd); >> + cmd =3D NULL; >> + } >> + local_irq_restore(flags); >> + return NULL; >> + >> +} >> + >> +void send_response(tpmcmd_t* cmd, tpmif_t* tpmif) >> +{ >> + tpmif_tx_request_t* tx; >> + int offset; >> + int i; >> + uint32_t domid; >> + int tocopy; >> + int flags; >> + >> + local_irq_save(flags); >> + >> + tx =3D &tpmif->tx->ring[0].req; >> + tx->size =3D cmd->resp_len; >> + >> + offset =3D 0; >> + for(i =3D 0; i < TPMIF_TX_RING_SIZE && offset < cmd->resp_len; ++i= ) { >> + tx =3D &tpmif->tx->ring[i].req; >> + >> + /* Map the page with the data */ >> + domid =3D (uint32_t)tpmif->domid; >> + if((tpmif->pages[i] =3D gntmap_map_grant_refs(>pmdev.map, 1, >> &domid, 0, &tx->ref, PROT_WRITE)) =3D=3D NULL) { >> + TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", >> (unsigned int) tpmif->domid, tpmif->handle); >> + goto error; >> + } >> + >> + /* do the copy now */ >> + tocopy =3D min(cmd->resp_len - offset, PAGE_SIZE); >> + memcpy(tpmif->pages[i], &cmd->resp[offset], tocopy); >> + offset +=3D tocopy; >> + >> + /* release the page */ >> + gntmap_munmap(>pmdev.map, (unsigned long)tpmif->pages[i], 1);= >> + >> + } >> + >> +#ifdef TPMBACK_PRINT_DEBUG >> + TPMBACK_DEBUG("Sent response to %u/%u of size %u", (unsigned int) >> tpmif->domid, tpmif->handle, cmd->resp_len); >> + for(i =3D 0; i < cmd->resp_len; ++i) { >> + if (!(i % 30)) { >> + TPMBACK_DEBUG_MORE("\n"); >> + } >> + TPMBACK_DEBUG_MORE("%02hhX ", cmd->resp[i]); >> + } >> + TPMBACK_DEBUG_MORE("\n\n"); >> +#endif >> + /* clear the ready flag and send the event channel notice to the >> frontend */ >> + tpmif_req_finished(tpmif); >> + notify_remote_via_evtchn(tpmif->evtchn); >> +error: >> + local_irq_restore(flags); >> + return; >> +} >> + >> +tpmcmd_t* tpmback_req_any(void) >> +{ >> + int i; >> + /* Block until something has a request */ >> + wait_event(waitq, (gtpmdev.flags & (TPMIF_REQ_READY | TPMIF_CLOSED= ))); >> + >> + /* Check if were shutting down */ >> + if(gtpmdev.flags & TPMIF_CLOSED) { >> + /* if something was waiting for us to give up the queue so it c= an >> shutdown, let it finish */ >> + schedule(); >> + return NULL; >> + } >> + >> + for(i =3D 0; i < gtpmdev.num_tpms; ++i) { >> + if(gtpmdev.tpmlist[i]->flags & TPMIF_REQ_READY) { >> + return get_request(gtpmdev.tpmlist[i]); >> + } >> + } >> + >> + TPMBACK_ERR("backend request ready flag was set but no interfaces >> were actually ready\n"); >> + return NULL; >> +} >> + >> +tpmcmd_t* tpmback_req(domid_t domid, unsigned int handle) >> +{ >> + tpmif_t* tpmif; >> + tpmif =3D get_tpmif(domid, handle); >> + if(tpmif =3D=3D NULL) { >> + return NULL; >> + } >> + >> + wait_event(waitq, (tpmif->flags & (TPMIF_REQ_READY | TPMIF_CLOSED)= >> || gtpmdev.flags & TPMIF_CLOSED)); >> + >> + /* Check if were shutting down */ >> + if(tpmif->flags & TPMIF_CLOSED || gtpmdev.flags & TPMIF_CLOSED) { >> + /* if something was waiting for us to give up the queue so it c= an >> free this instance, let it finish */ >> + schedule(); >> + return NULL; >> + } >> + >> + return get_request(tpmif); >> +} >> + >> +void tpmback_resp(tpmcmd_t* tpmcmd) >> +{ >> + tpmif_t* tpmif; >> + >> + /* Get the associated interface, if it doesnt exist then just quit= */ >> + tpmif =3D get_tpmif(tpmcmd->domid, tpmcmd->handle); >> + if(tpmif =3D=3D NULL) { >> + TPMBACK_ERR("Tried to send a reponse to non existant frontend >> %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle); >> + goto end; >> + } >> + >> + if(!(tpmif->flags & TPMIF_REQ_READY)) { >> + TPMBACK_ERR("Tried to send response to a frontend that was not >> waiting for one %u/%u\n", (unsigned int) tpmcmd->domid, tpmcmd->handle= ); >> + goto end; >> + } >> + >> + /* Send response to frontend */ >> + send_response(tpmcmd, tpmif); >> + >> +end: >> + if(tpmcmd->req !=3D NULL) { >> + free(tpmcmd->req); >> + } >> + free(tpmcmd); >> + return; >> +} >> + >> +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned int *h= andle) >> +{ >> + tpmif_t* tpmif; >> + int flags; >> + wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags & >> TPMIF_CLOSED)); >> + if(gtpmdev.flags & TPMIF_CLOSED) { >> + return -1; >> + } >> + local_irq_save(flags); >> + tpmif =3D gtpmdev.tpmlist[0]; >> + *domid =3D tpmif->domid; >> + *handle =3D tpmif->handle; >> + local_irq_restore(flags); >> + >> + return 0; >> +} >> + >> +int tpmback_num_frontends(void) >> +{ >> + return gtpmdev.num_tpms; >> +} >> diff --git a/extras/mini-os/tpmfront.c b/extras/mini-os/tpmfront.c >> --- /dev/null >> +++ b/extras/mini-os/tpmfront.c >> @@ -0,0 +1,606 @@ >> +/* >> + * Copyright (c) 2010-2012 United States Government, as represented b= y >> + * the Secretary of Defense. All rights reserved. >> + * >> + * This driver is free software: you can redistribute it and/or modif= y >> + * it under the terms of the GNU General Public License as published = by >> + * the Free Software Foundation, either version 3 of the License, or >> + * (at your option) any later version. >> + * >> + * This driver is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program. If not, see . >> + * >> + * Based upon the files: >> + * drivers/char/tpm/tpm_vtpm.c >> + * drivers/char/tpm/tpm_xen.c >> + * from the Linux kernel, which are Copyright (C) 2006 IBM Corporatio= n >> + */ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +//#define TPMFRONT_PRINT_DEBUG >> +#ifdef TPMFRONT_PRINT_DEBUG >> +#define TPMFRONT_DEBUG(fmt,...) printk("Tpmfront:Debug("__FILE__":%d)= " >> fmt, __LINE__, ##__VA_ARGS__) >> +#define TPMFRONT_DEBUG_MORE(fmt,...) printk(fmt, ##__VA_ARGS__) >> +#else >> +#define TPMFRONT_DEBUG(fmt,...) >> +#endif >> +#define TPMFRONT_ERR(fmt,...) printk("Tpmfront:Error " fmt, ##__VA_AR= GS__) >> +#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARG= S__) >> + >> +#define min(a,b) (((a) < (b)) ? (a) : (b)) >> + >> +void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void >> *data) { >> + struct tpmfront_dev* dev =3D (struct tpmfront_dev*) data; >> + /*If we get a response when we didnt make a request, just ignore i= t */ >> + if(!dev->waiting) { >> + return; >> + } >> + >> + dev->waiting =3D 0; >> +#ifdef HAVE_LIBC >> + if(dev->fd >=3D 0) { >> + files[dev->fd].read =3D 1; >> + } >> +#endif >> + wake_up(&dev->waitq); >> +} >> + >> +static int publish_xenbus(struct tpmfront_dev* dev) { >> + xenbus_transaction_t xbt; >> + int retry; >> + char* err; >> + /* Write the grant reference and event channel to xenstore */ >> +again: >> + if((err =3D xenbus_transaction_start(&xbt))) { >> + TPMFRONT_ERR("Unable to start xenbus transaction, error was >> %s\n", err); >> + free(err); >> + return -1; >> + } >> + >> + if((err =3D xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", >> (unsigned int) dev->ring_ref))) { >> + TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n", >> dev->nodename, err); >> + free(err); >> + goto abort_transaction; >> + } >> + >> + if((err =3D xenbus_printf(xbt, dev->nodename, "event-channel", "%u= ", >> (unsigned int) dev->evtchn))) { >> + TPMFRONT_ERR("Unable to write %s/event-channel, error was %s\n"= , >> dev->nodename, err); >> + free(err); >> + goto abort_transaction; >> + } >> + >> + if((err =3D xenbus_transaction_end(xbt, 0, &retry))) { >> + TPMFRONT_ERR("Unable to complete xenbus transaction, error was >> %s\n", err); >> + free(err); >> + return -1; >> + } >> + if(retry) { >> + goto again; >> + } >> + >> + return 0; >> +abort_transaction: >> + if((err =3D xenbus_transaction_end(xbt, 1, &retry))) { >> + free(err); >> + } >> + return -1; >> +} >> + >> +static int wait_for_backend_connect(xenbus_event_queue* events, char*= path) >> +{ >> + int state; >> + >> + TPMFRONT_LOG("Waiting for backend connection..\n"); >> + /* Wait for the backend to connect */ >> + while(1) { >> + state =3D xenbus_read_integer(path); >> + if ( state < 0) >> + state =3D XenbusStateUnknown; >> + switch(state) { >> + /* Bad states, we quit with error */ >> + case XenbusStateUnknown: >> + case XenbusStateClosing: >> + case XenbusStateClosed: >> + TPMFRONT_ERR("Unable to connect to backend\n"); >> + return -1; >> + /* If backend is connected then break out of loop */ >> + case XenbusStateConnected: >> + TPMFRONT_LOG("Backend Connected\n"); >> + return 0; >> + default: >> + xenbus_wait_for_watch(events); >> + } >> + } >> + >> +} >> + >> +static int wait_for_backend_closed(xenbus_event_queue* events, char* = path) >> +{ >> + int state; >> + >> + TPMFRONT_LOG("Waiting for backend to close..\n"); >> + while(1) { >> + state =3D xenbus_read_integer(path); >> + if ( state < 0) >> + state =3D XenbusStateUnknown; >> + switch(state) { >> + case XenbusStateUnknown: >> + TPMFRONT_ERR("Backend Unknown state, forcing shutdown\n"); >> + return -1; >> + case XenbusStateClosed: >> + TPMFRONT_LOG("Backend Closed\n"); >> + return 0; >> + default: >> + xenbus_wait_for_watch(events); >> + } >> + } >> + >> +} >> + >> +static int wait_for_backend_state_changed(struct tpmfront_dev* dev, >> XenbusState state) { >> + char* err; >> + int ret =3D 0; >> + xenbus_event_queue events =3D NULL; >> + char path[512]; >> + >> + snprintf(path, 512, "%s/state", dev->bepath); >> + /*Setup the watch to wait for the backend */ >> + if((err =3D xenbus_watch_path_token(XBT_NIL, path, path, &events))= ) { >> + TPMFRONT_ERR("Could not set a watch on %s, error was %s\n", pat= h, >> err); >> + free(err); >> + return -1; >> + } >> + >> + /* Do the actual wait loop now */ >> + switch(state) { >> + case XenbusStateConnected: >> + ret =3D wait_for_backend_connect(&events, path); >> + break; >> + case XenbusStateClosed: >> + ret =3D wait_for_backend_closed(&events, path); >> + break; >> + default: >> + break; >> + } >> + >> + if((err =3D xenbus_unwatch_path_token(XBT_NIL, path, path))) { >> + TPMFRONT_ERR("Unable to unwatch %s, error was %s, ignoring..\n"= , >> path, err); >> + free(err); >> + } >> + return ret; >> +} >> + >> +static int tpmfront_connect(struct tpmfront_dev* dev) >> +{ >> + char* err; >> + /* Create shared page */ >> + dev->tx =3D (tpmif_tx_interface_t*) alloc_page(); >> + if(dev->tx =3D=3D NULL) { >> + TPMFRONT_ERR("Unable to allocate page for shared memory\n"); >> + goto error; >> + } >> + memset(dev->tx, 0, PAGE_SIZE); >> + dev->ring_ref =3D gnttab_grant_access(dev->bedomid, >> virt_to_mfn(dev->tx), 0); >> + TPMFRONT_DEBUG("grant ref is %lu\n", (unsigned long) dev->ring_ref= ); >> + >> + /*Create event channel */ >> + if(evtchn_alloc_unbound(dev->bedomid, tpmfront_handler, dev, >> &dev->evtchn)) { >> + TPMFRONT_ERR("Unable to allocate event channel\n"); >> + goto error_postmap; >> + } >> + unmask_evtchn(dev->evtchn); >> + TPMFRONT_DEBUG("event channel is %lu\n", (unsigned long) dev->evtc= hn); >> + >> + /* Write the entries to xenstore */ >> + if(publish_xenbus(dev)) { >> + goto error_postevtchn; >> + } >> + >> + /* Change state to connected */ >> + dev->state =3D XenbusStateConnected; >> + >> + /* Tell the backend that we are ready */ >> + if((err =3D xenbus_printf(XBT_NIL, dev->nodename, "state", "%u", >> dev->state))) { >> + TPMFRONT_ERR("Unable to write to xenstore %s/state, value=3D%u"= , >> dev->nodename, XenbusStateConnected); >> + free(err); >> + goto error; >> + } >> + >> + return 0; >> +error_postevtchn: >> + mask_evtchn(dev->evtchn); >> + unbind_evtchn(dev->evtchn); >> +error_postmap: >> + gnttab_end_access(dev->ring_ref); >> + free_page(dev->tx); >> +error: >> + return -1; >> +} >> + >> +struct tpmfront_dev* init_tpmfront(const char* _nodename) >> +{ >> + struct tpmfront_dev* dev; >> + const char* nodename; >> + char path[512]; >> + char* value, *err; >> + unsigned long long ival; >> + int i; >> + >> + printk("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Init TPM Front =3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); >> + >> + dev =3D malloc(sizeof(struct tpmfront_dev)); >> + memset(dev, 0, sizeof(struct tpmfront_dev)); >> + >> +#ifdef HAVE_LIBC >> + dev->fd =3D -1; >> +#endif >> + >> + nodename =3D _nodename ? _nodename : "device/vtpm/0"; >> + dev->nodename =3D strdup(nodename); >> + >> + init_waitqueue_head(&dev->waitq); >> + >> + /* Get backend domid */ >> + snprintf(path, 512, "%s/backend-id", dev->nodename); >> + if((err =3D xenbus_read(XBT_NIL, path, &value))) { >> + TPMFRONT_ERR("Unable to read %s during tpmfront initialization!= >> error =3D %s\n", path, err); >> + free(err); >> + goto error; >> + } >> + if(sscanf(value, "%llu", &ival) !=3D 1) { >> + TPMFRONT_ERR("%s has non-integer value (%s)\n", path, value); >> + free(value); >> + goto error; >> + } >> + free(value); >> + dev->bedomid =3D ival; >> + >> + /* Get backend xenstore path */ >> + snprintf(path, 512, "%s/backend", dev->nodename); >> + if((err =3D xenbus_read(XBT_NIL, path, &dev->bepath))) { >> + TPMFRONT_ERR("Unable to read %s during tpmfront initialization!= >> error =3D %s\n", path, err); >> + free(err); >> + goto error; >> + } >> + >> + /* Create and publish grant reference and event channel */ >> + if (tpmfront_connect(dev)) { >> + goto error; >> + } >> + >> + /* Wait for backend to connect */ >> + if( wait_for_backend_state_changed(dev, XenbusStateConnected)) { >> + goto error; >> + } >> + >> + /* Allocate pages that will contain the messages */ >> + dev->pages =3D malloc(sizeof(void*) * TPMIF_TX_RING_SIZE); >> + if(dev->pages =3D=3D NULL) { >> + goto error; >> + } >> + memset(dev->pages, 0, sizeof(void*) * TPMIF_TX_RING_SIZE); >> + for(i =3D 0; i < TPMIF_TX_RING_SIZE; ++i) { >> + dev->pages[i] =3D (void*)alloc_page(); >> + if(dev->pages[i] =3D=3D NULL) { >> + goto error; >> + } >> + } >> + >> + TPMFRONT_LOG("Initialization Completed successfully\n"); >> + >> + return dev; >> + >> +error: >> + shutdown_tpmfront(dev); >> + return NULL; >> +} >> +void shutdown_tpmfront(struct tpmfront_dev* dev) >> +{ >> + char* err; >> + char path[512]; >> + int i; >> + tpmif_tx_request_t* tx; >> + if(dev =3D=3D NULL) { >> + return; >> + } >> + TPMFRONT_LOG("Shutting down tpmfront\n"); >> + /* disconnect */ >> + if(dev->state =3D=3D XenbusStateConnected) { >> + dev->state =3D XenbusStateClosing; >> + //FIXME: Transaction for this? >> + /* Tell backend we are closing */ >> + if((err =3D xenbus_printf(XBT_NIL, dev->nodename, "state", "%u"= , >> (unsigned int) dev->state))) { >> + free(err); >> + } >> + >> + /* Clean up xenstore entries */ >> + snprintf(path, 512, "%s/event-channel", dev->nodename); >> + if((err =3D xenbus_rm(XBT_NIL, path))) { >> + free(err); >> + } >> + snprintf(path, 512, "%s/ring-ref", dev->nodename); >> + if((err =3D xenbus_rm(XBT_NIL, path))) { >> + free(err); >> + } >> + >> + /* Tell backend we are closed */ >> + dev->state =3D XenbusStateClosed; >> + if((err =3D xenbus_printf(XBT_NIL, dev->nodename, "state", "%u"= , >> (unsigned int) dev->state))) { >> + TPMFRONT_ERR("Unable to write to %s, error was %s", dev->nodenam= e, >> err); >> + free(err); >> + } >> + >> + /* Wait for the backend to close and unmap shared pages, ignore= >> any errors */ >> + wait_for_backend_state_changed(dev, XenbusStateClosed); >> + >> + /* Cleanup any shared pages */ >> + if(dev->pages) { >> + for(i =3D 0; i < TPMIF_TX_RING_SIZE; ++i) { >> + if(dev->pages[i]) { >> + tx =3D &dev->tx->ring[i].req; >> + if(tx->ref !=3D 0) { >> + gnttab_end_access(tx->ref); >> + } >> + free_page(dev->pages[i]); >> + } >> + } >> + free(dev->pages); >> + } >> + >> + /* Close event channel and unmap shared page */ >> + mask_evtchn(dev->evtchn); >> + unbind_evtchn(dev->evtchn); >> + gnttab_end_access(dev->ring_ref); >> + >> + free_page(dev->tx); >> + >> + } >> + >> + /* Cleanup memory usage */ >> + if(dev->respbuf) { >> + free(dev->respbuf); >> + } >> + if(dev->bepath) { >> + free(dev->bepath); >> + } >> + if(dev->nodename) { >> + free(dev->nodename); >> + } >> + free(dev); >> +} >> + >> +int tpmfront_send(struct tpmfront_dev* dev, const uint8_t* msg, size_= t >> length) >> +{ >> + int i; >> + tpmif_tx_request_t* tx =3D NULL; >> + /* Error Checking */ >> + if(dev =3D=3D NULL || dev->state !=3D XenbusStateConnected) { >> + TPMFRONT_ERR("Tried to send message through disconnected >> frontend\n"); >> + return -1; >> + } >> + >> +#ifdef TPMFRONT_PRINT_DEBUG >> + TPMFRONT_DEBUG("Sending Msg to backend size=3D%u", (unsigned int) = length); >> + for(i =3D 0; i < length; ++i) { >> + if(!(i % 30)) { >> + TPMFRONT_DEBUG_MORE("\n"); >> + } >> + TPMFRONT_DEBUG_MORE("%02X ", msg[i]); >> + } >> + TPMFRONT_DEBUG_MORE("\n"); >> +#endif >> + >> + /* Copy to shared pages now */ >> + for(i =3D 0; length > 0 && i < TPMIF_TX_RING_SIZE; ++i) { >> + /* Share the page */ >> + tx =3D &dev->tx->ring[i].req; >> + tx->unused =3D 0; >> + tx->addr =3D virt_to_mach(dev->pages[i]); >> + tx->ref =3D gnttab_grant_access(dev->bedomid, >> virt_to_mfn(dev->pages[i]), 0); >> + /* Copy the bits to the page */ >> + tx->size =3D length > PAGE_SIZE ? PAGE_SIZE : length; >> + memcpy(dev->pages[i], &msg[i * PAGE_SIZE], tx->size); >> + >> + /* Update counters */ >> + length -=3D tx->size; >> + } >> + dev->waiting =3D 1; >> + dev->resplen =3D 0; >> +#ifdef HAVE_LIBC >> + if(dev->fd >=3D 0) { >> + files[dev->fd].read =3D 0; >> + files[dev->fd].tpmfront.respgot =3D 0; >> + files[dev->fd].tpmfront.offset =3D 0; >> + } >> +#endif >> + notify_remote_via_evtchn(dev->evtchn); >> + return 0; >> +} >> +int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *le= ngth) >> +{ >> + tpmif_tx_request_t* tx; >> + int i; >> + if(dev =3D=3D NULL || dev->state !=3D XenbusStateConnected) { >> + TPMFRONT_ERR("Tried to receive message from disconnected >> frontend\n"); >> + return -1; >> + } >> + /*Wait for the response */ >> + wait_event(dev->waitq, (!dev->waiting)); >> + >> + /* Initialize */ >> + *msg =3D NULL; >> + *length =3D 0; >> + >> + /* special case, just quit */ >> + tx =3D &dev->tx->ring[0].req; >> + if(tx->size =3D=3D 0 ) { >> + goto quit; >> + } >> + /* Get the total size */ >> + tx =3D &dev->tx->ring[0].req; >> + for(i =3D 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { >> + tx =3D &dev->tx->ring[i].req; >> + *length +=3D tx->size; >> + } >> + /* Alloc the buffer */ >> + if(dev->respbuf) { >> + free(dev->respbuf); >> + } >> + *msg =3D dev->respbuf =3D malloc(*length); >> + dev->resplen =3D *length; >> + /* Copy the bits */ >> + tx =3D &dev->tx->ring[0].req; >> + for(i =3D 0; i < TPMIF_TX_RING_SIZE && tx->size > 0; ++i) { >> + tx =3D &dev->tx->ring[i].req; >> + memcpy(&(*msg)[i * PAGE_SIZE], dev->pages[i], tx->size); >> + gnttab_end_access(tx->ref); >> + tx->ref =3D 0; >> + } >> +#ifdef TPMFRONT_PRINT_DEBUG >> + TPMFRONT_DEBUG("Received response from backend size=3D%u", (unsign= ed >> int) *length); >> + for(i =3D 0; i < *length; ++i) { >> + if(!(i % 30)) { >> + TPMFRONT_DEBUG_MORE("\n"); >> + } >> + TPMFRONT_DEBUG_MORE("%02X ", (*msg)[i]); >> + } >> + TPMFRONT_DEBUG_MORE("\n"); >> +#endif >> +#ifdef HAVE_LIBC >> + if(dev->fd >=3D 0) { >> + files[dev->fd].tpmfront.respgot =3D 1; >> + } >> +#endif >> +quit: >> + return 0; >> +} >> + >> +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqle= n, >> uint8_t** resp, size_t* resplen) >> +{ >> + int rc; >> + if((rc =3D tpmfront_send(dev, req, reqlen))) { >> + return rc; >> + } >> + if((rc =3D tpmfront_recv(dev, resp, resplen))) { >> + return rc; >> + } >> + >> + return 0; >> +} >> + >> +#ifdef HAVE_LIBC >> +#include >> +int tpmfront_open(struct tpmfront_dev* dev) >> +{ >> + /* Silently prevent multiple opens */ >> + if(dev->fd !=3D -1) { >> + return dev->fd; >> + } >> + >> + dev->fd =3D alloc_fd(FTYPE_TPMFRONT); >> + printk("tpmfront_open(%s) -> %d\n", dev->nodename, dev->fd); >> + files[dev->fd].tpmfront.dev =3D dev; >> + files[dev->fd].tpmfront.offset =3D 0; >> + files[dev->fd].tpmfront.respgot =3D 0; >> + return dev->fd; >> +} >> + >> +int tpmfront_posix_write(int fd, const uint8_t* buf, size_t count) >> +{ >> + int rc; >> + struct tpmfront_dev* dev; >> + dev =3D files[fd].tpmfront.dev; >> + >> + if(count =3D=3D 0) { >> + return 0; >> + } >> + >> + /* Return an error if we are already processing a command */ >> + if(dev->waiting) { >> + errno =3D EINPROGRESS; >> + return -1; >> + } >> + /* Send the command now */ >> + if((rc =3D tpmfront_send(dev, buf, count)) !=3D 0) { >> + errno =3D EIO; >> + return -1; >> + } >> + return count; >> +} >> + >> +int tpmfront_posix_read(int fd, uint8_t* buf, size_t count) >> +{ >> + int rc; >> + uint8_t* dummybuf; >> + size_t dummysz; >> + struct tpmfront_dev* dev; >> + >> + dev =3D files[fd].tpmfront.dev; >> + >> + if(count =3D=3D 0) { >> + return 0; >> + } >> + >> + /* get the response if we haven't already */ >> + if(files[dev->fd].tpmfront.respgot =3D=3D 0) { >> + if ((rc =3D tpmfront_recv(dev, &dummybuf, &dummysz)) !=3D 0) { >> + errno =3D EIO; >> + return -1; >> + } >> + } >> + >> + /* handle EOF case */ >> + if(files[dev->fd].tpmfront.offset >=3D dev->resplen) { >> + return 0; >> + } >> + >> + /* Compute the number of bytes and do the copy operation */ >> + if((rc =3D min(count, dev->resplen - files[dev->fd].tpmfront.offse= t)) >> !=3D 0) { >> + memcpy(buf, dev->respbuf + files[dev->fd].tpmfront.offset, rc);= >> + files[dev->fd].tpmfront.offset +=3D rc; >> + } >> + >> + return rc; >> +} >> + >> +int tpmfront_posix_fstat(int fd, struct stat* buf) >> +{ >> + uint8_t* dummybuf; >> + size_t dummysz; >> + int rc; >> + struct tpmfront_dev* dev =3D files[fd].tpmfront.dev; >> + >> + /* If we have a response waiting, then read it now from the backen= d >> + * so we can get its length*/ >> + if(dev->waiting || (files[dev->fd].read =3D=3D 1 && >> !files[dev->fd].tpmfront.respgot)) { >> + if ((rc =3D tpmfront_recv(dev, &dummybuf, &dummysz)) !=3D 0) { >> + errno =3D EIO; >> + return -1; >> + } >> + } >> + >> + buf->st_mode =3D O_RDWR; >> + buf->st_uid =3D 0; >> + buf->st_gid =3D 0; >> + buf->st_size =3D dev->resplen; >> + buf->st_atime =3D buf->st_mtime =3D buf->st_ctime =3D time(NULL); >> + >> + return 0; >> +} >> + >> + >> +#endif >> -- >> 1.7.4.4 >> >> >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@lists.xen.org >> http://lists.xen.org/xen-devel >> --------------ms090403080908030504050400 Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" Content-Description: S/MIME Cryptographic Signature MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIDyjCC A8YwggMvoAMCAQICBD/xyf0wDQYJKoZIhvcNAQEFBQAwLzELMAkGA1UEBhMCVVMxDzANBgNV BAoTBkpIVUFQTDEPMA0GA1UECxMGQklTRENBMB4XDTEwMDYxMTE4MjIwNloXDTEzMDYxMTE4 NTIwNlowZjELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkpIVUFQTDEPMA0GA1UECxMGUGVvcGxl MTUwFgYDVQQLEw9WUE5Hcm91cC1CSVNEQ0EwGwYDVQQDExRNYXR0aGV3IEUgRmlvcmF2YW50 ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAnpbwVSP6o1Nb5lcW7dd3yTo9iBJdi7qz 4nANOMFPK7JOy5npKN1iiousl28U/scUJES55gPwAWYJK3uVyQAsA4adgDKi5DoD1UHDQEwp bY7iHLJeq0NPr4BqYNqnCFPbE6HC8zSJrr4qKn+gVUQT39SIFqdiIPJwZL8FYTRQ/zsCAwEA AaOCAbYwggGyMAsGA1UdDwQEAwIHgDArBgNVHRAEJDAigA8yMDEwMDYxMTE4MjIwNlqBDzIw MTIwNzE3MjI1MjA2WjAbBg0rBgEEAbMlCwMBAQEBBAoWCGZpb3JhbWUxMBsGDSsGAQQBsyUL AwEBAQIEChIIMDAxMDQyNjEwWAYJYIZIAYb6ax4BBEsMSVRoZSBwcml2YXRlIGtleSBjb3Jy ZXNwb25kaW5nIHRvIHRoaXMgY2VydGlmaWNhdGUgbWF5IGhhdmUgYmVlbiBleHBvcnRlZC4w KAYDVR0RBCEwH4EdTWF0dGhldy5GaW9yYXZhbnRlQGpodWFwbC5lZHUwUgYDVR0fBEswSTBH oEWgQ6RBMD8xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZKSFVBUEwxDzANBgNVBAsTBkJJU0RD QTEOMAwGA1UEAxMFQ1JMNTYwHwYDVR0jBBgwFoAUCDUpmxH52EU2CyWmF2EJMB1yqeswHQYD VR0OBBYEFO6LYxg6r9wHZ+zdQtBHn1dZ/YTNMAkGA1UdEwQCMAAwGQYJKoZIhvZ9B0EABAww ChsEVjcuMQMCBLAwDQYJKoZIhvcNAQEFBQADgYEAJO9HQh4YNChVLzuZqK5ARJARD8JoujGZ fdo75quvg2jXFQe2sEjvLnxJZgm/pv8fdZakq48CWwjYHKuvIp7sDjTEsQfo+y7SpN/N2NvJ WU5SqfK1VgYtNLRRoGJUB5Q1aZ+Dg95g3kqpyfpUMISJL8IKVLtJVfN4fggFVUYZ9wwxggGr MIIBpwIBATA3MC8xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZKSFVBUEwxDzANBgNVBAsTBkJJ U0RDQQIEP/HJ/TAJBgUrDgMCGgUAoIHLMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJ KoZIhvcNAQkFMQ8XDTEyMDkyNjE0Mjk1OFowIwYJKoZIhvcNAQkEMRYEFEcAzP5UnVPMuk+D YwJMwsDYNzS0MGwGCSqGSIb3DQEJDzFfMF0wCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBAjAK BggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYI KoZIhvcNAwICASgwDQYJKoZIhvcNAQEBBQAEgYAfBuN5r3MFy9ps+PxEWtNxfD9eymkuuk6B 74uumrrsob4qbEMW+ola9EMrfENRKhFKeVWl1AF8NPnGUzyHaJ4+Fa7MvrPmD3W/NYo7Cngp 9AQkPJNAWHPqSWXpWoBh4qnB4QxR+rUs+g4Dcp91jGKqBwEhatRbyChMq0n76gBysQAAAAAA AA== --------------ms090403080908030504050400-- --===============3681841939449735748== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel --===============3681841939449735748==--