Exemplo n.º 1
0
    def AddConfigList(self, config_list, use_int=False):
        """Add a list of config items to the fdt.

    Normally these values are written to the fdt as strings, but integers
    are also supported, in which case the values will be converted to integers
    (if necessary) before being stored.

    Args:
      config_list: List of (config, value) tuples to add to the fdt. For each
          tuple:
              config: The fdt node to write to will be /config/<config>.
              value: An integer or string value to write.
      use_int: True to only write integer values.

    Raises:
      CmdError: if a value is required to be converted to integer but can't be.
    """
        if config_list:
            for config in config_list:
                value = config[1]
                if use_int:
                    try:
                        value = int(value)
                    except ValueError as str:
                        raise CmdError(
                            "Cannot convert config option '%s' to integer" %
                            value)
                if type(value) == type(1):
                    self.fdt.PutInteger('/config', '%s' % config[0], value)
                else:
                    self.fdt.PutString('/config', '%s' % config[0], value)
Exemplo n.º 2
0
    def ConfigureExynosBl2(self, fdt, spl_load_size, orig_bl2, name=''):
        """Configure an Exynos BL2 binary for our needs.

    We create a new modified BL2 and return its filename.

    Args:
      fdt: Device tree containing the parameter values.
      spl_load_size: Size of U-Boot image that SPL must load
      orig_bl2: Filename of original BL2 file to modify.
    """
        self._out.Info('Configuring BL2')
        bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
        data = self._tools.ReadFile(orig_bl2)
        self._tools.WriteFile(bl2, data)

        # Locate the parameter block
        data = self._tools.ReadFile(bl2)
        marker = struct.pack('<L', 0xdeadbeef)
        pos = data.rfind(marker)
        if not pos:
            raise CmdError("Could not find machine parameter block in '%s'" %
                           orig_bl2)
        data = self._UpdateBl2Parameters(fdt, spl_load_size, data, pos)
        data = self._UpdateChecksum(data)
        self._tools.WriteFile(bl2, data)
        return bl2
Exemplo n.º 3
0
  def AddProperty(self, name, value):
    """Add a new property which can be used by the fdt.

    Args:
      name: Name of property
      value: Value of property (typically a filename)
    """
    if not value:
      raise CmdError("Cannot find value for entry property '%s'" % name)
    self.props[name] = value
Exemplo n.º 4
0
    def AddEnableList(self, enable_list):
        """Process a list of nodes to enable/disable.

    Args:
      config_list: List of (node, value) tuples to add to the fdt. For each
          tuple:
              node: The fdt node to write to will be <node> or pointed to by
                  /aliases/<node>. We can tell which
              value: 0 to disable the node, 1 to enable it
    """
        if enable_list:
            for node_name, enabled in enable_list:
                try:
                    enabled = int(enabled)
                    if enabled not in (0, 1):
                        raise ValueError
                except ValueError as str:
                    raise CmdError("Invalid enable option value '%s' "
                                   "(should be 0 or 1)" % enabled)
                self.SetNodeEnabled(node_name, enabled)
Exemplo n.º 5
0
    def _BuildBlob(self, pack, fdt, blob_type):
        """Build the blob data for a particular blob type.

    Args:
      blob_type: The type of blob to create data for. Supported types are:
          coreboot    A coreboot image (ROM plus U-boot and .dtb payloads).
          signed      Nvidia T20/T30 signed image (BCT, U-Boot, .dtb).
    """
        if blob_type == 'coreboot':
            coreboot = self._CreateCorebootStub(self.uboot_fname,
                                                self.coreboot_fname)
            pack.AddProperty('coreboot', coreboot)
            pack.AddProperty('image', coreboot)
        elif blob_type == 'legacy':
            pack.AddProperty('legacy', self.seabios_fname)
        elif blob_type == 'signed':
            bootstub, signed = self._CreateBootStub(self.uboot_fname, fdt,
                                                    self.postload_fname)
            pack.AddProperty('bootstub', bootstub)
            pack.AddProperty('signed', signed)
            pack.AddProperty('image', signed)
        elif blob_type == 'exynos-bl1':
            pack.AddProperty(blob_type, self.exynos_bl1)

        # TODO([email protected]): Deprecate ecbin
        elif blob_type in ['ecrw', 'ecbin']:
            pack.AddProperty('ecrw', self.ecrw_fname)
            pack.AddProperty('ecbin', self.ecrw_fname)
        elif blob_type == 'ecro':
            # crosbug.com/p/13143
            # We cannot have an fmap in the EC image since there can be only one,
            # which is the main fmap describing the whole image.
            # Ultimately the EC will not have an fmap, since with software sync
            # there is no flashrom involvement in updating the EC flash, and thus
            # no need for the fmap.
            # For now, mangle the fmap name to avoid problems.
            updated_ecro = os.path.join(self._tools.outdir, 'updated-ecro.bin')
            data = self._tools.ReadFile(self.ecro_fname)
            data = re.sub('__FMAP__', '__fMAP__', data)
            self._tools.WriteFile(updated_ecro, data)
            pack.AddProperty(blob_type, updated_ecro)
        elif blob_type == 'exynos-bl2':
            spl_payload = pack.GetBlobParams(blob_type)

            # TODO(sjg@chromium): Remove this later, when we remove boot+dtb
            # from all flash map files.
            if not spl_payload:
                spl_load_size = os.stat(pack.GetProperty('boot+dtb')).st_size
                prop_list = 'boot+dtb'

                # Do this later, when we remove boot+dtb.
                # raise CmdError("No parameters provided for blob type '%s'" %
                #     blob_type)
            else:
                prop_list = spl_payload[0].split(',')
                spl_load_size = len(
                    pack.ConcatPropContents(prop_list, False)[0])
            self._out.Info(
                "BL2/SPL contains '%s', size is %d / %#x" %
                (', '.join(prop_list), spl_load_size, spl_load_size))
            bl2 = self.ConfigureExynosBl2(fdt, spl_load_size, self.exynos_bl2)
            pack.AddProperty(blob_type, bl2)
        elif pack.GetProperty(blob_type):
            pass
        else:
            raise CmdError("Unknown blob type '%s' required in flash map" %
                           blob_type)
Exemplo n.º 6
0
    def _UpdateBl2Parameters(self, fdt, spl_load_size, data, pos):
        """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_size: Size of U-Boot image that SPL must load
      data: The BL2 data.
      pos: The position of the start of the parameter block.

    Returns:
      The new contents of the parameter block, after updating.
    """
        version, size = struct.unpack('<2L', 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(data):
            raise CmdError("Machine parameter block size %d is invalid: "
                           "pos=%d, size=%d, space=%d, len=%d" %
                           (size, pos, size, len(data) - pos, len(data)))

        # Move past the header and read the parameter list, which is terminated
        # with \0.
        pos += 12
        param_list = struct.unpack('<%ds' % (len(data) - pos), data[pos:])[0]
        param_len = param_list.find('\0')
        param_list = param_list[:param_len]
        pos += (param_len + 4) & ~3

        # Work through the parameters one at a time, adding each value
        new_data = ''
        upto = 0
        for param in param_list:
            value = struct.unpack('<1L', data[pos + upto:pos + upto + 4])[0]

            # Use this to detect a missing value from the fdt.
            not_given = 'not-given-invalid-value'
            if 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 not mem_type 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 not mem_manuf 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 not mem_freq 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 == 'v':
                value = 31
                self._out.Info('  Memory interleave: %#0x' % value)
            elif param == 'u':
                value = (spl_load_size + 0xfff) & ~0xfff
                self._out.Info('  U-Boot size: %#0x (rounded up from %#0x)' %
                               (value, spl_load_size))
            elif param == 'b':
                # These values come from enum boot_mode in U-Boot's cpu.h
                if self.spl_source == 'straps':
                    value = 32
                elif self.spl_source == 'emmc':
                    value = 4
                elif self.spl_source == 'spi':
                    value = 20
                elif self.spl_source == 'usb':
                    value = 33
                else:
                    raise CmdError("Invalid boot source '%s'" %
                                   self.spl_source)
                self._out.Info('  Boot source: %#0x' % 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.
        data = data[:pos] + new_data + data[pos + len(new_data):]
        self._out.Info('BL2 configuration complete')
        return data
Exemplo n.º 7
0
    def _CreateBootStub(self, uboot, base_fdt, postload):
        """Create a boot stub and a signed boot stub.

    For postload:
    We add a /config/postload-text-offset entry to the signed bootstub's
    fdt so that U-Boot can find the postload code.

    The raw (unsigned) bootstub will have a value of -1 for this since we will
    simply append the postload code to the bootstub and it can find it there.
    This will be used for RW A/B firmware.

    For the signed case this value will specify where in the flash to find
    the postload code. This will be used for RO firmware.

    Args:
      uboot: Path to u-boot.bin (may be chroot-relative)
      base_fdt: Fdt object containing the flat device tree.
      postload: Path to u-boot-post.bin, or None if none.

    Returns:
      Tuple containing:
        Full path to bootstub (uboot + fdt(-1) + postload).
        Full path to signed (uboot + fdt(flash pos) + bct) + postload.

    Raises:
      CmdError if a command fails.
    """
        bootstub = os.path.join(self._tools.outdir, 'u-boot-fdt.bin')
        text_base = self.CalcTextBase('', self.fdt, uboot)
        uboot_data = self._tools.ReadFile(uboot)

        # Make a copy of the fdt for the bootstub
        fdt = base_fdt.Copy(os.path.join(self._tools.outdir, 'bootstub.dtb'))
        fdt.PutInteger('/config', 'postload-text-offset', 0xffffffff)
        fdt_data = self._tools.ReadFile(fdt.fname)

        self._tools.WriteFile(bootstub, uboot_data + fdt_data)
        self._tools.OutputSize('U-Boot binary', self.uboot_fname)
        self._tools.OutputSize('U-Boot fdt', self._fdt_fname)
        self._tools.OutputSize('Combined binary', bootstub)

        # Sign the bootstub; this is a combination of the board specific
        # bct and the stub u-boot image.
        signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
                                    bootstub, text_base)

        signed_postload = os.path.join(self._tools.outdir,
                                       'signed-postload.bin')
        data = self._tools.ReadFile(signed)

        if postload:
            # We must add postload to the bootstub since A and B will need to
            # be able to find it without the /config/postload-text-offset mechanism.
            bs_data = self._tools.ReadFile(bootstub)
            bs_data += self._tools.ReadFile(postload)
            bootstub = os.path.join(self._tools.outdir,
                                    'u-boot-fdt-postload.bin')
            self._tools.WriteFile(bootstub, bs_data)
            self._tools.OutputSize('Combined binary with postload', bootstub)

            # Now that we know the file size, adjust the fdt and re-sign
            postload_bootstub = os.path.join(self._tools.outdir,
                                             'postload.bin')
            fdt.PutInteger('/config', 'postload-text-offset', len(data))
            fdt_data = self._tools.ReadFile(fdt.fname)
            self._tools.WriteFile(postload_bootstub, uboot_data + fdt_data)
            signed = self._SignBootstub(self._tools.Filename(self.bct_fname),
                                        postload_bootstub, text_base)
            if len(data) != os.path.getsize(signed):
                raise CmdError(
                    'Signed file size changed from %d to %d after updating '
                    'fdt' % (len(data), os.path.getsize(signed)))

            # Re-read the signed image, and add the post-load binary.
            data = self._tools.ReadFile(signed)
            data += self._tools.ReadFile(postload)
            self._tools.OutputSize('Post-load binary', postload)

        self._tools.WriteFile(signed_postload, data)
        self._tools.OutputSize('Final bootstub with postload', signed_postload)

        return bootstub, signed_postload
Exemplo n.º 8
0
def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
                    bundle, update=True, verify=False, dest=None,
                    flash_dest=None, kernel=None, bootstub=None, servo='any',
                    method='tegra'):
  """A simple function to write firmware to a device.

  This creates a WriteFirmware object and uses it to write the firmware image
  to the given destination device.

  Args:
    output: cros_output object to use.
    tools: Tools object to use.
    fdt: Fdt object to use as our device tree.
    flasher: U-Boot binary to use as the flasher.
    file_list: Dictionary containing files that we might need.
    image_fname: Filename of image to write.
    bundle: The bundle object which created the image.
    update: Use faster update algorithm rather then full device erase.
    verify: Verify the write by doing a readback and CRC.
    dest: Destination device to write firmware to (usb, sd).
    flash_dest: Destination device for flasher to program payload into.
    kernel: Kernel file to write after U-Boot
    bootstub: string, file name of the boot stub, if present
    servo: Describes the servo unit to use: none=none; any=any; otherwise
           port number of servo to use.
  """
  write = WriteFirmware(tools, fdt, output, bundle)
  write.SelectServo(servo)
  write.update = update
  write.verify = verify
  if dest == 'usb':
    method = fdt.GetString('/chromeos-config', 'flash-method', method)
    if method == 'tegra':
      tools.CheckTool('tegrarcm')
      if flash_dest:
        write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
      elif bootstub:
        write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
      ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
          image_fname, bootstub)
    elif method == 'exynos':
      tools.CheckTool('lsusb', 'usbutils')
      tools.CheckTool('smdk-usbdl', 'smdk-dltool')
      ok = write.ExynosFlashImage(flash_dest, flasher,
          file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
          kernel)
    else:
      raise CmdError("Unknown flash method '%s'" % method)
    if ok:
      output.Progress('Image uploaded - please wait for flashing to '
          'complete')
    else:
      raise CmdError('Image upload failed - please check board connection')
  elif dest == 'em100':
    # crosbug.com/31625
    tools.CheckTool('em100')
    write.Em100FlashImage(image_fname)
  elif dest.startswith('sd'):
    write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
  else:
    raise CmdError("Unknown destination device '%s'" % dest)
Exemplo n.º 9
0
  def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
                        kernel):
    """Flash the image to SPI flash.

    This creates a special Flasher binary, with the image to be flashed as
    a payload. This is then sent to the board using the tegrarcm utility.

    Args:
      flash_dest: Destination for flasher, or None to not create a flasher
          Valid options are spi, sdmmc.
      flash_uboot: Full path to u-boot.bin to use for flasher.
      bl1: Full path to file containing BL1 (pre-boot).
      bl2: Full path to file containing BL2 (SPL).
      payload: Full path to payload.
      kernel: Kernel to send after the payload, or None.

    Returns:
      True if ok, False if failed.
    """
    if flash_dest:
      image = self.PrepareFlasher(flash_uboot, payload, self.update,
                                  self.verify, flash_dest, '1:0')
    else:
      bl1, bl2, image = self._ExtractPayloadParts(payload)

    vendor_id = 0x04e8
    product_id = 0x1234

    # Preserve dut_hub_sel state.
    preserved_dut_hub_sel = self._DutControl(['dut_hub_sel',]
                                             ).strip().split(':')[-1]
    required_dut_hub_sel = 'dut_sees_servo'
    args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.1',
        'warm_reset:off']
    if preserved_dut_hub_sel != required_dut_hub_sel:
      # Need to set it to get the port properly powered up.
      args += ['dut_hub_sel:%s' % required_dut_hub_sel]
    # TODO(sjg) If the board is bricked a reset does not seem to bring it
    # back to life.
    # BUG=chromium-os:28229
    args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off'] + args
    self._out.Progress('Reseting board via servo')
    self._DutControl(args)

    # If we have a kernel to write, create a new image with that added.
    if kernel:
      dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
      data = self._tools.ReadFile(image)

      # Pad the original payload out to the original length
      data += '\0' * (os.stat(payload).st_size - len(data))
      data += self._tools.ReadFile(kernel)
      self._tools.WriteFile(dl_image, data)
    else:
      dl_image = image

    self._out.Progress('Uploading image')
    download_list = [
        # The numbers are the download addresses (in SRAM) for each piece
        # TODO([email protected]): Perhaps pick these up from the fdt?
        ['bl1', 0x02021400, bl1],
        ['bl2', 0x02023400, bl2],
        ['u-boot', 0x43e00000, dl_image]
        ]
    try:
      for upto in range(len(download_list)):
        item = download_list[upto]
        if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
          if upto == 0:
            raise CmdError('Could not find Exynos board on USB port')
          raise CmdError("Stage '%s' did not complete" % item[0])
        self._out.Notice(item[2])
        self._out.Progress("Uploading stage '%s'" % item[0])

        if upto == 0:
          # The IROM needs roughly 200ms here to be ready for USB download
          time.sleep(.5)

        args = ['-a', '%#x' % item[1], '-f', item[2]]
        self._tools.Run('smdk-usbdl', args, sudo=True)
        if upto == 1:
          # Once SPL starts up we can release the power buttom
          args = ['fw_up:off', 'pwr_button:release']
          self._DutControl(args)

    finally:
      # Make sure that the power button is released and dut_sel_hub state is
      # restored, whatever happens
      args = ['fw_up:off', 'pwr_button:release']
      if preserved_dut_hub_sel != required_dut_hub_sel:
        args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
      self._DutControl(args)

    self._out.Notice('Image downloaded - please see serial output '
        'for progress.')
    return True
Exemplo n.º 10
0
  def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
    """Flash the image to SPI flash.

    This creates a special Flasher binary, with the image to be flashed as
    a payload. This is then sent to the board using the tegrarcm utility.

    Args:
      flash_dest: Destination for flasher, or None to not create a flasher
          Valid options are spi, sdmmc
      uboot: Full path to u-boot.bin.
      bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
      payload: Full path to payload.
      bootstub: Full path to bootstub, which is the payload without the
          signing information (i.e. bootstub is u-boot.bin + the FDT)

    Returns:
      True if ok, False if failed.
    """
    # Use a Regex to pull Boot type from BCT file.
    match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
    bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()

    # TODO(sjg): The boot type is currently selected by the bct, rather than
    # flash_dest selecting which bct to use. This is a bit backwards. For now
    # we go with the bct's idea.
    boot_type = filter(match.match, bct_dumped)
    boot_type = match.match(boot_type[0]).group('boot').lower()

    if flash_dest:
      image = self.PrepareFlasher(uboot, payload, self.update, self.verify,
                                    boot_type, 0)
    elif bootstub:
      image = bootstub

    else:
      image = payload
      # If we don't know the textbase, extract it from the payload.
      if self.text_base == -1:
        data = self._tools.ReadFile(payload)
        # Skip the BCT which is the first 64KB
        self.text_base = self._bundle.DecodeTextBase(data[0x10000:])

    self._out.Notice('TEXT_BASE is %#x' % self.text_base)
    self._out.Progress('Uploading flasher image')
    args = [
      '--bct', bct,
      '--bootloader',  image,
      '--loadaddr', "%#x" % self.text_base
    ]

    # TODO(sjg): Check for existence of board - but chroot has no lsusb!
    last_err = None
    for _ in range(10):
      try:
        # TODO(sjg): Use Chromite library so we can monitor output
        self._tools.Run('tegrarcm', args, sudo=True)
        self._out.Notice('Flasher downloaded - please see serial output '
            'for progress.')
        return True

      except CmdError as err:
        if not self._out.stdout_is_tty:
          return False

        # Only show the error output once unless it changes.
        err = str(err)
        if not 'could not open USB device' in err:
          raise CmdError('tegrarcm failed: %s' % err)

        if err != last_err:
          self._out.Notice(err)
          last_err = err
          self._out.Progress('Please connect USB A-A cable and do a '
              'recovery-reset', True)
        time.sleep(1)

    return False