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

Last change on this file since 186 was 179, checked in by max@…, 7 years ago

fix a lock leak, there are many others left...

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