1 /*
2 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #include <inttypes.h>
8 #include <stdbool.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include "thread.h"
13 #include "psa/client.h"
14 #include "psa/service.h"
15 #include "internal_status_code.h"
16 #include "cmsis_compiler.h"
17 #include "utilities.h"
18 #include "lists.h"
19 #include "tfm_pools.h"
20
21 /* Magic value that indicates a pool chunk has been allocated */
22 #define POOL_MAGIC_ALLOCATED UINT32_C(0xF0F0CCAA)
23
tfm_pool_init(struct tfm_pool_instance_t * pool,size_t poolsz,size_t chunksz,size_t num)24 psa_status_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
25 size_t chunksz, size_t num)
26 {
27 struct tfm_pool_chunk_t *pchunk;
28 size_t i;
29
30 if (!pool || (num == 0)) {
31 return SPM_ERROR_BAD_PARAMETERS;
32 }
33
34 /* Ensure buffer is large enough */
35 if (poolsz != (((chunksz + sizeof(struct tfm_pool_chunk_t)) * num) +
36 sizeof(struct tfm_pool_instance_t))) {
37 return SPM_ERROR_BAD_PARAMETERS;
38 }
39
40 /* Buffer should be BSS cleared but clear it again */
41 spm_memset(pool, 0, poolsz);
42
43 /* Chain pool chunks */
44 UNI_LIST_INIT_NODE(pool, next);
45
46 pchunk = (struct tfm_pool_chunk_t *)pool->chunks;
47 for (i = 0; i < num; i++) {
48 UNI_LIST_INSERT_AFTER(pool, pchunk, next);
49 pchunk = (struct tfm_pool_chunk_t *)&pchunk->data[chunksz];
50 }
51
52 /* Prepare instance and insert to pool list */
53 pool->chunksz = chunksz;
54 pool->pool_sz = poolsz;
55
56 return PSA_SUCCESS;
57 }
58
tfm_pool_alloc(struct tfm_pool_instance_t * pool)59 void *tfm_pool_alloc(struct tfm_pool_instance_t *pool)
60 {
61 struct tfm_pool_chunk_t *node;
62
63 if (!pool) {
64 return NULL;
65 }
66
67 if (UNI_LIST_IS_EMPTY(pool, next)) {
68 return NULL;
69 }
70
71 node = UNI_LIST_NEXT_NODE(pool, next);
72 UNI_LIST_REMOVE_NODE(pool, node, next);
73
74 node->magic = POOL_MAGIC_ALLOCATED;
75
76 return &(node->data);
77 }
78
tfm_pool_free(struct tfm_pool_instance_t * pool,void * ptr)79 void tfm_pool_free(struct tfm_pool_instance_t *pool, void *ptr)
80 {
81 struct tfm_pool_chunk_t *pchunk;
82
83 /* In debug builds, trap invalid frees. */
84 assert(is_valid_chunk_data_in_pool(pool, ptr));
85
86 pchunk = TO_CONTAINER(ptr, struct tfm_pool_chunk_t, data);
87
88 pchunk->magic = 0;
89
90 UNI_LIST_INSERT_AFTER(pool, pchunk, next);
91
92 /* In debug builds, overwrite the data to catch use-after-free bugs. */
93 #ifndef NDEBUG
94 spm_memset(pchunk->data, 0xFF, pool->chunksz);
95 #endif
96 }
97
is_valid_chunk_data_in_pool(struct tfm_pool_instance_t * pool,uint8_t * data)98 bool is_valid_chunk_data_in_pool(struct tfm_pool_instance_t *pool,
99 uint8_t *data)
100 {
101 const uintptr_t chunks_start = (uintptr_t)(pool->chunks);
102 const size_t chunks_offset = (uintptr_t)data - chunks_start;
103 struct tfm_pool_chunk_t *pchunk;
104
105 /* Check that the message was allocated from the pool. */
106 if (((uintptr_t)data < chunks_start) || (chunks_offset >= pool->pool_sz)) {
107 return false;
108 }
109
110 if ((chunks_offset % (pool->chunksz + sizeof(struct tfm_pool_chunk_t)))
111 != offsetof(struct tfm_pool_chunk_t, data)) {
112 return false;
113 }
114
115 pchunk = TO_CONTAINER(data, struct tfm_pool_chunk_t, data);
116
117 if (pchunk->magic != POOL_MAGIC_ALLOCATED) {
118 return false;
119 }
120
121 return true;
122 }
123