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

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

This version executed successfully the user "init" process on a mono-processor TSAR architecture.

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