/* * kmem.c - kernel memory allocator implementation. * * Authors Ghassan Almaless (2008,2009,2010,2011,2012) * Mohamed Lamine Karaoui (2015) * Alain Greiner (2016) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////// void kmem_print_kcm_table() { uint32_t index; kcm_t * kcm; cluster_t * cluster = LOCAL_CLUSTER; printk("\n *** KCM Pointers Table ***\n"); for( index = 0 ; index < KMEM_TYPES_NR ; index++ ) { kcm = cluster->kcm_tbl[index]; if( kcm != NULL ) { if( index == kcm->type ) { printk(" - KCM[%s] (at address %x) is OK\n", kmem_type_str( index ) , (intptr_t)kcm ); } else { printk(" - KCM[%s] (at address %x) is KO : has type %s\n", kmem_type_str( index ) , (intptr_t)kcm , kmem_type_str( kcm->type ) ); } } } } ///////////////////////////////////////// uint32_t kmem_type_size( uint32_t type ) { if ( type == KMEM_PAGE ) return CONFIG_PPM_PAGE_SIZE; else if( type == KMEM_GENERIC ) return 0; else if( type == KMEM_KCM ) return sizeof( kcm_t ); else if( type == KMEM_VSEG ) return sizeof( vseg_t ); else if( type == KMEM_DEVICE ) return sizeof( chdev_t ); else if( type == KMEM_MAPPER ) return sizeof( mapper_t ); else if( type == KMEM_PROCESS ) return sizeof( process_t ); else if( type == KMEM_CPU_CTX ) return CONFIG_CPU_CTX_SIZE; else if( type == KMEM_FPU_CTX ) return CONFIG_FPU_CTX_SIZE; else if( type == KMEM_BARRIER ) return sizeof( remote_barrier_t ); else if( type == KMEM_DEVFS_CTX ) return sizeof( fatfs_ctx_t ); else if( type == KMEM_FATFS_CTX ) return sizeof( fatfs_ctx_t ); else if( type == KMEM_VFS_CTX ) return sizeof( vfs_ctx_t ); else if( type == KMEM_VFS_INODE ) return sizeof( vfs_inode_t ); else if( type == KMEM_VFS_DENTRY ) return sizeof( vfs_dentry_t ); else if( type == KMEM_VFS_FILE ) return sizeof( vfs_file_t ); else if( type == KMEM_SEM ) return sizeof( remote_sem_t ); else if( type == KMEM_CONDVAR ) return sizeof( remote_condvar_t ); else if( type == KMEM_MUTEX ) return sizeof( remote_mutex_t ); else if( type == KMEM_512_BYTES ) return 512; else return 0; } ///////////////////////////////////// char * kmem_type_str( uint32_t type ) { if ( type == KMEM_PAGE ) return "KMEM_PAGE"; else if( type == KMEM_GENERIC ) return "KMEM_GENERIC"; else if( type == KMEM_KCM ) return "KMEM_KCM"; else if( type == KMEM_VSEG ) return "KMEM_VSEG"; else if( type == KMEM_DEVICE ) return "KMEM_DEVICE"; else if( type == KMEM_MAPPER ) return "KMEM_MAPPER"; else if( type == KMEM_PROCESS ) return "KMEM_PROCESS"; else if( type == KMEM_CPU_CTX ) return "KMEM_CPU_CTX"; else if( type == KMEM_FPU_CTX ) return "KMEM_FPU_CTX"; else if( type == KMEM_BARRIER ) return "KMEM_BARRIER"; else if( type == KMEM_DEVFS_CTX ) return "KMEM_DEVFS_CTX"; else if( type == KMEM_FATFS_CTX ) return "KMEM_FATFS_CTX"; else if( type == KMEM_VFS_CTX ) return "KMEM_VFS_CTX"; else if( type == KMEM_VFS_INODE ) return "KMEM_VFS_INODE"; else if( type == KMEM_VFS_DENTRY ) return "KMEM_VFS_DENTRY"; else if( type == KMEM_VFS_FILE ) return "KMEM_VFS_FILE"; else if( type == KMEM_SEM ) return "KMEM_SEM"; else if( type == KMEM_CONDVAR ) return "KMEM_CONDVAR"; else if( type == KMEM_MUTEX ) return "KMEM_MUTEX"; else if( type == KMEM_512_BYTES ) return "KMEM_512_BYTES"; else return "undefined"; } ///////////////////////////////////////////////////////////////////////////////////////////// // This static function dynamically allocates and initializes a specific KCM allocator. // It uses the KCM allocator embedded in cluster manager, initialized by cluster_init(). ///////////////////////////////////////////////////////////////////////////////////////////// static error_t kmem_create_kcm( uint32_t type ) { kcm_t * kcm; assert( ((type > 1) && (type < KMEM_TYPES_NR) ) , __FUNCTION__ , "illegal KCM type" ); kmem_dmsg("\n[DBG] %s : enters / KCM type %s missing in cluster %x\n", __FUNCTION__ , kmem_type_str( type ) , local_cxy ); cluster_t * cluster = LOCAL_CLUSTER; // allocate memory for the requested KCM allocator // from the KCM allocator embedded in cluster descriptor kcm = kcm_alloc( &cluster->kcm ); if( kcm == NULL ) { printk("\n[ERROR] in %s : failed to create KCM type %d in cluster %x\n", __FUNCTION__ , type , local_cxy ); return ENOMEM; } // initialize the new KCM allocator kcm_init( kcm , type ); // register it if the KCM pointers Table cluster->kcm_tbl[type] = kcm; hal_fence(); kmem_dmsg("\n[DBG] %s : exit / KCM type %s created in cluster %x\n", __FUNCTION__ , kmem_type_str( type ) , local_cxy ); return 0; } ///////////////////////////////////// void * kmem_alloc( kmem_req_t * req ) { cluster_t * cluster = LOCAL_CLUSTER; uint32_t type; uint32_t flags; uint32_t size; // ln( pages ) if PPM / bytes if KHM / unused if KCM void * ptr; // memory buffer if KHM or KCM / page descriptor if PPM type = req->type; size = req->size; flags = req->flags; assert( (type < KMEM_TYPES_NR) , __FUNCTION__ , "illegal KMEM request type" ); kmem_dmsg("\n[DBG] %s : enters in cluster %x for type %s\n", __FUNCTION__ , local_cxy , kmem_type_str( type ) ); // analyse request type if( type == KMEM_PAGE ) // PPM allocator { // allocate the number of requested pages ptr = (void *)ppm_alloc_pages( size ); if( ptr == NULL ) { printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n", __FUNCTION__ , type , size , local_cxy ); return NULL; } // reset page if requested if( flags & AF_ZERO ) page_zero( (page_t *)ptr ); kmem_dmsg("\n[DBG] %s : exit in cluster %x for type %s / page = %x / base = %x\n", __FUNCTION__, local_cxy , kmem_type_str( type ) , (intptr_t)ptr , (intptr_t)ppm_page2base( ptr ) ); } else if( type == KMEM_GENERIC ) // KHM allocator { // allocate memory from KHM ptr = khm_alloc( &cluster->khm , size ); if( ptr == NULL ) { printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n", __FUNCTION__ , type , size , local_cxy ); return NULL; } // reset memory if requested if( flags & AF_ZERO ) memset( ptr , 0 , size ); kmem_dmsg("\n[DBG] %s : exit in cluster %x for type %s / base = %x / size = %d\n", __FUNCTION__, local_cxy , kmem_type_str( type ) , (intptr_t)ptr , req->size ); } else // KCM allocator { // initialize the KCM allocator if not already done if( cluster->kcm_tbl[type] == NULL ) { spinlock_lock( &cluster->kcm_lock ); error_t error = kmem_create_kcm( type ); spinlock_unlock( &cluster->kcm_lock ); if ( error ) return NULL; } // allocate memory from KCM ptr = kcm_alloc( cluster->kcm_tbl[type] ); if( ptr == NULL ) { printk("\n[ERROR] in %s : failed for type %d / size %d in cluster %x\n", __FUNCTION__ , type , size , local_cxy ); return NULL; } // reset memory if requested if( flags & AF_ZERO ) memset( ptr , 0 , kmem_type_size( type ) ); kmem_dmsg("\n[DBG] %s : exit in cluster %x for type %s / base = %x / size = %d\n", __FUNCTION__, local_cxy , kmem_type_str( type ) , (intptr_t)ptr , kmem_type_size( type ) ); } return ptr; } ////////////////////////////////// void kmem_free( kmem_req_t * req ) { if( req->type >= KMEM_TYPES_NR ) { panic("illegal request type"); } switch(req->type) { case KMEM_PAGE: ppm_free_pages( (page_t*)req->ptr ); return; case KMEM_GENERIC: khm_free( req->ptr ); return; default: kcm_free( req->ptr ); return; } }