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

Last change on this file since 625 was 625, checked in by alain, 6 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
Line 
1/*
2 * sys_mmap.c - map files, memory or devices into process virtual address space
3 *
4 * Authors       Alain Greiner (2016,2017,2018,2019)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
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 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
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
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_kernel_types.h>
25#include <hal_uspace.h>
26#include <hal_vmm.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#include <syscalls.h>
38
39//////////////////////////////////
40int sys_mmap( mmap_attr_t * attr )
41{
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;
48    reg_t         save_sr;      // required to enable IRQs
49
50        thread_t    * this    = CURRENT_THREAD;
51        process_t   * process = this->process;
52
53#if (DEBUG_SYS_MMAP || CONFIG_INSTRUMENTATION_SYSCALLS)
54uint64_t     tm_start = hal_get_cycles();
55#endif
56
57#if DEBUG_SYS_MMAP
58if( DEBUG_SYS_MMAP < tm_start )
59printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
60__FUNCTION__, process->pid, this->trdid, (uint32_t)tm_start );
61#endif
62
63    // check user buffer (containing attributes) is mapped
64    error = vmm_get_vseg( process , (intptr_t)attr , &vseg );
65
66    if( error )
67    {
68
69#if DEBUG_SYSCALLS_ERROR
70printk("\n[ERROR] in %s : thread[%x,%x] / mmap attributes unmapped %x\n",
71__FUNCTION__ , process->pid, this->trdid, (intptr_t)attr );
72hal_vmm_display( process , false );
73#endif
74                this->errno = EINVAL;
75                return -1;
76    }
77
78    // copy attributes from user space to kernel space
79    hal_copy_from_uspace( &k_attr , attr , sizeof(mmap_attr_t) );
80
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;
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    {
96
97#if DEBUG_SYSCALLS_ERROR
98printk("\n[ERROR] in %s : thread[%x,%x] / MAP_FIXED not supported\n",
99__FUNCTION__ , process->pid, this->trdid );
100#endif
101        this->errno = EINVAL;
102        return -1;
103    }
104
105    if( map_shared == map_private )
106    {
107
108#if DEBUG_SYSCALLS_ERROR
109printk("\n[ERROR] in %s : thread[%x,%x] / MAP_SHARED == MAP_PRIVATE\n",
110__FUNCTION__ , process->pid, this->trdid );
111#endif
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
120    /////////////////////////////////////////////////////////// MAP_FILE
121    if( (map_anon == false) && (map_remote == false) )   
122    {
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
130            // FIXME: handle concurent delete of file by another thread closing it
131
132                if( fdid >= CONFIG_PROCESS_FILE_MAX_NR ) 
133                {
134
135#if DEBUG_SYSCALLS_ERROR
136printk("\n[ERROR] in %s : thread[%x,%x] / bad file descriptor %d\n",
137__FUNCTION__ , process->pid , this->trdid , fdid );
138#endif
139            this->errno = EBADFD;
140            return -1;
141        }
142
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        {
148
149#if DEBUG_SYSCALLS_ERROR
150printk("\n[ERROR] in %s : thread[%x,%x] / file descriptor %d not found\n",
151__FUNCTION__  , this->trdid , process->pid , fdid );
152#endif
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
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
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
172                uint32_t size = hal_remote_l32( XPTR( file_cxy , &inode_ptr->size ) );
173
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
180        // chek offset and length arguments
181                if( (offset + length) > size)
182                {
183
184#if DEBUG_SYSCALLS_ERROR
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 );
187#endif
188            this->errno = ERANGE;
189            return -1;
190                }
191
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
198        // check access rights
199                if( (prot_read  && !(file_attr & FD_ATTR_READ_ENABLE)) ||
200                    (prot_write && !(file_attr & FD_ATTR_WRITE_ENABLE)) )
201                {
202
203#if DEBUG_SYSCALLS_ERROR
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 );
206#endif
207                        this->errno = EACCES;
208                        return -1;
209                }
210*/
211
212                // increment file refcount
213                vfs_file_count_up( file_xp );
214
215        mapper_xp = XPTR( file_cxy , mapper_ptr );
216        vseg_type = VSEG_TYPE_FILE;
217        vseg_cxy  = file_cxy;
218    }
219    ///////////////////////////////////////////////////////// MAP_ANON
220    else if ( map_anon )                                 
221    {
222        mapper_xp = XPTR_NULL;
223        vseg_type = VSEG_TYPE_ANON;
224        vseg_cxy  = local_cxy;
225
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    } 
233    /////////////////////////////////////////////////////// MAP_REMOTE
234    else                                                 
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 ) )
247        {
248
249#if DEBUG_SYSCALLS_ERROR
250printk("\n[ERROR] in %s : thread[%x,%x] / illegal cxy %x for REMOTE\n",
251__FUNCTION__, this->trdid , process->pid, vseg_cxy );
252#endif
253            this->errno = EINVAL;
254            return -1;
255        }
256    }
257
258    // enable IRQs
259    hal_enable_irq( &save_sr );
260
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 );
264    process_t * ref_ptr = GET_PTR( ref_xp );
265
266    // create the vseg in reference cluster
267    if( local_cxy == ref_cxy )
268    {
269        vseg = vmm_create_vseg( process,
270                                vseg_type,
271                                0,               // vseg base (unused for mmap)
272                                length,          // vseg size
273                                offset,          // file offset
274                                0,               // file_size (unused for mmap)
275                                mapper_xp,
276                                vseg_cxy );
277    }
278    else
279    {
280        rpc_vmm_create_vseg_client( ref_cxy,
281                                    ref_ptr,
282                                    vseg_type,
283                                    0,            // vseg base (unused for mmap)
284                                    length,       // vseg size
285                                    offset,       // file offset
286                                    0,            // file size (unused for mmap)
287                                    mapper_xp,
288                                    vseg_cxy,
289                                    &vseg ); 
290    }
291   
292    // restore IRQs
293    hal_restore_irq( save_sr );
294
295    if( vseg == NULL )
296    {
297
298#if DEBUG_SYSCALLS_ERROR
299printk("\n[ERROR] in %s : thread[%x,%x] / cannot create vseg\n",
300__FUNCTION__, process->pid, this->trdid );
301#endif
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
309    hal_fence();
310
311#if (DEBUG_SYS_MMAP || CONFIG_INSTRUMENTATION_SYSCALLS)
312uint64_t     tm_end = hal_get_cycles();
313#endif
314
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
320#if DEBUG_SYS_MMAP
321if ( DEBUG_SYS_MMAP < tm_end )
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 );
325#endif
326
327        return 0;
328
329}  // end sys_mmap()
330
Note: See TracBrowser for help on using the repository browser.