home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / include / asm-i386 / pgtable.h < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-07  |  11.9 KB  |  360 lines

  1. #ifndef _I386_PGTABLE_H
  2. #define _I386_PGTABLE_H
  3.  
  4. /*
  5.  * The Linux memory management assumes a three-level page table setup. On
  6.  * the i386, we use that, but "fold" the mid level into the top-level page
  7.  * table, so that we physically have the same two-level page table as the
  8.  * i386 mmu expects.
  9.  *
  10.  * This file contains the functions and defines necessary to modify and use
  11.  * the i386 page table tree.
  12.  */
  13.  
  14. /* PMD_SHIFT determines the size of the area a second-level page table can map */
  15. #define PMD_SHIFT    22
  16. #define PMD_SIZE    (1UL << PMD_SHIFT)
  17. #define PMD_MASK    (~(PMD_SIZE-1))
  18.  
  19. /* PGDIR_SHIFT determines what a third-level page table entry can map */
  20. #define PGDIR_SHIFT    22
  21. #define PGDIR_SIZE    (1UL << PGDIR_SHIFT)
  22. #define PGDIR_MASK    (~(PGDIR_SIZE-1))
  23.  
  24. /*
  25.  * entries per page directory level: the i386 is two-level, so
  26.  * we don't really have any PMD directory physically.
  27.  */
  28. #define PTRS_PER_PTE    1024
  29. #define PTRS_PER_PMD    1
  30. #define PTRS_PER_PGD    1024
  31.  
  32. /* Just any arbitrary offset to the start of the vmalloc VM area: the
  33.  * current 8MB value just means that there will be a 8MB "hole" after the
  34.  * physical memory until the kernel virtual memory starts.  That means that
  35.  * any out-of-bounds memory accesses will hopefully be caught.
  36.  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  37.  * area for the same reason. ;)
  38.  */
  39. #define VMALLOC_OFFSET    (8*1024*1024)
  40. #define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
  41. #define VMALLOC_VMADDR(x) (TASK_SIZE + (unsigned long)(x))
  42.  
  43. #define _PAGE_PRESENT    0x001
  44. #define _PAGE_RW    0x002
  45. #define _PAGE_USER    0x004
  46. #define _PAGE_PCD    0x010
  47. #define _PAGE_ACCESSED    0x020
  48. #define _PAGE_DIRTY    0x040
  49. #define _PAGE_COW    0x200    /* implemented in software (one of the AVL bits) */
  50.  
  51. #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
  52. #define _PAGE_CHG_MASK    (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
  53.  
  54. #define PAGE_NONE    __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
  55. #define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
  56. #define PAGE_COPY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
  57. #define PAGE_READONLY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
  58. #define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
  59.  
  60. /*
  61.  * The i386 can't do page protection for execute, and considers that the same are read.
  62.  * Also, write permissions imply read permissions. This is the closest we can get..
  63.  */
  64. #define __P000    PAGE_NONE
  65. #define __P001    PAGE_READONLY
  66. #define __P010    PAGE_COPY
  67. #define __P011    PAGE_COPY
  68. #define __P100    PAGE_READONLY
  69. #define __P101    PAGE_READONLY
  70. #define __P110    PAGE_COPY
  71. #define __P111    PAGE_COPY
  72.  
  73. #define __S000    PAGE_NONE
  74. #define __S001    PAGE_READONLY
  75. #define __S010    PAGE_SHARED
  76. #define __S011    PAGE_SHARED
  77. #define __S100    PAGE_READONLY
  78. #define __S101    PAGE_READONLY
  79. #define __S110    PAGE_SHARED
  80. #define __S111    PAGE_SHARED
  81.  
  82. /*
  83.  * Define this if things work differently on a i386 and a i486:
  84.  * it will (on a i486) warn about kernel memory accesses that are
  85.  * done without a 'verify_area(VERIFY_WRITE,..)'
  86.  */
  87. #undef CONFIG_TEST_VERIFY_AREA
  88.  
  89. /* page table for 0-4MB for everybody */
  90. extern unsigned long pg0[1024];
  91.  
  92. /*
  93.  * BAD_PAGETABLE is used when we need a bogus page-table, while
  94.  * BAD_PAGE is used for a bogus page.
  95.  *
  96.  * ZERO_PAGE is a global shared page that is always zero: used
  97.  * for zero-mapped memory areas etc..
  98.  */
  99. extern pte_t __bad_page(void);
  100. extern pte_t * __bad_pagetable(void);
  101.  
  102. extern unsigned long __zero_page(void);
  103.  
  104. #define BAD_PAGETABLE __bad_pagetable()
  105. #define BAD_PAGE __bad_page()
  106. #define ZERO_PAGE __zero_page()
  107.  
  108. /* number of bits that fit into a memory pointer */
  109. #define BITS_PER_PTR            (8*sizeof(unsigned long))
  110.  
  111. /* to align the pointer to a pointer address */
  112. #define PTR_MASK            (~(sizeof(void*)-1))
  113.  
  114. /* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
  115. /* 64-bit machines, beware!  SRB. */
  116. #define SIZEOF_PTR_LOG2            2
  117.  
  118. /* to find an entry in a page-table */
  119. #define PAGE_PTR(address) \
  120. ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
  121.  
  122. /* to set the page-dir */
  123. #define SET_PAGE_DIR(tsk,pgdir) \
  124. do { \
  125.     (tsk)->tss.cr3 = (unsigned long) (pgdir); \
  126.     if ((tsk) == current) \
  127.         __asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \
  128. } while (0)
  129.  
  130. extern unsigned long high_memory;
  131.  
  132. extern inline int pte_none(pte_t pte)        { return !pte_val(pte); }
  133. extern inline int pte_present(pte_t pte)    { return pte_val(pte) & _PAGE_PRESENT; }
  134. extern inline int pte_inuse(pte_t *ptep)    { return mem_map[MAP_NR(ptep)] != 1; }
  135. extern inline void pte_clear(pte_t *ptep)    { pte_val(*ptep) = 0; }
  136. extern inline void pte_reuse(pte_t * ptep)
  137. {
  138.     if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
  139.         mem_map[MAP_NR(ptep)]++;
  140. }
  141.  
  142. extern inline int pmd_none(pmd_t pmd)        { return !pmd_val(pmd); }
  143. extern inline int pmd_bad(pmd_t pmd)        { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
  144. extern inline int pmd_present(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_PRESENT; }
  145. extern inline int pmd_inuse(pmd_t *pmdp)    { return 0; }
  146. extern inline void pmd_clear(pmd_t * pmdp)    { pmd_val(*pmdp) = 0; }
  147. extern inline void pmd_reuse(pmd_t * pmdp)    { }
  148.  
  149. #ifdef THREE_LEVEL
  150. /*
  151.  * The "pgd_xxx()" functions here are trivial for a folded two-level
  152.  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  153.  * into the pgd entry)
  154.  */
  155. extern inline int pgd_none(pgd_t pgd)        { return 0; }
  156. extern inline int pgd_bad(pgd_t pgd)        { return 0; }
  157. extern inline int pgd_present(pgd_t pgd)    { return 1; }
  158. extern inline int pgd_inuse(pgd_t * pgdp)    { return mem_map[MAP_NR(pgdp)] != 1; }
  159. extern inline void pgd_clear(pgd_t * pgdp)    { }
  160. extern inline void pgd_reuse(pgd_t * pgdp)
  161. {
  162.     if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
  163.         mem_map[MAP_NR(pgdp)]++;
  164. }
  165. #else
  166. /*
  167.  * These are the old (and incorrect) ones needed for code that doesn't
  168.  * know about three-level yet..
  169.  */
  170. extern inline int pgd_none(pgd_t pgd)        { return !pgd_val(pgd); }
  171. extern inline int pgd_bad(pgd_t pgd)        { return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
  172. extern inline int pgd_present(pgd_t pgd)    { return pgd_val(pgd) & _PAGE_PRESENT; }
  173. extern inline void pgd_clear(pgd_t * pgdp)    { pgd_val(*pgdp) = 0; }
  174. #endif
  175.  
  176. /*
  177.  * The following only work if pte_present() is true.
  178.  * Undefined behaviour if not..
  179.  */
  180. extern inline int pte_read(pte_t pte)        { return pte_val(pte) & _PAGE_USER; }
  181. extern inline int pte_write(pte_t pte)        { return pte_val(pte) & _PAGE_RW; }
  182. extern inline int pte_exec(pte_t pte)        { return pte_val(pte) & _PAGE_USER; }
  183. extern inline int pte_dirty(pte_t pte)        { return pte_val(pte) & _PAGE_DIRTY; }
  184. extern inline int pte_young(pte_t pte)        { return pte_val(pte) & _PAGE_ACCESSED; }
  185. extern inline int pte_cow(pte_t pte)        { return pte_val(pte) & _PAGE_COW; }
  186.  
  187. extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_RW; return pte; }
  188. extern inline pte_t pte_rdprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_USER; return pte; }
  189. extern inline pte_t pte_exprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_USER; return pte; }
  190. extern inline pte_t pte_mkclean(pte_t pte)    { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
  191. extern inline pte_t pte_mkold(pte_t pte)    { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
  192. extern inline pte_t pte_uncow(pte_t pte)    { pte_val(pte) &= ~_PAGE_COW; return pte; }
  193. extern inline pte_t pte_mkwrite(pte_t pte)    { pte_val(pte) |= _PAGE_RW; return pte; }
  194. extern inline pte_t pte_mkread(pte_t pte)    { pte_val(pte) |= _PAGE_USER; return pte; }
  195. extern inline pte_t pte_mkexec(pte_t pte)    { pte_val(pte) |= _PAGE_USER; return pte; }
  196. extern inline pte_t pte_mkdirty(pte_t pte)    { pte_val(pte) |= _PAGE_DIRTY; return pte; }
  197. extern inline pte_t pte_mkyoung(pte_t pte)    { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
  198. extern inline pte_t pte_mkcow(pte_t pte)    { pte_val(pte) |= _PAGE_COW; return pte; }
  199.  
  200. /*
  201.  * Conversion functions: convert a page and protection to a page entry,
  202.  * and a page entry and page directory to the page they refer to.
  203.  */
  204. extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
  205. { pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
  206.  
  207. extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  208. { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
  209.  
  210. extern inline unsigned long pte_page(pte_t pte)
  211. { return pte_val(pte) & PAGE_MASK; }
  212.  
  213. extern inline unsigned long pmd_page(pmd_t pmd)
  214. { return pmd_val(pmd) & PAGE_MASK; }
  215.  
  216. #ifndef THREE_LEVEL
  217.  
  218. extern inline unsigned long pgd_page(pgd_t pgd)
  219. { return pgd_val(pgd) & PAGE_MASK; }
  220.  
  221. extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
  222. { pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
  223.  
  224. #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
  225.  
  226. /* the no. of pointers that fit on a page: this will go away */
  227. #define PTRS_PER_PAGE    (PAGE_SIZE/sizeof(void*))
  228.  
  229. #endif
  230.  
  231. /* to find an entry in a page-table-directory */
  232. extern inline pgd_t * pgd_offset(struct task_struct * tsk, unsigned long address)
  233. {
  234.     return (pgd_t *) tsk->tss.cr3 + (address >> PGDIR_SHIFT);
  235. }
  236.  
  237. /* Find an entry in the second-level page table.. */
  238. extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
  239. {
  240.     return (pmd_t *) dir;
  241. }
  242.  
  243. /* Find an entry in the third-level page table.. */ 
  244. extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
  245. {
  246.     return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
  247. }
  248.  
  249. /*
  250.  * Allocate and free page tables. The xxx_kernel() versions are
  251.  * used to allocate a kernel page table - this turns on ASN bits
  252.  * if any, and marks the page tables reserved.
  253.  */
  254. extern inline void pte_free_kernel(pte_t * pte)
  255. {
  256.     mem_map[MAP_NR(pte)] = 1;
  257.     free_page((unsigned long) pte);
  258. }
  259.  
  260. extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
  261. {
  262.     address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
  263.     if (pmd_none(*pmd)) {
  264.         pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
  265.         if (pmd_none(*pmd)) {
  266.             if (page) {
  267.                 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
  268.                 mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
  269.                 return page + address;
  270.             }
  271.             pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
  272.             return NULL;
  273.         }
  274.         free_page((unsigned long) page);
  275.     }
  276.     if (pmd_bad(*pmd)) {
  277.         printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
  278.         pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
  279.         return NULL;
  280.     }
  281.     return (pte_t *) pmd_page(*pmd) + address;
  282. }
  283.  
  284. /*
  285.  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  286.  * inside the pgd, so has no extra memory associated with it.
  287.  */
  288. extern inline void pmd_free_kernel(pmd_t * pmd)
  289. {
  290. }
  291.  
  292. extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
  293. {
  294.     return (pmd_t *) pgd;
  295. }
  296.  
  297. extern inline void pte_free(pte_t * pte)
  298. {
  299.     free_page((unsigned long) pte);
  300. }
  301.  
  302. extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
  303. {
  304.     address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
  305.     if (pmd_none(*pmd)) {
  306.         pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
  307.         if (pmd_none(*pmd)) {
  308.             if (page) {
  309.                 pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
  310.                 return page + address;
  311.             }
  312.             pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
  313.             return NULL;
  314.         }
  315.         free_page((unsigned long) page);
  316.     }
  317.     if (pmd_bad(*pmd)) {
  318.         printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
  319.         pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
  320.         return NULL;
  321.     }
  322.     return (pte_t *) pmd_page(*pmd) + address;
  323. }
  324.  
  325. /*
  326.  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  327.  * inside the pgd, so has no extra memory associated with it.
  328.  */
  329. extern inline void pmd_free(pmd_t * pmd)
  330. {
  331. }
  332.  
  333. extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
  334. {
  335.     return (pmd_t *) pgd;
  336. }
  337.  
  338. extern inline void pgd_free(pgd_t * pgd)
  339. {
  340.     free_page((unsigned long) pgd);
  341. }
  342.  
  343. extern inline pgd_t * pgd_alloc(void)
  344. {
  345.     return (pgd_t *) get_free_page(GFP_KERNEL);
  346. }
  347.  
  348. extern pgd_t swapper_pg_dir[1024];
  349.  
  350. /*
  351.  * The i386 doesn't have any external MMU info: the kernel page
  352.  * tables contain all the necessary information.
  353.  */
  354. extern inline void update_mmu_cache(struct vm_area_struct * vma,
  355.     unsigned long address, pte_t pte)
  356. {
  357. }
  358.  
  359. #endif /* _I386_PAGE_H */
  360.