orangpione利用usb共享网络(RNDIS)实现tftp加载内核挂载到NFS根文件系统

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,相关配置如下图所示,这里要选择一个可以上外网的网卡进行桥接
hyperv交换机

   3、在编译好后,在开发板上电并进行网络通信的时候会在设备管理器出现RNDIS相管的提示信息,如果没有驱动,则按照https://www.mobileread.com/forums/showthread.php?p=3283986网址上的驱动方式对RNDIS进行驱动,先下载kindle_rndis.inf_amd64-v1.0.0.1.zip并解压,再执行第5个cmd脚本注册驱动签名,然后再设备管理器更新驱动管理程序,选择下载的驱动目录进行驱动,如果驱动成功,则在设备管理器会显示下面的驱动
RNDIS驱动

  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功能

  1. 在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

  1. 配置完成后,使用脚本命令./build.sh -j4进行uboot编译,如无意外,则可以正常编译通过,通过orangpi相关烧录指引,把sdcard.img烧录到sd卡中
  2. 烧录完成后,插入sd卡。连接调试串口,并启动orangepi,在uboot3s后输入空格停下启动信息,如下图所示


    stop uboot

2、测试uboot的RNDIS网络是否正常

  1. 在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
  1. 这里ping的ip是虚拟机的ip地址,需要查看uboot是否可以和虚拟机通讯,如果出现下图类似情况ip is alive则通讯成功


    ping

三、kernel的RNDIS测试

1、配置编译kernel的RNDIS功能

  1. 在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
  1. 通过源码修改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     }
  1. 配置修改完成后,使用脚本命令./build.sh -j4进行uboot编译,如无意外,则可以正常编译通过,通过orangpi相关烧录指引,把sdcard.img烧录到sd卡中

2、测试kernel的RNDIS网络是否正常

  1. 重新上电后,等等其加载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
  1. 通过ifconfig -a查看是否存在usb0网卡,如果存在usb0网卡,说明网卡正常驱动
  2. 启动usb0网卡且对其进行配置ifconfig usb0 up && ifconfig usb0 192.168.137.2 netmask 255.255.255.0
  3. 配置默认网关route add default gw 192.168.137.1
  4. 测试是否可以ping通虚拟机ping 192.168.1.111,如果正常ping通说明网络成功通讯
  5. 通过命令/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
  1. 通过命令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
  1. 通过命令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功能是否正常

  1. 在虚拟机服务器端开启nfs服务
  2. 在虚拟机通过命令ln -s nfsroot nfs创建nfs文件的的软连接,nfsroot是实际的根文件系统目录,而后面的nfs是创建的软连接目录
  3. 在虚拟机通过命令sudo vi /etc/exports修改文件内容,添加类似的内容/home/vencol/code/nfs *(insecure,rw,sync,no_root_squash,no_subtree_check)
  4. 在虚拟机通过命令sudo /etc/init.d/nfs-kernel-server restart重启nfs服务
  5. 在开发创建nfsdir目录,并且通过命令mount -t nfs -o nolock 192.168.1.111:/home/vencol/code/nfs nfsdir,如果挂载成功通过ls nfsdir则可以看到nfs根文件系统的内容。

四、综合测试RNDIS网络

1、通过uboot手动测试tftp加载kernel启动

  1. 由于前面我们使用了saveenv命令来保存uboot的环境参数,所以这里我们只要没有重新烧录,都可以不用再次设置,如果需要设置,请参考【测试uboot的RNDIS网络是否正常】章节内容
  2. 我们在虚拟机上通过执行./build.sh cp命令把zImage和sun8i-h3-orangepi-one.dtb设备树文件拷贝到我们的tftp服务器目录下。
  3. 我们在开发板上设置bootargs参数为setenv bootargs "console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait"并且通过saveenv保存该参数
  4. 在开发板上,使用tftp 0x42000000 zImage加载zimage到内存,通过tftp 0x43000000 sun8i-h3-orangepi-one.dtb加载设备树到内存
  5. 在开发板上,通过bootz 0x42000000 - 0x43000000启动内核,如无意外,可以成功进入登录界面,但是这时加载的是mmc根文件系统,下面我们开始加载nfs文件系统

2、通过uboot手动测试tftp加载kernel挂载nfs启动

  1. 在前面已经可以正常加载mmc根文件系统的前提下,进行nfs文件系统的加载
  2. 在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则是根据我们的实际情况设置,由于这里虚拟机和开发板不在同一网段,所以需要填写网关和掩码信息
  3. 在开发板上,使用tftp 0x42000000 zImage加载zimage到内存,通过tftp 0x43000000 sun8i-h3-orangepi-one.dtb加载设备树到内存
  4. 在开发板上,通过bootz 0x42000000 - 0x43000000启动内核,如无意外,可以成功进入登录界面,但是这时加载的是mmc根文件系统,下面我们开始加载nfs文件系统
  5. 出现问题排查

1.nfs服务器端的传输协议是否和开发版客户端的协议一致,如果不一致,在bootargs添加nfsserver=2,这里2是nfs2的意思,对应版本即可

  1. 查看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```
  2. 在源码文件init/do_mounts.c的do_mount_root函数中调用的do_mount函数返回的错误打印出来,查看错误码是什么,如果错误码为-93,那么就是服务器版本不对,这里有可能是下面4这点的问题。在服务器端用nfsstat -s查看版本,如果是其他错误可以参考/var/log/syslog中nfs的输出日志。
  3. 低版本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启动脚本

  1. boot.scr是通过mkimage工具生成的,这里我们需要先拷贝buildroot中orangepione的boot.cmd文件到脚本目录,在这个文件的基础上进行修改,其目录在buildroot/board/orangepi/orangepi-one/boot.cmd
  2. 修改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
  1. 通过脚本命令./build.sh env生成boot.scr文件在当前目录中
  2. 把boot.scr文件拷贝到nfs目录的root目录下
  3. 在开发板已经正常进入mmc根文件系统的情况下,挂载nfs目录到nfsdir目录中
  4. 通过命令mount /dev/mmcblk0p1 /mnt/fat/挂载boot分区到/mnt/fat/
  5. 把nfs目录的boot.scf拷贝到boot分区cp nfsdir/root/boot.scr /mnt/fat
  6. 确认boot分区的boot.scr文件更新后,卸载boot分区,并重启umount /mnt/fat && reboot
    如无意外,则可以看到类似的挂nfs信息出现
    nfs

:

你可能感兴趣的:(orangpione利用usb共享网络(RNDIS)实现tftp加载内核挂载到NFS根文件系统)