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$ 28280712Sian */ 29280712Sian 30280712Sian#ifndef _MACHINE_PMAP_VAR_H_ 31280712Sian#define _MACHINE_PMAP_VAR_H_ 32280712Sian 33280712Sian#include <machine/cpu-v6.h> 34295695Sskra#include <machine/pte-v6.h> 35280712Sian/* 36280712Sian * Various PMAP defines, exports, and inline functions 37280712Sian * definitions also usable in other MD code. 38280712Sian */ 39280712Sian 40280712Sian/* A number of pages in L1 page table. */ 41280712Sian#define NPG_IN_PT1 (NB_IN_PT1 / PAGE_SIZE) 42280712Sian 43280712Sian/* A number of L2 page tables in a page. */ 44280712Sian#define NPT2_IN_PG (PAGE_SIZE / NB_IN_PT2) 45280712Sian 46280712Sian/* A number of L2 page table entries in a page. */ 47280712Sian#define NPTE2_IN_PG (NPT2_IN_PG * NPTE2_IN_PT2) 48280712Sian 49280712Sian#ifdef _KERNEL 50280712Sian 51280712Sian/* 52280712Sian * A L2 page tables page contains NPT2_IN_PG L2 page tables. Masking of 53280712Sian * pte1_idx by PT2PG_MASK gives us an index to associated L2 page table 54280712Sian * in a page. The PT2PG_SHIFT definition depends on NPT2_IN_PG strictly. 55280712Sian * I.e., (1 << PT2PG_SHIFT) == NPT2_IN_PG must be fulfilled. 56280712Sian */ 57280712Sian#define PT2PG_SHIFT 2 58280712Sian#define PT2PG_MASK ((1 << PT2PG_SHIFT) - 1) 59280712Sian 60280712Sian/* 61280712Sian * A PT2TAB holds all allocated L2 page table pages in a pmap. 62280712Sian * Right shifting of virtual address by PT2TAB_SHIFT gives us an index 63280712Sian * to L2 page table page in PT2TAB which holds the address mapping. 64280712Sian */ 65280712Sian#define PT2TAB_ENTRIES (NPTE1_IN_PT1 / NPT2_IN_PG) 66280712Sian#define PT2TAB_SHIFT (PTE1_SHIFT + PT2PG_SHIFT) 67280712Sian 68280712Sian/* 69280712Sian * All allocated L2 page table pages in a pmap are mapped into PT2MAP space. 70280712Sian * An virtual address right shifting by PT2MAP_SHIFT gives us an index to PTE2 71280712Sian * which maps the address. 72280712Sian */ 73280712Sian#define PT2MAP_SIZE (NPTE1_IN_PT1 * NB_IN_PT2) 74280712Sian#define PT2MAP_SHIFT PTE2_SHIFT 75280712Sian 76280712Sianextern pt1_entry_t *kern_pt1; 77280712Sianextern pt2_entry_t *kern_pt2tab; 78280712Sianextern pt2_entry_t *PT2MAP; 79280712Sian 80280712Sian/* 81280712Sian * Virtual interface for L1 page table management. 82280712Sian */ 83280712Sian 84280712Sianstatic __inline u_int 85280712Sianpte1_index(vm_offset_t va) 86280712Sian{ 87280712Sian 88280712Sian return (va >> PTE1_SHIFT); 89280712Sian} 90280712Sian 91280712Sianstatic __inline pt1_entry_t * 92280712Sianpte1_ptr(pt1_entry_t *pt1, vm_offset_t va) 93280712Sian{ 94280712Sian 95280712Sian return (pt1 + pte1_index(va)); 96280712Sian} 97280712Sian 98280712Sianstatic __inline vm_offset_t 99280712Sianpte1_trunc(vm_offset_t va) 100280712Sian{ 101280712Sian 102280712Sian return (va & PTE1_FRAME); 103280712Sian} 104280712Sian 105280712Sianstatic __inline vm_offset_t 106280712Sianpte1_roundup(vm_offset_t va) 107280712Sian{ 108280712Sian 109280712Sian return ((va + PTE1_OFFSET) & PTE1_FRAME); 110280712Sian} 111280712Sian 112280712Sian/* 113280712Sian * Virtual interface for L1 page table entries management. 114280712Sian * 115280712Sian * XXX: Some of the following functions now with a synchronization barrier 116280712Sian * are called in a loop, so it could be useful to have two versions of them. 117280712Sian * One with the barrier and one without the barrier. In this case, pure 118280712Sian * barrier pte1_sync() should be implemented as well. 119280712Sian */ 120280712Sianstatic __inline void 121280712Sianpte1_sync(pt1_entry_t *pte1p) 122280712Sian{ 123280712Sian 124280712Sian dsb(); 125280712Sian#ifndef PMAP_PTE_NOCACHE 126280712Sian if (!cpuinfo.coherent_walk) 127280712Sian dcache_wb_pou((vm_offset_t)pte1p, sizeof(*pte1p)); 128280712Sian#endif 129280712Sian} 130280712Sian 131280712Sianstatic __inline void 132280712Sianpte1_sync_range(pt1_entry_t *pte1p, vm_size_t size) 133280712Sian{ 134280712Sian 135280712Sian dsb(); 136280712Sian#ifndef PMAP_PTE_NOCACHE 137280712Sian if (!cpuinfo.coherent_walk) 138280712Sian dcache_wb_pou((vm_offset_t)pte1p, size); 139280712Sian#endif 140280712Sian} 141280712Sian 142280712Sianstatic __inline void 143280712Sianpte1_store(pt1_entry_t *pte1p, pt1_entry_t pte1) 144280712Sian{ 145280712Sian 146298457Sskra dmb(); 147298457Sskra *pte1p = pte1; 148280712Sian pte1_sync(pte1p); 149280712Sian} 150280712Sian 151280712Sianstatic __inline void 152280712Sianpte1_clear(pt1_entry_t *pte1p) 153280712Sian{ 154280712Sian 155280712Sian pte1_store(pte1p, 0); 156280712Sian} 157280712Sian 158280712Sianstatic __inline void 159280712Sianpte1_clear_bit(pt1_entry_t *pte1p, uint32_t bit) 160280712Sian{ 161280712Sian 162298457Sskra *pte1p &= ~bit; 163280712Sian pte1_sync(pte1p); 164280712Sian} 165280712Sian 166280712Sianstatic __inline boolean_t 167280712Sianpte1_is_link(pt1_entry_t pte1) 168280712Sian{ 169280712Sian 170280712Sian return ((pte1 & L1_TYPE_MASK) == L1_TYPE_C); 171280712Sian} 172280712Sian 173280712Sianstatic __inline int 174280712Sianpte1_is_section(pt1_entry_t pte1) 175280712Sian{ 176280712Sian 177280712Sian return ((pte1 & L1_TYPE_MASK) == L1_TYPE_S); 178280712Sian} 179280712Sian 180280712Sianstatic __inline boolean_t 181280712Sianpte1_is_dirty(pt1_entry_t pte1) 182280712Sian{ 183280712Sian 184280712Sian return ((pte1 & (PTE1_NM | PTE1_RO)) == 0); 185280712Sian} 186280712Sian 187280712Sianstatic __inline boolean_t 188280712Sianpte1_is_global(pt1_entry_t pte1) 189280712Sian{ 190280712Sian 191280712Sian return ((pte1 & PTE1_NG) == 0); 192280712Sian} 193280712Sian 194280712Sianstatic __inline boolean_t 195280712Sianpte1_is_valid(pt1_entry_t pte1) 196280712Sian{ 197280712Sian int l1_type; 198280712Sian 199280712Sian l1_type = pte1 & L1_TYPE_MASK; 200280712Sian return ((l1_type == L1_TYPE_C) || (l1_type == L1_TYPE_S)); 201280712Sian} 202280712Sian 203280712Sianstatic __inline boolean_t 204280712Sianpte1_is_wired(pt1_entry_t pte1) 205280712Sian{ 206280712Sian 207280712Sian return (pte1 & PTE1_W); 208280712Sian} 209280712Sian 210280712Sianstatic __inline pt1_entry_t 211280712Sianpte1_load(pt1_entry_t *pte1p) 212280712Sian{ 213280712Sian pt1_entry_t pte1; 214280712Sian 215280712Sian pte1 = *pte1p; 216280712Sian return (pte1); 217280712Sian} 218280712Sian 219280712Sianstatic __inline pt1_entry_t 220280712Sianpte1_load_clear(pt1_entry_t *pte1p) 221280712Sian{ 222280712Sian pt1_entry_t opte1; 223280712Sian 224298457Sskra opte1 = *pte1p; 225298457Sskra *pte1p = 0; 226280712Sian pte1_sync(pte1p); 227280712Sian return (opte1); 228280712Sian} 229280712Sian 230280712Sianstatic __inline void 231280712Sianpte1_set_bit(pt1_entry_t *pte1p, uint32_t bit) 232280712Sian{ 233280712Sian 234298457Sskra *pte1p |= bit; 235280712Sian pte1_sync(pte1p); 236280712Sian} 237280712Sian 238280712Sianstatic __inline vm_paddr_t 239280712Sianpte1_pa(pt1_entry_t pte1) 240280712Sian{ 241280712Sian 242280712Sian return ((vm_paddr_t)(pte1 & PTE1_FRAME)); 243280712Sian} 244280712Sian 245280712Sianstatic __inline vm_paddr_t 246280712Sianpte1_link_pa(pt1_entry_t pte1) 247280712Sian{ 248280712Sian 249280712Sian return ((vm_paddr_t)(pte1 & L1_C_ADDR_MASK)); 250280712Sian} 251280712Sian 252280712Sian/* 253280712Sian * Virtual interface for L2 page table entries management. 254280712Sian * 255280712Sian * XXX: Some of the following functions now with a synchronization barrier 256280712Sian * are called in a loop, so it could be useful to have two versions of them. 257280712Sian * One with the barrier and one without the barrier. 258280712Sian */ 259280712Sian 260280712Sianstatic __inline void 261280712Sianpte2_sync(pt2_entry_t *pte2p) 262280712Sian{ 263280712Sian 264280712Sian dsb(); 265280712Sian#ifndef PMAP_PTE_NOCACHE 266280712Sian if (!cpuinfo.coherent_walk) 267280712Sian dcache_wb_pou((vm_offset_t)pte2p, sizeof(*pte2p)); 268280712Sian#endif 269280712Sian} 270280712Sian 271280712Sianstatic __inline void 272280712Sianpte2_sync_range(pt2_entry_t *pte2p, vm_size_t size) 273280712Sian{ 274280712Sian 275280712Sian dsb(); 276280712Sian#ifndef PMAP_PTE_NOCACHE 277280712Sian if (!cpuinfo.coherent_walk) 278280712Sian dcache_wb_pou((vm_offset_t)pte2p, size); 279280712Sian#endif 280280712Sian} 281280712Sian 282280712Sianstatic __inline void 283280712Sianpte2_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 284280712Sian{ 285280712Sian 286298457Sskra dmb(); 287298457Sskra *pte2p = pte2; 288280712Sian pte2_sync(pte2p); 289280712Sian} 290280712Sian 291280712Sianstatic __inline void 292280712Sianpte2_clear(pt2_entry_t *pte2p) 293280712Sian{ 294280712Sian 295280712Sian pte2_store(pte2p, 0); 296280712Sian} 297280712Sian 298280712Sianstatic __inline void 299280712Sianpte2_clear_bit(pt2_entry_t *pte2p, uint32_t bit) 300280712Sian{ 301280712Sian 302298457Sskra *pte2p &= ~bit; 303280712Sian pte2_sync(pte2p); 304280712Sian} 305280712Sian 306280712Sianstatic __inline boolean_t 307280712Sianpte2_is_dirty(pt2_entry_t pte2) 308280712Sian{ 309280712Sian 310280712Sian return ((pte2 & (PTE2_NM | PTE2_RO)) == 0); 311280712Sian} 312280712Sian 313280712Sianstatic __inline boolean_t 314280712Sianpte2_is_global(pt2_entry_t pte2) 315280712Sian{ 316280712Sian 317280712Sian return ((pte2 & PTE2_NG) == 0); 318280712Sian} 319280712Sian 320280712Sianstatic __inline boolean_t 321280712Sianpte2_is_valid(pt2_entry_t pte2) 322280712Sian{ 323280712Sian 324280712Sian return (pte2 & PTE2_V); 325280712Sian} 326280712Sian 327280712Sianstatic __inline boolean_t 328280712Sianpte2_is_wired(pt2_entry_t pte2) 329280712Sian{ 330280712Sian 331280712Sian return (pte2 & PTE2_W); 332280712Sian} 333280712Sian 334280712Sianstatic __inline pt2_entry_t 335280712Sianpte2_load(pt2_entry_t *pte2p) 336280712Sian{ 337280712Sian pt2_entry_t pte2; 338280712Sian 339280712Sian pte2 = *pte2p; 340280712Sian return (pte2); 341280712Sian} 342280712Sian 343280712Sianstatic __inline pt2_entry_t 344280712Sianpte2_load_clear(pt2_entry_t *pte2p) 345280712Sian{ 346280712Sian pt2_entry_t opte2; 347280712Sian 348298457Sskra opte2 = *pte2p; 349298457Sskra *pte2p = 0; 350280712Sian pte2_sync(pte2p); 351280712Sian return (opte2); 352280712Sian} 353280712Sian 354280712Sianstatic __inline void 355280712Sianpte2_set_bit(pt2_entry_t *pte2p, uint32_t bit) 356280712Sian{ 357280712Sian 358298457Sskra *pte2p |= bit; 359280712Sian pte2_sync(pte2p); 360280712Sian} 361280712Sian 362280712Sianstatic __inline void 363280712Sianpte2_set_wired(pt2_entry_t *pte2p, boolean_t wired) 364280712Sian{ 365280712Sian 366280712Sian /* 367280712Sian * Wired bit is transparent for page table walk, 368280712Sian * so pte2_sync() is not needed. 369280712Sian */ 370280712Sian if (wired) 371298457Sskra *pte2p |= PTE2_W; 372280712Sian else 373298457Sskra *pte2p &= ~PTE2_W; 374280712Sian} 375280712Sian 376280712Sianstatic __inline vm_paddr_t 377280712Sianpte2_pa(pt2_entry_t pte2) 378280712Sian{ 379280712Sian 380280712Sian return ((vm_paddr_t)(pte2 & PTE2_FRAME)); 381280712Sian} 382280712Sian 383280712Sianstatic __inline u_int 384280712Sianpte2_attr(pt2_entry_t pte2) 385280712Sian{ 386280712Sian 387280712Sian return ((u_int)(pte2 & PTE2_ATTR_MASK)); 388280712Sian} 389280712Sian 390280712Sian/* 391280712Sian * Virtual interface for L2 page tables mapping management. 392280712Sian */ 393280712Sian 394280712Sianstatic __inline u_int 395280712Sianpt2tab_index(vm_offset_t va) 396280712Sian{ 397280712Sian 398280712Sian return (va >> PT2TAB_SHIFT); 399280712Sian} 400280712Sian 401280712Sianstatic __inline pt2_entry_t * 402280712Sianpt2tab_entry(pt2_entry_t *pt2tab, vm_offset_t va) 403280712Sian{ 404280712Sian 405280712Sian return (pt2tab + pt2tab_index(va)); 406280712Sian} 407280712Sian 408280712Sianstatic __inline void 409280712Sianpt2tab_store(pt2_entry_t *pte2p, pt2_entry_t pte2) 410280712Sian{ 411280712Sian 412280712Sian pte2_store(pte2p,pte2); 413280712Sian} 414280712Sian 415280712Sianstatic __inline pt2_entry_t 416280712Sianpt2tab_load(pt2_entry_t *pte2p) 417280712Sian{ 418280712Sian 419280712Sian return (pte2_load(pte2p)); 420280712Sian} 421280712Sian 422280712Sianstatic __inline pt2_entry_t 423280712Sianpt2tab_load_clear(pt2_entry_t *pte2p) 424280712Sian{ 425280712Sian 426280712Sian return (pte2_load_clear(pte2p)); 427280712Sian} 428280712Sian 429280712Sianstatic __inline u_int 430280712Sianpt2map_index(vm_offset_t va) 431280712Sian{ 432280712Sian 433280712Sian return (va >> PT2MAP_SHIFT); 434280712Sian} 435280712Sian 436280712Sianstatic __inline pt2_entry_t * 437280712Sianpt2map_entry(vm_offset_t va) 438280712Sian{ 439280712Sian 440280712Sian return (PT2MAP + pt2map_index(va)); 441280712Sian} 442280712Sian 443280712Sian/* 444280712Sian * Virtual interface for pmap structure & kernel shortcuts. 445280712Sian */ 446280712Sian 447280712Sianstatic __inline pt1_entry_t * 448280712Sianpmap_pte1(pmap_t pmap, vm_offset_t va) 449280712Sian{ 450280712Sian 451280712Sian return (pte1_ptr(pmap->pm_pt1, va)); 452280712Sian} 453280712Sian 454280712Sianstatic __inline pt1_entry_t * 455280712Siankern_pte1(vm_offset_t va) 456280712Sian{ 457280712Sian 458280712Sian return (pte1_ptr(kern_pt1, va)); 459280712Sian} 460280712Sian 461280712Sianstatic __inline pt2_entry_t * 462280712Sianpmap_pt2tab_entry(pmap_t pmap, vm_offset_t va) 463280712Sian{ 464280712Sian 465280712Sian return (pt2tab_entry(pmap->pm_pt2tab, va)); 466280712Sian} 467280712Sian 468280712Sianstatic __inline pt2_entry_t * 469280712Siankern_pt2tab_entry(vm_offset_t va) 470280712Sian{ 471280712Sian 472280712Sian return (pt2tab_entry(kern_pt2tab, va)); 473280712Sian} 474280712Sian 475280712Sianstatic __inline vm_page_t 476280712Sianpmap_pt2_page(pmap_t pmap, vm_offset_t va) 477280712Sian{ 478280712Sian pt2_entry_t pte2; 479280712Sian 480280712Sian pte2 = pte2_load(pmap_pt2tab_entry(pmap, va)); 481280712Sian return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); 482280712Sian} 483280712Sian 484280712Sianstatic __inline vm_page_t 485280712Siankern_pt2_page(vm_offset_t va) 486280712Sian{ 487280712Sian pt2_entry_t pte2; 488280712Sian 489280712Sian pte2 = pte2_load(kern_pt2tab_entry(va)); 490280712Sian return (PHYS_TO_VM_PAGE(pte2 & PTE2_FRAME)); 491280712Sian} 492280712Sian 493280712Sian#endif /* _KERNEL */ 494280712Sian#endif /* !_MACHINE_PMAP_VAR_H_ */ 495