前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[mit6.s081] 笔记 Lab11: Networking | 网络

[mit6.s081] 笔记 Lab11: Networking | 网络

作者头像
Miigon
发布2022-10-27 16:09:04
5310
发布2022-10-27 16:09:04
举报
文章被收录于专栏:Miigon's Blog

这是我自学 MIT6.S081 操作系统课程的 lab 代码笔记第十一篇:Networking(最后一篇)。此 lab 大致耗时:2小时。 课程地址: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/Miigon/my-xv6-labs-2020/tree/net Commits: https://github.com/Miigon/my-xv6-labs-2020/commits/net 本文中代码注释是编写博客的时候加入的,原仓库中的代码可能缺乏注释或代码不完全相同。

Lab 11: Networking (hard)

熟悉系统驱动与外围设备的交互、内存映射寄存器与 DMA 数据传输,实现与 E1000 网卡交互的核心方法:transmit 与 recv。

本 lab 的难度主要在于阅读文档以及理解 CPU 与操作系统是如何与外围设备交互的。换言之,更重要的是理解概念以及 lab 已经写好的模版代码的作用。

代码实现

代码语言:javascript
复制
int
e1000_transmit(struct mbuf *m)
{
  acquire(&e1000_lock); // 获取 E1000 的锁,防止多进程同时发送数据出现 race

  uint32 ind = regs[E1000_TDT]; // 下一个可用的 buffer 的下标
  struct tx_desc *desc = &tx_ring[ind]; // 获取 buffer 的描述符,其中存储了关于该 buffer 的各种信息
  // 如果该 buffer 中的数据还未传输完,则代表我们已经将环形 buffer 列表全部用完,缓冲区不足,返回错误
  if(!(desc->status & E1000_TXD_STAT_DD)) {
    release(&e1000_lock);
    return -1;
  }
  
  // 如果该下标仍有之前发送完毕但未释放的 mbuf,则释放
  if(tx_mbufs[ind]) {
    mbuffree(tx_mbufs[ind]);
    tx_mbufs[ind] = 0;
  }

  // 将要发送的 mbuf 的内存地址与长度填写到发送描述符中
  desc->addr = (uint64)m->head;
  desc->length = m->len;
  // 设置参数,EOP 表示该 buffer 含有一个完整的 packet
  // RS 告诉网卡在发送完成后,设置 status 中的 E1000_TXD_STAT_DD 位,表示发送完成。
  desc->cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS;
  // 保留新 mbuf 的指针,方便后续再次用到同一下标时释放。
  tx_mbufs[ind] = m;

  // 环形缓冲区内下标增加一。
  regs[E1000_TDT] = (regs[E1000_TDT] + 1) % TX_RING_SIZE;
  
  release(&e1000_lock);
  return 0;
}

static void
e1000_recv(void)
{
  while(1) { // 每次 recv 可能接收多个包

    uint32 ind = (regs[E1000_RDT] + 1) % RX_RING_SIZE;
    
    struct rx_desc *desc = &rx_ring[ind];
    // 如果需要接收的包都已经接收完毕,则退出
    if(!(desc->status & E1000_RXD_STAT_DD)) {
      return;
    }

    rx_mbufs[ind]->len = desc->length;
    
    net_rx(rx_mbufs[ind]); // 传递给上层网络栈。上层负责释放 mbuf

    // 分配并设置新的 mbuf,供给下一次轮到该下标时使用
    rx_mbufs[ind] = mbufalloc(0); 
    desc->addr = (uint64)rx_mbufs[ind]->head;
    desc->status = 0;

    regs[E1000_RDT] = ind;
  }

}

操作系统想要发送数据的时候,将数据放入环形缓冲区数组 tx_ring 内,然后递增 E1000_TDT,网卡会自动将数据发出。当网卡收到数据的时候,网卡首先使用 direct memory access,将数据放入 rx_ring 环形缓冲区数组中,然后向 CPU 发起一个硬件中断,CPU 在收到中断后,直接读取 rx_ring 中的数据即可。

完结撒花

本 lab 的完成,为接近两个月的 MIT6.S081 旅途画上了句号。不得不说 MIT 的课程以及作业设计真的很不错,目标明确但又充满探索的 xv6 lab,加上自动 grading,体验简直好到爆。推荐同样对操作系统有兴趣的同学们可以来刷一刷,亲自动手体验实现操作系统各项机能。

同时,对计算机科学的探索依然没有穷尽,后面还会同步更新更多的刷课记录以及课程推荐。

课程地址:https://pdos.csail.mit.edu/6.S081/2020/schedule.html

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Lab 11: Networking (hard)
    • 代码实现
    • 完结撒花
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档