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

Last change on this file since 587 was 587, checked in by alain, 3 years ago

Modify the GPT (Generic Page Table) API to support remote accesses,
in order to improve page faults and COW handling.

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