| 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 |  | 
|---|
| 26 | #include <almos_config.h> | 
|---|
| 27 | #include <hal_types.h> | 
|---|
| 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> | 
|---|
| 39 | #include <device.h> | 
|---|
| 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> | 
|---|
| 46 | #include <mapper.h> | 
|---|
| 47 | #include <grdxt.h> | 
|---|
| 48 | #include <vseg.h> | 
|---|
| 49 | #include <kmem.h> | 
|---|
| 50 |  | 
|---|
| 51 | ///////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 52 | // This global array is indexed by the Kernel Memory Object Type (defined in kmem.h) | 
|---|
| 53 | // It contains the size of fixed size objects type dynamically allocated by the KCMs. | 
|---|
| 54 | // This array should be consistent with the enum defined kmem.h. | 
|---|
| 55 | ///////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 56 |  | 
|---|
| 57 | uint32_t  kmem_size_tbl[KMEM_TYPES_NR] = | 
|---|
| 58 | { | 
|---|
| 59 |     0,                        // 0  KMEM_PAGE is not a fixed size object | 
|---|
| 60 |     0,                        // 1  KMEM_GENERIC    | 
|---|
| 61 |     sizeof( kcm_t ),          // 2  KMEM_KCM | 
|---|
| 62 |     sizeof( vseg_t ),         // 3  KMEM_VSEG | 
|---|
| 63 |     sizeof( device_t ),       // 4  KMEM_DEVICE | 
|---|
| 64 |     sizeof( mapper_t ),       // 5  KMEM_MAPPER | 
|---|
| 65 |     sizeof( process_t ),      // 6  KMEM_PROCESS | 
|---|
| 66 |     0,                        // 7  | 
|---|
| 67 |     0,                        // 8   | 
|---|
| 68 |     0,                        // 9   | 
|---|
| 69 |  | 
|---|
| 70 |     sizeof( fatfs_inode_t ),  // 10 KMEM_FATFS_INODE | 
|---|
| 71 |     sizeof( fatfs_ctx_t ),    // 11 KMEM_FATFS_CTX | 
|---|
| 72 |     sizeof( ramfs_inode_t ),  // 12 KMEM_RAMFS_INODE | 
|---|
| 73 |     sizeof( ramfs_ctx_t ),    // 13 KMEM_RAMFS_CTX | 
|---|
| 74 |     sizeof( vfs_ctx_t ),      // 14 KMEM_VFS_CTX | 
|---|
| 75 |     sizeof( vfs_inode_t ),    // 15 KMEM_VFS_INODE | 
|---|
| 76 |     sizeof( vfs_dentry_t ),   // 16 KMEM_VFS_DENTRY | 
|---|
| 77 |     sizeof( vfs_file_t ),     // 17 KMEM_VFS_FILE | 
|---|
| 78 |     sizeof( remote_sem_t ),   // 18 KMEM_SEM | 
|---|
| 79 |     0,                        // 19  | 
|---|
| 80 |  | 
|---|
| 81 |     64,                       // 20 KMEM_64_BYTES | 
|---|
| 82 |     128,                      // 21 KMEM_128_BYTES | 
|---|
| 83 |     256,                      // 22 KMEM_256_BYTES | 
|---|
| 84 |     512,                      // 23 KMEM_512_BYTES | 
|---|
| 85 |     1024,                     // 24 KMEM_1024_BYTES | 
|---|
| 86 |     2048,                     // 25 KMEM_2048_BYTES | 
|---|
| 87 | }; | 
|---|
| 88 |  | 
|---|
| 89 | ///////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 90 | // This static function dynamically allocates and initializes a specific KCM allocator. | 
|---|
| 91 | // It uses the KCM allocator embedded in cluster manager, initialized by cluster_init(). | 
|---|
| 92 | ///////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 93 | static error_t kmem_get_kcm( uint32_t type ) | 
|---|
| 94 | { | 
|---|
| 95 |         kcm_t    * kcm; | 
|---|
| 96 |         error_t    error; | 
|---|
| 97 |  | 
|---|
| 98 |     // check kmem object type | 
|---|
| 99 |     if( (type < 2) || (type >= KMEM_TYPES_NR) ) | 
|---|
| 100 |     { | 
|---|
| 101 |         printk("\n[PANIC] in %s illegal request type\n", __FUNCTION__ ); | 
|---|
| 102 |         hal_core_sleep(); | 
|---|
| 103 |     } | 
|---|
| 104 |  | 
|---|
| 105 |     cluster_t * cluster = LOCAL_CLUSTER; | 
|---|
| 106 |  | 
|---|
| 107 |     // allocates memory for the requested KCM allocator | 
|---|
| 108 |         kcm = kcm_alloc( &cluster->kcm ); | 
|---|
| 109 |         if( kcm == NULL ) | 
|---|
| 110 |     { | 
|---|
| 111 |                 printk("\n[ERROR] in %s : failed to create KCM type %d in cluster %x\n", | 
|---|
| 112 |                __FUNCTION__ , type , local_cxy ); | 
|---|
| 113 |         return ENOMEM; | 
|---|
| 114 |     } | 
|---|
| 115 |  | 
|---|
| 116 |     // initializes the new KCM allocator  | 
|---|
| 117 |         error = kcm_init( kcm , type ); | 
|---|
| 118 |  | 
|---|
| 119 |         if( error ) | 
|---|
| 120 |         { | 
|---|
| 121 |                 printk("\n[ERROR] in %s : failed to init KCM type %d\n", | 
|---|
| 122 |                __FUNCTION__ , type , local_cxy ); | 
|---|
| 123 |                 return error; | 
|---|
| 124 |         } | 
|---|
| 125 |  | 
|---|
| 126 |         cluster->kcm_tbl[type] = kcm; | 
|---|
| 127 |         hal_wbflush(); | 
|---|
| 128 |  | 
|---|
| 129 |         return 0; | 
|---|
| 130 | } | 
|---|
| 131 |   | 
|---|
| 132 |  | 
|---|
| 133 | ///////////////////////////////////// | 
|---|
| 134 | void * kmem_alloc( kmem_req_t * req ) | 
|---|
| 135 | { | 
|---|
| 136 |         cluster_t * cluster = LOCAL_CLUSTER; | 
|---|
| 137 |  | 
|---|
| 138 |         uint32_t    type; | 
|---|
| 139 |         uint32_t    size;    // ln( pages ) if PPM / bytes if KHM or BKM / unused if KCM | 
|---|
| 140 |         uint32_t    flags; | 
|---|
| 141 |         void      * ptr;     // local pointer on allocated memory buffer | 
|---|
| 142 |  | 
|---|
| 143 |         type  = req->type; | 
|---|
| 144 |         size  = req->size; | 
|---|
| 145 |         flags = req->flags; | 
|---|
| 146 |    | 
|---|
| 147 |         kmem_dmsg("\n[INFO] %s in cluster %x : type %d, size %d, flags %x at cycle %d \n", | 
|---|
| 148 |                       __FUNCTION__, local_cxy , type, size, flags , hal_time_stamp() ); | 
|---|
| 149 |  | 
|---|
| 150 |         if( type >= KMEM_TYPES_NR ) | 
|---|
| 151 |     { | 
|---|
| 152 |         printk("\n[PANIC] in %s illegal request type\n", __FUNCTION__ ); | 
|---|
| 153 |         hal_core_sleep(); | 
|---|
| 154 |     } | 
|---|
| 155 |    | 
|---|
| 156 |     // analyse request type | 
|---|
| 157 |         if( type ==  KMEM_PAGE )                       // PPM allocator | 
|---|
| 158 |     {         | 
|---|
| 159 |         // allocate the number of requested pages | 
|---|
| 160 |                 ptr = (void*)ppm_alloc_pages( size ); | 
|---|
| 161 |  | 
|---|
| 162 |         // reset page if required | 
|---|
| 163 |                 if( flags & AF_ZERO ) page_zero( (page_t*)ptr ); | 
|---|
| 164 |         } | 
|---|
| 165 |     else if( type == KMEM_GENERIC )                // KHM allocator | 
|---|
| 166 |     { | 
|---|
| 167 |         // allocate memory from KHM | 
|---|
| 168 |                 ptr = khm_alloc( &cluster->khm , size ); | 
|---|
| 169 |  | 
|---|
| 170 |         // reset memory if requested | 
|---|
| 171 |                 if( flags & AF_ZERO ) memset( ptr , 0 , size ); | 
|---|
| 172 |         } | 
|---|
| 173 |     else                                           // KCM allocator | 
|---|
| 174 |     { | 
|---|
| 175 |         uint32_t error = 0; | 
|---|
| 176 |  | 
|---|
| 177 |         // initialize the KCM allocator if not already done | 
|---|
| 178 |             if( cluster->kcm_tbl[type] == NULL ) | 
|---|
| 179 |             {  | 
|---|
| 180 |             spinlock_lock( &cluster->kcm_lock ); | 
|---|
| 181 |                         error = kmem_get_kcm( type ); | 
|---|
| 182 |             spinlock_unlock( &cluster->kcm_lock ); | 
|---|
| 183 |             } | 
|---|
| 184 |  | 
|---|
| 185 |         // allocate memory from KCM if success | 
|---|
| 186 |         if( error ) ptr = NULL; | 
|---|
| 187 |         else        ptr = kcm_alloc( cluster->kcm_tbl[type] ); | 
|---|
| 188 |         } | 
|---|
| 189 |  | 
|---|
| 190 |     if( ptr == NULL ) | 
|---|
| 191 |     { | 
|---|
| 192 |             printk("\n[ERROR] in %s : failed for type %d, size %d, flags %x in cluster %x\n",  | 
|---|
| 193 |                __FUNCTION__ , type , size , flags , local_cxy ); | 
|---|
| 194 |   | 
|---|
| 195 |             return NULL; | 
|---|
| 196 |     } | 
|---|
| 197 |  | 
|---|
| 198 |         kmem_dmsg("\n[INFO] %s got ptr = %x in cluster %x at cycle %d\n", | 
|---|
| 199 |                   __FUNCTION__, (intptr_t)ptr , local_cxy , hal_time_stamp() ); | 
|---|
| 200 |              | 
|---|
| 201 |         return ptr; | 
|---|
| 202 |  | 
|---|
| 203 | } // end kmem_alloc() | 
|---|
| 204 |  | 
|---|
| 205 | ////////////////////////////////// | 
|---|
| 206 | void kmem_free( kmem_req_t * req ) | 
|---|
| 207 | { | 
|---|
| 208 |         if( req->type >= KMEM_TYPES_NR ) | 
|---|
| 209 |     { | 
|---|
| 210 |         printk("\n[PANIC] in %s : illegal request type\n", __FUNCTION__ ); | 
|---|
| 211 |         hal_core_sleep(); | 
|---|
| 212 |     } | 
|---|
| 213 |    | 
|---|
| 214 |         switch(req->type) | 
|---|
| 215 |         { | 
|---|
| 216 |             case KMEM_PAGE: | 
|---|
| 217 |                 ppm_free_pages( (page_t*)req->ptr ); | 
|---|
| 218 |                 return; | 
|---|
| 219 |  | 
|---|
| 220 |             case KMEM_GENERIC: | 
|---|
| 221 |             khm_free( req->ptr ); | 
|---|
| 222 |                 return; | 
|---|
| 223 |  | 
|---|
| 224 |             default: | 
|---|
| 225 |                 kcm_free( req->ptr ); | 
|---|
| 226 |                 return; | 
|---|
| 227 |         } | 
|---|
| 228 | } | 
|---|
| 229 |  | 
|---|
| 230 |  | 
|---|