source: trunk/kernel/mm/kmem.c @ 569

Last change on this file since 569 was 567, checked in by alain, 6 years ago

Complete restructuration of kernel locks.

File size: 9.9 KB
RevLine 
[1]1/*
2 * kmem.c - kernel memory allocator implementation.
3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
[567]5 *          Alain Greiner (2016,2017,2018)
[1]6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
[14]25#include <kernel_config.h>
[457]26#include <hal_kernel_types.h>
[1]27#include <hal_special.h>
28#include <printk.h>
[567]29#include <busylock.h>
[1]30#include <memcpy.h>
31#include <khm.h>
32#include <ppm.h>
33#include <page.h>
34#include <cluster.h>
35#include <thread.h>
36#include <process.h>
[7]37#include <chdev.h>
[1]38#include <mapper.h>
39#include <vfs.h>
40#include <fatfs.h>
41#include <ramfs.h>
42#include <remote_sem.h>
43#include <remote_barrier.h>
[23]44#include <remote_mutex.h>
45#include <remote_condvar.h>
[1]46#include <mapper.h>
47#include <grdxt.h>
48#include <vseg.h>
49#include <kmem.h>
50
[567]51/////////////////////////////////
[486]52void kmem_print_kcm_table( void )
[7]53{
[159]54        uint32_t    index;
55        kcm_t     * kcm;
56        cluster_t * cluster = LOCAL_CLUSTER;
[1]57
[159]58        printk("\n    *** KCM Pointers Table ***\n");
[7]59
[159]60        for( index = 0 ; index < KMEM_TYPES_NR ; index++ )
61        {
62                kcm = cluster->kcm_tbl[index];
63                if( kcm != NULL )
64                {
65                        if( index == kcm->type )
66                        {
67                                printk("     - KCM[%s] (at address %x) is OK\n",
68                                       kmem_type_str( index ) , (intptr_t)kcm );
69                        }
70                        else
71                        {
72                                printk("     - KCM[%s] (at address %x) is KO : has type %s\n",
73                                       kmem_type_str( index ) , (intptr_t)kcm , kmem_type_str( kcm->type ) );
74                        }
75                }
76        }
77}
[7]78
79/////////////////////////////////////////
80uint32_t  kmem_type_size( uint32_t type )
[1]81{
[188]82    if     ( type == KMEM_PAGE )          return CONFIG_PPM_PAGE_SIZE;
83    else if( type == KMEM_GENERIC )       return 0;
84    else if( type == KMEM_KCM )           return sizeof( kcm_t );
85    else if( type == KMEM_VSEG )          return sizeof( vseg_t );
86    else if( type == KMEM_DEVICE )        return sizeof( chdev_t );
87    else if( type == KMEM_MAPPER )        return sizeof( mapper_t );
88    else if( type == KMEM_PROCESS )       return sizeof( process_t );
89    else if( type == KMEM_CPU_CTX )       return CONFIG_CPU_CTX_SIZE;
90    else if( type == KMEM_FPU_CTX )       return CONFIG_FPU_CTX_SIZE;
91    else if( type == KMEM_BARRIER )       return sizeof( remote_barrier_t );
[1]92
[188]93    else if( type == KMEM_DEVFS_CTX )     return sizeof( fatfs_ctx_t );
94    else if( type == KMEM_FATFS_CTX )     return sizeof( fatfs_ctx_t );
95    else if( type == KMEM_VFS_CTX )       return sizeof( vfs_ctx_t );
96    else if( type == KMEM_VFS_INODE )     return sizeof( vfs_inode_t );
97    else if( type == KMEM_VFS_DENTRY )    return sizeof( vfs_dentry_t );
98    else if( type == KMEM_VFS_FILE )      return sizeof( vfs_file_t );
99    else if( type == KMEM_SEM )           return sizeof( remote_sem_t );
100    else if( type == KMEM_CONDVAR )       return sizeof( remote_condvar_t );
101    else if( type == KMEM_MUTEX )         return sizeof( remote_mutex_t );
[159]102        else if( type == KMEM_512_BYTES )     return 512;
[50]103
[159]104        else                                  return 0;
[18]105}
[1]106
[7]107/////////////////////////////////////
108char * kmem_type_str( uint32_t type )
109{
[159]110        if     ( type == KMEM_PAGE )          return "KMEM_PAGE";
111        else if( type == KMEM_GENERIC )       return "KMEM_GENERIC";
112        else if( type == KMEM_KCM )           return "KMEM_KCM";
113        else if( type == KMEM_VSEG )          return "KMEM_VSEG";
114        else if( type == KMEM_DEVICE )        return "KMEM_DEVICE";
115        else if( type == KMEM_MAPPER )        return "KMEM_MAPPER";
116        else if( type == KMEM_PROCESS )       return "KMEM_PROCESS";
117        else if( type == KMEM_CPU_CTX )       return "KMEM_CPU_CTX";
118        else if( type == KMEM_FPU_CTX )       return "KMEM_FPU_CTX";
119        else if( type == KMEM_BARRIER )       return "KMEM_BARRIER";
[1]120
[188]121    else if( type == KMEM_DEVFS_CTX )     return "KMEM_DEVFS_CTX";
122    else if( type == KMEM_FATFS_CTX )     return "KMEM_FATFS_CTX";
123    else if( type == KMEM_VFS_CTX )       return "KMEM_VFS_CTX";
124    else if( type == KMEM_VFS_INODE )     return "KMEM_VFS_INODE";
125    else if( type == KMEM_VFS_DENTRY )    return "KMEM_VFS_DENTRY";
126    else if( type == KMEM_VFS_FILE )      return "KMEM_VFS_FILE";
127    else if( type == KMEM_SEM )           return "KMEM_SEM";
128    else if( type == KMEM_CONDVAR )       return "KMEM_CONDVAR";
129    else if( type == KMEM_MUTEX )         return "KMEM_MUTEX";
[159]130        else if( type == KMEM_512_BYTES )     return "KMEM_512_BYTES";
[50]131
[159]132        else                                  return "undefined";
[7]133}
134
[1]135/////////////////////////////////////////////////////////////////////////////////////////////
136// This static function dynamically allocates and initializes a specific KCM allocator.
137// It uses the KCM allocator embedded in cluster manager, initialized by cluster_init().
138/////////////////////////////////////////////////////////////////////////////////////////////
[7]139static error_t kmem_create_kcm( uint32_t type )
[1]140{
141        kcm_t    * kcm;
142
[492]143        assert( ((type > 1) && (type < KMEM_TYPES_NR) ) , "illegal KCM type" );
[1]144
[438]145#if DEBUG_KMEM
[435]146uint32_t cycle = (uint32_t)hal_get_cycles();
[438]147if( DEBUG_KMEM < cycle )
[435]148printk("\n[DBG] %s : thread %x enter / KCM type %s missing in cluster %x / cycle %d\n",
149__FUNCTION__, CURRENT_THREAD, kmem_type_str( type ), local_cxy, cycle );
150#endif
[7]151
[159]152        cluster_t * cluster = LOCAL_CLUSTER;
[1]153
[180]154        // allocate memory for the requested KCM allocator
[159]155        // from the KCM allocator embedded in cluster descriptor
[1]156        kcm = kcm_alloc( &cluster->kcm );
[7]157
[1]158        if( kcm == NULL )
[159]159        {
[1]160                printk("\n[ERROR] in %s : failed to create KCM type %d in cluster %x\n",
[159]161                       __FUNCTION__ , type , local_cxy );
162                return ENOMEM;
163        }
[1]164
[180]165        // initialize the new KCM allocator
[7]166        kcm_init( kcm , type );
[1]167
[567]168        // register it in the KCM pointers Table
[7]169        cluster->kcm_tbl[type] = kcm;
[1]170
[124]171        hal_fence();
[1]172
[438]173#if DEBUG_KMEM
[435]174cycle = (uint32_t)hal_get_cycles();
[438]175if( DEBUG_KMEM < cycle )
[435]176printk("\n[DBG] %s : thread %x exit / cycle %d\n",
177__FUNCTION__, CURRENT_THREAD, cycle );
178#endif
[7]179
[1]180        return 0;
[159]181}
[7]182
[1]183/////////////////////////////////////
184void * kmem_alloc( kmem_req_t * req )
185{
186        cluster_t * cluster = LOCAL_CLUSTER;
187
188        uint32_t    type;
189        uint32_t    flags;
[7]190        uint32_t    size;    // ln( pages ) if PPM / bytes if KHM / unused if KCM
191        void      * ptr;     // memory buffer if KHM or KCM / page descriptor if PPM
[551]192        uint32_t    irq_state;
[1]193
[7]194
[1]195        type  = req->type;
196        size  = req->size;
197        flags = req->flags;
[18]198
[492]199        assert( (type < KMEM_TYPES_NR) , "illegal KMEM request type" );
[18]200
[438]201#if DEBUG_KMEM
[435]202uint32_t cycle = (uint32_t)hal_get_cycles();
[438]203if( DEBUG_KMEM < cycle )
[435]204printk("\n[DBG] %s : thread %x enter / type %s / cluster %x / cycle %d\n",
205__FUNCTION__, CURRENT_THREAD, kmem_type_str( type ), local_cxy, cycle );
206#endif
[1]207
[159]208        // analyse request type
[180]209        if( type == KMEM_PAGE )                        // PPM allocator
[159]210        {
211                // allocate the number of requested pages
[7]212                ptr = (void *)ppm_alloc_pages( size );
[180]213                if( ptr == NULL )
214                {
215                        printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
216                            __FUNCTION__ , type , size , local_cxy );
217                        return NULL;
218                }
[1]219
[159]220                // reset page if requested
[7]221                if( flags & AF_ZERO ) page_zero( (page_t *)ptr );
[18]222
[438]223#if DEBUG_KMEM
[435]224cycle = (uint32_t)hal_get_cycles();
[438]225if( DEBUG_KMEM < cycle )
[435]226printk("\n[DBG] %s : thread %x exit / %d page(s) allocated / ppn %x / cycle %d\n",
227__FUNCTION__, CURRENT_THREAD, 1<<size, ppm_page2ppn(XPTR(local_cxy,ptr)), cycle );
[433]228#endif
229
[1]230        }
[159]231        else if( type == KMEM_GENERIC )                // KHM allocator
232        {
233                // allocate memory from KHM
[1]234                ptr = khm_alloc( &cluster->khm , size );
[180]235                if( ptr == NULL )
236                {
237                        printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
238                            __FUNCTION__ , type , size , local_cxy );
239                        return NULL;
240                }
[1]241
[159]242                // reset memory if requested
[1]243                if( flags & AF_ZERO ) memset( ptr , 0 , size );
[7]244
[438]245#if DEBUG_KMEM
[435]246cycle = (uint32_t)hal_get_cycles();
[438]247if( DEBUG_KMEM < cycle )
[435]248printk("\n[DBG] %s : thread %x exit / type %s allocated / base %x / size %d / cycle %d\n",
249__FUNCTION__, CURRENT_THREAD, kmem_type_str( type ), (intptr_t)ptr, size, cycle );
250#endif
251
[1]252        }
[159]253        else                                           // KCM allocator
254        {
255                // initialize the KCM allocator if not already done
256                if( cluster->kcm_tbl[type] == NULL )
257                {
[567]258            // get lock protecting local kcm_tbl[] array
259                        busylock_acquire( &cluster->kcm_lock );
260
261            // create missing KCM
[7]262                        error_t error = kmem_create_kcm( type );
[567]263
264            // release lock protecting local kcm_tbl[] array
265                        busylock_release( &cluster->kcm_lock );
266
267                        if ( error ) 
268            {
269                 printk("\n[ERROR] in %s : cannot create KCM type %d in cluster %x\n",
270                 __FUNCTION__, type, local_cxy );
271                 return NULL;
272            }
[159]273                }
[1]274
[159]275                // allocate memory from KCM
276                ptr = kcm_alloc( cluster->kcm_tbl[type] );
[180]277                if( ptr == NULL )
278                {
279                        printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
[567]280                    __FUNCTION__ , type , size , local_cxy );
[180]281                        return NULL;
282                }
[7]283
[159]284                // reset memory if requested
[7]285                if( flags & AF_ZERO ) memset( ptr , 0 , kmem_type_size( type ) );
286
[438]287#if DEBUG_KMEM
[435]288cycle = (uint32_t)hal_get_cycles();
[438]289if( DEBUG_KMEM < cycle )
[435]290printk("\n[DBG] %s : thread %x exit / type %s allocated / base %x / size %d / cycle %d\n",
291__FUNCTION__, CURRENT_THREAD, kmem_type_str(type), (intptr_t)ptr, 
292kmem_type_size(type), cycle );
293#endif
294
[1]295        }
296
297        return ptr;
[159]298}
[1]299
300//////////////////////////////////
301void kmem_free( kmem_req_t * req )
302{
303        if( req->type >= KMEM_TYPES_NR )
[159]304        {
[492]305                assert( false , "illegal request type\n" );
[159]306        }
[18]307
[1]308        switch(req->type)
309        {
[159]310                case KMEM_PAGE:
[181]311                        ppm_free_pages( (page_t*)req->ptr );
312                        return;
[1]313
[159]314                case KMEM_GENERIC:
[181]315                        khm_free( req->ptr );
316                        return;
[1]317
[159]318                default:
[181]319                        kcm_free( req->ptr );
320                        return;
[1]321        }
322}
323
Note: See TracBrowser for help on using the repository browser.