1# SPDX-License-Identifier: GPL-2.0+
2# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# Entry-type module for a U-Boot binary with an embedded microcode pointer
6#
7
8import struct
9
10from binman import elf
11from binman.entry import Entry
12from binman.etype.blob import Entry_blob
13from dtoc import fdt_util
14from u_boot_pylib import tools
15from u_boot_pylib import command
16
17class Entry_u_boot_with_ucode_ptr(Entry_blob):
18    """U-Boot with embedded microcode pointer
19
20    Properties / Entry arguments:
21        - filename: Filename of u-boot-nodtb.bin (default 'u-boot-nodtb.bin')
22        - optional-ucode: boolean property to make microcode optional. If the
23            u-boot.bin image does not include microcode, no error will
24            be generated.
25
26    See Entry_u_boot_ucode for full details of the three entries involved in
27    this process. This entry updates U-Boot with the offset and size of the
28    microcode, to allow early x86 boot code to find it without doing anything
29    complicated. Otherwise it is the same as the u-boot entry.
30    """
31    def __init__(self, section, etype, node, auto_write_symbols=False):
32        super().__init__(section, etype, node, auto_write_symbols)
33        self.elf_fname = 'u-boot'
34        self.target_offset = None
35
36    def GetDefaultFilename(self):
37        return 'u-boot-nodtb.bin'
38
39    def ProcessFdt(self, fdt):
40        # Figure out where to put the microcode pointer
41        fname = tools.get_input_filename(self.elf_fname)
42        sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size')
43        if sym:
44           self.target_offset = sym
45        elif not fdt_util.GetBool(self._node, 'optional-ucode'):
46            self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot')
47        return True
48
49    def ProcessContents(self):
50        # If the image does not need microcode, there is nothing to do
51        if not self.target_offset:
52            return True
53
54        # Get the offset of the microcode
55        ucode_entry = self.section.FindEntryType('u-boot-ucode')
56        if not ucode_entry:
57            self.Raise('Cannot find microcode region u-boot-ucode')
58
59        # Check the target pos is in the section. If it is not, then U-Boot is
60        # being linked incorrectly, or is being placed at the wrong offset
61        # in the section.
62        #
63        # The section must be set up so that U-Boot is placed at the
64        # flash address to which it is linked. For example, if
65        # CONFIG_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then
66        # the U-Boot region must start at offset 7MB in the section. In this
67        # case the ROM starts at 0xff800000, so the offset of the first
68        # entry in the section corresponds to that.
69        if (self.target_offset < self.image_pos or
70                self.target_offset >= self.image_pos + self.size):
71            self.Raise('Microcode pointer _dt_ucode_base_size at %08x is outside the section ranging from %08x to %08x' %
72                (self.target_offset, self.image_pos,
73                 self.image_pos + self.size))
74
75        # Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode.
76        # If we have left the microcode in the device tree, then it will be
77        # in the latter. If we extracted the microcode from the device tree
78        # and collated it in one place, it will be in the former.
79        if ucode_entry.size:
80            offset, size = ucode_entry.offset, ucode_entry.size
81        else:
82            dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
83            if not dtb_entry:
84                dtb_entry = self.section.FindEntryType(
85                        'u-boot-tpl-dtb-with-ucode')
86            if not dtb_entry:
87                self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
88            offset = dtb_entry.offset + dtb_entry.ucode_offset
89            size = dtb_entry.ucode_size
90
91        # Write the microcode offset and size into the entry
92        offset_and_size = struct.pack('<2L', offset, size)
93        self.target_offset -= self.image_pos
94        return self.ProcessContentsUpdate(self.data[:self.target_offset] +
95                                          offset_and_size +
96                                          self.data[self.target_offset + 8:])
97