source: trunk/kernel/mm/ppm.c @ 561

Last change on this file since 561 was 551, checked in by nicolas.van.phan@…, 6 years ago

Make locks before IDLE Init busy

File size: 10.0 KB
RevLine 
[1]1/*
2 * ppm.c - Per-cluster Physical Pages Manager implementation
3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
[50]5 *          Alain Greiner    (2016,2017)
[1]6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH.is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
[14]25#include <kernel_config.h>
[457]26#include <hal_kernel_types.h>
[1]27#include <hal_special.h>
28#include <printk.h>
29#include <list.h>
30#include <bits.h>
31#include <page.h>
32#include <spinlock.h>
33#include <thread.h>
34#include <cluster.h>
35#include <kmem.h>
36#include <process.h>
37#include <dqdt.h>
38#include <ppm.h>
39
40////////////////////////////////////////////////
41inline bool_t ppm_page_is_valid( page_t * page )
42{
[160]43        ppm_t    * ppm  = &LOCAL_CLUSTER->ppm;
[1]44        uint32_t   pgnr = (uint32_t)( page - ppm->pages_tbl );
45        return (pgnr <= ppm->pages_nr);
46}
47
[50]48
[315]49
[50]50/////////////////////////////////////////////
[315]51inline xptr_t ppm_page2base( xptr_t page_xp )
[1]52{
[315]53        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
[1]54
[315]55    cxy_t    page_cxy = GET_CXY( page_xp );
[437]56    page_t * page_ptr = GET_PTR( page_xp );
[315]57
[406]58   void   * base_ptr = ppm->vaddr_base + 
59                       ((page_ptr - ppm->pages_tbl)<<CONFIG_PPM_PAGE_SHIFT);
60
[315]61        return XPTR( page_cxy , base_ptr );
62
63} // end ppm_page2base()
64
65/////////////////////////////////////////////
66inline xptr_t ppm_base2page( xptr_t base_xp )
[1]67{
[315]68        ppm_t  * ppm = &LOCAL_CLUSTER->ppm;
[1]69
[315]70    cxy_t    base_cxy = GET_CXY( base_xp );
[437]71    void   * base_ptr = GET_PTR( base_xp );
[315]72
73        page_t * page_ptr = ppm->pages_tbl + 
74                        ((base_ptr - ppm->vaddr_base)>>CONFIG_PPM_PAGE_SHIFT);
75
76        return XPTR( base_cxy , page_ptr );
77
78}  // end ppm_base2page()
79
80
81
[50]82///////////////////////////////////////////
[315]83inline ppn_t ppm_page2ppn( xptr_t page_xp )
84{
85        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
86
87    cxy_t    page_cxy = GET_CXY( page_xp );
[437]88    page_t * page_ptr = GET_PTR( page_xp );
[315]89
90    paddr_t  paddr    = PADDR( page_cxy , (page_ptr - ppm->pages_tbl)<<CONFIG_PPM_PAGE_SHIFT );
91
[437]92    return (ppn_t)(paddr >> CONFIG_PPM_PAGE_SHIFT);
[315]93
94}  // end hal_page2ppn()
95
96///////////////////////////////////////
97inline xptr_t ppm_ppn2page( ppn_t ppn )
98{
[437]99        ppm_t   * ppm  = &LOCAL_CLUSTER->ppm;
[315]100
[437]101    paddr_t  paddr = ((paddr_t)ppn) << CONFIG_PPM_PAGE_SHIFT;
[315]102
[437]103    cxy_t    cxy   = CXY_FROM_PADDR( paddr );
104    lpa_t    lpa   = LPA_FROM_PADDR( paddr );
[315]105
[437]106    return XPTR( cxy , &ppm->pages_tbl[lpa>>CONFIG_PPM_PAGE_SHIFT] );
[315]107
108}  // end hal_ppn2page
109
110
111
112///////////////////////////////////////
113inline xptr_t ppm_ppn2base( ppn_t ppn )
114{
[437]115        ppm_t  * ppm   = &LOCAL_CLUSTER->ppm;
[315]116   
[437]117    paddr_t  paddr = ((paddr_t)ppn) << CONFIG_PPM_PAGE_SHIFT;
[315]118
[437]119    cxy_t    cxy   = CXY_FROM_PADDR( paddr );
120    lpa_t    lpa   = LPA_FROM_PADDR( paddr );
[315]121
[437]122        return XPTR( cxy , (void *)ppm->vaddr_base + lpa );
[315]123
124}  // end ppm_ppn2base()
125
126///////////////////////////////////////////
127inline ppn_t ppm_base2ppn( xptr_t base_xp )
128{
129        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
130
131    cxy_t    base_cxy = GET_CXY( base_xp );
[437]132    void   * base_ptr = GET_PTR( base_xp );
[315]133
134    paddr_t  paddr    = PADDR( base_cxy , (base_ptr - ppm->vaddr_base) );
135
[437]136    return (ppn_t)(paddr >> CONFIG_PPM_PAGE_SHIFT);
[315]137
138}  // end ppm_base2ppn()
139
140
141
142///////////////////////////////////////////
[50]143void ppm_free_pages_nolock( page_t * page )
[1]144{
[7]145        page_t   * buddy;            // searched buddy page descriptor
146        uint32_t   buddy_index;      // buddy page index
147        page_t   * current;          // current (merged) page descriptor
148        uint32_t   current_index;    // current (merged) page index
[50]149        uint32_t   current_order;    // current (merged) page order
[7]150
[160]151        ppm_t    * ppm         = &LOCAL_CLUSTER->ppm;
152        page_t   * pages_tbl   = ppm->pages_tbl;
[1]153
[492]154        assert( !page_is_flag( page , PG_FREE ) ,
[407]155    "page already released : ppn = %x\n" , ppm_page2ppn(XPTR(local_cxy,page)) );
[177]156
[492]157        assert( !page_is_flag( page , PG_RESERVED ) ,
[407]158    "reserved page : ppn = %x\n" , ppm_page2ppn(XPTR(local_cxy,page)) );
159
[160]160        // update released page descriptor flags
[1]161        page_set_flag( page , PG_FREE );
162
[160]163        // search the buddy page descriptor
164        // - merge with current page descriptor if found
165        // - exit to release the current page descriptor if not found
166        current       = page ,
167        current_index = (uint32_t)(page - ppm->pages_tbl);
[18]168        for( current_order = page->order ;
[160]169             current_order < CONFIG_PPM_MAX_ORDER ;
170             current_order++ )
171        {
[7]172                buddy_index = current_index ^ (1 << current_order);
173                buddy       = pages_tbl + buddy_index;
[18]174
[7]175                if( !page_is_flag( buddy , PG_FREE ) || (buddy->order != current_order) ) break;
[1]176
[160]177                // remove buddy from free list
[7]178                list_unlink( &buddy->list );
[1]179                ppm->free_pages_nr[current_order] --;
[18]180
[160]181                // merge buddy with current
[7]182                buddy->order = 0;
183                current_index &= buddy_index;
[1]184        }
[18]185
[160]186        // update merged page descriptor order
[7]187        current        = pages_tbl + current_index;
188        current->order = current_order;
[1]189
[160]190        // insert current in free list
[7]191        list_add_first( &ppm->free_pages_root[current_order] , &current->list );
[1]192        ppm->free_pages_nr[current_order] ++;
193
[433]194}  // end ppm_free_pages_nolock()
195
[1]196////////////////////////////////////////////
197page_t * ppm_alloc_pages( uint32_t   order )
198{
[160]199        uint32_t   current_order;
[1]200        page_t   * remaining_block;
201        uint32_t   current_size;
[551]202
[438]203#if DEBUG_PPM_ALLOC_PAGES
[433]204uint32_t cycle = (uint32_t)hal_get_cycles();
[438]205if( DEBUG_PPM_ALLOC_PAGES < cycle )
[433]206printk("\n[DBG] in %s : thread %x enter for %d page(s) / cycle %d\n",
207__FUNCTION__ , CURRENT_THREAD , 1<<order, cycle );
208#endif
[1]209
[438]210#if(DEBUG_PPM_ALLOC_PAGES & 0x1)
211if( DEBUG_PPM_ALLOC_PAGES < cycle )
[433]212ppm_print();
213#endif
214
[160]215        ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
[1]216
[492]217        assert( (order < CONFIG_PPM_MAX_ORDER) ,
[407]218    "illegal order argument = %x\n" , order );
[1]219
[406]220        page_t * block = NULL; 
[1]221
[160]222        // take lock protecting free lists
[551]223        uint32_t       irq_state;
224        spinlock_lock_busy( &ppm->free_lock, &irq_state );
[1]225
[160]226        // find a free block equal or larger to requested size
[1]227        for( current_order = order ; current_order < CONFIG_PPM_MAX_ORDER ; current_order ++ )
228        {
229                if( !list_is_empty( &ppm->free_pages_root[current_order] ) )
230                {
231                        block = LIST_FIRST( &ppm->free_pages_root[current_order] , page_t , list );
232                        list_unlink( &block->list );
233                        break;
234                }
235        }
236
237        if( block == NULL ) // return failure
238        {
[160]239                // release lock protecting free lists
[551]240                spinlock_unlock_busy( &ppm->free_lock, irq_state );
[1]241
[438]242#if DEBUG_PPM_ALLOC_PAGES
[433]243cycle = (uint32_t)hal_get_cycles();
[438]244if( DEBUG_PPM_ALLOC_PAGES < cycle )
[433]245printk("\n[DBG] in %s : thread %x cannot allocate %d page(s) at cycle %d\n",
246__FUNCTION__ , CURRENT_THREAD , 1<<order, cycle );
247#endif
248
[160]249                return NULL;
250        }
[18]251
[160]252        // update free-lists after removing a block
[18]253        ppm->free_pages_nr[current_order] --;
[1]254        current_size = (1 << current_order);
255
[160]256        // split the removed block in smaller sub-blocks if required
257        // and update the free-lists accordingly
[1]258        while( current_order > order )
259        {
260                current_order --;
261                current_size >>= 1;
[18]262
[1]263                remaining_block = block + current_size;
264                remaining_block->order = current_order;
265
266                list_add_first( &ppm->free_pages_root[current_order] , &remaining_block->list );
267                ppm->free_pages_nr[current_order] ++;
268        }
[18]269
[160]270        // update page descriptor
271        page_clear_flag( block , PG_FREE );
[1]272        page_refcount_up( block );
273        block->order = order;
274
[160]275        // release lock protecting free lists
[551]276        spinlock_unlock_busy( &ppm->free_lock, irq_state );
[18]277
[438]278#if DEBUG_PPM_ALLOC_PAGES
[433]279cycle = (uint32_t)hal_get_cycles();
[438]280if( DEBUG_PPM_ALLOC_PAGES < cycle )
[433]281printk("\n[DBG] in %s : thread %x exit / %d page(s) allocated / ppn = %x / cycle %d\n",
282__FUNCTION__, CURRENT_THREAD, 1<<order, ppm_page2ppn(XPTR( local_cxy , block )), cycle );
283#endif
[7]284
[1]285        return block;
286
[433]287}  // end ppm_alloc_pages()
[1]288
[433]289
[1]290////////////////////////////////////
291void ppm_free_pages( page_t * page )
292{
293        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[18]294
[438]295#if DEBUG_PPM_FREE_PAGES
[433]296uint32_t cycle = (uint32_t)hal_get_cycles();
[438]297if( DEBUG_PPM_FREE_PAGES < cycle )
[433]298printk("\n[DBG] in %s : thread %x enter for %d page(s) / cycle %d\n",
299__FUNCTION__ , CURRENT_THREAD , 1<<page->order , cycle );
300#endif
301
[438]302#if(DEBUG_PPM_FREE_PAGES & 0x1)
303if( DEBUG_PPM_FREE_PAGES < cycle )
[433]304ppm_print();
305#endif
306
[160]307        // get lock protecting free_pages[] array
[1]308        spinlock_lock( &ppm->free_lock );
309
[18]310        ppm_free_pages_nolock( page );
[1]311
[160]312        // release lock protecting free_pages[] array
[1]313        spinlock_unlock( &ppm->free_lock );
[433]314
[438]315#if DEBUG_PPM_FREE_PAGES
[433]316cycle = (uint32_t)hal_get_cycles();
[438]317if( DEBUG_PPM_FREE_PAGES < cycle )
[433]318printk("\n[DBG] in %s : thread %x exit / %d page(s) released / ppn = %x / cycle %d\n",
319__FUNCTION__, CURRENT_THREAD, 1<<page->order, ppm_page2ppn(XPTR(local_cxy , page)), cycle );
320#endif
321
[1]322}
323
[433]324////////////////
[486]325void ppm_print( void )
[1]326{
327        uint32_t       order;
328        list_entry_t * iter;
329        page_t       * page;
330
[433]331    ppm_t * ppm = &LOCAL_CLUSTER->ppm;
332
[160]333        // get lock protecting free lists
[1]334        spinlock_lock( &ppm->free_lock );
335
[433]336        printk("\n***  PPM in cluster %x : %d pages ***\n", local_cxy , ppm->pages_nr );
[18]337
[1]338        for( order = 0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
339        {
[433]340                printk("- order = %d / free_pages = %d\t: ",
[160]341                       order , ppm->free_pages_nr[order] );
[18]342
[1]343                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
344                {
345                        page = LIST_ELEMENT( iter , page_t , list );
[433]346                        printk("%x," , page - ppm->pages_tbl );
[1]347                }
[18]348
[433]349                printk("\n");
[1]350        }
351
[160]352        // release lock protecting free lists
[1]353        spinlock_unlock( &ppm->free_lock );
[160]354}
[1]355
[53]356///////////////////////////////////////
357error_t ppm_assert_order( ppm_t * ppm )
[1]358{
359        uint32_t       order;
360        list_entry_t * iter;
361        page_t       * page;
[18]362
[407]363        for( order=0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
[1]364        {
365                if( list_is_empty( &ppm->free_pages_root[order] ) ) continue;
[18]366
[1]367                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
368                {
369                        page = LIST_ELEMENT( iter , page_t , list );
370
[160]371                        if( page->order != order )  return -1;
[1]372                }
373        }
374
[160]375        return 0;
376}
[53]377
Note: See TracBrowser for help on using the repository browser.