Merge "fix(rdv3): remove NEED_* from RD-V3 makefile" into integration
diff --git a/Makefile b/Makefile
index baf8431..2fc856a 100644
--- a/Makefile
+++ b/Makefile
@@ -121,6 +121,9 @@
SP_MK_GEN ?= ${SPTOOLPATH}/sp_mk_generator.py
SP_DTS_LIST_FRAGMENT ?= ${BUILD_PLAT}/sp_list_fragment.dts
+# Variables for use with Certificate Conversion (cot-dt2c) Tool
+CERTCONVPATH ?= tools/cot_dt2c
+
# Variables for use with ROMLIB
ROMLIBPATH ?= lib/romlib
@@ -1582,6 +1585,7 @@
clean:
$(s)echo " CLEAN"
$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
+ $(q)${MAKE} -C ${CERTCONVPATH} clean
ifdef UNIX_MK
$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
else
@@ -1597,6 +1601,7 @@
$(s)echo " REALCLEAN"
$(call SHELL_REMOVE_DIR,${BUILD_BASE})
$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
+ $(q)${MAKE} -C ${CERTCONVPATH} clean
ifdef UNIX_MK
$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
else
diff --git a/docs/components/cot-binding.rst b/docs/components/cot-binding.rst
index 702bb56..1d31e3d 100644
--- a/docs/components/cot-binding.rst
+++ b/docs/components/cot-binding.rst
@@ -138,7 +138,7 @@
trusted-key-cert: trusted-key-cert {
root-certificate;
image-id = <TRUSTED_KEY_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
trusted-world-pk: trusted-world-pk {
oid = TRUSTED_WORLD_PK_OID;
@@ -152,7 +152,7 @@
image-id = <SCP_FW_KEY_CERT_ID>;
parent = <&trusted-key-cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
scp_fw_content_pk: scp_fw_content_pk {
oid = SCP_FW_CONTENT_CERT_PK_OID;
@@ -312,13 +312,13 @@
#address-cells = <1>;
#size-cells = <0>;
- trusted-nv-counter: trusted_nv_counter {
+ trusted_nv_ctr: trusted_nv_ctr {
id = <TRUSTED_NV_CTR_ID>;
reg = <TFW_NVCTR_BASE>;
oid = TRUSTED_FW_NVCOUNTER_OID;
};
- non_trusted_nv_counter: non_trusted_nv_counter {
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
id = <NON_TRUSTED_NV_CTR_ID>;
reg = <NTFW_CTR_BASE>;
oid = NON_TRUSTED_FW_NVCOUNTER_OID;
diff --git a/docs/components/ffa-manifest-binding.rst b/docs/components/ffa-manifest-binding.rst
index ee322ac..29b89b2 100644
--- a/docs/components/ffa-manifest-binding.rst
+++ b/docs/components/ffa-manifest-binding.rst
@@ -1,5 +1,5 @@
FF-A manifest binding to device tree
-========================================
+====================================
This document defines the nodes and properties used to define a partition,
according to the FF-A specification.
@@ -82,7 +82,7 @@
the partition. Absence of this field indicates that the entry point is at
offset 0x0 from the base of the partition's binary.
-- xlat-granule [mandatory]
+- xlat-granule
- value type: <u32>
- Translation granule used with the partition:
@@ -91,10 +91,10 @@
- 0x2: 64k
- boot-order
- - value type: <u16>
+ - value type: <u32>
- A unique number amongst all partitions that specifies if this partition
must be booted before others. The partition with the smaller number will be
- booted first.
+ booted first. Highest vlue allowed for this field is 0xFFFF.
- rx-tx-buffer
- value type: "memory-regions" node
@@ -103,13 +103,15 @@
The "compatible" must be the string "arm,ffa-manifest-rx_tx-buffer".
- messaging-method [mandatory]
- - value type: <u8>
+ - value type: <u32>
- Specifies which messaging methods are supported by the partition, set bit
means the feature is supported, clear bit - not supported:
- - Bit[0]: partition can receive direct requests if set
- - Bit[1]: partition can send direct requests if set
+ - Bit[0]: partition can receive direct requests via FFA_MSG_SEND_DIRECT_REQ ABI if set
+ - Bit[1]: partition can send direct requests via FFA_MSG_SEND_DIRECT_REQ ABI if set
- Bit[2]: partition can send and receive indirect messages
+ - Bit[9]: partition can receive direct requests via FFA_MSG_SEND_DIRECT_REQ2 ABI if set
+ - Bit[10]: partition can send direct requests via FFA_MSG_SEND_DIRECT_REQ2 ABI if set
- managed-exit
- value type: <empty>
@@ -117,6 +119,11 @@
- This field is deprecated in favor of ns-interrupts-action field in the FF-A
v1.1 EAC0 spec.
+- managed-exit-virq
+ - value type: <empty>
+ - Indicates if the partition needs managed exit, if supported, to be signaled
+ through vFIQ signal.
+
- ns-interrupts-action [mandatory]
- value type: <u32>
- Specifies the action that the SPMC must take in response to a Non-secure
@@ -136,6 +143,12 @@
- 0x0: Other-Secure interrupt is queued
- 0x1: Other-Secure interrupt is signaled
+- runtime-model
+ - value type: <u32>
+ - Indicates whether the SP execution can be preempted.
+ - This field is deprecated in favor of other-s-interrupts-action and
+ ns-interrupts-action fields in the FF-A v1.1 spec.
+
- has-primary-scheduler
- value type: <empty>
- Presence of this field indicates that the partition implements the primary
@@ -157,11 +170,6 @@
the FF-A boot information blob to be passed in the specified general purpose
register.
-- stream-endpoint-ids
- - value type: <prop-encoded-array>
- - List of <u32> tuples, identifying the IDs this partition is acting as
- proxy for.
-
- power-management-messages
- value type: <u32>
- Specifies which power management messages a partition subscribes to.
@@ -172,6 +180,17 @@
- Bit[1]: CPU_SUSPEND
- Bit[2]: CPU_SUSPEND_RESUME
+- vm-availability-messages
+ - value type: <u32>
+ - Specifies which VM availability messages a partition subscribes to. A set
+ bit means the partition should be informed of the event, clear bit - should
+ not be informed of event:
+
+ - Bit[0]: VM created
+ - Bit[1]: VM destroyed
+
+.. _memory_region_node:
+
Memory Regions
--------------
@@ -209,6 +228,25 @@
then communicate the region properties (including the base address chosen
by the partition manager) to the partition.
+- stream-ids
+ - value type: <prop-encoded-array>
+ - List of IDs belonging to a DMA capable peripheral device that has access to
+ the memory region represented by current node.
+ - Each ID must have been declared in exactly one device region node.
+
+- smmu-id
+ - value type: <u32>
+ - Identifies the SMMU IP that enforces the access control for the DMA device
+ that owns the above stream-ids.
+
+- stream-ids-access-permissions
+ - value type: <prop-encoded-array>
+ - List of attributes representing the instruction and data access permissions
+ used by the DMA device streams to access the memory region represented by
+ current node.
+
+.. _device_region_node:
+
Device Regions
--------------
@@ -251,11 +289,10 @@
- stream-ids
- value type: <prop-encoded-array>
- - A list of (id, mem-manage) pair, where:
+ - List of IDs where an ID is a unique <u32> value amongst all devices assigned
+ to the partition.
- - id: A unique <u32> value amongst all devices assigned to the partition.
-
-- interrupts [mandatory]
+- interrupts
- value type: <prop-encoded-array>
- A list of (id, attributes) pair describing the device interrupts, where:
@@ -306,4 +343,4 @@
--------------
-*Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/secure-partition-manager.rst b/docs/components/secure-partition-manager.rst
index b6f4219..220c3ce 100644
--- a/docs/components/secure-partition-manager.rst
+++ b/docs/components/secure-partition-manager.rst
@@ -10,42 +10,12 @@
========
+--------+--------------------------------------+
-| CoT | Chain of Trust |
-+--------+--------------------------------------+
-| DMA | Direct Memory Access |
-+--------+--------------------------------------+
-| DTB | Device Tree Blob |
-+--------+--------------------------------------+
| DTS | Device Tree Source |
+--------+--------------------------------------+
-| EC | Execution Context |
-+--------+--------------------------------------+
-| FIP | Firmware Image Package |
-+--------+--------------------------------------+
| FF-A | Firmware Framework for Arm A-profile |
+--------+--------------------------------------+
-| IPA | Intermediate Physical Address |
-+--------+--------------------------------------+
-| JOP | Jump-Oriented Programming |
-+--------+--------------------------------------+
| NWd | Normal World |
+--------+--------------------------------------+
-| ODM | Original Design Manufacturer |
-+--------+--------------------------------------+
-| OEM | Original Equipment Manufacturer |
-+--------+--------------------------------------+
-| PA | Physical Address |
-+--------+--------------------------------------+
-| PE | Processing Element |
-+--------+--------------------------------------+
-| PM | Power Management |
-+--------+--------------------------------------+
-| PVM | Primary VM |
-+--------+--------------------------------------+
-| ROP | Return-Oriented Programming |
-+--------+--------------------------------------+
-| SMMU | System Memory Management Unit |
-+--------+--------------------------------------+
| SP | Secure Partition |
+--------+--------------------------------------+
| SPD | Secure Payload Dispatcher |
@@ -56,16 +26,8 @@
+--------+--------------------------------------+
| SPMD | SPM Dispatcher |
+--------+--------------------------------------+
-| SiP | Silicon Provider |
-+--------+--------------------------------------+
| SWd | Secure World |
+--------+--------------------------------------+
-| TLV | Tag-Length-Value |
-+--------+--------------------------------------+
-| TOS | Trusted Operating System |
-+--------+--------------------------------------+
-| VM | Virtual Machine |
-+--------+--------------------------------------+
Foreword
========
@@ -74,34 +36,14 @@
codebase:
#. S-EL2 SPMC based on the FF-A specification `[1]`_, enabling virtualization in
- the secure world, managing multiple S-EL1 or S-EL0 partitions.
+ the secure world, managing multiple S-EL1 or S-EL0 partitions `[5]`_.
#. EL3 SPMC based on the FF-A specification, managing a single S-EL1 partition
- without virtualization in the secure world.
+ without virtualization in the secure world `[6]`_.
#. EL3 SPM based on the MM specification, legacy implementation managing a
single S-EL0 partition `[2]`_.
These implementations differ in their respective SW architecture and only one
-can be selected at build time. This document:
-
-- describes the implementation from bullet 1. when the SPMC resides at S-EL2.
-- is not an architecture specification and it might provide assumptions
- on sections mandated as implementation-defined in the specification.
-- covers the implications to TF-A used as a bootloader, and Hafnium used as a
- reference code base for an S-EL2/SPMC secure firmware on platforms
- implementing the FEAT_SEL2 architecture extension.
-
-Terminology
------------
-
-- The term Hypervisor refers to the NS-EL2 component managing Virtual Machines
- (or partitions) in the normal world.
-- The term SPMC refers to the S-EL2 component managing secure partitions in
- the secure world when the FEAT_SEL2 architecture extension is implemented.
-- Alternatively, SPMC can refer to an S-EL1 component, itself being a secure
- partition and implementing the FF-A ABI on platforms not implementing the
- FEAT_SEL2 architecture extension.
-- The term VM refers to a normal world Virtual Machine managed by an Hypervisor.
-- The term SP refers to a secure world "Virtual Machine" managed by an SPMC.
+can be selected at build time.
Support for legacy platforms
----------------------------
@@ -123,16 +65,6 @@
- S-EL2 SPMC for platforms implementing the FEAT_SEL2 architecture
extension. The SPMD relays the FF-A protocol from EL3 to S-EL2.
-Sample reference stack
-======================
-
-The following diagram illustrates a possible configuration when the
-FEAT_SEL2 architecture extension is implemented, showing the SPMD
-and SPMC, one or multiple secure partitions, with an optional
-Hypervisor:
-
-.. image:: ../resources/diagrams/ff-a-spm-sel2.png
-
TF-A build options
==================
@@ -147,16 +79,15 @@
level to being at S-EL2. It defaults to enabled (value 1) when
SPD=spmd is chosen.
- **SPMC_AT_EL3**: this option adjusts the SPMC exception level to being
- at EL3.
-- If neither ``SPMD_SPM_AT_SEL2`` or ``SPMC_AT_EL3`` are enabled the SPMC
- exception level is set to S-EL1.
+ at EL3. If neither ``SPMD_SPM_AT_SEL2`` or ``SPMC_AT_EL3`` are enabled the
+ SPMC exception level is set to S-EL1.
``SPMD_SPM_AT_SEL2`` is enabled. The context save/restore routine
and exhaustive list of registers is visible at `[4]`_.
- **SPMC_AT_EL3_SEL0_SP**: this option enables the support to load SEL0 SP
when SPMC at EL3 support is enabled.
- **SP_LAYOUT_FILE**: this option specifies a text description file
providing paths to SP binary images and manifests in DTS format
- (see `Describing secure partitions`_). It
+ (see `[3]`_). It
is required when ``SPMD_SPM_AT_SEL2`` is enabled hence when multiple
secure partitions are to be loaded by BL2 on behalf of the SPMC.
@@ -275,1358 +206,28 @@
PLAT=fvp \
all fip
-FVP model invocation
-====================
-
-The FVP command line needs the following options to exercise the S-EL2 SPMC:
-
-+---------------------------------------------------+------------------------------------+
-| - cluster0.has_arm_v8-5=1 | Implements FEAT_SEL2, FEAT_PAuth, |
-| - cluster1.has_arm_v8-5=1 | and FEAT_BTI. |
-+---------------------------------------------------+------------------------------------+
-| - pci.pci_smmuv3.mmu.SMMU_AIDR=2 | Parameters required for the |
-| - pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B | SMMUv3.2 modeling. |
-| - pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 | |
-| - pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 | |
-| - pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0472 | |
-| - pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 | |
-| - pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 | |
-| - pci.pci_smmuv3.mmu.SMMU_S_IDR3=0 | |
-+---------------------------------------------------+------------------------------------+
-| - cluster0.has_branch_target_exception=1 | Implements FEAT_BTI. |
-| - cluster1.has_branch_target_exception=1 | |
-+---------------------------------------------------+------------------------------------+
-| - cluster0.has_pointer_authentication=2 | Implements FEAT_PAuth |
-| - cluster1.has_pointer_authentication=2 | |
-+---------------------------------------------------+------------------------------------+
-| - cluster0.memory_tagging_support_level=2 | Implements FEAT_MTE2 |
-| - cluster1.memory_tagging_support_level=2 | |
-| - bp.dram_metadata.is_enabled=1 | |
-+---------------------------------------------------+------------------------------------+
-
-Sample FVP command line invocation:
-
-.. code:: shell
-
- <path-to-fvp-model>/FVP_Base_RevC-2xAEMvA -C pctl.startup=0.0.0.0 \
- -C cluster0.NUM_CORES=4 -C cluster1.NUM_CORES=4 -C bp.secure_memory=1 \
- -C bp.secureflashloader.fname=trusted-firmware-a/build/fvp/debug/bl1.bin \
- -C bp.flashloader0.fname=trusted-firmware-a/build/fvp/debug/fip.bin \
- -C bp.pl011_uart0.out_file=fvp-uart0.log -C bp.pl011_uart1.out_file=fvp-uart1.log \
- -C bp.pl011_uart2.out_file=fvp-uart2.log \
- -C cluster0.has_arm_v8-5=1 -C cluster1.has_arm_v8-5=1 \
- -C cluster0.has_pointer_authentication=2 -C cluster1.has_pointer_authentication=2 \
- -C cluster0.has_branch_target_exception=1 -C cluster1.has_branch_target_exception=1 \
- -C cluster0.memory_tagging_support_level=2 -C cluster1.memory_tagging_support_level=2 \
- -C bp.dram_metadata.is_enabled=1 \
- -C pci.pci_smmuv3.mmu.SMMU_AIDR=2 -C pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B \
- -C pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 -C pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 \
- -C pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0472 -C pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 \
- -C pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 -C pci.pci_smmuv3.mmu.SMMU_S_IDR3=0
-
Boot process
============
-Loading Hafnium and secure partitions in the secure world
----------------------------------------------------------
-
-TF-A BL2 is the bootlader for the SPMC and SPs in the secure world.
-
-SPs may be signed by different parties (SiP, OEM/ODM, TOS vendor, etc.).
-Thus they are supplied as distinct signed entities within the FIP flash
-image. The FIP image itself is not signed hence this provides the ability
-to upgrade SPs in the field.
-
-Booting through TF-A
---------------------
-
-SP manifests
-~~~~~~~~~~~~
-
-An SP manifest describes SP attributes as defined in `[1]`_
-(partition manifest at virtual FF-A instance) in DTS format. It is
-represented as a single file associated with the SP. A sample is
-provided by `[5]`_. A binding document is provided by `[6]`_.
-
-Secure Partition packages
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Secure partitions are bundled as independent package files consisting
-of:
-
-- a header
-- a DTB
-- an image payload
-
-The header starts with a magic value and offset values to SP DTB and
-image payload. Each SP package is loaded independently by BL2 loader
-and verified for authenticity and integrity.
-
-The SP package identified by its UUID (matching FF-A uuid property) is
-inserted as a single entry into the FIP at end of the TF-A build flow
-as shown:
-
-.. code:: shell
-
- Trusted Boot Firmware BL2: offset=0x1F0, size=0x8AE1, cmdline="--tb-fw"
- EL3 Runtime Firmware BL31: offset=0x8CD1, size=0x13000, cmdline="--soc-fw"
- Secure Payload BL32 (Trusted OS): offset=0x1BCD1, size=0x15270, cmdline="--tos-fw"
- Non-Trusted Firmware BL33: offset=0x30F41, size=0x92E0, cmdline="--nt-fw"
- HW_CONFIG: offset=0x3A221, size=0x2348, cmdline="--hw-config"
- TB_FW_CONFIG: offset=0x3C569, size=0x37A, cmdline="--tb-fw-config"
- SOC_FW_CONFIG: offset=0x3C8E3, size=0x48, cmdline="--soc-fw-config"
- TOS_FW_CONFIG: offset=0x3C92B, size=0x427, cmdline="--tos-fw-config"
- NT_FW_CONFIG: offset=0x3CD52, size=0x48, cmdline="--nt-fw-config"
- B4B5671E-4A90-4FE1-B81F-FB13DAE1DACB: offset=0x3CD9A, size=0xC168, cmdline="--blob"
- D1582309-F023-47B9-827C-4464F5578FC8: offset=0x48F02, size=0xC168, cmdline="--blob"
-
-.. uml:: ../resources/diagrams/plantuml/fip-secure-partitions.puml
-
-Describing secure partitions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A json-formatted description file is passed to the build flow specifying paths
-to the SP binary image and associated DTS partition manifest file. The latter
-is processed by the dtc compiler to generate a DTB fed into the SP package.
-Optionally, the partition's json description can contain offsets for both
-the image and partition manifest within the SP package. Both offsets need to be
-4KB aligned, because it is the translation granule supported by Hafnium SPMC.
-These fields can be leveraged to support SPs with S1 translation granules that
-differ from 4KB, and to configure the regions allocated within the SP package,
-as well as to comply with the requirements for the implementation of the boot
-information protocol (see `Passing boot data to the SP`_ for more details). In
-case the offsets are absent in their json node, they default to 0x1000 and
-0x4000 for the manifest offset and image offset respectively.
-This file also specifies the SP owner (as an optional field) identifying the
-signing domain in case of dual root CoT.
-The SP owner can either be the silicon or the platform provider. The
-corresponding "owner" field value can either take the value of "SiP" or "Plat".
-In absence of "owner" field, it defaults to "SiP" owner.
-The UUID of the partition can be specified as a field in the description file or
-if it does not exist there the UUID is extracted from the DTS partition
-manifest.
-
-.. code:: shell
-
- {
- "tee1" : {
- "image": "tee1.bin",
- "pm": "tee1.dts",
- "owner": "SiP",
- "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
- },
-
- "tee2" : {
- "image": "tee2.bin",
- "pm": "tee2.dts",
- "owner": "Plat"
- },
-
- "tee3" : {
- "image": {
- "file": "tee3.bin",
- "offset":"0x2000"
- },
- "pm": {
- "file": "tee3.dts",
- "offset":"0x6000"
- },
- "owner": "Plat"
- },
- }
-
-SPMC manifest
-~~~~~~~~~~~~~
-
-This manifest contains the SPMC *attribute* node consumed by the SPMD at boot
-time. It implements `[1]`_ (SP manifest at physical FF-A instance) and serves
-two different cases:
-
-- The SPMC resides at S-EL1: the SPMC manifest is used by the SPMD to setup a
- SP that co-resides with the SPMC and executes at S-EL1 or Secure Supervisor
- mode.
-- The SPMC resides at S-EL2: the SPMC manifest is used by the SPMD to setup
- the environment required by the SPMC to run at S-EL2. SPs run at S-EL1 or
- S-EL0.
-
-.. code:: shell
-
- attribute {
- spmc_id = <0x8000>;
- maj_ver = <0x1>;
- min_ver = <0x1>;
- exec_state = <0x0>;
- load_address = <0x0 0x6000000>;
- entrypoint = <0x0 0x6000000>;
- binary_size = <0x60000>;
- };
-
-- *spmc_id* defines the endpoint ID value that SPMC can query through
- ``FFA_ID_GET``.
-- *maj_ver/min_ver*. SPMD checks provided version versus its internal
- version and aborts if not matching.
-- *exec_state* defines the SPMC execution state (AArch64 or AArch32).
- Notice Hafnium used as a SPMC only supports AArch64.
-- *load_address* and *binary_size* are mostly used to verify secondary
- entry points fit into the loaded binary image.
-- *entrypoint* defines the cold boot primary core entry point used by
- SPMD (currently matches ``BL32_BASE``) to enter the SPMC.
-
-Other nodes in the manifest are consumed by Hafnium in the secure world.
-A sample can be found at `[7]`_:
-
-- The *hypervisor* node describes SPs. *is_ffa_partition* boolean attribute
- indicates a FF-A compliant SP. The *load_address* field specifies the load
- address at which BL2 loaded the SP package.
-- *cpus* node provide the platform topology and allows MPIDR to VMPIDR mapping.
- Note the primary core is declared first, then secondary cores are declared
- in reverse order.
-- The *memory* nodes provide platform information on the ranges of memory
- available for use by SPs at runtime. These ranges relate to either
- secure or non-secure memory, depending on the *device_type* field.
- If the field specifies "memory" the range is secure, else if it specifies
- "ns-memory" the memory is non-secure. The system integrator must exclude
- the memory used by other components that are not SPs, such as the monitor,
- or the SPMC itself, the OS Kernel/Hypervisor, or other NWd VMs. The SPMC
- limits the SP's address space such that they do not access memory outside
- of those ranges.
+The boot process involving SPMC is highly dependent on the SPMC implementation.
+It is recommended to refer to corresponding SPMC documentation for further
+details. Some aspects of boot process are described here in the greater interest
+of the project.
SPMC boot
-~~~~~~~~~
+---------
-The SPMC is loaded by BL2 as the BL32 image.
+When SPMC resides at a lower EL i.e., S-EL1 or S-EL2, it is loaded by BL2 as the
+BL32 image. The SPMC manifest is loaded by BL2 as the ``TOS_FW_CONFIG`` image `[7]`_.
-The SPMC manifest is loaded by BL2 as the ``TOS_FW_CONFIG`` image `[9]`_.
-
-BL2 passes the SPMC manifest address to BL31 through a register.
-
-At boot time, the SPMD in BL31 runs from the primary core, initializes the core
-contexts and launches the SPMC (BL32) passing the following information through
-registers:
+BL2 passes the SPMC manifest address to BL31 through a register. At boot time,
+the SPMD in BL31 runs from the primary core, initializes the core contexts and
+launches the SPMC (BL32) passing the following information through registers:
- X0 holds the ``TOS_FW_CONFIG`` physical address (or SPMC manifest blob).
- X1 holds the ``HW_CONFIG`` physical address.
- X4 holds the currently running core linear id.
-Loading of SPs
-~~~~~~~~~~~~~~
-
-At boot time, BL2 loads SPs sequentially in addition to the SPMC as depicted
-below:
-
-.. uml:: ../resources/diagrams/plantuml/bl2-loading-sp.puml
-
-Note this boot flow is an implementation sample on Arm's FVP platform.
-Platforms not using TF-A's *Firmware CONFiguration* framework would adjust to a
-different boot flow. The flow restricts to a maximum of 8 secure partitions.
-
-Secure boot
-~~~~~~~~~~~
-
-The SP content certificate is inserted as a separate FIP item so that BL2 loads SPMC,
-SPMC manifest, secure partitions and verifies them for authenticity and integrity.
-Refer to TBBR specification `[3]`_.
-
-The multiple-signing domain feature (in current state dual signing domain `[8]`_) allows
-the use of two root keys namely S-ROTPK and NS-ROTPK:
-
-- SPMC (BL32) and SPMC manifest are signed by the SiP using the S-ROTPK.
-- BL33 may be signed by the OEM using NS-ROTPK.
-- An SP may be signed either by SiP (using S-ROTPK) or by OEM (using NS-ROTPK).
-- A maximum of 4 partitions can be signed with the S-ROTPK key and 4 partitions
- signed with the NS-ROTPK key.
-
-Also refer to `Describing secure partitions`_ and `TF-A build options`_ sections.
-
-Hafnium in the secure world
-===========================
-
-General considerations
-----------------------
-
-Build platform for the secure world
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In the Hafnium reference implementation specific code parts are only relevant to
-the secure world. Such portions are isolated in architecture specific files
-and/or enclosed by a ``SECURE_WORLD`` macro.
-
-Secure partitions scheduling
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The FF-A specification `[1]`_ provides two ways to relinquinsh CPU time to
-secure partitions. For this a VM (Hypervisor or OS kernel), or SP invokes one of:
-
-- the FFA_MSG_SEND_DIRECT_REQ interface.
-- the FFA_RUN interface.
-
-Additionally a secure interrupt can pre-empt the normal world execution and give
-CPU cycles by transitioning to EL3 and S-EL2.
-
-Platform topology
-~~~~~~~~~~~~~~~~~
-
-The *execution-ctx-count* SP manifest field can take the value of one or the
-total number of PEs. The FF-A specification `[1]`_ recommends the
-following SP types:
-
-- Pinned MP SPs: an execution context matches a physical PE. MP SPs must
- implement the same number of ECs as the number of PEs in the platform.
-- Migratable UP SPs: a single execution context can run and be migrated on any
- physical PE. Such SP declares a single EC in its SP manifest. An UP SP can
- receive a direct message request originating from any physical core targeting
- the single execution context.
-
-Parsing SP partition manifests
-------------------------------
-
-Hafnium consumes SP manifests as defined in `[1]`_ and `SP manifests`_.
-Note the current implementation may not implement all optional fields.
-
-The SP manifest may contain memory and device regions nodes. In case of
-an S-EL2 SPMC:
-
-- Memory regions are mapped in the SP EL1&0 Stage-2 translation regime at
- load time (or EL1&0 Stage-1 for an S-EL1 SPMC). A memory region node can
- specify RX/TX buffer regions in which case it is not necessary for an SP
- to explicitly invoke the ``FFA_RXTX_MAP`` interface. The memory referred
- shall be contained within the memory ranges defined in SPMC manifest. The
- NS bit in the attributes field should be consistent with the security
- state of the range that it relates to. I.e. non-secure memory shall be
- part of a non-secure memory range, and secure memory shall be contained
- in a secure memory range of a given platform.
-- Device regions are mapped in the SP EL1&0 Stage-2 translation regime (or
- EL1&0 Stage-1 for an S-EL1 SPMC) as peripherals and possibly allocate
- additional resources (e.g. interrupts).
-
-For the S-EL2 SPMC, base addresses for memory and device region nodes are IPAs
-provided the SPMC identity maps IPAs to PAs within SP EL1&0 Stage-2 translation
-regime.
-
-Note: in the current implementation both VTTBR_EL2 and VSTTBR_EL2 point to the
-same set of page tables. It is still open whether two sets of page tables shall
-be provided per SP. The memory region node as defined in the specification
-provides a memory security attribute hinting to map either to the secure or
-non-secure EL1&0 Stage-2 table if it exists.
-
-Passing boot data to the SP
----------------------------
-
-In `[1]`_ , the section "Boot information protocol" defines a method for passing
-data to the SPs at boot time. It specifies the format for the boot information
-descriptor and boot information header structures, which describe the data to be
-exchanged between SPMC and SP.
-The specification also defines the types of data that can be passed.
-The aggregate of both the boot info structures and the data itself is designated
-the boot information blob, and is passed to a Partition as a contiguous memory
-region.
-
-Currently, the SPM implementation supports the FDT type which is used to pass the
-partition's DTB manifest.
-
-The region for the boot information blob is allocated through the SP package.
-
-.. image:: ../resources/diagrams/partition-package.png
-
-To adjust the space allocated for the boot information blob, the json description
-of the SP (see section `Describing secure partitions`_) shall be updated to contain
-the manifest offset. If no offset is provided the manifest offset defaults to 0x1000,
-which is the page size in the Hafnium SPMC.
-
-The configuration of the boot protocol is done in the SPs manifest. As defined by
-the specification, the manifest field 'gp-register-num' configures the GP register
-which shall be used to pass the address to the partitions boot information blob when
-booting the partition.
-In addition, the Hafnium SPMC implementation requires the boot information arguments
-to be listed in a designated DT node:
-
-.. code:: shell
-
- boot-info {
- compatible = "arm,ffa-manifest-boot-info";
- ffa_manifest;
- };
-
-The whole secure partition package image (see `Secure Partition packages`_) is
-mapped to the SP secure EL1&0 Stage-2 translation regime. As such, the SP can
-retrieve the address for the boot information blob in the designated GP register,
-process the boot information header and descriptors, access its own manifest
-DTB blob and extract its partition manifest properties.
-
-SP Boot order
--------------
-
-SP manifests provide an optional boot order attribute meant to resolve
-dependencies such as an SP providing a service required to properly boot
-another SP. SPMC boots the SPs in accordance to the boot order attribute,
-lowest to the highest value. If the boot order attribute is absent from the FF-A
-manifest, the SP is treated as if it had the highest boot order value
-(i.e. lowest booting priority).
-
-It is possible for an SP to call into another SP through a direct request
-provided the latter SP has already been booted.
-
-Boot phases
------------
-
-Primary core boot-up
-~~~~~~~~~~~~~~~~~~~~
-
-Upon boot-up, BL31 hands over to the SPMC (BL32) on the primary boot physical
-core. The SPMC performs its platform initializations and registers the SPMC
-secondary physical core entry point physical address by the use of the
-`FFA_SECONDARY_EP_REGISTER`_ interface (SMC invocation from the SPMC to the SPMD
-at secure physical FF-A instance).
-
-The SPMC then creates secure partitions based on SP packages and manifests. Each
-secure partition is launched in sequence (`SP Boot order`_) on their "primary"
-execution context. If the primary boot physical core linear id is N, an MP SP is
-started using EC[N] on PE[N] (see `Platform topology`_). If the partition is a
-UP SP, it is started using its unique EC0 on PE[N].
-
-The SP primary EC (or the EC used when the partition is booted as described
-above):
-
-- Performs the overall SP boot time initialization, and in case of a MP SP,
- prepares the SP environment for other execution contexts.
-- In the case of a MP SP, it invokes the FFA_SECONDARY_EP_REGISTER at secure
- virtual FF-A instance (SMC invocation from SP to SPMC) to provide the IPA
- entry point for other execution contexts.
-- Exits through ``FFA_MSG_WAIT`` to indicate successful initialization or
- ``FFA_ERROR`` in case of failure.
-
-Secondary cores boot-up
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Once the system is started and NWd brought up, a secondary physical core is
-woken up by the ``PSCI_CPU_ON`` service invocation. The TF-A SPD hook mechanism
-calls into the SPMD on the newly woken up physical core. Then the SPMC is
-entered at the secondary physical core entry point.
-
-In the current implementation, the first SP is resumed on the coresponding EC
-(the virtual CPU which matches the physical core). The implication is that the
-first SP must be a MP SP.
-
-In a linux based system, once secure and normal worlds are booted but prior to
-a NWd FF-A driver has been loaded:
-
-- The first SP has initialized all its ECs in response to primary core boot up
- (at system initialization) and secondary core boot up (as a result of linux
- invoking PSCI_CPU_ON for all secondary cores).
-- Other SPs have their first execution context initialized as a result of secure
- world initialization on the primary boot core. Other ECs for those SPs have to
- be run first through ffa_run to complete their initialization (which results
- in the EC completing with FFA_MSG_WAIT).
-
-Refer to `Power management`_ for further details.
-
-Notifications
--------------
-
-The FF-A v1.1 specification `[1]`_ defines notifications as an asynchronous
-communication mechanism with non-blocking semantics. It allows for one FF-A
-endpoint to signal another for service provision, without hindering its current
-progress.
-
-Hafnium currently supports 64 notifications. The IDs of each notification define
-a position in a 64-bit bitmap.
-
-The signaling of notifications can interchangeably happen between NWd and SWd
-FF-A endpoints.
-
-The SPMC is in charge of managing notifications from SPs to SPs, from SPs to
-VMs, and from VMs to SPs. An hypervisor component would only manage
-notifications from VMs to VMs. Given the SPMC has no visibility of the endpoints
-deployed in NWd, the Hypervisor or OS kernel must invoke the interface
-FFA_NOTIFICATION_BITMAP_CREATE to allocate the notifications bitmap per FF-A
-endpoint in the NWd that supports it.
-
-A sender can signal notifications once the receiver has provided it with
-permissions. Permissions are provided by invoking the interface
-FFA_NOTIFICATION_BIND.
-
-Notifications are signaled by invoking FFA_NOTIFICATION_SET. Henceforth
-they are considered to be in a pending sate. The receiver can retrieve its
-pending notifications invoking FFA_NOTIFICATION_GET, which, from that moment,
-are considered to be handled.
-
-Per the FF-A v1.1 spec, each FF-A endpoint must be associated with a scheduler
-that is in charge of donating CPU cycles for notifications handling. The
-FF-A driver calls FFA_NOTIFICATION_INFO_GET to retrieve the information about
-which FF-A endpoints have pending notifications. The receiver scheduler is
-called and informed by the FF-A driver, and it should allocate CPU cycles to the
-receiver.
-
-There are two types of notifications supported:
-
-- Global, which are targeted to a FF-A endpoint and can be handled within any of
- its execution contexts, as determined by the scheduler of the system.
-- Per-vCPU, which are targeted to a FF-A endpoint and to be handled within a
- a specific execution context, as determined by the sender.
-
-The type of a notification is set when invoking FFA_NOTIFICATION_BIND to give
-permissions to the sender.
-
-Notification signaling resorts to two interrupts:
-
-- Schedule Receiver Interrupt: non-secure physical interrupt to be handled by
- the FF-A driver within the receiver scheduler. At initialization the SPMC
- donates a SGI ID chosen from the secure SGI IDs range and configures it as
- non-secure. The SPMC triggers this SGI on the currently running core when
- there are pending notifications, and the respective receivers need CPU cycles
- to handle them.
-- Notifications Pending Interrupt: virtual interrupt to be handled by the
- receiver of the notification. Set when there are pending notifications for the
- given secure partition. The NPI is pended when the NWd relinquishes CPU cycles
- to an SP.
-
-The notifications receipt support is enabled in the partition FF-A manifest.
-
-Mandatory interfaces
---------------------
-
-The following interfaces are exposed to SPs:
-
-- ``FFA_VERSION``
-- ``FFA_FEATURES``
-- ``FFA_RX_RELEASE``
-- ``FFA_RXTX_MAP``
-- ``FFA_RXTX_UNMAP``
-- ``FFA_PARTITION_INFO_GET``
-- ``FFA_ID_GET``
-- ``FFA_MSG_WAIT``
-- ``FFA_MSG_SEND_DIRECT_REQ``
-- ``FFA_MSG_SEND_DIRECT_RESP``
-- ``FFA_MEM_DONATE``
-- ``FFA_MEM_LEND``
-- ``FFA_MEM_SHARE``
-- ``FFA_MEM_RETRIEVE_REQ``
-- ``FFA_MEM_RETRIEVE_RESP``
-- ``FFA_MEM_RELINQUISH``
-- ``FFA_MEM_FRAG_RX``
-- ``FFA_MEM_FRAG_TX``
-- ``FFA_MEM_RECLAIM``
-- ``FFA_RUN``
-
-As part of the FF-A v1.1 support, the following interfaces were added:
-
- - ``FFA_NOTIFICATION_BITMAP_CREATE``
- - ``FFA_NOTIFICATION_BITMAP_DESTROY``
- - ``FFA_NOTIFICATION_BIND``
- - ``FFA_NOTIFICATION_UNBIND``
- - ``FFA_NOTIFICATION_SET``
- - ``FFA_NOTIFICATION_GET``
- - ``FFA_NOTIFICATION_INFO_GET``
- - ``FFA_SPM_ID_GET``
- - ``FFA_SECONDARY_EP_REGISTER``
- - ``FFA_MEM_PERM_GET``
- - ``FFA_MEM_PERM_SET``
- - ``FFA_MSG_SEND2``
- - ``FFA_RX_ACQUIRE``
-
-FFA_VERSION
-~~~~~~~~~~~
-
-``FFA_VERSION`` requires a *requested_version* parameter from the caller.
-The returned value depends on the caller:
-
-- Hypervisor or OS kernel in NS-EL1/EL2: the SPMD returns the SPMC version
- specified in the SPMC manifest.
-- SP: the SPMC returns its own implemented version.
-- SPMC at S-EL1/S-EL2: the SPMD returns its own implemented version.
-
-FFA_FEATURES
-~~~~~~~~~~~~
-
-FF-A features supported by the SPMC may be discovered by secure partitions at
-boot (that is prior to NWd is booted) or run-time.
-
-The SPMC calling FFA_FEATURES at secure physical FF-A instance always get
-FFA_SUCCESS from the SPMD.
-
-The request made by an Hypervisor or OS kernel is forwarded to the SPMC and
-the response relayed back to the NWd.
-
-FFA_RXTX_MAP/FFA_RXTX_UNMAP
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When invoked from a secure partition FFA_RXTX_MAP maps the provided send and
-receive buffers described by their IPAs to the SP EL1&0 Stage-2 translation
-regime as secure buffers in the MMU descriptors.
-
-When invoked from the Hypervisor or OS kernel, the buffers are mapped into the
-SPMC EL2 Stage-1 translation regime and marked as NS buffers in the MMU
-descriptors. The provided addresses may be owned by a VM in the normal world,
-which is expected to receive messages from the secure world. The SPMC will in
-this case allocate internal state structures to facilitate RX buffer access
-synchronization (through FFA_RX_ACQUIRE interface), and to permit SPs to send
-messages.
-
-The FFA_RXTX_UNMAP unmaps the RX/TX pair from the translation regime of the
-caller, either it being the Hypervisor or OS kernel, as well as a secure
-partition.
-
-FFA_PARTITION_INFO_GET
-~~~~~~~~~~~~~~~~~~~~~~
-
-Partition info get call can originate:
-
-- from SP to SPMC
-- from Hypervisor or OS kernel to SPMC. The request is relayed by the SPMD.
-
-FFA_ID_GET
-~~~~~~~~~~
-
-The FF-A id space is split into a non-secure space and secure space:
-
-- FF-A ID with bit 15 clear relates to VMs.
-- FF-A ID with bit 15 set related to SPs.
-- FF-A IDs 0, 0xffff, 0x8000 are assigned respectively to the Hypervisor, SPMD
- and SPMC.
-
-The SPMD returns:
-
-- The default zero value on invocation from the Hypervisor.
-- The ``spmc_id`` value specified in the SPMC manifest on invocation from
- the SPMC (see `SPMC manifest`_)
-
-This convention helps the SPMC to determine the origin and destination worlds in
-an FF-A ABI invocation. In particular the SPMC shall filter unauthorized
-transactions in its world switch routine. It must not be permitted for a VM to
-use a secure FF-A ID as origin world by spoofing:
-
-- A VM-to-SP direct request/response shall set the origin world to be non-secure
- (FF-A ID bit 15 clear) and destination world to be secure (FF-A ID bit 15
- set).
-- Similarly, an SP-to-SP direct request/response shall set the FF-A ID bit 15
- for both origin and destination IDs.
-
-An incoming direct message request arriving at SPMD from NWd is forwarded to
-SPMC without a specific check. The SPMC is resumed through eret and "knows" the
-message is coming from normal world in this specific code path. Thus the origin
-endpoint ID must be checked by SPMC for being a normal world ID.
-
-An SP sending a direct message request must have bit 15 set in its origin
-endpoint ID and this can be checked by the SPMC when the SP invokes the ABI.
-
-The SPMC shall reject the direct message if the claimed world in origin endpoint
-ID is not consistent:
-
-- It is either forwarded by SPMD and thus origin endpoint ID must be a "normal
- world ID",
-- or initiated by an SP and thus origin endpoint ID must be a "secure world ID".
-
-
-FFA_MSG_SEND_DIRECT_REQ/FFA_MSG_SEND_DIRECT_RESP
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This is a mandatory interface for secure partitions consisting in direct request
-and responses with the following rules:
-
-- An SP can send a direct request to another SP.
-- An SP can receive a direct request from another SP.
-- An SP can send a direct response to another SP.
-- An SP cannot send a direct request to an Hypervisor or OS kernel.
-- An Hypervisor or OS kernel can send a direct request to an SP.
-- An SP can send a direct response to an Hypervisor or OS kernel.
-
-FFA_NOTIFICATION_BITMAP_CREATE/FFA_NOTIFICATION_BITMAP_DESTROY
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The secure partitions notifications bitmap are statically allocated by the SPMC.
-Hence, this interface is not to be issued by secure partitions.
-
-At initialization, the SPMC is not aware of VMs/partitions deployed in the
-normal world. Hence, the Hypervisor or OS kernel must use both ABIs for SPMC
-to be prepared to handle notifications for the provided VM ID.
-
-FFA_NOTIFICATION_BIND/FFA_NOTIFICATION_UNBIND
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Pair of interfaces to manage permissions to signal notifications. Prior to
-handling notifications, an FF-A endpoint must allow a given sender to signal a
-bitmap of notifications.
-
-If the receiver doesn't have notification support enabled in its FF-A manifest,
-it won't be able to bind notifications, hence forbidding it to receive any
-notifications.
-
-FFA_NOTIFICATION_SET/FFA_NOTIFICATION_GET
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-FFA_NOTIFICATION_GET retrieves all pending global notifications and
-per-vCPU notifications targeted to the current vCPU.
-
-Hafnium maintains a global count of pending notifications which gets incremented
-and decremented when handling FFA_NOTIFICATION_SET and FFA_NOTIFICATION_GET
-respectively. A delayed SRI is triggered if the counter is non-zero when the
-SPMC returns to normal world.
-
-FFA_NOTIFICATION_INFO_GET
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Hafnium maintains a global count of pending notifications whose information
-has been retrieved by this interface. The count is incremented and decremented
-when handling FFA_NOTIFICATION_INFO_GET and FFA_NOTIFICATION_GET respectively.
-It also tracks notifications whose information has been retrieved individually,
-such that it avoids duplicating returned information for subsequent calls to
-FFA_NOTIFICATION_INFO_GET. For each notification, this state information is
-reset when receiver called FFA_NOTIFICATION_GET to retrieve them.
-
-FFA_SPM_ID_GET
-~~~~~~~~~~~~~~
-
-Returns the FF-A ID allocated to an SPM component which can be one of SPMD
-or SPMC.
-
-At initialization, the SPMC queries the SPMD for the SPMC ID, using the
-FFA_ID_GET interface, and records it. The SPMC can also query the SPMD ID using
-the FFA_SPM_ID_GET interface at the secure physical FF-A instance.
-
-Secure partitions call this interface at the virtual FF-A instance, to which
-the SPMC returns the priorly retrieved SPMC ID.
-
-The Hypervisor or OS kernel can issue the FFA_SPM_ID_GET call handled by the
-SPMD, which returns the SPMC ID.
-
-FFA_SECONDARY_EP_REGISTER
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When the SPMC boots, all secure partitions are initialized on their primary
-Execution Context.
-
-The FFA_SECONDARY_EP_REGISTER interface is to be used by a secure partition
-from its first execution context, to provide the entry point address for
-secondary execution contexts.
-
-A secondary EC is first resumed either upon invocation of PSCI_CPU_ON from
-the NWd or by invocation of FFA_RUN.
-
-FFA_RX_ACQUIRE/FFA_RX_RELEASE
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The RX buffers can be used to pass information to an FF-A endpoint in the
-following scenarios:
-
- - When it was targetted by a FFA_MSG_SEND2 invokation from another endpoint.
- - Return the result of calling ``FFA_PARTITION_INFO_GET``.
- - In a memory share operation, as part of the ``FFA_MEM_RETRIEVE_RESP``,
- with the memory descriptor of the shared memory.
-
-If a normal world VM is expected to exchange messages with secure world,
-its RX/TX buffer addresses are forwarded to the SPMC via FFA_RXTX_MAP ABI,
-and are from this moment owned by the SPMC.
-The hypervisor must call the FFA_RX_ACQUIRE interface before attempting
-to use the RX buffer, in any of the aforementioned scenarios. A successful
-call to FFA_RX_ACQUIRE transfers ownership of RX buffer to hypervisor, such
-that it can be safely used.
-
-The FFA_RX_RELEASE interface is used after the FF-A endpoint is done with
-processing the data received in its RX buffer. If the RX buffer has been
-acquired by the hypervisor, the FFA_RX_RELEASE call must be forwarded to
-the SPMC to reestablish SPMC's RX ownership.
-
-An attempt from an SP to send a message to a normal world VM whose RX buffer
-was acquired by the hypervisor fails with error code FFA_BUSY, to preserve
-the RX buffer integrity.
-The operation could then be conducted after FFA_RX_RELEASE.
-
-FFA_MSG_SEND2
-~~~~~~~~~~~~~
-
-Hafnium copies a message from the sender TX buffer into receiver's RX buffer.
-For messages from SPs to VMs, operation is only possible if the SPMC owns
-the receiver's RX buffer.
-
-Both receiver and sender need to enable support for indirect messaging,
-in their respective partition manifest. The discovery of support
-of such feature can be done via FFA_PARTITION_INFO_GET.
-
-On a successful message send, Hafnium pends an RX buffer full framework
-notification for the receiver, to inform it about a message in the RX buffer.
-
-The handling of framework notifications is similar to that of
-global notifications. Binding of these is not necessary, as these are
-reserved to be used by the hypervisor or SPMC.
-
-SPMC-SPMD direct requests/responses
------------------------------------
-
-Implementation-defined FF-A IDs are allocated to the SPMC and SPMD.
-Using those IDs in source/destination fields of a direct request/response
-permits SPMD to SPMC communication and either way.
-
-- SPMC to SPMD direct request/response uses SMC conduit.
-- SPMD to SPMC direct request/response uses ERET conduit.
-
-This is used in particular to convey power management messages.
-
-Memory Sharing
---------------
-
-Hafnium implements the following memory sharing interfaces:
-
- - ``FFA_MEM_SHARE`` - for shared access between lender and borrower.
- - ``FFA_MEM_LEND`` - borrower to obtain exclusive access, though lender
- retains ownership of the memory.
- - ``FFA_MEM_DONATE`` - lender permanently relinquishes ownership of memory
- to the borrower.
-
-The ``FFA_MEM_RETRIEVE_REQ`` interface is for the borrower to request the
-memory to be mapped into its address space: for S-EL1 partitions the SPM updates
-their stage 2 translation regime; for S-EL0 partitions the SPM updates their
-stage 1 translation regime. On a successful call, the SPMC responds back with
-``FFA_MEM_RETRIEVE_RESP``.
-
-The ``FFA_MEM_RELINQUISH`` interface is for when the borrower is done with using
-a memory region.
-
-The ``FFA_MEM_RECLAIM`` interface is for the owner of the memory to reestablish
-its ownership and exclusive access to the memory shared.
-
-The memory transaction descriptors are transmitted via RX/TX buffers. In
-situations where the size of the memory transaction descriptor exceeds the
-size of the RX/TX buffers, Hafnium provides support for fragmented transmission
-of the full transaction descriptor. The ``FFA_MEM_FRAG_RX`` and ``FFA_MEM_FRAG_TX``
-interfaces are for receiving and transmitting the next fragment, respectively.
-
-If lender and borrower(s) are SPs, all memory sharing operations are supported.
-
-Hafnium also supports memory sharing operations between the normal world and the
-secure world. If there is an SP involved, the SPMC allocates data to track the
-state of the operation.
-
-The SPMC is also the designated allocator for the memory handle. The hypervisor
-or OS kernel has the possibility to rely on the SPMC to maintain the state
-of the operation, thus saving memory.
-A lender SP can only donate NS memory to a borrower from the normal world.
-
-The SPMC supports the hypervisor retrieve request, as defined by the FF-A
-v1.1 EAC0 specification, in section 16.4.3. The intent is to aid with operations
-that the hypervisor must do for a VM retriever. For example, when handling
-an FFA_MEM_RECLAIM, if the hypervisor relies on SPMC to keep the state
-of the operation, the hypervisor retrieve request can be used to obtain
-that state information, do the necessary validations, and update stage 2
-memory translation.
-
-Hafnium also supports memory lend and share targetting multiple borrowers.
-This is the case for a lender SP to multiple SPs, and for a lender VM to
-multiple endpoints (from both secure world and normal world). If there is
-at least one borrower VM, the hypervisor is in charge of managing its
-stage 2 translation on a successful memory retrieve.
-The semantics of ``FFA_MEM_DONATE`` implies ownership transmission,
-which should target only one partition.
-
-The memory share interfaces are backwards compatible with memory transaction
-descriptors from FF-A v1.0. These get translated to FF-A v1.1 descriptors for
-Hafnium's internal processing of the operation. If the FF-A version of a
-borrower is v1.0, Hafnium provides FF-A v1.0 compliant memory transaction
-descriptors on memory retrieve response.
-
-PE MMU configuration
---------------------
-
-With secure virtualization enabled (``HCR_EL2.VM = 1``) and for S-EL1
-partitions, two IPA spaces (secure and non-secure) are output from the
-secure EL1&0 Stage-1 translation.
-The EL1&0 Stage-2 translation hardware is fed by:
-
-- A secure IPA when the SP EL1&0 Stage-1 MMU is disabled.
-- One of secure or non-secure IPA when the secure EL1&0 Stage-1 MMU is enabled.
-
-``VTCR_EL2`` and ``VSTCR_EL2`` provide configuration bits for controlling the
-NS/S IPA translations. The following controls are set up:
-``VSTCR_EL2.SW = 0`` , ``VSTCR_EL2.SA = 0``, ``VTCR_EL2.NSW = 0``,
-``VTCR_EL2.NSA = 1``:
-
-- Stage-2 translations for the NS IPA space access the NS PA space.
-- Stage-2 translation table walks for the NS IPA space are to the secure PA space.
-
-Secure and non-secure IPA regions (rooted to by ``VTTBR_EL2`` and ``VSTTBR_EL2``)
-use the same set of Stage-2 page tables within a SP.
-
-The ``VTCR_EL2/VSTCR_EL2/VTTBR_EL2/VSTTBR_EL2`` virtual address space
-configuration is made part of a vCPU context.
-
-For S-EL0 partitions with VHE enabled, a single secure EL2&0 Stage-1 translation
-regime is used for both Hafnium and the partition.
-
-Schedule modes and SP Call chains
----------------------------------
-
-An SP execution context is said to be in SPMC scheduled mode if CPU cycles are
-allocated to it by SPMC. Correspondingly, an SP execution context is said to be
-in Normal world scheduled mode if CPU cycles are allocated by the normal world.
-
-A call chain represents all SPs in a sequence of invocations of a direct message
-request. When execution on a PE is in the secure state, only a single call chain
-that runs in the Normal World scheduled mode can exist. FF-A v1.1 spec allows
-any number of call chains to run in the SPMC scheduled mode but the Hafnium
-SPMC restricts the number of call chains in SPMC scheduled mode to only one for
-keeping the implementation simple.
-
-Partition runtime models
-------------------------
-
-The runtime model of an endpoint describes the transitions permitted for an
-execution context between various states. These are the four partition runtime
-models supported (refer to `[1]`_ section 7):
-
- - RTM_FFA_RUN: runtime model presented to an execution context that is
- allocated CPU cycles through FFA_RUN interface.
- - RTM_FFA_DIR_REQ: runtime model presented to an execution context that is
- allocated CPU cycles through FFA_MSG_SEND_DIRECT_REQ interface.
- - RTM_SEC_INTERRUPT: runtime model presented to an execution context that is
- allocated CPU cycles by SPMC to handle a secure interrupt.
- - RTM_SP_INIT: runtime model presented to an execution context that is
- allocated CPU cycles by SPMC to initialize its state.
-
-If an endpoint execution context attempts to make an invalid transition or a
-valid transition that could lead to a loop in the call chain, SPMC denies the
-transition with the help of above runtime models.
-
-Interrupt management
---------------------
-
-GIC ownership
-~~~~~~~~~~~~~
-
-The SPMC owns the GIC configuration. Secure and non-secure interrupts are
-trapped at S-EL2. The SPMC manages interrupt resources and allocates interrupt
-IDs based on SP manifests. The SPMC acknowledges physical interrupts and injects
-virtual interrupts by setting the use of vIRQ/vFIQ bits before resuming a SP.
-
-Abbreviations:
-
- - NS-Int: A non-secure physical interrupt. It requires a switch to the normal
- world to be handled if it triggers while execution is in secure world.
- - Other S-Int: A secure physical interrupt targeted to an SP different from
- the one that is currently running.
- - Self S-Int: A secure physical interrupt targeted to the SP that is currently
- running.
-
-Non-secure interrupt handling
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This section documents the actions supported in SPMC in response to a non-secure
-interrupt as per the guidance provided by FF-A v1.1 EAC0 specification.
-An SP specifies one of the following actions in its partition manifest:
-
- - Non-secure interrupt is signaled.
- - Non-secure interrupt is signaled after a managed exit.
- - Non-secure interrupt is queued.
-
-An SP execution context in a call chain could specify a less permissive action
-than subsequent SP execution contexts in the same call chain. The less
-permissive action takes precedence over the more permissive actions specified
-by the subsequent execution contexts. Please refer to FF-A v1.1 EAC0 section
-8.3.1 for further explanation.
-
-Secure interrupt handling
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This section documents the support implemented for secure interrupt handling in
-SPMC as per the guidance provided by FF-A v1.1 EAC0 specification.
-The following assumptions are made about the system configuration:
-
- - In the current implementation, S-EL1 SPs are expected to use the para
- virtualized ABIs for interrupt management rather than accessing the virtual
- GIC interface.
- - Unless explicitly stated otherwise, this support is applicable only for
- S-EL1 SPs managed by SPMC.
- - Secure interrupts are configured as G1S or G0 interrupts.
- - All physical interrupts are routed to SPMC when running a secure partition
- execution context.
- - All endpoints with multiple execution contexts have their contexts pinned
- to corresponding CPUs. Hence, a secure virtual interrupt cannot be signaled
- to a target vCPU that is currently running or blocked on a different
- physical CPU.
-
-A physical secure interrupt could trigger while CPU is executing in normal world
-or secure world.
-The action of SPMC for a secure interrupt depends on: the state of the target
-execution context of the SP that is responsible for handling the interrupt;
-whether the interrupt triggered while execution was in normal world or secure
-world.
-
-Secure interrupt signaling mechanisms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Signaling refers to the mechanisms used by SPMC to indicate to the SP execution
-context that it has a pending virtual interrupt and to further run the SP
-execution context, such that it can handle the virtual interrupt. SPMC uses
-either the FFA_INTERRUPT interface with ERET conduit or vIRQ signal for signaling
-to S-EL1 SPs. When normal world execution is preempted by a secure interrupt,
-the SPMD uses the FFA_INTERRUPT ABI with ERET conduit to signal interrupt to SPMC
-running in S-EL2.
-
-+-----------+---------+---------------+---------------------------------------+
-| SP State | Conduit | Interface and | Description |
-| | | parameters | |
-+-----------+---------+---------------+---------------------------------------+
-| WAITING | ERET, | FFA_INTERRUPT,| SPMC signals to SP the ID of pending |
-| | vIRQ | Interrupt ID | interrupt. It pends vIRQ signal and |
-| | | | resumes execution context of SP |
-| | | | through ERET. |
-+-----------+---------+---------------+---------------------------------------+
-| BLOCKED | ERET, | FFA_INTERRUPT | SPMC signals to SP that an interrupt |
-| | vIRQ | | is pending. It pends vIRQ signal and |
-| | | | resumes execution context of SP |
-| | | | through ERET. |
-+-----------+---------+---------------+---------------------------------------+
-| PREEMPTED | vIRQ | NA | SPMC pends the vIRQ signal but does |
-| | | | not resume execution context of SP. |
-+-----------+---------+---------------+---------------------------------------+
-| RUNNING | ERET, | NA | SPMC pends the vIRQ signal and resumes|
-| | vIRQ | | execution context of SP through ERET. |
-+-----------+---------+---------------+---------------------------------------+
-
-Secure interrupt completion mechanisms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A SP signals secure interrupt handling completion to the SPMC through the
-following mechanisms:
-
- - ``FFA_MSG_WAIT`` ABI if it was in WAITING state.
- - ``FFA_RUN`` ABI if its was in BLOCKED state.
-
-This is a remnant of SPMC implementation based on the FF-A v1.0 specification.
-In the current implementation, S-EL1 SPs use the para-virtualized HVC interface
-implemented by SPMC to perform priority drop and interrupt deactivation (SPMC
-configures EOImode = 0, i.e. priority drop and deactivation are done together).
-The SPMC performs checks to deny the state transition upon invocation of
-either FFA_MSG_WAIT or FFA_RUN interface if the SP didn't perform the
-deactivation of the secure virtual interrupt.
-
-If the current SP execution context was preempted by a secure interrupt to be
-handled by execution context of target SP, SPMC resumes current SP after signal
-completion by target SP execution context.
-
-Actions for a secure interrupt triggered while execution is in normal world
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-+-------------------+----------+-----------------------------------------------+
-| State of target | Action | Description |
-| execution context | | |
-+-------------------+----------+-----------------------------------------------+
-| WAITING | Signaled | This starts a new call chain in SPMC scheduled|
-| | | mode. |
-+-------------------+----------+-----------------------------------------------+
-| PREEMPTED | Queued | The target execution must have been preempted |
-| | | by a non-secure interrupt. SPMC queues the |
-| | | secure virtual interrupt now. It is signaled |
-| | | when the target execution context next enters |
-| | | the RUNNING state. |
-+-------------------+----------+-----------------------------------------------+
-| BLOCKED, RUNNING | NA | The target execution context is blocked or |
-| | | running on a different CPU. This is not |
-| | | supported by current SPMC implementation and |
-| | | execution hits panic. |
-+-------------------+----------+-----------------------------------------------+
-
-If normal world execution was preempted by a secure interrupt, SPMC uses
-FFA_NORMAL_WORLD_RESUME ABI to indicate completion of secure interrupt handling
-and further returns execution to normal world.
-
-The following figure describes interrupt handling flow when a secure interrupt
-triggers while execution is in normal world:
-
-.. image:: ../resources/diagrams/ffa-secure-interrupt-handling-nwd.png
-
-A brief description of the events:
-
- - 1) Secure interrupt triggers while normal world is running.
- - 2) FIQ gets trapped to EL3.
- - 3) SPMD signals secure interrupt to SPMC at S-EL2 using FFA_INTERRUPT ABI.
- - 4) SPMC identifies target vCPU of SP and injects virtual interrupt (pends
- vIRQ).
- - 5) Assuming SP1 vCPU is in WAITING state, SPMC signals virtual interrupt
- using FFA_INTERRUPT with interrupt id as an argument and resumes the SP1
- vCPU using ERET in SPMC scheduled mode.
- - 6) Execution traps to vIRQ handler in SP1 provided that the virtual
- interrupt is not masked i.e., PSTATE.I = 0
- - 7) SP1 queries for the pending virtual interrupt id using a paravirtualized
- HVC call. SPMC clears the pending virtual interrupt state management
- and returns the pending virtual interrupt id.
- - 8) SP1 services the virtual interrupt and invokes the paravirtualized
- de-activation HVC call. SPMC de-activates the physical interrupt,
- clears the fields tracking the secure interrupt and resumes SP1 vCPU.
- - 9) SP1 performs secure interrupt completion through FFA_MSG_WAIT ABI.
- - 10) SPMC returns control to EL3 using FFA_NORMAL_WORLD_RESUME.
- - 11) EL3 resumes normal world execution.
-
-Actions for a secure interrupt triggered while execution is in secure world
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-+-------------------+----------+------------------------------------------------+
-| State of target | Action | Description |
-| execution context | | |
-+-------------------+----------+------------------------------------------------+
-| WAITING | Signaled | This starts a new call chain in SPMC scheduled |
-| | | mode. |
-+-------------------+----------+------------------------------------------------+
-| PREEMPTED by Self | Signaled | The target execution context reenters the |
-| S-Int | | RUNNING state to handle the secure virtual |
-| | | interrupt. |
-+-------------------+----------+------------------------------------------------+
-| PREEMPTED by | Queued | SPMC queues the secure virtual interrupt now. |
-| NS-Int | | It is signaled when the target execution |
-| | | context next enters the RUNNING state. |
-+-------------------+----------+------------------------------------------------+
-| BLOCKED | Signaled | Both preempted and target execution contexts |
-| | | must have been part of the Normal world |
-| | | scheduled call chain. Refer scenario 1 of |
-| | | Table 8.4 in the FF-A v1.1 EAC0 spec. |
-+-------------------+----------+------------------------------------------------+
-| RUNNING | NA | The target execution context is running on a |
-| | | different CPU. This scenario is not supported |
-| | | by current SPMC implementation and execution |
-| | | hits panic. |
-+-------------------+----------+------------------------------------------------+
-
-The following figure describes interrupt handling flow when a secure interrupt
-triggers while execution is in secure world. We assume OS kernel sends a direct
-request message to SP1. Further, SP1 sends a direct request message to SP2. SP1
-enters BLOCKED state and SPMC resumes SP2.
-
-.. image:: ../resources/diagrams/ffa-secure-interrupt-handling-swd.png
-
-A brief description of the events:
-
- - 1) Secure interrupt triggers while SP2 is running.
- - 2) SP2 gets preempted and execution traps to SPMC as IRQ.
- - 3) SPMC finds the target vCPU of secure partition responsible for handling
- this secure interrupt. In this scenario, it is SP1.
- - 4) SPMC pends vIRQ for SP1 and signals through FFA_INTERRUPT interface.
- SPMC further resumes SP1 through ERET conduit. Note that SP1 remains in
- Normal world schedule mode.
- - 6) Execution traps to vIRQ handler in SP1 provided that the virtual
- interrupt is not masked i.e., PSTATE.I = 0
- - 7) SP1 queries for the pending virtual interrupt id using a paravirtualized
- HVC call. SPMC clears the pending virtual interrupt state management
- and returns the pending virtual interrupt id.
- - 8) SP1 services the virtual interrupt and invokes the paravirtualized
- de-activation HVC call. SPMC de-activates the physical interrupt and
- clears the fields tracking the secure interrupt and resumes SP1 vCPU.
- - 9) Since SP1 direct request completed with FFA_INTERRUPT, it resumes the
- direct request to SP2 by invoking FFA_RUN.
- - 9) SPMC resumes the pre-empted vCPU of SP2.
-
-EL3 interrupt handling
-~~~~~~~~~~~~~~~~~~~~~~
-
-In GICv3 based systems, EL3 interrupts are configured as Group0 secure
-interrupts. Execution traps to SPMC when a Group0 interrupt triggers while an
-SP is running. Further, SPMC running at S-EL2 uses FFA_EL3_INTR_HANDLE ABI to
-request EL3 platform firmware to handle a pending Group0 interrupt.
-Similarly, SPMD registers a handler with interrupt management framework to
-delegate handling of Group0 interrupt to the platform if the interrupt triggers
-in normal world.
-
- - Platform hook
-
- - plat_spmd_handle_group0_interrupt
-
- SPMD provides platform hook to handle Group0 secure interrupts. In the
- current design, SPMD expects the platform not to delegate handling to the
- NWd (such as through SDEI) while processing Group0 interrupts.
-
-Power management
-----------------
-
-In platforms with or without secure virtualization:
-
-- The NWd owns the platform PM policy.
-- The Hypervisor or OS kernel is the component initiating PSCI service calls.
-- The EL3 PSCI library is in charge of the PM coordination and control
- (eventually writing to platform registers).
-- While coordinating PM events, the PSCI library calls backs into the Secure
- Payload Dispatcher for events the latter has statically registered to.
-
-When using the SPMD as a Secure Payload Dispatcher:
-
-- A power management event is relayed through the SPD hook to the SPMC.
-- In the current implementation only cpu on (svc_on_finish) and cpu off
- (svc_off) hooks are registered.
-- The behavior for the cpu on event is described in `Secondary cores boot-up`_.
- The SPMC is entered through its secondary physical core entry point.
-- The cpu off event occurs when the NWd calls PSCI_CPU_OFF. The PM event is
- signaled to the SPMC through a power management framework message.
- It consists in a SPMD-to-SPMC direct request/response (`SPMC-SPMD direct
- requests/responses`_) conveying the event details and SPMC response.
- The SPMD performs a synchronous entry into the SPMC. The SPMC is entered and
- updates its internal state to reflect the physical core is being turned off.
- In the current implementation no SP is resumed as a consequence. This behavior
- ensures a minimal support for CPU hotplug e.g. when initiated by the NWd linux
- userspace.
-
-Arm architecture extensions for security hardening
-==================================================
-
-Hafnium supports the following architecture extensions for security hardening:
-
-- Pointer authentication (FEAT_PAuth): the extension permits detection of forged
- pointers used by ROP type of attacks through the signing of the pointer
- value. Hafnium is built with the compiler branch protection option to permit
- generation of a pointer authentication code for return addresses (pointer
- authentication for instructions). The APIA key is used while Hafnium runs.
- A random key is generated at boot time and restored upon entry into Hafnium
- at run-time. APIA and other keys (APIB, APDA, APDB, APGA) are saved/restored
- in vCPU contexts permitting to enable pointer authentication in VMs/SPs.
-- Branch Target Identification (FEAT_BTI): the extension permits detection of
- unexpected indirect branches used by JOP type of attacks. Hafnium is built
- with the compiler branch protection option, inserting land pads at function
- prologues that are reached by indirect branch instructions (BR/BLR).
- Hafnium code pages are marked as guarded in the EL2 Stage-1 MMU descriptors
- such that an indirect branch must always target a landpad. A fault is
- triggered otherwise. VMs/SPs can (independently) mark their code pages as
- guarded in the EL1&0 Stage-1 translation regime.
-- Memory Tagging Extension (FEAT_MTE): the option permits detection of out of
- bound memory array accesses or re-use of an already freed memory region.
- Hafnium enables the compiler option permitting to leverage MTE stack tagging
- applied to core stacks. Core stacks are marked as normal tagged memory in the
- EL2 Stage-1 translation regime. A synchronous data abort is generated upon tag
- check failure on load/stores. A random seed is generated at boot time and
- restored upon entry into Hafnium. MTE system registers are saved/restored in
- vCPU contexts permitting MTE usage from VMs/SPs.
-
-SMMUv3 support in Hafnium
-=========================
-
-An SMMU is analogous to an MMU in a CPU. It performs address translations for
-Direct Memory Access (DMA) requests from system I/O devices.
-The responsibilities of an SMMU include:
-
-- Translation: Incoming DMA requests are translated from bus address space to
- system physical address space using translation tables compliant to
- Armv8/Armv7 VMSA descriptor format.
-- Protection: An I/O device can be prohibited from read, write access to a
- memory region or allowed.
-- Isolation: Traffic from each individial device can be independently managed.
- The devices are differentiated from each other using unique translation
- tables.
-
-The following diagram illustrates a typical SMMU IP integrated in a SoC with
-several I/O devices along with Interconnect and Memory system.
-
-.. image:: ../resources/diagrams/MMU-600.png
-
-SMMU has several versions including SMMUv1, SMMUv2 and SMMUv3. Hafnium provides
-support for SMMUv3 driver in both normal and secure world. A brief introduction
-of SMMUv3 functionality and the corresponding software support in Hafnium is
-provided here.
-
-SMMUv3 features
----------------
-
-- SMMUv3 provides Stage1, Stage2 translation as well as nested (Stage1 + Stage2)
- translation support. It can either bypass or abort incoming translations as
- well.
-- Traffic (memory transactions) from each upstream I/O peripheral device,
- referred to as Stream, can be independently managed using a combination of
- several memory based configuration structures. This allows the SMMUv3 to
- support a large number of streams with each stream assigned to a unique
- translation context.
-- Support for Armv8.1 VMSA where the SMMU shares the translation tables with
- a Processing Element. AArch32(LPAE) and AArch64 translation table format
- are supported by SMMUv3.
-- SMMUv3 offers non-secure stream support with secure stream support being
- optional. Logically, SMMUv3 behaves as if there is an indepdendent SMMU
- instance for secure and non-secure stream support.
-- It also supports sub-streams to differentiate traffic from a virtualized
- peripheral associated with a VM/SP.
-- Additionally, SMMUv3.2 provides support for PEs implementing Armv8.4-A
- extensions. Consequently, SPM depends on Secure EL2 support in SMMUv3.2
- for providing Secure Stage2 translation support to upstream peripheral
- devices.
-
-SMMUv3 Programming Interfaces
------------------------------
-
-SMMUv3 has three software interfaces that are used by the Hafnium driver to
-configure the behaviour of SMMUv3 and manage the streams.
-
-- Memory based data strutures that provide unique translation context for
- each stream.
-- Memory based circular buffers for command queue and event queue.
-- A large number of SMMU configuration registers that are memory mapped during
- boot time by Hafnium driver. Except a few registers, all configuration
- registers have independent secure and non-secure versions to configure the
- behaviour of SMMUv3 for translation of secure and non-secure streams
- respectively.
-
-Peripheral device manifest
---------------------------
-
-Currently, SMMUv3 driver in Hafnium only supports dependent peripheral devices.
-These devices are dependent on PE endpoint to initiate and receive memory
-management transactions on their behalf. The acccess to the MMIO regions of
-any such device is assigned to the endpoint during boot. Moreover, SMMUv3 driver
-uses the same stage 2 translations for the device as those used by partition
-manager on behalf of the PE endpoint. This ensures that the peripheral device
-has the same visibility of the physical address space as the endpoint. The
-device node of the corresponding partition manifest (refer to `[1]`_ section 3.2
-) must specify these additional properties for each peripheral device in the
-system :
-
-- smmu-id: This field helps to identify the SMMU instance that this device is
- upstream of.
-- stream-ids: List of stream IDs assigned to this device.
-
-.. code:: shell
-
- smmuv3-testengine {
- base-address = <0x00000000 0x2bfe0000>;
- pages-count = <32>;
- attributes = <0x3>;
- smmu-id = <0>;
- stream-ids = <0x0 0x1>;
- interrupts = <0x2 0x3>, <0x4 0x5>;
- exclusive-access;
- };
-
-SMMUv3 driver limitations
--------------------------
-
-The primary design goal for the Hafnium SMMU driver is to support secure
-streams.
-
-- Currently, the driver only supports Stage2 translations. No support for
- Stage1 or nested translations.
-- Supports only AArch64 translation format.
-- No support for features such as PCI Express (PASIDs, ATS, PRI), MSI, RAS,
- Fault handling, Performance Monitor Extensions, Event Handling, MPAM.
-- No support for independent peripheral devices.
-
-S-EL0 Partition support
-=======================
-The SPMC (Hafnium) has limited capability to run S-EL0 FF-A partitions using
-FEAT_VHE (mandatory with ARMv8.1 in non-secure state, and in secure world
-with ARMv8.4 and FEAT_SEL2).
-
-S-EL0 partitions are useful for simple partitions that don't require full
-Trusted OS functionality. It is also useful to reduce jitter and cycle
-stealing from normal world since they are more lightweight than VMs.
-
-S-EL0 partitions are presented, loaded and initialized the same as S-EL1 VMs by
-the SPMC. They are differentiated primarily by the 'exception-level' property
-and the 'execution-ctx-count' property in the SP manifest. They are host apps
-under the single EL2&0 Stage-1 translation regime controlled by the SPMC and
-call into the SPMC through SVCs as opposed to HVCs and SMCs. These partitions
-can use FF-A defined services (FFA_MEM_PERM_*) to update or change permissions
-for memory regions.
-
-S-EL0 partitions are required by the FF-A specification to be UP endpoints,
-capable of migrating, and the SPMC enforces this requirement. The SPMC allows
-a S-EL0 partition to accept a direct message from secure world and normal world,
-and generate direct responses to them.
-All S-EL0 partitions must use AArch64. AArch32 S-EL0 partitions are not supported.
-
-Memory sharing, indirect messaging, and notifications functionality with S-EL0
-partitions is supported.
-
-Interrupt handling is not supported with S-EL0 partitions and is work in
-progress.
References
==========
@@ -1641,8 +242,7 @@
.. _[3]:
-[3] `Trusted Boot Board Requirements
-Client <https://developer.arm.com/documentation/den0006/d/>`__
+[3] https://hafnium.readthedocs.io/en/latest/secure-partition-manager/secure-partition-manager.html#secure-partitions-layout-file
.. _[4]:
@@ -1650,23 +250,15 @@
.. _[5]:
-[5] https://git.trustedfirmware.org/TF-A/tf-a-tests.git/tree/spm/cactus/plat/arm/fvp/fdts/cactus.dts
+[5] https://hafnium.readthedocs.io/en/latest/secure-partition-manager/index.html
.. _[6]:
-[6] https://trustedfirmware-a.readthedocs.io/en/latest/components/ffa-manifest-binding.html
+[6] :ref:`EL3 Secure Partition Manager<EL3 Secure Partition Manager>`
.. _[7]:
-[7] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
-
-.. _[8]:
-
-[8] https://lists.trustedfirmware.org/archives/list/tf-a@lists.trustedfirmware.org/thread/CFQFGU6H2D5GZYMUYGTGUSXIU3OYZP6U/
-
-.. _[9]:
-
-[9] https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html#dynamic-configuration-during-cold-boot
+[7] https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html#dynamic-configuration-during-cold-boot
--------------
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 4c070ed..2e33911 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -99,6 +99,10 @@
file that contains the BL32 private key in PEM format or a PKCS11 URI. If
``SAVE_KEYS=1``, only a file is accepted and it will be used to save the key.
+- ``RMM``: This is an optional build option used when ``ENABLE_RME`` is set.
+ It specifies the path to RMM binary for the ``fip`` target. If the RMM option
+ is not specified, TF-A builds the TRP to load and run at R-EL2.
+
- ``BL33``: Path to BL33 image in the host file system. This is mandatory for
``fip`` target in case TF-A BL2 is used.
diff --git a/docs/license.rst b/docs/license.rst
index 8996105..9e0298b 100644
--- a/docs/license.rst
+++ b/docs/license.rst
@@ -93,9 +93,27 @@
- ``include/lib/dice/dice.h``
+- Some source files originating from the `pydevicetree`_ project.
+ These files are licensed under the Apache License, Version 2.0, which is a
+ permissive license compatible with BSD-3-Clause. Any contributions to this
+ code must also be made under the terms of `Apache License 2.0`_.
+ These files are:
+
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py``
+ - ``tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py``
+
+
.. _FreeBSD: http://www.freebsd.org
.. _Linux MIT license: https://raw.githubusercontent.com/torvalds/linux/master/LICENSES/preferred/MIT
.. _SCC: http://www.simple-cc.org/
.. _Open Profile for DICE: https://pigweed.googlesource.com/open-dice/
.. _Apache License 2.0: https://www.apache.org/licenses/LICENSE-2.0.txt
-
+.. _pydevicetree: https://pypi.org/project/pydevicetree/
diff --git a/docs/plat/xilinx-versal-net.rst b/docs/plat/xilinx-versal-net.rst
index e9dd772..d22a46d 100644
--- a/docs/plat/xilinx-versal-net.rst
+++ b/docs/plat/xilinx-versal-net.rst
@@ -75,7 +75,7 @@
| 0xc2001000-0xc2001FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
+---------------------------+-----------------------------------------------------------+
-PM SMC call ranges
+PM SMC call ranges for SiP SVC version 0.1
--------------------------------------------------------
+---------------------------+---------------------------------------------------------------------------+
@@ -84,6 +84,19 @@
| 0xc2000000-0xc2000FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+---------------------------+---------------------------------------------------------------------------+
+PM SMC call ranges for SiP SVC version 0.2
+--------------------------------------------------------
+
++---------------------------+---------------------------------------------------------------------------+
+| SMC Function Identifier | Service type |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000FFF | Fast SMC64 SiP Service call used for pass-through of AMD-Xilinx Platform |
+| | Management APIs to firmware |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000A00-0xc2000AFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+| | specific TF-A APIs |
++---------------------------+---------------------------------------------------------------------------+
+
SMC function IDs for SiP Service queries
----------------------------------------------
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
index 072329a..7185d91 100644
--- a/docs/plat/xilinx-versal.rst
+++ b/docs/plat/xilinx-versal.rst
@@ -14,11 +14,6 @@
make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31
```
-To build ATF for different platform (supported are "silicon"(default) and "versal_virt")
-```bash
-make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31
-```
-
To build bl32 TSP you have to rebuild bl31 too
```bash
make CROSS_COMPILE=aarch64-none-elf- PLAT=versal SPD=tspd RESET_TO_BL31=1 bl31 bl32
@@ -51,11 +46,6 @@
- `pl011`, `pl011_0`: ARM pl011 UART 0
- `pl011_1` : ARM pl011 UART 1
-* `VERSAL_PLATFORM`: Select the platform. Options:
- - `versal_virt` : Versal Virtual platform
- - `spp_itr6` : SPP ITR6
- - `emu_itr6` : EMU ITR6
-
* `CPU_PWRDWN_SGI`: Select the SGI for triggering CPU power down request to
secondary cores on receiving power down callback from
firmware. Options:
@@ -98,8 +88,8 @@
| 0xc2001000-0xc2001FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
+---------------------------+-----------------------------------------------------------+
-PM SMC call ranges
-------------------
+PM SMC call ranges for SiP SVC version 0.1
+--------------------------------------------------------
+---------------------------+---------------------------------------------------------------------------+
| SMC Function Identifier | Service type |
@@ -107,6 +97,19 @@
| 0xc2000000-0xc2000FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+---------------------------+---------------------------------------------------------------------------+
+PM SMC call ranges for SiP SVC version 0.2
+--------------------------------------------------------
+
++---------------------------+---------------------------------------------------------------------------+
+| SMC Function Identifier | Service type |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000FFF | Fast SMC64 SiP Service call used for pass-through of AMD-Xilinx Platform |
+| | Management APIs to firmware |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000A00-0xc2000AFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+| | specific TF-A APIs |
++---------------------------+---------------------------------------------------------------------------+
+
SMC function IDs for SiP Service queries
----------------------------------------
diff --git a/docs/tools/cot-dt2c.rst b/docs/tools/cot-dt2c.rst
new file mode 100644
index 0000000..7b7e56f
--- /dev/null
+++ b/docs/tools/cot-dt2c.rst
@@ -0,0 +1,149 @@
+TF-A CoT dt2c Tool
+==================
+
+This tool is used to automatically generate the corresponding c file for a
+CoT DT file. Since currently TF-A support two type of CoT file: static c file
+and CoT DT binding. This is error prone and hard to maintain, therefore this
+tool can generate the c file for the platform that does not support CoT DT
+binding, given the CoT DT file so the c file can be deprecated.
+
+Prerequisites
+~~~~~~~~~~~~~
+
+#. Python (3.8 or later)
+#. `Poetry`_ Python package manager
+
+
+Getting Started
+~~~~~~~~~~~~~~~
+
+#. Install the tool
+
+ .. code::
+
+ make install
+
+
+#. Verify that the tool runs correctly
+
+ .. code::
+
+ make test
+
+
+#. Usage of the tool
+
+ .. code::
+
+ cot-dt2c
+
+ This command will output the following as usage for this command
+
+ .. code-block:: text
+
+ Usage: cot-dt2c [OPTIONS] COMMAND [ARGS]...
+
+ Options:
+ --version Show the version and exit.
+ --help Show this message and exit.
+
+ Commands:
+ convert-to-c
+ validate-cot
+ visualize-cot
+ validate-dt
+
+#. Uninstall the tool
+ .. code::
+
+ make uninstall
+
+ This command will uninstall the tool
+
+
+#. Uninstall the tool and clean all the build file
+ .. code::
+
+ make clean
+
+ This command will clean all the build file and implicitly uninstall the tool
+
+
+#. Call the make file from TF-A root directory
+ .. code::
+
+ make -C tools/cot-dt2c install
+ make -C tools/cot-dt2c uninstall
+ make -C tools/cot-dt2c clean
+
+Convert CoT descriptors to C file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To convert the CoT descriptors
+
+This command is for the platform that does not use CoT DT parser,
+which can generate the C file given the CoT descriptors. Before
+the conversion to C file, the tool will do an implicit checks on
+the validity of the CoT DT file.
+
+.. code::
+
+ cot-dt2c convert-to-c [INPUT DTB PATH] [OUTPUT C PATH]
+ cot-dt2c convert-to-c fdts/tbbr_cot_descriptors.dtsi test.c
+
+
+Validate CoT descriptors
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To validate the certificate
+
+The tests folder in the tool folder provides some bad-example of the
+DT file, and the tool will print out "not a valid CoT DT file" on console.
+
+The command will check the format of the CoT file
+
+#. The open bracket
+#. The open ifdef macro
+#. The missing mandatory attribute
+#. Malformed DT file (cert missing parent, missing root certs. etc.)
+
+Currently the validation is specifically for checking the CoT DT file
+
+.. code::
+
+ cot-dt2c validate-cot [INPUT DTB PATH]
+ cot-dt2c validate-cot fdts/tbbr_cot_descriptors.dtsi
+
+
+Visualize CoT descriptors
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This command create a HTML to visualize the relationship between
+the certificates and the image of a CoT DT file.
+
+.. code::
+
+ cot-dt2c visualize-cot [INPUT DTB PATH]
+ cot-dt2c visualize-cot fdts/tbbr_cot_descriptors.dtsi
+
+
+Validate Other DT files
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The command will transform the dtsi/dts file into a more standard
+dtsi/dts file inside /tmp folder that can be used as input to dt-schema
+for further validation. Currently the tool will perform some basic validation
+for the file (syntax) and dt-schema can be used for advance checks. dt-schema
+is not installed along with the tool.
+
+.. code::
+
+ cot-dt2c validate-dt [INPUT DTS PATH or INPUT DTS folder]
+ cot-dt2c validate-dt fdts/
+ cot-dt2c validate-dt fdts/fvp-bsae-gicv3.dtsi
+
+--------------
+
+*Copyright (c) 2024, Arm Limited. All rights reserved.*
+
+.. _Poetry: https://python-poetry.org/docs/
diff --git a/docs/tools/index.rst b/docs/tools/index.rst
index 91651bf..c0e214a 100644
--- a/docs/tools/index.rst
+++ b/docs/tools/index.rst
@@ -7,6 +7,7 @@
memory-layout-tool
transfer-list-compiler
+ cot-dt2c
--------------
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
index 4489892..cc82ddb 100644
--- a/drivers/arm/gic/v3/arm_gicv3_common.c
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -28,10 +28,13 @@
void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
{
uintptr_t gicr_base = 0;
+ unsigned int typer_reg;
assert(gicv3_driver_data);
assert(gicv3_driver_data->rdistif_base_addrs);
+ assert(gicv3_driver_data->gicd_base != 0U);
+ typer_reg = gicd_read_typer(gicv3_driver_data->gicd_base);
/*
* The GICR_WAKER.Sleep bit should be set only when both
* GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
@@ -60,9 +63,14 @@
*/
gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
- /* Wait until the GICR_WAKER.Quiescent bit is set */
- while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
- ;
+ /*
+ * If LPIs are supported, wait until the GICR_WAKER.Quiescent bit is
+ * set.
+ */
+ if ((typer_reg & TYPER_LPIS) != 0U) {
+ while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
+ ;
+ }
}
/*
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 8ea164c..2be19db 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -686,6 +686,8 @@
gicr_write_ctlr(gicr_base,
rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT));
+ gicr_wait_for_pending_write(gicr_base);
+
/* Restore registers' content */
gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
diff --git a/drivers/auth/cca/bl1_cot.c b/drivers/auth/cca/bl1_cot.c
new file mode 100644
index 0000000..43cb18a
--- /dev/null
+++ b/drivers/auth/cca/bl1_cot.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <mbedtls/version.h>
+
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_mod.h>
+#include <platform_def.h>
+#include <tools_share/cca_oid.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
+
+/*
+ * Parameter type descriptors.
+ */
+static auth_param_type_desc_t cca_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, CCA_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_RAW_DATA, 0);
+
+static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
+
+/* CCA Content Certificate */
+static const auth_img_desc_t cca_content_cert = {
+ .img_id = CCA_CONTENT_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &subject_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &cca_nv_ctr,
+ .plat_nv_ctr = &cca_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &tb_fw_hash,
+ .data = {
+ .ptr = (void *)tb_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &tb_fw_config_hash,
+ .data = {
+ .ptr = (void *)tb_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &fw_config_hash,
+ .data = {
+ .ptr = (void *)fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t bl2_image = {
+ .img_id = BL2_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tb_fw_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t tb_fw_config = {
+ .img_id = TB_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tb_fw_config_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t fw_config = {
+ .img_id = FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &cca_content_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &fw_config_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [CCA_CONTENT_CERT_ID] = &cca_content_cert,
+ [BL2_IMAGE_ID] = &bl2_image,
+ [TB_FW_CONFIG_ID] = &tb_fw_config,
+ [FW_CONFIG_ID] = &fw_config,
+};
+
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/cca/cot.c b/drivers/auth/cca/cot.c
deleted file mode 100644
index 2a03604..0000000
--- a/drivers/auth/cca/cot.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-
-#include <mbedtls/version.h>
-
-#include <common/tbbr/cot_def.h>
-#include <drivers/auth/auth_mod.h>
-#include <tools_share/cca_oid.h>
-
-#include <platform_def.h>
-
-/*
- * Allocate static buffers to store the authentication parameters extracted from
- * the certificates.
- */
-static unsigned char fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char hw_config_hash_buf[HASH_DER_LEN];
-static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
-static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char rmm_hash_buf[HASH_DER_LEN];
-
-#ifdef IMAGE_BL2
-static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
-#if defined(SPD_spmd)
-static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
-#endif /* SPD_spmd */
-
-static unsigned char core_swd_pk_buf[PK_DER_LEN];
-static unsigned char plat_pk_buf[PK_DER_LEN];
-#endif /* IMAGE_BL2 */
-
-/*
- * Parameter type descriptors.
- */
-static auth_param_type_desc_t cca_nv_ctr = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_NV_CTR, CCA_FW_NVCOUNTER_OID);
-static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, 0);
-static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_SIG, 0);
-static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_SIG_ALG, 0);
-static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_RAW_DATA, 0);
-
-static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
-static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
-static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID);
-static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t rmm_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, RMM_HASH_OID);
-
-#ifdef IMAGE_BL2
-static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
-static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
-
-static auth_param_type_desc_t prot_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, PROT_PK_OID);
-static auth_param_type_desc_t swd_rot_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, SWD_ROT_PK_OID);
-static auth_param_type_desc_t core_swd_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, CORE_SWD_PK_OID);
-static auth_param_type_desc_t plat_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, PLAT_PK_OID);
-
-static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID);
-static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
-static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
-#if defined(SPD_spmd)
-static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
-static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
-static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
-static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
-static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
-static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
-static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
-static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
-#endif /* SPD_spmd */
-#endif /* IMAGE_BL2 */
-
-/* CCA Content Certificate */
-static const auth_img_desc_t cca_content_cert = {
- .img_id = CCA_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &subject_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &cca_nv_ctr,
- .plat_nv_ctr = &cca_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &tb_fw_hash,
- .data = {
- .ptr = (void *)tb_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &tb_fw_config_hash,
- .data = {
- .ptr = (void *)tb_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &fw_config_hash,
- .data = {
- .ptr = (void *)fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &hw_config_hash,
- .data = {
- .ptr = (void *)hw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [4] = {
- .type_desc = &soc_fw_hash,
- .data = {
- .ptr = (void *)soc_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [5] = {
- .type_desc = &soc_fw_config_hash,
- .data = {
- .ptr = (void *)soc_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [6] = {
- .type_desc = &rmm_hash,
- .data = {
- .ptr = (void *)rmm_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-#ifdef IMAGE_BL1
-static const auth_img_desc_t bl2_image = {
- .img_id = BL2_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tb_fw_hash
- }
- }
- }
-};
-
-static const auth_img_desc_t tb_fw_config = {
- .img_id = TB_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tb_fw_config_hash
- }
- }
- }
-};
-
-static const auth_img_desc_t fw_config = {
- .img_id = FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &fw_config_hash
- }
- }
- }
-};
-#endif /* IMAGE_BL1 */
-
-#ifdef IMAGE_BL2
-/* HW Config */
-static const auth_img_desc_t hw_config = {
- .img_id = HW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &hw_config_hash
- }
- }
- }
-};
-
-/* BL31 */
-static const auth_img_desc_t bl31_image = {
- .img_id = BL31_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &soc_fw_hash
- }
- }
- }
-};
-
-/* BL31 Config */
-static const auth_img_desc_t soc_fw_config = {
- .img_id = SOC_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &soc_fw_config_hash
- }
- }
- }
-};
-
-/* RMM */
-static const auth_img_desc_t rmm_image = {
- .img_id = RMM_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &cca_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &rmm_hash
- }
- }
- }
-};
-
-/* Core SWD Key Certificate */
-static const auth_img_desc_t core_swd_key_cert = {
- .img_id = CORE_SWD_KEY_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL, /* SWD ROOT CERT */
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &swd_rot_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &core_swd_pk,
- .data = {
- .ptr = (void *)core_swd_pk_buf,
- .len = (unsigned int)PK_DER_LEN
- }
- }
- }
-};
-
-/* SPMC Content Certificate */
-static const auth_img_desc_t trusted_os_fw_content_cert = {
- .img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &core_swd_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &core_swd_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &tos_fw_hash,
- .data = {
- .ptr = (void *)tos_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &tos_fw_config_hash,
- .data = {
- .ptr = (void *)tos_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-/* SPMC */
-static const auth_img_desc_t bl32_image = {
- .img_id = BL32_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_os_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tos_fw_hash
- }
- }
- }
-};
-
-/* SPM Config */
-static const auth_img_desc_t tos_fw_config = {
- .img_id = TOS_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_os_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tos_fw_config_hash
- }
- }
- }
-};
-
-/* Platform Key Certificate */
-static const auth_img_desc_t plat_key_cert = {
- .img_id = PLAT_KEY_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL, /* PLATFORM ROOT CERT */
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &prot_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &non_trusted_nv_ctr,
- .plat_nv_ctr = &non_trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &plat_pk,
- .data = {
- .ptr = (void *)plat_pk_buf,
- .len = (unsigned int)PK_DER_LEN
- }
- }
- }
-};
-
-/* Non-Trusted Firmware */
-static const auth_img_desc_t non_trusted_fw_content_cert = {
- .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &plat_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &plat_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &non_trusted_nv_ctr,
- .plat_nv_ctr = &non_trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &nt_world_bl_hash,
- .data = {
- .ptr = (void *)nt_world_bl_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &nt_fw_config_hash,
- .data = {
- .ptr = (void *)nt_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t bl33_image = {
- .img_id = BL33_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &non_trusted_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &nt_world_bl_hash
- }
- }
- }
-};
-
-/* NT FW Config */
-static const auth_img_desc_t nt_fw_config = {
- .img_id = NT_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &non_trusted_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &nt_fw_config_hash
- }
- }
- }
-};
-
-/*
- * Secure Partitions
- */
-#if defined(SPD_spmd)
-static const auth_img_desc_t sip_sp_content_cert = {
- .img_id = SIP_SP_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &core_swd_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &core_swd_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &sp_pkg1_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[0],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &sp_pkg2_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[1],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &sp_pkg3_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[2],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &sp_pkg4_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[3],
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-DEFINE_SIP_SP_PKG(1);
-DEFINE_SIP_SP_PKG(2);
-DEFINE_SIP_SP_PKG(3);
-DEFINE_SIP_SP_PKG(4);
-
-static const auth_img_desc_t plat_sp_content_cert = {
- .img_id = PLAT_SP_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &plat_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &plat_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &non_trusted_nv_ctr,
- .plat_nv_ctr = &non_trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &sp_pkg5_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[4],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &sp_pkg6_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[5],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &sp_pkg7_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[6],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &sp_pkg8_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[7],
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-DEFINE_PLAT_SP_PKG(5);
-DEFINE_PLAT_SP_PKG(6);
-DEFINE_PLAT_SP_PKG(7);
-DEFINE_PLAT_SP_PKG(8);
-#endif /* SPD_spmd */
-#endif /* IMAGE_BL2 */
-/*
- * Chain of trust definition
- */
-#ifdef IMAGE_BL1
-static const auth_img_desc_t * const cot_desc[] = {
- [CCA_CONTENT_CERT_ID] = &cca_content_cert,
- [BL2_IMAGE_ID] = &bl2_image,
- [TB_FW_CONFIG_ID] = &tb_fw_config,
- [FW_CONFIG_ID] = &fw_config,
-};
-#else /* IMAGE_BL2 */
-static const auth_img_desc_t * const cot_desc[] = {
- [CCA_CONTENT_CERT_ID] = &cca_content_cert,
- [HW_CONFIG_ID] = &hw_config,
- [BL31_IMAGE_ID] = &bl31_image,
- [SOC_FW_CONFIG_ID] = &soc_fw_config,
- [RMM_IMAGE_ID] = &rmm_image,
- [CORE_SWD_KEY_CERT_ID] = &core_swd_key_cert,
- [TRUSTED_OS_FW_CONTENT_CERT_ID] = &trusted_os_fw_content_cert,
- [BL32_IMAGE_ID] = &bl32_image,
- [TOS_FW_CONFIG_ID] = &tos_fw_config,
- [PLAT_KEY_CERT_ID] = &plat_key_cert,
- [NON_TRUSTED_FW_CONTENT_CERT_ID] = &non_trusted_fw_content_cert,
- [BL33_IMAGE_ID] = &bl33_image,
- [NT_FW_CONFIG_ID] = &nt_fw_config,
-#if defined(SPD_spmd)
- [SIP_SP_CONTENT_CERT_ID] = &sip_sp_content_cert,
- [PLAT_SP_CONTENT_CERT_ID] = &plat_sp_content_cert,
- [SP_PKG1_ID] = &sp_pkg1,
- [SP_PKG2_ID] = &sp_pkg2,
- [SP_PKG3_ID] = &sp_pkg3,
- [SP_PKG4_ID] = &sp_pkg4,
- [SP_PKG5_ID] = &sp_pkg5,
- [SP_PKG6_ID] = &sp_pkg6,
- [SP_PKG7_ID] = &sp_pkg7,
- [SP_PKG8_ID] = &sp_pkg8,
-#endif
-};
-#endif /* IMAGE_BL1 */
-
-/* Register the CoT in the authentication module */
-REGISTER_COT(cot_desc);
diff --git a/drivers/auth/dualroot/bl1_cot.c b/drivers/auth/dualroot/bl1_cot.c
new file mode 100644
index 0000000..a548170
--- /dev/null
+++ b/drivers/auth/dualroot/bl1_cot.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <mbedtls/version.h>
+
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_mod.h>
+#include <platform_def.h>
+#include <tools_share/dualroot_oid.h>
+
+/*
+ * Allocate static buffers to store the authentication parameters extracted from
+ * the certificates.
+ */
+static unsigned char fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char scp_fw_hash_buf[HASH_DER_LEN];
+static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+
+/*
+ * Parameter type descriptors.
+ */
+static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_RAW_DATA, 0);
+
+static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID);
+static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, AP_FWU_CFG_HASH_OID);
+static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC(
+ AUTH_PARAM_HASH, FWU_HASH_OID);
+
+static const auth_img_desc_t trusted_boot_fw_cert = {
+ .img_id = TRUSTED_BOOT_FW_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &subject_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ },
+ [1] = {
+ .type = AUTH_METHOD_NV_CTR,
+ .param.nv_ctr = {
+ .cert_nv_ctr = &trusted_nv_ctr,
+ .plat_nv_ctr = &trusted_nv_ctr
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &tb_fw_hash,
+ .data = {
+ .ptr = (void *)tb_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &tb_fw_config_hash,
+ .data = {
+ .ptr = (void *)tb_fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &fw_config_hash,
+ .data = {
+ .ptr = (void *)fw_config_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t bl2_image = {
+ .img_id = BL2_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &trusted_boot_fw_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tb_fw_hash
+ }
+ }
+ }
+};
+
+/* TB FW Config */
+static const auth_img_desc_t tb_fw_config = {
+ .img_id = TB_FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &trusted_boot_fw_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &tb_fw_config_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t fw_config = {
+ .img_id = FW_CONFIG_ID,
+ .img_type = IMG_RAW,
+ .parent = &trusted_boot_fw_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &fw_config_hash
+ }
+ }
+ }
+};
+
+/* FWU auth descriptor */
+static const auth_img_desc_t fwu_cert = {
+ .img_id = FWU_CERT_ID,
+ .img_type = IMG_CERT,
+ .parent = NULL,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_SIG,
+ .param.sig = {
+ .pk = &subject_pk,
+ .sig = &sig,
+ .alg = &sig_alg,
+ .data = &raw_data
+ }
+ }
+ },
+ .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+ [0] = {
+ .type_desc = &scp_bl2u_hash,
+ .data = {
+ .ptr = (void *)scp_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [1] = {
+ .type_desc = &bl2u_hash,
+ .data = {
+ .ptr = (void *)tb_fw_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ },
+ [2] = {
+ .type_desc = &ns_bl2u_hash,
+ .data = {
+ .ptr = (void *)nt_world_bl_hash_buf,
+ .len = (unsigned int)HASH_DER_LEN
+ }
+ }
+ }
+};
+
+/* SCP_BL2U */
+static const auth_img_desc_t scp_bl2u_image = {
+ .img_id = SCP_BL2U_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &fwu_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &scp_bl2u_hash
+ }
+ }
+ }
+};
+
+/* BL2U */
+static const auth_img_desc_t bl2u_image = {
+ .img_id = BL2U_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &fwu_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &bl2u_hash
+ }
+ }
+ }
+};
+
+/* NS_BL2U */
+static const auth_img_desc_t ns_bl2u_image = {
+ .img_id = NS_BL2U_IMAGE_ID,
+ .img_type = IMG_RAW,
+ .parent = &fwu_cert,
+ .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+ [0] = {
+ .type = AUTH_METHOD_HASH,
+ .param.hash = {
+ .data = &raw_data,
+ .hash = &ns_bl2u_hash
+ }
+ }
+ }
+};
+
+static const auth_img_desc_t * const cot_desc[] = {
+ [TRUSTED_BOOT_FW_CERT_ID] = &trusted_boot_fw_cert,
+ [BL2_IMAGE_ID] = &bl2_image,
+ [TB_FW_CONFIG_ID] = &tb_fw_config,
+ [FW_CONFIG_ID] = &fw_config,
+ [FWU_CERT_ID] = &fwu_cert,
+ [SCP_BL2U_IMAGE_ID] = &scp_bl2u_image,
+ [BL2U_IMAGE_ID] = &bl2u_image,
+ [NS_BL2U_IMAGE_ID] = &ns_bl2u_image
+};
+
+REGISTER_COT(cot_desc);
diff --git a/drivers/auth/dualroot/cot.c b/drivers/auth/dualroot/cot.c
deleted file mode 100644
index c89930c..0000000
--- a/drivers/auth/dualroot/cot.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
- * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stddef.h>
-
-#include <mbedtls/version.h>
-
-#include <common/tbbr/cot_def.h>
-#include <drivers/auth/auth_mod.h>
-
-#include <tools_share/dualroot_oid.h>
-
-#include <platform_def.h>
-
-/*
- * Allocate static buffers to store the authentication parameters extracted from
- * the certificates.
- */
-static unsigned char fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char hw_config_hash_buf[HASH_DER_LEN];
-static unsigned char scp_fw_hash_buf[HASH_DER_LEN];
-static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
-
-#ifdef IMAGE_BL2
-static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_extra1_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_extra2_hash_buf[HASH_DER_LEN];
-static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN];
-static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
-#if defined(SPD_spmd)
-static unsigned char sp_pkg_hash_buf[MAX_SP_IDS][HASH_DER_LEN];
-#endif /* SPD_spmd */
-
-static unsigned char trusted_world_pk_buf[PK_DER_LEN];
-static unsigned char content_pk_buf[PK_DER_LEN];
-#endif
-
-/*
- * Parameter type descriptors.
- */
-static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
-static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, 0);
-static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_SIG, 0);
-static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_SIG_ALG, 0);
-static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_RAW_DATA, 0);
-
-static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
-static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
-static auth_param_type_desc_t fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, FW_CONFIG_HASH_OID);
-#ifdef IMAGE_BL1
-static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID);
-static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, AP_FWU_CFG_HASH_OID);
-static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, FWU_HASH_OID);
-#endif /* IMAGE_BL1 */
-
-#ifdef IMAGE_BL2
-static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
-
-static auth_param_type_desc_t trusted_world_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, TRUSTED_WORLD_PK_OID);
-static auth_param_type_desc_t scp_fw_content_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, SCP_FW_CONTENT_CERT_PK_OID);
-static auth_param_type_desc_t soc_fw_content_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, SOC_FW_CONTENT_CERT_PK_OID);
-static auth_param_type_desc_t tos_fw_content_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, TRUSTED_OS_FW_CONTENT_CERT_PK_OID);
-static auth_param_type_desc_t prot_pk = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_PUB_KEY, PROT_PK_OID);
-
-static auth_param_type_desc_t scp_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SCP_FW_HASH_OID);
-static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID);
-static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID);
-static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID);
-static auth_param_type_desc_t tos_fw_extra1_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA1_HASH_OID);
-static auth_param_type_desc_t tos_fw_extra2_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA2_HASH_OID);
-static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
-static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
-#if defined(SPD_spmd)
-static auth_param_type_desc_t sp_pkg1_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG1_HASH_OID);
-static auth_param_type_desc_t sp_pkg2_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG2_HASH_OID);
-static auth_param_type_desc_t sp_pkg3_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG3_HASH_OID);
-static auth_param_type_desc_t sp_pkg4_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG4_HASH_OID);
-static auth_param_type_desc_t sp_pkg5_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG5_HASH_OID);
-static auth_param_type_desc_t sp_pkg6_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG6_HASH_OID);
-static auth_param_type_desc_t sp_pkg7_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG7_HASH_OID);
-static auth_param_type_desc_t sp_pkg8_hash = AUTH_PARAM_TYPE_DESC(
- AUTH_PARAM_HASH, SP_PKG8_HASH_OID);
-#endif /* SPD_spmd */
-#endif /* IMAGE_BL2 */
-
-
-/* BL2 */
-static const auth_img_desc_t trusted_boot_fw_cert = {
- .img_id = TRUSTED_BOOT_FW_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &subject_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &tb_fw_hash,
- .data = {
- .ptr = (void *)tb_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &tb_fw_config_hash,
- .data = {
- .ptr = (void *)tb_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &hw_config_hash,
- .data = {
- .ptr = (void *)hw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &fw_config_hash,
- .data = {
- .ptr = (void *)fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-#ifdef IMAGE_BL1
-static const auth_img_desc_t bl2_image = {
- .img_id = BL2_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_boot_fw_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tb_fw_hash
- }
- }
- }
-};
-#endif /* IMAGE_BL1 */
-
-/* HW Config */
-static const auth_img_desc_t hw_config = {
- .img_id = HW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_boot_fw_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &hw_config_hash
- }
- }
- }
-};
-
-/* TB FW Config */
-#ifdef IMAGE_BL1
-static const auth_img_desc_t tb_fw_config = {
- .img_id = TB_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_boot_fw_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tb_fw_config_hash
- }
- }
- }
-};
-
-static const auth_img_desc_t fw_config = {
- .img_id = FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_boot_fw_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &fw_config_hash
- }
- }
- }
-};
-
-#endif /* IMAGE_BL1 */
-
-#ifdef IMAGE_BL2
-/* Trusted key certificate */
-static const auth_img_desc_t trusted_key_cert = {
- .img_id = TRUSTED_KEY_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &subject_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &trusted_world_pk,
- .data = {
- .ptr = (void *)trusted_world_pk_buf,
- .len = (unsigned int)PK_DER_LEN
- }
- },
- }
-};
-
-/* SCP Firmware */
-static const auth_img_desc_t scp_fw_key_cert = {
- .img_id = SCP_FW_KEY_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &trusted_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &trusted_world_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &scp_fw_content_pk,
- .data = {
- .ptr = (void *)content_pk_buf,
- .len = (unsigned int)PK_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t scp_fw_content_cert = {
- .img_id = SCP_FW_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &scp_fw_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &scp_fw_content_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &scp_fw_hash,
- .data = {
- .ptr = (void *)scp_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t scp_bl2_image = {
- .img_id = SCP_BL2_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &scp_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &scp_fw_hash
- }
- }
- }
-};
-
-/* SoC Firmware */
-static const auth_img_desc_t soc_fw_key_cert = {
- .img_id = SOC_FW_KEY_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &trusted_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &trusted_world_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &soc_fw_content_pk,
- .data = {
- .ptr = (void *)content_pk_buf,
- .len = (unsigned int)PK_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t soc_fw_content_cert = {
- .img_id = SOC_FW_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &soc_fw_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &soc_fw_content_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &soc_fw_hash,
- .data = {
- .ptr = (void *)soc_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &soc_fw_config_hash,
- .data = {
- .ptr = (void *)soc_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t bl31_image = {
- .img_id = BL31_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &soc_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &soc_fw_hash
- }
- }
- }
-};
-
-/* SOC FW Config */
-static const auth_img_desc_t soc_fw_config = {
- .img_id = SOC_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &soc_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &soc_fw_config_hash
- }
- }
- }
-};
-
-/* Trusted OS Firmware */
-static const auth_img_desc_t trusted_os_fw_key_cert = {
- .img_id = TRUSTED_OS_FW_KEY_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &trusted_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &trusted_world_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &tos_fw_content_pk,
- .data = {
- .ptr = (void *)content_pk_buf,
- .len = (unsigned int)PK_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t trusted_os_fw_content_cert = {
- .img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &trusted_os_fw_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &tos_fw_content_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &tos_fw_hash,
- .data = {
- .ptr = (void *)tos_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &tos_fw_extra1_hash,
- .data = {
- .ptr = (void *)tos_fw_extra1_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &tos_fw_extra2_hash,
- .data = {
- .ptr = (void *)tos_fw_extra2_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &tos_fw_config_hash,
- .data = {
- .ptr = (void *)tos_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t bl32_image = {
- .img_id = BL32_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_os_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tos_fw_hash
- }
- }
- }
-};
-
-static const auth_img_desc_t bl32_extra1_image = {
- .img_id = BL32_EXTRA1_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_os_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tos_fw_extra1_hash
- }
- }
- }
-};
-
-static const auth_img_desc_t bl32_extra2_image = {
- .img_id = BL32_EXTRA2_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_os_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tos_fw_extra2_hash
- }
- }
- }
-};
-
-/* TOS FW Config */
-static const auth_img_desc_t tos_fw_config = {
- .img_id = TOS_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &trusted_os_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &tos_fw_config_hash
- }
- }
- }
-};
-
-/* Non-Trusted Firmware */
-static const auth_img_desc_t non_trusted_fw_content_cert = {
- .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL, /* Root certificate. */
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &prot_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &non_trusted_nv_ctr,
- .plat_nv_ctr = &non_trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &nt_world_bl_hash,
- .data = {
- .ptr = (void *)nt_world_bl_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &nt_fw_config_hash,
- .data = {
- .ptr = (void *)nt_fw_config_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-static const auth_img_desc_t bl33_image = {
- .img_id = BL33_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &non_trusted_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &nt_world_bl_hash
- }
- }
- }
-};
-
-/* NT FW Config */
-static const auth_img_desc_t nt_fw_config = {
- .img_id = NT_FW_CONFIG_ID,
- .img_type = IMG_RAW,
- .parent = &non_trusted_fw_content_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &nt_fw_config_hash
- }
- }
- }
-};
-
-/*
- * Secure Partitions
- */
-#if defined(SPD_spmd)
-static const auth_img_desc_t sip_sp_content_cert = {
- .img_id = SIP_SP_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = &trusted_key_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &trusted_world_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &trusted_nv_ctr,
- .plat_nv_ctr = &trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &sp_pkg1_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[0],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &sp_pkg2_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[1],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &sp_pkg3_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[2],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &sp_pkg4_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[3],
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-DEFINE_SIP_SP_PKG(1);
-DEFINE_SIP_SP_PKG(2);
-DEFINE_SIP_SP_PKG(3);
-DEFINE_SIP_SP_PKG(4);
-
-static const auth_img_desc_t plat_sp_content_cert = {
- .img_id = PLAT_SP_CONTENT_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &prot_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- },
- [1] = {
- .type = AUTH_METHOD_NV_CTR,
- .param.nv_ctr = {
- .cert_nv_ctr = &non_trusted_nv_ctr,
- .plat_nv_ctr = &non_trusted_nv_ctr
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &sp_pkg5_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[4],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &sp_pkg6_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[5],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &sp_pkg7_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[6],
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [3] = {
- .type_desc = &sp_pkg8_hash,
- .data = {
- .ptr = (void *)sp_pkg_hash_buf[7],
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-DEFINE_PLAT_SP_PKG(5);
-DEFINE_PLAT_SP_PKG(6);
-DEFINE_PLAT_SP_PKG(7);
-DEFINE_PLAT_SP_PKG(8);
-#endif /* SPD_spmd */
-
-#else /* IMAGE_BL2 */
-
-/* FWU auth descriptor */
-static const auth_img_desc_t fwu_cert = {
- .img_id = FWU_CERT_ID,
- .img_type = IMG_CERT,
- .parent = NULL,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_SIG,
- .param.sig = {
- .pk = &subject_pk,
- .sig = &sig,
- .alg = &sig_alg,
- .data = &raw_data
- }
- }
- },
- .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
- [0] = {
- .type_desc = &scp_bl2u_hash,
- .data = {
- .ptr = (void *)scp_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [1] = {
- .type_desc = &bl2u_hash,
- .data = {
- .ptr = (void *)tb_fw_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- },
- [2] = {
- .type_desc = &ns_bl2u_hash,
- .data = {
- .ptr = (void *)nt_world_bl_hash_buf,
- .len = (unsigned int)HASH_DER_LEN
- }
- }
- }
-};
-
-/* SCP_BL2U */
-static const auth_img_desc_t scp_bl2u_image = {
- .img_id = SCP_BL2U_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &fwu_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &scp_bl2u_hash
- }
- }
- }
-};
-
-/* BL2U */
-static const auth_img_desc_t bl2u_image = {
- .img_id = BL2U_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &fwu_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &bl2u_hash
- }
- }
- }
-};
-
-/* NS_BL2U */
-static const auth_img_desc_t ns_bl2u_image = {
- .img_id = NS_BL2U_IMAGE_ID,
- .img_type = IMG_RAW,
- .parent = &fwu_cert,
- .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
- [0] = {
- .type = AUTH_METHOD_HASH,
- .param.hash = {
- .data = &raw_data,
- .hash = &ns_bl2u_hash
- }
- }
- }
-};
-#endif /* IMAGE_BL2 */
-
-/*
- * Chain of trust definition
- */
-#ifdef IMAGE_BL1
-static const auth_img_desc_t * const cot_desc[] = {
- [TRUSTED_BOOT_FW_CERT_ID] = &trusted_boot_fw_cert,
- [BL2_IMAGE_ID] = &bl2_image,
- [HW_CONFIG_ID] = &hw_config,
- [TB_FW_CONFIG_ID] = &tb_fw_config,
- [FW_CONFIG_ID] = &fw_config,
- [FWU_CERT_ID] = &fwu_cert,
- [SCP_BL2U_IMAGE_ID] = &scp_bl2u_image,
- [BL2U_IMAGE_ID] = &bl2u_image,
- [NS_BL2U_IMAGE_ID] = &ns_bl2u_image
-};
-#else /* IMAGE_BL2 */
-static const auth_img_desc_t * const cot_desc[] = {
- [TRUSTED_BOOT_FW_CERT_ID] = &trusted_boot_fw_cert,
- [HW_CONFIG_ID] = &hw_config,
- [TRUSTED_KEY_CERT_ID] = &trusted_key_cert,
- [SCP_FW_KEY_CERT_ID] = &scp_fw_key_cert,
- [SCP_FW_CONTENT_CERT_ID] = &scp_fw_content_cert,
- [SCP_BL2_IMAGE_ID] = &scp_bl2_image,
- [SOC_FW_KEY_CERT_ID] = &soc_fw_key_cert,
- [SOC_FW_CONTENT_CERT_ID] = &soc_fw_content_cert,
- [BL31_IMAGE_ID] = &bl31_image,
- [SOC_FW_CONFIG_ID] = &soc_fw_config,
- [TRUSTED_OS_FW_KEY_CERT_ID] = &trusted_os_fw_key_cert,
- [TRUSTED_OS_FW_CONTENT_CERT_ID] = &trusted_os_fw_content_cert,
- [BL32_IMAGE_ID] = &bl32_image,
- [BL32_EXTRA1_IMAGE_ID] = &bl32_extra1_image,
- [BL32_EXTRA2_IMAGE_ID] = &bl32_extra2_image,
- [TOS_FW_CONFIG_ID] = &tos_fw_config,
- [NON_TRUSTED_FW_CONTENT_CERT_ID] = &non_trusted_fw_content_cert,
- [BL33_IMAGE_ID] = &bl33_image,
- [NT_FW_CONFIG_ID] = &nt_fw_config,
-#if defined(SPD_spmd)
- [SIP_SP_CONTENT_CERT_ID] = &sip_sp_content_cert,
- [PLAT_SP_CONTENT_CERT_ID] = &plat_sp_content_cert,
- [SP_PKG1_ID] = &sp_pkg1,
- [SP_PKG2_ID] = &sp_pkg2,
- [SP_PKG3_ID] = &sp_pkg3,
- [SP_PKG4_ID] = &sp_pkg4,
- [SP_PKG5_ID] = &sp_pkg5,
- [SP_PKG6_ID] = &sp_pkg6,
- [SP_PKG7_ID] = &sp_pkg7,
- [SP_PKG8_ID] = &sp_pkg8,
-#endif
-};
-#endif
-
-/* Register the CoT in the authentication module */
-REGISTER_COT(cot_desc);
diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
index 7ae9624..d62eed7 100644
--- a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
+++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
@@ -8,6 +8,10 @@
#include <lib/utils_def.h>
#define FXOSC_BASE_ADDR (0x40050000UL)
+#define ARMPLL_BASE_ADDR (0x40038000UL)
+#define ARM_DFS_BASE_ADDR (0x40054000UL)
+#define CGM0_BASE_ADDR (0x40030000UL)
+#define CGM1_BASE_ADDR (0x40034000UL)
/* FXOSC */
#define FXOSC_CTRL(FXOSC) ((FXOSC) + 0x0UL)
@@ -26,4 +30,80 @@
#define FXOSC_STAT(FXOSC) ((FXOSC) + 0x4UL)
#define FXOSC_STAT_OSC_STAT BIT_32(31U)
+/* PLL */
+#define PLLDIG_PLLCR(PLL) ((PLL) + 0x0UL)
+#define PLLDIG_PLLCR_PLLPD BIT_32(31U)
+
+#define PLLDIG_PLLSR(PLL) ((PLL) + 0x4UL)
+#define PLLDIG_PLLSR_LOCK BIT_32(2U)
+
+#define PLLDIG_PLLDV(PLL) ((PLL) + 0x8UL)
+#define PLLDIG_PLLDV_RDIV_OFFSET 12U
+#define PLLDIG_PLLDV_RDIV_MASK GENMASK_32(14U, PLLDIG_PLLDV_RDIV_OFFSET)
+#define PLLDIG_PLLDV_RDIV_SET(VAL) (PLLDIG_PLLDV_RDIV_MASK & \
+ ((VAL) << PLLDIG_PLLDV_RDIV_OFFSET))
+#define PLLDIG_PLLDV_MFI_MASK GENMASK_32(7U, 0U)
+#define PLLDIG_PLLDV_MFI(DIV) (PLLDIG_PLLDV_MFI_MASK & (DIV))
+
+#define PLLDIG_PLLFD(PLL) ((PLL) + 0x10UL)
+#define PLLDIG_PLLFD_SMDEN BIT_32(30U)
+#define PLLDIG_PLLFD_MFN_MASK GENMASK_32(14U, 0U)
+#define PLLDIG_PLLFD_MFN_SET(VAL) (PLLDIG_PLLFD_MFN_MASK & (VAL))
+
+#define PLLDIG_PLLCLKMUX(PLL) ((PLL) + 0x20UL)
+
+#define PLLDIG_PLLODIV(PLL, N) ((PLL) + 0x80UL + ((N) * 0x4UL))
+#define PLLDIG_PLLODIV_DE BIT_32(31U)
+#define PLLDIG_PLLODIV_DIV_OFFSET 16U
+#define PLLDIG_PLLODIV_DIV_MASK GENMASK_32(23U, PLLDIG_PLLODIV_DIV_OFFSET)
+#define PLLDIG_PLLODIV_DIV(VAL) (((VAL) & PLLDIG_PLLODIV_DIV_MASK) >> \
+ PLLDIG_PLLODIV_DIV_OFFSET)
+#define PLLDIG_PLLODIV_DIV_SET(VAL) (PLLDIG_PLLODIV_DIV_MASK & ((VAL) << \
+ PLLDIG_PLLODIV_DIV_OFFSET))
+
+/* MMC_CGM */
+#define CGM_MUXn_CSC(CGM_ADDR, MUX) ((CGM_ADDR) + 0x300UL + ((MUX) * 0x40UL))
+#define MC_CGM_MUXn_CSC_SELCTL_OFFSET 24U
+#define MC_CGM_MUXn_CSC_SELCTL_MASK GENMASK_32(29U, MC_CGM_MUXn_CSC_SELCTL_OFFSET)
+#define MC_CGM_MUXn_CSC_SELCTL(val) (MC_CGM_MUXn_CSC_SELCTL_MASK & ((val) \
+ << MC_CGM_MUXn_CSC_SELCTL_OFFSET))
+#define MC_CGM_MUXn_CSC_CLK_SW BIT_32(2U)
+#define MC_CGM_MUXn_CSC_SAFE_SW BIT_32(3U)
+
+#define CGM_MUXn_CSS(CGM_ADDR, MUX) ((CGM_ADDR) + 0x304UL + ((MUX) * 0x40UL))
+#define MC_CGM_MUXn_CSS_SELSTAT_OFFSET 24U
+#define MC_CGM_MUXn_CSS_SELSTAT_MASK GENMASK_32(29U, MC_CGM_MUXn_CSS_SELSTAT_OFFSET)
+#define MC_CGM_MUXn_CSS_SELSTAT(css) ((MC_CGM_MUXn_CSS_SELSTAT_MASK & (css))\
+ >> MC_CGM_MUXn_CSS_SELSTAT_OFFSET)
+#define MC_CGM_MUXn_CSS_SWTRG(css) ((MC_CGM_MUXn_CSS_SWTRG_MASK & (css)) \
+ >> MC_CGM_MUXn_CSS_SWTRG_OFFSET)
+#define MC_CGM_MUXn_CSS_SWTRG_OFFSET 17U
+#define MC_CGM_MUXn_CSS_SWTRG_MASK GENMASK_32(19U, MC_CGM_MUXn_CSS_SWTRG_OFFSET)
+#define MC_CGM_MUXn_CSS_SWTRG_SUCCESS 0x1U
+#define MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK 0x4U
+#define MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE 0x5U
+#define MC_CGM_MUXn_CSS_SWIP BIT_32(16U)
+#define MC_CGM_MUXn_CSS_SAFE_SW BIT_32(3U)
+
+/* DFS */
+#define DFS_PORTSR(DFS_ADDR) ((DFS_ADDR) + 0xCUL)
+#define DFS_PORTOLSR(DFS_ADDR) ((DFS_ADDR) + 0x10UL)
+#define DFS_PORTOLSR_LOL(N) (BIT_32(N) & GENMASK_32(5U, 0U))
+#define DFS_PORTRESET(DFS_ADDR) ((DFS_ADDR) + 0x14UL)
+#define DFS_PORTRESET_MASK GENMASK_32(5U, 0U)
+#define DFS_PORTRESET_SET(VAL) (((VAL) & DFS_PORTRESET_MASK))
+
+#define DFS_CTL(DFS_ADDR) ((DFS_ADDR) + 0x18UL)
+#define DFS_CTL_RESET BIT_32(1U)
+
+#define DFS_DVPORTn(DFS_ADDR, PORT) ((DFS_ADDR) + 0x1CUL + ((PORT) * 0x4UL))
+#define DFS_DVPORTn_MFI_MASK GENMASK_32(15U, 8U)
+#define DFS_DVPORTn_MFI_SHIFT 8U
+#define DFS_DVPORTn_MFN_MASK GENMASK_32(7U, 0U)
+#define DFS_DVPORTn_MFN_SHIFT 0U
+#define DFS_DVPORTn_MFI(MFI) (((MFI) & DFS_DVPORTn_MFI_MASK) >> DFS_DVPORTn_MFI_SHIFT)
+#define DFS_DVPORTn_MFN(MFN) (((MFN) & DFS_DVPORTn_MFN_MASK) >> DFS_DVPORTn_MFN_SHIFT)
+#define DFS_DVPORTn_MFI_SET(VAL) (((VAL) << DFS_DVPORTn_MFI_SHIFT) & DFS_DVPORTn_MFI_MASK)
+#define DFS_DVPORTn_MFN_SET(VAL) (((VAL) << DFS_DVPORTn_MFN_SHIFT) & DFS_DVPORTn_MFN_MASK)
+
#endif /* S32CC_CLK_REGS_H */
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index f35a469..e23d928 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -10,13 +10,21 @@
#include <common/debug.h>
#include <drivers/clk.h>
#include <lib/mmio.h>
+#include <s32cc-clk-ids.h>
#include <s32cc-clk-modules.h>
#include <s32cc-clk-utils.h>
#define MAX_STACK_DEPTH (15U)
+/* This is used for floating-point precision calculations. */
+#define FP_PRECISION (100000000UL)
+
struct s32cc_clk_drv {
uintptr_t fxosc_base;
+ uintptr_t armpll_base;
+ uintptr_t armdfs_base;
+ uintptr_t cgm0_base;
+ uintptr_t cgm1_base;
};
static int update_stack_depth(unsigned int *depth)
@@ -33,6 +41,10 @@
{
static struct s32cc_clk_drv driver = {
.fxosc_base = FXOSC_BASE_ADDR,
+ .armpll_base = ARMPLL_BASE_ADDR,
+ .armdfs_base = ARM_DFS_BASE_ADDR,
+ .cgm0_base = CGM0_BASE_ADDR,
+ .cgm1_base = CGM1_BASE_ADDR,
};
return &driver;
@@ -67,6 +79,43 @@
return -EINVAL;
}
+static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv,
+ uintptr_t *base)
+{
+ int ret = 0;
+
+ switch (id) {
+ case S32CC_FXOSC:
+ *base = drv->fxosc_base;
+ break;
+ case S32CC_ARM_PLL:
+ *base = drv->armpll_base;
+ break;
+ case S32CC_ARM_DFS:
+ *base = drv->armdfs_base;
+ break;
+ case S32CC_CGM0:
+ *base = drv->cgm0_base;
+ break;
+ case S32CC_CGM1:
+ *base = drv->cgm1_base;
+ break;
+ case S32CC_FIRC:
+ break;
+ case S32CC_SIRC:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret != 0) {
+ ERROR("Unknown clock source id: %u\n", id);
+ }
+
+ return ret;
+}
+
static void enable_fxosc(const struct s32cc_clk_drv *drv)
{
uintptr_t fxosc_base = drv->fxosc_base;
@@ -121,6 +170,593 @@
return ret;
}
+static int get_pll_mfi_mfn(unsigned long pll_vco, unsigned long ref_freq,
+ uint32_t *mfi, uint32_t *mfn)
+
+{
+ unsigned long vco;
+ unsigned long mfn64;
+
+ /* FRAC-N mode */
+ *mfi = (uint32_t)(pll_vco / ref_freq);
+
+ /* MFN formula : (double)(pll_vco % ref_freq) / ref_freq * 18432.0 */
+ mfn64 = pll_vco % ref_freq;
+ mfn64 *= FP_PRECISION;
+ mfn64 /= ref_freq;
+ mfn64 *= 18432UL;
+ mfn64 /= FP_PRECISION;
+
+ if (mfn64 > UINT32_MAX) {
+ return -EINVAL;
+ }
+
+ *mfn = (uint32_t)mfn64;
+
+ vco = ((unsigned long)*mfn * FP_PRECISION) / 18432UL;
+ vco += (unsigned long)*mfi * FP_PRECISION;
+ vco *= ref_freq;
+ vco /= FP_PRECISION;
+
+ if (vco != pll_vco) {
+ ERROR("Failed to find MFI and MFN settings for PLL freq %lu. Nearest freq = %lu\n",
+ pll_vco, vco);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct s32cc_clkmux *get_pll_mux(const struct s32cc_pll *pll)
+{
+ const struct s32cc_clk_obj *source = pll->source;
+ const struct s32cc_clk *clk;
+
+ if (source == NULL) {
+ ERROR("Failed to identify PLL's parent\n");
+ return NULL;
+ }
+
+ if (source->type != s32cc_clk_t) {
+ ERROR("The parent of the PLL isn't a clock\n");
+ return NULL;
+ }
+
+ clk = s32cc_obj2clk(source);
+
+ if (clk->module == NULL) {
+ ERROR("The clock isn't connected to a module\n");
+ return NULL;
+ }
+
+ source = clk->module;
+
+ if ((source->type != s32cc_clkmux_t) &&
+ (source->type != s32cc_shared_clkmux_t)) {
+ ERROR("The parent of the PLL isn't a MUX\n");
+ return NULL;
+ }
+
+ return s32cc_obj2clkmux(source);
+}
+
+static void disable_odiv(uintptr_t pll_addr, uint32_t div_index)
+{
+ mmio_clrbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
+}
+
+static void enable_odiv(uintptr_t pll_addr, uint32_t div_index)
+{
+ mmio_setbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
+}
+
+static void disable_odivs(uintptr_t pll_addr, uint32_t ndivs)
+{
+ uint32_t i;
+
+ for (i = 0; i < ndivs; i++) {
+ disable_odiv(pll_addr, i);
+ }
+}
+
+static void enable_pll_hw(uintptr_t pll_addr)
+{
+ /* Enable the PLL. */
+ mmio_write_32(PLLDIG_PLLCR(pll_addr), 0x0);
+
+ /* Poll until PLL acquires lock. */
+ while ((mmio_read_32(PLLDIG_PLLSR(pll_addr)) & PLLDIG_PLLSR_LOCK) == 0U) {
+ }
+}
+
+static void disable_pll_hw(uintptr_t pll_addr)
+{
+ mmio_write_32(PLLDIG_PLLCR(pll_addr), PLLDIG_PLLCR_PLLPD);
+}
+
+static int program_pll(const struct s32cc_pll *pll, uintptr_t pll_addr,
+ const struct s32cc_clk_drv *drv, uint32_t sclk_id,
+ unsigned long sclk_freq)
+{
+ uint32_t rdiv = 1, mfi, mfn;
+ int ret;
+
+ ret = get_pll_mfi_mfn(pll->vco_freq, sclk_freq, &mfi, &mfn);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ /* Disable ODIVs*/
+ disable_odivs(pll_addr, pll->ndividers);
+
+ /* Disable PLL */
+ disable_pll_hw(pll_addr);
+
+ /* Program PLLCLKMUX */
+ mmio_write_32(PLLDIG_PLLCLKMUX(pll_addr), sclk_id);
+
+ /* Program VCO */
+ mmio_clrsetbits_32(PLLDIG_PLLDV(pll_addr),
+ PLLDIG_PLLDV_RDIV_MASK | PLLDIG_PLLDV_MFI_MASK,
+ PLLDIG_PLLDV_RDIV_SET(rdiv) | PLLDIG_PLLDV_MFI(mfi));
+
+ mmio_write_32(PLLDIG_PLLFD(pll_addr),
+ PLLDIG_PLLFD_MFN_SET(mfn) | PLLDIG_PLLFD_SMDEN);
+
+ enable_pll_hw(pll_addr);
+
+ return ret;
+}
+
+static int enable_pll(const struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int *depth)
+{
+ const struct s32cc_pll *pll = s32cc_obj2pll(module);
+ const struct s32cc_clkmux *mux;
+ uintptr_t pll_addr = UL(0x0);
+ unsigned long sclk_freq;
+ uint32_t sclk_id;
+ int ret;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mux = get_pll_mux(pll);
+ if (mux == NULL) {
+ return -EINVAL;
+ }
+
+ if (pll->instance != mux->module) {
+ ERROR("MUX type is not in sync with PLL ID\n");
+ return -EINVAL;
+ }
+
+ ret = get_base_addr(pll->instance, drv, &pll_addr);
+ if (ret != 0) {
+ ERROR("Failed to detect PLL instance\n");
+ return ret;
+ }
+
+ switch (mux->source_id) {
+ case S32CC_CLK_FIRC:
+ sclk_freq = 48U * MHZ;
+ sclk_id = 0;
+ break;
+ case S32CC_CLK_FXOSC:
+ sclk_freq = 40U * MHZ;
+ sclk_id = 1;
+ break;
+ default:
+ ERROR("Invalid source selection for PLL 0x%lx\n",
+ pll_addr);
+ return -EINVAL;
+ };
+
+ return program_pll(pll, pll_addr, drv, sclk_id, sclk_freq);
+}
+
+static inline struct s32cc_pll *get_div_pll(const struct s32cc_pll_out_div *pdiv)
+{
+ const struct s32cc_clk_obj *parent;
+
+ parent = pdiv->parent;
+ if (parent == NULL) {
+ ERROR("Failed to identify PLL divider's parent\n");
+ return NULL;
+ }
+
+ if (parent->type != s32cc_pll_t) {
+ ERROR("The parent of the divider is not a PLL instance\n");
+ return NULL;
+ }
+
+ return s32cc_obj2pll(parent);
+}
+
+static void config_pll_out_div(uintptr_t pll_addr, uint32_t div_index, uint32_t dc)
+{
+ uint32_t pllodiv;
+ uint32_t pdiv;
+
+ pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, div_index));
+ pdiv = PLLDIG_PLLODIV_DIV(pllodiv);
+
+ if (((pdiv + 1U) == dc) && ((pllodiv & PLLDIG_PLLODIV_DE) != 0U)) {
+ return;
+ }
+
+ if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) {
+ disable_odiv(pll_addr, div_index);
+ }
+
+ pllodiv = PLLDIG_PLLODIV_DIV_SET(dc - 1U);
+ mmio_write_32(PLLDIG_PLLODIV(pll_addr, div_index), pllodiv);
+
+ enable_odiv(pll_addr, div_index);
+}
+
+static int enable_pll_div(const struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int *depth)
+{
+ const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
+ uintptr_t pll_addr = 0x0ULL;
+ const struct s32cc_pll *pll;
+ uint32_t dc;
+ int ret;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ pll = get_div_pll(pdiv);
+ if (pll == NULL) {
+ ERROR("The parent of the PLL DIV is invalid\n");
+ return 0;
+ }
+
+ ret = get_base_addr(pll->instance, drv, &pll_addr);
+ if (ret != 0) {
+ ERROR("Failed to detect PLL instance\n");
+ return -EINVAL;
+ }
+
+ dc = (uint32_t)(pll->vco_freq / pdiv->freq);
+
+ config_pll_out_div(pll_addr, pdiv->index, dc);
+
+ return 0;
+}
+
+static int cgm_mux_clk_config(uintptr_t cgm_addr, uint32_t mux, uint32_t source,
+ bool safe_clk)
+{
+ uint32_t css, csc;
+
+ css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux));
+
+ /* Already configured */
+ if ((MC_CGM_MUXn_CSS_SELSTAT(css) == source) &&
+ (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) &&
+ ((css & MC_CGM_MUXn_CSS_SWIP) == 0U) && !safe_clk) {
+ return 0;
+ }
+
+ /* Ongoing clock switch? */
+ while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) &
+ MC_CGM_MUXn_CSS_SWIP) != 0U) {
+ }
+
+ csc = mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux));
+
+ /* Clear previous source. */
+ csc &= ~(MC_CGM_MUXn_CSC_SELCTL_MASK);
+
+ if (!safe_clk) {
+ /* Select the clock source and trigger the clock switch. */
+ csc |= MC_CGM_MUXn_CSC_SELCTL(source) | MC_CGM_MUXn_CSC_CLK_SW;
+ } else {
+ /* Switch to safe clock */
+ csc |= MC_CGM_MUXn_CSC_SAFE_SW;
+ }
+
+ mmio_write_32(CGM_MUXn_CSC(cgm_addr, mux), csc);
+
+ /* Wait for configuration bit to auto-clear. */
+ while ((mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux)) &
+ MC_CGM_MUXn_CSC_CLK_SW) != 0U) {
+ }
+
+ /* Is the clock switch completed? */
+ while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) &
+ MC_CGM_MUXn_CSS_SWIP) != 0U) {
+ }
+
+ /*
+ * Check if the switch succeeded.
+ * Check switch trigger cause and the source.
+ */
+ css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux));
+ if (!safe_clk) {
+ if ((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) &&
+ (MC_CGM_MUXn_CSS_SELSTAT(css) == source)) {
+ return 0;
+ }
+
+ ERROR("Failed to change the source of mux %" PRIu32 " to %" PRIu32 " (CGM=%lu)\n",
+ mux, source, cgm_addr);
+ } else {
+ if (((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK) ||
+ (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE)) &&
+ ((MC_CGM_MUXn_CSS_SAFE_SW & css) != 0U)) {
+ return 0;
+ }
+
+ ERROR("The switch of mux %" PRIu32 " (CGM=%lu) to safe clock failed\n",
+ mux, cgm_addr);
+ }
+
+ return -EINVAL;
+}
+
+static int enable_cgm_mux(const struct s32cc_clkmux *mux,
+ const struct s32cc_clk_drv *drv)
+{
+ uintptr_t cgm_addr = UL(0x0);
+ uint32_t mux_hw_clk;
+ int ret;
+
+ ret = get_base_addr(mux->module, drv, &cgm_addr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mux_hw_clk = (uint32_t)S32CC_CLK_ID(mux->source_id);
+
+ return cgm_mux_clk_config(cgm_addr, mux->index,
+ mux_hw_clk, false);
+}
+
+static int enable_mux(const struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int *depth)
+{
+ const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
+ const struct s32cc_clk *clk;
+ int ret = 0;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (mux == NULL) {
+ return -EINVAL;
+ }
+
+ clk = s32cc_get_arch_clk(mux->source_id);
+ if (clk == NULL) {
+ ERROR("Invalid parent (%lu) for mux %" PRIu8 "\n",
+ mux->source_id, mux->index);
+ return -EINVAL;
+ }
+
+ switch (mux->module) {
+ /* PLL mux will be enabled by PLL setup */
+ case S32CC_ARM_PLL:
+ break;
+ case S32CC_CGM1:
+ ret = enable_cgm_mux(mux, drv);
+ break;
+ case S32CC_CGM0:
+ ret = enable_cgm_mux(mux, drv);
+ break;
+ default:
+ ERROR("Unknown mux parent type: %d\n", mux->module);
+ ret = -EINVAL;
+ break;
+ };
+
+ return ret;
+}
+
+static int enable_dfs(const struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int *depth)
+{
+ int ret = 0;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct s32cc_dfs *get_div_dfs(const struct s32cc_dfs_div *dfs_div)
+{
+ const struct s32cc_clk_obj *parent = dfs_div->parent;
+
+ if (parent->type != s32cc_dfs_t) {
+ ERROR("DFS DIV doesn't have a DFS as parent\n");
+ return NULL;
+ }
+
+ return s32cc_obj2dfs(parent);
+}
+
+static struct s32cc_pll *dfsdiv2pll(const struct s32cc_dfs_div *dfs_div)
+{
+ const struct s32cc_clk_obj *parent;
+ const struct s32cc_dfs *dfs;
+
+ dfs = get_div_dfs(dfs_div);
+ if (dfs == NULL) {
+ return NULL;
+ }
+
+ parent = dfs->parent;
+ if (parent->type != s32cc_pll_t) {
+ return NULL;
+ }
+
+ return s32cc_obj2pll(parent);
+}
+
+static int get_dfs_mfi_mfn(unsigned long dfs_freq, const struct s32cc_dfs_div *dfs_div,
+ uint32_t *mfi, uint32_t *mfn)
+{
+ uint64_t factor64, tmp64, ofreq;
+ uint32_t factor32;
+
+ unsigned long in = dfs_freq;
+ unsigned long out = dfs_div->freq;
+
+ /**
+ * factor = (IN / OUT) / 2
+ * MFI = integer(factor)
+ * MFN = (factor - MFI) * 36
+ */
+ factor64 = ((((uint64_t)in) * FP_PRECISION) / ((uint64_t)out)) / 2ULL;
+ tmp64 = factor64 / FP_PRECISION;
+ if (tmp64 > UINT32_MAX) {
+ return -EINVAL;
+ }
+
+ factor32 = (uint32_t)tmp64;
+ *mfi = factor32;
+
+ tmp64 = ((factor64 - ((uint64_t)*mfi * FP_PRECISION)) * 36UL) / FP_PRECISION;
+ if (tmp64 > UINT32_MAX) {
+ return -EINVAL;
+ }
+
+ *mfn = (uint32_t)tmp64;
+
+ /* div_freq = in / (2 * (*mfi + *mfn / 36.0)) */
+ factor64 = (((uint64_t)*mfn) * FP_PRECISION) / 36ULL;
+ factor64 += ((uint64_t)*mfi) * FP_PRECISION;
+ factor64 *= 2ULL;
+ ofreq = (((uint64_t)in) * FP_PRECISION) / factor64;
+
+ if (ofreq != dfs_div->freq) {
+ ERROR("Failed to find MFI and MFN settings for DFS DIV freq %lu\n",
+ dfs_div->freq);
+ ERROR("Nearest freq = %" PRIx64 "\n", ofreq);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int init_dfs_port(uintptr_t dfs_addr, uint32_t port,
+ uint32_t mfi, uint32_t mfn)
+{
+ uint32_t portsr, portolsr;
+ uint32_t mask, old_mfi, old_mfn;
+ uint32_t dvport;
+ bool init_dfs;
+
+ dvport = mmio_read_32(DFS_DVPORTn(dfs_addr, port));
+
+ old_mfi = DFS_DVPORTn_MFI(dvport);
+ old_mfn = DFS_DVPORTn_MFN(dvport);
+
+ portsr = mmio_read_32(DFS_PORTSR(dfs_addr));
+ portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr));
+
+ /* Skip configuration if it's not needed */
+ if (((portsr & BIT_32(port)) != 0U) &&
+ ((portolsr & BIT_32(port)) == 0U) &&
+ (mfi == old_mfi) && (mfn == old_mfn)) {
+ return 0;
+ }
+
+ init_dfs = (portsr == 0U);
+
+ if (init_dfs) {
+ mask = DFS_PORTRESET_MASK;
+ } else {
+ mask = DFS_PORTRESET_SET(BIT_32(port));
+ }
+
+ mmio_write_32(DFS_PORTOLSR(dfs_addr), mask);
+ mmio_write_32(DFS_PORTRESET(dfs_addr), mask);
+
+ while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & mask) != 0U) {
+ }
+
+ if (init_dfs) {
+ mmio_write_32(DFS_CTL(dfs_addr), DFS_CTL_RESET);
+ }
+
+ mmio_write_32(DFS_DVPORTn(dfs_addr, port),
+ DFS_DVPORTn_MFI_SET(mfi) | DFS_DVPORTn_MFN_SET(mfn));
+
+ if (init_dfs) {
+ /* DFS clk enable programming */
+ mmio_clrbits_32(DFS_CTL(dfs_addr), DFS_CTL_RESET);
+ }
+
+ mmio_clrbits_32(DFS_PORTRESET(dfs_addr), BIT_32(port));
+
+ while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & BIT_32(port)) != BIT_32(port)) {
+ }
+
+ portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr));
+ if ((portolsr & DFS_PORTOLSR_LOL(port)) != 0U) {
+ ERROR("Failed to lock DFS divider\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int enable_dfs_div(const struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int *depth)
+{
+ const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
+ const struct s32cc_pll *pll;
+ const struct s32cc_dfs *dfs;
+ uintptr_t dfs_addr = 0UL;
+ uint32_t mfi, mfn;
+ int ret = 0;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ dfs = get_div_dfs(dfs_div);
+ if (dfs == NULL) {
+ return -EINVAL;
+ }
+
+ pll = dfsdiv2pll(dfs_div);
+ if (pll == NULL) {
+ ERROR("Failed to identify DFS divider's parent\n");
+ return -EINVAL;
+ }
+
+ ret = get_base_addr(dfs->instance, drv, &dfs_addr);
+ if ((ret != 0) || (dfs_addr == 0UL)) {
+ return -EINVAL;
+ }
+
+ ret = get_dfs_mfi_mfn(pll->vco_freq, dfs_div, &mfi, &mfn);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ return init_dfs_port(dfs_addr, dfs_div->index, mfi, mfn);
+}
+
static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
{
const struct s32cc_clk_drv *drv = get_drv();
@@ -142,19 +778,27 @@
case s32cc_clk_t:
ret = enable_clk_module(module, drv, depth);
break;
+ case s32cc_pll_t:
+ ret = enable_pll(module, drv, depth);
+ break;
+ case s32cc_pll_out_div_t:
+ ret = enable_pll_div(module, drv, depth);
+ break;
case s32cc_clkmux_t:
- ret = -ENOTSUP;
+ ret = enable_mux(module, drv, depth);
break;
case s32cc_shared_clkmux_t:
- ret = -ENOTSUP;
+ ret = enable_mux(module, drv, depth);
break;
- case s32cc_pll_t:
- ret = -ENOTSUP;
- break;
- case s32cc_pll_out_div_t:
case s32cc_fixed_div_t:
ret = -ENOTSUP;
break;
+ case s32cc_dfs_t:
+ ret = enable_dfs(module, drv, depth);
+ break;
+ case s32cc_dfs_div_t:
+ ret = enable_dfs_div(module, drv, depth);
+ break;
default:
ret = -EINVAL;
break;
@@ -340,6 +984,63 @@
return ret;
}
+static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate,
+ unsigned long *orate, unsigned int *depth)
+{
+ const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
+ const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id);
+ int ret;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (clk == NULL) {
+ ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n",
+ mux->index, mux->source_id);
+ return -EINVAL;
+ }
+
+ return set_module_rate(&clk->desc, rate, orate, depth);
+}
+
+static int set_dfs_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
+ unsigned long *orate, unsigned int *depth)
+{
+ struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
+ const struct s32cc_dfs *dfs;
+ int ret;
+
+ ret = update_stack_depth(depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (dfs_div->parent == NULL) {
+ ERROR("Failed to identify DFS divider's parent\n");
+ return -EINVAL;
+ }
+
+ /* Sanity check */
+ dfs = s32cc_obj2dfs(dfs_div->parent);
+ if (dfs->parent == NULL) {
+ ERROR("Failed to identify DFS's parent\n");
+ return -EINVAL;
+ }
+
+ if ((dfs_div->freq != 0U) && (dfs_div->freq != rate)) {
+ ERROR("DFS DIV frequency was already set to %lu\n",
+ dfs_div->freq);
+ return -EINVAL;
+ }
+
+ dfs_div->freq = rate;
+ *orate = rate;
+
+ return ret;
+}
+
static int set_module_rate(const struct s32cc_clk_obj *module,
unsigned long rate, unsigned long *orate,
unsigned int *depth)
@@ -351,6 +1052,8 @@
return ret;
}
+ ret = -EINVAL;
+
switch (module->type) {
case s32cc_clk_t:
ret = set_clk_freq(module, rate, orate, depth);
@@ -368,11 +1071,18 @@
ret = set_fixed_div_freq(module, rate, orate, depth);
break;
case s32cc_clkmux_t:
+ ret = set_mux_freq(module, rate, orate, depth);
+ break;
case s32cc_shared_clkmux_t:
- ret = -ENOTSUP;
+ ret = set_mux_freq(module, rate, orate, depth);
+ break;
+ case s32cc_dfs_t:
+ ERROR("Setting the frequency of a DFS is not allowed!");
+ break;
+ case s32cc_dfs_div_t:
+ ret = set_dfs_div_freq(module, rate, orate, depth);
break;
default:
- ret = -EINVAL;
break;
}
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
index 039db2a..c4c73c7 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
@@ -43,6 +43,45 @@
static struct s32cc_clk arm_pll_phi0_clk =
S32CC_FREQ_MODULE_CLK(arm_pll_phi0_div, 0, GHZ);
+/* ARM DFS */
+static struct s32cc_dfs armdfs =
+ S32CC_DFS_INIT(armpll, S32CC_ARM_DFS);
+static struct s32cc_dfs_div arm_dfs1_div =
+ S32CC_DFS_DIV_INIT(armdfs, 0);
+static struct s32cc_clk arm_dfs1_clk =
+ S32CC_FREQ_MODULE_CLK(arm_dfs1_div, 0, 800 * MHZ);
+
+/* MC_CGM0 */
+static struct s32cc_clkmux cgm0_mux0 =
+ S32CC_SHARED_CLKMUX_INIT(S32CC_CGM0, 0, 2,
+ S32CC_CLK_FIRC,
+ S32CC_CLK_ARM_PLL_DFS1, 0, 0, 0);
+static struct s32cc_clk cgm0_mux0_clk = S32CC_MODULE_CLK(cgm0_mux0);
+
+/* XBAR */
+static struct s32cc_clk xbar_2x_clk =
+ S32CC_CHILD_CLK(cgm0_mux0_clk, 48 * MHZ, 800 * MHZ);
+static struct s32cc_fixed_div xbar_div2 =
+ S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 2);
+static struct s32cc_clk xbar_clk =
+ S32CC_FREQ_MODULE_CLK(xbar_div2, 24 * MHZ, 400 * MHZ);
+static struct s32cc_fixed_div xbar_div4 =
+ S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 4);
+static struct s32cc_clk xbar_div2_clk =
+ S32CC_FREQ_MODULE_CLK(xbar_div4, 12 * MHZ, 200 * MHZ);
+static struct s32cc_fixed_div xbar_div6 =
+ S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 6);
+static struct s32cc_clk xbar_div3_clk =
+ S32CC_FREQ_MODULE_CLK(xbar_div6, 8 * MHZ, 133333333);
+static struct s32cc_fixed_div xbar_div8 =
+ S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 8);
+static struct s32cc_clk xbar_div4_clk =
+ S32CC_FREQ_MODULE_CLK(xbar_div8, 6 * MHZ, 100 * MHZ);
+static struct s32cc_fixed_div xbar_div12 =
+ S32CC_FIXED_DIV_INIT(cgm0_mux0_clk, 12);
+static struct s32cc_clk xbar_div6_clk =
+ S32CC_FREQ_MODULE_CLK(xbar_div12, 4 * MHZ, 66666666);
+
/* MC_CGM1 */
static struct s32cc_clkmux cgm1_mux0 =
S32CC_SHARED_CLKMUX_INIT(S32CC_CGM1, 0, 3,
@@ -68,13 +107,15 @@
S32CC_FREQ_MODULE_CLK(a53_core_div10, S32CC_A53_MIN_FREQ / 10,
S32CC_A53_MAX_FREQ / 10);
-static struct s32cc_clk *s32cc_hw_clk_list[5] = {
+static struct s32cc_clk *s32cc_hw_clk_list[13] = {
/* Oscillators */
[S32CC_CLK_ID(S32CC_CLK_FIRC)] = &firc_clk,
[S32CC_CLK_ID(S32CC_CLK_SIRC)] = &sirc_clk,
[S32CC_CLK_ID(S32CC_CLK_FXOSC)] = &fxosc_clk,
/* ARM PLL */
[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_PHI0)] = &arm_pll_phi0_clk,
+ /* ARM DFS */
+ [S32CC_CLK_ID(S32CC_CLK_ARM_PLL_DFS1)] = &arm_dfs1_clk,
};
static struct s32cc_clk_array s32cc_hw_clocks = {
@@ -83,10 +124,19 @@
.n_clks = ARRAY_SIZE(s32cc_hw_clk_list),
};
-static struct s32cc_clk *s32cc_arch_clk_list[6] = {
+static struct s32cc_clk *s32cc_arch_clk_list[13] = {
/* ARM PLL */
[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_MUX)] = &arm_pll_mux_clk,
[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_VCO)] = &arm_pll_vco_clk,
+ /* MC_CGM0 */
+ [S32CC_CLK_ID(S32CC_CLK_MC_CGM0_MUX0)] = &cgm0_mux0_clk,
+ /* XBAR */
+ [S32CC_CLK_ID(S32CC_CLK_XBAR_2X)] = &xbar_2x_clk,
+ [S32CC_CLK_ID(S32CC_CLK_XBAR)] = &xbar_clk,
+ [S32CC_CLK_ID(S32CC_CLK_XBAR_DIV2)] = &xbar_div2_clk,
+ [S32CC_CLK_ID(S32CC_CLK_XBAR_DIV3)] = &xbar_div3_clk,
+ [S32CC_CLK_ID(S32CC_CLK_XBAR_DIV4)] = &xbar_div4_clk,
+ [S32CC_CLK_ID(S32CC_CLK_XBAR_DIV6)] = &xbar_div6_clk,
/* MC_CGM1 */
[S32CC_CLK_ID(S32CC_CLK_MC_CGM1_MUX0)] = &cgm1_mux0_clk,
/* A53 */
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index ac1f7d0..2c256a5 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -11,39 +11,129 @@
#define S32CC_FXOSC_FREQ (40U * MHZ)
#define S32CC_ARM_PLL_VCO_FREQ (2U * GHZ)
#define S32CC_ARM_PLL_PHI0_FREQ (1U * GHZ)
+#define S32CC_A53_FREQ (1U * GHZ)
+#define S32CC_XBAR_2X_FREQ (800U * MHZ)
-int s32cc_init_early_clks(void)
+static int enable_fxosc_clk(void)
{
int ret;
- s32cc_clk_register_drv();
+ ret = clk_set_rate(S32CC_CLK_FXOSC, S32CC_FXOSC_FREQ, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_enable(S32CC_CLK_FXOSC);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return ret;
+}
+
+static int enable_arm_pll(void)
+{
+ int ret;
ret = clk_set_parent(S32CC_CLK_ARM_PLL_MUX, S32CC_CLK_FXOSC);
if (ret != 0) {
return ret;
}
+ ret = clk_set_rate(S32CC_CLK_ARM_PLL_VCO, S32CC_ARM_PLL_VCO_FREQ, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_set_rate(S32CC_CLK_ARM_PLL_PHI0, S32CC_ARM_PLL_PHI0_FREQ, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_enable(S32CC_CLK_ARM_PLL_VCO);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_enable(S32CC_CLK_ARM_PLL_PHI0);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return ret;
+}
+
+static int enable_a53_clk(void)
+{
+ int ret;
+
ret = clk_set_parent(S32CC_CLK_MC_CGM1_MUX0, S32CC_CLK_ARM_PLL_PHI0);
if (ret != 0) {
return ret;
}
- ret = clk_set_rate(S32CC_CLK_FXOSC, S32CC_FXOSC_FREQ, NULL);
+ ret = clk_set_rate(S32CC_CLK_A53_CORE, S32CC_A53_FREQ, NULL);
if (ret != 0) {
return ret;
}
- ret = clk_set_rate(S32CC_CLK_ARM_PLL_VCO, S32CC_ARM_PLL_VCO_FREQ, NULL);
+ ret = clk_enable(S32CC_CLK_A53_CORE);
if (ret != 0) {
return ret;
}
- ret = clk_set_rate(S32CC_CLK_ARM_PLL_PHI0, S32CC_ARM_PLL_PHI0_FREQ, NULL);
+ return ret;
+}
+
+static int enable_xbar_clk(void)
+{
+ int ret;
+
+ ret = clk_set_parent(S32CC_CLK_MC_CGM0_MUX0, S32CC_CLK_ARM_PLL_DFS1);
if (ret != 0) {
return ret;
}
- ret = clk_enable(S32CC_CLK_FXOSC);
+ ret = clk_set_rate(S32CC_CLK_XBAR_2X, S32CC_XBAR_2X_FREQ, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_enable(S32CC_CLK_ARM_PLL_DFS1);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = clk_enable(S32CC_CLK_XBAR_2X);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return ret;
+}
+
+int s32cc_init_early_clks(void)
+{
+ int ret;
+
+ s32cc_clk_register_drv();
+
+ ret = enable_fxosc_clk();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = enable_arm_pll();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = enable_a53_clk();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = enable_xbar_clk();
if (ret != 0) {
return ret;
}
diff --git a/fdts/cca_cot_descriptors.dtsi b/fdts/cca_cot_descriptors.dtsi
index 821f600..93d60ea 100644
--- a/fdts/cca_cot_descriptors.dtsi
+++ b/fdts/cca_cot_descriptors.dtsi
@@ -15,7 +15,7 @@
cca_content_cert: cca_content_cert {
root-certificate;
image-id =<CCA_CONTENT_CERT_ID>;
- antirollback-counter = <&cca_nv_counter>;
+ antirollback-counter = <&cca_nv_ctr>;
tb_fw_hash: tb_fw_hash {
oid = TRUSTED_BOOT_FW_HASH_OID;
@@ -44,7 +44,7 @@
root-certificate;
image-id = <CORE_SWD_KEY_CERT_ID>;
signing-key = <&swd_rot_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
core_swd_pk: core_swd_pk {
oid = CORE_SWD_PK_OID;
@@ -55,7 +55,7 @@
image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
parent = <&core_swd_key_cert>;
signing-key = <&core_swd_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_hash: tos_fw_hash {
oid = TRUSTED_OS_FW_HASH_OID;
@@ -69,7 +69,7 @@
root-certificate;
image-id = <PLAT_KEY_CERT_ID>;
signing-key = <&prot_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
plat_pk: plat_pk {
oid = PLAT_PK_OID;
@@ -80,7 +80,7 @@
image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
parent = <&plat_key_cert>;
signing-key = <&plat_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
nt_world_bl_hash: nt_world_bl_hash {
oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -95,7 +95,7 @@
image-id = <SIP_SP_CONTENT_CERT_ID>;
parent = <&core_swd_key_cert>;
signing-key = <&core_swd_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
sp_pkg1_hash: sp_pkg1_hash {
oid = SP_PKG1_HASH_OID;
@@ -115,7 +115,7 @@
image-id = <PLAT_SP_CONTENT_CERT_ID>;
parent = <&plat_key_cert>;
signing-key = <&plat_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
sp_pkg5_hash: sp_pkg5_hash {
oid = SP_PKG5_HASH_OID;
@@ -242,17 +242,17 @@
#address-cells = <1>;
#size-cells = <0>;
- cca_nv_counter: cca_nv_counter {
+ cca_nv_ctr: cca_nv_ctr {
id = <TRUSTED_NV_CTR_ID>;
oid = CCA_FW_NVCOUNTER_OID;
};
- trusted_nv_counter: trusted_nv_counter {
+ trusted_nv_ctr: trusted_nv_ctr {
id = <TRUSTED_NV_CTR_ID>;
oid = TRUSTED_FW_NVCOUNTER_OID;
};
- non_trusted_nv_counter: non_trusted_nv_counter {
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
id = <NON_TRUSTED_NV_CTR_ID>;
oid = NON_TRUSTED_FW_NVCOUNTER_OID;
};
diff --git a/fdts/dualroot_cot_descriptors.dtsi b/fdts/dualroot_cot_descriptors.dtsi
index 459a1dd..bea7af5 100644
--- a/fdts/dualroot_cot_descriptors.dtsi
+++ b/fdts/dualroot_cot_descriptors.dtsi
@@ -15,7 +15,7 @@
trusted_boot_fw_cert: trusted_boot_fw_cert {
root-certificate;
image-id =<TRUSTED_BOOT_FW_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tb_fw_hash: tb_fw_hash {
oid = TRUSTED_BOOT_FW_HASH_OID;
@@ -34,7 +34,7 @@
trusted_key_cert: trusted_key_cert {
root-certificate;
image-id = <TRUSTED_KEY_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
trusted_world_pk: trusted_world_pk {
oid = TRUSTED_WORLD_PK_OID;
@@ -45,7 +45,7 @@
image-id = <SCP_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
scp_fw_content_pk: scp_fw_content_pk {
oid = SCP_FW_CONTENT_CERT_PK_OID;
@@ -56,7 +56,7 @@
image-id = <SCP_FW_CONTENT_CERT_ID>;
parent = <&scp_fw_key_cert>;
signing-key = <&scp_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
scp_fw_hash: scp_fw_hash {
oid = SCP_FW_HASH_OID;
@@ -67,7 +67,7 @@
image-id = <SOC_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
soc_fw_content_pk: soc_fw_content_pk {
oid = SOC_FW_CONTENT_CERT_PK_OID;
};
@@ -77,7 +77,7 @@
image-id = <SOC_FW_CONTENT_CERT_ID>;
parent = <&soc_fw_key_cert>;
signing-key = <&soc_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
soc_fw_hash: soc_fw_hash {
oid = SOC_AP_FW_HASH_OID;
@@ -91,7 +91,7 @@
image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_content_pk: tos_fw_content_pk {
oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
@@ -102,7 +102,7 @@
image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
parent = <&trusted_os_fw_key_cert>;
signing-key = <&tos_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_hash: tos_fw_hash {
oid = TRUSTED_OS_FW_HASH_OID;
@@ -122,7 +122,7 @@
root-certificate;
image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
signing-key = <&prot_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
nt_world_bl_hash: nt_world_bl_hash {
oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -137,7 +137,7 @@
image-id = <SIP_SP_CONTENT_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
sp_pkg1_hash: sp_pkg1_hash {
oid = SP_PKG1_HASH_OID;
@@ -157,7 +157,7 @@
root-certificate;
image-id = <PLAT_SP_CONTENT_CERT_ID>;
signing-key = <&prot_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
sp_pkg5_hash: sp_pkg5_hash {
oid = SP_PKG5_HASH_OID;
@@ -296,12 +296,12 @@
#address-cells = <1>;
#size-cells = <0>;
- trusted_nv_counter: trusted_nv_counter {
+ trusted_nv_ctr: trusted_nv_ctr {
id = <TRUSTED_NV_CTR_ID>;
oid = TRUSTED_FW_NVCOUNTER_OID;
};
- non_trusted_nv_counter: non_trusted_nv_counter {
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
id = <NON_TRUSTED_NV_CTR_ID>;
oid = NON_TRUSTED_FW_NVCOUNTER_OID;
};
diff --git a/fdts/stm32mp1-cot-descriptors.dtsi b/fdts/stm32mp1-cot-descriptors.dtsi
index eb632ff..05326be 100644
--- a/fdts/stm32mp1-cot-descriptors.dtsi
+++ b/fdts/stm32mp1-cot-descriptors.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2022, ARM Limited. All rights reserved.
+ * Copyright (c) 2020-2024, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,7 +15,7 @@
stm32mp_cfg_cert: stm32mp_cfg_cert {
root-certificate;
image-id = <STM32MP_CONFIG_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
hw_config_hash: hw_config_hash {
oid = HW_CONFIG_HASH_OID;
@@ -29,7 +29,7 @@
trusted_key_cert: trusted_key_cert {
root-certificate;
image-id = <TRUSTED_KEY_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
trusted_world_pk: trusted_world_pk {
oid = TRUSTED_WORLD_PK_OID;
@@ -43,7 +43,7 @@
image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_content_pk: tos_fw_content_pk {
oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
@@ -54,7 +54,7 @@
image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
parent = <&trusted_os_fw_key_cert>;
signing-key = <&tos_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_hash: tos_fw_hash {
oid = TRUSTED_OS_FW_HASH_OID;
@@ -74,7 +74,7 @@
image-id = <NON_TRUSTED_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&non_trusted_world_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
nt_fw_content_pk: nt_fw_content_pk {
oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID;
@@ -85,7 +85,7 @@
image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
parent = <&non_trusted_fw_key_cert>;
signing-key = <&nt_fw_content_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
nt_world_bl_hash: nt_world_bl_hash {
oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -144,12 +144,12 @@
#address-cells = <1>;
#size-cells = <0>;
- trusted_nv_counter: trusted_nv_counter {
+ trusted_nv_ctr: trusted_nv_ctr {
id = <TRUSTED_NV_CTR_ID>;
oid = TRUSTED_FW_NVCOUNTER_OID;
};
- non_trusted_nv_counter: non_trusted_nv_counter {
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
id = <NON_TRUSTED_NV_CTR_ID>;
oid = NON_TRUSTED_FW_NVCOUNTER_OID;
};
diff --git a/fdts/tbbr_cot_descriptors.dtsi b/fdts/tbbr_cot_descriptors.dtsi
index d11e2be..b3c0ca7 100644
--- a/fdts/tbbr_cot_descriptors.dtsi
+++ b/fdts/tbbr_cot_descriptors.dtsi
@@ -4,7 +4,12 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#if USE_TBBR_DEFS
#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
#include <common/tbbr/tbbr_img_def.h>
#include <common/nv_cntr_ids.h>
@@ -15,7 +20,7 @@
trusted_boot_fw_cert: trusted_boot_fw_cert {
root-certificate;
image-id =<TRUSTED_BOOT_FW_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tb_fw_hash: tb_fw_hash {
oid = TRUSTED_BOOT_FW_HASH_OID;
@@ -34,7 +39,7 @@
trusted_key_cert: trusted_key_cert {
root-certificate;
image-id = <TRUSTED_KEY_CERT_ID>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
trusted_world_pk: trusted_world_pk {
oid = TRUSTED_WORLD_PK_OID;
@@ -48,7 +53,7 @@
image-id = <SCP_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
scp_fw_content_pk: scp_fw_content_pk {
oid = SCP_FW_CONTENT_CERT_PK_OID;
@@ -59,7 +64,7 @@
image-id = <SCP_FW_CONTENT_CERT_ID>;
parent = <&scp_fw_key_cert>;
signing-key = <&scp_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
scp_fw_hash: scp_fw_hash {
oid = SCP_FW_HASH_OID;
@@ -70,7 +75,7 @@
image-id = <SOC_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
soc_fw_content_pk: soc_fw_content_pk {
oid = SOC_FW_CONTENT_CERT_PK_OID;
};
@@ -80,7 +85,7 @@
image-id = <SOC_FW_CONTENT_CERT_ID>;
parent = <&soc_fw_key_cert>;
signing-key = <&soc_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
soc_fw_hash: soc_fw_hash {
oid = SOC_AP_FW_HASH_OID;
@@ -94,7 +99,7 @@
image-id = <TRUSTED_OS_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_content_pk: tos_fw_content_pk {
oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID;
@@ -105,7 +110,7 @@
image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
parent = <&trusted_os_fw_key_cert>;
signing-key = <&tos_fw_content_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
tos_fw_hash: tos_fw_hash {
oid = TRUSTED_OS_FW_HASH_OID;
@@ -125,7 +130,7 @@
image-id = <NON_TRUSTED_FW_KEY_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&non_trusted_world_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
nt_fw_content_pk: nt_fw_content_pk {
oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID;
@@ -136,7 +141,7 @@
image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
parent = <&non_trusted_fw_key_cert>;
signing-key = <&nt_fw_content_pk>;
- antirollback-counter = <&non_trusted_nv_counter>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
nt_world_bl_hash: nt_world_bl_hash {
oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
@@ -151,7 +156,7 @@
image-id = <SIP_SP_CONTENT_CERT_ID>;
parent = <&trusted_key_cert>;
signing-key = <&trusted_world_pk>;
- antirollback-counter = <&trusted_nv_counter>;
+ antirollback-counter = <&trusted_nv_ctr>;
sp_pkg1_hash: sp_pkg1_hash {
oid = SP_PKG1_HASH_OID;
@@ -302,12 +307,12 @@
#address-cells = <1>;
#size-cells = <0>;
- trusted_nv_counter: trusted_nv_counter {
+ trusted_nv_ctr: trusted_nv_ctr {
id = <TRUSTED_NV_CTR_ID>;
oid = TRUSTED_FW_NVCOUNTER_OID;
};
- non_trusted_nv_counter: non_trusted_nv_counter {
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
id = <NON_TRUSTED_NV_CTR_ID>;
oid = NON_TRUSTED_FW_NVCOUNTER_OID;
};
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index bfda31b..ca46eb1 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -150,6 +150,7 @@
/* GICD_TYPER shifts and masks */
#define TYPER_ESPI U(1 << 8)
#define TYPER_DVIS U(1 << 18)
+#define TYPER_LPIS U(1 << 17)
#define TYPER_ESPI_RANGE_MASK U(0x1f)
#define TYPER_ESPI_RANGE_SHIFT U(27)
#define TYPER_ESPI_RANGE U(TYPER_ESPI_MASK << TYPER_ESPI_SHIFT)
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
index 633f173..b95cd32 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
@@ -78,4 +78,13 @@
#define S32CC_CLK_A53_CORE_DIV2 S32CC_ARCH_CLK(4)
#define S32CC_CLK_A53_CORE_DIV10 S32CC_ARCH_CLK(5)
+/* XBAR clock*/
+#define S32CC_CLK_MC_CGM0_MUX0 S32CC_ARCH_CLK(6)
+#define S32CC_CLK_XBAR_2X S32CC_ARCH_CLK(7)
+#define S32CC_CLK_XBAR S32CC_ARCH_CLK(8)
+#define S32CC_CLK_XBAR_DIV2 S32CC_ARCH_CLK(9)
+#define S32CC_CLK_XBAR_DIV3 S32CC_ARCH_CLK(10)
+#define S32CC_CLK_XBAR_DIV4 S32CC_ARCH_CLK(11)
+#define S32CC_CLK_XBAR_DIV6 S32CC_ARCH_CLK(12)
+
#endif /* S32CC_CLK_IDS_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
index 41fc6f4..703713b 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
@@ -17,6 +17,8 @@
s32cc_clk_t,
s32cc_pll_t,
s32cc_pll_out_div_t,
+ s32cc_dfs_t,
+ s32cc_dfs_div_t,
s32cc_clkmux_t,
s32cc_shared_clkmux_t,
s32cc_fixed_div_t,
@@ -27,6 +29,8 @@
S32CC_FXOSC,
S32CC_SIRC,
S32CC_ARM_PLL,
+ S32CC_ARM_DFS,
+ S32CC_CGM0,
S32CC_CGM1,
};
@@ -122,6 +126,38 @@
.index = (INDEX), \
}
+struct s32cc_dfs {
+ struct s32cc_clk_obj desc;
+ struct s32cc_clk_obj *parent;
+ enum s32cc_clk_source instance;
+ uintptr_t base;
+};
+
+#define S32CC_DFS_INIT(PARENT, INSTANCE) \
+{ \
+ .desc = { \
+ .type = s32cc_dfs_t, \
+ }, \
+ .parent = &(PARENT).desc, \
+ .instance = (INSTANCE), \
+}
+
+struct s32cc_dfs_div {
+ struct s32cc_clk_obj desc;
+ struct s32cc_clk_obj *parent;
+ uint32_t index;
+ unsigned long freq;
+};
+
+#define S32CC_DFS_DIV_INIT(PARENT, INDEX) \
+{ \
+ .desc = { \
+ .type = s32cc_dfs_div_t, \
+ }, \
+ .parent = &(PARENT).desc, \
+ .index = (INDEX), \
+}
+
struct s32cc_fixed_div {
struct s32cc_clk_obj desc;
struct s32cc_clk_obj *parent;
@@ -151,22 +187,26 @@
size_t n_clks;
};
-#define S32CC_FREQ_MODULE(PARENT_MODULE, MIN_F, MAX_F) \
-{ \
- .desc = { \
- .type = s32cc_clk_t, \
- }, \
- .module = &(PARENT_MODULE).desc, \
- .min_freq = (MIN_F), \
- .max_freq = (MAX_F), \
+#define S32CC_FREQ_CLK(PARENT_MODULE, PARENT, MIN_F, MAX_F) \
+{ \
+ .desc = { \
+ .type = s32cc_clk_t, \
+ }, \
+ .pclock = (PARENT), \
+ .module = (PARENT_MODULE), \
+ .min_freq = (MIN_F), \
+ .max_freq = (MAX_F), \
}
#define S32CC_FREQ_MODULE_CLK(PARENT_MODULE, MIN_F, MAX_F) \
- S32CC_FREQ_MODULE(PARENT_MODULE, MIN_F, MAX_F)
+ S32CC_FREQ_CLK(&(PARENT_MODULE).desc, NULL, MIN_F, MAX_F)
#define S32CC_MODULE_CLK(PARENT_MODULE) \
S32CC_FREQ_MODULE_CLK(PARENT_MODULE, 0, 0)
+#define S32CC_CHILD_CLK(PARENT, MIN_F, MAX_F) \
+ S32CC_FREQ_CLK(NULL, &(PARENT), MIN_F, MAX_F)
+
static inline struct s32cc_osc *s32cc_obj2osc(const struct s32cc_clk_obj *mod)
{
uintptr_t osc_addr;
@@ -237,4 +277,20 @@
return (struct s32cc_fixed_div *)fdiv_addr;
}
+static inline struct s32cc_dfs *s32cc_obj2dfs(const struct s32cc_clk_obj *mod)
+{
+ uintptr_t dfs_addr;
+
+ dfs_addr = ((uintptr_t)mod) - offsetof(struct s32cc_dfs, desc);
+ return (struct s32cc_dfs *)dfs_addr;
+}
+
+static inline struct s32cc_dfs_div *s32cc_obj2dfsdiv(const struct s32cc_clk_obj *mod)
+{
+ uintptr_t dfs_div_addr;
+
+ dfs_div_addr = ((uintptr_t)mod) - offsetof(struct s32cc_dfs_div, desc);
+ return (struct s32cc_dfs_div *)dfs_div_addr;
+}
+
#endif /* S32CC_CLK_MODULES_H */
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 9f0b190..375cdba 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -182,9 +182,9 @@
}
my_idx = plat_my_core_pos();
-
- for (lvl = PSCI_CPU_PWR_LVL; lvl <= end_pwrlvl; lvl++) {
- parent_idx = psci_cpu_pd_nodes[my_idx].parent_node;
+ parent_idx = psci_cpu_pd_nodes[my_idx].parent_node;
+ for (lvl = PSCI_CPU_PWR_LVL + U(1); lvl < end_pwrlvl; lvl++) {
+ parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
}
cpu_start_idx = psci_non_cpu_pd_nodes[parent_idx].cpu_start_idx;
diff --git a/plat/amd/versal2/include/def.h b/plat/amd/versal2/include/def.h
index a8cbaaf..67244a4 100644
--- a/plat/amd/versal2/include/def.h
+++ b/plat/amd/versal2/include/def.h
@@ -125,6 +125,10 @@
#define APU_CLUSTER_STEP U(0x100000)
#define SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL U(0xF1060504)
+#define PMXC_IOU_SLCR_SRAM_CSR U(0xF106104C)
+#define PMXC_IOU_SLCR_PHY_RESET U(0xF1061050)
+#define PMXC_IOU_SLCR_TX_RX_CONFIG_RDY U(0xF1061054)
+#define PMXC_CRP_RST_UFS U(0xF1260340)
/*******************************************************************************
* IRQ constants
diff --git a/plat/amd/versal2/include/versal2-scmi.h b/plat/amd/versal2/include/versal2-scmi.h
index 4d581e4..c08b4b1 100644
--- a/plat/amd/versal2/include/versal2-scmi.h
+++ b/plat/amd/versal2/include/versal2-scmi.h
@@ -136,5 +136,9 @@
#define RESET_I3C6_0 32
#define RESET_I3C7_0 33
#define RESET_I3C8_0 34
+#define RESET_UFSPHY_0 35
+
+#define PD_USB0 0
+#define PD_USB1 1
#endif /* _VERSAL2_SCMI_H */
diff --git a/plat/amd/versal2/plat_psci.c b/plat/amd/versal2/plat_psci.c
index 4faa434..6f0cbcb 100644
--- a/plat/amd/versal2/plat_psci.c
+++ b/plat/amd/versal2/plat_psci.c
@@ -161,12 +161,29 @@
static int32_t no_pm_ioctl(uint32_t device_id, uint32_t ioctl_id,
uint32_t arg1, uint32_t arg2)
{
+ int32_t ret = 0;
VERBOSE("%s: ioctl_id: %x, arg1: %x\n", __func__, ioctl_id, arg1);
- if (ioctl_id == IOCTL_OSPI_MUX_SELECT) {
+
+ switch (ioctl_id) {
+ case IOCTL_OSPI_MUX_SELECT:
mmio_write_32(SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL, arg1);
- return 0;
+ break;
+ case IOCTL_UFS_TXRX_CFGRDY_GET:
+ ret = (int32_t) mmio_read_32(PMXC_IOU_SLCR_TX_RX_CONFIG_RDY);
+ break;
+ case IOCTL_UFS_SRAM_CSR_SEL:
+ if (arg1 == 1) {
+ ret = (int32_t) mmio_read_32(PMXC_IOU_SLCR_SRAM_CSR);
+ } else if (arg1 == 0) {
+ mmio_write_32(PMXC_IOU_SLCR_SRAM_CSR, arg2);
+ }
+ break;
+ default:
+ ret = PM_RET_ERROR_NOFEATURE;
+ break;
}
- return PM_RET_ERROR_NOFEATURE;
+
+ return ret;
}
static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
@@ -187,7 +204,13 @@
case PM_IOCTL:
{
ret = no_pm_ioctl(arg[0], arg[1], arg[2], arg[3]);
- SMC_RET1(handle, (uint64_t)ret);
+ /* Firmware driver expects return code in upper 32 bits and
+ * status in lower 32 bits.
+ * status is always SUCCESS(0) for mmio low level register
+ * r/w calls and return value is the value returned from
+ * no_pm_ioctl
+ */
+ SMC_RET1(handle, ((uint64_t)ret << 32));
}
case PM_GET_CHIPID:
{
diff --git a/plat/amd/versal2/scmi.c b/plat/amd/versal2/scmi.c
index c3c517a..7f4b6df 100644
--- a/plat/amd/versal2/scmi.c
+++ b/plat/amd/versal2/scmi.c
@@ -10,6 +10,7 @@
#include <drivers/scmi-msg.h>
#include <drivers/scmi.h>
+#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <platform_def.h>
#include <scmi.h>
@@ -179,14 +180,40 @@
RESET_CELL(RESET_I3C6_0, RESET_I3C6_0, "i3c6"),
RESET_CELL(RESET_I3C7_0, RESET_I3C7_0, "i3c7"),
RESET_CELL(RESET_I3C8_0, RESET_I3C8_0, "i3c8"),
+ RESET_CELL(RESET_UFSPHY_0, RESET_UFSPHY_0, "ufsphy0"),
};
+/**
+ * struct scmi_pd - Data for the exposed power domain controller
+ * @pd_id: pd identifier in RCC reset driver
+ * @name: pd string ID exposed to agent
+ * @state: keep state setting
+ */
+struct scmi_pd {
+ unsigned long pd_id;
+ const char *name;
+ unsigned int state;
+};
+
+#define PD_CELL(_scmi_id, _id, _name, _state) \
+ [_scmi_id] = { \
+ .pd_id = _id, \
+ .name = _name, \
+ .state = _state, \
+ }
+
+static struct scmi_pd scmi0_pd[] = {
+ PD_CELL(PD_USB0, PD_USB0, "usb0", 0),
+ PD_CELL(PD_USB1, PD_USB1, "usb1", 0),
+};
+
struct scmi_resources {
struct scmi_clk *clock;
size_t clock_count;
struct scmi_reset *reset;
size_t reset_count;
-
+ struct scmi_pd *pd;
+ size_t pd_count;
};
static const struct scmi_resources resources[] = {
@@ -195,6 +222,8 @@
.clock_count = ARRAY_SIZE(scmi0_clock),
.reset = scmi0_reset,
.reset_count = ARRAY_SIZE(scmi0_reset),
+ .pd = scmi0_pd,
+ .pd_count = ARRAY_SIZE(scmi0_pd),
},
};
@@ -433,14 +462,122 @@
if (assert_not_deassert) {
NOTICE("SCMI reset %lu/%s set\n",
reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id));
+
+ switch (scmi_id) {
+ case RESET_UFS0_0:
+ mmio_write_32(PMXC_CRP_RST_UFS, 1);
+ break;
+ case RESET_UFSPHY_0:
+ mmio_write_32(PMXC_IOU_SLCR_PHY_RESET, 1);
+ break;
+ default:
+ break;
+ }
} else {
NOTICE("SCMI reset %lu/%s release\n",
reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id));
+
+ switch (scmi_id) {
+ case RESET_UFS0_0:
+ mmio_write_32(PMXC_CRP_RST_UFS, 0);
+ break;
+ case RESET_UFSPHY_0:
+ mmio_write_32(PMXC_IOU_SLCR_PHY_RESET, 0);
+ break;
+ default:
+ break;
+ }
}
return SCMI_SUCCESS;
}
+/*
+ * Platform SCMI reset domains
+ */
+static struct scmi_pd *find_pd(unsigned int agent_id, unsigned int pd_id)
+{
+ const struct scmi_resources *resource = find_resource(agent_id);
+ size_t n;
+
+ if (resource != NULL) {
+ for (n = 0U; n < resource->pd_count; n++) {
+ if (n == pd_id) {
+ return &resource->pd[n];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+size_t plat_scmi_pd_count(unsigned int agent_id)
+{
+ const struct scmi_resources *resource = find_resource(agent_id);
+ size_t ret;
+
+ if (resource == NULL) {
+ ret = 0U;
+ } else {
+ ret = resource->pd_count;
+
+ NOTICE("SCMI: PD: %d\n", (unsigned int)ret);
+ }
+ return ret;
+}
+
+const char *plat_scmi_pd_get_name(unsigned int agent_id, unsigned int pd_id)
+{
+ const struct scmi_pd *pd = find_pd(agent_id, pd_id);
+
+ if (pd == NULL) {
+ return NULL;
+ }
+
+ return pd->name;
+}
+
+unsigned int plat_scmi_pd_statistics(unsigned int agent_id, unsigned long *pd_id)
+{
+ return 0U;
+}
+
+unsigned int plat_scmi_pd_get_attributes(unsigned int agent_id, unsigned int pd_id)
+{
+ return 0U;
+}
+
+unsigned int plat_scmi_pd_get_state(unsigned int agent_id, unsigned int pd_id)
+{
+ const struct scmi_pd *pd = find_pd(agent_id, pd_id);
+
+ if (pd == NULL) {
+ return SCMI_NOT_SUPPORTED;
+ }
+
+ NOTICE("SCMI: PD: get id: %d, state: %x\n", pd_id, pd->state);
+
+ return pd->state;
+}
+
+int32_t plat_scmi_pd_set_state(unsigned int agent_id, unsigned int flags, unsigned int pd_id,
+ unsigned int state)
+{
+ struct scmi_pd *pd = find_pd(agent_id, pd_id);
+
+ if (pd == NULL) {
+ return SCMI_NOT_SUPPORTED;
+ }
+
+ NOTICE("SCMI: PD: set id: %d, orig state: %x, new state: %x, flags: %x\n",
+ pd_id, pd->state, state, flags);
+
+ pd->state = state;
+
+ return 0U;
+}
+
+
/* Currently only one channel is supported. Expectation is that channel 0 is used by NS SW */
static struct scmi_msg_channel scmi_channel[] = {
[0] = {
@@ -475,10 +612,8 @@
SCMI_PROTOCOL_ID_BASE,
SCMI_PROTOCOL_ID_CLOCK,
SCMI_PROTOCOL_ID_RESET_DOMAIN,
- /*
- *SCMI_PROTOCOL_ID_POWER_DOMAIN,
- *SCMI_PROTOCOL_ID_SENSOR,
- */
+ SCMI_PROTOCOL_ID_POWER_DOMAIN,
+ /* SCMI_PROTOCOL_ID_SENSOR, */
0U /* Null termination */
};
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
index 9fba4af..bf0e7f3 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -99,12 +99,17 @@
memory@2 {
device_type = "device-memory";
- reg = <0x0 0x1c090000 0x0 0x40000>, /* UART */
+ reg = <0x0 0x1c0b0000 0x0 0x20000>, /* UART 2-3 */
<0x0 0x2bfe0000 0x0 0x20000>, /* SMMUv3TestEngine */
<0x0 0x2a490000 0x0 0x20000>, /* SP805 Trusted Watchdog */
<0x0 0x1c130000 0x0 0x10000>; /* Virtio block device */
};
+ memory@3 {
+ device_type = "ns-device-memory";
+ reg = <0x0 0x1c090000 0x0 0x20000>; /* UART 0-1 */
+ };
+
#if MEASURED_BOOT
#include "event_log.dtsi"
diff --git a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
index b1d3bc1..f5d7f65 100644
--- a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
+++ b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
@@ -117,16 +117,16 @@
#if defined(ARM_COT_cca)
/* FVP does not support the CCA NV Counter so use the Trusted one. */
-&cca_nv_counter {
+&cca_nv_ctr {
reg = <TFW_NVCTR_BASE>;
};
#endif
-&trusted_nv_counter {
+&trusted_nv_ctr {
reg = <TFW_NVCTR_BASE>;
};
-&non_trusted_nv_counter {
+&non_trusted_nv_ctr {
reg = <NTFW_CTR_BASE>;
};
#endif
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 2c1888d..dff0135 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -377,30 +377,38 @@
ifneq (${COT_DESC_IN_DTB},0)
BL2_SOURCES += lib/fconf/fconf_cot_getter.c
else
- BL2_SOURCES += drivers/auth/tbbr/tbbr_cot_common.c
# Juno has its own TBBR CoT file for BL2
- ifneq (${PLAT},juno)
- BL2_SOURCES += drivers/auth/tbbr/tbbr_cot_bl2.c
+ ifeq (${PLAT},juno)
+ BL2_SOURCES += drivers/auth/tbbr/tbbr_cot_common.c
endif
endif
else ifeq (${COT},dualroot)
- BL1_SOURCES += drivers/auth/dualroot/cot.c
+ BL1_SOURCES += drivers/auth/dualroot/bl1_cot.c
ifneq (${COT_DESC_IN_DTB},0)
BL2_SOURCES += lib/fconf/fconf_cot_getter.c
- else
- BL2_SOURCES += drivers/auth/dualroot/cot.c
endif
else ifeq (${COT},cca)
- BL1_SOURCES += drivers/auth/cca/cot.c
+ BL1_SOURCES += drivers/auth/cca/bl1_cot.c
ifneq (${COT_DESC_IN_DTB},0)
BL2_SOURCES += lib/fconf/fconf_cot_getter.c
- else
- BL2_SOURCES += drivers/auth/cca/cot.c
endif
else
$(error Unknown chain of trust ${COT})
endif
+ ifeq (${COT_DESC_IN_DTB},0)
+ ifeq (${COT},dualroot)
+ COTDTPATH := fdts/dualroot_cot_descriptors.dtsi
+ else ifeq (${COT},cca)
+ COTDTPATH := fdts/cca_cot_descriptors.dtsi
+ else ifeq (${COT},tbbr)
+ ifneq (${PLAT},juno)
+ COTDTPATH := fdts/tbbr_cot_descriptors.dtsi
+ endif
+ endif
+ bl2: cot-dt2c
+ endif
+
BL1_SOURCES += ${AUTH_SOURCES} \
bl1/tbbr/tbbr_img_desc.c \
plat/arm/common/arm_bl1_fwu.c \
@@ -472,3 +480,17 @@
bl31: tl
endif
endif
+
+cot-dt2c:
+ifneq ($(COTDTPATH),)
+ $(info COT CONVERSION FOR ${COTDTPATH})
+ toolpath := $(shell which cot-dt2c)
+ ifeq (${toolpath},)
+ output := $(shell make -C ./${CERTCONVPATH} install)
+ $(info install output ${output})
+ toolpath := $(shell which cot-dt2c)
+ endif
+ output := $(shell ${toolpath} convert-to-c ${COTDTPATH} ${BUILD_PLAT}/bl2_cot.c)
+ $(info ${output})
+ BL2_SOURCES += ${BUILD_PLAT}/bl2_cot.c
+endif
diff --git a/plat/xilinx/common/include/pm_api_sys.h b/plat/xilinx/common/include/pm_api_sys.h
index ffee805..029bb43 100644
--- a/plat/xilinx/common/include/pm_api_sys.h
+++ b/plat/xilinx/common/include/pm_api_sys.h
@@ -64,6 +64,7 @@
uint32_t wake, uint32_t enable,
uint32_t flag);
enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload);
/*
* Assigning of argument values into array elements.
@@ -97,4 +98,9 @@
PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4)); \
}
+#define PM_PACK_PAYLOAD7(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5, arg6) { \
+ pl[6] = (uint32_t)(arg6); \
+ PM_PACK_PAYLOAD6(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4), (arg5)); \
+}
+
#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
index c0308ab..c38cdef 100644
--- a/plat/xilinx/common/include/pm_common.h
+++ b/plat/xilinx/common/include/pm_common.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -18,13 +18,15 @@
#if IPI_CRC_CHECK
#define PAYLOAD_ARG_CNT 8U
+#define RET_PAYLOAD_ARG_CNT 7U
#define IPI_W0_TO_W6_SIZE 28U
#define PAYLOAD_CRC_POS 7U
#define CRC_INIT_VALUE 0x4F4EU
#define CRC_ORDER 16U
#define CRC_POLYNOM 0x8005U
#else
-#define PAYLOAD_ARG_CNT 6U
+#define PAYLOAD_ARG_CNT 7U
+#define RET_PAYLOAD_ARG_CNT 6U
#endif
#define PAYLOAD_ARG_SIZE 4U /* size in bytes */
diff --git a/plat/xilinx/common/include/pm_defs.h b/plat/xilinx/common/include/pm_defs.h
index 055fa3d..9920611 100644
--- a/plat/xilinx/common/include/pm_defs.h
+++ b/plat/xilinx/common/include/pm_defs.h
@@ -35,6 +35,7 @@
(uint32_t)XPM_NODESUBCL_DEV_PERIPH, \
(uint32_t)XPM_NODETYPE_DEV_PERIPH, (IDX))
+#define TF_A_FEATURE_CHECK 0xa00U
#define PM_GET_CALLBACK_DATA 0xa01U
#define PM_GET_TRUSTZONE_VERSION 0xa03U
#define TF_A_PM_REGISTER_SGI 0xa04U
@@ -95,6 +96,8 @@
IOCTL_GET_LAST_RESET_REASON = 23,
/* AI engine NPI ISR clear */
IOCTL_AIE_ISR_CLEAR = 24,
+ IOCTL_UFS_TXRX_CFGRDY_GET = 40,
+ IOCTL_UFS_SRAM_CSR_SEL = 41,
};
/**
diff --git a/plat/xilinx/common/include/pm_svc_main.h b/plat/xilinx/common/include/pm_svc_main.h
index 67fbeae..000f198 100644
--- a/plat/xilinx/common/include/pm_svc_main.h
+++ b/plat/xilinx/common/include/pm_svc_main.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,6 +12,8 @@
extern bool pwrdwn_req_received;
+#define PASS_THROUGH_FW_CMD_ID U(0xfff)
+
/******************************************************************************/
/**
* SECURE_REDUNDANT_CALL() - Adds redundancy to the function call. This is to
diff --git a/plat/xilinx/common/pm_service/pm_api_sys.c b/plat/xilinx/common/pm_service/pm_api_sys.c
index 0a6e810..e9c5f13 100644
--- a/plat/xilinx/common/pm_service/pm_api_sys.c
+++ b/plat/xilinx/common/pm_service/pm_api_sys.c
@@ -122,7 +122,7 @@
}
PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
- return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
+ return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, RET_PAYLOAD_ARG_CNT);
}
/**
@@ -364,6 +364,37 @@
}
/**
+ * eemi_feature_check() - Returns the supported API version if supported.
+ * @api_id: API ID to check.
+ * @ret_payload: pointer to array of PAYLOAD_ARG_CNT number of
+ * words Returned supported API version
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload)
+{
+ enum pm_ret_status ret;
+
+ /* Return version of API which are implemented in TF-A only */
+ switch (api_id) {
+ case PM_GET_CALLBACK_DATA:
+ case PM_GET_TRUSTZONE_VERSION:
+ ret_payload[0] = PM_API_VERSION_2;
+ ret = PM_RET_SUCCESS;
+ break;
+ case TF_A_PM_REGISTER_SGI:
+ case TF_A_FEATURE_CHECK:
+ ret_payload[0] = PM_API_BASE_VERSION;
+ ret = PM_RET_SUCCESS;
+ break;
+ default:
+ ret = PM_RET_ERROR_NO_FEATURE;
+ }
+
+ return ret;
+}
+
+/**
* pm_feature_check() - Returns the supported API version if supported.
* @api_id: API ID to check.
* @flag: 0 - Call from secure source.
@@ -406,7 +437,7 @@
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
PM_FEATURE_CHECK, api_id);
- return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT);
+ return pm_ipi_send_sync(primary_proc, payload, ret_payload, RET_PAYLOAD_ARG_CNT);
}
/**
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
index 56567dd..205877c 100644
--- a/plat/xilinx/common/pm_service/pm_ipi.c
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -164,15 +164,10 @@
*
*/
static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
- uint32_t *value, size_t count)
+ uint32_t value[PAYLOAD_ARG_CNT])
{
size_t i;
enum pm_ret_status ret;
-#if IPI_CRC_CHECK
- uint32_t *payload_ptr = value;
- size_t j;
- uint32_t response_payload[PAYLOAD_ARG_CNT];
-#endif
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_REMOTE_OFFSET +
IPI_BUFFER_RESP_OFFSET;
@@ -184,27 +179,21 @@
* buf-2: unused
* buf-3: unused
*/
- for (i = 1; i <= count; i++) {
- *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
- value++;
+ for (i = 0; i < PAYLOAD_ARG_CNT; i++) {
+ value[i] = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
}
- ret = mmio_read_32(buffer_base);
+ ret = value[0];
#if IPI_CRC_CHECK
- for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
- response_payload[j] = mmio_read_32(buffer_base +
- (j * PAYLOAD_ARG_SIZE));
- }
-
- if (response_payload[PAYLOAD_CRC_POS] !=
- calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
+ if (value[PAYLOAD_CRC_POS] !=
+ calculate_crc(value, IPI_W0_TO_W6_SIZE)) {
NOTICE("ERROR in CRC response payload value:0x%x\n",
- response_payload[PAYLOAD_CRC_POS]);
+ value[PAYLOAD_CRC_POS]);
ret = PM_RET_ERROR_INVALID_CRC;
/* Payload data is invalid as CRC validation failed
* Clear the payload to avoid leakage of data to upper layers
*/
- memset(payload_ptr, 0, count);
+ memset(value, 0, PAYLOAD_ARG_CNT);
}
#endif
@@ -240,7 +229,7 @@
count = IPI_BUFFER_MAX_WORDS;
}
- for (i = 0; i <= count; i++) {
+ for (i = 0; i < count; i++) {
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
@@ -282,6 +271,7 @@
uint32_t *value, size_t count)
{
enum pm_ret_status ret;
+ uint32_t i, ret_payload[PAYLOAD_ARG_CNT] = {0U};
pm_ipi_lock_get();
@@ -290,7 +280,12 @@
goto unlock;
}
+ ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, ret_payload));
+
- ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count));
+ for (i = 1U; i <= count; i++) {
+ *value = ret_payload[i];
+ value++;
+ }
unlock:
pm_ipi_lock_release();
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
index 7ac0ac1..b431a6c 100644
--- a/plat/xilinx/common/pm_service/pm_svc_main.c
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -36,6 +36,32 @@
#define EVENT_CPU_PWRDWN (4U)
#define MBOX_SGI_SHARED_IPI (7U)
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ */
+#define upper_32_bits(n) ((uint32_t)((n) >> 32U))
+
+/**
+ * lower_32_bits - return bits 0-31 of a number
+ * @n: the number we're accessing
+ */
+#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffffU))
+
+/**
+ * EXTRACT_SMC_ARGS - extracts 32-bit payloads from 64-bit SMC arguments
+ * @pm_arg: array of 32-bit payloads
+ * @x: array of 64-bit SMC arguments
+ */
+#define EXTRACT_ARGS(pm_arg, x) \
+ for (uint32_t i = 0U; i < (PAYLOAD_ARG_CNT - 1U); i++) { \
+ if ((i % 2U) != 0U) { \
+ pm_arg[i] = lower_32_bits(x[(i / 2U) + 1U]); \
+ } else { \
+ pm_arg[i] = upper_32_bits(x[i / 2U]); \
+ } \
+ }
+
/* 1 sec of wait timeout for secondary core down */
#define PWRDWN_WAIT_TIMEOUT (1000U)
DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
@@ -278,7 +304,7 @@
case (uint32_t)PM_FEATURE_CHECK:
{
- uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t result[RET_PAYLOAD_ARG_CNT] = {0U};
ret = pm_feature_check(pm_arg[0], result, security_flag);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
@@ -367,6 +393,15 @@
{
switch (api_id) {
+ case TF_A_FEATURE_CHECK:
+ {
+ enum pm_ret_status ret;
+ uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+
+ ret = eemi_feature_check(pm_arg[0], result);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U));
+ }
+
case TF_A_PM_REGISTER_SGI:
{
int32_t ret;
@@ -424,7 +459,7 @@
void *handle, uint32_t security_flag)
{
enum pm_ret_status ret;
- uint32_t buf[PAYLOAD_ARG_CNT] = {0};
+ uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0};
ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
pm_arg[2], pm_arg[3], pm_arg[4],
@@ -449,6 +484,45 @@
}
/**
+ * eemi_api_handler() - Prepare EEMI payload and perform IPI transaction.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * EEMI - Embedded Energy Management Interface is AMD-Xilinx proprietary
+ * protocol to allow communication between power management controller and
+ * different processing clusters.
+ *
+ * This handler prepares EEMI protocol payload received from kernel and performs
+ * IPI transaction.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0
+ */
+static uintptr_t eemi_api_handler(uint32_t api_id, const uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+ uint32_t buf[PAYLOAD_ARG_CNT] = {0};
+ uint32_t payload[PAYLOAD_ARG_CNT] = {0};
+ uint32_t module_id;
+
+ module_id = (api_id & MODULE_ID_MASK) >> 8U;
+
+ PM_PACK_PAYLOAD7(payload, module_id, security_flag, api_id,
+ pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
+ pm_arg[4], pm_arg[5]);
+
+ ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
+ PAYLOAD_ARG_CNT);
+
+ SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
+ (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
+ (uint64_t)buf[3] | ((uint64_t)buf[4] << 32U),
+ (uint64_t)buf[5]);
+}
+
+/**
* pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
* @smc_fid: Function Identifier.
* @x1: SMC64 Arguments from kernel.
@@ -477,6 +551,7 @@
uint32_t security_flag = NON_SECURE_FLAG;
uint32_t api_id;
bool status = false, status_tmp = false;
+ uint64_t x[4] = {x1, x2, x3, x4};
/* Handle case where PM wasn't initialized properly */
if (pm_up == false) {
@@ -494,6 +569,14 @@
security_flag = SECURE_FLAG;
}
+ if ((smc_fid & FUNCID_NUM_MASK) == PASS_THROUGH_FW_CMD_ID) {
+ api_id = lower_32_bits(x[0]);
+
+ EXTRACT_ARGS(pm_arg, x);
+
+ return eemi_api_handler(api_id, pm_arg, handle, security_flag);
+ }
+
pm_arg[0] = (uint32_t)x1;
pm_arg[1] = (uint32_t)(x1 >> 32U);
pm_arg[2] = (uint32_t)x2;
diff --git a/plat/xilinx/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c
index 772477f..9e8134a 100644
--- a/plat/xilinx/versal/aarch64/versal_common.c
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -1,12 +1,11 @@
/*
* Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
-#include <drivers/generic_delay_timer.h>
#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat/common/platform.h>
@@ -18,7 +17,7 @@
#include <versal_def.h>
uint32_t platform_id, platform_version;
-uint32_t cpu_clock = VERSAL_CPU_CLOCK;
+uint32_t cpu_clock;
/*
* Table of regions to map using the MMU.
@@ -39,19 +38,10 @@
return plat_versal_mmap;
}
-static void versal_print_platform_name(void)
-{
- NOTICE("TF-A running on %s\n", PLATFORM_NAME);
-}
-
void versal_config_setup(void)
{
/* Configure IPI data for versal */
versal_ipi_config_table_init();
-
- versal_print_platform_name();
-
- generic_delay_timer_init();
}
void board_detection(void)
@@ -70,7 +60,50 @@
platform_version = FIELD_GET(PLATFORM_VERSION_MASK, plat_info[1]);
}
+const char *board_name_decode(void)
+{
+ const char *platform;
+
+ switch (platform_id) {
+ case VERSAL_SPP:
+ platform = "IPP";
+ break;
+ case VERSAL_EMU:
+ platform = "EMU";
+ break;
+ case VERSAL_QEMU:
+ platform = "QEMU";
+ break;
+ case VERSAL_SILICON:
+ platform = "SILICON";
+ break;
+ default:
+ platform = "unknown";
+ }
+
+ return platform;
+}
+
uint32_t get_uart_clk(void)
{
- return UART_CLOCK;
+ uint32_t uart_clock;
+
+ switch (platform_id) {
+ case VERSAL_SPP:
+ uart_clock = 25000000;
+ break;
+ case VERSAL_EMU:
+ uart_clock = 212000;
+ break;
+ case VERSAL_QEMU:
+ uart_clock = 25000000;
+ break;
+ case VERSAL_SILICON:
+ uart_clock = 100000000;
+ break;
+ default:
+ panic();
+ }
+
+ return uart_clock;
}
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
index 594784f..0e4ec1c 100644
--- a/plat/xilinx/versal/bl31_versal_setup.c
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,6 +12,7 @@
#include <bl31/bl31.h>
#include <common/bl_common.h>
#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat/common/platform.h>
@@ -73,22 +74,41 @@
enum pm_ret_status ret_status;
uint64_t addr[HANDOFF_PARAMS_MAX_SIZE];
- set_cnt_freq();
-
- setup_console();
-
- /* Initialize the platform config for future decision making */
- versal_config_setup();
-
- /* Get platform related information */
- board_detection();
-
/*
* Do initial security configuration to allow DRAM/device access. On
* Base VERSAL only DRAM security is programmable (via TrustZone), but
* other platforms might have more programmable security devices
* present.
*/
+ versal_config_setup();
+
+ /* Initialize the platform config for future decision making */
+ board_detection();
+
+ switch (platform_id) {
+ case VERSAL_SPP:
+ cpu_clock = 2720000;
+ break;
+ case VERSAL_EMU:
+ cpu_clock = 212000;
+ break;
+ case VERSAL_QEMU:
+ /* Random values now */
+ cpu_clock = 2720000;
+ break;
+ case VERSAL_SILICON:
+ cpu_clock = 100000000;
+ break;
+ default:
+ panic();
+ }
+ set_cnt_freq();
+
+ generic_delay_timer_init();
+
+ setup_console();
+
+ NOTICE("TF-A running on %s %d\n", board_name_decode(), platform_version);
/* Populate common information for BL32 and BL33 */
SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
diff --git a/plat/xilinx/versal/include/plat_private.h b/plat/xilinx/versal/include/plat_private.h
index 932c6de..4b2b6cf 100644
--- a/plat/xilinx/versal/include/plat_private.h
+++ b/plat/xilinx/versal/include/plat_private.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,6 +25,8 @@
extern uint32_t cpu_clock, platform_id, platform_version;
void board_detection(void);
+const char *board_name_decode(void);
+
void plat_versal_gic_driver_init(void);
void plat_versal_gic_init(void);
void plat_versal_gic_cpuif_enable(void);
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
index f21d409..b7691ad 100644
--- a/plat/xilinx/versal/include/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,13 +25,11 @@
#define CONSOLE_IS(con) (VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE)
-/* List all supported platforms */
-#define VERSAL_PLATFORM_ID_versal_virt 1
-#define VERSAL_PLATFORM_ID_spp_itr6 2
-#define VERSAL_PLATFORM_ID_emu_itr6 3
-#define VERSAL_PLATFORM_ID_silicon 4
-
-#define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
+/* List of platforms */
+#define VERSAL_SILICON U(0)
+#define VERSAL_SPP U(1)
+#define VERSAL_EMU U(2)
+#define VERSAL_QEMU U(3)
/* Firmware Image Package */
#define VERSAL_PRIMARY_CPU 0
@@ -75,27 +73,7 @@
/*******************************************************************************
* Platform related constants
******************************************************************************/
-#if VERSAL_PLATFORM_IS(versal_virt)
-# define PLATFORM_NAME "Versal Virt"
-# define UART_CLOCK 25000000
-# define UART_BAUDRATE 115200
-# define VERSAL_CPU_CLOCK 2720000
-#elif VERSAL_PLATFORM_IS(silicon)
-# define PLATFORM_NAME "Versal Silicon"
-# define UART_CLOCK 100000000
-# define UART_BAUDRATE 115200
-# define VERSAL_CPU_CLOCK 100000000
-#elif VERSAL_PLATFORM_IS(spp_itr6)
-# define PLATFORM_NAME "SPP ITR6"
-# define UART_CLOCK 25000000
-# define UART_BAUDRATE 115200
-# define VERSAL_CPU_CLOCK 2720000
-#elif VERSAL_PLATFORM_IS(emu_itr6)
-# define PLATFORM_NAME "EMU ITR6"
-# define UART_CLOCK 212000
-# define UART_BAUDRATE 9600
-# define VERSAL_CPU_CLOCK 212000
-#endif
+#define UART_BAUDRATE 115200
/* Access control register defines */
#define ACTLR_EL3_L2ACTLR_BIT (1 << 6)
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index 4cf1ed1..74c5bf3 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -197,7 +197,7 @@
*/
static void versal_pwr_domain_off(const psci_power_state_t *target_state)
{
- uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
uint32_t cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
index 2f07996..6cc28e1 100644
--- a/plat/xilinx/versal/platform.mk
+++ b/plat/xilinx/versal/platform.mk
@@ -1,5 +1,5 @@
# Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
-# Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+# Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -44,8 +44,9 @@
$(eval $(call add_define,IPI_CRC_CHECK))
endif
-VERSAL_PLATFORM ?= silicon
-$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
+ifdef VERSAL_PLATFORM
+ $(warning "VERSAL_PLATFORM has been deprecated")
+endif
ifdef XILINX_OF_BOARD_DTB_ADDR
$(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
index 4441d3e..3c0bd63 100644
--- a/plat/xilinx/versal/sip_svc_setup.c
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,7 +22,7 @@
/* SiP Service Calls version numbers */
#define SIP_SVC_VERSION_MAJOR U(0)
-#define SIP_SVC_VERSION_MINOR U(1)
+#define SIP_SVC_VERSION_MINOR U(2)
/* These macros are used to identify PM calls from the SMC function ID */
#define SIP_FID_MASK GENMASK(23, 16)
diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c
index e5a5235..fb2005d 100644
--- a/plat/xilinx/versal_net/plat_psci_pm.c
+++ b/plat/xilinx/versal_net/plat_psci_pm.c
@@ -59,7 +59,7 @@
*/
static void versal_net_pwr_domain_off(const psci_power_state_t *target_state)
{
- uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
uint32_t cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);
diff --git a/plat/xilinx/versal_net/sip_svc_setup.c b/plat/xilinx/versal_net/sip_svc_setup.c
index 80d5a53..c974810 100644
--- a/plat/xilinx/versal_net/sip_svc_setup.c
+++ b/plat/xilinx/versal_net/sip_svc_setup.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -25,7 +25,7 @@
/* SiP Service Calls version numbers */
#define SIP_SVC_VERSION_MAJOR (0U)
-#define SIP_SVC_VERSION_MINOR (1U)
+#define SIP_SVC_VERSION_MINOR (2U)
/* These macros are used to identify PM calls from the SMC function ID */
#define SIP_FID_MASK GENMASK(23, 16)
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
index 3d546b3..66f011a 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c
@@ -919,7 +919,7 @@
enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
uint32_t *bit_mask, uint8_t len)
{
- uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t ret_payload[RET_PAYLOAD_ARG_CNT] = {0U};
uint32_t status;
/* Get API version implemented in TF-A */
diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
index 5a6a9f8..bf17ea4 100644
--- a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c
@@ -285,7 +285,7 @@
uint32_t payload[PAYLOAD_ARG_CNT];
uint32_t pm_arg[5];
- uint32_t result[PAYLOAD_ARG_CNT] = {0};
+ uint32_t result[RET_PAYLOAD_ARG_CNT] = {0};
uint32_t api_id;
/* Handle case where PM wasn't initialized properly */
@@ -566,7 +566,7 @@
PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1],
pm_arg[2], pm_arg[3], pm_arg[4]);
ret = pm_ipi_send_sync(primary_proc, payload, result,
- PAYLOAD_ARG_CNT);
+ RET_PAYLOAD_ARG_CNT);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
(uint64_t)result[1] | ((uint64_t)result[2] << 32U));
}
diff --git a/tools/cot_dt2c/Makefile b/tools/cot_dt2c/Makefile
new file mode 100644
index 0000000..ad8d9f5
--- /dev/null
+++ b/tools/cot_dt2c/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+##* Variables
+SHELL := /usr/bin/env bash
+PYTHON := python
+PYTHONPATH := `pwd`
+
+.PHONY: dist
+dist: clean
+ poetry build
+
+#* Installation
+.PHONY: dev-install
+dev-install:
+ pip3 install mypy
+ pip3 install pytest
+ pip install -r requirements.txt
+ poetry lock -n && poetry export --without-hashes > requirements.txt
+ poetry install -n
+ -poetry run mypy --install-types --non-interactive ./
+
+.PHONY: install
+install: dist
+ pip install mypy
+ pip install pytest
+ pip install -r requirements.txt
+ pip install dist/*.whl
+
+clean-test: ## remove test and coverage artifacts
+ rm -fr .tox/
+ rm -f .coverage
+ rm -fr htmlcov/
+
+clean-pyc: ## remove Python file artifacts
+ find . -name '*.pyc' -exec rm -f {} +
+ find . -name '*.pyo' -exec rm -f {} +
+ find . -name '*~' -exec rm -f {} +
+ find . -name '__pycache__' -exec rm -fr {} +
+ find . | grep -E ".pytest_cache" | xargs rm -rf
+ find . | grep -E ".mypy_cache" | xargs rm -rf
+
+
+clean-build: ## remove build artifacts
+ rm -fr build/
+ rm -fr dist/
+ rm -fr .eggs/
+ find . -name '*.egg-info' -exec rm -fr {} +
+ find . -name '*.egg' -exec rm -f {} +
+
+clean-tmp:
+ rm -rf ./tmp
+
+#* Cleaning
+.PHONY: clean clean-build clean-pyc clean-test
+clean: uninstall clean-build clean-pyc clean-test clean-tmp ## remove all build, test, coverage and Python artifacts
+
+uninstall:
+ pip uninstall -y cot-dt2c
+
+.PHONY: reinstall
+reinstall: clean install
+
+.PHONY: test
+test:
+ PYTHONPATH=$(PYTHONPATH) poetry run pytest -c pyproject.toml tests/
diff --git a/tools/cot_dt2c/cot_dt2c/LICENSE b/tools/cot_dt2c/cot_dt2c/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/tools/cot_dt2c/cot_dt2c/__init__.py b/tools/cot_dt2c/cot_dt2c/__init__.py
new file mode 100644
index 0000000..621c55a
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/__init__.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+# type: ignore[attr-defined]
+
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+
+if sys.version_info >= (3, 8):
+ from importlib import metadata as importlib_metadata
+else:
+ import importlib_metadata
+
+
+def get_version() -> str:
+ try:
+ return importlib_metadata.version(__name__)
+ except importlib_metadata.PackageNotFoundError: # pragma: no cover
+ return "unknown"
+
+
+version: str = get_version()
diff --git a/tools/cot_dt2c/cot_dt2c/__main__.py b/tools/cot_dt2c/cot_dt2c/__main__.py
new file mode 100644
index 0000000..5aa4a92
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/__main__.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+# type: ignore[attr-defined]
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+from cot_dt2c.cli import cli
+if __name__ == "__main__":
+ cli()
diff --git a/tools/cot_dt2c/cot_dt2c/cli.py b/tools/cot_dt2c/cot_dt2c/cli.py
new file mode 100644
index 0000000..d338430
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/cli.py
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+from pathlib import Path
+from cot_dt2c.cot_dt2c import generateMain
+from cot_dt2c.cot_dt2c import validateMain
+from cot_dt2c.cot_dt2c import visualizeMain
+from cot_dt2c.dt_validator import dtValidatorMain
+
+import click
+
+@click.group()
+@click.version_option()
+def cli():
+ pass
+
+@cli.command()
+@click.argument("inputfile", type=click.Path(dir_okay=True))
+@click.argument("outputfile", type=click.Path(dir_okay=True))
+def convert_to_c(inputfile, outputfile):
+ generateMain(inputfile, outputfile)
+
+@cli.command()
+@click.argument("inputfile", type=click.Path(dir_okay=True))
+def validate_cot(inputfile):
+ validateMain(inputfile)
+
+@cli.command()
+@click.argument("inputfile", type=click.Path(dir_okay=True))
+def visualize_cot(inputfile):
+ visualizeMain(inputfile)
+
+@cli.command()
+@click.argument("inputfiledir", type=click.Path(dir_okay=True))
+def validate_dt(inputfiledir):
+ dtValidatorMain(inputfiledir)
diff --git a/tools/cot_dt2c/cot_dt2c/cot_dt2c.py b/tools/cot_dt2c/cot_dt2c/cot_dt2c.py
new file mode 100644
index 0000000..4056aac
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/cot_dt2c.py
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+from cot_dt2c.cot_parser import COT
+
+def generateMain(input, output=None):
+ cot = COT(input, output)
+ cot.generate_c_file()
+
+def validateMain(input):
+ cot = COT(input)
+ if not cot.validate_nodes():
+ print("not a valid CoT DT file")
+
+def visualizeMain(input):
+ cot = COT(input)
+ cot.tree_visualization()
+
+if __name__=="__main__":
+ if (len(sys.argv) < 2):
+ print("usage: python3 " + sys.argv[0] + " [dtsi file path] [optional output c file path]")
+ exit()
+ if len(sys.argv) == 3:
+ generateMain(sys.argv[1], sys.argv[2])
+ if len(sys.argv) == 2:
+ validateMain(sys.argv[1])
diff --git a/tools/cot_dt2c/cot_dt2c/cot_parser.py b/tools/cot_dt2c/cot_dt2c/cot_parser.py
new file mode 100644
index 0000000..c1d53e2
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/cot_parser.py
@@ -0,0 +1,804 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+import re
+from cot_dt2c.pydevicetree.source.parser import ifdef_stack
+from cot_dt2c.pydevicetree.ast import CellArray, LabelReference
+from cot_dt2c.pydevicetree import *
+from pathlib import Path
+
+def extractNumber(s):
+ for i in s:
+ if i.isdigit():
+ return (int)(i)
+
+ return -1
+
+def removeNumber(s):
+ result = ''.join([i for i in s if not i.isdigit()])
+ return result
+
+class COT:
+ def __init__(self, inputfile: str, outputfile=None):
+ with open(inputfile, 'r') as f:
+ contents = f.read()
+ pos = contents.find("cot")
+ if pos == -1:
+ print("not a valid CoT DT file")
+ exit(1)
+
+ contents = contents[pos:]
+
+ try:
+ self.tree = Devicetree.parseStr(contents)
+ except:
+ print("not a valid CoT DT file")
+ exit(1)
+
+ self.output = outputfile
+ self.input = inputfile
+ self.has_root = False
+
+ # edge cases
+ certs = self.get_all_certificates()
+ for c in certs:
+ if self.if_root(c):
+ if not c.get_fields("signing-key"):
+ c.properties.append(Property("signing-key", CellArray([LabelReference("subject_pk")])))
+
+ def print_cert_info(self, node:Node):
+ img_id = node.get_field("image-id").values[0].replace('"', "")
+ sign_key = self.get_sign_key(node)
+ nv = self.get_nv_ctr(node)
+
+ info = "<b>name:</b> {}<br><b>image-id:</b> {}<br>{}{}{}"\
+ .format(node.name, img_id, "<b>root-certificate</b><br>" if self.if_root(node) else "", \
+ "<b>signing-key:</b> " + self.extract_label(sign_key) + "<br>" if sign_key else "", \
+ "<b>nv counter:</b> " + self.extract_label(nv) + "<br>" if nv else "")
+ return info
+
+ def print_data_info(self, node:Node):
+ oid = node.get_field("oid")
+ info = "<b>name:</b> {}<br><b>oid:</b> {}<br>" \
+ .format(node.name, oid)
+
+ return info
+
+ def print_img_info(self, node:Node):
+ hash = self.extract_label(node.get_fields("hash"))
+ img_id = node.get_field("image-id").values[0].replace('"', "")
+ info = "<b>name:</b> {}<br><b>image-id:</b> {}<br><b>hash:</b> {}"\
+ .format(node.name, img_id, hash)
+
+ return info
+
+ def tree_width(self, parent_set, root):
+ ans = 1
+ stack = [root]
+
+ while stack:
+ tmp_stack = []
+ while stack:
+ cur_node = stack.pop()
+ child = parent_set[cur_node]
+ for c in child:
+ tmp_stack.append(c)
+
+ stack = tmp_stack.copy()
+ ans = max(ans, len(tmp_stack))
+
+ return ans
+
+ def resolve_lay(self, parent_set, lay, name_idx, root, bounds, break_name):
+ child = parent_set[root]
+
+ if len(child) == 0:
+ return
+
+ width = []
+ total_width = 0
+ for c in child:
+ w = self.tree_width(parent_set, c)
+ width.append(w)
+ total_width += w
+
+ allow_width = bounds[1] - bounds[0]
+ interval = allow_width / total_width
+ start = bounds[0]
+ for i, c in enumerate(child):
+ end = start + interval * width[i]
+ new_bounds = [start, end]
+ lay[name_idx[c]][0] = start + (end - start) / 2
+ if end - start < 0.28:
+ break_name.add(c)
+ start = end
+ self.resolve_lay(parent_set, lay, name_idx, c, new_bounds, break_name)
+
+ def tree_visualization(self):
+ import igraph
+ from igraph import Graph, EdgeSeq
+ import collections
+
+ cert = self.get_certificates()
+ pk = self.get_rot_keys()
+ nv = self.get_nv_counters()
+ image = self.get_images()
+
+ certs = cert.children
+ if pk:
+ pks = pk.children
+ else:
+ pks = []
+ nvs = nv.children
+ images = image.children
+
+ root_name = "CoT"
+
+ G = Graph()
+ detail = []
+ lay = []
+ name_idx = {}
+ parent_set = collections.defaultdict(list)
+
+ G.add_vertex(root_name)
+ detail.append("CoT Root")
+ name_idx[root_name] = len(lay)
+ lay.append([0,0])
+
+ G.add_vertex(cert.name)
+ G.add_edge(root_name, cert.name)
+ detail.append("All Certificates")
+ name_idx[cert.name] = len(lay)
+ lay.append([0, 1])
+ parent_set[root_name].append(cert.name)
+
+ if pk:
+ G.add_vertex(pk.name)
+ detail.append("All Public Trusted Key")
+ G.add_edge(root_name, pk.name)
+ name_idx[pk.name] = len(lay)
+ lay.append([-2.0, 1])
+ parent_set[root_name].append(pk.name)
+
+ G.add_vertex(nv.name)
+ detail.append("All NV Counters")
+ G.add_edge(root_name, nv.name)
+ name_idx[nv.name] = len(lay)
+ lay.append([2.0, 1])
+ parent_set[root_name].append(nv.name)
+
+ if pks:
+ for i, p in enumerate(pks):
+ G.add_vertex(p.name)
+ detail.append(self.print_data_info(p))
+ G.add_edge(pk.name, p.name)
+ name_idx[p.name] = len(lay)
+ parent_set[pk.name].append(p.name)
+ lay.append([0, lay[name_idx[pk.name]][1] + 1])
+
+ for c in certs:
+ G.add_vertex(c.name)
+ detail.append(self.print_cert_info(c))
+ name_idx[c.name] = len(lay)
+ if self.if_root(c):
+ G.add_edge(cert.name, c.name)
+ parent_set[cert.name].append(c.name)
+ lay.append([0, 2])
+ else:
+ parent = self.extract_label(c.get_fields("parent"))
+ G.add_edge(parent, c.name)
+ parent_set[parent].append(c.name)
+ lay.append([0, lay[name_idx[parent]][1] + 1])
+
+ for idx, i in enumerate(images):
+ G.add_vertex(i.name)
+ detail.append(self.print_img_info(i))
+ parent = self.extract_label(i.get_fields("parent"))
+ G.add_edge(parent, i.name)
+ parent_set[parent].append(i.name)
+ name_idx[i.name] = len(lay)
+ lay.append([0, lay[name_idx[parent]][1] + 1])
+
+ for i, n in enumerate(nvs):
+ G.add_vertex(n.name)
+ detail.append(self.print_data_info(n))
+ G.add_edge(nv.name, n.name)
+ name_idx[n.name] = len(lay)
+ parent_set[nv.name].append(n.name)
+ lay.append([0, lay[name_idx[nv.name]][1] + 1])
+
+ break_name = set()
+ self.resolve_lay(parent_set, lay, name_idx, root_name, [-3, 3], break_name)
+ #lay = G.layout('rt')
+
+ numVertex = len(G.get_vertex_dataframe())
+ vertices = G.get_vertex_dataframe()
+ v_label = []
+
+ for i in vertices['name']:
+ if i in break_name and len(i) > 10:
+ middle = len(i) // 2
+ v_label.append(i[:middle] + "<br>" + i[middle:])
+ else:
+ v_label.append(i)
+
+ position = {k: lay[k] for k in range(numVertex)}
+ Y = [lay[k][1] for k in range(numVertex)]
+ M = max(Y)
+
+ es = EdgeSeq(G) # sequence of edges
+ E = [e.tuple for e in G.es] # list of edges
+
+ L = len(position)
+ Xn = [position[k][0] for k in range(L)]
+ Yn = [2*M-position[k][1] for k in range(L)]
+ Xe = []
+ Ye = []
+ for edge in E:
+ Xe += [position[edge[0]][0], position[edge[1]][0], None]
+ Ye += [2*M-position[edge[0]][1], 2*M-position[edge[1]][1], None]
+
+ labels = v_label
+
+ import plotly.graph_objects as go
+ fig = go.Figure()
+ fig.add_trace(go.Scatter(x = Xe,
+ y = Ye,
+ mode = 'lines',
+ line = dict(color='rgb(210,210,210)', width=2),
+ hoverinfo = 'none'
+ ))
+ fig.add_trace(go.Scatter(x = Xn,
+ y = Yn,
+ mode = 'markers',
+ name = 'detail',
+ marker = dict(symbol = 'circle-dot',
+ size = 50,
+ color = 'rgba(135, 206, 250, 0.8)', #'#DB4551',
+ line = dict(color='MediumPurple', width=3)
+ ),
+ text=detail,
+ hoverinfo='text',
+ hovertemplate =
+ '<b>Detail</b><br>'
+ '%{text}',
+ opacity=0.8
+ ))
+
+ def make_annotations(pos, text, font_size=10, font_color='rgb(0,0,0)'):
+ L = len(pos)
+ if len(text) != L:
+ raise ValueError('The lists pos and text must have the same len')
+ annotations = []
+ for k in range(L):
+ annotations.append(
+ dict(
+ text = labels[k],
+ x = pos[k][0], y = 2*M-position[k][1],
+ xref = 'x1', yref = 'y1',
+ font = dict(color = font_color, size = font_size),
+ showarrow = False)
+ )
+ return annotations
+
+ axis = dict(showline=False, # hide axis line, grid, ticklabels and title
+ zeroline=False,
+ showgrid=False,
+ showticklabels=False,
+ )
+
+ fig.update_layout(title= 'CoT Device Tree',
+ annotations=make_annotations(position, v_label),
+ font_size=12,
+ showlegend=False,
+ xaxis=axis,
+ yaxis=axis,
+ margin=dict(l=40, r=40, b=85, t=100),
+ hovermode='closest',
+ plot_bgcolor='rgb(248,248,248)'
+ )
+
+ fig.show()
+
+ return
+
+ def if_root(self, node:Node) -> bool:
+ for p in node.properties:
+ if p.name == "root-certificate":
+ return True
+ return False
+
+ def get_sign_key(self, node:Node):
+ for p in node.properties:
+ if p.name == "signing-key":
+ return p.values
+
+ return None
+
+ def get_nv_ctr(self, node:Node):
+ for nv in node.properties:
+ if nv.name == "antirollback-counter":
+ return nv.values
+
+ return None
+
+ def extract_label(self, label) -> str:
+ if not label:
+ return label
+ return label[0].label.name
+
+ def get_auth_data(self, node:Node):
+ return node.children
+
+ def format_auth_data_val(self, node:Node, cert:Node):
+ type_desc = node.name
+ if "sp_pkg" in type_desc:
+ ptr = removeNumber(type_desc) + "_buf"
+ else:
+ ptr = type_desc + "_buf"
+ len = "(unsigned int)HASH_DER_LEN"
+ if "pk" in type_desc:
+ len = "(unsigned int)PK_DER_LEN"
+
+ # edge case
+ if not self.if_root(cert) and "key_cert" in cert.name:
+ if "content_pk" in ptr:
+ ptr = "content_pk_buf"
+
+ return type_desc, ptr, len
+
+ def get_node(self, nodes: list[Node], name: str) -> Node:
+ for i in nodes:
+ if i.name == name:
+ return i
+
+ def get_certificates(self) -> Node:
+ children = self.tree.children
+ for i in children:
+ if i.name == "cot":
+ return self.get_node(i.children, "manifests")
+
+ def get_images(self)-> Node:
+ children = self.tree.children
+ for i in children:
+ if i.name == "cot":
+ return self.get_node(i.children, "images")
+
+ def get_nv_counters(self) -> Node:
+ children = self.tree.children
+ return self.get_node(children, "non_volatile_counters")
+
+ def get_rot_keys(self) -> Node:
+ children = self.tree.children
+ return self.get_node(children, "rot_keys")
+
+ def get_all_certificates(self) -> Node:
+ cert = self.get_certificates()
+ return cert.children
+
+ def get_all_images(self) -> Node:
+ image = self.get_images()
+ return image.children
+
+ def get_all_nv_counters(self) -> Node:
+ nv = self.get_nv_counters()
+ return nv.children
+
+ def get_all_pks(self) -> Node:
+ pk = self.get_rot_keys()
+ if not pk:
+ return []
+ return pk.children
+
+ def validate_cert(self, node:Node) -> bool:
+ valid = True
+ if not node.has_field("image-id"):
+ print("{} missing mandatory attribute image-id".format(node.name))
+ valid = False
+
+ if not node.has_field("root-certificate"):
+ if not node.has_field("parent"):
+ print("{} missing mandatory attribute parent".format(node.name))
+ valid = False
+ else:
+ # check if refer to non existing parent
+ certs = self.get_all_certificates()
+ found = False
+ for c in certs:
+ if c.name == self.extract_label(node.get_fields("parent")):
+ found = True
+
+ if not found:
+ print("{} refer to non existing parent".format(node.name))
+ valid = False
+
+ else:
+ self.has_root = True
+
+ child = node.children
+ if child:
+ for c in child:
+ if not c.has_field("oid"):
+ print("{} missing mandatory attribute oid".format(c.name))
+ valid = False
+
+ return valid
+
+ def validate_img(self, node:Node) -> bool:
+ valid = True
+ if not node.has_field("image-id"):
+ print("{} missing mandatory attribute image-id".format(node.name))
+ valid = False
+
+ if not node.has_field("parent"):
+ print("{} missing mandatory attribute parent".format(node.name))
+ valid = False
+
+ if not node.has_field("hash"):
+ print("{} missing mandatory attribute hash".format(node.name))
+ valid = False
+
+ # check if refer to non existing parent
+ certs = self.get_all_certificates()
+ found = False
+ for c in certs:
+ if c.name == self.extract_label(node.get_fields("parent")):
+ found = True
+
+ if not found:
+ print("{} refer to non existing parent".format(node.name))
+ valid = False
+
+ return valid
+
+ def validate_nodes(self) -> bool:
+ valid = True
+
+ if ifdef_stack:
+ print("invalid ifdef macro")
+ valid = False
+
+ certs = self.get_all_certificates()
+ images = self.get_all_images()
+
+ for n in certs:
+ node_valid = self.validate_cert(n)
+ valid = valid and node_valid
+
+ for i in images:
+ node_valid = self.validate_img(i)
+ valid = valid and node_valid
+
+ if not self.has_root:
+ print("missing root certificate")
+
+ return valid
+
+ def extract_licence(self, f):
+ licence = []
+
+ licencereg = re.compile(r'/\*')
+ licenceendReg = re.compile(r'\*/')
+
+ licencePre = False
+
+ for line in f:
+ match = licencereg.search(line)
+ if match != None:
+ licence.append(line)
+ licencePre = True
+ continue
+
+ match = licenceendReg.search(line)
+ if match != None:
+ licence.append(line)
+ licencePre = False
+ return licence
+
+ if licencePre:
+ licence.append(line)
+ else:
+ return licence
+
+ return licence
+
+ def licence_to_c(self, licence, f):
+ if len(licence) != 0:
+ for i in licence:
+ f.write(i)
+
+ f.write("\n")
+ return
+
+ def extract_include(self, f):
+ include = []
+
+ for line in f:
+ if "cot" in line:
+ return include
+
+ if line != "" and "common" not in line and line != "\n":
+ include.append(line)
+
+ return include
+
+ def include_to_c(self, include, f):
+ f.write("#include <stddef.h>\n")
+ f.write("#include <mbedtls/version.h>\n")
+ f.write("#include <common/tbbr/cot_def.h>\n")
+ f.write("#include <drivers/auth/auth_mod.h>\n")
+ f.write("\n")
+ for i in include:
+ f.write(i)
+ f.write("\n")
+ f.write("#include <platform_def.h>\n\n")
+ return
+
+ def generate_header(self, input, output):
+ licence = self.extract_licence(input)
+ include = self.extract_include(input)
+ self.licence_to_c(licence, output)
+ self.include_to_c(include, output)
+
+ def all_cert_to_c(self, f):
+ certs = self.get_all_certificates()
+ for c in certs:
+ self.cert_to_c(c, f)
+
+ f.write("\n")
+
+ def cert_to_c(self, node: Node, f):
+ ifdef = node.get_fields("ifdef")
+ if ifdef:
+ for i in ifdef:
+ f.write("{}\n".format(i))
+
+ f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
+ f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
+ f.write("\t.img_type = IMG_CERT,\n")
+
+ if not self.if_root(node):
+ f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
+ else:
+ f.write("\t.parent = NULL,\n")
+
+ sign = self.get_sign_key(node)
+ nv_ctr = self.get_nv_ctr(node)
+
+ if sign or nv_ctr:
+ f.write("\t.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {\n")
+
+ if sign:
+ f.write("\t\t[0] = {\n")
+ f.write("\t\t\t.type = AUTH_METHOD_SIG,\n")
+ f.write("\t\t\t.param.sig = {\n")
+
+ f.write("\t\t\t\t.pk = &{},\n".format(self.extract_label(sign)))
+ f.write("\t\t\t\t.sig = &sig,\n")
+ f.write("\t\t\t\t.alg = &sig_alg,\n")
+ f.write("\t\t\t\t.data = &raw_data\n")
+ f.write("\t\t\t}\n")
+ f.write("\t\t}}{}\n".format("," if nv_ctr else ""))
+
+ if nv_ctr:
+ f.write("\t\t[1] = {\n")
+ f.write("\t\t\t.type = AUTH_METHOD_NV_CTR,\n")
+ f.write("\t\t\t.param.nv_ctr = {\n")
+
+ f.write("\t\t\t\t.cert_nv_ctr = &{},\n".format(self.extract_label(nv_ctr)))
+ f.write("\t\t\t\t.plat_nv_ctr = &{}\n".format(self.extract_label(nv_ctr)))
+
+ f.write("\t\t\t}\n")
+ f.write("\t\t}\n")
+
+ f.write("\t},\n")
+
+ auth_data = self.get_auth_data(node)
+ if auth_data:
+ f.write("\t.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {\n")
+
+ for i, d in enumerate(auth_data):
+ type_desc, ptr, data_len = self.format_auth_data_val(d, node)
+
+ f.write("\t\t[{}] = {{\n".format(i))
+ f.write("\t\t\t.type_desc = &{},\n".format(type_desc))
+ f.write("\t\t\t.data = {\n")
+
+ n = extractNumber(type_desc)
+ if "pkg" not in type_desc or n == -1:
+ f.write("\t\t\t\t.ptr = (void *){},\n".format(ptr))
+ else:
+ f.write("\t\t\t\t.ptr = (void *){}[{}],\n".format(ptr, n-1))
+
+ f.write("\t\t\t\t.len = {}\n".format(data_len))
+ f.write("\t\t\t}\n")
+
+ f.write("\t\t}}{}\n".format("," if i != len(auth_data) - 1 else ""))
+
+ f.write("\t}\n")
+
+ f.write("};\n\n")
+
+ if ifdef:
+ for i in ifdef:
+ f.write("#endif\n")
+ f.write("\n")
+
+ return
+
+
+ def img_to_c(self, node:Node, f):
+ ifdef = node.get_fields("ifdef")
+ if ifdef:
+ for i in ifdef:
+ f.write("{}\n".format(i))
+
+ f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
+ f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
+ f.write("\t.img_type = IMG_RAW,\n")
+ f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
+ f.write("\t.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {\n")
+
+ f.write("\t\t[0] = {\n")
+ f.write("\t\t\t.type = AUTH_METHOD_HASH,\n")
+ f.write("\t\t\t.param.hash = {\n")
+ f.write("\t\t\t\t.data = &raw_data,\n")
+ f.write("\t\t\t\t.hash = &{}\n".format(node.get_field("hash").label.name))
+ f.write("\t\t\t}\n")
+
+ f.write("\t\t}\n")
+ f.write("\t}\n")
+ f.write("};\n\n")
+
+ if ifdef:
+ for i in ifdef:
+ f.write("#endif\n")
+ f.write("\n")
+
+ return
+
+ def all_img_to_c(self, f):
+ images = self.get_all_images()
+ for i in images:
+ self.img_to_c(i, f)
+
+ f.write("\n")
+
+ def nv_to_c(self, f):
+ nv_ctr = self.get_all_nv_counters()
+
+ for nv in nv_ctr:
+ f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(nv.name, nv.get_field("oid")))
+
+ f.write("\n")
+
+ return
+
+ def pk_to_c(self, f):
+ pks = self.get_all_pks()
+
+ for p in pks:
+ f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(p.name, p.get_field("oid")))
+
+ f.write("\n")
+ return
+
+ def buf_to_c(self, f):
+ certs = self.get_all_certificates()
+
+ buffers = {}
+
+ for c in certs:
+ auth_data = self.get_auth_data(c)
+ for a in auth_data:
+ type_desc, ptr, data_len = self.format_auth_data_val(a, c)
+ if ptr not in buffers:
+ buffers[ptr] = c.get_fields("ifdef")
+
+ for key, values in buffers.items():
+ if values:
+ for i in values:
+ f.write("{}\n".format(i))
+
+ if "sp_pkg_hash_buf" in key:
+ f.write("static unsigned char {}[MAX_SP_IDS][HASH_DER_LEN];\n".format(key))
+ elif "pk" in key:
+ f.write("static unsigned char {}[PK_DER_LEN];\n".format(key))
+ else:
+ f.write("static unsigned char {}[HASH_DER_LEN];\n".format(key))
+
+ if values:
+ for i in values:
+ f.write("#endif\n")
+
+ f.write("\n")
+
+ def param_to_c(self, f):
+ f.write("static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, 0);\n")
+ f.write("static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_SIG, 0);\n")
+ f.write("static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_SIG_ALG, 0);\n")
+ f.write("static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_RAW_DATA, 0);\n")
+ f.write("\n")
+
+ certs = self.get_all_certificates()
+ for c in certs:
+ ifdef = c.get_fields("ifdef")
+ if ifdef:
+ for i in ifdef:
+ f.write("{}\n".format(i))
+
+ hash = c.children
+ for h in hash:
+ name = h.name
+ oid = h.get_field("oid")
+
+ if "pk" in name and "pkg" not in name:
+ f.write("static auth_param_type_desc_t {} = "\
+ "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(name, oid))
+ elif "hash" in name:
+ f.write("static auth_param_type_desc_t {} = "\
+ "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_HASH, {});\n".format(name, oid))
+ elif "ctr" in name:
+ f.write("static auth_param_type_desc_t {} = "\
+ "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(name, oid))
+
+ if ifdef:
+ for i in ifdef:
+ f.write("#endif\n")
+
+ f.write("\n")
+
+ def cot_to_c(self, f):
+ certs = self.get_all_certificates()
+ images = self.get_all_images()
+
+ f.write("static const auth_img_desc_t * const cot_desc[] = {\n")
+
+ for i, c in enumerate(certs):
+ ifdef = c.get_fields("ifdef")
+ if ifdef:
+ for i in ifdef:
+ f.write("{}\n".format(i))
+
+ f.write("\t[{}] = &{}{}\n".format(c.get_field("image-id").values[0], c.name, ","))
+
+ if ifdef:
+ for i in ifdef:
+ f.write("#endif\n")
+
+ for i, c in enumerate(images):
+ ifdef = c.get_fields("ifdef")
+ if ifdef:
+ for i in ifdef:
+ f.write("{}\n".format(i))
+
+ f.write("\t[{}] = &{}{}\n".format(c.get_field("image-id").values[0], c.name, "," if i != len(images) - 1 else ""))
+
+ if ifdef:
+ for i in ifdef:
+ f.write("#endif\n")
+
+ f.write("};\n\n")
+ f.write("REGISTER_COT(cot_desc);\n")
+ return
+
+ def generate_c_file(self):
+ filename = Path(self.output)
+ filename.parent.mkdir(exist_ok=True, parents=True)
+ output = open(self.output, 'w+')
+ input = open(self.input, "r")
+
+ self.generate_header(input, output)
+ self.buf_to_c(output)
+ self.param_to_c(output)
+ self.nv_to_c(output)
+ self.pk_to_c(output)
+ self.all_cert_to_c(output)
+ self.all_img_to_c(output)
+ self.cot_to_c(output)
+
+ return
diff --git a/tools/cot_dt2c/cot_dt2c/dt_validator.py b/tools/cot_dt2c/cot_dt2c/dt_validator.py
new file mode 100644
index 0000000..65e8ca2
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/dt_validator.py
@@ -0,0 +1,130 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import sys
+from os import path, walk, mkdir
+import subprocess
+from cot_dt2c.pydevicetree import *
+
+class bcolors:
+ HEADER = '\033[95m'
+ OKBLUE = '\033[94m'
+ OKCYAN = '\033[96m'
+ OKGREEN = '\033[92m'
+ WARNING = '\033[93m'
+ FAIL = '\033[91m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+
+class DTTree:
+ def __init__(self, input):
+ self.input = input
+ self.test_dir = "./tmp"
+ self.logging_file = self.test_dir + "/result.log"
+
+ def dtValidate(self):
+ subprocess.run(["rm", "-rf", self.test_dir])
+
+ if not path.exists(self.test_dir):
+ mkdir(self.test_dir)
+
+ if path.isfile(self.input):
+ self.dtValidateFile(self.input, printInfo=True)
+ return
+
+ if path.isdir(self.input):
+ self.dtValidateFiles()
+ return
+
+ def dtValidateFile(self, input, printInfo=False):
+ valid, tree = self.dtParseFile(input, printInfo)
+
+ if not valid:
+ return False
+
+ if input.rfind("/") != -1:
+ filename = self.test_dir + input[input.rfind("/"):]
+ else:
+ filename = self.test_dir + "/" + input
+
+ f = open(filename, "w+")
+ if "/dts-v1/;" not in str(tree):
+ f.write("/dts-v1/;\n\n")
+ f.write(str(tree))
+ f.close()
+
+ if str(tree) == "":
+ return valid
+
+ return valid
+
+ def dtParseFile(self, input, printInfo=False):
+ with open(input, 'r') as f:
+ contents = f.read()
+
+ pos = contents.find("/ {")
+ if pos != -1:
+ contents = contents[pos:]
+
+ try:
+ tree = Devicetree.parseStr(contents)
+ if printInfo:
+ print(bcolors.OKGREEN + "{} parse tree successfully".format(input) + bcolors.ENDC)
+ except Exception as e:
+ if printInfo:
+ print(bcolors.FAIL + "{} parse tree failed:\t{}".format(input, str(e)) + bcolors.ENDC)
+ else:
+ f = open(self.logging_file, "a")
+ f.write("=====================================================================================\n")
+ f.write("{} result:\n".format(input))
+ f.write("{} INVALID:\t{}\n".format(input, str(e)))
+ f.close()
+ return False, None
+
+ return True, tree
+
+ def dtValidateFiles(self):
+ f = []
+ for (dirpath, dirnames, filenames) in walk(self.input):
+ f.extend(filenames)
+
+ allFile = len(f)
+ dtsiFile = 0
+ validFile = 0
+ invalidFile = 0
+
+ for i in f:
+ if (".dtsi" in i or ".dts" in i) and "cot" not in i and "fw-config" not in i:
+ dtsiFile += 1
+ valid = True
+
+ if self.input[-1] == "/":
+ valid = self.dtValidateFile(self.input + i)
+ else:
+ valid = self.dtValidateFile(self.input + "/" + i)
+
+ if valid:
+ validFile += 1
+ else:
+ invalidFile += 1
+
+ print("=====================================================")
+ print("Total File: " + str(allFile))
+ print("Total DT File: " + str(dtsiFile))
+ print("Total Valid File: " + str(validFile))
+ print("Total Invalid File: " + str(invalidFile))
+
+def dtValidatorMain(input):
+ dt = DTTree(input)
+ dt.dtValidate()
+
+if __name__=="__main__":
+ if (len(sys.argv) < 2):
+ print("usage: python3 " + sys.argv[0] + " [dtsi file path] or [dtsi folder path]")
+ exit()
+ if len(sys.argv) == 2:
+ dtValidatorMain(sys.argv[1])
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py
new file mode 100644
index 0000000..49595a7
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from cot_dt2c.pydevicetree.ast import Devicetree, Node, Property, Directive, CellArray, LabelReference
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py
new file mode 100644
index 0000000..f30d897
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from cot_dt2c.pydevicetree.ast.directive import Directive
+from cot_dt2c.pydevicetree.ast.node import Node, NodeReference, Devicetree
+from cot_dt2c.pydevicetree.ast.property import PropertyValues, Bytestring, CellArray, StringList, Property, \
+ RegArray, OneString
+from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py
new file mode 100644
index 0000000..fdd6f0e
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import Any
+
+from cot_dt2c.pydevicetree.ast.helpers import formatLevel, wrapStrings
+
+class Directive:
+ """Represents a Devicetree directive
+
+ Directives in Devicetree source are statements of the form
+
+ /directive-name/ [option1 [option2 [...]]];
+
+ Common directive examples include:
+
+ /dts-v1/;
+ /include/ "overlay.dtsi";
+ /delete-node/ &uart0;
+ /delete-property/ status;
+
+ Their semantic meaning depends on the directive name, their location in the Devicetree,
+ and their options.
+ """
+ def __init__(self, directive: str, option: Any = None):
+ """Create a directive object"""
+ self.directive = directive
+ self.option = option
+
+ def __repr__(self) -> str:
+ return "<Directive %s>" % self.directive
+
+ def __str__(self) -> str:
+ return self.to_dts()
+
+ def to_dts(self, level: int = 0) -> str:
+ """Format the Directive in Devicetree Source format"""
+ if isinstance(self.option, list):
+ return formatLevel(level, "%s %s;\n" % (self.directive,
+ wrapStrings(self.option)))
+ if isinstance(self.option, str):
+ if self.directive == "/include/":
+ return formatLevel(level, "%s \"%s\"\n" % (self.directive, self.option))
+ return formatLevel(level, "%s \"%s\";\n" % (self.directive, self.option))
+ return formatLevel(level, "%s;\n" % self.directive)
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py
new file mode 100644
index 0000000..30c54dc
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import List, Any
+
+from cot_dt2c.pydevicetree.ast.reference import Reference
+
+def formatLevel(level: int, s: str) -> str:
+ """Helper to indent a string with a number of tabs"""
+ return "\t" * level + s
+
+def wrapStrings(values: List[Any], formatHex: bool = False) -> List[Any]:
+ """Helper to wrap strings in quotes where appropriate"""
+ wrapped = []
+ for v in values:
+ if isinstance(v, Reference):
+ wrapped.append(v.to_dts())
+ elif isinstance(v, str):
+ wrapped.append("\"%s\"" % v)
+ elif isinstance(v, int):
+ if formatHex:
+ wrapped.append("0x%x" % v)
+ else:
+ wrapped.append(str(v))
+ else:
+ wrapped.append(str(v))
+ return wrapped
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py
new file mode 100644
index 0000000..d203af8
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py
@@ -0,0 +1,514 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+import re
+import os
+from typing import List, Union, Optional, Iterable, Callable, Any, cast, Pattern
+
+from cot_dt2c.pydevicetree.ast.helpers import formatLevel
+from cot_dt2c.pydevicetree.ast.property import Property, PropertyValues, RegArray, RangeArray
+from cot_dt2c.pydevicetree.ast.directive import Directive
+from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
+
+# Type signature for elements passed to Devicetree constructor
+ElementList = Iterable[Union['Node', Property, Directive]]
+
+# Callback type signatures for Devicetree.match() and Devicetree.chosen()
+MatchFunc = Callable[['Node'], bool]
+MatchCallback = Optional[Callable[['Node'], None]]
+ChosenCallback = Optional[Callable[[PropertyValues], None]]
+
+class Node:
+ """Represents a Devicetree Node
+
+ A Devicetree Node generally takes the form
+
+ [label:] node-name@unit-address {
+ [directives]
+ [properties]
+ [child nodes]
+ };
+
+ The structure formed by creating trees of Nodes is the bulk of any Devicetree. As the naming
+ system implies, then, each node roughly corresponds to some conceptual device, subsystem of
+ devices, bus, etc.
+
+ Devices can be referenced by label or by path, and are generally uniquely identified by a
+ collection of string identifiers assigned to the "compatible" property.
+
+ For instance, a UART device might look like
+
+ uart0: uart@10013000 {
+ compatible = "sifive,uart0";
+ reg = <0x10013000 0x1000>;
+ reg-names = "control";
+ interrupt-parent = <&plic>;
+ interrupts = <3>;
+ clocks = <&busclk>;
+ status = "okay";
+ };
+
+ This node can be identified in the following ways:
+
+ - By label: uart0
+ - By path: /path/to/uart@10013000
+ - By name: uart@10013000 (for example when referenced in a /delete-node/ directive)
+ """
+ # pylint: disable=too-many-arguments
+ def __init__(self, name: str, label: Optional[str], address: Optional[int],
+ properties: List[Property], directives: List[Directive],
+ children: List['Node']):
+ """Initializes a Devicetree Node
+
+ Also evaluates the /delete-node/ and /delete-property/ directives found in the node
+ and deletes the respective nodes and properties.
+ """
+ self.name = name
+ self.parent = None # type: Optional['Node']
+
+ self.label = label
+ self.address = address
+ self.properties = properties
+ self.directives = directives
+ self.children = children
+ self.ifdef = []
+
+ for d in self.directives:
+ if d.directive == "/delete-node/":
+ if isinstance(d.option, LabelReference):
+ node = self.get_by_reference(d.option)
+ elif isinstance(d.option, str):
+ node = self.__get_child_by_handle(d.option)
+ if node:
+ self.remove_child(node)
+ elif d.directive == "/delete-property/":
+ # pylint: disable=cell-var-from-loop
+ properties = list(filter(lambda p: p.name == d.option, self.properties))
+ if properties:
+ del self.properties[self.properties.index(properties[0])]
+
+ def __repr__(self) -> str:
+ if self.address:
+ return "<Node %s@%x>" % (self.name, self.address)
+ return "<Node %s>" % self.name
+
+ def __str__(self) -> str:
+ return self.to_dts()
+
+ def __eq__(self, other) -> bool:
+ return self.name == other.name and self.address == other.address
+
+ def __hash__(self):
+ return hash((self.name, self.address))
+
+ @staticmethod
+ def from_dts(source: str) -> 'Node':
+ """Create a node from Devicetree Source"""
+ # pylint: disable=import-outside-toplevel,cyclic-import
+ from pydevicetree.source import parseNode
+ return parseNode(source)
+
+ def add_child(self, node: 'Node', merge: bool = True):
+ """Add a child node and merge it into the tree"""
+ node.parent = self
+ self.children.append(node)
+ if merge:
+ self.merge_tree()
+
+ def to_dts(self, level: int = 0) -> str:
+ """Format the subtree starting at the node as Devicetree Source"""
+ out = ""
+ if isinstance(self.address, int) and self.label:
+ out += formatLevel(level,
+ "%s: %s@%x {\n" % (self.label, self.name, self.address))
+ elif isinstance(self.address, int):
+ out += formatLevel(level, "%s@%x {\n" % (self.name, self.address))
+ elif self.label:
+ out += formatLevel(level, "%s: %s {\n" % (self.label, self.name))
+ elif self.name != "":
+ out += formatLevel(level, "%s {\n" % self.name)
+
+ for d in self.directives:
+ out += d.to_dts(level + 1)
+ for p in self.properties:
+ out += p.to_dts(level + 1)
+ for c in self.children:
+ out += c.to_dts(level + 1)
+
+ if self.name != "":
+ out += formatLevel(level, "};\n")
+
+ return out
+
+ def merge_tree(self):
+ """Recursively merge child nodes into a single tree
+
+ Parsed Devicetrees can describe the same tree multiple times, adding nodes and properties
+ each time. After parsing, this method is called to recursively merge the tree.
+ """
+ partitioned_children = []
+ for n in self.children:
+ partitioned_children.append([e for e in self.children if e == n])
+
+ new_children = []
+ for part in partitioned_children:
+ first = part[0]
+ rest = part[1:]
+ if first not in new_children:
+ for n in rest:
+ first.merge(n)
+ new_children.append(first)
+
+ self.children = new_children
+
+ for n in self.children:
+ n.parent = self
+ n.merge_tree()
+
+ def merge(self, other: 'Node'):
+ """Merge the contents of a node into this node.
+
+ Used by Node.merge_trees()
+ """
+ if not self.label and other.label:
+ self.label = other.label
+ self.properties += other.properties
+ self.directives += other.directives
+ self.children += other.children
+ self.ifdef += other.ifdef
+
+ def get_path(self, includeAddress: bool = True) -> str:
+ """Get the path of a node (ex. /cpus/cpu@0)"""
+ if self.name == "/":
+ return ""
+ if self.parent is None:
+ return "/" + self.name
+ if isinstance(self.address, int) and includeAddress:
+ return self.parent.get_path() + "/" + self.name + "@" + ("%x" % self.address)
+ return self.parent.get_path() + "/" + self.name
+
+ def get_by_reference(self, reference: Reference) -> Optional['Node']:
+ """Get a node from the subtree by reference (ex. &label, &{/path/to/node})"""
+ if isinstance(reference, LabelReference):
+ return self.get_by_label(reference.label)
+ if isinstance(reference, PathReference):
+ return self.get_by_path(reference.path)
+
+ return None
+
+ def get_by_label(self, label: Union[Label, str]) -> Optional['Node']:
+ """Get a node from the subtree by label"""
+ matching_nodes = list(filter(lambda n: n.label == label, self.child_nodes()))
+ if len(matching_nodes) != 0:
+ return matching_nodes[0]
+ return None
+
+ def __get_child_by_handle(self, handle: str) -> Optional['Node']:
+ """Get a child node by name or name and unit address"""
+ if '@' in handle:
+ name, addr_s = handle.split('@')
+ address = int(addr_s, base=16)
+ nodes = list(filter(lambda n: n.name == name and n.address == address, self.children))
+ else:
+ name = handle
+ nodes = list(filter(lambda n: n.name == name, self.children))
+
+ if not nodes:
+ return None
+ if len(nodes) > 1:
+ raise Exception("Handle %s is ambiguous!" % handle)
+ return nodes[0]
+
+ def get_by_path(self, path: Union[Path, str]) -> Optional['Node']:
+ """Get a node in the subtree by path"""
+ matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=True), \
+ self.child_nodes()))
+ if len(matching_nodes) != 0:
+ return matching_nodes[0]
+
+ matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=False), \
+ self.child_nodes()))
+ if len(matching_nodes) != 0:
+ return matching_nodes[0]
+ return None
+
+ def filter(self, matchFunc: MatchFunc, cbFunc: MatchCallback = None) -> List['Node']:
+ """Filter all child nodes by matchFunc
+
+ If cbFunc is provided, this method will iterate over the Nodes selected by matchFunc
+ and call cbFunc on each Node
+
+ Returns a list of all matching Nodes
+ """
+ nodes = list(filter(matchFunc, self.child_nodes()))
+
+ if cbFunc is not None:
+ for n in nodes:
+ cbFunc(n)
+
+ return nodes
+
+ def match(self, compatible: Pattern, func: MatchCallback = None) -> List['Node']:
+ """Get a node from the subtree by compatible string
+
+ Accepts a regular expression to match one of the strings in the compatible property.
+ """
+ regex = re.compile(compatible)
+
+ def match_compat(node: Node) -> bool:
+ compatibles = node.get_fields("compatible")
+ if compatibles is not None:
+ return any(regex.match(c) for c in compatibles)
+ return False
+
+ return self.filter(match_compat, func)
+
+ def child_nodes(self) -> Iterable['Node']:
+ """Get an iterable over all the nodes in the subtree"""
+ for n in self.children:
+ yield n
+ for m in n.child_nodes():
+ yield m
+
+ def remove_child(self, node):
+ """Remove a child node"""
+ del self.children[self.children.index(node)]
+
+ def get_fields(self, field_name: str) -> Optional[PropertyValues]:
+ """Get all the values of a property"""
+ for p in self.properties:
+ if p.name == field_name:
+ return p.values
+ return None
+
+ def has_field(self, field_name: str) -> bool:
+ for p in self.properties:
+ if p.name == field_name:
+ return True
+ return False
+
+ def get_field(self, field_name: str) -> Any:
+ """Get the first value of a property"""
+ fields = self.get_fields(field_name)
+ if fields is not None:
+ if len(cast(PropertyValues, fields)) != 0:
+ return fields[0]
+ return None
+
+ def get_reg(self) -> Optional[RegArray]:
+ """If the node defines a `reg` property, return a RegArray for easier querying"""
+ reg = self.get_fields("reg")
+ reg_names = self.get_fields("reg-names")
+ if reg is not None:
+ if reg_names is not None:
+ return RegArray(reg.values, self.address_cells(), self.size_cells(),
+ reg_names.values)
+ return RegArray(reg.values, self.address_cells(), self.size_cells())
+ return None
+
+ def get_ranges(self) -> Optional[RangeArray]:
+ """If the node defines a `ranges` property, return a RangeArray for easier querying"""
+ ranges = self.get_fields("ranges")
+ child_address_cells = self.get_field("#address-cells")
+ parent_address_cells = self.address_cells()
+ size_cells = self.get_field("#size-cells")
+ if ranges is not None:
+ return RangeArray(ranges.values, child_address_cells, parent_address_cells, size_cells)
+ return None
+
+ def address_cells(self):
+ """Get the number of address cells
+
+ The #address-cells property is defined by the parent of a node and describes how addresses
+ are encoded in cell arrays. If no property is defined, the default value is 2.
+ """
+ if self.parent is not None:
+ cells = self.parent.get_field("#address-cells")
+ if cells is not None:
+ return cells
+ return 2
+ return 2
+
+ def size_cells(self):
+ """Get the number of size cells
+
+ The #size-cells property is defined by the parent of a node and describes how addresses
+ are encoded in cell arrays. If no property is defined, the default value is 1.
+ """
+ if self.parent is not None:
+ cells = self.parent.get_field("#size-cells")
+ if cells is not None:
+ return cells
+ return 1
+ return 1
+
+class NodeReference(Node):
+ """A NodeReference is used to extend the definition of a previously-defined Node
+
+ NodeReferences are commonly used by Devicetree "overlays" to extend the properties of a node
+ or add child devices, such as to a bus like I2C.
+ """
+ def __init__(self, reference: Reference, properties: List[Property],
+ directives: List[Directive], children: List[Node]):
+ """Instantiate a Node identified by reference to another node"""
+ self.reference = reference
+ Node.__init__(self, label=None, name="", address=None, properties=properties,
+ directives=directives, children=children)
+
+ def __repr__(self) -> str:
+ return "<NodeReference %s>" % self.reference.to_dts()
+
+ def resolve_reference(self, tree: 'Devicetree') -> Node:
+ """Given the full tree, get the node being referenced"""
+ node = tree.get_by_reference(self.reference)
+ if node is None:
+ raise Exception("Node reference %s cannot be resolved" % self.reference.to_dts())
+ return cast(Node, node)
+
+ def to_dts(self, level: int = 0) -> str:
+ out = formatLevel(level, self.reference.to_dts() + " {\n")
+
+ for d in self.directives:
+ out += d.to_dts(level + 1)
+ for p in self.properties:
+ out += p.to_dts(level + 1)
+ for c in self.children:
+ out += c.to_dts(level + 1)
+
+ out += formatLevel(level, "};\n")
+
+ return out
+
+
+class Devicetree(Node):
+ """A Devicetree object describes the full Devicetree tree
+
+ This class encapsulates both the tree itself (starting at the root node /) and any Directives
+ or nodes which exist at the top level of the Devicetree Source files.
+
+ Devicetree Source files can be parsed by calling Devicetree.parseFile().
+ """
+ def __init__(self, elements: ElementList):
+ """Instantiate a Devicetree with the list of parsed elements
+
+ Resolves all reference nodes and merges the tree to combine all identical nodes.
+ """
+ properties = [] # type: List[Property]
+ directives = [] # type: List[Directive]
+ children = [] # type: List[Node]
+
+ for e in elements:
+ if isinstance(e, Node):
+ children.append(cast(Node, e))
+ elif isinstance(e, Property):
+ properties.append(cast(Property, e))
+ elif isinstance(e, Directive):
+ directives.append(cast(Directive, e))
+
+ Node.__init__(self, label=None, name="", address=None,
+ properties=properties, directives=directives, children=children)
+
+ for node in self.children:
+ node.parent = self
+
+ reference_nodes = self.filter(lambda n: isinstance(n, NodeReference))
+ for refnode in reference_nodes:
+ refnode = cast(NodeReference, refnode)
+
+ node = refnode.resolve_reference(self)
+
+ if refnode.parent:
+ cast(Node, refnode.parent).remove_child(refnode)
+
+ node.properties += refnode.properties
+ node.directives += refnode.directives
+ node.children += refnode.children
+
+ self.merge_tree()
+
+ def __repr__(self) -> str:
+ name = self.root().get_field("compatible")
+ return "<Devicetree %s>" % name
+
+ def to_dts(self, level: int = 0) -> str:
+ """Convert the tree back to Devicetree Source"""
+ out = ""
+
+ for d in self.directives:
+ out += d.to_dts()
+ for p in self.properties:
+ out += p.to_dts()
+ for c in self.children:
+ out += c.to_dts()
+
+ return out
+
+ def get_by_path(self, path: Union[Path, str]) -> Optional[Node]:
+ """Get a node in the tree by path (ex. /cpus/cpu@0)"""
+
+ # Find and replace all aliases in the path
+ aliases = self.aliases()
+ if aliases:
+ for prop in aliases.properties:
+ if prop.name in path and len(prop.values) > 0:
+ path = path.replace(prop.name, prop.values[0])
+
+ return self.root().get_by_path(path)
+
+ @staticmethod
+ # pylint: disable=arguments-differ
+ def from_dts(dts: str) -> 'Devicetree':
+ """Parse a string and return a Devicetree object"""
+ # pylint: disable=import-outside-toplevel,cyclic-import
+ from pydevicetree.source import parseTree
+ return parseTree(dts)
+
+ @staticmethod
+ def parseFile(filename: str, followIncludes: bool = False) -> 'Devicetree':
+ """Parse a file and return a Devicetree object"""
+ # pylint: disable=import-outside-toplevel,cyclic-import
+ from cot_dt2c.pydevicetree.source.parser import parseTree
+ with open(filename, 'r') as f:
+ contents = f.read()
+ dirname = os.path.dirname(filename)
+ if dirname != "":
+ dirname += "/"
+ return parseTree(contents, dirname, followIncludes)
+
+ @staticmethod
+ def parseStr(input: str, followIncludes: bool = False) -> 'Devicetree':
+ from cot_dt2c.pydevicetree.source.parser import parseTree
+ return parseTree(input, "", followIncludes)
+
+ def all_nodes(self) -> Iterable[Node]:
+ """Get an iterable over all nodes in the tree"""
+ return self.child_nodes()
+
+ def root(self) -> Node:
+ """Get the root node of the tree"""
+ for n in self.all_nodes():
+ if n.name == "/":
+ return n
+ raise Exception("Devicetree has no root node!")
+
+ def aliases(self) -> Optional[Node]:
+ """Get the aliases node of the tree if it exists"""
+ for n in self.all_nodes():
+ if n.name == "aliases":
+ return n
+ return None
+
+ def chosen(self, property_name: str, func: ChosenCallback = None) -> Optional[PropertyValues]:
+ """Get the values associated with one of the properties in the chosen node"""
+ def match_chosen(node: Node) -> bool:
+ return node.name == "chosen"
+
+ for n in filter(match_chosen, self.all_nodes()):
+ for p in n.properties:
+ if p.name == property_name:
+ if func is not None:
+ func(p.values)
+ return p.values
+
+ return None
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py
new file mode 100644
index 0000000..d5fb687
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py
@@ -0,0 +1,278 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import List, Any, cast, Tuple, Optional, Iterable
+from itertools import zip_longest
+
+from cot_dt2c.pydevicetree.ast.helpers import wrapStrings, formatLevel
+
+class PropertyValues:
+ """PropertyValues is the parent class of all values which can be assigned to a Property
+
+ Child classes include
+
+ Bytestring
+ CellArray
+ StringList
+ """
+ def __init__(self, values: List[Any]):
+ """Create a PropertyValue"""
+ self.values = values
+
+ def __repr__(self) -> str:
+ return "<PropertyValues " + self.values.__repr__() + ">"
+
+ def __str__(self) -> str:
+ return self.to_dts()
+
+ def __iter__(self):
+ return iter(self.values)
+
+ def __len__(self) -> int:
+ return len(self.values)
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the values in Devicetree Source format"""
+ return ", ".join(wrapStrings(self.values, formatHex))
+
+ def __getitem__(self, key) -> Any:
+ return self.values[key]
+
+ def __eq__(self, other) -> bool:
+ if isinstance(other, PropertyValues):
+ return self.values == other.values
+ return self.values == other
+
+class Bytestring(PropertyValues):
+ """A Bytestring is a sequence of bytes
+
+ In Devicetree, Bytestrings are represented as a sequence of two-digit hexadecimal integers,
+ optionally space-separated, enclosed by square brackets:
+
+ [de ad be eef]
+ """
+ def __init__(self, bytelist: List[int]):
+ """Create a Bytestring object"""
+ PropertyValues.__init__(self, cast(List[Any], bytearray(bytelist)))
+
+ def __repr__(self) -> str:
+ return "<Bytestring " + str(self.values) + ">"
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the bytestring in Devicetree Source format"""
+ return "[" + " ".join("%02x" % v for v in self.values) + "]"
+
+class CellArray(PropertyValues):
+ """A CellArray is an array of integer values
+
+ CellArrays are commonly used as the value of Devicetree properties like `reg` and `interrupts`.
+ The interpretation of each element of a CellArray is device-dependent. For example, the `reg`
+ property encodes a CellArray as a list of tuples (base address, size), while the `interrupts`
+ property encodes a CellArray as simply a list of interrupt line numbers.
+ """
+ def __init__(self, cells: List[Any]):
+ """Create a CellArray object"""
+ PropertyValues.__init__(self, cells)
+
+ def __repr__(self) -> str:
+ return "<CellArray " + self.values.__repr__() + ">"
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the cell array in Devicetree Source format"""
+ dtsValues = []
+ for i in self.values:
+ if not isinstance(i, OneString) and not isinstance(i, str):
+ dtsValues.append(i)
+ return "<" + " ".join(wrapStrings(dtsValues, formatHex)) + ">"
+
+class RegArray(CellArray):
+ """A RegArray is the CellArray assigned to the reg property"""
+ def __init__(self, cells: List[int],
+ address_cells: int, size_cells: int,
+ names: Optional[List[str]] = None):
+ """Create a RegArray from a list of ints"""
+ # pylint: disable=too-many-locals
+ CellArray.__init__(self, cells)
+ self.address_cells = address_cells
+ self.size_cells = size_cells
+
+ self.tuples = [] # type: List[Tuple[int, int, Optional[str]]]
+
+ group_size = self.address_cells + self.size_cells
+
+ if len(cells) % group_size != 0:
+ raise Exception("CellArray does not contain enough cells")
+
+ grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
+
+ if not names:
+ names = []
+
+ for group, name in zip_longest(grouped_cells, cast(Iterable[Any], names)):
+ address = 0
+ a_cells = list(reversed(group[:self.address_cells]))
+ for a, i in zip(a_cells, range(len(a_cells))):
+ address += (1 << (32 * i)) * a
+
+ size = 0
+ s_cells = list(reversed(group[self.address_cells:]))
+ for s, i in zip(s_cells, range(len(s_cells))):
+ size += (1 << (32 * i)) * s
+
+ self.tuples.append(cast(Tuple[int, int, Optional[str]], tuple([address, size, name])))
+
+ def get_by_name(self, name: str) -> Optional[Tuple[int, int]]:
+ """Returns the (address, size) tuple with a given name"""
+ for t in self.tuples:
+ if t[2] == name:
+ return cast(Tuple[int, int], tuple(t[:2]))
+ return None
+
+ def __repr__(self) -> str:
+ return "<RegArray " + self.values.__repr__() + ">"
+
+ def __iter__(self) -> Iterable[Tuple[int, int]]:
+ return cast(Iterable[Tuple[int, int]], map(lambda t: tuple(t[:2]), self.tuples))
+
+ def __len__(self) -> int:
+ return len(self.tuples)
+
+ def __getitem__(self, key) -> Optional[Tuple[int, int]]:
+ return list(self.__iter__())[key]
+
+class RangeArray(CellArray):
+ """A RangeArray is the CellArray assigned to the range property"""
+ def __init__(self, cells: List[int], child_address_cells: int,
+ parent_address_cells: int, size_cells: int):
+ """Create a RangeArray from a list of ints"""
+ # pylint: disable=too-many-locals
+ CellArray.__init__(self, cells)
+ self.child_address_cells = child_address_cells
+ self.parent_address_cells = parent_address_cells
+ self.size_cells = size_cells
+
+ self.tuples = [] # type: List[Tuple[int, int, int]]
+
+ group_size = self.child_address_cells + self.parent_address_cells + self.size_cells
+
+ if len(cells) % group_size != 0:
+ raise Exception("CellArray does not contain enough cells")
+
+ grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
+
+ def sum_cells(cells: List[int]):
+ value = 0
+ for cell, index in zip(list(reversed(cells)), range(len(cells))):
+ value += (1 << (32 * index)) * cell
+ return value
+
+ for group in grouped_cells:
+ child_address = sum_cells(group[:self.child_address_cells])
+ parent_address = sum_cells(group[self.child_address_cells: \
+ self.child_address_cells + self.parent_address_cells])
+ size = sum_cells(group[self.child_address_cells + self.parent_address_cells:])
+
+ self.tuples.append(cast(Tuple[int, int, int],
+ tuple([child_address, parent_address, size])))
+
+ def __repr__(self) -> str:
+ return "<RangeArray " + self.values.__repr__() + ">"
+
+ def __iter__(self):
+ return iter(self.tuples)
+
+ def __len__(self) -> int:
+ return len(self.tuples)
+
+ def __getitem__(self, key) -> Any:
+ return self.tuples[key]
+
+class StringList(PropertyValues):
+ """A StringList is a list of null-terminated strings
+
+ The most common use of a StringList in Devicetree is to describe the `compatible` property.
+ """
+ def __init__(self, strings: List[str]):
+ """Create a StringList object"""
+ PropertyValues.__init__(self, strings)
+
+ def __repr__(self) -> str:
+ return "<StringList " + self.values.__repr__() + ">"
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the list of strings in Devicetree Source format"""
+ return ", ".join(wrapStrings(self.values))
+
+class OneString(PropertyValues):
+ def __init__(self, string: str):
+ PropertyValues.__init__(self, string)
+
+ def __repr__(self) -> str:
+ return self.values.__repr__()
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ return super().to_dts(formatHex)
+
+class Property:
+ """A Property is a key-value pair for a Devicetree Node
+
+ Properties are used to describe Nodes in the tree. There are many common properties, like
+
+ - compatible
+ - reg
+ - reg-names
+ - ranges
+ - interrupt-controller
+ - interrupts
+ - interrupt-parent
+ - clocks
+ - status
+
+ Which might commonly describe many or all nodes in a tree, and there are device, vendor,
+ operating system, runtime-specific properties.
+
+ Properties can possess no value, conveing meaning solely by their presence:
+
+ interrupt-controller;
+
+ Properties can also possess values such as an array of cells, a list of strings, etc.
+
+ reg = <0x10013000 0x1000>;
+ compatible = "sifive,rocket0", "riscv";
+
+ And properties can posses arbitrarily complex values, such as the following from the
+ Devicetree specification:
+
+ example = <0xf00f0000 19>, "a strange property format";
+ """
+ def __init__(self, name: str, values: PropertyValues):
+ """Create a Property object"""
+ self.name = name
+ self.values = values
+
+ def __repr__(self) -> str:
+ return "<Property %s>" % self.name
+
+ def __str__(self) -> str:
+ return self.to_dts()
+
+ @staticmethod
+ def from_dts(dts: str) -> 'Property':
+ """Parse a file and return a Devicetree object"""
+ # pylint: disable=import-outside-toplevel,cyclic-import
+ from pydevicetree.source import parseProperty
+ return parseProperty(dts)
+
+ def to_dts(self, level: int = 0) -> str:
+ """Format the Property assignment in Devicetree Source format"""
+ if self.name in ["reg", "ranges"]:
+ value = self.values.to_dts(formatHex=True)
+ else:
+ value = self.values.to_dts(formatHex=False)
+
+ if value != "":
+ return formatLevel(level, "%s = %s;\n" % (self.name, value))
+ if self.name == "ifdef":
+ return ""
+ return formatLevel(level, "%s;\n" % self.name)
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py
new file mode 100644
index 0000000..54b2d28
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from typing import Union, Iterator
+
+class Label:
+ """A Label is a unique identifier for a Node
+
+ For example, the following node has the label "uart0":
+
+ uart0: uart@10013000 {
+ ...
+ };
+ """
+ def __init__(self, name: str):
+ """Create a Label"""
+ self.name = name
+
+ def __repr__(self) -> str:
+ return "<Label " + self.name + ">"
+
+ def __eq__(self, other: object) -> bool:
+ if isinstance(other, Label):
+ return self.name == other.name
+ if isinstance(other, str):
+ return self.name == other
+ return False
+
+ def to_dts(self) -> str:
+ """Format the label in Devicetree Source format"""
+ return self.name + ":"
+
+class Path:
+ """A Path uniquely identifies a Node by its parents and (optionally) unit address"""
+ def __init__(self, path: str):
+ """Create a path out of a string"""
+ self.path = path
+
+ def to_dts(self) -> str:
+ """Format the Path in Devicetree Source format"""
+ return self.path
+
+ def __repr__(self) -> str:
+ return "<Path " + self.to_dts() + ">"
+
+ def __eq__(self, other: object) -> bool:
+ if isinstance(other, Path):
+ return self.to_dts() == other.to_dts()
+ if isinstance(other, str):
+ return self.to_dts() == other
+ return False
+
+ def __iter__(self) -> Iterator[str]:
+ return iter(self.path.split("/"))
+
+ def replace(self, old: str, new: str) -> 'Path':
+ """Replace any elements of the path which match 'old' with a new element 'new'"""
+ return Path(self.path.replace(old, new))
+
+class Reference:
+ """A Reference is a Devicetree construct which points to a Node in the tree
+
+ The following are types of references:
+
+ - A reference to a label:
+
+ &my-label;
+
+ - A reference to a node by path:
+
+ &{/path/to/node@deadbeef}
+
+ This is the parent class for both types of references, LabelReference and PathReference
+ """
+ # pylint: disable=no-self-use
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the Reference in Devicetree Source format"""
+ return ""
+
+class LabelReference(Reference):
+ """A LabelReference is a reference to a Node by label"""
+ def __init__(self, label: Union[Label, str]):
+ """Create a LabelReference from a Label or string"""
+ if isinstance(label, Label):
+ self.label = label
+ elif isinstance(label, str):
+ self.label = Label(label)
+
+ def __repr__(self) -> str:
+ return "<LabelReference " + self.to_dts() + ">"
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the LabelReference in Devicetree Source format"""
+ return "&" + self.label.name
+
+class PathReference(Reference):
+ """A PathReference is a reference to a Node by path"""
+ def __init__(self, path: Union[Path, str]):
+ """Create a PathReference from a Path or string"""
+ if isinstance(path, Path):
+ self.path = path
+ elif isinstance(path, str):
+ self.path = Path(path)
+
+ def __repr__(self) -> str:
+ return "<PathReference " + self.to_dts() + ">"
+
+ def to_dts(self, formatHex: bool = False) -> str:
+ """Format the PathReference in Devicetree Source format"""
+ return "&{" + self.path.to_dts() + "}"
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py
new file mode 100644
index 0000000..96768b3
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from cot_dt2c.pydevicetree.source.parser import parseTree, parseNode, parseProperty
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py
new file mode 100644
index 0000000..fb165e1
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+import os
+import sys
+
+import pyparsing as p # type: ignore
+
+ENV_CACHE_OPTION = "PYDEVICETREE_CACHE_SIZE_BOUND"
+
+cache_bound = None
+if ENV_CACHE_OPTION in os.environ:
+ option = os.environ[ENV_CACHE_OPTION]
+ if option != "None":
+ try:
+ cache_bound = int(option)
+ except ValueError:
+ print("%s requires a valid integer" % ENV_CACHE_OPTION, file=sys.stderr)
+p.ParserElement.enablePackrat(cache_bound)
+
+node_name = p.Word(p.alphanums + ",.-+_") ^ p.Literal("/")
+integer = p.pyparsing_common.integer ^ (p.Literal("0x").suppress() + p.pyparsing_common.hex_integer)
+unit_address = p.pyparsing_common.hex_integer
+unit_addresses = p.delimitedList(unit_address("address"), delim=",")
+node_handle = node_name("node_name") + p.Optional(p.Literal("@") + unit_addresses)
+property_name = p.Word(p.alphanums + ",.-_+?#")
+label = p.Word(p.alphanums + "_").setResultsName("label")
+label_creation = p.Combine(label + p.Literal(":"))
+string = p.QuotedString(quoteChar='"')
+stringlist = p.delimitedList(string)
+node_path = p.Combine(p.Literal("/") + \
+ p.delimitedList(node_handle, delim="/", combine=True)).setResultsName("path")
+path_reference = p.Literal("&{").suppress() + node_path + p.Literal("}").suppress()
+label_reference = p.Literal("&").suppress() + label
+label_raw = p.Word(p.alphanums + "_")
+reference = path_reference ^ label_reference ^ label_raw
+include_directive = p.Literal("/include/") + p.QuotedString(quoteChar='"')
+generic_directive = p.QuotedString(quoteChar="/", unquoteResults=False) + \
+ p.Optional(string ^ property_name ^ node_name ^ reference ^ (integer * 2)) + \
+ p.Literal(";").suppress()
+directive = include_directive ^ generic_directive
+
+operator = p.oneOf("~ ! * / + - << >> < <= > >= == != & ^ | && ||")
+arith_expr = p.Forward()
+ternary_element = arith_expr ^ integer
+ternary_expr = ternary_element + p.Literal("?") + ternary_element + p.Literal(":") + ternary_element
+arith_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer) ^ ternary_expr))
+arth_str = p.Forward()
+arith_str_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer ^ label_raw ^ p.Literal(",")) ^ ternary_expr))
+
+label_list = p.OneOrMore(p.Combine(label + p.Literal("\n")))
+
+cell_array = p.Literal("<").suppress() + \
+ p.ZeroOrMore(integer ^ arith_expr ^ arith_str_expr ^ label_list ^ string ^ reference ^ label_creation.suppress()) + \
+ p.Literal(">").suppress()
+bytestring = p.Literal("[").suppress() + \
+ (p.OneOrMore(p.Word(p.hexnums, exact=2) ^ label_creation.suppress())) + \
+ p.Literal("]").suppress()
+property_values = p.Forward()
+property_values = p.delimitedList(property_values ^ cell_array ^ bytestring ^ stringlist ^ \
+ reference ^ label_raw)
+property_assignment = property_name("property_name") + p.Optional(p.Literal("=").suppress() + \
+ (property_values)).setResultsName("value") + p.Optional(p.Literal(";").suppress())
+
+ifdef_label = p.ZeroOrMore(p.Word(p.alphanums + " _|//*=/(/)"))
+ifdef_define = p.Combine(p.Keyword("#if") + ifdef_label)
+ifdef_end = p.Combine(p.Keyword("#endif") + ifdef_label)
+ifdef_define_values = p.Forward()
+ifdef_define_values = p.ZeroOrMore(ifdef_define)
+ifdef_end_values = p.Forward()
+ifdef_end_values = p.ZeroOrMore(ifdef_end)
+
+node_opener = ifdef_define_values + p.Optional(label_creation) + node_handle + p.Literal("{").suppress()
+node_reference_opener = reference + p.Literal("{").suppress()
+node_closer = p.Literal("}").suppress() + p.Literal(";").suppress() + ifdef_end_values
+node_definition = p.Forward()
+# pylint: disable=expression-not-assigned
+node_definition << (node_opener ^ node_reference_opener) + \
+ p.ZeroOrMore(property_assignment ^ directive ^ node_definition ^ ifdef_define ^ ifdef_end) + \
+ node_closer
+
+devicetree = p.ZeroOrMore(directive ^ node_definition)
+
+devicetree.ignore(p.cStyleComment)
+devicetree.ignore("//" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#include" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#define" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#else" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#error" + p.SkipTo(p.lineEnd))
+devicetree.ignore("#ifndef" + p.SkipTo(p.lineEnd))
+
+if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ devicetree.parseFile(sys.argv[1]).pprint()
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py
new file mode 100644
index 0000000..0692482
--- /dev/null
+++ b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019 SiFive Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+from itertools import chain
+
+from cot_dt2c.pydevicetree.source import grammar
+from cot_dt2c.pydevicetree.ast import *
+
+ifdef_stack = []
+
+def transformNode(string, location, tokens):
+ """Transforms a ParseResult into a Node"""
+ properties = [e for e in tokens.asList() if isinstance(e, Property)]
+ directives = [e for e in tokens.asList() if isinstance(e, Directive)]
+ children = [e for e in tokens.asList() if isinstance(e, Node)]
+
+ if isinstance(tokens[0], Reference):
+ return NodeReference(tokens[0], properties=properties,
+ directives=directives, children=children)
+ return Node(tokens.node_name, tokens.label, tokens.address, properties=properties,
+ directives=directives, children=children)
+
+def transformPropertyAssignment(string, location, tokens):
+ """Transforms a ParseResult into a Property"""
+ for v in tokens.value:
+ if isinstance(v, PropertyValues):
+ return Property(tokens.property_name, v)
+ if isinstance(v, CellArray):
+ return Property(tokens.property_name, v)
+ if isinstance(v, StringList):
+ return Property(tokens.property_name, v)
+ if isinstance(v, Reference):
+ return Property(tokens.property_name, v)
+
+ return Property(tokens.property_name, PropertyValues([]))
+
+def transformDirective(string, location, tokens):
+ """Transforms a ParseResult into a Directive"""
+ if len(tokens.asList()) > 1:
+ return Directive(tokens[0], tokens[1])
+ return Directive(tokens[0])
+
+def evaluateArithExpr(string, location, tokens):
+ """Evaluates a ParseResult as a python expression"""
+ flat_tokens = list(chain.from_iterable(tokens.asList()))
+ expr = " ".join(str(t) for t in flat_tokens)
+ # pylint: disable=eval-used
+ return eval(expr)
+
+def transformTernary(string, location, tokens):
+ """Evaluates a ParseResult as a ternary expression"""
+ # pylint: disable=eval-used
+ return eval(str(tokens[2]) +" if " + str(tokens[0]) + " else " + str(tokens[4]))
+
+def transformPropertyValues(string, location, tokens):
+ """Transforms a ParseResult into a PropertyValues"""
+ if len(tokens.asList()) == 1:
+ return tokens.asList()[0]
+ return PropertyValues(tokens.asList())
+
+def transformStringList(string, location, tokens):
+ """Transforms a ParseResult into a StringList"""
+ return StringList(tokens.asList())
+
+def transformString(string, location, token):
+ return OneString(token)
+
+def transformIfdefMacro(string, location, tokens):
+ tokenlist = tokens.asList()
+ for t in tokenlist:
+ ifdef_stack.append(t)
+ return Property("ifdef", PropertyValues(ifdef_stack.copy()))
+
+def transformIfdefEnd(string, location, tokens):
+ tokenlist = tokens.asList()
+ for t in tokenlist:
+ ifdef_stack.pop()
+
+def transformIfdef(string, location, tokens):
+ return Property("ifdef", PropertyValues(tokens))
+
+def evaluateStrArithExpr(string, location, tokens):
+ """Evaluates a ParseResult as a python expression"""
+ flat_tokens = list(chain.from_iterable(tokens.asList()))
+ for i, t in enumerate(flat_tokens):
+ if isinstance(t, int):
+ flat_tokens[i] = "(" + str(t) + ")"
+ expr = " ".join(str(t) for t in flat_tokens)
+ # pylint: disable=eval-used
+ return expr
+
+def transformBytestring(string, location, tokens):
+ """Transforms a ParseResult into a Bytestring"""
+ inttokens = []
+ for t in tokens.asList():
+ if all(c in "0123456789abcdefABCDEF" for c in t):
+ inttokens.append(int(t, base=16))
+ return Bytestring(inttokens)
+
+def transformCellArray(string, location, tokens):
+ """Transforms a ParseResult into a CellArray"""
+ return CellArray(tokens.asList())
+
+def transformLabel(string, location, tokens):
+ """Transforms a ParseResult into a Label"""
+ return Label(tokens.label)
+
+def transformPath(string, location, tokens):
+ """Transforms a ParseResult into a Path"""
+ path = ""
+ for handle in tokens.path[0].split("/"):
+ if "@" in handle:
+ node, address = handle.split("@")
+ path += "/%s@%x" % (node, int(address))
+ elif handle != "":
+ path += "/" + handle
+ return Path(path)
+
+def transformPathReference(string, location, tokens):
+ """Transforms a ParseResult into a PathReference"""
+ return PathReference(tokens[0])
+
+def transformLabelReference(string, location, tokens):
+ """Transforms a ParseResult into a LabelReference"""
+ return LabelReference(tokens[0])
+
+def transformReference(string, location, tokens):
+ """Transforms a ParseResult into a Reference"""
+ if isinstance(tokens[0], Reference):
+ return tokens[0]
+ return None
+
+grammar.label.setParseAction(transformLabel)
+grammar.node_path.setParseAction(transformPath)
+grammar.path_reference.setParseAction(transformPathReference)
+grammar.label_reference.setParseAction(transformLabelReference)
+grammar.reference.setParseAction(transformReference)
+grammar.node_definition.setParseAction(transformNode)
+grammar.property_assignment.setParseAction(transformPropertyAssignment)
+grammar.directive.setParseAction(transformDirective)
+grammar.arith_expr.setParseAction(evaluateArithExpr)
+grammar.ternary_expr.setParseAction(transformTernary)
+grammar.stringlist.setParseAction(transformStringList)
+grammar.bytestring.setParseAction(transformBytestring)
+grammar.cell_array.setParseAction(transformCellArray)
+grammar.property_values.setParseAction(transformPropertyValues)
+grammar.label_raw.setParseAction(transformString)
+grammar.ifdef_define_values.setParseAction(transformIfdefMacro)
+grammar.ifdef_end_values.setParseAction(transformIfdefEnd)
+grammar.arith_str_expr.setParseAction(transformPropertyValues)
+
+def printTree(tree, level=0):
+ """Helper function to print a bunch of elements as a tree"""
+ def printlevel(level, s):
+ print(" " * level + s)
+
+ for item in tree:
+ if isinstance(item, Node):
+ if item.address:
+ printlevel(level, "Node %s@%x" % (item.name, item.address))
+ else:
+ printlevel(level, "Node %s" % item.name)
+
+ if item.label:
+ printlevel(level, " Label: %s" % item.label)
+
+ if item.parent:
+ printlevel(level, " Parent: %s" % item.parent)
+
+ printTree(item.properties, level=(level + 1))
+
+ printTree(item.children, level=(level + 1))
+ elif isinstance(item, Property):
+ if item.values:
+ printlevel(level, "Property %s: %s" % (item.name, item.values))
+ else:
+ printlevel(level, "Property %s" % item.name)
+ elif isinstance(item, Directive):
+ if item.options:
+ printlevel(level, "Directive %s: %s" % (item.directive, item.options))
+ else:
+ printlevel(level, "Directive %s" % item.directive)
+
+def parentNodes(tree, parent=None):
+ """Walks a tree and sets Nodes' parent field to point at their parent"""
+ for item in tree:
+ if isinstance(item, Node):
+ item.parent = parent
+ parentNodes(item.children, item)
+
+def recurseIncludeFiles(elements, pwd):
+ """Recursively follows and parses /include/ directives an a tree"""
+ for e in elements:
+ if isinstance(e, Directive):
+ if e.directive == "/include/":
+ # Prefix with current directory if path is not absolute
+ if e.option[0] != '/':
+ e.option = pwd + e.option
+
+ with open(e.option, 'r') as f:
+ contents = f.read()
+
+ elements += parseElements(contents)
+
+ del elements[elements.asList().index(e)]
+
+def parseElements(dts, pwd="", followIncludes=False):
+ """Parses a string into a list of elements"""
+ elements = grammar.devicetree.parseString(dts, parseAll=True)
+ parentNodes(elements)
+ if followIncludes:
+ recurseIncludeFiles(elements, pwd)
+ return elements
+
+def parseTree(dts, pwd="", followIncludes=False):
+ """Parses a string into a full Devicetree"""
+ return Devicetree(parseElements(dts, pwd, followIncludes))
+
+def parseNode(dts):
+ """Parses a string into a Devictreee Node"""
+ return grammar.node_definition.parseString(dts, parseAll=True)[0]
+
+def parseProperty(dts):
+ """Parses a string into a Devicetree Property"""
+ return grammar.property_assignment.parseString(dts, parseAll=True)[0]
+
+if __name__ == "__main__":
+ import sys
+ if len(sys.argv) > 1:
+ with open(sys.argv[1], 'r') as f:
+ dts = f.read()
+ tree = parseTree(dts)
+ printTree(tree)
+ print(tree)
+ else:
+ print("Please pass the devicetree source file as an argument")
+ sys.exit(1)
diff --git a/tools/cot_dt2c/pyproject.toml b/tools/cot_dt2c/pyproject.toml
new file mode 100644
index 0000000..d383924
--- /dev/null
+++ b/tools/cot_dt2c/pyproject.toml
@@ -0,0 +1,60 @@
+# Poetry pyproject.toml: https://python-poetry.org/docs/pyproject/
+[build-system]
+requires = ["poetry_core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.poetry]
+name = "cot_dt2c"
+version = "0.1.0"
+description = "CoT-dt2c Tool is a python script to convert CoT DT file into corresponding C file"
+authors = ["Arm Ltd <tf-a@lists.trustedfirmware.org>"]
+license = "BSD-3"
+repository = "https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/"
+homepage = "https://trustedfirmware-a.readthedocs.io/en/latest/index.html"
+
+# Pypi classifiers: https://pypi.org/classifiers/
+classifiers = [
+ "Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Operating System :: OS Independent",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "License :: OSI Approved :: BSD License",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+]
+
+
+[tool.poetry.dependencies]
+python = "^3.8"
+click = "^8.1.7"
+pyparsing = "^2.4.7"
+plotly = "^5.23.0"
+pandas = "^2.2.2"
+igraph = "^0.11.6"
+
+[tool.poetry.dev-dependencies]
+mypy = "^0.910"
+pytest = "^6.2.5"
+pyparsing = "^2.4.7"
+plotly = "^5.23.0"
+pandas = "^2.2.2"
+igraph = "^0.11.6"
+
+[tool.mypy]
+# https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file
+python_version = 3.8
+pretty = true
+show_traceback = true
+color_output = true
+
+[tool.coverage.run]
+source = ["tests"]
+
+[coverage.paths]
+source = "cot_dt2c"
+
+[tool.poetry.scripts]
+# Entry points for the package https://python-poetry.org/docs/pyproject/#scripts
+# "cot-dt2c" = "cot_dt2c.__main__:cli"
+"cot-dt2c" = "cot_dt2c.__main__:cli"
diff --git a/tools/cot_dt2c/requirements.txt b/tools/cot_dt2c/requirements.txt
new file mode 100644
index 0000000..246b81d
--- /dev/null
+++ b/tools/cot_dt2c/requirements.txt
@@ -0,0 +1,6 @@
+mypy
+pylint
+pyparsing
+igraph
+pandas
+plotly
diff --git a/tools/cot_dt2c/tests/test.dtsi b/tools/cot_dt2c/tests/test.dtsi
new file mode 100644
index 0000000..ee744e6
--- /dev/null
+++ b/tools/cot_dt2c/tests/test.dtsi
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a valid CoT DT file
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+#if defined(test)
+ example_cert: example_cert {
+ root-certificate;
+ image-id =<EXAMPLE_ID>;
+ antirollback-counter = <&example_ctr>;
+
+ example_hash: example_hash
+ {
+ oid = EXAMPLE_HASH_ID;
+ };
+ };
+#endif
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ example {
+ image-id = <EXAMPLE_ID>;
+ parent = <&example_cert>;
+ hash = <&example_hash>;
+ };
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ example_ctr: example_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ example_pk: example_pk {
+ oid = EXAMPLE_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test2.dtsi b/tools/cot_dt2c/tests/test2.dtsi
new file mode 100644
index 0000000..c4dbf83
--- /dev/null
+++ b/tools/cot_dt2c/tests/test2.dtsi
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a valid CoT DT file
+ *
+ */
+
+#if test
+#include <example/example.h>
+#include <example/example/example.h>
+#endif
+
+cot
+{
+ manifests
+ {
+ compatible = "arm, cert-descs";
+#if defined (test)
+ example_cert: example_cert
+ {
+ root-certificate;
+ image-id =<EXAMPLE_ID>;
+ antirollback-counter = <&example_ctr>;
+
+ example_hash: example_hash
+ {
+ oid = EXAMPLE_HASH_ID;
+ };
+
+ };
+#endif
+ };
+
+ images
+ {
+ compatible = "arm, img-descs";
+
+ example
+ {
+ image-id = <EXAMPLE_ID>;
+ parent = <&example_cert>;
+ hash = <&example_hash>;
+ };
+ };
+};
+
+non_volatile_counters: non_volatile_counters
+{
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ example_ctr: example_ctr
+ {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys
+{
+ example_pk: example_pk
+ {
+ oid = EXAMPLE_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_bracket.dtsi b/tools/cot_dt2c/tests/test_invalid_bracket.dtsi
new file mode 100644
index 0000000..ec5f9c7
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_bracket.dtsi
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there is
+ * unmatching bracket
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ example_cert: example_cert {
+ root-certificate;
+ image-id =<EXAMPLE_ID>;
+ antirollback-counter = <&example_ctr>;
+
+ example_hash: example_hash
+ {
+ oid = EXAMPLE_HASH_ID;
+ };
+
+ };
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ example {
+ image-id = <EXAMPLE_ID>;
+ parent = <&example_cert>;
+ hash = <&example_hash>;
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ example_ctr: example_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ example_pk: example_pk {
+ oid = EXAMPLE_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_ifdef.dtsi b/tools/cot_dt2c/tests/test_invalid_ifdef.dtsi
new file mode 100644
index 0000000..5bc6bb9
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_ifdef.dtsi
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there is
+ * unmatching ifdef macro
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ example_cert: example_cert {
+ root-certificate;
+ image-id =<EXAMPLE_ID>;
+ antirollback-counter = <&example_ctr>;
+
+ example_hash: example_hash
+ {
+ oid = EXAMPLE_HASH_ID;
+ };
+
+ };
+ };
+
+#if defined(test)
+ images {
+ compatible = "arm, img-descs";
+
+ example {
+ image-id = <EXAMPLE_ID>;
+ parent = <&example_cert>;
+ hash = <&example_hash>;
+ };
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ example_ctr: example_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ example_pk: example_pk {
+ oid = EXAMPLE_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_ifdef2.dtsi b/tools/cot_dt2c/tests/test_invalid_ifdef2.dtsi
new file mode 100644
index 0000000..c915168
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_ifdef2.dtsi
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there is
+ * unmatching ifdef macro
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ example_cert: example_cert {
+ root-certificate;
+ image-id =<EXAMPLE_ID>;
+ antirollback-counter = <&example_ctr>;
+
+ example_hash: example_hash
+ {
+ oid = EXAMPLE_HASH_ID;
+ };
+
+ };
+ };
+
+#if defined(test)
+ images {
+ compatible = "arm, img-descs";
+
+ example {
+ image-id = <EXAMPLE_ID>;
+ parent = <&example_cert>;
+ hash = <&example_hash>;
+ };
+ };
+#endif
+#endif
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ example_ctr: example_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ example_pk: example_pk {
+ oid = EXAMPLE_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_attribute.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_attribute.dtsi
new file mode 100644
index 0000000..9c0a5f2
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_attribute.dtsi
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that missing mandantory attributes
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ cca_content_cert: cca_content_cert {
+ root-certificate;
+ antirollback-counter = <&cca_nv_ctr>;
+
+ tb_fw_hash: tb_fw_hash {
+ oid = TRUSTED_BOOT_FW_HASH_OID;
+ };
+ tb_fw_config_hash: tb_fw_config_hash {
+ oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+ };
+ hw_config_hash: hw_config_hash {
+ };
+ fw_config_hash: fw_config_hash {
+ oid = FW_CONFIG_HASH_OID;
+ };
+ soc_fw_hash: soc_fw_hash {
+ oid = SOC_AP_FW_HASH_OID;
+ };
+ soc_fw_config_hash: soc_fw_config_hash {
+ oid = SOC_FW_CONFIG_HASH_OID;
+ };
+ rmm_hash: rmm_hash {
+ oid = RMM_HASH_OID;
+ };
+ };
+
+ core_swd_key_cert: core_swd_key_cert {
+ root-certificate;
+ image-id = <CORE_SWD_KEY_CERT_ID>;
+ signing-key = <&swd_rot_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ core_swd_pk: core_swd_pk {
+ oid = CORE_SWD_PK_OID;
+ };
+ };
+
+ trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+ image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+ parent = <&core_swd_key_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ tos_fw_hash: tos_fw_hash {
+ oid = TRUSTED_OS_FW_HASH_OID;
+ };
+ tos_fw_config_hash: tos_fw_config_hash {
+ oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ plat_key_cert: plat_key_cert {
+ root-certificate;
+ image-id = <PLAT_KEY_CERT_ID>;
+ signing-key = <&prot_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ plat_pk: plat_pk {
+ oid = PLAT_PK_OID;
+ };
+ };
+
+ non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+ image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+ parent = <&plat_key_cert>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ nt_world_bl_hash: nt_world_bl_hash {
+ oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+ };
+ nt_fw_config_hash: nt_fw_config_hash {
+ oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+ };
+ };
+
+#if defined(SPD_spmd)
+ sip_sp_content_cert: sip_sp_content_cert {
+ image-id = <SIP_SP_CONTENT_CERT_ID>;
+ parent = <&core_swd_key_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ sp_pkg1_hash: sp_pkg1_hash {
+ oid = SP_PKG1_HASH_OID;
+ };
+ sp_pkg2_hash: sp_pkg2_hash {
+ oid = SP_PKG2_HASH_OID;
+ };
+ sp_pkg3_hash: sp_pkg3_hash {
+ oid = SP_PKG3_HASH_OID;
+ };
+ sp_pkg4_hash: sp_pkg4_hash {
+ oid = SP_PKG4_HASH_OID;
+ };
+ };
+
+ plat_sp_content_cert: plat_sp_content_cert {
+ parent = <&plat_key_cert>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ sp_pkg5_hash: sp_pkg5_hash {
+ oid = SP_PKG5_HASH_OID;
+ };
+ sp_pkg6_hash: sp_pkg6_hash {
+ oid = SP_PKG6_HASH_OID;
+ };
+ sp_pkg7_hash: sp_pkg7_hash {
+ oid = SP_PKG7_HASH_OID;
+ };
+ sp_pkg8_hash: sp_pkg8_hash {
+ oid = SP_PKG8_HASH_OID;
+ };
+ };
+#endif
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ hw_config {
+ image-id = <HW_CONFIG_ID>;
+ hash = <&hw_config_hash>;
+ };
+
+ bl31_image {
+ image-id = <BL31_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_hash>;
+ };
+
+ soc_fw_config {
+ image-id = <SOC_FW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_config_hash>;
+ };
+
+ rmm_image {
+ image-id = <RMM_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&rmm_hash>;
+ };
+
+ bl32_image {
+ image-id = <BL32_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_hash>;
+ };
+
+ tos_fw_config {
+ image-id = <TOS_FW_CONFIG_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_config_hash>;
+ };
+
+ bl33_image {
+ image-id = <BL33_IMAGE_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_world_bl_hash>;
+ };
+
+ nt_fw_config {
+ image-id = <NT_FW_CONFIG_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_fw_config_hash>;
+ };
+
+#if defined(SPD_spmd)
+ sp_pkg1 {
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg1_hash>;
+ };
+
+ sp_pkg2 {
+ image-id = <SP_PKG2_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg2_hash>;
+ };
+
+ sp_pkg3 {
+ image-id = <SP_PKG3_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg3_hash>;
+ };
+
+ sp_pkg4 {
+ image-id = <SP_PKG4_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg4_hash>;
+ };
+
+ sp_pkg5 {
+ image-id = <SP_PKG5_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg5_hash>;
+ };
+
+ sp_pkg6 {
+ image-id = <SP_PKG6_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg6_hash>;
+ };
+
+ sp_pkg7 {
+ image-id = <SP_PKG7_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg7_hash>;
+ };
+
+ sp_pkg8 {
+ image-id = <SP_PKG8_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg8_hash>;
+ };
+#endif
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cca_nv_ctr: cca_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+
+ trusted_nv_ctr: trusted_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ swd_rot_pk: swd_rot_pk {
+ oid = SWD_ROT_PK_OID;
+ };
+ prot_pk: prot_pk {
+ oid = PROT_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_attribute2.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_attribute2.dtsi
new file mode 100644
index 0000000..01b2597
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_attribute2.dtsi
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that points to invalid parent
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ cca_content_cert: cca_content_cert {
+ root-certificate;
+ image-id =<CCA_CONTENT_CERT_ID>;
+ antirollback-counter = <&cca_nv_ctr>;
+
+ tb_fw_hash: tb_fw_hash {
+ oid = TRUSTED_BOOT_FW_HASH_OID;
+ };
+ tb_fw_config_hash: tb_fw_config_hash {
+ oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+ };
+ hw_config_hash: hw_config_hash {
+ oid = HW_CONFIG_HASH_OID;
+ };
+ fw_config_hash: fw_config_hash {
+ oid = FW_CONFIG_HASH_OID;
+ };
+ soc_fw_hash: soc_fw_hash {
+ oid = SOC_AP_FW_HASH_OID;
+ };
+ soc_fw_config_hash: soc_fw_config_hash {
+ oid = SOC_FW_CONFIG_HASH_OID;
+ };
+ rmm_hash: rmm_hash {
+ oid = RMM_HASH_OID;
+ };
+ };
+
+ core_swd_key_cert: core_swd_key_cert {
+ root-certificate;
+ image-id = <CORE_SWD_KEY_CERT_ID>;
+ signing-key = <&swd_rot_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ core_swd_pk: core_swd_pk {
+ oid = CORE_SWD_PK_OID;
+ };
+ };
+
+ trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+ image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+ parent = <&core_swd_key_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ tos_fw_hash: tos_fw_hash {
+ oid = TRUSTED_OS_FW_HASH_OID;
+ };
+ tos_fw_config_hash: tos_fw_config_hash {
+ oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ plat_key_cert: plat_key_cert {
+ root-certificate;
+ image-id = <PLAT_KEY_CERT_ID>;
+ signing-key = <&prot_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ plat_pk: plat_pk {
+ oid = PLAT_PK_OID;
+ };
+ };
+
+ non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+ image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+ parent = <&cca_content_cert>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ nt_world_bl_hash: nt_world_bl_hash {
+ oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+ };
+ nt_fw_config_hash: nt_fw_config_hash {
+ oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+ };
+ };
+
+#if defined(SPD_spmd)
+ sip_sp_content_cert: sip_sp_content_cert {
+ image-id = <SIP_SP_CONTENT_CERT_ID>;
+ parent = <&cca_content_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ sp_pkg1_hash: sp_pkg1_hash {
+ oid = SP_PKG1_HASH_OID;
+ };
+ sp_pkg2_hash: sp_pkg2_hash {
+ oid = SP_PKG2_HASH_OID;
+ };
+ sp_pkg3_hash: sp_pkg3_hash {
+ oid = SP_PKG3_HASH_OID;
+ };
+ sp_pkg4_hash: sp_pkg4_hash {
+ oid = SP_PKG4_HASH_OID;
+ };
+ };
+
+ plat_sp_content_cert: plat_sp_content_cert {
+ image-id = <PLAT_SP_CONTENT_CERT_ID>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ sp_pkg5_hash: sp_pkg5_hash {
+ oid = SP_PKG5_HASH_OID;
+ };
+ sp_pkg6_hash: sp_pkg6_hash {
+ oid = SP_PKG6_HASH_OID;
+ };
+ sp_pkg7_hash: sp_pkg7_hash {
+ oid = SP_PKG7_HASH_OID;
+ };
+ sp_pkg8_hash: sp_pkg8_hash {
+ oid = SP_PKG8_HASH_OID;
+ };
+ };
+#endif
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ hw_config {
+ image-id = <HW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&hw_config_hash>;
+ };
+
+ bl31_image {
+ image-id = <BL31_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_hash>;
+ };
+
+ soc_fw_config {
+ image-id = <SOC_FW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_config_hash>;
+ };
+
+ rmm_image {
+ image-id = <RMM_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&rmm_hash>;
+ };
+
+ bl32_image {
+ image-id = <BL32_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_hash>;
+ };
+
+ tos_fw_config {
+ image-id = <TOS_FW_CONFIG_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_config_hash>;
+ };
+
+ bl33_image {
+ image-id = <BL33_IMAGE_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_world_bl_hash>;
+ };
+
+ nt_fw_config {
+ image-id = <NT_FW_CONFIG_ID>;
+ hash = <&nt_fw_config_hash>;
+ };
+
+#if defined(SPD_spmd)
+ sp_pkg1 {
+ image-id = <SP_PKG1_ID>;
+ hash = <&sp_pkg1_hash>;
+ };
+
+ sp_pkg2 {
+ image-id = <SP_PKG2_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg2_hash>;
+ };
+
+ sp_pkg3 {
+ image-id = <SP_PKG3_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg3_hash>;
+ };
+
+ sp_pkg4 {
+ image-id = <SP_PKG4_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg4_hash>;
+ };
+
+ sp_pkg5 {
+ image-id = <SP_PKG5_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg5_hash>;
+ };
+
+ sp_pkg6 {
+ image-id = <SP_PKG6_ID>;
+ parent = <&wrong_parent>;
+ hash = <&sp_pkg6_hash>;
+ };
+
+ sp_pkg7 {
+ image-id = <SP_PKG7_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg7_hash>;
+ };
+
+ sp_pkg8 {
+ image-id = <SP_PKG8_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg8_hash>;
+ };
+#endif
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cca_nv_ctr: cca_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+
+ trusted_nv_ctr: trusted_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ swd_rot_pk: swd_rot_pk {
+ oid = SWD_ROT_PK_OID;
+ };
+ prot_pk: prot_pk {
+ oid = PROT_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_ctr.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_ctr.dtsi
new file mode 100644
index 0000000..5958f5d
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_ctr.dtsi
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that missing definition of
+ * nv counters
+ *
+ */
+
+#include <example/example.h>
+#include <example/example/example.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ example_cert: example_cert {
+ root-certificate;
+ image-id =<EXAMPLE_ID>;
+ signing-key = <&swd_rot_pk>;
+ antirollback-counter = <&example_ctr>;
+
+ example_hash: example_hash
+ {
+ oid = EXAMPLE_HASH_ID;
+ };
+
+ };
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ example {
+ image-id = <EXAMPLE_ID>;
+ parent = <&example_cert>;
+ hash = <&example_hash>;
+ };
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+};
+
+rot_keys {
+ example_pk: example_pk {
+ oid = EXAMPLE_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_missing_root.dtsi b/tools/cot_dt2c/tests/test_invalid_missing_root.dtsi
new file mode 100644
index 0000000..465a4c6
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_missing_root.dtsi
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that missing root certificate
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ core_swd_key_cert: core_swd_key_cert {
+ image-id = <CORE_SWD_KEY_CERT_ID>;
+ signing-key = <&swd_rot_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ core_swd_pk: core_swd_pk {
+ oid = CORE_SWD_PK_OID;
+ };
+ };
+
+ trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+ image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+ parent = <&core_swd_key_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ tos_fw_hash: tos_fw_hash {
+ oid = TRUSTED_OS_FW_HASH_OID;
+ };
+ tos_fw_config_hash: tos_fw_config_hash {
+ oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ plat_key_cert: plat_key_cert {
+ image-id = <PLAT_KEY_CERT_ID>;
+ signing-key = <&prot_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ plat_pk: plat_pk {
+ oid = PLAT_PK_OID;
+ };
+ };
+
+ non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+ image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+ parent = <&plat_key_cert>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ nt_world_bl_hash: nt_world_bl_hash {
+ oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+ };
+ nt_fw_config_hash: nt_fw_config_hash {
+ oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+ };
+ };
+
+#if defined(SPD_spmd)
+ sip_sp_content_cert: sip_sp_content_cert {
+ image-id = <SIP_SP_CONTENT_CERT_ID>;
+ parent = <&core_swd_key_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ sp_pkg1_hash: sp_pkg1_hash {
+ oid = SP_PKG1_HASH_OID;
+ };
+ sp_pkg2_hash: sp_pkg2_hash {
+ oid = SP_PKG2_HASH_OID;
+ };
+ sp_pkg3_hash: sp_pkg3_hash {
+ oid = SP_PKG3_HASH_OID;
+ };
+ sp_pkg4_hash: sp_pkg4_hash {
+ oid = SP_PKG4_HASH_OID;
+ };
+ };
+
+ plat_sp_content_cert: plat_sp_content_cert {
+ image-id = <PLAT_SP_CONTENT_CERT_ID>;
+ parent = <&plat_key_cert>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ sp_pkg5_hash: sp_pkg5_hash {
+ oid = SP_PKG5_HASH_OID;
+ };
+ sp_pkg6_hash: sp_pkg6_hash {
+ oid = SP_PKG6_HASH_OID;
+ };
+ sp_pkg7_hash: sp_pkg7_hash {
+ oid = SP_PKG7_HASH_OID;
+ };
+ sp_pkg8_hash: sp_pkg8_hash {
+ oid = SP_PKG8_HASH_OID;
+ };
+ };
+#endif
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ hw_config {
+ image-id = <HW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&hw_config_hash>;
+ };
+
+ bl31_image {
+ image-id = <BL31_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_hash>;
+ };
+
+ soc_fw_config {
+ image-id = <SOC_FW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_config_hash>;
+ };
+
+ rmm_image {
+ image-id = <RMM_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&rmm_hash>;
+ };
+
+ bl32_image {
+ image-id = <BL32_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_hash>;
+ };
+
+ tos_fw_config {
+ image-id = <TOS_FW_CONFIG_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_config_hash>;
+ };
+
+ bl33_image {
+ image-id = <BL33_IMAGE_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_world_bl_hash>;
+ };
+
+ nt_fw_config {
+ image-id = <NT_FW_CONFIG_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_fw_config_hash>;
+ };
+
+#if defined(SPD_spmd)
+ sp_pkg1 {
+ image-id = <SP_PKG1_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg1_hash>;
+ };
+
+ sp_pkg2 {
+ image-id = <SP_PKG2_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg2_hash>;
+ };
+
+ sp_pkg3 {
+ image-id = <SP_PKG3_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg3_hash>;
+ };
+
+ sp_pkg4 {
+ image-id = <SP_PKG4_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg4_hash>;
+ };
+
+ sp_pkg5 {
+ image-id = <SP_PKG5_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg5_hash>;
+ };
+
+ sp_pkg6 {
+ image-id = <SP_PKG6_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg6_hash>;
+ };
+
+ sp_pkg7 {
+ image-id = <SP_PKG7_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg7_hash>;
+ };
+
+ sp_pkg8 {
+ image-id = <SP_PKG8_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg8_hash>;
+ };
+#endif
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cca_nv_ctr: cca_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+
+ trusted_nv_ctr: trusted_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ swd_rot_pk: swd_rot_pk {
+ oid = SWD_ROT_PK_OID;
+ };
+ prot_pk: prot_pk {
+ oid = PROT_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_invalid_undefined_parent.dtsi b/tools/cot_dt2c/tests/test_invalid_undefined_parent.dtsi
new file mode 100644
index 0000000..b761beb
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_invalid_undefined_parent.dtsi
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This file provide a malformed CoT DT file that there
+ * are image/certificate that points to invalid parent
+ *
+ */
+
+#include <tools_share/cca_oid.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <common/nv_cntr_ids.h>
+
+cot {
+ manifests {
+ compatible = "arm, cert-descs";
+
+ cca_content_cert: cca_content_cert {
+ root-certificate;
+ image-id =<CCA_CONTENT_CERT_ID>;
+ antirollback-counter = <&cca_nv_ctr>;
+
+ tb_fw_hash: tb_fw_hash {
+ oid = TRUSTED_BOOT_FW_HASH_OID;
+ };
+ tb_fw_config_hash: tb_fw_config_hash {
+ oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID;
+ };
+ hw_config_hash: hw_config_hash {
+ oid = HW_CONFIG_HASH_OID;
+ };
+ fw_config_hash: fw_config_hash {
+ oid = FW_CONFIG_HASH_OID;
+ };
+ soc_fw_hash: soc_fw_hash {
+ oid = SOC_AP_FW_HASH_OID;
+ };
+ soc_fw_config_hash: soc_fw_config_hash {
+ oid = SOC_FW_CONFIG_HASH_OID;
+ };
+ rmm_hash: rmm_hash {
+ oid = RMM_HASH_OID;
+ };
+ };
+
+ core_swd_key_cert: core_swd_key_cert {
+ root-certificate;
+ image-id = <CORE_SWD_KEY_CERT_ID>;
+ signing-key = <&swd_rot_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ core_swd_pk: core_swd_pk {
+ oid = CORE_SWD_PK_OID;
+ };
+ };
+
+ trusted_os_fw_content_cert: trusted_os_fw_content_cert {
+ image-id = <TRUSTED_OS_FW_CONTENT_CERT_ID>;
+ parent = <&core_swd_key_cert>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ tos_fw_hash: tos_fw_hash {
+ oid = TRUSTED_OS_FW_HASH_OID;
+ };
+ tos_fw_config_hash: tos_fw_config_hash {
+ oid = TRUSTED_OS_FW_CONFIG_HASH_OID;
+ };
+ };
+
+ plat_key_cert: plat_key_cert {
+ root-certificate;
+ image-id = <PLAT_KEY_CERT_ID>;
+ signing-key = <&prot_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ plat_pk: plat_pk {
+ oid = PLAT_PK_OID;
+ };
+ };
+
+ non_trusted_fw_content_cert: non_trusted_fw_content_cert {
+ image-id = <NON_TRUSTED_FW_CONTENT_CERT_ID>;
+ parent = <&wrong_parent>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ nt_world_bl_hash: nt_world_bl_hash {
+ oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID;
+ };
+ nt_fw_config_hash: nt_fw_config_hash {
+ oid = NON_TRUSTED_FW_CONFIG_HASH_OID;
+ };
+ };
+
+#if defined(SPD_spmd)
+ sip_sp_content_cert: sip_sp_content_cert {
+ image-id = <SIP_SP_CONTENT_CERT_ID>;
+ parent = <&wrong_parent>;
+ signing-key = <&core_swd_pk>;
+ antirollback-counter = <&trusted_nv_ctr>;
+
+ sp_pkg1_hash: sp_pkg1_hash {
+ oid = SP_PKG1_HASH_OID;
+ };
+ sp_pkg2_hash: sp_pkg2_hash {
+ oid = SP_PKG2_HASH_OID;
+ };
+ sp_pkg3_hash: sp_pkg3_hash {
+ oid = SP_PKG3_HASH_OID;
+ };
+ sp_pkg4_hash: sp_pkg4_hash {
+ oid = SP_PKG4_HASH_OID;
+ };
+ };
+
+ plat_sp_content_cert: plat_sp_content_cert {
+ image-id = <PLAT_SP_CONTENT_CERT_ID>;
+ signing-key = <&plat_pk>;
+ antirollback-counter = <&non_trusted_nv_ctr>;
+
+ sp_pkg5_hash: sp_pkg5_hash {
+ oid = SP_PKG5_HASH_OID;
+ };
+ sp_pkg6_hash: sp_pkg6_hash {
+ oid = SP_PKG6_HASH_OID;
+ };
+ sp_pkg7_hash: sp_pkg7_hash {
+ oid = SP_PKG7_HASH_OID;
+ };
+ sp_pkg8_hash: sp_pkg8_hash {
+ oid = SP_PKG8_HASH_OID;
+ };
+ };
+#endif
+ };
+
+ images {
+ compatible = "arm, img-descs";
+
+ hw_config {
+ image-id = <HW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&hw_config_hash>;
+ };
+
+ bl31_image {
+ image-id = <BL31_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_hash>;
+ };
+
+ soc_fw_config {
+ image-id = <SOC_FW_CONFIG_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&soc_fw_config_hash>;
+ };
+
+ rmm_image {
+ image-id = <RMM_IMAGE_ID>;
+ parent = <&cca_content_cert>;
+ hash = <&rmm_hash>;
+ };
+
+ bl32_image {
+ image-id = <BL32_IMAGE_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_hash>;
+ };
+
+ tos_fw_config {
+ image-id = <TOS_FW_CONFIG_ID>;
+ parent = <&trusted_os_fw_content_cert>;
+ hash = <&tos_fw_config_hash>;
+ };
+
+ bl33_image {
+ image-id = <BL33_IMAGE_ID>;
+ parent = <&non_trusted_fw_content_cert>;
+ hash = <&nt_world_bl_hash>;
+ };
+
+ nt_fw_config {
+ image-id = <NT_FW_CONFIG_ID>;
+ hash = <&nt_fw_config_hash>;
+ };
+
+#if defined(SPD_spmd)
+ sp_pkg1 {
+ image-id = <SP_PKG1_ID>;
+ hash = <&sp_pkg1_hash>;
+ };
+
+ sp_pkg2 {
+ image-id = <SP_PKG2_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg2_hash>;
+ };
+
+ sp_pkg3 {
+ image-id = <SP_PKG3_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg3_hash>;
+ };
+
+ sp_pkg4 {
+ image-id = <SP_PKG4_ID>;
+ parent = <&sip_sp_content_cert>;
+ hash = <&sp_pkg4_hash>;
+ };
+
+ sp_pkg5 {
+ image-id = <SP_PKG5_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg5_hash>;
+ };
+
+ sp_pkg6 {
+ image-id = <SP_PKG6_ID>;
+ parent = <&wrong_parent>;
+ hash = <&sp_pkg6_hash>;
+ };
+
+ sp_pkg7 {
+ image-id = <SP_PKG7_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg7_hash>;
+ };
+
+ sp_pkg8 {
+ image-id = <SP_PKG8_ID>;
+ parent = <&plat_sp_content_cert>;
+ hash = <&sp_pkg8_hash>;
+ };
+#endif
+ };
+};
+
+non_volatile_counters: non_volatile_counters {
+ compatible = "arm, non-volatile-counter";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cca_nv_ctr: cca_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = CCA_FW_NVCOUNTER_OID;
+ };
+
+ trusted_nv_ctr: trusted_nv_ctr {
+ id = <TRUSTED_NV_CTR_ID>;
+ oid = TRUSTED_FW_NVCOUNTER_OID;
+ };
+
+ non_trusted_nv_ctr: non_trusted_nv_ctr {
+ id = <NON_TRUSTED_NV_CTR_ID>;
+ oid = NON_TRUSTED_FW_NVCOUNTER_OID;
+ };
+};
+
+rot_keys {
+ swd_rot_pk: swd_rot_pk {
+ oid = SWD_ROT_PK_OID;
+ };
+ prot_pk: prot_pk {
+ oid = PROT_PK_OID;
+ };
+};
diff --git a/tools/cot_dt2c/tests/test_util.py b/tools/cot_dt2c/tests/test_util.py
new file mode 100644
index 0000000..b8e44d4
--- /dev/null
+++ b/tools/cot_dt2c/tests/test_util.py
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+import os
+import sys
+
+from cot_dt2c.cli import *
+from click.testing import CliRunner
+
+def get_script_path():
+ return os.path.dirname(os.path.realpath(sys.argv[0]))
+
+def test_convert():
+ runner = CliRunner()
+ test_file = get_script_path() + "/test.dtsi"
+ test_output = get_script_path() + "/test.c"
+
+ result = runner.invoke(convert_to_c, [test_file, test_output])
+ try:
+ assert result.output == ""
+ except:
+ print("test convert fail")
+
+ try:
+ os.remove(test_output)
+ except OSError:
+ pass
+
+if __name__=="__main__":
+ test_convert()