static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,

                                      uint64_t val, unsigned size,

                                      bool hw_access)

{

    TPMState *s = opaque;

    TPMTISEmuState *tis = &s->s.tis;

    uint16_t off = addr & 0xffc;

    uint8_t shift = (addr & 0x3) * 8;

    uint8_t locty = tpm_tis_locality_from_addr(addr);

    uint8_t active_locty, l;

    int c, set_new_locty = 1;

    uint16_t len;

    uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);



    DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);



    if (locty == 4 && !hw_access) {

        DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");

        return;

    }



    if (tpm_backend_had_startup_error(s->be_driver)) {

        return;

    }



    val &= mask;



    if (shift) {

        val <<= shift;

        mask <<= shift;

    }



    mask ^= 0xffffffff;



    switch (off) {

    case TPM_TIS_REG_ACCESS:



        if ((val & TPM_TIS_ACCESS_SEIZE)) {

            val &= ~(TPM_TIS_ACCESS_REQUEST_USE |

                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);

        }



        active_locty = tis->active_locty;



        if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {

            /* give up locality if currently owned */

            if (tis->active_locty == locty) {

                DPRINTF("tpm_tis: Releasing locality %d\n", locty);



                uint8_t newlocty = TPM_TIS_NO_LOCALITY;

                /* anybody wants the locality ? */

                for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {

                    if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {

                        DPRINTF("tpm_tis: Locality %d requests use.\n", c);

                        newlocty = c;

                        break;

                    }

                }

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "

                        "Next active locality: %d\n",

                        newlocty);



                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {

                    set_new_locty = 0;

                    tpm_tis_prep_abort(s, locty, newlocty);

                } else {

                    active_locty = TPM_TIS_NO_LOCALITY;

                }

            } else {

                /* not currently the owner; clear a pending request */

                tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;

            }

        }



        if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {

            tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;

        }



        if ((val & TPM_TIS_ACCESS_SEIZE)) {

            /*

             * allow seize if a locality is active and the requesting

             * locality is higher than the one that's active

             * OR

             * allow seize for requesting locality if no locality is

             * active

             */

            while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&

                    locty > tis->active_locty) ||

                    !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {

                bool higher_seize = FALSE;



                /* already a pending SEIZE ? */

                if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {

                    break;

                }



                /* check for ongoing seize by a higher locality */

                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {

                    if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {

                        higher_seize = TRUE;

                        break;

                    }

                }



                if (higher_seize) {

                    break;

                }



                /* cancel any seize by a lower locality */

                for (l = 0; l < locty - 1; l++) {

                    tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;

                }



                tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "

                        "Locality %d seized from locality %d\n",

                        locty, tis->active_locty);

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");

                set_new_locty = 0;

                tpm_tis_prep_abort(s, tis->active_locty, locty);

                break;

            }

        }



        if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {

            if (tis->active_locty != locty) {

                if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {

                    tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;

                } else {

                    /* no locality active -> make this one active now */

                    active_locty = locty;

                }

            }

        }



        if (set_new_locty) {

            tpm_tis_new_active_locality(s, active_locty);

        }



        break;

    case TPM_TIS_REG_INT_ENABLE:

        if (tis->active_locty != locty) {

            break;

        }



        tis->loc[locty].inte &= mask;

        tis->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |

                                        TPM_TIS_INT_POLARITY_MASK |

                                        TPM_TIS_INTERRUPTS_SUPPORTED));

        break;

    case TPM_TIS_REG_INT_VECTOR:

        /* hard wired -- ignore */

        break;

    case TPM_TIS_REG_INT_STATUS:

        if (tis->active_locty != locty) {

            break;

        }



        /* clearing of interrupt flags */

        if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&

            (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {

            tis->loc[locty].ints &= ~val;

            if (tis->loc[locty].ints == 0) {

                qemu_irq_lower(tis->irq);

                DPRINTF("tpm_tis: Lowering IRQ\n");

            }

        }

        tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);

        break;

    case TPM_TIS_REG_STS:

        if (tis->active_locty != locty) {

            break;

        }



        val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |

                TPM_TIS_STS_RESPONSE_RETRY);



        if (val == TPM_TIS_STS_COMMAND_READY) {

            switch (tis->loc[locty].state) {



            case TPM_TIS_STATE_READY:

                tis->loc[locty].w_offset = 0;

                tis->loc[locty].r_offset = 0;

            break;



            case TPM_TIS_STATE_IDLE:

                tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;

                tis->loc[locty].state = TPM_TIS_STATE_READY;

                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);

            break;



            case TPM_TIS_STATE_EXECUTION:

            case TPM_TIS_STATE_RECEPTION:

                /* abort currently running command */

                DPRINTF("tpm_tis: %s: Initiating abort.\n",

                        __func__);

                tpm_tis_prep_abort(s, locty, locty);

            break;



            case TPM_TIS_STATE_COMPLETION:

                tis->loc[locty].w_offset = 0;

                tis->loc[locty].r_offset = 0;

                /* shortcut to ready state with C/R set */

                tis->loc[locty].state = TPM_TIS_STATE_READY;

                if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {

                    tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;

                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);

                }

                tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);

            break;



            }

        } else if (val == TPM_TIS_STS_TPM_GO) {

            switch (tis->loc[locty].state) {

            case TPM_TIS_STATE_RECEPTION:

                if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {

                    tpm_tis_tpm_send(s, locty);

                }

                break;

            default:

                /* ignore */

                break;

            }

        } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {

            switch (tis->loc[locty].state) {

            case TPM_TIS_STATE_COMPLETION:

                tis->loc[locty].r_offset = 0;

                tis->loc[locty].sts = TPM_TIS_STS_VALID |

                                      TPM_TIS_STS_DATA_AVAILABLE;

                break;

            default:

                /* ignore */

                break;

            }

        }

        break;

    case TPM_TIS_REG_DATA_FIFO:

    case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:

        /* data fifo */

        if (tis->active_locty != locty) {

            break;

        }



        if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||

            tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||

            tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {

            /* drop the byte */

        } else {

            DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",

                    val, size);

            if (tis->loc[locty].state == TPM_TIS_STATE_READY) {

                tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;

                tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;

            }



            val >>= shift;

            if (size > 4 - (addr & 0x3)) {

                /* prevent access beyond FIFO */

                size = 4 - (addr & 0x3);

            }



            while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {

                if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {

                    tis->loc[locty].w_buffer.

                        buffer[tis->loc[locty].w_offset++] = (uint8_t)val;

                    val >>= 8;

                    size--;

                } else {

                    tis->loc[locty].sts = TPM_TIS_STS_VALID;

                }

            }



            /* check for complete packet */

            if (tis->loc[locty].w_offset > 5 &&

                (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {

                /* we have a packet length - see if we have all of it */

#ifdef RAISE_STS_IRQ

                bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);

#endif

                len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);

                if (len > tis->loc[locty].w_offset) {

                    tis->loc[locty].sts = TPM_TIS_STS_EXPECT |

                                          TPM_TIS_STS_VALID;

                } else {

                    /* packet complete */

                    tis->loc[locty].sts = TPM_TIS_STS_VALID;

                }

#ifdef RAISE_STS_IRQ

                if (needIrq) {

                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);

                }

#endif

            }

        }

        break;

    }

}

static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,

                                      uint64_t val, unsigned size,

                                      bool hw_access)

{

    TPMState *s = opaque;

    TPMTISEmuState *tis = &s->s.tis;

    uint16_t off = addr & 0xffc;

    uint8_t shift = (addr & 0x3) * 8;

    uint8_t locty = tpm_tis_locality_from_addr(addr);

    uint8_t active_locty, l;

    int c, set_new_locty = 1;

    uint16_t len;

    uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);



    DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);



    if (locty == 4 && !hw_access) {

        DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");

        return;

    }



    if (tpm_backend_had_startup_error(s->be_driver)) {

        return;

    }



    val &= mask;



    if (shift) {

        val <<= shift;

        mask <<= shift;

    }



    mask ^= 0xffffffff;



    switch (off) {

    case TPM_TIS_REG_ACCESS:



        if ((val & TPM_TIS_ACCESS_SEIZE)) {

            val &= ~(TPM_TIS_ACCESS_REQUEST_USE |

                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);

        }



        active_locty = tis->active_locty;



        if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {

            

            if (tis->active_locty == locty) {

                DPRINTF("tpm_tis: Releasing locality %d\n", locty);



                uint8_t newlocty = TPM_TIS_NO_LOCALITY;

                

                for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {

                    if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {

                        DPRINTF("tpm_tis: Locality %d requests use.\n", c);

                        newlocty = c;

                        break;

                    }

                }

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "

                        "Next active locality: %d\n",

                        newlocty);



                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {

                    set_new_locty = 0;

                    tpm_tis_prep_abort(s, locty, newlocty);

                } else {

                    active_locty = TPM_TIS_NO_LOCALITY;

                }

            } else {

                

                tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;

            }

        }



        if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {

            tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;

        }



        if ((val & TPM_TIS_ACCESS_SEIZE)) {

            













            while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&

                    locty > tis->active_locty) ||

                    !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {

                bool higher_seize = FALSE;



                

                if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {

                    break;

                }



                

                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {

                    if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {

                        higher_seize = TRUE;

                        break;

                    }

                }



                if (higher_seize) {

                    break;

                }



                

                for (l = 0; l < locty - 1; l++) {

                    tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;

                }



                tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "

                        "Locality %d seized from locality %d\n",

                        locty, tis->active_locty);

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");

                set_new_locty = 0;

                tpm_tis_prep_abort(s, tis->active_locty, locty);

                break;

            }

        }



        if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {

            if (tis->active_locty != locty) {

                if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {

                    tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;

                } else {

                    

                    active_locty = locty;

                }

            }

        }



        if (set_new_locty) {

            tpm_tis_new_active_locality(s, active_locty);

        }



        break;

    case TPM_TIS_REG_INT_ENABLE:

        if (tis->active_locty != locty) {

            break;

        }



        tis->loc[locty].inte &= mask;

        tis->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |

                                        TPM_TIS_INT_POLARITY_MASK |

                                        TPM_TIS_INTERRUPTS_SUPPORTED));

        break;

    case TPM_TIS_REG_INT_VECTOR:

        

        break;

    case TPM_TIS_REG_INT_STATUS:

        if (tis->active_locty != locty) {

            break;

        }



        

        if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&

            (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {

            tis->loc[locty].ints &= ~val;

            if (tis->loc[locty].ints == 0) {

                qemu_irq_lower(tis->irq);

                DPRINTF("tpm_tis: Lowering IRQ\n");

            }

        }

        tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);

        break;

    case TPM_TIS_REG_STS:

        if (tis->active_locty != locty) {

            break;

        }



        val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |

                TPM_TIS_STS_RESPONSE_RETRY);



        if (val == TPM_TIS_STS_COMMAND_READY) {

            switch (tis->loc[locty].state) {



            case TPM_TIS_STATE_READY:

                tis->loc[locty].w_offset = 0;

                tis->loc[locty].r_offset = 0;

            break;



            case TPM_TIS_STATE_IDLE:

                tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;

                tis->loc[locty].state = TPM_TIS_STATE_READY;

                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);

            break;



            case TPM_TIS_STATE_EXECUTION:

            case TPM_TIS_STATE_RECEPTION:

                

                DPRINTF("tpm_tis: %s: Initiating abort.\n",

                        __func__);

                tpm_tis_prep_abort(s, locty, locty);

            break;



            case TPM_TIS_STATE_COMPLETION:

                tis->loc[locty].w_offset = 0;

                tis->loc[locty].r_offset = 0;

                

                tis->loc[locty].state = TPM_TIS_STATE_READY;

                if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {

                    tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;

                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);

                }

                tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);

            break;



            }

        } else if (val == TPM_TIS_STS_TPM_GO) {

            switch (tis->loc[locty].state) {

            case TPM_TIS_STATE_RECEPTION:

                if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {

                    tpm_tis_tpm_send(s, locty);

                }

                break;

            default:

                

                break;

            }

        } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {

            switch (tis->loc[locty].state) {

            case TPM_TIS_STATE_COMPLETION:

                tis->loc[locty].r_offset = 0;

                tis->loc[locty].sts = TPM_TIS_STS_VALID |

                                      TPM_TIS_STS_DATA_AVAILABLE;

                break;

            default:

                

                break;

            }

        }

        break;

    case TPM_TIS_REG_DATA_FIFO:

    case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:

        

        if (tis->active_locty != locty) {

            break;

        }



        if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||

            tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||

            tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {

            

        } else {

            DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",

                    val, size);

            if (tis->loc[locty].state == TPM_TIS_STATE_READY) {

                tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;

                tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;

            }



            val >>= shift;

            if (size > 4 - (addr & 0x3)) {

                

                size = 4 - (addr & 0x3);

            }



            while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {

                if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {

                    tis->loc[locty].w_buffer.

                        buffer[tis->loc[locty].w_offset++] = (uint8_t)val;

                    val >>= 8;

                    size--;

                } else {

                    tis->loc[locty].sts = TPM_TIS_STS_VALID;

                }

            }



            

            if (tis->loc[locty].w_offset > 5 &&

                (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {

                

#ifdef RAISE_STS_IRQ

                bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);

#endif

                len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);

                if (len > tis->loc[locty].w_offset) {

                    tis->loc[locty].sts = TPM_TIS_STS_EXPECT |

                                          TPM_TIS_STS_VALID;

                } else {

                    

                    tis->loc[locty].sts = TPM_TIS_STS_VALID;

                }

#ifdef RAISE_STS_IRQ

                if (needIrq) {

                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);

                }

#endif

            }

        }

        break;

    }

}

static void FUNC_0(void *VAR_0, hwaddr VAR_1,

                                      uint64_t VAR_2, unsigned VAR_3,

                                      bool VAR_4)

{

    TPMState *s = VAR_0;

    TPMTISEmuState *tis = &s->s.tis;

    uint16_t off = VAR_1 & 0xffc;

    uint8_t shift = (VAR_1 & 0x3) * 8;

    uint8_t locty = tpm_tis_locality_from_addr(VAR_1);

    uint8_t active_locty, l;

    int VAR_5, VAR_6 = 1;

    uint16_t len;

    uint32_t mask = (VAR_3 == 1) ? 0xff : ((VAR_3 == 2) ? 0xffff : ~0);



    DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", VAR_3, (int)VAR_1, (uint32_t)VAR_2);



    if (locty == 4 && !VAR_4) {

        DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");

        return;

    }



    if (tpm_backend_had_startup_error(s->be_driver)) {

        return;

    }



    VAR_2 &= mask;



    if (shift) {

        VAR_2 <<= shift;

        mask <<= shift;

    }



    mask ^= 0xffffffff;



    switch (off) {

    case TPM_TIS_REG_ACCESS:



        if ((VAR_2 & TPM_TIS_ACCESS_SEIZE)) {

            VAR_2 &= ~(TPM_TIS_ACCESS_REQUEST_USE |

                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);

        }



        active_locty = tis->active_locty;



        if ((VAR_2 & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {

            

            if (tis->active_locty == locty) {

                DPRINTF("tpm_tis: Releasing locality %d\n", locty);



                uint8_t newlocty = TPM_TIS_NO_LOCALITY;

                

                for (VAR_5 = TPM_TIS_NUM_LOCALITIES - 1; VAR_5 >= 0; VAR_5--) {

                    if ((tis->loc[VAR_5].access & TPM_TIS_ACCESS_REQUEST_USE)) {

                        DPRINTF("tpm_tis: Locality %d requests use.\n", VAR_5);

                        newlocty = VAR_5;

                        break;

                    }

                }

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "

                        "Next active locality: %d\n",

                        newlocty);



                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {

                    VAR_6 = 0;

                    tpm_tis_prep_abort(s, locty, newlocty);

                } else {

                    active_locty = TPM_TIS_NO_LOCALITY;

                }

            } else {

                

                tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;

            }

        }



        if ((VAR_2 & TPM_TIS_ACCESS_BEEN_SEIZED)) {

            tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;

        }



        if ((VAR_2 & TPM_TIS_ACCESS_SEIZE)) {

            













            while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&

                    locty > tis->active_locty) ||

                    !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {

                bool higher_seize = FALSE;



                

                if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {

                    break;

                }



                

                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {

                    if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {

                        higher_seize = TRUE;

                        break;

                    }

                }



                if (higher_seize) {

                    break;

                }



                

                for (l = 0; l < locty - 1; l++) {

                    tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;

                }



                tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "

                        "Locality %d seized from locality %d\n",

                        locty, tis->active_locty);

                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");

                VAR_6 = 0;

                tpm_tis_prep_abort(s, tis->active_locty, locty);

                break;

            }

        }



        if ((VAR_2 & TPM_TIS_ACCESS_REQUEST_USE)) {

            if (tis->active_locty != locty) {

                if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {

                    tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;

                } else {

                    

                    active_locty = locty;

                }

            }

        }



        if (VAR_6) {

            tpm_tis_new_active_locality(s, active_locty);

        }



        break;

    case TPM_TIS_REG_INT_ENABLE:

        if (tis->active_locty != locty) {

            break;

        }



        tis->loc[locty].inte &= mask;

        tis->loc[locty].inte |= (VAR_2 & (TPM_TIS_INT_ENABLED |

                                        TPM_TIS_INT_POLARITY_MASK |

                                        TPM_TIS_INTERRUPTS_SUPPORTED));

        break;

    case TPM_TIS_REG_INT_VECTOR:

        

        break;

    case TPM_TIS_REG_INT_STATUS:

        if (tis->active_locty != locty) {

            break;

        }



        

        if (((VAR_2 & TPM_TIS_INTERRUPTS_SUPPORTED)) &&

            (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {

            tis->loc[locty].ints &= ~VAR_2;

            if (tis->loc[locty].ints == 0) {

                qemu_irq_lower(tis->irq);

                DPRINTF("tpm_tis: Lowering IRQ\n");

            }

        }

        tis->loc[locty].ints &= ~(VAR_2 & TPM_TIS_INTERRUPTS_SUPPORTED);

        break;

    case TPM_TIS_REG_STS:

        if (tis->active_locty != locty) {

            break;

        }



        VAR_2 &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |

                TPM_TIS_STS_RESPONSE_RETRY);



        if (VAR_2 == TPM_TIS_STS_COMMAND_READY) {

            switch (tis->loc[locty].state) {



            case TPM_TIS_STATE_READY:

                tis->loc[locty].w_offset = 0;

                tis->loc[locty].r_offset = 0;

            break;



            case TPM_TIS_STATE_IDLE:

                tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;

                tis->loc[locty].state = TPM_TIS_STATE_READY;

                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);

            break;



            case TPM_TIS_STATE_EXECUTION:

            case TPM_TIS_STATE_RECEPTION:

                

                DPRINTF("tpm_tis: %s: Initiating abort.\n",

                        __func__);

                tpm_tis_prep_abort(s, locty, locty);

            break;



            case TPM_TIS_STATE_COMPLETION:

                tis->loc[locty].w_offset = 0;

                tis->loc[locty].r_offset = 0;

                

                tis->loc[locty].state = TPM_TIS_STATE_READY;

                if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {

                    tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;

                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);

                }

                tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);

            break;



            }

        } else if (VAR_2 == TPM_TIS_STS_TPM_GO) {

            switch (tis->loc[locty].state) {

            case TPM_TIS_STATE_RECEPTION:

                if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {

                    tpm_tis_tpm_send(s, locty);

                }

                break;

            default:

                

                break;

            }

        } else if (VAR_2 == TPM_TIS_STS_RESPONSE_RETRY) {

            switch (tis->loc[locty].state) {

            case TPM_TIS_STATE_COMPLETION:

                tis->loc[locty].r_offset = 0;

                tis->loc[locty].sts = TPM_TIS_STS_VALID |

                                      TPM_TIS_STS_DATA_AVAILABLE;

                break;

            default:

                

                break;

            }

        }

        break;

    case TPM_TIS_REG_DATA_FIFO:

    case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:

        

        if (tis->active_locty != locty) {

            break;

        }



        if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||

            tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||

            tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {

            

        } else {

            DPRINTF("tpm_tis: Data to send to TPM: %08x (VAR_3=%d)\n",

                    VAR_2, VAR_3);

            if (tis->loc[locty].state == TPM_TIS_STATE_READY) {

                tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;

                tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;

            }



            VAR_2 >>= shift;

            if (VAR_3 > 4 - (VAR_1 & 0x3)) {

                

                VAR_3 = 4 - (VAR_1 & 0x3);

            }



            while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && VAR_3 > 0) {

                if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.VAR_3) {

                    tis->loc[locty].w_buffer.

                        buffer[tis->loc[locty].w_offset++] = (uint8_t)VAR_2;

                    VAR_2 >>= 8;

                    VAR_3--;

                } else {

                    tis->loc[locty].sts = TPM_TIS_STS_VALID;

                }

            }



            

            if (tis->loc[locty].w_offset > 5 &&

                (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {

                

#ifdef RAISE_STS_IRQ

                bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);

#endif

                len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);

                if (len > tis->loc[locty].w_offset) {

                    tis->loc[locty].sts = TPM_TIS_STS_EXPECT |

                                          TPM_TIS_STS_VALID;

                } else {

                    

                    tis->loc[locty].sts = TPM_TIS_STS_VALID;

                }

#ifdef RAISE_STS_IRQ

                if (needIrq) {

                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);

                }

#endif

            }

        }

        break;

    }

}

static void FUNC_0(void *VAR_0, hwaddr VAR_1,
uint64_t VAR_2, unsigned VAR_3,
bool VAR_4)
{ TPMState *s = VAR_0; TPMTISEmuState *tis = &s->s.tis; uint16_t off = VAR_1 & 0xffc; uint8_t shift = (VAR_1 & 0x3) * 8; uint8_t locty = tpm_tis_locality_from_addr(VAR_1); uint8_t active_locty, l; int VAR_5, VAR_6 = 1; uint16_t len; uint32_t mask = (VAR_3 == 1) ? 0xff : ((VAR_3 == 2) ? 0xffff : ~0); DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", VAR_3, (int)VAR_1, (uint32_t)VAR_2); if (locty == 4 && !VAR_4) { DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n"); return; } if (tpm_backend_had_startup_error(s->be_driver)) { return; } VAR_2 &= mask; if (shift) { VAR_2 <<= shift; mask <<= shift; } mask ^= 0xffffffff; switch (off) { case TPM_TIS_REG_ACCESS:
if ((VAR_2 & TPM_TIS_ACCESS_SEIZE)) { VAR_2 &= ~(TPM_TIS_ACCESS_REQUEST_USE |
TPM_TIS_ACCESS_ACTIVE_LOCALITY); } active_locty = tis->active_locty; if ((VAR_2 & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { if (tis->active_locty == locty) { DPRINTF("tpm_tis: Releasing locality %d\n", locty); uint8_t newlocty = TPM_TIS_NO_LOCALITY; for (VAR_5 = TPM_TIS_NUM_LOCALITIES - 1; VAR_5 >= 0; VAR_5--) { if ((tis->loc[VAR_5].access & TPM_TIS_ACCESS_REQUEST_USE)) { DPRINTF("tpm_tis: Locality %d requests use.\n", VAR_5); newlocty = VAR_5; break; } } DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
"Next active locality: %d\n",
newlocty); if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { VAR_6 = 0; tpm_tis_prep_abort(s, locty, newlocty); } else { active_locty = TPM_TIS_NO_LOCALITY; } } else { tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; } } if ((VAR_2 & TPM_TIS_ACCESS_BEEN_SEIZED)) { tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; } if ((VAR_2 & TPM_TIS_ACCESS_SEIZE)) { while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
locty > tis->active_locty) ||
!TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) { bool higher_seize = FALSE; if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { break; } for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { higher_seize = TRUE; break; } } if (higher_seize) { break; } for (l = 0; l < locty - 1; l++) { tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; } tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
"Locality %d seized from locality %d\n",
locty, tis->active_locty); DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n"); VAR_6 = 0; tpm_tis_prep_abort(s, tis->active_locty, locty); break; } } if ((VAR_2 & TPM_TIS_ACCESS_REQUEST_USE)) { if (tis->active_locty != locty) { if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) { tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; } else { active_locty = locty; } } } if (VAR_6) { tpm_tis_new_active_locality(s, active_locty); } break; case TPM_TIS_REG_INT_ENABLE:
if (tis->active_locty != locty) { break; } tis->loc[locty].inte &= mask; tis->loc[locty].inte |= (VAR_2 & (TPM_TIS_INT_ENABLED |
TPM_TIS_INT_POLARITY_MASK |
TPM_TIS_INTERRUPTS_SUPPORTED)); break; case TPM_TIS_REG_INT_VECTOR:
break; case TPM_TIS_REG_INT_STATUS:
if (tis->active_locty != locty) { break; } if (((VAR_2 & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
(tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { tis->loc[locty].ints &= ~VAR_2; if (tis->loc[locty].ints == 0) { qemu_irq_lower(tis->irq); DPRINTF("tpm_tis: Lowering IRQ\n"); } } tis->loc[locty].ints &= ~(VAR_2 & TPM_TIS_INTERRUPTS_SUPPORTED); break; case TPM_TIS_REG_STS:
if (tis->active_locty != locty) { break; } VAR_2 &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
TPM_TIS_STS_RESPONSE_RETRY); if (VAR_2 == TPM_TIS_STS_COMMAND_READY) { switch (tis->loc[locty].state) { case TPM_TIS_STATE_READY:
tis->loc[locty].w_offset = 0; tis->loc[locty].r_offset = 0; break; case TPM_TIS_STATE_IDLE:
tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY; tis->loc[locty].state = TPM_TIS_STATE_READY; tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); break; case TPM_TIS_STATE_EXECUTION:
case TPM_TIS_STATE_RECEPTION:
DPRINTF("tpm_tis: %s: Initiating abort.\n",
__func__); tpm_tis_prep_abort(s, locty, locty); break; case TPM_TIS_STATE_COMPLETION:
tis->loc[locty].w_offset = 0; tis->loc[locty].r_offset = 0; tis->loc[locty].state = TPM_TIS_STATE_READY; if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY; tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); } tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); break; } } else if (VAR_2 == TPM_TIS_STS_TPM_GO) { switch (tis->loc[locty].state) { case TPM_TIS_STATE_RECEPTION:
if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { tpm_tis_tpm_send(s, locty); } break; default:
break; } } else if (VAR_2 == TPM_TIS_STS_RESPONSE_RETRY) { switch (tis->loc[locty].state) { case TPM_TIS_STATE_COMPLETION:
tis->loc[locty].r_offset = 0; tis->loc[locty].sts = TPM_TIS_STS_VALID |
TPM_TIS_STS_DATA_AVAILABLE; break; default:
break; } } break; case TPM_TIS_REG_DATA_FIFO:
case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
if (tis->active_locty != locty) { break; } if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) { } else { DPRINTF("tpm_tis: Data to send to TPM: %08x (VAR_3=%d)\n",
VAR_2, VAR_3); if (tis->loc[locty].state == TPM_TIS_STATE_READY) { tis->loc[locty].state = TPM_TIS_STATE_RECEPTION; tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID; } VAR_2 >>= shift; if (VAR_3 > 4 - (VAR_1 & 0x3)) { VAR_3 = 4 - (VAR_1 & 0x3); } while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && VAR_3 > 0) { if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.VAR_3) { tis->loc[locty].w_buffer.
buffer[tis->loc[locty].w_offset++] = (uint8_t)VAR_2; VAR_2 >>= 8; VAR_3--; } else { tis->loc[locty].sts = TPM_TIS_STS_VALID; } } if (tis->loc[locty].w_offset > 5 &&
(tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) { #ifdef RAISE_STS_IRQ
bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID); #endif
len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer); if (len > tis->loc[locty].w_offset) { tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
TPM_TIS_STS_VALID; } else { tis->loc[locty].sts = TPM_TIS_STS_VALID; } #ifdef RAISE_STS_IRQ
if (needIrq) { tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); } #endif
} } break; } }