[MIT 6.1810]Lab7-networking

Lab7 networking

https://pdos.csail.mit.edu/6.828/2023/labs/net.html

背景

为E1000实现驱动,补全kernel/e1000.c中的两个空函数。
为了达成目的,需要看E1000的文档,对E1000有足够的了解。

驱动程序

驱动程序分为top、bottom两部分:

  • top:运行内核线程,由系统调用(例如read、write)调用,要求设备执行IO(发包)。
  • bottom:中断处理线程,硬件中断(例如网卡收到包)调用,处理中断(收包)。

本实验中,top部分的调用链示例:

E1000手册

接收描述符

网卡约定的数据格式。当收到一个数据包时,网卡填充的信息。
在这里插入图片描述
与之对应的代码是:
在这里插入图片描述

发送描述符

在这里插入图片描述
代码中与之对应的数据结构是tx_desc

寄存器约定

手册中约定了控制寄存器的地址,例如环形队列的地址…:
在这里插入图片描述
与之对应的宏定义在kernel/e1000_dev.h
举例:

  1. 硬件约定好了,0x02810位置存储了接收描述符环形队列的队首指针。
  2. 内核初始化时,将接收描述符环形队列的队首指针写入0x02810
  3. 此时,当硬件收到包时,会构建一个描述符,放在0x02810中存储的指针指向的环形队列队首,并产生一个中断。
环形队列

以接收环形队列为例:
为硬件所有,当网卡收到包时,会检查环形队列 head 位置的描述符。然后把数据写入 head 描述符的缓冲区。
在这里插入图片描述
接收功能的初始化代码,初始化了环形队列rx_ring;对应的mbuf;位于指定内存中的控制寄存器regs
在这里插入图片描述
所以,接收函数就是要去实现处理这个环形队列中已有的待处理包。
此时,生产者是硬件网卡(维护head指针),消费者是需要实现的接收函数(维护tail指针)。
生产者消费者之间的通讯方式是:网卡收到包时产生中断,中断处理程序去调用接收函数。

代码实现

发送

作为生产者将入参mbuf打包发送到发送环形队列中,这样硬件作为消费者会自己处理(发出去)。

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_tx);
  // 在环形队列中获取发送描述符位置
  uint idx = regs[E1000_TDT] % TX_RING_SIZE;
  struct tx_desc *desc = &tx_ring[idx];
  if (desc->status & E1000_TXD_STAT_DD) {
    // 发送描述符对应的mbuf
    if (tx_mbufs[idx]) {
      mbuffree(tx_mbufs[idx]);
    }
    desc->addr = (uint64)m->head;
    desc->length = m->len;
    desc->cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
    tx_mbufs[idx] = m;
    regs[E1000_TDT] = (idx + 1) % TX_RING_SIZE;
  } else {
    goto fail;
  }
  release(&e1000_lock_tx);
  return 0;
fail:
  release(&e1000_lock_tx);
  printf("e1000 tx error.\n");
  return -1;
}

接收

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()).
  //
  acquire(&e1000_lock_rx);
  while (1) {
    uint idx = (regs[E1000_RDT] + 1) % RX_RING_SIZE;
    struct rx_desc *desc = &rx_ring[idx];
    if (desc->status & E1000_RXD_STAT_DD) {
      // 获取描述符对应的mbuf
      rx_mbufs[idx]->len = desc->length;
      // 将包交给处理函数,解析包头协议&路由给对应的协议栈
      net_rx(rx_mbufs[idx]);
      // 收尾
      rx_mbufs[idx] = mbufalloc(0);
      desc->addr = (uint64)rx_mbufs[idx]->head;
      desc->status = 0;
      regs[E1000_RDT] = idx;
    } else {
      goto end;
    }
  }

end:
  release(&e1000_lock_rx);
  return;
}

  • 需要使用make grade进行测试。
  • desc->addr存储的是是mbuf->head
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值