Merge "docs(psci): expound runtime instrumentation docs" into integration
diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h
index 0aa6579..42d4149 100644
--- a/include/lib/coreboot.h
+++ b/include/lib/coreboot.h
@@ -41,5 +41,6 @@
 
 coreboot_memory_t coreboot_get_memory_type(uintptr_t start, size_t size);
 void coreboot_table_setup(void *base);
+void coreboot_get_table_location(uint64_t *address, uint32_t *size);
 
 #endif /* COREBOOT_H */
diff --git a/lib/compiler-rt/builtins/assembly.h b/lib/compiler-rt/builtins/assembly.h
index 69a3d86..169d496 100644
--- a/lib/compiler-rt/builtins/assembly.h
+++ b/lib/compiler-rt/builtins/assembly.h
@@ -267,7 +267,7 @@
 #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target)                         \
   .globl SYMBOL_NAME(name) SEPARATOR                                           \
   SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR                                  \
-  DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR                       \
+  DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR                                    \
   .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
 
 #if defined(__ARM_EABI__)
diff --git a/lib/compiler-rt/builtins/int_types.h b/lib/compiler-rt/builtins/int_types.h
index 7a72de4..e94d315 100644
--- a/lib/compiler-rt/builtins/int_types.h
+++ b/lib/compiler-rt/builtins/int_types.h
@@ -64,7 +64,7 @@
 } udwords;
 
 #if defined(__LP64__) || defined(__wasm__) || defined(__mips64) ||             \
-    defined(__riscv) || defined(_WIN64)
+    defined(__SIZEOF_INT128__) || defined(_WIN64)
 #define CRT_HAS_128BIT
 #endif
 
diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c
index fb31ef1..43e9835 100644
--- a/lib/coreboot/coreboot_table.c
+++ b/lib/coreboot/coreboot_table.c
@@ -46,6 +46,8 @@
 
 coreboot_memrange_t coreboot_memranges[COREBOOT_MAX_MEMRANGES];
 coreboot_serial_t coreboot_serial;
+uint64_t coreboot_table_addr;
+uint32_t coreboot_table_size;
 
 /*
  * The coreboot table is parsed before the MMU is enabled (i.e. with strongly
@@ -108,6 +110,12 @@
 	return CB_MEM_NONE;
 }
 
+void coreboot_get_table_location(uint64_t *address, uint32_t *size)
+{
+	*address = coreboot_table_addr;
+	*size = coreboot_table_size;
+}
+
 void coreboot_table_setup(void *base)
 {
 	cb_header_t *header = base;
@@ -118,6 +126,8 @@
 		ERROR("coreboot table signature corrupt!\n");
 		return;
 	}
+	coreboot_table_addr = (uint64_t) base;
+	coreboot_table_size = header->header_bytes + header->table_bytes;
 
 	ptr = base + header->header_bytes;
 	for (i = 0; i < header->table_entries; i++) {
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
index e52cbed..faccfdf 100644
--- a/lib/libc/printf.c
+++ b/lib/libc/printf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -81,6 +81,7 @@
  * %x - hexadecimal format
  * %s - string format
  * %d or %i - signed decimal format
+ * %c - character format
  * %u - unsigned decimal format
  * %p - pointer format
  *
@@ -130,6 +131,10 @@
 				count += unsigned_num_print(unum, 10,
 							    padc, padn);
 				break;
+			case 'c':
+				(void)putchar(va_arg(args, int));
+				count++;
+				break;
 			case 's':
 				str = va_arg(args, char *);
 				count += string_print(str);
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c
index 0e3256c..21d3416 100644
--- a/lib/libc/snprintf.c
+++ b/lib/libc/snprintf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -85,6 +85,7 @@
  *
  * %x (or %X) - hexadecimal format
  * %d or %i - signed decimal format
+ * %c - character format
  * %s - string format
  * %u - unsigned decimal format
  * %p - pointer format
@@ -181,6 +182,9 @@
 				unsigned_num_print(&s, n, &chars_printed,
 						   unum, 10, padc, padn, false);
 				break;
+			case 'c':
+				CHECK_AND_PUT_CHAR(s, n, chars_printed, va_arg(args, int));
+				break;
 			case 's':
 				str = va_arg(args, char *);
 				string_print(&s, n, &chars_printed, str);
diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c
index 9fe7cf4..20c6415 100644
--- a/lib/libfdt/fdt.c
+++ b/lib/libfdt/fdt.c
@@ -106,7 +106,6 @@
 	}
 	hdrsize = fdt_header_size(fdt);
 	if (!can_assume(VALID_DTB)) {
-
 		if ((fdt_totalsize(fdt) < hdrsize)
 		    || (fdt_totalsize(fdt) > INT_MAX))
 			return -FDT_ERR_TRUNCATED;
@@ -115,9 +114,7 @@
 		if (!check_off_(hdrsize, fdt_totalsize(fdt),
 				fdt_off_mem_rsvmap(fdt)))
 			return -FDT_ERR_TRUNCATED;
-	}
 
-	if (!can_assume(VALID_DTB)) {
 		/* Bounds check structure block */
 		if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
 			if (!check_off_(hdrsize, fdt_totalsize(fdt),
@@ -165,7 +162,7 @@
 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 {
 	const fdt32_t *tagp, *lenp;
-	uint32_t tag;
+	uint32_t tag, len, sum;
 	int offset = startoffset;
 	const char *p;
 
@@ -191,12 +188,19 @@
 		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
 		if (!can_assume(VALID_DTB) && !lenp)
 			return FDT_END; /* premature end */
+
+		len = fdt32_to_cpu(*lenp);
+		sum = len + offset;
+		if (!can_assume(VALID_DTB) &&
+		    (INT_MAX <= sum || sum < (uint32_t) offset))
+			return FDT_END; /* premature end */
+
 		/* skip-name offset, length and value */
-		offset += sizeof(struct fdt_property) - FDT_TAGSIZE
-			+ fdt32_to_cpu(*lenp);
+		offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len;
+
 		if (!can_assume(LATEST) &&
-		    fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
-		    ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+		    fdt_version(fdt) < 0x10 && len >= 8 &&
+		    ((offset - len) % 8) != 0)
 			offset += 4;
 		break;
 
diff --git a/plat/arm/board/morello/morello_bl31_setup.c b/plat/arm/board/morello/morello_bl31_setup.c
index cef42f4..e13a38b 100644
--- a/plat/arm/board/morello/morello_bl31_setup.c
+++ b/plat/arm/board/morello/morello_bl31_setup.c
@@ -12,6 +12,7 @@
 #include <services/arm_arch_svc.h>
 
 #include "morello_def.h"
+#include "morello_private.h"
 #include <platform_def.h>
 
 #ifdef TARGET_PLATFORM_SOC
@@ -33,6 +34,8 @@
 
 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
 {
+	ops->pwr_domain_off = morello_pwr_domain_off;
+	ops->pwr_domain_suspend = morello_pwr_domain_suspend;
 	return css_scmi_override_pm_ops(ops);
 }
 
diff --git a/plat/arm/board/morello/morello_pm.c b/plat/arm/board/morello/morello_pm.c
new file mode 100644
index 0000000..dda006e
--- /dev/null
+++ b/plat/arm/board/morello/morello_pm.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+#include "morello_private.h"
+
+/*******************************************************************************
+ * Morello specific functions called when turning off or suspending a power
+ * domain. Both additionally disable the GIC redistributor interface as cores
+ * are disabled to let cluster-PPU state transition to completion when a
+ * cluster is powered down.
+ ******************************************************************************/
+void morello_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	css_pwr_domain_off(target_state);
+	plat_arm_gic_redistif_off();
+}
+
+void morello_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	css_pwr_domain_suspend(target_state);
+	plat_arm_gic_redistif_off();
+}
diff --git a/plat/arm/board/morello/morello_private.h b/plat/arm/board/morello/morello_private.h
new file mode 100644
index 0000000..ea2fce9
--- /dev/null
+++ b/plat/arm/board/morello/morello_private.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MORELLO_PRIVATE_H
+#define MORELLO_PRIVATE_H
+
+#include <lib/psci/psci.h>
+
+void morello_pwr_domain_off(const psci_power_state_t *target_state);
+void morello_pwr_domain_suspend(const psci_power_state_t *target_state);
+
+#endif /* MORELLO_PRIVATE_H */
diff --git a/plat/arm/board/morello/platform.mk b/plat/arm/board/morello/platform.mk
index 0f0cabb..0ae7693 100644
--- a/plat/arm/board/morello/platform.mk
+++ b/plat/arm/board/morello/platform.mk
@@ -49,6 +49,7 @@
 				${INTERCONNECT_SOURCES}			\
 				${MORELLO_GIC_SOURCES}			\
 				${MORELLO_BASE}/morello_bl31_setup.c	\
+				${MORELLO_BASE}/morello_pm.c		\
 				${MORELLO_BASE}/morello_topology.c	\
 				${MORELLO_BASE}/morello_security.c	\
 				drivers/arm/css/sds/sds.c
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
index bd05660..db7215f 100644
--- a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,6 +14,7 @@
 #include <plat/arm/common/plat_arm.h>
 
 #include "n1sdp_def.h"
+#include "n1sdp_private.h"
 #include <platform_def.h>
 
 /*
@@ -69,6 +70,8 @@
 
 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
 {
+	ops->pwr_domain_off = n1sdp_pwr_domain_off;
+	ops->pwr_domain_suspend = n1sdp_pwr_domain_suspend;
 	return css_scmi_override_pm_ops(ops);
 }
 
diff --git a/plat/arm/board/n1sdp/n1sdp_pm.c b/plat/arm/board/n1sdp/n1sdp_pm.c
new file mode 100644
index 0000000..e43832a
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_pm.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+#include "n1sdp_private.h"
+
+/*******************************************************************************
+ * N1SDP specific functions called when turning off or suspending a power
+ * domain. Both additionally disable the GIC redistributor interface as cores
+ * are disabled to let cluster-PPU state transition to completion when a
+ * cluster is powered down.
+ ******************************************************************************/
+void n1sdp_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	css_pwr_domain_off(target_state);
+	plat_arm_gic_redistif_off();
+}
+
+void n1sdp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	css_pwr_domain_suspend(target_state);
+	plat_arm_gic_redistif_off();
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_private.h b/plat/arm/board/n1sdp/n1sdp_private.h
new file mode 100644
index 0000000..7a5c51d
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_private.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef N1SDP_PRIVATE_H
+#define N1SDP_PRIVATE_H
+
+#include <lib/psci/psci.h>
+
+void n1sdp_pwr_domain_off(const psci_power_state_t *target_state);
+void n1sdp_pwr_domain_suspend(const psci_power_state_t *target_state);
+
+#endif /* N1SDP_PRIVATE_H */
diff --git a/plat/arm/board/n1sdp/platform.mk b/plat/arm/board/n1sdp/platform.mk
index 9c0cc02..bd62614 100644
--- a/plat/arm/board/n1sdp/platform.mk
+++ b/plat/arm/board/n1sdp/platform.mk
@@ -47,6 +47,7 @@
 				${INTERCONNECT_SOURCES}			\
 				${N1SDP_GIC_SOURCES}			\
 				${N1SDP_BASE}/n1sdp_bl31_setup.c	\
+				${N1SDP_BASE}/n1sdp_pm.c		\
 				${N1SDP_BASE}/n1sdp_topology.c	        \
 				${N1SDP_BASE}/n1sdp_security.c		\
 				drivers/arm/css/sds/sds.c
diff --git a/services/spd/opteed/opteed.mk b/services/spd/opteed/opteed.mk
index 477b45d..f394744 100644
--- a/services/spd/opteed/opteed.mk
+++ b/services/spd/opteed/opteed.mk
@@ -31,4 +31,5 @@
 	platform")
 $(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
 $(eval $(call add_define,OPTEE_ALLOW_SMC_LOAD))
+include lib/libfdt/libfdt.mk
 endif
diff --git a/services/spd/opteed/opteed_main.c b/services/spd/opteed/opteed_main.c
index f069775..4d055db 100644
--- a/services/spd/opteed/opteed_main.c
+++ b/services/spd/opteed/opteed_main.c
@@ -24,9 +24,13 @@
 #include <common/bl_common.h>
 #include <common/debug.h>
 #include <common/runtime_svc.h>
+#include <lib/coreboot.h>
 #include <lib/el3_runtime/context_mgmt.h>
 #include <lib/optee_utils.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
+#if OPTEE_ALLOW_SMC_LOAD
+#include <libfdt.h>
+#endif  /* OPTEE_ALLOW_SMC_LOAD */
 #include <plat/common/platform.h>
 #include <tools_share/uuid.h>
 
@@ -51,6 +55,10 @@
 DEFINE_SVC_UUID2(optee_image_load_uuid,
 	0xb1eafba3, 0x5d31, 0x4612, 0xb9, 0x06,
 	0xc4, 0xc7, 0xa4, 0xbe, 0x3c, 0xc0);
+
+#define OPTEED_FDT_SIZE 256
+static uint8_t fdt_buf[OPTEED_FDT_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
+
 #else
 static int32_t opteed_init(void);
 #endif
@@ -209,6 +217,91 @@
 #endif  /* !OPTEE_ALLOW_SMC_LOAD */
 
 #if OPTEE_ALLOW_SMC_LOAD
+#if COREBOOT
+/*
+ * Adds a firmware/coreboot node with the coreboot table information to a device
+ * tree. Returns zero on success or if there is no coreboot table information;
+ * failure code otherwise.
+ */
+static int add_coreboot_node(void *fdt)
+{
+	int ret;
+	uint64_t coreboot_table_addr;
+	uint32_t coreboot_table_size;
+	struct {
+		uint64_t addr;
+		uint32_t size;
+	} reg_node;
+	coreboot_get_table_location(&coreboot_table_addr, &coreboot_table_size);
+	if (!coreboot_table_addr || !coreboot_table_size) {
+		WARN("Unable to get coreboot table location for device tree");
+		return 0;
+	}
+	ret = fdt_begin_node(fdt, "firmware");
+	if (ret)
+		return ret;
+
+	ret = fdt_property(fdt, "ranges", NULL, 0);
+	if (ret)
+		return ret;
+
+	ret = fdt_begin_node(fdt, "coreboot");
+	if (ret)
+		return ret;
+
+	ret = fdt_property_string(fdt, "compatible", "coreboot");
+	if (ret)
+		return ret;
+
+	reg_node.addr = cpu_to_fdt64(coreboot_table_addr);
+	reg_node.size = cpu_to_fdt32(coreboot_table_size);
+	ret = fdt_property(fdt, "reg", &reg_node,
+				sizeof(uint64_t) + sizeof(uint32_t));
+	if (ret)
+		return ret;
+
+	ret = fdt_end_node(fdt);
+	if (ret)
+		return ret;
+
+	return fdt_end_node(fdt);
+}
+#endif /* COREBOOT */
+
+/*
+ * Creates a device tree for passing into OP-TEE. Currently is populated with
+ * the coreboot table address.
+ * Returns 0 on success, error code otherwise.
+ */
+static int create_opteed_dt(void)
+{
+	int ret;
+
+	ret = fdt_create(fdt_buf, OPTEED_FDT_SIZE);
+	if (ret)
+		return ret;
+
+	ret = fdt_finish_reservemap(fdt_buf);
+	if (ret)
+		return ret;
+
+	ret = fdt_begin_node(fdt_buf, "");
+	if (ret)
+		return ret;
+
+#if COREBOOT
+	ret = add_coreboot_node(fdt_buf);
+	if (ret)
+		return ret;
+#endif /* COREBOOT */
+
+	ret = fdt_end_node(fdt_buf);
+	if (ret)
+		return ret;
+
+	return fdt_finish(fdt_buf);
+}
+
 /*******************************************************************************
  * This function is responsible for handling the SMC that loads the OP-TEE
  * binary image via a non-secure SMC call. It takes the size and physical
@@ -232,6 +325,7 @@
 	uint64_t target_size;
 	entry_point_info_t optee_ep_info;
 	uint32_t linear_id = plat_my_core_pos();
+	uint64_t dt_addr = 0;
 
 	mapped_data_pa = page_align(data_pa, DOWN);
 	mapped_data_va = mapped_data_pa;
@@ -292,12 +386,20 @@
 	/* Save the non-secure state */
 	cm_el1_sysregs_context_save(NON_SECURE);
 
+	rc = create_opteed_dt();
+	if (rc) {
+		ERROR("Failed device tree creation %d\n", rc);
+		return rc;
+	}
+	dt_addr = (uint64_t)fdt_buf;
+	flush_dcache_range(dt_addr, OPTEED_FDT_SIZE);
+
 	opteed_init_optee_ep_state(&optee_ep_info,
 				   opteed_rw,
 				   image_pa,
 				   0,
 				   0,
-				   0,
+				   dt_addr,
 				   &opteed_sp_context[linear_id]);
 	if (opteed_init_with_entry_point(&optee_ep_info) == 0) {
 		rc = -EFAULT;