Add support for using the Armv8-A CRC32 feature
The Armv8-A architecture specifies a CRC32 hardware feature, it can be
used through an intrinsic specified by ACLE. However, the HW feature is
mandatory only starting from v8.1, so for v8.0 CPUs we have to check its
availability. This commit implements a mechanism to do this check for
both Linux and SP environments, and override the default software CRC32
implementation when the HW feature is present.
Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Change-Id: Ia15fe1db9890b8aa076deec44c71639a4382cb35
diff --git a/components/app/fwu-tool/component.cmake b/components/app/fwu-tool/component.cmake
index 73a8524..90a07c2 100644
--- a/components/app/fwu-tool/component.cmake
+++ b/components/app/fwu-tool/component.cmake
@@ -19,7 +19,7 @@
add_components(TARGET ${TGT}
BASE_DIR ${TS_ROOT}
COMPONENTS
- "components/common/crc32/native"
+ "components/common/crc32"
"components/common/trace"
"components/common/utils"
)
diff --git a/components/common/crc32/tf-a/component.cmake b/components/common/crc32/component.cmake
similarity index 62%
rename from components/common/crc32/tf-a/component.cmake
rename to components/common/crc32/component.cmake
index 39636d5..4628b7f 100644
--- a/components/common/crc32/tf-a/component.cmake
+++ b/components/common/crc32/component.cmake
@@ -10,5 +10,16 @@
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/crc32.c"
- "${TFA_SOURCE_DIR}/common/tf_crc32.c"
+)
+
+if (TS_ENV STREQUAL "arm-linux")
+ target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crc32_linux.c"
)
+endif()
+
+if ((TS_ENV STREQUAL "opteesp") OR (TS_ENV STREQUAL "sp"))
+ target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/crc32_sp.c"
+ )
+endif()
diff --git a/components/common/crc32/native/crc32.c b/components/common/crc32/crc32.c
similarity index 79%
rename from components/common/crc32/native/crc32.c
rename to components/common/crc32/crc32.c
index 705db65..8c34eb1 100644
--- a/components/common/crc32/native/crc32.c
+++ b/components/common/crc32/crc32.c
@@ -8,10 +8,15 @@
* https://web.mit.edu/freebsd/head/sys/libkern/crc32.c
*/
-#include <common/crc32/crc32.h>
+#ifdef __aarch64__
+#include <arm_acle.h>
+#endif
+#include <stddef.h>
+#include <stdint.h>
-/* For compatability with TF-A components */
-uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size);
+#include "crc32.h"
+#include "crc32_discovery.h"
+#include "trace.h"
static const uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
@@ -59,18 +64,53 @@
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
-uint32_t crc32(uint32_t crc, const unsigned char *buf, size_t size)
+static uint32_t crc32_sw(uint32_t crc_prev, const uint8_t *buf, size_t size)
{
- uint32_t calc_crc = ~crc;
- const uint8_t *local_buf = buf;
- size_t local_size = size;
+ uint32_t crc = ~crc_prev;
- while (local_size--)
- calc_crc = crc32_tab[(calc_crc ^ *local_buf++) & 0xFF] ^ (calc_crc >> 8);
+ if (!buf)
+ return 0;
- return calc_crc ^ ~0U;
+ while (size > 0) {
+ crc = crc32_tab[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
+ buf++;
+ size--;
+ }
+
+ return ~crc;
}
+#if __ARM_FEATURE_CRC32
+static uint32_t crc32_armv8a(uint32_t crc_prev, const uint8_t *buf, size_t size)
+{
+ uint32_t crc = ~crc_prev;
+
+ if (!buf)
+ return 0;
+
+ while (size > 0) {
+ crc = __crc32b(crc, *buf);
+ buf++;
+ size--;
+ }
+
+ return ~crc;
+}
+#endif
+
+uint32_t (*crc32)(uint32_t crc_prev, const uint8_t *buf, size_t size) = crc32_sw;
+
+void crc32_init(void)
+{
+#if __ARM_FEATURE_CRC32
+ if (crc32_armv8a_hw_available()) {
+ DMSG("Using crc32_armv8a CRC32 implementation");
+ crc32 = crc32_armv8a;
+ }
+#endif
+}
+
+/* For compatability with TF-A components */
uint32_t tf_crc32(uint32_t crc, const unsigned char *buf, size_t size)
{
return crc32(crc, buf, size);
diff --git a/components/common/crc32/crc32.h b/components/common/crc32/crc32.h
index a04e380..ae185cc 100644
--- a/components/common/crc32/crc32.h
+++ b/components/common/crc32/crc32.h
@@ -15,15 +15,20 @@
#endif
/**
+ * \brief Initialize CRC32 to use HW acceleration if available
+ */
+void crc32_init(void);
+
+/**
* \brief Calculate a CRC32 over the provided data
*
- * \param[in] crc The starting CRC for previous data
- * \param[in] buf The buffer to calculate the CRC over
- * \param[in] size Number of bytes in the buffer
+ * \param[in] crc_prev The starting CRC for previous data
+ * \param[in] buf The buffer to calculate the CRC over
+ * \param[in] size Number of bytes in the buffer
*
* \return The calculated CRC32
*/
-uint32_t crc32(uint32_t crc, const unsigned char *buf, size_t size);
+extern uint32_t (*crc32)(uint32_t crc_prev, const uint8_t *buf, size_t size);
#ifdef __cplusplus
}
diff --git a/components/common/crc32/crc32_discovery.h b/components/common/crc32/crc32_discovery.h
new file mode 100644
index 0000000..77a22d1
--- /dev/null
+++ b/components/common/crc32/crc32_discovery.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRC32_DISCOVERY_H
+#define CRC32_DISCOVERY_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool crc32_armv8a_hw_available(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CRC32_DISCOVERY_H */
diff --git a/components/common/crc32/crc32_linux.c b/components/common/crc32/crc32_linux.c
new file mode 100644
index 0000000..d6dd8b6
--- /dev/null
+++ b/components/common/crc32/crc32_linux.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <sys/auxv.h>
+
+#include "crc32_discovery.h"
+
+bool crc32_armv8a_hw_available(void)
+{
+ unsigned long hwcaps = getauxval(AT_HWCAP);
+ return (hwcaps & HWCAP_CRC32) == HWCAP_CRC32;
+}
diff --git a/components/common/crc32/crc32_sp.c b/components/common/crc32/crc32_sp.c
new file mode 100644
index 0000000..9e2db8e
--- /dev/null
+++ b/components/common/crc32/crc32_sp.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "config/interface/config_store.h"
+#include "crc32_discovery.h"
+
+bool crc32_armv8a_hw_available(void)
+{
+ uint32_t value = 0;
+
+ if (!config_store_query(CONFIG_CLASSIFIER_HW_FEATURE, "crc32", 0, &value, sizeof(value)))
+ return false;
+
+ return value != 0;
+}
diff --git a/components/common/crc32/native/component.cmake b/components/common/crc32/native/component.cmake
deleted file mode 100644
index 9bbf298..0000000
--- a/components/common/crc32/native/component.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-if (NOT DEFINED TGT)
- message(FATAL_ERROR "mandatory parameter TGT is not defined.")
-endif()
-
-target_sources(${TGT} PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/crc32.c"
- )
diff --git a/components/common/crc32/test/crc32_test.cpp b/components/common/crc32/test/crc32_test.cpp
index a21286f..5e1ea8d 100644
--- a/components/common/crc32/test/crc32_test.cpp
+++ b/components/common/crc32/test/crc32_test.cpp
@@ -9,7 +9,10 @@
TEST_GROUP(Crc32Tests)
{
-
+ TEST_SETUP()
+ {
+ crc32_init();
+ }
};
/*
diff --git a/components/common/crc32/tf-a/crc32.c b/components/common/crc32/tf-a/crc32.c
deleted file mode 100644
index abc0f8a..0000000
--- a/components/common/crc32/tf-a/crc32.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include <common/crc32/crc32.h>
-#include <common/tf_crc32.h>
-
-
-uint32_t crc32(uint32_t crc, const unsigned char *buf, size_t size)
-{
- return tf_crc32(crc, buf, size);
-}