source: trunk/kernel/mm/vmm.c @ 313

Last change on this file since 313 was 313, checked in by alain, 7 years ago

RSeveral modifs in the page-fault handling.

File size: 47.2 KB
RevLine 
[1]1/*
2 * vmm.c - virtual memory manager related operations interface.
3 *
4 * Authors   Ghassan Almaless (2008,2009,2010,2011, 2012)
5 *           Mohamed Lamine Karaoui (2015)
6 *           Alain Greiner (2016)
[21]7 *
[1]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
[14]26#include <kernel_config.h>
[1]27#include <hal_types.h>
28#include <hal_special.h>
29#include <hal_gpt.h>
30#include <printk.h>
[23]31#include <memcpy.h>
[1]32#include <rwlock.h>
33#include <list.h>
34#include <bits.h>
35#include <process.h>
36#include <thread.h>
37#include <vseg.h>
38#include <cluster.h>
39#include <scheduler.h>
40#include <vfs.h>
41#include <mapper.h>
42#include <page.h>
43#include <kmem.h>
44#include <vmm.h>
45
46//////////////////////////////////////////////////////////////////////////////////
47//   Extern global variables
48//////////////////////////////////////////////////////////////////////////////////
49
50extern  process_t  process_zero;   // defined in cluster.c file
51
52
53////////////////////////////////////
54void vmm_init( process_t * process )
[21]55{
[1]56    error_t   error;
57    vseg_t  * vseg_kentry;
58    vseg_t  * vseg_args;
59    vseg_t  * vseg_envs;
60    vseg_t  * vseg_heap;
61    intptr_t  base;
62    intptr_t  size;
63
[204]64    vmm_dmsg("\n[INFO] %s : enter for process %x\n", __FUNCTION__ , process->pid );
65
[1]66    // get pointer on VMM
67    vmm_t   * vmm = &process->vmm;
68
[204]69    assert( ((CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) 
70            <= CONFIG_VMM_ELF_BASE) , __FUNCTION__ , "UTILS zone too small\n" );
[21]71
[204]72    assert( (CONFIG_THREAD_MAX_PER_CLUSTER <= 32) , __FUNCTION__ ,
73            "no more than 32 threads per cluster for a single process\n");
[1]74
[204]75    assert( ((CONFIG_VMM_STACK_SIZE * CONFIG_THREAD_MAX_PER_CLUSTER) <=
76             (CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE)) , __FUNCTION__ ,
77             "STACK zone too small\n");
[1]78
[21]79    // initialize the rwlock protecting the vsegs list
[1]80        rwlock_init( &vmm->vsegs_lock );
81
82    // initialize local list of vsegs and radix-tree
[23]83    vmm->vsegs_nr = 0;
[1]84        list_root_init( &vmm->vsegs_root );
85    error = grdxt_init( &vmm->grdxt,
86                        CONFIG_VMM_GRDXT_W1,
87                        CONFIG_VMM_GRDXT_W2,
88                        CONFIG_VMM_GRDXT_W3 );
[204]89 
90    assert( (error == 0) , __FUNCTION__ , "cannot initialize radix tree\n" );
[1]91
92    // register kentry vseg in VMM
93    base = 1 << CONFIG_PPM_PAGE_SHIFT;
94    size = CONFIG_VMM_KENTRY_SIZE << CONFIG_PPM_PAGE_SHIFT;
95    vseg_kentry = vmm_create_vseg( process , base , size , VSEG_TYPE_CODE );
[204]96
97    assert( (vseg_kentry != NULL) , __FUNCTION__ , "cannot register kentry vseg\n" );
98
[1]99    vmm->kent_vpn_base = 1;
100
101    // register the args vseg in VMM
102    base = (CONFIG_VMM_KENTRY_SIZE + 1 )<<CONFIG_PPM_PAGE_SHIFT;
103    size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
104    vseg_args = vmm_create_vseg( process , base , size , VSEG_TYPE_DATA );
[204]105
106    assert( (vseg_args != NULL) , __FUNCTION__ , "cannot register args vseg\n" );
107
[1]108    vmm->args_vpn_base = CONFIG_VMM_KENTRY_SIZE + 1;
109
110    // register the envs vseg in VMM
111    base = (CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + 1 )<<CONFIG_PPM_PAGE_SHIFT;
112    size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
113    vseg_envs = vmm_create_vseg( process , base , size , VSEG_TYPE_DATA );
[204]114
115    assert( (vseg_envs != NULL) , __FUNCTION__ , "cannot register envs vseg\n" );
116
[1]117    vmm->envs_vpn_base = CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + 1;
118
119    // register the heap vseg in VMM
120    base = CONFIG_VMM_HEAP_BASE << CONFIG_PPM_PAGE_SHIFT;
121    size = (CONFIG_VMM_MMAP_BASE-CONFIG_VMM_HEAP_BASE) << CONFIG_PPM_PAGE_SHIFT;
122    vseg_heap = vmm_create_vseg( process , base , size , VSEG_TYPE_HEAP );
[204]123
124    assert( (vseg_heap != NULL) , __FUNCTION__ , "cannot register heap vseg\n" );
125
[1]126    vmm->heap_vpn_base = CONFIG_VMM_HEAP_BASE;
127
128    // initialize generic page table
129    error = hal_gpt_create( &vmm->gpt );
130
[204]131    assert( (error == 0) , __FUNCTION__ , "cannot initialize page table\n");
132
[1]133    // initialize STACK allocator
134    vmm->stack_mgr.bitmap   = 0;
135    vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
136
137    // initialize MMAP allocator
138    vmm->mmap_mgr.vpn_base        = CONFIG_VMM_MMAP_BASE;
139    vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_MMAP_BASE;
140    vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_MMAP_BASE;
141    uint32_t i;
142    for( i = 0 ; i < 32 ; i++ ) list_root_init( &vmm->mmap_mgr.zombi_list[i] );
143
[21]144    // initialize instrumentation counters
[1]145        vmm->pgfault_nr          = 0;
146        vmm->u_err_nr            = 0;
147        vmm->m_err_nr            = 0;
148
[124]149    hal_fence();
[1]150
[204]151    vmm_dmsg("\n[INFO] %s : exit for process %x\n", __FUNCTION__ , process->pid );
152
153}  // end vmm_init()
154
[23]155//////////////////////////////////////////
156error_t vmm_copy( process_t * dst_process,
157                  process_t * src_process )
158{
159    error_t error;
160
161    vmm_t * src_vmm = &src_process->vmm;
162    vmm_t * dst_vmm = &dst_process->vmm;
163
164    // take the src_vmm vsegs_lock
165    rwlock_wr_lock( &src_vmm->vsegs_lock );
166
[178]167    // initialize dst_vmm vsegs_lock
[23]168    rwlock_init( &dst_vmm->vsegs_lock );
169
[178]170    // initialize the dst_vmm vsegs list and the radix tree
[23]171    dst_vmm->vsegs_nr = 0;
172    list_root_init( &dst_vmm->vsegs_root );
173    error = grdxt_init( &dst_vmm->grdxt,
174                        CONFIG_VMM_GRDXT_W1,
175                        CONFIG_VMM_GRDXT_W2,
176                        CONFIG_VMM_GRDXT_W3 );
177    if( error )
178    {
[178]179        printk("\n[ERROR] in %s : cannot initialize radix tree for process %x\n",
[23]180               __FUNCTION__ , dst_process->pid );
181        return ENOMEM;
182    }
183
184    // loop on src_vmm list of vsegs to create
185    // and register vsegs copies in dst_vmm
186    list_entry_t * iter;
187    vseg_t       * src_vseg;
188    vseg_t       * dst_vseg;
189    LIST_FOREACH( &src_vmm->vsegs_root , iter )
190    {
191        // get pointer on current src_vseg
192        src_vseg = LIST_ELEMENT( iter , vseg_t , list );
193
194        // allocate memory for a new dst_vseg
195        dst_vseg = vseg_alloc();
196
[178]197        if( dst_vseg == NULL )
[23]198        {
199            // release all allocated vsegs
200            LIST_FOREACH( &dst_vmm->vsegs_root , iter )
201            {
202                dst_vseg = LIST_ELEMENT( iter , vseg_t , list );
203                vseg_free( dst_vseg );
204            }
205            return ENOMEM;
206        }
207
208        // copy src_vseg to dst_vseg
209        vseg_init_from_ref( dst_vseg , XPTR( local_cxy , src_vseg ) );
210
211        // register dst_vseg in dst_vmm
212        vseg_attach( dst_vmm , dst_vseg );
213    }
214
215    // release the src_vmm vsegs_lock
216    rwlock_wr_unlock( &src_vmm->vsegs_lock );
217
218    // initialize generic page table
219    error = hal_gpt_create( &dst_vmm->gpt );
220
221    if( error )
222    {
223        printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ );
224        return ENOMEM;
225    }
226
227    // initialize STACK allocator
228    dst_vmm->stack_mgr.bitmap   = 0;
229    dst_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
230
231    // initialize MMAP allocator
232    dst_vmm->mmap_mgr.vpn_base        = CONFIG_VMM_MMAP_BASE;
233    dst_vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_MMAP_BASE;
234    dst_vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_MMAP_BASE;
235    uint32_t i;
236    for( i = 0 ; i < 32 ; i++ ) list_root_init( &dst_vmm->mmap_mgr.zombi_list[i] );
237
[178]238    // initialize instrumentation counters
[23]239        dst_vmm->pgfault_nr    = 0;
240        dst_vmm->u_err_nr      = 0;
241        dst_vmm->m_err_nr      = 0;
242
243    // copy base addresses
[178]244    dst_vmm->kent_vpn_base = src_vmm->kent_vpn_base;
245    dst_vmm->args_vpn_base = src_vmm->args_vpn_base;
246    dst_vmm->envs_vpn_base = src_vmm->envs_vpn_base;
247    dst_vmm->heap_vpn_base = src_vmm->heap_vpn_base;
248    dst_vmm->code_vpn_base = src_vmm->code_vpn_base;
249    dst_vmm->data_vpn_base = src_vmm->data_vpn_base;
[23]250
251    dst_vmm->entry_point   = src_vmm->entry_point;
252
253    // HEAP TODO : new heap for child ???
254    dst_vmm->heap_vseg     = src_vmm->heap_vseg;
255
256    // initialize generic page table
257    error = hal_gpt_create( &dst_vmm->gpt );
258
259    if( error )
260    {
261        printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ );
262        return ENOMEM;
263    }
264
265    // copy GPT content from src_vmm to dst_vmm, activating "Copy-On-Write"
266    // TODO register Copy-On_Write in page descriptors
267    bool_t cow = true;
268    hal_gpt_copy( &dst_vmm->gpt , &src_vmm->gpt , cow );
269
[124]270    hal_fence();
[23]271
272    return 0;
273
[204]274}  // vmm_copy()
275
[1]276///////////////////////////////////////
277void vmm_destroy( process_t * process )
278{
279        vseg_t * vseg;
280
281    // get pointer on VMM
282    vmm_t  * vmm = &process->vmm;
283
284    // get lock protecting vseg list
285        rwlock_wr_lock( &vmm->vsegs_lock );
286
287    // remove all vsegs registered in vmm
288        while( !list_is_empty( &vmm->vsegs_root ) )
289        {
290                vseg = LIST_FIRST( &vmm->vsegs_root ,  vseg_t , list );
291                vseg_detach( vmm , vseg );
292        vseg_free( vseg );
293        }
294
295    // delete vsegs radix_tree
296    grdxt_destroy( &vmm->grdxt );
297
298    // release lock
299        rwlock_wr_unlock(&vmm->vsegs_lock);
300
301    // remove all vsegs from zombi_lists in MMAP allocator
302    uint32_t i;
303    for( i = 0 ; i<32 ; i++ )
304    {
305            while( !list_is_empty( &vmm->mmap_mgr.zombi_list[i] ) )
306            {
307                    vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , list );
308                    vseg_detach( vmm , vseg );
309            vseg_free( vseg );
310            }
311    }
312
313    // release memory allocated to the local page table
314    hal_gpt_destroy( &vmm->gpt );
315
[204]316}  // end vmm_destroy()
317
[1]318/////////////////////////////////////////////////
319vseg_t * vmm_check_conflict( process_t * process,
[21]320                             vpn_t       vpn_base,
[1]321                             vpn_t       vpn_size )
322{
323    vmm_t        * vmm = &process->vmm;
324        vseg_t       * vseg;
325    list_entry_t * iter;
326
327    // scan the list of registered vsegs
328        LIST_FOREACH( &vmm->vsegs_root , iter )
329        {
330                vseg = LIST_ELEMENT( iter , vseg_t , list );
[204]331
[21]332                if( ((vpn_base + vpn_size) > vseg->vpn_base) &&
333             (vpn_base < (vseg->vpn_base + vseg->vpn_size)) ) return vseg;
[1]334        }
335    return NULL;
336
[204]337}  // end vmm_check_conflict()
338
[1]339////////////////////////////////////////////////////////////////////////////////////////////
340// This static function is called by the vmm_create_vseg() function, and implements
341// the VMM stack_vseg specific allocator.
342////////////////////////////////////////////////////////////////////////////////////////////
343// @ vmm      : pointer on VMM.
[21]344// @ vpn_base : (return value) first allocated page
[1]345// @ vpn_size : (return value) number of allocated pages
346////////////////////////////////////////////////////////////////////////////////////////////
347static error_t vmm_stack_alloc( vmm_t * vmm,
348                                vpn_t * vpn_base,
349                                vpn_t * vpn_size )
350{
351    // get stack allocator pointer
352    stack_mgr_t * mgr = &vmm->stack_mgr;
353
354    // get lock on stack allocator
355    spinlock_lock( &mgr->lock );
356
357    // get first free slot index in bitmap
358    int32_t index = bitmap_ffc( &mgr->bitmap , 4 );
[179]359    if( (index < 0) || (index > 31) )
360    {
361        spinlock_unlock( &mgr->lock );
362        return ENOMEM;
363    }
[1]364
365    // update bitmap
366    bitmap_set( &mgr->bitmap , index );
[21]367
[1]368    // release lock on stack allocator
369    spinlock_unlock( &mgr->lock );
370
[21]371    // returns vpn_base, vpn_size (one page non allocated)
[1]372    *vpn_base = mgr->vpn_base + index * CONFIG_VMM_STACK_SIZE + 1;
373    *vpn_size = CONFIG_VMM_STACK_SIZE - 1;
374    return 0;
375
[204]376} // end vmm_stack_alloc()
377
[1]378////////////////////////////////////////////////////////////////////////////////////////////
379// This static function is called by the vmm_create_vseg() function, and implements
380// the VMM MMAP specific allocator.
381////////////////////////////////////////////////////////////////////////////////////////////
382// @ vmm      : [in] pointer on VMM.
383// @ npages   : [in] requested number of pages.
[21]384// @ vpn_base : [out] first allocated page.
[1]385// @ vpn_size : [out] actual number of allocated pages.
386////////////////////////////////////////////////////////////////////////////////////////////
387static error_t vmm_mmap_alloc( vmm_t * vmm,
388                               vpn_t   npages,
389                               vpn_t * vpn_base,
390                               vpn_t * vpn_size )
391{
392    uint32_t   index;
393    vseg_t   * vseg;
394    vpn_t      base;
395    vpn_t      size;
[21]396    vpn_t      free;
[1]397
[21]398    // mmap vseg size must be power of 2
[1]399    // compute actual size and index in zombi_list array
400    size  = POW2_ROUNDUP( npages );
401    index = bits_log2( size );
402
403    // get mmap allocator pointer
404    mmap_mgr_t * mgr = &vmm->mmap_mgr;
405
406    // get lock on mmap allocator
407    spinlock_lock( &mgr->lock );
408
409    // get vseg from zombi_list or from mmap zone
410    if( list_is_empty( &mgr->zombi_list[index] ) )     // from mmap zone
411    {
412        // check overflow
413        free = mgr->first_free_vpn;
414        if( (free + size) > mgr->vpn_size ) return ENOMEM;
415
416        // update STACK allocator
417        mgr->first_free_vpn += size;
418
419        // compute base
420        base = free;
421    }
422    else                                             // from zombi_list
423    {
424        // get pointer on zombi vseg from zombi_list
425        vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , list );
426
427        // remove vseg from free-list
428        list_unlink( &vseg->list );
429
430        // compute base
431        base = vseg->vpn_base;
[21]432    }
433
[1]434    // release lock on mmap allocator
435    spinlock_unlock( &mgr->lock );
436
437    // returns vpn_base, vpn_size
438    *vpn_base = base;
439    *vpn_size = size;
440    return 0;
441
[204]442}  // end vmm_mmap_alloc()
443
[1]444//////////////////////////////////////////////
445vseg_t * vmm_create_vseg( process_t * process,
[21]446                          intptr_t    base,
447                              intptr_t    size,
[1]448                              uint32_t    type )
449{
450    vseg_t     * vseg;          // created vseg pointer
[204]451    vpn_t        vpn_base;      // first page index
[1]452    vpn_t        vpn_size;      // number of pages
453        error_t      error;
454
455    // get pointer on VMM
456        vmm_t * vmm = &process->vmm;
[21]457
[204]458        vmm_dmsg("\n[INFO] %s : enter for process %x / base = %x / size = %x / type = %s\n",
[101]459                     __FUNCTION__ , process->pid , base , size , vseg_type_str(type) );
[21]460
[204]461    // compute base, size, vpn_base, vpn_size, depending on vseg type
[1]462    // we use the VMM specific allocators for STACK and MMAP vsegs
463    if( type == VSEG_TYPE_STACK )
464    {
465        // get vpn_base and vpn_size from STACK allocator
466        error = vmm_stack_alloc( vmm , &vpn_base , &vpn_size );
467        if( error )
468        {
469            printk("\n[ERROR] in %s : no vspace for stack vseg / process %x in cluster %x\n",
470                   __FUNCTION__ , process->pid , local_cxy );
471            return NULL;
472        }
473
474        // compute vseg base and size from vpn_base and vpn_size
475        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
476        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
477    }
[21]478    else if( (type == VSEG_TYPE_ANON) ||
479             (type == VSEG_TYPE_FILE) ||
[1]480             (type == VSEG_TYPE_REMOTE) )
481    {
482        // get vpn_base and vpn_size from MMAP allocator
483        vpn_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
484        error = vmm_mmap_alloc( vmm , npages , &vpn_base , &vpn_size );
485        if( error )
486        {
487            printk("\n[ERROR] in %s : no vspace for mmap vseg / process %x in cluster %x\n",
488                   __FUNCTION__ , process->pid , local_cxy );
489            return NULL;
490        }
491
492        // compute vseg base and size from vpn_base and vpn_size
493        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
494        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
495    }
496    else
497    {
[204]498        uint32_t vpn_min = base >> CONFIG_PPM_PAGE_SHIFT;
499        uint32_t vpn_max = (base + size - 1) >> CONFIG_PPM_PAGE_SHIFT;
500
501        vpn_base = vpn_min;
502            vpn_size = vpn_max - vpn_min + 1;
[1]503    }
504
505    // check collisions
506    vseg = vmm_check_conflict( process , vpn_base , vpn_size );
507    if( vseg != NULL )
508    {
[21]509        printk("\n[ERROR] in %s for process %x : new vseg [vpn_base = %x / vpn_size = %x]\n"
[1]510               "  overlap existing vseg [vpn_base = %x / vpn_size = %x]\n",
[21]511               __FUNCTION__ , process->pid, vpn_base, vpn_size,
512               vseg->vpn_base, vseg->vpn_size );
[1]513        return NULL;
514    }
515
516    // allocate physical memory for vseg descriptor
517        vseg = vseg_alloc();
518        if( vseg == NULL )
519        {
520            printk("\n[ERROR] in %s for process %x : cannot allocate memory for vseg\n",
521             __FUNCTION__ , process->pid );
522        return NULL;
523        }
524
525    // initialize vseg descriptor
526        vseg_init( vseg , base, size , vpn_base , vpn_size , type , local_cxy , 0 , 0 );
527
528    // update "heap_vseg" in VMM
529        process->vmm.heap_vseg = vseg;
530
531    // attach vseg to vmm
532        rwlock_wr_lock( &vmm->vsegs_lock );
533        vseg_attach( vmm , vseg );
534        rwlock_wr_unlock( &vmm->vsegs_lock );
535
[204]536        vmm_dmsg("\n[INFO] %s : exit for process %x / vseg [%x, %x] has been mapped\n",
[1]537                     __FUNCTION__ , process->pid , vseg->min , vseg->max );
[21]538
[1]539        return vseg;
[178]540}
[1]541
542/////////////////////////////////////
543void vmm_remove_vseg( vseg_t * vseg )
544{
545    // get pointers on calling process and VMM
546    thread_t   * this    = CURRENT_THREAD;
547    process_t  * process = this->process;
548    vmm_t      * vmm     = &this->process->vmm;
549    uint32_t     type    = vseg->type;
550
551    // detach vseg from VMM
552        rwlock_wr_lock( &vmm->vsegs_lock );
553    vseg_detach( &process->vmm , vseg );
554        rwlock_wr_unlock( &vmm->vsegs_lock );
555
556    // release the stack slot to VMM stack allocator if STACK type
557    if( type == VSEG_TYPE_STACK )
558    {
559        // get pointer on stack allocator
560        stack_mgr_t * mgr = &vmm->stack_mgr;
561
562        // compute slot index
563        uint32_t index = ((vseg->vpn_base - mgr->vpn_base - 1) / CONFIG_VMM_STACK_SIZE);
564
565        // update stacks_bitmap
566        spinlock_lock( &mgr->lock );
567        bitmap_clear( &mgr->bitmap , index );
568        spinlock_unlock( &mgr->lock );
569    }
570
571    // release the vseg to VMM mmap allocator if MMAP type
572    if( (type == VSEG_TYPE_ANON) || (type == VSEG_TYPE_FILE) || (type == VSEG_TYPE_REMOTE) )
573    {
574        // get pointer on mmap allocator
575        mmap_mgr_t * mgr = &vmm->mmap_mgr;
576
577        // compute zombi_list index
578        uint32_t index = bits_log2( vseg->vpn_size );
579
580        // update zombi_list
581        spinlock_lock( &mgr->lock );
582        list_add_first( &mgr->zombi_list[index] , &vseg->list );
583        spinlock_unlock( &mgr->lock );
584    }
585
586    // release physical memory allocated for vseg descriptor if no MMAP type
587    if( (type != VSEG_TYPE_ANON) && (type != VSEG_TYPE_FILE) && (type != VSEG_TYPE_REMOTE) )
588    {
589        vseg_free( vseg );
590    }
[178]591}
[1]592
[68]593//////////////////////////////////////////////
594error_t vmm_map_kernel_vseg( vseg_t    * vseg,
595                             uint32_t    attr )
[1]596{
597    vpn_t       vpn;        // VPN of PTE to be set
598    vpn_t       vpn_min;    // VPN of first PTE to be set
599    vpn_t       vpn_max;    // VPN of last PTE to be set (excluded)
600        ppn_t       ppn;        // PPN of allocated physical page
601        uint32_t    order;      // ln( number of small pages for one single PTE )
602        page_t    * page;
603    error_t     error;
604
[68]605    // check vseg type : must be a kernel vseg
[1]606    uint32_t type = vseg->type;
[68]607    assert( ((type==VSEG_TYPE_KCODE) || (type==VSEG_TYPE_KDATA) || (type==VSEG_TYPE_KDEV)),
608            __FUNCTION__ , "not a kernel vseg\n" );
[1]609
610    // get pointer on page table
611    gpt_t * gpt = &process_zero.vmm.gpt;
612
[21]613    // define number of small pages per PTE
[1]614        if( attr & GPT_SMALL ) order = 0;   // 1 small page
615        else                   order = 9;   // 512 small pages
616
617    // loop on pages in vseg
618    vpn_min = vseg->vpn_base;
619    vpn_max = vpn_min + vseg->vpn_size;
620        for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
621        {
[68]622        // allocate a physical page from local PPM
[1]623            kmem_req_t req;
624            req.type  = KMEM_PAGE;
625            req.size  = order;
626            req.flags = AF_KERNEL | AF_ZERO;
627            page      = (page_t *)kmem_alloc( &req );
[21]628                if( page == NULL )
[1]629        {
630            printk("\n[ERROR] in %s : cannot allocate physical memory\n", __FUNCTION__ );
631            return ENOMEM;
632        }
633
634        // set page table entry
635        ppn = ppm_page2ppn( page );
636        error = hal_gpt_set_pte( gpt , vpn , ppn , attr );
[21]637                if( error )
[1]638        {
639            printk("\n[ERROR] in %s : cannot register PPE\n", __FUNCTION__ );
640            return ENOMEM;
641        }
642        }
[21]643
[1]644        return 0;
[178]645}
[1]646
647/////////////////////////////////////////
648void vmm_unmap_vseg( process_t * process,
649                     vseg_t    * vseg )
650{
[21]651    vpn_t       vpn;        // VPN of current PTE
652    vpn_t       vpn_min;    // VPN of first PTE
[1]653    vpn_t       vpn_max;    // VPN of last PTE (excluded)
654
655    // get pointer on process page table
656    gpt_t     * gpt = &process->vmm.gpt;
657
658    // loop on pages in vseg
659    vpn_min = vseg->vpn_base;
660    vpn_max = vpn_min + vseg->vpn_size;
661        for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
662    {
663        hal_gpt_reset_pte( gpt , vpn );
664    }
[178]665}
[1]666
667/////////////////////////////////////////////
668error_t vmm_resize_vseg( process_t * process,
669                         intptr_t    base,
670                         intptr_t    size )
671{
672        error_t error;
673
674    // get pointer on process VMM
675    vmm_t * vmm = &process->vmm;
676
677    intptr_t addr_min = base;
678        intptr_t addr_max = base + size;
[21]679    uint32_t shift    = CONFIG_PPM_PAGE_SHIFT;
[1]680
681    // get pointer on vseg
682        vseg_t * vseg = grdxt_lookup( &vmm->grdxt , (uint32_t)(base >> shift) );
683
684        if( vseg == NULL)  return EINVAL;
[21]685
[1]686    // get VMM lock protecting vsegs list
687        rwlock_wr_lock( &vmm->vsegs_lock );
[21]688
[1]689        if( (vseg->min > addr_min) || (vseg->max < addr_max) )   // region not included in vseg
690    {
691        error = EINVAL;
692    }
693        else if( (vseg->min == addr_min) && (vseg->max == addr_max) ) // vseg must be removed
694    {
695        vmm_remove_vseg( vseg );
696        error = 0;
697    }
698        else if( vseg->min == addr_min )                              // vseg must be resized
699    {
700        printk("\n[PANIC] in %s : resize not implemented yet\n", __FUNCTION__ );
701        hal_core_sleep();
702                error = 0;
703    }
704        else if( vseg->max == addr_max )                              // vseg must be resized
705    {
706        printk("\n[PANIC] in %s : resize not implemented yet\n", __FUNCTION__ );
707        hal_core_sleep();
708                error = 0;
709    }
710    else            // vseg cut in three regions => vseg must be resized & new vseg created
711    {
712        printk("\n[PANIC] in %s : resize not implemented yet\n", __FUNCTION__ );
713        hal_core_sleep();
714                error = 0;
715    }
716
717    // release VMM lock
718        rwlock_wr_unlock( &vmm->vsegs_lock );
719
720        return error;
[178]721}
[1]722
723///////////////////////////////////////////
724vseg_t * vmm_get_vseg( process_t * process,
725                       intptr_t    vaddr )
726{
727
728    // get pointer on process VMM
729    vmm_t * vmm = &process->vmm;
730
731    // get lock protecting the vseg list
732    rwlock_rd_lock( &vmm->vsegs_lock );
733
734    // get pointer on vseg from radix tree
735        vseg_t * vseg = grdxt_lookup( &vmm->grdxt, (uint32_t)(vaddr >> CONFIG_PPM_PAGE_SHIFT) );
736
737    // release the lock
738    rwlock_rd_unlock( &vmm->vsegs_lock );
739
740    return vseg;
[178]741}
[1]742
[313]743////////////////////////////////////////
744error_t vmm_get_one_ppn( vseg_t * vseg,
745                         vpn_t    vpn,
746                         ppn_t  * ppn )
747{
748    error_t    error;
749    cxy_t      page_cxy;          // physical page cluster
750    page_t   * page_ptr;          // local pointer on physical page descriptor
751
752    uint32_t   type      = vseg->type;
753    xptr_t     mapper_xp = vseg->mapper_xp;
754
755    // get mapper cluster and local pointer
756    cxy_t      mapper_cxy = GET_CXY( mapper_xp );
757    mapper_t * mapper_ptr = (mapper_t *)GET_PTR( mapper_xp );
758
759    // FILE type : simply get the physical page from the file mapper
760    if( type == VSEG_TYPE_FILE )
761    {
762        // compute index in file mapper
763        uint32_t index = vpn - vseg->vpn_base;
764
765        // get page descriptor from mapper
766        if( mapper_cxy == local_cxy )             // mapper is local
767        {
768            page_ptr = mapper_get_page( mapper_ptr , index );
769        }
770        else                                      // mapper is remote
771        {
772            rpc_mapper_get_page_client( mapper_cxy , mapper_ptr , index , &page_ptr );
773        }
774
775        if ( page_ptr == NULL ) return EINVAL;
776
777        page_cxy = mapper_cxy;
778    }
779
780    // all other types : allocate a physical page from target cluster,
781    else
782    {
783        // get target cluster for physical page
784        if( flags & VSEG_DISTRIB ) // depends on VPN LSB
785        {
786            uint32_t x_width = LOCAL_CLUSTER->x_width;
787            uint32_t y_width = LOCAL_CLUSTER->y_width;
788            page_cxy = vpn & ((1<<(x_width + y_width)) - 1);
789        }
790        else                       // defined in vseg descriptor
791        {
792            page_cxy = vseg->cxy;
793        }
794
795        // allocate a physical page in target cluster
796        kmem_req_t   req;
797        if( page_cxy == local_cxy )    // target cluster is the local cluster
798        {
799            req.type  = KMEM_PAGE;
800            req.size  = 0;
801            req.flags = AF_NONE;
802            page_ptr  = (page_t *)kmem_alloc( &req );
803        }
804        else                           // target cluster is not the local cluster
805        {
806            rpc_pmem_get_pages_client( page_cxy , 0 , &page_ptr );
807        }
808
809        if( page_ptr == NULL ) return ENOMEM;
810
811        // initialise page from .elf file mapper for DATA and CODE types
812        if( (type == VSEG_TYPE_CODE) || (type == VSEG_TYPE_DATA) )
813        {
814            // compute missing page index in vseg
815            vpn_t page_index = vpn - vseg->vpn_base;
816
817            // compute missing page offset in .elf file
818            intptr_t page_offset = vseg->file_offset + (page_index << PPM_PAGE_SHIFT);
819
820            // compute both local and extended pointer on page first byte
821            // WARNING : the pages_offset must have the same value in all clusters !!!
822            //           to use this ppm_page2vaddr() function for a remote cluster
823            uint8_t * base_ptr = (uint8_t *)ppm_page2vaddr( page_ptr );
824            xptr_t    base_xp  = XPTR( page_cxy , base_ptr );
825
826            // file_size can be smaller than vseg_size for BSS
827            file_size = vseg->file_size;
828
829            if( file_size < page_offset )                          // page fully in  BSS
830            {
831                if( page_cxy == local_cxy )
832                {
833                    memset( base_ptr , 0 , PPM_PAGE_SIZE );
834                }
835                else
836                {
837                   hal_remote_memset( base_xp , 0 , PPM_PAGE_SIZE );       
838                }
839            }
840            else if( file size >= (page_offset + PPM_PAGE_SIZE) )  // page fully in  mapper
841   
842                if( mapper_cxy == local_cxy ) 
843                {
844                    error = mapper_move_kernel( mapper_ptr,
845                                                true,             // to_buffer
846                                                page_offset,
847                                                base_xp,
848                                                PPM_PAGE_SIZE ); 
849                }
850                else 
851                {
852                    rpc_mapper_move_buffer_client( mapper_cxy,
853                                                   mapper_ptr,
854                                                   true,         // to buffer
855                                                   false,        // kernel buffer
856                                                   page_offset,
857                                                   (uint64_t)base_xp,
858                                                   PPM_PAGE_SIZE,
859                                                   &error );
860                }
861                if( error ) return EINVAL;
862            }
863            else  // in mapper : from page_offset -> (file_size - page_offset)
864                  // in BSS    : from file_size   -> (page_offset + page_size)
865            {
866                // initialize mapper part
867                if( mapper_cxy == local_cxy )                    // mapper is local
868                {
869                    error = mapper_move_kernel( mapper_ptr,
870                                                true,         // to_buffer
871                                                page_offset,
872                                                base_xp,
873                                                file_size - page_offset ); 
874                }
875                else                                             // mapper is remote
876                {
877                    rpc_mapper_move_buffer_client( mapper_cxy,
878                                                   mapper_ptr,
879                                                   true,
880                                                   false,        // kernel buffer
881                                                   page_offset,
882                                                   (uint64_t)base_xp,
883                                                   file_size - page_offset, 
884                                                   &error );
885                }
886                if( error ) return EINVAL;
887
888                // initialize BSS part
889                if( page_cxy == local_cxy )
890                {
891                    memset( base_ptr + file_size - page_offset , 0 , 
892                            page_offset + PPM_PAGE_SIZE - file_size );
893                }
894                else
895                {
896                   hal_remote_memset( base_xp + file_size - page_offset , 0 , 
897                                      page_offset + PPM_PAGE_SIZE - file_size );
898                }
899            }   
900        }  // end initialisation for CODE or DATA types   
901    } 
902
903    // return ppn
904    *ppn = hal_page2ppn( XPTR( page_cxy , page_ptr ) );
905    return 0;
906
907}  // end vmm_get_one_ppn()
908
[1]909/////////////////////////////////////////
910error_t vmm_get_pte( process_t * process,
911                     vpn_t       vpn,
912                     uint32_t  * ret_attr,
913                     ppn_t     * ret_ppn )
914{
915    vseg_t  * vseg;   // pointer on vseg containing VPN
[313]916    ppn_t     ppn;    // physical page number
[1]917    uint32_t  attr;   // attributes from GPT entry
918    error_t   error;
919
[178]920    // this function must be called by a thread running in the reference cluster
[68]921    assert( (GET_CXY( process->ref_xp ) == local_cxy ) , __FUNCTION__ ,
922             " not called in the reference cluster\n" );
[1]923
924    // get VMM pointer
925    vmm_t * vmm = &process->vmm;
926
927    // access GPT to get PTE attributes and PPN
928    hal_gpt_get_pte( &vmm->gpt , vpn , &attr , &ppn );
929
[313]930    // if PTE is unmapped
931    // 1) get VSEG containing the missing VPN
932    // 2) get & initialize physical page (depending on vseg type),
933    // 3) register the PTE in reference GPT
[21]934    if( (attr & GPT_MAPPED) == 0 )
[1]935    {
[313]936        // 1. get vseg pointer
[1]937        vseg = vmm_get_vseg( process , vpn<<CONFIG_PPM_PAGE_SHIFT );
938
[286]939        if( vseg == NULL )
[1]940        {
941            printk("\n[ERROR] in %s : out of segment / process = %x / vpn = %x\n",
942                   __FUNCTION__ , process->pid , vpn );
943            return EINVAL;
944        }
945
[313]946        // 2. get physical page number, depending on vseg type
947        error = vmm_get_one_ppn( vseg , vpn , &ppn );
[1]948
949        if( error )
950        {
951            printk("\n[ERROR] in %s : cannot allocate memory / process = %x / vpn = %x\n",
952                   __FUNCTION__ , process->pid , vpn );
[313]953            return error;
[1]954        }
955
[313]956        // 3. define attributes from vseg flags and register in GPT
[1]957        attr = GPT_MAPPED | GPT_SMALL;
958        if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
959        if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
960        if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
961        if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
962
963        error = hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
[313]964
[1]965        if( error )
966        {
967            printk("\n[ERROR] in %s : cannot register PTE / process = %x / vpn = %x\n",
968                   __FUNCTION__ , process->pid , vpn );
969            return ENOMEM;
970        }
[313]971    }  // end new PTE
[1]972
973    *ret_ppn  = ppn;
[21]974    *ret_attr = attr;
[1]975    return 0;
976
[313]977}  // end vmm_get_pte()
978
[1]979///////////////////////////////////////////////////
980error_t vmm_handle_page_fault( process_t * process,
981                               vseg_t    * vseg,
982                               vpn_t       vpn )
983{
984    uint32_t         attr;          // missing page attributes
[21]985    ppn_t            ppn;           // missing page PPN
[1]986    error_t          error;         // return value
987
988    // get local VMM pointer
989        vmm_t * vmm = &process->vmm;
990
991    // get reference process cluster and local pointer
992    cxy_t       ref_cxy = GET_CXY( process->ref_xp );
993    process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
994
[313]995    // get missing PTE attributes and PPN from reference cluster
[1]996    if( local_cxy != ref_cxy )   // local cluster is not the reference cluster
997    {
998        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , &attr , &ppn , &error );
999    }
[21]1000    else                              // local cluster is the reference cluster
[1]1001    {
1002        error = vmm_get_pte( process , vpn , &attr , &ppn );
1003    }
1004
1005    // check page allocation error
1006    if( error )
1007    {
1008        printk("\n[ERROR] in %s : cannot allocate memory / process = %x / vpn = %x\n",
[21]1009               __FUNCTION__ , process->pid , vpn );
[1]1010            return ENOMEM;
1011    }
1012
1013    // set the missing PTE in local VMM
1014    error = hal_gpt_set_pte( &vmm->gpt , vpn , attr , ppn );
1015    if( error )
1016    {
1017        printk("\n[ERROR] in %s : cannot register PTE / process = %x / vpn = %x\n",
[21]1018               __FUNCTION__ , process->pid , vpn );
[1]1019        return ENOMEM;
1020    }
[21]1021
[1]1022    return 0;
1023
[313]1024}  // end vmm_handle_page_fault()
1025
1026
[1]1027///////////////////////////////////////////
1028error_t vmm_v2p_translate( bool_t    ident,
1029                           void    * ptr,
1030                           paddr_t * paddr )
1031{
[23]1032    process_t * process = CURRENT_THREAD->process;
[1]1033
1034    if( ident )  // identity mapping
1035    {
[23]1036        *paddr = (paddr_t)PADDR( local_cxy , (lpa_t)ptr );
[1]1037        return 0;
1038    }
1039
[21]1040    // access page table
[1]1041    error_t  error;
1042    vpn_t    vpn;
1043    uint32_t attr;
1044    ppn_t    ppn;
1045    uint32_t offset;
1046
[23]1047    vpn    = (vpn_t)( (intptr_t)ptr >> CONFIG_PPM_PAGE_SHIFT );
1048    offset = (uint32_t)( ((intptr_t)ptr) & CONFIG_PPM_PAGE_MASK );
[1]1049
[50]1050    if( local_cxy == GET_CXY( process->ref_xp) ) // calling process is reference process
[1]1051    {
1052        error = vmm_get_pte( process, vpn , &attr , &ppn );
1053    }
[50]1054    else                                         // calling process is not reference process
[1]1055    {
1056        cxy_t       ref_cxy = GET_CXY( process->ref_xp );
1057        process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
1058        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , &attr , &ppn , &error );
1059    }
1060
[23]1061    // set paddr
[1]1062    *paddr = (((paddr_t)ppn) << CONFIG_PPM_PAGE_SHIFT) | offset;
[21]1063
[23]1064    return error;
[313]1065
[178]1066}
[1]1067/*
1068
1069///////////////////////////////////////////////////////////////////
1070///////////////////////////////////////////////////////////////////
1071error_t vmm_inval_shared_page( vseg_t *vseg, vma_t vaddr, ppn_t ppn)
1072{
1073        pmm_page_info_t current;
1074        error_t err;
1075
1076        error= pmm_get_page(&vseg->vmm->pmm, vaddr, &current);
1077
1078        if((err) || (current.ppn != ppn))
1079                goto ended;
1080
1081        current.ppn     = 0;
1082        current.attr    = 0;
1083        current.cluster = NULL;
1084
1085        error= pmm_set_page(&vseg->vmm->pmm, vaddr, &current);
1086
1087ended:
1088        return err;
1089}
1090
1091error_t vmm_update_shared_page( vseg_t *vseg, vma_t vaddr, ppn_t ppn)
1092{
1093        pmm_page_info_t current;
1094        error_t err;
1095
1096        error= pmm_get_page(&vseg->vmm->pmm, vaddr, &current);
1097
1098        if((err) || (current.attr != 0))
1099                goto ended;
1100
1101        current.ppn     = ppn;
1102        current.attr    = vseg->vm_pgprot;
[178]1103        current.cluster = NULL; // this function is called after invalidate one
[1]1104
1105        error= pmm_set_page(&vseg->vmm->pmm, vaddr , &current);
1106
1107ended:
1108        return err;
1109}
1110
[178]1111// Hypothesis: the vseg is shared-anon, mapper list is rdlocked, page is locked
[1]1112error_t vmm_migrate_shared_page_seq( vseg_t *vseg, struct page_s *page, struct page_s **new)
1113{
1114        register  vseg_t *reg;
1115        register struct process_s *process;
1116        register struct process_s *this_process;
1117        struct page_s *new_pg;
1118        struct list_entry *iter;
1119        kmem_req_t req;
1120        vma_t vaddr;
1121        ppn_t ppn;
1122        error_t err;
1123
1124        vaddr     = (page->index << PMM_PAGE_SHIFT) + vseg->vm_start + vseg->vm_offset;
1125        ppn       = ppm_page2ppn(page);
1126        this_process = (new == NULL) ? NULL : current_process;
1127        iter      = &vseg->vm_shared_list;
1128        error      = ECANCELED;
1129
[178]1130        // Invalidate All
[1]1131        do
1132        {
1133                reg  = list_element(iter,  vseg_t, vm_shared_list);
1134
1135                process = vmm_get_process(reg->vmm);
1136
1137                if(process != this_process)
1138                {
1139                        error= vmm_inval_shared_page(reg, vaddr, ppn);
1140
1141                        if(err) goto fail_inval;
1142                }
1143
1144                assert(vseg->vm_mapper.m_home_cid == current_cid);
1145                iter = list_next(&vseg->vm_mapper.m_reg_root, iter);
1146
1147        }while(iter != NULL);
1148
1149        req.type  = KMEM_PAGE;
1150        req.size  = 0;
1151        req.excep_code = AF_USER;
1152
1153        new_pg    = kmem_alloc(&req);
1154        *new      = new_pg;
1155
1156        if(new_pg == NULL)
1157        {
1158                error= ENOMEM;
1159                goto fail_alloc;
1160        }
1161
1162        page_copy(new_pg, page);
1163
1164        page_lock(new_pg);
1165
1166        new_pg->mapper = page->mapper;
1167        new_pg->index  = page->index;
1168
[178]1169        // TODO: do the complet job regading dirty page
[1]1170        if(PAGE_IS(page, PG_DIRTY))
1171                PAGE_SET(new_pg, PG_DIRTY);
1172
1173        ppn  = ppm_page2ppn(new_pg);
1174        iter = &vseg->vm_shared_list;
1175
1176        // Update All
1177        do
1178        {
1179                reg  = list_element(iter,  vseg_t, vm_shared_list);
1180
1181                process = vmm_get_process(reg->vmm);
1182
1183                if(process != this_process)
1184                        (void) vmm_update_shared_page(reg, vaddr, ppn);
1185
1186                assert(vseg->vm_mapper.m_home_cid == current_cid);
1187                iter = list_next(&vseg->vm_mapper.m_reg_root, iter);
1188
1189
1190        }while(iter != NULL);
1191
1192        page_unlock(new_pg);
1193
1194fail_alloc:
1195fail_inval:
1196        return err;
1197}
1198
1199//TODO: revisit all manipulation of the page->refcount
1200///////////////////////////////////////////////////////////////
[178]1201static inline error_t vmm_do_migrate( vseg_t     * vseg,
[1]1202                                      pmm_page_info_t * pinfo,
1203                                      uint32_t          vaddr )
1204{
1205        kmem_req_t        req;
1206        pmm_page_info_t   current;
1207        page_t          * newpage;
1208        cluster_t       * cluster;
1209        thread_t        * this;
1210        error_t           err;
1211        ppn_t             ppn;
[178]1212
[1]1213        assert( pinfo->ppn != 0 );
1214
1215        ppn = pinfo->ppn;
1216        this = current_thread;
1217        newpage = NULL;
1218        cluster = current_cluster;
[178]1219
[1]1220        current.attr = 0;
1221        current.ppn  = 0;
1222
1223        error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &current);
1224
[178]1225        if(error|| (current.isAtomic == false) ||
[1]1226              (current.ppn != ppn) || !(current.attr & PMM_MIGRATE))
1227        {
1228#if CONFIG_SHOW_SPURIOUS_PGFAULT
[178]1229                printk(INFO, "%s: pid %d, tid %d, cpu %d, nothing to do for vaddr %x\n",
1230                       __FUNCTION__,
1231                       this->process->pid,
1232                       this->info.order,
[1]1233                       cpu_get_id(),
1234                       vaddr);
1235#endif
1236                this->info.spurious_pgfault_cntr ++;
1237                pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
1238                pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
1239                return 0;
1240        }
[178]1241
[1]1242        if(!ppn_is_local(ppn))
1243        {
1244                req.type  = KMEM_PAGE;
1245                req.size  = 0;
1246                req.excep_code = AF_PGFAULT;
1247
1248                newpage = kmem_alloc(&req);
1249
1250                if(newpage)
1251                {
1252                        newpage->mapper = NULL;//?
1253                        ppn_copy(ppm_page2ppn(newpage), ppn);
1254
1255                        if(current.attr & PMM_COW)
1256                        {
1257                                current.attr |= PMM_WRITE;
1258                                current.attr &= ~(PMM_COW);
1259                        }
1260
1261                        current.ppn = ppm_page2ppn(newpage);
1262                }
1263        }
1264
1265        current.attr   |= PMM_PRESENT;
1266        current.attr   &= ~(PMM_MIGRATE);
1267        current.attr   &= ~(PMM_LOCKED);
1268        current.cluster = NULL;
1269
1270        //also unlock the table entry
1271        error= pmm_set_page(&vseg->vmm->pmm, vaddr, &current);
1272       
1273        if(err)
1274        {
[178]1275                // TODO: we should differ the kmem_free call
[1]1276                //page_unlock(page);
1277                (void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
1278                req.ptr = newpage;
1279                kmem_free(&req);
1280                return err;
[178]1281        }
[1]1282
1283
1284        if(newpage)
1285        {
1286                ppn_refcount_down(ppn);
1287                current_thread->info.remote_pages_cntr ++;
[178]1288#if CONFIG_SHOW_REMOTE_PGALLOC
[1]1289                printk(INFO, "%s: pid %d, tid %x, cpu %d, cid %d: got new remote page from cluster %d (vaddr %x)\n",
1290                       __FUNCTION__,
1291                       current_process->pid,
1292                       current_thread,
1293                       cpu_get_id(),
1294                       cluster->id,
1295                       newpage->cid,
1296                       vaddr);
1297#endif
1298        }
1299
1300#if CONFIG_SHOW_VMMMGRT_MSG
1301        printk(INFO, "%s: pid %d, tid %d, cpu %d: Asked to migrate page (vaddr %x) from cluster %d to cluster %d, error%d\n",
1302               __FUNCTION__,
1303               current_process->pid,
1304               current_thread->info.order,
1305               cpu_get_id(),
1306               vaddr,
1307               ppn_ppn2cid(ppn),
1308               cluster->id,
1309               err);
1310#endif
1311
1312        return err;
1313}
1314
1315error_t vmm_do_cow( vseg_t *vseg, pmm_page_info_t *pinfo, uint32_t vaddr)
1316{
1317        register struct page_s *newpage;
1318        register struct page_s *page;
1319        register struct thread_s *this;
1320        register error_t err;
1321        register uint32_t count;
1322        register bool_t isCountDown;
1323        pmm_page_info_t old;
1324        pmm_page_info_t new;
1325        kmem_req_t req;
1326
1327        this       = current_thread;
1328        old.attr  = 0;
1329        newpage    = NULL;
1330        isCountDown = true;
1331
1332        vmm_dmsg(2,"%s: pid %d, tid %d, cpu %d, vaddr %x\n",
1333                 __FUNCTION__,
1334                 this->process->pid,
1335                 this->info.order,
1336                 cpu_get_id(),
1337                 vaddr);
1338
[178]1339
[1]1340        error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &old);
1341
1342        //TODO: check this condition
1343        if(error|| (old.isAtomic == false) || !(old.attr & PMM_COW))
1344        {
1345#if CONFIG_SHOW_SPURIOUS_PGFAULT
[178]1346                printk(INFO, "%s: pid %d, tid %d, cpu %d, nothing to do for vaddr %x\n",
1347                       __FUNCTION__,
1348                       this->process->pid,
1349                       this->info.order,
[1]1350                       cpu_get_id(),
1351                       vaddr);
1352#endif
1353                this->info.spurious_pgfault_cntr ++;
1354                pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
1355                pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
1356                return err;
1357                //goto VMM_COW_END;
1358        }
1359
[178]1360        //if the ppn is local and the others (processus with wich we share the page)
[1]1361        //has done cow, then use the old.ppn directly
1362        if(ppn_is_local(old.ppn))
1363        {
1364                page = ppm_ppn2page(&current_cluster->ppm, old.ppn);
1365
1366                if(page->mapper == NULL)
1367                {
1368                        count = page_refcount_get(page);
1369                        if(count == 1)
1370                        {
1371                                newpage = page;//don't copy the page. use it directly.
1372                                isCountDown = false;
[178]1373                                vmm_dmsg(2, "%s: pid %d, tid %d, cpu %d, reuse same page for vaddr %x, pg_addr %x\n",
1374                                         __FUNCTION__,
1375                                         this->process->pid,
1376                                         this->info.order,
1377                                         cpu_get_id(),
1378                                         vaddr,
[1]1379                                         ppm_page2addr(page));
1380                        }
1381                }
1382                //else: we need to do the cow even if it's local!
1383
1384        }
1385
1386        //else: alocate newpage and copy the data from the remote node
1387        //also defcount down the ppn
1388        if(newpage == NULL)
[178]1389        {
[1]1390                req.type  = KMEM_PAGE;
1391                req.size  = 0;
1392                req.excep_code = AF_PGFAULT;
1393
1394                if((newpage = kmem_alloc(&req)) == NULL)
1395                {
1396                        (void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
1397                        return ENOMEM;
1398                }       
1399
1400                newpage->mapper = NULL;
1401
1402                ppn_copy(ppm_page2ppn(newpage), old.ppn);
1403                assert(isCountDown);
1404               
[178]1405                vmm_dmsg(2,
1406                         "%s: pid %d, tid %d, cpu %d, newpage for vaddr %x, pg_addr %x\n",
1407                         __FUNCTION__,
1408                         this->process->pid,
1409                         this->info.order,
1410                         cpu_get_id(),
1411                         vaddr,
[1]1412                         ppm_page2addr(newpage));
1413
1414                if(newpage->cid != current_cid)
1415                        this->info.remote_pages_cntr ++;
1416        }
1417
1418        new.attr    = vseg->vm_pgprot | PMM_WRITE;
1419        new.attr   &= ~(PMM_COW | PMM_MIGRATE);
1420        new.ppn     = ppm_page2ppn(newpage);
1421        new.cluster = NULL;
1422
1423        //this also unlock the table entry (if no error)
1424        error= pmm_set_page(&vseg->vmm->pmm, vaddr, &new);
1425
1426        if(err)
1427        {
1428                (void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
1429                req.ptr = newpage;
1430                kmem_free(&req);
1431                vmm_dmsg(3, "%s: ended [ error%d ]\n", __FUNCTION__, err);
1432                return err;
1433        }
1434       
1435        if(isCountDown) ppn_refcount_down(old.ppn);
1436       
[178]1437        vmm_dmsg(2, "%s, pid %d, tid %d, cpu %d, COW ended [vaddr %x]\n",
1438                 __FUNCTION__,
[1]1439                 this->process->pid,
1440                 this->info.order,
1441                 cpu_get_id(),
1442                 vaddr);
[178]1443
[1]1444        return 0;
1445}
1446
1447
1448//refcount is taken on the file at mmap
1449static inline error_t vmm_do_mapped( vseg_t *vseg, uint32_t vaddr, uint32_t excep_code)
1450{
1451        ppn_t ppn;
1452        error_t err;
1453        uint32_t index;
1454        bool_t isDone;
1455        pmm_page_info_t info;
1456        pmm_page_info_t current;
1457        struct thread_s *this;
1458
1459        this = current_thread;
1460
1461        current.attr = 1;
1462        current.ppn  = 1;
1463        isDone       = false;
1464
1465        error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &current);
1466       
1467        if(err) return err;
1468
1469        if((current.isAtomic == false) || (current.attr != 0))
1470        {
1471#if CONFIG_SHOW_SPURIOUS_PGFAULT
[178]1472                printk(INFO, "%s: pid %d, tid %d, cpu %d, nothing to do for vaddr %x\n",
1473                       __FUNCTION__,
1474                       this->process->pid,
1475                       this->info.order,
[1]1476                       cpu_get_id(),
1477                       vaddr);
1478#endif
1479                this->info.spurious_pgfault_cntr ++;
1480                pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
1481                return 0;
1482        }
1483
1484        index = ((vaddr - vseg->vm_start) + vseg->vm_offset) >> PMM_PAGE_SHIFT;
1485
1486        //also hold a refcount!
[178]1487        ppn = mapper_get_ppn(&vseg->vm_mapper,
1488                               index,
[1]1489                               MAPPER_SYNC_OP);
1490
1491        if(!ppn)
1492        {
1493                error= pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
1494                assert(!err); //FIXME: liberate the ppn ...
1495                return (VFS_FILE_IS_NULL(vseg->vm_file)) ? EIO : ENOMEM;
1496        }
1497
1498        info.attr    = vseg->vm_pgprot;
1499        info.ppn     = ppn;
1500        info.cluster = NULL;
1501
1502        //also unlock the page
1503        error= pmm_set_page(&vseg->vmm->pmm, vaddr, &info);
1504
1505        assert(!err);//FIXME: liberate the ppn and unlock the table entry ...
1506        //error= pmm_unlock_page(&vseg->vmm->pmm, vaddr, &current);
1507
1508        return err;
1509}
1510
1511/////////////////////////////////////////////////////
1512static inline error_t vmm_do_aod( vseg_t *vseg, uint32_t vaddr)
1513{
1514        register error_t err;
1515        register struct page_s *page;
1516        register struct cluster_s *cluster;
1517        struct thread_s *this;
1518        pmm_page_info_t old;
1519        pmm_page_info_t new;
1520        kmem_req_t req;
1521
1522        page      = NULL;
1523        old.attr  = 0;
1524        this      = current_thread;
[178]1525
[1]1526        error= pmm_lock_page(&vseg->vmm->pmm, vaddr, &old);
1527
1528        if(err) return err;
1529
1530        if(old.isAtomic == false)
1531        {
1532                this->info.spurious_pgfault_cntr ++;
1533                pmm_tlb_flush_vaddr(vaddr, PMM_DATA);
1534                return 0;
1535        }
1536
1537        req.type  = KMEM_PAGE;
1538        req.size  = 0;
1539        req.excep_code = AF_PGFAULT | AF_ZERO;
1540
1541        if((page = kmem_alloc(&req)) == NULL)
1542        {
1543                (void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
1544                return ENOMEM;
1545        }
1546
1547        page->mapper = NULL;
1548
1549        new.attr    = vseg->vm_pgprot;
1550        new.ppn     = ppm_page2ppn(page);
1551        new.cluster = NULL;
1552
1553        error= pmm_set_page(&vseg->vmm->pmm, vaddr, &new);
1554       
1555        if(err) goto fail_set_pg;
1556
1557        cluster = current_cluster;
1558
1559        if(page->cid != cluster->id)
1560                this->info.remote_pages_cntr ++;
1561
1562        return 0;
1563
1564fail_set_pg:
1565        (void)pmm_unlock_page(&vseg->vmm->pmm, vaddr, &old);
1566        req.ptr = page;
1567        kmem_free(&req);
1568
1569        vmm_dmsg(3, "%s: ended [ error%d ]\n", __FUNCTION__, err);
1570        return err;
1571}
1572
1573VSEGION_PAGE_FAULT(vmm_default_pagefault)
1574{
1575        register struct thread_s *this;
1576        register error_t err;
1577        pmm_page_info_t info;
1578
1579        if((error= pmm_get_page(&vseg->vmm->pmm, vaddr, &info)))
1580                return err;
1581
1582        if((info.attr != 0) && (info.ppn != 0))
1583        {
1584                if((info.attr & PMM_COW) && pmm_except_isWrite(excep_code))
1585                {
1586                        error= vmm_do_cow(vseg, &info, vaddr);
1587                        return err;
1588                }
1589
1590                if(info.attr & PMM_MIGRATE)
1591                        return vmm_do_migrate(vseg, &info, vaddr);
1592
1593                if(info.attr & PMM_PRESENT)
1594                {
1595                        this = current_thread;
1596
1597#if CONFIG_SHOW_SPURIOUS_PGFAULT
1598                        printk(WARNING, "WARNING: %s: pid %d, tid %d, cpu %d, excep_code %x but vaddr is valid %x, attr %x, ppn %x\n",
1599                               __FUNCTION__,
1600                               this->process->pid,
1601                               this->info.order,
1602                               cpu_get_id(),
1603                               excep_code,
1604                               vaddr,
1605                               info.attr,
1606                               info.ppn);
1607#endif
1608
1609                        current_thread->info.spurious_pgfault_cntr ++;
1610                        pmm_tlb_flush_vaddr(vaddr, PMM_UNKNOWN);
1611                        return 0;
1612                }
1613
1614                current_thread->info.spurious_pgfault_cntr ++;
1615                pmm_tlb_flush_vaddr(vaddr, PMM_UNKNOWN);
1616                return 0;
1617#if 0
1618#if CONFIG_SHOW_VMM_ERROR_MSG
[178]1619                printk(ERROR,
[1]1620                       "ERROR: %s: pid %d, cpu %d, Unexpected page attributes configuration for vaddr %x, found: ppn %x, attr %x\n",
1621                       __FUNCTION__,
1622                       current_process->pid,
[178]1623                       cpu_get_id(),
1624                       vaddr,
[1]1625                       info.ppn,
1626                       info.attr);
1627#endif
[178]1628
[1]1629                return EPERM;
1630#endif
1631        }
1632
1633        if(!MAPPER_IS_NULL(vseg->vm_mapper))
1634                return vmm_do_mapped(vseg, vaddr, excep_code);
1635
1636        return vmm_do_aod(vseg, vaddr);
1637}
1638*/
1639
Note: See TracBrowser for help on using the repository browser.