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
- Download usbwrite-nitrogen6x-20130420.zip.
- Extract to a single
FAT
orext2/3/4
filesystem. - Boot, log in and run
expose-usbdisks
.
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 https://commondatastorage.googleapis.com/boundarydevices.com/usbwrite-nitrogen6x-20130420.zip
--2013-04-20 12:53:45-- https://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
.
Ezurio (formerly 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 https://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).