=== modified file 'linaro_image_tools/hwpack/config.py'
--- linaro_image_tools/hwpack/config.py	2011-08-18 15:46:52 +0000
+++ linaro_image_tools/hwpack/config.py	2011-08-25 13:42:55 +0000
@@ -64,6 +64,7 @@
     BOOT_MIN_SIZE_KEY = "boot_min_size"
     ROOT_MIN_SIZE_KEY = "root_min_size"
     LOADER_MIN_SIZE_KEY = "loader_min_size"
+    LOADER_START_KEY = "loader_start"
     X_LOADER_PACKAGE_KEY = "x_loader_package"
     X_LOADER_FILE_KEY = "x_loader_file"
     VMLINUZ_KEY = "kernel_file"
@@ -73,11 +74,12 @@
     BOOT_SCRIPT_KEY = 'boot_script'
     UBOOT_IN_BOOT_PART_KEY = 'u_boot_in_boot_part'
     EXTRA_SERIAL_OPTS_KEY = 'extra_serial_options'
+    SNOWBALL_STARTUP_FILES_CONFIG_KEY = 'snowball_startup_files_config'
 
     DEFINED_PARTITION_LAYOUTS = [
         'bootfs16_rootfs',
         'bootfs_rootfs',
-        #'reserved_bootfs_rootfs',
+        'reserved_bootfs_rootfs',
         ]
 
 
@@ -119,6 +121,7 @@
             self._validate_boot_min_size()
             self._validate_root_min_size()
             self._validate_loader_min_size()
+            self._validate_loader_start()
             self._validate_x_loader_package()
             self._validate_x_loader_file()
             self._validate_vmlinuz()
@@ -128,6 +131,7 @@
             self._validate_boot_script()
             self._validate_uboot_in_boot_part()
             self._validate_extra_serial_opts()
+            self._validate_snowball_startup_files_config()
 
         self._validate_sections()
 
@@ -223,6 +227,15 @@
         return self._get_option_from_main_section(self.BOOT_SCRIPT_KEY)
 
     @property
+    def snowball_startup_files_config(self):
+        """File name of the snowball startfiles config file.
+
+        A str.
+        """
+        return self._get_option_from_main_section(
+            self.SNOWBALL_STARTUP_FILES_CONFIG_KEY)
+
+    @property
     def kernel_addr(self):
         """address where u-boot should load the kernel 
 
@@ -313,6 +326,14 @@
         return self._get_option_from_main_section(self.LOADER_MIN_SIZE_KEY)
 
     @property
+    def loader_start(self):
+        """Start of loader partition. If left out, defaults to 1.
+
+        An int.
+        """
+        return self._get_option_from_main_section(self.LOADER_START_KEY)
+
+    @property
     def origin(self):
         """The origin that should be recorded in the hwpack.
 
@@ -518,6 +539,14 @@
             self._assert_matches_pattern(
                 self.PATH_REGEX, boot_script, "Invalid path: %s" % boot_script)
 
+
+    def _validate_snowball_startup_files_config(self):
+        snowball_startup_files_config = self.snowball_startup_files_config
+        if snowball_startup_files_config is not None:
+            self._assert_matches_pattern(
+                self.PATH_REGEX, snowball_startup_files_config,
+                "Invalid path: %s" % snowball_startup_files_config)
+
     def _validate_serial_tty(self):
         serial_tty = self.serial_tty
         if serial_tty is None:
@@ -609,6 +638,16 @@
             raise HwpackConfigError(
                 "Invalid loader min size %s" % (loader_min_size))
 
+    def _validate_loader_start(self):
+        loader_start = self.loader_start
+        if loader_start is None:
+            return
+        try:
+            assert int(loader_start) > 0
+        except:
+            raise HwpackConfigError(
+                "Invalid loader start %s" % (loader_start))
+
     def _validate_include_debs(self):
         try:
             self.include_debs

=== modified file 'linaro_image_tools/hwpack/hardwarepack.py'
--- linaro_image_tools/hwpack/hardwarepack.py	2011-08-18 13:46:36 +0000
+++ linaro_image_tools/hwpack/hardwarepack.py	2011-08-25 13:42:55 +0000
@@ -84,7 +84,8 @@
                       loader_min_size=None, vmlinuz=None, initrd=None,
                       dtb_addr=None, extra_boot_options=None,
                       boot_script=None, uboot_in_boot_part=None,
-                      extra_serial_opts=None):
+                      extra_serial_opts=None, loader_start=None,
+                      snowball_startup_files_config=None):
         """Add fields that are specific to the new format.
 
         These fields are not present in earlier config files.
@@ -101,6 +102,7 @@
         self.boot_min_size = boot_min_size
         self.root_min_size = root_min_size
         self.loader_min_size = loader_min_size
+        self.loader_start = loader_start
         self.x_loader = None
         self.vmlinuz = vmlinuz
         self.initrd = initrd
@@ -110,6 +112,7 @@
         self.boot_script = boot_script
         self.uboot_in_boot_part = uboot_in_boot_part
         self.extra_serial_opts = extra_serial_opts
+        self.snowball_startup_files_config = snowball_startup_files_config
 
     @classmethod
     def from_config(cls, config, version, architecture):
@@ -146,6 +149,7 @@
                                    boot_min_size=config.boot_min_size,
                                    root_min_size=config.root_min_size,
                                    loader_min_size=config.loader_min_size,
+                                   loader_start=config.loader_start,
                                    vmlinuz=config.vmlinuz,
                                    initrd=config.initrd,
                                    dtb_file=config.dtb_file,
@@ -153,7 +157,8 @@
                                    extra_boot_options=config.extra_boot_options,
                                    boot_script=config.boot_script,
                                    uboot_in_boot_part=config.uboot_in_boot_part,
-                                   extra_serial_opts=config.extra_serial_opts)
+                                   extra_serial_opts=config.extra_serial_opts,
+                                   snowball_startup_files_config=config.snowball_startup_files_config)
         return metadata
 
     def __str__(self):
@@ -198,6 +203,8 @@
             metadata += "ROOT_MIN_SIZE=%s\n" % self.root_min_size
         if self.loader_min_size is not None:
             metadata += "LOADER_MIN_SIZE=%s\n" % self.loader_min_size
+        if self.loader_start is not None:
+            metadata += "LOADER_START=%s\n" % self.loader_start
         if self.x_loader is not None:
             metadata += "X_LOADER=%s\n" % self.x_loader
         if self.vmlinuz is not None:
@@ -214,6 +221,8 @@
             metadata += "U_BOOT_IN_BOOT_PART=%s\n" % self.uboot_in_boot_part
         if self.extra_serial_opts is not None:
             metadata += "EXTRA_SERIAL_OPTIONS=%s\n" % self.extra_serial_opts
+        if self.snowball_startup_files_config is not None:
+            metadata += "SNOWBALL_STARTUP_FILES_CONFIG=%s\n" % self.snowball_startup_files_config
 
         return metadata
 

=== modified file 'linaro_image_tools/media_create/boards.py'
--- linaro_image_tools/media_create/boards.py	2011-08-25 09:57:46 +0000
+++ linaro_image_tools/media_create/boards.py	2011-08-30 08:40:19 +0000
@@ -253,6 +253,8 @@
     mmc_id = None
     vmlinuz = None
     initrd = None
+    partition_layout = None
+    LOADER_START_S = 1
 
     hardwarepack_handler = None
 
@@ -293,7 +295,8 @@
             cls.dtb_addr = cls.get_metadata_field('dtb_addr')
             cls.serial_tty = cls.get_metadata_field('serial_tty')
             cls.wired_interfaces = cls.get_metadata_field('wired_interfaces')
-            cls.wireless_interfaces = cls.get_metadata_field('wireless_interfaces')
+            cls.wireless_interfaces = cls.get_metadata_field(
+                'wireless_interfaces')
             cls.mmc_id = cls.get_metadata_field('mmc_id')
             cls.vmlinuz = cls.get_metadata_field('kernel_file')
             cls.initrd = cls.get_metadata_field('initrd_file')
@@ -302,14 +305,18 @@
                 'extra_boot_options')
             cls.boot_script = cls.get_metadata_field('boot_script')
             cls.extra_serial_opts = cls.get_metadata_field('extra_serial_options')
+            cls.snowball_startup_files_config = cls.get_metadata_field(
+                'snowball_startup_files_config')
 
-            partition_layout = cls.get_metadata_field('partition_layout')
-            if partition_layout == 'bootfs_rootfs' or partition_layout is None:
+            cls.partition_layout = cls.get_metadata_field('partition_layout')
+            if cls.partition_layout in ['bootfs_rootfs', 'reserved_bootfs_rootfs',
+                                    None]:
                 cls.fat_size = 32
-            elif partition_layout == 'bootfs16_rootfs':
+            elif cls.partition_layout == 'bootfs16_rootfs':
                 cls.fat_size = 16
             else:
-                raise AssertionError("Unknown partition layout '%s'." % partition_layout)
+                raise AssertionError("Unknown partition layout '%s'." % \
+                                         cls.partition_layout)
 
             boot_min_size = cls.get_metadata_field('boot_min_size')
             if boot_min_size is not None:
@@ -332,6 +339,10 @@
             elif string.lower(uboot_in_boot_part) == 'no':
                 cls.uboot_in_boot_part = False
 
+            loader_start = cls.get_metadata_field('loader_start')
+            if loader_start is not None:
+                cls.LOADER_START_S = int(loader_start)
+
     @classmethod
     def get_file(cls, file_alias, default=None):
         file_in_hwpack = cls.hardwarepack_handler.get_file(file_alias)
@@ -341,13 +352,17 @@
             return default
 
     @classmethod
-    def get_sfdisk_cmd(cls, should_align_boot_part=False):
+    def get_v1_sfdisk_cmd(cls, should_align_boot_part=False):
         """Return the sfdisk command to partition the media.
 
         :param should_align_boot_part: Whether to align the boot partition too.
 
         This default implementation returns a boot vfat partition of type FAT16
         or FAT32, followed by a root partition.
+
+        XXX: This default implementation and all overrides are left for V1
+        compatibility only. They should be removed as part of the work to
+        kill off hwpacks V1.
         """
         if cls.fat_size == 32:
             partition_type = '0x0C'
@@ -379,6 +394,76 @@
             boot_start, boot_len, partition_type, root_start)
 
     @classmethod
+    def get_normal_sfdisk_cmd(cls, should_align_boot_part=False):
+        """Return the sfdisk command to partition the media.
+
+        :param should_align_boot_part: Whether to align the boot partition too.
+
+        This returns a boot vfat partition of type FAT16
+        or FAT32, followed by a root partition.
+        """
+        if cls.fat_size == 32:
+            partition_type = '0x0C'
+        else:
+            partition_type = '0x0E'
+
+        # align on sector 63 for compatibility with broken versions of x-loader
+        # unless align_boot_part is set
+        # XXX OMAP specific, might break other boards?
+        boot_align = 63
+        if should_align_boot_part:
+            boot_align = PART_ALIGN_S
+
+        # can only start on sector 1 (sector 0 is MBR / partition table)
+        boot_start, boot_end, boot_len = align_partition(
+            1, cls.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
+        # XXX OMAP specific, might break other boards?
+        boot_len = boot_len - boot_len % 2
+        boot_end = boot_start + boot_len - 1
+
+        # we ignore _root_end / _root_len and return a sfdisk command to
+        # instruct the use of all remaining space; XXX we now have root size
+        # config, so we can do something more sensible
+        root_start, _root_end, _root_len = align_partition(
+            boot_end + 1, cls.ROOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S)
+
+        return '%s,%s,%s,*\n%s,,,-' % (
+            boot_start, boot_len, partition_type, root_start)
+
+    @classmethod
+    def get_reserved_sfdisk_cmd(cls, should_align_boot_part=None):
+        """Return the sfdisk command to partition the media.
+
+        :param should_align_boot_part: Ignored.
+
+        This returns a loader partition, then a boot vfat partition of type
+        FAT16 or FAT32, followed by a root partition.
+        """
+        loader_start, loader_end, loader_len = align_partition(
+            cls.LOADER_START_S, cls.LOADER_MIN_SIZE_S, 1, PART_ALIGN_S)
+
+        boot_start, boot_end, boot_len = align_partition(
+            loader_end + 1, cls.BOOT_MIN_SIZE_S, PART_ALIGN_S, PART_ALIGN_S)
+
+        root_start, _root_end, _root_len = align_partition(
+            boot_end + 1, cls.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_sfdisk_cmd(cls, should_align_boot_part=False):
+        if cls.partition_layout in ['bootfs_rootfs', 'bootfs16_rootfs']:
+            return cls.get_normal_sfdisk_cmd(should_align_boot_part)
+        elif cls.partition_layout in ['reserved_bootfs_rootfs']:
+            return cls.get_reserved_sfdisk_cmd(should_align_boot_part)
+        else:
+            return cls.get_v1_sfdisk_cmd(should_align_boot_part)
+
+    @classmethod
     def _get_bootcmd(cls, d_img_data):
         """Get the bootcmd for this board.
 
@@ -743,11 +828,11 @@
     # 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'
+    snowball_startup_files_config = 'startfiles.cfg'
     TOC_SIZE = 512
 
     @classmethod
-    def get_sfdisk_cmd(cls, should_align_boot_part=None):
+    def get_v1_sfdisk_cmd(cls, should_align_boot_part=None):
         """Return the sfdisk command to partition the media.
 
         :param should_align_boot_part: Ignored.
@@ -800,7 +885,7 @@
                                      cls.SNOWBALL_LOADER_START_S)
         cls.delete_file(toc_filename)
         cls.delete_file(os.path.join(config_files_path,
-                                     cls.SNOWBALL_STARTUP_FILES_CONFIG))
+                                     cls.snowball_startup_files_config))
 
     @classmethod
     def install_snowball_boot_loader(cls, toc_file_name, files,
@@ -860,7 +945,7 @@
         ofs = cls.TOC_SIZE
         files = []
         bin_dir = os.path.join(chroot_dir, 'boot')
-        with open(os.path.join(bin_dir, cls.SNOWBALL_STARTUP_FILES_CONFIG),
+        with open(os.path.join(bin_dir, cls.snowball_startup_files_config),
                   'r') as info_file:
             for line in info_file:
                 file_data = line.split()
@@ -904,7 +989,7 @@
         return cls._extra_serial_opts % cls.serial_tty
 
     @classmethod
-    def get_sfdisk_cmd(cls, should_align_boot_part=None):
+    def get_v1_sfdisk_cmd(cls, should_align_boot_part=None):
         """Return the sfdisk command to partition the media.
 
         :param should_align_boot_part: Ignored.
@@ -1020,7 +1105,7 @@
         return cls._extra_serial_opts % cls.serial_tty
 
     @classmethod
-    def get_sfdisk_cmd(cls, should_align_boot_part=False):
+    def get_v1_sfdisk_cmd(cls, should_align_boot_part=False):
         # bootloaders partition needs to hold BL1, U-Boot environment, and BL2
         loaders_min_len = (
             SAMSUNG_V310_BL2_START + SAMSUNG_V310_BL2_LEN -

=== modified file 'linaro_image_tools/media_create/tests/test_media_create.py'
--- linaro_image_tools/media_create/tests/test_media_create.py	2011-08-25 09:57:46 +0000
+++ linaro_image_tools/media_create/tests/test_media_create.py	2011-08-30 08:40:19 +0000
@@ -46,6 +46,7 @@
 from linaro_image_tools.media_create.boards import (
     SAMSUNG_V310_BL1_START,
     SAMSUNG_V310_BL2_START,
+    SAMSUNG_V310_BL2_LEN,
     SECTOR_SIZE,
     align_up,
     align_partition,
@@ -685,7 +686,7 @@
                     ('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)
+        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
@@ -719,7 +720,7 @@
     def test_get_file_info_relative_path(self):
         # Create a config file
         cfg_file = os.path.join(self.temp_bootdir_path,
-                      boards.SnowballEmmcConfig.SNOWBALL_STARTUP_FILES_CONFIG)
+                      boards.SnowballEmmcConfig.snowball_startup_files_config)
         uboot_file = 'u-boot.bin'
         with open(cfg_file, 'w') as f:
                 f.write('%s %s %i %#x %s\n' % ('NORMAL', uboot_file, 0,
@@ -733,7 +734,7 @@
     def test_get_file_info_abs_path(self):
         # Create a config file
         cfg_file = os.path.join(self.temp_bootdir_path,
-                      boards.SnowballEmmcConfig.SNOWBALL_STARTUP_FILES_CONFIG)
+                      boards.SnowballEmmcConfig.snowball_startup_files_config)
         uboot_dir = tempfile.mkdtemp(dir=self.tempdir)
         uboot_file = os.path.join(uboot_dir, 'u-boot.bin')
         uboot_relative_file = uboot_file.replace(self.tempdir, '')
@@ -748,7 +749,7 @@
     def test_get_file_info_raises(self):
         # Create a config file
         cfg_file = os.path.join(self.temp_bootdir_path,
-                      boards.SnowballEmmcConfig.SNOWBALL_STARTUP_FILES_CONFIG)
+                      boards.SnowballEmmcConfig.snowball_startup_files_config)
         with open(cfg_file, 'w') as f:
                 f.write('%s %s %i %#x %s\n' % ('NORMAL', 'u-boot.bin', 0,
                                                0xBA0000, '9'))
@@ -1142,6 +1143,50 @@
                 '794624,-,E\n794624,524288,L\n1318912,1048576,L\n2367488,,,-', 
                 android_boards.AndroidSnowballEmmcConfig.get_sfdisk_cmd())
 
+class TestGetSfdiskCmdV2(TestCase):
+
+    def test_mx5(self):
+        class config(boards.Mx5Config):
+            partition_layout = 'reserved_bootfs_rootfs'
+        self.assertEqual(
+            '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-',
+            config.get_sfdisk_cmd())
+
+    def test_snowball_sd(self):
+        class config(boards.SnowballSdConfig):
+            partition_layout = 'bootfs_rootfs'
+        self.assertEqual(
+            '63,106432,0x0C,*\n106496,,,-',
+            config.get_sfdisk_cmd())
+
+    def test_snowball_emmc(self):
+        class config(boards.SnowballEmmcConfig):
+            partition_layout = 'reserved_bootfs_rootfs'
+            LOADER_START_S = (128 * 1024) / SECTOR_SIZE
+        self.assertEqual(
+            '256,7936,0xDA\n8192,106496,0x0C,*\n114688,,,-',
+            config.get_sfdisk_cmd())
+
+    def test_smdkv310(self):
+        class config(board_configs['smdkv310']):
+            partition_layout = 'reserved_bootfs_rootfs'
+            LOADER_MIN_SIZE_S = (SAMSUNG_V310_BL2_START +
+                                 SAMSUNG_V310_BL2_LEN -
+                                 SAMSUNG_V310_BL1_START)
+        self.assertEquals(
+            '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-',
+            config.get_sfdisk_cmd())
+
+    def test_origen(self):
+        class config(board_configs['origen']):
+            partition_layout = 'reserved_bootfs_rootfs'
+            LOADER_MIN_SIZE_S = (SAMSUNG_V310_BL2_START +
+                                 SAMSUNG_V310_BL2_LEN -
+                                 SAMSUNG_V310_BL1_START)
+        self.assertEquals(
+            '1,8191,0xDA\n8192,106496,0x0C,*\n114688,,,-',
+            config.get_sfdisk_cmd())
+
 
 class TestGetBootCmd(TestCase):
 

