Mit6.S081笔记Lab11: Network 网络设备驱动

课程地址:https://pdos.csail.mit.edu/6.S081/2020/schedule.html
Lab 地址:https://pdos.csail.mit.edu/6.S081/2020/labs/net.html
我的代码地址:https://github.com/Amroning/MIT6.S081/tree/net
xv6手册:https://pdos.csail.mit.edu/6.S081/2020/xv6/book-riscv-rev1.pdf
相关翻译:https://xv6.dgs.zone/labs/requirements/lab11.html
参考博客:https://blog.miigon.net/posts/s081-lab11-network/

学习笔记记录,如有错误恳请各位大佬指正

Lab11: Network

​ 给网络接口卡写驱动程序,使驱动程序可以发送和接收数据包。

​ 完整题目要求请去顶部链接查看

你的工作(hard)

您的工作是在*kernel/e1000.c*中完成e1000_transmit()e1000_recv(),以便驱动程序可以发送和接收数据包。当make grade表示您的解决方案通过了所有测试时,您就完成了。

​ 实现e1000_transmit函数的功能,用于将以太网帧传输到网络接口卡(NIC)的发送描述符环(TX descriptor ring)中,通过E1000网卡发送数据。编写的代码需要实现将以太网帧填入发送描述符环中,并更新发送描述符环的指针。实现细节在注释中:

int
e1000_transmit(struct mbuf *m)
{
  //
  // Your code here.
  //
  // the mbuf contains an ethernet frame; program it into
  // the TX descriptor ring so that the e1000 sends it. Stash
  // a pointer so that it can be freed after sending.
  //

    acquire(&e1000_lock);                               // 获取E1000锁,线程安全

    uint32 idx = regs[E1000_TDT];                       // 获取传输buf环的下一个可用索引
    struct tx_desc* desc = &tx_ring[idx];               // 获取当前传输buf的描述符指针

    if ((desc->status & E1000_TXD_STAT_DD) == 0) {      // E1000没有完成之前的传输请求,返回错误(此时已经用完了环形buf列表,缓冲区无空闲)
        release(&e1000_lock);
        return -1;
    }

    if (tx_mbufs[idx]) {                                // 该idx是否关联了一个mbuf
        mbuffree(tx_mbufs[idx]);                        // 表示之前该idx释放完毕了但未释放mbuf
        tx_mbufs[idx] = 0;
    }

    desc->addr = (uint64)m->head;                       // mbuf的地址填入发送描述符中
    desc->length = m->len;                              // mbuf的长度填入发送描述符中
    desc->cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS;   // EOP表示以太网帧的结束,RS表示需要报告发送状态
    tx_mbufs[idx] = m;                                  // 将mbuf关联到发送描述符

    // 更新发送描述符环的尾指针
    regs[E1000_TDT] = (regs[E1000_TDT] + 1) % TX_RING_SIZE;

    release(&e1000_lock);
    return 0;

    return 0;
}

​ 实现e1000_recv函数的功能,处理从E1000网卡接收到的数据包。检查接收描述符环(RX descriptor ring)中的数据包,为每个数据包创建一个缓冲区(mbuf),将其传递给网络层进行处理。实现细节在注释中:

static void
e1000_recv(void)
{
  //
  // Your code here.
  //
  // Check for packets that have arrived from the e1000
  // Create and deliver an mbuf for each packet (using net_rx()).
  //

    // 循环检查接收描述符环中的数据包
    while (1) {
        uint32 idx = (regs[E1000_RDT] + 1) % RX_RING_SIZE;      // 下一个接收描述符的索引

        struct rx_desc* desc = &rx_ring[idx];                   // 当前接收描述符的指针

        if ((desc->status & E1000_RXD_STAT_DD) == 0)            // 接收描述符环中已经没有数据包需要结束,退出函数
            return;

        rx_mbufs[idx]->len = desc->length;                      // 接受描述符中数据包的长度设置到mbuf的长度字段中

        net_rx(rx_mbufs[idx]);                                  // 将mbuf传递给网络层进行处理,网络层负责释放mbuf

        // 分配一个新的mbuf,将新的mbuf的地址设置为接收描述符的地址,状态清空,以便下一次使用该下标使用
        rx_mbufs[idx] = mbufalloc(0);
        desc->addr = (uint64)rx_mbufs[idx]->head;
        desc->status = 0;

        // 将接收描述符环的尾指针设置为当前索引
        regs[E1000_RDT] = idx;
    }
}

此时可以验证实验是否通过

posted @   Amroning  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤
点击右上角即可分享
微信分享提示