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

Last change on this file since 313 was 313, checked in by alain, 7 years ago

RSeveral modifs in the page-fault handling.

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