Understanding The i.MX28 sdimage Utility Code

by Conrad Gomes on

The i.MX28 development environment provides a utility like sdimage which is used to flash the bootstream files to the Freescale firmware partitions. In this post we walk through the code of sdimage to understand its implementation

MMC Boot

The instructions to prepare a MMC device for boot are given in the i.MX28 EVK Linux User.s Guide. At the time of writing this post the guide available from the Freescale website was used and its revision is Rev. L2.6.35_1.1.0. The document can be obtained from L2.6.35_1.1.0_LINUX_DOCS.

The steps for MMC boot in section 5.1.3.1 include using sdimage which is a part of the Linux Target Image Builder (LTIB) development environment to flash the bootstream images onto the MMC device.

This post walks through the steps to extract sdimage from the LTIB, build it and then goes through the source code for sdimage to understand what it is doing as it is not very clear.

Getting the sdimage utility from LTIB

To inspect the source code for sdimage we first extract it from the rpm sources in the LTIB

ubuntu@ubuntu-VirtualBox:~/beta/projectX/ltib$./ltib -p uuc.spec -m prep
on't have HTTP::Request::Common
Don't have LWP::UserAgent
Cannot test proxies, or remote file availability without both
HTTP::Request::Common and LWP::UserAgent

Processing: uuc
=================
Build path taken because: build key set, no prebuilt rpm,

rpmbuild --dbpath /home/ubuntu/beta/projectX/ltib/rootfs//var/lib/rpm --target arm --define '_unpackaged_files_terminate_build 0' --define '_target_cpu arm' --define '__strip strip' --define '_topdir /home/ubuntu/beta/projectX/ltib/rpm' --define '_prefix /usr' --define '_tmppath /home/ubuntu/beta/projectX/ltib/tmp' --define '_rpmdir /home/ubuntu/beta/projectX/ltib/rpm/RPMS'  --define '_mandir /usr/share/man' --define '_sysconfdir /etc' --define '_localstatedir /var' -bp  /home/ubuntu/beta/projectX/ltib/dist/lfs-5.1/uuc/uuc.spec
Building target platforms: arm
Building for target arm
Executing(%prep): /bin/sh -e /home/ubuntu/beta/projectX/ltib/tmp/rpm-tmp.79873
+ umask 022
+ cd /home/ubuntu/beta/projectX/ltib/rpm/BUILD
+ cd /home/ubuntu/beta/projectX/ltib/rpm/BUILD
+ rm -rf uuc-10.12.01
+ tar -xvvf -
+ /bin/gzip -dc /home/ubuntu/beta/projectX/ltib/rpm/SOURCES/uuc-10.12.01.tar.gz
drwxrwxr-x root/root         0 2010-09-29 06:35 uuc-10.12.01/
-rw-rw-r-- root/root       338 2010-09-29 06:35 uuc-10.12.01/Makefile
-rwxrwxr-x root/root       337 2010-09-29 06:35 uuc-10.12.01/linuxrc
-rw-rw-r-- root/root      4754 2010-09-29 06:35 uuc-10.12.01/sdimage.c
-rw-rw-r-- root/root     16753 2010-09-29 06:35 uuc-10.12.01/uu.c
+ STATUS=0
+ [ 0 -ne 0 ]
+ cd uuc-10.12.01
+ exit 0
Build time for uuc: 0 seconds

ubuntu@ubuntu-VirtualBox:~/beta/projectX/ltib$

Building the code

To build the code for sdimage we go to the rpm directory with the uuc source code and run gcc on the sdimage.c file.

ubuntu@ubuntu-VirtualBox:~/beta/projectX/ltib$ cd rpm/BUILD/uuc-10.12.01/
ubuntu@ubuntu-VirtualBox:~/beta/projectX/ltib/rpm/BUILD/uuc-10.12.01$ gcc sdimage.c -o sdimage
sdimage.c: In function âinâsdimage.c:134:2: warning: incompatible implicit declaration of built-in function âmsetâenabled by default]
.
.
ubuntu@ubuntu-VirtualBox:~/beta/projectX/ltib/rpm/BUILD/uuc-10.12.01$

Code Walk Through

  1. Read arguments passed.

    1. Filter -f and set the firmware file name to g_firmware.

      1. e.g imx28_linux.sb

    2. Filter -d and set the device file name to g_filedev.

      1. e.g /dev/sde, /dev/mmcblk

    3. Crib and return if either of the arguments are not passed

  2. Open the device file and save the handle.

    1. Assign device file handle to devhandle.

    2. Crib and return if error in opening the device file.

  3. Open the firmware file and save the handle.

    1. Assign firmware file handle to firmwarehandle.

    2. Crib and return if error in opening the firmware file.

  4. Get filestat of firmware file

    1. Crib and return if error in filestat.

  5. Read the Master Boot Record (MBR) from device handle devhandle into object variable mbr with a structure which matches the MBR structure

    1. Crib and return if number of bytes read is less than the size of the MBR structure.

  6. Check the signature of the MBR, it should be 0xAA55

    1. mbr.sign holds the signature

    2. Crib and return if signature does not match

  7. Iterate through the 4 physical partitions and search for a partition type OnTrack DM6 Aux3. (This is the Freescale firmware partition type as given in section 12.11 SD/MMC Boot Mode of i.MX28 Applications Processor Reference Manual, Rev. 2, 08/2013)

    1. mbr.part[i].filesystem holds the filesystem type

    2. Filesystem type is 'S' in ASCII. Hex code 53. Decimal value 83.

      1. To figure out the various filesystem types run fdisk utility. At the command prompt enter 'l' to list partition types.

      2. 'S' is hex code 53 which represents Linux partition type which is created when formatting the MMC device with fdisk.

      3. If "OnTrack DM6 Aux3" type of partition is not found then crib and return.

  8. Check if the size of the partition is greater than one byte plus two times the firmware file size obtained in step 4

    1. Crib and return if less as the partition size is too small.

    2. Partition size has to be slightly greater than twice the firmware file size

  9. Intialize the ConfigBlock structure variable bcb

    1. The config block holds the information about the boot information for the driver. (Further information about its structure is given in section 12.11.1 Boot Control Block (BCB) Data Structure of i.MX28 Applications Processor Reference Manual, Rev. 2, 08/2013)

    2. This structure holds the information about the primary and secondary boot tags.

    3. The bcb structure is initialized with appropriate signature0x00112233.

    4. The primary boot firmware is given a tag of 1

    5. The start of the primary boot firmware is initialized to the next sector after the start of the partition. The bcb structure is stored in the first sector.

    6. The secondary boot firmware is given a tag of 2

    7. The start of the secondary boot firmware is initialized to the next sector after the start of the partition. The bcb structure is stored in the first sector.

  10. Write the bcb data

    1. Seek to the first sector of the Freescale firmware partition.

    2. Write the bcb data

    3. Crib and exit if bytes written does not match with the size of the bcb.

  11. Write the primary and secondary firmware partitions

    1. Allocate memory of size equal to the firmware file

      1. Crib and exit if there is a memory allocation error.

    2. Read the firmware file from the firmwarehandle to a buffer buff.

      1. Crib and exit if there is a read error

    3. Seek to the second sector of the Freescale firmware partition.

    4. Write the firmware buffer buff to the address seeked above.

      1. Crib and exit if there is a write error

    5. Seek to the sector after the last sector containing the primary firmware.

    6. Write the firmware buffer buff to the address seeked above.

      1. Crib and exit if there is a write error

  12. Free the buffer allocated

  13. Close the device handle devhandle.

  14. Close the firmware file handle firmwarehandle.

  15. Exit.