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

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

Fix several bugs to use the instruction MMU in kernel mode
in replacement of the instruction address extension register,
and remove the "kentry" segment.

This version is running on the tsar_generic_iob" platform.

One interesting bug: the cp0_ebase defining the kernel entry point
(for interrupts, exceptions and syscalls) must be initialized
early in kernel_init(), because the VFS initialisation done by
kernel_ini() uses RPCs, and RPCs uses Inter-Processor-Interrup.

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