source: trunk/hal/tsar_mips32/core/hal_gpt.c @ 401

Last change on this file since 401 was 401, checked in by alain, 4 years ago

Few bugs in VMM

File size: 25.3 KB
Line 
1/*
2 * hal_gpt.c - implementation of the Generic Page Table API for TSAR-MIPS32
3 *
4 * Author   Alain Greiner (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_types.h>
25#include <hal_gpt.h>
26#include <hal_special.h>
27#include <printk.h>
28#include <bits.h>
29#include <process.h>
30#include <kmem.h>
31#include <thread.h>
32#include <cluster.h>
33#include <ppm.h>
34#include <page.h>
35
36////////////////////////////////////////////////////////////////////////////////////////
37// This define the masks for the TSAR MMU PTE attributes (from TSAR MMU specification)
38////////////////////////////////////////////////////////////////////////////////////////
39
40#define TSAR_MMU_MAPPED         0x80000000
41#define TSAR_MMU_SMALL          0x40000000
42#define TSAR_MMU_LOCAL          0x20000000
43#define TSAR_MMU_REMOTE         0x10000000
44#define TSAR_MMU_CACHABLE       0x08000000
45#define TSAR_MMU_WRITABLE       0x04000000
46#define TSAR_MMU_EXECUTABLE     0x02000000
47#define TSAR_MMU_USER           0x01000000
48#define TSAR_MMU_GLOBAL         0x00800000
49#define TSAR_MMU_DIRTY          0x00400000
50
51#define TSAR_MMU_COW            0x00000001       // only for small pages
52#define TSAR_MMU_SWAP           0x00000004       // only for small pages
53#define TSAR_MMU_LOCKED         0x00000008       // only for small pages
54
55////////////////////////////////////////////////////////////////////////////////////////
56//       TSAR MMU related macros  (from the TSAR MMU specification)
57// - IX1  on 11 bits
58// - IX2  on  9 bits
59// - PPN  on 28 bits
60////////////////////////////////////////////////////////////////////////////////////////
61
62#define TSAR_MMU_IX1_WIDTH                 11
63#define TSAR_MMU_IX2_WIDTH                 9
64#define TSAR_MMU_PPN_WIDTH                 28
65
66#define TSAR_MMU_PTE1_ATTR_MASK            0xFFC00000
67#define TSAR_MMU_PTE1_PPN_MASK             0x0007FFFF
68
69#define TSAR_MMU_IX1_FROM_VPN( vpn )       ((vpn >> 9) & 0x7FF)
70#define TSAR_MMU_IX2_FROM_VPN( vpn )       (vpn & 0x1FF)
71
72#define TSAR_MMU_PTBA_FROM_PTE1( pte1 )    (pte1 & 0x0FFFFFFF)
73#define TSAR_MMU_PPN_FROM_PTE1( pte1 )     ((pte1 & 0x0007FFFF)<<9)
74#define TSAR_MMU_ATTR_FROM_PTE1( pte1 )    (pte1 & 0xFFC00000)
75
76#define TSAR_MMU_PPN_FROM_PTE2( pte2 )     (pte2 & 0x0FFFFFFF)
77#define TSAR_MMU_ATTR_FROM_PTE2( pte2 )    (pte2 & 0xFFC000FF)
78
79
80///////////////////////////////////////////////////////////////////////////////////////
81// This static function translates the GPT attributes to the TSAR attributes
82///////////////////////////////////////////////////////////////////////////////////////
83static inline uint32_t gpt2tsar( uint32_t gpt_attr )
84{
85    uint32_t tsar_attr = 0;
86
87    if( gpt_attr & GPT_MAPPED     ) tsar_attr |= TSAR_MMU_MAPPED;
88    if( gpt_attr & GPT_SMALL      ) tsar_attr |= TSAR_MMU_SMALL;
89    if( gpt_attr & GPT_WRITABLE   ) tsar_attr |= TSAR_MMU_WRITABLE;
90    if( gpt_attr & GPT_EXECUTABLE ) tsar_attr |= TSAR_MMU_EXECUTABLE;
91    if( gpt_attr & GPT_CACHABLE   ) tsar_attr |= TSAR_MMU_CACHABLE; 
92    if( gpt_attr & GPT_USER       ) tsar_attr |= TSAR_MMU_USER;
93    if( gpt_attr & GPT_DIRTY      ) tsar_attr |= TSAR_MMU_DIRTY;
94    if( gpt_attr & GPT_ACCESSED   ) tsar_attr |= TSAR_MMU_LOCAL;
95    if( gpt_attr & GPT_GLOBAL     ) tsar_attr |= TSAR_MMU_GLOBAL;
96    if( gpt_attr & GPT_COW        ) tsar_attr |= TSAR_MMU_COW;
97    if( gpt_attr & GPT_SWAP       ) tsar_attr |= TSAR_MMU_SWAP;
98    if( gpt_attr & GPT_LOCKED     ) tsar_attr |= TSAR_MMU_LOCKED;
99
100    return tsar_attr;
101}
102
103///////////////////////////////////////////////////////////////////////////////////////
104// This static function translates the TSAR attributes to the GPT attributes
105///////////////////////////////////////////////////////////////////////////////////////
106static inline uint32_t tsar2gpt( uint32_t tsar_attr )
107{
108    uint32_t gpt_attr = 0;
109
110    if( tsar_attr & TSAR_MMU_MAPPED     ) gpt_attr |= GPT_MAPPED;
111    if( tsar_attr & TSAR_MMU_MAPPED     ) gpt_attr |= GPT_READABLE;
112    if( tsar_attr & TSAR_MMU_SMALL      ) gpt_attr |= GPT_SMALL;
113    if( tsar_attr & TSAR_MMU_WRITABLE   ) gpt_attr |= GPT_WRITABLE;
114    if( tsar_attr & TSAR_MMU_EXECUTABLE ) gpt_attr |= GPT_EXECUTABLE;
115    if( tsar_attr & TSAR_MMU_CACHABLE   ) gpt_attr |= GPT_CACHABLE; 
116    if( tsar_attr & TSAR_MMU_USER       ) gpt_attr |= GPT_USER;
117    if( tsar_attr & TSAR_MMU_DIRTY      ) gpt_attr |= GPT_DIRTY;
118    if( tsar_attr & TSAR_MMU_LOCAL      ) gpt_attr |= GPT_ACCESSED;
119    if( tsar_attr & TSAR_MMU_REMOTE     ) gpt_attr |= GPT_ACCESSED;
120    if( tsar_attr & TSAR_MMU_GLOBAL     ) gpt_attr |= GPT_GLOBAL;
121    if( tsar_attr & TSAR_MMU_COW        ) gpt_attr |= GPT_COW;
122    if( tsar_attr & TSAR_MMU_SWAP       ) gpt_attr |= GPT_SWAP;
123    if( tsar_attr & TSAR_MMU_LOCKED     ) gpt_attr |= GPT_LOCKED;
124
125    return gpt_attr;
126}
127
128/////////////////////////////////////
129error_t hal_gpt_create( gpt_t * gpt )
130{
131        page_t   * page;
132    xptr_t     page_xp;
133
134    // check page size
135    if( CONFIG_PPM_PAGE_SIZE != 4096 )
136    {
137        printk("\n[PANIC] in %s : For TSAR, the page must be 4 Kbytes\n", __FUNCTION__ );
138        hal_core_sleep();
139    }
140
141    // allocates 2 physical pages for PT1
142        kmem_req_t req;
143        req.type  = KMEM_PAGE;
144        req.size  = 1;                     // 2 small pages
145        req.flags = AF_KERNEL | AF_ZERO;
146        page = (page_t *)kmem_alloc( &req );
147
148        if( page == NULL )
149    {
150                printk("\n[ERROR] in %s : cannot allocate physical memory for PT1\n", __FUNCTION__ );
151        return ENOMEM;
152        }
153
154    // initialize generic page table descriptor
155    page_xp   = XPTR( local_cxy , page );
156
157        gpt->ptr  = GET_PTR( ppm_page2base( page_xp ) );
158        gpt->ppn  = ppm_page2ppn( page_xp );
159        gpt->page = GET_PTR( page_xp );
160
161        return 0;
162} // end hal_gpt_create()
163
164
165///////////////////////////////////
166void hal_gpt_destroy( gpt_t * gpt )
167{
168        uint32_t     ix1;
169        uint32_t     ix2;
170        uint32_t   * pt1;
171    uint32_t     pte1;
172    ppn_t        pt2_ppn;
173    uint32_t   * pt2;
174    uint32_t     attr;
175    vpn_t        vpn;     
176        kmem_req_t   req;
177    bool_t       is_ref;
178
179    // get pointer on calling process
180    process_t  * process = CURRENT_THREAD->process;
181
182    // compute is_ref
183    is_ref = ( GET_CXY( process->ref_xp ) == local_cxy );
184
185    // get pointer on PT1
186    pt1 = (uint32_t *)gpt->ptr;
187
188    // scan the PT1
189        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
190        {
191        pte1 = pt1[ix1];
192                if( (pte1 & TSAR_MMU_MAPPED) != 0 )  // PTE1 valid
193        {
194            if( (pte1 & TSAR_MMU_SMALL) == 0 )   // BIG page
195            {
196                if( (pte1 & TSAR_MMU_USER) != 0 ) 
197                {
198                    // warning message
199                    printk("\n[WARNING] in %s : found an USER BIG page / ix1 = %d\n", 
200                    __FUNCTION__ , ix1 );
201
202                    // release the big physical page if reference cluster
203                    if( is_ref )
204                    {
205                        vpn = (vpn_t)(ix1 << TSAR_MMU_IX2_WIDTH);
206                        hal_gpt_reset_pte( gpt , vpn );
207                    }
208                }
209            }
210            else                              // SMALL page
211            {
212                // get local pointer on PT2
213                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
214                xptr_t base_xp = ppm_ppn2base( pt2_ppn );
215                pt2 = (uint32_t *)GET_PTR( base_xp );
216
217                // scan the PT2 to release all entries VALID and USER if reference cluster
218                    if( is_ref )
219                {
220                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
221                    {
222                        attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
223                                if( ((attr & TSAR_MMU_MAPPED) != 0 ) && ((attr & TSAR_MMU_USER) != 0) ) 
224                        {
225                            // release the physical page
226                            vpn = (vpn_t)((ix1 << TSAR_MMU_IX2_WIDTH) | ix2);
227                            hal_gpt_reset_pte( gpt , vpn );
228                        }
229                    }
230                }
231
232                // release the PT2
233                req.type = KMEM_PAGE;
234                req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt2 ) ) );
235                kmem_free( &req );
236            }
237        }
238        }
239
240    // release the PT1
241    req.type = KMEM_PAGE;
242    req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt1 ) ) );
243    kmem_free( &req );
244
245} // end hal_gpt_destroy()
246
247/////////////////////////////////
248void hal_gpt_print( gpt_t * gpt )
249{
250        uint32_t   ix1;
251        uint32_t   ix2;
252        uint32_t * pt1;
253    uint32_t   pte1;
254    ppn_t      pt2_ppn;
255    uint32_t * pt2;
256    uint32_t   pte2_attr;
257    ppn_t      pte2_ppn;
258
259    printk("*** Page Table for process %x in cluster %x ***\n",
260           CURRENT_THREAD->process->pid , local_cxy );
261
262    pt1 = (uint32_t *)gpt->ptr;
263
264    // scan the PT1
265        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
266        {
267        pte1 = pt1[ix1];
268                if( (pte1 & TSAR_MMU_MAPPED) != 0 )
269        {
270            if( (pte1 & TSAR_MMU_SMALL) == 0 )  // BIG page
271            {
272                printk(" - BIG   : pt1[%d] = %x\n", ix1 , pte1 );
273            }
274            else                           // SMALL pages
275            {
276                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
277                xptr_t base_xp = ppm_ppn2base ( pt2_ppn );
278                pt2 = (uint32_t *)GET_PTR( base_xp );
279
280                // scan the PT2
281                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
282                {
283                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
284                    pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2( pt2[2 * ix2 + 1] );
285                            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )
286                    {
287                        printk(" - SMALL   : pt1[%d] = %x / pt2[%d] / pt2[%d]\n",
288                               ix1 , pt1[ix1] , 2*ix2 , pte2_attr , 2*ix2+1 , pte2_ppn );
289                    }
290                }
291            }
292        }
293        }
294} // end hal_gpt_print()
295
296
297///////////////////////////////////////
298error_t hal_gpt_set_pte( gpt_t   * gpt,
299                         vpn_t     vpn,
300                         ppn_t     ppn,
301                         uint32_t  attr )    // generic GPT attributes
302{
303    uint32_t          * pt1;                 // virtual base addres of PT1
304        volatile uint32_t * pte1_ptr;            // pointer on PT1 entry
305        uint32_t            pte1;                // PT1 entry value
306
307        ppn_t               pt2_ppn;             // PPN of PT2
308        uint32_t          * pt2;                 // virtual base address of PT2
309
310        uint32_t            small;               // requested PTE is for a small page
311        bool_t              atomic;
312
313        page_t            * page;                // pointer on new physical page descriptor
314    xptr_t              page_xp;             // extended pointer on new page descriptor
315
316    uint32_t            ix1;                 // index in PT1
317    uint32_t            ix2;                 // index in PT2
318
319    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
320
321    // compute indexes in PT1 and PT2
322    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
323    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
324
325    pt1   = gpt->ptr;
326        small = attr & GPT_SMALL;
327
328    // compute tsar_attr from generic attributes
329    tsar_attr = gpt2tsar( attr );
330
331    // get PT1 entry value
332        pte1_ptr  = &pt1[ix1];
333        pte1      = *pte1_ptr;
334
335    // Big pages (PTE1) are only set for the kernel vsegs, in the kernel init phase.
336    // There is no risk of concurrent access.
337        if( small == 0 ) 
338    {
339        if( pte1 != 0 )
340                {
341                        panic("\n[PANIC] in %s : set a big page in a mapped PT1 entry / PT1[%d] = %x\n",
342                   __FUNCTION__ , ix1 , pte1 );
343                }
344     
345        // set the PTE1
346                *pte1_ptr = (tsar_attr  & TSAR_MMU_PTE1_ATTR_MASK) | 
347                    ((ppn >> 9) & TSAR_MMU_PTE1_PPN_MASK);
348                hal_fence();
349                return 0;
350        }
351
352    // From this point, the requested PTE is a PTE2 (small page)
353
354        if( (pte1 & TSAR_MMU_MAPPED) == 0 )      // the PT1 entry is not valid
355        {
356        // allocate one physical page for the PT2
357            kmem_req_t req;
358            req.type  = KMEM_PAGE;
359            req.size  = 0;                     // 1 small page
360            req.flags = AF_KERNEL | AF_ZERO;
361            page = (page_t *)kmem_alloc( &req );
362        if( page == NULL )
363        {
364                        printk("\n[ERROR] in %s : try to set a small page but cannot allocate PT2\n",
365                    __FUNCTION__ );
366            return ENOMEM;
367        }
368
369        page_xp = XPTR( local_cxy , page );       
370        pt2_ppn = ppm_page2ppn( page_xp );
371        pt2     = (uint32_t *)GET_PTR( ppm_page2base( page_xp ) );
372
373        // try to atomicaly set a PTD1 in the PT1 entry
374                do 
375                {
376                    atomic = hal_atomic_cas( (void*)pte1, 0 , 
377                                      TSAR_MMU_MAPPED | TSAR_MMU_SMALL | pt2_ppn );
378        } 
379        while( (atomic == false) && (*pte1_ptr == 0) );
380
381            if( atomic == false ) // the mapping has been done by another thread !!!
382        {
383            // release the allocated page
384                ppm_free_pages( page );
385
386            // read PT1 entry again
387                        pte1 = *pte1_ptr;
388
389            // compute PPN of PT2 base
390                        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
391
392            // compute pointer on PT2 base
393                        pt2 = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
394                }
395        }
396        else                             // The PT1 entry is valid 
397        {
398        // This valid entry must be a PTD1
399        if( (pte1 & TSAR_MMU_SMALL) == 0 )
400        {
401                        printk("\n[ERROR] in %s : set a small page in a big PT1 entry / PT1[%d] = %x\n",
402                    __FUNCTION__ , ix1 , pte1 );
403            return EINVAL;
404        }
405
406        // compute PPN of PT2 base
407                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
408
409        // compute pointer on PT2 base
410            pt2 = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
411        }
412
413    // set PTE2 in this order
414        pt2[2 * ix2 + 1] = ppn;
415        hal_fence();
416        pt2[2 * ix2]     = tsar_attr;
417        hal_fence();
418
419        return 0;
420
421} // end of hal_gpt_set_pte()
422
423/////////////////////////////////////
424void hal_gpt_get_pte( gpt_t    * gpt,
425                      vpn_t      vpn,
426                      uint32_t * attr,
427                      ppn_t    * ppn )
428{
429    uint32_t * pt1;
430    uint32_t   pte1;
431
432    uint32_t * pt2;
433    ppn_t      pt2_ppn;
434
435    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
436    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
437
438    // get PTE1 value
439        pt1  = gpt->ptr;
440    pte1 = pt1[ix1];
441
442        if( (pte1 & TSAR_MMU_MAPPED) == 0 )   // PT1 entry not present
443        {
444                *attr = 0;
445                *ppn  = 0;
446        }
447
448        if( (pte1 & TSAR_MMU_SMALL) == 0 )     // it's a PTE1
449        {
450                *attr = tsar2gpt( TSAR_MMU_ATTR_FROM_PTE1( pte1 ) );
451        *ppn  = TSAR_MMU_PPN_FROM_PTE1( pte1 ) | (vpn & ((1<<TSAR_MMU_IX2_WIDTH)-1));
452        }
453    else                              // it's a PTD1
454    {
455        // compute PT2 base address
456        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
457        pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
458
459            *ppn  = pt2[2*ix2+1] & ((1<<TSAR_MMU_PPN_WIDTH)-1);
460            *attr = tsar2gpt( pt2[2*ix2] );
461    }
462} // end hal_gpt_get_pte()
463
464////////////////////////////////////
465void hal_gpt_reset_pte( gpt_t * gpt,
466                        vpn_t   vpn )
467{
468    uint32_t * pt1;         // PT1 base address
469    uint32_t   pte1;        // PT1 entry value
470
471    ppn_t      pt2_ppn;     // PPN of PT2
472    uint32_t * pt2;         // PT2 base address
473
474    ppn_t      ppn;         // PPN of page to be released
475
476    // get ix1 & ix2 indexes
477    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
478    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
479
480    // get PTE1 value
481        pt1      = gpt->ptr;
482    pte1     = pt1[ix1];
483
484        if( (pte1 & TSAR_MMU_MAPPED) == 0 )   // PT1 entry not present
485        {
486                return;
487        }
488
489        if( (pte1 & TSAR_MMU_SMALL) == 0 )      // it's a PTE1
490        {
491        // get PPN
492        ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
493
494        // unmap the big page
495        pt1[ix1] = 0;
496            hal_fence();
497
498        return;
499        }
500    else                                   // it's a PTD1
501    {
502        // compute PT2 base address
503        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
504        pt2 = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
505       
506        // get PPN
507            ppn = TSAR_MMU_PPN_FROM_PTE2( pt2[2*ix2+1] );
508
509        // unmap the small page
510            pt2[2*ix2]   = 0;            // only attr is reset
511            hal_fence();       
512
513        return;
514    }
515}  // end hal_gpt_reset_pte()
516
517//////////////////////////////////////
518error_t hal_gpt_lock_pte( gpt_t * gpt,
519                          vpn_t   vpn )
520{
521    uint32_t          * pt1;             // PT1 base address
522        volatile uint32_t * pte1_ptr;        // address of PT1 entry
523        uint32_t            pte1;            // value of PT1 entry
524
525    uint32_t          * pt2;             // PT2 base address
526        ppn_t               pt2_ppn;         // PPN of PT2 page if missing PT2
527        volatile uint32_t * pte2_ptr;        // address of PT2 entry
528
529        uint32_t            attr;
530        bool_t              atomic;
531    page_t            * page;
532    xptr_t              page_xp;
533
534    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
535    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
536
537    // get the PTE1 value
538    pt1       = gpt->ptr; 
539        pte1_ptr  = &pt1[ix1];
540        pte1      = *pte1_ptr;
541
542    // If present, the page must be small
543        if( ((pte1 & TSAR_MMU_MAPPED) != 0) && ((pte1 & TSAR_MMU_SMALL) == 0) )
544    {
545        printk("\n[ERROR] in %s : try to lock a big page / PT1[%d] = %x\n",
546               __FUNCTION__ , ix1 , pte1 );
547                return EINVAL;
548    }
549
550        if( (pte1 & TSAR_MMU_MAPPED) == 0 )  // missing PT1 entry   
551        {
552        // allocate one physical page for PT2
553            kmem_req_t req;
554            req.type  = KMEM_PAGE;
555            req.size  = 0;                     // 1 small page
556            req.flags = AF_KERNEL | AF_ZERO;
557            page = (page_t *)kmem_alloc( &req );
558
559        if( page == NULL )
560        {
561                        printk("\n[ERROR] in %s : try to set a small page but cannot allocate PT2\n",
562                      __FUNCTION__ );
563            return ENOMEM;
564        }
565
566        page_xp = XPTR( local_cxy , page );
567        pt2_ppn = ppm_page2ppn( page_xp );
568        pt2     = (uint32_t *)GET_PTR( ppm_page2base( page_xp ) );
569
570        // try to set the PT1 entry
571                do 
572                {
573                        atomic = hal_atomic_cas( (void*)pte1_ptr , 0 , 
574                                     TSAR_MMU_MAPPED | TSAR_MMU_SMALL | pt2_ppn );
575                } 
576        while( (atomic == false) && (*pte1_ptr == 0) );
577
578                if( atomic == false )  // missing PT2 has been allocate by another core
579                {
580            // release the allocated page
581                        ppm_free_pages( page );
582
583            // read again the PTE1     
584                        pte1 = *pte1_ptr;
585
586            // get the PT2 base address
587                        pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
588                        pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
589                }
590        }
591    else
592    {
593        // This valid entry must be a PTD1
594        if( (pte1 & TSAR_MMU_SMALL) == 0 )
595        {
596                        printk("\n[ERROR] in %s : set a small page in a big PT1 entry / PT1[%d] = %x\n",
597                    __FUNCTION__ , ix1 , pte1 );
598            return EINVAL;
599        }
600
601        // compute PPN of PT2 base
602                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
603
604        // compute pointer on PT2 base
605            pt2 = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
606    }
607   
608    // from here we have the PT2 pointer
609   
610    // compute pointer on PTE2
611    pte2_ptr = &pt2[2 * ix2];
612
613    // try to atomically lock the PTE2 until success
614        do
615    {
616        // busy waiting until TSAR_MMU_LOCK == 0
617        do
618                {
619                        attr = *pte2_ptr;
620                        hal_rdbar();
621                }
622        while( (attr & TSAR_MMU_LOCKED) != 0 );
623
624                atomic = hal_atomic_cas( (void*)pte2_ptr, attr , (attr | TSAR_MMU_LOCKED) );
625        }
626    while( atomic == 0 );
627
628        return 0;
629
630}  // end hal_gpt_lock_pte()
631
632////////////////////////////////////////
633error_t hal_gpt_unlock_pte( gpt_t * gpt,
634                            vpn_t   vpn )
635{
636    uint32_t * pt1;             // PT1 base address
637        uint32_t   pte1;            // value of PT1 entry
638
639    uint32_t * pt2;             // PT2 base address
640        ppn_t      pt2_ppn;         // PPN of PT2 page if missing PT2
641        uint32_t * pte2_ptr;        // address of PT2 entry
642
643        uint32_t   attr;            // PTE2 attribute
644
645    // compute indexes in P1 and PT2
646    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
647    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
648
649    // get pointer on PT1 base
650    pt1  = (uint32_t*)gpt->ptr;
651
652    // get PTE1
653    pte1 = pt1[ix1];
654
655    // check PTE1 present and small page
656    if( ((pte1 & TSAR_MMU_MAPPED) == 0) || ((pte1 & TSAR_MMU_SMALL) == 0) )
657    {
658        printk("\n[ERROR] in %s : try to unlock a big or undefined page / PT1[%d] = %x\n",
659                 __FUNCTION__ , ix1 , pte1 );
660        return EINVAL;
661    }
662
663    // get pointer on PT2 base
664    pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
665    pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
666 
667    // get pointer on PTE2
668        pte2_ptr = &pt2[2 * ix2];
669
670    // get PTE2_ATTR
671        attr = *pte2_ptr;
672
673    // check PTE2 present and locked
674    if( ((attr & TSAR_MMU_MAPPED) == 0) || ((attr & TSAR_MMU_LOCKED) == 0) );
675    {
676        printk("\n[ERROR] in %s : unlock an unlocked/unmapped page / PT1[%d] = %x\n",
677                 __FUNCTION__ , ix1 , pte1 );
678        return EINVAL;
679    }
680
681    // reset GPT_LOCK
682        *pte2_ptr = attr & ~TSAR_MMU_LOCKED;
683
684        return 0;
685
686}  // end hal_gpt_unlock_pte()
687
688///////////////////////////////////////
689error_t hal_gpt_copy( gpt_t  * dst_gpt,
690                      gpt_t  * src_gpt,
691                      bool_t   cow )
692{
693    uint32_t     ix1;       // index in PT1
694    uint32_t     ix2;       // index in PT2
695
696        uint32_t   * src_pt1;   // local pointer on PT1 for SRC_GPT
697        uint32_t   * dst_pt1;   // local pointer on PT1 for DST_GPT
698    uint32_t   * dst_pt2;   // local pointer on PT2 for DST_GPT
699    uint32_t   * src_pt2;   // local pointer on PT2 for SRC_GPT
700
701    uint32_t     pte1;
702    uint32_t     pte2_attr;
703    uint32_t     pte2_ppn;
704    uint32_t     pte2_writable;
705
706    page_t     * page;
707    xptr_t       page_xp;
708
709    ppn_t        src_pt2_ppn;
710    ppn_t        dst_pt2_ppn;
711
712    // get pointers on PT1 for src_gpt & dst_gpt
713    src_pt1 = (uint32_t *)src_gpt->ptr;
714    dst_pt1 = (uint32_t *)dst_gpt->ptr;
715
716    // scan the SRC_PT1
717        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
718        {
719        pte1 = src_pt1[ix1];
720                if( (pte1 & TSAR_MMU_MAPPED) != 0 )
721        {
722            if( (pte1 & TSAR_MMU_SMALL) == 0 )  // PTE1 => big kernel page
723            {
724                // big kernel pages are shared by all processes => copy it
725                dst_pt1[ix1] = pte1;
726            }
727            else                           // PTD1 => smal pages
728            {
729                // allocate one physical page for a PT2 in DST_GPT
730                    kmem_req_t req;
731                    req.type  = KMEM_PAGE;
732                    req.size  = 0;                     // 1 small page
733                    req.flags = AF_KERNEL | AF_ZERO;
734                    page = (page_t *)kmem_alloc( &req );
735
736                if( page == NULL )
737                {
738                    // TODO release all memory allocated to DST_GPT
739                                printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
740                    return ENOMEM;
741                }
742
743                // get extended pointer on page descriptor
744                page_xp = XPTR( local_cxy , page );
745
746                // get pointer on new PT2 in DST_GPT
747                xptr_t base_xp = ppm_page2base( page_xp );
748                dst_pt2 = (uint32_t *)GET_PTR( base_xp );
749
750                // set a new PTD1 in DST_GPT
751                dst_pt2_ppn  = (ppn_t)ppm_page2ppn( page_xp );
752                dst_pt1[ix1] = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | dst_pt2_ppn;
753
754                // get pointer on PT2 in SRC_GPT
755                src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( pte1 );
756                src_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
757
758                // scan the SRC_PT2
759                for( ix2 = 0 ; ix2 < 512 ; ix2++ )
760                {
761                    // get attr & ppn from PTE2
762                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( src_pt2[2 * ix2] );
763
764                            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )  // valid PTE2 in SRC_GPT
765                    {
766                        // get GPT_WRITABLE & PPN
767                        pte2_writable = pte2_attr & GPT_WRITABLE;
768                        pte2_ppn      = TSAR_MMU_PPN_FROM_PTE2(  src_pt2[2 * ix2 + 1] );
769
770                        // set a new PTE2 in DST_GPT
771                        dst_pt2[2*ix2]     = pte2_attr;
772                        dst_pt2[2*ix2 + 1] = pte2_ppn;
773                       
774                        // handle Copy-On-Write
775                        if( cow && pte2_writable )
776                        {
777                            // reset GPT_WRITABLE in both SRC_GPT and DST_GPT
778                            hal_atomic_and( &dst_pt2[2*ix2] , ~GPT_WRITABLE );
779                            hal_atomic_and( &src_pt2[2*ix2] , ~GPT_WRITABLE );
780
781                            // register PG_COW in page descriptor
782                            page = (page_t *)GET_PTR( ppm_ppn2page( pte2_ppn ) );
783                            hal_atomic_or( &page->flags , PG_COW );
784                                                        hal_atomic_add( &page->fork_nr , 1 );
785                        }
786                    }
787                }  // end loop on ix2
788            } 
789        }
790    }  // end loop ix1
791
792    hal_fence();
793
794    return 0;
795
796}  // end hal_gpt_copy()
797
Note: See TracBrowser for help on using the repository browser.