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

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

This version replace the RPC by direct remote memory access
for physical pages allacation/release.
It is commited before being tested.

File size: 81.5 KB
RevLine 
[1]1/*
[611]2 * vmm.c - virtual memory manager related operations definition.
[1]3 *
4 * Authors   Ghassan Almaless (2008,2009,2010,2011, 2012)
5 *           Mohamed Lamine Karaoui (2015)
[625]6 *           Alain Greiner (2016,2017,2018,2019)
[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>
[457]27#include <hal_kernel_types.h>
[1]28#include <hal_special.h>
29#include <hal_gpt.h>
[409]30#include <hal_vmm.h>
[577]31#include <hal_macros.h>
[1]32#include <printk.h>
[23]33#include <memcpy.h>
[567]34#include <remote_rwlock.h>
35#include <remote_queuelock.h>
[1]36#include <list.h>
[408]37#include <xlist.h>
[1]38#include <bits.h>
39#include <process.h>
40#include <thread.h>
41#include <vseg.h>
42#include <cluster.h>
43#include <scheduler.h>
44#include <vfs.h>
45#include <mapper.h>
46#include <page.h>
47#include <kmem.h>
48#include <vmm.h>
[585]49#include <hal_exception.h>
[1]50
51//////////////////////////////////////////////////////////////////////////////////
52//   Extern global variables
53//////////////////////////////////////////////////////////////////////////////////
54
[567]55extern  process_t  process_zero;      // allocated in cluster.c
[1]56
[625]57////////////////////////////////////////////////////////////////////////////////////////////
58// This static function is called by the vmm_create_vseg() function, and implements
59// the VMM STACK specific allocator.
60////////////////////////////////////////////////////////////////////////////////////////////
61// @ vmm      : [in]  pointer on VMM.
62// @ ltid     : [in]  requested slot == local user thread identifier.
63// @ vpn_base : [out] first allocated page
64// @ vpn_size : [out] number of allocated pages
65////////////////////////////////////////////////////////////////////////////////////////////
66static void vmm_stack_alloc( vmm_t  * vmm,
67                             ltid_t   ltid,
68                             vpn_t  * vpn_base,
69                             vpn_t  * vpn_size )
[21]70{
[625]71
72// check ltid argument
73assert( (ltid <= ((CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE) / CONFIG_VMM_STACK_SIZE)),
74"slot index %d too large for an user stack vseg", ltid );
75
76    // get stack allocator pointer
77    stack_mgr_t * mgr = &vmm->stack_mgr;
78
79    // get lock on stack allocator
80    busylock_acquire( &mgr->lock );
81
82// check requested slot is available
83assert( (bitmap_state( &mgr->bitmap , ltid ) == false),
84"slot index %d already allocated", ltid );
85
86    // update bitmap
87    bitmap_set( &mgr->bitmap , ltid );
88
89    // release lock on stack allocator
90    busylock_release( &mgr->lock );
91
92    // returns vpn_base, vpn_size (first page non allocated)
93    *vpn_base = mgr->vpn_base + ltid * CONFIG_VMM_STACK_SIZE + 1;
94    *vpn_size = CONFIG_VMM_STACK_SIZE - 1;
95
96} // end vmm_stack_alloc()
97
98////////////////////////////////////////////////////////////////////////////////////////////
99// This static function is called by the vmm_remove_vseg() function, and implements
100// the VMM STACK specific desallocator.
101////////////////////////////////////////////////////////////////////////////////////////////
102// @ vmm      : [in] pointer on VMM.
103// @ vseg     : [in] pointer on released vseg.
104////////////////////////////////////////////////////////////////////////////////////////////
105static void vmm_stack_free( vmm_t  * vmm,
106                            vseg_t * vseg )
107{
108    // get stack allocator pointer
109    stack_mgr_t * mgr = &vmm->stack_mgr;
110
111    // compute slot index
112    uint32_t index = (vseg->vpn_base - 1 - mgr->vpn_base) / CONFIG_VMM_STACK_SIZE;
113
114// check index
115assert( (index <= ((CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE) / CONFIG_VMM_STACK_SIZE)),
116"slot index %d too large for an user stack vseg", index );
117
118// check released slot is allocated
119assert( (bitmap_state( &mgr->bitmap , index ) == true),
120"released slot index %d non allocated", index );
121
122    // get lock on stack allocator
123    busylock_acquire( &mgr->lock );
124
125    // update stacks_bitmap
126    bitmap_clear( &mgr->bitmap , index );
127
128    // release lock on stack allocator
129    busylock_release( &mgr->lock );
130
131}  // end vmm_stack_free()
132
133////////////////////////////////////////////////////////////////////////////////////////////
134// This static function is called by the vmm_create_vseg() function, and implements
135// the VMM MMAP specific allocator.
136////////////////////////////////////////////////////////////////////////////////////////////
137// @ vmm      : [in] pointer on VMM.
138// @ npages   : [in] requested number of pages.
139// @ vpn_base : [out] first allocated page.
140// @ vpn_size : [out] actual number of allocated pages.
141////////////////////////////////////////////////////////////////////////////////////////////
142static error_t vmm_mmap_alloc( vmm_t * vmm,
143                               vpn_t   npages,
144                               vpn_t * vpn_base,
145                               vpn_t * vpn_size )
146{
147    uint32_t   order;
148    xptr_t     vseg_xp;
149    vseg_t   * vseg;
150    vpn_t      base;
151    vpn_t      size;
152    vpn_t      free;
153
154#if DEBUG_VMM_MMAP_ALLOC
155thread_t * this = CURRENT_THREAD;
156uint32_t cycle = (uint32_t)hal_get_cycles();
157if( DEBUG_VMM_MMAP_ALLOC < cycle )
158printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
159__FUNCTION__, this->process->pid, this->trdid, cycle );
160#endif
161
162    // number of allocated pages must be power of 2
163    // compute actual size and order
164    size  = POW2_ROUNDUP( npages );
165    order = bits_log2( size );
166
167    // get mmap allocator pointer
168    mmap_mgr_t * mgr = &vmm->mmap_mgr;
169
170    // build extended pointer on root of zombi_list[order]
171    xptr_t root_xp = XPTR( local_cxy , &mgr->zombi_list[order] );
172
173    // take lock protecting zombi_lists
174    busylock_acquire( &mgr->lock );
175
176    // get vseg from zombi_list or from mmap zone
177    if( xlist_is_empty( root_xp ) )                   // from mmap zone
178    {
179        // check overflow
180        free = mgr->first_free_vpn;
181        if( (free + size) > mgr->vpn_size ) return -1;
182
183        // update MMAP allocator
184        mgr->first_free_vpn += size;
185
186        // compute base
187        base = free;
188    }
189    else                                              // from zombi_list
190    {
191        // get pointer on zombi vseg from zombi_list
192        vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
193        vseg    = GET_PTR( vseg_xp );
194
195        // remove vseg from free-list
196        xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
197
198        // compute base
199        base = vseg->vpn_base;
200    }
201
202    // release lock
203    busylock_release( &mgr->lock );
204
205#if DEBUG_VMM_MMAP_ALLOC
206cycle = (uint32_t)hal_get_cycles();
207if( DEBUG_VMM_DESTROY < cycle )
208printk("\n[%s] thread[%x,%x] exit / vpn_base %x / vpn_size %x / cycle %d\n",
209__FUNCTION__, this->process->pid, this->trdid, base, size, cycle );
210#endif
211
212    // returns vpn_base, vpn_size
213    *vpn_base = base;
214    *vpn_size = size;
215    return 0;
216
217}  // end vmm_mmap_alloc()
218
219////////////////////////////////////////////////////////////////////////////////////////////
220// This static function is called by the vmm_remove_vseg() function, and implements
221// the VMM MMAP specific desallocator.
222////////////////////////////////////////////////////////////////////////////////////////////
223// @ vmm      : [in] pointer on VMM.
224// @ vseg     : [in] pointer on released vseg.
225////////////////////////////////////////////////////////////////////////////////////////////
226static void vmm_mmap_free( vmm_t  * vmm,
227                           vseg_t * vseg )
228{
229    // get pointer on mmap allocator
230    mmap_mgr_t * mgr = &vmm->mmap_mgr;
231
232    // compute zombi_list order
233    uint32_t order = bits_log2( vseg->vpn_size );
234
235    // take lock protecting zombi lists
236    busylock_acquire( &mgr->lock );
237
238    // update relevant zombi_list
239    xlist_add_first( XPTR( local_cxy , &mgr->zombi_list[order] ),
240                     XPTR( local_cxy , &vseg->xlist ) );
241
242    // release lock
243    busylock_release( &mgr->lock );
244
245}  // end of vmm_mmap_free()
246
247////////////////////////////////////////////////////////////////////////////////////////////
248// This static function registers one vseg in the VSL of a local process descriptor.
249////////////////////////////////////////////////////////////////////////////////////////////
250// vmm       : [in] pointer on VMM.
251// vseg      : [in] pointer on vseg.
252////////////////////////////////////////////////////////////////////////////////////////////
253void vmm_attach_vseg_to_vsl( vmm_t  * vmm,
254                             vseg_t * vseg )
255{
256    // update vseg descriptor
257    vseg->vmm = vmm;
258
259    // increment vsegs number
260    vmm->vsegs_nr++;
261
262    // add vseg in vmm list
263    xlist_add_last( XPTR( local_cxy , &vmm->vsegs_root ),
264                    XPTR( local_cxy , &vseg->xlist ) );
265
266}  // end vmm_attach_vseg_from_vsl()
267
268////////////////////////////////////////////////////////////////////////////////////////////
269// This static function removes one vseg from the VSL of a local process descriptor.
270////////////////////////////////////////////////////////////////////////////////////////////
271// vmm       : [in] pointer on VMM.
272// vseg      : [in] pointer on vseg.
273////////////////////////////////////////////////////////////////////////////////////////////
274void vmm_detach_vseg_from_vsl( vmm_t  * vmm,
275                               vseg_t * vseg )
276{
277    // update vseg descriptor
278    vseg->vmm = NULL;
279
280    // decrement vsegs number
281    vmm->vsegs_nr--;
282
283    // remove vseg from VSL
284    xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
285
286}  // end vmm_detach_from_vsl()
287
288
289
290
291////////////////////////////////////////////
292error_t vmm_user_init( process_t * process )
293{
[1]294    vseg_t  * vseg_args;
295    vseg_t  * vseg_envs;
296    intptr_t  base;
297    intptr_t  size;
[614]298    uint32_t  i;
[1]299
[625]300#if DEBUG_VMM_USER_INIT
[567]301thread_t * this = CURRENT_THREAD;
[433]302uint32_t cycle = (uint32_t)hal_get_cycles();
[625]303if( DEBUG_VMM_USER_INIT )
[614]304printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n", 
305__FUNCTION__ , this->process->pid, this->trdid, process->pid, local_cxy, cycle );
[433]306#endif
[204]307
[1]308    // get pointer on VMM
309    vmm_t   * vmm = &process->vmm;
310
[625]311// check UTILS zone
[624]312assert( ((CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) <= 
313         (CONFIG_VMM_ELF_BASE - CONFIG_VMM_UTILS_BASE)) ,
314         "UTILS zone too small\n" );
[21]315
[625]316// check STACK zone
[567]317assert( ((CONFIG_VMM_STACK_SIZE * CONFIG_THREADS_MAX_PER_CLUSTER) <=
318(CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE)) ,
319"STACK zone too small\n");
[1]320
[625]321    // register "args" vseg in VSL
[624]322    base = CONFIG_VMM_UTILS_BASE << CONFIG_PPM_PAGE_SHIFT;
[1]323    size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
[406]324
[407]325    vseg_args = vmm_create_vseg( process,
326                                 VSEG_TYPE_DATA,
327                                 base,
328                                 size,
329                                 0,             // file_offset unused
330                                 0,             // file_size unused
331                                 XPTR_NULL,     // mapper_xp unused
332                                 local_cxy );
[415]333    if( vseg_args == NULL )
334    {
335        printk("\n[ERROR] in %s : cannot register args vseg\n", __FUNCTION__ );
336        return -1;
337    }
[204]338
[406]339    vmm->args_vpn_base = base;
[1]340
[625]341    // register "envs" vseg in VSL
[624]342    base = (CONFIG_VMM_UTILS_BASE + CONFIG_VMM_ARGS_SIZE) << CONFIG_PPM_PAGE_SHIFT;
[1]343    size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
[406]344
[407]345    vseg_envs = vmm_create_vseg( process,
346                                 VSEG_TYPE_DATA,
347                                 base,
348                                 size,
349                                 0,             // file_offset unused
350                                 0,             // file_size unused
351                                 XPTR_NULL,     // mapper_xp unused
352                                 local_cxy );
[415]353    if( vseg_envs == NULL )
354    {
355        printk("\n[ERROR] in %s : cannot register envs vseg\n", __FUNCTION__ );
356        return -1;
357    }
[204]358
[406]359    vmm->envs_vpn_base = base;
[1]360
361    // initialize STACK allocator
362    vmm->stack_mgr.bitmap   = 0;
363    vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
[567]364    busylock_init( &vmm->stack_mgr.lock , LOCK_VMM_STACK );
[1]365
366    // initialize MMAP allocator
[407]367    vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
368    vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
369    vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
[567]370    busylock_init( &vmm->mmap_mgr.lock , LOCK_VMM_MMAP );
[625]371    for( i = 0 ; i < 32 ; i++ )
372    {
373        xlist_root_init( XPTR( local_cxy , &vmm->mmap_mgr.zombi_list[i] ) );
374    }
[1]375
[21]376    // initialize instrumentation counters
[409]377        vmm->pgfault_nr = 0;
[1]378
[124]379    hal_fence();
[1]380
[625]381#if DEBUG_VMM_USER_INIT
[433]382cycle = (uint32_t)hal_get_cycles();
[625]383if( DEBUG_VMM_USER_INIT )
[614]384printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n", 
385__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
[433]386#endif
[204]387
[415]388    return 0;
389
[625]390}  // end vmm_user_init()
[204]391
[611]392//////////////////////////////////////////
[625]393void vmm_user_reset( process_t * process )
[567]394{
[625]395    xptr_t       vseg_xp;
396        vseg_t     * vseg;
397    vseg_type_t  vseg_type;
[567]398
[625]399#if DEBUG_VMM_USER_RESET
400uint32_t cycle = (uint32_t)hal_get_cycles();
401thread_t * this = CURRENT_THREAD;
402if( DEBUG_VMM_USER_RESET < cycle )
403printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
404__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
405#endif
[567]406
[625]407#if (DEBUG_VMM_USER_RESET & 1 )
408if( DEBUG_VMM_USER_RESET < cycle )
409hal_vmm_display( process , true );
410#endif
[567]411
[625]412    // get pointer on local VMM
413    vmm_t * vmm = &process->vmm;
[624]414
[625]415    // build extended pointer on VSL root and VSL lock
416    xptr_t   root_xp = XPTR( local_cxy , &vmm->vsegs_root );
417    xptr_t   lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
[567]418
[625]419    // take the VSL lock
420        remote_rwlock_wr_acquire( lock_xp );
[567]421
[625]422    // scan the VSL to delete all non kernel vsegs
423    // (we don't use a FOREACH in case of item deletion)
424    xptr_t   iter_xp;
425    xptr_t   next_xp;
426        for( iter_xp = hal_remote_l64( root_xp ) ; 
427         iter_xp != root_xp ;
428         iter_xp = next_xp )
429        {
430        // save extended pointer on next item in xlist
431        next_xp = hal_remote_l64( iter_xp );
[611]432
[625]433        // get pointers on current vseg in VSL
434        vseg_xp   = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
435        vseg      = GET_PTR( vseg_xp );
436        vseg_type = vseg->type;
[567]437
[625]438#if( DEBUG_VMM_USER_RESET & 1 )
439if( DEBUG_VMM_USER_RESET < cycle )
440printk("\n[%s] found %s vseg / vpn_base %x / vpn_size %d\n",
441__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
442#endif
443        // delete non kernel vseg 
444        if( (vseg_type != VSEG_TYPE_KCODE) && 
445            (vseg_type != VSEG_TYPE_KDATA) && 
446            (vseg_type != VSEG_TYPE_KDEV ) )
447        {
448            // remove vseg from VSL
449            vmm_remove_vseg( process , vseg );
[567]450
[625]451#if( DEBUG_VMM_USER_RESET & 1 )
452if( DEBUG_VMM_USER_RESET < cycle )
453printk("\n[%s] %s vseg deleted / vpn_base %x / vpn_size %d\n",
454__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
455#endif
456        }
457        else
458        {
[567]459
[625]460#if( DEBUG_VMM_USER_RESET & 1 )
461if( DEBUG_VMM_USER_RESET < cycle )
462printk("\n[%s] keep %s vseg / vpn_base %x / vpn_size %d\n",
463__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
464#endif
465        }
466        }  // end loop on vsegs in VSL
[567]467
[625]468    // release the VSL lock
469        remote_rwlock_wr_release( lock_xp );
[567]470
[625]471// FIXME il faut gérer les process copies...
[611]472
[625]473#if DEBUG_VMM_USER_RESET
474cycle = (uint32_t)hal_get_cycles();
475if( DEBUG_VMM_USER_RESET < cycle )
476printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
477__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy , cycle );
478#endif
[611]479
[625]480}  // end vmm_user_reset()
[611]481
[595]482////////////////////////////////////////////////
[433]483void vmm_global_update_pte( process_t * process,
484                            vpn_t       vpn,
485                            uint32_t    attr,
486                            ppn_t       ppn )
[23]487{
[408]488    xlist_entry_t * process_root_ptr;
489    xptr_t          process_root_xp;
490    xptr_t          process_iter_xp;
[23]491
[408]492    xptr_t          remote_process_xp;
493    cxy_t           remote_process_cxy;
494    process_t     * remote_process_ptr;
495    xptr_t          remote_gpt_xp;
[23]496
[408]497    pid_t           pid;
498    cxy_t           owner_cxy;
499    lpid_t          owner_lpid;
[23]500
[438]501#if DEBUG_VMM_UPDATE_PTE
[433]502uint32_t cycle = (uint32_t)hal_get_cycles();
[595]503thread_t * this = CURRENT_THREAD;
[438]504if( DEBUG_VMM_UPDATE_PTE < cycle )
[595]505printk("\n[%s] thread[%x,%x] enter for process %x / vpn %x / cycle %d\n",
506__FUNCTION__, this->process->pid, this->trdid, process->pid , vpn , cycle );
[433]507#endif
508
[567]509// check cluster is reference
[585]510assert( (GET_CXY( process->ref_xp ) == local_cxy) , "not called in reference cluster\n");
[433]511
[408]512    // get extended pointer on root of process copies xlist in owner cluster
513    pid              = process->pid;
514    owner_cxy        = CXY_FROM_PID( pid );
515    owner_lpid       = LPID_FROM_PID( pid );
516    process_root_ptr = &LOCAL_CLUSTER->pmgr.copies_root[owner_lpid];
517    process_root_xp  = XPTR( owner_cxy , process_root_ptr );
[23]518
[408]519    // loop on destination process copies
520    XLIST_FOREACH( process_root_xp , process_iter_xp )
521    {
522        // get cluster and local pointer on remote process
523        remote_process_xp  = XLIST_ELEMENT( process_iter_xp , process_t , copies_list );
[433]524        remote_process_ptr = GET_PTR( remote_process_xp );
[408]525        remote_process_cxy = GET_CXY( remote_process_xp );
[407]526
[438]527#if (DEBUG_VMM_UPDATE_PTE & 0x1)
528if( DEBUG_VMM_UPDATE_PTE < cycle )
[595]529printk("\n[%s] threadr[%x,%x] handling vpn %x for process %x in cluster %x\n",
530__FUNCTION__, this->process->pid, this->trdid, vpn, process->pid, remote_process_cxy );
[433]531#endif
532
[408]533        // get extended pointer on remote gpt
534        remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt );
535
[433]536        // update remote GPT
537        hal_gpt_update_pte( remote_gpt_xp, vpn, attr, ppn );
[408]538    } 
539
[438]540#if DEBUG_VMM_UPDATE_PTE
[433]541cycle = (uint32_t)hal_get_cycles();
[438]542if( DEBUG_VMM_UPDATE_PTE < cycle )
[595]543printk("\n[%s] thread[%x,%x] exit for process %x / vpn %x / cycle %d\n",
544__FUNCTION__, this->process->pid, this->trdid, process->pid , vpn , cycle );
[433]545#endif
546
547}  // end vmm_global_update_pte()
548
[408]549///////////////////////////////////////
550void vmm_set_cow( process_t * process )
551{
552    vmm_t         * vmm;
553
554    xlist_entry_t * process_root_ptr;
555    xptr_t          process_root_xp;
556    xptr_t          process_iter_xp;
557
558    xptr_t          remote_process_xp;
559    cxy_t           remote_process_cxy;
560    process_t     * remote_process_ptr;
561    xptr_t          remote_gpt_xp;
562
563    xptr_t          vseg_root_xp;
564    xptr_t          vseg_iter_xp;
565
566    xptr_t          vseg_xp;
567    vseg_t        * vseg;
568
569    pid_t           pid;
570    cxy_t           owner_cxy;
571    lpid_t          owner_lpid;
572
[438]573#if DEBUG_VMM_SET_COW
[595]574uint32_t   cycle = (uint32_t)hal_get_cycles();
575thread_t * this  = CURRENT_THREAD;
[438]576if( DEBUG_VMM_SET_COW < cycle )
[595]577printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
578__FUNCTION__, this->process->pid, this->trdid, process->pid , cycle );
[433]579#endif
[408]580
[567]581// check cluster is reference
582assert( (GET_CXY( process->ref_xp ) == local_cxy) ,
583"local cluster is not process reference cluster\n");
[408]584
585    // get pointer on reference VMM
586    vmm = &process->vmm;
587
588    // get extended pointer on root of process copies xlist in owner cluster
589    pid              = process->pid;
590    owner_cxy        = CXY_FROM_PID( pid );
591    owner_lpid       = LPID_FROM_PID( pid );
592    process_root_ptr = &LOCAL_CLUSTER->pmgr.copies_root[owner_lpid];
593    process_root_xp  = XPTR( owner_cxy , process_root_ptr );
594
595    // get extended pointer on root of vsegs xlist from reference VMM
596    vseg_root_xp  = XPTR( local_cxy , &vmm->vsegs_root ); 
597
598    // loop on destination process copies
599    XLIST_FOREACH( process_root_xp , process_iter_xp )
600    {
601        // get cluster and local pointer on remote process
602        remote_process_xp  = XLIST_ELEMENT( process_iter_xp , process_t , copies_list );
[433]603        remote_process_ptr = GET_PTR( remote_process_xp );
[408]604        remote_process_cxy = GET_CXY( remote_process_xp );
605
[595]606#if (DEBUG_VMM_SET_COW & 1)
[438]607if( DEBUG_VMM_SET_COW < cycle )
[595]608printk("\n[%s] thread[%x,%x] handling process %x in cluster %x\n",
609__FUNCTION__, this->process->pid, this->trdid, process->pid , remote_process_cxy );
[433]610#endif
[408]611
612        // get extended pointer on remote gpt
613        remote_gpt_xp = XPTR( remote_process_cxy , &remote_process_ptr->vmm.gpt );
614
615        // loop on vsegs in (local) reference process VSL
616        XLIST_FOREACH( vseg_root_xp , vseg_iter_xp )
617        {
618            // get pointer on vseg
619            vseg_xp  = XLIST_ELEMENT( vseg_iter_xp , vseg_t , xlist );
[433]620            vseg     = GET_PTR( vseg_xp );
[408]621
[567]622assert( (GET_CXY( vseg_xp ) == local_cxy) ,
623"all vsegs in reference VSL must be local\n" );
[408]624
625            // get vseg type, base and size
626            uint32_t type     = vseg->type;
627            vpn_t    vpn_base = vseg->vpn_base;
628            vpn_t    vpn_size = vseg->vpn_size;
629
[595]630#if (DEBUG_VMM_SET_COW & 1)
[438]631if( DEBUG_VMM_SET_COW < cycle )
[595]632printk("\n[%s] thread[%x,%x] handling vseg %s / vpn_base = %x / vpn_size = %x\n",
633__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(type), vpn_base, vpn_size );
[433]634#endif
635            // only DATA, ANON and REMOTE vsegs
[408]636            if( (type == VSEG_TYPE_DATA)  ||
637                (type == VSEG_TYPE_ANON)  ||
638                (type == VSEG_TYPE_REMOTE) )
639            {
[433]640                vpn_t      vpn;
641                uint32_t   attr;
642                ppn_t      ppn;
643                xptr_t     page_xp;
644                cxy_t      page_cxy;
645                page_t   * page_ptr;
646                xptr_t     forks_xp;
[469]647                xptr_t     lock_xp;
[433]648
649                // update flags in remote GPT
650                hal_gpt_set_cow( remote_gpt_xp,
651                                 vpn_base,
652                                 vpn_size ); 
653
654                // atomically increment pending forks counter in physical pages,
655                // for all vseg pages that are mapped in reference cluster
656                if( remote_process_cxy == local_cxy )
657                {
658                    // scan all pages in vseg
659                    for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
660                    {
661                        // get page attributes and PPN from reference GPT
[585]662                        hal_gpt_get_pte( remote_gpt_xp , vpn , &attr , &ppn ); 
[433]663
664                        // atomically update pending forks counter if page is mapped
665                        if( attr & GPT_MAPPED )
666                        {
[469]667                            // get pointers and cluster on page descriptor
[433]668                            page_xp  = ppm_ppn2page( ppn );
669                            page_cxy = GET_CXY( page_xp );
670                            page_ptr = GET_PTR( page_xp );
[469]671
672                            // get extended pointers on "forks" and "lock"
[433]673                            forks_xp = XPTR( page_cxy , &page_ptr->forks );
[469]674                            lock_xp  = XPTR( page_cxy , &page_ptr->lock );
675
[567]676                            // take lock protecting "forks" counter
677                            remote_busylock_acquire( lock_xp );
678
[469]679                            // increment "forks"
[433]680                            hal_remote_atomic_add( forks_xp , 1 );
[567]681
682                            // release lock protecting "forks" counter
683                            remote_busylock_release( lock_xp );
[433]684                        }
685                    }   // end loop on vpn
686                }   // end if local
687            }   // end if vseg type
688        }   // end loop on vsegs
[408]689    }   // end loop on process copies
690 
[438]691#if DEBUG_VMM_SET_COW
[433]692cycle = (uint32_t)hal_get_cycles();
[438]693if( DEBUG_VMM_SET_COW < cycle )
[595]694printk("\n[%s] thread[%x,%x] exit for process %x / cycle %d\n",
695__FUNCTION__, this->process->pid, this->trdid, process->pid , cycle );
[433]696#endif
[408]697
698}  // end vmm_set-cow()
699
700/////////////////////////////////////////////////
701error_t vmm_fork_copy( process_t * child_process,
702                       xptr_t      parent_process_xp )
703{
704    error_t     error;
705    cxy_t       parent_cxy;
706    process_t * parent_process;
707    vmm_t     * parent_vmm;
708    xptr_t      parent_lock_xp;
709    vmm_t     * child_vmm;
710    xptr_t      iter_xp;
711    xptr_t      parent_vseg_xp;
712    vseg_t    * parent_vseg;
713    vseg_t    * child_vseg;
714    uint32_t    type;
715    bool_t      cow;
716    vpn_t       vpn;           
717    vpn_t       vpn_base;
718    vpn_t       vpn_size;
[469]719    xptr_t      page_xp;        // extended pointer on page descriptor
[408]720    page_t    * page_ptr;
721    cxy_t       page_cxy;
[469]722    xptr_t      forks_xp;       // extended pointer on forks counter in page descriptor
[408]723    xptr_t      parent_root_xp;
724    bool_t      mapped; 
725    ppn_t       ppn;
726
[438]727#if DEBUG_VMM_FORK_COPY
[433]728uint32_t cycle = (uint32_t)hal_get_cycles();
[595]729thread_t * this = CURRENT_THREAD;
[438]730if( DEBUG_VMM_FORK_COPY < cycle )
[595]731printk("\n[%s] thread %x enter / cycle %d\n",
732__FUNCTION__ , this->process->pid, this->trdid, cycle );
[433]733#endif
[408]734
735    // get parent process cluster and local pointer
736    parent_cxy     = GET_CXY( parent_process_xp );
[433]737    parent_process = GET_PTR( parent_process_xp );
[408]738
739    // get local pointers on parent and child VMM
740    parent_vmm = &parent_process->vmm; 
741    child_vmm  = &child_process->vmm;
742
[629]743    // initialize the lock protecting the child VSL
[625]744        remote_rwlock_init( XPTR( local_cxy , &child_vmm->vsl_lock ) , LOCK_VMM_VSL );
[408]745
746    // initialize the child VSL as empty
747    xlist_root_init( XPTR( local_cxy, &child_vmm->vsegs_root ) );
748    child_vmm->vsegs_nr = 0;
749
[625]750    // create an empty child GPT
[408]751    error = hal_gpt_create( &child_vmm->gpt );
[407]752    if( error )
753    {
[408]754        printk("\n[ERROR] in %s : cannot create GPT\n", __FUNCTION__ );
755        return -1;
[407]756    }
757
[625]758    // build extended pointer on parent VSL root and lock
[408]759    parent_root_xp = XPTR( parent_cxy , &parent_vmm->vsegs_root );
[625]760    parent_lock_xp = XPTR( parent_cxy , &parent_vmm->vsl_lock );
[408]761
[567]762    // take the lock protecting the parent VSL in read mode
763    remote_rwlock_rd_acquire( parent_lock_xp );
[415]764
[408]765    // loop on parent VSL xlist
766    XLIST_FOREACH( parent_root_xp , iter_xp )
[23]767    {
[625]768        // get pointers on current parent vseg
[408]769        parent_vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
[433]770        parent_vseg    = GET_PTR( parent_vseg_xp );
[23]771
[408]772        // get vseg type
[567]773        type = hal_remote_l32( XPTR( parent_cxy , &parent_vseg->type ) );
[408]774       
[438]775#if DEBUG_VMM_FORK_COPY
[433]776cycle = (uint32_t)hal_get_cycles();
[438]777if( DEBUG_VMM_FORK_COPY < cycle )
[595]778printk("\n[%s] thread[%x,%x] found parent vseg %s / vpn_base = %x / cycle %d\n",
779__FUNCTION__ , this->process->pid, this->trdid, vseg_type_str(type),
[567]780hal_remote_l32( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
[433]781#endif
[23]782
[623]783        // all parent vsegs - but STACK and kernel vsegs - must be copied in child VSL
784        if( (type != VSEG_TYPE_STACK) && (type != VSEG_TYPE_KCODE) &&
785            (type != VSEG_TYPE_KDATA) && (type != VSEG_TYPE_KDEV) )
[23]786        {
[408]787            // allocate memory for a new child vseg
788            child_vseg = vseg_alloc();
789            if( child_vseg == NULL )   // release all allocated vsegs
[23]790            {
[408]791                vmm_destroy( child_process );
792                printk("\n[ERROR] in %s : cannot create vseg for child\n", __FUNCTION__ );
793                return -1;
[23]794            }
795
[408]796            // copy parent vseg to child vseg
797            vseg_init_from_ref( child_vseg , parent_vseg_xp );
[23]798
[625]799            // build extended pointer on VSL lock
800            xptr_t lock_xp = XPTR( local_cxy , &child_vmm->vsl_lock );
801 
802            // take the VSL lock in write mode
803            remote_rwlock_wr_acquire( lock_xp );
804
[408]805            // register child vseg in child VSL
[611]806            vmm_attach_vseg_to_vsl( child_vmm , child_vseg );
[407]807
[625]808            // release the VSL lock
809            remote_rwlock_wr_release( lock_xp );
810
[438]811#if DEBUG_VMM_FORK_COPY
[433]812cycle = (uint32_t)hal_get_cycles();
[438]813if( DEBUG_VMM_FORK_COPY < cycle )
[595]814printk("\n[%s] thread[%x,%x] copied vseg %s / vpn_base = %x to child VSL / cycle %d\n",
815__FUNCTION__ , this->process->pid, this->trdid, vseg_type_str(type),
[567]816hal_remote_l32( XPTR( parent_cxy , &parent_vseg->vpn_base ) ) , cycle );
[433]817#endif
[625]818            // copy DATA, ANON, REMOTE, FILE parent GPT entries to child GPT
[408]819            if( type != VSEG_TYPE_CODE )
820            {
[625]821                // activate the COW for DATA, ANON, REMOTE vsegs only
[408]822                cow = ( type != VSEG_TYPE_FILE );
[23]823
[408]824                vpn_base = child_vseg->vpn_base;
825                vpn_size = child_vseg->vpn_size;
[23]826
[408]827                // scan pages in parent vseg
828                for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
829                {
830                    error = hal_gpt_pte_copy( &child_vmm->gpt,
[625]831                                              vpn,
[408]832                                              XPTR( parent_cxy , &parent_vmm->gpt ),
833                                              vpn,
834                                              cow,
835                                              &ppn,
836                                              &mapped );
837                    if( error )
838                    {
839                        vmm_destroy( child_process );
840                        printk("\n[ERROR] in %s : cannot copy GPT\n", __FUNCTION__ );
841                        return -1;
842                    }
843
[433]844                    // increment pending forks counter in page if mapped
[408]845                    if( mapped )
846                    {
[469]847                        // get pointers and cluster on page descriptor
848                        page_xp  = ppm_ppn2page( ppn );
[408]849                        page_cxy = GET_CXY( page_xp );
[433]850                        page_ptr = GET_PTR( page_xp );
[408]851
[469]852                        // get extended pointers on "forks" and "lock"
853                        forks_xp = XPTR( page_cxy , &page_ptr->forks );
854                        lock_xp  = XPTR( page_cxy , &page_ptr->lock );
855
[567]856                        // get lock protecting "forks" counter
857                        remote_busylock_acquire( lock_xp );
858
[469]859                        // increment "forks"
860                        hal_remote_atomic_add( forks_xp , 1 );
861
[567]862                        // release lock protecting "forks" counter
863                        remote_busylock_release( lock_xp );
864
[438]865#if DEBUG_VMM_FORK_COPY
[433]866cycle = (uint32_t)hal_get_cycles();
[438]867if( DEBUG_VMM_FORK_COPY < cycle )
[595]868printk("\n[%s] thread[%x,%x] copied vpn %x to child GPT / cycle %d\n",
869__FUNCTION__ , this->process->pid, this->trdid , vpn , cycle );
[433]870#endif
[408]871                    }
872                }
873            }   // end if no code & no stack
874        }   // end if no stack
875    }   // end loop on vsegs
876
[567]877    // release the parent VSL lock in read mode
878    remote_rwlock_rd_release( parent_lock_xp );
[408]879
[623]880    // update child VMM with kernel vsegs
881    error = hal_vmm_kernel_update( child_process );
[415]882
883    if( error )
884    {
[623]885        printk("\n[ERROR] in %s : cannot update child VMM\n", __FUNCTION__ );
[415]886        return -1;
887    }
888
[408]889    // initialize the child VMM STACK allocator
890    child_vmm->stack_mgr.bitmap   = 0;
891    child_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
892
893    // initialize the child VMM MMAP allocator
[23]894    uint32_t i;
[408]895    child_vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
896    child_vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
897    child_vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
[625]898    for( i = 0 ; i < 32 ; i++ ) 
899    {
900        xlist_root_init( XPTR( local_cxy , &child_vmm->mmap_mgr.zombi_list[i] ) );
901    }
[23]902
[178]903    // initialize instrumentation counters
[408]904        child_vmm->pgfault_nr    = 0;
[23]905
[408]906    // copy base addresses from parent VMM to child VMM
907    child_vmm->args_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->args_vpn_base));
908    child_vmm->envs_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->envs_vpn_base));
909    child_vmm->heap_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->heap_vpn_base));
910    child_vmm->code_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->code_vpn_base));
911    child_vmm->data_vpn_base = (vpn_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->data_vpn_base));
[23]912
[408]913    child_vmm->entry_point = (intptr_t)hal_remote_lpt(XPTR(parent_cxy, &parent_vmm->entry_point));
[23]914
[124]915    hal_fence();
[23]916
[438]917#if DEBUG_VMM_FORK_COPY
[433]918cycle = (uint32_t)hal_get_cycles();
[438]919if( DEBUG_VMM_FORK_COPY < cycle )
[595]920printk("\n[%s] thread[%x,%x] exit successfully / cycle %d\n",
921__FUNCTION__ , this->process->pid, this->trdid , cycle );
[433]922#endif
923
[23]924    return 0;
925
[408]926}  // vmm_fork_copy()
[204]927
[1]928///////////////////////////////////////
929void vmm_destroy( process_t * process )
930{
[408]931    xptr_t   vseg_xp;
[1]932        vseg_t * vseg;
933
[438]934#if DEBUG_VMM_DESTROY
[433]935uint32_t cycle = (uint32_t)hal_get_cycles();
[595]936thread_t * this = CURRENT_THREAD;
[438]937if( DEBUG_VMM_DESTROY < cycle )
[595]938printk("\n[%s] thread[%x,%x] enter for process %x in cluster %x / cycle %d\n",
939__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy, cycle );
[433]940#endif
[416]941
[438]942#if (DEBUG_VMM_DESTROY & 1 )
[443]943if( DEBUG_VMM_DESTROY < cycle )
[624]944hal_vmm_display( process , true );
[437]945#endif
946
[433]947    // get pointer on local VMM
[1]948    vmm_t  * vmm = &process->vmm;
949
[625]950    // build extended pointer on VSL root, VSL lock and GPT lock
951    xptr_t   vsl_root_xp = XPTR( local_cxy , &vmm->vsegs_root );
952    xptr_t   vsl_lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
[408]953
[625]954    // take the VSL lock
955    remote_rwlock_wr_acquire( vsl_lock_xp );
956
[611]957    // scan the VSL to delete all registered vsegs
[625]958    // (we don't use a FOREACH in case of item deletion)
959    xptr_t  iter_xp;
960    xptr_t  next_xp;
961        for( iter_xp = hal_remote_l64( vsl_root_xp ) ; 
962         iter_xp != vsl_root_xp ;
963         iter_xp = next_xp )
[1]964        {
[625]965        // save extended pointer on next item in xlist
966        next_xp = hal_remote_l64( iter_xp );
[409]967
[625]968        // get pointers on current vseg in VSL
969        vseg_xp   = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
970        vseg      = GET_PTR( vseg_xp );
971
[611]972        // delete vseg and release physical pages
[625]973        vmm_remove_vseg( process , vseg );
[409]974
[443]975#if( DEBUG_VMM_DESTROY & 1 )
976if( DEBUG_VMM_DESTROY < cycle )
[611]977printk("\n[%s] %s vseg deleted / vpn_base %x / vpn_size %d\n",
[443]978__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
979#endif
980
[1]981        }
982
[625]983    // release the VSL lock
984    remote_rwlock_wr_release( vsl_lock_xp );
985
986    // remove all registered MMAP vsegs
987    // from zombi_lists in MMAP allocator
[1]988    uint32_t i;
989    for( i = 0 ; i<32 ; i++ )
990    {
[625]991        // build extended pointer on zombi_list[i]
992        xptr_t root_xp = XPTR( local_cxy , &vmm->mmap_mgr.zombi_list[i] );
993 
994        // scan zombi_list[i]
995            while( !xlist_is_empty( root_xp ) )
[1]996            {
[625]997                    vseg_xp = XLIST_FIRST( root_xp , vseg_t , xlist );
998            vseg    = GET_PTR( vseg_xp );
[443]999
1000#if( DEBUG_VMM_DESTROY & 1 )
1001if( DEBUG_VMM_DESTROY < cycle )
[595]1002printk("\n[%s] found zombi vseg / vpn_base %x / vpn_size %d\n",
[443]1003__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
1004#endif
[611]1005            // clean vseg descriptor
1006            vseg->vmm = NULL;
1007
[625]1008            // remove vseg from  zombi_list
[611]1009            xlist_unlink( XPTR( local_cxy , &vseg->xlist ) );
1010
1011                    // release vseg descriptor
[1]1012            vseg_free( vseg );
[443]1013
1014#if( DEBUG_VMM_DESTROY & 1 )
1015if( DEBUG_VMM_DESTROY < cycle )
[595]1016printk("\n[%s] zombi vseg released / vpn_base %x / vpn_size %d\n",
[443]1017__FUNCTION__ , vseg_type_str( vseg->type ), vseg->vpn_base, vseg->vpn_size );
1018#endif
[1]1019            }
1020    }
1021
[409]1022    // release memory allocated to the GPT itself
[1]1023    hal_gpt_destroy( &vmm->gpt );
1024
[438]1025#if DEBUG_VMM_DESTROY
[433]1026cycle = (uint32_t)hal_get_cycles();
[438]1027if( DEBUG_VMM_DESTROY < cycle )
[595]1028printk("\n[%s] thread[%x,%x] exit for process %x in cluster %x / cycle %d\n",
1029__FUNCTION__, this->process->pid, this->trdid, process->pid, local_cxy , cycle );
[433]1030#endif
[416]1031
[204]1032}  // end vmm_destroy()
1033
[1]1034/////////////////////////////////////////////////
1035vseg_t * vmm_check_conflict( process_t * process,
[21]1036                             vpn_t       vpn_base,
[1]1037                             vpn_t       vpn_size )
1038{
1039    vmm_t        * vmm = &process->vmm;
[408]1040
1041    // scan the VSL
[1]1042        vseg_t       * vseg;
[408]1043    xptr_t         iter_xp;
1044    xptr_t         vseg_xp;
1045    xptr_t         root_xp = XPTR( local_cxy , &vmm->vsegs_root );
[1]1046
[408]1047        XLIST_FOREACH( root_xp , iter_xp )
[1]1048        {
[408]1049                vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
[433]1050        vseg    = GET_PTR( vseg_xp );
[204]1051
[21]1052                if( ((vpn_base + vpn_size) > vseg->vpn_base) &&
1053             (vpn_base < (vseg->vpn_base + vseg->vpn_size)) ) return vseg;
[1]1054        }
1055    return NULL;
1056
[204]1057}  // end vmm_check_conflict()
1058
[1]1059
1060
[407]1061////////////////////////////////////////////////
1062vseg_t * vmm_create_vseg( process_t   * process,
1063                              vseg_type_t   type,
1064                          intptr_t      base,
1065                              uint32_t      size,
1066                          uint32_t      file_offset,
1067                          uint32_t      file_size,
1068                          xptr_t        mapper_xp,
1069                          cxy_t         cxy )
[1]1070{
1071    vseg_t     * vseg;          // created vseg pointer
[204]1072    vpn_t        vpn_base;      // first page index
[595]1073    vpn_t        vpn_size;      // number of pages covered by vseg
[1]1074        error_t      error;
1075
[438]1076#if DEBUG_VMM_CREATE_VSEG
[595]1077thread_t * this  = CURRENT_THREAD;
1078uint32_t   cycle = (uint32_t)hal_get_cycles();
[438]1079if( DEBUG_VMM_CREATE_VSEG < cycle )
[614]1080printk("\n[%s] thread[%x,%x] enter for process %x / %s / cxy %x / cycle %d\n",
1081__FUNCTION__, this->process->pid, this->trdid, process->pid, vseg_type_str(type), cxy, cycle );
[433]1082#endif
[21]1083
[407]1084    // get pointer on VMM
1085        vmm_t * vmm    = &process->vmm;
[21]1086
[204]1087    // compute base, size, vpn_base, vpn_size, depending on vseg type
[407]1088    // we use the VMM specific allocators for "stack", "file", "anon", & "remote" vsegs
[595]1089
[1]1090    if( type == VSEG_TYPE_STACK )
1091    {
1092        // get vpn_base and vpn_size from STACK allocator
[625]1093        vmm_stack_alloc( vmm , base , &vpn_base , &vpn_size );
[1]1094
1095        // compute vseg base and size from vpn_base and vpn_size
1096        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
1097        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
1098    }
[595]1099    else if( type == VSEG_TYPE_FILE )
1100    {
1101        // compute page index (in mapper) for first byte
1102        vpn_t    vpn_min    = file_offset >> CONFIG_PPM_PAGE_SHIFT;
1103
1104        // compute page index (in mapper) for last byte
1105        vpn_t    vpn_max    = (file_offset + size - 1) >> CONFIG_PPM_PAGE_SHIFT;
1106
1107        // compute offset in first page
1108        uint32_t offset = file_offset & CONFIG_PPM_PAGE_MASK;
1109
1110        // compute number of pages required in virtual space
1111        vpn_t    npages      = vpn_max - vpn_min + 1;
1112
1113        // get vpn_base and vpn_size from MMAP allocator
1114        error = vmm_mmap_alloc( vmm , npages , &vpn_base , &vpn_size );
1115        if( error )
1116        {
1117            printk("\n[ERROR] in %s : no vspace for mmap vseg / process %x in cluster %x\n",
1118                   __FUNCTION__ , process->pid , local_cxy );
1119            return NULL;
1120        }
1121
1122        // set the vseg base (not always aligned for FILE)
1123        base = (vpn_base << CONFIG_PPM_PAGE_SHIFT) + offset; 
1124    }
[21]1125    else if( (type == VSEG_TYPE_ANON) ||
[1]1126             (type == VSEG_TYPE_REMOTE) )
1127    {
[595]1128        // compute number of required pages in virtual space
1129        vpn_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
1130        if( size & CONFIG_PPM_PAGE_MASK) npages++;
1131       
[1]1132        // get vpn_base and vpn_size from MMAP allocator
1133        error = vmm_mmap_alloc( vmm , npages , &vpn_base , &vpn_size );
1134        if( error )
1135        {
1136            printk("\n[ERROR] in %s : no vspace for mmap vseg / process %x in cluster %x\n",
1137                   __FUNCTION__ , process->pid , local_cxy );
1138            return NULL;
1139        }
1140
[595]1141        // set vseg base (always aligned for ANON or REMOTE)
[1]1142        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
1143    }
[623]1144    else    // VSEG_TYPE_DATA, VSEG_TYPE_CODE or KERNEL vseg
[1]1145    {
[204]1146        uint32_t vpn_min = base >> CONFIG_PPM_PAGE_SHIFT;
1147        uint32_t vpn_max = (base + size - 1) >> CONFIG_PPM_PAGE_SHIFT;
1148
1149        vpn_base = vpn_min;
1150            vpn_size = vpn_max - vpn_min + 1;
[1]1151    }
1152
1153    // check collisions
1154    vseg = vmm_check_conflict( process , vpn_base , vpn_size );
[624]1155
[1]1156    if( vseg != NULL )
1157    {
[614]1158        printk("\n[ERROR] in %s for process %x : new vseg [vpn_base %x / vpn_size %x]\n"
1159               "  overlap existing vseg [vpn_base %x / vpn_size %x]\n",
[407]1160        __FUNCTION__ , process->pid, vpn_base, vpn_size, vseg->vpn_base, vseg->vpn_size );
[1]1161        return NULL;
1162    }
1163
1164    // allocate physical memory for vseg descriptor
1165        vseg = vseg_alloc();
1166        if( vseg == NULL )
1167        {
1168            printk("\n[ERROR] in %s for process %x : cannot allocate memory for vseg\n",
[407]1169        __FUNCTION__ , process->pid );
[1]1170        return NULL;
1171        }
1172
[614]1173#if DEBUG_VMM_CREATE_VSEG
1174if( DEBUG_VMM_CREATE_VSEG < cycle )
1175printk("\n[%s] thread[%x,%x] : base %x / size %x / vpn_base %x / vpn_size %x\n",
1176__FUNCTION__, this->process->pid, this->trdid, base, size, vpn_base, vpn_size );
1177#endif
1178
[1]1179    // initialize vseg descriptor
[407]1180        vseg_init( vseg,
1181               type,
1182               base,
1183               size,
1184               vpn_base,
1185               vpn_size,
1186               file_offset,
1187               file_size,
1188               mapper_xp,
1189               cxy );
[1]1190
[625]1191    // build extended pointer on VSL lock
1192    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
1193 
1194    // take the VSL lock in write mode
1195    remote_rwlock_wr_acquire( lock_xp );
1196
[408]1197    // attach vseg to VSL
[611]1198        vmm_attach_vseg_to_vsl( vmm , vseg );
[1]1199
[625]1200    // release the VSL lock
1201    remote_rwlock_wr_release( lock_xp );
1202
[438]1203#if DEBUG_VMM_CREATE_VSEG
[433]1204cycle = (uint32_t)hal_get_cycles();
[438]1205if( DEBUG_VMM_CREATE_VSEG < cycle )
[595]1206printk("\n[%s] thread[%x,%x] exit / %s / cxy %x / cycle %d\n",
1207__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(type), cxy, cycle );
[433]1208#endif
[21]1209
[1]1210        return vseg;
1211
[406]1212}  // vmm_create_vseg()
1213
[625]1214
1215//////////////////////////////////////////
1216void vmm_remove_vseg( process_t * process,
1217                      vseg_t    * vseg )
[1]1218{
[625]1219    vmm_t     * vmm;        // local pointer on process VMM
[629]1220    xptr_t      gpt_xp;     // extended pointer on GPT
[625]1221    bool_t      is_ref;     // local process is reference process
1222    uint32_t    vseg_type;  // vseg type
[21]1223    vpn_t       vpn;        // VPN of current PTE
1224    vpn_t       vpn_min;    // VPN of first PTE
[1]1225    vpn_t       vpn_max;    // VPN of last PTE (excluded)
[409]1226    ppn_t       ppn;        // current PTE ppn value
1227    uint32_t    attr;       // current PTE attributes
1228    xptr_t      page_xp;    // extended pointer on page descriptor
1229    cxy_t       page_cxy;   // page descriptor cluster
1230    page_t    * page_ptr;   // page descriptor pointer
[625]1231    xptr_t      count_xp;   // extended pointer on page refcount
1232    uint32_t    count;      // current value of page refcount
[1]1233
[625]1234// check arguments
1235assert( (process != NULL), "process argument is NULL" );
1236assert( (vseg    != NULL), "vseg argument is NULL" );
[409]1237
[625]1238    // compute is_ref
1239    is_ref = (GET_CXY( process->ref_xp ) == local_cxy);
[1]1240
[625]1241    // get pointers on local process VMM
[611]1242    vmm = &process->vmm;
1243
[629]1244    // build extended pointer on GPT
1245    gpt_xp = XPTR( local_cxy , &vmm->gpt );
1246
[623]1247    // get relevant vseg infos
[624]1248    vseg_type = vseg->type;
1249    vpn_min   = vseg->vpn_base;
1250    vpn_max   = vpn_min + vseg->vpn_size;
[623]1251
[625]1252#if DEBUG_VMM_REMOVE_VSEG
1253uint32_t   cycle = (uint32_t)hal_get_cycles();
1254thread_t * this  = CURRENT_THREAD;
1255if( DEBUG_VMM_REMOVE_VSEG < cycle )
1256printk("\n[%s] thread[%x,%x] enter / process %x / %s / base %x / cycle %d\n",
1257__FUNCTION__, this->process->pid, this->trdid, 
1258process->pid, vseg_type_str(vseg->type), vseg->min, cycle );
1259#endif
1260
1261    // loop on PTEs in GPT
[1]1262        for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
1263    {
[625]1264        // get ppn and attr
[629]1265        hal_gpt_get_pte( gpt_xp , vpn , &attr , &ppn );
[409]1266
[625]1267        if( attr & GPT_MAPPED )  // PTE is mapped
[409]1268        { 
[437]1269
[625]1270#if( DEBUG_VMM_REMOVE_VSEG & 1 )
1271if( DEBUG_VMM_REMOVE_VSEG < cycle )
1272printk("- unmap vpn %x / ppn %x / %s" , vpn , ppn, vseg_type_str(vseg_type) );
[437]1273#endif
[585]1274            // unmap GPT entry in local GPT
[629]1275            hal_gpt_reset_pte( gpt_xp , vpn );
[409]1276
[625]1277            // get pointers on physical page descriptor
1278            page_xp  = ppm_ppn2page( ppn );
1279            page_cxy = GET_CXY( page_xp );
1280            page_ptr = GET_PTR( page_xp );
[409]1281
[625]1282            // decrement page refcount
1283            count_xp = XPTR( page_cxy , &page_ptr->refcount );
1284            count    = hal_remote_atomic_add( count_xp , -1 );
[624]1285
[625]1286            // compute the ppn_release condition depending on vseg type
1287            bool_t ppn_release;
1288            if( (vseg_type == VSEG_TYPE_FILE)  ||
1289                (vseg_type == VSEG_TYPE_KCODE) || 
1290                (vseg_type == VSEG_TYPE_KDATA) || 
1291                (vseg_type == VSEG_TYPE_KDEV) )           
1292            {
1293                // no physical page release for FILE and KERNEL
1294                ppn_release = false;
1295            }
1296            else if( (vseg_type == VSEG_TYPE_CODE)  ||
1297                     (vseg_type == VSEG_TYPE_STACK) ) 
1298            {
1299                // always release physical page for private vsegs
1300                ppn_release = true;
1301            }
1302            else if( (vseg_type == VSEG_TYPE_ANON)  ||
1303                     (vseg_type == VSEG_TYPE_REMOTE) )
1304            {
1305                // release physical page if reference cluster
1306                ppn_release = is_ref;
1307            }
1308            else if( is_ref )  // vseg_type == DATA in reference cluster
1309            {
1310                // get extended pointers on forks and lock field in page descriptor
1311                xptr_t forks_xp = XPTR( page_cxy , &page_ptr->forks );
1312                xptr_t lock_xp  = XPTR( page_cxy , &page_ptr->lock );
[433]1313
[625]1314                // take lock protecting "forks" counter
[621]1315                remote_busylock_acquire( lock_xp );
[623]1316
[625]1317                // get number of pending forks from page descriptor
1318                uint32_t forks = hal_remote_l32( forks_xp );
[623]1319
[625]1320                // decrement pending forks counter if required
1321                if( forks )  hal_remote_atomic_add( forks_xp , -1 );
[624]1322
[625]1323                // release lock protecting "forks" counter
1324                remote_busylock_release( lock_xp );
[624]1325
[625]1326                // release physical page if forks == 0
1327                ppn_release = (forks == 0); 
1328            }
1329            else              // vseg_type == DATA not in reference cluster
1330            {
1331                // no physical page release if not in reference cluster
1332                ppn_release = false;
1333            }
[611]1334
[625]1335            // release physical page to relevant kmem when required
[632]1336            if( ppn_release ) ppm_remote_free_pages( page_cxy , page_ptr );
[623]1337
[625]1338#if( DEBUG_VMM_REMOVE_VSEG & 1 )
1339if( DEBUG_VMM_REMOVE_VSEG < cycle )
1340{
1341    if( ppn_release ) printk(" / released to kmem\n" );
1342    else              printk("\n");
1343}
1344#endif
[409]1345        }
[1]1346    }
[433]1347
[625]1348    // remove vseg from VSL
[611]1349    vmm_detach_vseg_from_vsl( vmm , vseg );
1350
[625]1351    // release vseg descriptor depending on vseg type
1352    if( vseg_type == VSEG_TYPE_STACK )
1353    {
1354        // release slot to local stack allocator
1355        vmm_stack_free( vmm , vseg );
1356
1357        // release vseg descriptor to local kmem
1358        vseg_free( vseg );
1359    }
1360    else if( (vseg_type == VSEG_TYPE_ANON) || 
1361             (vseg_type == VSEG_TYPE_FILE) || 
1362             (vseg_type == VSEG_TYPE_REMOTE) ) 
1363    {
1364        // release vseg to local mmap allocator
1365        vmm_mmap_free( vmm , vseg );
1366    }
1367    else
1368    {
1369        // release vseg descriptor to local kmem
1370        vseg_free( vseg );
1371    }
1372
1373#if DEBUG_VMM_REMOVE_VSEG
[433]1374cycle = (uint32_t)hal_get_cycles();
[625]1375if( DEBUG_VMM_REMOVE_VSEG < cycle )
1376printk("[%s] thread[%x,%x] exit / process %x / %s / base %x / cycle %d\n",
1377__FUNCTION__, this->process->pid, this->trdid, 
1378process->pid, vseg_type_str(vseg->type), vseg->min, cycle );
[433]1379#endif
1380
[625]1381}  // end vmm_remove_vseg()
[1]1382
[625]1383
1384///////////////////////////////////
1385void vmm_delete_vseg( pid_t    pid,
1386                      intptr_t vaddr )
1387{
1388    process_t * process;    // local pointer on local process
1389    vseg_t    * vseg;       // local pointer on local vseg containing vaddr
1390
1391    // get local pointer on local process descriptor
1392    process = cluster_get_local_process_from_pid( pid );
1393
1394    if( process == NULL )
1395    {
1396        printk("\n[WARNING] in %s : cannot get local process descriptor\n",
1397        __FUNCTION__ );
1398        return;
1399    }
1400
1401    // get local pointer on local vseg containing vaddr
1402    vseg = vmm_vseg_from_vaddr( &process->vmm , vaddr );
1403
1404    if( vseg == NULL )
1405    {
1406        printk("\n[WARNING] in %s : cannot get vseg descriptor\n",
1407        __FUNCTION__ );
1408        return;
1409    }
1410
1411    // call relevant function
1412    vmm_remove_vseg( process , vseg );
1413
1414}  // end vmm_delete_vseg
1415
1416
[611]1417/////////////////////////////////////////////
1418vseg_t * vmm_vseg_from_vaddr( vmm_t    * vmm,
1419                              intptr_t   vaddr )
[406]1420{
[408]1421    xptr_t   vseg_xp;
1422    vseg_t * vseg;
[625]1423    xptr_t   iter_xp;
[406]1424
[408]1425    // get extended pointers on VSL lock and root
[625]1426    xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
[408]1427    xptr_t root_xp = XPTR( local_cxy , &vmm->vsegs_root );
[406]1428
[408]1429    // get lock protecting the VSL
[567]1430    remote_rwlock_rd_acquire( lock_xp );
[408]1431
1432    // scan the list of vsegs in VSL
1433    XLIST_FOREACH( root_xp , iter_xp )
[406]1434    {
[625]1435        // get pointers on vseg
[408]1436        vseg_xp = XLIST_ELEMENT( iter_xp , vseg_t , xlist );
[433]1437        vseg    = GET_PTR( vseg_xp );
[595]1438
[625]1439        // return success when match
[408]1440        if( (vaddr >= vseg->min) && (vaddr < vseg->max) )
[595]1441        { 
[408]1442            // return success
[567]1443            remote_rwlock_rd_release( lock_xp );
[408]1444            return vseg;
1445        }
[406]1446    }
1447
[408]1448    // return failure
[567]1449    remote_rwlock_rd_release( lock_xp );
[408]1450    return NULL;
[406]1451
[595]1452}  // end vmm_vseg_from_vaddr()
[406]1453
[1]1454/////////////////////////////////////////////
1455error_t vmm_resize_vseg( process_t * process,
1456                         intptr_t    base,
1457                         intptr_t    size )
1458{
[406]1459    error_t   error;
1460    vseg_t  * new;
1461    vpn_t     vpn_min;
1462    vpn_t     vpn_max;
[1]1463
[623]1464#if DEBUG_VMM_RESIZE_VSEG
1465uint32_t   cycle = (uint32_t)hal_get_cycles();
1466thread_t * this  = CURRENT_THREAD;
1467if( DEBUG_VMM_RESIZE_VSEG < cycle )
1468printk("\n[%s] thread[%x,%x] enter / process %x / base %x / size %d / cycle %d\n",
1469__FUNCTION__, this->process->pid, this->trdid, process->pid, base, size, cycle );
1470#endif
1471
[1]1472    // get pointer on process VMM
1473    vmm_t * vmm = &process->vmm;
1474
1475    intptr_t addr_min = base;
1476        intptr_t addr_max = base + size;
1477
1478    // get pointer on vseg
[595]1479        vseg_t * vseg = vmm_vseg_from_vaddr( vmm , base );
[1]1480
[623]1481        if( vseg == NULL)
1482    {
1483        printk("\n[ERROR] in %s : vseg(%x,%d) not found\n",
1484        __FUNCTION__, base , size );
1485        return -1;
1486    }
[21]1487
[623]1488    // resize depends on unmapped region base and size
[611]1489        if( (vseg->min > addr_min) || (vseg->max < addr_max) )        // not included in vseg
[1]1490    {
[623]1491        printk("\n[ERROR] in %s : unmapped region[%x->%x[ not included in vseg[%x->%x[\n",
1492        __FUNCTION__, addr_min, addr_max, vseg->min, vseg->max );
1493
[611]1494        error = -1;
[1]1495    }
[611]1496        else if( (vseg->min == addr_min) && (vseg->max == addr_max) )  // vseg must be deleted
[1]1497    {
[623]1498
1499#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1500if( DEBUG_VMM_RESIZE_VSEG < cycle )
1501printk("\n[%s] unmapped region[%x->%x[ equal vseg[%x->%x[\n",
1502__FUNCTION__, addr_min, addr_max, vseg->min, vseg->max );
1503#endif
[611]1504        vmm_delete_vseg( process->pid , vseg->min );
[623]1505
1506#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1507if( DEBUG_VMM_RESIZE_VSEG < cycle )
1508printk("\n[%s] thread[%x,%x] deleted vseg\n",
1509__FUNCTION__, this->process->pid, this->trdid );
1510#endif
[1]1511        error = 0;
1512    }
[611]1513        else if( vseg->min == addr_min )                               // vseg must be resized
[1]1514    {
[623]1515
1516#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1517if( DEBUG_VMM_RESIZE_VSEG < cycle )
1518printk("\n[%s] unmapped region[%x->%x[ included in vseg[%x->%x[\n",
1519__FUNCTION__, addr_min, addr_max, vseg->min, vseg->max );
1520#endif
1521        // update vseg min address
[406]1522        vseg->min = addr_max;
1523
1524        // update vpn_base and vpn_size
1525        vpn_min        = vseg->min >> CONFIG_PPM_PAGE_SHIFT;
1526        vpn_max        = (vseg->max - 1) >> CONFIG_PPM_PAGE_SHIFT;
1527        vseg->vpn_base = vpn_min;
1528        vseg->vpn_size = vpn_max - vpn_min + 1;
[623]1529
1530#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1531if( DEBUG_VMM_RESIZE_VSEG < cycle )
1532printk("\n[%s] thread[%x,%x] changed vseg_min\n",
1533__FUNCTION__, this->process->pid, this->trdid );
1534#endif
[406]1535        error = 0;
[1]1536    }
[611]1537        else if( vseg->max == addr_max )                              // vseg must be resized
[1]1538    {
[623]1539
1540#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1541if( DEBUG_VMM_RESIZE_VSEG < cycle )
1542printk("\n[%s] unmapped region[%x->%x[ included in vseg[%x->%x[\n",
1543__FUNCTION__, addr_min, addr_max, vseg->min, vseg->max );
1544#endif
[406]1545        // update vseg max address
1546        vseg->max = addr_min;
1547
1548        // update vpn_base and vpn_size
1549        vpn_min        = vseg->min >> CONFIG_PPM_PAGE_SHIFT;
1550        vpn_max        = (vseg->max - 1) >> CONFIG_PPM_PAGE_SHIFT;
1551        vseg->vpn_base = vpn_min;
1552        vseg->vpn_size = vpn_max - vpn_min + 1;
[623]1553
1554#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1555if( DEBUG_VMM_RESIZE_VSEG < cycle )
1556printk("\n[%s] thread[%x,%x] changed vseg_max\n",
1557__FUNCTION__, this->process->pid, this->trdid );
1558#endif
[406]1559        error = 0;
[623]1560
[1]1561    }
[611]1562    else                                                          // vseg cut in three regions
[1]1563    {
[623]1564
1565#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1566if( DEBUG_VMM_RESIZE_VSEG < cycle )
1567printk("\n[%s] unmapped region[%x->%x[ included in vseg[%x->%x[\n",
1568__FUNCTION__, addr_min, addr_max, vseg->min, vseg->max );
1569#endif
[406]1570        // resize existing vseg
1571        vseg->max = addr_min;
1572
1573        // update vpn_base and vpn_size
1574        vpn_min        = vseg->min >> CONFIG_PPM_PAGE_SHIFT;
1575        vpn_max        = (vseg->max - 1) >> CONFIG_PPM_PAGE_SHIFT;
1576        vseg->vpn_base = vpn_min;
1577        vseg->vpn_size = vpn_max - vpn_min + 1;
1578
1579        // create new vseg
[407]1580        new = vmm_create_vseg( process, 
1581                               vseg->type,
1582                               addr_min, 
1583                               (vseg->max - addr_max),
1584                               vseg->file_offset,
1585                               vseg->file_size,
1586                               vseg->mapper_xp,
1587                               vseg->cxy ); 
1588
[623]1589#if( DEBUG_VMM_RESIZE_VSEG & 1 )
1590if( DEBUG_VMM_RESIZE_VSEG < cycle )
1591printk("\n[%s] thread[%x,%x] replaced vseg by two smal vsegs\n",
1592__FUNCTION__, this->process->pid, this->trdid );
1593#endif
1594
1595        if( new == NULL ) error = -1;
[406]1596        else              error = 0;
[1]1597    }
1598
[623]1599#if DEBUG_VMM_RESIZE_VSEG
1600if( DEBUG_VMM_RESIZE_VSEG < cycle )
1601printk("\n[%s] thread[%x,%x] exit / process %x / base %x / size %d / cycle %d\n",
1602__FUNCTION__, this->process->pid, this->trdid, process->pid, base, size, cycle );
1603#endif
[1]1604
1605        return error;
1606
[406]1607}  // vmm_resize_vseg()
1608
[1]1609///////////////////////////////////////////
[388]1610error_t  vmm_get_vseg( process_t * process,
[394]1611                       intptr_t    vaddr,
[388]1612                       vseg_t   ** found_vseg )
[1]1613{
[595]1614    xptr_t    vseg_xp;
1615    vseg_t  * vseg;
1616    vmm_t   * vmm;
1617    error_t   error;
[1]1618
[440]1619    // get pointer on local VMM
1620    vmm = &process->vmm;
[1]1621
[440]1622    // try to get vseg from local VMM
[595]1623    vseg = vmm_vseg_from_vaddr( vmm , vaddr );
[440]1624
[388]1625    if( vseg == NULL )   // vseg not found in local cluster => try to get it from ref
1626        {
1627        // get extended pointer on reference process
1628        xptr_t ref_xp = process->ref_xp;
[1]1629
[388]1630        // get cluster and local pointer on reference process
1631        cxy_t       ref_cxy = GET_CXY( ref_xp );
[433]1632        process_t * ref_ptr = GET_PTR( ref_xp );
[388]1633
1634        if( local_cxy == ref_cxy )  return -1;   // local cluster is the reference
1635
1636        // get extended pointer on reference vseg
[394]1637        rpc_vmm_get_vseg_client( ref_cxy , ref_ptr , vaddr , &vseg_xp , &error );
[388]1638           
[440]1639        if( error )   return -1;                // vseg not found => illegal user vaddr
[388]1640       
1641        // allocate a vseg in local cluster
1642        vseg = vseg_alloc();
1643
[440]1644        if( vseg == NULL ) return -1;           // cannot allocate a local vseg
[388]1645
1646        // initialise local vseg from reference
1647        vseg_init_from_ref( vseg , vseg_xp );
1648
[625]1649        // build extended pointer on VSL lock
1650        xptr_t lock_xp = XPTR( local_cxy , &vmm->vsl_lock );
1651 
1652        // take the VSL lock in write mode
1653        remote_rwlock_wr_acquire( lock_xp );
1654
[611]1655        // register local vseg in local VSL
1656        vmm_attach_vseg_to_vsl( vmm , vseg );
[625]1657 
1658        // release the VSL lock
1659        remote_rwlock_wr_release( lock_xp );
[388]1660    }   
[595]1661
[388]1662    // success
1663    *found_vseg = vseg;
[394]1664    return 0;
[388]1665
1666}  // end vmm_get_vseg()
1667
[407]1668//////////////////////////////////////////////////////////////////////////////////////
1669// This static function compute the target cluster to allocate a physical page
[632]1670// for a given <vpn> in a given <vseg>, allocates the page and returns an extended
1671// pointer on the allocated page descriptor.
[407]1672// The vseg cannot have the FILE type.
1673//////////////////////////////////////////////////////////////////////////////////////
1674static xptr_t vmm_page_allocate( vseg_t * vseg,
1675                                 vpn_t    vpn )
1676{
[433]1677
[632]1678#if DEBUG_VMM_PAGE_ALLOCATE
[619]1679uint32_t   cycle   = (uint32_t)hal_get_cycles();
1680thread_t * this    = CURRENT_THREAD;
[632]1681if( DEBUG_VMM_PAGE_ALLOCATE < cycle )
[595]1682printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
1683__FUNCTION__ , this->process->pid, this->trdid, vpn, cycle );
[433]1684#endif
1685
[632]1686    xptr_t       page_xp;
[407]1687    cxy_t        page_cxy;
[577]1688    uint32_t     index;
[407]1689
[577]1690    uint32_t     type   = vseg->type;
1691    uint32_t     flags  = vseg->flags;
1692    uint32_t     x_size = LOCAL_CLUSTER->x_size;
1693    uint32_t     y_size = LOCAL_CLUSTER->y_size;
[407]1694
[567]1695// check vseg type
1696assert( ( type != VSEG_TYPE_FILE ) , "illegal vseg type\n" );
[407]1697
1698    if( flags & VSEG_DISTRIB )    // distributed => cxy depends on vpn LSB
1699    {
[577]1700        index    = vpn & ((x_size * y_size) - 1);
1701        page_cxy = HAL_CXY_FROM_XY( (index / y_size) , (index % y_size) );
[561]1702
[577]1703        // If the cluster selected from VPN's LSBs is empty, we select one randomly
1704        if ( cluster_is_active( page_cxy ) == false )
1705        {
1706            page_cxy = cluster_random_select();
[561]1707        }
[407]1708    }
1709    else                          // other cases => cxy specified in vseg
1710    {
[561]1711        page_cxy = vseg->cxy;
[407]1712    }
1713
[632]1714    // allocate a 4 Kbytes physical page from target cluster
1715    page_xp = ppm_remote_alloc_pages( page_cxy , 0 );
[407]1716
[632]1717#if DEBUG_VMM_PAGE_ALLOCATE
[595]1718cycle = (uint32_t)hal_get_cycles();
[632]1719if( DEBUG_VMM_PAGE_ALLOCATE < cycle )
1720printk("\n[%s] thread[%x,%x] exit for vpn %x / ppn %x / cluster %x / cycle %d\n",
1721__FUNCTION__ , this->process->pid, this->trdid, vpn, ppm_page2ppn(page_xp), page_cxy, cycle );
[433]1722#endif
1723
[632]1724    return page_xp;
[407]1725
1726}  // end vmm_page_allocate() 
1727
[313]1728////////////////////////////////////////
1729error_t vmm_get_one_ppn( vseg_t * vseg,
1730                         vpn_t    vpn,
1731                         ppn_t  * ppn )
1732{
1733    error_t    error;
[407]1734    xptr_t     page_xp;           // extended pointer on physical page descriptor
[606]1735    uint32_t   page_id;           // missing page index in vseg mapper
[406]1736    uint32_t   type;              // vseg type;
[313]1737
[406]1738    type      = vseg->type;
[606]1739    page_id   = vpn - vseg->vpn_base;
[313]1740
[438]1741#if DEBUG_VMM_GET_ONE_PPN
[595]1742uint32_t   cycle = (uint32_t)hal_get_cycles();
1743thread_t * this  = CURRENT_THREAD;
[632]1744// if( DEBUG_VMM_GET_ONE_PPN < cycle )
1745if( vpn == 0x40B )
[606]1746printk("\n[%s] thread[%x,%x] enter for vpn %x / type %s / page_id  %d / cycle %d\n",
1747__FUNCTION__, this->process->pid, this->trdid, vpn, vseg_type_str(type), page_id, cycle );
[433]1748#endif
[313]1749
[406]1750    // FILE type : get the physical page from the file mapper
[313]1751    if( type == VSEG_TYPE_FILE )
1752    {
[406]1753        // get extended pointer on mapper
[407]1754        xptr_t mapper_xp = vseg->mapper_xp;
[313]1755
[567]1756assert( (mapper_xp != XPTR_NULL),
1757"mapper not defined for a FILE vseg\n" );
[406]1758       
[606]1759        // get extended pointer on page descriptor
1760        page_xp = mapper_remote_get_page( mapper_xp , page_id );
[406]1761
[606]1762        if ( page_xp == XPTR_NULL ) return EINVAL;
[313]1763    }
1764
[406]1765    // Other types : allocate a physical page from target cluster,
[407]1766    // as defined by vseg type and vpn value
[313]1767    else
1768    {
[433]1769        // allocate one physical page
[407]1770        page_xp = vmm_page_allocate( vseg , vpn );
[406]1771
[407]1772        if( page_xp == XPTR_NULL ) return ENOMEM;
[313]1773
[406]1774        // initialise missing page from .elf file mapper for DATA and CODE types
[440]1775        // the vseg->mapper_xp field is an extended pointer on the .elf file mapper
[313]1776        if( (type == VSEG_TYPE_CODE) || (type == VSEG_TYPE_DATA) )
1777        {
[406]1778            // get extended pointer on mapper
1779            xptr_t     mapper_xp = vseg->mapper_xp;
[313]1780
[567]1781assert( (mapper_xp != XPTR_NULL),
1782"mapper not defined for a CODE or DATA vseg\n" );
[406]1783       
1784            // compute missing page offset in vseg
[606]1785            uint32_t offset = page_id << CONFIG_PPM_PAGE_SHIFT;
[406]1786
[313]1787            // compute missing page offset in .elf file
[406]1788            uint32_t elf_offset = vseg->file_offset + offset;
[313]1789
[438]1790#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
[632]1791// if( DEBUG_VMM_GET_ONE_PPN < cycle )
1792if( vpn == 0x40B )
[595]1793printk("\n[%s] thread[%x,%x] for vpn = %x / elf_offset = %x\n",
1794__FUNCTION__, this->process->pid, this->trdid, vpn, elf_offset );
[433]1795#endif
[406]1796            // compute extended pointer on page base
[407]1797            xptr_t base_xp  = ppm_page2base( page_xp );
[313]1798
[406]1799            // file_size (in .elf mapper) can be smaller than vseg_size (BSS)
1800            uint32_t file_size = vseg->file_size;
1801
1802            if( file_size < offset )                 // missing page fully in  BSS
[313]1803            {
[406]1804
[438]1805#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
[632]1806// if( DEBUG_VMM_GET_ONE_PPN < cycle )
1807if( vpn == 0x40B )
[595]1808printk("\n[%s] thread[%x,%x] for vpn  %x / fully in BSS\n",
1809__FUNCTION__, this->process->pid, this->trdid, vpn );
[433]1810#endif
[407]1811                if( GET_CXY( page_xp ) == local_cxy )
[313]1812                {
[315]1813                    memset( GET_PTR( base_xp ) , 0 , CONFIG_PPM_PAGE_SIZE );
[313]1814                }
1815                else
1816                {
[315]1817                   hal_remote_memset( base_xp , 0 , CONFIG_PPM_PAGE_SIZE );       
[313]1818                }
1819            }
[406]1820            else if( file_size >= (offset + CONFIG_PPM_PAGE_SIZE) )  // fully in  mapper
[315]1821            {
[406]1822
[438]1823#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
[632]1824// if( DEBUG_VMM_GET_ONE_PPN < cycle )
1825if( vpn == 0x40B )
[595]1826printk("\n[%s] thread[%x,%x] for vpn  %x / fully in mapper\n",
1827__FUNCTION__, this->process->pid, this->trdid, vpn );
[433]1828#endif
[606]1829                error = mapper_move_kernel( mapper_xp,
1830                                            true,             // to_buffer
1831                                            elf_offset,
1832                                            base_xp,
1833                                            CONFIG_PPM_PAGE_SIZE ); 
[313]1834                if( error ) return EINVAL;
1835            }
[406]1836            else  // both in mapper and in BSS :
1837                  // - (file_size - offset)             bytes from mapper
1838                  // - (page_size + offset - file_size) bytes from BSS
[313]1839            {
[406]1840
[438]1841#if (DEBUG_VMM_GET_ONE_PPN & 0x1)
[632]1842// if( DEBUG_VMM_GET_ONE_PPN < cycle )
1843if( vpn == 0x40B )
[610]1844printk("\n[%s] thread[%x,%x] for vpn  %x / both mapper & BSS\n"
[433]1845"      %d bytes from mapper / %d bytes from BSS\n",
[595]1846__FUNCTION__, this->process->pid, this->trdid, vpn,
[407]1847file_size - offset , offset + CONFIG_PPM_PAGE_SIZE - file_size  );
[433]1848#endif
[313]1849                // initialize mapper part
[606]1850                error = mapper_move_kernel( mapper_xp,
1851                                            true,         // to buffer
1852                                            elf_offset,
1853                                            base_xp,
1854                                            file_size - offset ); 
[313]1855                if( error ) return EINVAL;
1856
1857                // initialize BSS part
[407]1858                if( GET_CXY( page_xp ) == local_cxy )
[313]1859                {
[406]1860                    memset( GET_PTR( base_xp ) + file_size - offset , 0 , 
1861                            offset + CONFIG_PPM_PAGE_SIZE - file_size );
[313]1862                }
1863                else
1864                {
[406]1865                   hal_remote_memset( base_xp + file_size - offset , 0 , 
1866                                      offset + CONFIG_PPM_PAGE_SIZE - file_size );
[313]1867                }
1868            }   
1869        }  // end initialisation for CODE or DATA types   
1870    } 
1871
1872    // return ppn
[407]1873    *ppn = ppm_page2ppn( page_xp );
[406]1874
[438]1875#if DEBUG_VMM_GET_ONE_PPN
[595]1876cycle = (uint32_t)hal_get_cycles();
[632]1877// if( DEBUG_VMM_GET_ONE_PPN < cycle )
1878if( vpn == 0x40B )
[595]1879printk("\n[%s] thread[%x,%x] exit for vpn %x / ppn %x / cycle\n",
1880__FUNCTION__ , this->process->pid, this->trdid , vpn , *ppn, cycle );
[433]1881#endif
[406]1882
[313]1883    return 0;
1884
1885}  // end vmm_get_one_ppn()
1886
[585]1887///////////////////////////////////////////////////
1888error_t vmm_handle_page_fault( process_t * process,
1889                               vpn_t       vpn )
[1]1890{
[585]1891    vseg_t         * vseg;            // vseg containing vpn
[629]1892    uint32_t         attr;            // PTE_ATTR value
1893    ppn_t            ppn;             // PTE_PPN value
[585]1894    uint32_t         ref_attr;        // PTE_ATTR value in reference GPT
1895    ppn_t            ref_ppn;         // PTE_PPN value in reference GPT
1896    cxy_t            ref_cxy;         // reference cluster for missing vpn
1897    process_t      * ref_ptr;         // reference process for missing vpn
1898    xptr_t           local_gpt_xp;    // extended pointer on local GPT
1899    xptr_t           ref_gpt_xp;      // extended pointer on reference GPT
1900    error_t          error;           // value returned by called functions
[1]1901
[629]1902    thread_t * this  = CURRENT_THREAD;
1903
1904#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
1905uint32_t start_cycle = (uint32_t)hal_get_cycles();
1906#endif
1907
[625]1908#if DEBUG_VMM_HANDLE_PAGE_FAULT
[632]1909if( vpn == 0x40b )
[625]1910printk("\n[%s] thread[%x,%x] enter for vpn %x / cycle %d\n",
[629]1911__FUNCTION__, this->process->pid, this->trdid, vpn, start_cycle );
[625]1912#endif
1913
[629]1914#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
1915hal_vmm_display( this->process , false );
1916#endif
1917
[585]1918    // get local vseg (access to reference VSL can be required)
1919    error = vmm_get_vseg( process, 
1920                          (intptr_t)vpn<<CONFIG_PPM_PAGE_SHIFT,
1921                          &vseg );
1922    if( error )
1923    {
[629]1924        printk("\n[ERROR] in %s : vpn %x in thread[%x,%x] not in registered vseg\n",
1925        __FUNCTION__ , vpn , process->pid, this->trdid );
[585]1926       
1927        return EXCP_USER_ERROR;
1928    }
1929
[625]1930#if DEBUG_VMM_HANDLE_PAGE_FAULT
[632]1931uint32_t cycle = (uint32_t)hal_get_cycles();
1932if( vpn == 0x40b )
1933printk("\n[%s] thread[%x,%x] found vseg %s / cycle %d\n",
1934__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type), cycle );
[433]1935#endif
[406]1936
[629]1937    // build extended pointer on local GPT
1938    local_gpt_xp  = XPTR( local_cxy , &process->vmm.gpt );
1939
[632]1940    // lock PTE in local GPT and get current PPN and attributes
[629]1941    error = hal_gpt_lock_pte( local_gpt_xp,
1942                              vpn,
1943                              &attr,
1944                              &ppn );
1945    if( error )
[438]1946    {
[629]1947        printk("\n[PANIC] in %s : cannot lock PTE in local GPT / vpn %x / process %x\n",
1948        __FUNCTION__ , vpn , process->pid );
1949       
1950        return EXCP_KERNEL_PANIC;
1951    }
[407]1952
[632]1953#if DEBUG_VMM_HANDLE_PAGE_FAULT
1954cycle = (uint32_t)hal_get_cycles();
1955if( vpn == 0x40b )
1956printk("\n[%s] thread[%x,%x] locked vpn %x in cluster %x / cycle %d\n",
1957__FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy, cycle );
1958#endif
1959
1960    // handle page fault only if local PTE still unmapped after lock
[629]1961    if( (attr & GPT_MAPPED) == 0 )
1962    {
1963        // get reference process cluster and local pointer
1964        ref_cxy = GET_CXY( process->ref_xp );
1965        ref_ptr = GET_PTR( process->ref_xp );
[407]1966
[630]1967        /////////////// private vseg or (local == reference)
1968        /////////////// => access only the local GPT
[629]1969        if( (vseg->type == VSEG_TYPE_STACK) ||
1970            (vseg->type == VSEG_TYPE_CODE)  ||
1971            (ref_cxy    == local_cxy ) )
1972        {
[632]1973
1974#if DEBUG_VMM_HANDLE_PAGE_FAULT
1975if( vpn == 0x40b )
1976printk("\n[%s] thread[%x,%x] : access local gpt : local_cxy %x / ref_cxy %x / type %s\n",
1977__FUNCTION__, this->process->pid, this->trdid, local_cxy, ref_cxy, vseg_type_str(vseg->type) );
1978#endif
1979            // allocate and initialise a physical page
[629]1980            error = vmm_get_one_ppn( vseg , vpn , &ppn );
[407]1981
[585]1982            if( error )
[408]1983            {
[629]1984                printk("\n[ERROR] in %s : no physical page / process = %x / vpn = %x\n",
[408]1985                __FUNCTION__ , process->pid , vpn );
[1]1986
[629]1987                // unlock PTE in local GPT
1988                hal_gpt_unlock_pte( local_gpt_xp , vpn );
[406]1989
[585]1990                return EXCP_KERNEL_PANIC;
[407]1991            }
1992
[629]1993            // define attr from vseg flags
[632]1994            attr = GPT_MAPPED | GPT_SMALL | GPT_READABLE;
[629]1995            if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
1996            if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
1997            if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
1998            if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
[407]1999
[629]2000            // set PTE to local GPT
[632]2001            // it unlocks this PTE
[629]2002            hal_gpt_set_pte( local_gpt_xp,
2003                             vpn,
2004                             attr,
2005                             ppn );
[585]2006
[629]2007#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
2008uint32_t end_cycle = (uint32_t)hal_get_cycles();
2009#endif
[585]2010
2011#if DEBUG_VMM_HANDLE_PAGE_FAULT
[632]2012if( vpn == 0x40b )
2013printk("\n[%s] thread[%x,%x] handled local pgfault / ppn %x / attr %x / cycle %d\n",
2014__FUNCTION__, this->process->pid, this->trdid, ppn, attr, end_cycle );
[585]2015#endif
2016
[629]2017#if CONFIG_INSTRUMENTATION_PGFAULTS
2018this->info.local_pgfault_nr++;
2019this->info.local_pgfault_cost += (end_cycle - start_cycle);
2020#endif
2021            return EXCP_NON_FATAL;
[585]2022
[629]2023        }   // end local GPT access
[585]2024
[630]2025        /////////////////// public vseg and (local != reference)
2026        /////////////////// => access ref GPT to update local GPT
[629]2027        else                               
2028        {
[632]2029
2030#if DEBUG_VMM_HANDLE_PAGE_FAULT
2031if( vpn == 0x40b )
2032printk("\n[%s] thread[%x,%x] access ref gpt : local_cxy %x / ref_cxy %x / type %s\n",
2033__FUNCTION__, this->process->pid, this->trdid, local_cxy, ref_cxy, vseg_type_str(vseg->type) );
2034#endif
[629]2035            // build extended pointer on reference GPT
2036            ref_gpt_xp = XPTR( ref_cxy , &ref_ptr->vmm.gpt );
[585]2037
[632]2038            // lock PTE in reference GPT and get current PPN and attributes
2039            error = hal_gpt_lock_pte( ref_gpt_xp,
2040                                      vpn,
2041                                      &ref_attr,
2042                                      &ref_ppn );
2043            if( error )
2044            {
2045                printk("\n[PANIC] in %s : cannot lock PTE in ref GPT / vpn %x / process %x\n",
2046                __FUNCTION__ , vpn , process->pid );
2047       
2048                // unlock PTE in local GPT
2049                hal_gpt_unlock_pte( local_gpt_xp , vpn );
2050                   
2051                return EXCP_KERNEL_PANIC;
2052            }
[1]2053
[632]2054#if DEBUG_VMM_HANDLE_PAGE_FAULT
2055if( vpn == 0x40b )
2056printk("\n[%s] thread[%x,%x] get pte from ref gpt / attr %x / ppn %x\n",
2057__FUNCTION__, this->process->pid, this->trdid, ref_attr, ref_ppn );
2058#endif
2059
2060            if( ref_attr & GPT_MAPPED )        // false page fault
[585]2061            {
[629]2062                // update local GPT from reference GPT values
[632]2063                // this unlocks the PTE in local GPT
[629]2064                hal_gpt_set_pte( local_gpt_xp,
2065                                 vpn,
2066                                 ref_attr,
2067                                 ref_ppn );
[585]2068
[632]2069#if DEBUG_VMM_HANDLE_PAGE_FAULT
2070if( vpn == 0x40b )
2071printk("\n[%s] thread[%x,%x] updated local gpt for a false pgfault\n",
2072__FUNCTION__, this->process->pid, this->trdid );
2073#endif
2074
2075                // unlock the PTE in reference GPT
2076                hal_gpt_unlock_pte( ref_gpt_xp, vpn );
2077                             
2078#if DEBUG_VMM_HANDLE_PAGE_FAULT
2079if( vpn == 0x40b )
2080printk("\n[%s] thread[%x,%x] unlock the ref gpt after a false pgfault\n",
2081__FUNCTION__, this->process->pid, this->trdid );
2082#endif
2083
[629]2084#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
2085uint32_t end_cycle = (uint32_t)hal_get_cycles();
2086#endif
2087
[585]2088#if DEBUG_VMM_HANDLE_PAGE_FAULT
[632]2089if( vpn == 0x40b )
2090printk("\n[%s] thread[%x,%x] handled false pgfault / ppn %x / attr %x / cycle %d\n",
2091__FUNCTION__, this->process->pid, this->trdid, ref_ppn, ref_attr, end_cycle );
[433]2092#endif
[406]2093
[629]2094#if CONFIG_INSTRUMENTATION_PGFAULTS
2095this->info.false_pgfault_nr++;
2096this->info.false_pgfault_cost += (end_cycle - start_cycle);
2097#endif
2098                return EXCP_NON_FATAL;
2099            }
[632]2100            else                            // true page fault
[629]2101            {
[585]2102                // allocate and initialise a physical page depending on the vseg type
[629]2103                error = vmm_get_one_ppn( vseg , vpn , &ppn );
[1]2104
[585]2105                if( error )
2106                {
2107                    printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
2108                    __FUNCTION__ , process->pid , vpn );
[313]2109
[632]2110                    // unlock PTE in local GPT and in reference GPT
[629]2111                    hal_gpt_unlock_pte( local_gpt_xp , vpn );
[632]2112                    hal_gpt_unlock_pte( ref_gpt_xp   , vpn );
[585]2113                   
[629]2114                    return EXCP_KERNEL_PANIC;
[585]2115                }
[1]2116
[629]2117                // define attr from vseg flags
[632]2118                attr = GPT_MAPPED | GPT_SMALL | GPT_READABLE;
[629]2119                if( vseg->flags & VSEG_USER  ) attr |= GPT_USER;
2120                if( vseg->flags & VSEG_WRITE ) attr |= GPT_WRITABLE;
2121                if( vseg->flags & VSEG_EXEC  ) attr |= GPT_EXECUTABLE;
2122                if( vseg->flags & VSEG_CACHE ) attr |= GPT_CACHABLE;
[585]2123
[632]2124#if DEBUG_VMM_HANDLE_PAGE_FAULT
2125if( vpn == 0x40b )
2126printk("\n[%s] thread[%x,%x] build a new PTE for a true pgfault\n",
2127__FUNCTION__, this->process->pid, this->trdid );
2128#endif
[629]2129                // set PTE in reference GPT
[632]2130                // this unlock the PTE
[629]2131                hal_gpt_set_pte( ref_gpt_xp,
2132                                 vpn,
2133                                 attr,
2134                                 ppn );
2135
[632]2136#if DEBUG_VMM_HANDLE_PAGE_FAULT
2137if( vpn == 0x40b )
2138printk("\n[%s] thread[%x,%x] set new PTE in ref gpt for a true page fault\n",
2139__FUNCTION__, this->process->pid, this->trdid );
2140#endif
2141
[629]2142                // set PTE in local GPT
[632]2143                // this unlock the PTE
[629]2144                hal_gpt_set_pte( local_gpt_xp,
2145                                 vpn,
2146                                 attr,
2147                                 ppn );
2148
2149#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
2150uint32_t end_cycle = (uint32_t)hal_get_cycles();
2151#endif
2152
[440]2153#if DEBUG_VMM_HANDLE_PAGE_FAULT
[632]2154if( vpn == 0x40b )
2155printk("\n[%s] thread[%x,%x] handled global pgfault / ppn %x / attr %x / cycle %d\n",
2156__FUNCTION__, this->process->pid, this->trdid, ppn, attr, end_cycle );
[435]2157#endif
[629]2158
2159#if CONFIG_INSTRUMENTATION_PGFAULTS
2160this->info.global_pgfault_nr++;
2161this->info.global_pgfault_cost += (end_cycle - start_cycle);
2162#endif
2163                return EXCP_NON_FATAL;
2164            }
[585]2165        }
2166    }
[629]2167    else   // page has been locally mapped by another concurrent thread
2168    {
[632]2169        // unlock the PTE in local GPT
[629]2170        hal_gpt_unlock_pte( local_gpt_xp , vpn );
2171
[632]2172#if (CONFIG_INSTRUMENTATION_PGFAULTS || DEBUG_VMM_HANDLE_PAGE_FAULT)
2173uint32_t end_cycle = (uint32_t)hal_get_cycles();
2174#endif
2175
2176#if DEBUG_VMM_HANDLE_PAGE_FAULT
2177if( vpn == 0x40b )
2178printk("\n[%s] handled by another thread / vpn %x / ppn %x / attr %x / cycle %d\n",
2179__FUNCTION__, vpn, ppn, attr, end_cycle );
2180#endif
2181
2182#if CONFIG_INSTRUMENTATION_PGFAULTS
2183this->info.false_pgfault_nr++;
2184this->info.false_pgfault_cost += (end_cycle - start_cycle);
2185#endif
[629]2186        return EXCP_NON_FATAL;
2187    }
2188
[585]2189}   // end vmm_handle_page_fault()
[435]2190
[585]2191////////////////////////////////////////////
2192error_t vmm_handle_cow( process_t * process,
2193                        vpn_t       vpn )
2194{
2195    vseg_t         * vseg;            // vseg containing vpn
[629]2196    xptr_t           gpt_xp;          // extended pointer on GPT (local or reference)
2197    gpt_t          * gpt_ptr;         // local pointer on GPT (local or reference)
2198    cxy_t            gpt_cxy;         // GPT cluster identifier
[585]2199    uint32_t         old_attr;        // current PTE_ATTR value
2200    ppn_t            old_ppn;         // current PTE_PPN value
2201    uint32_t         new_attr;        // new PTE_ATTR value
2202    ppn_t            new_ppn;         // new PTE_PPN value
[629]2203    cxy_t            ref_cxy;         // reference process cluster
2204    process_t      * ref_ptr;         // local pointer on reference process
[585]2205    error_t          error;
[1]2206
[629]2207    thread_t * this  = CURRENT_THREAD;
[625]2208
[585]2209#if DEBUG_VMM_HANDLE_COW
[629]2210uint32_t   cycle = (uint32_t)hal_get_cycles();
[585]2211if( DEBUG_VMM_HANDLE_COW < cycle )
[595]2212printk("\n[%s] thread[%x,%x] enter for vpn %x / core[%x,%d] / cycle %d\n",
[619]2213__FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy, this->core->lid, cycle );
[629]2214#endif
2215
2216#if (DEBUG_VMM_HANDLE_PAGE_FAULT & 1)
[625]2217hal_vmm_display( process , true );
[585]2218#endif
2219
2220    // get local vseg
2221    error = vmm_get_vseg( process, 
2222                          (intptr_t)vpn<<CONFIG_PPM_PAGE_SHIFT,
2223                          &vseg );
[440]2224    if( error )
[1]2225    {
[629]2226        printk("\n[ERROR] in %s : vpn %x in thread[%x,%x] not in a registered vseg\n",
[625]2227        __FUNCTION__, vpn, process->pid, this->trdid );
[585]2228
[629]2229        return EXCP_USER_ERROR;
[440]2230    }
[407]2231
[629]2232#if DEBUG_VMM_HANDLE_COW
[619]2233if( DEBUG_VMM_HANDLE_COW < cycle )
[629]2234printk("\n[%s] thread[%x,%x] get vseg %s\n",
2235__FUNCTION__, this->process->pid, this->trdid, vseg_type_str(vseg->type) );
[619]2236#endif
2237
[629]2238    // get reference process cluster and local pointer
[585]2239    ref_cxy = GET_CXY( process->ref_xp );
2240    ref_ptr = GET_PTR( process->ref_xp );
[407]2241
[629]2242    // build pointers on relevant GPT
2243    // - access only local GPT for a private vseg 
2244    // - access reference GPT and all copies for a public vseg
[585]2245    if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
[440]2246    {
[629]2247        gpt_cxy = local_cxy;
2248        gpt_ptr = &process->vmm.gpt;
2249        gpt_xp  = XPTR( gpt_cxy , gpt_ptr );
[1]2250    }
[440]2251    else
[1]2252    {
[629]2253        gpt_cxy = ref_cxy;
2254        gpt_ptr = &ref_ptr->vmm.gpt;
2255        gpt_xp  = XPTR( gpt_cxy , gpt_ptr );
[1]2256    }
2257
[629]2258    // lock target PTE in relevant GPT (local or reference)
[632]2259    // and get current PTE value
[629]2260    error = hal_gpt_lock_pte( gpt_xp,
2261                              vpn,
2262                              &old_attr,
2263                              &old_ppn );
2264    if( error )
2265    {
2266        printk("\n[PANIC] in %s : cannot lock PTE in GPT / cxy %x / vpn %x / process %x\n",
2267        __FUNCTION__ , gpt_cxy, vpn , process->pid );
2268       
2269        return EXCP_KERNEL_PANIC;
2270    }
[441]2271
[629]2272#if DEBUG_VMM_HANDLE_COW
[619]2273if( DEBUG_VMM_HANDLE_COW < cycle )
2274printk("\n[%s] thread[%x,%x] get pte for vpn %x : ppn %x / attr %x\n",
2275__FUNCTION__, this->process->pid, this->trdid, vpn, old_ppn, old_attr );
2276#endif
2277
[629]2278    // return user error if COW attribute not set or PTE2 unmapped
2279    if( ((old_attr & GPT_COW) == 0) || ((old_attr & GPT_MAPPED) == 0) )
[585]2280    {
[629]2281        hal_gpt_unlock_pte( gpt_xp , vpn );
[407]2282
[629]2283        return EXCP_USER_ERROR;
[407]2284    }
2285
[619]2286    // get pointers on physical page descriptor
[585]2287    xptr_t   page_xp  = ppm_ppn2page( old_ppn );
2288    cxy_t    page_cxy = GET_CXY( page_xp );
2289    page_t * page_ptr = GET_PTR( page_xp );
[435]2290
[585]2291    // get extended pointers on forks and lock field in page descriptor
2292    xptr_t forks_xp       = XPTR( page_cxy , &page_ptr->forks );
2293    xptr_t forks_lock_xp  = XPTR( page_cxy , &page_ptr->lock );
[407]2294
[585]2295    // take lock protecting "forks" counter
2296    remote_busylock_acquire( forks_lock_xp );
[407]2297
[585]2298    // get number of pending forks from page descriptor
2299    uint32_t forks = hal_remote_l32( forks_xp );
[441]2300
[629]2301#if DEBUG_VMM_HANDLE_COW
[619]2302if( DEBUG_VMM_HANDLE_COW < cycle )
2303printk("\n[%s] thread[%x,%x] get forks = %d for vpn %x\n",
2304__FUNCTION__, this->process->pid, this->trdid, forks, vpn );
2305#endif
2306
[585]2307    if( forks )        // pending fork => allocate a new page, and copy old to new
2308    {
[619]2309        // decrement pending forks counter in page descriptor
2310        hal_remote_atomic_add( forks_xp , -1 );
2311
2312        // release lock protecting "forks" counter
2313        remote_busylock_release( forks_lock_xp );
2314
[629]2315        // allocate a new physical page depending on vseg type
[585]2316        page_xp = vmm_page_allocate( vseg , vpn );
[619]2317
[585]2318        if( page_xp == XPTR_NULL ) 
2319        {
2320            printk("\n[PANIC] in %s : no memory for vpn %x in process %x\n",
2321            __FUNCTION__ , vpn, process->pid );
[441]2322
[629]2323            hal_gpt_unlock_pte( gpt_xp , vpn ); 
[441]2324
[585]2325            return EXCP_KERNEL_PANIC;
2326        }
[441]2327
[585]2328        // compute allocated page PPN
2329        new_ppn = ppm_page2ppn( page_xp );
[441]2330
[629]2331#if DEBUG_VMM_HANDLE_COW
[619]2332if( DEBUG_VMM_HANDLE_COW < cycle )
2333printk("\n[%s] thread[%x,%x] get new ppn %x for vpn %x\n",
2334__FUNCTION__, this->process->pid, this->trdid, new_ppn, vpn );
2335#endif
2336
[585]2337        // copy old page content to new page
[619]2338        hal_remote_memcpy( ppm_ppn2base( new_ppn ),
2339                           ppm_ppn2base( old_ppn ),
2340                           CONFIG_PPM_PAGE_SIZE );
[441]2341
[629]2342#if DEBUG_VMM_HANDLE_COW
[585]2343if( DEBUG_VMM_HANDLE_COW < cycle )
[619]2344printk("\n[%s] thread[%x,%x] copied old page to new page\n",
2345__FUNCTION__, this->process->pid, this->trdid );
[585]2346#endif
[440]2347
[585]2348    }             
2349    else               // no pending fork => keep the existing page
2350    {
[619]2351        // release lock protecting "forks" counter
2352        remote_busylock_release( forks_lock_xp );
[1]2353
[585]2354#if(DEBUG_VMM_HANDLE_COW & 1)
2355if( DEBUG_VMM_HANDLE_COW < cycle )
[619]2356printk("\n[%s] thread[%x,%x]  no pending forks / keep existing PPN %x\n",
2357__FUNCTION__, this->process->pid, this->trdid, old_ppn );
[585]2358#endif
2359        new_ppn = old_ppn;
2360    }
[1]2361
[629]2362    // build new_attr : set WRITABLE, reset COW, reset LOCKED
2363    new_attr = (((old_attr | GPT_WRITABLE) & (~GPT_COW)) & (~GPT_LOCKED));
[585]2364
[629]2365    // update the relevant GPT(s)
2366    // - private vseg => update only the local GPT
2367    // - public vseg => update the reference GPT AND all the GPT copies
[585]2368    if( (vseg->type == VSEG_TYPE_STACK) || (vseg->type == VSEG_TYPE_CODE) )
[1]2369    {
[629]2370        // set the new PTE2
[585]2371        hal_gpt_set_pte( gpt_xp,
2372                         vpn,
2373                         new_attr,
2374                         new_ppn );
[1]2375    }
[585]2376    else
[1]2377    {
[585]2378        if( ref_cxy == local_cxy )                  // reference cluster is local
2379        {
2380            vmm_global_update_pte( process,
2381                                   vpn,
2382                                   new_attr,
2383                                   new_ppn );
2384        }
2385        else                                        // reference cluster is remote
2386        {
2387            rpc_vmm_global_update_pte_client( ref_cxy,
2388                                              ref_ptr,
2389                                              vpn,
2390                                              new_attr,
2391                                              new_ppn );
2392        }
[1]2393    }
2394
[585]2395#if DEBUG_VMM_HANDLE_COW
2396cycle = (uint32_t)hal_get_cycles();
2397if( DEBUG_VMM_HANDLE_COW < cycle )
[595]2398printk("\n[%s] thread[%x,%x] exit for vpn %x / core[%x,%d] / cycle %d\n",
[619]2399__FUNCTION__, this->process->pid, this->trdid, vpn, local_cxy, this->core->lid, cycle );
[585]2400#endif
[313]2401
[585]2402     return EXCP_NON_FATAL;
[1]2403
[585]2404}   // end vmm_handle_cow()
2405
Note: See TracBrowser for help on using the repository browser.