=== modified file 'linaro_media_create/boards.py'
--- linaro_media_create/boards.py	2011-03-08 15:15:39 +0000
+++ linaro_media_create/boards.py	2011-03-09 15:55:56 +0000
@@ -29,6 +29,8 @@
 import os
 import re
 import tempfile
+import struct
+from binascii import crc32
 
 from linaro_media_create import cmd_runner
 from linaro_media_create.partitions import SECTOR_SIZE
@@ -63,6 +65,44 @@
 # root partition; at least 50 MiB; XXX this shouldn't be hardcoded
 ROOT_MIN_SIZE_S = align_up(50 * 1024 * 1024, SECTOR_SIZE) / SECTOR_SIZE
 
+# Samsung v310 implementation notes
+# * BL1 (SPL) is expected at offset +1s and is 32s long
+# * BL2 (u-boot) is loaded at a raw MMC offset of +65s by BL1 which currently
+# doesn't support FAT
+# * the u-boot environment is at +33s and is 32s long (16 KiB)
+# * currently, some hardware issues on certain boards causes u-boot to not be
+# able to use FAT to load uImage and uInitrd (or boot.scr); as a temporary
+# workaround, these are loaded from +1089s and +9281s respectively
+# * hence we hardcode all offsets, make sure that the files aren't larger than
+# their reserved spot, and create a bootloader partition from the first
+# sector after MBR up to end of initrd
+SAMSUNG_V310_BL1_START = 1
+SAMSUNG_V310_BL1_LEN = 32
+SAMSUNG_V310_ENV_START = SAMSUNG_V310_BL1_START + SAMSUNG_V310_BL1_LEN
+SAMSUNG_V310_ENV_LEN = 32
+assert SAMSUNG_V310_ENV_START == 33, "BL1 expects u-boot environment at +33s"
+assert SAMSUNG_V310_ENV_LEN * SECTOR_SIZE == 16 * 1024, (
+    "BL1 expects u-boot environment to be 16 KiB")
+SAMSUNG_V310_BL2_START = SAMSUNG_V310_ENV_START + SAMSUNG_V310_ENV_LEN
+SAMSUNG_V310_BL2_LEN = 1024
+assert SAMSUNG_V310_BL2_LEN * SECTOR_SIZE == 512 * 1024, (
+    "BL1 expects BL2 (u-boot) to be 512 KiB")
+SAMSUNG_V310_UIMAGE_START = SAMSUNG_V310_BL2_START + SAMSUNG_V310_BL2_LEN
+SAMSUNG_V310_UIMAGE_LEN = 8192
+assert SAMSUNG_V310_UIMAGE_START == 1089, (
+    "BL2 (u-boot) expects uImage at +1089s")
+assert SAMSUNG_V310_UIMAGE_LEN * SECTOR_SIZE == 4 * 1024 * 1024, (
+    "BL2 (u-boot) expects uImage to be 4 MiB")
+SAMSUNG_V310_UINITRD_START = (
+    SAMSUNG_V310_UIMAGE_START + SAMSUNG_V310_UIMAGE_LEN)
+SAMSUNG_V310_UINITRD_RESERVED_LEN = 204800
+SAMSUNG_V310_UINITRD_COPY_LEN = 32768
+assert SAMSUNG_V310_UINITRD_START == 9281, (
+    "BL2 (u-boot) expects uInitrd at +9281s")
+assert SAMSUNG_V310_UINITRD_RESERVED_LEN * SECTOR_SIZE == 100 * 1024 * 1024, (
+    "BL2 (u-boot) expects uInitrd to be 100 MiB")
+assert SAMSUNG_V310_UINITRD_COPY_LEN * SECTOR_SIZE == 16 * 1024 * 1024, (
+    "Only copy 16MiB for a faster boot")
 
 def align_partition(min_start, min_length, start_alignment, end_alignment):
     """Compute partition start and end offsets based on specified constraints.
@@ -81,6 +121,14 @@
     return start, end, length
 
 
+class classproperty(object):
+    """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)
+
+
 class BoardConfig(object):
     """The configuration used when building an image for a board."""
     # These attributes may not need to be redefined on some subclasses.
@@ -139,9 +187,24 @@
         return '%s,%s,%s,*\n%s,,,-' % (
             boot_start, boot_len, partition_type, root_start)
 
+    @classproperty
+    def bootcmd(cls):
+        """Get the bootcmd for this board.
+
+        In general subclasses should not have to override this.
+        """
+        replacements = dict(
+            mmc_option=cls.mmc_option, kernel_addr=cls.kernel_addr,
+            initrd_addr=cls.initrd_addr)
+        return (
+            "fatload mmc %(mmc_option)s %(kernel_addr)s "
+                "uImage; fatload mmc %(mmc_option)s %(initrd_addr)s uInitrd; "
+                "bootm %(kernel_addr)s %(initrd_addr)s"
+                % replacements)
+
     @classmethod
-    def _get_boot_cmd(cls, is_live, is_lowmem, consoles, rootfs_uuid):
-        """Get the boot command for this board.
+    def _get_bootargs(cls, is_live, is_lowmem, consoles, rootfs_uuid):
+        """Get the bootargs for this board.
 
         In general subclasses should not have to override this.
         """
@@ -161,30 +224,37 @@
                 lowmem_opt = 'only-ubiquity'
 
         replacements = dict(
-            mmc_option=cls.mmc_option, kernel_addr=cls.kernel_addr,
-            initrd_addr=cls.initrd_addr, serial_opts=serial_opts,
+            serial_opts=serial_opts,
             lowmem_opt=lowmem_opt, boot_snippet=boot_snippet,
             boot_args_options=boot_args_options)
         return (
-            "setenv bootcmd 'fatload mmc %(mmc_option)s %(kernel_addr)s "
-                "uImage; fatload mmc %(mmc_option)s %(initrd_addr)s uInitrd; "
-                "bootm %(kernel_addr)s %(initrd_addr)s'\n"
-            "setenv bootargs '%(serial_opts)s %(lowmem_opt)s "
-                "%(boot_snippet)s %(boot_args_options)s'\n"
-            "boot" % replacements)
+            "%(serial_opts)s %(lowmem_opt)s "
+                "%(boot_snippet)s %(boot_args_options)s"
+             % replacements)
+
+    @classmethod
+    def _get_boot_env(cls, is_live, is_lowmem, consoles, rootfs_uuid):
+        """Get the boot environment for this board.
+
+        In general subclasses should not have to override this.
+        """
+        boot_env = {}
+        boot_env["bootargs"] = cls._get_bootargs(
+            is_live, is_lowmem, consoles, rootfs_uuid)
+        boot_env["bootcmd"] = cls.bootcmd
+        return boot_env
 
     @classmethod
     def make_boot_files(cls, uboot_parts_dir, is_live, is_lowmem, consoles,
-                        root_dir, rootfs_uuid, boot_dir, boot_script,
+                        chroot_dir, rootfs_uuid, boot_dir, boot_script,
                         boot_device_or_file):
-        boot_cmd = cls._get_boot_cmd(
-            is_live, is_lowmem, consoles, rootfs_uuid)
+        boot_env = cls._get_boot_env(is_live, is_lowmem, consoles, rootfs_uuid)
         cls._make_boot_files(
-            uboot_parts_dir, boot_cmd, root_dir, boot_dir, boot_script,
+            uboot_parts_dir, boot_env, chroot_dir, boot_dir, boot_script,
             boot_device_or_file)
 
     @classmethod
-    def _make_boot_files(cls, uboot_parts_dir, boot_cmd, root_dir, boot_dir,
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
                          boot_script, boot_device_or_file):
         """Make the necessary boot files for this board.
 
@@ -194,14 +264,6 @@
         raise NotImplementedError()
 
 
-class classproperty(object):
-    """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)
-
-
 class OmapConfig(BoardConfig):
     kernel_suffix = 'linaro-omap'
     uboot_in_boot_part = True
@@ -248,24 +310,24 @@
 
     @classmethod
     def make_boot_files(cls, uboot_parts_dir, is_live, is_lowmem, consoles,
-                        root_dir, rootfs_uuid, boot_dir, boot_script,
+                        chroot_dir, rootfs_uuid, boot_dir, boot_script,
                         boot_device_or_file):
         # XXX: This is also part of our temporary hack to fix bug 697824; we
         # need to call set_appropriate_serial_tty() before doing anything that
         # may use cls.serial_tty.
-        cls.set_appropriate_serial_tty(root_dir)
+        cls.set_appropriate_serial_tty(chroot_dir)
         super(OmapConfig, cls).make_boot_files(
-            uboot_parts_dir, is_live, is_lowmem, consoles, root_dir,
+            uboot_parts_dir, is_live, is_lowmem, consoles, chroot_dir,
             rootfs_uuid, boot_dir, boot_script, boot_device_or_file)
 
     @classmethod
-    def _make_boot_files(cls, uboot_parts_dir, boot_cmd, chroot_dir,
-                         boot_dir, boot_script, boot_device_or_file):
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
+                         boot_script, boot_device_or_file):
         install_omap_boot_loader(chroot_dir, boot_dir)
         make_uImage(
             cls.load_addr, uboot_parts_dir, cls.kernel_suffix, boot_dir)
         make_uInitrd(uboot_parts_dir, cls.kernel_suffix, boot_dir)
-        make_boot_script(boot_cmd, boot_script)
+        make_boot_script(boot_env, boot_script)
         make_boot_ini(boot_script, boot_dir)
 
 
@@ -315,12 +377,12 @@
     uboot_flavor = None
 
     @classmethod
-    def _make_boot_files(cls, uboot_parts_dir, boot_cmd, chroot_dir,
-                         boot_dir, boot_script, boot_device_or_file):
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
+                         boot_script, boot_device_or_file):
         make_uImage(
             cls.load_addr, uboot_parts_dir, cls.kernel_suffix, boot_dir)
         make_uInitrd(uboot_parts_dir, cls.kernel_suffix, boot_dir)
-        make_boot_script(boot_cmd, boot_script)
+        make_boot_script(boot_env, boot_script)
         make_boot_ini(boot_script, boot_dir)
 
 
@@ -341,12 +403,12 @@
     mmc_option = '1:1'
 
     @classmethod
-    def _make_boot_files(cls, uboot_parts_dir, boot_cmd, chroot_dir,
-                         boot_dir, boot_script, boot_device_or_file):
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
+                         boot_script, boot_device_or_file):
         make_uImage(
             cls.load_addr, uboot_parts_dir, cls.kernel_suffix, boot_dir)
         make_uInitrd(uboot_parts_dir, cls.kernel_suffix, boot_dir)
-        make_boot_script(boot_cmd, boot_script)
+        make_boot_script(boot_env, boot_script)
 
 
 class Mx5Config(BoardConfig):
@@ -390,15 +452,15 @@
             loader_start, loader_len, boot_start, boot_len, root_start)
 
     @classmethod
-    def _make_boot_files(cls, uboot_parts_dir, boot_cmd, chroot_dir,
-                         boot_dir, boot_script, boot_device_or_file):
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
+                         boot_script, boot_device_or_file):
         uboot_file = os.path.join(
             chroot_dir, 'usr', 'lib', 'u-boot', cls.uboot_flavor, 'u-boot.imx')
         install_mx5_boot_loader(uboot_file, boot_device_or_file)
         make_uImage(
             cls.load_addr, uboot_parts_dir, cls.kernel_suffix, boot_dir)
         make_uInitrd(uboot_parts_dir, cls.kernel_suffix, boot_dir)
-        make_boot_script(boot_cmd, boot_script)
+        make_boot_script(boot_env, boot_script)
 
 
 class EfikamxConfig(Mx5Config):
@@ -433,12 +495,90 @@
     fat_size = 16
 
     @classmethod
-    def _make_boot_files(cls, uboot_parts_dir, boot_cmd, chroot_dir,
-                         boot_dir, boot_script, boot_device_or_file):
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
+                         boot_script, boot_device_or_file):
         make_uImage(
             cls.load_addr, uboot_parts_dir, cls.kernel_suffix, boot_dir)
         make_uInitrd(uboot_parts_dir, cls.kernel_suffix, boot_dir)
 
+class SMDKV310Config(BoardConfig):
+    serial_tty = 'ttySAC1'
+    extra_serial_opts = 'console=%s,115200n8' % serial_tty
+    kernel_addr = '0x40007000'
+    initrd_addr = '0x41000000'
+    load_addr = '0x40008000'
+    kernel_suffix = 's5pv310'
+    boot_script = 'boot.scr'
+    mmc_part_offset = 1
+    mmc_option = '0:2'
+
+    @classmethod
+    def get_sfdisk_cmd(cls, should_align_boot_part=False):
+        # bootloader partition needs to hold everything from BL1 to uInitrd
+        # inclusive
+        min_len = (
+            SAMSUNG_V310_UINITRD_START + SAMSUNG_V310_UINITRD_RESERVED_LEN -
+            SAMSUNG_V310_BL1_START)
+
+        # bootloader partition
+        loader_start, loader_end, loader_len = align_partition(
+            1, min_len, 1, PART_ALIGN_S)
+
+        # FAT boot partition
+        boot_start, boot_end, boot_len = align_partition(
+            loader_end + 1, BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S)
+
+        # root partition
+        # we ignore _root_end / _root_len and return a sfdisk command to
+        # instruct the use of all remaining space; XXX if we had some root size
+        # config, we could do something more sensible
+        root_start, _root_end, _root_len = align_partition(
+            boot_end + 1, ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S)
+
+        return '%s,%s,0xDA\n%s,%s,0x0C,*\n%s,,,-' % (
+            loader_start, loader_len, boot_start, boot_len, root_start)
+
+    @classmethod
+    def _get_boot_env(cls, is_live, is_lowmem, consoles, rootfs_uuid):
+        boot_env = super(SMDKV310Config, cls)._get_boot_env(
+            is_live, is_lowmem, consoles, rootfs_uuid)
+
+        boot_env["ethact"] = "smc911x-0"
+        boot_env["ethaddr"] = "00:40:5c:26:0a:5b"
+        # XXX fixme once FAT support is fixed in u-boot bug 727978
+        boot_env["bootcmd"] = (
+            "movi read kernel %(kernel_addr)s; "
+            "movi read rootfs %(initrd_addr)s %(rootfs_size)s; "
+            "bootm %(kernel_addr)s %(initrd_addr)s" % {
+                'kernel_addr': cls.kernel_addr,
+                'initrd_addr': cls.initrd_addr,
+                'rootfs_size': hex(SAMSUNG_V310_UINITRD_COPY_LEN * SECTOR_SIZE)})
+
+        return boot_env
+
+    @classmethod
+    def _make_boot_files(cls, uboot_parts_dir, boot_env, chroot_dir, boot_dir,
+                         boot_script, boot_device_or_file):
+        uboot_file = os.path.join(
+            chroot_dir, 'usr', 'lib', 'u-boot', 'smdkv310', 'u-boot.v310')
+        install_smdkv310_boot_loader(uboot_file, boot_device_or_file)
+
+        env_size = SAMSUNG_V310_ENV_LEN * SECTOR_SIZE
+        env_file = make_flashable_env(boot_env, env_size)
+        install_smdkv310_boot_env(env_file, boot_device_or_file)
+
+        uImage_file = make_uImage(
+            cls.load_addr, uboot_parts_dir, cls.kernel_suffix, boot_dir)
+        install_smdkv310_uImage(uImage_file, boot_device_or_file)
+
+        uInitrd_file = make_uInitrd(
+            uboot_parts_dir, cls.kernel_suffix, boot_dir)
+        install_smdkv310_initrd(uInitrd_file, boot_device_or_file)
+
+        # unused at the moment once FAT support enabled for the 
+        # Samsung u-boot this can be used bug 727978
+        #make_boot_script(boot_env, boot_script)
+
 
 board_configs = {
     'beagle': BeagleConfig,
@@ -450,9 +590,26 @@
     'mx51evk': Mx51evkConfig,
     'mx53loco' : Mx53LoCoConfig,
     'overo': OveroConfig,
+    'smdkv310': SMDKV310Config,
     }
 
 
+def _dd(input_file, output_file, block_size=SECTOR_SIZE, count=None, seek=None,
+        skip=None):
+    """Wrapper around the dd command"""
+    cmd = [
+        "dd", "if=%s" % input_file, "of=%s" % output_file,
+        "bs=%s" % block_size, "conv=notrunc"]
+    if count is not None:
+        cmd.append("count=%s" % count)
+    if seek is not None:
+        cmd.append("seek=%s" % seek)
+    if skip is not None:
+        cmd.append("skip=%s" % skip)
+    proc = cmd_runner.run(cmd, as_root=True)
+    proc.wait()
+
+
 def _run_mkimage(img_type, load_addr, entry_point, name, img_data, img,
                  stdout=None, as_root=True):
     cmd = ['mkimage',
@@ -491,18 +648,26 @@
     img_data = _get_file_matching(
         '%s/vmlinuz-*-%s' % (uboot_parts_dir, suffix))
     img = '%s/uImage' % boot_disk
-    return _run_mkimage(
+    _run_mkimage(
         'kernel', load_addr, load_addr, 'Linux', img_data, img)
+    return img
 
 
 def make_uInitrd(uboot_parts_dir, suffix, boot_disk):
     img_data = _get_file_matching(
         '%s/initrd.img-*-%s' % (uboot_parts_dir, suffix))
     img = '%s/uInitrd' % boot_disk
-    return _run_mkimage('ramdisk', '0', '0', 'initramfs', img_data, img)
-
-
-def make_boot_script(boot_script_data, boot_script):
+    _run_mkimage('ramdisk', '0', '0', 'initramfs', img_data, img)
+    return img
+
+
+def make_boot_script(boot_env, boot_script):
+    boot_script_data = (
+        "setenv bootcmd '%(bootcmd)s'\n"
+        "setenv bootargs '%(bootargs)s'\n"
+        "boot"
+        % boot_env)
+
     # Need to save the boot script data into a file that will be passed to
     # mkimage.
     _, tmpfile = tempfile.mkstemp()
@@ -516,15 +681,40 @@
         'script', '0', '0', 'boot script', plain_boot_script, boot_script)
 
 
+def make_flashable_env(boot_env, env_size):
+    env_strings = ["%s=%s" % (k, v) for k, v in boot_env.items()]
+    env_strings.sort()
+    env = struct.pack('B', 0).join(env_strings)
+
+    # we still need to zero-terminate the last string, and 4 bytes for crc
+    assert len(env) + 1 + 4 <= env_size, (
+        "environment doesn't fit in %s bytes" % env_size)
+
+    # pad the rest of the env for the CRC calc; the "s" format will write zero
+    # bytes to pad the (empty) string to repeat count
+    env += struct.pack('%ss' % (env_size - len(env) - 4), '')
+
+    crc = crc32(env)
+    env = struct.pack('<i', crc) + env
+
+    _, tmpfile = tempfile.mkstemp()
+
+    with open(tmpfile, 'w') as fd:
+        fd.write(env)
+
+    return tmpfile
+
+
 def install_mx5_boot_loader(imx_file, boot_device_or_file):
-    proc = cmd_runner.run([
-        "dd",
-        "if=%s" % imx_file,
-        "of=%s" % boot_device_or_file,
-        "bs=1024",
-        "seek=1",
-        "conv=notrunc"], as_root=True)
-    proc.wait()
+    # bootloader partition starts at +1s but we write the file at +2s, so we
+    # need to check that the bootloader partition minus 1s is at least as large
+    # as the u-boot binary; note that the real bootloader partition might be
+    # larger than LOADER_MIN_SIZE_S, but if u-boot is larger it's a sign we
+    # need to bump LOADER_MIN_SIZE_S
+    max_size = (LOADER_MIN_SIZE_S - 1) * SECTOR_SIZE
+    assert os.path.getsize(imx_file) <= max_size, (
+        "%s is larger than guaranteed bootloader partition size" % imx_file)
+    _dd(imx_file, boot_device_or_file, seek=2)
 
 
 def _get_mlo_file(chroot_dir):
@@ -561,3 +751,54 @@
     proc = cmd_runner.run(
         ["cp", "-v", boot_script, "%s/boot.ini" % boot_disk], as_root=True)
     proc.wait()
+
+
+def install_smdkv310_uImage(uImage_file, boot_device_or_file):
+    # the layout keeps SAMSUNG_V310_UIMAGE_LEN sectors for uImage; make sure
+    # uImage isn't actually larger or it would be truncated
+    max_size = SAMSUNG_V310_UIMAGE_LEN * SECTOR_SIZE
+    assert os.path.getsize(uImage_file) <= max_size, (
+        "%s is larger than the allocated v310 uImage length" % uImage_file)
+    _dd(uImage_file, boot_device_or_file, count=SAMSUNG_V310_UIMAGE_LEN,
+        seek=SAMSUNG_V310_UIMAGE_START)
+
+
+def install_smdkv310_initrd(initrd_file, boot_device_or_file):
+    # the layout keeps SAMSUNG_V310_UINITRD_RESERVED_LEN sectors for uInitrd
+    # but only SAMSUNG_V310_UINITRD_COPY_LEN sectors are loaded into memory;
+    # make sure uInitrd isn't actually larger or it would be truncated in
+    # memory
+    max_size = SAMSUNG_V310_UINITRD_COPY_LEN * SECTOR_SIZE
+    assert os.path.getsize(initrd_file) <= max_size, (
+        "%s is larger than the v310 uInitrd length as used by u-boot"
+            % initrd_file)
+    _dd(initrd_file, boot_device_or_file,
+        count=SAMSUNG_V310_UINITRD_COPY_LEN,
+        seek=SAMSUNG_V310_UINITRD_START)
+
+
+def install_smdkv310_boot_env(env_file, boot_device_or_file):
+    # the environment file is exactly SAMSUNG_V310_ENV_LEN as created by
+    # make_flashable_env(), so we don't need to check the size of env_file
+    _dd(env_file, boot_device_or_file, count=SAMSUNG_V310_ENV_LEN,
+        seek=SAMSUNG_V310_ENV_START)
+
+
+def install_smdkv310_boot_loader(v310_file, boot_device_or_file):
+    """Samsung specific terminology
+    BL0 is the first stage bootloader,
+    BL1 is the SPL (secondary program loader)
+    v310_file is a binary with the same layout as BL1 + u-boot environment +
+    BL2; write BL1 (SPL) piece first (SAMSUNG_V310_BL1_LEN sectors at +0s in
+    the file and +SAMSUNG_V310_BL1_START on disk), then write BL2 (u-boot)
+    piece (rest of the file starting at +(SAMSUNG_V310_BL1_LEN +
+    SAMSUNG_V310_ENV_LEN)s in the file which is the same as
+    +(SAMSUNG_V310_BL2_START - SAMSUNG_V310_BL1_START)s)
+    """
+    _dd(v310_file, boot_device_or_file, count=SAMSUNG_V310_BL1_LEN,
+        seek=SAMSUNG_V310_BL1_START)
+    # XXX need to check that the length of v310_file - 64s is smaller than
+    # SAMSUNG_V310_BL2_LEN
+    _dd(v310_file, boot_device_or_file, seek=SAMSUNG_V310_BL2_START,
+        skip=(SAMSUNG_V310_BL2_START - SAMSUNG_V310_BL1_START))
+

=== modified file 'linaro_media_create/tests/test_media_create.py'
--- linaro_media_create/tests/test_media_create.py	2011-03-03 13:44:11 +0000
+++ linaro_media_create/tests/test_media_create.py	2011-03-09 15:55:56 +0000
@@ -43,9 +43,12 @@
     )
 import linaro_media_create
 from linaro_media_create.boards import (
+    LOADER_MIN_SIZE_S,
+    SECTOR_SIZE,
     align_up,
     align_partition,
     board_configs,
+    make_flashable_env,
     install_mx5_boot_loader,
     install_omap_boot_loader,
     make_boot_script,
@@ -258,6 +261,15 @@
             'make_boot_script']
         self.assertEqual(expected, self.funcs_calls)
 
+    def test_smdkv310_steps(self):
+        self.make_boot_files(boards.SMDKV310Config)
+        expected = [
+            'install_smdkv310_boot_loader', 'make_flashable_env',
+            'install_smdkv310_boot_env', 'make_uImage',
+            'install_smdkv310_uImage', 'make_uInitrd',
+            'install_smdkv310_initrd',]
+        self.assertEqual(expected, self.funcs_calls)
+
     def test_ux500_steps(self):
         self.make_boot_files(boards.Ux500Config)
         expected = ['make_uImage', 'make_uInitrd', 'make_boot_script']
@@ -372,44 +384,67 @@
             '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-',
             boards.Mx5Config.get_sfdisk_cmd())
 
+    def test_smdkv310(self):
+        self.assertEquals(
+            '1,221183,0xDA\n221184,106496,0x0C,*\n327680,,,-',
+            board_configs['smdkv310'].get_sfdisk_cmd())
+
 
 class TestGetBootCmd(TestCase):
 
     def test_vexpress(self):
-        boot_cmd = board_configs['vexpress']._get_boot_cmd(
+        boot_commands = board_configs['vexpress']._get_boot_env(
             is_live=False, is_lowmem=False, consoles=['ttyXXX'],
             rootfs_uuid="deadbeef")
-        expected = (
-            "setenv bootcmd 'fatload mmc 0:1 0x60008000 uImage; fatload mmc "
-            "0:1 0x81000000 uInitrd; bootm 0x60008000 0x81000000'\nsetenv "
-            "bootargs 'console=tty0 console=ttyAMA0,38400n8 console=ttyXXX  "
-            "root=UUID=deadbeef rootwait ro'\nboot")
-        self.assertEqual(expected, boot_cmd)
+        expected = {
+            'bootargs': 'console=tty0 console=ttyAMA0,38400n8 console=ttyXXX  '
+                        'root=UUID=deadbeef rootwait ro',
+            'bootcmd': 'fatload mmc 0:1 0x60008000 uImage; '
+                       'fatload mmc 0:1 0x81000000 uInitrd; '
+                       'bootm 0x60008000 0x81000000'}
+        self.assertEqual(expected, boot_commands)
 
     def test_mx5(self):
-        boot_cmd = boards.Mx5Config._get_boot_cmd(
-            is_live=False, is_lowmem=False, consoles=[],
-            rootfs_uuid="deadbeef")
-        expected = (
-            "setenv bootcmd 'fatload mmc 0:2 0x90000000 uImage; fatload mmc "
-            "0:2 0x90800000 uInitrd; bootm 0x90000000 0x90800000'\nsetenv "
-            "bootargs 'console=tty0 console=ttymxc0,115200n8  "
-            "root=UUID=deadbeef rootwait ro'\nboot")
-        self.assertEqual(expected, boot_cmd)
+        boot_commands = boards.Mx5Config._get_boot_env(
+            is_live=False, is_lowmem=False, consoles=[],
+            rootfs_uuid="deadbeef")
+        expected = {
+            'bootargs': 'console=tty0 console=ttymxc0,115200n8  '
+                        'root=UUID=deadbeef rootwait ro',
+            'bootcmd': 'fatload mmc 0:2 0x90000000 uImage; '
+                       'fatload mmc 0:2 0x90800000 uInitrd; '
+                       'bootm 0x90000000 0x90800000'}
+        self.assertEqual(expected, boot_commands)
+
+    def test_smdkv310(self):
+        boot_commands = board_configs['smdkv310']._get_boot_env(
+            is_live=False, is_lowmem=False, consoles=[],
+            rootfs_uuid="deadbeef")
+        expected = {
+            'bootargs': 'console=ttySAC1,115200n8  root=UUID=deadbeef '
+                        'rootwait ro',
+             'bootcmd': 'movi read kernel 0x40007000; '
+                        'movi read rootfs 0x41000000 0x1000000; '
+                        'bootm 0x40007000 0x41000000',
+             'ethact': 'smc911x-0',
+             'ethaddr': '00:40:5c:26:0a:5b'}
+        self.assertEqual(expected, boot_commands)
 
     def test_ux500(self):
-        boot_cmd = board_configs['ux500']._get_boot_cmd(
+        boot_commands = board_configs['ux500']._get_boot_env(
             is_live=False, is_lowmem=False, consoles=[],
             rootfs_uuid="deadbeef")
-        expected = (
-            "setenv bootcmd 'fatload mmc 1:1 0x00100000 uImage; fatload mmc "
-            "1:1 0x08000000 uInitrd; bootm 0x00100000 0x08000000'\nsetenv "
-            "bootargs 'console=tty0 console=ttyAMA2,115200n8  "
-            "root=UUID=deadbeef rootwait ro earlyprintk rootdelay=1 fixrtc "
-            "nocompcache mem=96M@0 mem_modem=32M@96M mem=44M@128M "
-            "pmem=22M@172M mem=30M@194M mem_mali=32M@224M "
-            "pmem_hwb=54M@256M hwmem=48M@302M mem=152M@360M'\nboot")
-        self.assertEqual(expected, boot_cmd)
+        expected = {
+            'bootargs': 'console=tty0 console=ttyAMA2,115200n8  '
+                        'root=UUID=deadbeef rootwait ro earlyprintk '
+                        'rootdelay=1 fixrtc nocompcache mem=96M@0 '
+                        'mem_modem=32M@96M mem=44M@128M pmem=22M@172M '
+                        'mem=30M@194M mem_mali=32M@224M pmem_hwb=54M@256M '
+                        'hwmem=48M@302M mem=152M@360M',
+            'bootcmd': 'fatload mmc 1:1 0x00100000 uImage; '
+                       'fatload mmc 1:1 0x08000000 uInitrd; '
+                       'bootm 0x00100000 0x08000000'}
+        self.assertEqual(expected, boot_commands)
 
     def test_panda(self):
         # XXX: To fix bug 697824 we have to change class attributes of our
@@ -417,17 +452,18 @@
         # don't interfere with us we'll reset that before doing anything.
         config = board_configs['panda']
         config.serial_tty = config._serial_tty
-        boot_cmd = config._get_boot_cmd(
+        boot_commands = config._get_boot_env(
             is_live=False, is_lowmem=False, consoles=[],
             rootfs_uuid="deadbeef")
-        expected = (
-            "setenv bootcmd 'fatload mmc 0:1 0x80200000 uImage; fatload mmc "
-            "0:1 0x81600000 uInitrd; bootm 0x80200000 0x81600000'\nsetenv "
-            "bootargs 'console=tty0 console=ttyO2,115200n8  "
-            "root=UUID=deadbeef rootwait ro earlyprintk fixrtc nocompcache "
-            "vram=32M omapfb.vram=0:8M mem=463M "
-            "ip=none'\nboot")
-        self.assertEqual(expected, boot_cmd)
+        expected = {
+            'bootargs': 'console=tty0 console=ttyO2,115200n8  '
+                        'root=UUID=deadbeef rootwait ro earlyprintk fixrtc '
+                        'nocompcache vram=32M omapfb.vram=0:8M mem=463M '
+                        'ip=none',
+            'bootcmd': 'fatload mmc 0:1 0x80200000 uImage; '
+                       'fatload mmc 0:1 0x81600000 uInitrd; '
+                       'bootm 0x80200000 0x81600000'}
+        self.assertEqual(expected, boot_commands)
 
     def test_beagle(self):
         # XXX: To fix bug 697824 we have to change class attributes of our
@@ -435,17 +471,17 @@
         # don't interfere with us we'll reset that before doing anything.
         config = board_configs['beagle']
         config.serial_tty = config._serial_tty
-        boot_cmd = config._get_boot_cmd(
+        boot_commands = config._get_boot_env(
             is_live=False, is_lowmem=False, consoles=[],
             rootfs_uuid="deadbeef")
-        expected = (
-            "setenv bootcmd 'fatload mmc 0:1 0x80000000 uImage; "
-            "fatload mmc 0:1 0x81600000 uInitrd; bootm 0x80000000 "
-            "0x81600000'\nsetenv bootargs 'console=tty0 "
-            "console=ttyO2,115200n8  root=UUID=deadbeef rootwait ro "
-            "earlyprintk fixrtc nocompcache vram=12M "
-            "omapfb.mode=dvi:1280x720MR-16@60'\nboot")
-        self.assertEqual(expected, boot_cmd)
+        expected = {
+            'bootargs': 'console=tty0 console=ttyO2,115200n8  '
+                        'root=UUID=deadbeef rootwait ro earlyprintk fixrtc '
+                        'nocompcache vram=12M omapfb.mode=dvi:1280x720MR-16@60',
+            'bootcmd': 'fatload mmc 0:1 0x80000000 uImage; '
+                       'fatload mmc 0:1 0x81600000 uInitrd; '
+                       'bootm 0x80000000 0x81600000'}
+        self.assertEqual(expected, boot_commands)
 
     def test_overo(self):
         # XXX: To fix bug 697824 we have to change class attributes of our
@@ -453,17 +489,19 @@
         # don't interfere with us we'll reset that before doing anything.
         config = board_configs['overo']
         config.serial_tty = config._serial_tty
-        boot_cmd = config._get_boot_cmd(
+        boot_commands = config._get_boot_env(
             is_live=False, is_lowmem=False, consoles=[],
             rootfs_uuid="deadbeef")
-        expected = (
-            "setenv bootcmd 'fatload mmc 0:1 0x80000000 uImage; "
-            "fatload mmc 0:1 0x81600000 uInitrd; bootm 0x80000000 "
-            "0x81600000'\nsetenv bootargs 'console=tty0 "
-            "console=ttyO2,115200n8  root=UUID=deadbeef rootwait ro "
-            "earlyprintk mpurate=500 vram=12M "
-            "omapfb.mode=dvi:1024x768MR-16@60 omapdss.def_disp=dvi'\nboot")
-        self.assertEqual(expected, boot_cmd)
+        expected = {
+            'bootargs': 'console=tty0 console=ttyO2,115200n8  '
+                        'root=UUID=deadbeef rootwait ro earlyprintk '
+                        'mpurate=500 vram=12M '
+                        'omapfb.mode=dvi:1024x768MR-16@60 '
+                        'omapdss.def_disp=dvi',
+            'bootcmd': 'fatload mmc 0:1 0x80000000 uImage; '
+                       'fatload mmc 0:1 0x81600000 uInitrd; '
+                       'bootm 0x80000000 0x81600000'}
+        self.assertEqual(expected, boot_commands)
 
 
 class TestUnpackBinaryTarball(TestCaseWithFixtures):
@@ -586,14 +624,35 @@
             '-d', 'parts_dir/initrd.img-*-sub_arch', 'boot_disk/uInitrd']
         self.assertEqual([expected], fixture.mock.calls)
 
+    def test_make_flashable_env_too_small_env(self):
+        env = {'verylong': 'evenlonger'}
+        self.assertRaises(AssertionError, make_flashable_env, env, 8)
+
+    def test_make_flashable_env(self):
+        env_file = self.createTempFileAsFixture()
+        self.useFixture(MockSomethingFixture(
+            tempfile, "mkstemp", lambda: (None, env_file)))
+        env = {'a': 'b', 'x': 'y'}
+        make_flashable_env(env, 12)
+        with open(env_file, "r") as fd:
+            self.assertEqual("\x80\x29\x2E\x89a=b\x00x=y\x00", fd.read())
+
     def test_install_mx5_boot_loader(self):
         fixture = self._mock_Popen()
-        install_mx5_boot_loader("imx_file", "boot_device_or_file")
+        imx_file = self.createTempFileAsFixture()
+        install_mx5_boot_loader(imx_file, "boot_device_or_file")
         expected = [
-            'sudo', 'dd', 'if=imx_file', 'of=boot_device_or_file', 'bs=1024',
-            'seek=1', 'conv=notrunc']
+            'sudo', 'dd', 'if=%s' % imx_file, 'of=boot_device_or_file',
+            'bs=512', 'conv=notrunc', 'seek=2']
         self.assertEqual([expected], fixture.mock.calls)
 
+    def test_install_mx5_boot_loader_too_large(self):
+        self.useFixture(MockSomethingFixture(
+            os.path, "getsize",
+            lambda s: (LOADER_MIN_SIZE_S - 1) * SECTOR_SIZE + 1))
+        self.assertRaises(AssertionError,
+            install_mx5_boot_loader, "imx_file", "boot_device_or_file")
+
     def test_install_omap_boot_loader(self):
         fixture = self._mock_Popen()
         self.useFixture(MockSomethingFixture(
@@ -613,7 +672,8 @@
         fixture = self._mock_Popen()
         boot_script_path = os.path.join(tempdir, 'boot.scr')
         plain_boot_script_path = os.path.join(tempdir, 'boot.txt')
-        make_boot_script('boot script data', boot_script_path)
+        boot_env = {'bootargs': 'mybootargs', 'bootcmd': 'mybootcmd'}
+        make_boot_script(boot_env, boot_script_path)
         expected = [
             ['sudo', 'cp', '/tmp/random-abxzr', plain_boot_script_path],
             ['sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'script',
@@ -692,6 +752,25 @@
             [('1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-', 255, 63, '', self.media.path)],
             sfdisk_fixture.mock.calls)
 
+    def test_create_partitions_for_smdkv310(self):
+        # For this board we create a one cylinder partition at the beginning.
+        popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
+        sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
+
+        create_partitions(
+            board_configs['smdkv310'], self.media, 255, 63, '')
+
+        self.assertEqual(
+            [['sudo', 'parted', '-s', self.media.path, 'mklabel', 'msdos'],
+             ['sync']],
+            popen_fixture.mock.calls)
+        # Notice that we create all partitions in a single sfdisk run because
+        # every time we run sfdisk it actually repartitions the device,
+        # erasing any partitions created previously.
+        self.assertEqual(
+            [('1,221183,0xDA\n221184,106496,0x0C,*\n327680,,,-', 255, 63, '',
+              self.media.path)], sfdisk_fixture.mock.calls)
+
     def test_create_partitions_for_beagle(self):
         popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
         sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
@@ -711,9 +790,9 @@
         popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
         sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
 
-        tempfile = self.createTempFileAsFixture()
+        tmpfile = self.createTempFileAsFixture()
         create_partitions(
-            board_configs['beagle'], Media(tempfile), 255, 63, '')
+            board_configs['beagle'], Media(tmpfile), 255, 63, '')
 
         # Unlike the test for partitioning of a regular block device, in this
         # case parted was not called as there's no existing partition table
@@ -721,26 +800,26 @@
         self.assertEqual([['sync']], popen_fixture.mock.calls)
 
         self.assertEqual(
-            [('63,106432,0x0C,*\n106496,,,-', 255, 63, '', tempfile)],
+            [('63,106432,0x0C,*\n106496,,,-', 255, 63, '', tmpfile)],
             sfdisk_fixture.mock.calls)
 
     def test_run_sfdisk_commands(self):
-        tempfile = self.createTempFileAsFixture()
+        tmpfile = self.createTempFileAsFixture()
         proc = cmd_runner.run(
-            ['qemu-img', 'create', '-f', 'raw', tempfile, '10M'],
+            ['qemu-img', 'create', '-f', 'raw', tmpfile, '10M'],
             stdout=subprocess.PIPE)
         proc.communicate()
         stdout, stderr = run_sfdisk_commands(
-            '2,16063,0xDA', 255, 63, '', tempfile, as_root=False,
+            '2,16063,0xDA', 255, 63, '', tmpfile, as_root=False,
             stderr=subprocess.PIPE)
         self.assertIn('Successfully wrote the new partition table', stdout)
 
     def test_run_sfdisk_commands_raises_on_non_zero_returncode(self):
-        tempfile = self.createTempFileAsFixture()
+        tmpfile = self.createTempFileAsFixture()
         self.assertRaises(
             cmd_runner.SubcommandNonZeroReturnValue,
             run_sfdisk_commands,
-            ',1,0xDA', 255, 63, '', tempfile, as_root=False,
+            ',1,0xDA', 255, 63, '', tmpfile, as_root=False,
             stderr=subprocess.PIPE)
 
 
@@ -756,7 +835,7 @@
         super(TestPartitionSetup, self).tearDown()
         time.sleep = self.orig_sleep
 
-    def _create_tempfile(self):
+    def _create_tmpfile(self):
         # boot part at +8 MiB, root part at +16 MiB
         return self._create_qemu_img_with_partitions(
             '16384,15746,0x0C,*\n32768,,,-')
@@ -771,19 +850,19 @@
         self.assertEqual(12 * 1024**3, convert_size_to_bytes('12G'))
 
     def test_calculate_partition_size_and_offset(self):
-        tempfile = self._create_tempfile()
+        tmpfile = self._create_tmpfile()
         vfat_size, vfat_offset, linux_size, linux_offset = (
-            calculate_partition_size_and_offset(tempfile))
+            calculate_partition_size_and_offset(tmpfile))
         self.assertEqual(
             [8061952L, 8388608L, 14680064L, 16777216L],
             [vfat_size, vfat_offset, linux_size, linux_offset])
 
     def test_partition_numbering(self):
         # another Linux partition at +24 MiB after the boot/root parts
-        tempfile = self._create_qemu_img_with_partitions(
+        tmpfile = self._create_qemu_img_with_partitions(
             '16384,15746,0x0C,*\n32768,15427,,-\n49152,,,-')
         vfat_size, vfat_offset, linux_size, linux_offset = (
-            calculate_partition_size_and_offset(tempfile))
+            calculate_partition_size_and_offset(tmpfile))
         # check that the linux partition offset starts at +16 MiB so that it's
         # the partition immediately following the vfat one
         self.assertEqual(linux_offset, 32768 * 512)
@@ -791,39 +870,39 @@
     def test_get_boot_and_root_partitions_for_media_beagle(self):
         self.useFixture(MockSomethingFixture(
             partitions, '_get_device_file_for_partition_number',
-            lambda dev, partition: '%s%d' % (tempfile, partition)))
-        tempfile = self.createTempFileAsFixture()
-        media = Media(tempfile)
+            lambda dev, partition: '%s%d' % (tmpfile, partition)))
+        tmpfile = self.createTempFileAsFixture()
+        media = Media(tmpfile)
         media.is_block_device = True
         self.assertEqual(
-            ("%s%d" % (tempfile, 1), "%s%d" % (tempfile, 2)),
+            ("%s%d" % (tmpfile, 1), "%s%d" % (tmpfile, 2)),
             get_boot_and_root_partitions_for_media(
                 media, board_configs['beagle']))
 
     def test_get_boot_and_root_partitions_for_media_mx5(self):
         self.useFixture(MockSomethingFixture(
             partitions, '_get_device_file_for_partition_number',
-            lambda dev, partition: '%s%d' % (tempfile, partition)))
-        tempfile = self.createTempFileAsFixture()
-        media = Media(tempfile)
+            lambda dev, partition: '%s%d' % (tmpfile, partition)))
+        tmpfile = self.createTempFileAsFixture()
+        media = Media(tmpfile)
         media.is_block_device = True
         self.assertEqual(
-            ("%s%d" % (tempfile, 2), "%s%d" % (tempfile, 3)),
+            ("%s%d" % (tmpfile, 2), "%s%d" % (tmpfile, 3)),
             get_boot_and_root_partitions_for_media(media, boards.Mx5Config))
 
     def _create_qemu_img_with_partitions(self, sfdisk_commands):
-        tempfile = self.createTempFileAsFixture()
+        tmpfile = self.createTempFileAsFixture()
         proc = cmd_runner.run(
-            ['qemu-img', 'create', '-f', 'raw', tempfile, '30M'],
+            ['qemu-img', 'create', '-f', 'raw', tmpfile, '30M'],
             stdout=subprocess.PIPE)
         proc.communicate()
         stdout, stderr = run_sfdisk_commands(
-            sfdisk_commands, 255, 63, '', tempfile, as_root=False,
+            sfdisk_commands, 255, 63, '', tmpfile, as_root=False,
             # Throw away stderr as sfdisk complains a lot when operating on a
             # qemu image.
             stderr=subprocess.PIPE)
         self.assertIn('Successfully wrote the new partition table', stdout)
-        return tempfile
+        return tmpfile
 
     def test_ensure_partition_is_not_mounted_for_mounted_partition(self):
         self.useFixture(MockSomethingFixture(
@@ -841,18 +920,18 @@
         self.assertEqual(None, popen_fixture.mock.calls)
 
     def test_get_boot_and_root_loopback_devices(self):
-        tempfile = self._create_tempfile()
+        tmpfile = self._create_tmpfile()
         atexit_fixture = self.useFixture(MockSomethingFixture(
             atexit, 'register', AtExitRegister()))
         popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
         # We can't test the return value of get_boot_and_root_loopback_devices
         # because it'd require running losetup as root, so we just make sure
         # it calls losetup correctly.
-        get_boot_and_root_loopback_devices(tempfile)
+        get_boot_and_root_loopback_devices(tmpfile)
         self.assertEqual(
-            [['sudo', 'losetup', '-f', '--show', tempfile, '--offset',
+            [['sudo', 'losetup', '-f', '--show', tmpfile, '--offset',
               '8388608', '--sizelimit', '8061952'],
-             ['sudo', 'losetup', '-f', '--show', tempfile, '--offset',
+             ['sudo', 'losetup', '-f', '--show', tmpfile, '--offset',
               '16777216', '--sizelimit', '14680064']],
             popen_fixture.mock.calls)
 
@@ -873,7 +952,7 @@
         # but here we mock Popen() and thanks to that the image is not setup
         # (via qemu-img) inside setup_partitions.  That's why we pass an
         # already setup image file.
-        tempfile = self._create_tempfile()
+        tmpfile = self._create_tmpfile()
         popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
         self.useFixture(MockSomethingFixture(
             sys, 'stdout', open('/dev/null', 'w')))
@@ -890,14 +969,14 @@
             partitions, 'get_boot_and_root_loopback_devices',
             lambda image: ('/dev/loop99', '/dev/loop98')))
         bootfs_dev, rootfs_dev = setup_partitions(
-            board_configs['beagle'], Media(tempfile), '2G', 'boot',
+            board_configs['beagle'], Media(tmpfile), '2G', 'boot',
             'root', 'ext3', True, True, True)
         self.assertEqual(
              # This is the call that would create a 2 GiB image file.
-            [['qemu-img', 'create', '-f', 'raw', tempfile, '2147483648'],
+            [['qemu-img', 'create', '-f', 'raw', tmpfile, '2147483648'],
              # This call would partition the image file.
              ['sudo', 'sfdisk', '--force', '-D', '-uS', '-H', '255', '-S',
-              '63', '-C', '261', tempfile],
+              '63', '-C', '261', tmpfile],
              # Make sure changes are written to disk.
              ['sync'],
              ['sudo', 'mkfs.vfat', '-F', '32', bootfs_dev, '-n', 'boot'],
@@ -910,21 +989,21 @@
         # Pretend the partitions are mounted.
         self.useFixture(MockSomethingFixture(
             partitions, 'is_partition_mounted', lambda part: True))
-        tempfile = self._create_tempfile()
+        tmpfile = self._create_tmpfile()
         self.useFixture(MockSomethingFixture(
             partitions, '_get_device_file_for_partition_number',
-            lambda dev, partition: '%s%d' % (tempfile, partition)))
-        media = Media(tempfile)
-        # Pretend our tempfile is a block device.
+            lambda dev, partition: '%s%d' % (tmpfile, partition)))
+        media = Media(tmpfile)
+        # Pretend our tmpfile is a block device.
         media.is_block_device = True
         popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
         bootfs_dev, rootfs_dev = setup_partitions(
             board_configs['beagle'], media, '2G', 'boot', 'root', 'ext3',
             True, True, True)
         self.assertEqual(
-            [['sudo', 'parted', '-s', tempfile, 'mklabel', 'msdos'],
+            [['sudo', 'parted', '-s', tmpfile, 'mklabel', 'msdos'],
              ['sudo', 'sfdisk', '--force', '-D', '-uS', '-H', '255', '-S',
-              '63', tempfile],
+              '63', tmpfile],
              ['sync'],
              # Since the partitions are mounted, setup_partitions will umount
              # them before running mkfs.

