binman: Support x86 microcode in TPL

When TPL is used on x86 we may want to program the microcode (at least for
the first CPU) early in boot. Add support for this by refactoring the
existing code to be more generic.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2018-09-14 04:57:32 -06:00
parent e0e5df9310
commit f025363543
9 changed files with 151 additions and 21 deletions

View File

@ -462,6 +462,8 @@ both SPL and the device tree).
Entry: u-boot-spl-with-ucode-ptr: U-Boot SPL with embedded microcode pointer
----------------------------------------------------------------------------
This is used when SPL must set up the microcode for U-Boot.
See Entry_u_boot_ucode for full details of the entries involved in this
process.
@ -503,6 +505,24 @@ to activate.
Entry: u-boot-tpl-dtb-with-ucode: U-Boot TPL with embedded microcode pointer
----------------------------------------------------------------------------
This is used when TPL must set up the microcode for U-Boot.
See Entry_u_boot_ucode for full details of the entries involved in this
process.
Entry: u-boot-tpl-with-ucode-ptr: U-Boot TPL with embedded microcode pointer
----------------------------------------------------------------------------
See Entry_u_boot_ucode for full details of the entries involved in this
process.
Entry: u-boot-ucode: U-Boot microcode block
-------------------------------------------

View File

@ -43,6 +43,9 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
# If the section does not need microcode, there is nothing to do
ucode_dest_entry = self.section.FindEntryType(
'u-boot-spl-with-ucode-ptr')
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
ucode_dest_entry = self.section.FindEntryType(
'u-boot-tpl-with-ucode-ptr')
if not ucode_dest_entry or not ucode_dest_entry.target_offset:
ucode_dest_entry = self.section.FindEntryType(
'u-boot-with-ucode-ptr')
@ -70,14 +73,14 @@ class Entry_u_boot_dtb_with_ucode(Entry_blob_dtb):
def ObtainContents(self):
# Call the base class just in case it does something important.
Entry_blob_dtb.ObtainContents(self)
self._pathname = state.GetFdtPath(self._filename)
self.ReadBlobContents()
if self.ucode:
if self.ucode and not self.collate:
for node in self.ucode.subnodes:
data_prop = node.props.get('data')
if data_prop and not self.collate:
if data_prop:
# Find the offset in the device tree of the ucode data
self.ucode_offset = data_prop.GetOffset() + 12
self.ucode_size = len(data_prop.bytes)
self.ready = True
return True
self.ready = True
else:
self.ready = True
return self.ready

View File

@ -16,6 +16,8 @@ import tools
class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
"""U-Boot SPL with embedded microcode pointer
This is used when SPL must set up the microcode for U-Boot.
See Entry_u_boot_ucode for full details of the entries involved in this
process.
"""

View File

@ -0,0 +1,25 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# Entry-type module for U-Boot device tree with the microcode removed
#
import control
from entry import Entry
from u_boot_dtb_with_ucode import Entry_u_boot_dtb_with_ucode
import tools
class Entry_u_boot_tpl_dtb_with_ucode(Entry_u_boot_dtb_with_ucode):
"""U-Boot TPL with embedded microcode pointer
This is used when TPL must set up the microcode for U-Boot.
See Entry_u_boot_ucode for full details of the entries involved in this
process.
"""
def __init__(self, section, etype, node):
Entry_u_boot_dtb_with_ucode.__init__(self, section, etype, node)
def GetDefaultFilename(self):
return 'tpl/u-boot-tpl.dtb'

View File

@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# Entry-type module for an TPL 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_tpl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr):
"""U-Boot TPL with embedded microcode pointer
See Entry_u_boot_ucode for full details of the entries involved in this
process.
"""
def __init__(self, section, etype, node):
Entry_u_boot_with_ucode_ptr.__init__(self, section, etype, node)
self.elf_fname = 'tpl/u-boot-tpl'
def GetDefaultFilename(self):
return 'tpl/u-boot-tpl-nodtb.bin'

View File

@ -62,19 +62,24 @@ class Entry_u_boot_ucode(Entry_blob):
def ObtainContents(self):
# If the section does not need microcode, there is nothing to do
ucode_dest_entry = self.section.FindEntryType('u-boot-with-ucode-ptr')
ucode_dest_entry_spl = self.section.FindEntryType(
'u-boot-spl-with-ucode-ptr')
if ((not ucode_dest_entry or not ucode_dest_entry.target_offset) and
(not ucode_dest_entry_spl or not ucode_dest_entry_spl.target_offset)):
found = False
for suffix in ['', '-spl', '-tpl']:
name = 'u-boot%s-with-ucode-ptr' % suffix
entry = self.section.FindEntryType(name)
if entry and entry.target_offset:
found = True
if not found:
self.data = ''
return True
# Get the microcode from the device tree entry. If it is not available
# yet, return False so we will be called later. If the section simply
# doesn't exist, then we may as well return True, since we are going to
# get an error anyway.
fdt_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
for suffix in ['', '-spl', '-tpl']:
name = 'u-boot%s-dtb-with-ucode' % suffix
fdt_entry = self.section.FindEntryType(name)
if fdt_entry:
break
if not fdt_entry:
return True
if not fdt_entry.ready:
@ -86,12 +91,9 @@ class Entry_u_boot_ucode(Entry_blob):
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 = tools.GetOutputFilename('u-boot-ucode.bin')
tools.WriteFile(self._pathname, fdt_entry.ucode_data)
self._pathname = fname
self.ReadBlobContents()
return True

View File

@ -74,13 +74,16 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob):
# 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.
# in the latter. If we extracted the microcode from the device tree
# and collated it in one place, it will be in the former.
if ucode_entry.size:
offset, size = ucode_entry.offset, ucode_entry.size
else:
dtb_entry = self.section.FindEntryType('u-boot-dtb-with-ucode')
if not dtb_entry or not dtb_entry.ready:
if not dtb_entry:
dtb_entry = self.section.FindEntryType(
'u-boot-tpl-dtb-with-ucode')
if not dtb_entry:
self.Raise('Cannot find microcode region u-boot-dtb-with-ucode')
offset = dtb_entry.offset + dtb_entry.ucode_offset
size = dtb_entry.ucode_size

View File

@ -44,6 +44,7 @@ X86_START16_SPL_DATA = 'start16spl'
X86_START16_TPL_DATA = 'start16tpl'
U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
FSP_DATA = 'fsp'
CMC_DATA = 'cmc'
VBT_DATA = 'vbt'
@ -103,6 +104,8 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
U_BOOT_SPL_NODTB_DATA)
TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
U_BOOT_TPL_NODTB_DATA)
TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
@ -1644,6 +1647,22 @@ class TestFunctional(unittest.TestCase):
m.update(16 * 'a')
self.assertEqual(m.digest(), ''.join(hash_node.value))
def testPackUBootTplMicrocode(self):
"""Test that x86 microcode can be handled correctly in TPL
We expect to see the following in the image, in order:
u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
place
u-boot-tpl.dtb with the microcode removed
the microcode
"""
with open(self.TestFile('u_boot_ucode_ptr')) as fd:
TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
first, pos_and_size = self._RunMicrocodeTest('93_x86_tpl_ucode.dts',
U_BOOT_TPL_NODTB_DATA)
self.assertEqual('tplnodtb with microc' + pos_and_size +
'ter somewhere in here', first)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,29 @@
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
sort-by-offset;
end-at-4gb;
size = <0x200>;
u-boot-tpl-with-ucode-ptr {
};
u-boot-tpl-dtb-with-ucode {
};
u-boot-ucode {
};
};
microcode {
update@0 {
data = <0x12345678 0x12345679>;
};
update@1 {
data = <0xabcd0000 0x78235609>;
};
};
};