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

Last change on this file since 560 was 551, checked in by nicolas.van.phan@…, 6 years ago

Make locks before IDLE Init busy

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