MIT 6.828 操作系统工程 Lab6: 网络驱动程序
这篇是我自己探索实现 MIT 6.828 lab6 的笔记记录,会包含一部分代码注释和要求的翻译记录,以及踩过的坑/个人的解决方案
这里是我实现的完整代码仓库,也包含其他笔记等等:https://github.com/yunwei37/6.828-2018-labs
目录:
lab6 实际上并没有想象中那么难,代码量很少,主要是需要理解网卡外设的运作方式。
根据网页上的提示,在需要的时候去查找手册就好。
理解这张图的结构:
练习 1.time_tick
一个简单的接口调用。
syscall.c
static int
sys_time_msec(void)
{
// LAB 6: Your code here.
return time_msec();
}
练习 2.浏览英特尔的E1000软件开发人员手册
现在不要担心细节;只需感受一下文档的结构,您就可以稍后查找内容。
练习 3. 实现一个附加函数来初始化 E1000
pci:
// pci_attach_vendor matches the vendor ID and device ID of a PCI device. key1
// and key2 should be the vendor ID and device ID respectively
struct pci_driver pci_attach_vendor[] = {
{
0x8086, 0x100e, pci_e1000_attach },
{
0, 0, 0 },
};
e1000
volatile void *e1000_base = 0;
inline static void
write_reg(int reg, uint32_t value) {
assert(e1000_base);
*(uint32_t*)(e1000_base + reg) = value;
}
inline static uint32_t
read_reg(int reg) {
assert(e1000_base);
return *(uint32_t*)(e1000_base + reg);
}
int
pci_e1000_attach(struct pci_func *pcif)
{
pci_func_enable(pcif);
cprintf("pci_e1000_attach reg_base[0] %x reg_size[0] %x\n", pcif->reg_base[0], pcif->reg_size[0]);
return 1;
}
练习 4. mmio_map_regio
在您的附加函数中,通过调用mmio_map_region(您在实验 4 中编写以支持内存映射 LAPIC)为 E1000 的 BAR 0 创建虚拟内存映射 。
volatile void *e1000_base = 0;
inline static void
write_reg(int reg, uint32_t value) {
assert(e1000_base);
*(uint32_t*)(e1000_base + reg) = value;
}
inline static uint32_t
read_reg(int reg) {
assert(e1000_base);
return *(uint32_t*)(e1000_base + reg);
}
...
e1000_base = mmio_map_region(pcif->reg_base[0], pcif->reg_size[0]);
assert(read_reg(E1000_STATUS) == 0x80080783);
...
练习 5.执行第 14.5 节(但不是其小节)中描述的初始化步骤。
注意这里都需要使用物理地址。
struct tx_desc TXDarray[TDARRAY_SIZE] = {
0};
char tx_buffer[TDARRAY_SIZE * 1518] = {
0};
for (int i = 0;i < TDARRAY_SIZE; ++i) {
TXDarray[i].addr = PADDR((tx_buffer + i * 1518));
TXDarray[i].status |= 1;
//TXDarray[i].length = 1518;
}
write_reg(E1000_TDBAH, 0);
write_reg(E1000_TDBAL, PADDR