| 1 | /* | 
|---|
| 2 |  * sys_mmap.c - map files, memory or devices into process virtual address space | 
|---|
| 3 |  *  | 
|---|
| 4 |  * Authors       Ghassan Almaless (2008,2009,2010,2011,2012) | 
|---|
| 5 |  *               Alain Greiner (2016,2017) | 
|---|
| 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 |  | 
|---|
| 25 | #include <hal_types.h> | 
|---|
| 26 | #include <hal_uspace.h> | 
|---|
| 27 | #include <hal_irqmask.h> | 
|---|
| 28 | #include <shared_syscalls.h> | 
|---|
| 29 | #include <errno.h> | 
|---|
| 30 | #include <thread.h> | 
|---|
| 31 | #include <printk.h> | 
|---|
| 32 | #include <mapper.h> | 
|---|
| 33 | #include <vfs.h> | 
|---|
| 34 | #include <process.h> | 
|---|
| 35 | #include <vmm.h> | 
|---|
| 36 |  | 
|---|
| 37 | ////////////////////////////////// | 
|---|
| 38 | int sys_mmap( mmap_attr_t * attr ) | 
|---|
| 39 | { | 
|---|
| 40 |     vseg_t      * vseg; | 
|---|
| 41 |     cxy_t         vseg_cxy; | 
|---|
| 42 |     vseg_type_t   vseg_type; | 
|---|
| 43 |     mmap_attr_t   k_attr;       // attributes copy in kernel space | 
|---|
| 44 |     xptr_t        mapper_xp; | 
|---|
| 45 |     error_t       error; | 
|---|
| 46 |     paddr_t       paddr;        // unused, but required for user space checking | 
|---|
| 47 |     reg_t         save_sr;      // required to enable IRQs | 
|---|
| 48 |  | 
|---|
| 49 |         thread_t    * this    = CURRENT_THREAD; | 
|---|
| 50 |         process_t   * process = this->process; | 
|---|
| 51 |  | 
|---|
| 52 | #if CONFIG_DEBUG_SYS_MMAP | 
|---|
| 53 | uint64_t      tm_start; | 
|---|
| 54 | uint64_t      tm_end; | 
|---|
| 55 | tm_start = hal_get_cycles(); | 
|---|
| 56 | if ( CONFIG_DEBUG_SYS_MMAP < tm_start ) | 
|---|
| 57 | printk("\n[DBG] %s : thread %x enter / process %x / cycle %d\n", | 
|---|
| 58 | __FUNCTION__, this, process->pid, (uint32_t)tm_start ); | 
|---|
| 59 | #endif | 
|---|
| 60 |  | 
|---|
| 61 |     // check arguments in user space | 
|---|
| 62 |     error = vmm_v2p_translate( false , attr , &paddr ); | 
|---|
| 63 |  | 
|---|
| 64 |     if ( error ) | 
|---|
| 65 |     { | 
|---|
| 66 |  | 
|---|
| 67 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 68 | printk("\n[ERROR] in %s : arguments not in used space = %x\n", __FUNCTION__ , (intptr_t)attr ); | 
|---|
| 69 | #endif | 
|---|
| 70 |                 this->errno = EINVAL; | 
|---|
| 71 |                 return -1; | 
|---|
| 72 |     } | 
|---|
| 73 |  | 
|---|
| 74 |     // copy arguments from uspace | 
|---|
| 75 |     hal_copy_from_uspace( &k_attr , attr , sizeof(mmap_attr_t) ); | 
|---|
| 76 |  | 
|---|
| 77 |     // get fdid, offset, and length arguments | 
|---|
| 78 |     uint32_t fdid   = k_attr.fdid; | 
|---|
| 79 |     uint32_t offset = k_attr.offset; | 
|---|
| 80 |     uint32_t length = k_attr.length; | 
|---|
| 81 |  | 
|---|
| 82 |     // get flags | 
|---|
| 83 |     bool_t     map_fixed   = ( (k_attr.flags & MAP_FIXED)   != 0 ); | 
|---|
| 84 |     bool_t     map_anon    = ( (k_attr.flags & MAP_ANON)    != 0 ); | 
|---|
| 85 |     bool_t     map_remote  = ( (k_attr.flags & MAP_REMOTE)  != 0 ); | 
|---|
| 86 |     bool_t     map_shared  = ( (k_attr.flags & MAP_SHARED)  != 0 ); | 
|---|
| 87 |     bool_t     map_private = ( (k_attr.flags & MAP_PRIVATE) != 0 ); | 
|---|
| 88 |  | 
|---|
| 89 |     // MAP_FIXED not supported | 
|---|
| 90 |     if( map_fixed ) | 
|---|
| 91 |     { | 
|---|
| 92 |  | 
|---|
| 93 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 94 | printk("\n[ERROR] in %s : MAP_FIXED not supported\n", __FUNCTION__ ); | 
|---|
| 95 | #endif | 
|---|
| 96 |         this->errno = EINVAL; | 
|---|
| 97 |         return -1; | 
|---|
| 98 |     } | 
|---|
| 99 |  | 
|---|
| 100 |     if( map_shared == map_private ) | 
|---|
| 101 |     { | 
|---|
| 102 |  | 
|---|
| 103 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 104 | printk("\n[ERROR] in %s : MAP_SHARED xor MAP_PRIVATE\n", __FUNCTION__ ); | 
|---|
| 105 | #endif | 
|---|
| 106 |         this->errno = EINVAL; | 
|---|
| 107 |         return -1; | 
|---|
| 108 |     } | 
|---|
| 109 |  | 
|---|
| 110 |     // FIXME handle Copy_On_Write for MAP_PRIVATE... | 
|---|
| 111 |  | 
|---|
| 112 |     // get access rigths | 
|---|
| 113 |     bool_t     prot_read   = ( (k_attr.prot & PROT_READ )   != 0 ); | 
|---|
| 114 |     bool_t     prot_write  = ( (k_attr.prot & PROT_WRITE)   != 0 ); | 
|---|
| 115 |  | 
|---|
| 116 |     // test mmap type : can be FILE / ANON / REMOTE | 
|---|
| 117 |  | 
|---|
| 118 |     if( (map_anon == false) && (map_remote == false) )   // FILE | 
|---|
| 119 |     { | 
|---|
| 120 |             // FIXME: handle concurent delete of file by another thread closing it  | 
|---|
| 121 |  | 
|---|
| 122 |                 if( fdid >= CONFIG_PROCESS_FILE_MAX_NR )  | 
|---|
| 123 |                 { | 
|---|
| 124 |  | 
|---|
| 125 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 126 | printk("\n[ERROR] in %s: bad file descriptor = %d\n", __FUNCTION__ , fdid ); | 
|---|
| 127 | #endif | 
|---|
| 128 |             this->errno = EBADFD; | 
|---|
| 129 |             return -1; | 
|---|
| 130 |         } | 
|---|
| 131 |  | 
|---|
| 132 |         // get extended pointer on file descriptor | 
|---|
| 133 |         xptr_t file_xp = process_fd_get_xptr( process , fdid ); | 
|---|
| 134 |  | 
|---|
| 135 |         if( file_xp == XPTR_NULL ) | 
|---|
| 136 |         { | 
|---|
| 137 |  | 
|---|
| 138 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 139 | printk("\n[ERROR] in %s: file %d not found\n", __FUNCTION__ , fdid ); | 
|---|
| 140 | #endif | 
|---|
| 141 |             this->errno = EBADFD; | 
|---|
| 142 |             return -1; | 
|---|
| 143 |         } | 
|---|
| 144 |  | 
|---|
| 145 |         // get file cluster and local pointer | 
|---|
| 146 |         cxy_t        file_cxy = GET_CXY( file_xp ); | 
|---|
| 147 |         vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp ); | 
|---|
| 148 |  | 
|---|
| 149 |         // get inode pointer, mapper pointer and file attributes | 
|---|
| 150 |         vfs_inode_t * inode_ptr  = hal_remote_lpt(XPTR(file_cxy , &file_ptr->inode )); | 
|---|
| 151 |         uint32_t      file_attr  = hal_remote_lw (XPTR(file_cxy , &file_ptr->attr  )); | 
|---|
| 152 |         mapper_t    * mapper_ptr = hal_remote_lpt(XPTR(file_cxy , &file_ptr->mapper)); | 
|---|
| 153 |  | 
|---|
| 154 |         // get file size | 
|---|
| 155 |                 uint32_t size = hal_remote_lw( XPTR( file_cxy , &inode_ptr->size ) ); | 
|---|
| 156 |  | 
|---|
| 157 |         // chek offset and length arguments | 
|---|
| 158 |                 if( (offset + length) > size) | 
|---|
| 159 |                 { | 
|---|
| 160 |  | 
|---|
| 161 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 162 | printk("\n[ERROR] in %s: offset (%d) + len (%d) >= file's size (%d)\n",  | 
|---|
| 163 | __FUNCTION__, k_attr.offset, k_attr.length, size ); | 
|---|
| 164 | #endif | 
|---|
| 165 |             this->errno = ERANGE; | 
|---|
| 166 |             return -1; | 
|---|
| 167 |                 } | 
|---|
| 168 |  | 
|---|
| 169 |         // check access rights | 
|---|
| 170 |                 if( (prot_read  && !(file_attr & FD_ATTR_READ_ENABLE)) || | 
|---|
| 171 |                     (prot_write && !(file_attr & FD_ATTR_WRITE_ENABLE)) ) | 
|---|
| 172 |                 { | 
|---|
| 173 |  | 
|---|
| 174 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 175 | printk("\n[ERROR] in %s: prot = %x / file_attr = %x)\n",  | 
|---|
| 176 | __FUNCTION__ , k_attr.prot , file_attr ); | 
|---|
| 177 | #endif | 
|---|
| 178 |                         this->errno = EACCES; | 
|---|
| 179 |                         return -1; | 
|---|
| 180 |                 } | 
|---|
| 181 |  | 
|---|
| 182 |                 // increment file refcount | 
|---|
| 183 |                 vfs_file_count_up( file_xp ); | 
|---|
| 184 |  | 
|---|
| 185 |         mapper_xp = XPTR( file_cxy , mapper_ptr ); | 
|---|
| 186 |         vseg_type = VSEG_TYPE_FILE; | 
|---|
| 187 |         vseg_cxy  = file_cxy; | 
|---|
| 188 |     } | 
|---|
| 189 |     else                                                // ANON or REMOTE | 
|---|
| 190 |     { | 
|---|
| 191 |         // no mapper for ANON or REMOTE | 
|---|
| 192 |         mapper_xp = XPTR_NULL; | 
|---|
| 193 |  | 
|---|
| 194 |         if( map_anon ) | 
|---|
| 195 |         { | 
|---|
| 196 |             vseg_type = VSEG_TYPE_ANON; | 
|---|
| 197 |             vseg_cxy  = local_cxy; | 
|---|
| 198 |         } | 
|---|
| 199 |         else | 
|---|
| 200 |         { | 
|---|
| 201 |             vseg_type = VSEG_TYPE_REMOTE; | 
|---|
| 202 |             vseg_cxy  = k_attr.fdid; | 
|---|
| 203 |   | 
|---|
| 204 |             if( cluster_is_undefined( vseg_cxy ) ) | 
|---|
| 205 |             { | 
|---|
| 206 |  | 
|---|
| 207 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 208 | printk("\n[ERROR] in %s : illegal cxy for MAP_REMOTE\n", __FUNCTION__ ); | 
|---|
| 209 | #endif | 
|---|
| 210 |                 this->errno = EINVAL; | 
|---|
| 211 |                 return -1; | 
|---|
| 212 |             } | 
|---|
| 213 |         } | 
|---|
| 214 |     } | 
|---|
| 215 |  | 
|---|
| 216 |     // enable IRQs | 
|---|
| 217 |     hal_enable_irq( &save_sr ); | 
|---|
| 218 |  | 
|---|
| 219 |     // get reference process cluster and local pointer | 
|---|
| 220 |     xptr_t      ref_xp  = process->ref_xp; | 
|---|
| 221 |     cxy_t       ref_cxy = GET_CXY( ref_xp ); | 
|---|
| 222 |     process_t * ref_ptr = (process_t *)GET_PTR( ref_xp ); | 
|---|
| 223 |  | 
|---|
| 224 |     // create the vseg in reference cluster | 
|---|
| 225 |     if( local_cxy == ref_cxy ) | 
|---|
| 226 |     { | 
|---|
| 227 |         vseg = vmm_create_vseg( process, | 
|---|
| 228 |                                 vseg_type, | 
|---|
| 229 |                                 0,               // base address unused for mmap() | 
|---|
| 230 |                                 length, | 
|---|
| 231 |                                 offset, | 
|---|
| 232 |                                 0,               // file_size unused for mmap() | 
|---|
| 233 |                                 mapper_xp, | 
|---|
| 234 |                                 vseg_cxy ); | 
|---|
| 235 |     } | 
|---|
| 236 |     else | 
|---|
| 237 |     { | 
|---|
| 238 |         rpc_vmm_create_vseg_client( ref_cxy, | 
|---|
| 239 |                                     ref_ptr, | 
|---|
| 240 |                                     vseg_type, | 
|---|
| 241 |                                     0,            // base address unused for mmap() | 
|---|
| 242 |                                     length, | 
|---|
| 243 |                                     offset, | 
|---|
| 244 |                                     0,            // file size unused for mmap() | 
|---|
| 245 |                                     mapper_xp, | 
|---|
| 246 |                                     vseg_cxy, | 
|---|
| 247 |                                     &vseg );  | 
|---|
| 248 |     } | 
|---|
| 249 |      | 
|---|
| 250 |     // restore IRQs | 
|---|
| 251 |     hal_restore_irq( save_sr ); | 
|---|
| 252 |  | 
|---|
| 253 |     if( vseg == NULL ) | 
|---|
| 254 |     { | 
|---|
| 255 |  | 
|---|
| 256 | #if CONFIG_DEBUG_SYSCALLS_ERROR | 
|---|
| 257 | printk("\n[ERROR] in %s : cannot create vseg\n", __FUNCTION__ ); | 
|---|
| 258 | #endif | 
|---|
| 259 |         this->errno = ENOMEM; | 
|---|
| 260 |         return -1; | 
|---|
| 261 |     } | 
|---|
| 262 |  | 
|---|
| 263 |     // copy vseg base address to user space | 
|---|
| 264 |     hal_copy_to_uspace( &attr->addr , &vseg->min , sizeof(intptr_t) ); | 
|---|
| 265 |  | 
|---|
| 266 |     hal_fence(); | 
|---|
| 267 |  | 
|---|
| 268 | #if CONFIG_DEBUG_SYS_MMAP | 
|---|
| 269 | tm_end = hal_get_cycles(); | 
|---|
| 270 | if ( CONFIG_DEBUG_SYS_MMAP < tm_start ) | 
|---|
| 271 | printk("\n[DBG] %s : thread %x enter / process %x / cycle %d\n" | 
|---|
| 272 | "vseg %s / cluster %x / base %x / size %x / cost %d\n",  | 
|---|
| 273 | __FUNCTION__, this, process->pid, (uint32_t)tm_end, | 
|---|
| 274 | vseg_type_str(vseg->type), vseg->cxy, vseg->min, length, (uint32_t)(tm_end - tm_start) ); | 
|---|
| 275 | #endif | 
|---|
| 276 |  | 
|---|
| 277 |         return 0; | 
|---|
| 278 |  | 
|---|
| 279 | }  // end sys_mmap() | 
|---|
| 280 |  | 
|---|