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

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

First import

File size: 9.2 KB
Line 
1/*
2 * ppm.c - Per-cluster Physical Pages Manager implementation
3 *
4 * Authors  Ghassan Almaless (2008,2009,2010,2011,2012)
5 *          Alain Greiner    (2016)
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
25#include <almos_config.h>
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////////////////////////////////////////////
51inline void * ppm_page2base( page_t * page )
52{
53        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
54        return (void*)((page - ppm->pages_tbl) << CONFIG_PPM_PAGE_SHIFT);
55}
56
57////////////////////////////////////////////
58inline page_t * ppm_base2page( void * base ) 
59{
60        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
61        return (ppm->pages_tbl + (((uint32_t)base ) >> CONFIG_PPM_PAGE_SHIFT));
62}
63
64//////////////////////////////////////////
65inline ppn_t ppm_page2ppn( page_t * page )
66{
67        ppm_t  * ppm  = &LOCAL_CLUSTER->ppm;
68        return (ppn_t)( page - ppm->pages_tbl );
69}
70
71/////////////////////////////////////////
72inline page_t * ppm_ppn2page( ppn_t ppn )
73{
74        ppm_t  * ppm  = &LOCAL_CLUSTER->ppm;
75        return &ppm->pages_tbl[ppn];
76}
77
78///////////////////////////////////////
79inline void * ppm_ppn2base( ppn_t ppn )
80{
81        return (void*)( ppn << CONFIG_PPM_PAGE_SHIFT );
82}
83
84////////////////////////////////////////
85inline ppn_t ppm_base2ppn( void * base )
86{
87        return (ppn_t)( (uint32_t)base >> CONFIG_PPM_PAGE_SHIFT );
88}
89
90//////////////////////////////////////////////////
91static void ppm_free_pages_nolock( page_t * page )
92{
93    ppm_t    * ppm         = &LOCAL_CLUSTER->ppm;
94    page_t   * pages_tbl   = ppm->pages_tbl;
95    uint32_t   page_order  = page->order;
96    uint32_t   page_index  = (uint32_t)(page - ppm->pages_tbl);
97
98        page_t   * block;
99        uint32_t   block_index;
100        uint32_t   current_order;
101
102    // update page descriptor flag
103        page_set_flag( page , PG_FREE );
104
105    // update free_lists
106        for( current_order = page_order ; current_order < CONFIG_PPM_MAX_ORDER ; current_order++ )
107    {
108                block_index = page_index ^ (1 << current_order);
109                block = pages_tbl + block_index;
110   
111                if( page_is_flag( block , PG_FREE ) || (block->order != current_order) ) break;
112
113                list_unlink( &block->list );
114                ppm->free_pages_nr[current_order] --;
115        ppm->total_free_pages -= (1 << current_order);
116   
117                block->order = 0;
118                page_index &= block_index;
119        }
120 
121        block        = pages_tbl + page_index;
122        block->order = current_order;
123
124        list_add_first( &ppm->free_pages_root[current_order] , &block->list );
125        ppm->free_pages_nr[current_order] ++;
126    ppm->total_free_pages += (1 << current_order);
127
128}  // end ppm_free_pages_nolock()
129
130/////////////////////////////////
131void ppm_init( ppm_t    * ppm,
132               uint32_t   pages_nr,        // total pages number
133               uint32_t   pages_offset )   // occupied pages
134{
135        uint32_t   i;
136
137    // set signature
138        ppm->signature = PPM_SIGNATURE;
139
140    // initialize lock protecting the free_pages[] array
141        spinlock_init( &ppm->free_lock );
142
143    // initialize free_pages[] array as empty
144        ppm->total_free_pages = 0;
145        for( i = 0 ; i < CONFIG_PPM_MAX_ORDER ; i++ )
146        {
147                list_root_init( &ppm->free_pages_root[i] );
148                ppm->free_pages_nr[i] = 0;
149        }
150 
151    // initialize dirty_list as empty
152    list_root_init( &ppm->dirty_root );
153
154    // initialize pointer on page descriptors array
155        ppm->pages_tbl = (page_t*)( pages_offset << CONFIG_PPM_PAGE_SHIFT );
156
157    // compute size of pages descriptor array rounded to an integer number of pages
158    uint32_t bytes = ARROUND_UP( pages_nr * sizeof(page_t), CONFIG_PPM_PAGE_SIZE );
159
160    // compute number of pages required to store page descriptor array
161        uint32_t pages_array  = bytes >> CONFIG_PPM_PAGE_SHIFT;
162
163    // compute total number of reserved pages (kernel code & pages_tbl[])
164        uint32_t reserved_pages = pages_offset + pages_array;
165
166        // set pages numbers
167        ppm->pages_nr      = pages_nr;
168    ppm->pages_offset  = pages_offset;
169
170    // initialises all page descriptors in pages_tbl[]
171    // TODO Peut-on accélérer ces monstrueuses boucle ? [AG]
172        for( i = 0 ; i < pages_nr ; i++ )
173    { 
174        page_init( &ppm->pages_tbl[i] );
175    } 
176
177    // set PG_RESERVED flag for reserved pages (kernel code & pages_tbl[])
178        for( i = 0 ; i < reserved_pages ; i++) 
179    {
180        page_set_flag( &ppm->pages_tbl[i] , PG_RESERVED );
181    }
182
183    // initialise the free lists by releasing all non reserved pages
184        for( i = 0 ; i < pages_nr ; i++ )
185        {
186                page_t * page = &ppm->pages_tbl[i];
187                if( page_is_flag( page , PG_RESERVED) ) ppm_free_pages_nolock( page );
188        }
189} // end ppm_init()
190
191////////////////////////////////////////////
192page_t * ppm_alloc_pages( uint32_t   order )
193{
194    uint32_t   current_order;
195        page_t   * remaining_block;
196        uint32_t   current_size;
197
198    ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
199
200        if( ppm->signature != PPM_SIGNATURE )
201    {
202        printk("\n[PANIC] in %s : PPM non initialised in cluster %x\n",
203               __FUNCTION__ , local_cxy );
204        hal_core_sleep();
205    }
206
207        if( order >= CONFIG_PPM_MAX_ORDER )
208    {
209        printk("\n[PANIC] in %s : illegal order argument in cluster %x\n",
210               __FUNCTION__ , local_cxy );
211        hal_core_sleep();
212    }
213
214        page_t * block = NULL;
215
216    // take lock protecting free lists
217        spinlock_lock( &ppm->free_lock );
218
219    // find a block larger or equal to requested size
220        for( current_order = order ; current_order < CONFIG_PPM_MAX_ORDER ; current_order ++ )
221        {
222                if( !list_is_empty( &ppm->free_pages_root[current_order] ) )
223                {
224                        block = LIST_FIRST( &ppm->free_pages_root[current_order] , page_t , list );
225                        list_unlink( &block->list );
226                        break;
227                }
228        }
229
230        if( block == NULL ) // return failure
231        {
232        // release lock protecting free lists
233            spinlock_unlock( &ppm->free_lock );
234
235        return NULL;
236    }
237 
238    // update free-lists after removing a block
239        ppm->total_free_pages -= (1 << current_order);
240        ppm->free_pages_nr[current_order] --; 
241        current_size = (1 << current_order);
242
243    // split the removed block in smaller sub-blocks if required
244    // and update the free-lists accordingly
245        while( current_order > order )
246        {
247                current_order --;
248                current_size >>= 1;
249   
250                remaining_block = block + current_size;
251                remaining_block->order = current_order;
252
253                list_add_first( &ppm->free_pages_root[current_order] , &remaining_block->list );
254                ppm->free_pages_nr[current_order] ++;
255        ppm->total_free_pages += (1 << current_order);
256        }
257 
258    // update page descriptor
259    page_clear_flag( block , PG_FREE );
260        page_refcount_up( block );
261        block->order = order;
262
263    // release lock protecting free lists
264        spinlock_unlock( &ppm->free_lock );
265 
266        return block;
267}  // end pmm_alloc-pages()
268
269
270////////////////////////////////////
271void ppm_free_pages( page_t * page )
272{
273        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
274 
275    // get lock protecting free_pages[] array
276        spinlock_lock( &ppm->free_lock );
277
278        ppm_free_pages_nolock( page ); 
279
280    // release lock protecting free_pages[] array
281        spinlock_unlock( &ppm->free_lock );
282}
283
284/////////////////////////////
285void ppm_print( ppm_t * ppm )
286{
287        uint32_t       order;
288        list_entry_t * iter;
289        page_t       * page;
290
291    // get lock protecting free lists
292        spinlock_lock( &ppm->free_lock );
293
294        printk("***  PPM state in cluster %x : pages = %d / offset = %d / free = %d ***\n",
295               local_cxy , ppm->pages_nr , ppm->pages_offset , ppm->total_free_pages ); 
296       
297        for( order = 0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
298        {
299                printk("- order = %d / free_pages = %d  [\n",
300               order , ppm->free_pages_nr[order] );
301               
302                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
303                {
304                        page = LIST_ELEMENT( iter , page_t , list );
305                        printk("%d," , page - ppm->pages_tbl );
306                }
307   
308                printk("]\n", NULL );
309        }
310
311    // release lock protecting free lists
312        spinlock_unlock( &ppm->free_lock );
313}
314
315////////////////////////////////////////
316void ppm_assert_order(struct ppm_s *ppm)
317{
318        uint32_t       order;
319        list_entry_t * iter;
320        page_t       * page;
321       
322        for(order=0; order < CONFIG_PPM_MAX_ORDER; order++)
323        {
324                if( list_is_empty( &ppm->free_pages_root[order] ) ) continue;
325               
326                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
327                {
328                        page = LIST_ELEMENT( iter , page_t , list );
329
330                        if( page->order != order )
331            {
332                    printk("%s detected inconsistency at order %d, page %d\n", 
333                           __FUNCTION__, order , page - ppm->pages_tbl );
334            }
335                }
336        }
337        return;
338}
339
Note: See TracBrowser for help on using the repository browser.