Changeset 635 for trunk/kernel/mm/kmem.c


Ignore:
Timestamp:
Jun 26, 2019, 11:42:37 AM (5 years ago)
Author:
alain
Message:

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/mm/kmem.c

    r619 r635  
    22 * kmem.c - kernel memory allocator implementation.
    33 *
    4  * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
    5  *          Alain Greiner (2016,2017,2018)
     4 * Authors  Alain Greiner (2016,2017,2018,2019)
    65 *
    76 * Copyright (c) UPMC Sorbonne Universites
     
    2726#include <hal_special.h>
    2827#include <printk.h>
    29 #include <busylock.h>
     28#include <cluster.h>
    3029#include <memcpy.h>
    3130#include <khm.h>
    3231#include <ppm.h>
     32#include <kcm.h>
    3333#include <page.h>
    34 #include <cluster.h>
    35 #include <thread.h>
    36 #include <process.h>
    37 #include <chdev.h>
    38 #include <mapper.h>
    39 #include <vfs.h>
    40 #include <fatfs.h>
    41 #include <ramfs.h>
    42 #include <user_dir.h>
    43 #include <remote_sem.h>
    44 #include <remote_barrier.h>
    45 #include <remote_mutex.h>
    46 #include <remote_condvar.h>
    47 #include <mapper.h>
    48 #include <grdxt.h>
    49 #include <vseg.h>
    5034#include <kmem.h>
    51 
    52 /////////////////////////////////
    53 void kmem_print_kcm_table( void )
    54 {
    55         uint32_t    index;
    56         kcm_t     * kcm;
    57         cluster_t * cluster = LOCAL_CLUSTER;
    58 
    59         printk("\n    *** KCM Pointers Table ***\n");
    60 
    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 }
    79 
    80 /////////////////////////////////////////
    81 uint32_t  kmem_type_size( uint32_t type )
    82 {
    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;
    92     else if( type == KMEM_GEN_BARRIER )   return sizeof( generic_barrier_t );
    93 
    94     else if( type == KMEM_SMP_BARRIER )   return sizeof( simple_barrier_t );
    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 );
    104 
    105     else if( type == KMEM_DIR )           return sizeof( user_dir_t );
    106         else if( type == KMEM_512_BYTES )     return 512;
    107 
    108         else                                  return 0;
    109 }
    110 
    111 /////////////////////////////////////
    112 char * kmem_type_str( uint32_t type )
    113 {
    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";
    123         else if( type == KMEM_GEN_BARRIER )   return "KMEM_GEN_BARRIER";
    124 
    125     else if( type == KMEM_SMP_BARRIER )   return "KMEM_SMP_BARRIER";
    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";
    135 
    136     else if( type == KMEM_DIR )           return "KMEM_DIR";
    137         else if( type == KMEM_512_BYTES )     return "KMEM_512_BYTES";
    138 
    139         else                                  return "undefined";
    140 }
    141 
    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 /////////////////////////////////////////////////////////////////////////////////////////////
    146 static error_t kmem_create_kcm( uint32_t type )
    147 {
    148         kcm_t    * kcm;
    149 
    150         assert( ((type > 1) && (type < KMEM_TYPES_NR) ) , "illegal KCM type" );
    151 
    152 #if DEBUG_KMEM
    153 thread_t * this = CURRENT_THREAD;
    154 uint32_t cycle = (uint32_t)hal_get_cycles();
    155 if( DEBUG_KMEM < cycle )
    156 printk("\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 );
    158 #endif
    159 
    160         cluster_t * cluster = LOCAL_CLUSTER;
    161 
    162         // allocate memory for the requested KCM allocator
    163         // from the KCM allocator embedded in cluster descriptor
    164         kcm = kcm_alloc( &cluster->kcm );
    165 
    166         if( kcm == NULL )
    167         {
    168                 printk("\n[ERROR] in %s : failed to create KCM type %d in cluster %x\n",
    169                        __FUNCTION__ , type , local_cxy );
    170                 return ENOMEM;
    171         }
    172 
    173         // initialize the new KCM allocator
    174         kcm_init( kcm , type );
    175 
    176         // register it in the KCM pointers Table
    177         cluster->kcm_tbl[type] = kcm;
    178 
    179         hal_fence();
    180 
    181 #if DEBUG_KMEM
    182 cycle = (uint32_t)hal_get_cycles();
    183 if( DEBUG_KMEM < cycle )
    184 printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
    185 __FUNCTION__, this->process->pid, this->trdid, cycle );
    186 #endif
    187 
    188         return 0;
    189 }
    19035
    19136/////////////////////////////////////
    19237void * kmem_alloc( kmem_req_t * req )
    19338{
    194         cluster_t * cluster = LOCAL_CLUSTER;
    195 
    196         uint32_t    type;
    197         uint32_t    flags;
    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
     39        uint32_t    type;    // KMEM_PPM / KMEM_KCM / KMEM_KHM
     40        uint32_t    flags;   // AF_NONE / AF_ZERO / AF_KERNEL
     41        uint32_t    order;   // PPM: ln(pages) / KCM: ln(bytes) / KHM: bytes
    20042
    20143        type  = req->type;
    202         size  = req->size;
     44        order = req->order;
    20345        flags = req->flags;
    20446
    205         assert( (type < KMEM_TYPES_NR) , "illegal KMEM request type" );
     47    ////////////////////////////////// PPM
     48        if( type == KMEM_PPM )
     49        {
     50                // allocate the number of requested pages
     51                page_t * page_ptr = (void *)ppm_alloc_pages( order );
     52
     53                if( page_ptr == NULL )
     54                {
     55                        printk("\n[ERROR] in %s : PPM failed / order %d / cluster %x\n",
     56                        __FUNCTION__ , order , local_cxy );
     57                        return NULL;
     58                }
     59
     60        xptr_t page_xp = XPTR( local_cxy , page_ptr );
     61
     62                // reset page if requested
     63                if( flags & AF_ZERO ) page_zero( page_ptr );
     64
     65        // get pointer on buffer from the page descriptor
     66        void * ptr = GET_PTR( ppm_page2base( page_xp ) );
    20667
    20768#if DEBUG_KMEM
    208 thread_t * this = CURRENT_THREAD;
    209 uint32_t cycle = (uint32_t)hal_get_cycles();
     69thread_t * this  = CURRENT_THREAD;
     70uint32_t   cycle = (uint32_t)hal_get_cycles();
    21071if( DEBUG_KMEM < cycle )
    211 printk("\n[%s] thread [%x,%x] enter / %s / size %d / cluster %x / cycle %d\n",
     72printk("\n[%s] thread[%x,%x] from PPM / %d page(s) / ppn %x / cxy %x / cycle %d\n",
     73__FUNCTION__, this->process->pid, this->trdid,
     741<<order, ppm_page2ppn(XPTR(local_cxy,ptr)), local_cxy, cycle );
     75#endif
     76        return ptr;
     77        }
     78    ///////////////////////////////////// KCM
     79        else if( type == KMEM_KCM )
     80        {
     81                // allocate memory from KCM
     82                void * ptr = kcm_alloc( order );
     83
     84                if( ptr == NULL )
     85                {
     86                        printk("\n[ERROR] in %s : KCM failed / order %d / cluster %x\n",
     87                    __FUNCTION__ , order , local_cxy );
     88                        return NULL;
     89                }
     90
     91                // reset memory if requested
     92                if( flags & AF_ZERO ) memset( ptr , 0 , 1<<order );
     93
     94#if DEBUG_KMEM
     95thread_t * this  = CURRENT_THREAD;
     96uint32_t   cycle = (uint32_t)hal_get_cycles();
     97if( DEBUG_KMEM < cycle )
     98printk("\n[%s] thread [%x,%x] from KCM / %d bytes / base %x / cxy %x / cycle %d\n",
     99__FUNCTION__, this->process->pid, this->trdid,
     1001<<order, ptr, local_cxy, cycle );
     101#endif
     102        return ptr;
     103        }
     104    //////////////////////////////////// KHM
     105        else if( type == KMEM_KHM )
     106        {
     107                // allocate memory from KHM
     108                void * ptr = khm_alloc( &LOCAL_CLUSTER->khm , order );
     109
     110                if( ptr == NULL )
     111                {
     112                        printk("\n[ERROR] in %s : KHM failed / order %d / cluster %x\n",
     113                        __FUNCTION__ , order , local_cxy );
     114                        return NULL;
     115                }
     116
     117                // reset memory if requested
     118                if( flags & AF_ZERO ) memset( ptr , 0 , order );
     119
     120#if DEBUG_KMEM
     121thread_t * this  = CURRENT_THREAD;
     122uint32_t   cycle = (uint32_t)hal_get_cycles();
     123if( DEBUG_KMEM < cycle )
     124printk("\n[%s] thread[%x,%x] from KHM / %d bytes / base %x / cxy %x / cycle %d\n",
    212125__FUNCTION__, this->process->pid, this->trdid,
    213 kmem_type_str( type ), size, local_cxy, cycle );
    214 #endif
    215 
    216         // analyse request type
    217         if( type == KMEM_PAGE )                        // PPM allocator
    218         {
    219                 // allocate the number of requested pages
    220                 ptr = (void *)ppm_alloc_pages( size );
    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                 }
    227 
    228                 // reset page if requested
    229                 if( flags & AF_ZERO ) page_zero( (page_t *)ptr );
    230 
    231 #if DEBUG_KMEM
    232 cycle = (uint32_t)hal_get_cycles();
    233 if( DEBUG_KMEM < cycle )
    234 printk("\n[%s] thread[%x,%x] exit / %d page(s) allocated / ppn %x / cycle %d\n",
    235 __FUNCTION__, this->process->pid, this->trdid,
    236 1<<size, ppm_page2ppn(XPTR(local_cxy,ptr)), cycle );
    237 #endif
    238 
    239         }
    240         else if( type == KMEM_GENERIC )                // KHM allocator
    241         {
    242                 // allocate memory from KHM
    243                 ptr = khm_alloc( &cluster->khm , size );
    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                 }
    250 
    251                 // reset memory if requested
    252                 if( flags & AF_ZERO ) memset( ptr , 0 , size );
    253 
    254 #if DEBUG_KMEM
    255 cycle = (uint32_t)hal_get_cycles();
    256 if( DEBUG_KMEM < cycle )
    257 printk("\n[%s] thread[%x,%x] exit / type %s allocated / base %x / size %d / cycle %d\n",
    258 __FUNCTION__, this->process->pid, this->trdid,
    259 kmem_type_str( type ), (intptr_t)ptr, size, cycle );
    260 #endif
    261 
    262         }
    263         else                                           // KCM allocator
    264         {
    265                 // initialize the KCM allocator if not already done
    266                 if( cluster->kcm_tbl[type] == NULL )
    267                 {
    268             // get lock protecting local kcm_tbl[] array
    269                         busylock_acquire( &cluster->kcm_lock );
    270 
    271             // create missing KCM
    272                         error_t error = kmem_create_kcm( type );
    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             }
    283                 }
    284 
    285                 // allocate memory from KCM
    286                 ptr = kcm_alloc( cluster->kcm_tbl[type] );
    287                 if( ptr == NULL )
    288                 {
    289                         printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n",
    290                     __FUNCTION__ , type , size , local_cxy );
    291                         return NULL;
    292                 }
    293 
    294                 // reset memory if requested
    295                 if( flags & AF_ZERO ) memset( ptr , 0 , kmem_type_size( type ) );
    296 
    297 #if DEBUG_KMEM
    298 cycle = (uint32_t)hal_get_cycles();
    299 if( DEBUG_KMEM < cycle )
    300 printk("\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,
    302 kmem_type_size(type), cycle );
    303 #endif
    304 
    305         }
    306 
    307         return ptr;
    308 }
     126order, ptr, local_cxy, cycle );
     127#endif
     128        return ptr;
     129        }
     130    else
     131    {
     132        printk("\n[ERROR] in %s : illegal allocator type\n", __FUNCTION__);
     133        return NULL;
     134    }
     135}  // end kmem_alloc()
    309136
    310137//////////////////////////////////
    311138void kmem_free( kmem_req_t * req )
    312139{
    313         if( req->type >= KMEM_TYPES_NR )
    314         {
    315                 assert( false , "illegal request type\n" );
    316         }
    317 
    318         switch(req->type)
    319         {
    320                 case KMEM_PAGE:
    321                         ppm_free_pages( (page_t*)req->ptr );
    322                         return;
    323 
    324                 case KMEM_GENERIC:
    325                         khm_free( req->ptr );
    326                         return;
    327 
    328                 default:
    329                         kcm_free( req->ptr );
    330                         return;
    331         }
    332 }
    333 
     140    uint32_t type = req->type;
     141
     142        if( type == KMEM_PPM )
     143        {
     144        page_t * page = GET_PTR( ppm_base2page( XPTR( local_cxy , req->ptr ) ) );
     145
     146        ppm_free_pages( page );
     147    }
     148    else if( type == KMEM_KCM )
     149    {
     150        kcm_free( req->ptr );
     151        }
     152    else if( type == KMEM_KHM )
     153    {
     154        khm_free( req->ptr );
     155    }
     156    else
     157    {
     158        printk("\n[ERROR] in %s : illegal allocator type\n", __FUNCTION__);
     159    }
     160}  // end kmem_free()
     161
     162///////////////////////////////////////////
     163void * kmem_remote_alloc( cxy_t        cxy,
     164                          kmem_req_t * req )
     165{
     166        uint32_t    type;    // KMEM_PPM / KMEM_KCM / KMEM_KHM
     167        uint32_t    flags;   // AF_ZERO / AF_KERNEL / AF_NONE
     168        uint32_t    order;   // PPM: ln(pages) / KCM: ln(bytes) / KHM: bytes
     169
     170        type  = req->type;
     171        order = req->order;
     172        flags = req->flags;
     173
     174        ///////////////////////////////// PPM
     175        if( type == KMEM_PPM )
     176        {
     177                // allocate the number of requested pages
     178                page_t * page_ptr = ppm_remote_alloc_pages( cxy , order );
     179
     180                if( page_ptr == NULL )
     181                {
     182                        printk("\n[ERROR] in %s : failed for PPM / order %d in cluster %x\n",
     183                        __FUNCTION__ , order , cxy );
     184                        return NULL;
     185                }
     186
     187        xptr_t page_xp = XPTR( cxy , page_ptr );
     188
     189        // get pointer on buffer from the page descriptor
     190        xptr_t base_xp = ppm_page2base( page_xp );
     191
     192                // reset page if requested
     193                if( flags & AF_ZERO ) hal_remote_memset( base_xp , 0 , CONFIG_PPM_PAGE_SIZE );
     194
     195        void * ptr = GET_PTR( base_xp );
     196
     197#if DEBUG_KMEM_REMOTE
     198thread_t * this = CURRENT_THREAD;
     199uint32_t   cycle = (uint32_t)hal_get_cycles();
     200if( DEBUG_KMEM_REMOTE < cycle )
     201printk("\n[%s] thread[%x,%x] from PPM / %d page(s) / ppn %x / cxy %x / cycle %d\n",
     202__FUNCTION__, this->process->pid, this->trdid,
     2031<<order, ppm_page2ppn(XPTR(local_cxy,ptr)), cxy, cycle );
     204#endif
     205        return ptr;
     206        }
     207    /////////////////////////////////// KCM
     208        else if( type == KMEM_KCM )
     209        {
     210                // allocate memory from KCM
     211                void * ptr = kcm_remote_alloc( cxy , order );
     212
     213                if( ptr == NULL )
     214                {
     215                        printk("\n[ERROR] in %s : failed for KCM / order %d in cluster %x\n",
     216                    __FUNCTION__ , order , cxy );
     217                        return NULL;
     218                }
     219
     220                // reset memory if requested
     221                if( flags & AF_ZERO )  hal_remote_memset( XPTR( cxy , ptr ) , 0 , 1<<order );
     222
     223#if DEBUG_KMEM_REMOTE
     224thread_t * this = CURRENT_THREAD;
     225uint32_t   cycle = (uint32_t)hal_get_cycles();
     226if( DEBUG_KMEM_REMOTE < cycle )
     227printk("\n[%s] thread [%x,%x] from KCM / %d bytes / base %x / cxy %x / cycle %d\n",
     228__FUNCTION__, this->process->pid, this->trdid,
     2291<<order, ptr, cxy, cycle );
     230#endif
     231        return ptr;
     232        }
     233        /////////////////////////////////// KHM
     234        else if( type == KMEM_KHM )               
     235        {
     236        printk("\n[ERROR] in %s : remote access not supported for KHM\n", __FUNCTION__  );
     237                return NULL;
     238        }
     239    else
     240    {
     241        printk("\n[ERROR] in %s : illegal allocator type\n", __FUNCTION__);
     242        return NULL;
     243    }
     244}  // kmem_remote_malloc()
     245
     246////////////////////////////////////////
     247void kmem_remote_free( cxy_t        cxy,
     248                       kmem_req_t * req )
     249{
     250    uint32_t type = req->type;
     251
     252        if( type == KMEM_PPM )
     253        {
     254        page_t * page = GET_PTR( ppm_base2page( XPTR( cxy , req->ptr ) ) );
     255
     256        ppm_remote_free_pages( cxy , page );
     257    }
     258    else if( type == KMEM_KCM )
     259    {
     260        kcm_remote_free( cxy , req->ptr );
     261        }
     262    else if( type == KMEM_KHM )
     263    {
     264        printk("\n[ERROR] in %s : remote access not supported for KHM\n", __FUNCTION__ );
     265    }
     266    else
     267    {
     268        printk("\n[ERROR] in %s : illegal allocator type\n", __FUNCTION__);
     269    }
     270}  // end kmem_remote_free()
     271
     272
     273
Note: See TracChangeset for help on using the changeset viewer.