From 1ef366f9b068980a662b25d8ca4ef8e28f46e072 Mon Sep 17 00:00:00 2001 From: J-Alves Date: Wed, 4 Dec 2024 17:00:19 +0000 Subject: [PATCH 1/8] chore: add fdt dependencies to poetry The FDT python dependency is needed for the script: `sp_mk_generator.py'. It is used to obtain information from DT files. Signed-off-by: J-Alves Change-Id: Id98b93f8ab77d4864dd392fdb70bfd932b78c246 --- poetry.lock | 15 +++++++++++++-- pyproject.toml | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 341a2bd03..d05e199c7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -280,6 +280,17 @@ files = [ {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, ] +[[package]] +name = "fdt" +version = "0.3.3" +description = "Flattened Device Tree Python Module" +optional = false +python-versions = ">=3.5" +files = [ + {file = "fdt-0.3.3-py3-none-any.whl", hash = "sha256:6b2fae2e8dfa38e9b0f9666aa001dd25be74e893d293a8d60001438f732e9e47"}, + {file = "fdt-0.3.3.tar.gz", hash = "sha256:81a215930fef2ab8894913c4f474105bb53e14f07129fe07cb6eff2d5fdf26d2"}, +] + [[package]] name = "filelock" version = "3.16.0" @@ -540,7 +551,7 @@ files = [ [[package]] name = "memory" version = "0.1.0" -description = "A tool for analysis of " +description = "A tool for analysis of static memory consumption by TF-A images" optional = false python-versions = "^3.8.0" files = [] @@ -1331,4 +1342,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "7574eee0a05db1d9631bb29288abfc806810906a66e087a5a32e6e3920eb4bba" +content-hash = "c78729d7072714d77b4a69d6aabccab35dcf0548f08aa440ff178bc7bf2824be" diff --git a/pyproject.toml b/pyproject.toml index 55f3f2a3c..88c475393 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,3 +25,4 @@ sphinxcontrib-svg2pdfconverter = "^1.2.2" [tool.poetry.group.ci.dependencies] click = "^8.1.3" +fdt = "^0.3.0" From cc594af66e05b5f863b00dfab939f53e558d9c23 Mon Sep 17 00:00:00 2001 From: Kathleen Capella Date: Wed, 16 Oct 2024 18:14:33 -0400 Subject: [PATCH 2/8] feat(sptool): add the HOB list creation script Add python library to build the Handoff Block list (HOB list) for an SP at build time. Signed-off-by: Kathleen Capella Change-Id: I17d46f7ed21ce42a83f33dfdc4fad038653d1ec3 --- tools/sptool/hob.py | 396 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 tools/sptool/hob.py diff --git a/tools/sptool/hob.py b/tools/sptool/hob.py new file mode 100644 index 000000000..372ec68a5 --- /dev/null +++ b/tools/sptool/hob.py @@ -0,0 +1,396 @@ +#!/usr/bin/python3 +# Copyright (c) 2025, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +import struct + +EFI_HOB_HANDOFF_TABLE_VERSION = 0x000A + +PAGE_SIZE_SHIFT = 12 # TODO assuming 4K page size + +# HobType values of EFI_HOB_GENERIC_HEADER. + +EFI_HOB_TYPE_HANDOFF = 0x0001 +EFI_HOB_TYPE_MEMORY_ALLOCATION = 0x0002 +EFI_HOB_TYPE_RESOURCE_DESCRIPTOR = 0x0003 +EFI_HOB_TYPE_GUID_EXTENSION = 0x0004 +EFI_HOB_TYPE_FV = 0x0005 +EFI_HOB_TYPE_CPU = 0x0006 +EFI_HOB_TYPE_MEMORY_POOL = 0x0007 +EFI_HOB_TYPE_FV2 = 0x0009 +EFI_HOB_TYPE_LOAD_PEIM_UNUSED = 0x000A +EFI_HOB_TYPE_UEFI_CAPSULE = 0x000B +EFI_HOB_TYPE_FV3 = 0x000C +EFI_HOB_TYPE_UNUSED = 0xFFFE +EFI_HOB_TYPE_END_OF_HOB_LIST = 0xFFFF + +# GUID values +"""struct efi_guid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_and_node[8]; +}""" + +MM_PEI_MMRAM_MEMORY_RESERVE_GUID = ( + 0x0703F912, + 0xBF8D, + 0x4E2A, + (0xBE, 0x07, 0xAB, 0x27, 0x25, 0x25, 0xC5, 0x92), +) +MM_NS_BUFFER_GUID = ( + 0xF00497E3, + 0xBFA2, + 0x41A1, + (0x9D, 0x29, 0x54, 0xC2, 0xE9, 0x37, 0x21, 0xC5), +) + +# MMRAM states and capabilities +# See UEFI Platform Initialization Specification Version 1.8, IV-5.3.5 +EFI_MMRAM_OPEN = 0x00000001 +EFI_MMRAM_CLOSED = 0x00000002 +EFI_MMRAM_LOCKED = 0x00000004 +EFI_CACHEABLE = 0x00000008 +EFI_ALLOCATED = 0x00000010 +EFI_NEEDS_TESTING = 0x00000020 +EFI_NEEDS_ECC_INITIALIZATION = 0x00000040 + +EFI_SMRAM_OPEN = EFI_MMRAM_OPEN +EFI_SMRAM_CLOSED = EFI_MMRAM_CLOSED +EFI_SMRAM_LOCKED = EFI_MMRAM_LOCKED + +# EFI boot mode. +EFI_BOOT_WITH_FULL_CONFIGURATION = 0x00 +EFI_BOOT_WITH_MINIMAL_CONFIGURATION = 0x01 +EFI_BOOT_ASSUMING_NO_CONFIGURATION_CHANGES = 0x02 +EFI_BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS = 0x03 +EFI_BOOT_WITH_DEFAULT_SETTINGS = 0x04 +EFI_BOOT_ON_S4_RESUME = 0x05 +EFI_BOOT_ON_S5_RESUME = 0x06 +EFI_BOOT_WITH_MFG_MODE_SETTINGS = 0x07 +EFI_BOOT_ON_S2_RESUME = 0x10 +EFI_BOOT_ON_S3_RESUME = 0x11 +EFI_BOOT_ON_FLASH_UPDATE = 0x12 +EFI_BOOT_IN_RECOVERY_MODE = 0x20 + +STMM_BOOT_MODE = EFI_BOOT_WITH_FULL_CONFIGURATION +STMM_MMRAM_REGION_STATE_DEFAULT = EFI_CACHEABLE | EFI_ALLOCATED +STMM_MMRAM_REGION_STATE_HEAP = EFI_CACHEABLE + + +# Helper for fdt node property parsing +def get_integer_property_value(fdt_node, name): + if fdt_node.exist_property(name): + p = fdt_node.get_property(name) + + # Device Tree value + if len(p) == 1: + return p.value + # Device Tree value represented as two 32-bit values + if len(p) == 2: + msb = p[0] + lsb = p[1] + return lsb | (msb << 32) + return None + + +class EfiGuid: + """Class representing EFI GUID (Globally Unique Identifier) as described by + the UEFI Specification v2.10""" + + def __init__(self, time_low, time_mid, time_hi_and_version, clock_seq_and_node): + self.time_low = time_low + self.time_mid = time_mid + self.time_hi_and_version = time_hi_and_version + self.clock_seq_and_node = clock_seq_and_node + self.format_str = "IHH8B" + + def pack(self): + return struct.pack( + self.format_str, + self.time_low, + self.time_mid, + self.time_hi_and_version, + *self.clock_seq_and_node, + ) + + def __str__(self): + return f"{hex(self.time_low)}, {hex(self.time_mid)}, \ + {hex(self.time_hi_and_version)}, {[hex(i) for i in self.clock_seq_and_node]}" + + +class HobGenericHeader: + """Class representing the Hob Generic Header data type as described + in the UEFI Platform Initialization Specification version 1.8. + + Each HOB is required to contain this header specifying the type and length + of the HOB. + """ + + def __init__(self, hob_type, hob_length): + self.format_str = "HHI" + self.hob_type = hob_type + self.hob_length = struct.calcsize(self.format_str) + hob_length + self.reserved = 0 + + def pack(self): + return struct.pack( + self.format_str, self.hob_type, self.hob_length, self.reserved + ) + + def __str__(self): + return f"Hob Type: {self.hob_type} Hob Length: {self.hob_length}" + + +class HobGuid: + """Class representing the Guid Extension HOB as described in the UEFI + Platform Initialization Specification version 1.8. + + Allows the production of HOBs whose types are not defined by the + specification by generating a GUID for the HOB entry.""" + + def __init__(self, name: EfiGuid, data_format_str, data): + hob_length = struct.calcsize(name.format_str) + struct.calcsize(data_format_str) + self.header = HobGenericHeader(EFI_HOB_TYPE_GUID_EXTENSION, hob_length) + self.name = name + self.data = data + self.data_format_str = data_format_str + self.format_str = ( + self.header.format_str + self.name.format_str + data_format_str + ) + + def pack(self): + return ( + self.header.pack() + + self.name.pack() + + struct.pack(self.data_format_str, *self.data) + ) + + def __str__(self): + return f"Header: {self.header}\n Name: {self.name}\n Data: {self.data}" + + +class HandoffInfoTable: + """Class representing the Handoff Info Table HOB (also known as PHIT HOB) + as described in the UEFI Platform Initialization Specification version 1.8. + + Must be the first HOB in the HOB list. Contains general state + information. + + For an SP, the range `memory_bottom` to `memory_top` will be the memory + range for the SP starting at the load address. `free_memory_bottom` to + `free_memory_top` indicates space where more HOB's could be added to the + HOB List.""" + + def __init__(self, memory_base, memory_size, free_memory_base, free_memory_size): + # header,uint32t,uint32t, uint64_t * 5 + self.format_str = "II5Q" + hob_length = struct.calcsize(self.format_str) + self.header = HobGenericHeader(EFI_HOB_TYPE_HANDOFF, hob_length) + self.version = EFI_HOB_HANDOFF_TABLE_VERSION + self.boot_mode = STMM_BOOT_MODE + self.memory_top = memory_base + memory_size + self.memory_bottom = memory_base + self.free_memory_top = free_memory_base + free_memory_size + self.free_memory_bottom = free_memory_base + self.header.hob_length + self.hob_end = None + + def set_hob_end_addr(self, hob_end_addr): + self.hob_end = hob_end_addr + + def set_free_memory_bottom_addr(self, addr): + self.free_memory_bottom = addr + + def pack(self): + return self.header.pack() + struct.pack( + self.format_str, + self.version, + self.boot_mode, + self.memory_top, + self.memory_bottom, + self.free_memory_top, + self.free_memory_bottom, + self.hob_end, + ) + + +class FirmwareVolumeHob: + """Class representing the Firmware Volume HOB type as described in the + UEFI Platform Initialization Specification version 1.8. + + For an SP this will detail where the SP binary is located. + """ + + def __init__(self, base_address, img_offset, img_size): + # header, uint64_t, uint64_t + self.data_format_str = "2Q" + hob_length = struct.calcsize(self.data_format_str) + self.header = HobGenericHeader(EFI_HOB_TYPE_FV, hob_length) + self.format_str = self.header.format_str + self.data_format_str + self.base_address = base_address + img_offset + self.length = img_size - img_offset + + def pack(self): + return self.header.pack() + struct.pack( + self.data_format_str, self.base_address, self.length + ) + + +class EndOfHobListHob: + """Class representing the End of HOB List HOB type as described in the + UEFI Platform Initialization Specification version 1.8. + + Must be the last entry in a HOB list. + """ + + def __init__(self): + self.header = HobGenericHeader(EFI_HOB_TYPE_END_OF_HOB_LIST, 0) + self.format_str = "" + + def pack(self): + return self.header.pack() + + +class HobList: + """Class representing a HOB (Handoff Block list) based on the UEFI Platform + Initialization Sepcification version 1.8""" + + def __init__(self, phit: HandoffInfoTable): + if phit is None: + raise Exception("HobList must be initialized with valid PHIT HOB") + final_hob = EndOfHobListHob() + phit.hob_end = phit.free_memory_bottom + phit.free_memory_bottom += final_hob.header.hob_length + self.hob_list = [phit, final_hob] + + def add(self, hob): + if hob is not None: + if hob.header.hob_length > ( + self.get_phit().free_memory_top - self.get_phit().free_memory_bottom + ): + raise MemoryError( + f"Cannot add HOB of length {hob.header.hob_length}. \ + Resulting table size would exceed max table size of \ + {self.max_size}. Current table size: {self.size}." + ) + self.hob_list.insert(-1, hob) + self.get_phit().hob_end += hob.header.hob_length + self.get_phit().free_memory_bottom += hob.header.hob_length + + def get_list(self): + return self.hob_list + + def get_phit(self): + if self.hob_list is not None: + if type(self.hob_list[0]) is not HandoffInfoTable: + raise Exception("First hob in list must be of type PHIT") + return self.hob_list[0] + + +def generate_mmram_desc(base_addr, page_count, granule, region_state): + physical_size = page_count << (PAGE_SIZE_SHIFT + (granule << 1)) + physical_start = base_addr + cpu_start = base_addr + + return ("4Q", (physical_start, cpu_start, physical_size, region_state)) + + +def generate_ns_buffer_guid(mmram_desc): + return HobGuid(EfiGuid(*MM_NS_BUFFER_GUID), *mmram_desc) + + +def generate_pei_mmram_memory_reserve_guid(regions): + # uint32t n_reserved regions, array of mmram descriptors + format_str = "I" + data = [len(regions)] + for desc_format_str, mmram_desc in regions: + format_str += desc_format_str + data.extend(mmram_desc) + guid_data = (format_str, data) + return HobGuid(EfiGuid(*MM_PEI_MMRAM_MEMORY_RESERVE_GUID), *guid_data) + + +def generate_hob_from_fdt_node(sp_fdt, hob_offset, hob_size=None): + """Create a HOB list binary from an SP FDT.""" + fv_hob = None + ns_buffer_hob = None + mmram_reserve_hob = None + shared_buf_hob = None + + load_address = get_integer_property_value(sp_fdt, "load-address") + img_size = get_integer_property_value(sp_fdt, "image-size") + entrypoint_offset = get_integer_property_value(sp_fdt, "entrypoint-offset") + + if entrypoint_offset is None: + entrypoint_offset = 0x0 + if hob_offset is None: + hob_offset = 0x0 + if img_size is None: + img_size = 0x0 + + if sp_fdt.exist_node("memory-regions"): + if sp_fdt.exist_property("xlat-granule"): + granule = int(sp_fdt.get_property("xlat-granule").value) + else: + # Default granule to 4K + granule = 0 + memory_regions = sp_fdt.get_node("memory-regions") + regions = [] + for node in memory_regions.nodes: + base_addr = get_integer_property_value(node, "base-address") + page_count = get_integer_property_value(node, "pages-count") + + if base_addr is None: + offset = get_integer_property_value( + node, "load-address-relative-offset" + ) + if offset is None: + # Cannot create memory descriptor without base address, so skip + # node if base address cannot be defined + continue + else: + base_addr = load_address + offset + + if node.name.strip() == "heap": + region_state = STMM_MMRAM_REGION_STATE_HEAP + else: + region_state = STMM_MMRAM_REGION_STATE_DEFAULT + + mmram_desc = generate_mmram_desc( + base_addr, page_count, granule, region_state + ) + + if node.name.strip() == "ns_comm_buffer": + ns_buffer_hob = generate_ns_buffer_guid(mmram_desc) + + regions.append(mmram_desc) + + mmram_reserve_hob = generate_pei_mmram_memory_reserve_guid(regions) + + fv_hob = FirmwareVolumeHob(load_address, entrypoint_offset, img_size) + hob_list_base = load_address + hob_offset + + # TODO assuming default of 1 page allocated for HOB List + if hob_size is not None: + max_table_size = hob_size + else: + max_table_size = 1 << PAGE_SIZE_SHIFT + phit = HandoffInfoTable( + load_address, entrypoint_offset + img_size, hob_list_base, max_table_size + ) + + # Create a HobList containing only PHIT and EndofHobList HOBs. + hob_list = HobList(phit) + + # Add HOBs to HOB list + if fv_hob is not None: + hob_list.add(fv_hob) + if ns_buffer_hob is not None: + hob_list.add(ns_buffer_hob) + if mmram_reserve_hob is not None: + hob_list.add(mmram_reserve_hob) + if shared_buf_hob is not None: + hob_list.add(shared_buf_hob) + + return hob_list From 2d317e80c201573e9a05472ac1c96b0e6fe6e3bf Mon Sep 17 00:00:00 2001 From: J-Alves Date: Mon, 16 Dec 2024 17:48:52 +0000 Subject: [PATCH 3/8] feat(sptool): invoke the HOB list creation code Add an SP setup function that invokes the HOB creation utilities. It introduces an argument "hob_path" to the shared dictionary of args with the location of the generated binary containing the HOB list. Signed-off-by: Kathleen Capella Signed-off-by: J-Alves Change-Id: I26a07027b6344c9d7ba732d022932736a62e2505 --- tools/sptool/sp_mk_generator.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tools/sptool/sp_mk_generator.py b/tools/sptool/sp_mk_generator.py index f80050e04..e15b11b3f 100644 --- a/tools/sptool/sp_mk_generator.py +++ b/tools/sptool/sp_mk_generator.py @@ -55,10 +55,15 @@ import os import re import sys import uuid +import fdt from spactions import SpSetupActions +import hob +import struct +from hob import HobList MAX_SP = 8 UUID_LEN = 4 +HOB_OFFSET_DEFAULT=0x2000 # Some helper functions to access args propagated to the action functions in # SpSetupActions framework. @@ -179,6 +184,28 @@ def gen_fdt_sources(sp_layout, sp, args :dict): write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args) return args +@SpSetupActions.sp_action(exec_order=1) +def generate_hob_list(sp_layout, sp, args: dict): + ''' + Generates a HOB file for the partition, if it requested it in its FF-A + manifest. + ''' + with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as f: + sp_fdt = fdt.parse_dts(f.read()) + + if sp_fdt.exist_property('hob_list', '/boot-info'): + sp_hob_name = os.path.basename(sp + ".hob.bin") + sp_hob_name = os.path.join(args["out_dir"], f"{sp_hob_name}") + + # Add to the args so it can be consumed by the TL pkg function. + sp_layout[sp]["hob_path"] = sp_hob_name + hob_list = hob.generate_hob_from_fdt_node(sp_fdt, HOB_OFFSET_DEFAULT) + with open(sp_hob_name, "wb") as h: + for block in hob_list.get_list(): + h.write(block.pack()) + + return args + def generate_sp_pkg(sp_node, pkg, sp_img, sp_dtb): ''' Generates the rule in case SP is to be generated in an SP Pkg. ''' pm_offset = get_pm_offset(sp_node) From 32ecc0ef781d44f462aaeb441458d72b7dd5023d Mon Sep 17 00:00:00 2001 From: J-Alves Date: Mon, 16 Dec 2024 17:49:47 +0000 Subject: [PATCH 4/8] feat(sptool): include HOB file in the TL pkg If the "hob_path" has been introduced in the `args` dictionary, use it when creating a Transfer List type of package. Create a HOB entry in the transfer list with the respective transfer entry type. Signed-off-by: Kathleen Capella Signed-off-by: J-Alves Change-Id: Ie5fefe90205cf89ee26c3683048bf42229cb4bee --- tools/sptool/sp_mk_generator.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/sptool/sp_mk_generator.py b/tools/sptool/sp_mk_generator.py index e15b11b3f..9a00c745a 100644 --- a/tools/sptool/sp_mk_generator.py +++ b/tools/sptool/sp_mk_generator.py @@ -227,11 +227,12 @@ def generate_tl_pkg(sp_node, pkg, sp_img, sp_dtb, hob_path = None): TE_SP_BINARY = 0x103 # TE Type for the HOB List. TE_HOB_LIST = 0x3 - tlc_add_hob = f"\t$(Q)poetry run tlc add --entry {TE_HOB_LIST} {hob_path} {pkg}" if hob_path is not None else "" + tlc_add_hob = f"\t$(Q)$(TLCTOOL) add --entry {TE_HOB_LIST} {hob_path} {pkg}" if hob_path is not None else "" return f''' {pkg}: {sp_dtb} {sp_img} \t$(Q)echo Generating {pkg} \t$(Q)$(TLCTOOL) create --size {get_size(sp_node)} --entry {TE_FFA_MANIFEST} {sp_dtb} {pkg} --align 12 +{tlc_add_hob} \t$(Q)$(TLCTOOL) add --entry {TE_SP_BINARY} {sp_img} {pkg} ''' @@ -255,7 +256,10 @@ def gen_partition_pkg(sp_layout, sp, args :dict): if package_type == "sp_pkg": partition_pkg_rule = generate_sp_pkg(sp_layout[sp], pkg, sp_img, sp_dtb) elif package_type == "tl_pkg": - partition_pkg_rule = generate_tl_pkg(sp_layout[sp], pkg, sp_img, sp_dtb) + # Conditionally provide the Hob. + hob_path = sp_layout[sp]["hob_path"] if "hob_path" in sp_layout[sp] else None + partition_pkg_rule = generate_tl_pkg( + sp_layout[sp], pkg, sp_img, sp_dtb, hob_path) else: raise ValueError(f"Specified invalid pkg type {package_type}") From dcd8d7f13d5318ea3b38e6558c13e7401d57530c Mon Sep 17 00:00:00 2001 From: J-Alves Date: Fri, 13 Dec 2024 14:41:02 +0000 Subject: [PATCH 5/8] feat(fvp): increase cactus-tertiary size Increase the size of cactus-tertiary partition to match update in manifest. Part of effort to use cactus-tertiary partition in StMM/HOB testing. Dependent on https://review.trustedfirmware.org/c/TF-A/tf-a-tests/+/35383 Signed-off-by: Kathleen Capella Signed-off-by: J-Alves Change-Id: I5b91400848e2cf5d04d1c7442874a7a4b9847399 --- plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts index bf0e7f387..b62df1a6f 100644 --- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts +++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts @@ -34,7 +34,7 @@ debug_name = "cactus-primary"; load_address = <0x7000000>; vcpu_count = <8>; - mem_size = <1048576>; + mem_size = <0x100000>; /* * Platform specific SiP SMC call handled at EL3. Used * to pend an interrupt for testing purpose. @@ -46,21 +46,21 @@ debug_name = "cactus-secondary"; load_address = <0x7100000>; vcpu_count = <8>; - mem_size = <1048576>; + mem_size = <0x100000>; }; vm3 { is_ffa_partition; debug_name = "cactus-tertiary"; load_address = <0x7200000>; vcpu_count = <1>; - mem_size = <1048576>; + mem_size = <0x300000>; }; vm4 { is_ffa_partition; debug_name = "ivy"; load_address = <0x7600000>; vcpu_count = <1>; - mem_size = <1048576>; + mem_size = <0x100000>; }; }; From 49c656633178d21679afd467e41f43a761d4238c Mon Sep 17 00:00:00 2001 From: Kathleen Capella Date: Wed, 18 Dec 2024 18:39:21 -0500 Subject: [PATCH 6/8] feat(sptool): specify endianness for HOB bin Specify endianness encoding when packing HOB binary. Little-endian is used as target platforms are expected to be little-endian. Signed-off-by: Kathleen Capella Change-Id: I28d7b302f79482ed142c1964409c310f713a9b8c --- tools/sptool/hob.py | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/tools/sptool/hob.py b/tools/sptool/hob.py index 372ec68a5..9715f4015 100644 --- a/tools/sptool/hob.py +++ b/tools/sptool/hob.py @@ -78,6 +78,20 @@ STMM_BOOT_MODE = EFI_BOOT_WITH_FULL_CONFIGURATION STMM_MMRAM_REGION_STATE_DEFAULT = EFI_CACHEABLE | EFI_ALLOCATED STMM_MMRAM_REGION_STATE_HEAP = EFI_CACHEABLE +"""`struct` python module allows user to specify endianness. +We are expecting FVP or STMM platform as target and that they will be +little-endian. See `struct` python module documentation if other endianness is +needed.""" +ENDIANNESS = "<" + + +def struct_pack_with_endianness(format_str, *args): + return struct.pack((ENDIANNESS + format_str), *args) + + +def struct_calcsize_with_endianness(format_str): + return struct.calcsize(ENDIANNESS + format_str) + # Helper for fdt node property parsing def get_integer_property_value(fdt_node, name): @@ -107,7 +121,7 @@ class EfiGuid: self.format_str = "IHH8B" def pack(self): - return struct.pack( + return struct_pack_with_endianness( self.format_str, self.time_low, self.time_mid, @@ -131,11 +145,11 @@ class HobGenericHeader: def __init__(self, hob_type, hob_length): self.format_str = "HHI" self.hob_type = hob_type - self.hob_length = struct.calcsize(self.format_str) + hob_length + self.hob_length = struct_calcsize_with_endianness(self.format_str) + hob_length self.reserved = 0 def pack(self): - return struct.pack( + return struct_pack_with_endianness( self.format_str, self.hob_type, self.hob_length, self.reserved ) @@ -151,7 +165,9 @@ class HobGuid: specification by generating a GUID for the HOB entry.""" def __init__(self, name: EfiGuid, data_format_str, data): - hob_length = struct.calcsize(name.format_str) + struct.calcsize(data_format_str) + hob_length = struct_calcsize_with_endianness( + name.format_str + ) + struct_calcsize_with_endianness(data_format_str) self.header = HobGenericHeader(EFI_HOB_TYPE_GUID_EXTENSION, hob_length) self.name = name self.data = data @@ -164,7 +180,7 @@ class HobGuid: return ( self.header.pack() + self.name.pack() - + struct.pack(self.data_format_str, *self.data) + + struct_pack_with_endianness(self.data_format_str, *self.data) ) def __str__(self): @@ -186,7 +202,7 @@ class HandoffInfoTable: def __init__(self, memory_base, memory_size, free_memory_base, free_memory_size): # header,uint32t,uint32t, uint64_t * 5 self.format_str = "II5Q" - hob_length = struct.calcsize(self.format_str) + hob_length = struct_calcsize_with_endianness(self.format_str) self.header = HobGenericHeader(EFI_HOB_TYPE_HANDOFF, hob_length) self.version = EFI_HOB_HANDOFF_TABLE_VERSION self.boot_mode = STMM_BOOT_MODE @@ -203,7 +219,7 @@ class HandoffInfoTable: self.free_memory_bottom = addr def pack(self): - return self.header.pack() + struct.pack( + return self.header.pack() + struct_pack_with_endianness( self.format_str, self.version, self.boot_mode, @@ -225,14 +241,14 @@ class FirmwareVolumeHob: def __init__(self, base_address, img_offset, img_size): # header, uint64_t, uint64_t self.data_format_str = "2Q" - hob_length = struct.calcsize(self.data_format_str) + hob_length = struct_calcsize_with_endianness(self.data_format_str) self.header = HobGenericHeader(EFI_HOB_TYPE_FV, hob_length) self.format_str = self.header.format_str + self.data_format_str self.base_address = base_address + img_offset self.length = img_size - img_offset def pack(self): - return self.header.pack() + struct.pack( + return self.header.pack() + struct_pack_with_endianness( self.data_format_str, self.base_address, self.length ) @@ -301,8 +317,9 @@ def generate_ns_buffer_guid(mmram_desc): def generate_pei_mmram_memory_reserve_guid(regions): - # uint32t n_reserved regions, array of mmram descriptors - format_str = "I" + # uint32t n_reserved regions, 4 bytes for padding so that array is aligned, + # array of mmram descriptors + format_str = "I4x" data = [len(regions)] for desc_format_str, mmram_desc in regions: format_str += desc_format_str From 35530877967fd943186cd0afc895f71f0976bf23 Mon Sep 17 00:00:00 2001 From: Kathleen Capella Date: Thu, 13 Feb 2025 11:52:36 -0500 Subject: [PATCH 7/8] feat(sptool): add StMM memory region descriptor StandaloneMM partition requires that the first memory region in its list of reserved memory regions describe the full partition layout. Hafnium SPMC checks that memory regions in FF-A manifest do not overlap. Therefore, this region is added directly in HOB generation code rather than as a memory region in the FF-A manifest for the StMM partition. Signed-off-by: Kathleen Capella Change-Id: Ia22174d755a5776e20ecf9639584f3c08cf9e60e --- tools/sptool/hob.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/sptool/hob.py b/tools/sptool/hob.py index 9715f4015..dced08650 100644 --- a/tools/sptool/hob.py +++ b/tools/sptool/hob.py @@ -312,6 +312,13 @@ def generate_mmram_desc(base_addr, page_count, granule, region_state): return ("4Q", (physical_start, cpu_start, physical_size, region_state)) +def generate_stmm_region_descriptor(base_addr, physical_size): + region_state = STMM_MMRAM_REGION_STATE_DEFAULT + physical_start = base_addr + cpu_start = base_addr + return ("4Q", (physical_start, cpu_start, physical_size, region_state)) + + def generate_ns_buffer_guid(mmram_desc): return HobGuid(EfiGuid(*MM_NS_BUFFER_GUID), *mmram_desc) @@ -346,6 +353,12 @@ def generate_hob_from_fdt_node(sp_fdt, hob_offset, hob_size=None): if img_size is None: img_size = 0x0 + regions = [] + + # StMM requires the first memory region described in the + # MM_PEI_MMRAM_MEMORY_RESERVE_GUID describe the full partition layout. + regions.append(generate_stmm_region_descriptor(load_address, img_size)) + if sp_fdt.exist_node("memory-regions"): if sp_fdt.exist_property("xlat-granule"): granule = int(sp_fdt.get_property("xlat-granule").value) @@ -353,7 +366,6 @@ def generate_hob_from_fdt_node(sp_fdt, hob_offset, hob_size=None): # Default granule to 4K granule = 0 memory_regions = sp_fdt.get_node("memory-regions") - regions = [] for node in memory_regions.nodes: base_addr = get_integer_property_value(node, "base-address") page_count = get_integer_property_value(node, "pages-count") From dd816235771e19df1fd04ef2c6f1c6d11e429fd5 Mon Sep 17 00:00:00 2001 From: Kathleen Capella Date: Thu, 13 Feb 2025 17:34:21 -0600 Subject: [PATCH 8/8] fix(build): run sp_mk_gen.py with poetry If Poetry is available in the build environment, use Poetry when running sp_mk_gen.py script. This ensures dependencies that are needed to run the script are accounted for. Needed to successfully run the following config: spm-l2-boot-tests/fvp-default,fvp-spm-optee-sp,fvp-default: \ fvp-spm.optee.sp Change-Id: Icca4249dab929f1bcf5f4454d472cf6923e3ee17 Signed-off-by: Kathleen Capella --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4368279a2..4cba2b019 100644 --- a/Makefile +++ b/Makefile @@ -1658,7 +1658,8 @@ endif #(NEED_FDT) # Add Secure Partition packages ifeq (${NEED_SP_PKG},yes) $(BUILD_PLAT)/sp_gen.mk: ${SP_MK_GEN} ${SP_LAYOUT_FILE} | $$(@D)/ - $(q)${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT} ${SP_DTS_LIST_FRAGMENT} + $(if $(host-poetry),$(q)poetry -q install) + $(q)$(if $(host-poetry),poetry run )${PYTHON} "$<" "$@" $(filter-out $<,$^) $(BUILD_PLAT) ${COT} ${SP_DTS_LIST_FRAGMENT} sp: $(DTBS) $(BUILD_PLAT)/sp_gen.mk $(SP_PKGS) $(s)echo $(s)echo "Built SP Images successfully"