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

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

Redefine the fuctions ppm_base2page() / ppm_page2base() / ppm_page2ppn() / ppm_ppn2page() / ppm_base2ppn() / ppm_ppn2base(),
to use explicitely extended pointers.

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