source: trunk/kernel/syscalls/sys_mmap.c @ 625

Last change on this file since 625 was 625, checked in by alain, 5 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 9.9 KB
RevLine 
[1]1/*
[23]2 * sys_mmap.c - map files, memory or devices into process virtual address space
[1]3 *
[625]4 * Authors       Alain Greiner (2016,2017,2018,2019)
[1]5 *
[23]6 * Copyright (c) UPMC Sorbonne Universites
[1]7 *
[23]8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
[1]11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
[23]14 * ALMOS-MKH is distributed in the hope that it will be useful, but
[1]15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
[23]20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
[1]21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[457]24#include <hal_kernel_types.h>
[407]25#include <hal_uspace.h>
[625]26#include <hal_vmm.h>
[435]27#include <hal_irqmask.h>
[407]28#include <shared_syscalls.h>
[1]29#include <errno.h>
30#include <thread.h>
[23]31#include <printk.h>
[407]32#include <mapper.h>
[1]33#include <vfs.h>
34#include <process.h>
35#include <vmm.h>
36
[506]37#include <syscalls.h>
38
[407]39//////////////////////////////////
[23]40int sys_mmap( mmap_attr_t * attr )
[1]41{
[407]42    vseg_t      * vseg;
43    cxy_t         vseg_cxy;
44    vseg_type_t   vseg_type;
45    mmap_attr_t   k_attr;       // attributes copy in kernel space
46    xptr_t        mapper_xp;
47    error_t       error;
[435]48    reg_t         save_sr;      // required to enable IRQs
[1]49
[407]50        thread_t    * this    = CURRENT_THREAD;
51        process_t   * process = this->process;
52
[594]53#if (DEBUG_SYS_MMAP || CONFIG_INSTRUMENTATION_SYSCALLS)
54uint64_t     tm_start = hal_get_cycles();
55#endif
56
[438]57#if DEBUG_SYS_MMAP
[623]58if( DEBUG_SYS_MMAP < tm_start )
[594]59printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
60__FUNCTION__, process->pid, this->trdid, (uint32_t)tm_start );
[435]61#endif
62
[594]63    // check user buffer (containing attributes) is mapped
[440]64    error = vmm_get_vseg( process , (intptr_t)attr , &vseg );
[407]65
[594]66    if( error )
[407]67    {
[435]68
[438]69#if DEBUG_SYSCALLS_ERROR
[594]70printk("\n[ERROR] in %s : thread[%x,%x] / mmap attributes unmapped %x\n",
71__FUNCTION__ , process->pid, this->trdid, (intptr_t)attr );
[624]72hal_vmm_display( process , false );
[435]73#endif
[407]74                this->errno = EINVAL;
75                return -1;
76    }
77
[594]78    // copy attributes from user space to kernel space
[407]79    hal_copy_from_uspace( &k_attr , attr , sizeof(mmap_attr_t) );
80
[594]81    // get addr, fdid, offset, and length attributes
82    uint32_t  fdid   = k_attr.fdid;
83    uint32_t  offset = k_attr.offset;
84    uint32_t  length = k_attr.length;
[407]85
86    // get flags
87    bool_t     map_fixed   = ( (k_attr.flags & MAP_FIXED)   != 0 );
88    bool_t     map_anon    = ( (k_attr.flags & MAP_ANON)    != 0 );
89    bool_t     map_remote  = ( (k_attr.flags & MAP_REMOTE)  != 0 );
90    bool_t     map_shared  = ( (k_attr.flags & MAP_SHARED)  != 0 );
91    bool_t     map_private = ( (k_attr.flags & MAP_PRIVATE) != 0 );
92
93    // MAP_FIXED not supported
94    if( map_fixed )
95    {
[435]96
[438]97#if DEBUG_SYSCALLS_ERROR
[594]98printk("\n[ERROR] in %s : thread[%x,%x] / MAP_FIXED not supported\n",
99__FUNCTION__ , process->pid, this->trdid );
[435]100#endif
[407]101        this->errno = EINVAL;
102        return -1;
103    }
104
105    if( map_shared == map_private )
106    {
[435]107
[438]108#if DEBUG_SYSCALLS_ERROR
[594]109printk("\n[ERROR] in %s : thread[%x,%x] / MAP_SHARED == MAP_PRIVATE\n",
110__FUNCTION__ , process->pid, this->trdid );
[435]111#endif
[407]112        this->errno = EINVAL;
113        return -1;
114    }
115
116    // FIXME handle Copy_On_Write for MAP_PRIVATE...
117
118    // test mmap type : can be FILE / ANON / REMOTE
119
[611]120    /////////////////////////////////////////////////////////// MAP_FILE
121    if( (map_anon == false) && (map_remote == false) )   
[407]122    {
[594]123
124#if (DEBUG_SYS_MMAP & 1)
125if ( DEBUG_SYS_MMAP < tm_start )
126printk("\n[%s] thread[%x,%x] map file : fdid %d / offset %d / %d bytes\n",
127__FUNCTION__, process->pid, this->trdid, fdid, offset, length );
128#endif
129
[407]130            // FIXME: handle concurent delete of file by another thread closing it
131
132                if( fdid >= CONFIG_PROCESS_FILE_MAX_NR ) 
[1]133                {
[435]134
[438]135#if DEBUG_SYSCALLS_ERROR
[594]136printk("\n[ERROR] in %s : thread[%x,%x] / bad file descriptor %d\n",
137__FUNCTION__ , process->pid , this->trdid , fdid );
[435]138#endif
[407]139            this->errno = EBADFD;
140            return -1;
141        }
[1]142
[407]143        // get extended pointer on file descriptor
144        xptr_t file_xp = process_fd_get_xptr( process , fdid );
145
146        if( file_xp == XPTR_NULL )
147        {
[435]148
[438]149#if DEBUG_SYSCALLS_ERROR
[594]150printk("\n[ERROR] in %s : thread[%x,%x] / file descriptor %d not found\n",
151__FUNCTION__  , this->trdid , process->pid , fdid );
[435]152#endif
[407]153            this->errno = EBADFD;
154            return -1;
155        }
156
157        // get file cluster and local pointer
158        cxy_t        file_cxy = GET_CXY( file_xp );
159        vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp );
160
[594]161#if (DEBUG_SYS_MMAP & 1)
162if ( DEBUG_SYS_MMAP < tm_start )
163printk("\n[%s] thread[%x,%x] get file pointer %x in cluster %x\n",
164__FUNCTION__, process->pid, this->trdid, file_ptr, file_cxy );
165#endif
166
167        // get inode pointer & mapper pointer
[407]168        vfs_inode_t * inode_ptr  = hal_remote_lpt(XPTR(file_cxy , &file_ptr->inode ));
169        mapper_t    * mapper_ptr = hal_remote_lpt(XPTR(file_cxy , &file_ptr->mapper));
170
171        // get file size
[566]172                uint32_t size = hal_remote_l32( XPTR( file_cxy , &inode_ptr->size ) );
[407]173
[594]174#if (DEBUG_SYS_MMAP & 1)
175if ( DEBUG_SYS_MMAP < tm_start )
176printk("\n[%s] thread[%x,%x] get file size : %d bytes\n",
177__FUNCTION__, process->pid, this->trdid, size );
178#endif
179
[407]180        // chek offset and length arguments
181                if( (offset + length) > size)
[1]182                {
[435]183
[438]184#if DEBUG_SYSCALLS_ERROR
[594]185printk("\n[ERROR] in %s: thread[%x,%x] / offset(%d) + len(%d) >= file's size(%d)\n", 
186__FUNCTION__, process->pid, this->trdid, k_attr.offset, k_attr.length, size );
[435]187#endif
[407]188            this->errno = ERANGE;
189            return -1;
[1]190                }
191
[594]192/* TODO
193        // chek access rigths
194        uint32_t   file_attr  = hal_remote_l32(XPTR(file_cxy , &file_ptr->attr  ));
195        bool_t     prot_read  = ( (k_attr.prot & PROT_READ )   != 0 );
196        bool_t     prot_write = ( (k_attr.prot & PROT_WRITE)   != 0 );
197
[407]198        // check access rights
199                if( (prot_read  && !(file_attr & FD_ATTR_READ_ENABLE)) ||
200                    (prot_write && !(file_attr & FD_ATTR_WRITE_ENABLE)) )
[1]201                {
[435]202
[438]203#if DEBUG_SYSCALLS_ERROR
[440]204printk("\n[ERROR] in %s: prot = %x / file_attr = %x / thread %x , process %x\n",
205__FUNCTION__ , k_attr.prot , file_attr , this->trdid , process->pid );
[435]206#endif
[407]207                        this->errno = EACCES;
208                        return -1;
[1]209                }
[594]210*/
[1]211
[407]212                // increment file refcount
213                vfs_file_count_up( file_xp );
[1]214
[407]215        mapper_xp = XPTR( file_cxy , mapper_ptr );
216        vseg_type = VSEG_TYPE_FILE;
217        vseg_cxy  = file_cxy;
218    }
[611]219    ///////////////////////////////////////////////////////// MAP_ANON
220    else if ( map_anon )                                 
[407]221    {
222        mapper_xp = XPTR_NULL;
[594]223        vseg_type = VSEG_TYPE_ANON;
224        vseg_cxy  = local_cxy;
[1]225
[594]226#if (DEBUG_SYS_MMAP & 1)
227if ( DEBUG_SYS_MMAP < tm_start )
228printk("\n[%s] thread[%x,%x] map anon / %d bytes / cluster %x\n",
229__FUNCTION__, process->pid, this->trdid, length, vseg_cxy );
230#endif
231
232    } 
[611]233    /////////////////////////////////////////////////////// MAP_REMOTE
234    else                                                 
[594]235    {
236        mapper_xp = XPTR_NULL;
237        vseg_type = VSEG_TYPE_REMOTE;
238        vseg_cxy  = k_attr.fdid;
239
240#if (DEBUG_SYS_MMAP & 1)
241if ( DEBUG_SYS_MMAP < tm_start )
242printk("\n[%s] thread[%x,%x] map remote / %d bytes / cluster %x\n",
243__FUNCTION__, process->pid, this->trdid, length, vseg_cxy );
244#endif
245 
246        if( cluster_is_undefined( vseg_cxy ) )
[407]247        {
[435]248
[438]249#if DEBUG_SYSCALLS_ERROR
[594]250printk("\n[ERROR] in %s : thread[%x,%x] / illegal cxy %x for REMOTE\n",
251__FUNCTION__, this->trdid , process->pid, vseg_cxy );
[435]252#endif
[594]253            this->errno = EINVAL;
254            return -1;
[407]255        }
256    }
[1]257
[435]258    // enable IRQs
259    hal_enable_irq( &save_sr );
260
[407]261    // get reference process cluster and local pointer
262    xptr_t      ref_xp  = process->ref_xp;
263    cxy_t       ref_cxy = GET_CXY( ref_xp );
[594]264    process_t * ref_ptr = GET_PTR( ref_xp );
[407]265
266    // create the vseg in reference cluster
267    if( local_cxy == ref_cxy )
268    {
269        vseg = vmm_create_vseg( process,
270                                vseg_type,
[594]271                                0,               // vseg base (unused for mmap)
272                                length,          // vseg size
273                                offset,          // file offset
274                                0,               // file_size (unused for mmap)
[407]275                                mapper_xp,
276                                vseg_cxy );
277    }
278    else
279    {
280        rpc_vmm_create_vseg_client( ref_cxy,
281                                    ref_ptr,
282                                    vseg_type,
[594]283                                    0,            // vseg base (unused for mmap)
284                                    length,       // vseg size
285                                    offset,       // file offset
286                                    0,            // file size (unused for mmap)
[407]287                                    mapper_xp,
288                                    vseg_cxy,
289                                    &vseg ); 
290    }
291   
[435]292    // restore IRQs
293    hal_restore_irq( save_sr );
294
[407]295    if( vseg == NULL )
296    {
[435]297
[438]298#if DEBUG_SYSCALLS_ERROR
[594]299printk("\n[ERROR] in %s : thread[%x,%x] / cannot create vseg\n",
300__FUNCTION__, process->pid, this->trdid );
[435]301#endif
[407]302        this->errno = ENOMEM;
303        return -1;
304    }
305
306    // copy vseg base address to user space
307    hal_copy_to_uspace( &attr->addr , &vseg->min , sizeof(intptr_t) );
308
[435]309    hal_fence();
[407]310
[594]311#if (DEBUG_SYS_MMAP || CONFIG_INSTRUMENTATION_SYSCALLS)
312uint64_t     tm_end = hal_get_cycles();
313#endif
314
[623]315#if CONFIG_INSTRUMENTATION_SYSCALLS
316hal_atomic_add( &syscalls_cumul_cost[SYS_MMAP] , tm_end - tm_start );
317hal_atomic_add( &syscalls_occurences[SYS_MMAP] , 1 );
318#endif
319
[438]320#if DEBUG_SYS_MMAP
[623]321if ( DEBUG_SYS_MMAP < tm_end )
[594]322printk("\n[%s] thread[%x,%x] exit / %s / cxy %x / base %x / size %d / cycle %d\n",
323__FUNCTION__, process->pid, this->trdid,
324vseg_type_str(vseg->type), vseg->cxy, vseg->min, length, (uint32_t)tm_end );
[435]325#endif
[407]326
327        return 0;
328
[23]329}  // end sys_mmap()
[407]330
Note: See TracBrowser for help on using the repository browser.