自制工业控制系统:网络驱动与协议栈实战——e1000有线网卡、USB无线路径与自研TCP/IP
Contents
起因
盘能读写、U 盘能交换之后,还缺一条跟外界说话的路:程序下发、参数上传、车间 MES 对接、NTP 校时,后面合规篇的 4G 远程管控,载体全是网。要自研的这套东西年纪都不小:以太网是 Metcalfe 1973 年在 Xerox PARC 写进备忘录的实验,1980 年 DIX 三家(DEC/Intel/Xerox)把它定成标准;TCP/IP 是 Cerf 和 Kahn 1974 年的论文,1983 年 1 月 ARPANET 整网切换换来一战成名。半个世纪过去骨架没换,换的只是速度——自研协议栈要实现的正是这套稳定了几十年的骨架。这篇分三块:有线网卡驱动(PCIe 以太网控制器,寄存器级)、无线的现实路径(USB Wi-Fi 的坑与替代方案)、以及之上的自研 TCP/IP 协议栈——延续零依赖原则,一个字节的外部代码都不引。
一、有线网卡:以 Intel e1000 为参考实现
选型理由:e1000(8254x 系列)寄存器文档公开、行为经典(描述符环模型是几乎所有网卡的原型)、QEMU 原生模拟(-device e1000,netdev=n0 -netdev user,id=n0)——真机工业板上最常见的 Realtek r8169 也是同款描述符环思路,换个寄存器表而已。
PCIe 枚举认亲:Vendor 0x8086、Device 0x100E(QEMU 的 82540EM),BAR0 是寄存器窗口。关键寄存器(BAR0 偏移):
| 偏移 | 名称 | 用途 |
|---|---|---|
| 0x0000 | CTRL | 全局控制(复位、链路使能) |
| 0x0008 | STATUS | 链路状态/速率 |
| 0x0014 | EERD | EEPROM 读(MAC 地址的原始出处) |
| 0x00D0 / 0x00D8 | IMS / IMC | 中断使能/屏蔽 |
| 0x2800–0x2818 | RDBAL/RDBAH/RDLEN/RDH/RDT | 接收描述符环:基址/长度/头/尾 |
| 0x3800–0x3818 | TDBAL/TDBAH/TDLEN/TDH/TDT | 发送描述符环 |
| 0x5400–0x5404 | RAL / RAH | MAC 地址寄存器(读它也能拿本机 MAC) |
描述符环是网卡驱动的核心抽象:一块 DMA 内存排成环,每项 16 字节,指向一个包缓冲区。初始化按这个顺序来:
|
|
描述符本体(legacy 格式):RX 项 = 缓冲地址 8B + 长度 2B + 校验 2B + 状态 1B(bit0 DD、bit1 EOP)+ 错误 1B + 特殊 2B;TX 项 = 缓冲地址 8B + 长度 2B + CSO/CSS 各 1B + CMD 1B(bit0 EOP、bit1 IFCS、bit3 RS) + 状态 1B + 特殊 2B。DD(Descriptor Done)是唯一可靠的动作信号,收发都看它。
收包:网卡 DMA 写完一个包,把对应 RX 描述符的 DD 位置 1 并触发中断;ISR(设备向量区)只做"把描述符索引进环形队列",协议逻辑一概不碰,协作层的网络任务慢慢消费:读包缓冲 → 处理 → 描述符回填新缓冲地址(状态清零)→ 推进 RDT,网卡才认这个槽还回来了。发包:填 TX 描述符(缓冲地址、长度、CMD 置 EOP|IFCS|RS)→ 推进 TDT → 网卡搬完置 DD,同一槽位下一帧要等 DD。中断上半部轻、协议处理下半部重,跟 NVMe 的完成队列一个套路。
二、无线网卡(USB):为什么不直连
USB Wi-Fi 是裸机驱动里公认的天花板之一,难点不在 USB 传输(EHCI 篇已解决)而在设备本身:
- 固件加载:多数 USB Wi-Fi 芯片(Realtek RTL8188/8821 系列最常见)上电时 RAM 是空的,主机要通过控制/批量传输把几百 KB 固件灌进去——固件二进制从厂商驱动里提取,许可和来源都是灰色地带
- 802.11 管理层(MLME):扫描、关联、四次握手、密钥派生,一套完整的状态机,工作量比有线网卡大一个量级
工程上给两条路,推荐第一条:
- 无线网桥方案(推荐):机箱里加一个 USB 供电的 Wi-Fi 桥/随身路由,它对外是 Wi-Fi、对内是以太网口——我们的系统只看见一块普通 e1000/r8169 有线网卡,无线复杂性整体外包给成品硬件。工业现场这本来就是主流做法(4G/5G 路由器同理)。USB 4G 模块直插还有条中间路:RNDIS/CDC-NCM 本质是"USB 上的以太网",控制传输建好通道后批量端点跑的就是以太网帧,当第二块网卡挂进同一个协议栈(合规篇的 4G 远程管控走这条)——比 USB Wi-Fi 少了固件灌载和 MLME 两座山,量级接近有线网卡
- 直连 USB Wi-Fi(按需立项):如果必须直连(成本/结构限制),锁定一款芯片(如 RTL8188CUS 级别)单点突破:vendor 特定命令走控制传输、固件灌载、然后是 802.11 数据帧收发 + MLME。当成一个独立项目排期,不塞进基础篇
三、TCP/IP 协议栈:自己写一个最小的
延续零外部依赖原则(smoltcp 这类现成栈按许可证纪律 vendor 也可以,但自写一个工业最小栈比想象中可行,且完全可控)。分层与各层的"最小可用集":
以太网层:帧头 14 字节(目的 MAC/源 MAC/类型),类型表就三个——0x0800 IPv4、0x0806 ARP、(0x86DD IPv6 留位不做)。收发直接对接 e1000 的包缓冲。
ARP:维护一张 16 项的 IP→MAC 缓存;收到请求若目标是自己 IP 就应答;发包前查表,没有就广播请求并暂存待发包。表项带老化时间(TSC 时间戳——APIC 篇的钟再立一功)。
IPv4:头校验和(16 位反码和)必验必算,一个函数两头用:
|
|
发包时校验和字段先清零、算完填入;收包验算把整头(含校验和)喂进去,结果非 0 直接丢。分片直接不支持(以太网内 MTU 1500,工控网可控,遇到分片丢弃并计数);协议号只认 ICMP(1)/UDP(17)/TCP(6)。
ICMP:回显请求→应答,ping 通了链路就活了——调网第一工具,几十行代码。
UDP + DHCP:UDP 头 8 字节,校验和在 IPv4 里允许填 0(表示不算)——最小栈先填 0 省事,链路层有以太网 FCS 兜底;要做端到端校验再按"伪头+数据"补反码和。第一个应用就是 DHCP 客户端:广播 DISCOVER(UDP 67/68)→ 收 OFFER → REQUEST → ACK,从选项段(魔数 0x63825363 后)解析出本机 IP/掩码/网关/DNS;每个包带随机 4 字节 xid,回包先核对 xid 再收——不核对,网络上别的 DHCP 应答会混进你的配置。500ms 无应答重发,三连失败在界面上报"网络故障"而不是干等。没有 DHCP 的车间就静态配置——两条路都留。
TCP:难点全在这,但工业场景能砍掉大半通用复杂度。状态机收敛为:CLOSED → LISTEN → SYN_RCVD → ESTABLISHED → FIN_WAIT/CLOSE;连接表固定 8 槽(现场对接 MES/上位机用不了几个连接);滑动窗口做简化版(固定窗口,不做动态拥塞控制——车间内网不是互联网,丢包率是另一个量级,这个减法说得过去,注释里写明前提);重传定时器用 APIC 定时器驱动,200ms 起步指数退避,3 次封顶报断线。三次握手、序号确认、FIN 挥手——骨架省不得,两个细节也别漏:SYN 里把 MSS 选项写成 1460,不发这个选项对端按默认 536 切包,吞吐直接废掉;收到不属于任何连接的四元组段回 RST 而不是静默丢弃,丢弃会让对端一直重传干等到超时。
应用层先立三个:NTP 客户端(UDP,校时回写 RTC——接上系统时间篇)、TFTP(UDP,最简单的文件传输,配合 exFAT 做程序下发)、Modbus/TCP(本站有 Modbus 基础,工业现场对接现成协议)。
四、网络任务在两级模型里的位置
整个协议栈跑在协作层:一个 net_step 函数,每轮消费 RX 队列里的包描述符 → 逐层解封装 → 分发给 ARP/DHCP/TCP 状态机 → 汇集待发包走 TX 环。网卡中断只进 ISR 搬索引,不碰任何协议逻辑。多核篇把双核分工定下来之后,net_step 归 Core1 的服务循环;网络的事毫秒级抖动无所谓,Core0 上插补和放电的微秒级节拍根本看不见它。RX 队列深度要按"最坏卡顿 × 线速"算:协作层要是被日志落盘卡住几百毫秒,64 项的环形队列会绕圈覆盖——覆盖发生时记一条错误日志,别静默吞包。
总结
实战清单:e1000 认亲(0x8086:0x100E)、RX/TX 描述符环五步初始化、DD 位+RDT/TDT 的收发配合、中断上半部只搬索引;无线走网桥方案(直连 USB Wi-Fi 是独立量级的项目,固件灌载+MLME 是两座山);协议栈最小集=以太网+ARP+IPv4+ICMP+UDP(DHCP)+简化 TCP,反码和校验、8 槽连接表、固定窗口,应用层 NTP/TFTP/Modbus 起步。跑通标志:QEMU -netdev user 下 DHCP 拿到 10.0.2.15,宿主机 ping 通,TFTP 传来一个文件写进 exFAT 盘。物理层到应用层,网这条路也全是自己的代码。下一篇收拾平台:电源控制、风扇调速、内存信息获取。
参考链接
- Intel 8254x 千兆网卡控制器数据手册——寄存器与描述符格式权威定义
- OSDev Wiki: Intel 8254x / Network Stack
- RFC 791 / 792 / 793 / 826 / 2131——IPv4/ICMP/TCP/ARP/DHCP 原始定义
- 本系列 EHCI 篇:USB 2.0主机控制器实战、APIC 篇:定时器与系统时间实战
- 本系列第一篇:自制工业控制系统:从UEFI到内核
Author 软件开发大郭
LastMod 2026-09-11