| [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 | //////////////////////////////////////////////// | 
|---|
|  | 43 | inline 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 | ///////////////////////////////////////////// | 
|---|
|  | 53 | inline 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 | ////////////////////////////////////////////// | 
|---|
|  | 60 | inline 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 | ////////////////////////////////////////// | 
|---|
|  | 69 | inline 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 | ///////////////////////////////////////// | 
|---|
|  | 76 | inline 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] | 85 | inline 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 | ////////////////////////////////////////// | 
|---|
|  | 92 | inline 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 | /////////////////////////////////////////// | 
|---|
|  | 101 | void 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] , ¤t->list ); | 
|---|
| [1] | 144 | ppm->free_pages_nr[current_order] ++; | 
|---|
|  | 145 |  | 
|---|
|  | 146 | }  // end ppm_free_pages_nolock() | 
|---|
|  | 147 |  | 
|---|
|  | 148 | //////////////////////////////////////////// | 
|---|
|  | 149 | page_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 | //////////////////////////////////// | 
|---|
|  | 220 | void 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 | //////////////////////////// | 
|---|
|  | 234 | void 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 | /////////////////////////////////////// | 
|---|
|  | 267 | error_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 |  | 
|---|