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

Last change on this file since 634 was 619, checked in by alain, 6 years ago

1) Fix a bug in KSH : after the "load" command,

the [ksh] prompt is now printed after completion
of the loaded application.

2) Fix a bug in vmm_handle_cow() : the copy-on-write

use now a hal_remote_memcpy() to replicate the page content.


File size: 10.4 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>
[612]42#include <user_dir.h>
[1]43#include <remote_sem.h>
44#include <remote_barrier.h>
[23]45#include <remote_mutex.h>
46#include <remote_condvar.h>
[1]47#include <mapper.h>
48#include <grdxt.h>
49#include <vseg.h>
50#include <kmem.h>
51
[567]52/////////////////////////////////
[486]53void kmem_print_kcm_table( void )
[7]54{
[159]55        uint32_t    index;
56        kcm_t     * kcm;
57        cluster_t * cluster = LOCAL_CLUSTER;
[1]58
[159]59        printk("\n    *** KCM Pointers Table ***\n");
[7]60
[159]61        for( index = 0 ; index < KMEM_TYPES_NR ; index++ )
62        {
63                kcm = cluster->kcm_tbl[index];
64                if( kcm != NULL )
65                {
66                        if( index == kcm->type )
67                        {
68                                printk("     - KCM[%s] (at address %x) is OK\n",
69                                       kmem_type_str( index ) , (intptr_t)kcm );
70                        }
71                        else
72                        {
73                                printk("     - KCM[%s] (at address %x) is KO : has type %s\n",
74                                       kmem_type_str( index ) , (intptr_t)kcm , kmem_type_str( kcm->type ) );
75                        }
76                }
77        }
78}
[7]79
80/////////////////////////////////////////
81uint32_t  kmem_type_size( uint32_t type )
[1]82{
[188]83    if     ( type == KMEM_PAGE )          return CONFIG_PPM_PAGE_SIZE;
84    else if( type == KMEM_GENERIC )       return 0;
85    else if( type == KMEM_KCM )           return sizeof( kcm_t );
86    else if( type == KMEM_VSEG )          return sizeof( vseg_t );
87    else if( type == KMEM_DEVICE )        return sizeof( chdev_t );
88    else if( type == KMEM_MAPPER )        return sizeof( mapper_t );
89    else if( type == KMEM_PROCESS )       return sizeof( process_t );
90    else if( type == KMEM_CPU_CTX )       return CONFIG_CPU_CTX_SIZE;
91    else if( type == KMEM_FPU_CTX )       return CONFIG_FPU_CTX_SIZE;
[619]92    else if( type == KMEM_GEN_BARRIER )   return sizeof( generic_barrier_t );
[1]93
[619]94    else if( type == KMEM_SMP_BARRIER )   return sizeof( simple_barrier_t );
[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 );
[619]104
[612]105    else if( type == KMEM_DIR )           return sizeof( user_dir_t );
[159]106        else if( type == KMEM_512_BYTES )     return 512;
[50]107
[159]108        else                                  return 0;
[18]109}
[1]110
[7]111/////////////////////////////////////
112char * kmem_type_str( uint32_t type )
113{
[159]114        if     ( type == KMEM_PAGE )          return "KMEM_PAGE";
115        else if( type == KMEM_GENERIC )       return "KMEM_GENERIC";
116        else if( type == KMEM_KCM )           return "KMEM_KCM";
117        else if( type == KMEM_VSEG )          return "KMEM_VSEG";
118        else if( type == KMEM_DEVICE )        return "KMEM_DEVICE";
119        else if( type == KMEM_MAPPER )        return "KMEM_MAPPER";
120        else if( type == KMEM_PROCESS )       return "KMEM_PROCESS";
121        else if( type == KMEM_CPU_CTX )       return "KMEM_CPU_CTX";
122        else if( type == KMEM_FPU_CTX )       return "KMEM_FPU_CTX";
[619]123        else if( type == KMEM_GEN_BARRIER )   return "KMEM_GEN_BARRIER";
[1]124
[619]125    else if( type == KMEM_SMP_BARRIER )   return "KMEM_SMP_BARRIER";
[188]126    else if( type == KMEM_DEVFS_CTX )     return "KMEM_DEVFS_CTX";
127    else if( type == KMEM_FATFS_CTX )     return "KMEM_FATFS_CTX";
128    else if( type == KMEM_VFS_CTX )       return "KMEM_VFS_CTX";
129    else if( type == KMEM_VFS_INODE )     return "KMEM_VFS_INODE";
130    else if( type == KMEM_VFS_DENTRY )    return "KMEM_VFS_DENTRY";
131    else if( type == KMEM_VFS_FILE )      return "KMEM_VFS_FILE";
132    else if( type == KMEM_SEM )           return "KMEM_SEM";
133    else if( type == KMEM_CONDVAR )       return "KMEM_CONDVAR";
134    else if( type == KMEM_MUTEX )         return "KMEM_MUTEX";
[619]135
[611]136    else if( type == KMEM_DIR )           return "KMEM_DIR";
[159]137        else if( type == KMEM_512_BYTES )     return "KMEM_512_BYTES";
[50]138
[159]139        else                                  return "undefined";
[7]140}
141
[1]142/////////////////////////////////////////////////////////////////////////////////////////////
143// This static function dynamically allocates and initializes a specific KCM allocator.
144// It uses the KCM allocator embedded in cluster manager, initialized by cluster_init().
145/////////////////////////////////////////////////////////////////////////////////////////////
[7]146static error_t kmem_create_kcm( uint32_t type )
[1]147{
148        kcm_t    * kcm;
149
[492]150        assert( ((type > 1) && (type < KMEM_TYPES_NR) ) , "illegal KCM type" );
[1]151
[438]152#if DEBUG_KMEM
[611]153thread_t * this = CURRENT_THREAD;
[435]154uint32_t cycle = (uint32_t)hal_get_cycles();
[438]155if( DEBUG_KMEM < cycle )
[611]156printk("\n[%s] thread[%x,%x] enter / KCM type %s missing in cluster %x / cycle %d\n",
157__FUNCTION__, this->process->pid, this->trdid, kmem_type_str( type ), local_cxy, cycle );
[435]158#endif
[7]159
[159]160        cluster_t * cluster = LOCAL_CLUSTER;
[1]161
[180]162        // allocate memory for the requested KCM allocator
[159]163        // from the KCM allocator embedded in cluster descriptor
[1]164        kcm = kcm_alloc( &cluster->kcm );
[7]165
[1]166        if( kcm == NULL )
[159]167        {
[1]168                printk("\n[ERROR] in %s : failed to create KCM type %d in cluster %x\n",
[159]169                       __FUNCTION__ , type , local_cxy );
170                return ENOMEM;
171        }
[1]172
[180]173        // initialize the new KCM allocator
[7]174        kcm_init( kcm , type );
[1]175
[567]176        // register it in the KCM pointers Table
[7]177        cluster->kcm_tbl[type] = kcm;
[1]178
[124]179        hal_fence();
[1]180
[438]181#if DEBUG_KMEM
[435]182cycle = (uint32_t)hal_get_cycles();
[438]183if( DEBUG_KMEM < cycle )
[611]184printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
185__FUNCTION__, this->process->pid, this->trdid, cycle );
[435]186#endif
[7]187
[1]188        return 0;
[159]189}
[7]190
[1]191/////////////////////////////////////
192void * kmem_alloc( kmem_req_t * req )
193{
194        cluster_t * cluster = LOCAL_CLUSTER;
195
196        uint32_t    type;
197        uint32_t    flags;
[7]198        uint32_t    size;    // ln( pages ) if PPM / bytes if KHM / unused if KCM
199        void      * ptr;     // memory buffer if KHM or KCM / page descriptor if PPM
[1]200
201        type  = req->type;
202        size  = req->size;
203        flags = req->flags;
[18]204
[492]205        assert( (type < KMEM_TYPES_NR) , "illegal KMEM request type" );
[18]206
[438]207#if DEBUG_KMEM
[611]208thread_t * this = CURRENT_THREAD;
[435]209uint32_t cycle = (uint32_t)hal_get_cycles();
[438]210if( DEBUG_KMEM < cycle )
[611]211printk("\n[%s] thread [%x,%x] enter / %s / size %d / cluster %x / cycle %d\n",
212__FUNCTION__, this->process->pid, this->trdid, 
213kmem_type_str( type ), size, local_cxy, cycle );
[435]214#endif
[1]215
[159]216        // analyse request type
[180]217        if( type == KMEM_PAGE )                        // PPM allocator
[159]218        {
219                // allocate the number of requested pages
[7]220                ptr = (void *)ppm_alloc_pages( size );
[180]221                if( ptr == NULL )
222                {
223                        printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
224                            __FUNCTION__ , type , size , local_cxy );
225                        return NULL;
226                }
[1]227
[159]228                // reset page if requested
[7]229                if( flags & AF_ZERO ) page_zero( (page_t *)ptr );
[18]230
[438]231#if DEBUG_KMEM
[435]232cycle = (uint32_t)hal_get_cycles();
[438]233if( DEBUG_KMEM < cycle )
[611]234printk("\n[%s] thread[%x,%x] exit / %d page(s) allocated / ppn %x / cycle %d\n",
235__FUNCTION__, this->process->pid, this->trdid,
2361<<size, ppm_page2ppn(XPTR(local_cxy,ptr)), cycle );
[433]237#endif
238
[1]239        }
[159]240        else if( type == KMEM_GENERIC )                // KHM allocator
241        {
242                // allocate memory from KHM
[1]243                ptr = khm_alloc( &cluster->khm , size );
[180]244                if( ptr == NULL )
245                {
246                        printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
247                            __FUNCTION__ , type , size , local_cxy );
248                        return NULL;
249                }
[1]250
[159]251                // reset memory if requested
[1]252                if( flags & AF_ZERO ) memset( ptr , 0 , size );
[7]253
[438]254#if DEBUG_KMEM
[435]255cycle = (uint32_t)hal_get_cycles();
[438]256if( DEBUG_KMEM < cycle )
[611]257printk("\n[%s] thread[%x,%x] exit / type %s allocated / base %x / size %d / cycle %d\n",
258__FUNCTION__, this->process->pid, this->trdid, 
259kmem_type_str( type ), (intptr_t)ptr, size, cycle );
[435]260#endif
261
[1]262        }
[159]263        else                                           // KCM allocator
264        {
265                // initialize the KCM allocator if not already done
266                if( cluster->kcm_tbl[type] == NULL )
267                {
[567]268            // get lock protecting local kcm_tbl[] array
269                        busylock_acquire( &cluster->kcm_lock );
270
271            // create missing KCM
[7]272                        error_t error = kmem_create_kcm( type );
[567]273
274            // release lock protecting local kcm_tbl[] array
275                        busylock_release( &cluster->kcm_lock );
276
277                        if ( error ) 
278            {
279                 printk("\n[ERROR] in %s : cannot create KCM type %d in cluster %x\n",
280                 __FUNCTION__, type, local_cxy );
281                 return NULL;
282            }
[159]283                }
[1]284
[159]285                // allocate memory from KCM
286                ptr = kcm_alloc( cluster->kcm_tbl[type] );
[180]287                if( ptr == NULL )
288                {
289                        printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
[567]290                    __FUNCTION__ , type , size , local_cxy );
[180]291                        return NULL;
292                }
[7]293
[159]294                // reset memory if requested
[7]295                if( flags & AF_ZERO ) memset( ptr , 0 , kmem_type_size( type ) );
296
[438]297#if DEBUG_KMEM
[435]298cycle = (uint32_t)hal_get_cycles();
[438]299if( DEBUG_KMEM < cycle )
[611]300printk("\n[%s] thread [%x,%x] exit / type %s allocated / base %x / size %d / cycle %d\n",
301__FUNCTION__, this->process->pid, this->trdid, kmem_type_str(type), (intptr_t)ptr, 
[435]302kmem_type_size(type), cycle );
303#endif
304
[1]305        }
306
307        return ptr;
[159]308}
[1]309
310//////////////////////////////////
311void kmem_free( kmem_req_t * req )
312{
313        if( req->type >= KMEM_TYPES_NR )
[159]314        {
[492]315                assert( false , "illegal request type\n" );
[159]316        }
[18]317
[1]318        switch(req->type)
319        {
[159]320                case KMEM_PAGE:
[181]321                        ppm_free_pages( (page_t*)req->ptr );
322                        return;
[1]323
[159]324                case KMEM_GENERIC:
[181]325                        khm_free( req->ptr );
326                        return;
[1]327
[159]328                default:
[181]329                        kcm_free( req->ptr );
330                        return;
[1]331        }
332}
333
Note: See TracBrowser for help on using the repository browser.