162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OpenRISC Linux 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Linux architectural port borrowing liberally from similar works of 662306a36Sopenharmony_ci * others. All original copyrights apply as per the original source 762306a36Sopenharmony_ci * declaration. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * OpenRISC implementation: 1062306a36Sopenharmony_ci * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> 1162306a36Sopenharmony_ci * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> 1262306a36Sopenharmony_ci * et al. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* or1k pgtable.h - macros and functions to manipulate page tables 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Based on: 1862306a36Sopenharmony_ci * include/asm-cris/pgtable.h 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifndef __ASM_OPENRISC_PGTABLE_H 2262306a36Sopenharmony_ci#define __ASM_OPENRISC_PGTABLE_H 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <asm-generic/pgtable-nopmd.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 2762306a36Sopenharmony_ci#include <asm/mmu.h> 2862306a36Sopenharmony_ci#include <asm/fixmap.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * The Linux memory management assumes a three-level page table setup. On 3262306a36Sopenharmony_ci * or1k, we use that, but "fold" the mid level into the top-level page 3362306a36Sopenharmony_ci * table. Since the MMU TLB is software loaded through an interrupt, it 3462306a36Sopenharmony_ci * supports any page table structure, so we could have used a three-level 3562306a36Sopenharmony_ci * setup, but for the amounts of memory we normally use, a two-level is 3662306a36Sopenharmony_ci * probably more efficient. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * This file contains the functions and defines necessary to modify and use 3962306a36Sopenharmony_ci * the or1k page table tree. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciextern void paging_init(void); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Certain architectures need to do special things when pte's 4562306a36Sopenharmony_ci * within a page table are directly modified. Thus, the following 4662306a36Sopenharmony_ci * hook is made available. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * (pmds are folded into pgds so this doesn't get actually called, 5262306a36Sopenharmony_ci * but the define is needed for a generic inline function.) 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-2)) 5762306a36Sopenharmony_ci#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 5862306a36Sopenharmony_ci#define PGDIR_MASK (~(PGDIR_SIZE-1)) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * entries per page directory level: we use a two-level, so 6262306a36Sopenharmony_ci * we don't really have any PMD directory physically. 6362306a36Sopenharmony_ci * pointers are 4 bytes so we can use the page size and 6462306a36Sopenharmony_ci * divide it by 4 (shift by 2). 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-2)) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define PTRS_PER_PGD (1UL << (32-PGDIR_SHIFT)) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* calculate how many PGD entries a user-level program can use 7162306a36Sopenharmony_ci * the first mappable virtual address is 0 7262306a36Sopenharmony_ci * (TASK_SIZE is the maximum virtual address space) 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * Kernels own virtual memory area. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * The size and location of the vmalloc area are chosen so that modules 8362306a36Sopenharmony_ci * placed in this area aren't more than a 28-bit signed offset from any 8462306a36Sopenharmony_ci * kernel functions that they may need. This greatly simplifies handling 8562306a36Sopenharmony_ci * of the relocations for l.j and l.jal instructions as we don't need to 8662306a36Sopenharmony_ci * introduce any trampolines for reaching "distant" code. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * 64 MB of vmalloc area is comparable to what's available on other arches. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define VMALLOC_START (PAGE_OFFSET-0x04000000UL) 9262306a36Sopenharmony_ci#define VMALLOC_END (PAGE_OFFSET) 9362306a36Sopenharmony_ci#define VMALLOC_VMADDR(x) ((unsigned long)(x)) 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* Define some higher level generic page attributes. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * If you change _PAGE_CI definition be sure to change it in 9862306a36Sopenharmony_ci * io.h for ioremap() too. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * An OR32 PTE looks like this: 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * | 31 ... 10 | 9 | 8 ... 6 | 5 | 4 | 3 | 2 | 1 | 0 | 10562306a36Sopenharmony_ci * Phys pg.num L PP Index D A WOM WBC CI CC 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * L : link 10862306a36Sopenharmony_ci * PPI: Page protection index 10962306a36Sopenharmony_ci * D : Dirty 11062306a36Sopenharmony_ci * A : Accessed 11162306a36Sopenharmony_ci * WOM: Weakly ordered memory 11262306a36Sopenharmony_ci * WBC: Write-back cache 11362306a36Sopenharmony_ci * CI : Cache inhibit 11462306a36Sopenharmony_ci * CC : Cache coherent 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * The protection bits below should correspond to the layout of the actual 11762306a36Sopenharmony_ci * PTE as per above 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define _PAGE_CC 0x001 /* software: pte contains a translation */ 12162306a36Sopenharmony_ci#define _PAGE_CI 0x002 /* cache inhibit */ 12262306a36Sopenharmony_ci#define _PAGE_WBC 0x004 /* write back cache */ 12362306a36Sopenharmony_ci#define _PAGE_WOM 0x008 /* weakly ordered memory */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define _PAGE_A 0x010 /* accessed */ 12662306a36Sopenharmony_ci#define _PAGE_D 0x020 /* dirty */ 12762306a36Sopenharmony_ci#define _PAGE_URE 0x040 /* user read enable */ 12862306a36Sopenharmony_ci#define _PAGE_UWE 0x080 /* user write enable */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define _PAGE_SRE 0x100 /* superuser read enable */ 13162306a36Sopenharmony_ci#define _PAGE_SWE 0x200 /* superuser write enable */ 13262306a36Sopenharmony_ci#define _PAGE_EXEC 0x400 /* software: page is executable */ 13362306a36Sopenharmony_ci#define _PAGE_U_SHARED 0x800 /* software: page is shared in user space */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* 0x001 is cache coherency bit, which should always be set to 13662306a36Sopenharmony_ci * 1 - for SMP (when we support it) 13762306a36Sopenharmony_ci * 0 - otherwise 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * we just reuse this bit in software for _PAGE_PRESENT and 14062306a36Sopenharmony_ci * force it to 0 when loading it into TLB. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci#define _PAGE_PRESENT _PAGE_CC 14362306a36Sopenharmony_ci#define _PAGE_USER _PAGE_URE 14462306a36Sopenharmony_ci#define _PAGE_WRITE (_PAGE_UWE | _PAGE_SWE) 14562306a36Sopenharmony_ci#define _PAGE_DIRTY _PAGE_D 14662306a36Sopenharmony_ci#define _PAGE_ACCESSED _PAGE_A 14762306a36Sopenharmony_ci#define _PAGE_NO_CACHE _PAGE_CI 14862306a36Sopenharmony_ci#define _PAGE_SHARED _PAGE_U_SHARED 14962306a36Sopenharmony_ci#define _PAGE_READ (_PAGE_URE | _PAGE_SRE) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) 15262306a36Sopenharmony_ci#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED) 15362306a36Sopenharmony_ci#define _PAGE_ALL (_PAGE_PRESENT | _PAGE_ACCESSED) 15462306a36Sopenharmony_ci#define _KERNPG_TABLE \ 15562306a36Sopenharmony_ci (_PAGE_BASE | _PAGE_SRE | _PAGE_SWE | _PAGE_ACCESSED | _PAGE_DIRTY) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* We borrow bit 11 to store the exclusive marker in swap PTEs. */ 15862306a36Sopenharmony_ci#define _PAGE_SWP_EXCLUSIVE _PAGE_U_SHARED 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define PAGE_NONE __pgprot(_PAGE_ALL) 16162306a36Sopenharmony_ci#define PAGE_READONLY __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE) 16262306a36Sopenharmony_ci#define PAGE_READONLY_X __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_EXEC) 16362306a36Sopenharmony_ci#define PAGE_SHARED \ 16462306a36Sopenharmony_ci __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_UWE | _PAGE_SWE \ 16562306a36Sopenharmony_ci | _PAGE_SHARED) 16662306a36Sopenharmony_ci#define PAGE_SHARED_X \ 16762306a36Sopenharmony_ci __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_UWE | _PAGE_SWE \ 16862306a36Sopenharmony_ci | _PAGE_SHARED | _PAGE_EXEC) 16962306a36Sopenharmony_ci#define PAGE_COPY __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE) 17062306a36Sopenharmony_ci#define PAGE_COPY_X __pgprot(_PAGE_ALL | _PAGE_URE | _PAGE_SRE | _PAGE_EXEC) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define PAGE_KERNEL \ 17362306a36Sopenharmony_ci __pgprot(_PAGE_ALL | _PAGE_SRE | _PAGE_SWE \ 17462306a36Sopenharmony_ci | _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC) 17562306a36Sopenharmony_ci#define PAGE_KERNEL_RO \ 17662306a36Sopenharmony_ci __pgprot(_PAGE_ALL | _PAGE_SRE \ 17762306a36Sopenharmony_ci | _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC) 17862306a36Sopenharmony_ci#define PAGE_KERNEL_NOCACHE \ 17962306a36Sopenharmony_ci __pgprot(_PAGE_ALL | _PAGE_SRE | _PAGE_SWE \ 18062306a36Sopenharmony_ci | _PAGE_SHARED | _PAGE_DIRTY | _PAGE_EXEC | _PAGE_CI) 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* zero page used for uninitialized stuff */ 18362306a36Sopenharmony_ciextern unsigned long empty_zero_page[2048]; 18462306a36Sopenharmony_ci#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* number of bits that fit into a memory pointer */ 18762306a36Sopenharmony_ci#define BITS_PER_PTR (8*sizeof(unsigned long)) 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/* to align the pointer to a pointer address */ 19062306a36Sopenharmony_ci#define PTR_MASK (~(sizeof(void *)-1)) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */ 19362306a36Sopenharmony_ci/* 64-bit machines, beware! SRB. */ 19462306a36Sopenharmony_ci#define SIZEOF_PTR_LOG2 2 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* to find an entry in a page-table */ 19762306a36Sopenharmony_ci#define PAGE_PTR(address) \ 19862306a36Sopenharmony_ci((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* to set the page-dir */ 20162306a36Sopenharmony_ci#define SET_PAGE_DIR(tsk, pgdir) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#define pte_none(x) (!pte_val(x)) 20462306a36Sopenharmony_ci#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) 20562306a36Sopenharmony_ci#define pte_clear(mm, addr, xp) do { pte_val(*(xp)) = 0; } while (0) 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#define pmd_none(x) (!pmd_val(x)) 20862306a36Sopenharmony_ci#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK)) != _KERNPG_TABLE) 20962306a36Sopenharmony_ci#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) 21062306a36Sopenharmony_ci#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * The following only work if pte_present() is true. 21462306a36Sopenharmony_ci * Undefined behaviour if not.. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } 21862306a36Sopenharmony_cistatic inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } 21962306a36Sopenharmony_cistatic inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; } 22062306a36Sopenharmony_cistatic inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } 22162306a36Sopenharmony_cistatic inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_WRITE); 22662306a36Sopenharmony_ci return pte; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic inline pte_t pte_rdprotect(pte_t pte) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_READ); 23262306a36Sopenharmony_ci return pte; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic inline pte_t pte_exprotect(pte_t pte) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_EXEC); 23862306a36Sopenharmony_ci return pte; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_DIRTY); 24462306a36Sopenharmony_ci return pte; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci pte_val(pte) &= ~(_PAGE_ACCESSED); 25062306a36Sopenharmony_ci return pte; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci pte_val(pte) |= _PAGE_WRITE; 25662306a36Sopenharmony_ci return pte; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic inline pte_t pte_mkread(pte_t pte) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci pte_val(pte) |= _PAGE_READ; 26262306a36Sopenharmony_ci return pte; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline pte_t pte_mkexec(pte_t pte) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci pte_val(pte) |= _PAGE_EXEC; 26862306a36Sopenharmony_ci return pte; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci pte_val(pte) |= _PAGE_DIRTY; 27462306a36Sopenharmony_ci return pte; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci pte_val(pte) |= _PAGE_ACCESSED; 28062306a36Sopenharmony_ci return pte; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* 28462306a36Sopenharmony_ci * Conversion functions: convert a page and protection to a page entry, 28562306a36Sopenharmony_ci * and a page entry and page directory to the page they refer to. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* What actually goes as arguments to the various functions is less than 28962306a36Sopenharmony_ci * obvious, but a rule of thumb is that struct page's goes as struct page *, 29062306a36Sopenharmony_ci * really physical DRAM addresses are unsigned long's, and DRAM "virtual" 29162306a36Sopenharmony_ci * addresses (the 0xc0xxxxxx's) goes as void *'s. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic inline pte_t __mk_pte(void *page, pgprot_t pgprot) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci pte_t pte; 29762306a36Sopenharmony_ci /* the PTE needs a physical address */ 29862306a36Sopenharmony_ci pte_val(pte) = __pa(page) | pgprot_val(pgprot); 29962306a36Sopenharmony_ci return pte; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci#define mk_pte(page, pgprot) __mk_pte(page_address(page), (pgprot)) 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci#define mk_pte_phys(physpage, pgprot) \ 30562306a36Sopenharmony_ci({ \ 30662306a36Sopenharmony_ci pte_t __pte; \ 30762306a36Sopenharmony_ci \ 30862306a36Sopenharmony_ci pte_val(__pte) = (physpage) + pgprot_val(pgprot); \ 30962306a36Sopenharmony_ci __pte; \ 31062306a36Sopenharmony_ci}) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); 31562306a36Sopenharmony_ci return pte; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* 32062306a36Sopenharmony_ci * pte_val refers to a page in the 0x0xxxxxxx physical DRAM interval 32162306a36Sopenharmony_ci * __pte_page(pte_val) refers to the "virtual" DRAM interval 32262306a36Sopenharmony_ci * pte_pagenr refers to the page-number counted starting from the virtual 32362306a36Sopenharmony_ci * DRAM start 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic inline unsigned long __pte_page(pte_t pte) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci /* the PTE contains a physical address */ 32962306a36Sopenharmony_ci return (unsigned long)__va(pte_val(pte) & PAGE_MASK); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT) 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* permanent address of a page */ 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT)) 33762306a36Sopenharmony_ci#define pte_page(pte) (mem_map+pte_pagenr(pte)) 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/* 34062306a36Sopenharmony_ci * only the pte's themselves need to point to physical DRAM (see above) 34162306a36Sopenharmony_ci * the pagetable links are purely handled within the kernel SW and thus 34262306a36Sopenharmony_ci * don't need the __pa and __va transformations. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistatic inline void pmd_set(pmd_t *pmdp, pte_t *ptep) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci pmd_val(*pmdp) = _KERNPG_TABLE | (unsigned long) ptep; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci#define pmd_pfn(pmd) (pmd_val(pmd) >> PAGE_SHIFT) 35062306a36Sopenharmony_ci#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic inline unsigned long pmd_page_vaddr(pmd_t pmd) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci#define __pmd_offset(address) \ 35862306a36Sopenharmony_ci (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci#define PFN_PTE_SHIFT PAGE_SHIFT 36162306a36Sopenharmony_ci#define pte_pfn(x) ((unsigned long)(((x).pte)) >> PAGE_SHIFT) 36262306a36Sopenharmony_ci#define pfn_pte(pfn, prot) __pte((((pfn) << PAGE_SHIFT)) | pgprot_val(prot)) 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci#define pte_ERROR(e) \ 36562306a36Sopenharmony_ci printk(KERN_ERR "%s:%d: bad pte %p(%08lx).\n", \ 36662306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pte_val(e)) 36762306a36Sopenharmony_ci#define pgd_ERROR(e) \ 36862306a36Sopenharmony_ci printk(KERN_ERR "%s:%d: bad pgd %p(%08lx).\n", \ 36962306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pgd_val(e)) 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ciextern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistruct vm_area_struct; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic inline void update_tlb(struct vm_area_struct *vma, 37662306a36Sopenharmony_ci unsigned long address, pte_t *pte) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ciextern void update_cache(struct vm_area_struct *vma, 38162306a36Sopenharmony_ci unsigned long address, pte_t *pte); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic inline void update_mmu_cache_range(struct vm_fault *vmf, 38462306a36Sopenharmony_ci struct vm_area_struct *vma, unsigned long address, 38562306a36Sopenharmony_ci pte_t *ptep, unsigned int nr) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci update_tlb(vma, address, ptep); 38862306a36Sopenharmony_ci update_cache(vma, address, ptep); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci#define update_mmu_cache(vma, addr, ptep) \ 39262306a36Sopenharmony_ci update_mmu_cache_range(NULL, vma, addr, ptep, 1) 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/* __PHX__ FIXME, SWAP, this probably doesn't work */ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* 39762306a36Sopenharmony_ci * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that 39862306a36Sopenharmony_ci * are !pte_none() && !pte_present(). 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * Format of swap PTEs: 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 40362306a36Sopenharmony_ci * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 40462306a36Sopenharmony_ci * <-------------- offset ---------------> E <- type --> 0 0 0 0 0 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * E is the exclusive marker that is not stored in swap entries. 40762306a36Sopenharmony_ci * The zero'ed bits include _PAGE_PRESENT. 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci#define __swp_type(x) (((x).val >> 5) & 0x3f) 41062306a36Sopenharmony_ci#define __swp_offset(x) ((x).val >> 12) 41162306a36Sopenharmony_ci#define __swp_entry(type, offset) \ 41262306a36Sopenharmony_ci ((swp_entry_t) { (((type) & 0x3f) << 5) | ((offset) << 12) }) 41362306a36Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) 41462306a36Sopenharmony_ci#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic inline int pte_swp_exclusive(pte_t pte) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic inline pte_t pte_swp_mkexclusive(pte_t pte) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci pte_val(pte) |= _PAGE_SWP_EXCLUSIVE; 42462306a36Sopenharmony_ci return pte; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_exclusive(pte_t pte) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci pte_val(pte) &= ~_PAGE_SWP_EXCLUSIVE; 43062306a36Sopenharmony_ci return pte; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_citypedef pte_t *pte_addr_t; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 43662306a36Sopenharmony_ci#endif /* __ASM_OPENRISC_PGTABLE_H */ 437