# 使用 Rust 实现 e1000 驱动

是的。我又来了。上次做了[使用 Rust 实现 VirtIO 驱动](https://jia.je/programming/2019/01/29/virtio-drivers-implementation/index.md)之后，继续往 rCore 加更多的驱动支持。由于现在工作重点是 x86_64 下的 syscall 实现，所以选了一个比较有代表性的驱动 e1000 来实现。其实如果只是为了在 qemu 下运行的话，其实只需要支持 virtio-pci 就可以了，原来的 virtio-net 直接拿来用就可以了。

为什么挑 e1000 呢，一方面是支持的设备多，有真实硬件可以测试，虽然不一定要裸机上跑，但是可以通过 PCI passthrough 来测试驱动的正确性。另一方面是网上的资料比较多，有现成的简单的代码可以借鉴。这次主要借鉴了三个来源：一是 Biscuit OS，二是 Judge Duck OS，三是 Linux。

首先是实现了简单的 PCI 总线的枚举，然后找到对应的设备，激活，并且找到映射的内存地址，然后把原来 C 语言的实现搬运到 Rust 中。这个过程中遇到很多坑，例如一开始我以为内核里 pa 和 va 是一个固定的偏移，不过多次尝试后才发现这个假设只对 riscv 平台里的实现成立。

这个时候就可以收到外面给进来的以太网帧了。接着就是把它接入到 smoltcp 的 API 中。但是发包又不工作了，尝试了很多次，各种方法也不行。其中特别要提到的就是 qemu 的 tracing API，它在帮助我调试之前的 virtio 驱动和这次的 e1000(e) 驱动中起到了很大的帮助。不过，遗憾的是，发包相关的代码里的 trace 不足以让我找到问题的所在，我只好采用了最后一招：

下载 QEMU，自己改，然后自己编译。

这个方法果然很有效啊，经过简单的几个修改，很快就定位到问题所在了，原来就是一个简单的错误，把 4 写成了 8。这个过程中我也发现 QEMU 在 incremental build 的时候似乎会 segfault，我没管这么多，反正编译也不慢，次数也不多，每次 clean 再 build 问题也不大。

接下来要摸索 82559 的网卡适用情况如何，因为有一个真实的 82559 网卡可供测试。另一方面就要开始考虑 socket 那一套 syscall 怎么做了。
