From mboxrd@z Thu Jan 1 00:00:00 1970 From: Matthew Fioravante Subject: [PATCH 4/7] vtpm Mini-Os domain: mini-os tpm device drivers Date: Wed, 25 Aug 2010 11:18:53 -0400 Message-ID: <4C75345D.1010309@jhuapl.edu> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1764765069==" Return-path: List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: "xen-devel@lists.xensource.com" List-Id: xen-devel@lists.xenproject.org This is a cryptographically signed message in MIME format. --===============1764765069== Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha1; boundary="------------ms050001050206050301030400" This is a cryptographically signed message in MIME format. --------------ms050001050206050301030400 Content-Type: multipart/mixed; boundary="------------010402050409050407020909" This is a multi-part message in MIME format. --------------010402050409050407020909 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: quoted-printable Signed-off-by: Matthew Fioravante This patch adds tpm frontend (tpmfront) and tpm backend (tpmback) device = drivers to mini-os. While these are used by vtpm-stubdom, they could be=20 used by any mini-os domain that needs a vtpm. --------------010402050409050407020909 Content-Type: text/plain; name="4-tpmdevices-minios" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="4-tpmdevices-minios" diff -r 6615dd4045c7 -r 22a23fed2920 extras/mini-os/include/tpmback.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/include/tpmback.h Tue Jul 20 16:38:40 2010 -0400 @@ -0,0 +1,52 @@ +#include +#include +#include +#ifndef TPMBACK_H +#define TPMBACK_H + +struct tpmcmd { + domid_t domid; /* Domid of the frontend */ + unsigned long handle; /* Handle of the frontend */ + unsigned int req_len; /* Size of the command in buf - set by tpmback= driver */ + uint8_t* req; /* tpm command bits, allocated by driver, DON'T FREE = IT */ + unsigned int resp_len; /* Size of the outgoing command,=20 + you set this before passing the cmd object to tpmback_resp */ + uint8_t* resp; /* Buffer for response - YOU MUST ALLOCATE IT, YOU MU= ST ALSO FREE IT */ +}; +typedef struct tpmcmd tpmcmd_t; + +/* Initialize the tpm backend driver */ +void init_tpmback(void); +/* 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.=20 + * 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=20 + * This function will free the tpmcmd object, but you must free the resp= + * buffer yourself */ +void tpmback_resp(tpmcmd_t* tpmcmd); + +/* Waits for the first frontend to connect and then sets domid and handl= e appropriately. + * If one or more frontends are already connected, this will set domid a= nd handle to one=20 + * of them arbitrarily. The main use for this function is to wait until = a single + * frontend connection has occured. + * returns 0 on success, non-zero on failure */ +int tpmback_wait_for_frontend_connect(domid_t *domid, unsigned long *han= dle); + +/* returns the number of frontends connected */ +int tpmback_num_frontends(void); + +#endif diff -r 6615dd4045c7 -r 22a23fed2920 extras/mini-os/include/tpmfront.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/include/tpmfront.h Tue Jul 20 16:38:40 2010 -0400 @@ -0,0 +1,51 @@ +#ifndef TPMFRONT_H +#define TPMFRONT_H + +#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; + + int dmi_id; + +}; + + +/*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. Value = is undefined on error + * + * returns 0 on success, non zero on failure.=20 + * */ +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, = uint8_t** resp, size_t* resplen); + +#endif diff -r 6615dd4045c7 -r 22a23fed2920 extras/mini-os/tpmback.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/tpmback.c Tue Jul 20 16:38:40 2010 -0400 @@ -0,0 +1,1006 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_TPMBACK + +#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) " fm= t, __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; + + /* state flags */ + int flags; +}; +typedef struct tpmif tpmif_t; + +struct tpmback_dev { + + tpmif_t** tpmlist;=20 + 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; + + xenbus_event_queue events; +}; +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, +}; +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 han= dle 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(tpmif_t** list, int n, domid_t domid, unsigned int= handle) +{ + int i =3D n /2; + tpmif_t* tmp; + + if( n =3D=3D 0 ) + return -1; + + tmp =3D list[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 <=3D tmp->handle)) { + return __get_tpmif_index(list, i, domid, handle); + } else { + return i + 1 + __get_tpmif_index(list + i + 1, i -1 + (n % 2), dom= id, handle); + } +} + +/* Returns the array index of the tpmif domid/handle. Returns -1 if no s= uch tpmif exists */ +int get_tpmif_index(domid_t domid, unsigned int handle)=20 +{ + int flags; + int index; + local_irq_save(flags); + index =3D __get_tpmif_index(gtpmdev.tpmlist, 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)=20 +{ + 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)=20 +{ + 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 and t= urn off the ready flag */ + tpmdev_check_req(); + =20 + local_irq_restore(flags); + + /* Stop listening for events on this tpm interface */ + if((err =3D xenbus_unwatch_path_token(XBT_NIL, tpmif->fe_state_path, = tpmif->fe_state_path))) { + TPMBACK_ERR("Unable to unwatch path token `%s' Error was %s Ignori= ng..\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->han= dle) { + TPMBACK_ERR("Tried to insert duplicate tpm interface %u/%u\n", (unsign= ed int) tpmif->domid, (unsigned int) tpmif->handle); + goto error; + } + if((tpmif->domid < tmp->domid) ||=20 + (tpmif->domid =3D=3D tmp->domid && tpmif->handle <=3D tmp->handle))= { + 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, tp= mif->fe_state_path, >pmdev.events))) + { + /* if we got an error here we should carefully remove the interfac= e and then return */ + TPMBACK_ERR("Unable to watch path token `%s' Error was %s\n", tpmi= f->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", (unsi= gned int) tpmif->domid, (unsigned int) 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, (unsigned int) tpmif->handle); + + if((err =3D xenbus_read(XBT_NIL, path, &value))) { + TPMBACK_ERR("Unable to read backend state %s, error was %s\n", pat= h, 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 som= ething else behind our back */ + if(readst !=3D tpmif->state) { + TPMBACK_DEBUG("tpm interface state was %d but xenstore state was %= 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= , (unsigned int) 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; + 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); + } + free(tpmif); +} +/* Creates a new tpm interface, adds it to the sorted array and returns = it. + * returns NULL on error=20 + * 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); + + /* 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) dom= id, (unsigned int) handle); + if((err =3D xenbus_read(XBT_NIL, path, &tpmif->fe_path))) { + TPMBACK_ERR("Error creating new tpm instance xenbus_read(%s), Erro= r =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, (unsi= gned int) 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, (uns= igned int) tpmif->handle); + if(tpmif->flags & TPMIF_CLOSED) { + TPMBACK_ERR("Tried to free an instance twice! Theres a bug somewhe= re!\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, (unsigned int) tpmif->handle); + } + + unbind_evtchn(tpmif->evtchn); + } + tpmif->status =3D DISCONNECTED; + tpmif_change_state(tpmif, XenbusStateClosed); + + /* remove from array */ + remove_tpmif(tpmif); + + /* Wake up anyone possibly waiting on this interface and let them exi= t */ + wake_up(&waitq); + schedule(); + + /* Remove the old xenbus entries */ + snprintf(path, 512, "backend/vtpm/%u/%u", (unsigned int) tpmif->domid= , (unsigned int) 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->do= mid, (unsigned int) 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 *dat= a) +{ + 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 unm= asking */ + if(tx->size =3D=3D 0) + return; + + TPMBACK_DEBUG("EVENT CHANNEL FIRE %u/%u\n", (unsigned int) tpmif->dom= id, (unsigned int) 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 connect= ed?\n", (unsigned int) tpmif->domid, (unsigned int) 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, (unsigned int) tpmif->handle); + return -1; + } + memset(tpmif->tx, 0, PAGE_SIZE); + + /*Bind the event channel */ + if((evtchn_bind_interdomain(tpmif->domid, evtchn, tpmback_handler, tp= mif, &tpmif->evtchn))) + { + TPMBACK_ERR("%u/%u Unable to bind to interdomain event channel!\n"= , (unsigned int) tpmif->domid, (unsigned int) 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= , (unsigned int) 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, (unsigned int) tpmif->handle);=20 + 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= , (unsigned int) 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 int) = tpmif->domid, (unsigned int) 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", (unsigned int= ) tpmif->domid, (unsigned int) 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", (unsi= gned int) tpmif->domid, (unsigned int) 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 in= t* handle) +{ + int ret; + char cmd[40]; + char* err; + char* value; + unsigned int udomid =3D 0; + /* First check for new frontends, this occurs when /backend/vtpm// gets created. Note we what the sscanf to 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 the = 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 should n= ot happen */ + if(get_tpmif(*domid, *handle)) { + TPMBACK_DEBUG("Duplicate tpm entries!\n"); + return EV_NONE; + } + return EV_NEWFE; + } else if((ret =3D sscanf(evstr, "/local/domain/%u/device/vtpm/%u/%40= s", &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, (unsigned int) 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, (unsigned int) handle, evst= r); + } + 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; +} + + +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= =2Eevents)) !=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 back= end + * 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(void) +{ + 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; + + eventthread =3D create_thread("tpmback-listener", event_thread, NULL)= ; + +} + +void shutdown_tpmback(void) +{ + 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 ha= ndle)=20 +{ + tpmcmd->domid =3D domid; + tpmcmd->handle =3D handle; + 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); + + 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, &do= mid, 0, &tx->ref, PROT_READ)) =3D=3D NULL) { + TPMBACK_ERR("%u/%u Unable to map shared page during read!\n", (unsigne= d int) tpmif->domid, (unsigned int) 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, (unsigned int) 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, &do= mid, 0, &tx->ref, PROT_WRITE)) =3D=3D NULL) { + TPMBACK_ERR("%u/%u Unable to map shared page during write!\n", (unsign= ed int) tpmif->domid, (unsigned int) 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) tpm= if->domid, (unsigned int) 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 fron= tend */ + 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 can = 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 wer= e 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 can = 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, (unsigned int) tpmcmd->handle); + goto end; + } + + if(!(tpmif->flags & TPMIF_REQ_READY)) { + TPMBACK_ERR("Tried to send response to a frontend that was not wai= ting for one %u/%u\n", (unsigned int) tpmcmd->domid, (unsigned int) tpmcm= d->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 long *han= dle) +{ + tpmif_t* tpmif; + int flags; + wait_event(waitq, ((gtpmdev.num_tpms > 0) || gtpmdev.flags & TPMIF_CL= OSED)); + 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)=20 +{ + return gtpmdev.num_tpms; +} + +#endif + diff -r 6615dd4045c7 -r 22a23fed2920 extras/mini-os/tpmfront.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/tpmfront.c Tue Jul 20 16:38:40 2010 -0400 @@ -0,0 +1,470 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef NO_TPMFRONT + +//#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_ARGS_= _) +#define TPMFRONT_LOG(fmt,...) printk("Tpmfront:Info " fmt, ##__VA_ARGS__= ) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +void tpmfront_handler(evtchn_port_t port, struct pt_regs *regs, void *da= ta) { + struct tpmfront_dev* dev =3D (struct tpmfront_dev*) data; + /*If we get a response when we didnt make a request, just ignore it *= / + if(!dev->waiting) { + return; + } + + dev->waiting =3D 0; + 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", (unsi= gned int) dev->ring_ref))) { + TPMFRONT_ERR("Unable to write %s/ring-ref, error was %s\n", dev->n= odename, 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", d= ev->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* pa= th) +{ + 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* pat= h) +{ + 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, Xenb= usState 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", path, = 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", p= ath, 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->ev= tchn)) { + 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->evtchn)= ; + + /* 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", d= ev->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)); + + 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! er= ror =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! er= ror =3D %s\n", path, err); + free(err); + goto error; + } + + /* Create and publish grant reference and event channel */ + if (tpmfront_connect(dev)) { + goto error; + } + =20 + /* 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; + } + } + + /*Wait for the DMI instance number */ + snprintf(path, 512, "%s/instance", dev->bepath); + while((err =3D xenbus_read(XBT_NIL, path, &value)) !=3D NULL) { + free(err); + msleep(1000); + } + sscanf(value, "%d", &dev->dmi_id); + free(value); + + 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->nodename, err= ); + free(err); + } + + /* Wait for the backend to close and unmap shared pages, ignore an= y 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, 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) len= gth); + 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->pag= es[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; + notify_remote_via_evtchn(dev->evtchn); + return 0; +} +int tpmfront_recv(struct tpmfront_dev* dev, uint8_t** msg, size_t *lengt= h) +{ + 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); + /* 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", (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 +quit: + return 0; +} + +int tpmfront_cmd(struct tpmfront_dev* dev, uint8_t* req, size_t reqlen, = 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; +} + +#endif --------------010402050409050407020909-- --------------ms050001050206050301030400 Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" Content-Description: S/MIME Cryptographic Signature MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIHZzCC A5kwggMCoAMCAQICBD/xkcEwDQYJKoZIhvcNAQEFBQAwLzELMAkGA1UEBhMCVVMxDzANBgNV BAoTBkpIVUFQTDEPMA0GA1UECxMGQklTRENBMB4XDTA5MDcxNzE1MDgwOVoXDTEyMDcxNzE1 MzgwOVowZjELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkpIVUFQTDEPMA0GA1UECxMGUGVvcGxl MTUwFgYDVQQLEw9WUE5Hcm91cC1CSVNEQ0EwGwYDVQQDExRNYXR0aGV3IEUgRmlvcmF2YW50 ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyzeGk9zPA33fsB3uvk/Izs9GGHCpHI8b zXdBIVg6++S+jK53PoaWgmtSLr/c732ea1zPR6ACymwAWON+U5rB+VJAUZ4l/p0T3LZjE1Kq nbQJ+pgb+WAmBtdrxrtky61E9HD8dO70x37+ejhunpF9OuSU5MnOPmMx6ranvahUsOsCAwEA AaOCAYkwggGFMAsGA1UdDwQEAwIFIDAbBg0rBgEEAbMlCwMBAQEBBAoWCGZpb3JhbWUxMBsG DSsGAQQBsyULAwEBAQIEChIIMDAxMDQyNjEwWAYJYIZIAYb6ax4BBEsMSVRoZSBwcml2YXRl IGtleSBjb3JyZXNwb25kaW5nIHRvIHRoaXMgY2VydGlmaWNhdGUgbWF5IGhhdmUgYmVlbiBl eHBvcnRlZC4wKAYDVR0RBCEwH4EdTWF0dGhldy5GaW9yYXZhbnRlQGpodWFwbC5lZHUwUgYD VR0fBEswSTBHoEWgQ6RBMD8xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZKSFVBUEwxDzANBgNV BAsTBkJJU0RDQTEOMAwGA1UEAxMFQ1JMNDkwHwYDVR0jBBgwFoAUCDUpmxH52EU2CyWmF2EJ MB1yqeswHQYDVR0OBBYEFO3ziReJlElP3ilaLQ5gwsg0RlgoMAkGA1UdEwQCMAAwGQYJKoZI hvZ9B0EABAwwChsEVjcuMQMCBLAwDQYJKoZIhvcNAQEFBQADgYEAMOY3Zf6gx3gv/fDd11cz h2Daj+8NExx/2Le3c88gfDVhPVgVX5S52EjeFbK5yVP0Xlm82vRADO47dTA2PKbpp50rJcAZ rl5bg5tQ/WbLAaRITCtOJWVVKXD9V7X2o3Z/IM2op3hb4mmDXSDS+Hzn0Jd2mAXl4iHPfI0p XlXqA9QwggPGMIIDL6ADAgECAgQ/8cn9MA0GCSqGSIb3DQEBBQUAMC8xCzAJBgNVBAYTAlVT MQ8wDQYDVQQKEwZKSFVBUEwxDzANBgNVBAsTBkJJU0RDQTAeFw0xMDA2MTExODIyMDZaFw0x MzA2MTExODUyMDZaMGYxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZKSFVBUEwxDzANBgNVBAsT BlBlb3BsZTE1MBYGA1UECxMPVlBOR3JvdXAtQklTRENBMBsGA1UEAxMUTWF0dGhldyBFIEZp b3JhdmFudGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ6W8FUj+qNTW+ZXFu3Xd8k6 PYgSXYu6s+JwDTjBTyuyTsuZ6SjdYoqLrJdvFP7HFCREueYD8AFmCSt7lckALAOGnYAyouQ6 A9VBw0BMKW2O4hyyXqtDT6+AamDapwhT2xOhwvM0ia6+Kip/oFVEE9/UiBanYiDycGS/BWE0 UP87AgMBAAGjggG2MIIBsjALBgNVHQ8EBAMCB4AwKwYDVR0QBCQwIoAPMjAxMDA2MTExODIy MDZagQ8yMDEyMDcxNzIyNTIwNlowGwYNKwYBBAGzJQsDAQEBAQQKFghmaW9yYW1lMTAbBg0r BgEEAbMlCwMBAQECBAoSCDAwMTA0MjYxMFgGCWCGSAGG+mseAQRLDElUaGUgcHJpdmF0ZSBr ZXkgY29ycmVzcG9uZGluZyB0byB0aGlzIGNlcnRpZmljYXRlIG1heSBoYXZlIGJlZW4gZXhw b3J0ZWQuMCgGA1UdEQQhMB+BHU1hdHRoZXcuRmlvcmF2YW50ZUBqaHVhcGwuZWR1MFIGA1Ud HwRLMEkwR6BFoEOkQTA/MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGSkhVQVBMMQ8wDQYDVQQL EwZCSVNEQ0ExDjAMBgNVBAMTBUNSTDU2MB8GA1UdIwQYMBaAFAg1KZsR+dhFNgslphdhCTAd cqnrMB0GA1UdDgQWBBTui2MYOq/cB2fs3ULQR59XWf2EzTAJBgNVHRMEAjAAMBkGCSqGSIb2 fQdBAAQMMAobBFY3LjEDAgSwMA0GCSqGSIb3DQEBBQUAA4GBACTvR0IeGDQoVS87maiuQESQ EQ/CaLoxmX3aO+arr4No1xUHtrBI7y58SWYJv6b/H3WWpKuPAlsI2ByrryKe7A40xLEH6Psu 0qTfzdjbyVlOUqnytVYGLTS0UaBiVAeUNWmfg4PeYN5Kqcn6VDCEiS/CClS7SVXzeH4IBVVG GfcMMYICMTCCAi0CAQEwNzAvMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGSkhVQVBMMQ8wDQYD VQQLEwZCSVNEQ0ECBD/xyf0wCQYFKw4DAhoFAKCCAVAwGAYJKoZIhvcNAQkDMQsGCSqGSIb3 DQEHATAcBgkqhkiG9w0BCQUxDxcNMTAwODI1MTUxODUzWjAjBgkqhkiG9w0BCQQxFgQUQOUh IJkbT48VL/FiaJrbiGMNW8YwRgYJKwYBBAGCNxAEMTkwNzAvMQswCQYDVQQGEwJVUzEPMA0G A1UEChMGSkhVQVBMMQ8wDQYDVQQLEwZCSVNEQ0ECBD/xkcEwSAYLKoZIhvcNAQkQAgsxOaA3 MC8xCzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZKSFVBUEwxDzANBgNVBAsTBkJJU0RDQQIEP/GR wTBfBgkqhkiG9w0BCQ8xUjBQMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0D AgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZIhvcN AQEBBQAEgYBzgkV5uTUN+7rfH/PJ6UXwF2tn9IabTFdBrSmcBA2pxBphZtXlvLbC2XVdu8i5 O8bmUpkLNhnQLE29Rg5sUpadFC9XrhSaBfO1o1qXXq5ICpH35/J7Pmw9AgIN4j0djjhbyAFk 11fQ1KVfbm3AU9wErLmRFw3kE+24TKfGsqyT1gAAAAAAAA== --------------ms050001050206050301030400-- --===============1764765069== 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.xensource.com http://lists.xensource.com/xen-devel --===============1764765069==--