Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.12-rc2 352 lines 12 kB view raw
1/* 2 * CRIS pgtable.h - macros and functions to manipulate page tables. 3 */ 4 5#ifndef _CRIS_PGTABLE_H 6#define _CRIS_PGTABLE_H 7 8#include <asm-generic/4level-fixup.h> 9 10#ifndef __ASSEMBLY__ 11#include <linux/config.h> 12#include <linux/sched.h> 13#include <asm/mmu.h> 14#endif 15#include <asm/arch/pgtable.h> 16 17/* 18 * The Linux memory management assumes a three-level page table setup. On 19 * CRIS, we use that, but "fold" the mid level into the top-level page 20 * table. Since the MMU TLB is software loaded through an interrupt, it 21 * supports any page table structure, so we could have used a three-level 22 * setup, but for the amounts of memory we normally use, a two-level is 23 * probably more efficient. 24 * 25 * This file contains the functions and defines necessary to modify and use 26 * the CRIS page table tree. 27 */ 28#ifndef __ASSEMBLY__ 29extern void paging_init(void); 30#endif 31 32/* Certain architectures need to do special things when pte's 33 * within a page table are directly modified. Thus, the following 34 * hook is made available. 35 */ 36#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) 37#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) 38 39/* 40 * (pmds are folded into pgds so this doesn't get actually called, 41 * but the define is needed for a generic inline function.) 42 */ 43#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) 44#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) 45 46/* PMD_SHIFT determines the size of the area a second-level page table can 47 * map. It is equal to the page size times the number of PTE's that fit in 48 * a PMD page. A PTE is 4-bytes in CRIS. Hence the following number. 49 */ 50 51#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-2)) 52#define PMD_SIZE (1UL << PMD_SHIFT) 53#define PMD_MASK (~(PMD_SIZE-1)) 54 55/* PGDIR_SHIFT determines what a third-level page table entry can map. 56 * Since we fold into a two-level structure, this is the same as PMD_SHIFT. 57 */ 58 59#define PGDIR_SHIFT PMD_SHIFT 60#define PGDIR_SIZE (1UL << PGDIR_SHIFT) 61#define PGDIR_MASK (~(PGDIR_SIZE-1)) 62 63/* 64 * entries per page directory level: we use a two-level, so 65 * we don't really have any PMD directory physically. 66 * pointers are 4 bytes so we can use the page size and 67 * divide it by 4 (shift by 2). 68 */ 69#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-2)) 70#define PTRS_PER_PMD 1 71#define PTRS_PER_PGD (1UL << (PAGE_SHIFT-2)) 72 73/* calculate how many PGD entries a user-level program can use 74 * the first mappable virtual address is 0 75 * (TASK_SIZE is the maximum virtual address space) 76 */ 77 78#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) 79#define FIRST_USER_PGD_NR 0 80 81/* zero page used for uninitialized stuff */ 82#ifndef __ASSEMBLY__ 83extern unsigned long empty_zero_page; 84#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) 85#endif 86 87/* number of bits that fit into a memory pointer */ 88#define BITS_PER_PTR (8*sizeof(unsigned long)) 89 90/* to align the pointer to a pointer address */ 91#define PTR_MASK (~(sizeof(void*)-1)) 92 93/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */ 94/* 64-bit machines, beware! SRB. */ 95#define SIZEOF_PTR_LOG2 2 96 97/* to find an entry in a page-table */ 98#define PAGE_PTR(address) \ 99((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) 100 101/* to set the page-dir */ 102#define SET_PAGE_DIR(tsk,pgdir) 103 104#define pte_none(x) (!pte_val(x)) 105#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) 106#define pte_clear(mm,addr,xp) do { pte_val(*(xp)) = 0; } while (0) 107 108#define pmd_none(x) (!pmd_val(x)) 109/* by removing the _PAGE_KERNEL bit from the comparision, the same pmd_bad 110 * works for both _PAGE_TABLE and _KERNPG_TABLE pmd entries. 111 */ 112#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_KERNEL)) != _PAGE_TABLE) 113#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) 114#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) 115 116#ifndef __ASSEMBLY__ 117 118/* 119 * The "pgd_xxx()" functions here are trivial for a folded two-level 120 * setup: the pgd is never bad, and a pmd always exists (as it's folded 121 * into the pgd entry) 122 */ 123extern inline int pgd_none(pgd_t pgd) { return 0; } 124extern inline int pgd_bad(pgd_t pgd) { return 0; } 125extern inline int pgd_present(pgd_t pgd) { return 1; } 126extern inline void pgd_clear(pgd_t * pgdp) { } 127 128/* 129 * The following only work if pte_present() is true. 130 * Undefined behaviour if not.. 131 */ 132 133extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } 134extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } 135extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } 136extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } 137extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } 138extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } 139 140extern inline pte_t pte_wrprotect(pte_t pte) 141{ 142 pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); 143 return pte; 144} 145 146extern inline pte_t pte_rdprotect(pte_t pte) 147{ 148 pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); 149 return pte; 150} 151 152extern inline pte_t pte_exprotect(pte_t pte) 153{ 154 pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); 155 return pte; 156} 157 158extern inline pte_t pte_mkclean(pte_t pte) 159{ 160 pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); 161 return pte; 162} 163 164extern inline pte_t pte_mkold(pte_t pte) 165{ 166 pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); 167 return pte; 168} 169 170extern inline pte_t pte_mkwrite(pte_t pte) 171{ 172 pte_val(pte) |= _PAGE_WRITE; 173 if (pte_val(pte) & _PAGE_MODIFIED) 174 pte_val(pte) |= _PAGE_SILENT_WRITE; 175 return pte; 176} 177 178extern inline pte_t pte_mkread(pte_t pte) 179{ 180 pte_val(pte) |= _PAGE_READ; 181 if (pte_val(pte) & _PAGE_ACCESSED) 182 pte_val(pte) |= _PAGE_SILENT_READ; 183 return pte; 184} 185 186extern inline pte_t pte_mkexec(pte_t pte) 187{ 188 pte_val(pte) |= _PAGE_READ; 189 if (pte_val(pte) & _PAGE_ACCESSED) 190 pte_val(pte) |= _PAGE_SILENT_READ; 191 return pte; 192} 193 194extern inline pte_t pte_mkdirty(pte_t pte) 195{ 196 pte_val(pte) |= _PAGE_MODIFIED; 197 if (pte_val(pte) & _PAGE_WRITE) 198 pte_val(pte) |= _PAGE_SILENT_WRITE; 199 return pte; 200} 201 202extern inline pte_t pte_mkyoung(pte_t pte) 203{ 204 pte_val(pte) |= _PAGE_ACCESSED; 205 if (pte_val(pte) & _PAGE_READ) 206 { 207 pte_val(pte) |= _PAGE_SILENT_READ; 208 if ((pte_val(pte) & (_PAGE_WRITE | _PAGE_MODIFIED)) == 209 (_PAGE_WRITE | _PAGE_MODIFIED)) 210 pte_val(pte) |= _PAGE_SILENT_WRITE; 211 } 212 return pte; 213} 214 215/* 216 * Conversion functions: convert a page and protection to a page entry, 217 * and a page entry and page directory to the page they refer to. 218 */ 219 220/* What actually goes as arguments to the various functions is less than 221 * obvious, but a rule of thumb is that struct page's goes as struct page *, 222 * really physical DRAM addresses are unsigned long's, and DRAM "virtual" 223 * addresses (the 0xc0xxxxxx's) goes as void *'s. 224 */ 225 226extern inline pte_t __mk_pte(void * page, pgprot_t pgprot) 227{ 228 pte_t pte; 229 /* the PTE needs a physical address */ 230 pte_val(pte) = __pa(page) | pgprot_val(pgprot); 231 return pte; 232} 233 234#define mk_pte(page, pgprot) __mk_pte(page_address(page), (pgprot)) 235 236#define mk_pte_phys(physpage, pgprot) \ 237({ \ 238 pte_t __pte; \ 239 \ 240 pte_val(__pte) = (physpage) + pgprot_val(pgprot); \ 241 __pte; \ 242}) 243 244extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 245{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } 246 247 248/* pte_val refers to a page in the 0x4xxxxxxx physical DRAM interval 249 * __pte_page(pte_val) refers to the "virtual" DRAM interval 250 * pte_pagenr refers to the page-number counted starting from the virtual DRAM start 251 */ 252 253extern inline unsigned long __pte_page(pte_t pte) 254{ 255 /* the PTE contains a physical address */ 256 return (unsigned long)__va(pte_val(pte) & PAGE_MASK); 257} 258 259#define pte_pagenr(pte) ((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT) 260 261/* permanent address of a page */ 262 263#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT)) 264#define pte_page(pte) (mem_map+pte_pagenr(pte)) 265 266/* only the pte's themselves need to point to physical DRAM (see above) 267 * the pagetable links are purely handled within the kernel SW and thus 268 * don't need the __pa and __va transformations. 269 */ 270 271extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) 272{ pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; } 273 274#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) 275#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) 276 277/* to find an entry in a page-table-directory. */ 278#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) 279 280/* to find an entry in a page-table-directory */ 281extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) 282{ 283 return mm->pgd + pgd_index(address); 284} 285 286/* to find an entry in a kernel page-table-directory */ 287#define pgd_offset_k(address) pgd_offset(&init_mm, address) 288 289/* Find an entry in the second-level page table.. */ 290extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) 291{ 292 return (pmd_t *) dir; 293} 294 295/* Find an entry in the third-level page table.. */ 296#define __pte_offset(address) \ 297 (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 298#define pte_offset_kernel(dir, address) \ 299 ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) 300#define pte_offset_map(dir, address) \ 301 ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) 302#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address) 303 304#define pte_unmap(pte) do { } while (0) 305#define pte_unmap_nested(pte) do { } while (0) 306#define pte_pfn(x) ((unsigned long)(__va((x).pte)) >> PAGE_SHIFT) 307#define pfn_pte(pfn, prot) __pte((__pa((pfn) << PAGE_SHIFT)) | pgprot_val(prot)) 308 309#define pte_ERROR(e) \ 310 printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), pte_val(e)) 311#define pmd_ERROR(e) \ 312 printk("%s:%d: bad pmd %p(%08lx).\n", __FILE__, __LINE__, &(e), pmd_val(e)) 313#define pgd_ERROR(e) \ 314 printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) 315 316 317extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ 318 319/* 320 * CRIS doesn't have any external MMU info: the kernel page 321 * tables contain all the necessary information. 322 * 323 * Actually I am not sure on what this could be used for. 324 */ 325extern inline void update_mmu_cache(struct vm_area_struct * vma, 326 unsigned long address, pte_t pte) 327{ 328} 329 330/* Encode and de-code a swap entry (must be !pte_none(e) && !pte_present(e)) */ 331/* Since the PAGE_PRESENT bit is bit 4, we can use the bits above */ 332 333#define __swp_type(x) (((x).val >> 5) & 0x7f) 334#define __swp_offset(x) ((x).val >> 12) 335#define __swp_entry(type, offset) ((swp_entry_t) { ((type) << 5) | ((offset) << 12) }) 336#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) 337#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) 338 339#define kern_addr_valid(addr) (1) 340 341#include <asm-generic/pgtable.h> 342 343/* 344 * No page table caches to initialise 345 */ 346#define pgtable_cache_init() do { } while (0) 347 348#define pte_to_pgoff(x) (pte_val(x) >> 6) 349#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) 350 351#endif /* __ASSEMBLY__ */ 352#endif /* _CRIS_PGTABLE_H */