1# Copyright (c) 2016 Google, Inc
2# Written by Simon Glass <sjg@chromium.org>
3#
4# SPDX-License-Identifier:      GPL-2.0+
5#
6# Entry-type module for a U-Boot binary with an embedded microcode pointer
7#
8
9import struct
10
11import command
12from entry import Entry
13from blob import Entry_blob
14import fdt_util
15import tools
16
17class Entry_u_boot_with_ucode_ptr(Entry_blob):
18    """U-Boot with embedded microcode pointer
19
20    See Entry_u_boot_ucode for full details of the 3 entries involved in this
21    process.
22    """
23    def __init__(self, image, etype, node):
24        Entry_blob.__init__(self, image, etype, node)
25        self.elf_fname = 'u-boot'
26        self.target_pos = None
27
28    def GetDefaultFilename(self):
29        return 'u-boot-nodtb.bin'
30
31    def ObtainContents(self):
32        # Figure out where to put the microcode pointer
33        fname = tools.GetInputFilename(self.elf_fname)
34        args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']]
35        out = (command.RunPipe(args, capture=True, raise_on_error=False).
36               stdout.splitlines())
37        if len(out) == 1:
38            self.target_pos = int(out[0].split()[0], 16)
39        elif not fdt_util.GetBool(self._node, 'optional-ucode'):
40            self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
41
42        return Entry_blob.ObtainContents(self)
43
44    def ProcessContents(self):
45        # If the image does not need microcode, there is nothing to do
46        if not self.target_pos:
47            return
48
49        # Get the position of the microcode
50        ucode_entry = self.image.FindEntryType('u-boot-ucode')
51        if not ucode_entry:
52            self.Raise('Cannot find microcode region u-boot-ucode')
53
54        # Check the target pos is in the image. If it is not, then U-Boot is
55        # being linked incorrectly, or is being placed at the wrong position
56        # in the image.
57        #
58        # The image must be set up so that U-Boot is placed at the
59        # flash address to which it is linked. For example, if
60        # CONFIG_SYS_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then
61        # the U-Boot region must start at position 7MB in the image. In this
62        # case the ROM starts at 0xff800000, so the position of the first
63        # entry in the image corresponds to that.
64        if (self.target_pos < self.pos or
65                self.target_pos >= self.pos + self.size):
66            self.Raise('Microcode pointer _dt_ucode_base_size at %08x is '
67                'outside the image ranging from %08x to %08x' %
68                (self.target_pos, self.pos, self.pos + self.size))
69
70        # Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
71        # If we have left the microcode in the device tree, then it will be
72        # in the former. If we extracted the microcode from the device tree
73        # and collated it in one place, it will be in the latter.
74        if ucode_entry.size:
75            pos, size = ucode_entry.pos, ucode_entry.size
76        else:
77            dtb_entry = self.image.FindEntryType('u-boot-dtb-with-ucode')
78            if not dtb_entry:
79                self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
80            pos = dtb_entry.pos + dtb_entry.ucode_offset
81            size = dtb_entry.ucode_size
82
83        # Write the microcode position and size into the entry
84        pos_and_size = struct.pack('<2L', pos, size)
85        self.target_pos -= self.pos
86        self.data = (self.data[:self.target_pos] + pos_and_size +
87                     self.data[self.target_pos + 8:])
88