source: trunk/kernel/mm/mapper.c @ 654

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

1) Improve the VMM MMAP allocator: implement the "buddy" algorithm
to allocate only aligned blocks.
2) fix a bug in the pthread_join() / pthread_exit() mmechanism.

File size: 27.2 KB
Line 
1/*
2 * mapper.c - Kernel cache for FS files or directories implementation.
3 *
4 * Authors   Mohamed Lamine Karaoui (2015)
5 *           Alain Greiner (2016,2017,2018,2019)
6 *
7 * Copyright (c)  UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <kernel_config.h>
26#include <hal_kernel_types.h>
27#include <hal_special.h>
28#include <hal_uspace.h>
29#include <grdxt.h>
30#include <string.h>
31#include <rwlock.h>
32#include <printk.h>
33#include <memcpy.h>
34#include <thread.h>
35#include <core.h>
36#include <process.h>
37#include <kmem.h>
38#include <kcm.h>
39#include <ppm.h>
40#include <page.h>
41#include <cluster.h>
42#include <vfs.h>
43#include <mapper.h>
44#include <dev_ioc.h>
45
46
47//////////////////////////////////////////////
48mapper_t * mapper_create( vfs_fs_type_t type )
49{
50    mapper_t * mapper;
51    kmem_req_t req;
52    error_t    error;
53
54    // allocate memory for mapper descriptor
55    req.type  = KMEM_KCM;
56    req.order = bits_log2( sizeof(mapper_t) );
57    req.flags = AF_KERNEL | AF_ZERO;
58    mapper    = kmem_alloc( &req );
59
60    if( mapper == NULL )
61    {
62        printk("\n[ERROR] in %s : no memory for mapper descriptor\n", __FUNCTION__ );
63        return NULL;
64    }
65
66    // initialize refcount & inode
67    mapper->refcount = 0;
68    mapper->inode    = NULL;
69
70    // initialize radix tree
71    error = grdxt_init( &mapper->rt,
72                        CONFIG_MAPPER_GRDXT_W1,
73                        CONFIG_MAPPER_GRDXT_W2,
74                        CONFIG_MAPPER_GRDXT_W3 );
75    if( error )
76    {
77        printk("\n[ERROR] in %s : cannot initialize radix tree\n", __FUNCTION__ );
78        req.type  = KMEM_KCM;
79        req.ptr   = mapper;
80        kmem_free( &req );
81        return NULL;
82    }
83
84    // initialize mapper type
85    mapper->type = type;
86
87    // initialize mapper lock
88    remote_rwlock_init( XPTR( local_cxy , &mapper->lock ) , LOCK_MAPPER_STATE );
89
90    // initialize waiting threads xlist (empty)
91    xlist_root_init( XPTR( local_cxy , &mapper->wait_root ) );
92
93    // initialize vsegs xlist (empty)
94    xlist_root_init( XPTR( local_cxy , &mapper->vsegs_root ) );
95
96    return mapper;
97
98}  // end mapper_create()
99
100////////////////////////////////////////
101void mapper_destroy( mapper_t * mapper )
102{
103    page_t   * page;
104    uint32_t   found_index = 0;
105    uint32_t   start_index = 0;
106    kmem_req_t req;
107
108    // scan radix tree
109    do
110    {
111        // get page from radix tree
112        page = (page_t *)grdxt_get_first( &mapper->rt , start_index , &found_index );
113
114        // release registered pages to PPM
115        if( page != NULL )
116        {
117            // remove page from mapper and release to PPM
118            mapper_remote_release_page( XPTR( local_cxy , mapper ) , page );
119
120            // update start_key value for next page
121            start_index = found_index;
122        }
123    }
124    while( page != NULL );
125
126    // release the memory allocated to radix tree itself
127    grdxt_destroy( &mapper->rt );
128
129    // release memory for mapper descriptor
130    req.type = KMEM_KCM;
131    req.ptr  = mapper;
132    kmem_free( &req );
133
134}  // end mapper_destroy()
135
136////////////////////////////////////////////////////////
137error_t mapper_remote_handle_miss( xptr_t     mapper_xp,
138                                   uint32_t   page_id,
139                                   xptr_t   * page_xp_ptr )
140{
141    error_t    error;
142
143    thread_t * this = CURRENT_THREAD;
144
145    // get target mapper cluster and local pointer
146    cxy_t      mapper_cxy = GET_CXY( mapper_xp );
147    mapper_t * mapper_ptr = GET_PTR( mapper_xp );
148
149#if DEBUG_MAPPER_HANDLE_MISS
150uint32_t      cycle = (uint32_t)hal_get_cycles();
151char          name[CONFIG_VFS_MAX_NAME_LENGTH];
152vfs_inode_t * inode = mapper->inode;
153if( (DEBUG_MAPPER_HANDLE_MISS < cycle) && (inode != NULL) )
154{
155    vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
156    printk("\n[%s] thread[%x,%x] enter for page %d in <%s> / cluster %x / cycle %d",
157    __FUNCTION__, this->process->pid, this->trdid, page_id, name, mapper_cxy, cycle );
158    if( DEBUG_MAPPER_HANDLE_MISS & 1 ) grdxt_display( XPTR(local_cxy,&mapper->rt), name );
159}
160if( (DEBUG_MAPPER_HANDLE_MISS < cycle) && (inode == NULL) )
161{
162    printk("\n[%s] thread[%x,%x] enter for page %d in FAT / cluster %x / cycle %d",
163    __FUNCTION__, this->process->pid, this->trdid, page_id, mapper_cxy, cycle );
164    if( DEBUG_MAPPER_HANDLE_MISS & 1 ) grdxt_display( XPTR(local_cxy,&mapper->rt), "FAT" );
165}
166#endif
167
168    // allocate one 4 Kbytes page from the remote mapper cluster
169    page_t * page_ptr = ppm_remote_alloc_pages( mapper_cxy , 0 );
170                           
171    if( page_ptr == NULL )
172    {
173        printk("\n[ERROR] in %s : thread [%x,%x] cannot allocate page in cluster %x\n",
174        __FUNCTION__ , this->process->pid, this->trdid , mapper_cxy );
175        return -1;
176    }
177
178    // build extended pointer on new page descriptor
179    xptr_t page_xp = XPTR( mapper_cxy , page_ptr );
180
181    // initialize the page descriptor
182    page_remote_init( page_xp );
183
184    hal_remote_s32( XPTR( mapper_cxy , &page_ptr->refcount ) , 1          );
185    hal_remote_s32( XPTR( mapper_cxy , &page_ptr->index )    , page_id    );
186    hal_remote_spt( XPTR( mapper_cxy , &page_ptr->mapper )   , mapper_ptr );
187    hal_remote_s32( XPTR( mapper_cxy , &page_ptr->flags )    , PG_INIT    );
188
189    // insert page in mapper radix tree
190    error = grdxt_remote_insert( XPTR( mapper_cxy , &mapper_ptr->rt),
191                                 page_id,
192                                 page_ptr );
193
194    if( error )
195    {
196        printk("\n[ERROR] in %s : thread[%x,%x] cannot insert page in mapper\n",
197        __FUNCTION__ , this->process->pid, this->trdid );
198        ppm_remote_free_pages( mapper_cxy , page_ptr );
199        return -1;
200    }
201
202    // launch I/O operation to load page from IOC device to mapper
203    error = vfs_fs_move_page( page_xp , IOC_SYNC_READ );
204
205    if( error )
206    {
207        printk("\n[ERROR] in %s : thread[%x,%x] cannot load page from device\n",
208        __FUNCTION__ , this->process->pid, this->trdid );
209        mapper_remote_release_page( mapper_xp , page_ptr );
210        return -1;
211    }
212
213    // return extended pointer on allocated page
214    *page_xp_ptr = page_xp;
215
216#if DEBUG_MAPPER_HANDLE_MISS
217cycle = (uint32_t)hal_get_cycles();
218if( (DEBUG_MAPPER_HANDLE_MISS < cycle) && (inode != NULL) )
219{
220    printk("\n[%s] thread[%x,%x] exit for page %d in <%s> / ppn %x / cycle %d",
221    __FUNCTION__, this->process->pid, this->trdid,
222    page_id, name, ppm_page2ppn( page_xp ), cycle );
223    if( DEBUG_MAPPER_HANDLE_MISS & 1 ) grdxt_display( XPTR(local_cxy,&mapper->rt) , name );
224}
225if( (DEBUG_MAPPER_HANDLE_MISS < cycle) && (inode == NULL) )
226{
227    printk("\n[%s] thread[%x,%x] exit for page %d in FAT / ppn %x / cycle %d",
228    __FUNCTION__, this->process->pid, this->trdid,
229    page_id, ppm_page2ppn( page_xp ), cycle );
230    if( DEBUG_MAPPER_HANDLE_MISS & 1 ) grdxt_display( XPTR(local_cxy,&mapper->rt ), "FAT" );
231}
232#endif
233
234    return 0;
235
236}  // end mapper_remote_handle_miss()
237
238////////////////////////////////////////////////////
239xptr_t  mapper_remote_get_page( xptr_t    mapper_xp,
240                                uint32_t  page_id )
241{
242    error_t       error;
243    mapper_t    * mapper_ptr;
244    cxy_t         mapper_cxy;
245    xptr_t        lock_xp;        // extended pointer on mapper lock
246    xptr_t        page_xp;        // extended pointer on searched page descriptor
247    xptr_t        rt_xp;          // extended pointer on radix tree in mapper
248
249    thread_t * this = CURRENT_THREAD;
250
251    // get mapper cluster and local pointer
252    mapper_ptr = GET_PTR( mapper_xp );
253    mapper_cxy = GET_CXY( mapper_xp );
254
255#if DEBUG_MAPPER_GET_PAGE
256vfs_inode_t * inode = hal_remote_lpt( XPTR( mapper_cxy , &mapper_ptr->inode ) );
257uint32_t      cycle = (uint32_t)hal_get_cycles();
258char          name[CONFIG_VFS_MAX_NAME_LENGTH];
259if( (DEBUG_MAPPER_GET_PAGE < cycle) && (inode == NULL) )  // FAT mapper
260{
261    printk("\n[%s] thread[%x,%x] enter for page %d of FAT mapper / cycle %d\n",
262    __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
263}
264if( (DEBUG_MAPPER_GET_PAGE < cycle) && (inode != NULL) )  // file mapper
265{
266    vfs_inode_get_name( XPTR( mapper_cxy , inode ) , name );
267    printk("\n[%s] thread[%x,%x] enter for page %d of <%s> mapper / cycle %d\n",
268    __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
269}
270#endif
271
272    // check thread can yield
273    thread_assert_can_yield( this , __FUNCTION__ );
274
275    // build extended pointer on mapper lock and mapper rt
276    lock_xp  = XPTR( mapper_cxy , &mapper_ptr->lock );
277    rt_xp    = XPTR( mapper_cxy , &mapper_ptr->rt );
278
279    // take mapper lock in READ_MODE
280    remote_rwlock_rd_acquire( lock_xp );
281
282    // search page in radix tree
283    page_xp  = grdxt_remote_lookup( rt_xp , page_id );
284
285    // test mapper miss
286    if( page_xp == XPTR_NULL )                  // miss => handle it
287    {
288        // release the lock in READ_MODE and take it in WRITE_MODE
289        remote_rwlock_rd_release( lock_xp );
290        remote_rwlock_wr_acquire( lock_xp );
291
292        // second test on missing page because the page status can be modified
293        // by another thread, when passing from READ_MODE to WRITE_MODE.
294        // from this point there is no concurrent accesses to mapper.
295        page_xp = grdxt_remote_lookup( rt_xp , page_id );
296
297        if ( page_xp == XPTR_NULL )  // miss confirmed => handle it
298        {
299            error = mapper_remote_handle_miss( mapper_xp,
300                                               page_id,
301                                               &page_xp );
302            if( error )
303            {
304                printk("\n[ERROR] in %s : thread[%x,%x] cannot handle mapper miss\n",
305                __FUNCTION__ , this->process->pid, this->trdid );
306                remote_rwlock_wr_release( lock_xp );
307                return XPTR_NULL;
308            }
309        }
310
311#if (DEBUG_MAPPER_GET_PAGE & 1)
312if( DEBUG_MAPPER_GET_PAGE < cycle )
313printk("\n[%s] thread[%x,%x] load missing page from FS : ppn %x\n",
314__FUNCTION__, this->process->pid, this->trdid, ppm_page2ppn(page_xp) );
315#endif
316       
317        // release mapper lock from WRITE_MODE
318        remote_rwlock_wr_release( lock_xp );
319    }
320    else                                              // hit
321    {
322        // release mapper lock from READ_MODE
323        remote_rwlock_rd_release( lock_xp );
324    }
325
326#if DEBUG_MAPPER_GET_PAGE
327cycle = (uint32_t)hal_get_cycles();
328if( (DEBUG_MAPPER_GET_PAGE < cycle) && (inode != NULL) )
329{
330    printk("\n[%s] thread[%x,%x] exit for page %d of <%s> mapper / ppn %x / cycle %d\n",
331    __FUNCTION__, this->process->pid, this->trdid, page_id,
332    name, ppm_page2ppn(page_xp), cycle );
333}
334if( (DEBUG_MAPPER_GET_PAGE < cycle) && (inode == NULL) )
335{
336    printk("\n[%s] thread[%x,%x] exit for page %d of FAT mapper  / ppn %x / cycle %d\n",
337    __FUNCTION__, this->process->pid, this->trdid, page_id,
338    ppm_page2ppn(page_xp), cycle );
339}
340#endif
341
342    return page_xp;
343
344}  // end mapper_remote_get_page()
345
346////////////////////////////////////////////////////
347void mapper_remote_release_page( xptr_t   mapper_xp,
348                                 page_t * page )
349{
350    // get mapper cluster an local pointer
351    cxy_t      mapper_cxy = GET_CXY( mapper_xp );
352    mapper_t * mapper_ptr = GET_PTR( mapper_xp );
353
354    // build extended pointer on mapper lock
355    xptr_t lock_xp = XPTR( mapper_cxy , &mapper_ptr->lock );
356
357    // take mapper lock in WRITE_MODE
358    remote_rwlock_wr_acquire( lock_xp );
359
360    // remove physical page from radix tree
361    grdxt_remote_remove( XPTR( mapper_cxy , &mapper_ptr->rt ) , page->index );
362
363    // release mapper lock from WRITE_MODE
364    remote_rwlock_wr_release( lock_xp );
365
366    // release page to PPM
367    ppm_remote_free_pages( mapper_cxy , page );
368                           
369}  // end mapper_release_page()
370
371///////////////////////////////////////////////
372error_t mapper_move_user( xptr_t     mapper_xp,
373                          bool_t     to_buffer,
374                          uint32_t   file_offset,
375                          void     * buffer,
376                          uint32_t   size )
377{
378    uint32_t   page_offset;    // first byte to move to/from a mapper page
379    uint32_t   page_bytes;     // number of bytes to move to/from a mapper page
380    uint32_t   page_id;        // current mapper page index
381    uint32_t   done;           // number of moved bytes
382    xptr_t     page_xp;        // extended pointer on current mapper page descriptor
383
384#if DEBUG_MAPPER_MOVE_USER
385uint32_t      cycle      = (uint32_t)hal_get_cycles();
386thread_t    * this       = CURRENT_THREAD;
387cxy_t         mapper_cxy = GET_CXY( mapper_xp );
388mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
389vfs_inode_t * inode_ptr  = hal_remote_lpt( XPTR( mapper_cxy , &mapper_ptr->inode ) );
390xptr_t        inode_xp   = XPTR( mapper_cxy , inode_ptr );
391char          name[CONFIG_VFS_MAX_NAME_LENGTH];
392vfs_inode_get_name( inode_xp , name );
393if( DEBUG_MAPPER_MOVE_USER < cycle )
394{
395    if( to_buffer )
396    printk("\n[%s] thread[%x,%x] : mapper(%s) -> buffer(%x) / bytes %d / cycle %d\n",
397    __FUNCTION__, this->process->pid, this->trdid, name, buffer, size, cycle );
398    else
399    printk("\n[%s] thread[%x,%x] : buffer(%x) -> mapper(%s) / bytes %d / cycle %d\n",
400    __FUNCTION__, this->process->pid, this->trdid, buffer, name, size, cycle );
401}
402#endif
403
404    // compute indexes of first and last bytes in file
405    uint32_t min_byte = file_offset;
406    uint32_t max_byte = file_offset + size - 1;
407
408    // compute indexes of pages for first and last byte in mapper
409    uint32_t first = min_byte >> CONFIG_PPM_PAGE_SHIFT;
410    uint32_t last  = max_byte >> CONFIG_PPM_PAGE_SHIFT;
411
412#if (DEBUG_MAPPER_MOVE_USER & 1)
413if( DEBUG_MAPPER_MOVE_USER < cycle )
414printk("\n[%s] thread[%x,%x] : mapper(%x,%x) / first_page %d / last_page %d\n",
415__FUNCTION__, this->process->pid, this->trdid, mapper_cxy, mapper_ptr, first, last );
416#endif
417
418    done = 0;
419
420    // loop on pages in mapper
421    for( page_id = first ; page_id <= last ; page_id++ )
422    {
423        // compute page_offset
424        if( page_id == first ) page_offset = min_byte & CONFIG_PPM_PAGE_MASK;
425        else                   page_offset = 0;
426
427        // compute number of bytes in page
428        if      ( first   == last  ) page_bytes = size;
429        else if ( page_id == first ) page_bytes = CONFIG_PPM_PAGE_SIZE - page_offset;
430        else if ( page_id == last  ) page_bytes = (max_byte & CONFIG_PPM_PAGE_MASK) + 1;
431        else                         page_bytes = CONFIG_PPM_PAGE_SIZE;
432
433#if (DEBUG_MAPPER_MOVE_USER & 1)
434if( DEBUG_MAPPER_MOVE_USER < cycle )
435printk("\n[%s] thread[%x,%x] : page_id %d / page_offset %d / bytes %d\n",
436__FUNCTION__, this->process->pid, this->trdid, page_id , page_offset , page_bytes );
437#endif
438
439        // get extended pointer on page descriptor in mapper
440        page_xp = mapper_remote_get_page( mapper_xp , page_id ); 
441
442        if ( page_xp == XPTR_NULL ) return -1;
443
444        // compute extended pointer on kernel mapper
445        xptr_t     map_xp  = ppm_page2base( page_xp ) + page_offset;
446
447#if (DEBUG_MAPPER_MOVE_USER & 1)
448if( DEBUG_MAPPER_MOVE_USER < cycle )
449printk("\n[%s] thread[%x,%x] : get buffer(%x,%x) in mapper\n",
450__FUNCTION__, this->process->pid, this->trdid, GET_CXY(map_xp), GET_PTR(map_xp) );
451#endif
452        // compute pointer in user buffer
453        uint8_t * buf_ptr = (uint8_t *)buffer + done;
454
455        // move fragment
456        if( to_buffer )
457        {
458            hal_copy_to_uspace( buf_ptr , map_xp , page_bytes ); 
459
460#if DEBUG_MAPPER_MOVE_USER & 1
461if( DEBUG_MAPPER_MOVE_USER < cycle )
462printk("\n[%s] thread[%x,%x] moved %d bytes / mapper %s (%x,%x) -> user buffer(%x,%x)\n",
463__FUNCTION__, this->process->pid, this->trdid, page_bytes,
464name, GET_CXY(map_xp), GET_PTR(map_xp), local_cxy, buf_ptr );
465#endif
466
467        }
468        else
469        {
470            ppm_page_do_dirty( page_xp ); 
471            hal_copy_from_uspace( map_xp , buf_ptr , page_bytes ); 
472
473#if DEBUG_MAPPER_MOVE_USER & 1
474if( DEBUG_MAPPER_MOVE_USER < cycle )
475printk("\n[%s] thread[%x,%x] moved %d bytes / user buffer(%x,%x) -> mapper %s (%x,%x)\n",
476__FUNCTION__, this->process->pid, this->trdid, page_bytes,
477local_cxy, buf_ptr, name, GET_CXY(map_xp), GET_PTR(map_xp) );
478mapper_display_page(  mapper_xp , page_id, 128 );
479#endif
480
481        }
482
483        done += page_bytes;
484    }
485
486#if DEBUG_MAPPER_MOVE_USER
487cycle      = (uint32_t)hal_get_cycles();
488if( DEBUG_MAPPER_MOVE_USER < cycle )
489{
490    if( to_buffer )
491    printk("\n[%s] thread[%x,%x] completed mapper(%s) -> buffer(%x) / cycle %d\n",
492    __FUNCTION__, this->process->pid, this->trdid, name, buffer, cycle );
493    else
494    printk("\n[%s] thread[%x,%x] completed buffer(%x) -> mapper(%s) / cycle %d\n",
495    __FUNCTION__, this->process->pid, this->trdid, buffer, name, cycle );
496}
497#endif
498
499    return 0;
500
501}  // end mapper_move_user()
502
503////////////////////////////////////////////////
504error_t mapper_move_kernel( xptr_t    mapper_xp,
505                            bool_t    to_buffer,
506                            uint32_t  file_offset,
507                            xptr_t    buffer_xp,
508                            uint32_t  size )
509{
510    uint32_t   page_offset;    // first byte to move to/from a mapper page
511    uint32_t   page_bytes;     // number of bytes to move to/from a mapper page
512    uint32_t   page_id;        // current mapper page index
513    uint32_t   done;           // number of moved bytes
514    xptr_t     page_xp;        // extended pointer on current mapper page descriptor
515
516    uint8_t  * src_ptr;        // source buffer local pointer
517    cxy_t      src_cxy;        // source cluster
518    uint8_t  * dst_ptr;        // destination buffer local pointer
519    cxy_t      dst_cxy;        // destination cluster
520
521    // get buffer cluster and local pointer
522    cxy_t     buffer_cxy = GET_CXY( buffer_xp );
523    uint8_t * buffer_ptr = GET_PTR( buffer_xp );
524
525    // get mapper cluster
526    cxy_t     mapper_cxy = GET_CXY( mapper_xp );
527
528#if DEBUG_MAPPER_MOVE_KERNEL
529char          name[CONFIG_VFS_MAX_NAME_LENGTH];
530uint32_t      cycle  = (uint32_t)hal_get_cycles();
531thread_t    * this   = CURRENT_THREAD;
532mapper_t    * mapper = GET_PTR( mapper_xp );
533vfs_inode_t * inode  = hal_remote_lpt( XPTR( mapper_cxy , &mapper->inode ) );
534vfs_inode_get_name( XPTR( mapper_cxy , inode ) , name );
535if( DEBUG_MAPPER_MOVE_KERNEL < cycle )
536printk("\n[%s] thread[%x,%x] enter / %d bytes / offset %d / mapper <%s> / cycle %d\n",
537__FUNCTION__, this->process->pid, this->trdid, size, file_offset, name, cycle );
538#endif
539
540    // compute offsets of first and last bytes in file
541    uint32_t min_byte = file_offset;
542    uint32_t max_byte = file_offset + size -1;
543
544    // compute indexes for first and last pages in mapper
545    uint32_t first = min_byte >> CONFIG_PPM_PAGE_SHIFT;
546    uint32_t last  = max_byte >> CONFIG_PPM_PAGE_SHIFT;
547
548    // compute source and destination clusters
549    if( to_buffer )
550    {
551        dst_cxy = buffer_cxy;
552        src_cxy = mapper_cxy;
553    }
554    else
555    {
556        src_cxy = buffer_cxy;
557        dst_cxy = mapper_cxy;
558    }
559
560    done = 0;
561
562    // loop on pages in mapper
563    for( page_id = first ; page_id <= last ; page_id++ )
564    {
565        // compute page_offset
566        if( page_id == first ) page_offset = min_byte & CONFIG_PPM_PAGE_MASK;
567        else                   page_offset = 0;
568
569        // compute number of bytes to move in page
570        if      ( first == last  )   page_bytes = size;
571        else if ( page_id == first ) page_bytes = CONFIG_PPM_PAGE_SIZE - page_offset;
572        else if ( page_id == last  ) page_bytes = (max_byte & CONFIG_PPM_PAGE_MASK) + 1;
573        else                         page_bytes = CONFIG_PPM_PAGE_SIZE;
574
575        // get extended pointer on page descriptor
576        page_xp = mapper_remote_get_page( mapper_xp , page_id );
577
578        if ( page_xp == XPTR_NULL ) return -1;
579
580        // get page base address
581        xptr_t    base_xp  = ppm_page2base( page_xp );
582        uint8_t * base_ptr = (uint8_t *)GET_PTR( base_xp );
583
584        // compute source and destination pointers
585        if( to_buffer )
586        {
587            dst_ptr = buffer_ptr + done;
588            src_ptr = base_ptr + page_offset;
589        }
590        else
591        {
592            src_ptr = buffer_ptr + done;
593            dst_ptr = base_ptr + page_offset;
594
595            ppm_page_do_dirty( page_xp );
596        }
597
598#if (DEBUG_MAPPER_MOVE_KERNEL & 1)
599if( DEBUG_MAPPER_MOVE_KERNEL < cycle )
600{
601    if( to_buffer )
602    printk("\n[%s] mapper <%s> page %d => buffer(%x,%x) / %d bytes\n",
603    __FUNCTION__, name, page_id, dst_cxy, dst_ptr, page_bytes );
604    else
605    printk("\n[%s] buffer(%x,%x) => mapper <%s> page %d / %d bytes\n",
606    __FUNCTION__, src_cxy, src_ptr, name, page_id, page_bytes );
607}
608#endif
609
610        // move fragment
611        hal_remote_memcpy( XPTR( dst_cxy , dst_ptr ), XPTR( src_cxy , src_ptr ), page_bytes );
612
613        done += page_bytes;
614    }
615
616#if DEBUG_MAPPER_MOVE_KERNEL
617cycle  = (uint32_t)hal_get_cycles();
618if( DEBUG_MAPPER_MOVE_KERNEL < cycle )
619printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
620__FUNCTION__, this->process->pid, this->trdid, cycle );
621#endif
622
623    return 0;
624
625}  // end mapper_move_kernel()
626
627///////////////////////////////////////////////////
628error_t mapper_remote_get_32( xptr_t     mapper_xp,
629                              uint32_t   page_id,
630                              uint32_t   word_id,
631                              uint32_t * value )
632{
633    xptr_t     page_xp;      // extended pointer on searched page descriptor
634    xptr_t     base_xp;      // extended pointer on searched page base
635   
636    // get page containing the searched word
637    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
638
639    if( page_xp == XPTR_NULL )  return -1;
640   
641    // get page base
642    base_xp = ppm_page2base( page_xp );
643
644    // get the value from mapper
645    *value = hal_remote_l32( base_xp + (word_id<<2) ); 
646
647    return 0;
648
649}  // end mapper_remote_get_32()
650
651///////////////////////////////////////////////////
652error_t mapper_remote_set_32( xptr_t     mapper_xp,
653                              uint32_t   page_id,
654                              uint32_t   word_id,
655                              uint32_t   value )
656{
657    xptr_t     page_xp;      // extended pointer on searched page descriptor
658    xptr_t     base_xp;      // extended pointer on searched page base
659
660    // get page containing the searched word
661    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
662
663    if( page_xp == XPTR_NULL ) return -1;
664
665    // get page base
666    base_xp = ppm_page2base( page_xp );
667
668    // set value to mapper
669    hal_remote_s32( (base_xp + (word_id << 2)) , value );
670
671    // set the dirty flag in page descriptor
672    ppm_page_do_dirty( page_xp );
673
674    return 0;
675
676}  // end mapper_remote_set_32()
677
678/////////////////////////////////////////
679error_t mapper_sync( mapper_t *  mapper )
680{
681    page_t   * page;                // local pointer on current page descriptor
682    xptr_t     page_xp;             // extended pointer on current page descriptor
683    grdxt_t  * rt;                  // pointer on radix_tree descriptor
684    uint32_t   start_key;           // start page index in mapper
685    uint32_t   found_key;           // current page index in mapper
686    error_t    error;
687
688#if DEBUG_MAPPER_SYNC
689thread_t * this  = CURRENT_THREAD;
690uint32_t   cycle = (uint32_t)hal_get_cycles();
691char       name[CONFIG_VFS_MAX_NAME_LENGTH];
692vfs_inode_get_name( XPTR( local_cxy , mapper->inode ) , name );
693#endif
694
695    // get pointer on radix tree
696    rt = &mapper->rt;
697
698    // initialise loop variable
699    start_key = 0;
700
701    // scan radix-tree until last page found
702    while( 1 )
703    {
704        // get page descriptor from radix tree
705        page = (page_t *)grdxt_get_first( rt , start_key , &found_key );
706         
707        if( page == NULL ) break;
708
709assert( (page->index == found_key ), "wrong page descriptor index" );
710assert( (page->order == 0),          "mapper page order must be 0" );
711
712        // build extended pointer on page descriptor
713        page_xp = XPTR( local_cxy , page );
714
715        // synchronize page if dirty
716        if( (page->flags & PG_DIRTY) != 0 )
717        {
718
719#if DEBUG_MAPPER_SYNC
720if( cycle > DEBUG_MAPPER_SYNC )
721printk("\n[%s] thread[%x,%x] synchonise page %d of <%s> to IOC device\n",
722__FUNCTION__, this->process->pid, this->trdid, page->index, name );
723#endif
724            // copy page to file system
725            error = vfs_fs_move_page( page_xp , IOC_WRITE );
726
727            if( error )
728            {
729                printk("\n[ERROR] in %s : cannot synchonize dirty page %d\n", 
730                __FUNCTION__, page->index );
731                return -1;
732            }
733
734            // remove page from PPM dirty list
735            ppm_page_undo_dirty( page_xp ); 
736        } 
737        else
738        {
739
740#if DEBUG_MAPPER_SYNC
741if( cycle > DEBUG_MAPPER_SYNC )
742printk("\n[%s] thread[%x,%x] skip page %d for <%s>\n",
743__FUNCTION__, this->process->pid, this->trdid, page->index, name );
744#endif
745        }
746
747        // update loop variable
748        start_key = page->index + 1;
749    }  // end while
750
751    return 0;
752
753}  // end mapper_sync()
754
755//////////////////////////////////////////////////
756error_t mapper_display_page( xptr_t     mapper_xp,
757                             uint32_t   page_id,
758                             uint32_t   nbytes )
759{
760    xptr_t        page_xp;        // extended pointer on page descriptor
761    xptr_t        base_xp;        // extended pointer on page base
762    char          buffer[4096];   // local buffer
763    uint32_t    * tabi;           // pointer on uint32_t to scan buffer
764    uint32_t      line;           // line index
765    uint32_t      word;           // word index
766    cxy_t         mapper_cxy;     // mapper cluster identifier
767    mapper_t    * mapper_ptr;     // mapper local pointer
768    vfs_inode_t * inode_ptr;      // inode local pointer
769 
770    char       name[CONFIG_VFS_MAX_NAME_LENGTH];
771
772    if( nbytes > 4096)
773    {
774        printk("\n[ERROR] in %s : nbytes (%d) cannot be larger than 4096\n",
775        __FUNCTION__, nbytes );
776        return -1;
777    }
778   
779    // get extended pointer on page descriptor
780    page_xp = mapper_remote_get_page( mapper_xp , page_id );
781
782    if( page_xp == XPTR_NULL)
783    {
784        printk("\n[ERROR] in %s : cannot access page %d in mapper\n",
785        __FUNCTION__, page_id );
786        return -1;
787    }
788
789    // get cluster and local pointer
790    mapper_cxy = GET_CXY( mapper_xp );
791    mapper_ptr = GET_PTR( mapper_xp );
792
793    // get inode
794    inode_ptr = hal_remote_lpt( XPTR( mapper_cxy , &mapper_ptr->inode ) );
795
796    // get inode name
797    if( inode_ptr == NULL ) strcpy( name , "fat" );
798    else  vfs_inode_get_name( XPTR( mapper_cxy , inode_ptr ) , name );
799   
800    // get extended pointer on page base
801    base_xp = ppm_page2base( page_xp );
802   
803    // copy remote page to local buffer
804    hal_remote_memcpy( XPTR( local_cxy , buffer ) , base_xp , nbytes );
805
806    // display 8 words per line
807    tabi = (uint32_t *)buffer;
808    printk("\n***** mapper <%s> / %d bytes in page %d (%x,%x)\n",
809    name, nbytes, page_id, GET_CXY(base_xp), GET_PTR(base_xp) );
810    for( line = 0 ; line < (nbytes >> 5) ; line++ )
811    {
812        printk("%X : ", line << 5 );
813        for( word = 0 ; word < 8 ; word++ ) printk("%X ", tabi[(line<<3) + word] );
814        printk("\n");
815    }
816
817    return 0;
818
819}  // end mapper_display_page
820
821
Note: See TracBrowser for help on using the repository browser.