Boot: Clear RAM before starting secure firmware

Clearing RAM to not leak accidentally any sensitive
information to software components running after boot.
This change also addressing the conformance with
the R30_TBFU_EXEC rule in PSA-TBFU spec (version 1.0.beta.1).

Change-Id: I173ecee9f2c163d385d74c2f14887ed655df7cd5
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/CommonConfig.cmake b/CommonConfig.cmake
index eff3005..361e763 100644
--- a/CommonConfig.cmake
+++ b/CommonConfig.cmake
@@ -51,6 +51,7 @@
 set(BUILD_BOOT_SEED Off)
 set(BUILD_DEVICE_ID Off)
 set(BUILD_PLAT_TEST Off)
+set(BUILD_BOOT_HAL Off)
 if(NOT DEFINED PLATFORM_CMAKE_FILE)
 	message (FATAL_ERROR "Platform specific CMake is not defined. Please set PLATFORM_CMAKE_FILE.")
 elseif(NOT EXISTS ${PLATFORM_CMAKE_FILE})
diff --git a/bl2/ext/mcuboot/CMakeLists.txt b/bl2/ext/mcuboot/CMakeLists.txt
index 80f0610..684de64 100644
--- a/bl2/ext/mcuboot/CMakeLists.txt
+++ b/bl2/ext/mcuboot/CMakeLists.txt
@@ -47,6 +47,7 @@
 set(BUILD_UART_STDOUT On)
 set(BUILD_FLASH On)
 set(BUILD_PLAT_TEST Off)
+set(BUILD_BOOT_HAL On)
 
 if (MCUBOOT_HW_KEY)
 	set(BUILD_TARGET_HARDWARE_KEYS On)
diff --git a/bl2/ext/mcuboot/bl2_main.c b/bl2/ext/mcuboot/bl2_main.c
index 7a8a451..f86c4c2 100644
--- a/bl2/ext/mcuboot/bl2_main.c
+++ b/bl2/ext/mcuboot/bl2_main.c
@@ -29,6 +29,7 @@
 #include "flash_map/flash_map.h"
 #include "bl2/include/boot_record.h"
 #include "security_cnt.h"
+#include "bl2/include/boot_hal.h"
 
 /* Avoids the semihosting issue */
 #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
@@ -56,6 +57,41 @@
     uint32_t reset;
 };
 
+/*!
+ * \brief Chain-loading the next image in the boot sequence.
+ *
+ * This function calls the Reset_Handler of the next image in the boot sequence,
+ * usually it is the secure firmware. Before passing the execution to next image
+ * there is conditional rule to remove the secrets from the memory. This must be
+ * done if the following conditions are satisfied:
+ *  - Memory is shared between SW components at different stages of the trusted
+ *    boot process.
+ *  - There are secrets in the memory: KDF parameter, symmetric key,
+ *    manufacturer sensitive code/data, etc.
+ */
+__attribute__((naked)) void boot_jump_to_next_image(uint32_t reset_handler_addr)
+{
+    __ASM volatile(
+        ".syntax unified                 \n"
+        "mov     r7, r0                  \n"
+        "bl      boot_clear_bl2_ram_area \n" /* Clear RAM before jump */
+        "movs    r0, #0                  \n" /* Clear registers: R0-R12, */
+        "mov     r1, r0                  \n" /* except R7 */
+        "mov     r2, r0                  \n"
+        "mov     r3, r0                  \n"
+        "mov     r4, r0                  \n"
+        "mov     r5, r0                  \n"
+        "mov     r6, r0                  \n"
+        "mov     r8, r0                  \n"
+        "mov     r9, r0                  \n"
+        "mov     r10, r0                 \n"
+        "mov     r11, r0                 \n"
+        "mov     r12, r0                 \n"
+        "mov     lr,  r0                 \n"
+        "bx      r7                      \n" /* Jump to Reset_handler */
+    );
+}
+
 static void do_boot(struct boot_rsp *rsp)
 {
     /* Clang at O0, stores variables on the stack with SP relative addressing.
@@ -107,7 +143,7 @@
     __DSB();
     __ISB();
 
-    ((void (*)(void))vt->reset)();
+    boot_jump_to_next_image(vt->reset);
 }
 
 int main(void)
diff --git a/bl2/include/boot_hal.h b/bl2/include/boot_hal.h
new file mode 100644
index 0000000..133c789
--- /dev/null
+++ b/bl2/include/boot_hal.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __BOOT_HAL_H__
+#define __BOOT_HAL_H__
+
+/* Include header section */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * \brief It clears that part of the RAM which was used by MCUBoot, expect the
+ *        TFM_SHARED_DATA area, which is used to pass data to the TF-M runtime.
+ *
+ * \note  This function must be implemented per target platform by system
+ *        integrator. If the bootloader has not loaded any secret to the shared
+ *        RAM then this function can immediately return to shorten the boot-up
+ *        time. Clearing RAM area can be done several way, it is platform
+ *        dependent:
+ *        - Overwritten with a pre-defined constant value (i.e.: 0).
+ *        - Overwritten with a random value.
+ *        - Change the secret if its location is known.
+ *        - Set a register which can hide some part of the flash/RAM against
+ *          next stage software components.
+ *        - Etc.
+ */
+void boot_clear_bl2_ram_area(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BOOT_HAL_H__ */
diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
index 46f5607..55300f7 100644
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -140,6 +140,12 @@
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/plat_test.c")
 endif()
 
+if (NOT DEFINED BUILD_BOOT_HAL)
+  message(FATAL_ERROR "Configuration variable BUILD_BOOT_HAL (true|false) is undefined!")
+elseif(BUILD_BOOT_HAL)
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an519/boot_hal.c")
+endif()
+
 if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
   message(FATAL_ERROR "Configuration variable BUILD_TARGET_HARDWARE_KEYS (true|false) is undefined!")
 elseif(BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index 630eca2..462daa8 100644
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -141,6 +141,12 @@
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/plat_test.c")
 endif()
 
+if (NOT DEFINED BUILD_BOOT_HAL)
+  message(FATAL_ERROR "Configuration variable BUILD_BOOT_HAL (true|false) is undefined!")
+elseif(BUILD_BOOT_HAL)
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps2/an521/boot_hal.c")
+endif()
+
 if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
   message(FATAL_ERROR "Configuration variable BUILD_TARGET_HARDWARE_KEYS (true|false) is undefined!")
 elseif(BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/Mps2AN539.cmake b/platform/ext/Mps2AN539.cmake
index 7a94d8c..16cf161 100644
--- a/platform/ext/Mps2AN539.cmake
+++ b/platform/ext/Mps2AN539.cmake
@@ -175,6 +175,12 @@
   list(APPEND ALL_SRC_C "${AN539_DIR}/plat_test.c")
 endif()
 
+if (NOT DEFINED BUILD_BOOT_HAL)
+  message(FATAL_ERROR "Configuration variable BUILD_BOOT_HAL (true|false) is undefined!")
+elseif(BUILD_BOOT_HAL)
+  list(APPEND ALL_SRC_C "${AN539_DIR}/boot_hal.c")
+endif()
+
 if (NOT DEFINED BUILD_FLASH)
   message(FATAL_ERROR "Configuration variable BUILD_FLASH (true|false) is undefined!")
 elseif(BUILD_FLASH)
diff --git a/platform/ext/Mps3AN524.cmake b/platform/ext/Mps3AN524.cmake
index 687d2a4..bb09fcc 100644
--- a/platform/ext/Mps3AN524.cmake
+++ b/platform/ext/Mps3AN524.cmake
@@ -147,6 +147,12 @@
   list(APPEND ALL_SRC_C "${AN524_DIR}/plat_test.c")
 endif()
 
+if (NOT DEFINED BUILD_BOOT_HAL)
+  message(FATAL_ERROR "Configuration variable BUILD_BOOT_HAL (true|false) is undefined!")
+elseif(BUILD_BOOT_HAL)
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/mps3/an524/boot_hal.c")
+endif()
+
 if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
   message(FATAL_ERROR "Configuration variable BUILD_TARGET_HARDWARE_KEYS (true|false) is undefined!")
 elseif(BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index b850ccb9..173b17b 100644
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -129,6 +129,12 @@
   list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/plat_test.c")
 endif()
 
+if (NOT DEFINED BUILD_BOOT_HAL)
+  message(FATAL_ERROR "Configuration variable BUILD_BOOT_HAL (true|false) is undefined!")
+elseif(BUILD_BOOT_HAL)
+  list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_a/boot_hal.c")
+endif()
+
 if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
   message(FATAL_ERROR "Configuration variable BUILD_TARGET_HARDWARE_KEYS (true|false) is undefined!")
 elseif(BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/musca_b1.cmake b/platform/ext/musca_b1.cmake
index f869d9b..23c27ad 100644
--- a/platform/ext/musca_b1.cmake
+++ b/platform/ext/musca_b1.cmake
@@ -148,6 +148,12 @@
     list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_b1/plat_test.c")
 endif()
 
+if (NOT DEFINED BUILD_BOOT_HAL)
+    message(FATAL_ERROR "Configuration variable BUILD_BOOT_HAL (true|false) is undefined!")
+elseif(BUILD_BOOT_HAL)
+    list(APPEND ALL_SRC_C "${PLATFORM_DIR}/target/musca_b1/boot_hal.c")
+endif()
+
 if (NOT DEFINED BUILD_TARGET_HARDWARE_KEYS)
     message(FATAL_ERROR "Configuration variable BUILD_TARGET_HARDWARE_KEYS (true|false) is undefined!")
 elseif (BUILD_TARGET_HARDWARE_KEYS)
diff --git a/platform/ext/target/mps2/an519/boot_hal.c b/platform/ext/target/mps2/an519/boot_hal.c
new file mode 100644
index 0000000..26d7ce9
--- /dev/null
+++ b/platform/ext/target/mps2/an519/boot_hal.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis.h"
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+    __ASM volatile(
+        ".syntax unified                             \n"
+        "movs    r0, #0                              \n"
+        "ldr     r1, =Image$$ER_DATA$$Base           \n"
+        "ldr     r2, =Image$$ARM_LIB_HEAP$$ZI$$Limit \n"
+        "subs    r2, r2, r1                          \n"
+        "Loop:                                       \n"
+        "subs    r2, #4                              \n"
+        "blt     Clear_done                          \n"
+        "str     r0, [r1, r2]                        \n"
+        "b       Loop                                \n"
+        "Clear_done:                                 \n"
+        "bx      lr                                  \n"
+         : : : "r0" , "r1" , "r2" , "memory"
+    );
+}
diff --git a/platform/ext/target/mps2/an519/gcc/mps2_an519_bl2.ld b/platform/ext/target/mps2/an519/gcc/mps2_an519_bl2.ld
index e40adcf..2a8eae3 100644
--- a/platform/ext/target/mps2/an519/gcc/mps2_an519_bl2.ld
+++ b/platform/ext/target/mps2/an519/gcc/mps2_an519_bl2.ld
@@ -154,6 +154,7 @@
         __data_end__ = .;
 
     } > RAM
+    Image$$ER_DATA$$Base = ADDR(.data);
 
     .bss :
     {
@@ -183,6 +184,7 @@
         __HeapLimit = .;
         __heap_limit = .; /* Add for _sbrk */
     } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
 
     PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
 }
diff --git a/platform/ext/target/mps2/an521/boot_hal.c b/platform/ext/target/mps2/an521/boot_hal.c
new file mode 100644
index 0000000..5dadc3f
--- /dev/null
+++ b/platform/ext/target/mps2/an521/boot_hal.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis.h"
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+    __ASM volatile(
+        ".syntax unified                             \n"
+        "mov     r0, #0                              \n"
+        "ldr     r1, =Image$$ER_DATA$$Base           \n"
+        "ldr     r2, =Image$$ARM_LIB_HEAP$$ZI$$Limit \n"
+        "subs    r2, r2, r1                          \n"
+        "Loop:                                       \n"
+        "subs    r2, #4                              \n"
+        "itt     ge                                  \n"
+        "strge   r0, [r1, r2]                        \n"
+        "bge     Loop                                \n"
+        "bx      lr                                  \n"
+         : : : "r0" , "r1" , "r2" , "memory"
+    );
+}
diff --git a/platform/ext/target/mps2/an521/gcc/mps2_an521_bl2.ld b/platform/ext/target/mps2/an521/gcc/mps2_an521_bl2.ld
index 6e03b29..9dfddf3 100644
--- a/platform/ext/target/mps2/an521/gcc/mps2_an521_bl2.ld
+++ b/platform/ext/target/mps2/an521/gcc/mps2_an521_bl2.ld
@@ -154,6 +154,7 @@
         __data_end__ = .;
 
     } > RAM
+    Image$$ER_DATA$$Base = ADDR(.data);
 
     .bss :
     {
@@ -183,6 +184,7 @@
         __HeapLimit = .;
         __heap_limit = .; /* Add for _sbrk */
     } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
 
     PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
 }
diff --git a/platform/ext/target/mps2/an539/boot_hal.c b/platform/ext/target/mps2/an539/boot_hal.c
new file mode 100644
index 0000000..26d7ce9
--- /dev/null
+++ b/platform/ext/target/mps2/an539/boot_hal.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis.h"
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+    __ASM volatile(
+        ".syntax unified                             \n"
+        "movs    r0, #0                              \n"
+        "ldr     r1, =Image$$ER_DATA$$Base           \n"
+        "ldr     r2, =Image$$ARM_LIB_HEAP$$ZI$$Limit \n"
+        "subs    r2, r2, r1                          \n"
+        "Loop:                                       \n"
+        "subs    r2, #4                              \n"
+        "blt     Clear_done                          \n"
+        "str     r0, [r1, r2]                        \n"
+        "b       Loop                                \n"
+        "Clear_done:                                 \n"
+        "bx      lr                                  \n"
+         : : : "r0" , "r1" , "r2" , "memory"
+    );
+}
diff --git a/platform/ext/target/mps2/an539/device/source/gcc/an539_mps2_bl2.ld b/platform/ext/target/mps2/an539/device/source/gcc/an539_mps2_bl2.ld
index f929819..68bfe01 100644
--- a/platform/ext/target/mps2/an539/device/source/gcc/an539_mps2_bl2.ld
+++ b/platform/ext/target/mps2/an539/device/source/gcc/an539_mps2_bl2.ld
@@ -154,6 +154,7 @@
         __data_end__ = .;
 
     } > RAM
+    Image$$ER_DATA$$Base = ADDR(.data);
 
     .bss :
     {
@@ -183,6 +184,7 @@
         __HeapLimit = .;
         __heap_limit = .; /* Add for _sbrk */
     } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
 
     PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
 }
diff --git a/platform/ext/target/mps3/an524/boot_hal.c b/platform/ext/target/mps3/an524/boot_hal.c
new file mode 100644
index 0000000..5dadc3f
--- /dev/null
+++ b/platform/ext/target/mps3/an524/boot_hal.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis.h"
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+    __ASM volatile(
+        ".syntax unified                             \n"
+        "mov     r0, #0                              \n"
+        "ldr     r1, =Image$$ER_DATA$$Base           \n"
+        "ldr     r2, =Image$$ARM_LIB_HEAP$$ZI$$Limit \n"
+        "subs    r2, r2, r1                          \n"
+        "Loop:                                       \n"
+        "subs    r2, #4                              \n"
+        "itt     ge                                  \n"
+        "strge   r0, [r1, r2]                        \n"
+        "bge     Loop                                \n"
+        "bx      lr                                  \n"
+         : : : "r0" , "r1" , "r2" , "memory"
+    );
+}
diff --git a/platform/ext/target/mps3/an524/device/source/gcc/mps3_an524_bl2.ld b/platform/ext/target/mps3/an524/device/source/gcc/mps3_an524_bl2.ld
index 06c91ae..ce1ffc0 100644
--- a/platform/ext/target/mps3/an524/device/source/gcc/mps3_an524_bl2.ld
+++ b/platform/ext/target/mps3/an524/device/source/gcc/mps3_an524_bl2.ld
@@ -154,6 +154,7 @@
         __data_end__ = .;
 
     } > RAM
+    Image$$ER_DATA$$Base = ADDR(.data);
 
     .bss :
     {
@@ -184,6 +185,7 @@
         __HeapLimit = .;
         __heap_limit = .; /* Add for _sbrk */
     } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
 
     PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
 }
diff --git a/platform/ext/target/musca_a/Device/Source/gcc/musca_bl2.ld b/platform/ext/target/musca_a/Device/Source/gcc/musca_bl2.ld
index afd6878..c792fff 100644
--- a/platform/ext/target/musca_a/Device/Source/gcc/musca_bl2.ld
+++ b/platform/ext/target/musca_a/Device/Source/gcc/musca_bl2.ld
@@ -183,6 +183,7 @@
         __data_end__ = .;
 
     } > RAM
+    Image$$ER_DATA$$Base = ADDR(.data);
 
     .bss :
     {
@@ -212,6 +213,7 @@
         __HeapLimit = .;
         __heap_limit = .; /* Add for _sbrk */
     } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
 
     PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
 }
diff --git a/platform/ext/target/musca_a/boot_hal.c b/platform/ext/target/musca_a/boot_hal.c
new file mode 100644
index 0000000..5dadc3f
--- /dev/null
+++ b/platform/ext/target/musca_a/boot_hal.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis.h"
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+    __ASM volatile(
+        ".syntax unified                             \n"
+        "mov     r0, #0                              \n"
+        "ldr     r1, =Image$$ER_DATA$$Base           \n"
+        "ldr     r2, =Image$$ARM_LIB_HEAP$$ZI$$Limit \n"
+        "subs    r2, r2, r1                          \n"
+        "Loop:                                       \n"
+        "subs    r2, #4                              \n"
+        "itt     ge                                  \n"
+        "strge   r0, [r1, r2]                        \n"
+        "bge     Loop                                \n"
+        "bx      lr                                  \n"
+         : : : "r0" , "r1" , "r2" , "memory"
+    );
+}
diff --git a/platform/ext/target/musca_b1/Device/Source/gcc/musca_bl2.ld b/platform/ext/target/musca_b1/Device/Source/gcc/musca_bl2.ld
index d2afb86..fcf01ae 100644
--- a/platform/ext/target/musca_b1/Device/Source/gcc/musca_bl2.ld
+++ b/platform/ext/target/musca_b1/Device/Source/gcc/musca_bl2.ld
@@ -154,6 +154,7 @@
         __data_end__ = .;
 
     } > RAM
+    Image$$ER_DATA$$Base = ADDR(.data);
 
     .bss :
     {
@@ -184,6 +185,7 @@
         __HeapLimit = .;
         __heap_limit = .; /* Add for _sbrk */
     } > RAM
+    Image$$ARM_LIB_HEAP$$ZI$$Limit = ADDR(.heap) + SIZEOF(.heap);
 
     PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
 }
diff --git a/platform/ext/target/musca_b1/boot_hal.c b/platform/ext/target/musca_b1/boot_hal.c
new file mode 100644
index 0000000..5dadc3f
--- /dev/null
+++ b/platform/ext/target/musca_b1/boot_hal.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis.h"
+
+__attribute__((naked)) void boot_clear_bl2_ram_area(void)
+{
+    __ASM volatile(
+        ".syntax unified                             \n"
+        "mov     r0, #0                              \n"
+        "ldr     r1, =Image$$ER_DATA$$Base           \n"
+        "ldr     r2, =Image$$ARM_LIB_HEAP$$ZI$$Limit \n"
+        "subs    r2, r2, r1                          \n"
+        "Loop:                                       \n"
+        "subs    r2, #4                              \n"
+        "itt     ge                                  \n"
+        "strge   r0, [r1, r2]                        \n"
+        "bge     Loop                                \n"
+        "bx      lr                                  \n"
+         : : : "r0" , "r1" , "r2" , "memory"
+    );
+}