https://www.mobileread.com/forums/showthread.php?p=3283986
目录结构说明
一、环境说明
1、环境介绍
2、RNDIS介绍
3、网络环境配置
4、编译脚本说明
二、uboot的RNDIS测试
1、配置编译uboot的RNDIS功能
2、测试uboot的RNDIS网络是否正常
三、kernel的RNDIS测试
1、配置编译kernel的RNDIS功能
2、测试kernel的RNDIS网络是否正常
3、测试kernel的RNDIS网络的nfs功能是否正常
四、综合测试RNDIS网络
1、通过uboot手动测试tftp加载kernel启动
2、通过uboot手动测试tftp加载kernel挂载nfs启动
3、把测试启动的nfs命令转换成boot.scr启动脚本
一、环境说明
1、环境介绍
首先这里我们需要安装一些基础的编译环境,安装tftp服务器,安装nfs服务器等,这里我们可以参考文章《用buildroot编译整个系统,用qemu仿真vexpressa9》中的环境准备章节,自行安装相关服务,在这里不展开。
2、RNDIS介绍
RNDIS是指Remote NDIS,基于USB实现RNDIS实际上就是TCP/IP over USB,就是在USB设备上跑TCP/IP,让USB设备看上去像一块网卡。简单的来说,就是通过USB模拟了一个网卡,这样我们可以通过这个网卡实现和虚拟机的联机,以及正常的网络访问。相关内容可以参考网站https://zhidao.baidu.com/question/1930394656632188907.html
3、网络环境配置
1、这里我们实现的网络环境配置如下图所示。在win10主机上虚拟一个网桥,win10主机和Ubuntu虚拟机通过这个网桥连接到无线网络,访问外网。同时orangepione开发板则通过USB实现与win10主机的RNDIS网络共享。通过主机访问外网。
2、通过win10的hyperv创建虚拟网桥,把虚拟机的网络和主机的网络通过网桥桥接起来。在hyperv管理器上面找的虚拟交换机管理器,并点击新建虚拟交换机网络,这里名字随意就好,我这里的名字叫做hyper-net,相关配置如下图所示,这里要选择一个可以上外网的网卡进行桥接
3、在编译好后,在开发板上电并进行网络通信的时候会在设备管理器出现RNDIS相管的提示信息,如果没有驱动,则按照https://www.mobileread.com/forums/showthread.php?p=3283986网址上的驱动方式对RNDIS进行驱动,先下载kindle_rndis.inf_amd64-v1.0.0.1.zip并解压,再执行第5个cmd脚本注册驱动签名,然后再设备管理器更新驱动管理程序,选择下载的驱动目录进行驱动,如果驱动成功,则在设备管理器会显示下面的驱动
4、设置和主机的网络共享,在驱动成功后,需要在更改适配器选项界面,设置共享配置,这里选择共享的是之前hyperv桥接的网卡,这里建议把hyperv桥接网卡的ip设置为静态ip,后面共享的网卡需要通过该网卡的ip进行dns解析,配置如下图所示
这里如果配置不成功,后面会不能正常通讯
4、编译脚本说明
这里我们和还是使用文章《用buildroot编译整个系统,用qemu仿真vexpressa9》提到的buildroot环境进行开发。但是我们这里稍微改变了一下在orangepione目录下的脚本build.sh,脚本的主要功能是编译,和拷贝文件到tftp目录,以及修改生成boot.scr文件,可能需要根据实际的情况进行相关的调整
#! /bin/bash
NPWD=`realpath .`
echo $NPWD
if [ $1_x == cp_x ];then
cp $NPWD/rootfs/build/linux-custom/arch/arm/boot/zImage ~/tftp
cp $NPWD/rootfs/build/linux-custom/arch/arm/boot/dts/sun8i-h3-orangepi-one.dtb ~/tftp
elif [ $1_x == env_x ];then
/home/vencol/code/buildroot/host/bin/mkimage -C none -A arm -T script -d $NPWD/boot.cmd $NPWD/boot.scr
cp $NPWD/boot.scr $NPWD/rootfs/images/boot.scr
else
cd $NPWD/../buildroot
mkdir -p $NPWD/rootfs
make O=$NPWD/rootfs ARCH=arm $1
fi
二、uboot的RNDIS测试
1、配置编译uboot的RNDIS功能
- 在orangepi目录执行
./build.sh uboot-menuconfig
会弹出uboot的menuconfig的配置界面,我们的配置选项如下 Device Drivers --->USB support --->
EHCI HCD (USB 2.0) support --->CONFIG_USB_EHCI_HCD
Support for generic EHCI USB controller--->CONFIG_USB_EHCI_GENERIC
MUSB gadget mode support--->CONFIG_USB_MUSB_GADGET
Enable sunxi OTG / DRC USB controller--->CONFIG_USB_MUSB_SUNXI
Disable MUSB bulk split/combine--->CONFIG_USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
Disable DMA (always use PIO)--->CONFIG_USB_MUSB_PIO_ONLY
USB Gadget Support--->CONFIG_USB_GADGET
(0x0525) Vendor ID of the USB device--->CONFIG_USB_GADGET_VENDOR_NUM
(0xA4A2) Product ID of the USB device--->CONFIG_USB_GADGET_PRODUCT_NUM
USB Ethernet Gadget--->CONFIG_USB_ETHER
USB Ethernet Gadget Model (RNDIS Protocol)--->CONFIG_USB_ETH_RNDIS
(de:ad:be:ef:00:01) USB Gadget Ethernet device mac address--->CONFIG_USBNET_DEVADDR
(de:ad:be:ef:00:00) USB Gadget Ethernet host mac address--->CONFIG_USBNET_HOST_ADDR
- 配置完成后,使用脚本命令
./build.sh -j4
进行uboot编译,如无意外,则可以正常编译通过,通过orangpi相关烧录指引,把sdcard.img烧录到sd卡中 -
烧录完成后,插入sd卡。连接调试串口,并启动orangepi,在uboot3s后输入空格停下启动信息,如下图所示
2、测试uboot的RNDIS网络是否正常
- 在uboot停止的页面输入下面的内容
usb start
setenv ethact usb_ether
setenv ipaddr 192.168.137.2
setenv netmask 255.255.255.0
setenv gatewayip 192.168.137.1
saveenv
ping 192.168.1.111
-
这里ping的ip是虚拟机的ip地址,需要查看uboot是否可以和虚拟机通讯,如果出现下图类似情况ip is alive则通讯成功
三、kernel的RNDIS测试
1、配置编译kernel的RNDIS功能
- 在orangepi目录执行
./build.sh linux-menuconfig
会弹出kernel的menuconfig的配置界面,我们的配置选项如下
RNDIS选项的配置 (这里一开始我们先配置为模块,调用g_ether.ko,调试通过后再编译进内核)Device Drivers --->USB support --->
Support for Host-side USB--->CONFIG_USB
Enable USB persist by default--->CONFIG_USB_DEFAULT_PERSIST
EHCI HCD (USB 2.0) support--->CONFIG_USB_EHCI_HCD
Improved Transaction Translator scheduling--->CONFIG_USB_EHCI_TT_NEWSCHED
Generic EHCI driver for a platform device--->CONFIG_USB_EHCI_HCD_PLATFORM
OHCI HCD (USB 1.1) support--->CONFIG_USB_OHCI_HCD
Generic OHCI driver for a platform device--->CONFIG_USB_OHCI_HCD_PLATFORM
Inventra Highspeed Dual Role Controller--->CONFIG_USB_MUSB_HDRC
MUSB Mode Selection (Gadget only mode)--->CONFIG_USB_MUSB_GADGET
Allwinner (sunxi)--->USB_MUSB_SUNXI
USB Gadget Support--->CONFIG_USB_GADGET
USB Gadget precomposed configurations--->
Ethernet Gadget (with CDC Ethernet support)--->CONFIG_USB_ETH
RNDIS support--->CONFIG_USB_ETH_RNDIS
NFS网络选项的配置 Networking support --->Networking options --->
TCP/IP networking--->CONFIG_INET
IP: kernel level autoconfiguration--->CONFIG_IP_PNP
IP: DHCP support--->CONFIG_IP_PNP_DHCP
IP: BOOTP support--->CONFIG_IP_PNP_BOOTP
NFS文件系统选项的配置 File systems --->Network File Systems --->
NFS client support--->CONFIG_NFS_FS
NFS client support for NFS version 2--->CONFIG_NFS_V2
NFS client support for NFS version 3--->CONFIG_NFS_V3
NFS client support for the NFSv3 ACL protocol extension--->CONFIG_NFS_V3_ACL
NFS client support for NFS version 4--->CONFIG_NFS_V4
Root file system on NFS--->CONFIG_ROOT_NFS
- 通过源码修改kernel的ubs0网卡地址,因为如果不修改地址,每次重启都会产生一个随机的网卡地址,那么win10这边识别的就不是前面设置的共享网卡了,这里我们需要把网卡设置成和uboot的网卡地址一样,这里我么需要修改的文件是,kernel源码下面的u_ether.c文件的gether_setup_name_default函数添加usb网卡的判断,当识别到usb网卡的时候,设置其默认的host地址为de:ad:be:ef:00:00,dev地址为de:ad:be:ef:00:01
837 snprintf(net->name, sizeof(net->name), "%s%%d", netname);
838
839 if(memcmp(netname, "usb", 3) == 0)
840 {
841 eth_random_addr(dev->dev_mac);
842 pr_warn("using usb my random %s ethernet address\n", "self");
843 eth_random_addr(dev->host_mac);
844 pr_warn("using usb my %s ethernet address\n", "host");
845 dev->host_mac[0] = 222;
846 dev->host_mac[1] = 173;
847 dev->host_mac[2] = 190;
848 dev->host_mac[3] = 239;
849 dev->host_mac[4] = 0;
850 dev->host_mac[5] = 0;
851
852 dev->dev_mac[0] = 222;
853 dev->dev_mac[1] = 173;
854 dev->dev_mac[2] = 190;
855 dev->dev_mac[3] = 239;
856 dev->dev_mac[4] = 0;
857 dev->dev_mac[5] = 1;
858 }
859 else
860 {
861 eth_random_addr(dev->dev_mac);
862 pr_warn("using random %s ethernet address\n", "self");
863 eth_random_addr(dev->host_mac);
864 pr_warn("using random %s ethernet address\n", "host");
865 }
- 配置修改完成后,使用脚本命令
./build.sh -j4
进行uboot编译,如无意外,则可以正常编译通过,通过orangpi相关烧录指引,把sdcard.img烧录到sd卡中
2、测试kernel的RNDIS网络是否正常
- 重新上电后,等等其加载mmc的根文件系统,加载成功后登陆系统,通过命令
modprobe g_ether
加载模块驱动,如果加载成功,会出现类似的信息
[ 1.526195] usb0: HOST MAC de:ad:be:ef:00:00
[ 1.530505] usb0: MAC de:ad:be:ef:00:01
[ 1.534355] using usb my random self ethernet address
[ 1.539399] using usb my host ethernet address
[ 1.543905] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
[ 1.550519] g_ether gadget: g_ether ready
- 通过
ifconfig -a
查看是否存在usb0网卡,如果存在usb0网卡,说明网卡正常驱动 - 启动usb0网卡且对其进行配置
ifconfig usb0 up && ifconfig usb0 192.168.137.2 netmask 255.255.255.0
- 配置默认网关
route add default gw 192.168.137.1
- 测试是否可以ping通虚拟机
ping 192.168.1.111
,如果正常ping通说明网络成功通讯 - 通过命令
/etc/network/nfs_check
创建网卡启动时对nfs的检查文件
#!/bin/sh
# This allows NFS booting to work while also being able to configure
# the network interface via DHCP when not NFS booting. Otherwise, a
# NFS booted system will likely hang during DHCP configuration.
# Attempting to configure the network interface used for NFS will
# initially bring that network down. Since the root filesystem is
# accessed over this network, the system hangs.
# This script is run by ifup and will attempt to detect if a NFS root
# mount uses the interface to be configured (IFACE), and if so does
# not configure it. This should allow the same build to be disk/flash
# booted or NFS booted.
nfsip=`sed -n '/^[^ ]*:.* \/ nfs.*[ ,]addr=\([0-9.]\+\).*/s//\1/p' /proc/mounts`
if [ -n "$nfsip" ] && ip route get to "$nfsip" | grep -q "dev $IFACE"; then
echo Skipping $IFACE, used for NFS from $nfsip
exit 1
fi
- 通过命令
vi /etc/network/interfaces
添加usb0网卡开机自动挂载
auto usb0
iface usb0 inet static
pre-up /etc/network/nfs_check
address 192.168.137.2
netmask 255.255.255.0
gateway 192.168.137.1
#dns-nameservers 8.8.8.8 192.168.137.1 211.136.20.203
- 通过命令
vi /etc/resolv.conf
配置dns服务器,注意resolv.conf文件不能是链接文件
nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 192.168.137.1
3、测试kernel的RNDIS网络的nfs功能是否正常
- 在虚拟机服务器端开启nfs服务
- 在虚拟机通过命令
ln -s nfsroot nfs
创建nfs文件的的软连接,nfsroot是实际的根文件系统目录,而后面的nfs是创建的软连接目录 - 在虚拟机通过命令
sudo vi /etc/exports
修改文件内容,添加类似的内容/home/vencol/code/nfs *(insecure,rw,sync,no_root_squash,no_subtree_check)
- 在虚拟机通过命令
sudo /etc/init.d/nfs-kernel-server restart
重启nfs服务 - 在开发创建nfsdir目录,并且通过命令
mount -t nfs -o nolock 192.168.1.111:/home/vencol/code/nfs nfsdir
,如果挂载成功通过ls nfsdir
则可以看到nfs根文件系统的内容。
四、综合测试RNDIS网络
1、通过uboot手动测试tftp加载kernel启动
- 由于前面我们使用了saveenv命令来保存uboot的环境参数,所以这里我们只要没有重新烧录,都可以不用再次设置,如果需要设置,请参考【测试uboot的RNDIS网络是否正常】章节内容
- 我们在虚拟机上通过执行
./build.sh cp
命令把zImage和sun8i-h3-orangepi-one.dtb设备树文件拷贝到我们的tftp服务器目录下。 - 我们在开发板上设置bootargs参数为
setenv bootargs "console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait"
并且通过saveenv保存该参数 - 在开发板上,使用
tftp 0x42000000 zImage
加载zimage到内存,通过tftp 0x43000000 sun8i-h3-orangepi-one.dtb
加载设备树到内存 - 在开发板上,通过
bootz 0x42000000 - 0x43000000
启动内核,如无意外,可以成功进入登录界面,但是这时加载的是mmc根文件系统,下面我们开始加载nfs文件系统
2、通过uboot手动测试tftp加载kernel挂载nfs启动
- 在前面已经可以正常加载mmc根文件系统的前提下,进行nfs文件系统的加载
- 在uboot界面停下,由于前面保存了相关的环境变量,这里我们直接进行bootargs参数的修改,通过命令修改bootargs参数为,
setenv bootargs root=/dev/nfs rw rootpath=/home/vencol/code/nfs nfsroot=192.168.1.111:/home/vencol/code/nfs,nolock ip=192.168.137.2:192.168.1.111:192.168.137.1:255.255.255.0 console=ttyS0,115200 nfsvers=2
这里的rootpath是虚拟机上nfs根文件的地址,而ip则是根据我们的实际情况设置,由于这里虚拟机和开发板不在同一网段,所以需要填写网关和掩码信息 - 在开发板上,使用
tftp 0x42000000 zImage
加载zimage到内存,通过tftp 0x43000000 sun8i-h3-orangepi-one.dtb
加载设备树到内存 - 在开发板上,通过
bootz 0x42000000 - 0x43000000
启动内核,如无意外,可以成功进入登录界面,但是这时加载的是mmc根文件系统,下面我们开始加载nfs文件系统 - 出现问题排查
1.nfs服务器端的传输协议是否和开发版客户端的协议一致,如果不一致,在bootargs添加nfsserver=2,这里2是nfs2的意思,对应版本即可
- 查看nfs根文件系统中的/dev目录是否存在,/dev/console和/dev/null,如果不存在通过下面命令创建
sudo mknod console c 5 1 //创建console字符设备,
sudo mknod null c 1 3 //创建null 字符设备,
sudo chown 1000:1000 console null```- 在源码文件init/do_mounts.c的do_mount_root函数中调用的do_mount函数返回的错误打印出来,查看错误码是什么,如果错误码为-93,那么就是服务器版本不对,这里有可能是下面4这点的问题。在服务器端用
nfsstat -s
查看版本,如果是其他错误可以参考/var/log/syslog
中nfs的输出日志。- 低版本uboot和高版本ubuntu搭配进行开发时,发现nfs不能使用.uboot默认启动协议为2.而高版本的ubuntu17之后nfs就默认支持3和4,因此需要ubuntu支持协议2。在文件
/etc/default/nfs-kernel-server
末尾添加RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog"
,然后重启nfs服务。
3、把测试启动的nfs命令转换成boot.scr启动脚本
- boot.scr是通过mkimage工具生成的,这里我们需要先拷贝buildroot中orangepione的boot.cmd文件到脚本目录,在这个文件的基础上进行修改,其目录在
buildroot/board/orangepi/orangepi-one/boot.cmd
- 修改boot.cmd文件如下,其中rootdelay=3看具体情况使用
setenv fdt_high ffffffff
usb start
setenv ethact usb_ether
setenv ipaddr 192.168.137.2
setenv gatewayip 192.168.137.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.111
#setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
setenv bootargs root=/dev/nfs rw rootpath=/home/vencol/code/nfs nfsroot=192.168.1.111:/home/vencol/code/nfs,nolock ip=192.168.137.2:192.168.1.111:192.168.137.1:255.255.255.0 console=ttyS0,115200 nfsvers=2 rootdelay=3
tftp $kernel_addr_r zImage
tftp $fdt_addr_r sun8i-h3-orangepi-one.dtb
bootz $kernel_addr_r - $fdt_addr_r
#fatload mmc 0 $kernel_addr_r zImage
#fatload mmc 0 $fdt_addr_r sun8i-h3-orangepi-one.dtb
#bootz $kernel_addr_r - $fdt_addr_r
- 通过脚本命令
./build.sh env
生成boot.scr文件在当前目录中 - 把boot.scr文件拷贝到nfs目录的root目录下
- 在开发板已经正常进入mmc根文件系统的情况下,挂载nfs目录到nfsdir目录中
- 通过命令
mount /dev/mmcblk0p1 /mnt/fat/
挂载boot分区到/mnt/fat/ - 把nfs目录的boot.scf拷贝到boot分区
cp nfsdir/root/boot.scr /mnt/fat
- 确认boot分区的boot.scr文件更新后,卸载boot分区,并重启
umount /mnt/fat && reboot
如无意外,则可以看到类似的挂nfs信息出现
: