Implement FFA_CONSOLE_LOG interface
Implement FFA_CONSOLE_LOG interface for sending debug logs to the SPMC.
The commit also replaces the proprietary trace call by FFA_CONSOLE_LOG.
Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I5275470683e2674fdd6f5a61f9c5ab8dd71dcb11
diff --git a/components/common/trace/trace.c b/components/common/trace/trace.c
index bc7f0a9..0b8cb53 100644
--- a/components/common/trace/trace.c
+++ b/components/common/trace/trace.c
@@ -30,10 +30,18 @@
if (offset < sizeof(buffer)) {
va_start(ap, fmt);
- vsnprintf(buffer + offset, sizeof(buffer) - offset, fmt, ap);
+ offset += vsnprintf(buffer + offset, sizeof(buffer) - offset, fmt, ap);
va_end(ap);
}
+ if (offset < sizeof(buffer) - 2) {
+ buffer[offset] = '\n';
+ buffer[offset + 1] = '\0';
+ } else {
+ buffer[sizeof(buffer) - 2] = '\n';
+ buffer[sizeof(buffer) - 1] = '\0';
+ }
+
trace_puts(buffer);
}
#endif
diff --git a/components/messaging/ffa/libsp/ffa.c b/components/messaging/ffa/libsp/ffa.c
index caacc79..6a51379 100644
--- a/components/messaging/ffa/libsp/ffa.c
+++ b/components/messaging/ffa/libsp/ffa.c
@@ -6,6 +6,7 @@
#include <assert.h> // for assert
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint16_t, uintptr_t, U
+#include <string.h> // for memcpy
#include "ffa_api.h" // for FFA_OK, ffa_interrupt_handler, ffa_fea...
#include "ffa_api_defines.h" // for FFA_PARAM_MBZ, FFA_OK, FFA_ERROR, FFA_...
#include "ffa_api_types.h" // for ffa_result, ffa_direct_msg, ffa_uuid
@@ -525,3 +526,43 @@
assert(result.a0 == FFA_SUCCESS_32);
return FFA_OK;
}
+
+ffa_result ffa_console_log_32(const char *message, size_t length)
+{
+ struct ffa_params result = {0};
+ uint32_t char_lists[6] = {0};
+
+ assert(length > 0 && length <= sizeof(char_lists));
+
+ memcpy(char_lists, message, MIN(length, sizeof(char_lists)));
+
+ ffa_svc(FFA_CONSOLE_LOG_32, length, char_lists[0], char_lists[1],
+ char_lists[2], char_lists[3], char_lists[4], char_lists[5],
+ &result);
+
+ if (result.a0 == FFA_ERROR)
+ return ffa_get_errorcode(&result);
+
+ assert(result.a0 == FFA_SUCCESS_32);
+ return FFA_OK;
+}
+
+ffa_result ffa_console_log_64(const char *message, size_t length)
+{
+ struct ffa_params result = {0};
+ uint64_t char_lists[6] = {0};
+
+ assert(length > 0 && length <= sizeof(char_lists));
+
+ memcpy(char_lists, message, MIN(length, sizeof(char_lists)));
+
+ ffa_svc(FFA_CONSOLE_LOG_64, length, char_lists[0], char_lists[1],
+ char_lists[2], char_lists[3], char_lists[4], char_lists[5],
+ &result);
+
+ if (result.a0 == FFA_ERROR)
+ return ffa_get_errorcode(&result);
+
+ assert(result.a0 == FFA_SUCCESS_32);
+ return FFA_OK;
+}
diff --git a/components/messaging/ffa/libsp/include/ffa_api.h b/components/messaging/ffa/libsp/include/ffa_api.h
index 4b7073b..e18e381 100644
--- a/components/messaging/ffa/libsp/include/ffa_api.h
+++ b/components/messaging/ffa/libsp/include/ffa_api.h
@@ -362,6 +362,26 @@
uint32_t mem_perm);
/**
+ * @brief Allow an entity to provide debug logging to the console. Uses
+ * 32 bit registers to pass characters.
+ *
+ * @param message Message characters
+ * @param length Message length, max FFA_CONSOLE_LOG_32_MAX_LENGTH
+ * @return The FF-A error status code
+ */
+ffa_result ffa_console_log_32(const char *message, size_t length);
+
+/**
+ * @brief Allow an entity to provide debug logging to the console. Uses
+ * 64 bit registers to pass characters.
+ *
+ * @param message Message characters
+ * @param length Message length, max FFA_CONSOLE_LOG_64_MAX_LENGTH
+ * @return The FF-A error status code
+ */
+ffa_result ffa_console_log_64(const char *message, size_t length);
+
+/**
* @brief Interrupt handler prototype. Must be implemented by another
* component.
*
diff --git a/components/messaging/ffa/libsp/include/ffa_api_defines.h b/components/messaging/ffa/libsp/include/ffa_api_defines.h
index 17a5eda..f6e0212 100644
--- a/components/messaging/ffa/libsp/include/ffa_api_defines.h
+++ b/components/messaging/ffa/libsp/include/ffa_api_defines.h
@@ -57,6 +57,8 @@
#define FFA_MEM_FRAG_TX UINT32_C(0x8400007B)
#define FFA_MEM_PERM_GET UINT32_C(0x84000088)
#define FFA_MEM_PERM_SET UINT32_C(0x84000089)
+#define FFA_CONSOLE_LOG_32 UINT32_C(0x8400008A)
+#define FFA_CONSOLE_LOG_64 UINT32_C(0xC400008A)
/* Utility macros */
#define FFA_TO_32_BIT_FUNC(x) ((x) & (~UINT32_C(0x40000000)))
@@ -273,4 +275,8 @@
#define FFA_MEM_PERM_RESERVED_MASK GENMASK_32(31, 3)
+/* FFA_CONSOLE_LOG */
+#define FFA_CONSOLE_LOG_32_MAX_LENGTH UINT32_C(24)
+#define FFA_CONSOLE_LOG_64_MAX_LENGTH UINT32_C(48)
+
#endif /* LIBSP_INCLUDE_FFA_API_DEFINES_H_ */
diff --git a/components/messaging/ffa/libsp/mock/mock_ffa_api.cpp b/components/messaging/ffa/libsp/mock/mock_ffa_api.cpp
index a01848c..38637cf 100644
--- a/components/messaging/ffa/libsp/mock/mock_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/mock/mock_ffa_api.cpp
@@ -561,3 +561,39 @@
.withUnsignedIntParameter("mem_perm", mem_perm)
.returnIntValue();
}
+
+void expect_ffa_console_log_32(const char *message, size_t length,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_console_log_32")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .andReturnValue(result);
+}
+
+ffa_result ffa_console_log_32(const char *message, size_t length)
+{
+ return mock()
+ .actualCall("ffa_console_log_32")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .returnIntValue();
+}
+
+void expect_ffa_console_log_64(const char *message, size_t length,
+ ffa_result result)
+{
+ mock().expectOneCall("ffa_console_log_64")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .andReturnValue(result);
+}
+
+ffa_result ffa_console_log_64(const char *message, size_t length)
+{
+ return mock()
+ .actualCall("ffa_console_log_64")
+ .withStringParameter("message", message)
+ .withUnsignedIntParameter("length", length)
+ .returnIntValue();
+}
diff --git a/components/messaging/ffa/libsp/mock/mock_ffa_api.h b/components/messaging/ffa/libsp/mock/mock_ffa_api.h
index 4213ccb..9c3dbc8 100644
--- a/components/messaging/ffa/libsp/mock/mock_ffa_api.h
+++ b/components/messaging/ffa/libsp/mock/mock_ffa_api.h
@@ -98,4 +98,10 @@
void expect_ffa_mem_perm_set(const void *base_address, uint32_t page_count,
uint32_t mem_perm, ffa_result result);
+void expect_ffa_console_log_32(const char *message, size_t length,
+ ffa_result result);
+
+void expect_ffa_console_log_64(const char *message, size_t length,
+ ffa_result result);
+
#endif /* FFA_LIBSP_TEST_MOCK_FFA_API_H_ */
diff --git a/components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp b/components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp
index c1cbdd6..8b793d3 100644
--- a/components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/mock/test/test_mock_ffa_api.cpp
@@ -345,3 +345,21 @@
expect_ffa_mem_perm_set(base_address, page_count, mem_perm, result);
LONGS_EQUAL(result, ffa_mem_perm_set(base_address, page_count, mem_perm));
}
+
+TEST(mock_ffa_api, ffa_console_log_32)
+{
+ const char *message = "log message";
+ const size_t length = 11;
+
+ expect_ffa_console_log_32(message, length, result);
+ LONGS_EQUAL(result, ffa_console_log_32(message, length));
+}
+
+TEST(mock_ffa_api, ffa_console_log_64)
+{
+ const char *message = "log message";
+ const size_t length = 11;
+
+ expect_ffa_console_log_64(message, length, result);
+ LONGS_EQUAL(result, ffa_console_log_64(message, length));
+}
diff --git a/components/messaging/ffa/libsp/test/test_ffa_api.cpp b/components/messaging/ffa/libsp/test/test_ffa_api.cpp
index 6cca085..8395662 100644
--- a/components/messaging/ffa/libsp/test/test_ffa_api.cpp
+++ b/components/messaging/ffa/libsp/test/test_ffa_api.cpp
@@ -1507,4 +1507,115 @@
if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
ffa_mem_perm_set(base_addr, page_count, mem_perm);
}
-}
\ No newline at end of file
+}
+
+TEST(ffa_api, ffa_console_log_32_zero)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_32("", 0);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_too_long)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_32("", 25);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_unknown_response)
+{
+ assert_environment_t assert_env;
+ const char *message = "0";
+ const size_t length = 1;
+
+ svc_result.a0 = 0x12345678;
+ expect_ffa_svc(0x8400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_32(message, length);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_32_error)
+{
+ const char *message = "0";
+ const size_t length = 1;
+
+ setup_error_response(-1);
+ expect_ffa_svc(0x8400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+ ffa_result result = ffa_console_log_32(message, length);
+ LONGS_EQUAL(-1, result);
+}
+
+TEST(ffa_api, ffa_console_log_32)
+{
+ const char *message = "0123456789abcdefghijklmn";
+ const size_t length = 24;
+
+ svc_result.a0 = 0x84000061;
+ expect_ffa_svc(0x8400008A, length, 0x33323130, 0x37363534, 0x62613938,
+ 0x66656463, 0x6A696867, 0x6E6D6C6B, &svc_result);
+ ffa_result result = ffa_console_log_32(message, length);
+ LONGS_EQUAL(0, result);
+}
+
+TEST(ffa_api, ffa_console_log_64_zero)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_64("", 0);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_64_too_long)
+{
+ assert_environment_t assert_env;
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_64("", 49);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_64_unknown_response)
+{
+ assert_environment_t assert_env;
+ const char *message = "0";
+ const size_t length = 1;
+
+ svc_result.a0 = 0x12345678;
+ expect_ffa_svc(0xC400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+
+ if (SETUP_ASSERT_ENVIRONMENT(assert_env)) {
+ ffa_console_log_64(message, length);
+ }
+}
+
+TEST(ffa_api, ffa_console_log_64_error)
+{
+ const char *message = "0";
+ const size_t length = 1;
+
+ setup_error_response(-1);
+ expect_ffa_svc(0xC400008A, length, 0x30, 0, 0, 0, 0, 0, &svc_result);
+ ffa_result result = ffa_console_log_64(message, length);
+ LONGS_EQUAL(-1, result);
+}
+
+TEST(ffa_api, ffa_console_log_64)
+{
+ const char *message = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ab";
+ const size_t length = 48;
+
+ svc_result.a0 = 0x84000061;
+ expect_ffa_svc(0xC400008A, length, 0x3736353433323130,
+ 0x6665646362613938, 0x6E6D6C6B6A696867,
+ 0x767574737271706F, 0x333231307A797877,
+ 0x6261393837363534, &svc_result);
+ ffa_console_log_64(message, length);
+}
diff --git a/environments/opteesp/sp_trace.c b/environments/opteesp/sp_trace.c
index 6ac0ddc..586b41c 100644
--- a/environments/opteesp/sp_trace.c
+++ b/environments/opteesp/sp_trace.c
@@ -4,15 +4,20 @@
*/
#include "trace.h"
-#include "ffa_internal_api.h"
+#include "ffa_api.h"
+#include <string.h>
#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
void trace_puts(const char *str)
{
- struct ffa_params resp;
+ size_t length = strlen(str);
+ size_t i = 0;
- ffa_svc(0xdeadbeef, (uintptr_t)str, 0, 0, 0, 0, 0, 0, &resp);
+ for (i = 0; i < length; i += FFA_CONSOLE_LOG_64_MAX_LENGTH) {
+ ffa_console_log_64(&str[i], MIN(FFA_CONSOLE_LOG_64_MAX_LENGTH,
+ length - i));
+ }
}
#endif /* TRACE_LEVEL >= TRACE_LEVEL_ERROR */
diff --git a/environments/sp/sp_trace.c b/environments/sp/sp_trace.c
index 606e45d..7e8cb9c 100644
--- a/environments/sp/sp_trace.c
+++ b/environments/sp/sp_trace.c
@@ -4,15 +4,20 @@
*/
#include "trace.h"
-#include "ffa_internal_api.h"
+#include "ffa_api.h"
+#include <string.h>
#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
void trace_puts(const char *str)
{
- struct ffa_params resp;
+ size_t length = strlen(str);
+ size_t i = 0;
- ffa_svc(0xdeadbeef, (uintptr_t)str, 0, 0, 0, 0, 0, 0, &resp);
+ for (i = 0; i < length; i += FFA_CONSOLE_LOG_64_MAX_LENGTH) {
+ ffa_console_log_64(&str[i], MIN(FFA_CONSOLE_LOG_64_MAX_LENGTH,
+ length - i));
+ }
}
#endif /* TRACE_LEVEL >= TRACE_LEVEL_ERROR */