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

Last change on this file since 420 was 420, checked in by alain, 4 years ago

Fix a bug found by Axel in hal_gpt_unlock_pte()

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