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;
}
}
此时可以验证实验是否通过
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤