From 04c7303b9c3d2215eebc3d59431519990abe03d0 Mon Sep 17 00:00:00 2001 From: Okash Khawaja Date: Fri, 4 Nov 2022 12:38:01 +0000 Subject: [PATCH] feat(cpus): make cache ops conditional When a core is in debug recovery mode its caches are not invalidated upon reset, so the L1 and L2 cache contents from before reset are observable after reset. Similarly, debug recovery mode of DynamIQ cluster ensures that contents of the shared L3 cache are also not invalidated upon transition to On mode. Booting cores in debug recovery mode means booting with caches disabled and preserving the caches until a point where software can dump the caches and retrieve their contents. TF-A however unconditionally cleans and invalidates caches at multiple points during boot. This can lead to memory corruption as well as loss of cache contents to be used for debugging. This patch fixes this by calling a platform hook before performing CMOs in helper routines in cache_helpers.S. The platform hook plat_can_cmo is an assembly routine which must not clobber x2 and x3, and avoid using stack. The whole checking is conditional upon `CONDITIONAL_CMO` which can be set at compile time. Signed-off-by: Okash Khawaja Change-Id: I172e999e4acd0f872c24056e647cc947ee54b193 --- Makefile | 2 ++ docs/getting_started/build-options.rst | 6 ++++++ docs/getting_started/porting-guide.rst | 16 ++++++++++++++++ lib/aarch32/cache_helpers.S | 22 ++++++++++++++++++++++ lib/aarch64/cache_helpers.S | 21 +++++++++++++++++++++ make_helpers/defaults.mk | 4 ++++ 6 files changed, 71 insertions(+) diff --git a/Makefile b/Makefile index 70d5338eb..b664ac0af 100644 --- a/Makefile +++ b/Makefile @@ -1080,6 +1080,7 @@ $(eval $(call assert_booleans,\ SIMICS_BUILD \ FEATURE_DETECTION \ TRNG_SUPPORT \ + CONDITIONAL_CMO \ ))) $(eval $(call assert_numerics,\ @@ -1241,6 +1242,7 @@ $(eval $(call add_defines,\ FEATURE_DETECTION \ TWED_DELAY \ ENABLE_FEAT_TWED \ + CONDITIONAL_CMO \ ))) ifeq (${SANITIZE_UB},trap) diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index 68ef4cefd..d1acf4f4e 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -1031,6 +1031,12 @@ Common build options functionalities). When enabled (``1``), a mocked version of the APIs are used. The default value is 0. +- ``CONDITIONAL_CMO``: Boolean option to enable call to platform-defined routine + ``plat_can_cmo`` which will return zero if cache management operations should + be skipped and non-zero otherwise. By default, this option is disabled which + means platform hook won't be checked and CMOs will always be performed when + related functions are called. + GICv3 driver options -------------------- diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst index 668af5714..4639fd5fd 100644 --- a/docs/getting_started/porting-guide.rst +++ b/docs/getting_started/porting-guide.rst @@ -1461,6 +1461,22 @@ When the MEASURED_BOOT flag is enabled: When the MEASURED_BOOT flag is disabled, this function doesn't do anything. +Function : plat_can_cmo() +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + Argument : void + Return : uint64_t + +When CONDITIONAL_CMO flag is enabled: + +- This function indicates whether cache management operations should be + performed. It returns 0 if CMOs should be skipped and non-zero + otherwise. +- The function must not clobber x2 and x3. It's also not safe to rely on stack. + Otherwise obey AAPCS. + Modifications specific to a Boot Loader stage --------------------------------------------- diff --git a/lib/aarch32/cache_helpers.S b/lib/aarch32/cache_helpers.S index 13d1872f8..fd9b33f2d 100644 --- a/lib/aarch32/cache_helpers.S +++ b/lib/aarch32/cache_helpers.S @@ -37,12 +37,27 @@ exit_loop_\op: bx lr .endm +.macro check_plat_can_cmo +#if CONDITIONAL_CMO + mov r3, lr + mov r2, r0 + bl plat_can_cmo + mov lr, r3 + cmp r0, #0 + bne 1f + bx lr +1: + mov r0, r2 +#endif +.endm + /* ------------------------------------------ * Clean+Invalidate from base address till * size. 'r0' = addr, 'r1' = size * ------------------------------------------ */ func flush_dcache_range + check_plat_can_cmo do_dcache_maintenance_by_mva cimvac, DCCIMVAC endfunc flush_dcache_range @@ -52,6 +67,7 @@ endfunc flush_dcache_range * ------------------------------------------ */ func clean_dcache_range + check_plat_can_cmo do_dcache_maintenance_by_mva cmvac, DCCMVAC endfunc clean_dcache_range @@ -61,6 +77,7 @@ endfunc clean_dcache_range * ------------------------------------------ */ func inv_dcache_range + check_plat_can_cmo do_dcache_maintenance_by_mva imvac, DCIMVAC endfunc inv_dcache_range @@ -168,6 +185,7 @@ endfunc do_dcsw_op * --------------------------------------------------------------- */ func dcsw_op_louis + check_plat_can_cmo dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_louis @@ -180,6 +198,7 @@ endfunc dcsw_op_louis * --------------------------------------------------------------- */ func dcsw_op_all + check_plat_can_cmo dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_all @@ -205,6 +224,7 @@ endfunc dcsw_op_all * --------------------------------------------------------------- */ func dcsw_op_level1 + check_plat_can_cmo dcsw_op_level #(1 << LEVEL_SHIFT) endfunc dcsw_op_level1 @@ -217,6 +237,7 @@ endfunc dcsw_op_level1 * --------------------------------------------------------------- */ func dcsw_op_level2 + check_plat_can_cmo dcsw_op_level #(2 << LEVEL_SHIFT) endfunc dcsw_op_level2 @@ -229,5 +250,6 @@ endfunc dcsw_op_level2 * --------------------------------------------------------------- */ func dcsw_op_level3 + check_plat_can_cmo dcsw_op_level #(3 << LEVEL_SHIFT) endfunc dcsw_op_level3 diff --git a/lib/aarch64/cache_helpers.S b/lib/aarch64/cache_helpers.S index 6faf545a1..67fafb1e7 100644 --- a/lib/aarch64/cache_helpers.S +++ b/lib/aarch64/cache_helpers.S @@ -35,6 +35,19 @@ loop_\op: dsb sy exit_loop_\op: ret +.endm + +.macro check_plat_can_cmo +#if CONDITIONAL_CMO + mov x3, x30 + mov x2, x0 + bl plat_can_cmo + mov x30, x3 + cbnz x0, 1f + ret +1: + mov x0, x2 +#endif .endm /* ------------------------------------------ * Clean+Invalidate from base address till @@ -42,6 +55,7 @@ exit_loop_\op: * ------------------------------------------ */ func flush_dcache_range + check_plat_can_cmo do_dcache_maintenance_by_mva civac endfunc flush_dcache_range @@ -51,6 +65,7 @@ endfunc flush_dcache_range * ------------------------------------------ */ func clean_dcache_range + check_plat_can_cmo do_dcache_maintenance_by_mva cvac endfunc clean_dcache_range @@ -60,6 +75,7 @@ endfunc clean_dcache_range * ------------------------------------------ */ func inv_dcache_range + check_plat_can_cmo do_dcache_maintenance_by_mva ivac endfunc inv_dcache_range @@ -79,6 +95,7 @@ endfunc inv_dcache_range func flush_dcache_to_popa_range /* Exit early if size is zero */ cbz x1, exit_loop_dc_cipapa + check_plat_can_cmo dcache_line_size x2, x3 sub x3, x2, #1 bic x0, x0, x3 @@ -205,6 +222,7 @@ endfunc dcsw_op_louis func dcsw_op_all + check_plat_can_cmo dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_all @@ -228,6 +246,7 @@ endfunc dcsw_op_all * --------------------------------------------------------------- */ func dcsw_op_level1 + check_plat_can_cmo dcsw_op_level #(1 << LEVEL_SHIFT) endfunc dcsw_op_level1 @@ -239,6 +258,7 @@ endfunc dcsw_op_level1 * --------------------------------------------------------------- */ func dcsw_op_level2 + check_plat_can_cmo dcsw_op_level #(2 << LEVEL_SHIFT) endfunc dcsw_op_level2 @@ -250,5 +270,6 @@ endfunc dcsw_op_level2 * --------------------------------------------------------------- */ func dcsw_op_level3 + check_plat_can_cmo dcsw_op_level #(3 << LEVEL_SHIFT) endfunc dcsw_op_level3 diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 772b28de0..4b238e346 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -480,3 +480,7 @@ PLAT_RSS_NOT_SUPPORTED := 0 # Dynamic Root of Trust for Measurement support DRTM_SUPPORT := 0 + +# Check platform if cache management operations should be performed. +# Disabled by default. +CONDITIONAL_CMO := 0