/* * 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 ///////////////////////////////////////////////////////////////////////////////////////////// // This global array is indexed by the Kernel Memory Object Type (defined in kmem.h) // It contains the size of fixed size objects type dynamically allocated by the KCMs. // This array should be consistent with the enum defined kmem.h. ///////////////////////////////////////////////////////////////////////////////////////////// uint32_t kmem_size_tbl[KMEM_TYPES_NR] = { 0, // 0 KMEM_PAGE is not a fixed size object 0, // 1 KMEM_GENERIC sizeof( kcm_t ), // 2 KMEM_KCM sizeof( vseg_t ), // 3 KMEM_VSEG sizeof( device_t ), // 4 KMEM_DEVICE sizeof( mapper_t ), // 5 KMEM_MAPPER sizeof( process_t ), // 6 KMEM_PROCESS 0, // 7 0, // 8 0, // 9 sizeof( fatfs_inode_t ), // 10 KMEM_FATFS_INODE sizeof( fatfs_ctx_t ), // 11 KMEM_FATFS_CTX sizeof( ramfs_inode_t ), // 12 KMEM_RAMFS_INODE sizeof( ramfs_ctx_t ), // 13 KMEM_RAMFS_CTX sizeof( vfs_ctx_t ), // 14 KMEM_VFS_CTX sizeof( vfs_inode_t ), // 15 KMEM_VFS_INODE sizeof( vfs_dentry_t ), // 16 KMEM_VFS_DENTRY sizeof( vfs_file_t ), // 17 KMEM_VFS_FILE sizeof( remote_sem_t ), // 18 KMEM_SEM 0, // 19 64, // 20 KMEM_64_BYTES 128, // 21 KMEM_128_BYTES 256, // 22 KMEM_256_BYTES 512, // 23 KMEM_512_BYTES 1024, // 24 KMEM_1024_BYTES 2048, // 25 KMEM_2048_BYTES }; ///////////////////////////////////////////////////////////////////////////////////////////// // 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_get_kcm( uint32_t type ) { kcm_t * kcm; error_t error; // check kmem object type if( (type < 2) || (type >= KMEM_TYPES_NR) ) { printk("\n[PANIC] in %s illegal request type\n", __FUNCTION__ ); hal_core_sleep(); } cluster_t * cluster = LOCAL_CLUSTER; // allocates memory for the requested KCM allocator 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; } // initializes the new KCM allocator error = kcm_init( kcm , type ); if( error ) { printk("\n[ERROR] in %s : failed to init KCM type %d\n", __FUNCTION__ , type , local_cxy ); return error; } cluster->kcm_tbl[type] = kcm; hal_wbflush(); return 0; } ///////////////////////////////////// void * kmem_alloc( kmem_req_t * req ) { cluster_t * cluster = LOCAL_CLUSTER; uint32_t type; uint32_t size; // ln( pages ) if PPM / bytes if KHM or BKM / unused if KCM uint32_t flags; void * ptr; // local pointer on allocated memory buffer type = req->type; size = req->size; flags = req->flags; kmem_dmsg("\n[INFO] %s in cluster %x : type %d, size %d, flags %x at cycle %d \n", __FUNCTION__, local_cxy , type, size, flags , hal_time_stamp() ); if( type >= KMEM_TYPES_NR ) { printk("\n[PANIC] in %s illegal request type\n", __FUNCTION__ ); hal_core_sleep(); } // analyse request type if( type == KMEM_PAGE ) // PPM allocator { // allocate the number of requested pages ptr = (void*)ppm_alloc_pages( size ); // reset page if required if( flags & AF_ZERO ) page_zero( (page_t*)ptr ); } else if( type == KMEM_GENERIC ) // KHM allocator { // allocate memory from KHM ptr = khm_alloc( &cluster->khm , size ); // reset memory if requested if( flags & AF_ZERO ) memset( ptr , 0 , size ); } else // KCM allocator { uint32_t error = 0; // initialize the KCM allocator if not already done if( cluster->kcm_tbl[type] == NULL ) { spinlock_lock( &cluster->kcm_lock ); error = kmem_get_kcm( type ); spinlock_unlock( &cluster->kcm_lock ); } // allocate memory from KCM if success if( error ) ptr = NULL; else ptr = kcm_alloc( cluster->kcm_tbl[type] ); } if( ptr == NULL ) { printk("\n[ERROR] in %s : failed for type %d, size %d, flags %x in cluster %x\n", __FUNCTION__ , type , size , flags , local_cxy ); return NULL; } kmem_dmsg("\n[INFO] %s got ptr = %x in cluster %x at cycle %d\n", __FUNCTION__, (intptr_t)ptr , local_cxy , hal_time_stamp() ); return ptr; } // end kmem_alloc() ////////////////////////////////// void kmem_free( kmem_req_t * req ) { if( req->type >= KMEM_TYPES_NR ) { printk("\n[PANIC] in %s : illegal request type\n", __FUNCTION__ ); hal_core_sleep(); } 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; } }