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

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

Simplify the hal_mmu_exception() function.

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