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

Last change on this file since 408 was 408, checked in by alain, 6 years ago

Fix several bugs in the fork() syscall.

File size: 33.5 KB
RevLine 
[1]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////////////////////////////////////////////////////////////////////////////////////////
[401]37// This define the masks for the TSAR MMU PTE attributes (from TSAR MMU specification)
[1]38////////////////////////////////////////////////////////////////////////////////////////
39
[401]40#define TSAR_MMU_MAPPED         0x80000000
41#define TSAR_MMU_SMALL          0x40000000
[1]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
[401]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
[1]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
[401]66#define TSAR_MMU_PTE1_ATTR_MASK            0xFFC00000
67#define TSAR_MMU_PTE1_PPN_MASK             0x0007FFFF
68
[1]69#define TSAR_MMU_IX1_FROM_VPN( vpn )       ((vpn >> 9) & 0x7FF)
70#define TSAR_MMU_IX2_FROM_VPN( vpn )       (vpn & 0x1FF)
71
[315]72#define TSAR_MMU_PTBA_FROM_PTE1( pte1 )    (pte1 & 0x0FFFFFFF)
73#define TSAR_MMU_PPN_FROM_PTE1( pte1 )     ((pte1 & 0x0007FFFF)<<9)
[1]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
[401]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
[1]128/////////////////////////////////////
129error_t hal_gpt_create( gpt_t * gpt )
130{
131        page_t   * page;
[315]132    xptr_t     page_xp;
[406]133    vpn_t      vpn;
134    error_t    error;
135    uint32_t   attr;
[1]136
[407]137gpt_dmsg("\n[DBG] %s : core[%x,%d] enter\n", 
138__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
[406]139
[1]140    // check page size
[406]141    assert( (CONFIG_PPM_PAGE_SIZE == 4096) , __FUNCTION__ ,
142    "for TSAR, the page must be 4 Kbytes\n" );
[1]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
[406]151        if( page == NULL ) 
[1]152    {
[406]153        printk("\n[ERROR] in %s : cannot allocate memory for PT1\n", __FUNCTION__ );
[1]154        return ENOMEM;
[406]155    }
[1]156
157    // initialize generic page table descriptor
[315]158    page_xp   = XPTR( local_cxy , page );
159        gpt->ptr  = GET_PTR( ppm_page2base( page_xp ) );
160        gpt->ppn  = ppm_page2ppn( page_xp );
161
[406]162    // identity map the kentry_vseg (must exist for all processes)
163    attr = GPT_MAPPED | GPT_SMALL | GPT_EXECUTABLE | GPT_CACHABLE | GPT_GLOBAL;
164    for( vpn = CONFIG_VMM_KENTRY_BASE;
165         vpn < (CONFIG_VMM_KENTRY_BASE + CONFIG_VMM_KENTRY_SIZE); vpn++ )
166    {
167
[407]168gpt_dmsg("\n[DBG] %s : identity map vpn %d\n", __FUNCTION__ , vpn );
169
[406]170        error = hal_gpt_set_pte( gpt,
171                                 vpn,
[408]172                                 attr,
173                                 (local_cxy<<20) | (vpn & 0xFFFFF) );
[406]174
175        if( error )
176        {
177            printk("\n[ERROR] in %s : cannot identity map kentry vseg\n", __FUNCTION__ );
178            return ENOMEM;
179        }
180    }
181
[407]182gpt_dmsg("\n[DBG] %s : core[%x,%d] exit\n",
183__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid );
[406]184
[1]185        return 0;
[406]186
[1]187} // end hal_gpt_create()
188
189
190///////////////////////////////////
191void hal_gpt_destroy( gpt_t * gpt )
192{
193        uint32_t     ix1;
194        uint32_t     ix2;
195        uint32_t   * pt1;
196    uint32_t     pte1;
197    ppn_t        pt2_ppn;
198    uint32_t   * pt2;
199    uint32_t     attr;
200    vpn_t        vpn;     
201        kmem_req_t   req;
202    bool_t       is_ref;
203
204    // get pointer on calling process
205    process_t  * process = CURRENT_THREAD->process;
206
207    // compute is_ref
[23]208    is_ref = ( GET_CXY( process->ref_xp ) == local_cxy );
[1]209
210    // get pointer on PT1
211    pt1 = (uint32_t *)gpt->ptr;
212
213    // scan the PT1
214        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
215        {
216        pte1 = pt1[ix1];
[401]217                if( (pte1 & TSAR_MMU_MAPPED) != 0 )  // PTE1 valid
[1]218        {
[401]219            if( (pte1 & TSAR_MMU_SMALL) == 0 )   // BIG page
[1]220            {
[391]221                if( (pte1 & TSAR_MMU_USER) != 0 ) 
[1]222                {
223                    // warning message
224                    printk("\n[WARNING] in %s : found an USER BIG page / ix1 = %d\n", 
[391]225                    __FUNCTION__ , ix1 );
[1]226
227                    // release the big physical page if reference cluster
228                    if( is_ref )
229                    {
230                        vpn = (vpn_t)(ix1 << TSAR_MMU_IX2_WIDTH);
231                        hal_gpt_reset_pte( gpt , vpn );
232                    }
233                }
234            }
[391]235            else                              // SMALL page
[1]236            {
[315]237                // get local pointer on PT2
[1]238                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
[315]239                xptr_t base_xp = ppm_ppn2base( pt2_ppn );
240                pt2 = (uint32_t *)GET_PTR( base_xp );
[1]241
242                // scan the PT2 to release all entries VALID and USER if reference cluster
243                    if( is_ref )
244                {
245                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
246                    {
247                        attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
[401]248                                if( ((attr & TSAR_MMU_MAPPED) != 0 ) && ((attr & TSAR_MMU_USER) != 0) ) 
[1]249                        {
250                            // release the physical page
251                            vpn = (vpn_t)((ix1 << TSAR_MMU_IX2_WIDTH) | ix2);
252                            hal_gpt_reset_pte( gpt , vpn );
253                        }
254                    }
255                }
256
257                // release the PT2
258                req.type = KMEM_PAGE;
[315]259                req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt2 ) ) );
[1]260                kmem_free( &req );
261            }
262        }
263        }
264
265    // release the PT1
266    req.type = KMEM_PAGE;
[315]267    req.ptr  = GET_PTR( ppm_base2page( XPTR(local_cxy , pt1 ) ) );
[1]268    kmem_free( &req );
269
270} // end hal_gpt_destroy()
271
[407]272///////////////////////////////////////////
273void hal_gpt_display( process_t * process )
[1]274{
[407]275    gpt_t    * gpt;
[1]276        uint32_t   ix1;
277        uint32_t   ix2;
278        uint32_t * pt1;
279    uint32_t   pte1;
280    ppn_t      pt2_ppn;
281    uint32_t * pt2;
282    uint32_t   pte2_attr;
283    ppn_t      pte2_ppn;
[406]284    vpn_t      vpn;
[1]285
[407]286    assert( (process != NULL) , __FUNCTION__ , "NULL process pointer\n");
[1]287
[407]288    // get pointer on gpt
289    gpt = &(process->vmm.gpt);
290
291    // get pointer on PT1
[1]292    pt1 = (uint32_t *)gpt->ptr;
293
[406]294    printk("\n***** Generic Page Table for process %x : &gpt = %x / &pt1 = %x\n\n",
[407]295    process->pid , gpt , pt1 );
[406]296
[1]297    // scan the PT1
298        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
299        {
300        pte1 = pt1[ix1];
[401]301                if( (pte1 & TSAR_MMU_MAPPED) != 0 )
[1]302        {
[401]303            if( (pte1 & TSAR_MMU_SMALL) == 0 )  // BIG page
[1]304            {
[406]305                vpn = ix1 << 9;
306                printk(" - BIG   : vpn = %x / pt1[%d] = %X\n", vpn , ix1 , pte1 );
[1]307            }
308            else                           // SMALL pages
309            {
310                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
[315]311                xptr_t base_xp = ppm_ppn2base ( pt2_ppn );
312                pt2 = (uint32_t *)GET_PTR( base_xp );
[1]313
314                // scan the PT2
315                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
316                {
317                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
318                    pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2( pt2[2 * ix2 + 1] );
[406]319
[401]320                            if( (pte2_attr & TSAR_MMU_MAPPED) != 0 )
[1]321                    {
[406]322                        vpn = (ix1 << 9) | ix2;
[408]323                        printk(" - SMALL : vpn %X / ppn %X / attr %X\n",
324                        vpn , pte2_ppn , tsar2gpt(pte2_attr) );
[1]325                    }
326                }
327            }
328        }
329        }
[407]330} // end hal_gpt_display()
[1]331
332
333///////////////////////////////////////
334error_t hal_gpt_set_pte( gpt_t   * gpt,
335                         vpn_t     vpn,
[408]336                         uint32_t  attr,     // generic GPT attributes
337                         ppn_t     ppn )
[1]338{
[406]339    uint32_t          * pt1;                 // PT1 base addres
340        uint32_t          * pte1_ptr;            // pointer on PT1 entry
[401]341        uint32_t            pte1;                // PT1 entry value
[1]342
[401]343        ppn_t               pt2_ppn;             // PPN of PT2
[406]344        uint32_t          * pt2;                 // PT2 base address
[1]345
[401]346        uint32_t            small;               // requested PTE is for a small page
[406]347    bool_t              success;             // exit condition for while loop below
[315]348
[401]349        page_t            * page;                // pointer on new physical page descriptor
350    xptr_t              page_xp;             // extended pointer on new page descriptor
[1]351
[401]352    uint32_t            ix1;                 // index in PT1
353    uint32_t            ix2;                 // index in PT2
[1]354
[401]355    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
356
[408]357gpt_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn = %x / ppn = %x / gpt_attr = %x\n", 
358__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , ppn , attr );
[406]359 
[1]360    // compute indexes in PT1 and PT2
361    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
362    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
363
364    pt1   = gpt->ptr;
[401]365        small = attr & GPT_SMALL;
[1]366
[401]367    // compute tsar_attr from generic attributes
368    tsar_attr = gpt2tsar( attr );
369
[408]370gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / &pt1 = %x / tsar_attr = %x\n", 
371__FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pt1 , tsar_attr );
[406]372
373    // get pointer on PT1[ix1]
[1]374        pte1_ptr  = &pt1[ix1];
375
[406]376    // PTE1 (big page) are only set for the kernel vsegs, in the kernel init phase.
[1]377    // There is no risk of concurrent access.
[401]378        if( small == 0 ) 
379    {
[406]380        // get current pte1 value
381        pte1 = *pte1_ptr;
382
383        assert( (pte1 == 0) , __FUNCTION__ ,
384                "try to set a big page in a mapped PT1 entry / PT1[%d] = %x\n", ix1 , pte1 );
[1]385     
386        // set the PTE1
[401]387                *pte1_ptr = (tsar_attr  & TSAR_MMU_PTE1_ATTR_MASK) | 
388                    ((ppn >> 9) & TSAR_MMU_PTE1_PPN_MASK);
[124]389                hal_fence();
[1]390                return 0;
391        }
392
393    // From this point, the requested PTE is a PTE2 (small page)
394
[406]395    // loop to access PTE1 and get pointer on PT2
396    success = false;
397    do
398    {
399        // get current pte1 value
400        pte1 = *pte1_ptr;
401       
[408]402gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / current_pte1 = %x\n", 
403__FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 );
[406]404       
405        // allocate a PT2 if PT1 entry not valid
406        if( (pte1 & TSAR_MMU_MAPPED) == 0 )             // PT1 entry not valid
407            {
408            // allocate one physical page for the PT2
409                kmem_req_t req;
410                req.type  = KMEM_PAGE;
411                req.size  = 0;                       // 1 small page
412                req.flags = AF_KERNEL | AF_ZERO;
413            page = (page_t *)kmem_alloc( &req );
414            if( page == NULL )
415            {
416                        printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
417                return ENOMEM;
418            }
[1]419
[406]420            // get the PT2 PPN
421            page_xp = XPTR( local_cxy , page );       
422            pt2_ppn = ppm_page2ppn( page_xp );
[315]423
[406]424            // try to atomicaly set the PT1 entry
425            pte1 = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | pt2_ppn;
426                    success = hal_atomic_cas( pte1_ptr , 0 , pte1 );
[1]427
[406]428            // release allocated PT2 if PT1 entry modified by another thread
429            if( success == false ) ppm_free_pages( page );
430        }
431        else                                           // PT1 entry is valid
[1]432        {
[406]433            // This valid entry must be a PTD1
434            assert( (pte1 & TSAR_MMU_SMALL) , __FUNCTION__ ,
435            "try to set a small page in a big PT1 entry / PT1[%d] = %x\n", ix1 , pte1 );
[1]436
[406]437            success = true;
[1]438        }
439
[406]440        // get PT2 base from pte1
441            pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
442            pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[1]443
[408]444gpt_dmsg("\n[DBG] %s : core[%x,%d] / vpn = %x / pte1 = %x / &pt2 = %x\n", 
445__FUNCTION__, local_cxy , CURRENT_THREAD->core->lid , vpn , pte1 , pt2 );
[406]446       
447    }
448    while (success == false);
[1]449
450    // set PTE2 in this order
451        pt2[2 * ix2 + 1] = ppn;
[124]452        hal_fence();
[401]453        pt2[2 * ix2]     = tsar_attr;
[124]454        hal_fence();
[1]455
[408]456gpt_dmsg("\n[DBG] %s : core[%x,%d] exit / vpn = %x / pte2_attr = %x / pte2_ppn = %x\n", 
457__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn , 
458pt2[2 * ix2] , pt2[2 * ix2 + 1] );
[406]459 
[1]460        return 0;
[401]461
[1]462} // end of hal_gpt_set_pte()
463
[406]464
[1]465/////////////////////////////////////
466void hal_gpt_get_pte( gpt_t    * gpt,
467                      vpn_t      vpn,
468                      uint32_t * attr,
469                      ppn_t    * ppn )
470{
471    uint32_t * pt1;
472    uint32_t   pte1;
473
474    uint32_t * pt2;
475    ppn_t      pt2_ppn;
476
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
[401]484        if( (pte1 & TSAR_MMU_MAPPED) == 0 )   // PT1 entry not present
[1]485        {
486                *attr = 0;
487                *ppn  = 0;
488        }
489
[401]490        if( (pte1 & TSAR_MMU_SMALL) == 0 )     // it's a PTE1
[1]491        {
[401]492                *attr = tsar2gpt( TSAR_MMU_ATTR_FROM_PTE1( pte1 ) );
[1]493        *ppn  = TSAR_MMU_PPN_FROM_PTE1( pte1 ) | (vpn & ((1<<TSAR_MMU_IX2_WIDTH)-1));
494        }
495    else                              // it's a PTD1
496    {
497        // compute PT2 base address
498        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
[315]499        pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[1]500
501            *ppn  = pt2[2*ix2+1] & ((1<<TSAR_MMU_PPN_WIDTH)-1);
[401]502            *attr = tsar2gpt( pt2[2*ix2] );
[1]503    }
504} // end hal_gpt_get_pte()
505
506////////////////////////////////////
507void hal_gpt_reset_pte( gpt_t * gpt,
508                        vpn_t   vpn )
509{
510    uint32_t * pt1;         // PT1 base address
511    uint32_t   pte1;        // PT1 entry value
512
513    ppn_t      pt2_ppn;     // PPN of PT2
514    uint32_t * pt2;         // PT2 base address
515
516    ppn_t      ppn;         // PPN of page to be released
517
[391]518    // get ix1 & ix2 indexes
[1]519    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
520    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
521
522    // get PTE1 value
523        pt1      = gpt->ptr;
524    pte1     = pt1[ix1];
525
[401]526        if( (pte1 & TSAR_MMU_MAPPED) == 0 )   // PT1 entry not present
[1]527        {
528                return;
529        }
530
[401]531        if( (pte1 & TSAR_MMU_SMALL) == 0 )      // it's a PTE1
[1]532        {
533        // get PPN
534        ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
535
536        // unmap the big page
537        pt1[ix1] = 0;
[124]538            hal_fence();
[1]539
540        return;
541        }
[391]542    else                                   // it's a PTD1
[1]543    {
544        // compute PT2 base address
545        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
[315]546        pt2 = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[1]547       
548        // get PPN
549            ppn = TSAR_MMU_PPN_FROM_PTE2( pt2[2*ix2+1] );
550
551        // unmap the small page
[391]552            pt2[2*ix2]   = 0;            // only attr is reset
553            hal_fence();       
[1]554
555        return;
556    }
557}  // end hal_gpt_reset_pte()
558
559//////////////////////////////////////
560error_t hal_gpt_lock_pte( gpt_t * gpt,
561                          vpn_t   vpn )
562{
563    uint32_t          * pt1;             // PT1 base address
564        volatile uint32_t * pte1_ptr;        // address of PT1 entry
565        uint32_t            pte1;            // value of PT1 entry
566
567    uint32_t          * pt2;             // PT2 base address
568        ppn_t               pt2_ppn;         // PPN of PT2 page if missing PT2
569        volatile uint32_t * pte2_ptr;        // address of PT2 entry
570
571        uint32_t            attr;
572        bool_t              atomic;
573    page_t            * page;
[315]574    xptr_t              page_xp;
[1]575
576    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
577    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
578
579    // get the PTE1 value
580    pt1       = gpt->ptr; 
581        pte1_ptr  = &pt1[ix1];
582        pte1      = *pte1_ptr;
583
584    // If present, the page must be small
[401]585        if( ((pte1 & TSAR_MMU_MAPPED) != 0) && ((pte1 & TSAR_MMU_SMALL) == 0) )
[1]586    {
587        printk("\n[ERROR] in %s : try to lock a big page / PT1[%d] = %x\n",
588               __FUNCTION__ , ix1 , pte1 );
589                return EINVAL;
590    }
591
[401]592        if( (pte1 & TSAR_MMU_MAPPED) == 0 )  // missing PT1 entry   
[1]593        {
594        // allocate one physical page for PT2
595            kmem_req_t req;
596            req.type  = KMEM_PAGE;
597            req.size  = 0;                     // 1 small page
598            req.flags = AF_KERNEL | AF_ZERO;
599            page = (page_t *)kmem_alloc( &req );
[23]600
[1]601        if( page == NULL )
602        {
603                        printk("\n[ERROR] in %s : try to set a small page but cannot allocate PT2\n",
604                      __FUNCTION__ );
605            return ENOMEM;
606        }
[23]607
[315]608        page_xp = XPTR( local_cxy , page );
609        pt2_ppn = ppm_page2ppn( page_xp );
610        pt2     = (uint32_t *)GET_PTR( ppm_page2base( page_xp ) );
[1]611
612        // try to set the PT1 entry
613                do 
614                {
615                        atomic = hal_atomic_cas( (void*)pte1_ptr , 0 , 
[401]616                                     TSAR_MMU_MAPPED | TSAR_MMU_SMALL | pt2_ppn );
[1]617                } 
618        while( (atomic == false) && (*pte1_ptr == 0) );
619
620                if( atomic == false )  // missing PT2 has been allocate by another core
621                {
622            // release the allocated page
623                        ppm_free_pages( page );
624
625            // read again the PTE1     
626                        pte1 = *pte1_ptr;
627
628            // get the PT2 base address
629                        pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
[315]630                        pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[1]631                }
632        }
633    else
634    {
635        // This valid entry must be a PTD1
[401]636        if( (pte1 & TSAR_MMU_SMALL) == 0 )
[1]637        {
638                        printk("\n[ERROR] in %s : set a small page in a big PT1 entry / PT1[%d] = %x\n",
639                    __FUNCTION__ , ix1 , pte1 );
640            return EINVAL;
641        }
642
643        // compute PPN of PT2 base
644                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
645
646        // compute pointer on PT2 base
[315]647            pt2 = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[1]648    }
649   
650    // from here we have the PT2 pointer
651   
652    // compute pointer on PTE2
653    pte2_ptr = &pt2[2 * ix2];
654
655    // try to atomically lock the PTE2 until success
656        do
657    {
[401]658        // busy waiting until TSAR_MMU_LOCK == 0
[1]659        do
660                {
661                        attr = *pte2_ptr;
662                        hal_rdbar();
663                }
[401]664        while( (attr & TSAR_MMU_LOCKED) != 0 );
[1]665
[401]666                atomic = hal_atomic_cas( (void*)pte2_ptr, attr , (attr | TSAR_MMU_LOCKED) );
[1]667        }
668    while( atomic == 0 );
669
670        return 0;
[401]671
[1]672}  // end hal_gpt_lock_pte()
673
674////////////////////////////////////////
675error_t hal_gpt_unlock_pte( gpt_t * gpt,
676                            vpn_t   vpn )
677{
678    uint32_t * pt1;             // PT1 base address
679        uint32_t   pte1;            // value of PT1 entry
680
681    uint32_t * pt2;             // PT2 base address
682        ppn_t      pt2_ppn;         // PPN of PT2 page if missing PT2
683        uint32_t * pte2_ptr;        // address of PT2 entry
684
685        uint32_t   attr;            // PTE2 attribute
686
687    // compute indexes in P1 and PT2
688    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
689    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
690
691    // get pointer on PT1 base
692    pt1  = (uint32_t*)gpt->ptr;
693
694    // get PTE1
695    pte1 = pt1[ix1];
696
697    // check PTE1 present and small page
[401]698    if( ((pte1 & TSAR_MMU_MAPPED) == 0) || ((pte1 & TSAR_MMU_SMALL) == 0) )
[1]699    {
700        printk("\n[ERROR] in %s : try to unlock a big or undefined page / PT1[%d] = %x\n",
701                 __FUNCTION__ , ix1 , pte1 );
702        return EINVAL;
703    }
704
705    // get pointer on PT2 base
706    pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
[315]707    pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[1]708 
709    // get pointer on PTE2
710        pte2_ptr = &pt2[2 * ix2];
711
712    // get PTE2_ATTR
713        attr = *pte2_ptr;
714
715    // check PTE2 present and locked
[401]716    if( ((attr & TSAR_MMU_MAPPED) == 0) || ((attr & TSAR_MMU_LOCKED) == 0) );
[1]717    {
[401]718        printk("\n[ERROR] in %s : unlock an unlocked/unmapped page / PT1[%d] = %x\n",
[1]719                 __FUNCTION__ , ix1 , pte1 );
720        return EINVAL;
721    }
722
723    // reset GPT_LOCK
[401]724        *pte2_ptr = attr & ~TSAR_MMU_LOCKED;
[1]725
726        return 0;
[401]727
[1]728}  // end hal_gpt_unlock_pte()
729
[408]730///////////////////////////////////////////
731error_t hal_gpt_pte_copy( gpt_t  * dst_gpt,
732                          xptr_t   src_gpt_xp,
733                          vpn_t    vpn,
734                          bool_t   cow,
735                          ppn_t  * ppn,
736                          bool_t * mapped )
[23]737{
738    uint32_t     ix1;       // index in PT1
739    uint32_t     ix2;       // index in PT2
[1]740
[408]741    cxy_t        src_cxy;   // SRC GPT cluster
742    gpt_t      * src_gpt;   // SRC GPT local pointer
[1]743
[408]744        uint32_t   * src_pt1;   // local pointer on SRC PT1
745        uint32_t   * dst_pt1;   // local pointer on DST PT1
746    uint32_t   * src_pt2;   // local pointer on SRC PT2
747    uint32_t   * dst_pt2;   // local pointer on DST PT2
748
[407]749        kmem_req_t   req;       // for dynamic PT2 allocation
750
751    uint32_t     src_pte1;
752    uint32_t     dst_pte1;
753
[408]754    uint32_t     src_pte2_attr;
755    uint32_t     src_pte2_ppn;
[1]756
[23]757    page_t     * page;
[315]758    xptr_t       page_xp;
[1]759
[23]760    ppn_t        src_pt2_ppn;
761    ppn_t        dst_pt2_ppn;
[1]762
[408]763gpt_dmsg("\n[DBG] %s : core[%x,%d] enter for vpn %x\n", 
764__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
[407]765
[408]766    // get remote src_gpt cluster and local pointer
767    src_cxy = GET_CXY( src_gpt_xp );
768    src_gpt = (gpt_t *)GET_PTR( src_gpt_xp );
[407]769
[408]770    // get remote src_pt1 and local dst_pt1
771    src_pt1 = (uint32_t *)hal_remote_lpt( XPTR( src_cxy , &src_gpt->ptr ) );
[23]772    dst_pt1 = (uint32_t *)dst_gpt->ptr;
[1]773
[408]774    // check src_pt1 and dst_pt1 existence
775    assert( (src_pt1 != NULL) , __FUNCTION__ , "src_pt1 does not exist\n");
776    assert( (dst_pt1 != NULL) , __FUNCTION__ , "dst_pt1 does not exist\n");
[407]777
[408]778    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
779    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
[407]780
[408]781    // get src_pte1
782    src_pte1 = hal_remote_lw( XPTR( src_cxy , &src_pt1[ix1] ) );
[407]783
[408]784    // do nothing if src_pte1 not MAPPED or not SMALL
785        if( (src_pte1 & TSAR_MMU_MAPPED) && (src_pte1 & TSAR_MMU_SMALL) )   
786    {
787        // get dst_pt1 entry
788        dst_pte1 = dst_pt1[ix1];
[407]789
[408]790        // map dst_pte1 if required
791        if( (dst_pte1 & TSAR_MMU_MAPPED) == 0 ) 
792        { 
793            // allocate one physical page for a new PT2
794                req.type  = KMEM_PAGE;
795                req.size  = 0;                     // 1 small page
796                req.flags = AF_KERNEL | AF_ZERO;
797                page = (page_t *)kmem_alloc( &req );
[407]798
[408]799            if( page == NULL )
800            {
801                        printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
802                return -1;
803            }
[407]804
[408]805            // build extended pointer on page descriptor
806            page_xp = XPTR( local_cxy , page );
[407]807
[408]808            // get PPN for this new PT2
809            dst_pt2_ppn = (ppn_t)ppm_page2ppn( page_xp );
[407]810
[408]811            // build the new dst_pte1
812            dst_pte1 = TSAR_MMU_MAPPED | TSAR_MMU_SMALL | dst_pt2_ppn;
[407]813
[408]814            // register it in DST_GPT
815            dst_pt1[ix1] = dst_pte1;
816        }
[407]817
[408]818        // get pointer on src_pt2
819        src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( src_pte1 );
820        src_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( src_pt2_ppn ) );
[407]821
[408]822        // get pointer on dst_pt2
823        dst_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( dst_pte1 );
824        dst_pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( dst_pt2_ppn ) );
[407]825
[408]826        // get attr and ppn from SRC_PT2
827        src_pte2_attr = hal_remote_lw( XPTR( src_cxy , &src_pt2[2 * ix2]     ) );
828        src_pte2_ppn  = hal_remote_lw( XPTR( src_cxy , &src_pt2[2 * ix2 + 1] ) );
[407]829
[408]830        // do nothing if src_pte2 not MAPPED
831        if( (src_pte2_attr & TSAR_MMU_MAPPED) != 0 ) 
832        {
833            // set PPN in DST PTE2
834            dst_pt2[2*ix2+1] = src_pte2_ppn;
835                       
836            // set attributes in DST PTE2         
837            if( cow && (src_pte2_attr & TSAR_MMU_WRITABLE) ) 
[407]838            {
[408]839                dst_pt2[2*ix2] = (src_pte2_attr | TSAR_MMU_COW) & (~TSAR_MMU_WRITABLE);
840            } 
841            else
842            {
843                dst_pt2[2*ix2] = src_pte2_attr;
844            }
[407]845
[408]846            // return "successfully copied"
847            *mapped = true;
848            *ppn    = src_pte2_ppn;
849       
850gpt_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn %x / copy done\n", 
851__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
[407]852
[408]853            hal_fence();
[407]854
[408]855            return 0;
856        }   // end if PTE2 mapped
857    }   // end if PTE1 mapped
858
859    // return "nothing done"
860    *mapped = false;
861    *ppn    = 0;
862   
863gpt_dmsg("\n[DBG] %s : core[%x,%d] exit for vpn %x / nothing done\n", 
864__FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , vpn );
865
[407]866    hal_fence();
867
868    return 0;
869
[408]870}  // end hal_gpt_pte_copy()
[407]871
[408]872//////////////////////////////////////////
873bool_t hal_gpt_pte_is_mapped( gpt_t * gpt,
874                              vpn_t   vpn )
875{
876    uint32_t * pt1;
877    uint32_t   pte1;
878    uint32_t   pte2_attr;
879
880    uint32_t * pt2;
881    ppn_t      pt2_ppn;
882
883    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
884    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
885
886    // get PTE1 value
887        pt1  = gpt->ptr;
888    pte1 = pt1[ix1];
889
890        if( (pte1 & TSAR_MMU_MAPPED) == 0 ) return false;
891
892        if( (pte1 & TSAR_MMU_SMALL) == 0 ) return false; 
893
894    // compute PT2 base address
895    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
896    pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
897
898    // get pte2_attr
899    pte2_attr = pt2[2*ix2];
900
901    if( (pte2_attr & TSAR_MMU_MAPPED) == 0 ) return false;
902    else                                     return true;
903
904}   // end hal_gpt_pte_is_mapped()
905
[407]906///////////////////////////////////////
907bool_t hal_gpt_pte_is_cow( gpt_t * gpt,
908                           vpn_t   vpn )
909{
910    uint32_t * pt1;
911    uint32_t   pte1;
[408]912    uint32_t   pte2_attr;
[407]913
914    uint32_t * pt2;
915    ppn_t      pt2_ppn;
916
917    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
918    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
919
920    // get PTE1 value
921        pt1  = gpt->ptr;
922    pte1 = pt1[ix1];
923
[408]924        if( (pte1 & TSAR_MMU_MAPPED) == 0 ) return false;
[407]925
[408]926        if( (pte1 & TSAR_MMU_SMALL) == 0 ) return false;
[407]927
[408]928    // compute PT2 base address
929    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
930    pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
931
932    // get pte2_attr
933    pte2_attr = pt2[2*ix2];
934
935if( (CURRENT_THREAD == 0xe0000) && (hal_time_stamp() > 5380000) )
936printk("\n@@@ %s : vpn = %X / attr = %X\n", __FUNCTION__ , vpn , tsar2gpt( pte2_attr ) );
937
938    if( (pte2_attr & TSAR_MMU_MAPPED) == 0 ) return false;
939
940    if( (pte2_attr & TSAR_MMU_COW)    == 0 ) return false;
941    else                                     return true;
942
[407]943}   // end hal_gpt_pte_is_cow()
944
[408]945/////////////////////////////////////////
946void hal_gpt_flip_cow( bool_t  set_cow,
947                       xptr_t  gpt_xp,
948                       vpn_t   vpn_base,
949                       vpn_t   vpn_size )
950{
951    cxy_t      gpt_cxy;
952    gpt_t    * gpt_ptr;
[407]953
[408]954    vpn_t      vpn;
[407]955
[408]956    uint32_t   ix1;
957    uint32_t   ix2;
[407]958
[408]959    uint32_t * pt1;
960    uint32_t   pte1;
[407]961
[408]962    uint32_t * pt2;
963    ppn_t      pt2_ppn;
[407]964
[408]965    uint32_t   old_attr;
966    uint32_t   new_attr;
[407]967
[408]968    // get GPT cluster and local pointer
969    gpt_cxy = GET_CXY( gpt_xp );
970    gpt_ptr = (gpt_t *)GET_PTR( gpt_xp );
[407]971
[408]972    // get local PT1 pointer
973    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
[407]974
[408]975    // loop on pages
976    for( vpn = vpn_base ; vpn < (vpn_base + vpn_size) ; vpn++ )
977    {
978        ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
979        ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
[407]980
[408]981        // get PTE1 value
982        pte1 = hal_remote_lw( XPTR( gpt_cxy , &pt1[ix1] ) );
[407]983
[408]984        // only MAPPED & SMALL PTEs are modified
985            if( (pte1 & TSAR_MMU_MAPPED) && (pte1 & TSAR_MMU_SMALL) )
986        {
987            // compute PT2 base address
988            pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
989            pt2     = (uint32_t*)GET_PTR( ppm_ppn2base( pt2_ppn ) );
[407]990
[408]991            assert( (GET_CXY( ppm_ppn2base( pt2_ppn ) ) == gpt_cxy ), __FUNCTION__,
992            "PT2 and PT1 must be in the same cluster\n");
993 
994            // get current PTE2 attributes
995            old_attr = hal_remote_lw( XPTR( gpt_cxy , &pt2[2*ix2] ) );
996
997            // only MAPPED PTEs are modified       
998            if( old_attr & TSAR_MMU_MAPPED ) 
[23]999            {
[408]1000                if( (set_cow != 0) && (old_attr & TSAR_MMU_WRITABLE) )
1001                { 
1002                    new_attr = (old_attr | TSAR_MMU_COW) & (~TSAR_MMU_WRITABLE);
1003                    hal_remote_sw( XPTR( gpt_cxy , &pt2[2*ix2] ) , new_attr );
[23]1004                }
[408]1005                if( (set_cow == 0) && (old_attr & TSAR_MMU_COW ) )
1006                { 
1007                    new_attr = (old_attr | TSAR_MMU_WRITABLE) & (~TSAR_MMU_COW);
1008                    hal_remote_sw( XPTR( gpt_cxy , &pt2[2*ix2] ) , new_attr );
1009                }
1010            }   // end if PTE2 mapped
1011        }   // end if PTE1 mapped
1012    }   // end loop on pages
[23]1013
[408]1014}  // end hal_gpt_flip_cow()
[315]1015
[408]1016//////////////////////////////////////////
1017void hal_gpt_update_pte( xptr_t    gpt_xp,
1018                         vpn_t     vpn,
1019                         uint32_t  attr,     // generic GPT attributes
1020                         ppn_t     ppn )
1021{
1022    uint32_t          * pt1;                 // PT1 base addres
1023        uint32_t            pte1;                // PT1 entry value
[23]1024
[408]1025        ppn_t               pt2_ppn;             // PPN of PT2
1026        uint32_t          * pt2;                 // PT2 base address
[23]1027
[408]1028    uint32_t            ix1;                 // index in PT1
1029    uint32_t            ix2;                 // index in PT2
[23]1030
[408]1031    uint32_t            tsar_attr;           // PTE attributes for TSAR MMU
[23]1032
[408]1033    // check attr argument MAPPED and SMALL
1034    if( (attr & GPT_MAPPED) == 0 )  return;
1035    if( (attr & GPT_SMALL ) == 0 )  return;
[23]1036
[408]1037    // get cluster and local pointer on remote GPT
1038    cxy_t   gpt_cxy = GET_CXY( gpt_xp );
1039    gpt_t * gpt_ptr = (gpt_t *)GET_PTR( gpt_xp );
[23]1040
[408]1041    // compute indexes in PT1 and PT2
1042    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
1043    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
[23]1044
[408]1045    // get PT1 base
1046    pt1 = (uint32_t *)hal_remote_lpt( XPTR( gpt_cxy , &gpt_ptr->ptr ) );
[23]1047
[408]1048    // compute tsar_attr from generic attributes
1049    tsar_attr = gpt2tsar( attr );
[23]1050
[408]1051    // get PTE1 value
1052    pte1 = hal_remote_lw( XPTR( gpt_cxy , &pt1[ix1] ) );
[23]1053
[408]1054    if( (pte1 & TSAR_MMU_MAPPED) == 0 ) return;
1055    if( (pte1 & TSAR_MMU_SMALL ) == 0 ) return;
1056
1057    // get PT2 base from PTE1
1058    pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
1059    pt2     = (uint32_t *)GET_PTR( ppm_ppn2base( pt2_ppn ) );
1060
1061    // reset PTE2
1062        hal_remote_sw( XPTR( gpt_cxy, &pt2[2 * ix2]     ) , 0 );
1063        hal_fence();
1064
1065    // set PTE2 in this order
1066        hal_remote_sw( XPTR( gpt_cxy, &pt2[2 * ix2 + 1] ) , ppn );
1067        hal_fence();
1068        hal_remote_sw( XPTR( gpt_cxy, &pt2[2 * ix2]     ) , tsar_attr );
1069        hal_fence();
1070
1071} // end hal_gpt_update_pte()
1072
Note: See TracBrowser for help on using the repository browser.