]> begriffs open source - freertos/blob - portable/IAR/ARM_CM33/secure/secure_heap.c
Style: uncrusitfy
[freertos] / portable / IAR / ARM_CM33 / secure / secure_heap.c
1 /*\r
2  * FreeRTOS Kernel V10.3.1\r
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  */\r
26 \r
27 /* Standard includes. */\r
28 #include <stdint.h>\r
29 \r
30 /* Secure context heap includes. */\r
31 #include "secure_heap.h"\r
32 \r
33 /* Secure port macros. */\r
34 #include "secure_port_macros.h"\r
35 \r
36 /**\r
37  * @brief Total heap size.\r
38  */\r
39 #define secureconfigTOTAL_HEAP_SIZE    ( ( ( size_t ) ( 10 * 1024 ) ) )\r
40 \r
41 /* No test marker by default. */\r
42 #ifndef mtCOVERAGE_TEST_MARKER\r
43     #define mtCOVERAGE_TEST_MARKER()\r
44 #endif\r
45 \r
46 /* No tracing by default. */\r
47 #ifndef traceMALLOC\r
48     #define traceMALLOC( pvReturn, xWantedSize )\r
49 #endif\r
50 \r
51 /* No tracing by default. */\r
52 #ifndef traceFREE\r
53     #define traceFREE( pv, xBlockSize )\r
54 #endif\r
55 \r
56 /* Block sizes must not get too small. */\r
57 #define secureheapMINIMUM_BLOCK_SIZE    ( ( size_t ) ( xHeapStructSize << 1 ) )\r
58 \r
59 /* Assumes 8bit bytes! */\r
60 #define secureheapBITS_PER_BYTE         ( ( size_t ) 8 )\r
61 /*-----------------------------------------------------------*/\r
62 \r
63 /* Allocate the memory for the heap. */\r
64 #if ( configAPPLICATION_ALLOCATED_HEAP == 1 )\r
65 \r
66 /* The application writer has already defined the array used for the RTOS\r
67 * heap - probably so it can be placed in a special segment or address. */\r
68     extern uint8_t ucHeap[ secureconfigTOTAL_HEAP_SIZE ];\r
69 #else /* configAPPLICATION_ALLOCATED_HEAP */\r
70     static uint8_t ucHeap[ secureconfigTOTAL_HEAP_SIZE ];\r
71 #endif /* configAPPLICATION_ALLOCATED_HEAP */\r
72 \r
73 /**\r
74  * @brief The linked list structure.\r
75  *\r
76  * This is used to link free blocks in order of their memory address.\r
77  */\r
78 typedef struct A_BLOCK_LINK\r
79 {\r
80     struct A_BLOCK_LINK * pxNextFreeBlock; /**< The next free block in the list. */\r
81     size_t xBlockSize;                     /**< The size of the free block. */\r
82 } BlockLink_t;\r
83 /*-----------------------------------------------------------*/\r
84 \r
85 /**\r
86  * @brief Called automatically to setup the required heap structures the first\r
87  * time pvPortMalloc() is called.\r
88  */\r
89 static void prvHeapInit( void );\r
90 \r
91 /**\r
92  * @brief Inserts a block of memory that is being freed into the correct\r
93  * position in the list of free memory blocks.\r
94  *\r
95  * The block being freed will be merged with the block in front it and/or the\r
96  * block behind it if the memory blocks are adjacent to each other.\r
97  *\r
98  * @param[in] pxBlockToInsert The block being freed.\r
99  */\r
100 static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert );\r
101 /*-----------------------------------------------------------*/\r
102 \r
103 /**\r
104  * @brief The size of the structure placed at the beginning of each allocated\r
105  * memory block must by correctly byte aligned.\r
106  */\r
107 static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( secureportBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) secureportBYTE_ALIGNMENT_MASK );\r
108 \r
109 /**\r
110  * @brief Create a couple of list links to mark the start and end of the list.\r
111  */\r
112 static BlockLink_t xStart, * pxEnd = NULL;\r
113 \r
114 /**\r
115  * @brief Keeps track of the number of free bytes remaining, but says nothing\r
116  * about fragmentation.\r
117  */\r
118 static size_t xFreeBytesRemaining            = 0U;\r
119 static size_t xMinimumEverFreeBytesRemaining = 0U;\r
120 \r
121 /**\r
122  * @brief Gets set to the top bit of an size_t type.\r
123  *\r
124  * When this bit in the xBlockSize member of an BlockLink_t structure is set\r
125  * then the block belongs to the application. When the bit is free the block is\r
126  * still part of the free heap space.\r
127  */\r
128 static size_t xBlockAllocatedBit             = 0;\r
129 /*-----------------------------------------------------------*/\r
130 \r
131 static void prvHeapInit( void )\r
132 {\r
133     BlockLink_t * pxFirstFreeBlock;\r
134     uint8_t *     pucAlignedHeap;\r
135     size_t        uxAddress;\r
136     size_t        xTotalHeapSize = secureconfigTOTAL_HEAP_SIZE;\r
137 \r
138     /* Ensure the heap starts on a correctly aligned boundary. */\r
139     uxAddress                         = ( size_t ) ucHeap;\r
140 \r
141     if( ( uxAddress & secureportBYTE_ALIGNMENT_MASK ) != 0 )\r
142     {\r
143         uxAddress      += ( secureportBYTE_ALIGNMENT - 1 );\r
144         uxAddress      &= ~( ( size_t ) secureportBYTE_ALIGNMENT_MASK );\r
145         xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;\r
146     }\r
147 \r
148     pucAlignedHeap                    = ( uint8_t * ) uxAddress;\r
149 \r
150     /* xStart is used to hold a pointer to the first item in the list of free\r
151      * blocks.  The void cast is used to prevent compiler warnings. */\r
152     xStart.pxNextFreeBlock            = ( void * ) pucAlignedHeap;\r
153     xStart.xBlockSize                 = ( size_t ) 0;\r
154 \r
155     /* pxEnd is used to mark the end of the list of free blocks and is inserted\r
156      * at the end of the heap space. */\r
157     uxAddress                         = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;\r
158     uxAddress                        -= xHeapStructSize;\r
159     uxAddress                        &= ~( ( size_t ) secureportBYTE_ALIGNMENT_MASK );\r
160     pxEnd                             = ( void * ) uxAddress;\r
161     pxEnd->xBlockSize                 = 0;\r
162     pxEnd->pxNextFreeBlock            = NULL;\r
163 \r
164     /* To start with there is a single free block that is sized to take up the\r
165      * entire heap space, minus the space taken by pxEnd. */\r
166     pxFirstFreeBlock                  = ( void * ) pucAlignedHeap;\r
167     pxFirstFreeBlock->xBlockSize      = uxAddress - ( size_t ) pxFirstFreeBlock;\r
168     pxFirstFreeBlock->pxNextFreeBlock = pxEnd;\r
169 \r
170     /* Only one block exists - and it covers the entire usable heap space. */\r
171     xMinimumEverFreeBytesRemaining    = pxFirstFreeBlock->xBlockSize;\r
172     xFreeBytesRemaining               = pxFirstFreeBlock->xBlockSize;\r
173 \r
174     /* Work out the position of the top bit in a size_t variable. */\r
175     xBlockAllocatedBit                = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * secureheapBITS_PER_BYTE ) - 1 );\r
176 }\r
177 /*-----------------------------------------------------------*/\r
178 \r
179 static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert )\r
180 {\r
181     BlockLink_t * pxIterator;\r
182     uint8_t *     puc;\r
183 \r
184     /* Iterate through the list until a block is found that has a higher address\r
185      * than the block being inserted. */\r
186     for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )\r
187     {\r
188         /* Nothing to do here, just iterate to the right position. */\r
189     }\r
190 \r
191     /* Do the block being inserted, and the block it is being inserted after\r
192      * make a contiguous block of memory? */\r
193     puc = ( uint8_t * ) pxIterator;\r
194 \r
195     if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )\r
196     {\r
197         pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;\r
198         pxBlockToInsert         = pxIterator;\r
199     }\r
200     else\r
201     {\r
202         mtCOVERAGE_TEST_MARKER();\r
203     }\r
204 \r
205     /* Do the block being inserted, and the block it is being inserted before\r
206      * make a contiguous block of memory? */\r
207     puc = ( uint8_t * ) pxBlockToInsert;\r
208 \r
209     if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )\r
210     {\r
211         if( pxIterator->pxNextFreeBlock != pxEnd )\r
212         {\r
213             /* Form one big block from the two blocks. */\r
214             pxBlockToInsert->xBlockSize     += pxIterator->pxNextFreeBlock->xBlockSize;\r
215             pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;\r
216         }\r
217         else\r
218         {\r
219             pxBlockToInsert->pxNextFreeBlock = pxEnd;\r
220         }\r
221     }\r
222     else\r
223     {\r
224         pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;\r
225     }\r
226 \r
227     /* If the block being inserted plugged a gab, so was merged with the block\r
228      * before and the block after, then it's pxNextFreeBlock pointer will have\r
229      * already been set, and should not be set here as that would make it point\r
230      * to itself. */\r
231     if( pxIterator != pxBlockToInsert )\r
232     {\r
233         pxIterator->pxNextFreeBlock = pxBlockToInsert;\r
234     }\r
235     else\r
236     {\r
237         mtCOVERAGE_TEST_MARKER();\r
238     }\r
239 }\r
240 /*-----------------------------------------------------------*/\r
241 \r
242 void * pvPortMalloc( size_t xWantedSize )\r
243 {\r
244     BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;\r
245     void *        pvReturn = NULL;\r
246 \r
247     /* If this is the first call to malloc then the heap will require\r
248      * initialisation to setup the list of free blocks. */\r
249     if( pxEnd == NULL )\r
250     {\r
251         prvHeapInit();\r
252     }\r
253     else\r
254     {\r
255         mtCOVERAGE_TEST_MARKER();\r
256     }\r
257 \r
258     /* Check the requested block size is not so large that the top bit is set.\r
259      * The top bit of the block size member of the BlockLink_t structure is used\r
260      * to determine who owns the block - the application or the kernel, so it\r
261      * must be free. */\r
262     if( ( xWantedSize & xBlockAllocatedBit ) == 0 )\r
263     {\r
264         /* The wanted size is increased so it can contain a BlockLink_t\r
265          * structure in addition to the requested amount of bytes. */\r
266         if( xWantedSize > 0 )\r
267         {\r
268             xWantedSize += xHeapStructSize;\r
269 \r
270             /* Ensure that blocks are always aligned to the required number of\r
271              * bytes. */\r
272             if( ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) != 0x00 )\r
273             {\r
274                 /* Byte alignment required. */\r
275                 xWantedSize += ( secureportBYTE_ALIGNMENT - ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) );\r
276                 secureportASSERT( ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) == 0 );\r
277             }\r
278             else\r
279             {\r
280                 mtCOVERAGE_TEST_MARKER();\r
281             }\r
282         }\r
283         else\r
284         {\r
285             mtCOVERAGE_TEST_MARKER();\r
286         }\r
287 \r
288         if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )\r
289         {\r
290             /* Traverse the list from the start (lowest address) block until\r
291              * one of adequate size is found. */\r
292             pxPreviousBlock = &xStart;\r
293             pxBlock         = xStart.pxNextFreeBlock;\r
294 \r
295             while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )\r
296             {\r
297                 pxPreviousBlock = pxBlock;\r
298                 pxBlock         = pxBlock->pxNextFreeBlock;\r
299             }\r
300 \r
301             /* If the end marker was reached then a block of adequate size was\r
302              * not found. */\r
303             if( pxBlock != pxEnd )\r
304             {\r
305                 /* Return the memory space pointed to - jumping over the\r
306                  * BlockLink_t structure at its start. */\r
307                 pvReturn                         = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );\r
308 \r
309                 /* This block is being returned for use so must be taken out\r
310                  * of the list of free blocks. */\r
311                 pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
312 \r
313                 /* If the block is larger than required it can be split into\r
314                  * two. */\r
315                 if( ( pxBlock->xBlockSize - xWantedSize ) > secureheapMINIMUM_BLOCK_SIZE )\r
316                 {\r
317                     /* This block is to be split into two.  Create a new\r
318                      * block following the number of bytes requested. The void\r
319                      * cast is used to prevent byte alignment warnings from the\r
320                      * compiler. */\r
321                     pxNewBlockLink             = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );\r
322                     secureportASSERT( ( ( ( size_t ) pxNewBlockLink ) & secureportBYTE_ALIGNMENT_MASK ) == 0 );\r
323 \r
324                     /* Calculate the sizes of two blocks split from the single\r
325                      * block. */\r
326                     pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
327                     pxBlock->xBlockSize        = xWantedSize;\r
328 \r
329                     /* Insert the new block into the list of free blocks. */\r
330                     prvInsertBlockIntoFreeList( pxNewBlockLink );\r
331                 }\r
332                 else\r
333                 {\r
334                     mtCOVERAGE_TEST_MARKER();\r
335                 }\r
336 \r
337                 xFreeBytesRemaining             -= pxBlock->xBlockSize;\r
338 \r
339                 if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )\r
340                 {\r
341                     xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;\r
342                 }\r
343                 else\r
344                 {\r
345                     mtCOVERAGE_TEST_MARKER();\r
346                 }\r
347 \r
348                 /* The block is being returned - it is allocated and owned by\r
349                  * the application and has no "next" block. */\r
350                 pxBlock->xBlockSize             |= xBlockAllocatedBit;\r
351                 pxBlock->pxNextFreeBlock         = NULL;\r
352             }\r
353             else\r
354             {\r
355                 mtCOVERAGE_TEST_MARKER();\r
356             }\r
357         }\r
358         else\r
359         {\r
360             mtCOVERAGE_TEST_MARKER();\r
361         }\r
362     }\r
363     else\r
364     {\r
365         mtCOVERAGE_TEST_MARKER();\r
366     }\r
367 \r
368     traceMALLOC( pvReturn, xWantedSize );\r
369 \r
370     #if ( secureconfigUSE_MALLOC_FAILED_HOOK == 1 )\r
371         {\r
372             if( pvReturn == NULL )\r
373             {\r
374                 extern void vApplicationMallocFailedHook( void );\r
375                 vApplicationMallocFailedHook();\r
376             }\r
377             else\r
378             {\r
379                 mtCOVERAGE_TEST_MARKER();\r
380             }\r
381         }\r
382     #endif /* if ( secureconfigUSE_MALLOC_FAILED_HOOK == 1 ) */\r
383 \r
384     secureportASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) secureportBYTE_ALIGNMENT_MASK ) == 0 );\r
385     return pvReturn;\r
386 }\r
387 /*-----------------------------------------------------------*/\r
388 \r
389 void vPortFree( void * pv )\r
390 {\r
391     uint8_t *     puc = ( uint8_t * ) pv;\r
392     BlockLink_t * pxLink;\r
393 \r
394     if( pv != NULL )\r
395     {\r
396         /* The memory being freed will have an BlockLink_t structure immediately\r
397          * before it. */\r
398         puc   -= xHeapStructSize;\r
399 \r
400         /* This casting is to keep the compiler from issuing warnings. */\r
401         pxLink = ( void * ) puc;\r
402 \r
403         /* Check the block is actually allocated. */\r
404         secureportASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );\r
405         secureportASSERT( pxLink->pxNextFreeBlock == NULL );\r
406 \r
407         if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )\r
408         {\r
409             if( pxLink->pxNextFreeBlock == NULL )\r
410             {\r
411                 /* The block is being returned to the heap - it is no longer\r
412                  * allocated. */\r
413                 pxLink->xBlockSize &= ~xBlockAllocatedBit;\r
414 \r
415                 secureportDISABLE_NON_SECURE_INTERRUPTS();\r
416                 {\r
417                     /* Add this block to the list of free blocks. */\r
418                     xFreeBytesRemaining += pxLink->xBlockSize;\r
419                     traceFREE( pv, pxLink->xBlockSize );\r
420                     prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );\r
421                 }\r
422                 secureportENABLE_NON_SECURE_INTERRUPTS();\r
423             }\r
424             else\r
425             {\r
426                 mtCOVERAGE_TEST_MARKER();\r
427             }\r
428         }\r
429         else\r
430         {\r
431             mtCOVERAGE_TEST_MARKER();\r
432         }\r
433     }\r
434 }\r
435 /*-----------------------------------------------------------*/\r
436 \r
437 size_t xPortGetFreeHeapSize( void )\r
438 {\r
439     return xFreeBytesRemaining;\r
440 }\r
441 /*-----------------------------------------------------------*/\r
442 \r
443 size_t xPortGetMinimumEverFreeHeapSize( void )\r
444 {\r
445     return xMinimumEverFreeBytesRemaining;\r
446 }\r
447 /*-----------------------------------------------------------*/\r
448 \r
449 void vPortInitialiseBlocks( void )\r
450 {\r
451     /* This just exists to keep the linker quiet. */\r
452 }\r
453 /*-----------------------------------------------------------*/\r