| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """This module supports creating Exynos bootprom images.""" |
| |
| import hashlib |
| import os |
| import struct |
| |
| from tools import CmdError |
| |
| HASH_ALGO_LEN = 32 |
| HASH_LEN = 32 |
| HASH_SIGNATURE = 0xdead4eef |
| HASH_VERSION = 1 |
| HASH_FLAGS = 0 |
| HASH_HEADER_LEN = 16 |
| |
| |
| class ExynosBl2(object): |
| """Class for processing Exynos SPL blob. |
| |
| Second phase loader (SPL) is also called boot loader 2 (BL2), these terms |
| mean the same and are used in this class interchangeably. |
| |
| SPL is a binary blob which is in fact a short program running from internal |
| SRAM. It initializes main DRAM and loads the actual boot loader after that. |
| The program is encapsulated using one of two methods - fixed or variable |
| size. Both methods provide rudimentary checksum protection. |
| |
| SPL is supposed to know some details about the hardware it runs on. This |
| information is stored in the so called machine parameters structure in the |
| blob. Some of it is available at compile time, but most of it comes form the |
| platform specific flat device tree. SPL generated by u-boot make file |
| includes machine parameter structure with default configuration values, not |
| suitable to run on actual hardware. |
| |
| This class provides the following services: |
| |
| - check integrity of the passed in SPL blob, and determining its |
| the encapsulation method along the way. |
| |
| - parse the passed in device tree and pack the retrieved information into |
| the machine parameters structure. The structure location in the blob is |
| identified by a 4 byte structure header signature. |
| |
| Note that this method of finding the structure in the blob is quite |
| brittle: it would silently produce catastrophically wrong result if for |
| some reason, this same pattern is present anywhere in the blob above the |
| structure. |
| |
| - update the checksum as appropriate for the detected format, and save the |
| modified SPL in a file. |
| |
| Attributes: |
| _tools: A tools.Tools object to use for external tools, provided by the |
| caller |
| _out: A cros_output.Output object to use for console output, provided by |
| the caller |
| _spl_type: an enum defined below, describing type (fixed of variable size) |
| of the SPL being handled |
| _spl_data: a binary blob representing the SPL data being handled. It comes |
| as the value read from the u-boot makefile generated image and |
| goes as an enhanced image including the updated machine parameters |
| structure and possibly concatenated with the hash and revision |
| table. |
| """ |
| |
| VAR_SPL = 1 |
| FIXED_SPL = 2 |
| |
| def __init__(self, tools, output): |
| """Set up a new object.""" |
| self._tools = tools |
| self._out = output |
| self._spl_type = None |
| self.spl_source = 'straps' # SPL boot according to board settings |
| self._spl_data = None # SPL blob to configure |
| |
| def _BootingUsingEFS(self, fdt, use_efs_memory): |
| """Check if we are booting using early-firmware-selection. |
| |
| This is just a helper function to avoid using the same logic in many |
| places. |
| |
| Args: |
| fdt: Device tree file to use. |
| use_efs_memory: True to use early-firmware-selection memory (i.e. IRAM), |
| False, to ignore it. |
| |
| Returns: |
| True if EFS is enabled and we are configured to use EFS memory, else |
| False. |
| """ |
| return (use_efs_memory and |
| fdt.GetInt('/chromeos-config', 'early-firmware-selection', 0)) |
| |
| def _GetAddress(self, fdt, use_efs_memory, name, config_node='/config', |
| allow_none=False): |
| """Work out the correct address for a region of memory. |
| |
| This deals with EFS and the memory map automatically. |
| |
| Args: |
| fdt: Device tree file containing memory map. |
| use_efs_memory: True to return the address in EFS memory (i.e. SRAM), |
| False to use SDRAM |
| name: Name of the region to look up, e.g. 'u-boot' |
| config_node: Node containing configuration information |
| allow_none: True if it is OK to find nothing. |
| |
| Returns: |
| Address to load that region, or None if none. |
| """ |
| efs_suffix = '' |
| if self._BootingUsingEFS(fdt, use_efs_memory): |
| efs_suffix = ',efs' |
| |
| # Use the correct memory section, and then find the offset in that. |
| default = 'none' if allow_none else None |
| memory = fdt.GetString(config_node, '%s-memory%s' % (name, efs_suffix), |
| default) |
| if memory == 'none': |
| return None |
| base = fdt.GetIntList(memory, 'reg')[0] |
| offset = fdt.GetIntList(config_node, '%s-offset%s' % (name, efs_suffix))[0] |
| addr = base + offset |
| return addr |
| |
| def GetUBootAddress(self, fdt, use_efs_memory): |
| """Work out the correct address for loading U-Boot. |
| |
| This deals with EFS and the memory map automatically. |
| |
| Args: |
| fdt: Device tree file containing memory map. |
| use_efs_memory: True to return the address in EFS memory (i.e. SRAM), |
| False to use SDRAM |
| |
| Returns: |
| Address to load U-Boot |
| """ |
| addr = self._GetAddress(fdt, use_efs_memory, 'u-boot') |
| self._out.Notice('EFS: Loading U-Boot to %x' % addr) |
| return addr |
| |
| def _GetRWSPLDetails(self, fdt, use_efs_memory): |
| if not self._BootingUsingEFS(fdt, use_efs_memory): |
| return 0, 0, 0 |
| |
| memory = fdt.GetString('/chromeos-config', 'rw-spl-memory,efs') |
| base = fdt.GetIntList(memory, 'reg')[0] |
| offset, size = fdt.GetIntList('/chromeos-config', 'rw-spl-offset,efs') |
| addr = base + offset |
| return 1, addr, size |
| |
| def _MpRevMap(self, _unused1, offset, fdt, pos): |
| """Add the revision map to the SPL blob. |
| |
| Read the revison map table from the device tree, and place it in the SPL |
| blob. If we detect that there wasn't already space allocated for the |
| revision map we'll append it to the end of the SPL blob. If there was |
| already space for the revision map we'll overwrite the existing one. |
| |
| The revision map could be anywhere in the SPL. We store an offset from the |
| beginning of the machine params structure as the value in machine params |
| to allow us to find the map. If the offset is 0 it means that there is no |
| revision map space allocated. |
| |
| Args: |
| _unused1 - a single character string, machine parameter name |
| offset - If there's alreasy space for the revision map, this will be non- |
| zero and we can find it in the SPL data at "pos + offset". |
| fdt - the Fdt object representing the target device tree |
| pos - an int, offset of the machine parameter structure into data |
| |
| Returns: |
| offset - The new location of the revision map. |
| """ |
| |
| rev_map = 'google,board-rev-map' |
| try: |
| rev_table = fdt.GetIntList('/board-rev', rev_map) |
| except CmdError: |
| self._out.Info('No value for %s' % rev_map) |
| return 0 |
| |
| extra = struct.pack('%dB' % len(rev_table), *rev_table) |
| |
| if offset: |
| self._spl_data = (self._spl_data[:pos + offset] + |
| extra + |
| self._spl_data[pos + offset + len(extra):]) |
| else: |
| # offset of the revision table from machine param table |
| offset = len(self._spl_data) - pos |
| self._spl_data += extra |
| return offset |
| |
| def _UpdateParameters(self, fdt, spl_load_offset, spl_load_size, pos, |
| use_efs_memory, skip_sdram_init): |
| """Update the parameters in a BL2 blob. |
| |
| We look at the list in the parameter block, extract the value of each |
| from the device tree, and write that value to the parameter block. |
| |
| Args: |
| fdt: Device tree containing the parameter values. |
| spl_load_offset: Offset in boot media that SPL must start loading (bytes) |
| spl_load_size: Size of U-Boot image that SPL must load |
| pos: The position of the start of the parameter block. |
| use_efs_memory: True to return the address in EFS memory (i.e. SRAM), |
| False to use SDRAM |
| skip_sdram_init: True to skip SDRAM initialization. |
| """ |
| version, size = struct.unpack('<2L', self._spl_data[pos + 4:pos + 12]) |
| if version != 1: |
| raise CmdError("Cannot update machine parameter block version '%d'" % |
| version) |
| if size < 0 or pos + size > len(self._spl_data): |
| raise CmdError('Machine parameter block size %d is invalid: ' |
| 'pos=%d, size=%d, space=%d, len=%d' % |
| (size, pos, size, len(self._spl_data) |
| - pos, len(self._spl_data))) |
| |
| # |
| # A dictionary of functions processing machine parameters. This is being |
| # introduced after more than 20 parameters have been already defined and |
| # are handled by the ugly if/elif/... construct below. It will be |
| # refactored eventually (one should hope), no new parameters' processing |
| # should be added there. |
| # |
| # The key of the dictionary is the parameter name, the value is a list. |
| # the first element of the list is the function to call to process the |
| # parameter, the rest of the elements are parameters to pass to the |
| # function. |
| # |
| # The first three parameters passed to the function are always prepended |
| # to those obtained from the list and are as follows: |
| # |
| # - the machine parameter name (one character string) |
| # - value read from the appropriate spot of the machine param structure, |
| # as generated by the u-boot makefile, a - 32 bit int |
| # - fdt object representing the target FDT |
| # |
| # The function is expected to return a 32 bit value to plug into the |
| # machine parameters structure. |
| # |
| mp_router = { |
| 't': [self._MpRevMap, pos] |
| } |
| |
| # Move past the header and read the parameter list, which is terminated |
| # with \0. |
| pos += 12 |
| param_list = struct.unpack('<%ds' % (len(self._spl_data) - pos), |
| self._spl_data[pos:])[0] |
| param_len = param_list.find('\0') |
| param_list = param_list[:param_len] |
| pos += (param_len + 4) & ~3 |
| |
| # Use this to detect a missing value from the fdt. |
| not_given = 'not-given-invalid-value' |
| |
| # Work through the parameters one at a time, adding each value |
| new_data = '' |
| upto = 0 |
| for param in param_list: |
| value = struct.unpack('<1L', self._spl_data[pos + upto:pos + upto + 4])[0] |
| |
| if param in mp_router: |
| value = mp_router[param][0](param, value, fdt, *mp_router[param][1:]) |
| elif param == 'm': |
| mem_type = fdt.GetString('/dmc', 'mem-type', not_given) |
| if mem_type == not_given: |
| mem_type = 'ddr3' |
| self._out.Warning("No value for memory type: using '%s'" % mem_type) |
| mem_types = ['ddr2', 'ddr3', 'lpddr2', 'lpddr3'] |
| if mem_type not in mem_types: |
| raise CmdError("Unknown memory type '%s'" % mem_type) |
| value = mem_types.index(mem_type) |
| self._out.Info(' Memory type: %s (%d)' % (mem_type, value)) |
| elif param == 'M': |
| mem_manuf = fdt.GetString('/dmc', 'mem-manuf', not_given) |
| if mem_manuf == not_given: |
| mem_manuf = 'samsung' |
| self._out.Warning("No value for memory manufacturer: using '%s'" % |
| mem_manuf) |
| mem_manufs = ['autodetect', 'elpida', 'samsung'] |
| if mem_manuf not in mem_manufs: |
| raise CmdError("Unknown memory manufacturer: '%s'" % mem_manuf) |
| value = mem_manufs.index(mem_manuf) |
| self._out.Info(' Memory manufacturer: %s (%d)' % (mem_manuf, value)) |
| elif param == 'f': |
| mem_freq = fdt.GetInt('/dmc', 'clock-frequency', -1) |
| if mem_freq == -1: |
| mem_freq = 800000000 |
| self._out.Warning("No value for memory frequency: using '%s'" % |
| mem_freq) |
| mem_freq /= 1000000 |
| if mem_freq not in [533, 667, 800]: |
| self._out.Warning("Unexpected memory speed '%s'" % mem_freq) |
| value = mem_freq |
| self._out.Info(' Memory speed: %d' % mem_freq) |
| elif param == 'a': |
| arm_freq = fdt.GetInt('/dmc', 'arm-frequency', -1) |
| if arm_freq == -1: |
| arm_freq = 1700000000 |
| self._out.Warning("No value for ARM frequency: using '%s'" % |
| arm_freq) |
| arm_freq /= 1000000 |
| value = arm_freq |
| self._out.Info(' ARM speed: %d' % arm_freq) |
| elif param == 'i': |
| i2c_addr = -1 |
| lookup = fdt.GetString('/aliases', 'pmic', '') |
| if lookup: |
| i2c_addr, size = fdt.GetIntList(lookup, 'reg', 2) |
| if i2c_addr == -1: |
| self._out.Warning('No value for PMIC I2C address: using %#08x' % |
| value) |
| else: |
| value = i2c_addr |
| self._out.Info(' PMIC I2C Address: %#08x' % value) |
| elif param == 's': |
| serial_addr = -1 |
| lookup = fdt.GetString('/aliases', 'console', '') |
| if lookup: |
| serial_addr, size = fdt.GetIntList(lookup, 'reg', 2) |
| if serial_addr == -1: |
| self._out.Warning('No value for Console address: using %#08x' % |
| value) |
| else: |
| value = serial_addr |
| self._out.Info(' Console Address: %#08x' % value) |
| elif param == 'v': |
| value = 31 |
| self._out.Info(' Memory interleave: %#0x' % value) |
| elif param == 'u': |
| value = spl_load_size |
| self._out.Info(' U-Boot size: %#0x' % value) |
| elif param == 'S': |
| value = self.GetUBootAddress(fdt, use_efs_memory) |
| self._out.Info(' U-Boot start: %#0x' % value) |
| elif param == 'o': |
| value = spl_load_offset |
| self._out.Info(' U-Boot offset: %#0x' % value) |
| elif param == 'l': |
| load_addr = fdt.GetInt('/config', 'u-boot-load-addr', -1) |
| if load_addr == -1: |
| self._out.Warning("No value for U-Boot load address: using '%08x'" % |
| value) |
| else: |
| value = load_addr |
| self._out.Info(' U-Boot load address: %#0x' % value) |
| elif param == 'b': |
| # These values come from enum boot_mode in U-Boot's cpu.h |
| # For EFS we select SPI as the boot source always. We could support |
| # eMMC if we want to add EFS support for eMMC. |
| if (self.spl_source == 'spi' or |
| self._BootingUsingEFS(fdt, use_efs_memory)): |
| value = 20 |
| elif self.spl_source == 'straps': |
| value = 32 |
| elif self.spl_source == 'emmc': |
| value = 4 |
| elif self.spl_source == 'usb': |
| value = 33 |
| else: |
| raise CmdError("Invalid boot source '%s'" % self.spl_source) |
| self._out.Info(' Boot source: %#0x' % value) |
| elif param in ['r', 'R']: |
| records = fdt.GetIntList('/board-rev', 'google,board-rev-gpios', |
| None, '0 0') |
| gpios = [] |
| for i in range(1, len(records), 3): |
| gpios.append(records[i]) |
| gpios.extend([0, 0, 0, 0]) |
| if param == 'r': |
| value = gpios[0] + (gpios[1] << 16) |
| self._out.Info(' Board ID GPIOs: tit0=%d, tit1=%d' % (gpios[0], |
| gpios[1])) |
| else: |
| value = gpios[2] + (gpios[3] << 16) |
| self._out.Info(' Board ID GPIOs: tit2=%d, tit3=%d' % (gpios[2], |
| gpios[3])) |
| elif param == 'w': |
| records = fdt.GetIntList('/config', 'google,bad-wake-gpios', |
| 3, '0 0xffffffff 0') |
| value = records[1] |
| self._out.Info(' Bad Wake GPIO: %#x' % value) |
| elif param == 'z': |
| compress = fdt.GetString('/flash/ro-boot', 'compress', 'none') |
| compress_types = ['none', 'lzo'] |
| if compress not in compress_types: |
| raise CmdError("Unknown compression type '%s'" % compress) |
| value = compress_types.index(compress) |
| self._out.Info(' Compression type: %#0x' % value) |
| elif param == 'c': |
| rtc_type = 0 |
| try: |
| rtc_alias = fdt.GetString('/aliases/', 'rtc') |
| rtc_compat = fdt.GetString(rtc_alias, 'compatible') |
| if rtc_compat == 'samsung,s5m8767-pmic': |
| rtc_type = 1 |
| elif rtc_compat == 'maxim,max77802-pmic': |
| rtc_type = 2 |
| except CmdError: |
| self._out.Warning('Failed to find rtc') |
| value = rtc_type |
| elif param == 'W': |
| try: |
| records = fdt.GetIntList('/chromeos-config/vboot-flag-write-protect', |
| 'gpio', 3) |
| value = records[1] |
| self._out.Info(' Write Protect GPIO: %#x' % value) |
| except CmdError: |
| self._out.Warning('No value for write protect GPIO: using %#x' % |
| value) |
| elif param in ['j', 'A', 'U']: |
| jump, addr, size = self._GetRWSPLDetails(fdt, use_efs_memory) |
| if param == 'j': |
| value = jump |
| self._out.Info(' Jump to RW SPL: %d' % value) |
| elif param == 'A': |
| value = addr |
| self._out.Info(' RW SPL addr: %#x' % value) |
| elif param == 'U': |
| value = size |
| self._out.Info(' RW SPL size: %#x' % value) |
| elif param == 'd': |
| value = 1 if skip_sdram_init else 0 |
| self._out.Info(' Skip SDRAM init: %d' % value) |
| elif param == 'p': |
| addr = self._GetAddress(fdt, use_efs_memory, 'vboot-persist', |
| '/chromeos-config', True) |
| if addr is None: |
| value = 0 |
| else: |
| value = addr |
| self._out.Info(' Vboot persist addr: %x' % value) |
| elif param == 'D': |
| value = fdt.GetBool('/config', 'spl-debug') |
| self._out.Info(' SPL debug: %d' % value) |
| else: |
| self._out.Warning("Unknown machine parameter type '%s'" % param) |
| self._out.Info(' Unknown value: %#0x' % value) |
| new_data += struct.pack('<L', value) |
| upto += 4 |
| |
| # Put the data into our block. |
| self._spl_data = self._spl_data[:pos] + new_data + self._spl_data[ |
| pos + len(new_data):] |
| |
| def _UpdateChecksum(self): |
| """Update the BL2 size and checksum. |
| |
| For the fixed size spl the checksum is a 4 byte sum of all the bytes in |
| the image before the last 4 bytes (which hold the checksum). |
| |
| For the variable size SPL the first four bytes of the blob is the size of |
| the blob and the second four bytes is the sum of bytes in the rest of the |
| blob. |
| |
| Raises: |
| CmdError if spl type is not set properly. |
| """ |
| |
| if self._spl_type == self.FIXED_SPL: |
| checksum = sum(ord(x) for x in self._spl_data[:-4]) |
| checksum_offset = len(self._spl_data) - 4 |
| elif self._spl_type == self.VAR_SPL: |
| # Data size could have changed (the rev table could have been added). |
| if len(self._spl_data) % 4: |
| # Bl1 expects data size to be divisible by 4 |
| self._spl_data += '\0' * (4 - len(self._spl_data) % 4) |
| self._spl_data = struct.pack('<L', |
| len(self._spl_data)) + self._spl_data[4:] |
| checksum = sum(ord(x) for x in self._spl_data[8:]) |
| checksum_offset = 4 |
| else: |
| raise CmdError('SPL type not set') |
| |
| self._spl_data = self._spl_data[:checksum_offset] + struct.pack( |
| '<L', checksum) + self._spl_data[checksum_offset+4:] |
| |
| def _UpdateHash(self, digest): |
| """Update the BL2 hash. |
| |
| The BL2 header may have a pointer to the hash block, but if not, then we |
| add it (at the end of SPL). |
| |
| Args: |
| digest: The hash digest to write. |
| |
| Raises: |
| CmdError if spl type is not variable size. We don't support this |
| function with fixed-sized SPL. |
| """ |
| if self._spl_type != self.VAR_SPL: |
| raise CmdError('Hash is only supported for variable-size SPL') |
| |
| # See if there is already a hash there. |
| hash_offset = struct.unpack('<L', self._spl_data[8:12])[0] |
| if not hash_offset: |
| hash_offset = len(self._spl_data) |
| algo = 'sha256'.ljust(HASH_ALGO_LEN, '\x00') |
| hash_block = algo + digest |
| hash_block_len = len(hash_block) + HASH_HEADER_LEN |
| hash_hdr = struct.pack('<4L', HASH_SIGNATURE, HASH_VERSION, hash_block_len, |
| HASH_FLAGS) |
| self._spl_data = (self._spl_data[:hash_offset] + hash_hdr + hash_block + |
| self._spl_data[hash_offset + hash_block_len:]) |
| |
| # Update the size and hash_offset. |
| self._spl_data = struct.pack('<LLL', len(self._spl_data), 0, hash_offset |
| ) + self._spl_data[12:] |
| self._out.Info(' Added hash: %s' % ''. |
| join(['%02x' % ord(d) for d in digest])) |
| |
| def _VerifyBl2(self, loose_check): |
| """Verify BL2 integrity. |
| |
| Fixed size and variable size SPL have different formats. Determine format, |
| verify SPL integrity and save its type (fixed or variable size) for future |
| reference. |
| |
| Args: |
| loose_check: a Boolean, if true - the variable size SPL blob could be |
| larger than the size value in the header |
| Raises: |
| CmdError if SPL blob is of unrecognizable format. |
| """ |
| |
| data = self._spl_data # Cache it to improve readability. |
| # Variable size format is more sophisticated, check it first. |
| try: |
| size = struct.unpack('<I', data[:4])[0] |
| if size == len(data) or (loose_check and (size < len(data))): |
| check_sum = sum(ord(x) for x in data[8:size]) |
| # Compare with header checksum |
| if check_sum == struct.unpack('<I', data[4:8])[0]: |
| # this is a variable size SPL |
| self._out.Progress('Variable size BL2 detected') |
| self._spl_type = self.VAR_SPL |
| return |
| |
| # This is not var size spl, let's see if it's the fixed size one. |
| # Checksum is placed at a fixed location in the blob, as defined in |
| # tools/mkexynosspl.c in the u--boot tree. There are two possibilities |
| # for blob sizes - 14K or 30K. The checksum is put in the last 4 bytes |
| # of the blob. |
| # |
| # To complicate things further the blob here could have come not from |
| # mkexynosspl directly, it could have been pulled out of a previously |
| # bundled image. I that case it the blob will be in a chunk aligned to |
| # the closest 16K boundary. |
| blob_size = ((len(data) + 0x3fff) & ~0x3fff) - 2 * 1024 |
| if blob_size == len(data) or (loose_check and (blob_size < len(data))): |
| check_sum = sum(ord(x) for x in data[:blob_size - 4]) |
| if check_sum == struct.unpack('<I', data[blob_size - 4:blob_size])[0]: |
| self._spl_type = self.FIXED_SPL |
| self._out.Progress('Fixed size BL2 detected') |
| return |
| except IndexError: |
| # This will be thrown if bl2 is too small |
| pass |
| raise CmdError('Unrecognizable bl2 format') |
| |
| def Configure(self, fdt, spl_load_offset, spl_load_size, orig_bl2, name='', |
| loose_check=False, digest=None, use_efs_memory=True, |
| skip_sdram_init=False): |
| """Configure an Exynos BL2 binary for our needs. |
| |
| We create a new modified BL2 and return its file name. |
| |
| Args: |
| fdt: Device tree containing the parameter values. |
| spl_load_offset: Offset in boot media that SPL must start loading (bytes) |
| spl_load_size: Size of U-Boot image that SPL must load |
| orig_bl2: Filename of original BL2 file to modify. |
| name: a string, suffix to add to the generated file name |
| loose_check: if True - allow var size SPL blob to be larger, then the |
| size value in the header. This is necessary for cases when |
| SPL is pulled out of an image (and is padded). |
| digest: If not None, hash digest to add to this BL2 (a string of bytes). |
| use_efs_memory: True to return the address in EFS memory (i.e. SRAM), |
| False to use SDRAM |
| skip_sdram_init: True to skip SDRAM initialization. |
| |
| Returns: |
| Filename of configured bl2. |
| |
| Raises: |
| CmdError if machine parameter block could not be found. |
| """ |
| bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name) |
| self._out.Info('Configuring BL2 %s' % bl2) |
| self._spl_data = self._tools.ReadFile(orig_bl2) |
| self._VerifyBl2(loose_check) |
| |
| # Locate the parameter block |
| marker = struct.pack('<L', 0xdeadbeef) |
| pos = self._spl_data.rfind(marker) |
| if not pos: |
| raise CmdError("Could not find machine parameter block in '%s'" % |
| orig_bl2) |
| self._UpdateParameters(fdt, spl_load_offset, spl_load_size, |
| pos, use_efs_memory, skip_sdram_init) |
| if digest: |
| self._UpdateHash(digest) |
| self._UpdateChecksum() |
| |
| self._tools.WriteFile(bl2, self._spl_data) |
| return bl2 |
| |
| # pylint: disable=E1101 |
| |
| def MakeSpl(self, pack, fdt, blob, vanilla_bl2): |
| """Create a configured SPL based on the supplied vanilla one. |
| |
| This handles the process of working out what to configure in a SPL |
| and also doing it. The settings of what to configure are in the |
| flash map node which requested this SPL to be included. For example |
| a 'compress' property sets the type of compresion to use for the |
| payload that SPL loads. |
| |
| Args: |
| pack: The PackFirmware object, providing access to the contents. |
| fdt: The device tree containing the flash map. |
| blob: A namedtuple with these members: |
| node - Full path to device tree node |
| key - Key name (e.g. exynos-bl2') |
| params - List of parameters to the node - the first element is the |
| list of files within the blob, for example 'boot,dtb' |
| vanilla_bl2: The original SPL that needs configuring. |
| |
| Returns: |
| Filename of the configured SPL. |
| |
| Raises: |
| CmdError if there are no parameters provided (and therefore no payload). |
| """ |
| spl_payload = blob.params |
| |
| if not spl_payload: |
| raise CmdError('No parameters provided for Exynos SPL/BL2') |
| prop_list = spl_payload[0].split(',') |
| name = blob.key.split('.') |
| |
| # At this stage name may be plain 'exynos-bl2', but it is possible to have |
| # different versions, named 'exynos-bl2.rw' for RW SPL, and |
| # 'exynos-bl2.rec' for recovery SPL (in fact anything else can be used). |
| # This logic selects the string to append to the standard name, i.e. we |
| # want '.rw' or '.rec', or an empty string if there is no suffix. |
| if len(name) > 1: |
| name = '.' + name[1] |
| else: |
| name = '' |
| compress = fdt.GetString(blob.node, 'compress', 'none') |
| if compress == 'none': |
| compress = None |
| data = pack.ConcatPropContents(prop_list, compress, False)[0] |
| spl_load_size = len(data) |
| |
| # Figure out what flash region SPL needs to load. |
| payload = fdt.GetString(blob.node, 'payload', 'none') |
| if payload == 'none': |
| payload = '/flash/ro-boot' |
| self._out.Warning("No payload boot media for '%s' - using %s" % |
| (blob.node, payload)) |
| spl_load_offset = fdt.GetIntList(payload, 'reg', 2)[0] |
| |
| # Tell this SPL to use EFS memory (i.e. SRAM, if available) if we are |
| # loading ro-boot. Otherwise we are loading normal U-Boot, so will use |
| # SDRAM. |
| use_efs_memory = 'ro-boot' in prop_list |
| |
| self._out.Info("BL2/SPL contains '%s', size is %d / %#x" % |
| (', '.join(prop_list), spl_load_size, spl_load_size)) |
| if fdt.GetBool(blob.node, 'hash-target'): |
| hasher = hashlib.sha256() |
| hasher.update(data) |
| digest = hasher.digest() |
| else: |
| digest = None |
| skip_sdram_init = fdt.GetBool(blob.node, 'skip-sdram-init') |
| bl2 = self.Configure(fdt, spl_load_offset, spl_load_size, vanilla_bl2, |
| name=name, digest=digest, |
| use_efs_memory=use_efs_memory, |
| skip_sdram_init=skip_sdram_init) |
| return bl2 |