Introduction: Accessing Remote Root Filesystem Using DB410 As a Ethernet Dongle

Objectives:

  • Install toolchain and recompile kernel to insert USB Ethernet CDC Gadget support;
  • Recreate boot.img from Linaro to boot USB Ethernet CDC;
  • Create NFS server to host root filesystem;
  • IP configuration in DEVICE and HOST.

Step 1: Requeriments

You will need the following itens:

  1. A DragonBoard™ 410c (named here DEVICE);
  2. A PC using Ubuntu 16.04.3 updated (named here HOST) with internet connection and SDCard slot;
  3. A clean installation of Linaro-developer version 431 - Link: Snapshot Linaro Debian v431
  4. A HDMI monitor;
  5. A USB keyboard;
  6. A 8Gb SDCard;
  7. A USB cable, uUSB <-> USB to connect the DEVICE on HOST.

Step 2: Configuring Host to Build Kernel and Building Kernel in the HOST

First, we'll create all directories before to continue. So:

$ cd ~
$ mkdir db410remoteroot
$ cd db410remoteroot
$ mkdir toolchain
$ mkdir db410c-modules

Unfortunately, linux kernel used by Linaro (Version 431) doesn't have support for USB Ethernet gadget, due to that, Linux kernel must be rebuilded for this specific version. Download Linaro toolchain to build and deploy linux kernel on Dragonboard410c from x86 host machine.

$ wget https://releases.linaro.org/components/toolchain/binaries/7.3-2018.05/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
$ tar -xf gcc-*-x86_64_aarch64-linux-gnu.tar.xz -C ./toolchain --strip-components=1 

Now install packages which are required to build the kernel:

$ sudo apt update && sudo apt-get install git build-essential abootimg kernel-package fakeroot libncurses5-dev libssl-dev ccache 

Get Linux Kernel source Clone Qualcomm landing team Linux repository:

$ git clone http://git.linaro.org/landing-teams/working/qualcomm/kernel.git
$ cd kernel
$ git checkout origin/release/qcomlt-4.14 -b my-custom-4.14 

Now, set compilation environment variables:

$ export ARCH=arm64
$ export CROSS_COMPILE=$(pwd)/../toolchain/bin/aarch64-linux-gnu-

At this point, we need to add the modules to USB Ethernet CDC in the kernel. I did that before and you can get this in the end of this step. I removed some itens but it's works.

Before to compile, please correct a kernel bug into drivers/mmc/host/sdhci-msm.c changing the struct in the line 1150 to:

static const struct sdhci_ops sdhci_msm_ops = {
    .reset = sdhci_reset,
    .set_clock = sdhci_msm_set_clock,
    .get_min_clock = sdhci_msm_get_min_clock,
    .get_max_clock = sdhci_msm_get_max_clock,
    .set_bus_width = sdhci_set_bus_width,
    .set_uhs_signaling = sdhci_msm_set_uhs_signaling,
    .voltage_switch = sdhci_msm_voltage_switch,
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
    .write_w = sdhci_msm_write_w,
#endif
};

Uncompress configfile.zip, copy .config file to kernel directory, build kernel, modules and install modules in a directory:

$ make -j$(nproc) Image.gz dtbs
$ make -j$(nproc) modules
$ make modules_install INSTALL_MOD_PATH=../db410c-modules

Reference: 96Boards Documentation

Step 3: Rebuild Boot.img in the HOST

In this step, we need to open the initrd image, put the modules built inside the image, configure system to start that modules and rebuild a initrd.img with a new kernel command line to boot root filesystem remotely.

So, first, we have to download initrd.img from linaro website:

$ cd ..
$ mkdir inird_nfs
$ cd initrd_nfs
$ wget -O ramdisk.img http://snapshots.linaro.org/96boards/dragonboard410c/linaro/debian/431/initrd.img-4.14.0-qcomlt-arm64

Now, after download, uncompress and extract the initrd:

$ zcat ramdisk.img | cpio -idmv

In this directory, we have the root filesystem used by kernel in initialization, so we'll configure USB Ethernet CDC modules and NFS remote parameters like NFS server IP and ethernet (usb) needed here.

Now, let's configure some files:

  • conf/initramfs.conf:
MODULES=most
BUSYBOX=auto
COMPRESS=gzip
DEVICE=usb0
NFSROOT=auto
RUNSIZE=10%

Create the directory init-premount in the directory scripts/

$ mkdir scripts/init-premount

and add the files in these just created directory:

  • ORDER
/scripts/init-premount/usb "$@"
[ -e /conf/param.conf ] && . /conf/param.conf
  • usb
#!/bin/sh

PREREQ=""
prereqs()
{
    echo "$PREREQ"
}
case $1 in
# get pre-requisites
prereqs)
    prereqs
    exit 0
    ;;
esac

modprobe usb_f_ecm
modprobe libcomposite
modprobe usb_f_rndis
modprobe g_ether

Don't forget to use chmod in usb file to make it executable:

$ chmod +x scripts/init-premount/usb

Now, copy all directory with the modules from db410c-modules (STEP 2) to lib/modules in initrd:

$ cp -R ../db410-modules/lib usr/

Remove all files in lib/modules/4.14.96-xxxx-dirty except all files module.* and that file list:

kernel/drivers/usb/gadget/legacy/g_ether.ko
kernel/drivers/usb/gadget/legacy/g_mass_storage.ko
kernel/drivers/usb/gadget/legacy/g_cdc.ko
kernel/drivers/usb/gadget/legacy/g_serial.ko
kernel/drivers/usb/gadget/function/usb_f_mass_storage.ko
kernel/drivers/usb/gadget/function/usb_f_acm.ko
kernel/drivers/usb/gadget/function/u_ether.ko
kernel/drivers/usb/gadget/function/usb_f_obex.ko
kernel/drivers/usb/gadget/function/usb_f_serial.ko
kernel/drivers/usb/gadget/function/usb_f_ecm.ko
kernel/drivers/usb/gadget/function/usb_f_rndis.ko
kernel/drivers/usb/gadget/function/u_serial.ko
kernel/drivers/usb/gadget/function/usb_f_fs.ko
kernel/drivers/usb/gadget/function/usb_f_ecm_subset.ko
kernel/drivers/usb/gadget/libcomposite.ko

Those files are all modules needed to start USB Ethernet CDC.

Finally repack and compress the initrd image:

$ find . | cpio -o -H newc | gzip -9 > ../kernel/initrd_nfs.img

At least, the kernel image and DTB file need to be packed into an Android boot image. Such image can be generated with abootimg tool.

Let's in kernel directory and use the command below to build image and append DTB in the compressed kernel image:

$ cd ../kernel
$ cat arch/$ARCH/boot/Image.gz arch/$ARCH/boot/dts/qcom/apq8016-sbc.dtb > Image.gz+dtb 

And finally, generate the boot image (here our rootfs is located a remote partition in 10.42.0.1)

abootimg --create boot-db410c.img -k Image.gz+dtb -r initrd_nfs.img -c pagesize=2048 
-c kerneladdr=0x80008000 -c ramdiskaddr=0x81000000 -c cmdline="root=/dev/nfs 
nfsroot=10.42.0.1:/srv/nfs/rootfs ip=10.42.0.2:10.42.0.1:10.42.0.1:255.255.255.0:db410c:usb0:off rw 
rootwait console=tty0 console=ttyMSM0,115200n8"<br>

References:

Step 4: Creating Root Filesystem in the HOST

Now, we have got a new boot image to update the dragonboard 410c. But we need a root filesystem in the remote server to boot modules, services and applications. In this step, we will build a shared directory in the host to save all these data.
That way, let's download a rootfs filesystem from linaro site with the same version used in initrd. So, go back one directory and download linaro-developer rootfs image with version 431.

$ cd ..
$ wget http://snapshots.linaro.org/96boards/dragonboard410c/linaro/debian/431/dragonboard-410c-sdcard-developer-buster-431.zip

Uncompress this file

$ unzip dragonboard-410c-sdcard-developer-buster-431.zip

Using this file, let's write all image in a sdcard to access all partitions and copy rootfs files. So, ensure that data from uSDCard is backed up because everything on SDCard will be lost.

To find your SDCard device name, remove SDCard and run the following command:

$ lsblk

Save in your mind all recognized disk names. Now insert SDCard, wait a moment and execute the command again:

$ lsblk

Note the newly recognized disk. This will be your SDCard. Remember your name and change the parameter "of=" for your SDCard device name and be sure to use the device name without the partition, p.e.: /dev/mmcblk0

$ sudo dd if=dragonboard-410c-sdcard-developer-buster-431.img of=/dev/XXX bs=4M oflag=sync status=progress

Notes:

  • This command will take some time to execute. Be patient and avoid tampering with the terminal until process has ended.
  • Once SD card is done flashing, remove from host computer.

Reference: 96boards documentation

Step 5: Creating Server NFS in the HOST and Copying Files

In this point, we have a boot image to be flashed into dragonboard 410c and a SDCard with a rootfs filesystem for ours modules, services and applications. The next step is create a remote directory to connect the USB Ethernet DEVICE toguther with HOST rootfs filesystem. That can be done using a package from Ubuntu named nfs-kernel-server.

This package install a NFS service into Ubuntu permiting to share some directories for some devices on the network, we can configure which directory will be used for each device by using yours IP.

So, let's install the package and configure it.

$ sudo apt-get install nfs-kernel-server

The NFS service starts automatically. To control NFS services use:

$ sudo service nfs-kernel-server restart   // to restart, or use 'stop', or 'start' as needed.

To check the status of the NFS service from the command line use:

$ sudo service nfs-kernel-server status
nfsd running          	// Service is Up
nfsd not running     	// Service is Down

Now, let's create a top directory /srv/nfs, and create a subdirectory under that for each NFS mounted root filesystem required. Here we include a shared root filesystem to keep ours root filesystem:

$ sudo mkdir -p /srv/nfs
$ sudo mkdir -p /srv/nfs/rootfs

Now, the NFS server requires /etc/exports to be configured correctly, to control access to each NFS filesystem directory to specific hosts. In this case the hosts are identified by their IP address. So, for each root filesystem that is created, add the export control line to /etc/exports, adjusting for your local IP address and directory naming scheme if necessary. In this tutorial, we always use that:

/srv/nfs/rootfs 10.42.0.2(rw,sync,no_root_squash,no_subtree_check) \

Insert again your SDCard, mount it and copy all rootfs filesystem into /srv/nfs/rootfs, restart NFS service to update the directory using new copied files.

Additionaly, we need copy the new modules files into rootfs filesystem because we compiled the kernel on step 2. So, copy all directories in ~/db410c-modules/ to /srv/nfs/rootfs.

$ sudo cp -R ~/db410c-modules/* /srv/nfs/rootfs/

Ensure that these directories are made visible by the NFS service. Either:

$ sudo exportfs -a

Reference: TFTP/NFS Root Filesystem

Step 6: Updating Dragonboard 410c Boot Image and Configuring Network Interfaces

We made early all steps to implement a remote rootfs filesystem, now we need update the boot image inside dragonboard 410c, for that, connect yours USB cable on PC and on dragonboard uUSB connector. So make sure fastboot is set up on host computer, if not install using:

$ sudo apt install fastboot

Now to update image, start de dragonboard into fastboot mode following this steps:

  • Press and hold the Vol (-) button on the DragonBoard 410c, this is the S4 button. DragonBoard™ 410c should still NOT be powered on
  • While holding the Vol (-) button, power on the DragonBoard 410c by plugging it in
  • Once DragonBoard 410c is plugged into power, release your hold on the Vol (-) button.
  • Wait for about 20 seconds.
  • Board should boot into fastboot mode.

From the connected host machine terminal window, run the following commands:

$ sudo fastboot devices

Typically it will show as below

de82318	fastboot

At this point you should be connected to your DragonBoard 410c with a USB to microUSB cable. Your DragonBoard 410c should be booted into fastboot mode and ready to be flashed with the appropriate images. Let's update boot image with ours boot image:

$ sudo fastboot flash boot ~/db410remoteroot/kernel/initrd_nfs.img

And, restart the board

$ sudo fastboot reboot

Now, your HOST will detect a new interface named usb0, but it hasn't a IP yet. So, add a static IP to this interface using:

$ sudo ifconfig usb0 10.42.0.1 netmask 255.255.255.0 up

Or enter in "Configuration" on HOST, in the item "network", setting USB Ethernet a static IP to that interface.

Now, restart again the dragonboard and verify the system startup, trying to connect using ssh:

$ ssh linaro@10.42.0.2

References: