Creating A Ubuntu Xenial 16.04 rootfs for Zybo and Zynq

In one of my previous blog posts we went over how to make a minimal (sort of) root filesystem using buysbox.  This is great is you don’t need a package manager and want to built all our utilities and frameworks from source yourself. But if you would rather use a distribution to install packages and tools then then using a Ubuntu core distribution would be a good option.

Ubuntu base is basically a small Ubuntu root filesystem that only includes a command line interface.  It’s great starting point for any embedded system.  Even if you need a GUI X11 can be installed and configured.  Ubuntu base does not include a kernel, we need to provide that so it’s not as easy as the distributions you’d download and install on a laptop or desktop.

Before we get started please take a look at this page which basically already does what I’m about the explain.

Let’s download the ubuntu 16.04 Xenial for arm from here, we will need to download the following file ubuntu-base-16.04-core-armhf.tar.gz.

Make a directory where we will be creating our root filesystem, this is what I did on my system

mkdir -p zynq_xenial_rootfs

Now we need to uncompress the base system that we downloaded.  We can uncompress it into the directory we just made.

cd zynq_xenial_rootfs
sudo tar xf ubuntu-base-16.04-core-armhf.tar.gz

In our directory there should be the skeleton of the root filesystem with the correct permission since we uncompressed with sudo.  We still need to configure our serial port to have show our terminal output.  We’ll also create a chroot jail to test out our root filesystem and also install an utilities we may need.  To do this we will need to install qemu.

sudo apt-get install qemu-user-static

So you may be wondering why we want to create a chroot jail using qemu? I’ve used this method when I don’t have access to ethernet on my target board.  There may be situations where you can’t connect to wifi or there is no wired network that allows random devices to optain an IP address.  In these cases we can create our chroot jail and install any packages we need to get moving.

sudo cp $(which qemu-arm-static) zynq_xenial_rootfs/usr/bin/

Next, we are going to bind our hosts systems proc directory to our root filesystem.  This simply allows our chroot file system to use the hosts proc directory.  There is no harm in this and we can safely unmount it when we are done.

sudo mount -t proc proc zynq_xenial_rootfs/proc

We also need to set up the resolv.conf file, we will copy the one from our hosts system over.

sudo cp /etc/resolv.conf zynq_xenial_rootfs/etc/resolv.conf

We can now start our simulated chroot jail by executing the following command

 sudo chroot zynq_xenial_rootfs /bin/bash

We should now see the # sign to show we are logged in as root, we can use the exit command at any time to exit the chroot jail.

There are a couple things we will do using the chroot jail that will help when we first boot into our embedded Linux system.  We will set the root password, create a non-root user and install a couple of packages.

First let’s set the root password

passwd root

Enter the password that you’d like to use for root

Now we can create a non-root

adduser ubuntu

Then you’ll be asked to set a password for the new user.  Now that we’ve set up some users you are pretty much ready to use your system.  Since this system is Ubuntu (debian) based we can try using the package manager to install some utilities we will need.  Let’s try install python3,

apt-get install python3
apt-get install wireless-tools
apt-get install vim
apt-get isntall sudo

I’m assuming you are still logged in as root if not add sudo in front of this.  Install any other packages that your system may need.

One package we will need to install is the udev package.  For some reason it’s not included in the base image and will cause a fair amount of headaches when we are trying to spawn our serial console.  Let’s go ahead and install that, we will see some warnings in the output but we can ignore them.  The warnings are a result of us using a chroot jail.

apt-get -y install udev

In order to log into our system though the uart of the Zybo we need to configure the console login process for ttyPS0 which is UART0 on the ARM processor.  To do this we need to create a file called /etc/init/ttyPS0.conf. 

vi /etc/init/ttyPS0.conf

This file will spawn a console over our uart port on start up, the contents of the file should look like:

start on stopped rc or RUNLEVEL=[12345]
stop on runlevel [!12345]

respawn
exec /sbin/getty -L 115200 ttyPS0 vt102

Next we need to add ttyPS0 to the UART section in the file /etc/securetty.  We also need to edit the /etc/fstab file so that our root filesystem is mounted on start up.  Our /etc/fstab file should look like:

/dev/mmc.blk0p2 /   ext4    relatime,errors=remount-ro  0   1

I edited all my files with vi, which is why we installed it in the previous step.  Since we are done with our chroot environment we can type in exit on the command line and we should be back in our proper host system.

All that’s left to do now is to edit a couple of files on the linux and uboot side of things and we are good to go.

First we’ll need to edit the zynq-common.h file in u-boot so that we don’t try to load the initramfs filesystem anymore.

Back in our host environment we can switch into our u-boot source directory. We will need to edit the file include/configs/zynq-common.h

We will need to remove the following lines:

"load mmc 0 ${ramdisk_load_address} ${ramdisk_image} && " \
"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}; " 

Replace it with the following line :

"bootm ${kernel_load_address} - ${devicetree_load_address}; "  

Now u-boot should look for or try to load the ram disk when it starts up.  We will have to rebuild u-boot and replace it on our sdcard.

On the Linux side we’ll modify the device tree file to change where the rootfs is located.  In the zynq-zybo.dts file we will be changing the boot args.  Open zynq-zybo.dts which is located in the dts directory, and find the line that assigns the bootargs.  Change the boot args to the following.

bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1";

Once we have those changes done we’ll need to recompile the device tree.  Since we’ve already built the kernel once (hopefully) we can run that command again and the devicetree files will be recompiled.

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- O=<path_to_output_directory>UIMAGE_LOADADDR=0x8000 uImage modules dtbs

If you haven’t built the kernel yet now would be a good time to look at this tutorial.

Now we should copy our u-boot binary and new devicetree binary to the boot partition of our sdcard and we should have a fully working Ubuntu 16.04.  Remember to login using the new passwords we set above.  Now you can use the ubuntu package manager to install any tools that will be needed.

Throughout these tutorials I’ve been assuming you’ve been using the sdcard for all the files we need.  You should have two partitions on your sdcard.  One partition should be formated FAT32 and the other should be ext4.  These two partitions will hold our filesystem and boot files.  If you’ve looked at my previous posts you can see all of your boot files go into the FAT32 parition.  We are now going to populate our ext4 partition.  These patition will hold our root filesystem and give us a area of persistent storage.  We could do this with our busybox approach byt that’s a story for another post.  Let’s go ahead and populate that partition.

sudo rsync -aAXv <path_to_your_rootfs>/* /path/to/mount/point/

That should copy all of our files over to our sdcard and we are ready to boot into ubuntu.  Screenshot from 2017-07-03 10-29-32

11 thoughts on “Creating A Ubuntu Xenial 16.04 rootfs for Zybo and Zynq

  1. i’m getting Authentication token manipulation error when trying to change the root password, any ideas why?

    thank you

      1. thank you for your reply,
        i’ve managed to solve it by using command line/terminal when extracting the ubuntu core archive, the problem is with the archive manager i’m using

        thank you again

  2. Hello Greg, thank you very much for the great tutorial, at least someone is also explaining each step, without just giving them 🙂 I magaged to boot Ubuntu and login (with root and ubuntu user) through the console.

    just 1 remark : before exiting the chroot, I think we should ‘unmount proc’, otherwise rsync tries to create all the proc files on the sd-card. I could for example see (using rsync –progress …) that it was trying to create the /proc/kcore file (which was terrabytes in size :-).

    question : did you get your ethernet connection up and running? I’m trying to find out how, but so far no success.

    On the Xilinx forum, I’ve detailed what I tried to do so far. I also made a reference to your blog post, so other readers can find your page. Would you mind checking this post? I must be missing something, I can see my ethernet interfaces, but they are just not ‘up and running’

    thanks in advance,

    https://forums.xilinx.com/t5/Embedded-Linux/AR-66636-cannot-get-eth0-working-on-a-ubuntu-base-image-16-04-3/m-p/807108#M22656

    1. Thanks, I completely forgot to do the umount step, yes we don’t want to copy anything from proc over. I’ll fix that up. I should have some time this weekend to talk a look at the ehternet, I’ll check the kernel configuration.

      1. Did you find a way to activate ethernet? (I’m using your tutorial for a Arty-Z7-20 board)

    2. To get ethernet, copy /etc/network and /etc/NetworkManager from the image where network is available. Then install network-manager using apt in the chroot. That got ethernet working for me.

  3. Did you make sure that the kernel module for the neet driver is being loaded? It looks like I didn’t talk about how to launch the kernel modules by default when we build the kernel.

  4. To get ethernet, copy /etc/network and /etc/NetworkManager from the image where network is available. Then install network-manager using apt in the chroot. That got ethernet working for me.

Leave a comment