Thursday, August 9, 2012

Zedboard - Modifying Your Ram Disk Image

So one thing that you will notice about your Zedboard, is that every time you reboot your Zedboard any changes you make don't stick.  This is because the / directory is being loaded into Memory, and not to a hard disk or the SD-Card.  This isn't a bad thing, as it allows for every fast boot times.  But as you move along with your projects you may want to modify your Ram Disk Image to include different things such as your custom program code.

FIRST!!! BACK UP YOUR SD-CARD CONTENTS!!!!

No matter what!  The SD-Card is FAT32 formatted so you don't have any excuse in the world to not have the contents backed up!

If you are running on a windows machine simply just insert the SD Card into the computer and Windows will automatically mount it for you.  On most modern Linux machines, a similar functionality should exist, but if it does not then it is probably under /dev/mmcblk#p# where the first # is the SD Card slot number, and the second # is the partition number.

Okay, now that you have your SD-Card backed up we can continue :D.

I will be working on Ubuntu 12.04 LTS x64 for this example.

Since my development system is in a VM, I don't have access to a SD-Card slot, so I am going to mount the SD-Card on my Zedboard and pull the image file off of it via FTP.

zynq> cd /
zynq> ls
bin         etc         licenses    lost+found  opt         root        sys         usr
dev         lib         linuxrc     mnt         proc        sbin        tmp         var
zynq> mkdir sdcard
zynq> mount /dev/mmcblk0p1 /sdcard
zynq> cd /sdcard
zynq> ls
BOOT.BIN                backup                  ramdisk8M.image.gz      zImage
README                  devicetree_ramdisk.dtb  temp

Ok, I now have my SD-Card mounted.  Since my root login points to / for the home directory on my FTP server I will be able to get to this folder.  Now back on my Ubuntu box:

zynqgeek@beth:~$ cd
zynqgeek@beth:~$ cd arm-devel/
zynqgeek@beth:~/arm-devel$ mkdir ramdisk
zynqgeek@beth:~/arm-devel$ cd ramdisk/
zynqgeek@beth:~/arm-devel/ramdisk$ ftp 192.168.2.210
Connected to 192.168.2.210.
220 Operation successful
Name (192.168.2.210:tim): root
230 Operation successful
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 Operation successful
150 Directory listing
total 59
drwxr-xr-x    2 12319    300           2048 Jan  9  2012 bin
drwxr-xr-x    4 12319    300           3072 Jan  1 00:00 dev
drwxr-xr-x    4 12319    300           1024 Jan  1 00:00 etc
drwxr-xr-x    3 12319    300           2048 Jul 12  2012 lib
drwxr-xr-x   11 12319    300           1024 Jan  9  2012 licenses
lrwxrwxrwx    1 12319    300             11 Jan  9  2012 linuxrc -> bin/busybox
drwx------    2 root     0            12288 Jan  9  2012 lost+found
drwxr-xr-x    2 12319    300           1024 Aug 21  2010 mnt
drwxr-xr-x    2 12319    300           1024 Aug 21  2010 opt
dr-xr-xr-x   49 root     0                0 Jan  1 00:00 proc
drwxr-xr-x    2 12319    300           1024 Jan  1 00:25 root
drwxr-xr-x    2 12319    300           1024 Jan  9  2012 sbin
drwxr-xr-x    4 root     0            32768 Jan  1 00:00 sdcard
drwxr-xr-x   12 root     0                0 Jan  1 00:00 sys
drwxrwxrwt    2 root     0               40 Jan  1 00:00 tmp
drwxr-xr-x    5 12319    300           1024 Mar 30  2012 usr
drwxr-xr-x    4 12319    300           1024 Oct 25  2010 var
226 Operation successful
ftp> cd sdcard
250 Operation successful
ftp> ls
200 Operation successful
150 Directory listing
total 10400
-rwxr-xr-x    1 root     0          4317256 Jul 13  2012 BOOT.BIN
-rwxr-xr-x    1 root     0             2779 Jul 13  2012 README
drwxr-xr-x    2 root     0            32768 Aug  8  2012 backup
-rwxr-xr-x    1 root     0             5817 Jul 13  2012 devicetree_ramdisk.dtb
-rwxr-xr-x    1 root     0          3694108 Jul 13  2012 ramdisk8M.image.gz
-rwxr-xr-x    1 root     0          2479640 Jul 13  2012 zImage
226 Operation successful
ftp> get ramdisk8M.image.gz
local: ramdisk8M.image.gz remote: ramdisk8M.image.gz
200 Operation successful
150 Opening BINARY connection for ramdisk8M.image.gz (3694108 bytes)
226 Operation successful
3694108 bytes received in 0.20 secs (18384.3 kB/s)
ftp> quit
221 Operation successful
zynqgeek@beth:~/arm-devel/ramdisk$ ls
ramdisk8M.image.gz

Alright! Now we have the ramdisk image locally on our development machine.  We need to unzip it and mount it so we can see it's contents.

zynqgeek@beth:~/arm-devel/ramdisk$ mkdir ram_image_mount
zynqgeek@beth:~/arm-devel/ramdisk$ gunzip ramdisk8M.image.gz
zynqgeek@beth:~/arm-devel/ramdisk$ ls
ramdisk8M.image  ram_image_mount
zynqgeek@beth:~/arm-devel/ramdisk$ sudo mount -o loop ramdisk8M.image ram_image_mount
[sudo] password for zynqgeek:
zynqgeek@beth:~/arm-devel/ramdisk$ ls
ramdisk8M.image  ram_image_mount
zynqgeek@beth:~/arm-devel/ramdisk$ cd ram_image_mount/
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount$ ls
bin  etc  licenses  lost+found  opt   root  sys  usr
dev  lib  linuxrc   mnt         proc  sbin  tmp  var

Note how I had to mount the folder as root.  If you want to give access to yourself you will need to perform a chown <folder> <username> to give access.

Well that was easy!  Alright, let's take our helloworld program and have it automatically run at the end of our startup script.  First we need to copy our helloworld program to the ramdisk image.  Let's do that.  My helloworld program was in /home/zynqgeek/arm_devel/helloworld and was called simply helloworld.

zynqgeek@beth:~/arm-devel/ramdisk$ sudo cp /home/zynqgeek/arm-devel/helloworld/helloworld ./ram_image_mount/root/
zynqgeek@beth:~/arm-devel/ramdisk$ cd ram_image_mount/
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount$ ls
bin  etc  licenses  lost+found  opt   root  sys  usr
dev  lib  linuxrc   mnt         proc  sbin  tmp  var
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount$ cd root/
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/root$ ls
helloworld  logo.bin
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/root$

Ok, so we now have our helloworld application within our ram disk image.  Now we need to find our startup script in the /etc/init.d folder.  The file is called rcS.  Let's look at it's contents.

zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/root$ cd ..
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount$ cd etc
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/etc$ cd init.d/
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/etc/init.d$ ls
rcK  rcS  rcS.orig
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/etc/init.d$ cat rcS
#!/bin/sh

echo "Starting rcS..."

echo "++ Mounting filesystem"
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp

echo "++ Setting up mdev"

echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

mkdir -p /dev/pts
mkdir -p /dev/i2c
mount -t devpts devpts /dev/pts

echo "++ Configure static IP 192.168.1.10"
ifconfig eth0 down
ifconfig eth0 192.168.1.10 up

echo "++ Starting telnet daemon"
telnetd -l /bin/sh

echo "++ Starting http daemon"
httpd -h /var/www

echo "++ Starting ftp daemon"
tcpsvd 0:21 ftpd ftpd -w /&

echo "++ Starting dropbear (ssh) daemon"
dropbear

echo "++ Starting OLED Display"
load_oled

echo "++ Exporting LEDs & SWs"
for i in 0 1 2 3 4 5 6 7;
do
        sw=$(($i+69));
        led=$(($i+61));
        echo $sw > /sys/class/gpio/export;
        echo $led > /sys/class/gpio/export;
        echo out > /sys/class/gpio/gpio$led/direction;
done;

export PATH=$PATH:/usr/local/bin

echo "rcS Complete"
zynqgeek@beth:~/arm-devel/ramdisk/ram_image_mount/etc/init.d$

Not too bad.  We can see that it sets up some mounts, sets up our eth0 ethernet connection, and then loads various networking services such as our webserver and ssh server.  Finally it performs some Digilent/Zedboard specific functions to fiddle with the OLED display, LED's and Switches found on the board.

We can place our application to execute right before the last line so it is executed within the script.  I placed the following lines into my script file:

cd /root
./helloworld
cd /

This will move into the /root directory, execute our helloworld program, and then return the directory back to  / for the first zynq> prompt.

Finally, now that we have our file added and our script updated in our image, we need to un-mount it, and re-compress it.

zynqgeek@beth:~/arm-devel# sudo umount -l /home/tim/arm-devel/ramdisk/ram_image_mount

Now we need to recompress it using gzip.

zynqgeek@beth:~/arm-devel/ramdisk# gzip -9 ram
zynqgeek.image  ram_image_mount/
zynqgeek@beth:~/arm-devel/ramdisk# gzip -9 ramdisk8M.image
zynqgeek@beth:~/arm-devel/ramdisk# ls
ramdisk8M.image.gz  ram_image_mount

And finally, after you have backed-up your SD-Card contents, you can ftp back into your Zedboard and replace the ramdisk image file.  First, go onto your Zedboard and list the size of the ramdisk8M.image.gz file:

zynq> cd sdcard/
zynq> lss
-sh: lss: not found
zynq> ls
BOOT.BIN                backup                  ramdisk8M.image.gz      zImage
README                  devicetree_ramdisk.dtb  temp
zynq> ls -al
total 10433
drwxr-xr-x    4 root     0            32768 Jan  1 00:00 .
drwxr-xr-x   18 12319    300           1024 Jan  1 19:33 ..
-rwxr-xr-x    1 root     0          4317256 Jul 13  2012 BOOT.BIN
-rwxr-xr-x    1 root     0             2779 Jul 13  2012 README
drwxr-xr-x    2 root     0            32768 Aug  8  2012 backup
-rwxr-xr-x    1 root     0             5817 Jul 13  2012 devicetree_ramdisk.dtb
-rwxr-xr-x    1 root     0          3694108 Jul 13  2012 ramdisk8M.image.gz
drwxr-xr-x    3 root     0            32768 Jan  1  1980 temp
-rwxr-xr-x    1 root     0          2479640 Jul 13  2012 zImage

We can see that it is 3694108 Bytes.  Now, on your development box ftp in and overwrite this file with our new image.

zynqgeek@beth:~/arm-devel/ramdisk# ftp 192.168.2.210
Connected to 192.168.2.210.
220 Operation successful
Name (192.168.2.210:tim): root
230 Operation successful
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd sdcard
250 Operation successful
ftp> ls
200 Operation successful
150 Directory listing
total 10400
-rwxr-xr-x    1 root     0          4317256 Jul 13  2012 BOOT.BIN
-rwxr-xr-x    1 root     0             2779 Jul 13  2012 README
drwxr-xr-x    2 root     0            32768 Aug  8  2012 backup
-rwxr-xr-x    1 root     0             5817 Jul 13  2012 devicetree_ramdisk.dtb
-rwxr-xr-x    1 root     0          3694108 Jul 13  2012 ramdisk8M.image.gz
drwxr-xr-x    3 root     0            32768 Jan  1  1980 temp
-rwxr-xr-x    1 root     0          2479640 Jul 13  2012 zImage
226 Operation successful
ftp> put ramdisk8M.image.gz
local: ramdisk8M.image.gz remote: ramdisk8M.image.gz
200 Operation successful
150 Ok to send data
226 Operation successful
3692720 bytes sent in 0.10 secs (37462.4 kB/s)
ftp>

And finally back on your Zedboard list the files sizes again and we see an increase in size to 3692720 Bytes.

zynq> ls -al
total 10433
drwxr-xr-x    4 root     0            32768 Jan  1 00:00 .
drwxr-xr-x   18 12319    300           1024 Jan  1 19:33 ..
-rwxr-xr-x    1 root     0          4317256 Jul 13  2012 BOOT.BIN
-rwxr-xr-x    1 root     0             2779 Jul 13  2012 README
drwxr-xr-x    2 root     0            32768 Aug  8  2012 backup
-rwxr-xr-x    1 root     0             5817 Jul 13  2012 devicetree_ramdisk.dtb
-rwxr-xr-x    1 root     0          3692720 Jan  1 19:53 ramdisk8M.image.gz
drwxr-xr-x    3 root     0            32768 Jan  1  1980 temp
-rwxr-xr-x    1 root     0          2479640 Jul 13  2012 zImage

Alright, that's it!  We just need to unmount our SD-Card and reboot our zedboard.

zynq> cd /
zynq> umount /sdcard
zynq> mount
none on /proc type proc (0)
none on /sys type sysfs (0)
none on /tmp type tmpfs (0)
devpts on /dev/pts type devpts (0)

After I hit the PS-RST button on my Zedboard, here is my UART output:

U-Boot 2011.03-dirty (Jul 11 2012 - 16:07:00)

DRAM:  512 MiB
MMC:   SDHCI: 0
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   zynq_gem
Hit any key to stop autoboot:  0
Copying Linux from SD to RAM...
Device: SDHCI
Manufacturer ID: 3
OEM: 5344
Name: SU04G
Tran Speed: 25000000
Rd Block Len: 512
SD version 1.10
High Capacity: Yes
Capacity: 3965190144
Bus Width: 1-bit
reading zImage

2479640 bytes read
reading devicetree_ramdisk.dtb

5817 bytes read
reading ramdisk8M.image.gz

3692720 bytes read
## Starting application at 0x00008000 ...
Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0
[    0.000000] Linux version 3.3.0-digilent-12.07-zed-beta 

...

Starting rcS...
++ Mounting filesystem
++ Setting up mdev
++ Configure static IP 192.168.1.10
[    1.510000] GEM: lp->tx_bd ffdfb000 lp->tx_bd_dma 18fd4000 lp->tx_skb d8ac27c0
[    1.520000] GEM: lp->rx_bd ffdfc000 lp->rx_bd_dma 18fd5000 lp->rx_skb d8ac28c0
[    1.530000] GEM: MAC 0x00350a00, 0x00002201, 00:0a:35:00:01:22
[    1.530000] GEM: phydev d8b7f400, phydev->phy_id 0x1410dd1, phydev->addr 0x0
[    1.540000] eth0, phy_addr 0x0, phy_id 0x01410dd1
[    1.540000] eth0, attach [Marvell 88E1510] phy driver
++ Starting telnet daemon
++ Starting http daemon
++ Starting ftp daemon
++ Starting dropbear (ssh) daemon
++ Starting OLED Display
[    1.580000] pmodoled-gpio-spi [zed_oled] SPI Probing
++ Exporting LEDs & SWs
Hello World!
rcS Complete
zynq> [    5.550000] eth0: link up (1000/FULL)


There you have it!  Now you know how to both modify your Ram Disk, as well as automatically launch applications at boot.  Happy Zynq'ing!

2 comments:

  1. Thanks for the brilliant hint!
    However, it might be a little easier to not doing it on the development machine but on the zedboard linux itself:

    Log in to the Linux on the ZED Board either via SSH or USB serial terminal:

    Now we mount the SD-Card on the Zedboard Linux.

    > mkdir /sdcard
    > mount /dev/mmcblk0p1 /sdcard/

    Here, it might make sense to make a copy of the current boot image on the SD-Card...

    > cp /sdcard/ramdisk8M.image.gz /sdcard/ramdisk8M.image.gz_original

    Now proceed as before. Unzip, mount, modify, unmount, zip, copy over to the SD-Card.

    -----------------------

    OK, let's automate this. On the zedboard Linux do:

    > vi /root/mountimage

    mkdir /sdcard
    mount /dev/mmcblk0p1 /sdcard/
    cp /sdcard/ramdisk8M.image.gz /sdcard/ramdisk8M.image.gz_old
    cp /sdcard/ramdisk8M.image.gz /tmp/
    gunzip /tmp/ramdisk8M.image.gz
    mount -o loop /tmp/ramdisk8M.image /mnt/
    echo "boot image mounted at /mnt/"


    > vi /root/umountimage

    echo "unmounting and compressing boot-image"
    umount -l /mnt
    gzip -9 /tmp/ramdisk8M.image
    mv /tmp/ramdisk8M.image.gz /sdcard/
    umount -l /sdcard
    echo "done. please poweroff and toggle power-switch."


    > chmod a+x /root/*mountimage


    allright. Now you type:

    > ./mountimage

    then you make your changes. e.g.

    cp /root/*mountimage /mnt/root/

    and then you install the new image and reboot

    > ./umountimage


    Now the two files are permanently stored on your boot image.
    That is convenient, is it not?

    Cheers, Joachim

    ReplyDelete
  2. Thanks Zynqgeek and Joachim, this all worked well. For starters my tweaked Zedboard filesystem includes /root/*mountimage, a new /root/logo.bin OLED image, and a DHCP setup (/usr/share/udhcpc/default.script, /etc/resolv.conf, and "udhcpc -i eth0" in /etc/init.d/rcS).

    ReplyDelete