⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tpm_tis.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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};static CPUWriteMemoryFunc *tis_writefn[3]={    tis_mem_writel,    tis_mem_writel,    tis_mem_writel};/* * Save the internal state of this interface for later resumption.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -