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

Last change on this file since 14 was 14, checked in by alain, 8 years ago

Bugs fix.

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