pmap_var.h revision 295695
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: head/sys/arm/include/pmap_var.h 295695 2016-02-17 12:57:05Z skra $ 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 76extern pt1_entry_t *kern_pt1; 77extern pt2_entry_t *kern_pt2tab; 78extern pt2_entry_t *PT2MAP; 79 80/* 81 * Virtual interface for L1 page table management. 82 */ 83 84static __inline u_int 85pte1_index(vm_offset_t va) 86{ 87 88 return (va >> PTE1_SHIFT); 89} 90 91static __inline pt1_entry_t * 92pte1_ptr(pt1_entry_t *pt1, vm_offset_t va) 93{ 94 95 return (pt1 + pte1_index(va)); 96} 97 98static __inline vm_offset_t 99pte1_trunc(vm_offset_t va) 100{ 101 102 return (va & PTE1_FRAME); 103} 104 105static __inline vm_offset_t 106pte1_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 */ 120static __inline void 121pte1_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 131static __inline void 132pte1_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 142static __inline void 143pte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1) 144{ 145 146 atomic_store_rel_int(pte1p, pte1); 147 pte1_sync(pte1p); 148} 149 150static __inline void 151pte1_clear(pt1_entry_t *pte1p) 152{ 153 154 pte1_store(pte1p, 0); 155} 156 157static __inline void 158pte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit) 159{ 160 161 atomic_clear_int(pte1p, bit); 162 pte1_sync(pte1p); 163} 164 165static __inline boolean_t 166pte1_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 176static __inline boolean_t 177pte1_is_link(pt1_entry_t pte1) 178{ 179 180 return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C); 181} 182 183static __inline int 184pte1_is_section(pt1_entry_t pte1) 185{ 186 187 return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S); 188} 189 190static __inline boolean_t 191pte1_is_dirty(pt1_entry_t pte1) 192{ 193 194 return ((pte1 & (PTE1_NM | PTE1_RO)) == 0); 195} 196 197static __inline boolean_t 198pte1_is_global(pt1_entry_t pte1) 199{ 200 201 return ((pte1 & PTE1_NG) == 0); 202} 203 204static __inline boolean_t 205pte1_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 213static __inline boolean_t 214pte1_is_wired(pt1_entry_t pte1) 215{ 216 217 return (pte1 & PTE1_W); 218} 219 220static __inline pt1_entry_t 221pte1_load(pt1_entry_t *pte1p) 222{ 223 pt1_entry_t pte1; 224 225 pte1 = *pte1p; 226 return (pte1); 227} 228 229static __inline pt1_entry_t 230pte1_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 239static __inline void 240pte1_set_bit(pt1_entry_t *pte1p, uint32_t bit) 241{ 242 243 atomic_set_int(pte1p, bit); 244 pte1_sync(pte1p); 245} 246 247static __inline vm_paddr_t 248pte1_pa(pt1_entry_t pte1) 249{ 250 251 return ((vm_paddr_t)(pte1 & PTE1_FRAME)); 252} 253 254static __inline vm_paddr_t 255pte1_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 269static __inline void 270pte2_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 280static __inline void 281pte2_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 291static __inline void 292pte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 293{ 294 295 atomic_store_rel_int(pte2p, pte2); 296 pte2_sync(pte2p); 297} 298 299static __inline void 300pte2_clear(pt2_entry_t *pte2p) 301{ 302 303 pte2_store(pte2p, 0); 304} 305 306static __inline void 307pte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit) 308{ 309 310 atomic_clear_int(pte2p, bit); 311 pte2_sync(pte2p); 312} 313 314static __inline boolean_t 315pte2_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 325static __inline boolean_t 326pte2_is_dirty(pt2_entry_t pte2) 327{ 328 329 return ((pte2 & (PTE2_NM | PTE2_RO)) == 0); 330} 331 332static __inline boolean_t 333pte2_is_global(pt2_entry_t pte2) 334{ 335 336 return ((pte2 & PTE2_NG) == 0); 337} 338 339static __inline boolean_t 340pte2_is_valid(pt2_entry_t pte2) 341{ 342 343 return (pte2 & PTE2_V); 344} 345 346static __inline boolean_t 347pte2_is_wired(pt2_entry_t pte2) 348{ 349 350 return (pte2 & PTE2_W); 351} 352 353static __inline pt2_entry_t 354pte2_load(pt2_entry_t *pte2p) 355{ 356 pt2_entry_t pte2; 357 358 pte2 = *pte2p; 359 return (pte2); 360} 361 362static __inline pt2_entry_t 363pte2_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 372static __inline void 373pte2_set_bit(pt2_entry_t *pte2p, uint32_t bit) 374{ 375 376 atomic_set_int(pte2p, bit); 377 pte2_sync(pte2p); 378} 379 380static __inline void 381pte2_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 394static __inline vm_paddr_t 395pte2_pa(pt2_entry_t pte2) 396{ 397 398 return ((vm_paddr_t)(pte2 & PTE2_FRAME)); 399} 400 401static __inline u_int 402pte2_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 412static __inline u_int 413pt2tab_index(vm_offset_t va) 414{ 415 416 return (va >> PT2TAB_SHIFT); 417} 418 419static __inline pt2_entry_t * 420pt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va) 421{ 422 423 return (pt2tab + pt2tab_index(va)); 424} 425 426static __inline void 427pt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 428{ 429 430 pte2_store(pte2p,pte2); 431} 432 433static __inline pt2_entry_t 434pt2tab_load(pt2_entry_t *pte2p) 435{ 436 437 return (pte2_load(pte2p)); 438} 439 440static __inline pt2_entry_t 441pt2tab_load_clear(pt2_entry_t *pte2p) 442{ 443 444 return (pte2_load_clear(pte2p)); 445} 446 447static __inline u_int 448pt2map_index(vm_offset_t va) 449{ 450 451 return (va >> PT2MAP_SHIFT); 452} 453 454static __inline pt2_entry_t * 455pt2map_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 465static __inline pt1_entry_t * 466pmap_pte1(pmap_t pmap, vm_offset_t va) 467{ 468 469 return (pte1_ptr(pmap->pm_pt1, va)); 470} 471 472static __inline pt1_entry_t * 473kern_pte1(vm_offset_t va) 474{ 475 476 return (pte1_ptr(kern_pt1, va)); 477} 478 479static __inline pt2_entry_t * 480pmap_pt2tab_entry(pmap_t pmap, vm_offset_t va) 481{ 482 483 return (pt2tab_entry(pmap->pm_pt2tab, va)); 484} 485 486static __inline pt2_entry_t * 487kern_pt2tab_entry(vm_offset_t va) 488{ 489 490 return (pt2tab_entry(kern_pt2tab, va)); 491} 492 493static __inline vm_page_t 494pmap_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 502static __inline vm_page_t 503kern_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