If you’re using
our Android sources, we have a script named
mksdcard.sh to partition an SD card and copy the output files. This works pretty well when using a removable SD card, but doesn’t address how you might do the same if you’re booting to a non-removable device like
eMMC or
SATA. It also requires you to have an SD card reader.
Well, the i.MX6 has a USB OTG port, and the Linux kernel supports something called
g_mass_storage, or
USB Mass Storage Gadget. By putting the two of those together, we can make our
Nitrogen6X or
BD-SL-i.MX6 board look like removable storage and use normal filesystem utilities on a Linux development machine to manipulate the storage devices.
For the impatient
If you’re cabled up to your development machine, you should see a new storage device auto-mount with the filesystem you created and booted. If you have multiple storage devices attached to your i.MX6 board, you should see a new device for each. Each device will correspond to one of the block devices:
- SD card,
- eMMC (for those of you with custom boards),
- SATA, or
- USB flash drive
The last one is kind of pointless, but is supported by default.
Note that when finished, you should shut down gracefully by:
- Using unmount on the host machine, and
- Issuing sync && reboot on the i.MX6 device.
Detailed usage:
1. Grab the image
Since all of this is constructed using open-source code, this part is simple:
~/$ wget http://commondatastorage.googleapis.com/boundarydevices.com/usbwrite-nitrogen6x-20130420.zip
--2013-04-20 12:53:45-- http://commondatastorage.googleapis.com/boundarydevices.com/usbwrite-nitrogen6x-20130420.zip
Resolving commondatastorage.googleapis.com (commondatastorage.googleapis.com)... 74.125.28.132, 2607:f8b0:400e:c04::84
Connecting to commondatastorage.googleapis.com (commondatastorage.googleapis.com)|74.125.28.132|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3507828 (3.3M) [application/zip]
Saving to: `usbwrite-nitrogen6x-20130420.zip'
100%[======================================>] 3,507,828 1.56M/s in 2.1s
2013-04-20 12:53:48 (1.56 MB/s) - `usbwrite-nitrogen6x-20130420.zip' saved [3507828/3507828]
Note that the image is really tiny (3.5MB) because we pruned the kernel a bit and used
Buildroot to construct a userspace using
the uClibc library and no tools beyond
busybox.
2. Partition an SD card
Okay, so this step is a bit ironic, since it requires an SD card reader other than the i.MX6. It’s also not technically necessary. You could certainly boot the kernel and ram disk over TFTP, though we won’t cover that here.
If your SD reader shows up as
/dev/sdc, you can create a single
FAT partition like so:
~/$ sudo umount /media/* # just in case
~/$ echo ',,b,*' | sudo sfdisk /dev/sdc
Checking that no-one is using this disk right now ...
OK
Disk /dev/sdc: 61168 cylinders, 4 heads, 32 sectors/track
Old situation:
Units = cylinders of 65536 bytes, blocks of 1024 bytes, counting from 0
Device Boot Start End #cyls #blocks Id System
/dev/sdc1 * 0+ 61167 61168- 3914751+ 83 Linux
/dev/sdc2 0 - 0 0 0 Empty
/dev/sdc3 0 - 0 0 0 Empty
/dev/sdc4 0 - 0 0 0 Empty
New situation:
Units = cylinders of 65536 bytes, blocks of 1024 bytes, counting from 0
Device Boot Start End #cyls #blocks Id System
/dev/sdc1 * 0+ 61167 61168- 3914751+ b W95 FAT32
/dev/sdc2 0 - 0 0 0 Empty
/dev/sdc3 0 - 0 0 0 Empty
/dev/sdc4 0 - 0 0 0 Empty
Successfully wrote the new partition table
Re-reading the partition table ...
If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)
to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1
(See fdisk(8).)
~/$ sudo mkfs.vfat -n usbwrite /dev/sdc1
mkfs.vfat 3.0.12 (29 Oct 2011)
~/$ udisks --mount /dev/sdc1
Mounted /org/freedesktop/UDisks/devices/sdc1 at /media/usbwrite
3. Extract
Because the example above used the
FAT filesystem, there’s no reason to use
sudo to extract the files.
~/$ unzip usbwrite-nitrogen6x-20130420.zip -d /media/usbwrite/
Archive: usbwrite-nitrogen6x-20130420.zip
inflating: /media/usbwrite/6x_bootscript
inflating: /media/usbwrite/uImage
inflating: /media/usbwrite/uramdisk.img
inflating: /media/usbwrite/buildroot.config
inflating: /media/usbwrite/kernel.config
~/$ sync && sudo umount /media/usbwrite
4. Boot, Login, and Run expose-usbdisks
The RAM disk image is configured to offer a login prompt (a
getty) on both the serial console (
/dev/ttymxc1) and a monitor/keyboard (
/dev/tty0) if present.
The only user defined is
root and the password is
Boundary.
Boundary Devices
boundary login: root
Password:
# expose-usbdisks
1 drives: /dev/mmcblk0
exporting 1 drives:
mmcblk0: SD: : 3823 MBytes
If you have another SD card,
eMMC, or SATA drive connected, you’ll see additional devices listed when you run
expose-usbdisks.
5. Access from dev machine
If you’ve connected your USB OTG port to a development machine, you’ll see a new device appear and auto-mount:
~/$ mount
...
/dev/sdc1 on /media/usbwrite type vfat (rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks)
Note that while the storage device on the i.MX6 machine is connected through
g_mass_storage, you should
not try to access it from the i.MX6 side of the link. There’s no locking in place between the two sides, and filesystem
corruption will occur.
6. Shut down gracefully
When done manipulating files from your dev machine, you should dismount all partitions:
~/$ sudo umount /media/*
And you should reboot gracefully on the i.MX6 side:
root@boundary: ~/$ sync && reboot
The details
uramdisk.img was built using Buildroot
Specifically, the RAM disk was built using
buildroot-2013.02.tar.bz2 and the configuration is in the zip-file as
buildroot.config.
You can repeat this like so:
~/$ wget http://buildroot.uclibc.org/downloads/buildroot-2013.02.tar.bz2
~/$ tar jxvf buildroot-2013.02.tar.bz2
~/$ unzip usbwrite-nitrogen6x-20130420.zip \
-d buildroot-2013.02
buildroot.config
~/$ cd buildroot-2013.02/
~/buildroot-2013.02$ mv buildroot.config .config
~/buildroot-2013.02$ make
Buildroot is configured to create a
gzipped cpio archive in
output/images/rootfs.cpio.gz and it’s ready to be wrapped for U-Boot using
mkimage.
~/buildroot-2013.02$ mkimage -A arm -O linux -T ramdisk -n "Initial Ram Disk" \
-d output/images/rootfs.cpio.gz uramdisk.img
Okay, so this is
almost true. We did a little more to this image because we added the
expose-usbdisks script. We did this by using the utility scripts described in our
Hacking RAM disks post.
The expose-usbdisks script itself.
The
expose-usbdisks script is a fairly simple shell script that
determines what block devices are connected to the system by looking in
/sys/class/block for
mmcblk? and
sd?:
#!/bin/sh
cd /sys/class/block
drives=`for d in * ; do echo $d ; done | grep -e 'mmcblk[01]$\|sd[a-z]$'`
dcount=0;
dlist='';
for d in $drives ; do
dlist=$dlist,/dev/$d ;
dcount=`expr $dcount + 1 `;
done ;
dlist=${dlist:1} ;
echo $dcount drives: $dlist;
modprobe g_mass_storage file=$dlist;
echo "exporting $dcount drives:" | tee /dev/tty0
for d in $drives ; do
name='';
type='';
if [ -e /sys/class/block/$d/device/model ]; then
type=`cat /sys/class/block/$d/device/vendor`;
name=`cat /sys/class/block/$d/device/model`;
else if [ -e /sys/class/block/$d/device/type ]; then
type=`cat /sys/class/block/$d/device/type`;
else
type='unknown';
name=other;
fi ; fi
size=`cat /sys/class/block/$d/size`
size=`expr $size \* 512`
size=`expr $size / 1048576`
echo -e "\t$d: $type: $name: $size MBytes"
done | tee /dev/tty0
The primary purpose is to build a parameter string for the
g_mass_storage kernel module as described
the document describing the backing store.
The boot script.
If you’ve been using and modifying our
boot scripts to load your kernel, you might notice that this differs somewhat from some other distributions. In our Timesys, LTIB, and Ubuntu builds, we generally use an
ext3 partition as the root filesystem and don’t boot to a RAM disk.
The boot script updates for this are pretty simple: we simply load the RAM disk into memory at address
0x12800000 and pass it as a second parameter to the
bootm command:
${fs}load ${dtype} ${disk}:1 10800000 /uImage
&& ${fs}load ${dtype} ${disk}:1 12800000 /uramdisk.img
&& bootm 10800000 12800000 ;
The source for the boot script is in
/root/6x_bootscript within the RAM disk itself.
Conclusion
This post may seem like a lot of detail for something simple, but we hope that either the image or the description of the pieces will likely be useful to those of you dealing with how to access storage on your boards.
Let us know if you find this useful (or confusing).