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

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

1/ Fix a bug in the Multithreaded "sort" applicationr:
The pthread_create() arguments must be declared as global variables.
2/ The exit syscall can be called by any thread of a process..

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