📄 tpm_tis.c
字号:
* Need to get any outstanding responses from the vTPM back, so * this might delay the suspend for a while. */static void tpm_save(QEMUFile* f,void* opaque){ tpmState* s=(tpmState*)opaque; uint8_t locty = s->active_loc; int c; /* need to wait for outstanding requests to complete */ if (s->loc[locty].state == STATE_EXECUTION) { int repeats = 30; /* 30 seconds; really should be infty */ while (repeats > 0 && !(s->loc[s->active_loc].sts & STS_DATA_AVAILABLE)) { int n = TPM_Receive(s, &s->buffer); if (n > 0) { if (IS_VALID_LOC(s->active_loc)) { s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE; s->loc[s->active_loc].state = STATE_COMPLETION; tis_raise_irq(s, s->active_loc, INT_DATA_AVAILABLE); } /* close the connection with the vTPM for good */ close_vtpm_channel(s, 1); break; } sleep(1); } } if (IS_COMM_WITH_VTPM(s)) { close_vtpm_channel(s, 1); } qemu_put_be32s(f,&s->offset); qemu_put_buffer(f, s->buffer.buf, TPM_MAX_PKT); qemu_put_8s(f, &s->active_loc); qemu_put_8s(f, &s->irq_pending); for (c = 0; c < NUM_LOCALITIES; c++) { qemu_put_be32s(f, &s->loc[c].state); qemu_put_8s(f, &s->loc[c].access); qemu_put_8s(f, &s->loc[c].sts); qemu_put_be32s(f, &s->loc[c].inte); qemu_put_be32s(f, &s->loc[c].ints); }}/* * load TIS interface state */static int tpm_load(QEMUFile* f,void* opaque,int version_id){ tpmState* s=(tpmState*)opaque; int c; if (version_id != 1) return -EINVAL; qemu_get_be32s(f,&s->offset); qemu_get_buffer(f, s->buffer.buf, TPM_MAX_PKT); qemu_get_8s(f, &s->active_loc); qemu_get_8s(f, &s->irq_pending); for (c = 0; c < NUM_LOCALITIES; c++) { qemu_get_be32s(f, &s->loc[c].state); qemu_get_8s(f, &s->loc[c].access); qemu_get_8s(f, &s->loc[c].sts); qemu_get_be32s(f, &s->loc[c].inte); qemu_get_be32s(f, &s->loc[c].ints); } /* need to be able to get the instance number from the xenstore */ s->vtpm_instance = vtpm_instance_from_xenstore(); if (s->vtpm_instance == VTPM_BAD_INSTANCE) return -EINVAL; tpm_initialize_instance(s, s->vtpm_instance); return 0;}typedef struct LPCtpmState { tpmState tpm; int mem;} LPCtpmState;/* * initialize TIS interface */void tpm_tis_init(SetIRQFunc *set_irq, void *opaque, int irq){ LPCtpmState *d; tpmState *s; int c = 0; uint32_t vtpm_in; vtpm_in = vtpm_instance_from_xenstore(); /* no valid vtpm instance -> no device */ if (vtpm_in == VTPM_BAD_INSTANCE) return; d = qemu_mallocz(sizeof(LPCtpmState)); d->mem = cpu_register_io_memory(0, tis_readfn, tis_writefn, d); if (d->mem == -1) { return; } cpu_register_physical_memory(TIS_ADDR_BASE, 0x1000 * NUM_LOCALITIES, d->mem); /* initialize tpmState */ s = &d->tpm; s->offset = 0; s->active_loc = NO_LOCALITY; while (c < NUM_LOCALITIES) { s->loc[c].access = (1 << 7); s->loc[c].sts = 0; s->loc[c].inte = (1 << 3); s->loc[c].ints = 0; s->loc[c].state = STATE_IDLE; c++; } s->poll_timer = qemu_new_timer(vm_clock, tis_poll_timer, s); s->set_irq = set_irq; s->irq_opaque = opaque; s->irq = irq; s->vtpm_instance = vtpm_in; s->Transmitlayer = -1; s->tpmTx.fd[0] = -1; s->tpmTx.fd[1] = -1; s->aborting_locty = NO_LOCALITY; tpm_initialize_instance(s, s->vtpm_instance); memset(s->buffer.buf,0,sizeof(s->buffer.buf)); register_savevm("tpm-tis", 0, 1, tpm_save, tpm_load, s); open_vtpm_channel(s); for (c = 0; !IS_COMM_WITH_VTPM(s) && (c < 5); c++) { sleep(1); open_vtpm_channel(s); }}/****************************************************************************//* optional verbose logging of data to/from vtpm *//****************************************************************************/#ifdef DEBUG_TPMstatic void showBuff(unsigned char *buff, char *string){ uint32_t i, len; len = tpm_get_size_from_buffer(buff); fprintf(logfile,"%s length = %d\n", string, len); for (i = 0; i < len; i++) { if (i && !(i % 16)) { fprintf(logfile,"\n"); } fprintf(logfile,"%.2X ", buff[i]); } fprintf(logfile,"\n");}#endif/****************************************************************************//* Transmit request to TPM and read Response *//****************************************************************************/const static unsigned char tpm_failure[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09};/* * Send a TPM request. */static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg){ int len; uint32_t size = tpm_get_size_from_buffer(buffer->buf); /* try to establish a connection to the vTPM */ if ( !IS_COMM_WITH_VTPM(s)) { open_vtpm_channel(s); } if ( !IS_COMM_WITH_VTPM(s)) { unsigned char tag = buffer->buf[1]; /* there's a failure response from the TPM */ memcpy(buffer->buf, tpm_failure, sizeof(tpm_failure)); buffer->buf[1] = tag + 3; if (IS_VALID_LOC(s->active_loc)) { s->loc[s->active_loc].sts = STS_DATA_AVAILABLE | STS_VALID; }#ifdef DEBUG_TPM fprintf(logfile,"No TPM running!\n");#endif /* the request went out ok. */ return sizeof(buffer->instance) + size; }#ifdef DEBUG_TPM showBuff(buffer->buf, "To TPM");#endif /* transmit the locality in the highest 3 bits */ buffer->instance[0] &= 0x1f; buffer->instance[0] |= (locty << 5); len = vTPMTransmit[s->Transmitlayer].write_fn(s, buffer); if (len < 0) { s->Transmitlayer = -1; } return len;}/* * Try to receive data from the file descriptor. Since it is in * non-blocking mode it is possible that no data are actually received - * whatever calls this function needs to try again later. */static int TPM_Receive(tpmState *s, tpmBuffer *buffer){ int off; off = vTPMTransmit[s->Transmitlayer].read_fn(s, buffer); if (off < 0) { /* EAGAIN is set in errno due to non-blocking mode */ return -1; } if (off == 0) {#ifdef DEBUG_TPM fprintf(logfile,"TPM GONE? errno=%d\n",errno);#endif close_vtpm_channel(s, 1); /* pretend that data are available */ if (IS_VALID_LOC(s->active_loc)) { s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE; s->loc[s->active_loc].state = STATE_COMPLETION; tis_raise_irq(s, s->active_loc, INT_DATA_AVAILABLE); } return -1; }#ifdef DEBUG_TPM if (off > sizeof(buffer->instance ) + 6) { uint32_t size = tpm_get_size_from_buffer(buffer->buf); if (size + sizeof(buffer->instance) != off) { fprintf(logfile,"TPM: Packet size is bad! %d != %d\n", (int)(size + sizeof(buffer->instance)), off); } else { uint32_t ret; showBuff(buffer->buf, "From TPM"); ret = (buffer->buf[8])*256 + buffer->buf[9]; if (ret) fprintf(logfile,"Receive failed with error %d\n", ret); else fprintf(logfile,"Receive succeeded. Got response of length %d (=%d)\n", size, off); } }#endif /* assuming reading in one chunk for now */ return off;}/**************************************************************************** Helper functions for reading data from the xenstore such as reading virtual TPM instance information ****************************************************************************/int has_tpm_device(void){ int ret = 0; struct xs_handle *handle = xs_daemon_open(); if (handle) { ret = xenstore_domain_has_devtype(handle, "vtpm"); xs_daemon_close(handle); } return ret;}/* * Wait until hotplug scripts have finished then read the vTPM instance * number from the xenstore. */static uint32_t vtpm_instance_from_xenstore(void){ unsigned int num; uint32_t number = VTPM_BAD_INSTANCE; int end = 0; char *token = "tok"; int subscribed = 0; int ctr = 0; fd_set readfds; struct xs_handle *handle = xs_daemon_open(); FD_ZERO(&readfds); if (handle) { char **e = xenstore_domain_get_devices(handle, "vtpm", &num); int fd = xs_fileno(handle); FD_SET(fd, &readfds); if (e) { do { struct timeval tv = { .tv_sec = 30, .tv_usec = 0, }; /* need to make sure that the hotplug scripts have finished */ char *status = xenstore_read_hotplug_status(handle, "vtpm", e[0]); if (status) { if (!strcmp(status, "connected")) { char *inst = xenstore_backend_read_variable(handle, "vtpm", e[0], "instance"); if (1 != (sscanf(inst,"%d",&number))) number = VTPM_BAD_INSTANCE; free(inst); } else { fprintf(logfile, "bad status '%s' from vtpm hotplug\n", status); } free(status); end = 1; } else { /* no status, yet */ int rc; unsigned int nr; char **f; if (!subscribed) { rc = xenstore_subscribe_to_hotplug_status(handle, "vtpm", e[0], token); if (rc != 0) break; subscribed = 1; } rc = select(fd+1, &readfds, NULL, NULL, &tv); /* get what's available -- drain the fd */ f = xs_read_watch(handle, &nr); ctr++; free(f); if (ctr > 2) end = 1; } } while (end == 0); free(e); } if (subscribed) { /* clean up */ xenstore_unsubscribe_from_hotplug_status(handle, "vtpm", e[0], token); } xs_daemon_close(handle); } if (number == VTPM_BAD_INSTANCE) fprintf(logfile, "no valid vtpm instance"); else fprintf(logfile,"vtpm instance:%d\n",number); return number;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -