source: soft/giet_vm/giet_common/kernel_malloc.c @ 707

Last change on this file since 707 was 594, checked in by alain, 9 years ago

1) Fix a bug in the _free() function in kernel_malloc.c
2) Introduce a strlen() function in utils.c

  • Property svn:executable set to *
File size: 21.2 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// File     : kernel_malloc.c
3// Date     : 05/12/2014
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6////////////////////////////////////////////////////////////////////////////////
7// Implementation note:
8// - As this code is used to implement the SQT lock ptotecting TTY0,
9//   all functions here use the kernel _nolock_printf() function.
10// - It must exist one vseg with the HEAP type in each cluster. The length
11//   must be a power of 2, and the base address must be aligned.
12// - An array kernel_heap[x][y] containing the heap descriptors is
13//   stored in cluster[0][0].
14// - Each kernel_heap[x][y] structure contains a specific queuing spin-lock.
15////////////////////////////////////////////////////////////////////////////////
16// Allocation policy:
17// - All allocated blocks have a size that is a power of 2, larger or equal
18//   to MIN_BLOCK_SIZE (typically 64 bytes), and are aligned.
19// - All free blocks are pre-classed in 32 linked lists of free blocks, where
20//   all blocks in a given list have the same size.
21// - The NEXT pointer implementing those linked lists is written
22//   in the 4 first bytes of the block itself, using the unsigned int type.
23// - The pointers on the first free block for each size are stored in an
24//   array of pointers free[32] in the heap[x][y) structure itself.
25// - The block size required can be any value, but the allocated block size
26//   is the smallest power of 2 value larger or equal to the requested size.
27// - It pop the linked list of free blocks corresponding to size,
28//   and returns the block B if the list[size] is not empty.
29// - If the list[size] is empty, it pop the list[size * 2].
30//   If a block B' is found, it break this block in 2 B/2 blocks, returns
31//   the first B/2 block and push the other B/2 block into list[size].
32// - If the list[size * 2] is empty, it pop the list[size * 4].
33//   If a block B is found, it break this block in 3 blocks B/4, B/4 and B/2,
34//   returns the first B/4 block, push the other blocks B/4 and B/2 into
35//   the proper lists. etc...
36////////////////////////////////////////////////////////////////////////////////
37// Free policy:
38// - Each allocated block is registered in an alloc[] array of unsigned char.
39// - This registration is required by the free() operation, because the size
40//   of the allocated block must be obtained from the base address of the block. 
41// - The number of entries in this array is equal to the max number
42//   of allocated block is : heap_size / MIN_BLOCK_SIZE
43// - For each allocated block, the value registered in the alloc[] array
44//   is log2( size_of_allocated_block ).
45// - The index in this array is computed from the allocated block base address:
46//      index = (block_base - heap_base) / MIN_BLOCK_SIZE
47// - The alloc[] array is stored at the end of heap segment. This consume
48//   (1 / MIN_BLOCK_SIZE) of the total heap storage capacity.
49////////////////////////////////////////////////////////////////////////////////
50
51#include "giet_config.h"
52#include "hard_config.h"
53#include "mapping_info.h"
54#include "kernel_malloc.h"
55#include "kernel_locks.h"
56#include "sys_handler.h"
57#include "tty0.h"
58#include "utils.h"
59
60///////////////////////////////////////////////////////////////////////////////
61// Global variables defining the heap descriptors array (one heap per cluster)
62///////////////////////////////////////////////////////////////////////////////
63
64__attribute__((section(".kdata")))
65kernel_heap_t     kernel_heap[X_SIZE][Y_SIZE];
66
67///////////////////////////////////////////////////////////////////////////////
68// Macro returning the smallest power of 2 larger or equal to size value
69///////////////////////////////////////////////////////////////////////////////
70#define GET_SIZE_INDEX(size)                (size <= 0x00000001) ? 0  :\
71                                            (size <= 0x00000002) ? 1  :\
72                                            (size <= 0x00000004) ? 2  :\
73                                            (size <= 0x00000008) ? 3  :\
74                                            (size <= 0x00000010) ? 4  :\
75                                            (size <= 0x00000020) ? 5  :\
76                                            (size <= 0x00000040) ? 6  :\
77                                            (size <= 0x00000080) ? 7  :\
78                                            (size <= 0x00000100) ? 8  :\
79                                            (size <= 0x00000200) ? 9  :\
80                                            (size <= 0x00000400) ? 10 :\
81                                            (size <= 0x00000800) ? 11 :\
82                                            (size <= 0x00001000) ? 12 :\
83                                            (size <= 0x00002000) ? 13 :\
84                                            (size <= 0x00004000) ? 14 :\
85                                            (size <= 0x00008000) ? 15 :\
86                                            (size <= 0x00010000) ? 16 :\
87                                            (size <= 0x00020000) ? 17 :\
88                                            (size <= 0x00040000) ? 18 :\
89                                            (size <= 0x00080000) ? 19 :\
90                                            (size <= 0x00100000) ? 20 :\
91                                            (size <= 0x00200000) ? 21 :\
92                                            (size <= 0x00400000) ? 22 :\
93                                            (size <= 0x00800000) ? 23 :\
94                                            (size <= 0x01000000) ? 24 :\
95                                            (size <= 0x02000000) ? 25 :\
96                                            (size <= 0x04000000) ? 26 :\
97                                            (size <= 0x08000000) ? 27 :\
98                                            (size <= 0x10000000) ? 28 :\
99                                            (size <= 0x20000000) ? 29 :\
100                                            (size <= 0x40000000) ? 30 :\
101                                            (size <= 0x80000000) ? 31 :\
102                                                                   32
103
104#if GIET_DEBUG_SYS_MALLOC
105
106////////////////////////////////////////////////
107static void _display_free_array( unsigned int x,
108                                 unsigned int y )
109{
110    unsigned int next;
111    unsigned int id;
112    unsigned int iter;
113
114    _nolock_printf("\nKernel Heap[%d][%d] base = %x / size = %x\n", x , y , 
115                   kernel_heap[x][y].heap_base, kernel_heap[x][y].heap_size );
116    for ( id = 6 ; id < 24 ; id++ )
117    { 
118        next = kernel_heap[x][y].free[id];
119        _nolock_printf(" - free[%d] = " , id );
120        iter = 0;
121        while ( next != 0 )
122        {
123            _nolock_printf("%x | ", next );
124            next = (*(unsigned int*)next);
125            iter++;
126        }
127        _nolock_printf("0\n");
128    }
129}  // end _display_free_array()
130
131#endif
132
133
134
135
136////////////////////////////////////////////////////////////////////////////////
137// This function returns the heap_base and heap_size values for cluster[x][y],
138// from information defined in the mapping.
139////////////////////////////////////////////////////////////////////////////////
140unsigned int _get_heap_info( unsigned int* heap_base,
141                             unsigned int* heap_size,
142                             unsigned int  x,
143                             unsigned int  y )
144{
145    mapping_header_t  * header   = (mapping_header_t *)SEG_BOOT_MAPPING_BASE;
146    mapping_vseg_t    * vsegs    = _get_vseg_base(header);
147    mapping_pseg_t    * psegs    = _get_pseg_base(header);
148    mapping_cluster_t * clusters = _get_cluster_base(header);
149
150    unsigned int vseg_id;
151    unsigned int pseg_id;
152    unsigned int cluster_id;
153
154    // checking coordinates
155    if ( (x >= X_SIZE) || (y >= Y_SIZE) )
156    {
157        _nolock_printf("\n[GIET ERROR] _get_heap_info()"
158                       " illegal (%d,%d) coordinates\n", x , y );
159        _exit();
160    }
161
162    // scan all global vsegs
163    for ( vseg_id = 0 ; vseg_id < header->globals ; vseg_id++ )
164    {
165        pseg_id    = vsegs[vseg_id].psegid;
166        cluster_id = psegs[pseg_id].clusterid;
167        if ( (vsegs[vseg_id].type == VSEG_TYPE_HEAP) &&
168             (clusters[cluster_id].x == x) && 
169             (clusters[cluster_id].y == y) )
170        {
171            *heap_base = vsegs[vseg_id].vbase;
172            *heap_size = vsegs[vseg_id].length;
173            return 0;
174        }
175    }
176
177    return 1;
178} // end _get_heap_info()
179
180
181
182/////////////////
183void _heap_init()
184{
185    unsigned int heap_base;
186    unsigned int heap_size;
187    unsigned int heap_index;
188
189    unsigned int alloc_base; 
190    unsigned int alloc_size;
191    unsigned int alloc_index;
192
193    unsigned int index;
194    unsigned int x;
195    unsigned int y;
196    unsigned int ko;
197
198    for ( x = 0 ; x < X_SIZE ; x++ )
199    {
200        for ( y = 0 ; y < Y_SIZE ; y++ )
201        {
202            // get heap_base & heap size
203            ko = _get_heap_info( &heap_base, &heap_size, x, y );
204       
205            if ( ko )  // no kernel heap found in cluster[x][y]
206            {
207                // initialise kernel_heap[x][y] descriptor to empty
208                kernel_heap[x][y].heap_base  = 0;
209                kernel_heap[x][y].heap_size  = 0;
210            }
211            else       // kernel heap found in cluster[x][y]
212            {
213                heap_index = GET_SIZE_INDEX( heap_size );
214
215                // check heap[x][y] constraints
216                if ( heap_size != (1<<heap_index) )
217                {
218                    _nolock_printf("\n[GIET ERROR] in _heap_init()"
219                                   " kernel_heap[‰d,‰d] not power of 2\n", x , y );
220                    _exit();
221                }
222                if ( heap_base % heap_size ) 
223                {
224                    _nolock_printf("\n[GIET ERROR] in _heap_init()"
225                                   " kernel_heap[‰d,‰d] not aligned\n", x , y );
226                    _exit();
227                }
228
229                // compute size of block containin alloc[] array
230                alloc_size = heap_size / MIN_BLOCK_SIZE;
231                if ( alloc_size < MIN_BLOCK_SIZE) alloc_size = MIN_BLOCK_SIZE;
232
233                // get index for the corresponding block
234                alloc_index = GET_SIZE_INDEX( alloc_size );
235
236                // compute alloc[] array base address
237                alloc_base = heap_base + heap_size - alloc_size;
238
239                // reset the free[] array
240                for ( index = 0 ; index < 32 ; index++ )
241                {
242                    kernel_heap[x][y].free[index] = 0;
243                }
244
245                // reset the alloc_size array
246                memset( (unsigned char*)alloc_base , 0 , alloc_size );
247 
248                // split the heap into various sizes blocks,
249                // initializes the free[] array and NEXT pointers
250                // base is the block base address
251                unsigned int   base = heap_base;
252                unsigned int*  ptr;
253                for ( index = heap_index-1 ; index >= alloc_index ; index-- )
254                {
255                    kernel_heap[x][y].free[index] = base;
256                    ptr = (unsigned int*)base;
257                    *ptr = 0;
258                    base = base + (1<<index);
259                }
260
261                kernel_heap[x][y].heap_base  = heap_base;
262                kernel_heap[x][y].heap_size  = heap_size;
263                kernel_heap[x][y].alloc_size = alloc_size;
264                kernel_heap[x][y].alloc_base = alloc_base;
265
266                // initialise lock
267                _spin_lock_init( &kernel_heap[x][y].lock );
268            }
269
270#if GIET_DEBUG_SYS_MALLOC
271_nolock_printf("\n[DEBUG KERNEL_MALLOC] Completing kernel_heap[%d][%d]"
272               " initialisation\n", x, y );
273_display_free_array(x,y);
274#endif
275               
276        }
277    }
278}  // end _heap_init()
279
280
281
282//////////////////////////////////////////////
283unsigned int _split_block( kernel_heap_t* heap,
284                           unsigned int   vaddr, 
285                           unsigned int   searched_index,
286                           unsigned int   requested_index )
287{
288    // push the upper half block into free[searched_index-1]
289    unsigned int* new            = (unsigned int*)(vaddr + (1<<(searched_index-1)));
290    *new                         = heap->free[searched_index-1]; 
291    heap->free[searched_index-1] = (unsigned int)new;
292       
293    if ( searched_index == requested_index + 1 )  //  return lower half block
294    {
295        return vaddr;
296    }
297    else            // non terminal case : lower half block must be split again
298    {                               
299        return _split_block( heap, vaddr, searched_index-1, requested_index );
300    }
301} // end _split_block()
302
303
304
305/////////////////////////////////////////////
306unsigned int _get_block( kernel_heap_t* heap,
307                         unsigned int   searched_index,
308                         unsigned int   requested_index )
309{
310    // test terminal case
311    if ( (1<<searched_index) > heap->heap_size )  // failure : return a NULL value
312    {
313        return 0;
314    }
315    else                            // search a block in free[searched_index]
316    {
317        unsigned int vaddr = heap->free[searched_index];
318        if ( vaddr == 0 )     // block not found : search in free[searched_index+1]
319        {
320            return _get_block( heap, searched_index+1, requested_index );
321        }
322        else                // block found : pop it from free[searched_index]
323        {
324            // pop the block from free[searched_index]
325            unsigned int next = *((unsigned int*)vaddr); 
326            heap->free[searched_index] = next;
327           
328            // test if the block must be split
329            if ( searched_index == requested_index )  // no split required
330            {
331                return vaddr;
332            }
333            else                                      // split is required
334            {
335                return _split_block( heap, vaddr, searched_index, requested_index );
336            }
337        } 
338    }
339} // end _get_block()
340
341
342
343////////////////////////////////////////
344void* _remote_malloc( unsigned int size,
345                      unsigned int x,
346                      unsigned int y ) 
347{
348    // checking arguments
349    if ( x >= X_SIZE )
350    {
351        _nolock_printf("\n[GIET ERROR] _remote_malloc() : x coordinate too large\n");
352        _exit();
353    }
354    if ( y >= Y_SIZE )
355    {
356        _nolock_printf("\n[GIET ERROR] _remote_malloc() : y coordinate too large\n");
357        _exit();
358    }
359    if ( kernel_heap[x][y].heap_size == 0 )
360    {
361        _nolock_printf("\n[GIET ERROR] _remote_malloc() : No heap[%d][%d]\n", x, y );
362        _exit();
363     
364    }
365
366    // normalize size
367    if ( size < MIN_BLOCK_SIZE ) size = MIN_BLOCK_SIZE;
368
369    // compute requested_index for the free[] array
370    unsigned int requested_index = GET_SIZE_INDEX( size );
371
372    // get the lock protecting heap[x][y]
373    _spin_lock_acquire( &kernel_heap[x][y].lock );
374
375    // call the recursive function get_block()
376    unsigned int base = _get_block( &kernel_heap[x][y], 
377                                    requested_index, 
378                                    requested_index );
379
380    // check block found
381    if ( base == 0 )
382    {
383        _nolock_printf("\n[GIET ERROR] in _remote_malloc() : "
384                       "no more space in kernel_heap[%d][%d]\n", x , y );
385        _spin_lock_release( &kernel_heap[x][y].lock );
386        _exit();
387    }
388
389    // compute pointer in alloc[] array
390    unsigned offset    = (base - kernel_heap[x][y].heap_base) / MIN_BLOCK_SIZE;
391    unsigned char* ptr = (unsigned char*)(kernel_heap[x][y].alloc_base + offset);
392
393    // check the alloc[] array
394    if ( *ptr != 0 )
395    {
396        _nolock_printf("\n[GIET ERROR] in _remote_malloc() for heap[%d][%d] "
397                       "selected block %X already allocated...\n", x , y , base );
398        _spin_lock_release( &kernel_heap[x][y].lock );
399        _exit();
400    }
401
402    // update alloc_array
403    *ptr = requested_index;
404
405    // release the lock
406    _spin_lock_release( &kernel_heap[x][y].lock );
407 
408#if GIET_DEBUG_SYS_MALLOC
409_nolock_printf("\n[DEBUG KERNEL_MALLOC] _remote-malloc()"
410               " / vaddr %x / size = %x from heap[%d][%d]\n", base , size, x , y );
411_display_free_array(x,y);
412#endif
413
414    return (void*)base;
415
416} // end _remote_malloc()
417
418
419
420//////////////////////////////////
421void* _malloc( unsigned int size )
422{
423    unsigned int procid  = _get_procid();
424    unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
425    unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
426
427    return _remote_malloc( size , x , y );
428
429}  // end _malloc()
430
431
432///////////////////////////////////////////////
433void _update_free_array( kernel_heap_t*  heap,
434                         unsigned int    base,
435                         unsigned int    size_index )
436{
437    // This recursive function try to merge the released block
438    // with the companion block if this companion block is free.
439    // This companion has the same size, and almost the same address
440    // (only one address bit is different)
441    // - If the companion is not in free[size_index],
442    //   the released block is pushed in free[size_index].
443    // - If the companion is found, it is evicted from free[size_index]
444    //   and the merged bloc is pushed in the free[size_index+1].
445
446    // compute released block size
447    unsigned int size = 1<<size_index;
448
449    // compute companion block and merged block base address
450    unsigned int companion_base; 
451    unsigned int merged_base; 
452
453    if ( (base & size) == 0 )   // the released block is aligned on (size*2)
454    {
455        companion_base  = base + size;
456        merged_base     = base;
457    }
458    else
459    {
460        companion_base  = base - size;
461        merged_base     = base - size;
462    }
463
464#if GIET_DEBUG_SYS_MALLOC > 1
465_nolock_printf("\n[DEBUG KERNEL_MALLOC] _update_free_array() :\n"
466               " - size           = %X\n"
467               " - released_base  = %X\n"
468               " - companion_base = %X\n"
469               " - merged_base    = %X\n",
470               size , base , companion_base , merged_base , (base & size) );
471#endif
472
473    // scan all blocks in free[size_index]
474    // the iter & prev variables are actually addresses
475    unsigned int  found = 0;
476    unsigned int  iter  = heap->free[size_index];
477    unsigned int  prev  = (unsigned int)(&heap->free[size_index]);
478    while ( iter ) 
479    {
480        if ( iter == companion_base ) 
481        {
482            found = 1;
483            break;
484        }
485        prev = iter;
486        iter = *(unsigned int*)iter;
487    }
488
489    if ( found == 0 )  // Companion not found => register in free[size_index]
490    {
491
492#if GIET_DEBUG_SYS_MALLOC > 1
493_nolock_printf("\n[DEBUG KERNEL_MALLOC] _update_free_array() : companion "
494               " not found => register block %x in free[%d]", base , size );
495#endif
496
497        // push the block in free[size_index] 
498        *(unsigned int*)base   = heap->free[size_index];
499        heap->free[size_index] = base;
500    }
501    else               // Companion found : merge and try in free[size_index + 1]
502    {
503        // pop the companion block (address == iter) from free[size_index]
504        *(unsigned int*)prev = *(unsigned int*)iter;
505
506        // call the update_free() function for free[size_index+1]
507        _update_free_array( heap, merged_base , size_index+1 );
508    }
509}  // end _update_free_array()
510
511
512
513///////////////////////
514void _free( void* ptr )
515{
516    // get cluster coordinates from ptr value
517    unsigned int x;
518    unsigned int y;
519    _sys_xy_from_ptr( ptr, &x, &y );
520
521    // check ptr value
522    unsigned int base = (unsigned int)ptr;
523    if ( (base < kernel_heap[x][y].heap_base) || 
524         (base >= (kernel_heap[x][y].heap_base + kernel_heap[x][y].heap_size)) )
525    {
526        _printf("\n[GIET ERROR] in _free() : illegal pointer for released block");
527        _exit();
528    }
529 
530    // get the lock protecting heap[x][y]
531    _spin_lock_acquire( &kernel_heap[x][y].lock );
532
533    // compute released block index in alloc[] array
534    unsigned index = (base - kernel_heap[x][y].heap_base ) / MIN_BLOCK_SIZE;
535 
536    // get the released block size_index
537    unsigned char* pchar      = (unsigned char*)(kernel_heap[x][y].alloc_base + index);
538    unsigned int   size_index = (unsigned int)*pchar;
539
540    // check block allocation
541    if ( size_index == 0 )
542    {
543        _printf("\n[GIET ERROR] in _free() : released block %X not allocated "
544                "in kernel_heap[%d][%d]\n", (unsigned int)ptr , x , y );
545        _spin_lock_release( &kernel_heap[x][y].lock );
546        _exit();
547    }
548
549    // check released block alignment
550    if ( base % (1 << size_index) )
551    {
552        _printf("\n[GIET ERROR] in _free() : released block %X not aligned "
553                "in kernel_heap[%d][%d]\n", (unsigned int)ptr , x , y );
554        _spin_lock_release( &kernel_heap[x][y].lock );
555        _exit();
556    }
557
558    // remove block from allocated blocks array
559    *pchar = 0;
560
561    // call the recursive function update_free_array()
562    _update_free_array( &kernel_heap[x][y] , base , size_index ); 
563
564    // release the lock
565    _spin_lock_release( &kernel_heap[x][y].lock );
566
567#if GIET_DEBUG_SYS_MALLOC
568_nolock_printf("\n[DEBUG KERNEL_MALLOC] _free() : vaddr = %x / size = %x "
569               "to heap[%d][%d]\n", (unsigned int)ptr , 1<<size_index , x , y );
570_display_free_array(x,y);
571#endif
572
573}  // end _free()
574
575// Local Variables:
576// tab-width: 4
577// c-basic-offset: 4
578// c-file-offsets:((innamespace . 0)(inline-open . 0))
579// indent-tabs-mode: nil
580// End:
581// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
582
583
584
Note: See TracBrowser for help on using the repository browser.