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

Last change on this file since 77 was 53, checked in by alain, 8 years ago

Compilation OK pout TSAR

File size: 7.5 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>
[1]26#include <hal_types.h>
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
41
42////////////////////////////////////////////////
43inline bool_t ppm_page_is_valid( page_t * page )
44{
45    ppm_t    * ppm  = &LOCAL_CLUSTER->ppm;
46        uint32_t   pgnr = (uint32_t)( page - ppm->pages_tbl );
47        return (pgnr <= ppm->pages_nr);
48}
49
[50]50
51
52/////////////////////////////////////////////
53inline void * ppm_page2vaddr( page_t * page )
[1]54{
55        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[50]56        return ppm->vaddr_base + ((page - ppm->pages_tbl) << CONFIG_PPM_PAGE_SHIFT);
[1]57}
58
[50]59//////////////////////////////////////////////
60inline page_t * ppm_vaddr2page( void * vaddr )
[1]61{
62        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[50]63        return ppm->pages_tbl + (vaddr - ppm->vaddr_base);
[1]64}
65
[50]66
67
[1]68//////////////////////////////////////////
69inline ppn_t ppm_page2ppn( page_t * page )
70{
71        ppm_t  * ppm  = &LOCAL_CLUSTER->ppm;
72        return (ppn_t)( page - ppm->pages_tbl );
73}
74
75/////////////////////////////////////////
76inline page_t * ppm_ppn2page( ppn_t ppn )
77{
78        ppm_t  * ppm  = &LOCAL_CLUSTER->ppm;
79        return &ppm->pages_tbl[ppn];
80}
81
[50]82
83
[1]84///////////////////////////////////////
[50]85inline void * ppm_ppn2vaddr( ppn_t ppn )
[1]86{
[50]87        ppm_t  * ppm  = &LOCAL_CLUSTER->ppm;
88        return ppm->vaddr_base + (ppn << CONFIG_PPM_PAGE_SHIFT);
[1]89}
90
[50]91//////////////////////////////////////////
92inline ppn_t ppm_vaddr2ppn( void * vaddr )
[1]93{
[50]94        ppm_t  * ppm  = &LOCAL_CLUSTER->ppm;
95        return  ( (ppm->vaddr_base - vaddr) >> CONFIG_PPM_PAGE_SHIFT );
[1]96}
97
[50]98
99
100///////////////////////////////////////////
101void ppm_free_pages_nolock( page_t * page )
[1]102{
[7]103        page_t   * buddy;            // searched buddy page descriptor
104        uint32_t   buddy_index;      // buddy page index
105        page_t   * current;          // current (merged) page descriptor
106        uint32_t   current_index;    // current (merged) page index
[50]107        uint32_t   current_order;    // current (merged) page order
[7]108
[1]109    ppm_t    * ppm         = &LOCAL_CLUSTER->ppm;
110    page_t   * pages_tbl   = ppm->pages_tbl;
111
[7]112    // update released page descriptor flags
[1]113        page_set_flag( page , PG_FREE );
114
[7]115    // search the buddy page descriptor
116    // - merge with current page descriptor if found
[18]117    // - exit to release the current page descriptor if not found
118    current       = page ,
[7]119    current_index = (uint32_t)(page - ppm->pages_tbl);
[18]120        for( current_order = page->order ;
[7]121         current_order < CONFIG_PPM_MAX_ORDER ;
122         current_order++ )
[1]123    {
[7]124                buddy_index = current_index ^ (1 << current_order);
125                buddy       = pages_tbl + buddy_index;
[18]126
[7]127                if( !page_is_flag( buddy , PG_FREE ) || (buddy->order != current_order) ) break;
[1]128
[18]129        // remove buddy from free list
[7]130                list_unlink( &buddy->list );
[1]131                ppm->free_pages_nr[current_order] --;
[18]132
[7]133        // merge buddy with current
134                buddy->order = 0;
135                current_index &= buddy_index;
[1]136        }
[18]137
[7]138    // update merged page descriptor order
139        current        = pages_tbl + current_index;
140        current->order = current_order;
[1]141
[7]142    // insert current in free list
143        list_add_first( &ppm->free_pages_root[current_order] , &current->list );
[1]144        ppm->free_pages_nr[current_order] ++;
145
146}  // end ppm_free_pages_nolock()
147
148////////////////////////////////////////////
149page_t * ppm_alloc_pages( uint32_t   order )
150{
151    uint32_t   current_order;
152        page_t   * remaining_block;
153        uint32_t   current_size;
154
155    ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
156
[7]157        assert( (order < CONFIG_PPM_MAX_ORDER) , __FUNCTION__ , "illegal order argument" );
[1]158
159        page_t * block = NULL;
160
[7]161    ppm_dmsg("\n[INFO] %s : enters / order = %d\n",
162             __FUNCTION__ , order );
163
[1]164    // take lock protecting free lists
165        spinlock_lock( &ppm->free_lock );
166
[7]167    // find a free block equal or larger to requested size
[1]168        for( current_order = order ; current_order < CONFIG_PPM_MAX_ORDER ; current_order ++ )
169        {
170                if( !list_is_empty( &ppm->free_pages_root[current_order] ) )
171                {
172                        block = LIST_FIRST( &ppm->free_pages_root[current_order] , page_t , list );
173                        list_unlink( &block->list );
174                        break;
175                }
176        }
177
178        if( block == NULL ) // return failure
179        {
180        // release lock protecting free lists
181            spinlock_unlock( &ppm->free_lock );
182
183        return NULL;
184    }
[18]185
186    // update free-lists after removing a block
187        ppm->free_pages_nr[current_order] --;
[1]188        current_size = (1 << current_order);
189
190    // split the removed block in smaller sub-blocks if required
191    // and update the free-lists accordingly
192        while( current_order > order )
193        {
194                current_order --;
195                current_size >>= 1;
[18]196
[1]197                remaining_block = block + current_size;
198                remaining_block->order = current_order;
199
200                list_add_first( &ppm->free_pages_root[current_order] , &remaining_block->list );
201                ppm->free_pages_nr[current_order] ++;
202        }
[18]203
[1]204    // update page descriptor
205    page_clear_flag( block , PG_FREE );
206        page_refcount_up( block );
207        block->order = order;
208
209    // release lock protecting free lists
210        spinlock_unlock( &ppm->free_lock );
[18]211
[7]212    ppm_dmsg("\n[INFO] %s : base = %x / order = %d\n",
213             __FUNCTION__ , (uint32_t)ppm_page2base( block ) , order );
214
[1]215        return block;
216}  // end pmm_alloc-pages()
217
218
219////////////////////////////////////
220void ppm_free_pages( page_t * page )
221{
222        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[18]223
[1]224    // get lock protecting free_pages[] array
225        spinlock_lock( &ppm->free_lock );
226
[18]227        ppm_free_pages_nolock( page );
[1]228
229    // release lock protecting free_pages[] array
230        spinlock_unlock( &ppm->free_lock );
231}
232
[7]233////////////////////////////
234void ppm_print( ppm_t * ppm,
235                char  * string )
[1]236{
237        uint32_t       order;
238        list_entry_t * iter;
239        page_t       * page;
240
241    // get lock protecting free lists
242        spinlock_lock( &ppm->free_lock );
243
[50]244        printk("\n***  PPM in cluster %x : %d pages / &pages_tbl = %x / vaddr_base = %x ***\n",
245               local_cxy , ppm->pages_nr , (intptr_t)ppm->pages_tbl , (intptr_t)ppm->vaddr_base );
[18]246
[1]247        for( order = 0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
248        {
[7]249                printk("- order = %d / free_pages = %d  [",
[1]250               order , ppm->free_pages_nr[order] );
[18]251
[1]252                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
253                {
254                        page = LIST_ELEMENT( iter , page_t , list );
255                        printk("%d," , page - ppm->pages_tbl );
256                }
[18]257
[1]258                printk("]\n", NULL );
259        }
260
261    // release lock protecting free lists
262        spinlock_unlock( &ppm->free_lock );
263
[7]264}  // end ppm_print()
[18]265
[53]266///////////////////////////////////////
267error_t ppm_assert_order( ppm_t * ppm )
[1]268{
269        uint32_t       order;
270        list_entry_t * iter;
271        page_t       * page;
[18]272
[1]273        for(order=0; order < CONFIG_PPM_MAX_ORDER; order++)
274        {
275                if( list_is_empty( &ppm->free_pages_root[order] ) ) continue;
[18]276
[1]277                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
278                {
279                        page = LIST_ELEMENT( iter , page_t , list );
280
[53]281                        if( page->order != order )  return -1; 
[1]282                }
283        }
284
[53]285    return 0;
286
[7]287}  // end ppm_assert_order()
288
Note: See TracBrowser for help on using the repository browser.