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