?? tpm-tis-device
字號:
+ */+static uint32_t tpm_data_read(tpmState *s, uint8_t locty)+{+ uint32_t ret, len;++ /* try to receive data, if none are there it is ok */+ tis_attempt_receive(s, locty);++ if (s->loc[locty].state != STATE_COMPLETION) {+ return 0xff;+ }++ len = tpm_get_size_from_buffer(s->buffer.buf);+ ret = s->buffer.buf[s->offset++];+ if (s->offset >= len) {+ s->loc[locty].sts = STS_VALID ;+ s->offset = 0;+ }+#ifdef DEBUG_TPM+ fprintf(logfile,"tpm_data_read byte x%02x [%d]\n",ret,s->offset-1);+#endif+ return ret;+}++++/* raise an interrupt if allowed */+static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask)+{+ if (!s->irq_pending &&+ (s->loc[locty].inte & INT_ENABLED) &&+ (s->loc[locty].inte & irqmask)) {+ if ((irqmask & s->loc[locty].ints) == 0) {+#ifdef DEBUG_TPM+ fprintf(logfile,"Raising IRQ for flag %08x\n",irqmask);+#endif+ s->set_irq(s->irq_opaque, s->irq, 1);+ s->irq_pending = 1;+ s->loc[locty].ints |= irqmask;+ }+ }+}++/* abort execution of command */+static void tis_abort(tpmState *s)+{+ s->offset = 0;+ s->active_loc = s->next_locty;++ /*+ * Need to react differently depending on who's aborting now and+ * which locality will become active afterwards.+ */+ if (s->aborting_locty == s->next_locty) {+ s->loc[s->aborting_locty].state = STATE_READY;+ s->loc[s->aborting_locty].sts = STS_COMMAND_READY;+ tis_raise_irq(s, s->aborting_locty, INT_COMMAND_READY);+ }++ /* locality after abort is another one than the current one */+ if (s->aborting_locty != s->next_locty && s->next_locty != NO_LOCALITY) {+ s->loc[s->aborting_locty].access &= ~ACCESS_ACTIVE_LOCALITY;+ s->loc[s->next_locty].access |= ACCESS_ACTIVE_LOCALITY;+ tis_raise_irq(s, s->next_locty, INT_LOCALITY_CHANGED);+ }++ s->aborting_locty = NO_LOCALITY; /* nobody's aborting a command anymore */++ qemu_del_timer(s->poll_timer);+}++/* abort current command */+static void tis_prep_abort(tpmState *s, uint8_t locty, uint8_t newlocty)+{+ s->aborting_locty = locty; /* current locality */+ s->next_locty = newlocty; /* locality after successful abort */++ /*+ * only abort a command using an interrupt if currently executing+ * a command AND if there's a valid connection to the vTPM.+ */+ if (s->loc[locty].state == STATE_EXECUTION &&+ IS_COMM_WITH_VTPM(s)) {+ /* start timer and inside the timer wait for the result */+ s->poll_attempts = 0;+ tis_prep_next_interrupt(s);+ } else {+ tis_abort(s);+ }+}+++/*+ * Try to receive a response from the vTPM+ */+static void tis_attempt_receive(tpmState *s, uint8_t locty)+{+ /*+ * Attempt to read from the vTPM here if+ * - not aborting a command+ * - command has been sent and state is 'EXECUTION' now+ * - no data are already available (data have already been read)+ * - there's a communication path to the vTPM established+ */+ if (!IS_VALID_LOC(s->aborting_locty)) {+ if (s->loc[locty].state == STATE_EXECUTION) {+ if (0 == (s->loc[locty].sts & STS_DATA_AVAILABLE)){+ if (IS_COMM_WITH_VTPM(s)) {+ int n = TPM_Receive(s, &s->buffer);+ if (n > 0) {+ s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE;+ s->loc[locty].state = STATE_COMPLETION;+ close_vtpm_channel(s, FORCE_CLOSE);+ tis_raise_irq(s, locty, INT_DATA_AVAILABLE);+ }+ }+ }+ }+ }+}++/*+ * Read a register of the TIS interface+ * See specs pages 33-63 for description of the registers+ */+static uint32_t tis_mem_readl(void *opaque, target_phys_addr_t addr)+{+ tpmState *s = (tpmState *)opaque;+ uint16_t offset = addr & 0xffc;+ uint8_t shift = (addr & 0x3) * 8;+ uint32_t val = 0;+ uint8_t locty = locality_from_addr(addr);++ if (offset == TPM_REG_ACCESS) {+ if (s->active_loc == locty) {+ s->loc[locty].access |= (1 << 5);+ } else {+ s->loc[locty].access &= ~(1 << 5);+ }+ val = s->loc[locty].access;+ } else+ if (offset == TPM_REG_INT_ENABLE) {+ val = s->loc[locty].inte;+ } else+ if (offset == TPM_REG_INT_VECTOR) {+ val = s->irq;+ } else+ if (offset == TPM_REG_INT_STATUS) {+ tis_attempt_receive(s, locty);+ val = s->loc[locty].ints;+ } else+ if (offset == TPM_REG_INTF_CAPABILITY) {+ val = CAPABILITIES_SUPPORTED;+ } else+ if (offset == TPM_REG_STS) { /* status register */+ tis_attempt_receive(s, locty);+ val = (sizeof(s->buffer.buf) - s->offset) << 8 | s->loc[locty].sts;+ } else+ if (offset == TPM_REG_DATA_FIFO) {+ val = tpm_data_read(s, locty);+ } else+ if (offset == TPM_REG_DID_VID) {+ val = (TPM_DID << 16) | TPM_VID;+ } else+ if (offset == TPM_REG_RID) {+ val = TPM_RID;+ }++ if (shift)+ val >>= shift;++#ifdef DEBUG_TPM+ fprintf(logfile," read(%08x) = %08x\n",+ (int)addr,+ val);+#endif++ return val;+}++/*+ * Write a value to a register of the TIS interface+ * See specs pages 33-63 for description of the registers+ */+static void tis_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)+{+ tpmState* s=(tpmState*)opaque;+ uint16_t off = addr & 0xfff;+ uint8_t locty = locality_from_addr(addr);+ int n, c;+ uint32_t len;++#ifdef DEBUG_TPM+ fprintf(logfile,"write(%08x) = %08x\n",+ (int)addr,+ val);+#endif++ if (off == TPM_REG_ACCESS) {+ if (val & ACCESS_ACTIVE_LOCALITY) {+ /* give up locality if currently owned */+ if (s->active_loc == locty) {+ uint8_t newlocty = NO_LOCALITY;+ s->loc[locty].access &= ~(ACCESS_PENDING_REQUEST);+ /* anybody wants the locality ? */+ for (c = NUM_LOCALITIES - 1; c >= 0; c--) {+ if (s->loc[c].access & ACCESS_REQUEST_USE) {+ s->loc[c].access |= ACCESS_TPM_REG_VALID_STS;+ s->loc[c].access &= ~ACCESS_REQUEST_USE;+ newlocty = c;+ break;+ }+ }+ tis_prep_abort(s, locty, newlocty);+ }+ }+ if (val & ACCESS_BEEN_SEIZED) {+ /* clear the flag */+ s->loc[locty].access &= ~ACCESS_BEEN_SEIZED;+ }+ if (val & ACCESS_SEIZE) {+ if (locty > s->active_loc && IS_VALID_LOC(s->active_loc)) {+ s->loc[s->active_loc].access |= ACCESS_BEEN_SEIZED;+ s->loc[locty].access = ACCESS_TPM_REG_VALID_STS;+ tis_prep_abort(s, s->active_loc, locty);+ }+ }+ if (val & ACCESS_REQUEST_USE) {+ if (IS_VALID_LOC(s->active_loc)) {+ /* locality election */+ s->loc[s->active_loc].access |= ACCESS_PENDING_REQUEST;+ } else {+ /* no locality active -> make this one active now */+ s->loc[locty].access |= ACCESS_ACTIVE_LOCALITY;+ s->active_loc = locty;+ tis_raise_irq(s, locty, INT_LOCALITY_CHANGED);+ }+ }+ } else+ if (off == TPM_REG_INT_ENABLE) {+ s->loc[locty].inte = (val & (INT_ENABLED | (0x3 << 3) |+ INTERRUPTS_SUPPORTED));+ } else+ if (off == TPM_REG_INT_STATUS) {+ /* clearing of interrupt flags */+ if ((val & INTERRUPTS_SUPPORTED) &&+ (s->loc[locty].ints & INTERRUPTS_SUPPORTED)) {+ s->set_irq(s->irq_opaque, s->irq, 0);+ s->irq_pending = 0;+ }+ s->loc[locty].ints &= ~(val & INTERRUPTS_SUPPORTED);+ } else+ if (off == TPM_REG_STS) {+ if (val & STS_COMMAND_READY) {+ if (s->loc[locty].state == STATE_IDLE) {+ s->loc[locty].sts = STS_COMMAND_READY;+ s->loc[locty].state = STATE_READY;+ tis_raise_irq(s, locty, INT_COMMAND_READY);+ } else if (s->loc[locty].state == STATE_COMPLETION ||+ s->loc[locty].state == STATE_EXECUTION ||+ s->loc[locty].state == STATE_RECEPTION) {+ /* abort currently running command */+ tis_prep_abort(s, locty, locty);+ }+ }+ if (val & STS_TPM_GO) {+ n = TPM_Send(s, &s->buffer, locty, "tpm_data_write");+ if (n > 0) {+ /* sending of data was successful */+ s->offset = 0;+ s->loc[locty].state = STATE_EXECUTION;+ if (s->loc[locty].inte & (INT_ENABLED | INT_DATA_AVAILABLE)) {+ s->poll_attempts = 0;+ tis_prep_next_interrupt(s);+ }+ }+ }+ if (val & STS_RESPONSE_RETRY) {+ s->offset = 0;+ }+ } else if (off == TPM_REG_DATA_FIFO) {+ /* data fifo */+ if (s->loc[locty].state == STATE_IDLE ||+ s->loc[locty].state == STATE_EXECUTION ||+ s->loc[locty].state == STATE_COMPLETION) {+ /* drop the byte */+ } else {+#ifdef TPM_DEBUG+ fprintf(logfile,"Byte to send to TPM: %02x\n", val);+#endif+ s->loc[locty].state = STATE_RECEPTION;++ if (s->offset < sizeof(s->buffer.buf))+ s->buffer.buf[s->offset++] = (uint8_t)val;++ if (s->offset > 5) {+ /* we have a packet length - see if we have all of it */+ len = tpm_get_size_from_buffer(s->buffer.buf);+ if (len > s->offset) {+ s->loc[locty].sts = STS_EXPECT | STS_VALID;+ } else {+ s->loc[locty].sts = STS_VALID;+ }+ }+ }+ }+}++/*+ * Prepare the next interrupt for example after a command has+ * been sent out for the purpose of receiving the response.+ * Depending on how many interrupts (used for polling on the fd) have+ * already been schedule, this function determines the delta in time+ * to the next interrupt. This accomodates for commands that finish+ * quickly.+ */+static void tis_prep_next_interrupt(tpmState *s)+{+ int64_t expiration;+ int rate = 5; /* 5 times per second */++ /*+ poll often at the beginning for quickly finished commands,+ then back off+ */+ if (s->poll_attempts < 5) {+ rate = 20;+ } else if (s->poll_attempts < 10) {+ rate = 10;+ }++ expiration = qemu_get_clock(vm_clock) + (ticks_per_sec / rate);+ qemu_mod_timer(s->poll_timer, expiration);+ s->poll_attempts++;+}+++/*+ * The polling routine called when the 'timer interrupt' fires.+ * Tries to receive a command from the vTPM.+ */+static void tis_poll_timer(void *opaque)+{+ tpmState* s=(tpmState*)opaque;+ uint8_t locty = s->active_loc;++ if (!IS_VALID_LOC(locty) ||+ (!(s->loc[locty].inte & INT_ENABLED) &&+ (s->aborting_locty != NO_LOCALITY)) ||+ !IS_COMM_WITH_VTPM(s)) {+ /* no more interrupts requested, so no more polling needed */+ qemu_del_timer(s->poll_timer);+ }++ if (!IS_COMM_WITH_VTPM(s)) {+ if (s->aborting_locty != NO_LOCALITY) {+ tis_abort(s);+ }+ return;+ }++ if (s->aborting_locty != NO_LOCALITY) {+ int n = TPM_Receive(s, &s->buffer);+#ifdef DEBUG_TPM+ fprintf(logfile,"Receiving for abort.\n");+#endif+ if (n > 0) {+ close_vtpm_channel(s, FORCE_CLOSE);+ tis_abort(s);+#ifdef DEBUG_TPM+ fprintf(logfile,"Abort is complete.\n");+#endif+ } else {+ tis_prep_next_interrupt(s);+ }+ } else if (IS_VALID_LOC(locty)) {+ if (s->loc[locty].state == STATE_EXECUTION) {+ /* poll for result */+ int n = TPM_Receive(s, &s->buffer);+ if (n > 0) {+ s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE;+ s->loc[locty].state = STATE_COMPLETION;+ close_vtpm_channel(s, FORCE_CLOSE);+ tis_raise_irq(s, locty, INT_DATA_AVAILABLE);+ } else {+ /* nothing received */+ tis_prep_next_interrupt(s);+ }+ }+ }+}+++static CPUReadMemoryFunc *tis_readfn[3]={+ tis_mem_readl,+ tis_mem_readl,+ tis_mem_readl+};+
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -