Lec18-23: 学习笔记
- lec18 阅读论文《The Performance of µ-Kernel-Based Systems》
- lec19 阅读论文《Dune: Safe User-level Access to Privileged CPU Features》
- lec20 阅读论文《The benefits and costs of writing a POSIX kernel in a high-level language》
- lec21 阅读论文 Eliminating Receive Livelock in an Interrupt-driven Kernel
- lec22 阅读论文《Meltdown: Reading Kernel Memory from User Space》
- lec23 阅读论文《RCU Usage In the Linux Kernel: One Decade Later》
实验链接
https://pdos.csail.mit.edu/6.S081/2020/labs/net.html
实验
Lab: networking
实验的目的是为了让我们实现一个网卡驱动在数据链路层的数据收发函数,该函数的实现需要参考E1000的用户手册来完成。
不过,实验中作者给出的hint非常详细,按照hint一步一步实现即可(感觉不看用户手册和xv6代码,感兴趣的可以多看看哈)。
函数e1000_recv
需要注意的地方:
- 不需要加锁,因为该函数会一次性读取
rx_ring
上所有的数据,且该函数位于数据链路层,数据链路层还不涉及进程的概念。在读取完数据之后,该函数会调用net_rx
函数,将数据送给上层应用。 - 关于
index
的理解,在recv
函数中,寄存器里保存的index
是上次已经被处理过的位置,因此,拿到寄存器里的值后,需要加一移动至下个位置。且本次的数据被送至上层应用之后,会对其mbuf进行清理并申请新的mbuf用于保存下次接收的数据。
函数e1000_transmit
需要注意的地方:
- 该相关寄存器中保存的
index
值为本次需要处理的数据索引,因此,本次处理完之后,需要对该值加一并重新放入寄存器。
具体实现如下:
-
文件
e1000.c
,函数e1000_transmit
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. // // printf("e1000 transmit\n"); acquire(&e1000_lock); // First ask the E1000 for the TX ring index at which it's expecting // the next packet, by reading the E1000_TDT control register. uint32 index = regs[E1000_TDT]; // Then check if the the ring is overflowing. If E1000_TXD_STAT_DD is // not set in the descriptor indexed by E1000_TDT, the E1000 hasn't // finished the corresponding previous transmission request, so return an error. if ((tx_ring[index].status & E1000_TXD_STAT_DD) == 0) { release(&e1000_lock); return -1; } // Otherwise, use mbuffree() to free the last mbuf that was transmitted // from that descriptor (if there was one). if (tx_mbufs[index]) { mbuffree(tx_mbufs[index]); } // m->head points to the packet's content in memory tx_ring[index].addr = (uint64)(m->head); // and m->len is the packet length tx_ring[index].length = m->len; // Set the necessary cmd flags (look at Section 3.3 in the E1000 manual) tx_ring[index].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP; // and stash away a pointer to the mbuf for later freeing. tx_mbufs[index] = m; // update the ring position by adding one to E1000_TDT modulo TX_RING_SIZE. regs[E1000_TDT] = (index + 1) % TX_RING_SIZE; release(&e1000_lock); return 0; }
-
文件
e1000.c
,函数e1000_recv
。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()). // // printf("e2000 receive\n"); for (;;) { // First ask the E1000 for the ring index at which the next waiting // received packet (if any) is located, by fetching the E1000_RDT // control register and adding one modulo RX_RING_SIZE. uint32 index = regs[E1000_RDT]; index = (index + 1) % RX_RING_SIZE; // Then check if a new packet is available by checking for the // E1000_RXD_STAT_DD bit in the status portion of the descriptor. // If not, stop. if ((rx_ring[index].status & E1000_RXD_STAT_DD) == 0) { return; } // update the mbuf's m->len to the length reported in the descriptor. rx_mbufs[index]->len = rx_ring[index].length; // rx_mbufs[index]->head = (char*)rx_ring[index].addr; // Deliver the mbuf to the network stack using net_rx() net_rx(rx_mbufs[index]); // Then allocate a new mbuf using mbufalloc() to replace the one just // given to net_rx(). struct mbuf* buf = mbufalloc(0); rx_mbufs[index] = buf; // Program its data pointer (m->head) into the descriptor. rx_ring[index].addr = (uint64)buf->head; // Clear the descriptor's status bits to zero rx_ring[index].status = 0; // Finally, update the E1000_RDT register to be the index of the // last ring descriptor processed. regs[E1000_RDT] = index; } }
-
文件
nettest.c
的dns
函数,将8.8.8.8
改为114.114.114.114
;static void dns() { xxx // 8.8.8.8: google's name server // dst = (8 << 24) | (8 << 16) | (8 << 8) | (8 << 0); dst = (114 << 24) | (114 << 16) | (114 << 8) | (114 << 0); xxx }
-
执行结果1
结果
$ make grade
提交结果
$ git commit -m "lab network"
$ make handin
查看结果
登录网站https://6828.scripts.mit.edu/2020/handin.py/student
,可以看到提交的结果。
参考链接
https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081
https://pdos.csail.mit.edu/6.S081/2020/schedule.html
Github
源码: https://github.com/aerfalwl/mit-xv6-labs-2020
完结撒花!