Exercise 1

在每一次时钟中断时调用 time_tick, 实现 sys_time_msec 系统调用 image

image

image

Exercise 2

阅读 Software Developer’s Manual,了解 e1000

Exercise 3

实现一个连接函数来初始化 e1000, 在 pci_attach_vendor 中增加一项,使得一旦发现了 pci 设备就能够激活预先定义的函数,这项包含三个,前两个一个是 vender id, 一个是 device id 可以在 intel 手册的 5.2 找到,最后一个是激活函数的地址。kern/e1000.c 和 kern/e1000.h 已经存在,但是是空的需要补充

image

image

image

Exercise 4

实现 e1000 的内存 io 映射,参照 lapic

image

image

Exercise 5

通过 intel 手册了解 transmit descriptors 和 transmit descriptor array 然后完成发送流程的初始化 首先分配一个 transmit descriptors 数组,因为 TDLEN 是 128 位,所以数组的长度必须是 8 的倍数,评分的脚本要求其大小不能超过 64,因为超过无法检测发送队列满的情况,这里我把它设置为 32, 再为每个 descrioptor 分配一个队列,因为标准以太网的包大小最大为 1518 字节,并且要求缓冲区必须是连续的,所以我们将包缓冲区大小为设置为 2048,并按照物理页大小对齐

image image

然后根据手册对寄存器进行出初始化,这里有一些寄存器的宏可以根据 e1000_hw.h 来设定 image

image

Exercise 6

写一个函数来传送网络包,检测队列中的下一个描述符所指的内存是不是空的,空的话将数据拷贝到缓冲区,并更新尾指针寄存器 TDT 的值,确保处理队列满的情况

image

Exercise 7

添加发送包的系统调用 image

image

image

image

Exercise 8

实现 output image

Question 1

如何判定发送队列已经满了? 如何队列的下一个描述符所指的内存区域不是空,描述符的 DD 为 0 的话说明队列已满,因为如果 e1000 将包发出去以后,会将描述符的 dd 位置 1,说明这个内存区域可以存储下一个包,如果没有设置就说明还没有发出去,说明队列已经满了

Exercise 9

阅读手册 3.2

Exercise 10

实现接收队列,不必指针接收超过以太网标准的长包或多址传送,需要去掉以太网的 crc 校验。 默认的,网卡会过滤掉所有的包,需要设置接收地址寄存器为网卡的的 mac 地址,使得网卡能接收目的地址是其 mac 地址的包,可以直接硬编码为 qemu 的默认 mac 地址 52:54:00:12:34:56,注意 mac 地址表示的顺序是从低字节序到高字节,所以 52:54:00:12 是存储在低 32 位,34:56 存储在搞 16 位 e1000 只支持一些特点的包缓冲区大小,如果你的缓冲区设置的足够大,并且不开启长包支持的话,就不必担心一个包会接收在不同的缓冲区,另外和发送队列一样,要保证缓冲区在物理内存是连续的 至少需要 128 个接收描述符

image

image

image

image

image

Exercise 11

实现接收包的函数,和系统调用,确保处理了接收队列为空的情况 实现和发送的基本一样 image

Exercise 12

实现 input image

Question 2

和 question1 一样的方法

Exercise 13

实现 web server 的 send_file 和 send_data image

image

结束

image