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

Last change on this file since 623 was 623, checked in by alain, 5 years ago

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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