1 /*- 2 * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> 3 * Copyright 2014 Michal Meloun <meloun@miracle.cz> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #ifndef _MACHINE_PMAP_VAR_H_ 31 #define _MACHINE_PMAP_VAR_H_ 32 33 #include <machine/cpu-v6.h> 34 #include <machine/pte-v6.h> 35 /* 36 * Various PMAP defines, exports, and inline functions 37 * definitions also usable in other MD code. 38 */ 39 40 /* A number of pages in L1 page table. */ 41 #define NPG_IN_PT1 (NB_IN_PT1 / PAGE_SIZE) 42 43 /* A number of L2 page tables in a page. */ 44 #define NPT2_IN_PG (PAGE_SIZE / NB_IN_PT2) 45 46 /* A number of L2 page table entries in a page. */ 47 #define NPTE2_IN_PG (NPT2_IN_PG * NPTE2_IN_PT2) 48 49 #ifdef _KERNEL 50 51 /* 52 * A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of 53 * pte1_idx by PT2PG_MASK gives us an index to associated L2 page table 54 * in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly. 55 * I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled. 56 */ 57 #define PT2PG_SHIFT 2 58 #define PT2PG_MASK ((1 << PT2PG_SHIFT) - 1) 59 60 /* 61 * A PT2TAB holds all allocated L2 page table pages in a pmap. 62 * Right shifting of virtual address by PT2TAB_SHIFT gives us an index 63 * to L2 page table page in PT2TAB which holds the address mapping. 64 */ 65 #define PT2TAB_ENTRIES (NPTE1_IN_PT1 / NPT2_IN_PG) 66 #define PT2TAB_SHIFT (PTE1_SHIFT + PT2PG_SHIFT) 67 68 /* 69 * All allocated L2 page table pages in a pmap are mapped into PT2MAP space. 70 * An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2 71 * which maps the address. 72 */ 73 #define PT2MAP_SIZE (NPTE1_IN_PT1 * NB_IN_PT2) 74 #define PT2MAP_SHIFT PTE2_SHIFT 75 76 extern pt1_entry_t *kern_pt1; 77 extern pt2_entry_t *kern_pt2tab; 78 extern pt2_entry_t *PT2MAP; 79 80 /* 81 * Virtual interface for L1 page table management. 82 */ 83 84 static __inline u_int 85 pte1_index(vm_offset_t va) 86 { 87 88 return (va >> PTE1_SHIFT); 89 } 90 91 static __inline pt1_entry_t * 92 pte1_ptr(pt1_entry_t *pt1, vm_offset_t va) 93 { 94 95 return (pt1 + pte1_index(va)); 96 } 97 98 static __inline vm_offset_t 99 pte1_trunc(vm_offset_t va) 100 { 101 102 return (va & PTE1_FRAME); 103 } 104 105 static __inline vm_offset_t 106 pte1_roundup(vm_offset_t va) 107 { 108 109 return ((va + PTE1_OFFSET) & PTE1_FRAME); 110 } 111 112 /* 113 * Virtual interface for L1 page table entries management. 114 * 115 * XXX: Some of the following functions now with a synchronization barrier 116 * are called in a loop, so it could be useful to have two versions of them. 117 * One with the barrier and one without the barrier. In this case, pure 118 * barrier pte1_sync() should be implemented as well. 119 */ 120 static __inline void 121 pte1_sync(pt1_entry_t *pte1p) 122 { 123 124 dsb(); 125 #ifndef PMAP_PTE_NOCACHE 126 if (!cpuinfo.coherent_walk) 127 dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p)); 128 #endif 129 } 130 131 static __inline void 132 pte1_sync_range(pt1_entry_t *pte1p, vm_size_t size) 133 { 134 135 dsb(); 136 #ifndef PMAP_PTE_NOCACHE 137 if (!cpuinfo.coherent_walk) 138 dcache_wb_pou((vm_offset_t)pte1p, size); 139 #endif 140 } 141 142 static __inline void 143 pte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1) 144 { 145 146 atomic_store_rel_int(pte1p, pte1); 147 pte1_sync(pte1p); 148 } 149 150 static __inline void 151 pte1_clear(pt1_entry_t *pte1p) 152 { 153 154 pte1_store(pte1p, 0); 155 } 156 157 static __inline void 158 pte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit) 159 { 160 161 atomic_clear_int(pte1p, bit); 162 pte1_sync(pte1p); 163 } 164 165 static __inline boolean_t 166 pte1_cmpset(pt1_entry_t *pte1p, pt1_entry_t opte1, pt1_entry_t npte1) 167 { 168 boolean_t ret; 169 170 ret = atomic_cmpset_int(pte1p, opte1, npte1); 171 if (ret) pte1_sync(pte1p); 172 173 return (ret); 174 } 175 176 static __inline boolean_t 177 pte1_is_link(pt1_entry_t pte1) 178 { 179 180 return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C); 181 } 182 183 static __inline int 184 pte1_is_section(pt1_entry_t pte1) 185 { 186 187 return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S); 188 } 189 190 static __inline boolean_t 191 pte1_is_dirty(pt1_entry_t pte1) 192 { 193 194 return ((pte1 & (PTE1_NM | PTE1_RO)) == 0); 195 } 196 197 static __inline boolean_t 198 pte1_is_global(pt1_entry_t pte1) 199 { 200 201 return ((pte1 & PTE1_NG) == 0); 202 } 203 204 static __inline boolean_t 205 pte1_is_valid(pt1_entry_t pte1) 206 { 207 int l1_type; 208 209 l1_type = pte1 & L1_TYPE_MASK; 210 return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S)); 211 } 212 213 static __inline boolean_t 214 pte1_is_wired(pt1_entry_t pte1) 215 { 216 217 return (pte1 & PTE1_W); 218 } 219 220 static __inline pt1_entry_t 221 pte1_load(pt1_entry_t *pte1p) 222 { 223 pt1_entry_t pte1; 224 225 pte1 = *pte1p; 226 return (pte1); 227 } 228 229 static __inline pt1_entry_t 230 pte1_load_clear(pt1_entry_t *pte1p) 231 { 232 pt1_entry_t opte1; 233 234 opte1 = atomic_readandclear_int(pte1p); 235 pte1_sync(pte1p); 236 return (opte1); 237 } 238 239 static __inline void 240 pte1_set_bit(pt1_entry_t *pte1p, uint32_t bit) 241 { 242 243 atomic_set_int(pte1p, bit); 244 pte1_sync(pte1p); 245 } 246 247 static __inline vm_paddr_t 248 pte1_pa(pt1_entry_t pte1) 249 { 250 251 return ((vm_paddr_t)(pte1 & PTE1_FRAME)); 252 } 253 254 static __inline vm_paddr_t 255 pte1_link_pa(pt1_entry_t pte1) 256 { 257 258 return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK)); 259 } 260 261 /* 262 * Virtual interface for L2 page table entries management. 263 * 264 * XXX: Some of the following functions now with a synchronization barrier 265 * are called in a loop, so it could be useful to have two versions of them. 266 * One with the barrier and one without the barrier. 267 */ 268 269 static __inline void 270 pte2_sync(pt2_entry_t *pte2p) 271 { 272 273 dsb(); 274 #ifndef PMAP_PTE_NOCACHE 275 if (!cpuinfo.coherent_walk) 276 dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p)); 277 #endif 278 } 279 280 static __inline void 281 pte2_sync_range(pt2_entry_t *pte2p, vm_size_t size) 282 { 283 284 dsb(); 285 #ifndef PMAP_PTE_NOCACHE 286 if (!cpuinfo.coherent_walk) 287 dcache_wb_pou((vm_offset_t)pte2p, size); 288 #endif 289 } 290 291 static __inline void 292 pte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 293 { 294 295 atomic_store_rel_int(pte2p, pte2); 296 pte2_sync(pte2p); 297 } 298 299 static __inline void 300 pte2_clear(pt2_entry_t *pte2p) 301 { 302 303 pte2_store(pte2p, 0); 304 } 305 306 static __inline void 307 pte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit) 308 { 309 310 atomic_clear_int(pte2p, bit); 311 pte2_sync(pte2p); 312 } 313 314 static __inline boolean_t 315 pte2_cmpset(pt2_entry_t *pte2p, pt2_entry_t opte2, pt2_entry_t npte2) 316 { 317 boolean_t ret; 318 319 ret = atomic_cmpset_int(pte2p, opte2, npte2); 320 if (ret) pte2_sync(pte2p); 321 322 return (ret); 323 } 324 325 static __inline boolean_t 326 pte2_is_dirty(pt2_entry_t pte2) 327 { 328 329 return ((pte2 & (PTE2_NM | PTE2_RO)) == 0); 330 } 331 332 static __inline boolean_t 333 pte2_is_global(pt2_entry_t pte2) 334 { 335 336 return ((pte2 & PTE2_NG) == 0); 337 } 338 339 static __inline boolean_t 340 pte2_is_valid(pt2_entry_t pte2) 341 { 342 343 return (pte2 & PTE2_V); 344 } 345 346 static __inline boolean_t 347 pte2_is_wired(pt2_entry_t pte2) 348 { 349 350 return (pte2 & PTE2_W); 351 } 352 353 static __inline pt2_entry_t 354 pte2_load(pt2_entry_t *pte2p) 355 { 356 pt2_entry_t pte2; 357 358 pte2 = *pte2p; 359 return (pte2); 360 } 361 362 static __inline pt2_entry_t 363 pte2_load_clear(pt2_entry_t *pte2p) 364 { 365 pt2_entry_t opte2; 366 367 opte2 = atomic_readandclear_int(pte2p); 368 pte2_sync(pte2p); 369 return (opte2); 370 } 371 372 static __inline void 373 pte2_set_bit(pt2_entry_t *pte2p, uint32_t bit) 374 { 375 376 atomic_set_int(pte2p, bit); 377 pte2_sync(pte2p); 378 } 379 380 static __inline void 381 pte2_set_wired(pt2_entry_t *pte2p, boolean_t wired) 382 { 383 384 /* 385 * Wired bit is transparent for page table walk, 386 * so pte2_sync() is not needed. 387 */ 388 if (wired) 389 atomic_set_int(pte2p, PTE2_W); 390 else 391 atomic_clear_int(pte2p, PTE2_W); 392 } 393 394 static __inline vm_paddr_t 395 pte2_pa(pt2_entry_t pte2) 396 { 397 398 return ((vm_paddr_t)(pte2 & PTE2_FRAME)); 399 } 400 401 static __inline u_int 402 pte2_attr(pt2_entry_t pte2) 403 { 404 405 return ((u_int)(pte2 & PTE2_ATTR_MASK)); 406 } 407 408 /* 409 * Virtual interface for L2 page tables mapping management. 410 */ 411 412 static __inline u_int 413 pt2tab_index(vm_offset_t va) 414 { 415 416 return (va >> PT2TAB_SHIFT); 417 } 418 419 static __inline pt2_entry_t * 420 pt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va) 421 { 422 423 return (pt2tab + pt2tab_index(va)); 424 } 425 426 static __inline void 427 pt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 428 { 429 430 pte2_store(pte2p,pte2); 431 } 432 433 static __inline pt2_entry_t 434 pt2tab_load(pt2_entry_t *pte2p) 435 { 436 437 return (pte2_load(pte2p)); 438 } 439 440 static __inline pt2_entry_t 441 pt2tab_load_clear(pt2_entry_t *pte2p) 442 { 443 444 return (pte2_load_clear(pte2p)); 445 } 446 447 static __inline u_int 448 pt2map_index(vm_offset_t va) 449 { 450 451 return (va >> PT2MAP_SHIFT); 452 } 453 454 static __inline pt2_entry_t * 455 pt2map_entry(vm_offset_t va) 456 { 457 458 return (PT2MAP + pt2map_index(va)); 459 } 460 461 /* 462 * Virtual interface for pmap structure & kernel shortcuts. 463 */ 464 465 static __inline pt1_entry_t * 466 pmap_pte1(pmap_t pmap, vm_offset_t va) 467 { 468 469 return (pte1_ptr(pmap->pm_pt1, va)); 470 } 471 472 static __inline pt1_entry_t * 473 kern_pte1(vm_offset_t va) 474 { 475 476 return (pte1_ptr(kern_pt1, va)); 477 } 478 479 static __inline pt2_entry_t * 480 pmap_pt2tab_entry(pmap_t pmap, vm_offset_t va) 481 { 482 483 return (pt2tab_entry(pmap->pm_pt2tab, va)); 484 } 485 486 static __inline pt2_entry_t * 487 kern_pt2tab_entry(vm_offset_t va) 488 { 489 490 return (pt2tab_entry(kern_pt2tab, va)); 491 } 492 493 static __inline vm_page_t 494 pmap_pt2_page(pmap_t pmap, vm_offset_t va) 495 { 496 pt2_entry_t pte2; 497 498 pte2 = pte2_load(pmap_pt2tab_entry(pmap, va)); 499 return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); 500 } 501 502 static __inline vm_page_t 503 kern_pt2_page(vm_offset_t va) 504 { 505 pt2_entry_t pte2; 506 507 pte2 = pte2_load(kern_pt2tab_entry(va)); 508 return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); 509 } 510 511 #endif /* _KERNEL */ 512 #endif /* !_MACHINE_PMAP_VAR_H_ */ 513