From patchwork Fri Jul 1 14:58:20 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mattias Backman X-Patchwork-Id: 2403 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id B581E23F4D for ; Fri, 1 Jul 2011 14:58:23 +0000 (UTC) Received: from mail-qy0-f180.google.com (mail-qy0-f180.google.com [209.85.216.180]) by fiordland.canonical.com (Postfix) with ESMTP id 3C172A184C1 for ; Fri, 1 Jul 2011 14:58:23 +0000 (UTC) Received: by qyk30 with SMTP id 30so2316861qyk.11 for ; Fri, 01 Jul 2011 07:58:22 -0700 (PDT) Received: by 10.224.217.7 with SMTP id hk7mr2612295qab.59.1309532302675; Fri, 01 Jul 2011 07:58:22 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.229.48.135 with SMTP id r7cs106665qcf; Fri, 1 Jul 2011 07:58:22 -0700 (PDT) Received: by 10.227.62.207 with SMTP id y15mr2981084wbh.86.1309532301634; Fri, 01 Jul 2011 07:58:21 -0700 (PDT) Received: from adelie.canonical.com (adelie.canonical.com [91.189.90.139]) by mx.google.com with ESMTP id gb12si2663227wbb.102.2011.07.01.07.58.21; Fri, 01 Jul 2011 07:58:21 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.139 as permitted sender) client-ip=91.189.90.139; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.139 as permitted sender) smtp.mail=bounces@canonical.com Received: from loganberry.canonical.com ([91.189.90.37]) by adelie.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1QcfAi-0001m3-SR for ; Fri, 01 Jul 2011 14:58:20 +0000 Received: from loganberry.canonical.com (localhost [127.0.0.1]) by loganberry.canonical.com (Postfix) with ESMTP id D21F62E889C for ; Fri, 1 Jul 2011 14:58:20 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: linaro-image-tools X-Launchpad-Branch: ~linaro-image-tools/linaro-image-tools/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 368 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [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> Date: Fri, 01 Jul 2011 14:58:20 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="13333"; Instance="initZopeless config overlay" X-Launchpad-Hash: cf0d0ea02cc485f7f44d3c445c511e57c8b421c4 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 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 === 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(' # # 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)