[Branch,~linaro-image-tools/linaro-image-tools/trunk] Rev 368: Add support for the Snowball board to linaro-android-media-create, written by Ola Borgelin. Add t...

Message ID 20110701145820.18032.23983.launchpad@loganberry.canonical.com
State Accepted
Headers show

Commit Message

Mattias Backman July 1, 2011, 2:58 p.m.
Merge authors:
  Markus Andersson (markus-m-andersson)
  Mattias Backman (mabac)
  Ola Borgelin (olab)
Related merge proposals:
  https://code.launchpad.net/~mabac/linaro-image-tools/ste-snowball-android/+merge/66297
  proposed by: Ola Borgelin (olab)
  review: Approve - Mattias Backman (mabac)
  review: Approve - James Westby (james-w)
------------------------------------------------------------
revno: 368 [merge]
committer: Mattias Backman <mattias.backman@linaro.org>
branch nick: trunk
timestamp: Fri 2011-07-01 11:18:48 +0200
message:
  Add support for the Snowball board to linaro-android-media-create, written by Ola Borgelin. Add tests for Snowball code, written by Hans Odeberg and Markus Andersson.
modified:
  linaro-android-media-create
  linaro_image_tools/media_create/android_boards.py
  linaro_image_tools/media_create/boards.py
  linaro_image_tools/media_create/partitions.py
  linaro_image_tools/media_create/tests/test_media_create.py


--
lp:linaro-image-tools
https://code.launchpad.net/~linaro-image-tools/linaro-image-tools/trunk

You are subscribed to branch lp:linaro-image-tools.
To unsubscribe from this branch go to https://code.launchpad.net/~linaro-image-tools/linaro-image-tools/trunk/+edit-subscription

Patch

=== modified file 'linaro-android-media-create'
--- linaro-android-media-create	2011-05-26 09:16:35 +0000
+++ linaro-android-media-create	2011-06-30 12:09:46 +0000
@@ -133,12 +133,13 @@ 
     unpack_android_binary_tarball(args.system, SYSTEM_DIR)
     unpack_android_binary_tarball(args.userdata, DATA_DIR)
 
-    # Create partitions    
+    # Create partitions
     boot_partition, system_partition, cache_partition, \
         data_partition, sdcard_partition = setup_android_partitions( \
         board_config, media, args.image_size, args.boot_label,
         args.should_create_partitions, args.should_align_boot_part)
 
+    board_config.populate_raw_partition(args.device, BOOT_DIR)
     populate_partition(BOOT_DIR + "/boot", BOOT_DISK, boot_partition)
     board_config.populate_boot_script(boot_partition, BOOT_DISK, args.consoles)
     populate_partition(SYSTEM_DIR + "/system", SYSTEM_DISK, system_partition)

=== modified file 'linaro_image_tools/media_create/android_boards.py'
--- linaro_image_tools/media_create/android_boards.py	2011-06-23 13:08:29 +0000
+++ linaro_image_tools/media_create/android_boards.py	2011-07-01 09:16:24 +0000
@@ -28,6 +28,8 @@ 
 from linaro_image_tools.media_create.boards import PART_ALIGN_S
 from linaro_image_tools.media_create.boards import BeagleConfig
 from linaro_image_tools.media_create.boards import PandaConfig
+from linaro_image_tools.media_create.boards import SnowballSdConfig
+from linaro_image_tools.media_create.boards import SnowballEmmcConfig
 from linaro_image_tools.media_create.boards import (
     align_up,
     align_partition,
@@ -37,6 +39,7 @@ 
 from linaro_image_tools import cmd_runner
 import os
 
+
 class AndroidBoardConfig(object):
     @classmethod
     def _get_bootargs(cls, consoles):
@@ -78,7 +81,7 @@ 
             as_root=True).wait()
 
         boot_env = cls._get_boot_env(consoles)
-        cmdline_filepath = os.path.join(boot_disk, "cmdline") 
+        cmdline_filepath = os.path.join(boot_disk, "cmdline")
         cmdline_file = open(cmdline_filepath, 'r')
         android_kernel_cmdline = cmdline_file.read()
         boot_env['bootargs'] = boot_env['bootargs'] + ' ' + \
@@ -96,7 +99,8 @@ 
             pass
 
     @classmethod
-    def get_sfdisk_cmd(cls, should_align_boot_part=False):
+    def get_sfdisk_cmd(cls, should_align_boot_part=False,
+                       start_addr=0, extra_part=False):
         if cls.fat_size == 32:
             partition_type = '0x0C'
         else:
@@ -116,7 +120,7 @@ 
 
         # can only start on sector 1 (sector 0 is MBR / partition table)
         boot_start, boot_end, boot_len = align_partition(
-            1, BOOT_MIN_SIZE_S, boot_align, PART_ALIGN_S)
+            start_addr + 1, BOOT_MIN_SIZE_S, boot_align, PART_ALIGN_S)
         # apparently OMAP3 ROMs require the vfat length to be an even number
         # of sectors (multiple of 1 KiB); decrease the length if it's odd,
         # there should still be enough room
@@ -131,12 +135,28 @@ 
             _cache_end + 1, USERDATA_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S)
         sdcard_start, _sdcard_end, _sdcard_len = align_partition(
             _userdata_end + 1, SDCARD_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S)
- 
+
+        # Snowball board needs a raw partition added to the beginning of image.
+        # If extra_part is True an extra primary partition will be added.
+        # Due to a maximum of 4 primary partitions cache data will be placed in
+        # a extended partition
+        if extra_part == True:
+            assert start_addr > 0, ("Not possible to add extra partition" \
+                                    "when boot partition starts at '0'")
+            return '%s,%s,%s,*\n%s,%s,L\n%s,-,E\n%s,%s,L\n%s,%s,L\n%s,,,-' % (
+            boot_start, boot_len, partition_type, system_start, _system_len,
+            cache_start, cache_start, _cache_len, userdata_start,
+            _userdata_len, sdcard_start)
+
         return '%s,%s,%s,*\n%s,%s,L\n%s,%s,L\n%s,-,E\n%s,%s,L\n%s,,,-' % (
             boot_start, boot_len, partition_type, system_start, _system_len,
             cache_start, _cache_len, userdata_start, userdata_start,
             _userdata_len, sdcard_start)
 
+    @classmethod
+    def populate_raw_partition(cls, media, boot_dir):
+        super(AndroidBoardConfig, cls).populate_raw_partition(boot_dir, media)
+
 
 class AndroidOmapConfig(AndroidBoardConfig):
     pass
@@ -155,7 +175,44 @@ 
     android_specific_args = 'init=/init androidboot.console=ttyO2'
 
 
+class AndroidSnowballSdConfig(AndroidBoardConfig, SnowballSdConfig):
+    extra_boot_args_options = (
+        'earlyprintk rootdelay=1 fixrtc nocompcache '
+        'mem=128M@0 mali.mali_mem=64M@128M mem=24M@192M hwmem=167M@216M '
+        'mem_issw=1M@383M mem=640M@384M vmalloc=256M')
+    _extra_serial_opts = 'console=tty0 console=ttyO2,115200n8'
+    android_specific_args = 'init=/init androidboot.console=ttyAMA2'
+
+
+class AndroidSnowballEmmcConfig(AndroidBoardConfig, SnowballEmmcConfig):
+    extra_boot_args_options = (
+        'earlyprintk rootdelay=1 fixrtc nocompcache '
+        'mem=128M@0 mali.mali_mem=64M@128M mem=24M@192M hwmem=167M@216M '
+        'mem_issw=1M@383M mem=640M@384M vmalloc=256M')
+    _extra_serial_opts = 'console=tty0 console=ttyAMA2,115200n8'
+    android_specific_args = 'init=/init androidboot.console=ttyAMA2'
+
+    @classmethod
+    def get_sfdisk_cmd(cls, should_align_boot_part=False):
+
+        LOADER_MIN_SIZE_S = align_up(
+            1 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE
+
+        loader_start, loader_end, loader_len = align_partition(
+            SnowballEmmcConfig.SNOWBALL_LOADER_START_S,
+            LOADER_MIN_SIZE_S, 1, PART_ALIGN_S)
+
+        command = super(AndroidSnowballEmmcConfig, cls).get_sfdisk_cmd(
+            should_align_boot_part=True, start_addr=loader_end,
+            extra_part=True)
+
+        return '%s,%s,0xDA\n%s' % (
+            loader_start, loader_len, command)
+
+
 android_board_configs = {
     'beagle': AndroidBeagleConfig,
     'panda': AndroidPandaConfig,
+    'snowball_sd': AndroidSnowballSdConfig,
+    'snowball_emmc': AndroidSnowballEmmcConfig,
     }

=== modified file 'linaro_image_tools/media_create/boards.py'
--- linaro_image_tools/media_create/boards.py	2011-06-29 19:29:43 +0000
+++ linaro_image_tools/media_create/boards.py	2011-07-01 09:18:48 +0000
@@ -58,6 +58,7 @@ 
 # align on 4 MiB
 PART_ALIGN_S = 4 * 1024 * 1024 / SECTOR_SIZE
 
+
 def align_up(value, align):
     """Round value to the next multiple of align."""
     return (value + align - 1) / align * align
@@ -104,6 +105,7 @@ 
 assert SAMSUNG_V310_BL2_LEN * SECTOR_SIZE == 512 * 1024, (
     "BL1 expects BL2 (u-boot) to be 512 KiB")
 
+
 def align_partition(min_start, min_length, start_alignment, end_alignment):
     """Compute partition start and end offsets based on specified constraints.
 
@@ -125,6 +127,7 @@ 
     """A descriptor that provides @property behavior on class methods."""
     def __init__(self, getter):
         self.getter = getter
+
     def __get__(self, instance, cls):
         return self.getter(cls)
 
@@ -337,6 +340,11 @@ 
             "No kernel found matching %s for flavors %s" % (
                 KERNEL_GLOB, " ".join(cls.kernel_flavors)))
 
+    @classmethod
+    def populate_raw_partition(cls, media, boot_dir):
+        # Override in subclass if needed
+        pass
+
 
 class OmapConfig(BoardConfig):
     kernel_flavors = ['linaro-omap4', 'linaro-lt-omap', 'linaro-omap', 'omap4']
@@ -517,7 +525,7 @@ 
        and u-boot.'''
     # Boot ROM looks for a boot table of contents (TOC) at 0x20000
     # Actually, it first looks at address 0, but that's where l-m-c
-    # puts the MBR, so the boot loader skips that address. 
+    # puts the MBR, so the boot loader skips that address.
     supports_writing_to_mmc = False
     SNOWBALL_LOADER_START_S = (128 * 1024) / SECTOR_SIZE
     SNOWBALL_STARTUP_FILES_CONFIG = 'startfiles.cfg'
@@ -537,11 +545,11 @@ 
         This is done since the boot rom always boots off the internal memory;
         there simply is no point to having a loader partition on SD card.
         """
-        # boot ROM expects bootloader at 0x20000, which is sector 0x100 
+        # boot ROM expects bootloader at 0x20000, which is sector 0x100
         # with the usual SECTOR_SIZE of 0x200.
         # (sector 0 is MBR / partition table)
         loader_start, loader_end, loader_len = align_partition(
-            SnowballEmmcConfig.SNOWBALL_LOADER_START_S, 
+            SnowballEmmcConfig.SNOWBALL_LOADER_START_S,
             LOADER_MIN_SIZE_S, 1, PART_ALIGN_S)
 
         boot_start, boot_end, boot_len = align_partition(
@@ -562,15 +570,22 @@ 
         make_uImage(cls.load_addr, k_img_data, boot_dir)
         boot_script_path = os.path.join(boot_dir, cls.boot_script)
         make_boot_script(boot_env, boot_script_path)
+        cls.populate_raw_partition(chroot_dir, boot_device_or_file)
+
+    @classmethod
+    def populate_raw_partition(cls, chroot_dir, boot_device_or_file):
+        # Populate created raw partition with TOC and startup files.
+        config_files_path = os.path.join(chroot_dir, 'boot')
         _, toc_filename = tempfile.mkstemp()
-        atexit.register(os.unlink, toc_filename)
-        config_files_path = os.path.join(chroot_dir, 'boot')
         new_files = cls.get_file_info(config_files_path)
         with open(toc_filename, 'wb') as toc:
             cls.create_toc(toc, new_files)
         cls.install_snowball_boot_loader(toc_filename, new_files,
                                      boot_device_or_file,
                                      cls.SNOWBALL_LOADER_START_S)
+        cls.delete_file(toc_filename)
+        cls.delete_file(os.path.join(config_files_path,
+                                     cls.SNOWBALL_STARTUP_FILES_CONFIG))
 
     @classmethod
     def install_snowball_boot_loader(cls, toc_file_name, files,
@@ -584,13 +599,21 @@ 
         for file in files:
             # XXX We need checks that these files do not overwrite each
             # other. This code assumes that offset and file sizes are ok.
+            filename = file['filename']
             if (file['offset'] % SECTOR_SIZE) != 0:
                 seek_bytes = start_sector * SECTOR_SIZE + file['offset']
-                _dd(file['filename'], boot_device_or_file, block_size=1,
+                _dd(filename, boot_device_or_file, block_size=1,
                     seek=seek_bytes)
             else:
-                seek_sectors = start_sector + file['offset']/SECTOR_SIZE
-                _dd(file['filename'], boot_device_or_file, seek=seek_sectors)
+                seek_sectors = start_sector + file['offset'] / SECTOR_SIZE
+                _dd(filename, boot_device_or_file, seek=seek_sectors)
+            cls.delete_file(filename)
+
+    @classmethod
+    def delete_file(cls, file_path):
+            cmd = ["rm", "%s" % file_path]
+            proc = cmd_runner.run(cmd, as_root=True)
+            proc.wait()
 
     @classmethod
     def create_toc(cls, f, files):
@@ -605,6 +628,8 @@ 
             # i; int; load_address,
             # 12s; string of char; name
             # http://igloocommunity.org/support/index.php/ConfigPartitionOverview
+            assert len(file['section_name']) < 12, (
+                "Section name %s too large" % file['section_name'])
             flags = 0
             load_adress = file['align']
             data = struct.pack('<IIIii12s', file['offset'], file['size'],
@@ -748,6 +773,7 @@ 
         make_uImage(cls.load_addr, k_img_data, boot_dir)
         make_uInitrd(i_img_data, boot_dir)
 
+
 class SMDKV310Config(BoardConfig):
     uboot_flavor = 'smdkv310'
     serial_tty = 'ttySAC1'
@@ -825,7 +851,7 @@ 
     'efikamx': EfikamxConfig,
     'efikasb': EfikasbConfig,
     'mx51evk': Mx51evkConfig,
-    'mx53loco' : Mx53LoCoConfig,
+    'mx53loco': Mx53LoCoConfig,
     'overo': OveroConfig,
     'smdkv310': SMDKV310Config,
     }

=== modified file 'linaro_image_tools/media_create/partitions.py'
--- linaro_image_tools/media_create/partitions.py	2011-05-31 06:45:22 +0000
+++ linaro_image_tools/media_create/partitions.py	2011-06-29 09:16:39 +0000
@@ -3,7 +3,7 @@ 
 # Author: Guilherme Salgado <guilherme.salgado@linaro.org>
 #
 # This file is part of Linaro Image Tools.
-# 
+#
 # Linaro Image Tools is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
@@ -28,6 +28,7 @@ 
     Device,
     Disk,
     PARTITION_NORMAL,
+    PARTITION_EXTENDED,
     )
 
 from linaro_image_tools import cmd_runner
@@ -71,9 +72,8 @@ 
         bootfs = partitions[0]
         system = partitions[1]
         cache = partitions[2]
-        data = partitions[4]
-        sdcard = partitions[5]
-            
+        data = partitions[3]
+        sdcard = partitions[4]
 
     print "\nFormating boot partition\n"
     proc = cmd_runner.run(
@@ -98,6 +98,7 @@ 
 
     return bootfs, system, cache, data, sdcard
 
+
 # I wonder if it'd make sense to convert this into a small shim which calls
 # the appropriate function for the given type of device?  I think it's still
 # small enough that there's not much benefit in doing that, but if it grows we
@@ -296,18 +297,28 @@ 
     # Here we can use parted.Device to read the partitions because we're
     # reading from a regular file rather than a block device.  If it was a
     # block device we'd need root rights.
+    vfat_partition = None
     disk = Disk(Device(image_file))
     partition_info = []
     for partition in disk.partitions:
-        geometry = partition.geometry
-        partition_info.append((geometry.start * SECTOR_SIZE,
-                               geometry.length * SECTOR_SIZE))
+        # Will ignore any partitions before boot and of type EXTENDED
+        if 'boot' in partition.getFlagsAsString():
+            vfat_partition = partition
+            geometry = partition.geometry
+            partition_info.append((geometry.start * SECTOR_SIZE,
+                                   geometry.length * SECTOR_SIZE))
+        elif (vfat_partition is not None and
+              partition.type != PARTITION_EXTENDED):
+            geometry = partition.geometry
+            partition_info.append((geometry.start * SECTOR_SIZE,
+                                   geometry.length * SECTOR_SIZE))
         # NB: don't use vfat_partition.nextPartition() as that might return
         # a partition of type PARTITION_FREESPACE; it's much easier to
         # iterate disk.partitions which only returns
         # parted.PARTITION_NORMAL partitions
-
-    assert len(partition_info) == 6
+    assert vfat_partition is not None, (
+        "Couldn't find boot partition on %s" % image_file)
+    assert len(partition_info) == 5
     return partition_info
 
 
@@ -347,6 +358,7 @@ 
     return boot_partition, system_partition, cache_partition, \
         data_partition, sdcard_partition
 
+
 def get_boot_and_root_partitions_for_media(media, board_config):
     """Return the device files for the boot and root partitions of media.
 

=== modified file 'linaro_image_tools/media_create/tests/test_media_create.py'
--- linaro_image_tools/media_create/tests/test_media_create.py	2011-06-23 15:12:13 +0000
+++ linaro_image_tools/media_create/tests/test_media_create.py	2011-07-01 09:16:24 +0000
@@ -28,6 +28,7 @@ 
 import textwrap
 import time
 import types
+import struct
 
 from testtools import TestCase
 
@@ -38,6 +39,7 @@ 
     boards,
     partitions,
     rootfs,
+    android_boards,
     )
 from linaro_image_tools.media_create.boards import (
     LOADER_MIN_SIZE_S,
@@ -206,6 +208,256 @@ 
         self.assertEquals(uboot_file, _get_smdk_uboot(chroot_dir, uboot_flavor))
 
 
+class TestCreateToc(TestCaseWithFixtures):
+    ''' Tests boards.SnowballEmmcConfig.create_toc()'''
+
+    def setUp(self):
+        ''' Create a temporary directory to work in'''
+        super(TestCreateToc, self).setUp()
+        self.tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir()
+        #Create the test's input data structures
+        zero = '\x00\x00\x00\x00'
+        line1 = zero + zero + zero + zero + zero + 'b' + zero + zero + \
+                 '\x00\x00\x00'
+        maxint = '\xFF\xFF\xFF\x7F'
+        minint = '\xFF\xFF\xFF\xFF'
+        line2 = maxint + maxint + zero + minint + minint + \
+                 'hello' + zero + '\x00\x00\x00'
+        line3 = '\x01\x00\x00\x00' '\x64\x00\x00\x00' + zero + \
+                 '\x05\x00\x00\x00' '\x05\x00\x00\x00' \
+                 'hello' + zero + '\x00\x00\x00'
+        self.expected = line1 + line2 + line3
+
+    def create_files_structure(self, src_data):
+        ''' Creates the data structure that the tested function
+            needs as input'''
+        files = []
+        for line in src_data:
+            files.append({'section_name': line[5],
+                  'filename': 'N/A',
+                  'align': line[3],
+                  'offset': line[0],
+                  'size': line[1],
+                  'load_adress': 'N/A'})
+        return files
+
+    def test_create_toc_normal_case(self):
+        ''' Creates a toc file, and then reads the created
+            file and compares it to precomputed data'''
+        correct_data = [(0, 0, 0, 0, 0, 'b'),
+                        (0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, -1, -1, 'hello'),
+                        (1, 100, 1000, 5, 10, 'hello')]
+        files = self.create_files_structure(correct_data)
+        filename = os.path.join(self.tempdir, 'toc')
+        with open(filename, 'w') as f:
+            boards.SnowballEmmcConfig.create_toc(f, files)
+        with open(filename, 'r') as f:
+            actual = f.read()
+        self.assertEquals(96, len(actual))
+        for i in range(len(actual)):
+            self.assertEquals(self.expected[i], actual[i], 'Mismatch at ix' \
+                ' %d, ref=%c, actual=%c' % (i, self.expected[i], actual[i]))
+
+    def test_create_toc_error_too_large_section_name(self):
+        '''Verify that trying to write past the end of the
+           section name field raises an exception'''
+        illegal_name_data = [(0, 0, 0, 0, 0, 'Too_longName')]
+        files = self.create_files_structure(illegal_name_data)
+        with open(os.path.join(self.tempdir, 'toc'), 'w') as f:
+            self.assertRaises(AssertionError,
+                              boards.SnowballEmmcConfig.create_toc,
+                              f, files)
+
+    def test_create_toc_error_negative_unsigned(self):
+        '''Verify that trying to write a negative number to an unsigned
+           field raises an exception'''
+        illegal_unsigned_data = [(-3, 0, 0, 0, 0, 'xxx')]
+        files = self.create_files_structure(illegal_unsigned_data)
+        with open(os.path.join(self.tempdir, 'toc'), 'w') as f:
+            self.assertRaises(struct.error,
+                              boards.SnowballEmmcConfig.create_toc,
+                              f, files)
+
+
+class TestSnowballBootFiles(TestCaseWithFixtures):
+    ''' Tests boards.SnowballEmmcConfig.install_snowball_boot_loader()'''
+    ''' Tests boards.SnowballEmmcConfig._make_boot_files()'''
+    ''' Tests boards.SnowballEmmcConfig.get_file_info()'''
+
+    def setUp(self):
+        ''' Create temporary directory to work in'''
+        super(TestSnowballBootFiles, self).setUp()
+        self.tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir()
+        self.temp_bootdir_path = os.path.join(self.tempdir, 'boot')
+        if not os.path.exists(self.temp_bootdir_path):
+            os.makedirs(self.temp_bootdir_path)
+
+    def setupFiles(self):
+        ''' Adds some files in the temp dir that the tested function
+            can use as input:
+            * A config file, which the tested function reads to
+              discover which binary files should be written to
+              the loader partition.
+            * Test versions of the binary files themselves,
+              containing dummy data.
+            Returns the expected value that the tested function should
+            return, given these input files.  '''
+        src_data = [('ISSW', 'boot_image_issw.bin', -1, 0, '5'),
+                    ('X-LOADER', 'boot_image_x-loader.bin', -1, 0, '6'),
+                    ('MEM_INIT', 'mem_init.bin', 0, 0x160000, '7'),
+                    ('PWR_MGT', 'power_management.bin', 0, 0x170000, '8'),
+                    ('NORMAL', 'u-boot.bin', 0, 0xBA0000, '9'),
+                    ('UBOOT_ENV', 'u-boot-env.bin', 0, 0x00C1F000, '10')]
+        # Create a config file
+        cfg_file = os.path.join(self.temp_bootdir_path,
+        boards.SnowballEmmcConfig.SNOWBALL_STARTUP_FILES_CONFIG)
+        with open(cfg_file, 'w') as f:
+            for line in src_data:
+                # Write comments, so we test that the parser can read them
+                f.write('#Yet another comment\n')
+                f.write('%s %s %i %#x %s\n' % line)
+        expected = []
+        # Define dummy binary files, containing nothing but their own
+        # section names.
+        for line in src_data:
+            with open(os.path.join(self.temp_bootdir_path, line[1]), 'w') as f:
+                f.write(line[0])
+        #define the expected values read from the config file
+        expected = []
+        ofs = [boards.SnowballEmmcConfig.TOC_SIZE,
+               boards.SnowballEmmcConfig.TOC_SIZE + len('ISSW'), 0x160000,
+               0x170000, 0xBA0000, 0xC1F000]
+        size = [len('ISSW'), len('X-LOADER'), len('MEM_INIT'), \
+                len('PWR_MGT'), len('NORMAL'), len('UBOOT_ENV')]
+        i = 0
+        for line in src_data:
+            filename = os.path.join(self.temp_bootdir_path, line[1])
+            expected.append({'section_name': line[0],
+                             'filename': filename,
+                             'align': int(line[2]),
+                             'offset': ofs[i],
+                             'size': long(size[i]),
+                             'load_adress': line[4]})
+            i += 1
+        return expected
+
+    def test_file_name_size(self):
+        ''' Test using a to large toc file '''
+        _, toc_filename = tempfile.mkstemp()
+        atexit.register(os.unlink, toc_filename)
+        filedata = 'X'
+        bytes = boards.SnowballEmmcConfig.TOC_SIZE + 1
+        tmpfile = open(toc_filename, 'wb')
+        for n in xrange(bytes):
+            tmpfile.write(filedata)
+        tmpfile.close()
+        files = self.setupFiles()
+        self.assertRaises(AssertionError,
+            boards.SnowballEmmcConfig.install_snowball_boot_loader,
+            toc_filename, files, "boot_device_or_file",
+            boards.SnowballEmmcConfig.SNOWBALL_LOADER_START_S)
+
+    def test_install_snowball_boot_loader_toc(self):
+        fixture = self.useFixture(MockCmdRunnerPopenFixture())
+        toc_filename = self.createTempFileAsFixture()
+        files = self.setupFiles()
+        boards.SnowballEmmcConfig.install_snowball_boot_loader(toc_filename,
+            files, "boot_device_or_file",
+            boards.SnowballEmmcConfig.SNOWBALL_LOADER_START_S)
+        expected = [
+            '%s dd if=%s of=boot_device_or_file bs=512 conv=notrunc' \
+            ' seek=%s' % (sudo_args, toc_filename,
+            boards.SnowballEmmcConfig.SNOWBALL_LOADER_START_S),
+            '%s dd if=%s/boot_image_issw.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=257' % (sudo_args, self.temp_bootdir_path),
+            '%s rm %s/boot_image_issw.bin' % (sudo_args,
+            self.temp_bootdir_path),
+            '%s dd if=%s/boot_image_x-loader.bin of=boot_device_or_file' \
+            ' bs=1 conv=notrunc seek=131588'
+            % (sudo_args, self.temp_bootdir_path),
+            '%s rm %s/boot_image_x-loader.bin' % (sudo_args,
+            self.temp_bootdir_path),
+            '%s dd if=%s/mem_init.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=3072' % (sudo_args, self.temp_bootdir_path),
+            '%s rm %s/mem_init.bin' % (sudo_args, self.temp_bootdir_path),
+            '%s dd if=%s/power_management.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=3200' % (sudo_args, self.temp_bootdir_path),
+            '%s rm %s/power_management.bin' % (sudo_args,
+            self.temp_bootdir_path),
+            '%s dd if=%s/u-boot.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=24064' % (sudo_args, self.temp_bootdir_path),
+            '%s rm %s/u-boot.bin' % (sudo_args, self.temp_bootdir_path),
+            '%s dd if=%s/u-boot-env.bin of=boot_device_or_file bs=512'
+            ' conv=notrunc seek=25080' % (sudo_args, self.temp_bootdir_path),
+            '%s rm %s/u-boot-env.bin' % (sudo_args, self.temp_bootdir_path)]
+
+        self.assertEqual(expected, fixture.mock.commands_executed)
+
+    def test_snowball_make_boot_files(self):
+        fixture = self.useFixture(MockCmdRunnerPopenFixture())
+        self.useFixture(MockSomethingFixture(tempfile, 'mkstemp',
+            lambda: (-1, '/tmp/temp_snowball_make_boot_files')))
+        self.setupFiles()
+        k_img_file = os.path.join(self.tempdir, 'vmlinuz-1-ux500')
+        i_img_file = os.path.join(self.tempdir, 'initrd.img-1-ux500')
+
+        boot_env = board_configs['snowball_emmc']._get_boot_env(
+            is_live=False, is_lowmem=False, consoles=[],
+            rootfs_uuid="test_boot_env_uuid", d_img_data=None)
+        boards.SnowballEmmcConfig._make_boot_files(boot_env, self.tempdir,
+            self.temp_bootdir_path, 'boot_device_or_file', k_img_file,
+            i_img_file, None)
+        expected = [
+            '%s mkimage -A arm -O linux -T kernel -C none -a 0x00008000 -e' \
+            ' 0x00008000 -n Linux -d %s %s/boot/uImage' % (sudo_args,
+            k_img_file, self.tempdir),
+            '%s cp /tmp/temp_snowball_make_boot_files %s/boot/boot.txt'
+            % (sudo_args, self.tempdir),
+            '%s mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n boot' \
+            ' script -d %s/boot/boot.txt %s/boot/flash.scr'
+            % (sudo_args, self.tempdir, self.tempdir),
+            '%s dd if=/tmp/temp_snowball_make_boot_files' \
+            ' of=boot_device_or_file bs=512 conv=notrunc seek=256'
+            % (sudo_args),
+            '%s dd if=%s/boot/boot_image_issw.bin of=boot_device_or_file' \
+            ' bs=512 conv=notrunc seek=257' % (sudo_args, self.tempdir),
+            '%s rm %s/boot_image_issw.bin' % (sudo_args,
+            self.temp_bootdir_path),
+            '%s dd if=%s/boot/boot_image_x-loader.bin of=boot_device_or_file' \
+            ' bs=1 conv=notrunc seek=131588' % (sudo_args, self.tempdir),
+            '%s rm %s/boot_image_x-loader.bin' % (sudo_args,
+            self.temp_bootdir_path),
+            '%s dd if=%s/boot/mem_init.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=3072' % (sudo_args, self.tempdir),
+            '%s rm %s/mem_init.bin' % (sudo_args, self.temp_bootdir_path),
+            '%s dd if=%s/boot/power_management.bin of=boot_device_or_file' \
+            ' bs=512 conv=notrunc seek=3200' % (sudo_args, self.tempdir),
+            '%s rm %s/power_management.bin' % (sudo_args,
+            self.temp_bootdir_path),
+            '%s dd if=%s/boot/u-boot.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=24064' % (sudo_args, self.tempdir),
+            '%s rm %s/u-boot.bin' % (sudo_args, self.temp_bootdir_path),
+            '%s dd if=%s/boot/u-boot-env.bin of=boot_device_or_file bs=512' \
+            ' conv=notrunc seek=25080' % (sudo_args, self.tempdir),
+            '%s rm %s/u-boot-env.bin' % (sudo_args, self.temp_bootdir_path),
+            '%s rm /tmp/temp_snowball_make_boot_files' % (sudo_args),
+            '%s rm %s/startfiles.cfg' % (sudo_args, self.temp_bootdir_path)]
+
+        self.assertEqual(expected, fixture.mock.commands_executed)
+
+    def test_missing_files(self):
+        '''When the files cannot be read, an IOError should be raised'''
+        self.assertRaises(IOError,
+                          boards.SnowballEmmcConfig.get_file_info,
+                          self.tempdir)
+
+    def test_normal_case(self):
+        expected = self.setupFiles()
+        actual = boards.SnowballEmmcConfig.get_file_info(
+            self.temp_bootdir_path)
+        self.assertEquals(expected, actual)
+
+
 class TestBootSteps(TestCaseWithFixtures):
 
     def setUp(self):
@@ -410,6 +662,18 @@ 
             '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-',
             board_configs['smdkv310'].get_sfdisk_cmd())
 
+    def test_panda_android(self):
+        self.assertEqual(
+            '63,270272,0x0C,*\n270336,524288,L\n794624,524288,L\n' \
+                '1318912,-,E\n1318912,1048576,L\n2367488,,,-', 
+                android_boards.AndroidPandaConfig.get_sfdisk_cmd())
+
+    def test_snowball_emmc_android(self):
+        self.assertEqual(
+            '256,7936,0xDA\n8192,262144,0x0C,*\n270336,524288,L\n' \
+                '794624,-,E\n794624,524288,L\n1318912,1048576,L\n2367488,,,-', 
+                android_boards.AndroidSnowballEmmcConfig.get_sfdisk_cmd())
+
 
 class TestGetBootCmd(TestCase):
 
@@ -583,6 +847,21 @@ 
                        'fatload mmc 0:1 0x81600000 uInitrd; '
                        'bootm 0x80200000 0x81600000'}
         self.assertEqual(expected, boot_commands)
+	
+    def test_android_snowball_emmc(self):
+        boot_commands = (android_boards.AndroidSnowballEmmcConfig.
+                         _get_boot_env(consoles=[]))
+        expected = {
+            'bootargs': 'console=tty0 console=ttyAMA2,115200n8 '
+                        'rootwait ro earlyprintk '
+                        'rootdelay=1 fixrtc nocompcache '
+                        'mem=128M@0 mali.mali_mem=64M@128M mem=24M@192M '
+                        'hwmem=167M@216M mem_issw=1M@383M mem=640M@384M '
+                        'vmalloc=256M init=/init androidboot.console=ttyAMA2',
+            'bootcmd': 'fatload mmc 1:1 0x00100000 uImage; '
+                       'fatload mmc 1:1 0x08000000 uInitrd; '
+                       'bootm 0x00100000 0x08000000'}
+        self.assertEqual(expected, boot_commands)
 
 
 class TestUnpackBinaryTarball(TestCaseWithFixtures):
@@ -986,13 +1265,21 @@ 
             (63 * SECTOR_SIZE, 32768 * SECTOR_SIZE),
             (32831 * SECTOR_SIZE, 65536 * SECTOR_SIZE),
             (98367 * SECTOR_SIZE, 65536 * SECTOR_SIZE),
-            (294975 * SECTOR_SIZE, (self.android_image_size - 
-                                     294975 * SECTOR_SIZE)),
             ((294975 + ext_part_size) * SECTOR_SIZE,
              (131072 - ext_part_size) * SECTOR_SIZE),
             ((426047 + ext_part_size) * SECTOR_SIZE, 
              self.android_image_size - (426047 + ext_part_size) * SECTOR_SIZE)
             ]
+        
+        self.android_snowball_offsets_and_sizes = [
+            (8192 * SECTOR_SIZE, 24639 * SECTOR_SIZE),
+            (32831 * SECTOR_SIZE, 65536 * SECTOR_SIZE),
+            ((98367  + ext_part_size)* SECTOR_SIZE, 
+             (65536 - ext_part_size) * SECTOR_SIZE),
+            (294975 * SECTOR_SIZE, 131072 * SECTOR_SIZE),
+            ((426047 + ext_part_size) * SECTOR_SIZE, 
+             self.android_image_size - (426047 + ext_part_size) * SECTOR_SIZE)
+            ]
 
     def tearDown(self):
         super(TestPartitionSetup, self).tearDown()
@@ -1009,6 +1296,13 @@ 
             '63,32768,0x0C,*\n32831,65536,L\n98367,65536,L\n294975,-,E\n' \
                 '294975,131072,L\n426047,,,-', '%s' % self.android_image_size)
 
+    def _create_snowball_android_tmpfile(self):
+        # raw, boot, system, cache, (extended), userdata and sdcard partitions
+        return self._create_qemu_img_with_partitions(
+            '256,7936,0xDA\n8192,24639,0x0C,*\n32831,65536,L\n' \
+            '98367,-,E\n98367,65536,L\n294975,131072,L\n' \
+            '426047,,,-', '%s' % self.android_image_size)
+
     def test_convert_size_no_suffix(self):
         self.assertEqual(524288, convert_size_to_bytes('524288'))
 
@@ -1038,6 +1332,15 @@ 
                                               self.android_offsets_and_sizes):
             self.assertEqual(device_pair, expected_pair)
 
+    def test_calculate_snowball_android_partition_size_and_offset(self):
+        tmpfile = self._create_snowball_android_tmpfile()
+        device_info = calculate_android_partition_size_and_offset(tmpfile)
+        # We use map(None, ...) since it would catch if the lists are not of
+        # equal length and zip() would not in all cases.
+        for device_pair, expected_pair in map(None, device_info,
+                                              self.android_snowball_offsets_and_sizes):
+            self.assertEqual(device_pair, expected_pair)
+
     def test_partition_numbering(self):
         # another Linux partition at +24 MiB after the boot/root parts
         tmpfile = self._create_qemu_img_with_partitions(
@@ -1147,7 +1450,7 @@ 
 
         # get_boot_and_root_loopback_devices will also setup two exit handlers
         # to de-register the loopback devices set up above.
-        self.assertEqual(6, len(atexit_fixture.mock.funcs))
+        self.assertEqual(5, len(atexit_fixture.mock.funcs))
         popen_fixture.mock.calls = []
         atexit_fixture.mock.run_funcs()
         # We did not really run losetup above (as it requires root) so here we
@@ -1158,7 +1461,6 @@ 
              '%s losetup -d ' % sudo_args,
              '%s losetup -d ' % sudo_args,
              '%s losetup -d ' % sudo_args,
-             '%s losetup -d ' % sudo_args,
              '%s losetup -d ' % sudo_args],
             popen_fixture.mock.commands_executed)