pmap_var.h revision 280712
1280712Sian/*- 2280712Sian * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> 3280712Sian * Copyright 2014 Michal Meloun <meloun@miracle.cz> 4280712Sian * All rights reserved. 5280712Sian * 6280712Sian * Redistribution and use in source and binary forms, with or without 7280712Sian * modification, are permitted provided that the following conditions 8280712Sian * are met: 9280712Sian * 1. Redistributions of source code must retain the above copyright 10280712Sian * notice, this list of conditions and the following disclaimer. 11280712Sian * 2. Redistributions in binary form must reproduce the above copyright 12280712Sian * notice, this list of conditions and the following disclaimer in the 13280712Sian * documentation and/or other materials provided with the distribution. 14280712Sian * 15280712Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16280712Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17280712Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18280712Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19280712Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20280712Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21280712Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22280712Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23280712Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24280712Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25280712Sian * SUCH DAMAGE. 26280712Sian * 27280712Sian * $FreeBSD: head/sys/arm/include/pmap_var.h 280712 2015-03-26 21:13:53Z ian $ 28280712Sian */ 29280712Sian 30280712Sian#ifndef _MACHINE_PMAP_VAR_H_ 31280712Sian#define _MACHINE_PMAP_VAR_H_ 32280712Sian 33280712Sian#include <machine/cpu-v6.h> 34280712Sian/* 35280712Sian * Various PMAP defines, exports, and inline functions 36280712Sian * definitions also usable in other MD code. 37280712Sian */ 38280712Sian 39280712Sian/* A number of pages in L1 page table. */ 40280712Sian#define NPG_IN_PT1 (NB_IN_PT1 / PAGE_SIZE) 41280712Sian 42280712Sian/* A number of L2 page tables in a page. */ 43280712Sian#define NPT2_IN_PG (PAGE_SIZE / NB_IN_PT2) 44280712Sian 45280712Sian/* A number of L2 page table entries in a page. */ 46280712Sian#define NPTE2_IN_PG (NPT2_IN_PG * NPTE2_IN_PT2) 47280712Sian 48280712Sian#ifdef _KERNEL 49280712Sian 50280712Sian/* 51280712Sian * A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of 52280712Sian * pte1_idx by PT2PG_MASK gives us an index to associated L2 page table 53280712Sian * in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly. 54280712Sian * I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled. 55280712Sian */ 56280712Sian#define PT2PG_SHIFT 2 57280712Sian#define PT2PG_MASK ((1 << PT2PG_SHIFT) - 1) 58280712Sian 59280712Sian/* 60280712Sian * A PT2TAB holds all allocated L2 page table pages in a pmap. 61280712Sian * Right shifting of virtual address by PT2TAB_SHIFT gives us an index 62280712Sian * to L2 page table page in PT2TAB which holds the address mapping. 63280712Sian */ 64280712Sian#define PT2TAB_ENTRIES (NPTE1_IN_PT1 / NPT2_IN_PG) 65280712Sian#define PT2TAB_SHIFT (PTE1_SHIFT + PT2PG_SHIFT) 66280712Sian 67280712Sian/* 68280712Sian * All allocated L2 page table pages in a pmap are mapped into PT2MAP space. 69280712Sian * An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2 70280712Sian * which maps the address. 71280712Sian */ 72280712Sian#define PT2MAP_SIZE (NPTE1_IN_PT1 * NB_IN_PT2) 73280712Sian#define PT2MAP_SHIFT PTE2_SHIFT 74280712Sian 75280712Sianextern pt1_entry_t *kern_pt1; 76280712Sianextern pt2_entry_t *kern_pt2tab; 77280712Sianextern pt2_entry_t *PT2MAP; 78280712Sian 79280712Sian/* 80280712Sian * Virtual interface for L1 page table management. 81280712Sian */ 82280712Sian 83280712Sianstatic __inline u_int 84280712Sianpte1_index(vm_offset_t va) 85280712Sian{ 86280712Sian 87280712Sian return (va >> PTE1_SHIFT); 88280712Sian} 89280712Sian 90280712Sianstatic __inline pt1_entry_t * 91280712Sianpte1_ptr(pt1_entry_t *pt1, vm_offset_t va) 92280712Sian{ 93280712Sian 94280712Sian return (pt1 + pte1_index(va)); 95280712Sian} 96280712Sian 97280712Sianstatic __inline vm_offset_t 98280712Sianpte1_trunc(vm_offset_t va) 99280712Sian{ 100280712Sian 101280712Sian return (va & PTE1_FRAME); 102280712Sian} 103280712Sian 104280712Sianstatic __inline vm_offset_t 105280712Sianpte1_roundup(vm_offset_t va) 106280712Sian{ 107280712Sian 108280712Sian return ((va + PTE1_OFFSET) & PTE1_FRAME); 109280712Sian} 110280712Sian 111280712Sian/* 112280712Sian * Virtual interface for L1 page table entries management. 113280712Sian * 114280712Sian * XXX: Some of the following functions now with a synchronization barrier 115280712Sian * are called in a loop, so it could be useful to have two versions of them. 116280712Sian * One with the barrier and one without the barrier. In this case, pure 117280712Sian * barrier pte1_sync() should be implemented as well. 118280712Sian */ 119280712Sianstatic __inline void 120280712Sianpte1_sync(pt1_entry_t *pte1p) 121280712Sian{ 122280712Sian 123280712Sian dsb(); 124280712Sian#ifndef PMAP_PTE_NOCACHE 125280712Sian if (!cpuinfo.coherent_walk) 126280712Sian dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p)); 127280712Sian#endif 128280712Sian} 129280712Sian 130280712Sianstatic __inline void 131280712Sianpte1_sync_range(pt1_entry_t *pte1p, vm_size_t size) 132280712Sian{ 133280712Sian 134280712Sian dsb(); 135280712Sian#ifndef PMAP_PTE_NOCACHE 136280712Sian if (!cpuinfo.coherent_walk) 137280712Sian dcache_wb_pou((vm_offset_t)pte1p, size); 138280712Sian#endif 139280712Sian} 140280712Sian 141280712Sianstatic __inline void 142280712Sianpte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1) 143280712Sian{ 144280712Sian 145280712Sian atomic_store_rel_int(pte1p, pte1); 146280712Sian pte1_sync(pte1p); 147280712Sian} 148280712Sian 149280712Sianstatic __inline void 150280712Sianpte1_clear(pt1_entry_t *pte1p) 151280712Sian{ 152280712Sian 153280712Sian pte1_store(pte1p, 0); 154280712Sian} 155280712Sian 156280712Sianstatic __inline void 157280712Sianpte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit) 158280712Sian{ 159280712Sian 160280712Sian atomic_clear_int(pte1p, bit); 161280712Sian pte1_sync(pte1p); 162280712Sian} 163280712Sian 164280712Sianstatic __inline boolean_t 165280712Sianpte1_cmpset(pt1_entry_t *pte1p, pt1_entry_t opte1, pt1_entry_t npte1) 166280712Sian{ 167280712Sian boolean_t ret; 168280712Sian 169280712Sian ret = atomic_cmpset_int(pte1p, opte1, npte1); 170280712Sian if (ret) pte1_sync(pte1p); 171280712Sian 172280712Sian return (ret); 173280712Sian} 174280712Sian 175280712Sianstatic __inline boolean_t 176280712Sianpte1_is_link(pt1_entry_t pte1) 177280712Sian{ 178280712Sian 179280712Sian return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C); 180280712Sian} 181280712Sian 182280712Sianstatic __inline int 183280712Sianpte1_is_section(pt1_entry_t pte1) 184280712Sian{ 185280712Sian 186280712Sian return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S); 187280712Sian} 188280712Sian 189280712Sianstatic __inline boolean_t 190280712Sianpte1_is_dirty(pt1_entry_t pte1) 191280712Sian{ 192280712Sian 193280712Sian return ((pte1 & (PTE1_NM | PTE1_RO)) == 0); 194280712Sian} 195280712Sian 196280712Sianstatic __inline boolean_t 197280712Sianpte1_is_global(pt1_entry_t pte1) 198280712Sian{ 199280712Sian 200280712Sian return ((pte1 & PTE1_NG) == 0); 201280712Sian} 202280712Sian 203280712Sianstatic __inline boolean_t 204280712Sianpte1_is_valid(pt1_entry_t pte1) 205280712Sian{ 206280712Sian int l1_type; 207280712Sian 208280712Sian l1_type = pte1 & L1_TYPE_MASK; 209280712Sian return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S)); 210280712Sian} 211280712Sian 212280712Sianstatic __inline boolean_t 213280712Sianpte1_is_wired(pt1_entry_t pte1) 214280712Sian{ 215280712Sian 216280712Sian return (pte1 & PTE1_W); 217280712Sian} 218280712Sian 219280712Sianstatic __inline pt1_entry_t 220280712Sianpte1_load(pt1_entry_t *pte1p) 221280712Sian{ 222280712Sian pt1_entry_t pte1; 223280712Sian 224280712Sian pte1 = *pte1p; 225280712Sian return (pte1); 226280712Sian} 227280712Sian 228280712Sianstatic __inline pt1_entry_t 229280712Sianpte1_load_clear(pt1_entry_t *pte1p) 230280712Sian{ 231280712Sian pt1_entry_t opte1; 232280712Sian 233280712Sian opte1 = atomic_readandclear_int(pte1p); 234280712Sian pte1_sync(pte1p); 235280712Sian return (opte1); 236280712Sian} 237280712Sian 238280712Sianstatic __inline void 239280712Sianpte1_set_bit(pt1_entry_t *pte1p, uint32_t bit) 240280712Sian{ 241280712Sian 242280712Sian atomic_set_int(pte1p, bit); 243280712Sian pte1_sync(pte1p); 244280712Sian} 245280712Sian 246280712Sianstatic __inline vm_paddr_t 247280712Sianpte1_pa(pt1_entry_t pte1) 248280712Sian{ 249280712Sian 250280712Sian return ((vm_paddr_t)(pte1 & PTE1_FRAME)); 251280712Sian} 252280712Sian 253280712Sianstatic __inline vm_paddr_t 254280712Sianpte1_link_pa(pt1_entry_t pte1) 255280712Sian{ 256280712Sian 257280712Sian return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK)); 258280712Sian} 259280712Sian 260280712Sian/* 261280712Sian * Virtual interface for L2 page table entries management. 262280712Sian * 263280712Sian * XXX: Some of the following functions now with a synchronization barrier 264280712Sian * are called in a loop, so it could be useful to have two versions of them. 265280712Sian * One with the barrier and one without the barrier. 266280712Sian */ 267280712Sian 268280712Sianstatic __inline void 269280712Sianpte2_sync(pt2_entry_t *pte2p) 270280712Sian{ 271280712Sian 272280712Sian dsb(); 273280712Sian#ifndef PMAP_PTE_NOCACHE 274280712Sian if (!cpuinfo.coherent_walk) 275280712Sian dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p)); 276280712Sian#endif 277280712Sian} 278280712Sian 279280712Sianstatic __inline void 280280712Sianpte2_sync_range(pt2_entry_t *pte2p, vm_size_t size) 281280712Sian{ 282280712Sian 283280712Sian dsb(); 284280712Sian#ifndef PMAP_PTE_NOCACHE 285280712Sian if (!cpuinfo.coherent_walk) 286280712Sian dcache_wb_pou((vm_offset_t)pte2p, size); 287280712Sian#endif 288280712Sian} 289280712Sian 290280712Sianstatic __inline void 291280712Sianpte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 292280712Sian{ 293280712Sian 294280712Sian atomic_store_rel_int(pte2p, pte2); 295280712Sian pte2_sync(pte2p); 296280712Sian} 297280712Sian 298280712Sianstatic __inline void 299280712Sianpte2_clear(pt2_entry_t *pte2p) 300280712Sian{ 301280712Sian 302280712Sian pte2_store(pte2p, 0); 303280712Sian} 304280712Sian 305280712Sianstatic __inline void 306280712Sianpte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit) 307280712Sian{ 308280712Sian 309280712Sian atomic_clear_int(pte2p, bit); 310280712Sian pte2_sync(pte2p); 311280712Sian} 312280712Sian 313280712Sianstatic __inline boolean_t 314280712Sianpte2_cmpset(pt2_entry_t *pte2p, pt2_entry_t opte2, pt2_entry_t npte2) 315280712Sian{ 316280712Sian boolean_t ret; 317280712Sian 318280712Sian ret = atomic_cmpset_int(pte2p, opte2, npte2); 319280712Sian if (ret) pte2_sync(pte2p); 320280712Sian 321280712Sian return (ret); 322280712Sian} 323280712Sian 324280712Sianstatic __inline boolean_t 325280712Sianpte2_is_dirty(pt2_entry_t pte2) 326280712Sian{ 327280712Sian 328280712Sian return ((pte2 & (PTE2_NM | PTE2_RO)) == 0); 329280712Sian} 330280712Sian 331280712Sianstatic __inline boolean_t 332280712Sianpte2_is_global(pt2_entry_t pte2) 333280712Sian{ 334280712Sian 335280712Sian return ((pte2 & PTE2_NG) == 0); 336280712Sian} 337280712Sian 338280712Sianstatic __inline boolean_t 339280712Sianpte2_is_valid(pt2_entry_t pte2) 340280712Sian{ 341280712Sian 342280712Sian return (pte2 & PTE2_V); 343280712Sian} 344280712Sian 345280712Sianstatic __inline boolean_t 346280712Sianpte2_is_wired(pt2_entry_t pte2) 347280712Sian{ 348280712Sian 349280712Sian return (pte2 & PTE2_W); 350280712Sian} 351280712Sian 352280712Sianstatic __inline pt2_entry_t 353280712Sianpte2_load(pt2_entry_t *pte2p) 354280712Sian{ 355280712Sian pt2_entry_t pte2; 356280712Sian 357280712Sian pte2 = *pte2p; 358280712Sian return (pte2); 359280712Sian} 360280712Sian 361280712Sianstatic __inline pt2_entry_t 362280712Sianpte2_load_clear(pt2_entry_t *pte2p) 363280712Sian{ 364280712Sian pt2_entry_t opte2; 365280712Sian 366280712Sian opte2 = atomic_readandclear_int(pte2p); 367280712Sian pte2_sync(pte2p); 368280712Sian return (opte2); 369280712Sian} 370280712Sian 371280712Sianstatic __inline void 372280712Sianpte2_set_bit(pt2_entry_t *pte2p, uint32_t bit) 373280712Sian{ 374280712Sian 375280712Sian atomic_set_int(pte2p, bit); 376280712Sian pte2_sync(pte2p); 377280712Sian} 378280712Sian 379280712Sianstatic __inline void 380280712Sianpte2_set_wired(pt2_entry_t *pte2p, boolean_t wired) 381280712Sian{ 382280712Sian 383280712Sian /* 384280712Sian * Wired bit is transparent for page table walk, 385280712Sian * so pte2_sync() is not needed. 386280712Sian */ 387280712Sian if (wired) 388280712Sian atomic_set_int(pte2p, PTE2_W); 389280712Sian else 390280712Sian atomic_clear_int(pte2p, PTE2_W); 391280712Sian} 392280712Sian 393280712Sianstatic __inline vm_paddr_t 394280712Sianpte2_pa(pt2_entry_t pte2) 395280712Sian{ 396280712Sian 397280712Sian return ((vm_paddr_t)(pte2 & PTE2_FRAME)); 398280712Sian} 399280712Sian 400280712Sianstatic __inline u_int 401280712Sianpte2_attr(pt2_entry_t pte2) 402280712Sian{ 403280712Sian 404280712Sian return ((u_int)(pte2 & PTE2_ATTR_MASK)); 405280712Sian} 406280712Sian 407280712Sian/* 408280712Sian * Virtual interface for L2 page tables mapping management. 409280712Sian */ 410280712Sian 411280712Sianstatic __inline u_int 412280712Sianpt2tab_index(vm_offset_t va) 413280712Sian{ 414280712Sian 415280712Sian return (va >> PT2TAB_SHIFT); 416280712Sian} 417280712Sian 418280712Sianstatic __inline pt2_entry_t * 419280712Sianpt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va) 420280712Sian{ 421280712Sian 422280712Sian return (pt2tab + pt2tab_index(va)); 423280712Sian} 424280712Sian 425280712Sianstatic __inline void 426280712Sianpt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 427280712Sian{ 428280712Sian 429280712Sian pte2_store(pte2p,pte2); 430280712Sian} 431280712Sian 432280712Sianstatic __inline pt2_entry_t 433280712Sianpt2tab_load(pt2_entry_t *pte2p) 434280712Sian{ 435280712Sian 436280712Sian return (pte2_load(pte2p)); 437280712Sian} 438280712Sian 439280712Sianstatic __inline pt2_entry_t 440280712Sianpt2tab_load_clear(pt2_entry_t *pte2p) 441280712Sian{ 442280712Sian 443280712Sian return (pte2_load_clear(pte2p)); 444280712Sian} 445280712Sian 446280712Sianstatic __inline u_int 447280712Sianpt2map_index(vm_offset_t va) 448280712Sian{ 449280712Sian 450280712Sian return (va >> PT2MAP_SHIFT); 451280712Sian} 452280712Sian 453280712Sianstatic __inline pt2_entry_t * 454280712Sianpt2map_entry(vm_offset_t va) 455280712Sian{ 456280712Sian 457280712Sian return (PT2MAP + pt2map_index(va)); 458280712Sian} 459280712Sian 460280712Sian/* 461280712Sian * Virtual interface for pmap structure & kernel shortcuts. 462280712Sian */ 463280712Sian 464280712Sianstatic __inline pt1_entry_t * 465280712Sianpmap_pte1(pmap_t pmap, vm_offset_t va) 466280712Sian{ 467280712Sian 468280712Sian return (pte1_ptr(pmap->pm_pt1, va)); 469280712Sian} 470280712Sian 471280712Sianstatic __inline pt1_entry_t * 472280712Siankern_pte1(vm_offset_t va) 473280712Sian{ 474280712Sian 475280712Sian return (pte1_ptr(kern_pt1, va)); 476280712Sian} 477280712Sian 478280712Sianstatic __inline pt2_entry_t * 479280712Sianpmap_pt2tab_entry(pmap_t pmap, vm_offset_t va) 480280712Sian{ 481280712Sian 482280712Sian return (pt2tab_entry(pmap->pm_pt2tab, va)); 483280712Sian} 484280712Sian 485280712Sianstatic __inline pt2_entry_t * 486280712Siankern_pt2tab_entry(vm_offset_t va) 487280712Sian{ 488280712Sian 489280712Sian return (pt2tab_entry(kern_pt2tab, va)); 490280712Sian} 491280712Sian 492280712Sianstatic __inline vm_page_t 493280712Sianpmap_pt2_page(pmap_t pmap, vm_offset_t va) 494280712Sian{ 495280712Sian pt2_entry_t pte2; 496280712Sian 497280712Sian pte2 = pte2_load(pmap_pt2tab_entry(pmap, va)); 498280712Sian return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); 499280712Sian} 500280712Sian 501280712Sianstatic __inline vm_page_t 502280712Siankern_pt2_page(vm_offset_t va) 503280712Sian{ 504280712Sian pt2_entry_t pte2; 505280712Sian 506280712Sian pte2 = pte2_load(kern_pt2tab_entry(va)); 507280712Sian return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); 508280712Sian} 509280712Sian 510280712Sian#endif /* _KERNEL */ 511280712Sian#endif /* !_MACHINE_PMAP_VAR_H_ */ 512