diff options
Diffstat (limited to 'tools/binman/etype')
-rw-r--r-- | tools/binman/etype/_testing.py | 26 | ||||
-rw-r--r-- | tools/binman/etype/blob.py | 37 | ||||
-rw-r--r-- | tools/binman/etype/entry.py | 200 | ||||
-rw-r--r-- | tools/binman/etype/intel_cmc.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/intel_descriptor.py | 55 | ||||
-rw-r--r-- | tools/binman/etype/intel_fsp.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/intel_me.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/intel_mrc.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/intel_vga.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/u_boot.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_dtb.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_dtb_with_ucode.py | 78 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_img.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_nodtb.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_spl.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_spl_bss_pad.py | 26 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_spl_with_ucode_ptr.py | 28 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_ucode.py | 84 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_with_ucode_ptr.py | 87 | ||||
-rw-r--r-- | tools/binman/etype/x86_start16.py | 17 | ||||
-rw-r--r-- | tools/binman/etype/x86_start16_spl.py | 17 |
21 files changed, 825 insertions, 0 deletions
diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py new file mode 100644 index 0000000..1783098 --- /dev/null +++ b/tools/binman/etype/_testing.py @@ -0,0 +1,26 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for testing purposes. Not used in real images. +# + +from entry import Entry +import fdt_util +import tools + +class Entry__testing(Entry): + def __init__(self, image, etype, node): + Entry.__init__(self, image, etype, node) + + def ObtainContents(self): + self.data = 'a' + self.contents_size = len(self.data) + return True + + def ReadContents(self): + return True + + def GetPositions(self): + return {'invalid-entry': [1, 2]} diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py new file mode 100644 index 0000000..def2164 --- /dev/null +++ b/tools/binman/etype/blob.py @@ -0,0 +1,37 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for blobs, which are binary objects read from files +# + +from entry import Entry +import fdt_util +import tools + +class Entry_blob(Entry): + def __init__(self, image, etype, node): + Entry.__init__(self, image, etype, node) + self._filename = fdt_util.GetString(self._node, "filename", self.etype) + + def ObtainContents(self): + self._filename = self.GetDefaultFilename() + self._pathname = tools.GetInputFilename(self._filename) + self.ReadContents() + return True + + def ReadContents(self): + with open(self._pathname) as fd: + # We assume the data is small enough to fit into memory. If this + # is used for large filesystem image that might not be true. + # In that case, Image.BuildImage() could be adjusted to use a + # new Entry method which can read in chunks. Then we could copy + # the data in chunks and avoid reading it all at once. For now + # this seems like an unnecessary complication. + self.data = fd.read() + self.contents_size = len(self.data) + return True + + def GetDefaultFilename(self): + return self._filename diff --git a/tools/binman/etype/entry.py b/tools/binman/etype/entry.py new file mode 100644 index 0000000..67c5734 --- /dev/null +++ b/tools/binman/etype/entry.py @@ -0,0 +1,200 @@ +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Base class for all entries +# + +# importlib was introduced in Python 2.7 but there was a report of it not +# working in 2.7.12, so we work around this: +# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html +try: + import importlib + have_importlib = True +except: + have_importlib = False + +import fdt_util +import tools + +modules = {} + +class Entry(object): + """An Entry in the image + + An entry corresponds to a single node in the device-tree description + of the image. Each entry ends up being a part of the final image. + Entries can be placed either right next to each other, or with padding + between them. The type of the entry determines the data that is in it. + + This class is not used by itself. All entry objects are subclasses of + Entry. + + Attributes: + image: The image containing this entry + node: The node that created this entry + pos: Absolute position of entry within the image, None if not known + size: Entry size in bytes, None if not known + contents_size: Size of contents in bytes, 0 by default + align: Entry start position alignment, or None + align_size: Entry size alignment, or None + align_end: Entry end position alignment, or None + pad_before: Number of pad bytes before the contents, 0 if none + pad_after: Number of pad bytes after the contents, 0 if none + data: Contents of entry (string of bytes) + """ + def __init__(self, image, etype, node, read_node=True): + self.image = image + self.etype = etype + self._node = node + self.pos = None + self.size = None + self.contents_size = 0 + self.align = None + self.align_size = None + self.align_end = None + self.pad_before = 0 + self.pad_after = 0 + self.pos_unset = False + if read_node: + self.ReadNode() + + @staticmethod + def Create(image, node, etype=None): + """Create a new entry for a node. + + Args: + image: Image object containing this node + node: Node object containing information about the entry to create + etype: Entry type to use, or None to work it out (used for tests) + + Returns: + A new Entry object of the correct type (a subclass of Entry) + """ + if not etype: + etype = fdt_util.GetString(node, 'type', node.name) + module_name = etype.replace('-', '_') + module = modules.get(module_name) + + # Import the module if we have not already done so. + if not module: + try: + if have_importlib: + module = importlib.import_module(module_name) + else: + module = __import__(module_name) + except ImportError: + raise ValueError("Unknown entry type '%s' in node '%s'" % + (etype, node.path)) + modules[module_name] = module + + # Call its constructor to get the object we want. + obj = getattr(module, 'Entry_%s' % module_name) + return obj(image, etype, node) + + def ReadNode(self): + """Read entry information from the node + + This reads all the fields we recognise from the node, ready for use. + """ + self.pos = fdt_util.GetInt(self._node, 'pos') + self.size = fdt_util.GetInt(self._node, 'size') + self.align = fdt_util.GetInt(self._node, 'align') + if tools.NotPowerOfTwo(self.align): + raise ValueError("Node '%s': Alignment %s must be a power of two" % + (self._node.path, self.align)) + self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0) + self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0) + self.align_size = fdt_util.GetInt(self._node, 'align-size') + if tools.NotPowerOfTwo(self.align_size): + raise ValueError("Node '%s': Alignment size %s must be a power " + "of two" % (self._node.path, self.align_size)) + self.align_end = fdt_util.GetInt(self._node, 'align-end') + self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset') + + def ObtainContents(self): + """Figure out the contents of an entry. + + Returns: + True if the contents were found, False if another call is needed + after the other entries are processed. + """ + # No contents by default: subclasses can implement this + return True + + def Pack(self, pos): + """Figure out how to pack the entry into the image + + Most of the time the entries are not fully specified. There may be + an alignment but no size. In that case we take the size from the + contents of the entry. + + If an entry has no hard-coded position, it will be placed at @pos. + + Once this function is complete, both the position and size of the + entry will be know. + + Args: + Current image position pointer + + Returns: + New image position pointer (after this entry) + """ + if self.pos is None: + if self.pos_unset: + self.Raise('No position set with pos-unset: should another ' + 'entry provide this correct position?') + self.pos = tools.Align(pos, self.align) + needed = self.pad_before + self.contents_size + self.pad_after + needed = tools.Align(needed, self.align_size) + size = self.size + if not size: + size = needed + new_pos = self.pos + size + aligned_pos = tools.Align(new_pos, self.align_end) + if aligned_pos != new_pos: + size = aligned_pos - self.pos + new_pos = aligned_pos + + if not self.size: + self.size = size + + if self.size < needed: + self.Raise("Entry contents size is %#x (%d) but entry size is " + "%#x (%d)" % (needed, needed, self.size, self.size)) + # Check that the alignment is correct. It could be wrong if the + # and pos or size values were provided (i.e. not calculated), but + # conflict with the provided alignment values + if self.size != tools.Align(self.size, self.align_size): + self.Raise("Size %#x (%d) does not match align-size %#x (%d)" % + (self.size, self.size, self.align_size, self.align_size)) + if self.pos != tools.Align(self.pos, self.align): + self.Raise("Position %#x (%d) does not match align %#x (%d)" % + (self.pos, self.pos, self.align, self.align)) + + return new_pos + + def Raise(self, msg): + """Convenience function to raise an error referencing a node""" + raise ValueError("Node '%s': %s" % (self._node.path, msg)) + + def GetPath(self): + """Get the path of a node + + Returns: + Full path of the node for this entry + """ + return self._node.path + + def GetData(self): + return self.data + + def GetPositions(self): + return {} + + def SetPositionSize(self, pos, size): + self.pos = pos + self.size = size + + def ProcessContents(self): + pass diff --git a/tools/binman/etype/intel_cmc.py b/tools/binman/etype/intel_cmc.py new file mode 100644 index 0000000..9bce8ae --- /dev/null +++ b/tools/binman/etype/intel_cmc.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Chip Microcode binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_cmc(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'cmc.bin' diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py new file mode 100644 index 0000000..7f4ea0b --- /dev/null +++ b/tools/binman/etype/intel_descriptor.py @@ -0,0 +1,55 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for 'u-boot' +# + +import struct + +from entry import Entry +from blob import Entry_blob + +FD_SIGNATURE = struct.pack('<L', 0x0ff0a55a) +MAX_REGIONS = 5 + +(REGION_DESCRIPTOR, REGION_BIOS, REGION_ME, REGION_GBE, + REGION_PDATA) = range(5) + +class Region: + def __init__(self, data, frba, region_num): + pos = frba + region_num * 4 + val = struct.unpack('<L', data[pos:pos + 4])[0] + self.base = (val & 0xfff) << 12 + self.limit = ((val & 0x0fff0000) >> 4) | 0xfff + self.size = self.limit - self.base + 1 + +class Entry_intel_descriptor(Entry_blob): + """Intel flash descriptor block (4KB) + + This is placed at the start of flash and provides information about + the SPI flash regions. In particular it provides the base address and + size of the ME region, allowing us to place the ME binary in the right + place. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self._regions = [] + + def GetDefaultFilename(self): + return 'descriptor.bin' + + def GetPositions(self): + pos = self.data.find(FD_SIGNATURE) + if pos == -1: + self.Raise('Cannot find FD signature') + flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL', + self.data[pos:pos + 16]) + frba = ((flmap0 >> 16) & 0xff) << 4 + for i in range(MAX_REGIONS): + self._regions.append(Region(self.data, frba, i)) + + # Set the offset for ME only, for now, since the others are not used + return {'intel-me': [self._regions[REGION_ME].base, + self._regions[REGION_ME].size]} diff --git a/tools/binman/etype/intel_fsp.py b/tools/binman/etype/intel_fsp.py new file mode 100644 index 0000000..d75be5b --- /dev/null +++ b/tools/binman/etype/intel_fsp.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Firmware Support Package binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_fsp(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'fsp.bin' diff --git a/tools/binman/etype/intel_me.py b/tools/binman/etype/intel_me.py new file mode 100644 index 0000000..45ab50c --- /dev/null +++ b/tools/binman/etype/intel_me.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Management Engine binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_me(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'me.bin' diff --git a/tools/binman/etype/intel_mrc.py b/tools/binman/etype/intel_mrc.py new file mode 100644 index 0000000..f6cedb7 --- /dev/null +++ b/tools/binman/etype/intel_mrc.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Memory Reference Code binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_mrc(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'mrc.bin' diff --git a/tools/binman/etype/intel_vga.py b/tools/binman/etype/intel_vga.py new file mode 100644 index 0000000..d8f270b --- /dev/null +++ b/tools/binman/etype/intel_vga.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for x86 VGA ROM binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_vga(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'vga.bin' diff --git a/tools/binman/etype/u_boot.py b/tools/binman/etype/u_boot.py new file mode 100644 index 0000000..1fcff73 --- /dev/null +++ b/tools/binman/etype/u_boot.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot binary +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot.bin' diff --git a/tools/binman/etype/u_boot_dtb.py b/tools/binman/etype/u_boot_dtb.py new file mode 100644 index 0000000..1122c95 --- /dev/null +++ b/tools/binman/etype/u_boot_dtb.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot device tree +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_dtb(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot.dtb' diff --git a/tools/binman/etype/u_boot_dtb_with_ucode.py b/tools/binman/etype/u_boot_dtb_with_ucode.py new file mode 100644 index 0000000..fc02c67 --- /dev/null +++ b/tools/binman/etype/u_boot_dtb_with_ucode.py @@ -0,0 +1,78 @@ +# Copyright (c) 2016 Google, Inc +## Written by Simon Glass <sjg@chromium.org> + +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot device tree with the microcode removed +# + +import fdt_select +from entry import Entry +from blob import Entry_blob +import tools + +class Entry_u_boot_dtb_with_ucode(Entry_blob): + """A U-Boot device tree file, with the microcode removed + + See Entry_u_boot_ucode for full details of the 3 entries involved in this + process. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self.ucode_data = '' + self.collate = False + self.ucode_offset = None + self.ucode_size = None + + def GetDefaultFilename(self): + return 'u-boot.dtb' + + def ObtainContents(self): + Entry_blob.ObtainContents(self) + + # If the image does not need microcode, there is nothing to do + ucode_dest_entry = self.image.FindEntryType('u-boot-spl-with-ucode-ptr') + if not ucode_dest_entry or not ucode_dest_entry.target_pos: + ucode_dest_entry = self.image.FindEntryType('u-boot-with-ucode-ptr') + if not ucode_dest_entry or not ucode_dest_entry.target_pos: + return True + + # Create a new file to hold the copied device tree + dtb_name = 'u-boot-dtb-with-ucode.dtb' + fname = tools.GetOutputFilename(dtb_name) + with open(fname, 'wb') as fd: + fd.write(self.data) + + # Remove the microcode + fdt = fdt_select.FdtScan(fname) + fdt.Scan() + ucode = fdt.GetNode('/microcode') + if not ucode: + raise self.Raise("No /microcode node found in '%s'" % fname) + + # There's no need to collate it (move all microcode into one place) + # if we only have one chunk of microcode. + self.collate = len(ucode.subnodes) > 1 + for node in ucode.subnodes: + data_prop = node.props.get('data') + if data_prop: + self.ucode_data += ''.join(data_prop.bytes) + if not self.collate: + poffset = data_prop.GetOffset() + if poffset is None: + # We cannot obtain a property offset. Collate instead. + self.collate = True + else: + # Find the offset in the device tree of the ucode data + self.ucode_offset = poffset + 12 + self.ucode_size = len(data_prop.bytes) + if self.collate: + prop = node.DeleteProp('data') + if self.collate: + fdt.Pack() + fdt.Flush() + + # Make this file the contents of this entry + self._pathname = fname + self.ReadContents() + return True diff --git a/tools/binman/etype/u_boot_img.py b/tools/binman/etype/u_boot_img.py new file mode 100644 index 0000000..744f1b4 --- /dev/null +++ b/tools/binman/etype/u_boot_img.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot binary +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_img(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot.img' diff --git a/tools/binman/etype/u_boot_nodtb.py b/tools/binman/etype/u_boot_nodtb.py new file mode 100644 index 0000000..3721c3b --- /dev/null +++ b/tools/binman/etype/u_boot_nodtb.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for 'u-boot-nodtb.bin' +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_nodtb(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot-nodtb.bin' diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py new file mode 100644 index 0000000..68b0148 --- /dev/null +++ b/tools/binman/etype/u_boot_spl.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for spl/u-boot-spl.bin +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_spl(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'spl/u-boot-spl.bin' diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py new file mode 100644 index 0000000..c005f28 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_bss_pad.py @@ -0,0 +1,26 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for BSS padding for spl/u-boot-spl.bin. This padding +# can be added after the SPL binary to ensure that anything concatenated +# to it will appear to SPL to be at the end of BSS rather than the start. +# + +import command +from entry import Entry +from blob import Entry_blob +import tools + +class Entry_u_boot_spl_bss_pad(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def ObtainContents(self): + fname = tools.GetInputFilename('spl/u-boot-spl') + args = [['nm', fname], ['grep', '__bss_size']] + out = command.RunPipe(args, capture=True).stdout.splitlines() + bss_size = int(out[0].split()[0], 16) + self.data = chr(0) * bss_size + self.contents_size = bss_size diff --git a/tools/binman/etype/u_boot_spl_with_ucode_ptr.py b/tools/binman/etype/u_boot_spl_with_ucode_ptr.py new file mode 100644 index 0000000..764c282 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_with_ucode_ptr.py @@ -0,0 +1,28 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for an SPL binary with an embedded microcode pointer +# + +import struct + +import command +from entry import Entry +from blob import Entry_blob +from u_boot_with_ucode_ptr import Entry_u_boot_with_ucode_ptr +import tools + +class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr): + """U-Boot SPL with embedded microcode pointer + + See Entry_u_boot_ucode for full details of the entries involved in this + process. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self.elf_fname = 'spl/u-boot-spl' + + def GetDefaultFilename(self): + return 'spl/u-boot-spl.bin' diff --git a/tools/binman/etype/u_boot_ucode.py b/tools/binman/etype/u_boot_ucode.py new file mode 100644 index 0000000..8fe27ac --- /dev/null +++ b/tools/binman/etype/u_boot_ucode.py @@ -0,0 +1,84 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for a U-Boot binary with an embedded microcode pointer +# + +from entry import Entry +from blob import Entry_blob +import tools + +class Entry_u_boot_ucode(Entry_blob): + """U-Boot microcode block + + U-Boot on x86 needs a single block of microcode. This is collected from + the various microcode update nodes in the device tree. It is also unable + to read the microcode from the device tree on platforms that use FSP + (Firmware Support Package) binaries, because the API requires that the + microcode is supplied before there is any SRAM available to use (i.e. + the FSP sets up the SRAM / cache-as-RAM but does so in the call that + requires the microcode!). To keep things simple, all x86 platforms handle + microcode the same way in U-Boot (even non-FSP platforms). This is that + a table is placed at _dt_ucode_base_size containing the base address and + size of the microcode. This is either passed to the FSP (for FSP + platforms), or used to set up the microcode (for non-FSP platforms). + This all happens in the build system since it is the only way to get + the microcode into a single blob and accessible without SRAM. + + There are two cases to handle. If there is only one microcode blob in + the device tree, then the ucode pointer it set to point to that. This + entry (u-boot-ucode) is empty. If there is more than one update, then + this entry holds the concatenation of all updates, and the device tree + entry (u-boot-dtb-with-ucode) is updated to remove the microcode. This + last step ensures that that the microcode appears in one contiguous + block in the image and is not unnecessarily duplicated in the device + tree. It is referred to as 'collation' here. + + Entry types that have a part to play in handling microcode: + + Entry_u_boot_with_ucode_ptr: + Contains u-boot-nodtb.bin (i.e. U-Boot without the device tree). + It updates it with the address and size of the microcode so that + U-Boot can find it early on start-up. + Entry_u_boot_dtb_with_ucode: + Contains u-boot.dtb. It stores the microcode in a + 'self.ucode_data' property, which is then read by this class to + obtain the microcode if needed. If collation is performed, it + removes the microcode from the device tree. + Entry_u_boot_ucode: + This class. If collation is enabled it reads the microcode from + the Entry_u_boot_dtb_with_ucode entry, and uses it as the + contents of this entry. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def ObtainContents(self): + # If the image does not need microcode, there is nothing to do + ucode_dest_entry = self.image.FindEntryType('u-boot-with-ucode-ptr') + if ucode_dest_entry and not ucode_dest_entry.target_pos: + self.data = '' + return True + + # Get the microcode from the device tree entry + fdt_entry = self.image.FindEntryType('u-boot-dtb-with-ucode') + if not fdt_entry or not fdt_entry.ucode_data: + return False + + if not fdt_entry.collate: + # This section can be empty + self.data = '' + return True + + # Write it out to a file + dtb_name = 'u-boot-ucode.bin' + fname = tools.GetOutputFilename(dtb_name) + with open(fname, 'wb') as fd: + fd.write(fdt_entry.ucode_data) + + self._pathname = fname + self.ReadContents() + + return True diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py new file mode 100644 index 0000000..6f01adb --- /dev/null +++ b/tools/binman/etype/u_boot_with_ucode_ptr.py @@ -0,0 +1,87 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for a U-Boot binary with an embedded microcode pointer +# + +import struct + +import command +from entry import Entry +from blob import Entry_blob +import fdt_util +import tools + +class Entry_u_boot_with_ucode_ptr(Entry_blob): + """U-Boot with embedded microcode pointer + + See Entry_u_boot_ucode for full details of the 3 entries involved in this + process. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self.elf_fname = 'u-boot' + self.target_pos = None + + def GetDefaultFilename(self): + return 'u-boot-nodtb.bin' + + def ObtainContents(self): + # Figure out where to put the microcode pointer + fname = tools.GetInputFilename(self.elf_fname) + args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']] + out = (command.RunPipe(args, capture=True, raise_on_error=False). + stdout.splitlines()) + if len(out) == 1: + self.target_pos = int(out[0].split()[0], 16) + elif not fdt_util.GetBool(self._node, 'optional-ucode'): + self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot') + + return Entry_blob.ObtainContents(self) + + def ProcessContents(self): + # If the image does not need microcode, there is nothing to do + if not self.target_pos: + return + + # Get the position of the microcode + ucode_entry = self.image.FindEntryType('u-boot-ucode') + if not ucode_entry: + self.Raise('Cannot find microcode region u-boot-ucode') + + # Check the target pos is in the image. If it is not, then U-Boot is + # being linked incorrectly, or is being placed at the wrong position + # in the image. + # + # The image must be set up so that U-Boot is placed at the + # flash address to which it is linked. For example, if + # CONFIG_SYS_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then + # the U-Boot region must start at position 7MB in the image. In this + # case the ROM starts at 0xff800000, so the position of the first + # entry in the image corresponds to that. + if (self.target_pos < self.pos or + self.target_pos >= self.pos + self.size): + self.Raise('Microcode pointer _dt_ucode_base_size at %08x is ' + 'outside the image ranging from %08x to %08x' % + (self.target_pos, self.pos, self.pos + self.size)) + + # Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode. + # If we have left the microcode in the device tree, then it will be + # in the former. If we extracted the microcode from the device tree + # and collated it in one place, it will be in the latter. + if ucode_entry.size: + pos, size = ucode_entry.pos, ucode_entry.size + else: + dtb_entry = self.image.FindEntryType('u-boot-dtb-with-ucode') + if not dtb_entry: + self.Raise('Cannot find microcode region u-boot-dtb-with-ucode') + pos = dtb_entry.pos + dtb_entry.ucode_offset + size = dtb_entry.ucode_size + + # Write the microcode position and size into the entry + pos_and_size = struct.pack('<2L', pos, size) + self.target_pos -= self.pos + self.data = (self.data[:self.target_pos] + pos_and_size + + self.data[self.target_pos + 8:]) diff --git a/tools/binman/etype/x86_start16.py b/tools/binman/etype/x86_start16.py new file mode 100644 index 0000000..a44ea68 --- /dev/null +++ b/tools/binman/etype/x86_start16.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for the 16-bit x86 start-up code for U-Boot +# + +from entry import Entry +from blob import Entry_blob + +class Entry_x86_start16(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot-x86-16bit.bin' diff --git a/tools/binman/etype/x86_start16_spl.py b/tools/binman/etype/x86_start16_spl.py new file mode 100644 index 0000000..3679a43 --- /dev/null +++ b/tools/binman/etype/x86_start16_spl.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for the 16-bit x86 start-up code for U-Boot SPL +# + +from entry import Entry +from blob import Entry_blob + +class Entry_x86_start16_spl(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'spl/u-boot-x86-16bit-spl.bin' |