* zeroing.
*/
void zeromem(void *mem, u_register_t length);
+
+/*
+ * Utility function to return the address of a symbol. By default, the
+ * compiler generates adr/adrp instruction pair to return the reference
+ * to the symbol and this utility is used to override this compiler
+ * generated to code to use `ldr` instruction.
+ *
+ * This helps when Position Independent Executable needs to reference a symbol
+ * which is constant and does not depend on the execute address of the binary.
+ */
+#define DEFINE_LOAD_SYM_ADDR(_name) \
+static inline u_register_t load_addr_## _name(void) \
+{ \
+ u_register_t v; \
+ /* Create a void reference to silence compiler */ \
+ (void) _name; \
+ __asm__ volatile ("ldr %0, =" #_name : "=r" (v)); \
+ return v; \
+}
+
+/* Helper to invoke the function defined by DEFINE_LOAD_SYM_ADDR() */
+#define LOAD_ADDR_OF(_name) (typeof(_name) *) load_addr_## _name()
+
#endif /* !(defined(__LINKER__) || defined(__ASSEMBLY__)) */
#endif /* __UTILS_H__ */
#include <plat_arm.h>
#include <platform.h>
#include <platform_def.h>
+#include <utils.h>
/******************************************************************************
* The following functions are defined as weak to allow a platform to override
/*
* We save and restore the GICv3 context on system suspend. Allocate the
- * data in the designated EL3 Secure carve-out memory
+ * data in the designated EL3 Secure carve-out memory. The `volatile`
+ * is used to prevent the compiler from removing the gicv3 contexts even
+ * though the DEFINE_LOAD_SYM_ADDR creates a dummy reference to it.
*/
-static gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
-static gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+static volatile gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+static volatile gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+
+/* Define accessor function to get reference to the GICv3 context */
+DEFINE_LOAD_SYM_ADDR(rdist_ctx)
+DEFINE_LOAD_SYM_ADDR(dist_ctx)
/*
* MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
*****************************************************************************/
void plat_arm_gic_save(void)
{
+ gicv3_redist_ctx_t * const rdist_context =
+ (gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
+ gicv3_dist_ctx_t * const dist_context =
+ (gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
/*
* If an ITS is available, save its context before
* we only need to save the context of the CPU that is issuing
* the SYSTEM SUSPEND call, i.e. the current CPU.
*/
- gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+ gicv3_rdistif_save(plat_my_core_pos(), rdist_context);
/* Save the GIC Distributor context */
- gicv3_distif_save(&dist_ctx);
+ gicv3_distif_save(dist_context);
/*
* From here, all the components of the GIC can be safely powered down
void plat_arm_gic_resume(void)
{
+ const gicv3_redist_ctx_t *rdist_context =
+ (gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
+ const gicv3_dist_ctx_t *dist_context =
+ (gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
+
/* Restore the GIC Distributor context */
- gicv3_distif_init_restore(&dist_ctx);
+ gicv3_distif_init_restore(dist_context);
/*
* Restore the GIC Redistributor and ITS contexts after the
* we only need to restore the context of the CPU that issued
* the SYSTEM SUSPEND call.
*/
- gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+ gicv3_rdistif_init_restore(plat_my_core_pos(), rdist_context);
/*
* If an ITS is available, restore its context after