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

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

Redefine the fuctions ppm_base2page() / ppm_page2base() / ppm_page2ppn() / ppm_ppn2page() / ppm_base2ppn() / ppm_ppn2base(),
to use explicitely extended pointers.

File size: 8.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
[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 );
56    page_t * page_ptr = (page_t *)GET_PTR( page_xp );
57
58    void   * base_ptr = ppm->vaddr_base + 
59                        ((page_ptr - ppm->pages_tbl)<<CONFIG_PPM_PAGE_SHIFT);
60 
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 );
71    void   * base_ptr = (void *)GET_PTR( base_xp );
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 );
88    page_t * page_ptr = (page_t *)GET_PTR( page_xp );
89
90    paddr_t  paddr    = PADDR( page_cxy , (page_ptr - ppm->pages_tbl)<<CONFIG_PPM_PAGE_SHIFT );
91
92    return paddr >> CONFIG_PPM_PAGE_SHIFT;
93
94}  // end hal_page2ppn()
95
96///////////////////////////////////////
97inline xptr_t ppm_ppn2page( ppn_t ppn )
98{
99        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
100
101    paddr_t  paddr    = ppn << CONFIG_PPM_PAGE_SHIFT;
102
103    cxy_t    page_cxy = CXY_FROM_PADDR( paddr );
104    lpa_t    page_lpa = LPA_FROM_PADDR( paddr );
105
106    return XPTR( page_cxy , &ppm->pages_tbl[page_lpa>>CONFIG_PPM_PAGE_SHIFT] );
107
108}  // end hal_ppn2page
109
110
111
112///////////////////////////////////////
113inline xptr_t ppm_ppn2base( ppn_t ppn )
114{
115        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
116   
117    paddr_t  paddr    = ppn << CONFIG_PPM_PAGE_SHIFT;
118
119    cxy_t    page_cxy = CXY_FROM_PADDR( paddr );
120    lpa_t    page_lpa = LPA_FROM_PADDR( paddr );
121
122    void   * base_ptr = (void *)ppm->vaddr_base + (page_lpa & ~CONFIG_PPM_PAGE_SHIFT);
123 
124        return XPTR( page_cxy , base_ptr );
125
126}  // end ppm_ppn2base()
127
128///////////////////////////////////////////
129inline ppn_t ppm_base2ppn( xptr_t base_xp )
130{
131        ppm_t  * ppm      = &LOCAL_CLUSTER->ppm;
132
133    cxy_t    base_cxy = GET_CXY( base_xp );
134    void   * base_ptr = (void *)GET_PTR( base_xp );
135
136    paddr_t  paddr    = PADDR( base_cxy , (base_ptr - ppm->vaddr_base) );
137
138    return paddr >> CONFIG_PPM_PAGE_SHIFT;
139
140}  // end ppm_base2ppn()
141
142
143
144///////////////////////////////////////////
[50]145void ppm_free_pages_nolock( page_t * page )
[1]146{
[7]147        page_t   * buddy;            // searched buddy page descriptor
148        uint32_t   buddy_index;      // buddy page index
149        page_t   * current;          // current (merged) page descriptor
150        uint32_t   current_index;    // current (merged) page index
[50]151        uint32_t   current_order;    // current (merged) page order
[7]152
[160]153        ppm_t    * ppm         = &LOCAL_CLUSTER->ppm;
154        page_t   * pages_tbl   = ppm->pages_tbl;
[1]155
[177]156        assert( !page_is_flag( page , PG_FREE ) , __FUNCTION__ , "page already freed" );
157        assert( !page_is_flag( page , PG_RESERVED ) , __FUNCTION__ , "freeing reserved page" );
158
[160]159        // update released page descriptor flags
[1]160        page_set_flag( page , PG_FREE );
161
[160]162        // search the buddy page descriptor
163        // - merge with current page descriptor if found
164        // - exit to release the current page descriptor if not found
165        current       = page ,
166        current_index = (uint32_t)(page - ppm->pages_tbl);
[18]167        for( current_order = page->order ;
[160]168             current_order < CONFIG_PPM_MAX_ORDER ;
169             current_order++ )
170        {
[7]171                buddy_index = current_index ^ (1 << current_order);
172                buddy       = pages_tbl + buddy_index;
[18]173
[7]174                if( !page_is_flag( buddy , PG_FREE ) || (buddy->order != current_order) ) break;
[1]175
[160]176                // remove buddy from free list
[7]177                list_unlink( &buddy->list );
[1]178                ppm->free_pages_nr[current_order] --;
[18]179
[160]180                // merge buddy with current
[7]181                buddy->order = 0;
182                current_index &= buddy_index;
[1]183        }
[18]184
[160]185        // update merged page descriptor order
[7]186        current        = pages_tbl + current_index;
187        current->order = current_order;
[1]188
[160]189        // insert current in free list
[7]190        list_add_first( &ppm->free_pages_root[current_order] , &current->list );
[1]191        ppm->free_pages_nr[current_order] ++;
[160]192}
[1]193
194////////////////////////////////////////////
195page_t * ppm_alloc_pages( uint32_t   order )
196{
[160]197        uint32_t   current_order;
[1]198        page_t   * remaining_block;
199        uint32_t   current_size;
200
[160]201        ppm_t    * ppm = &LOCAL_CLUSTER->ppm;
[1]202
[7]203        assert( (order < CONFIG_PPM_MAX_ORDER) , __FUNCTION__ , "illegal order argument" );
[1]204
205        page_t * block = NULL;
206
[160]207        ppm_dmsg("\n[INFO] %s : enters / order = %d\n",
208                 __FUNCTION__ , order );
[7]209
[160]210        // take lock protecting free lists
[1]211        spinlock_lock( &ppm->free_lock );
212
[160]213        // find a free block equal or larger to requested size
[1]214        for( current_order = order ; current_order < CONFIG_PPM_MAX_ORDER ; current_order ++ )
215        {
216                if( !list_is_empty( &ppm->free_pages_root[current_order] ) )
217                {
218                        block = LIST_FIRST( &ppm->free_pages_root[current_order] , page_t , list );
219                        list_unlink( &block->list );
220                        break;
221                }
222        }
223
224        if( block == NULL ) // return failure
225        {
[160]226                // release lock protecting free lists
227                spinlock_unlock( &ppm->free_lock );
[1]228
[160]229                return NULL;
230        }
[18]231
[160]232        // update free-lists after removing a block
[18]233        ppm->free_pages_nr[current_order] --;
[1]234        current_size = (1 << current_order);
235
[160]236        // split the removed block in smaller sub-blocks if required
237        // and update the free-lists accordingly
[1]238        while( current_order > order )
239        {
240                current_order --;
241                current_size >>= 1;
[18]242
[1]243                remaining_block = block + current_size;
244                remaining_block->order = current_order;
245
246                list_add_first( &ppm->free_pages_root[current_order] , &remaining_block->list );
247                ppm->free_pages_nr[current_order] ++;
248        }
[18]249
[160]250        // update page descriptor
251        page_clear_flag( block , PG_FREE );
[1]252        page_refcount_up( block );
253        block->order = order;
254
[160]255        // release lock protecting free lists
[1]256        spinlock_unlock( &ppm->free_lock );
[18]257
[160]258        ppm_dmsg("\n[INFO] %s : base = %x / order = %d\n",
259                 __FUNCTION__ , (uint32_t)ppm_page2base( block ) , order );
[7]260
[1]261        return block;
[160]262}
[1]263
264
265////////////////////////////////////
266void ppm_free_pages( page_t * page )
267{
268        ppm_t * ppm = &LOCAL_CLUSTER->ppm;
[18]269
[160]270        // get lock protecting free_pages[] array
[1]271        spinlock_lock( &ppm->free_lock );
272
[18]273        ppm_free_pages_nolock( page );
[1]274
[160]275        // release lock protecting free_pages[] array
[1]276        spinlock_unlock( &ppm->free_lock );
277}
278
[7]279////////////////////////////
280void ppm_print( ppm_t * ppm,
281                char  * string )
[1]282{
283        uint32_t       order;
284        list_entry_t * iter;
285        page_t       * page;
286
[160]287        // get lock protecting free lists
[1]288        spinlock_lock( &ppm->free_lock );
289
[50]290        printk("\n***  PPM in cluster %x : %d pages / &pages_tbl = %x / vaddr_base = %x ***\n",
291               local_cxy , ppm->pages_nr , (intptr_t)ppm->pages_tbl , (intptr_t)ppm->vaddr_base );
[18]292
[1]293        for( order = 0 ; order < CONFIG_PPM_MAX_ORDER ; order++ )
294        {
[7]295                printk("- order = %d / free_pages = %d  [",
[160]296                       order , ppm->free_pages_nr[order] );
[18]297
[1]298                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
299                {
300                        page = LIST_ELEMENT( iter , page_t , list );
301                        printk("%d," , page - ppm->pages_tbl );
302                }
[18]303
[1]304                printk("]\n", NULL );
305        }
306
[160]307        // release lock protecting free lists
[1]308        spinlock_unlock( &ppm->free_lock );
[160]309}
[1]310
[53]311///////////////////////////////////////
312error_t ppm_assert_order( ppm_t * ppm )
[1]313{
314        uint32_t       order;
315        list_entry_t * iter;
316        page_t       * page;
[18]317
[1]318        for(order=0; order < CONFIG_PPM_MAX_ORDER; order++)
319        {
320                if( list_is_empty( &ppm->free_pages_root[order] ) ) continue;
[18]321
[1]322                LIST_FOREACH( &ppm->free_pages_root[order] , iter )
323                {
324                        page = LIST_ELEMENT( iter , page_t , list );
325
[160]326                        if( page->order != order )  return -1;
[1]327                }
328        }
329
[160]330        return 0;
331}
[53]332
Note: See TracBrowser for help on using the repository browser.