Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion components/freertos_kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2023-2024 Arm Limited and/or its affiliates
# Copyright 2023-2025 Arm Limited and/or its affiliates
# <[email protected]>
# SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -29,6 +29,9 @@ else()
$<$<STREQUAL:${ARM_CORSTONE_BSP_TARGET_PLATFORM},corstone310>:${IOT_REFERENCE_ARM_CORSTONE3XX_SOURCE_DIR}/bsp/corstone310/include>
$<$<STREQUAL:${ARM_CORSTONE_BSP_TARGET_PLATFORM},corstone315>:${IOT_REFERENCE_ARM_CORSTONE3XX_SOURCE_DIR}/bsp/corstone315/include>
$<$<STREQUAL:${ARM_CORSTONE_BSP_TARGET_PLATFORM},corstone320>:${IOT_REFERENCE_ARM_CORSTONE3XX_SOURCE_DIR}/bsp/corstone320/include>
${CMAKE_CURRENT_LIST_DIR}/integration/inc
)
add_subdirectory(library)
endif()

add_subdirectory(integration)
19 changes: 19 additions & 0 deletions components/freertos_kernel/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Arm Limited and/or its affiliates
# <[email protected]>
# SPDX-License-Identifier: MIT

cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)

add_library(heap-management
STATIC
src/heap_management.c
)

target_include_directories(heap-management
PRIVATE
inc
)

if(BUILD_TESTING AND NOT CMAKE_CROSSCOMPILING)
add_subdirectory(tests)
endif()
67 changes: 67 additions & 0 deletions components/freertos_kernel/integration/inc/heap_management.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* Copyright 2025 Arm Limited and/or its affiliates
* <[email protected]>
* SPDX-License-Identifier: MIT
*/

/**
* @file heap_management.h
* @brief Thin wrappers around the C library used by the integration code.
*/
#ifndef HEAP_MANAGEMENT_H
#define HEAP_MANAGEMENT_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Wrapper for the C libraries malloc
* @param xWantedSize The number of bytes to be allocated
* @return Either a non-NULL pointer to a block of memory on success, or NULL on failure
*/
void * pvPortMalloc( size_t xWantedSize );

/**
* @brief Wrapper for the C libraries free function
* @param pv Pointer to a memory location to be freed, or NULL
*/
void vPortFree( void * pv );

/**
* @brief Wrapper for the C libraries calloc
* @param xNum The number of elements
* @param xSize The size of each element in bytes
* @return Either a non-NULL pointer to a block of memory on success, or NULL on failure
*/
void * pvPortCalloc( size_t xNum,
size_t xSize );

/**
* @brief A dummy implementation as C standard library does not provide
* functions to get the statistics of heap memory.
* @return Always 0 in the integration build
* @note These dummy implementation are needed
* as this API is used as part of FreeRTOS Plus TCP code which is unused in the
* FRI code (removed by the linker) but ARMClang linker requires all the compiled
* symbols to be defined.
*/
size_t xPortGetFreeHeapSize( void );

/**
* @brief A dummy implementation as C standard library does not provide
* functions to get the statistics of heap memory.
* @return Always 0 in the integration build
* @note These dummy implementation are needed
* as this API is used as part of FreeRTOS Plus TCP code which is unused in the
* FRI code (removed by the linker) but ARMClang linker requires all the compiled
* symbols to be defined.
*/
size_t xPortGetMinimumEverFreeHeapSize( void );

#ifdef __cplusplus
}
#endif

#endif /* HEAP_MANAGEMENT_H */
8 changes: 2 additions & 6 deletions components/freertos_kernel/integration/src/heap_management.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* Copyright 2024 Arm Limited and/or its affiliates
/* Copyright 2024-2025 Arm Limited and/or its affiliates
* <[email protected]>
* SPDX-License-Identifier: MIT
*/

#include "heap_management.h"
#include <stdlib.h>

void * pvPortMalloc( size_t xWantedSize )
Expand All @@ -21,11 +22,6 @@ void * pvPortCalloc( size_t xNum,
return calloc( xNum, xSize );
}

/* These are dummy implementations as C standard library does not provide
* functions to get the statistics of heap memory. These dummy implementation are needed
* as these APIs are used as part of FreeRTOS Plus TCP code which is unused in the FRI code (removed by the linker)
* but ARMClang linker requires all the compiled symbols to be defined.
*/
size_t xPortGetFreeHeapSize( void )
{
return 0;
Expand Down
31 changes: 31 additions & 0 deletions components/freertos_kernel/integration/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2025 Arm Limited and/or its affiliates
# <[email protected]>
# SPDX-License-Identifier: MIT

cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)

add_executable(heap-management-test
test_heap_management.cpp
)

target_include_directories(heap-management-test
PRIVATE
../inc
../../library_mocks/inc
)

target_link_libraries(heap-management-test
PRIVATE
fff
freertos-kernel-mock
heap-management
)

target_link_options(heap-management-test
PRIVATE
-Wl,--wrap=malloc
-Wl,--wrap=calloc
-Wl,--wrap=free
)

iot_reference_arm_corstone3xx_add_test(heap-management-test)
190 changes: 190 additions & 0 deletions components/freertos_kernel/integration/tests/test_heap_management.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/* Copyright 2025 Arm Limited and/or its affiliates
* <[email protected]>
* SPDX-License-Identifier: MIT
*/

#include "gtest/gtest.h"
#include <stdint.h>

extern "C" {
#include "heap_management.h"
#include "alloc_fakes.h"
}

class TestHeapManagement : public ::testing::Test {
public:
TestHeapManagement()
{
RESET_FAKE( test_malloc );
RESET_FAKE( test_calloc );
RESET_FAKE( test_free );
}
};

TEST_F( TestHeapManagement, calls_malloc_and_returns_same_pointer )
{
static uint8_t dummy[ 32 ];

test_malloc_fake.return_val = dummy;
void * allocated_ptr = pvPortMalloc( 32 );
ASSERT_EQ( allocated_ptr, static_cast<void *>( dummy ) );

EXPECT_EQ( test_malloc_fake.call_count, 1 );
EXPECT_EQ( test_malloc_fake.arg0_val, static_cast<size_t>( 32 ) );
}

TEST_F( TestHeapManagement, calling_malloc_with_size_zero_may_return_null )
{
test_malloc_fake.return_val = nullptr;
void * allocated_ptr = pvPortMalloc( 0 );
ASSERT_EQ( allocated_ptr, nullptr );

EXPECT_EQ( test_malloc_fake.call_count, 1 );
EXPECT_EQ( test_malloc_fake.arg0_val, static_cast<size_t>( 0 ) );
}

TEST_F( TestHeapManagement, calling_malloc_with_size_zero_may_return_pointer )
{
static uint8_t dummy[ 1 ];

test_malloc_fake.return_val = dummy;
void * allocated_ptr = pvPortMalloc( 0 );
ASSERT_EQ( allocated_ptr, static_cast<void *>( dummy ) );

EXPECT_EQ( test_malloc_fake.call_count, 1 );
EXPECT_EQ( test_malloc_fake.arg0_val, static_cast<size_t>( 0 ) );
}

TEST_F( TestHeapManagement, returns_null_when_malloc_fails )
{
test_malloc_fake.return_val = nullptr;
void * allocated_ptr = pvPortMalloc( 64 );
ASSERT_EQ( allocated_ptr, nullptr );

EXPECT_EQ( test_malloc_fake.call_count, 1 );
EXPECT_EQ( test_malloc_fake.arg0_val, static_cast<size_t>( 64 ) );
}

TEST_F( TestHeapManagement, calls_free_with_same_pointer )
{
static uint8_t dummy[ 16 ];
void * allocated_ptr = static_cast<void *>( dummy );

vPortFree( allocated_ptr );

EXPECT_EQ( test_free_fake.call_count, 1 );
EXPECT_EQ( test_free_fake.arg0_val, allocated_ptr );
}

TEST_F( TestHeapManagement, calls_free_with_null )
{
vPortFree( nullptr );
EXPECT_EQ( test_free_fake.call_count, 1 );
EXPECT_EQ( test_free_fake.arg0_val, nullptr );
}

TEST_F( TestHeapManagement, calls_calloc_and_returns_same_pointer )
{
static uint64_t dummy[ 4 ];

test_calloc_fake.return_val = dummy;
void * allocated_ptr = pvPortCalloc( 4, 8 );
ASSERT_EQ( allocated_ptr, static_cast<void *>( dummy ) );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 4 );
EXPECT_EQ( test_calloc_fake.arg1_val, 8 );
}

TEST_F( TestHeapManagement, calling_calloc_with_num_zero_may_return_null )
{
test_calloc_fake.return_val = nullptr;
void * allocated_ptr = pvPortCalloc( 0, 8 );
ASSERT_EQ( allocated_ptr, nullptr );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 0 );
EXPECT_EQ( test_calloc_fake.arg1_val, 8 );
}

TEST_F( TestHeapManagement, calling_calloc_with_num_zero_may_return_pointer )
{
static uint8_t dummy[ 1 ];

test_calloc_fake.return_val = dummy;
void * allocated_ptr = pvPortCalloc( 0, 8 );
ASSERT_EQ( allocated_ptr, static_cast<void *>( dummy ) );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 0 );
EXPECT_EQ( test_calloc_fake.arg1_val, 8 );
}

TEST_F( TestHeapManagement, calling_calloc_with_size_zero_may_return_null )
{
test_calloc_fake.return_val = nullptr;
void * allocated_ptr = pvPortCalloc( 8, 0 );
ASSERT_EQ( allocated_ptr, nullptr );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 8 );
EXPECT_EQ( test_calloc_fake.arg1_val, 0 );
}

TEST_F( TestHeapManagement, calling_calloc_with_size_zero_may_return_pointer )
{
static uint8_t dummy[ 1 ];

test_calloc_fake.return_val = dummy;
void * allocated_ptr = pvPortCalloc( 8, 0 );
ASSERT_EQ( allocated_ptr, static_cast<void *>( dummy ) );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 8 );
EXPECT_EQ( test_calloc_fake.arg1_val, 0 );
}

TEST_F( TestHeapManagement, calling_calloc_zero_zero_may_return_null )
{
test_calloc_fake.return_val = nullptr;
void * allocated_ptr = pvPortCalloc( 0, 0 );
ASSERT_EQ( allocated_ptr, nullptr );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 0 );
EXPECT_EQ( test_calloc_fake.arg1_val, 0 );
}

TEST_F( TestHeapManagement, calling_calloc_zero_zero_may_return_pointer )
{
static uint8_t dummy[ 1 ];

test_calloc_fake.return_val = dummy;
void * allocated_ptr = pvPortCalloc( 0, 0 );
ASSERT_EQ( allocated_ptr, static_cast<void *>( dummy ) );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 0 );
EXPECT_EQ( test_calloc_fake.arg1_val, 0 );
}

TEST_F( TestHeapManagement, returns_null_when_calloc_fails )
{
test_calloc_fake.return_val = nullptr;
void * allocated_ptr = pvPortCalloc( 16, 8 );
ASSERT_EQ( allocated_ptr, nullptr );

EXPECT_EQ( test_calloc_fake.call_count, 1 );
EXPECT_EQ( test_calloc_fake.arg0_val, 16 );
EXPECT_EQ( test_calloc_fake.arg1_val, 8 );
}

TEST_F( TestHeapManagement, xPortGetFreeHeapSize_returns_zero )
{
ASSERT_EQ( xPortGetFreeHeapSize(), 0 );
}

TEST_F( TestHeapManagement, xPortGetMinimumEverFreeHeapSize_returns_zero )
{
ASSERT_EQ( xPortGetMinimumEverFreeHeapSize(), 0 );
}
3 changes: 2 additions & 1 deletion components/freertos_kernel/library_mocks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2023-2024 Arm Limited and/or its affiliates
# Copyright 2023-2025 Arm Limited and/or its affiliates
# <[email protected]>
# SPDX-License-Identifier: MIT

Expand All @@ -7,6 +7,7 @@ add_library(freertos-kernel-mock
src/semphr.c
src/tasks.c
src/queue.c
src/alloc_fakes.c
)

target_include_directories(freertos-kernel-mock
Expand Down
16 changes: 16 additions & 0 deletions components/freertos_kernel/library_mocks/inc/alloc_fakes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* Copyright 2025 Arm Limited and/or its affiliates
* <[email protected]>
* SPDX-License-Identifier: MIT
*/

#ifndef ALLOC_FAKES_H
#define ALLOC_FAKES_H

#include <stddef.h>
#include "fff.h"

DECLARE_FAKE_VALUE_FUNC( void *, test_malloc, size_t );
DECLARE_FAKE_VALUE_FUNC( void *, test_calloc, size_t, size_t );
DECLARE_FAKE_VOID_FUNC( test_free, void * );

#endif /* ALLOC_FAKES_H*/
Loading