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

Last change on this file since 407 was 407, checked in by alain, 6 years ago

First implementation of fork/exec.

File size: 45.8 KB
Line 
1/*
2 * vmm.c - virtual memory manager related operations interface.
3 *
4 * Authors   Ghassan Almaless (2008,2009,2010,2011, 2012)
5 *           Mohamed Lamine Karaoui (2015)
6 *           Alain Greiner (2016)
7 *
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
26#include <kernel_config.h>
27#include <hal_types.h>
28#include <hal_special.h>
29#include <hal_gpt.h>
30#include <printk.h>
31#include <memcpy.h>
32#include <rwlock.h>
33#include <list.h>
34#include <bits.h>
35#include <process.h>
36#include <thread.h>
37#include <vseg.h>
38#include <cluster.h>
39#include <scheduler.h>
40#include <vfs.h>
41#include <mapper.h>
42#include <page.h>
43#include <kmem.h>
44#include <vmm.h>
45
46//////////////////////////////////////////////////////////////////////////////////
47//   Extern global variables
48//////////////////////////////////////////////////////////////////////////////////
49
50extern  process_t  process_zero;   // defined in cluster.c file
51
52
53////////////////////////////////////
54void vmm_init( process_t * process )
55{
56    error_t   error;
57    vseg_t  * vseg_kentry;
58    vseg_t  * vseg_args;
59    vseg_t  * vseg_envs;
60    intptr_t  base;
61    intptr_t  size;
62
63vmm_dmsg("\n[DBG] %s : core[%x,%d] enters for process %x\n", 
64__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , process->pid );
65
66    // get pointer on VMM
67    vmm_t   * vmm = &process->vmm;
68
69    // initialize local list of vsegs
70    vmm->vsegs_nr = 0;
71        list_root_init( &vmm->vsegs_root );
72        rwlock_init( &vmm->vsegs_lock );
73
74    assert( ((CONFIG_VMM_KENTRY_SIZE + CONFIG_VMM_ARGS_SIZE + CONFIG_VMM_ENVS_SIZE) 
75            <= CONFIG_VMM_ELF_BASE) , __FUNCTION__ , "UTILS zone too small\n" );
76
77    assert( (CONFIG_THREAD_MAX_PER_CLUSTER <= 32) , __FUNCTION__ ,
78            "no more than 32 threads per cluster for a single process\n");
79
80    assert( ((CONFIG_VMM_STACK_SIZE * CONFIG_THREAD_MAX_PER_CLUSTER) <=
81             (CONFIG_VMM_VSPACE_SIZE - CONFIG_VMM_STACK_BASE)) , __FUNCTION__ ,
82             "STACK zone too small\n");
83
84    // register kentry vseg in VMM
85    base = CONFIG_VMM_KENTRY_BASE << CONFIG_PPM_PAGE_SHIFT;
86    size = CONFIG_VMM_KENTRY_SIZE << CONFIG_PPM_PAGE_SHIFT;
87
88    vseg_kentry = vmm_create_vseg( process,
89                                   VSEG_TYPE_CODE,
90                                   base,
91                                   size,
92                                   0,             // file_offset unused
93                                   0,             // file_size unused
94                                   XPTR_NULL,     // mapper_xp unused
95                                   local_cxy );
96
97    assert( (vseg_kentry != NULL) , __FUNCTION__ , "cannot register kentry vseg\n" );
98
99    vmm->kent_vpn_base = base;
100
101    // register args vseg in VMM
102    base = (CONFIG_VMM_KENTRY_BASE + 
103            CONFIG_VMM_KENTRY_SIZE ) << CONFIG_PPM_PAGE_SHIFT;
104    size = CONFIG_VMM_ARGS_SIZE << CONFIG_PPM_PAGE_SHIFT;
105
106    vseg_args = vmm_create_vseg( process,
107                                 VSEG_TYPE_DATA,
108                                 base,
109                                 size,
110                                 0,             // file_offset unused
111                                 0,             // file_size unused
112                                 XPTR_NULL,     // mapper_xp unused
113                                 local_cxy );
114
115    assert( (vseg_args != NULL) , __FUNCTION__ , "cannot create args vseg\n" );
116
117    vmm->args_vpn_base = base;
118
119    // register the envs vseg in VMM
120    base = (CONFIG_VMM_KENTRY_BASE + 
121            CONFIG_VMM_KENTRY_SIZE +
122            CONFIG_VMM_ARGS_SIZE   ) << CONFIG_PPM_PAGE_SHIFT;
123    size = CONFIG_VMM_ENVS_SIZE << CONFIG_PPM_PAGE_SHIFT;
124
125    vseg_envs = vmm_create_vseg( process,
126                                 VSEG_TYPE_DATA,
127                                 base,
128                                 size,
129                                 0,             // file_offset unused
130                                 0,             // file_size unused
131                                 XPTR_NULL,     // mapper_xp unused
132                                 local_cxy );
133
134    assert( (vseg_envs != NULL) , __FUNCTION__ , "cannot create envs vseg\n" );
135
136    vmm->envs_vpn_base = base;
137
138    // initialize generic page table
139    error = hal_gpt_create( &vmm->gpt );
140
141    assert( (error == 0) , __FUNCTION__ , "cannot initialize page table\n");
142
143    // initialize STACK allocator
144    vmm->stack_mgr.bitmap   = 0;
145    vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
146
147    // initialize MMAP allocator
148    vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
149    vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
150    vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
151    uint32_t i;
152    for( i = 0 ; i < 32 ; i++ ) list_root_init( &vmm->mmap_mgr.zombi_list[i] );
153
154    // initialize instrumentation counters
155        vmm->pgfault_nr          = 0;
156        vmm->u_err_nr            = 0;
157        vmm->m_err_nr            = 0;
158
159    hal_fence();
160
161vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for process %x / entry_point = %x\n",
162__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , 
163process->pid , process->vmm.entry_point );
164
165}  // end vmm_init()
166
167//////////////////////////////////////
168void vmm_display( process_t * process,
169                  bool_t      mapping )
170{
171    vmm_t * vmm = &process->vmm;
172    gpt_t * gpt = &vmm->gpt;
173
174    printk("\n***** VSL and GPT for process %x\n\n", 
175    process->pid );
176
177    // get lock protecting the vseg list
178    rwlock_rd_lock( &vmm->vsegs_lock );
179
180    // scan the list of vsegs
181    list_entry_t * iter;
182    vseg_t       * vseg;
183    LIST_FOREACH( &vmm->vsegs_root , iter )
184    {
185        vseg = LIST_ELEMENT( iter , vseg_t , list );
186        printk(" - %s : base = %X / size = %X / npages = %d\n",
187        vseg_type_str( vseg->type ) , vseg->min , vseg->max - vseg->min , vseg->vpn_size );
188
189        if( mapping )
190        {
191            vpn_t    vpn;
192            ppn_t    ppn;
193            uint32_t attr;
194            vpn_t    base = vseg->vpn_base;
195            vpn_t    size = vseg->vpn_size;
196            for( vpn = base ; vpn < (base+size) ; vpn++ )
197            {
198                hal_gpt_get_pte( gpt , vpn , &attr , &ppn );
199                if( attr & GPT_MAPPED )
200                {
201                    printk("    . vpn = %X / attr = %X / ppn = %X\n", vpn , attr , ppn );
202                }
203            }
204        }
205    }
206
207    // release the lock
208    rwlock_rd_unlock( &vmm->vsegs_lock );
209}
210
211//////////////////////////////////////////
212error_t vmm_copy( process_t * dst_process,
213                  process_t * src_process )
214{
215    error_t error;
216
217    vmm_t * src_vmm = &src_process->vmm;
218    vmm_t * dst_vmm = &dst_process->vmm;
219
220    // take the src_vmm vsegs_lock
221    rwlock_wr_lock( &src_vmm->vsegs_lock );
222
223    // initialize dst_vmm vsegs_lock
224    rwlock_init( &dst_vmm->vsegs_lock );
225
226    // initialize the dst_vmm vsegs list
227    dst_vmm->vsegs_nr = 0;
228    list_root_init( &dst_vmm->vsegs_root );
229
230    // initialize generic page table
231    error = hal_gpt_create( &dst_vmm->gpt );
232
233    if( error )
234    {
235        printk("\n[ERROR] in %s : cannot initialize page table\n", __FUNCTION__ );
236        return ENOMEM;
237    }
238
239    // loop on SRC VSL to register vsegs copies in DST VSL
240    // and copy valid PTEs from SRC GPT to DST GPT
241    list_entry_t * iter;
242    vseg_t       * src_vseg;
243    vseg_t       * dst_vseg;
244    LIST_FOREACH( &src_vmm->vsegs_root , iter )
245    {
246        // get pointer on current src_vseg
247        src_vseg = LIST_ELEMENT( iter , vseg_t , list );
248
249        // allocate memory for a new dst_vseg
250        dst_vseg = vseg_alloc();
251
252        if( dst_vseg == NULL )
253        {
254            // release all allocated vsegs
255            LIST_FOREACH( &dst_vmm->vsegs_root , iter )
256            {
257                dst_vseg = LIST_ELEMENT( iter , vseg_t , list );
258                vseg_free( dst_vseg );
259            }
260            return ENOMEM;
261        }
262
263        // copy src_vseg to dst_vseg
264        vseg_init_from_ref( dst_vseg , XPTR( local_cxy , src_vseg ) );
265
266        // register dst_vseg in DST VSL
267        vseg_attach( dst_vmm , dst_vseg );
268
269        // copy SRC GPT to DST GPT / set COW for all writable vsegs, but the FILE type
270        bool_t cow = (src_vseg->type != VSEG_TYPE_FILE) && (src_vseg->flags & VSEG_WRITE); 
271        error = hal_gpt_copy( &dst_vmm->gpt, 
272                              &src_vmm->gpt,
273                              src_vseg->vpn_base,
274                              src_vseg->vpn_size,
275                              cow );
276        if( error )
277        {
278            printk("\n[ERROR] in %s : cannot copy page GPT\n", __FUNCTION__ );
279            hal_gpt_destroy( &dst_vmm->gpt );
280            return ENOMEM;
281        }
282    }
283
284    // release the src_vmm vsegs_lock
285    rwlock_wr_unlock( &src_vmm->vsegs_lock );
286
287    // initialize STACK allocator
288    dst_vmm->stack_mgr.bitmap   = 0;
289    dst_vmm->stack_mgr.vpn_base = CONFIG_VMM_STACK_BASE;
290
291    // initialize MMAP allocator
292    dst_vmm->mmap_mgr.vpn_base        = CONFIG_VMM_HEAP_BASE;
293    dst_vmm->mmap_mgr.vpn_size        = CONFIG_VMM_STACK_BASE - CONFIG_VMM_HEAP_BASE;
294    dst_vmm->mmap_mgr.first_free_vpn  = CONFIG_VMM_HEAP_BASE;
295    uint32_t i;
296    for( i = 0 ; i < 32 ; i++ ) list_root_init( &dst_vmm->mmap_mgr.zombi_list[i] );
297
298    // initialize instrumentation counters
299        dst_vmm->pgfault_nr    = 0;
300        dst_vmm->u_err_nr      = 0;
301        dst_vmm->m_err_nr      = 0;
302
303    // copy base addresses
304    dst_vmm->kent_vpn_base = src_vmm->kent_vpn_base;
305    dst_vmm->args_vpn_base = src_vmm->args_vpn_base;
306    dst_vmm->envs_vpn_base = src_vmm->envs_vpn_base;
307    dst_vmm->heap_vpn_base = src_vmm->heap_vpn_base;
308    dst_vmm->code_vpn_base = src_vmm->code_vpn_base;
309    dst_vmm->data_vpn_base = src_vmm->data_vpn_base;
310
311    dst_vmm->entry_point   = src_vmm->entry_point;
312
313    hal_fence();
314
315    return 0;
316
317}  // vmm_copy()
318
319///////////////////////////////////////
320void vmm_destroy( process_t * process )
321{
322        vseg_t * vseg;
323
324    // get pointer on VMM
325    vmm_t  * vmm = &process->vmm;
326
327    // get lock protecting vseg list
328        rwlock_wr_lock( &vmm->vsegs_lock );
329
330    // remove all vsegs registered in vmm
331        while( !list_is_empty( &vmm->vsegs_root ) )
332        {
333                vseg = LIST_FIRST( &vmm->vsegs_root ,  vseg_t , list );
334                vseg_detach( vmm , vseg );
335        vseg_free( vseg );
336        }
337
338    // release lock
339        rwlock_wr_unlock(&vmm->vsegs_lock);
340
341    // remove all vsegs from zombi_lists in MMAP allocator
342    uint32_t i;
343    for( i = 0 ; i<32 ; i++ )
344    {
345            while( !list_is_empty( &vmm->mmap_mgr.zombi_list[i] ) )
346            {
347                    vseg = LIST_FIRST( &vmm->mmap_mgr.zombi_list[i] , vseg_t , list );
348                    vseg_detach( vmm , vseg );
349            vseg_free( vseg );
350            }
351    }
352
353    // release memory allocated to the local page table
354    hal_gpt_destroy( &vmm->gpt );
355
356}  // end vmm_destroy()
357
358/////////////////////////////////////////////////
359vseg_t * vmm_check_conflict( process_t * process,
360                             vpn_t       vpn_base,
361                             vpn_t       vpn_size )
362{
363    vmm_t        * vmm = &process->vmm;
364        vseg_t       * vseg;
365    list_entry_t * iter;
366
367    // scan the list of registered vsegs
368        LIST_FOREACH( &vmm->vsegs_root , iter )
369        {
370                vseg = LIST_ELEMENT( iter , vseg_t , list );
371
372                if( ((vpn_base + vpn_size) > vseg->vpn_base) &&
373             (vpn_base < (vseg->vpn_base + vseg->vpn_size)) ) return vseg;
374        }
375    return NULL;
376
377}  // end vmm_check_conflict()
378
379////////////////////////////////////////////////////////////////////////////////////////////
380// This static function is called by the vmm_create_vseg() function, and implements
381// the VMM stack_vseg specific allocator.
382////////////////////////////////////////////////////////////////////////////////////////////
383// @ vmm      : pointer on VMM.
384// @ vpn_base : (return value) first allocated page
385// @ vpn_size : (return value) number of allocated pages
386////////////////////////////////////////////////////////////////////////////////////////////
387static error_t vmm_stack_alloc( vmm_t * vmm,
388                                vpn_t * vpn_base,
389                                vpn_t * vpn_size )
390{
391    // get stack allocator pointer
392    stack_mgr_t * mgr = &vmm->stack_mgr;
393
394    // get lock on stack allocator
395    spinlock_lock( &mgr->lock );
396
397    // get first free slot index in bitmap
398    int32_t index = bitmap_ffc( &mgr->bitmap , 4 );
399    if( (index < 0) || (index > 31) )
400    {
401        spinlock_unlock( &mgr->lock );
402        return ENOMEM;
403    }
404
405    // update bitmap
406    bitmap_set( &mgr->bitmap , index );
407
408    // release lock on stack allocator
409    spinlock_unlock( &mgr->lock );
410
411    // returns vpn_base, vpn_size (one page non allocated)
412    *vpn_base = mgr->vpn_base + index * CONFIG_VMM_STACK_SIZE + 1;
413    *vpn_size = CONFIG_VMM_STACK_SIZE - 1;
414    return 0;
415
416} // end vmm_stack_alloc()
417
418////////////////////////////////////////////////////////////////////////////////////////////
419// This static function is called by the vmm_create_vseg() function, and implements
420// the VMM MMAP specific allocator.
421////////////////////////////////////////////////////////////////////////////////////////////
422// @ vmm      : [in] pointer on VMM.
423// @ npages   : [in] requested number of pages.
424// @ vpn_base : [out] first allocated page.
425// @ vpn_size : [out] actual number of allocated pages.
426////////////////////////////////////////////////////////////////////////////////////////////
427static error_t vmm_mmap_alloc( vmm_t * vmm,
428                               vpn_t   npages,
429                               vpn_t * vpn_base,
430                               vpn_t * vpn_size )
431{
432    uint32_t   index;
433    vseg_t   * vseg;
434    vpn_t      base;
435    vpn_t      size;
436    vpn_t      free;
437
438    // mmap vseg size must be power of 2
439    // compute actual size and index in zombi_list array
440    size  = POW2_ROUNDUP( npages );
441    index = bits_log2( size );
442
443    // get mmap allocator pointer
444    mmap_mgr_t * mgr = &vmm->mmap_mgr;
445
446    // get lock on mmap allocator
447    spinlock_lock( &mgr->lock );
448
449    // get vseg from zombi_list or from mmap zone
450    if( list_is_empty( &mgr->zombi_list[index] ) )     // from mmap zone
451    {
452        // check overflow
453        free = mgr->first_free_vpn;
454        if( (free + size) > mgr->vpn_size ) return ENOMEM;
455
456        // update STACK allocator
457        mgr->first_free_vpn += size;
458
459        // compute base
460        base = free;
461    }
462    else                                             // from zombi_list
463    {
464        // get pointer on zombi vseg from zombi_list
465        vseg = LIST_FIRST( &mgr->zombi_list[index] , vseg_t , list );
466
467        // remove vseg from free-list
468        list_unlink( &vseg->list );
469
470        // compute base
471        base = vseg->vpn_base;
472    }
473
474    // release lock on mmap allocator
475    spinlock_unlock( &mgr->lock );
476
477    // returns vpn_base, vpn_size
478    *vpn_base = base;
479    *vpn_size = size;
480    return 0;
481
482}  // end vmm_mmap_alloc()
483
484////////////////////////////////////////////////
485vseg_t * vmm_create_vseg( process_t   * process,
486                              vseg_type_t   type,
487                          intptr_t      base,
488                              uint32_t      size,
489                          uint32_t      file_offset,
490                          uint32_t      file_size,
491                          xptr_t        mapper_xp,
492                          cxy_t         cxy )
493{
494    vseg_t     * vseg;          // created vseg pointer
495    vpn_t        vpn_base;      // first page index
496    vpn_t        vpn_size;      // number of pages
497        error_t      error;
498
499vmm_dmsg("\n[DBG] %s : core[%x,%d] enters / process %x / base %x / size %x / %s / cxy = %x\n",
500__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ,
501process->pid , base , size , vseg_type_str(type) , cxy );
502
503    // get pointer on VMM
504        vmm_t * vmm    = &process->vmm;
505
506    // compute base, size, vpn_base, vpn_size, depending on vseg type
507    // we use the VMM specific allocators for "stack", "file", "anon", & "remote" vsegs
508    if( type == VSEG_TYPE_STACK )
509    {
510        // get vpn_base and vpn_size from STACK allocator
511        error = vmm_stack_alloc( vmm , &vpn_base , &vpn_size );
512        if( error )
513        {
514            printk("\n[ERROR] in %s : no space for stack vseg / process %x in cluster %x\n",
515            __FUNCTION__ , process->pid , local_cxy );
516            return NULL;
517        }
518
519        // compute vseg base and size from vpn_base and vpn_size
520        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
521        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
522    }
523    else if( (type == VSEG_TYPE_ANON) ||
524             (type == VSEG_TYPE_FILE) ||
525             (type == VSEG_TYPE_REMOTE) )
526    {
527        // get vpn_base and vpn_size from MMAP allocator
528        vpn_t npages = size >> CONFIG_PPM_PAGE_SHIFT;
529        error = vmm_mmap_alloc( vmm , npages , &vpn_base , &vpn_size );
530        if( error )
531        {
532            printk("\n[ERROR] in %s : no vspace for mmap vseg / process %x in cluster %x\n",
533                   __FUNCTION__ , process->pid , local_cxy );
534            return NULL;
535        }
536
537        // compute vseg base and size from vpn_base and vpn_size
538        base = vpn_base << CONFIG_PPM_PAGE_SHIFT;
539        size = vpn_size << CONFIG_PPM_PAGE_SHIFT;
540    }
541    else
542    {
543        uint32_t vpn_min = base >> CONFIG_PPM_PAGE_SHIFT;
544        uint32_t vpn_max = (base + size - 1) >> CONFIG_PPM_PAGE_SHIFT;
545
546        vpn_base = vpn_min;
547            vpn_size = vpn_max - vpn_min + 1;
548    }
549
550    // check collisions
551    vseg = vmm_check_conflict( process , vpn_base , vpn_size );
552    if( vseg != NULL )
553    {
554        printk("\n[ERROR] in %s for process %x : new vseg [vpn_base = %x / vpn_size = %x]\n"
555               "  overlap existing vseg [vpn_base = %x / vpn_size = %x]\n",
556        __FUNCTION__ , process->pid, vpn_base, vpn_size, vseg->vpn_base, vseg->vpn_size );
557        return NULL;
558    }
559
560    // allocate physical memory for vseg descriptor
561        vseg = vseg_alloc();
562        if( vseg == NULL )
563        {
564            printk("\n[ERROR] in %s for process %x : cannot allocate memory for vseg\n",
565        __FUNCTION__ , process->pid );
566        return NULL;
567        }
568
569    // initialize vseg descriptor
570        vseg_init( vseg,
571               type,
572               base,
573               size,
574               vpn_base,
575               vpn_size,
576               file_offset,
577               file_size,
578               mapper_xp,
579               cxy );
580
581    // attach vseg to vmm
582        rwlock_wr_lock( &vmm->vsegs_lock );
583        vseg_attach( vmm , vseg );
584        rwlock_wr_unlock( &vmm->vsegs_lock );
585
586vmm_dmsg("\n[DBG] %s : core[%x,%d] exit / process %x / base %x / size %x / type %s\n",
587__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ,
588process->pid , base , size , vseg_type_str(type) );
589
590        return vseg;
591
592}  // vmm_create_vseg()
593
594/////////////////////////////////////
595void vmm_remove_vseg( vseg_t * vseg )
596{
597    // get pointers on calling process and VMM
598    thread_t   * this    = CURRENT_THREAD;
599    process_t  * process = this->process;
600    vmm_t      * vmm     = &this->process->vmm;
601    uint32_t     type    = vseg->type;
602
603    // detach vseg from VMM
604        rwlock_wr_lock( &vmm->vsegs_lock );
605    vseg_detach( &process->vmm , vseg );
606        rwlock_wr_unlock( &vmm->vsegs_lock );
607
608    // release the stack slot to VMM stack allocator if STACK type
609    if( type == VSEG_TYPE_STACK )
610    {
611        // get pointer on stack allocator
612        stack_mgr_t * mgr = &vmm->stack_mgr;
613
614        // compute slot index
615        uint32_t index = ((vseg->vpn_base - mgr->vpn_base - 1) / CONFIG_VMM_STACK_SIZE);
616
617        // update stacks_bitmap
618        spinlock_lock( &mgr->lock );
619        bitmap_clear( &mgr->bitmap , index );
620        spinlock_unlock( &mgr->lock );
621    }
622
623    // release the vseg to VMM mmap allocator if MMAP type
624    if( (type == VSEG_TYPE_ANON) || (type == VSEG_TYPE_FILE) || (type == VSEG_TYPE_REMOTE) )
625    {
626        // get pointer on mmap allocator
627        mmap_mgr_t * mgr = &vmm->mmap_mgr;
628
629        // compute zombi_list index
630        uint32_t index = bits_log2( vseg->vpn_size );
631
632        // update zombi_list
633        spinlock_lock( &mgr->lock );
634        list_add_first( &mgr->zombi_list[index] , &vseg->list );
635        spinlock_unlock( &mgr->lock );
636    }
637
638    // release physical memory allocated for vseg descriptor if no MMAP type
639    if( (type != VSEG_TYPE_ANON) && (type != VSEG_TYPE_FILE) && (type != VSEG_TYPE_REMOTE) )
640    {
641        vseg_free( vseg );
642    }
643}  // end vmm_remove_vseg()
644
645//////////////////////////////////////////////
646error_t vmm_map_kernel_vseg( vseg_t    * vseg,
647                             uint32_t    attr )
648{
649    vpn_t       vpn;        // VPN of PTE to be set
650    vpn_t       vpn_min;    // VPN of first PTE to be set
651    vpn_t       vpn_max;    // VPN of last PTE to be set (excluded)
652        ppn_t       ppn;        // PPN of allocated physical page
653        uint32_t    order;      // ln( number of small pages for one single PTE )
654        page_t    * page;
655    error_t     error;
656
657    // check vseg type : must be a kernel vseg
658    uint32_t type = vseg->type;
659    assert( ((type==VSEG_TYPE_KCODE) || (type==VSEG_TYPE_KDATA) || (type==VSEG_TYPE_KDEV)),
660            __FUNCTION__ , "not a kernel vseg\n" );
661
662    // get pointer on page table
663    gpt_t * gpt = &process_zero.vmm.gpt;
664
665    // define number of small pages per PTE
666        if( attr & GPT_SMALL ) order = 0;   // 1 small page
667        else                   order = 9;   // 512 small pages
668
669    // loop on pages in vseg
670    vpn_min = vseg->vpn_base;
671    vpn_max = vpn_min + vseg->vpn_size;
672        for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
673        {
674        // allocate a physical page from local PPM
675            kmem_req_t req;
676            req.type  = KMEM_PAGE;
677            req.size  = order;
678            req.flags = AF_KERNEL | AF_ZERO;
679            page      = (page_t *)kmem_alloc( &req );
680                if( page == NULL )
681        {
682            printk("\n[ERROR] in %s : cannot allocate physical memory\n", __FUNCTION__ );
683            return ENOMEM;
684        }
685
686        // set page table entry
687        ppn = ppm_page2ppn( XPTR( local_cxy , page ) );
688        error = hal_gpt_set_pte( gpt , vpn , ppn , attr );
689                if( error )
690        {
691            printk("\n[ERROR] in %s : cannot register PPE\n", __FUNCTION__ );
692            return ENOMEM;
693        }
694        }
695
696        return 0;
697}
698
699/////////////////////////////////////////
700void vmm_unmap_vseg( process_t * process,
701                     vseg_t    * vseg )
702{
703    vpn_t       vpn;        // VPN of current PTE
704    vpn_t       vpn_min;    // VPN of first PTE
705    vpn_t       vpn_max;    // VPN of last PTE (excluded)
706
707    // get pointer on process page table
708    gpt_t     * gpt = &process->vmm.gpt;
709
710    // loop on pages in vseg
711    vpn_min = vseg->vpn_base;
712    vpn_max = vpn_min + vseg->vpn_size;
713        for( vpn = vpn_min ; vpn < vpn_max ; vpn++ )
714    {
715        hal_gpt_reset_pte( gpt , vpn );
716    }
717}
718
719//////////////////////////////////////////////////////////////////////////////////////////
720// This low-level static function is called by the vmm_get_vseg() and vmm_resize_vseg()
721// functions.  It scan the list of registered vsegs to find the unique vseg containing
722// a given virtual address.
723//////////////////////////////////////////////////////////////////////////////////////////
724// @ vmm     : pointer on the process VMM.
725// @ vaddr   : virtual address.
726// @ return vseg pointer if success / return NULL if not found.
727//////////////////////////////////////////////////////////////////////////////////////////
728static vseg_t * vseg_from_vaddr( vmm_t    * vmm,
729                                 intptr_t   vaddr )
730{
731    list_entry_t * iter;
732    vseg_t       * vseg = NULL;
733
734    // get lock protecting the vseg list
735    rwlock_rd_lock( &vmm->vsegs_lock );
736
737    // scan the list of vsegs
738    LIST_FOREACH( &vmm->vsegs_root , iter )
739    {
740        vseg = LIST_ELEMENT( iter , vseg_t , list );
741        if( (vaddr >= vseg->min) && (vaddr < vseg->max) ) break;
742    }
743
744    // release the lock
745    rwlock_rd_unlock( &vmm->vsegs_lock );
746
747    return vseg;
748}
749
750/////////////////////////////////////////////
751error_t vmm_resize_vseg( process_t * process,
752                         intptr_t    base,
753                         intptr_t    size )
754{
755    error_t   error;
756    vseg_t  * new;
757    vpn_t     vpn_min;
758    vpn_t     vpn_max;
759
760    // get pointer on process VMM
761    vmm_t * vmm = &process->vmm;
762
763    intptr_t addr_min = base;
764        intptr_t addr_max = base + size;
765
766    // get pointer on vseg
767        vseg_t * vseg = vseg_from_vaddr( vmm , base );
768
769        if( vseg == NULL)  return EINVAL;
770
771    // get VMM lock protecting vsegs list
772        rwlock_wr_lock( &vmm->vsegs_lock );
773
774        if( (vseg->min > addr_min) || (vseg->max < addr_max) )   // region not included in vseg
775    {
776        error = EINVAL;
777    }
778        else if( (vseg->min == addr_min) && (vseg->max == addr_max) ) // vseg must be removed
779    {
780        vmm_remove_vseg( vseg );
781        error = 0;
782    }
783        else if( vseg->min == addr_min )                         // vseg must be resized
784    {
785        // update vseg base address
786        vseg->min = addr_max;
787
788        // update vpn_base and vpn_size
789        vpn_min        = vseg->min >> CONFIG_PPM_PAGE_SHIFT;
790        vpn_max        = (vseg->max - 1) >> CONFIG_PPM_PAGE_SHIFT;
791        vseg->vpn_base = vpn_min;
792        vseg->vpn_size = vpn_max - vpn_min + 1;
793        error = 0;
794    }
795        else if( vseg->max == addr_max )                          // vseg must be resized
796    {
797        // update vseg max address
798        vseg->max = addr_min;
799
800        // update vpn_base and vpn_size
801        vpn_min        = vseg->min >> CONFIG_PPM_PAGE_SHIFT;
802        vpn_max        = (vseg->max - 1) >> CONFIG_PPM_PAGE_SHIFT;
803        vseg->vpn_base = vpn_min;
804        vseg->vpn_size = vpn_max - vpn_min + 1;
805        error = 0;
806    }
807    else                                                      // vseg cut in three regions
808    {
809        // resize existing vseg
810        vseg->max = addr_min;
811
812        // update vpn_base and vpn_size
813        vpn_min        = vseg->min >> CONFIG_PPM_PAGE_SHIFT;
814        vpn_max        = (vseg->max - 1) >> CONFIG_PPM_PAGE_SHIFT;
815        vseg->vpn_base = vpn_min;
816        vseg->vpn_size = vpn_max - vpn_min + 1;
817
818        // create new vseg
819        new = vmm_create_vseg( process, 
820                               vseg->type,
821                               addr_min, 
822                               (vseg->max - addr_max),
823                               vseg->file_offset,
824                               vseg->file_size,
825                               vseg->mapper_xp,
826                               vseg->cxy ); 
827
828        if( new == NULL ) error = EINVAL;
829        else              error = 0;
830    }
831
832    // release VMM lock
833        rwlock_wr_unlock( &vmm->vsegs_lock );
834
835        return error;
836
837}  // vmm_resize_vseg()
838
839///////////////////////////////////////////
840error_t  vmm_get_vseg( process_t * process,
841                       intptr_t    vaddr,
842                       vseg_t   ** found_vseg )
843{
844    vmm_t  * vmm = &process->vmm;
845
846    // get vseg from vaddr
847    vseg_t * vseg = vseg_from_vaddr( vmm , vaddr );
848
849    if( vseg == NULL )   // vseg not found in local cluster => try to get it from ref
850        {
851        // get extended pointer on reference process
852        xptr_t ref_xp = process->ref_xp;
853
854        // get cluster and local pointer on reference process
855        cxy_t       ref_cxy = GET_CXY( ref_xp );
856        process_t * ref_ptr = (process_t *)GET_PTR( ref_xp );
857
858        if( local_cxy == ref_cxy )  return -1;   // local cluster is the reference
859
860        // get extended pointer on reference vseg
861        xptr_t   vseg_xp;
862        error_t  error;
863
864        rpc_vmm_get_vseg_client( ref_cxy , ref_ptr , vaddr , &vseg_xp , &error );
865           
866        if( error )   return -1;       // vseg not found => illegal user vaddr
867       
868        // allocate a vseg in local cluster
869        vseg = vseg_alloc();
870
871        if( vseg == NULL ) return -1;
872
873        // initialise local vseg from reference
874        vseg_init_from_ref( vseg , vseg_xp );
875
876        // register local vseg in local VMM
877        vseg_attach( &process->vmm , vseg );
878    }   
879   
880    // success
881    *found_vseg = vseg;
882    return 0;
883
884}  // end vmm_get_vseg()
885
886//////////////////////////////////////////////////////////////////////////////////////
887// This static function compute the target cluster to allocate a physical page
888// for a given <vpn> in a given <vseg>, allocates the page (with an RPC if required)
889// and returns an extended pointer on the allocated page descriptor.
890// The vseg cannot have the FILE type.
891//////////////////////////////////////////////////////////////////////////////////////
892static xptr_t vmm_page_allocate( vseg_t * vseg,
893                                 vpn_t    vpn )
894{
895    // compute target cluster
896    page_t     * page_ptr;
897    cxy_t        page_cxy;
898    kmem_req_t   req;
899
900    uint32_t     type  = vseg->type;
901    uint32_t     flags = vseg->flags;
902
903    assert( ( type != VSEG_TYPE_FILE ) , __FUNCTION__ , "illegal vseg type\n" );
904
905    if( flags & VSEG_DISTRIB )    // distributed => cxy depends on vpn LSB
906    {
907        uint32_t x_size  = LOCAL_CLUSTER->x_size;
908        uint32_t y_size  = LOCAL_CLUSTER->y_size;
909        uint32_t y_width = LOCAL_CLUSTER->y_width;
910        uint32_t index   = vpn & ((x_size * y_size) - 1);
911        uint32_t x       = index / y_size;
912        uint32_t y       = index % y_size;
913        page_cxy         = (x<<y_width) + y;
914    }
915    else                          // other cases => cxy specified in vseg
916    {
917        page_cxy         = vseg->cxy;
918    }
919
920    // allocate a physical page from target cluster
921    if( page_cxy == local_cxy )  // target cluster is the local cluster
922    {
923        req.type  = KMEM_PAGE;
924        req.size  = 0;
925        req.flags = AF_NONE;
926        page_ptr  = (page_t *)kmem_alloc( &req );
927    }
928    else                           // target cluster is not the local cluster
929    {
930        rpc_pmem_get_pages_client( page_cxy , 0 , &page_ptr );
931    }
932
933    if( page_ptr == NULL ) return XPTR_NULL;
934    else                   return XPTR( page_cxy , page_ptr );
935
936}  // end vmm_page_allocate() 
937
938////////////////////////////////////////
939error_t vmm_get_one_ppn( vseg_t * vseg,
940                         vpn_t    vpn,
941                         ppn_t  * ppn )
942{
943    error_t    error;
944    xptr_t     page_xp;           // extended pointer on physical page descriptor
945    page_t   * page_ptr;          // local pointer on physical page descriptor
946    uint32_t   index;             // missing page index in vseg mapper
947    uint32_t   type;              // vseg type;
948
949    type      = vseg->type;
950    index     = vpn - vseg->vpn_base;
951
952vmm_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x / type = %s / index = %d\n",
953__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn, vseg_type_str(type), index );
954
955    // FILE type : get the physical page from the file mapper
956    if( type == VSEG_TYPE_FILE )
957    {
958        // get extended pointer on mapper
959        xptr_t mapper_xp = vseg->mapper_xp;
960
961        assert( (mapper_xp != XPTR_NULL), __FUNCTION__,
962        "mapper not defined for a FILE vseg\n" );
963       
964        // get mapper cluster and local pointer
965        cxy_t      mapper_cxy = GET_CXY( mapper_xp );
966        mapper_t * mapper_ptr = (mapper_t *)GET_PTR( mapper_xp );
967
968        // get page descriptor from mapper
969        if( mapper_cxy == local_cxy )             // mapper is local
970        {
971            page_ptr = mapper_get_page( mapper_ptr , index );
972        }
973        else                                      // mapper is remote
974        {
975            rpc_mapper_get_page_client( mapper_cxy , mapper_ptr , index , &page_ptr );
976        }
977
978        if ( page_ptr == NULL ) return EINVAL;
979
980        page_xp = XPTR( mapper_cxy , page_ptr );
981    }
982
983    // Other types : allocate a physical page from target cluster,
984    // as defined by vseg type and vpn value
985    else
986    {
987        // allocate physical page
988        page_xp = vmm_page_allocate( vseg , vpn );
989
990        if( page_xp == XPTR_NULL ) return ENOMEM;
991
992        // initialise missing page from .elf file mapper for DATA and CODE types
993        // => the mapper_xp field is an extended pointer on the .elf file mapper
994        if( (type == VSEG_TYPE_CODE) || (type == VSEG_TYPE_DATA) )
995        {
996            // get extended pointer on mapper
997            xptr_t     mapper_xp = vseg->mapper_xp;
998
999            assert( (mapper_xp != XPTR_NULL), __FUNCTION__,
1000            "mapper not defined for a CODE or DATA vseg\n" );
1001       
1002            // get mapper cluster and local pointer
1003            cxy_t      mapper_cxy = GET_CXY( mapper_xp );
1004            mapper_t * mapper_ptr = (mapper_t *)GET_PTR( mapper_xp );
1005
1006            // compute missing page offset in vseg
1007            uint32_t offset = index << CONFIG_PPM_PAGE_SHIFT;
1008
1009            // compute missing page offset in .elf file
1010            uint32_t elf_offset = vseg->file_offset + offset;
1011
1012vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / elf_offset = %x\n",
1013__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn, elf_offset );
1014
1015            // compute extended pointer on page base
1016            xptr_t base_xp  = ppm_page2base( page_xp );
1017
1018            // file_size (in .elf mapper) can be smaller than vseg_size (BSS)
1019            uint32_t file_size = vseg->file_size;
1020
1021            if( file_size < offset )                 // missing page fully in  BSS
1022            {
1023vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / fully in BSS\n",
1024__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
1025
1026                if( GET_CXY( page_xp ) == local_cxy )
1027                {
1028                    memset( GET_PTR( base_xp ) , 0 , CONFIG_PPM_PAGE_SIZE );
1029                }
1030                else
1031                {
1032                   hal_remote_memset( base_xp , 0 , CONFIG_PPM_PAGE_SIZE );       
1033                }
1034            }
1035            else if( file_size >= (offset + CONFIG_PPM_PAGE_SIZE) )  // fully in  mapper
1036            {
1037
1038vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / fully in mapper\n",
1039__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn );
1040
1041                if( mapper_cxy == local_cxy ) 
1042                {
1043                    error = mapper_move_kernel( mapper_ptr,
1044                                                true,             // to_buffer
1045                                                elf_offset,
1046                                                base_xp,
1047                                                CONFIG_PPM_PAGE_SIZE ); 
1048                }
1049                else 
1050                {
1051                    rpc_mapper_move_buffer_client( mapper_cxy,
1052                                                   mapper_ptr,
1053                                                   true,         // to buffer
1054                                                   false,        // kernel buffer
1055                                                   elf_offset,
1056                                                   base_xp,
1057                                                   CONFIG_PPM_PAGE_SIZE,
1058                                                   &error );
1059                }
1060                if( error ) return EINVAL;
1061            }
1062            else  // both in mapper and in BSS :
1063                  // - (file_size - offset)             bytes from mapper
1064                  // - (page_size + offset - file_size) bytes from BSS
1065            {
1066
1067vmm_dmsg("\n[DBG] %s : core[%x,%d] for vpn = %x / both mapper & BSS\n"
1068         "      %d bytes from mapper / %d bytes from BSS\n",
1069__FUNCTION__, local_cxy, CURRENT_THREAD->core->lid, vpn,
1070file_size - offset , offset + CONFIG_PPM_PAGE_SIZE - file_size  );
1071
1072                // initialize mapper part
1073                if( mapper_cxy == local_cxy )
1074                {
1075                    error = mapper_move_kernel( mapper_ptr,
1076                                                true,         // to buffer
1077                                                elf_offset,
1078                                                base_xp,
1079                                                file_size - offset ); 
1080                }
1081                else                               
1082                {
1083                    rpc_mapper_move_buffer_client( mapper_cxy,
1084                                                   mapper_ptr,
1085                                                   true,         // to buffer
1086                                                   false,        // kernel buffer
1087                                                   elf_offset,
1088                                                   base_xp,
1089                                                   file_size - offset, 
1090                                                   &error );
1091                }
1092                if( error ) return EINVAL;
1093
1094                // initialize BSS part
1095                if( GET_CXY( page_xp ) == local_cxy )
1096                {
1097                    memset( GET_PTR( base_xp ) + file_size - offset , 0 , 
1098                            offset + CONFIG_PPM_PAGE_SIZE - file_size );
1099                }
1100                else
1101                {
1102                   hal_remote_memset( base_xp + file_size - offset , 0 , 
1103                                      offset + CONFIG_PPM_PAGE_SIZE - file_size );
1104                }
1105            }   
1106        }  // end initialisation for CODE or DATA types   
1107    } 
1108
1109    // return ppn
1110    *ppn = ppm_page2ppn( page_xp );
1111
1112vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn = %x / ppn = %x\n",
1113__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , *ppn );
1114
1115    return 0;
1116
1117}  // end vmm_get_one_ppn()
1118
1119/////////////////////////////////////////
1120error_t vmm_get_pte( process_t * process,
1121                     vpn_t       vpn,
1122                     bool_t      cow,
1123                     uint32_t  * attr,
1124                     ppn_t     * ppn )
1125{
1126    vseg_t  * vseg;       // pointer on vseg containing VPN
1127    ppn_t     old_ppn;    // current PTE_PPN
1128    uint32_t  old_attr;   // current PTE_ATTR
1129    ppn_t     new_ppn;    // new PTE_PPN
1130    uint32_t  new_attr;   // new PTE_ATTR
1131    xptr_t    page_xp;    // extended pointer on allocated page descriptor
1132    error_t   error;
1133
1134    // this function must be called by a thread running in the reference cluster
1135    assert( (GET_CXY( process->ref_xp ) == local_cxy ) , __FUNCTION__ ,
1136    "not called in the reference cluster\n" );
1137
1138vmm_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x in process %x / cow = %d\n",
1139__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , process->pid , %d);
1140
1141    // get VMM pointer
1142    vmm_t * vmm = &process->vmm;
1143
1144    // get vseg pointer from ref VSL
1145    error = vmm_get_vseg( process , vpn<<CONFIG_PPM_PAGE_SHIFT , &vseg );
1146
1147    if( error )
1148    {
1149        printk("\n[ERROR] in %s : out of segment / process = %x / vpn = %x\n",
1150        __FUNCTION__ , process->pid , vpn );
1151        return error;
1152    }
1153
1154vmm_dmsg("\n[DBG] %s : core[%x,%d] found vseg %s / vpn_base = %x / vpn_size = %x\n",
1155__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid ,
1156vseg_type_str(vseg->type) , vseg->vpn_base , vseg->vpn_size );
1157
1158    // access GPT to get current PTE attributes and PPN
1159    hal_gpt_get_pte( &vmm->gpt , vpn , &old_attr , &old_ppn );
1160
1161    // for both copy_on_write and page_fault events, we allocate a physical page,
1162    // initialize it, register it in the GPT, and return the new_ppn and new_attr
1163
1164    if( cow )               ////////////// copy_on_write request ///////////
1165    {
1166        assert( (*attr & GPT_MAPPED) , __FUNCTION__ , 
1167        "PTE must be mapped for a copy-on-write\n" );
1168
1169vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x must be copied => do it\n",
1170__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
1171
1172        // allocate a physical page depending on vseg type
1173        page_xp = vmm_page_allocate( vseg , vpn );
1174
1175        if( page_xp == XPTR_NULL ) 
1176        {
1177            printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
1178            __FUNCTION__ , process->pid , vpn );
1179            return ENOMEM;
1180        }
1181
1182        // compute allocated page PPN
1183        new_ppn = ppm_page2ppn( page_xp );
1184
1185        // copy old page content to new page
1186        xptr_t  old_base_xp = ppm_ppn2base( old_ppn );
1187        xptr_t  new_base_xp = ppm_ppn2base( new_ppn );
1188        memcpy( GET_PTR( new_base_xp ),
1189                GET_PTR( old_base_xp ),
1190                CONFIG_PPM_PAGE_SIZE );
1191
1192        // update attributes: reset COW and set WRITABLE
1193        new_attr = old_attr & ~GPT_COW; 
1194        new_attr = new_attr | GPT_WRITABLE;
1195
1196        // register PTE in GPT
1197        error = hal_gpt_set_pte( &vmm->gpt , vpn , new_ppn , new_attr );
1198
1199        if( error )
1200        {
1201            printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n",
1202            __FUNCTION__ , process->pid , vpn );
1203            return error;
1204        }
1205    }
1206    else                    //////////////////// page_fault request ///////////
1207    { 
1208        if( (old_attr & GPT_MAPPED) == 0 )    // PTE unmapped in ref GPT
1209        {
1210
1211vmm_dmsg("\n[DBG] %s : core[%x,%d] page %x unmapped => try to map it\n",
1212__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
1213
1214            // allocate one physical page, depending on vseg type
1215            error = vmm_get_one_ppn( vseg , vpn , &new_ppn );
1216
1217            if( error )
1218            {
1219                printk("\n[ERROR] in %s : no memory / process = %x / vpn = %x\n",
1220                __FUNCTION__ , process->pid , vpn );
1221                return error;
1222            }
1223
1224            // define attributes from vseg flags
1225            new_attr = GPT_MAPPED | GPT_SMALL;
1226            if( vseg->flags & VSEG_USER  ) new_attr |= GPT_USER;
1227            if( vseg->flags & VSEG_WRITE ) new_attr |= GPT_WRITABLE;
1228            if( vseg->flags & VSEG_EXEC  ) new_attr |= GPT_EXECUTABLE;
1229            if( vseg->flags & VSEG_CACHE ) new_attr |= GPT_CACHABLE;
1230
1231            // register PTE in GPT
1232            error = hal_gpt_set_pte( &vmm->gpt , vpn , new_ppn , new_attr );
1233
1234            if( error )
1235            {
1236                printk("\n[ERROR] in %s : cannot update GPT / process = %x / vpn = %x\n",
1237                __FUNCTION__ , process->pid , vpn );
1238                return error;
1239            }
1240        }
1241        else
1242        {
1243            new_attr = old_attr;
1244            new_ppn  = old_ppn;
1245        }
1246    }
1247
1248vmm_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn = %x / ppn = %x / attr = %x\n",
1249__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , new_ppn , new_attr );
1250
1251    *ppn  = new_ppn;
1252    *attr = new_attr;
1253    return 0;
1254
1255}  // end vmm_get_pte()
1256
1257///////////////////////////////////////////////////
1258error_t vmm_handle_page_fault( process_t * process,
1259                               vpn_t       vpn )
1260{
1261    uint32_t         attr;          // missing page attributes
1262    ppn_t            ppn;           // missing page PPN
1263    error_t          error;
1264
1265    // get reference process cluster and local pointer
1266    cxy_t       ref_cxy = GET_CXY( process->ref_xp );
1267    process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
1268
1269    // get missing PTE attributes and PPN from reference cluster
1270    if( local_cxy != ref_cxy ) 
1271    {
1272        rpc_vmm_get_pte_client( ref_cxy,
1273                                ref_ptr,
1274                                vpn,
1275                                false,    // page_fault
1276                                &attr,
1277                                &ppn,
1278                                &error );
1279
1280        // get local VMM pointer
1281        vmm_t * vmm = &process->vmm;
1282
1283        // update local GPT
1284        error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
1285    }
1286    else   // local cluster is the reference cluster
1287    {
1288        error = vmm_get_pte( process,
1289                             vpn,
1290                             false,      // page-fault
1291                             &attr,
1292                             &ppn );
1293    }
1294
1295    return error;
1296
1297}  // end vmm_handle_page_fault()
1298
1299///////////////////////////////////////////////
1300error_t vmm_copy_on_write( process_t * process,
1301                           vpn_t       vpn )
1302{
1303    uint32_t         attr;          // missing page attributes
1304    ppn_t            ppn;           // missing page PPN
1305    error_t          error;
1306
1307    // get reference process cluster and local pointer
1308    cxy_t       ref_cxy = GET_CXY( process->ref_xp );
1309    process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
1310
1311    // get new PTE attributes and PPN from reference cluster
1312    if( local_cxy != ref_cxy )
1313    {
1314        rpc_vmm_get_pte_client( ref_cxy,
1315                                ref_ptr,
1316                                vpn,
1317                                true,     // copy-on-write
1318                                &attr,
1319                                &ppn,
1320                                &error );
1321
1322        // get local VMM pointer
1323        vmm_t * vmm = &process->vmm;
1324
1325        // update local GPT
1326        error |= hal_gpt_set_pte( &vmm->gpt , vpn , ppn , attr );
1327    }
1328    else   // local cluster is the reference cluster
1329    {
1330        error = vmm_get_pte( process,
1331                             vpn,
1332                             true,      // copy-on-write
1333                             &attr,
1334                             &ppn );
1335    }
1336
1337    return error;
1338
1339}  // end vmm_copy_on_write()
1340
1341///////////////////////////////////////////
1342error_t vmm_v2p_translate( bool_t    ident,
1343                           void    * ptr,
1344                           paddr_t * paddr )
1345{
1346    process_t * process = CURRENT_THREAD->process;
1347
1348    if( ident )  // identity mapping
1349    {
1350        *paddr = (paddr_t)PADDR( local_cxy , (lpa_t)ptr );
1351        return 0;
1352    }
1353
1354    // access page table
1355    error_t  error;
1356    vpn_t    vpn;
1357    uint32_t attr;
1358    ppn_t    ppn;
1359    uint32_t offset;
1360
1361    vpn    = (vpn_t)( (intptr_t)ptr >> CONFIG_PPM_PAGE_SHIFT );
1362    offset = (uint32_t)( ((intptr_t)ptr) & CONFIG_PPM_PAGE_MASK );
1363
1364    if( local_cxy == GET_CXY( process->ref_xp) ) // calling process is reference process
1365    {
1366        error = vmm_get_pte( process, vpn , false , &attr , &ppn );
1367    }
1368    else                                         // calling process is not reference process
1369    {
1370        cxy_t       ref_cxy = GET_CXY( process->ref_xp );
1371        process_t * ref_ptr = (process_t *)GET_PTR( process->ref_xp );
1372        rpc_vmm_get_pte_client( ref_cxy , ref_ptr , vpn , false , &attr , &ppn , &error );
1373    }
1374
1375    // set paddr
1376    *paddr = (((paddr_t)ppn) << CONFIG_PPM_PAGE_SHIFT) | offset;
1377
1378    return error;
1379
1380}  // end vmm_v2p_translate()
1381
1382
Note: See TracBrowser for help on using the repository browser.