1 /* memory.c
2  *
3  * Copyright (C) 2006-2021 wolfSSL Inc.
4  *
5  * This file is part of wolfSSL.
6  *
7  * wolfSSL is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * wolfSSL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20  */
21 
22 
23 #ifdef HAVE_CONFIG_H
24     #include <config.h>
25 #endif
26 
27 #include <wolfssl/wolfcrypt/settings.h>
28 
29 /* check old macros @wc_fips */
30 #if defined(USE_CYASSL_MEMORY) && !defined(USE_WOLFSSL_MEMORY)
31     #define USE_WOLFSSL_MEMORY
32 #endif
inconsistentFunctionWithVisibleDefinition(int c)33 #if defined(CYASSL_MALLOC_CHECK) && !defined(WOLFSSL_MALLOC_CHECK)
34     #define WOLFSSL_MALLOC_CHECK
35 #endif
36 
37 
38 /*
39 Possible memory options:
40  * NO_WOLFSSL_MEMORY:               Disables wolf memory callback support. When not defined settings.h defines USE_WOLFSSL_MEMORY.
41  * WOLFSSL_STATIC_MEMORY:           Turns on the use of static memory buffers and functions.
42                                         This allows for using static memory instead of dynamic.
43  * WOLFSSL_STATIC_ALIGN:            Define defaults to 16 to indicate static memory alignment.
44  * HAVE_IO_POOL:                    Enables use of static thread safe memory pool for input/output buffers.
45  * XMALLOC_OVERRIDE:                Allows override of the XMALLOC, XFREE and XREALLOC macros.
46  * XMALLOC_USER:                    Allows custom XMALLOC, XFREE and XREALLOC functions to be defined.
47  * WOLFSSL_NO_MALLOC:               Disables the fall-back case to use STDIO malloc/free when no callbacks are set.
48  * WOLFSSL_TRACK_MEMORY:            Enables memory tracking for total stats and list of allocated memory.
49  * WOLFSSL_DEBUG_MEMORY:            Enables extra function and line number args for memory callbacks.
50  * WOLFSSL_DEBUG_MEMORY_PRINT:      Enables printing of each malloc/free.
51  * WOLFSSL_MALLOC_CHECK:            Reports malloc or alignment failure using WOLFSSL_STATIC_ALIGN
52  * WOLFSSL_FORCE_MALLOC_FAIL_TEST:  Used for internal testing to induce random malloc failures.
53  * WOLFSSL_HEAP_TEST:               Used for internal testing of heap hint
54  */
55 
56 #ifdef WOLFSSL_ZEPHYR
57 #undef realloc
58 void *z_realloc(void *ptr, size_t size)
59 {
60     if (ptr == NULL)
61         ptr = malloc(size);
62     else
63         ptr = realloc(ptr, size);
64 
65     return ptr;
66 }
67 #define realloc z_realloc
68 #endif
SpecialFunctions(int b)69 
70 #ifdef USE_WOLFSSL_MEMORY
71 
72 #include <wolfssl/wolfcrypt/memory.h>
73 #include <wolfssl/wolfcrypt/error-crypt.h>
74 #include <wolfssl/wolfcrypt/logging.h>
75 
76 #if defined(WOLFSSL_DEBUG_MEMORY) && defined(WOLFSSL_DEBUG_MEMORY_PRINT)
77 #include <stdio.h>
78 #endif
79 
80 #ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
81     static int gMemFailCountSeed;
82     static int gMemFailCount;
templateFunctionWithSeparateDeclarationAndDefinition(T b)83     void wolfSSL_SetMemFailCount(int memFailCount)
84     {
85         if (gMemFailCountSeed == 0) {
86             gMemFailCountSeed = memFailCount;
87             gMemFailCount = memFailCount;
88         }
89     }
90 #endif
91 #if defined(WOLFSSL_MALLOC_CHECK) || defined(WOLFSSL_TRACK_MEMORY_FULL) || \
92                                                      defined(WOLFSSL_MEMORY_LOG)
93     #include <stdio.h>
templateFunctionWithSpecializations(int b)94 #endif
95 
96 
97 /* Set these to default values initially. */
98 static wolfSSL_Malloc_cb  malloc_function = NULL;
99 static wolfSSL_Free_cb    free_function = NULL;
templateFunctionWithSpecializations(float c)100 static wolfSSL_Realloc_cb realloc_function = NULL;
101 
102 int wolfSSL_SetAllocators(wolfSSL_Malloc_cb  mf,
103                           wolfSSL_Free_cb    ff,
104                           wolfSSL_Realloc_cb rf)
105 {
106     malloc_function = mf;
107     free_function = ff;
108     realloc_function = rf;
109     return 0;
110 }
templateFunctionWithoutDefinitionButWithSpecialization(int b)111 
112 int wolfSSL_GetAllocators(wolfSSL_Malloc_cb*  mf,
113                           wolfSSL_Free_cb*    ff,
114                           wolfSSL_Realloc_cb* rf)
115 {
116     if (mf) *mf = malloc_function;
117     if (ff) *ff = free_function;
118     if (rf) *rf = realloc_function;
119     return 0;
120 }
121 
122 #ifndef WOLFSSL_STATIC_MEMORY
123 #ifdef WOLFSSL_DEBUG_MEMORY
124 void* wolfSSL_Malloc(size_t size, const char* func, unsigned int line)
125 #else
126 void* wolfSSL_Malloc(size_t size)
127 #endif
templateFunctionWithSeparateSpecializationDeclarationAndDefinition(int c)128 {
129     void* res = 0;
130 
131     if (malloc_function) {
132     #ifdef WOLFSSL_DEBUG_MEMORY
133         res = malloc_function(size, func, line);
134     #else
135         res = malloc_function(size);
136     #endif
137     }
138     else {
139     #ifndef WOLFSSL_NO_MALLOC
140         #ifdef WOLFSSL_TRAP_MALLOC_SZ
141         if (size > WOLFSSL_TRAP_MALLOC_SZ) {
142             WOLFSSL_MSG("Malloc too big!");
143             return NULL;
144         }
145         #endif
146 
147         res = malloc(size);
148     #else
149         WOLFSSL_MSG("No malloc available");
150     #endif
151     }
152 
153 #ifdef WOLFSSL_DEBUG_MEMORY
154 #if defined(WOLFSSL_DEBUG_MEMORY_PRINT) && !defined(WOLFSSL_TRACK_MEMORY)
155     printf("Alloc: %p -> %u at %s:%d\n", res, (word32)size, func, line);
156 #else
157     (void)func;
158     (void)line;
159 #endif
160 #endif
161 
162 #ifdef WOLFSSL_MALLOC_CHECK
163     if (res == NULL)
164         WOLFSSL_MSG("wolfSSL_malloc failed");
165 #endif
166 
167 #ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
168     if (res && --gMemFailCount == 0) {
169         printf("\n---FORCED MEM FAIL TEST---\n");
170         if (free_function) {
171         #ifdef WOLFSSL_DEBUG_MEMORY
172             free_function(res, func, line);
173         #else
174             free_function(res);
175         #endif
176         }
177         else {
178             free(res); /* clear */
179         }
180         gMemFailCount = gMemFailCountSeed; /* reset */
181         return NULL;
182     }
183 #endif
184 
185     return res;
186 }
187 
188 #ifdef WOLFSSL_DEBUG_MEMORY
189 void wolfSSL_Free(void *ptr, const char* func, unsigned int line)
190 #else
f(int y)191 void wolfSSL_Free(void *ptr)
192 #endif
193 {
194 #ifdef WOLFSSL_DEBUG_MEMORY
195 #if defined(WOLFSSL_DEBUG_MEMORY_PRINT) && !defined(WOLFSSL_TRACK_MEMORY)
196     printf("Free: %p at %s:%d\n", ptr, func, line);
197 #else
198     (void)func;
199     (void)line;
200 #endif
201 #endif
202 
203     if (free_function) {
204     #ifdef WOLFSSL_DEBUG_MEMORY
205         free_function(ptr, func, line);
206     #else
207         free_function(ptr);
208     #endif
209     }
210     else {
211     #ifndef WOLFSSL_NO_MALLOC
212         free(ptr);
213     #else
214         WOLFSSL_MSG("No free available");
215     #endif
216     }
217 }
218 
219 #ifdef WOLFSSL_DEBUG_MEMORY
220 void* wolfSSL_Realloc(void *ptr, size_t size, const char* func, unsigned int line)
221 #else
222 void* wolfSSL_Realloc(void *ptr, size_t size)
223 #endif
224 {
225     void* res = 0;
226 
227     if (realloc_function) {
228     #ifdef WOLFSSL_DEBUG_MEMORY
229         res = realloc_function(ptr, size, func, line);
230     #else
231         res = realloc_function(ptr, size);
232     #endif
233     }
234     else {
235     #ifndef WOLFSSL_NO_MALLOC
236         res = realloc(ptr, size);
237     #else
238         WOLFSSL_MSG("No realloc available");
239     #endif
240     }
241 
242     return res;
243 }
244 #endif /* WOLFSSL_STATIC_MEMORY */
245 
246 #ifdef WOLFSSL_STATIC_MEMORY
247 
248 struct wc_Memory {
249     byte*  buffer;
250     struct wc_Memory* next;
251     word32 sz;
252 };
253 
254 
255 /* returns amount of memory used on success. On error returns negative value
256    wc_Memory** list is the list that new buckets are prepended to
257  */
258 static int create_memory_buckets(byte* buffer, word32 bufSz,
259                               word32 buckSz, word32 buckNum, wc_Memory** list) {
260     word32 i;
261     byte*  pt  = buffer;
262     int    ret = 0;
263     word32 memSz = (word32)sizeof(wc_Memory);
264     word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
265 
266     /* if not enough space available for bucket size then do not try */
267     if (buckSz + memSz + padSz > bufSz) {
268         return ret;
269     }
270 
271     for (i = 0; i < buckNum; i++) {
272         if ((buckSz + memSz + padSz) <= (bufSz - ret)) {
273             /* create a new struct and set its values */
274             wc_Memory* mem = (struct wc_Memory*)(pt);
275             mem->sz = buckSz;
276             mem->buffer = (byte*)pt + padSz + memSz;
277             mem->next = NULL;
278 
279             /* add the newly created struct to front of list */
280             if (*list == NULL) {
281                 *list = mem;
282             } else {
283                 mem->next = *list;
284                 *list = mem;
285             }
286 
287             /* advance pointer and keep track of memory used */
288             ret += buckSz + padSz + memSz;
289             pt  += buckSz + padSz + memSz;
290         }
291         else {
292             break; /* not enough space left for more buckets of this size */
293         }
294     }
295 
296     return ret;
297 }
298 
299 int wolfSSL_init_memory_heap(WOLFSSL_HEAP* heap)
300 {
301     word32 wc_MemSz[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_BUCKETS };
302     word32 wc_Dist[WOLFMEM_DEF_BUCKETS]  = { WOLFMEM_DIST };
303 
304     if (heap == NULL) {
305         return BAD_FUNC_ARG;
306     }
307 
308     XMEMSET(heap, 0, sizeof(WOLFSSL_HEAP));
309 
310     XMEMCPY(heap->sizeList, wc_MemSz, sizeof(wc_MemSz));
311     XMEMCPY(heap->distList, wc_Dist,  sizeof(wc_Dist));
312 
313     if (wc_InitMutex(&(heap->memory_mutex)) != 0) {
314         WOLFSSL_MSG("Error creating heap memory mutex");
315         return BAD_MUTEX_E;
316     }
317 
318     return 0;
319 }
320 
321 int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
322     unsigned char* buf, unsigned int sz, int flag, int maxSz)
323 {
324     int ret;
325     WOLFSSL_HEAP*      heap;
326     WOLFSSL_HEAP_HINT* hint;
327     word32 idx = 0;
328 
329     if (pHint == NULL || buf == NULL) {
330         return BAD_FUNC_ARG;
331     }
332 
333     if ((sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)) > sz - idx) {
334         return BUFFER_E; /* not enough memory for structures */
335     }
336 
337     /* check if hint has already been assigned */
338     if (*pHint == NULL) {
339         heap = (WOLFSSL_HEAP*)buf;
340         idx += sizeof(WOLFSSL_HEAP);
341         hint = (WOLFSSL_HEAP_HINT*)(buf + idx);
342         idx += sizeof(WOLFSSL_HEAP_HINT);
343 
344         ret = wolfSSL_init_memory_heap(heap);
345         if (ret != 0) {
346             return ret;
347         }
348 
349         XMEMSET(hint, 0, sizeof(WOLFSSL_HEAP_HINT));
350         hint->memory = heap;
351     }
352     else {
353     #ifdef WOLFSSL_HEAP_TEST
354         /* do not load in memory if test has been set */
355         if (heap == (void*)WOLFSSL_HEAP_TEST) {
356             return 0;
357         }
358     #endif
359 
360         hint = (WOLFSSL_HEAP_HINT*)(*pHint);
361         heap = hint->memory;
362     }
363 
364     ret = wolfSSL_load_static_memory(buf + idx, sz - idx, flag, heap);
365     if (ret != 1) {
366         WOLFSSL_MSG("Error partitioning memory");
367         return -1;
368     }
369 
370     /* determine what max applies too */
371     if ((flag & WOLFMEM_IO_POOL) || (flag & WOLFMEM_IO_POOL_FIXED)) {
372         heap->maxIO = maxSz;
373     }
374     else { /* general memory used in handshakes */
375         heap->maxHa = maxSz;
376     }
377 
378     heap->flag |= flag;
379     *pHint = hint;
380 
381     (void)maxSz;
382 
383     return 0;
384 }
385 
386 int wolfSSL_load_static_memory(byte* buffer, word32 sz, int flag,
387                                                              WOLFSSL_HEAP* heap)
388 {
389     word32 ava = sz;
390     byte*  pt  = buffer;
391     int    ret = 0;
392     word32 memSz = (word32)sizeof(wc_Memory);
393     word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
394 
395     WOLFSSL_ENTER("wolfSSL_load_static_memory");
396 
397     if (buffer == NULL) {
398         return BAD_FUNC_ARG;
399     }
400 
401     /* align pt */
402     while ((wc_ptr_t)pt % WOLFSSL_STATIC_ALIGN && pt < (buffer + sz)) {
403         *pt = 0x00;
404         pt++;
405         ava--;
406     }
407 
408 #ifdef WOLFSSL_DEBUG_MEMORY
409     printf("Allocated %d bytes for static memory @ %p\n", ava, pt);
410 #endif
411 
412     /* divide into chunks of memory and add them to available list */
413     while (ava >= (heap->sizeList[0] + padSz + memSz)) {
414         int i;
415         /* creating only IO buffers from memory passed in, max TLS is 16k */
416         if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
417             if ((ret = create_memory_buckets(pt, ava,
418                                           WOLFMEM_IO_SZ, 1, &(heap->io))) < 0) {
419                 WOLFSSL_LEAVE("wolfSSL_load_static_memory", ret);
420                 return ret;
421             }
422 
423             /* check if no more room left for creating IO buffers */
424             if (ret == 0) {
425                 break;
426             }
427 
428             /* advance pointer in buffer for next buckets and keep track
429                of how much memory is left available */
430             pt  += ret;
431             ava -= ret;
432         }
433         else {
434             /* start at largest and move to smaller buckets */
435             for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
436                 if ((heap->sizeList[i] + padSz + memSz) <= ava) {
437                     if ((ret = create_memory_buckets(pt, ava, heap->sizeList[i],
438                                      heap->distList[i], &(heap->ava[i]))) < 0) {
439                         WOLFSSL_LEAVE("wolfSSL_load_static_memory", ret);
440                         return ret;
441                     }
442 
443                     /* advance pointer in buffer for next buckets and keep track
444                        of how much memory is left available */
445                     pt  += ret;
446                     ava -= ret;
447                 }
448             }
449         }
450     }
451 
452     return 1;
453 }
454 
455 
456 /* returns the size of management memory needed for each bucket.
457  * This is memory that is used to keep track of and align memory buckets. */
458 int wolfSSL_MemoryPaddingSz(void)
459 {
460     word32 memSz = (word32)sizeof(wc_Memory);
461     word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
462     return memSz + padSz;
463 }
464 
465 
466 /* Used to calculate memory size for optimum use with buckets.
467    returns the suggested size rounded down to the nearest bucket. */
468 int wolfSSL_StaticBufferSz(byte* buffer, word32 sz, int flag)
469 {
470     word32 bucketSz[WOLFMEM_MAX_BUCKETS] = {WOLFMEM_BUCKETS};
471     word32 distList[WOLFMEM_MAX_BUCKETS] = {WOLFMEM_DIST};
472 
473     word32 ava = sz;
474     byte*  pt  = buffer;
475     word32 memSz = (word32)sizeof(wc_Memory);
476     word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
477 
478     WOLFSSL_ENTER("wolfSSL_static_size");
479 
480     if (buffer == NULL) {
481         return BAD_FUNC_ARG;
482     }
483 
484     /* align pt */
485     while ((wc_ptr_t)pt % WOLFSSL_STATIC_ALIGN && pt < (buffer + sz)) {
486         pt++;
487         ava--;
488     }
489 
490     /* creating only IO buffers from memory passed in, max TLS is 16k */
491     if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
492         if (ava < (memSz + padSz + WOLFMEM_IO_SZ)) {
493             return 0; /* not enough room for even one bucket */
494         }
495 
496         ava = ava % (memSz + padSz + WOLFMEM_IO_SZ);
497     }
498     else {
499         int i, k;
500 
501         if (ava < (bucketSz[0] + padSz + memSz)) {
502             return 0; /* not enough room for even one bucket */
503         }
504 
505         while ((ava >= (bucketSz[0] + padSz + memSz)) && (ava > 0)) {
506             /* start at largest and move to smaller buckets */
507             for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
508                 for (k = distList[i]; k > 0; k--) {
509                     if ((bucketSz[i] + padSz + memSz) <= ava) {
510                         ava -= bucketSz[i] + padSz + memSz;
511                     }
512                 }
513             }
514         }
515     }
516 
517     return sz - ava; /* round down */
518 }
519 
520 
521 int FreeFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io)
522 {
523     WOLFSSL_MSG("Freeing fixed IO buffer");
524 
525     /* check if fixed buffer was set */
526     if (*io == NULL) {
527         return 1;
528     }
529 
530     if (heap == NULL) {
531         WOLFSSL_MSG("No heap to return fixed IO too");
532     }
533     else {
534         /* put IO buffer back into IO pool */
535         (*io)->next = heap->io;
536         heap->io    = *io;
537         *io         = NULL;
538     }
539 
540     return 1;
541 }
542 
543 
544 int SetFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io)
545 {
546     WOLFSSL_MSG("Setting fixed IO for SSL");
547     if (heap == NULL) {
548         return MEMORY_E;
549     }
550 
551     *io = heap->io;
552 
553     if (*io != NULL) {
554         heap->io = (*io)->next;
555         (*io)->next = NULL;
556     }
557     else { /* failed to grab an IO buffer */
558         return 0;
559     }
560 
561     return 1;
562 }
563 
564 
565 int wolfSSL_GetMemStats(WOLFSSL_HEAP* heap, WOLFSSL_MEM_STATS* stats)
566 {
567         word32     i;
568         wc_Memory* pt;
569 
570         XMEMSET(stats, 0, sizeof(WOLFSSL_MEM_STATS));
571 
572         stats->totalAlloc = heap->alloc;
573         stats->totalFr    = heap->frAlc;
574         stats->curAlloc   = stats->totalAlloc - stats->totalFr;
575         stats->maxHa      = heap->maxHa;
576         stats->maxIO      = heap->maxIO;
577         for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
578             stats->blockSz[i] = heap->sizeList[i];
579             for (pt = heap->ava[i]; pt != NULL; pt = pt->next) {
580                 stats->avaBlock[i] += 1;
581             }
582         }
583 
584         for (pt = heap->io; pt != NULL; pt = pt->next) {
585             stats->avaIO++;
586         }
587 
588         stats->flag       = heap->flag; /* flag used */
589 
590     return 1;
591 }
592 
593 
594 #ifdef WOLFSSL_DEBUG_MEMORY
595 void* wolfSSL_Malloc(size_t size, void* heap, int type, const char* func, unsigned int line)
596 #else
597 void* wolfSSL_Malloc(size_t size, void* heap, int type)
598 #endif
599 {
600     void* res = 0;
601     wc_Memory* pt = NULL;
602     int   i;
603 
604     /* check for testing heap hint was set */
605 #ifdef WOLFSSL_HEAP_TEST
606     if (heap == (void*)WOLFSSL_HEAP_TEST) {
607         return malloc(size);
608     }
609 #endif
610 
611     /* if no heap hint then use dynamic memory*/
612     if (heap == NULL) {
613         #ifdef WOLFSSL_HEAP_TEST
614             /* allow using malloc for creating ctx and method */
615             if (type == DYNAMIC_TYPE_CTX || type == DYNAMIC_TYPE_METHOD ||
616                                             type == DYNAMIC_TYPE_CERT_MANAGER) {
617                 WOLFSSL_MSG("ERROR allowing null heap hint for ctx/method");
618                 res = malloc(size);
619             }
620             else {
621                 WOLFSSL_MSG("ERROR null heap hint passed into XMALLOC");
622                 res = NULL;
623             }
624         #else
625         #ifndef WOLFSSL_NO_MALLOC
626             #ifdef FREERTOS
627                 res = pvPortMalloc(size);
628             #else
629                 res = malloc(size);
630             #endif
631 
632             #ifdef WOLFSSL_DEBUG_MEMORY
633                 printf("Alloc: %p -> %u at %s:%d\n", res, (word32)size, func, line);
634             #endif
635         #else
636             WOLFSSL_MSG("No heap hint found to use and no malloc");
637             #ifdef WOLFSSL_DEBUG_MEMORY
638             printf("ERROR: at %s:%d\n", func, line);
639             #endif
640         #endif /* WOLFSSL_NO_MALLOC */
641         #endif /* WOLFSSL_HEAP_TEST */
642     }
643     else {
644         WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap;
645         WOLFSSL_HEAP*      mem  = hint->memory;
646 
647         if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
648             WOLFSSL_MSG("Bad memory_mutex lock");
649             return NULL;
650         }
651 
652         /* case of using fixed IO buffers */
653         if (mem->flag & WOLFMEM_IO_POOL_FIXED &&
654                                              (type == DYNAMIC_TYPE_OUT_BUFFER ||
655                                               type == DYNAMIC_TYPE_IN_BUFFER)) {
656             if (type == DYNAMIC_TYPE_OUT_BUFFER) {
657                 pt = hint->outBuf;
658             }
659             if (type == DYNAMIC_TYPE_IN_BUFFER) {
660                 pt = hint->inBuf;
661             }
662         }
663         else {
664             /* check if using IO pool flag */
665             if (mem->flag & WOLFMEM_IO_POOL &&
666                                              (type == DYNAMIC_TYPE_OUT_BUFFER ||
667                                               type == DYNAMIC_TYPE_IN_BUFFER)) {
668                 if (mem->io != NULL) {
669                     pt      = mem->io;
670                     mem->io = pt->next;
671                 }
672             }
673 
674             /* general static memory */
675             if (pt == NULL) {
676                 for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
677                     if ((word32)size <= mem->sizeList[i]) {
678                         if (mem->ava[i] != NULL) {
679                             pt = mem->ava[i];
680                             mem->ava[i] = pt->next;
681                             break;
682                         }
683                     #ifdef WOLFSSL_DEBUG_STATIC_MEMORY
684                         else {
685                             printf("Size: %ld, Empty: %d\n", size,
686                                                               mem->sizeList[i]);
687                         }
688                     #endif
689                     }
690                 }
691             }
692         }
693 
694         if (pt != NULL) {
695             mem->inUse += pt->sz;
696             mem->alloc += 1;
697             res = pt->buffer;
698 
699         #ifdef WOLFSSL_DEBUG_MEMORY
700             printf("Alloc: %p -> %u at %s:%d\n", pt->buffer, pt->sz, func, line);
701         #endif
702 
703             /* keep track of connection statistics if flag is set */
704             if (mem->flag & WOLFMEM_TRACK_STATS) {
705                 WOLFSSL_MEM_CONN_STATS* stats = hint->stats;
706                 if (stats != NULL) {
707                     stats->curMem += pt->sz;
708                     if (stats->peakMem < stats->curMem) {
709                         stats->peakMem = stats->curMem;
710                     }
711                     stats->curAlloc++;
712                     if (stats->peakAlloc < stats->curAlloc) {
713                         stats->peakAlloc = stats->curAlloc;
714                     }
715                     stats->totalAlloc++;
716                 }
717             }
718         }
719         else {
720             WOLFSSL_MSG("ERROR ran out of static memory");
721             #ifdef WOLFSSL_DEBUG_MEMORY
722             printf("Looking for %lu bytes at %s:%d\n", size, func, line);
723             #endif
724         }
725 
726         wc_UnLockMutex(&(mem->memory_mutex));
727     }
728 
729     #ifdef WOLFSSL_MALLOC_CHECK
730         if ((wc_ptr_t)res % WOLFSSL_STATIC_ALIGN) {
731             WOLFSSL_MSG("ERROR memory is not aligned");
732             res = NULL;
733         }
734     #endif
735 
736 
737     (void)i;
738     (void)pt;
739     (void)type;
740 
741     return res;
742 }
743 
744 
745 #ifdef WOLFSSL_DEBUG_MEMORY
746 void wolfSSL_Free(void *ptr, void* heap, int type, const char* func, unsigned int line)
747 #else
748 void wolfSSL_Free(void *ptr, void* heap, int type)
749 #endif
750 {
751     int i;
752     wc_Memory* pt;
753 
754     if (ptr) {
755         /* check for testing heap hint was set */
756     #ifdef WOLFSSL_HEAP_TEST
757         if (heap == (void*)WOLFSSL_HEAP_TEST) {
758         #ifdef WOLFSSL_DEBUG_MEMORY
759             printf("Free: %p at %s:%d\n", pt, func, line);
760         #endif
761             return free(ptr);
762         }
763     #endif
764 
765         if (heap == NULL) {
766         #ifdef WOLFSSL_HEAP_TEST
767             /* allow using malloc for creating ctx and method */
768             if (type == DYNAMIC_TYPE_CTX || type == DYNAMIC_TYPE_METHOD ||
769                                             type == DYNAMIC_TYPE_CERT_MANAGER) {
770                 WOLFSSL_MSG("ERROR allowing null heap hint for ctx/method");
771             }
772             else {
773                 WOLFSSL_MSG("ERROR null heap hint passed into XFREE");
774             }
775         #endif
776         #ifndef WOLFSSL_NO_MALLOC
777             #ifdef FREERTOS
778                 vPortFree(ptr);
779             #else
780                 free(ptr);
781             #endif
782         #else
783             WOLFSSL_MSG("Error trying to call free when turned off");
784         #endif /* WOLFSSL_NO_MALLOC */
785         }
786         else {
787             WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap;
788             WOLFSSL_HEAP*      mem  = hint->memory;
789             word32 padSz = -(int)sizeof(wc_Memory) & (WOLFSSL_STATIC_ALIGN - 1);
790 
791             /* get memory struct and add it to available list */
792             pt = (wc_Memory*)((byte*)ptr - sizeof(wc_Memory) - padSz);
793             if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
794                 WOLFSSL_MSG("Bad memory_mutex lock");
795                 return;
796             }
797 
798             /* case of using fixed IO buffers */
799             if (mem->flag & WOLFMEM_IO_POOL_FIXED &&
800                                              (type == DYNAMIC_TYPE_OUT_BUFFER ||
801                                               type == DYNAMIC_TYPE_IN_BUFFER)) {
802                 /* fixed IO pools are free'd at the end of SSL lifetime
803                    using FreeFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io) */
804             }
805             else if (mem->flag & WOLFMEM_IO_POOL && pt->sz == WOLFMEM_IO_SZ &&
806                                              (type == DYNAMIC_TYPE_OUT_BUFFER ||
807                                               type == DYNAMIC_TYPE_IN_BUFFER)) {
808                 pt->next = mem->io;
809                 mem->io  = pt;
810             }
811             else { /* general memory free */
812                 for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
813                     if (pt->sz == mem->sizeList[i]) {
814                         pt->next = mem->ava[i];
815                         mem->ava[i] = pt;
816                         break;
817                     }
818                 }
819             }
820             mem->inUse -= pt->sz;
821             mem->frAlc += 1;
822 
823         #ifdef WOLFSSL_DEBUG_MEMORY
824             printf("Free: %p -> %u at %s:%d\n", pt->buffer, pt->sz, func, line);
825         #endif
826 
827             /* keep track of connection statistics if flag is set */
828             if (mem->flag & WOLFMEM_TRACK_STATS) {
829                 WOLFSSL_MEM_CONN_STATS* stats = hint->stats;
830                 if (stats != NULL) {
831                     /* avoid under flow */
832                     if (stats->curMem > pt->sz) {
833                         stats->curMem -= pt->sz;
834                     }
835                     else {
836                         stats->curMem = 0;
837                     }
838 
839                     if (stats->curAlloc > 0) {
840                         stats->curAlloc--;
841                     }
842                     stats->totalFr++;
843                 }
844             }
845             wc_UnLockMutex(&(mem->memory_mutex));
846         }
847     }
848 
849     (void)i;
850     (void)pt;
851     (void)type;
852 }
853 
854 #ifdef WOLFSSL_DEBUG_MEMORY
855 void* wolfSSL_Realloc(void *ptr, size_t size, void* heap, int type, const char* func, unsigned int line)
856 #else
857 void* wolfSSL_Realloc(void *ptr, size_t size, void* heap, int type)
858 #endif
859 {
860     void* res = 0;
861     wc_Memory* pt = NULL;
862     word32 prvSz;
863     int    i;
864 
865     /* check for testing heap hint was set */
866 #ifdef WOLFSSL_HEAP_TEST
867     if (heap == (void*)WOLFSSL_HEAP_TEST) {
868         return realloc(ptr, size);
869     }
870 #endif
871 
872     if (heap == NULL) {
873         #ifdef WOLFSSL_HEAP_TEST
874             WOLFSSL_MSG("ERROR null heap hint passed in to XREALLOC");
875         #endif
876         #ifndef WOLFSSL_NO_MALLOC
877             res = realloc(ptr, size);
878         #else
879             WOLFSSL_MSG("NO heap found to use for realloc");
880         #endif /* WOLFSSL_NO_MALLOC */
881     }
882     else {
883         WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap;
884         WOLFSSL_HEAP*      mem  = hint->memory;
885         word32 padSz = -(int)sizeof(wc_Memory) & (WOLFSSL_STATIC_ALIGN - 1);
886 
887         if (ptr == NULL) {
888         #ifdef WOLFSSL_DEBUG_MEMORY
889             return wolfSSL_Malloc(size, heap, type, func, line);
890         #else
891             return wolfSSL_Malloc(size, heap, type);
892         #endif
893         }
894 
895         if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
896             WOLFSSL_MSG("Bad memory_mutex lock");
897             return NULL;
898         }
899 
900         /* case of using fixed IO buffers or IO pool */
901         if (((mem->flag & WOLFMEM_IO_POOL)||(mem->flag & WOLFMEM_IO_POOL_FIXED))
902                                           && (type == DYNAMIC_TYPE_OUT_BUFFER ||
903                                               type == DYNAMIC_TYPE_IN_BUFFER)) {
904             /* no realloc, is fixed size */
905             pt = (wc_Memory*)((byte*)ptr - padSz - sizeof(wc_Memory));
906             if (pt->sz < size) {
907                 WOLFSSL_MSG("Error IO memory was not large enough");
908                 res = NULL; /* return NULL in error case */
909             }
910             res = pt->buffer;
911         }
912         else {
913         /* general memory */
914             for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
915                 if ((word32)size <= mem->sizeList[i]) {
916                     if (mem->ava[i] != NULL) {
917                         pt = mem->ava[i];
918                         mem->ava[i] = pt->next;
919                         break;
920                     }
921                 }
922             }
923 
924             if (pt != NULL && res == NULL) {
925                 res = pt->buffer;
926 
927                 /* copy over original information and free ptr */
928                 prvSz = ((wc_Memory*)((byte*)ptr - padSz -
929                                                sizeof(wc_Memory)))->sz;
930                 prvSz = (prvSz > pt->sz)? pt->sz: prvSz;
931                 XMEMCPY(pt->buffer, ptr, prvSz);
932                 mem->inUse += pt->sz;
933                 mem->alloc += 1;
934 
935                 /* free memory that was previously being used */
936                 wc_UnLockMutex(&(mem->memory_mutex));
937                 wolfSSL_Free(ptr, heap, type
938             #ifdef WOLFSSL_DEBUG_MEMORY
939                     , func, line
940             #endif
941                 );
942                 if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
943                     WOLFSSL_MSG("Bad memory_mutex lock");
944                     return NULL;
945                 }
946             }
947         }
948         wc_UnLockMutex(&(mem->memory_mutex));
949     }
950 
951     #ifdef WOLFSSL_MALLOC_CHECK
952         if ((wc_ptr_t)res % WOLFSSL_STATIC_ALIGN) {
953             WOLFSSL_MSG("ERROR memory is not aligned");
954             res = NULL;
955         }
956     #endif
957 
958     (void)i;
959     (void)pt;
960     (void)type;
961 
962     return res;
963 }
964 #endif /* WOLFSSL_STATIC_MEMORY */
965 
966 #endif /* USE_WOLFSSL_MEMORY */
967 
968 
969 #ifdef HAVE_IO_POOL
970 
971 /* Example for user io pool, shared build may need definitions in lib proper */
972 
973 #include <wolfssl/wolfcrypt/types.h>
974 #include <stdlib.h>
975 
976 #ifndef HAVE_THREAD_LS
977     #error "Oops, simple I/O pool example needs thread local storage"
978 #endif
979 
980 
981 /* allow simple per thread in and out pools */
982 /* use 17k size since max record size is 16k plus overhead */
983 static THREAD_LS_T byte pool_in[17*1024];
984 static THREAD_LS_T byte pool_out[17*1024];
985 
986 
987 void* XMALLOC(size_t n, void* heap, int type)
988 {
989     (void)heap;
990 
991     if (type == DYNAMIC_TYPE_IN_BUFFER) {
992         if (n < sizeof(pool_in))
993             return pool_in;
994         else
995             return NULL;
996     }
997 
998     if (type == DYNAMIC_TYPE_OUT_BUFFER) {
999         if (n < sizeof(pool_out))
1000             return pool_out;
1001         else
1002             return NULL;
1003     }
1004 
1005     return malloc(n);
1006 }
1007 
1008 void* XREALLOC(void *p, size_t n, void* heap, int type)
1009 {
1010     (void)heap;
1011 
1012     if (type == DYNAMIC_TYPE_IN_BUFFER) {
1013         if (n < sizeof(pool_in))
1014             return pool_in;
1015         else
1016             return NULL;
1017     }
1018 
1019     if (type == DYNAMIC_TYPE_OUT_BUFFER) {
1020         if (n < sizeof(pool_out))
1021             return pool_out;
1022         else
1023             return NULL;
1024     }
1025 
1026     return realloc(p, n);
1027 }
1028 
1029 void XFREE(void *p, void* heap, int type)
1030 {
1031     (void)heap;
1032 
1033     if (type == DYNAMIC_TYPE_IN_BUFFER)
1034         return;  /* do nothing, static pool */
1035 
1036     if (type == DYNAMIC_TYPE_OUT_BUFFER)
1037         return;  /* do nothing, static pool */
1038 
1039     free(p);
1040 }
1041 
1042 #endif /* HAVE_IO_POOL */
1043 
1044 #ifdef WOLFSSL_MEMORY_LOG
1045 void *xmalloc(size_t n, void* heap, int type, const char* func,
1046               const char* file, unsigned int line)
1047 {
1048     void*   p = NULL;
1049     word32* p32;
1050 
1051     if (malloc_function)
1052         p32 = malloc_function(n + sizeof(word32) * 4);
1053     else
1054         p32 = malloc(n + sizeof(word32) * 4);
1055 
1056     if (p32 != NULL) {
1057         p32[0] = (word32)n;
1058         p = (void*)(p32 + 4);
1059 
1060         fprintf(stderr, "Alloc: %p -> %u (%d) at %s:%s:%u\n", p, (word32)n,
1061                                                         type, func, file, line);
1062     }
1063 
1064     (void)heap;
1065 
1066     return p;
1067 }
1068 void *xrealloc(void *p, size_t n, void* heap, int type, const char* func,
1069                const char* file, unsigned int line)
1070 {
1071     void*   newp = NULL;
1072     word32* p32;
1073     word32* oldp32 = NULL;
1074     word32  oldLen;
1075 
1076     if (p != NULL) {
1077         oldp32 = (word32*)p;
1078         oldp32 -= 4;
1079         oldLen = oldp32[0];
1080     }
1081 
1082     if (realloc_function)
1083         p32 = realloc_function(oldp32, n + sizeof(word32) * 4);
1084     else
1085         p32 = realloc(oldp32, n + sizeof(word32) * 4);
1086 
1087     if (p32 != NULL) {
1088         p32[0] = (word32)n;
1089         newp = (void*)(p32 + 4);
1090 
1091         fprintf(stderr, "Alloc: %p -> %u (%d) at %s:%s:%u\n", newp, (word32)n,
1092                                                         type, func, file, line);
1093         if (p != NULL) {
1094             fprintf(stderr, "Free: %p -> %u (%d) at %s:%s:%u\n", p, oldLen,
1095                                                         type, func, file, line);
1096         }
1097     }
1098 
1099     (void)heap;
1100 
1101     return newp;
1102 }
1103 void xfree(void *p, void* heap, int type, const char* func, const char* file,
1104            unsigned int line)
1105 {
1106     word32* p32 = (word32*)p;
1107 
1108     if (p != NULL) {
1109         p32 -= 4;
1110 
1111         fprintf(stderr, "Free: %p -> %u (%d) at %s:%s:%u\n", p, p32[0], type,
1112                                                               func, file, line);
1113 
1114         if (free_function)
1115             free_function(p32);
1116         else
1117             free(p32);
1118     }
1119 
1120     (void)heap;
1121 }
1122 #endif /* WOLFSSL_MEMORY_LOG */
1123 
1124 #ifdef WOLFSSL_STACK_LOG
1125 /* Note: this code only works with GCC using -finstrument-functions. */
1126 void __attribute__((no_instrument_function))
1127      __cyg_profile_func_enter(void *func,  void *caller)
1128 {
1129     register void* sp asm("sp");
1130     fprintf(stderr, "ENTER: %016lx %p\n", (unsigned long)(wc_ptr_t)func, sp);
1131     (void)caller;
1132 }
1133 
1134 void __attribute__((no_instrument_function))
1135      __cyg_profile_func_exit(void *func, void *caller)
1136 {
1137     register void* sp asm("sp");
1138     fprintf(stderr, "EXIT: %016lx %p\n", (unsigned long)(wc_ptr_t)func, sp);
1139     (void)caller;
1140 }
1141 #endif
1142 
1143 #if defined(WOLFSSL_LINUXKM_SIMD_X86)
1144     static union fpregs_state **wolfcrypt_linuxkm_fpu_states = NULL;
1145 
1146     static WARN_UNUSED_RESULT inline int am_in_hard_interrupt_handler(void)
1147     {
1148         return (preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0;
1149     }
1150 
1151     WARN_UNUSED_RESULT int allocate_wolfcrypt_linuxkm_fpu_states(void)
1152     {
1153         wolfcrypt_linuxkm_fpu_states =
1154             (union fpregs_state **)kzalloc(nr_cpu_ids
1155                                            * sizeof(struct fpu_state *),
1156                                            GFP_KERNEL);
1157         if (! wolfcrypt_linuxkm_fpu_states) {
1158             pr_err("warning, allocation of %lu bytes for "
1159                    "wolfcrypt_linuxkm_fpu_states failed.\n",
1160                    nr_cpu_ids * sizeof(struct fpu_state *));
1161             return MEMORY_E;
1162         }
1163         {
1164             typeof(nr_cpu_ids) i;
1165             for (i=0; i<nr_cpu_ids; ++i) {
1166                 _Static_assert(sizeof(union fpregs_state) <= PAGE_SIZE,
1167                                "union fpregs_state is larger than expected.");
1168                 wolfcrypt_linuxkm_fpu_states[i] =
1169                     (union fpregs_state *)kzalloc(PAGE_SIZE
1170                                                   /* sizeof(union fpregs_state) */,
1171                                                   GFP_KERNEL);
1172                 if (! wolfcrypt_linuxkm_fpu_states[i])
1173                     break;
1174                 /* double-check that the allocation is 64-byte-aligned as needed
1175                  * for xsave.
1176                  */
1177                 if ((unsigned long)wolfcrypt_linuxkm_fpu_states[i] & 63UL) {
1178                     pr_err("warning, allocation for wolfcrypt_linuxkm_fpu_states "
1179                            "was not properly aligned (%px).\n",
1180                            wolfcrypt_linuxkm_fpu_states[i]);
1181                     kfree(wolfcrypt_linuxkm_fpu_states[i]);
1182                     wolfcrypt_linuxkm_fpu_states[i] = 0;
1183                     break;
1184                 }
1185             }
1186             if (i < nr_cpu_ids) {
1187                 pr_err("warning, only %u/%u allocations succeeded for "
1188                        "wolfcrypt_linuxkm_fpu_states.\n",
1189                        i, nr_cpu_ids);
1190                 return MEMORY_E;
1191             }
1192         }
1193         return 0;
1194     }
1195 
1196     void free_wolfcrypt_linuxkm_fpu_states(void)
1197     {
1198         if (wolfcrypt_linuxkm_fpu_states) {
1199             typeof(nr_cpu_ids) i;
1200             for (i=0; i<nr_cpu_ids; ++i) {
1201                 if (wolfcrypt_linuxkm_fpu_states[i])
1202                     kfree(wolfcrypt_linuxkm_fpu_states[i]);
1203             }
1204             kfree(wolfcrypt_linuxkm_fpu_states);
1205             wolfcrypt_linuxkm_fpu_states = 0;
1206         }
1207     }
1208 
1209     WARN_UNUSED_RESULT int save_vector_registers_x86(void)
1210     {
1211         int processor_id;
1212 
1213         preempt_disable();
1214 
1215         processor_id = smp_processor_id();
1216 
1217         {
1218             static int _warned_on_null = -1;
1219             if ((wolfcrypt_linuxkm_fpu_states == NULL) ||
1220                 (wolfcrypt_linuxkm_fpu_states[processor_id] == NULL))
1221             {
1222                 preempt_enable();
1223                 if (_warned_on_null < processor_id) {
1224                     _warned_on_null = processor_id;
1225                     pr_err("save_vector_registers_x86 called for cpu id %d "
1226                            "with null context buffer.\n", processor_id);
1227                 }
1228                 return BAD_STATE_E;
1229             }
1230         }
1231 
1232         if (! irq_fpu_usable()) {
1233             if (am_in_hard_interrupt_handler()) {
1234 
1235                 /* allow for nested calls */
1236                 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] != 0) {
1237                     if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] == 255) {
1238                         preempt_enable();
1239                         pr_err("save_vector_registers_x86 recursion register overflow for "
1240                                "cpu id %d.\n", processor_id);
1241                         return BAD_STATE_E;
1242                     } else {
1243                         ++((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1];
1244                         return 0;
1245                     }
1246                 }
1247                 /* note, fpregs_lock() is not needed here, because
1248                  * interrupts/preemptions are already disabled here.
1249                  */
1250                 {
1251                     /* save_fpregs_to_fpstate() only accesses fpu->state, which
1252                      * has stringent alignment requirements (64 byte cache
1253                      * line), but takes a pointer to the parent struct.  work
1254                      * around this.
1255                      */
1256                     struct fpu *fake_fpu_pointer =
1257                         (struct fpu *)(((char *)wolfcrypt_linuxkm_fpu_states[processor_id])
1258                                        - offsetof(struct fpu, state));
1259                 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
1260                     copy_fpregs_to_fpstate(fake_fpu_pointer);
1261                 #else
1262                     save_fpregs_to_fpstate(fake_fpu_pointer);
1263                 #endif
1264                 }
1265                 /* mark the slot as used. */
1266                 ((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] = 1;
1267                 /* note, not preempt_enable()ing, mirroring kernel_fpu_begin()
1268                  * semantics, even though routine will have been entered already
1269                  * non-preemptable.
1270                  */
1271                 return 0;
1272             } else {
1273                 preempt_enable();
1274                 return BAD_STATE_E;
1275             }
1276         } else {
1277 
1278             /* allow for nested calls */
1279             if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] != 0) {
1280                 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] == 255) {
1281                     preempt_enable();
1282                     pr_err("save_vector_registers_x86 recursion register overflow for "
1283                            "cpu id %d.\n", processor_id);
1284                     return BAD_STATE_E;
1285                 } else {
1286                     ++((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1];
1287                     return 0;
1288                 }
1289             }
1290 
1291             kernel_fpu_begin();
1292             preempt_enable(); /* kernel_fpu_begin() does its own
1293                                * preempt_disable().  decrement ours.
1294                                */
1295             ((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] = 1;
1296             return 0;
1297         }
1298     }
1299     void restore_vector_registers_x86(void)
1300     {
1301         int processor_id = smp_processor_id();
1302 
1303         if ((wolfcrypt_linuxkm_fpu_states == NULL) ||
1304             (wolfcrypt_linuxkm_fpu_states[processor_id] == NULL))
1305         {
1306                 pr_err("restore_vector_registers_x86 called for cpu id %d "
1307                        "without null context buffer.\n", processor_id);
1308                 return;
1309         }
1310 
1311         if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] == 0)
1312         {
1313             pr_err("restore_vector_registers_x86 called for cpu id %d "
1314                    "without saved context.\n", processor_id);
1315             return;
1316         }
1317 
1318         if (--((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] > 0) {
1319             preempt_enable(); /* preempt_disable count will still be nonzero after this decrement. */
1320             return;
1321         }
1322 
1323         if (am_in_hard_interrupt_handler()) {
1324         #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
1325             copy_kernel_to_fpregs(wolfcrypt_linuxkm_fpu_states[processor_id]);
1326         #else
1327             __restore_fpregs_from_fpstate(wolfcrypt_linuxkm_fpu_states[processor_id],
1328                                           xfeatures_mask_all);
1329         #endif
1330             preempt_enable();
1331         } else {
1332             kernel_fpu_end();
1333         }
1334         return;
1335     }
1336 #endif /* WOLFSSL_LINUXKM_SIMD_X86 && WOLFSSL_LINUXKM_SIMD_X86_IRQ_ALLOWED */
1337