之前在VMware 10.0上成功安装了NetBSD-1.0,虽然系统在每次重启的时候会弹出一个错误提示框,而且有时候系统启动还会提示“ffs vmalloc dup ...”这样的错误,但是总体来讲,至少还是能用的。不过让我最感到遗憾的是系统的网络连接有问题。最开始我以为是网络配置不正确,从网上找了不少资料后才确认,是NetBSD-1.0不能识别虚拟机的网卡导致的。这让我感到很郁闷,毕竟安装NetBSD-1.0的目的就是为了学习《TCP/IP详解 卷2:实现》的,如果不能连接到别的主机,那不是很没意思?
经过一段时间的摸索,确认在VMware 10.0上能连接网络的最近的版本是1.2的。所以我决定把1.2的网卡驱动程序移植到1.0上。经过一个多星期的努力,最终总算是成功了!至少目前ping和ftp传输都是没有问题的。VMware 10.0模拟的是 AMD PCNet 7990 的PCI网卡,但是在1.0的版本上只有ISA接口的驱动,还没有PCI接口的。移植过程中遇到不少问题,内核都编译了40次左右。而且为了保证源文件的一致,都是先在我的本机修改完成,然后才复制到虚拟机上的(在虚拟机上直接修改都没法传会本机)。而NetBSD-1.0的系统既不能加载光盘,又不支持新的软盘(我本机系统使用的是Fedora 20,创建NetBSD-1.0可以加载的软盘镜像文件都只能是只读的,没法往镜像文件里添加文件),每次都只能把修改后的源文件放到一个ISO镜像文件中,然后使用NetBSD-1.3的boot.fs安装镜像启动,复制修改后的源文件到虚拟机的硬盘上,相当麻烦。
NetBSD-1.2系统上支持 AMD PCNet 7990 网卡驱动的,涉及以下几个文件:
/usr/src/sys/dev/pci/if_levar.h
/usr/src/sys/dev/pci/if_le_pci.c -- 网卡驱动程序的系统接口
/usr/src/sys/dev/ic/am7990reg.h
/usr/src/sys/dev/ic/am7990var.h
/usr/src/sys/dev/ic/am7990.c -- 实际的驱动代码文件
驱动模块使用的是“le”这个名字,但是在NetBSD-1.0上已经被ISA接口的驱动使用了,为了避免冲突,移植过来的时候就改用了“tle”这个名字。在NetBSD-1.0上新增/修改的文件列表如下:
/usr/src/sys/arch/i386/pci/pcivar.h -- 为 pci_attach_args 结构增加成员
/usr/src/sys/arch/i386/pci/am7990reg.h -- 从NetBSD-1.2复制过来
/usr/src/sys/arch/i386/pci/am7990var.h -- 从NetBSD-1.2复制过来
/usr/src/sys/arch/i386/pci/tle_pci.h -- 从NetBSD-1.2的 if_levar.h复制过来,并增加了其他必须的声明和定义
/usr/src/sys/arch/i386/pci/tle_pci.c -- 整合了 if_le_pci.c 和 am7990.c
/usr/src/sys/netinet/if_ether.h -- 增加 arp_ifinit 函数的声明
/usr/src/sys/netinet/if_ether.c -- 增加 arp_ifinit 函数的定义。arp_ifinit 函数内部调用的 arprequest 是定义为 static 的,不好放到 tle_pci.c 文件里
文件下载链接:http://files.cnblogs.com/StupidTortoise/tle.zip
编译说明:
在 /usr/src/sys/arch/i386/conf/files.i386 文件中增加 tle_pci.c 文件的声明:
在内核配置文件中增加 tle 驱动模块:
另外,虚拟机需要使用“Workstation 5.x”的硬件兼容选项:
在创建虚拟机的时候使用自定义方式就可以选择了,其他倒没有特殊要求了。
在移植过程中,有两个最大的问题,一个是变量、函数依赖的声明和定义。解决的方式就是根据编译的报错信息一个一个处理,虽然烦琐,但也还算简单。第二个就是野指针的问题。由于两个版本的差异,在NetBSD-1.2版本的内核函数里会对用到的指针做初始化或者赋值,但是1.0版本的根本就没处理。这个问题通常都是直接导致内核core的,只能使用printf输出语句去定位具体的代码行。有个内核选项DDB,但是内核崩溃的时候没法关联源代码(或许可以关联,只是我还不会-_-),还是不能定位出错的代码行。
内核编译通过,第一次运行的时候就core了,核查代码的时候,我很怀疑是在 BUS I/O 的时候直接导致内核core的,对这部分代码调试了很久,还到图书馆借了PCI接口方面的书籍,想了解对PCI的端口是如何操作的。结果书上、网络上能查到的资料都很少,让我预感可能得在这个问题上花很长时间了。由于能查到的资料太少了,所以我采用了另一种方式来找问题,就是运行NetBSD-1.2的内核,看看对应的变量、BUS端口的值差异在哪。结果让我很意外,两个版本的内核输出都是一样的。我郁闷了很久,没头绪的调来调去,偶然的发现 BUS I/O 后面的printf语句是可以正常的输出的!之后往下核查,才发现是一个复制函数的目标参数根本就还没有初始化!这让我感触很大,之前花了那么多的时间和精力,原来一直用在了错误的地方......
PS:内核重新编译好之后,将 /etc/ftpusers 文件中的 root 用户注释掉,并给 root 设置密码,就可以通过 root 用户使用NetBSD-1.0的FTP功能了。