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

Last change on this file since 275 was 124, checked in by max@…, 7 years ago

rename hal_wbflush->hal_fence

File size: 23.0 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// the GPT masks are derived from the TSAR MMU PTE attributes
39// in the TSAR specific hal_gpt_create() function.
40////////////////////////////////////////////////////////////////////////////////////////
41
42#define TSAR_MMU_PRESENT        0x80000000
43#define TSAR_MMU_PTD1           0x40000000
44#define TSAR_MMU_LOCAL          0x20000000
45#define TSAR_MMU_REMOTE         0x10000000
46#define TSAR_MMU_CACHABLE       0x08000000
47#define TSAR_MMU_WRITABLE       0x04000000
48#define TSAR_MMU_EXECUTABLE     0x02000000
49#define TSAR_MMU_USER           0x01000000
50#define TSAR_MMU_GLOBAL         0x00800000
51#define TSAR_MMU_DIRTY          0x00400000
52
53#define TSAR_MMU_COW            0x00000001
54#define TSAR_MMU_SWAP           0x00000004
55#define TSAR_MMU_LOCKED         0x00000008
56
57////////////////////////////////////////////////////////////////////////////////////////
58//       TSAR MMU related macros  (from the TSAR MMU specification)
59// - IX1  on 11 bits
60// - IX2  on  9 bits
61// - PPN  on 28 bits
62////////////////////////////////////////////////////////////////////////////////////////
63
64#define TSAR_MMU_IX1_WIDTH                 11
65#define TSAR_MMU_IX2_WIDTH                 9
66#define TSAR_MMU_PPN_WIDTH                 28
67
68#define TSAR_MMU_IX1_FROM_VPN( vpn )       ((vpn >> 9) & 0x7FF)
69#define TSAR_MMU_IX2_FROM_VPN( vpn )       (vpn & 0x1FF)
70
71#define TSAR_MMU_PTBA_FROM_PTE1( pte1 )    (pte1 & 0xFFFFFFF)
72#define TSAR_MMU_PPN_FROM_PTE1( pte1 )     ((pte1 & 0x7FFFF)<<9)
73#define TSAR_MMU_ATTR_FROM_PTE1( pte1 )    (pte1 & 0xFFC00000)
74
75#define TSAR_MMU_PPN_FROM_PTE2( pte2 )     (pte2 & 0x0FFFFFFF)
76#define TSAR_MMU_ATTR_FROM_PTE2( pte2 )    (pte2 & 0xFFC000FF)
77
78/****************************************************************************************
79 * These global variables defines the masks for the Generic Page Table Entry attributes,
80 * and must be defined in all GPT implementation.
81 ***************************************************************************************/
82
83uint32_t  GPT_MAPPED;
84uint32_t  GPT_SMALL;
85uint32_t  GPT_READABLE;
86uint32_t  GPT_WRITABLE; 
87uint32_t  GPT_EXECUTABLE;
88uint32_t  GPT_CACHABLE; 
89uint32_t  GPT_USER; 
90uint32_t  GPT_DIRTY;
91uint32_t  GPT_ACCESSED;
92uint32_t  GPT_GLOBAL;
93uint32_t  GPT_COW;
94uint32_t  GPT_SWAP;
95uint32_t  GPT_LOCKED;
96
97/////////////////////////////////////
98error_t hal_gpt_create( gpt_t * gpt )
99{
100        page_t   * page;
101
102    // check page size
103    if( CONFIG_PPM_PAGE_SIZE != 4096 )
104    {
105        printk("\n[PANIC] in %s : For TSAR, the page must be 4 Kbytes\n", __FUNCTION__ );
106        hal_core_sleep();
107    }
108
109    // allocates 2 physical pages for PT1
110        kmem_req_t req;
111        req.type  = KMEM_PAGE;
112        req.size  = 1;                     // 2 small pages
113        req.flags = AF_KERNEL | AF_ZERO;
114        page = (page_t *)kmem_alloc( &req );
115
116        if( page == NULL )
117    {
118                printk("\n[ERROR] in %s : cannot allocate physical memory for PT1\n", __FUNCTION__ );
119        return ENOMEM;
120        }
121
122    // initialize generic page table descriptor
123        gpt->ptr  = ppm_page2vaddr( page );
124        gpt->ppn  = ppm_page2ppn( page );
125        gpt->page = page;
126
127    // initialize PTE entries attributes masks
128    GPT_MAPPED     = TSAR_MMU_PRESENT;
129    GPT_SMALL      = TSAR_MMU_PTD1;
130    GPT_READABLE   = TSAR_MMU_PRESENT;
131    GPT_WRITABLE   = TSAR_MMU_WRITABLE;
132    GPT_EXECUTABLE = TSAR_MMU_EXECUTABLE;
133    GPT_CACHABLE   = TSAR_MMU_CACHABLE;
134    GPT_USER       = TSAR_MMU_USER;     
135    GPT_DIRTY      = TSAR_MMU_DIRTY;   
136    GPT_ACCESSED   = TSAR_MMU_LOCAL | TSAR_MMU_REMOTE;
137    GPT_GLOBAL     = TSAR_MMU_GLOBAL; 
138    GPT_COW        = TSAR_MMU_COW;
139    GPT_SWAP       = TSAR_MMU_SWAP;
140    GPT_LOCKED     = TSAR_MMU_LOCKED;
141
142        return 0;
143} // end hal_gpt_create()
144
145
146///////////////////////////////////
147void hal_gpt_destroy( gpt_t * gpt )
148{
149        uint32_t     ix1;
150        uint32_t     ix2;
151        uint32_t   * pt1;
152    uint32_t     pte1;
153    ppn_t        pt2_ppn;
154    uint32_t   * pt2;
155    uint32_t     attr;
156    vpn_t        vpn;     
157        kmem_req_t   req;
158    bool_t       is_ref;
159
160    // get pointer on calling process
161    process_t  * process = CURRENT_THREAD->process;
162
163    // compute is_ref
164    is_ref = ( GET_CXY( process->ref_xp ) == local_cxy );
165
166    // get pointer on PT1
167    pt1 = (uint32_t *)gpt->ptr;
168
169    // scan the PT1
170        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
171        {
172        pte1 = pt1[ix1];
173                if( (pte1 & GPT_MAPPED) != 0 )  // PTE1 valid
174        {
175            if( (pte1 & GPT_SMALL) == 0 )   // BIG page
176            {
177                if( (pte1 & GPT_USER) != 0 ) 
178                {
179                    // warning message
180                    printk("\n[WARNING] in %s : found an USER BIG page / ix1 = %d\n", 
181                           __FUNCTION__ , ix1 );
182
183                    // release the big physical page if reference cluster
184                    if( is_ref )
185                    {
186                        vpn = (vpn_t)(ix1 << TSAR_MMU_IX2_WIDTH);
187                        hal_gpt_reset_pte( gpt , vpn );
188                    }
189                }
190            }
191            else                           // SMALL page
192            {
193                // get pointer on PT2
194                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
195                pt2 = ppm_ppn2vaddr( pt2_ppn );
196
197                // scan the PT2 to release all entries VALID and USER if reference cluster
198                    if( is_ref )
199                {
200                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
201                    {
202                        attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
203                                if( ((attr & GPT_MAPPED) != 0 ) && ((attr & GPT_USER) != 0) ) 
204                        {
205                            // release the physical page
206                            vpn = (vpn_t)((ix1 << TSAR_MMU_IX2_WIDTH) | ix2);
207                            hal_gpt_reset_pte( gpt , vpn );
208                        }
209                    }
210                }
211
212                // release the PT2
213                req.type = KMEM_PAGE;
214                req.ptr  = ppm_vaddr2page( pt2 );
215                kmem_free( &req );
216            }
217        }
218        }
219
220    // release the PT1
221    req.type = KMEM_PAGE;
222    req.ptr  = ppm_vaddr2page( pt1 );
223    kmem_free( &req );
224
225} // end hal_gpt_destroy()
226
227/////////////////////////////////
228void hal_gpt_print( gpt_t * gpt )
229{
230        uint32_t   ix1;
231        uint32_t   ix2;
232        uint32_t * pt1;
233    uint32_t   pte1;
234    ppn_t      pt2_ppn;
235    uint32_t * pt2;
236    uint32_t   pte2_attr;
237    ppn_t      pte2_ppn;
238
239    printk("*** Page Table for process %x in cluster %x ***\n",
240           CURRENT_THREAD->process->pid , local_cxy );
241
242    pt1 = (uint32_t *)gpt->ptr;
243
244    // scan the PT1
245        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
246        {
247        pte1 = pt1[ix1];
248                if( (pte1 & GPT_MAPPED) != 0 )
249        {
250            if( (pte1 & GPT_SMALL) == 0 )  // BIG page
251            {
252                printk(" - BIG   : pt1[%d] = %x\n", ix1 , pte1 );
253            }
254            else                           // SMALL pages
255            {
256                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
257                pt2 = ppm_ppn2vaddr( pt2_ppn );
258
259                // scan the PT2
260                    for( ix2 = 0 ; ix2 < 512 ; ix2++ )
261                {
262                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( pt2[2 * ix2] );
263                    pte2_ppn  = TSAR_MMU_PPN_FROM_PTE2( pt2[2 * ix2 + 1] );
264                            if( (pte2_attr & GPT_MAPPED) != 0 )
265                    {
266                        printk(" - SMALL   : pt1[%d] = %x / pt2[%d] / pt2[%d]\n",
267                               ix1 , pt1[ix1] , 2*ix2 , pte2_attr , 2*ix2+1 , pte2_ppn );
268                    }
269                }
270            }
271        }
272        }
273} // end hal_gpt_print()
274
275
276///////////////////////////////////////
277error_t hal_gpt_set_pte( gpt_t   * gpt,
278                         vpn_t     vpn,
279                         ppn_t     ppn,
280                         uint32_t  attr )
281{
282    uint32_t          * pt1;         // virtual base addres of PT1
283        volatile uint32_t * pte1_ptr;    // pointer on PT1 entry
284        uint32_t            pte1;        // PT1 entry value
285
286        ppn_t               pt2_ppn;     // PPN of PT2
287        uint32_t          * pt2;         // virtual base address of PT2
288
289        uint32_t            small;       // requested PTE is for a small page
290        bool_t              atomic;      //
291        page_t            * page;        // pointer on new physical page descriptor
292
293    uint32_t            ix1;         // index in PT1
294    uint32_t            ix2;         // index in PT2
295
296    // compute indexes in PT1 and PT2
297    ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
298    ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
299
300    pt1   = gpt->ptr;
301        small = (attr & GPT_SMALL);
302
303    // get PT1 entry value
304        pte1_ptr  = &pt1[ix1];
305        pte1      = *pte1_ptr;
306
307    // Big pages (PTE1) are only set for the kernel vsegs, in the kernel init phase.
308    // There is no risk of concurrent access.
309        if( small == 0 )
310        {
311                if( (pte1 != 0) || (attr & GPT_COW) )
312                {
313                        printk("\n[ERROR] in %s : set a big page in a mapped PT1 entry / PT1[%d] = %x\n",
314                   __FUNCTION__ , ix1 , pte1 );
315                        return EINVAL;
316                }
317     
318        // set the PTE1
319                *pte1_ptr = attr | (ppn >> 9);
320                hal_fence();
321                return 0;
322        }
323
324    // From this point, the requested PTE is a PTE2 (small page)
325
326        if( (pte1 & GPT_MAPPED) == 0 )      // the PT1 entry is not valid
327        {
328        // allocate one physical page for the PT2
329            kmem_req_t req;
330            req.type  = KMEM_PAGE;
331            req.size  = 0;                     // 1 small page
332            req.flags = AF_KERNEL | AF_ZERO;
333            page = (page_t *)kmem_alloc( &req );
334        if( page == NULL )
335        {
336                        printk("\n[ERROR] in %s : try to set a small page but cannot allocate PT2\n",
337                    __FUNCTION__ );
338            return ENOMEM;
339        }
340        pt2_ppn = ppm_page2ppn( page );
341        pt2     = ppm_page2vaddr( page );
342
343        // try to atomicaly set a PTD1 in the PT1 entry
344                do 
345                {
346                    atomic = hal_atomic_cas( (void*)pte1, 0 , 
347                                      TSAR_MMU_PRESENT | TSAR_MMU_PTD1 | pt2_ppn );
348        } 
349        while( (atomic == false) && (*pte1_ptr == 0) );
350
351            if( atomic == false ) // the mapping has been done by another thread !!!
352        {
353            // release the allocated page
354                ppm_free_pages( page );
355
356            // read PT1 entry again
357                        pte1 = *pte1_ptr;
358
359            // compute PPN of PT2 base
360                        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
361
362            // compute pointer on PT2 base
363                        pt2 = (uint32_t*)ppm_ppn2vaddr( pt2_ppn );
364                }
365        }
366        else                             // The PT1 entry is valid 
367        {
368        // This valid entry must be a PTD1
369        if( (pte1 & GPT_SMALL) == 0 )
370        {
371                        printk("\n[ERROR] in %s : set a small page in a big PT1 entry / PT1[%d] = %x\n",
372                    __FUNCTION__ , ix1 , pte1 );
373            return EINVAL;
374        }
375
376        // compute PPN of PT2 base
377                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
378
379        // compute pointer on PT2 base
380            pt2 = (uint32_t*)ppm_ppn2vaddr( pt2_ppn );
381        }
382
383    // set PTE2 in this order
384        pt2[2 * ix2 + 1] = ppn;
385        hal_fence();
386        pt2[2 * ix2]     = attr;
387        hal_fence();
388
389        return 0;
390} // end of hal_gpt_set_pte()
391
392/////////////////////////////////////
393void hal_gpt_get_pte( gpt_t    * gpt,
394                      vpn_t      vpn,
395                      uint32_t * attr,
396                      ppn_t    * ppn )
397{
398    uint32_t * pt1;
399    uint32_t   pte1;
400
401    uint32_t * pt2;
402    ppn_t      pt2_ppn;
403
404    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
405    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
406
407    // get PTE1 value
408        pt1  = gpt->ptr;
409    pte1 = pt1[ix1];
410
411        if( (pte1 & GPT_MAPPED) == 0 )   // PT1 entry not present
412        {
413                *attr = 0;
414                *ppn  = 0;
415        }
416
417        if( (pte1 & GPT_SMALL) == 0 )     // it's a PTE1
418        {
419                *attr = TSAR_MMU_ATTR_FROM_PTE1( pte1 );
420        *ppn  = TSAR_MMU_PPN_FROM_PTE1( pte1 ) | (vpn & ((1<<TSAR_MMU_IX2_WIDTH)-1));
421        }
422    else                              // it's a PTD1
423    {
424        // compute PT2 base address
425        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
426        pt2     = (uint32_t*)ppm_ppn2vaddr( pt2_ppn );
427
428            *ppn  = pt2[2*ix2+1] & ((1<<TSAR_MMU_PPN_WIDTH)-1);
429            *attr = pt2[2*ix2];
430    }
431} // end hal_gpt_get_pte()
432
433////////////////////////////////////
434void hal_gpt_reset_pte( gpt_t * gpt,
435                        vpn_t   vpn )
436{
437    uint32_t * pt1;         // PT1 base address
438    uint32_t   pte1;        // PT1 entry value
439
440    ppn_t      pt2_ppn;     // PPN of PT2
441    uint32_t * pt2;         // PT2 base address
442
443    ppn_t      ppn;         // PPN of page to be released
444
445    kmem_req_t req;
446
447    uint32_t   ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );
448    uint32_t   ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );
449
450    // get PTE1 value
451        pt1      = gpt->ptr;
452    pte1     = pt1[ix1];
453
454        if( (pte1 & GPT_MAPPED) == 0 )   // PT1 entry not present
455        {
456                return;
457        }
458
459        if( (pte1 & GPT_SMALL) == 0 )     // it's a PTE1
460        {
461        // get PPN
462        ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
463
464        // unmap the big page
465        pt1[ix1] = 0;
466            hal_fence();
467
468        // releases the big page
469        req.type  = KMEM_PAGE;
470            req.size  = 9;
471        req.ptr   = (void*)(ppn << CONFIG_PPM_PAGE_SHIFT);
472            kmem_free( &req );
473
474        return;
475        }
476    else                              // it's a PTD1
477    {
478        // compute PT2 base address
479        pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
480        pt2 = (uint32_t*)ppm_ppn2vaddr( pt2_ppn );
481       
482        // get PPN
483            ppn = TSAR_MMU_PPN_FROM_PTE2( pt2[2*ix2+1] );
484
485        // unmap the small page
486            pt2[2*ix2]   = 0;
487            hal_fence();
488            pt2[2*ix2+1] = 0;
489            hal_fence();
490
491        // releases the small page
492        req.type  = KMEM_PAGE;
493            req.size  = 0;
494        req.ptr   = (void*)(ppn << CONFIG_PPM_PAGE_SHIFT);
495            kmem_free( &req );
496
497        return;
498    }
499}  // end hal_gpt_reset_pte()
500
501//////////////////////////////////////
502error_t hal_gpt_lock_pte( gpt_t * gpt,
503                          vpn_t   vpn )
504{
505    uint32_t          * pt1;             // PT1 base address
506        volatile uint32_t * pte1_ptr;        // address of PT1 entry
507        uint32_t            pte1;            // value of PT1 entry
508
509    uint32_t          * pt2;             // PT2 base address
510        ppn_t               pt2_ppn;         // PPN of PT2 page if missing PT2
511        volatile uint32_t * pte2_ptr;        // address of PT2 entry
512
513        uint32_t            attr;
514        bool_t              atomic;
515    page_t            * page;
516
517    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
518    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
519
520    // get the PTE1 value
521    pt1       = gpt->ptr; 
522        pte1_ptr  = &pt1[ix1];
523        pte1      = *pte1_ptr;
524
525    // If present, the page must be small
526        if( ((pte1 & GPT_MAPPED) != 0) && ((pte1 & GPT_SMALL) == 0) )
527    {
528        printk("\n[ERROR] in %s : try to lock a big page / PT1[%d] = %x\n",
529               __FUNCTION__ , ix1 , pte1 );
530                return EINVAL;
531    }
532
533        if( (pte1 & GPT_MAPPED) == 0 )  // missing PT1 entry   
534        {
535        // allocate one physical page for PT2
536            kmem_req_t req;
537            req.type  = KMEM_PAGE;
538            req.size  = 0;                     // 1 small page
539            req.flags = AF_KERNEL | AF_ZERO;
540            page = (page_t *)kmem_alloc( &req );
541
542        if( page == NULL )
543        {
544                        printk("\n[ERROR] in %s : try to set a small page but cannot allocate PT2\n",
545                      __FUNCTION__ );
546            return ENOMEM;
547        }
548
549        pt2_ppn = ppm_page2ppn( page );
550        pt2     = ppm_page2vaddr( page );
551
552        // try to set the PT1 entry
553                do 
554                {
555                        atomic = hal_atomic_cas( (void*)pte1_ptr , 0 , 
556                                     TSAR_MMU_PRESENT | TSAR_MMU_PTD1 | pt2_ppn );
557                } 
558        while( (atomic == false) && (*pte1_ptr == 0) );
559
560                if( atomic == false )  // missing PT2 has been allocate by another core
561                {
562            // release the allocated page
563                        ppm_free_pages( page );
564
565            // read again the PTE1     
566                        pte1 = *pte1_ptr;
567
568            // get the PT2 base address
569                        pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
570                        pt2     = (uint32_t*)ppm_ppn2vaddr( pt2_ppn );
571                }
572        }
573    else
574    {
575        // This valid entry must be a PTD1
576        if( (pte1 & GPT_SMALL) == 0 )
577        {
578                        printk("\n[ERROR] in %s : set a small page in a big PT1 entry / PT1[%d] = %x\n",
579                    __FUNCTION__ , ix1 , pte1 );
580            return EINVAL;
581        }
582
583        // compute PPN of PT2 base
584                pt2_ppn = TSAR_MMU_PTBA_FROM_PTE1( pte1 );
585
586        // compute pointer on PT2 base
587            pt2 = (uint32_t*)ppm_ppn2vaddr( pt2_ppn );
588    }
589   
590    // from here we have the PT2 pointer
591   
592    // compute pointer on PTE2
593    pte2_ptr = &pt2[2 * ix2];
594
595    // try to atomically lock the PTE2 until success
596        do
597    {
598        // busy waiting until GPT_LOCK == 0
599        do
600                {
601                        attr = *pte2_ptr;
602                        hal_rdbar();
603                }
604        while( (attr & GPT_LOCKED) != 0 );
605
606        // try to set the GPT_LOCK wit a CAS
607                atomic = hal_atomic_cas( (void*)pte2_ptr, attr , (attr | GPT_LOCKED) );
608        }
609    while( atomic == 0 );
610
611        return 0;
612}  // end hal_gpt_lock_pte()
613
614////////////////////////////////////////
615error_t hal_gpt_unlock_pte( gpt_t * gpt,
616                            vpn_t   vpn )
617{
618    uint32_t * pt1;             // PT1 base address
619        uint32_t   pte1;            // value of PT1 entry
620
621    uint32_t * pt2;             // PT2 base address
622        ppn_t      pt2_ppn;         // PPN of PT2 page if missing PT2
623        uint32_t * pte2_ptr;        // address of PT2 entry
624
625        uint32_t   attr;            // PTE2 attribute
626
627    // compute indexes in P1 and PT2
628    uint32_t  ix1 = TSAR_MMU_IX1_FROM_VPN( vpn );    // index in PT1
629    uint32_t  ix2 = TSAR_MMU_IX2_FROM_VPN( vpn );    // index in PT2
630
631    // get pointer on PT1 base
632    pt1  = (uint32_t*)gpt->ptr;
633
634    // get PTE1
635    pte1 = pt1[ix1];
636
637    // check PTE1 present and small page
638    if( ((pte1 & GPT_MAPPED) == 0) || ((pte1 & GPT_SMALL) == 0) )
639    {
640        printk("\n[ERROR] in %s : try to unlock a big or undefined page / PT1[%d] = %x\n",
641                 __FUNCTION__ , ix1 , pte1 );
642        return EINVAL;
643    }
644
645    // get pointer on PT2 base
646    pt2_ppn = TSAR_MMU_PPN_FROM_PTE1( pte1 );
647    pt2     = ppm_ppn2vaddr( pt2_ppn );
648 
649    // get pointer on PTE2
650        pte2_ptr = &pt2[2 * ix2];
651
652    // get PTE2_ATTR
653        attr = *pte2_ptr;
654
655    // check PTE2 present and locked
656    if( ((attr & GPT_MAPPED) == 0) || ((attr & GPT_LOCKED) == 0) );
657    {
658        printk("\n[ERROR] in %s : try to unlock an undefined page / PT1[%d] = %x\n",
659                 __FUNCTION__ , ix1 , pte1 );
660        return EINVAL;
661    }
662
663    // reset GPT_LOCK
664        *pte2_ptr = attr & !GPT_LOCKED;
665
666        return 0;
667}  // end hal_gpt_unlock_pte()
668
669///////////////////////////////////////
670error_t hal_gpt_copy( gpt_t  * dst_gpt,
671                      gpt_t  * src_gpt,
672                      bool_t   cow )
673{
674    uint32_t     ix1;       // index in PT1
675    uint32_t     ix2;       // index in PT2
676
677        uint32_t   * src_pt1;   // local pointer on PT1 for SRC_GPT
678        uint32_t   * dst_pt1;   // local pointer on PT1 for DST_GPT
679    uint32_t   * dst_pt2;   // local pointer on PT2 for DST_GPT
680    uint32_t   * src_pt2;   // local pointer on PT2 for SRC_GPT
681
682    uint32_t     pte1;
683    uint32_t     pte2_attr;
684    uint32_t     pte2_ppn;
685    uint32_t     pte2_writable;
686
687    page_t     * page;
688
689    ppn_t        src_pt2_ppn;
690    ppn_t        dst_pt2_ppn;
691
692    // get pointers on PT1 for src_gpt & dst_gpt
693    src_pt1 = (uint32_t *)src_gpt->ptr;
694    dst_pt1 = (uint32_t *)dst_gpt->ptr;
695
696    // scan the SRC_PT1
697        for( ix1 = 0 ; ix1 < 2048 ; ix1++ )
698        {
699        pte1 = src_pt1[ix1];
700                if( (pte1 & GPT_MAPPED) != 0 )
701        {
702            if( (pte1 & GPT_SMALL) == 0 )  // PTE1 => big kernel page
703            {
704                // big kernel pages are shared by all processes => copy it
705                dst_pt1[ix1] = pte1;
706            }
707            else                           // PTD1 => smal pages
708            {
709                // allocate one physical page for a PT2 in DST_GPT
710                    kmem_req_t req;
711                    req.type  = KMEM_PAGE;
712                    req.size  = 0;                     // 1 small page
713                    req.flags = AF_KERNEL | AF_ZERO;
714                    page = (page_t *)kmem_alloc( &req );
715
716                if( page == NULL )
717                {
718                    // TODO release all memory allocated to DST_GPT
719                                printk("\n[ERROR] in %s : cannot allocate PT2\n", __FUNCTION__ );
720                    return ENOMEM;
721                }
722
723                // get pointer on new PT2 in DST_GPT
724                dst_pt2 = (uint32_t *)ppm_page2vaddr( page );
725
726                // set a new PTD1 in DST_GPT
727                dst_pt2_ppn  = (ppn_t)ppm_page2ppn( page );
728                dst_pt1[ix1] = TSAR_MMU_PRESENT | TSAR_MMU_PTD1 | dst_pt2_ppn;
729
730                // get pointer on PT2 in SRC_GPT
731                src_pt2_ppn = (ppn_t)TSAR_MMU_PTBA_FROM_PTE1( pte1 );
732                src_pt2     = (uint32_t *)ppm_ppn2vaddr( src_pt2_ppn );
733
734                // scan the SRC_PT2
735                for( ix2 = 0 ; ix2 < 512 ; ix2++ )
736                {
737                    // get attr & ppn from PTE2
738                    pte2_attr = TSAR_MMU_ATTR_FROM_PTE2( src_pt2[2 * ix2] );
739
740                            if( (pte2_attr & GPT_MAPPED) != 0 )  // valid PTE2 in SRC_GPT
741                    {
742                        // get GPT_WRITABLE & PPN
743                        pte2_writable = pte2_attr & GPT_WRITABLE;
744                        pte2_ppn      = TSAR_MMU_PPN_FROM_PTE2(  src_pt2[2 * ix2 + 1] );
745
746                        // set a new PTE2 in DST_GPT
747                        dst_pt2[2*ix2]     = pte2_attr;
748                        dst_pt2[2*ix2 + 1] = pte2_ppn;
749                       
750                        // handle Copy-On-Write
751                        if( cow && pte2_writable )
752                        {
753                            // reset GPT_WRITABLE in both SRC_GPT and DST_GPT
754                            hal_atomic_and( &dst_pt2[2*ix2] , ~GPT_WRITABLE );
755                            hal_atomic_and( &src_pt2[2*ix2] , ~GPT_WRITABLE );
756
757                            // register PG_COW in page descriptor
758                            page = ppm_ppn2page( pte2_ppn );
759                            hal_atomic_or( &page->flags , PG_COW );
760                                                        hal_atomic_add( &page->fork_nr , 1 );
761                        }
762                    }
763                }  // end loop on ix2
764            } 
765        }
766    }  // end loop ix1
767
768    hal_fence();
769
770    return 0;
771
772}  // end hal_gpt_copy()
773
Note: See TracBrowser for help on using the repository browser.