]> git.sur5r.net Git - freertos/blob - FreeRTOS/Source/portable/GCC/ARM_CM33/secure/secure_heap.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS / Source / portable / GCC / ARM_CM33 / secure / secure_heap.c
1 /*\r
2  * FreeRTOS Kernel V10.3.0\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  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /* Standard includes. */\r
29 #include <stdint.h>\r
30 \r
31 /* Secure context heap includes. */\r
32 #include "secure_heap.h"\r
33 \r
34 /* Secure port macros. */\r
35 #include "secure_port_macros.h"\r
36 \r
37 /**\r
38  * @brief Total heap size.\r
39  */\r
40 #define secureconfigTOTAL_HEAP_SIZE             ( ( ( size_t ) ( 10 * 1024 ) ) )\r
41 \r
42 /* No test marker by default. */\r
43 #ifndef mtCOVERAGE_TEST_MARKER\r
44         #define mtCOVERAGE_TEST_MARKER()\r
45 #endif\r
46 \r
47 /* No tracing by default. */\r
48 #ifndef traceMALLOC\r
49         #define traceMALLOC( pvReturn, xWantedSize )\r
50 #endif\r
51 \r
52 /* No tracing by default. */\r
53 #ifndef traceFREE\r
54         #define traceFREE( pv, xBlockSize )\r
55 #endif\r
56 \r
57 /* Block sizes must not get too small. */\r
58 #define secureheapMINIMUM_BLOCK_SIZE    ( ( size_t ) ( xHeapStructSize << 1 ) )\r
59 \r
60 /* Assumes 8bit bytes! */\r
61 #define secureheapBITS_PER_BYTE                 ( ( size_t ) 8 )\r
62 /*-----------------------------------------------------------*/\r
63 \r
64 /* Allocate the memory for the heap. */\r
65 #if( configAPPLICATION_ALLOCATED_HEAP == 1 )\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         if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )\r
195         {\r
196                 pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;\r
197                 pxBlockToInsert = pxIterator;\r
198         }\r
199         else\r
200         {\r
201                 mtCOVERAGE_TEST_MARKER();\r
202         }\r
203 \r
204         /* Do the block being inserted, and the block it is being inserted before\r
205          * make a contiguous block of memory? */\r
206         puc = ( uint8_t * ) pxBlockToInsert;\r
207         if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )\r
208         {\r
209                 if( pxIterator->pxNextFreeBlock != pxEnd )\r
210                 {\r
211                         /* Form one big block from the two blocks. */\r
212                         pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;\r
213                         pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;\r
214                 }\r
215                 else\r
216                 {\r
217                         pxBlockToInsert->pxNextFreeBlock = pxEnd;\r
218                 }\r
219         }\r
220         else\r
221         {\r
222                 pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;\r
223         }\r
224 \r
225         /* If the block being inserted plugged a gab, so was merged with the block\r
226          * before and the block after, then it's pxNextFreeBlock pointer will have\r
227          * already been set, and should not be set here as that would make it point\r
228          * to itself. */\r
229         if( pxIterator != pxBlockToInsert )\r
230         {\r
231                 pxIterator->pxNextFreeBlock = pxBlockToInsert;\r
232         }\r
233         else\r
234         {\r
235                 mtCOVERAGE_TEST_MARKER();\r
236         }\r
237 }\r
238 /*-----------------------------------------------------------*/\r
239 \r
240 void *pvPortMalloc( size_t xWantedSize )\r
241 {\r
242 BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;\r
243 void *pvReturn = NULL;\r
244 \r
245         /* If this is the first call to malloc then the heap will require\r
246          * initialisation to setup the list of free blocks. */\r
247         if( pxEnd == NULL )\r
248         {\r
249                 prvHeapInit();\r
250         }\r
251         else\r
252         {\r
253                 mtCOVERAGE_TEST_MARKER();\r
254         }\r
255 \r
256         /* Check the requested block size is not so large that the top bit is set.\r
257          * The top bit of the block size member of the BlockLink_t structure is used\r
258          * to determine who owns the block - the application or the kernel, so it\r
259          * must be free. */\r
260         if( ( xWantedSize & xBlockAllocatedBit ) == 0 )\r
261         {\r
262                 /* The wanted size is increased so it can contain a BlockLink_t\r
263                  * structure in addition to the requested amount of bytes. */\r
264                 if( xWantedSize > 0 )\r
265                 {\r
266                         xWantedSize += xHeapStructSize;\r
267 \r
268                         /* Ensure that blocks are always aligned to the required number of\r
269                          * bytes. */\r
270                         if( ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) != 0x00 )\r
271                         {\r
272                                 /* Byte alignment required. */\r
273                                 xWantedSize += ( secureportBYTE_ALIGNMENT - ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) );\r
274                                 secureportASSERT( ( xWantedSize & secureportBYTE_ALIGNMENT_MASK ) == 0 );\r
275                         }\r
276                         else\r
277                         {\r
278                                 mtCOVERAGE_TEST_MARKER();\r
279                         }\r
280                 }\r
281                 else\r
282                 {\r
283                         mtCOVERAGE_TEST_MARKER();\r
284                 }\r
285 \r
286                 if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )\r
287                 {\r
288                         /* Traverse the list from the start (lowest address) block until\r
289                          * one of adequate size is found. */\r
290                         pxPreviousBlock = &xStart;\r
291                         pxBlock = xStart.pxNextFreeBlock;\r
292                         while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )\r
293                         {\r
294                                 pxPreviousBlock = pxBlock;\r
295                                 pxBlock = pxBlock->pxNextFreeBlock;\r
296                         }\r
297 \r
298                         /* If the end marker was reached then a block of adequate size was\r
299                          * not found. */\r
300                         if( pxBlock != pxEnd )\r
301                         {\r
302                                 /* Return the memory space pointed to - jumping over the\r
303                                  * BlockLink_t structure at its start. */\r
304                                 pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );\r
305 \r
306                                 /* This block is being returned for use so must be taken out\r
307                                  * of the list of free blocks. */\r
308                                 pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
309 \r
310                                 /* If the block is larger than required it can be split into\r
311                                  * two. */\r
312                                 if( ( pxBlock->xBlockSize - xWantedSize ) > secureheapMINIMUM_BLOCK_SIZE )\r
313                                 {\r
314                                         /* This block is to be split into two.  Create a new\r
315                                          * block following the number of bytes requested. The void\r
316                                          * cast is used to prevent byte alignment warnings from the\r
317                                          * compiler. */\r
318                                         pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );\r
319                                         secureportASSERT( ( ( ( size_t ) pxNewBlockLink ) & secureportBYTE_ALIGNMENT_MASK ) == 0 );\r
320 \r
321                                         /* Calculate the sizes of two blocks split from the single\r
322                                          * block. */\r
323                                         pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
324                                         pxBlock->xBlockSize = xWantedSize;\r
325 \r
326                                         /* Insert the new block into the list of free blocks. */\r
327                                         prvInsertBlockIntoFreeList( pxNewBlockLink );\r
328                                 }\r
329                                 else\r
330                                 {\r
331                                         mtCOVERAGE_TEST_MARKER();\r
332                                 }\r
333 \r
334                                 xFreeBytesRemaining -= pxBlock->xBlockSize;\r
335 \r
336                                 if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )\r
337                                 {\r
338                                         xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;\r
339                                 }\r
340                                 else\r
341                                 {\r
342                                         mtCOVERAGE_TEST_MARKER();\r
343                                 }\r
344 \r
345                                 /* The block is being returned - it is allocated and owned by\r
346                                  * the application and has no "next" block. */\r
347                                 pxBlock->xBlockSize |= xBlockAllocatedBit;\r
348                                 pxBlock->pxNextFreeBlock = NULL;\r
349                         }\r
350                         else\r
351                         {\r
352                                 mtCOVERAGE_TEST_MARKER();\r
353                         }\r
354                 }\r
355                 else\r
356                 {\r
357                         mtCOVERAGE_TEST_MARKER();\r
358                 }\r
359         }\r
360         else\r
361         {\r
362                 mtCOVERAGE_TEST_MARKER();\r
363         }\r
364 \r
365         traceMALLOC( pvReturn, xWantedSize );\r
366 \r
367         #if( secureconfigUSE_MALLOC_FAILED_HOOK == 1 )\r
368         {\r
369                 if( pvReturn == NULL )\r
370                 {\r
371                         extern void vApplicationMallocFailedHook( void );\r
372                         vApplicationMallocFailedHook();\r
373                 }\r
374                 else\r
375                 {\r
376                         mtCOVERAGE_TEST_MARKER();\r
377                 }\r
378         }\r
379         #endif\r
380 \r
381         secureportASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) secureportBYTE_ALIGNMENT_MASK ) == 0 );\r
382         return pvReturn;\r
383 }\r
384 /*-----------------------------------------------------------*/\r
385 \r
386 void vPortFree( void *pv )\r
387 {\r
388 uint8_t *puc = ( uint8_t * ) pv;\r
389 BlockLink_t *pxLink;\r
390 \r
391         if( pv != NULL )\r
392         {\r
393                 /* The memory being freed will have an BlockLink_t structure immediately\r
394                  * before it. */\r
395                 puc -= xHeapStructSize;\r
396 \r
397                 /* This casting is to keep the compiler from issuing warnings. */\r
398                 pxLink = ( void * ) puc;\r
399 \r
400                 /* Check the block is actually allocated. */\r
401                 secureportASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );\r
402                 secureportASSERT( pxLink->pxNextFreeBlock == NULL );\r
403 \r
404                 if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )\r
405                 {\r
406                         if( pxLink->pxNextFreeBlock == NULL )\r
407                         {\r
408                                 /* The block is being returned to the heap - it is no longer\r
409                                  * allocated. */\r
410                                 pxLink->xBlockSize &= ~xBlockAllocatedBit;\r
411 \r
412                                 secureportDISABLE_NON_SECURE_INTERRUPTS();\r
413                                 {\r
414                                         /* Add this block to the list of free blocks. */\r
415                                         xFreeBytesRemaining += pxLink->xBlockSize;\r
416                                         traceFREE( pv, pxLink->xBlockSize );\r
417                                         prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );\r
418                                 }\r
419                                 secureportENABLE_NON_SECURE_INTERRUPTS();\r
420                         }\r
421                         else\r
422                         {\r
423                                 mtCOVERAGE_TEST_MARKER();\r
424                         }\r
425                 }\r
426                 else\r
427                 {\r
428                         mtCOVERAGE_TEST_MARKER();\r
429                 }\r
430         }\r
431 }\r
432 /*-----------------------------------------------------------*/\r
433 \r
434 size_t xPortGetFreeHeapSize( void )\r
435 {\r
436         return xFreeBytesRemaining;\r
437 }\r
438 /*-----------------------------------------------------------*/\r
439 \r
440 size_t xPortGetMinimumEverFreeHeapSize( void )\r
441 {\r
442         return xMinimumEverFreeBytesRemaining;\r
443 }\r
444 /*-----------------------------------------------------------*/\r
445 \r
446 void vPortInitialiseBlocks( void )\r
447 {\r
448         /* This just exists to keep the linker quiet. */\r
449 }\r
450 /*-----------------------------------------------------------*/\r