diff --git a/tools/binman/README b/tools/binman/README
index c73fb3c299a18f7a43da3042d7b5b327240ea6e8..45e741e3b39c131413c077049cf147677fac0d48 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -369,6 +369,17 @@ Examples of the above options can be found in the tests. See the
 tools/binman/test directory.
 
 
+Special properties
+------------------
+
+Some entries support special properties, documented here:
+
+u-boot-with-ucode-ptr:
+	optional-ucode: boolean property to make microcode optional. If the
+		u-boot.bin image does not include microcode, no error will
+		be generated.
+
+
 Order of image creation
 -----------------------
 
diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f4ea0b21be98c1d68bfa2b97b621794240c2d7d
--- /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_me.py b/tools/binman/etype/intel_me.py
new file mode 100644
index 0000000000000000000000000000000000000000..45ab50c1ec3e6c7cfd688db43177972acc7b9499
--- /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 0000000000000000000000000000000000000000..f6cedb70586208b2071d0848a1fc5ba363d21b39
--- /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 0000000000000000000000000000000000000000..d8f270bbd9593d66a07c6985fb857693cf5809ab
--- /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_dtb_with_ucode.py b/tools/binman/etype/u_boot_dtb_with_ucode.py
new file mode 100644
index 0000000000000000000000000000000000000000..732d10a14eed341c1574b0a87e9d436317b53a96
--- /dev/null
+++ b/tools/binman/etype/u_boot_dtb_with_ucode.py
@@ -0,0 +1,76 @@
+# 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-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_ucode.py b/tools/binman/etype/u_boot_ucode.py
new file mode 100644
index 0000000000000000000000000000000000000000..8fe27acb2453a25d15bb1525ff864720c0e480fb
--- /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 0000000000000000000000000000000000000000..6f01adb9701892cb7277f6c115bad929e7e81939
--- /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 0000000000000000000000000000000000000000..a44ea68ac47268e39a7d4a3e25e390a12ff21ae5
--- /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/func_test.py b/tools/binman/func_test.py
index bf6e9ed6c355f3f4dd64e5078654e949ce74c2aa..341957b59f0f13e096013bb35c7d221de1622645 100644
--- a/tools/binman/func_test.py
+++ b/tools/binman/func_test.py
@@ -65,10 +65,21 @@ class TestFunctional(unittest.TestCase):
         TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
         TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
         TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
+        TestFunctional._MakeInputFile('me.bin', ME_DATA)
+        TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
+        TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
         TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
         self._output_setup = False
 
+        # ELF file with a '_dt_ucode_base_size' symbol
+        with open(self.TestFile('u_boot_ucode_ptr')) as fd:
+            TestFunctional._MakeInputFile('u-boot', fd.read())
+
+        # Intel flash descriptor file
+        with open(self.TestFile('descriptor.bin')) as fd:
+            TestFunctional._MakeInputFile('descriptor.bin', fd.read())
+
     @classmethod
     def tearDownClass(self):
         """Remove the temporary input directory and its contents"""
@@ -125,6 +136,18 @@ class TestFunctional(unittest.TestCase):
                               '-d', self.TestFile(fname))
 
     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
+        """Set up a new test device-tree file
+
+        The given file is compiled and set up as the device tree to be used
+        for ths test.
+
+        Args:
+            fname: Filename of .dts file to read
+            outfile: Output filename for compiled device tree binary
+
+        Returns:
+            Contents of device tree binary
+        """
         if not self._output_setup:
             tools.PrepareOutputDir(self._indir, True)
             self._output_setup = True
@@ -132,8 +155,9 @@ class TestFunctional(unittest.TestCase):
         with open(dtb) as fd:
             data = fd.read()
             TestFunctional._MakeInputFile(outfile, data)
+            return data
 
-    def _DoReadFile(self, fname, use_real_dtb=False):
+    def _DoReadFileDtb(self, fname, use_real_dtb=False):
         """Run binman and return the resulting image
 
         This runs binman with a given test file and then reads the resulting
@@ -148,10 +172,16 @@ class TestFunctional(unittest.TestCase):
                 the u-boot-dtb entry. Normally this is not needed and the
                 test contents (the U_BOOT_DTB_DATA string) can be used.
                 But in some test we need the real contents.
+
+        Returns:
+            Tuple:
+                Resulting image contents
+                Device tree contents
         """
+        dtb_data = None
         # Use the compiled test file as the u-boot-dtb input
         if use_real_dtb:
-            self._SetupDtb(fname)
+            dtb_data = self._SetupDtb(fname)
 
         try:
             retcode = self._DoTestFile(fname)
@@ -162,12 +192,16 @@ class TestFunctional(unittest.TestCase):
             fname = tools.GetOutputFilename('image.bin')
             self.assertTrue(os.path.exists(fname))
             with open(fname) as fd:
-                return fd.read()
+                return fd.read(), dtb_data
         finally:
             # Put the test file back
             if use_real_dtb:
                 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
 
+    def _DoReadFile(self, fname, use_real_dtb=False):
+        """Helper function which discards the device-tree binary"""
+        return self._DoReadFileDtb(fname, use_real_dtb)[0]
+
     @classmethod
     def _MakeInputFile(self, fname, contents):
         """Create a new test input file, creating directories as needed
@@ -213,6 +247,17 @@ class TestFunctional(unittest.TestCase):
             self.assertEqual(pos, entry.pos)
             pos += entry.size
 
+    def GetFdtLen(self, dtb):
+        """Get the totalsize field from a device tree binary
+
+        Args:
+            dtb: Device tree binary contents
+
+        Returns:
+            Total size of device tree binary, from the header
+        """
+        return struct.unpack('>L', dtb[4:8])[0]
+
     def testRun(self):
         """Test a basic run with valid args"""
         result = self._RunBinman('-h')
@@ -540,3 +585,131 @@ class TestFunctional(unittest.TestCase):
         """Test that a device tree can be added to U-Boot"""
         data = self._DoReadFile('26_pack_u_boot_dtb.dts')
         self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
+
+    def testPackX86RomNoSize(self):
+        """Test that the end-at-4gb property requires a size property"""
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('27_pack_4gb_no_size.dts')
+        self.assertIn("Image '/binman': Image size must be provided when "
+                      "using end-at-4gb", str(e.exception))
+
+    def testPackX86RomOutside(self):
+        """Test that the end-at-4gb property checks for position boundaries"""
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('28_pack_4gb_outside.dts')
+        self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside "
+                      "the image starting at 0xfffffff0 (4294967280)",
+                      str(e.exception))
+
+    def testPackX86Rom(self):
+        """Test that a basic x86 ROM can be created"""
+        data = self._DoReadFile('29_x86-rom.dts')
+        self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA +
+                         chr(0) * 6, data)
+
+    def testPackX86RomMeNoDesc(self):
+        """Test that an invalid Intel descriptor entry is detected"""
+        TestFunctional._MakeInputFile('descriptor.bin', '')
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('31_x86-rom-me.dts')
+        self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
+                      "signature", str(e.exception))
+
+    def testPackX86RomBadDesc(self):
+        """Test that the Intel requires a descriptor entry"""
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('30_x86-rom-me-no-desc.dts')
+        self.assertIn("Node '/binman/intel-me': No position set with "
+                      "pos-unset: should another entry provide this correct "
+                      "position?", str(e.exception))
+
+    def testPackX86RomMe(self):
+        """Test that an x86 ROM with an ME region can be created"""
+        data = self._DoReadFile('31_x86-rom-me.dts')
+        self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
+
+    def testPackVga(self):
+        """Test that an image with a VGA binary can be created"""
+        data = self._DoReadFile('32_intel-vga.dts')
+        self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
+
+    def testPackStart16(self):
+        """Test that an image with an x86 start16 region can be created"""
+        data = self._DoReadFile('33_x86-start16.dts')
+        self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
+
+    def testPackUbootMicrocode(self):
+        """Test that x86 microcode can be handled correctly
+
+        We expect to see the following in the image, in order:
+            u-boot-nodtb.bin with a microcode pointer inserted at the correct
+                place
+            u-boot.dtb with the microcode removed
+            the microcode
+        """
+        data = self._DoReadFile('34_x86_ucode.dts', True)
+
+        # Now check the device tree has no microcode
+        second = data[len(U_BOOT_NODTB_DATA):]
+        fname = tools.GetOutputFilename('test.dtb')
+        with open(fname, 'wb') as fd:
+            fd.write(second)
+        fdt = fdt_select.FdtScan(fname)
+        ucode = fdt.GetNode('/microcode')
+        self.assertTrue(ucode)
+        for node in ucode.subnodes:
+            self.assertFalse(node.props.get('data'))
+
+        fdt_len = self.GetFdtLen(second)
+        third = second[fdt_len:]
+
+        # Check that the microcode appears immediately after the Fdt
+        # This matches the concatenation of the data properties in
+        # the /microcode/update@xxx nodes in x86_ucode.dts.
+        ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
+                                 0x78235609)
+        self.assertEqual(ucode_data, third[:len(ucode_data)])
+        ucode_pos = len(U_BOOT_NODTB_DATA) + fdt_len
+
+        # Check that the microcode pointer was inserted. It should match the
+        # expected position and size
+        pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
+                                   len(ucode_data))
+        first = data[:len(U_BOOT_NODTB_DATA)]
+        self.assertEqual('nodtb with microcode' + pos_and_size +
+                         ' somewhere in here', first)
+
+    def _RunPackUbootSingleMicrocode(self, collate):
+        """Test that x86 microcode can be handled correctly
+
+        We expect to see the following in the image, in order:
+            u-boot-nodtb.bin with a microcode pointer inserted at the correct
+                place
+            u-boot.dtb with the microcode
+            an empty microcode region
+        """
+        # We need the libfdt library to run this test since only that allows
+        # finding the offset of a property. This is required by
+        # Entry_u_boot_dtb_with_ucode.ObtainContents().
+        if not fdt_select.have_libfdt:
+            return
+        data = self._DoReadFile('35_x86_single_ucode.dts', True)
+
+        second = data[len(U_BOOT_NODTB_DATA):]
+
+        fdt_len = self.GetFdtLen(second)
+        third = second[fdt_len:]
+        second = second[:fdt_len]
+
+        if not collate:
+            ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
+            self.assertIn(ucode_data, second)
+            ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
+
+            # Check that the microcode pointer was inserted. It should match the
+            # expected position and size
+            pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
+                                    len(ucode_data))
+            first = data[:len(U_BOOT_NODTB_DATA)]
+            self.assertEqual('nodtb with microcode' + pos_and_size +
+                            ' somewhere in here', first)
diff --git a/tools/binman/test/27_pack_4gb_no_size.dts b/tools/binman/test/27_pack_4gb_no_size.dts
new file mode 100644
index 0000000000000000000000000000000000000000..e0b6519e75bb7652dd83acb848788ebcb019a103
--- /dev/null
+++ b/tools/binman/test/27_pack_4gb_no_size.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		u-boot {
+			pos = <0xfffffff0>;
+		};
+
+		u-boot-spl {
+			pos = <0xfffffff7>;
+		};
+	};
+};
diff --git a/tools/binman/test/28_pack_4gb_outside.dts b/tools/binman/test/28_pack_4gb_outside.dts
new file mode 100644
index 0000000000000000000000000000000000000000..ff468c7d41d031aab7bc4a4ce7e0729cdfd2bc54
--- /dev/null
+++ b/tools/binman/test/28_pack_4gb_outside.dts
@@ -0,0 +1,19 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		size = <16>;
+		u-boot {
+			pos = <0>;
+		};
+
+		u-boot-spl {
+			pos = <0xfffffff7>;
+		};
+	};
+};
diff --git a/tools/binman/test/29_x86-rom.dts b/tools/binman/test/29_x86-rom.dts
new file mode 100644
index 0000000000000000000000000000000000000000..075ede36ab32e6c8b07a99b2bf0561cd5263861d
--- /dev/null
+++ b/tools/binman/test/29_x86-rom.dts
@@ -0,0 +1,19 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		size = <16>;
+		u-boot {
+			pos = <0xfffffff0>;
+		};
+
+		u-boot-spl {
+			pos = <0xfffffff7>;
+		};
+	};
+};
diff --git a/tools/binman/test/30_x86-rom-me-no-desc.dts b/tools/binman/test/30_x86-rom-me-no-desc.dts
new file mode 100644
index 0000000000000000000000000000000000000000..4578f660ac01e2679670a3a1122c53d3972eb35c
--- /dev/null
+++ b/tools/binman/test/30_x86-rom-me-no-desc.dts
@@ -0,0 +1,15 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		size = <16>;
+		intel-me {
+			pos-unset;
+		};
+	};
+};
diff --git a/tools/binman/test/31_x86-rom-me.dts b/tools/binman/test/31_x86-rom-me.dts
new file mode 100644
index 0000000000000000000000000000000000000000..b484ab31cf786335e688d5e4ce775fe168c2a081
--- /dev/null
+++ b/tools/binman/test/31_x86-rom-me.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		size = <0x800000>;
+		intel-descriptor {
+		};
+
+		intel-me {
+			pos-unset;
+		};
+	};
+};
diff --git a/tools/binman/test/32_intel-vga.dts b/tools/binman/test/32_intel-vga.dts
new file mode 100644
index 0000000000000000000000000000000000000000..1790833238fa2cb0a0b704651c2ed3f2bee0612d
--- /dev/null
+++ b/tools/binman/test/32_intel-vga.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		size = <16>;
+
+		intel-vga {
+		};
+	};
+};
diff --git a/tools/binman/test/33_x86-start16.dts b/tools/binman/test/33_x86-start16.dts
new file mode 100644
index 0000000000000000000000000000000000000000..2e279dee9d63a5e1fb1652a3d2a38aed1dbf6b03
--- /dev/null
+++ b/tools/binman/test/33_x86-start16.dts
@@ -0,0 +1,13 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		size = <16>;
+
+		x86-start16 {
+		};
+	};
+};
diff --git a/tools/binman/test/34_x86_ucode.dts b/tools/binman/test/34_x86_ucode.dts
new file mode 100644
index 0000000000000000000000000000000000000000..64a6c2c3d5d43f8d60cd3765937f6da21e5853f8
--- /dev/null
+++ b/tools/binman/test/34_x86_ucode.dts
@@ -0,0 +1,29 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		size = <0x200>;
+		u-boot-with-ucode-ptr {
+		};
+
+		u-boot-dtb-with-ucode {
+		};
+
+		u-boot-ucode {
+		};
+	};
+
+	microcode {
+		update@0 {
+			data = <0x12345678 0x12345679>;
+		};
+		update@1 {
+			data = <0xabcd0000 0x78235609>;
+		};
+	};
+};
diff --git a/tools/binman/test/35_x86_single_ucode.dts b/tools/binman/test/35_x86_single_ucode.dts
new file mode 100644
index 0000000000000000000000000000000000000000..973e97f8641dbe294e6aa7fe096ffb1963b60dac
--- /dev/null
+++ b/tools/binman/test/35_x86_single_ucode.dts
@@ -0,0 +1,26 @@
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		sort-by-pos;
+		end-at-4gb;
+		size = <0x200>;
+		u-boot-with-ucode-ptr {
+		};
+
+		u-boot-dtb-with-ucode {
+		};
+
+		u-boot-ucode {
+		};
+	};
+
+	microcode {
+		update@0 {
+			data = <0x12345678 0x12345679>;
+		};
+	};
+};
diff --git a/tools/binman/test/descriptor.bin b/tools/binman/test/descriptor.bin
new file mode 100644
index 0000000000000000000000000000000000000000..3d549436c27c76f0a3b6289a16f68de4c14d70f6
Binary files /dev/null and b/tools/binman/test/descriptor.bin differ
diff --git a/tools/binman/test/u_boot_ucode_ptr b/tools/binman/test/u_boot_ucode_ptr
new file mode 100755
index 0000000000000000000000000000000000000000..dbfb184cecfbcf55cf43ed4f4ac0ee90a7364d93
Binary files /dev/null and b/tools/binman/test/u_boot_ucode_ptr differ
diff --git a/tools/binman/test/u_boot_ucode_ptr.c b/tools/binman/test/u_boot_ucode_ptr.c
new file mode 100644
index 0000000000000000000000000000000000000000..434c9f44003720fba57bf0e9bd8bfb73d68ecdec
--- /dev/null
+++ b/tools/binman/test/u_boot_ucode_ptr.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ *
+ * Simple program to create a _dt_ucode_base_size symbol which can be read
+ * by 'nm'. This is used by binman tests.
+ *
+ * Build with:
+ * cc -march=i386 -m32 -o u_boot_ucode_ptr -T u_boot_ucode_ptr.lds -nostdlib \
+	u_boot_ucode_ptr.c
+ */
+
+static unsigned long _dt_ucode_base_size[2]
+		__attribute__((section(".ucode"))) = {1, 2};
diff --git a/tools/binman/test/u_boot_ucode_ptr.lds b/tools/binman/test/u_boot_ucode_ptr.lds
new file mode 100644
index 0000000000000000000000000000000000000000..167debfe348630187f3edcba73ba34b4473a45c4
--- /dev/null
+++ b/tools/binman/test/u_boot_ucode_ptr.lds
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:      GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0xfffffdf0;
+	_start = .;
+	.ucode : {
+		*(.ucode)
+	}
+}