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

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

Introduce syscalls.

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