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

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

Restructure the mini_libc.

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