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

📄 e100.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 5 页
字号:
                                cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf,                                        sizeof(tx_buf));                                tx_buf.is_el_set &= 0x1;                                tx_buf.size &= 0x7fff;                                tbd_array += 8;                                if ( tx_buf.size > sizeof(s->pkt_buf) - len )                                {                                    logout("Warning: Get a too big TBD, ignore it"                                            "(buf addr %#x, size %d, el:%#x)\n",                                            tx_buf.addr, tx_buf.size, tx_buf.is_el_set);                                    continue;                                }                                cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len],                                        tx_buf.size);                                logout("TBD (standard mode): buf addr %#x, size %d, el:%#x\n",                                        tx_buf.addr, tx_buf.size, tx_buf.is_el_set);                                len += tx_buf.size;                                if ( tx_buf.is_el_set )                                    break;                            }                        }                        //FIXME: Extend mode is not be tested                        else                        {                            /* Extend TCB mode */                            /* A strandard TCB followed by two TBDs */                            uint32_t tbd_addr = cb_addr+16;                            int i = 0;                            for ( ; i<2 && i<tx.tbd.tbd_num; i++ )                            {                                cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf,                                        sizeof(tx_buf));                                tx_buf.is_el_set &= 0x1;                                tbd_addr += 8;                                /* From Intel's spec, size of TBD equal to zero                                 * has same effect with EL bit set                                 */                                if ( tx_buf.size == 0 )                                {                                    tx_buf.is_el_set = 1;                                    break;                                }                                if ( tx_buf.size + len > sizeof(s->pkt_buf) )                                {                                    logout("TX frame is too large, discarding it"                                            "(buf addr=%#x, size=%#x)\n", tx_buf.addr,                                            tx_buf.size);                                    //continue;                                    break;                                }                                logout("TBD (extended mode): buf addr %#08x, size %#04x, el:%#x\n",                                        tx_buf.addr, tx_buf.size, tx_buf.is_el_set);                                cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len],                                        tx_buf.size);                                len += tx_buf.size;                                if ( tx_buf.is_el_set )                                    break;                            }                            /* In extend TCB mode, TDB array point to the thrid TBD                             * if it is not NULL(0xffffffff) and EL bit of before                             * two TBDs is not set                             */                            if ( tbd_array != (uint32_t)-1 && !tx_buf.is_el_set )                            {                                tbd_addr = tbd_array;                                /* TBD number includes first two TBDs, so don't                                 * initialize i here                                 */                                for ( ; i<tx.tbd.tbd_num; i++ )                                {                                    cpu_physical_memory_read(tbd_addr, (uint8_t *)&tx_buf,                                            sizeof(tx_buf));                                    tx_buf.is_el_set &= 0x1;                                    tbd_addr += 8;                                    cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len],                                            tx_buf.size);                                    logout("TBD (extended mode): buf addr 0x%#08x, size 0x%#04x\n",                                            tx_buf.addr, tx_buf.size);                                    len += tx_buf.size;                                    if ( tx_buf.is_el_set )                                        break;                                }                            }                        }                    }                    s->pkt_buf_len = len;/* Below codes are used for Threshold. But with these logic, network of guest * getting bad performance. So I comment it and leave codes here to hope anyone * fix it */#if 0                    /* If threshold is set, only send packet when threshold                     * bytes are read                     */                    if ( tx.tbd.tx_threshold && s->pkt_buf_len < tx.tbd.tx_threshold * 8 )                    {                        logout("Current data length in FIFO buffer:%d\n", s->pkt_buf_len);                        break;                    }#endif                    if ( s->pkt_buf_len )                    {                        qemu_send_packet(s->vc, s->pkt_buf, s->pkt_buf_len);                        s->statistics.tx_good_frames ++;                        logout("Send out frame successful(size=%d,"                                "already sent %d frames)\n", s->pkt_buf_len,                                s->statistics.tx_good_frames);                        s->pkt_buf_len = 0;                    }                    e100_dump("Dest addr:", (uint8_t *)s->pkt_buf, 6);                    e100_dump("Src addr:", (uint8_t *)(s->pkt_buf+6), 6);                    e100_dump("type:", (uint8_t *)(s->pkt_buf+8), 2);                    break;                }            case CBL_LOAD_MICROCODE:#ifdef DEBUG_E100                {                    /* Don't support load marco code, just dump it */                    #define MICRO_CODE_LEN 256                    uint8_t micro_code[MICRO_CODE_LEN] = {0};                    cpu_physical_memory_read(cb_addr+8, micro_code, MICRO_CODE_LEN);                    e100_dump("Load micro code:", micro_code, MICRO_CODE_LEN);                }#endif                break;            case CBL_DUMP:                logout("Control block dump\n");                break;            case CBL_DIAGNOSE:                logout("Control block diagnose\n");                break;            default:                logout("Unknown Control block command(val=%#x)\n", cb.cmd);                break;        }        /* Now, we finished executing a command, update status of CB.         * We always success         */        cb.c = 1;        cb.ok = 1;        // Only update C bit and OK bit field in TCB        cpu_physical_memory_write(cb_addr, (uint8_t *)&cb, 2);        logout("Finished a command from CB list:\n"                "\tok:%d\n"                "\tc:%d\n"                "\tcommand name:%s(cmd=%#x)\n"                "\ti:%d\n"                "\ts:%d\n"                "\tel:%d\n"                "\tlink address:%#x\n",                cb.ok, cb.c, CB_CMD_NAME(cb.cmd), cb.cmd,                cb.i, cb.s, cb.el, cb.link_addr);        if ( cb.i )            e100_interrupt(s, (uint16_t)INT_CX_TNO);        // Suspend CU        if ( cb.s )        {            logout("CU go to suspend\n");            SET_CU_STATE(CU_SUSPENDED);            s->cu_next = cb.link_addr; // Save it for go on executing when resume            // Trigger CNA interrupt only when CNA mode is configured            if ( !(s->config.ci_intr) && cb.i )                e100_interrupt(s, (uint16_t)INT_CNA);            return;        }        // This is last command in CB list, CU go back to IDLE        if ( cb.el )        {            logout("Command block list is empty, CU go to idle\n");            SET_CU_STATE(CU_IDLE);            /* Either in CNA mode or CI mode, interrupt need be triggered             * when CU go to idle.             */            if ( cb.i )                e100_interrupt(s, (uint16_t)INT_CNA);            return;        }        s->cu_offset = le32_to_cpu(cb.link_addr); // get next CB offset    }}static void dump_statistics(E100State * s, uint32_t complete_word){    /* Dump statistical data. Most data is never changed by the emulation     * and always 0.     */    s->statistics.complete_word = complete_word;    cpu_physical_memory_write(s->statsaddr, (uint8_t *)&s->statistics, sizeof(s->statistics));}static void e100_cu_command(E100State *s, uint8_t val){    switch ( val )    {        case CU_NOP:            /* Will not be here */            break;        case CU_START:            /* This strictly follow Intel's spec */            if ( GET_CU_STATE != CU_IDLE && GET_CU_STATE != CU_SUSPENDED )            {                logout("Illegal CU start command. Device is not idle or suspend\n");                return;            }            SET_CU_STATE(CU_LPQ_ACTIVE);            logout("CU start\n");            e100_execute_cb_list(s, 0);            break;        case CU_RESUME:            {                uint32_t previous_cb = s->cu_base + s->cu_offset;                struct control_block cb;                /* Resume from suspend */                /* FIXME:From Intel's spec, CU resume from idle is                 * forbidden, but e100 drive in linux                 * indeed do this.                 */                if ( GET_CU_STATE == CU_IDLE )                {                    logout("Illegal resume form IDLE\n");                }                cpu_physical_memory_read(previous_cb, (uint8_t *)&cb,                                        sizeof(cb));                //FIXME: Need any speical handle when CU is active ?                /* Driver must clean S bit in previous CB when                 * it issue CU resume command                 */                if ( cb.s )                {                    logout("CU still in suspend\n");                    break;                }                SET_CU_STATE(CU_LPQ_ACTIVE);                if ( cb.el )                {                    logout("CB list is empty, CU just go to active\n");                    break;                }                // Continue next command                s->cu_offset = s->cu_next;                e100_execute_cb_list(s, 1);                logout("CU resume\n");            }            break;        case CU_STATSADDR:            /* Load dump counters address */            s->statsaddr = CSR_VAL(CSR_POINTER);            logout("Load Stats address at %#x\n", s->statsaddr);            break;        case CU_SHOWSTATS:            /* Dump statistical counters */            dump_statistics(s, 0xa005);            logout("Execute dump statistics\n");            break;        case CU_CMD_BASE:            /* Load CU base */            s->cu_base = CSR_VAL(CSR_POINTER);            logout("Load CU base at %x\n", s->cu_base);            break;        case CU_DUMPSTATS:            /* Dump statistical counters and reset counters. */            dump_statistics(s, 0xa007);            memset(&s->statistics, 0x0, sizeof(s->statistics));            logout("Execute dump and reset statistics\n");            break;        case CU_S_RESUME:            /* CU static resume */            logout("CU static resume is not implemented\n");            break;        default:            logout("Unknown CU command(val=%#x)\n", val);            break;    }}static void scb_cmd_func(E100State *s, uint16_t val, int dir){    /* ignore NOP operation */    if ( val & 0x0f )    {        e100_ru_command(s, val & 0x0f);        CSR(CSR_CMD, ru_cmd) = 0;    }    else if ( val & 0xf0 )    {        e100_cu_command(s, val & 0xf0);        CSR(CSR_CMD, cu_cmd) = 0;    }}enum{    WRITEB,    WRITEW,    WRITEL,    OP_IS_READ,} WRITE_BYTES;/* Driver may issue a command by writting one 32bit-entry, * two 16bit-entries or four 8bit-entries. In late two case, we * must wait until driver finish writting to the highest byte. The parameter * 'bytes' means write action of driver(writeb, wirtew, wirtel) */static void e100_execute(E100State *s, uint32_t addr_offset,        uint32_t val, int dir, int bytes){    switch ( addr_offset )    {        case SCB_STATUS:            if ( bytes == WRITEB )                break;        case SCB_ACK:            if ( dir == OP_WRITE )            {                uint8_t _val = 0;                if ( bytes == WRITEB )                    _val = (uint8_t)val;                else if ( bytes == WRITEW )                    _val = ((uint16_t)val) >> 8;                else if ( bytes == WRITEL)                {                    // This should not be happen                    _val = ((uint16_t)val) >> 8;                    logout("WARNNING: Drvier write 4 bytes to CSR register at offset %d,"                           "emulator may do things wrong!!!\n", addr_offset);                }                e100_interrupt_ack(s, _val);            }            break;        case SCB_CMD:            if ( dir == OP_WRITE )                scb_cmd_func(s, val, dir);/* I don't know whether there is any driver writes command words and * interrupt mask at same time by two bytes. This is not a regular operation. * but if we meet the case, below codes could copy with it. As far * as I know. windows's and linux's driver don't do this thing. */#if 0            if ( bytes == WRITEW && (val&0xff00) != 0 )                ;            else                break;#endif            break;        case SCB_INTERRUPT_MASK:            if ( dir == OP_WRITE )            {                uint8_t _val = 0;                if ( bytes == WRITEB )          

⌨️ 快捷键说明

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