Newer
Older
mbed-os / platform / CThunkBase.cpp
@Martin Kojtal Martin Kojtal on 28 Nov 2018 4 KB platform: add spdx license
/* mbed Microcontroller Library
 * Copyright (c) 2018-2018 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "platform/platform.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_assert.h"
#include "platform/mbed_error.h"


#include "CThunkBase.h"

MBED_STATIC_ASSERT(MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX < 256, "MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX must be less than 256");
MBED_STATIC_ASSERT(MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX > 0, "MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX must be greater than 0");

#define ENABLE_N(N) ((MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX & N) ? 1 : 0)

#define START_128   0
#define START_64    (START_128 + ENABLE_N(128) * 128)
#define START_32    (START_64  + ENABLE_N(64)  * 64)
#define START_16    (START_32  + ENABLE_N(32)  * 32)
#define START_8     (START_16  + ENABLE_N(16)  * 16)
#define START_4     (START_8   + ENABLE_N(8)   * 8)
#define START_2     (START_4   + ENABLE_N(4)   * 4)
#define START_1     (START_2   + ENABLE_N(2)   * 2)

#define DECLARE_THUNK128(start) \
    DECLARE_THUNK64(start),     \
    DECLARE_THUNK64(start + 64)
#define DECLARE_THUNK64(start) \
    DECLARE_THUNK32(start),     \
    DECLARE_THUNK32(start + 32)
#define DECLARE_THUNK32(start) \
    DECLARE_THUNK16(start),     \
    DECLARE_THUNK16(start + 16)
#define DECLARE_THUNK16(start) \
    DECLARE_THUNK8(start),      \
    DECLARE_THUNK8(start + 8)
#define DECLARE_THUNK8(start)  \
    DECLARE_THUNK4(start),      \
    DECLARE_THUNK4(start + 4)
#define DECLARE_THUNK4(start)  \
    DECLARE_THUNK2(start),      \
    DECLARE_THUNK2(start + 2)
#define DECLARE_THUNK2(start)  \
    DECLARE_THUNK1(start),       \
    DECLARE_THUNK1(start + 1)
#define DECLARE_THUNK1(index)  &CThunkBase::thunk_entry<index>

const CThunkEntry CThunkBase::_thunk_table[MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX] = {
#if ENABLE_N(128)
    DECLARE_THUNK128(START_128),
#endif
#if ENABLE_N(64)
    DECLARE_THUNK64(START_64),
#endif
#if ENABLE_N(32)
    DECLARE_THUNK32(START_32),
#endif
#if ENABLE_N(16)
    DECLARE_THUNK16(START_16),
#endif
#if ENABLE_N(8)
    DECLARE_THUNK8(START_8),
#endif
#if ENABLE_N(4)
    DECLARE_THUNK4(START_4),
#endif
#if ENABLE_N(2)
    DECLARE_THUNK2(START_2),
#endif
#if ENABLE_N(1)
    DECLARE_THUNK1(START_1)
#endif
};

CThunkBase *CThunkBase::_thunk_storage[MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX];

CThunkBase::CthunkFree CThunkBase::_cthunk_free_real = NULL;

CThunkEntry CThunkBase::cthunk_alloc(CThunkBase *cthunk)
{
    // Atomically allocate one entry
    core_util_critical_section_enter();
    CThunkEntry entry = NULL;
    for (int i = 0; i < MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX; i++) {
        if (_thunk_storage[i] == NULL) {
            _thunk_storage[i] = cthunk;
            entry = _thunk_table[i];
            break;
        }
    }
    core_util_critical_section_exit();

    if (entry == NULL) {
        MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_RESOURCES), "Ran out of CThunk entries. Increase MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX to fix this error");
    }

    // Set function pointer on first use. This allows _thunk_table
    // and _thunk_storage to get removed by the linker if
    // cthunk_alloc is never used.
    _cthunk_free_real = &cthunk_free_real;

    return entry;
}

void CThunkBase::cthunk_free(CThunkEntry item)
{
    if (_cthunk_free_real) {
        _cthunk_free_real(item);
    }
}

void CThunkBase::cthunk_free_real(CThunkEntry item)
{
    bool found = false;

    core_util_critical_section_enter();
    for (int i = 0; i < MBED_CONF_PLATFORM_CTHUNK_COUNT_MAX; i++) {
        if (_thunk_table[i] == item) {
            _thunk_storage[i] = NULL;
            found = true;
            break;
        }
    }
    core_util_critical_section_exit();

    if (!found) {
        MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT), "Tried to free invalid CThunkEntry");
    }

}