home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lxapi32.zip / Include / asm / pgtable.h < prev    next >
C/C++ Source or Header  |  2002-04-26  |  13KB  |  366 lines

  1. /* $Id: pgtable.h,v 1.2 2002/04/26 23:09:20 smilcke Exp $ */
  2.  
  3. #ifndef _I386_PGTABLE_H
  4. #define _I386_PGTABLE_H
  5.  
  6. #include <linux/config.h>
  7.  
  8. /*
  9.  * The Linux memory management assumes a three-level page table setup. On
  10.  * the i386, we use that, but "fold" the mid level into the top-level page
  11.  * table, so that we physically have the same two-level page table as the
  12.  * i386 mmu expects.
  13.  *
  14.  * This file contains the functions and defines necessary to modify and use
  15.  * the i386 page table tree.
  16.  */
  17. #ifndef __ASSEMBLY__
  18. //#include <asm/processor.h>
  19. //#include <asm/fixmap.h>
  20. //#include <linux/threads.h>
  21.  
  22. #ifndef _I386_BITOPS_H
  23. //#include <asm/bitops.h>
  24. #endif
  25.  
  26. extern pgd_t swapper_pg_dir[1024];
  27. extern void paging_init(void);
  28.  
  29. /* Caches aren't brain-dead on the intel. */
  30. #define flush_cache_all()            do { } while (0)
  31. #define flush_cache_mm(mm)            do { } while (0)
  32. #define flush_cache_range(mm, start, end)    do { } while (0)
  33. #define flush_cache_page(vma, vmaddr)        do { } while (0)
  34. #define flush_page_to_ram(page)            do { } while (0)
  35. #define flush_dcache_page(page)            do { } while (0)
  36. #define flush_icache_range(start, end)        do { } while (0)
  37. #define flush_icache_page(vma,pg)        do { } while (0)
  38.  
  39. #define __flush_tlb()                            \
  40.     do {                                \
  41.         unsigned int tmpreg;                    \
  42.                                     \
  43.         __asm__ __volatile__(                    \
  44.             "movl %%cr3, %0;  # flush TLB \n"        \
  45.             "movl %0, %%cr3;              \n"        \
  46.             : "=r" (tmpreg)                    \
  47.             :: "memory");                    \
  48.     } while (0)
  49.  
  50. /*
  51.  * Global pages have to be flushed a bit differently. Not a real
  52.  * performance problem because this does not happen often.
  53.  */
  54. #define __flush_tlb_global()                        \
  55.     do {                                \
  56.         unsigned int tmpreg;                    \
  57.                                     \
  58.         __asm__ __volatile__(                    \
  59.             "movl %1, %%cr4;  # turn off PGE     \n"    \
  60.             "movl %%cr3, %0;  # flush TLB        \n"    \
  61.             "movl %0, %%cr3;                     \n"    \
  62.             "movl %2, %%cr4;  # turn PGE back on \n"    \
  63.             : "=&r" (tmpreg)                \
  64.             : "r" (mmu_cr4_features & ~X86_CR4_PGE),    \
  65.               "r" (mmu_cr4_features)            \
  66.             : "memory");                    \
  67.     } while (0)
  68.  
  69. extern unsigned long pgkern_mask;
  70.  
  71. /*
  72.  * Do not check the PGE bit unnecesserily if this is a PPro+ kernel.
  73.  */
  74. #ifdef CONFIG_X86_PGE
  75. # define __flush_tlb_all() __flush_tlb_global()
  76. #else
  77. # define __flush_tlb_all()                        \
  78.     do {                                \
  79.         if (cpu_has_pge)                    \
  80.             __flush_tlb_global();                \
  81.         else                            \
  82.             __flush_tlb();                    \
  83.     } while (0)
  84. #endif
  85.  
  86. #ifndef CONFIG_X86_INVLPG
  87. #define __flush_tlb_one(addr) __flush_tlb()
  88. #else
  89. #define __flush_tlb_one(addr) \
  90. __asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
  91. #endif
  92.  
  93. /*
  94.  * ZERO_PAGE is a global shared page that is always zero: used
  95.  * for zero-mapped memory areas etc..
  96.  */
  97. extern unsigned long empty_zero_page[1024];
  98. #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
  99.  
  100. #endif /* !__ASSEMBLY__ */
  101.  
  102. /*
  103.  * The Linux x86 paging architecture is 'compile-time dual-mode', it
  104.  * implements both the traditional 2-level x86 page tables and the
  105.  * newer 3-level PAE-mode page tables.
  106.  */
  107. #ifndef __ASSEMBLY__
  108. #if CONFIG_X86_PAE
  109. # include <asm/pgtable-3level.h>
  110.  
  111. /*
  112.  * Need to initialise the X86 PAE caches
  113.  */
  114. extern void pgtable_cache_init(void);
  115.  
  116. #else
  117. //# include <asm/pgtable-2level.h>
  118.  
  119. /*
  120.  * No page table caches to initialise
  121.  */
  122. #define pgtable_cache_init()    do { } while (0)
  123.  
  124. #endif
  125. #endif
  126.  
  127. #define __beep() asm("movb $0x3,%al; outb %al,$0x61")
  128.  
  129. #define PMD_SIZE    (1UL << PMD_SHIFT)
  130. #define PMD_MASK    (~(PMD_SIZE-1))
  131. #define PGDIR_SIZE    (1UL << PGDIR_SHIFT)
  132. #define PGDIR_MASK    (~(PGDIR_SIZE-1))
  133.  
  134. #define USER_PTRS_PER_PGD    (TASK_SIZE/PGDIR_SIZE)
  135. #define FIRST_USER_PGD_NR    0
  136.  
  137. #define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
  138. #define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
  139.  
  140. #define TWOLEVEL_PGDIR_SHIFT    22
  141. #define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
  142. #define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
  143.  
  144.  
  145. #ifndef __ASSEMBLY__
  146. /* Just any arbitrary offset to the start of the vmalloc VM area: the
  147.  * current 8MB value just means that there will be a 8MB "hole" after the
  148.  * physical memory until the kernel virtual memory starts.  That means that
  149.  * any out-of-bounds memory accesses will hopefully be caught.
  150.  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  151.  * area for the same reason. ;)
  152.  */
  153. #define VMALLOC_OFFSET    (8*1024*1024)
  154. #define VMALLOC_START    (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
  155.                         ~(VMALLOC_OFFSET-1))
  156. #define VMALLOC_VMADDR(x) ((unsigned long)(x))
  157. #if CONFIG_HIGHMEM
  158. # define VMALLOC_END    (PKMAP_BASE-2*PAGE_SIZE)
  159. #else
  160. # define VMALLOC_END    (FIXADDR_START-2*PAGE_SIZE)
  161. #endif
  162.  
  163. /*
  164.  * The 4MB page is guessing..  Detailed in the infamous "Chapter H"
  165.  * of the Pentium details, but assuming intel did the straightforward
  166.  * thing, this bit set in the page directory entry just means that
  167.  * the page directory entry points directly to a 4MB-aligned block of
  168.  * memory. 
  169.  */
  170. #define _PAGE_BIT_PRESENT    0
  171. #define _PAGE_BIT_RW        1
  172. #define _PAGE_BIT_USER        2
  173. #define _PAGE_BIT_PWT        3
  174. #define _PAGE_BIT_PCD        4
  175. #define _PAGE_BIT_ACCESSED    5
  176. #define _PAGE_BIT_DIRTY        6
  177. #define _PAGE_BIT_PSE        7    /* 4 MB (or 2MB) page, Pentium+, if present.. */
  178. #define _PAGE_BIT_GLOBAL    8    /* Global TLB entry PPro+ */
  179.  
  180. #define _PAGE_PRESENT    0x001
  181. #define _PAGE_RW    0x002
  182. #define _PAGE_USER    0x004
  183. #define _PAGE_PWT    0x008
  184. #define _PAGE_PCD    0x010
  185. #define _PAGE_ACCESSED    0x020
  186. #define _PAGE_DIRTY    0x040
  187. #define _PAGE_PSE    0x080    /* 4 MB (or 2MB) page, Pentium+, if present.. */
  188. #define _PAGE_GLOBAL    0x100    /* Global TLB entry PPro+ */
  189.  
  190. #define _PAGE_PROTNONE    0x080    /* If not present */
  191.  
  192. #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
  193. #define _KERNPG_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
  194. #define _PAGE_CHG_MASK    (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
  195.  
  196. #define PAGE_NONE    __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
  197. #define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
  198. #define PAGE_COPY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
  199. #define PAGE_READONLY    __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
  200.  
  201. #define __PAGE_KERNEL \
  202.     (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
  203. #define __PAGE_KERNEL_NOCACHE \
  204.     (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED)
  205. #define __PAGE_KERNEL_RO \
  206.     (_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
  207.  
  208. #ifdef CONFIG_X86_PGE
  209. # define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
  210. #else
  211. # define MAKE_GLOBAL(x)                        \
  212.     ({                            \
  213.         pgprot_t __ret;                    \
  214.                                 \
  215.         if (cpu_has_pge)                \
  216.             __ret = __pgprot((x) | _PAGE_GLOBAL);    \
  217.         else                        \
  218.             __ret = __pgprot(x);            \
  219.         __ret;                        \
  220.     })
  221. #endif
  222.  
  223. #define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
  224. #define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
  225. #define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
  226.  
  227. /*
  228.  * The i386 can't do page protection for execute, and considers that
  229.  * the same are read. Also, write permissions imply read permissions.
  230.  * This is the closest we can get..
  231.  */
  232. #define __P000    PAGE_NONE
  233. #define __P001    PAGE_READONLY
  234. #define __P010    PAGE_COPY
  235. #define __P011    PAGE_COPY
  236. #define __P100    PAGE_READONLY
  237. #define __P101    PAGE_READONLY
  238. #define __P110    PAGE_COPY
  239. #define __P111    PAGE_COPY
  240.  
  241. #define __S000    PAGE_NONE
  242. #define __S001    PAGE_READONLY
  243. #define __S010    PAGE_SHARED
  244. #define __S011    PAGE_SHARED
  245. #define __S100    PAGE_READONLY
  246. #define __S101    PAGE_READONLY
  247. #define __S110    PAGE_SHARED
  248. #define __S111    PAGE_SHARED
  249.  
  250. /*
  251.  * Define this if things work differently on an i386 and an i486:
  252.  * it will (on an i486) warn about kernel memory accesses that are
  253.  * done without a 'verify_area(VERIFY_WRITE,..)'
  254.  */
  255. #undef TEST_VERIFY_AREA
  256.  
  257. /* page table for 0-4MB for everybody */
  258. extern unsigned long pg0[1024];
  259.  
  260. #define pte_present(x)    ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE))
  261. #define pte_clear(xp)    do { set_pte(xp, __pte(0)); } while (0)
  262.  
  263. #define pmd_none(x)    (!pmd_val(x))
  264. #define pmd_present(x)    (pmd_val(x) & _PAGE_PRESENT)
  265. #define pmd_clear(xp)    do { set_pmd(xp, __pmd(0)); } while (0)
  266. #define    pmd_bad(x)    ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
  267.  
  268. /*
  269.  * Permanent address of a page. Obviously must never be
  270.  * called on a highmem page.
  271.  */
  272. #define page_address(page) ((page)->virtual)
  273. #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
  274.  
  275. /*
  276.  * The following only work if pte_present() is true.
  277.  * Undefined behaviour if not..
  278.  */
  279. #ifndef TARGET_OS2
  280. static __inline__ int pte_read(pte_t pte)        { return (pte).pte_low & _PAGE_USER; }
  281. static __inline__ int pte_exec(pte_t pte)        { return (pte).pte_low & _PAGE_USER; }
  282. static __inline__ int pte_dirty(pte_t pte)        { return (pte).pte_low & _PAGE_DIRTY; }
  283. static __inline__ int pte_young(pte_t pte)        { return (pte).pte_low & _PAGE_ACCESSED; }
  284. static __inline__ int pte_write(pte_t pte)        { return (pte).pte_low & _PAGE_RW; }
  285.  
  286. static __inline__ pte_t pte_rdprotect(pte_t pte)    { (pte).pte_low &= ~_PAGE_USER; return pte; }
  287. static __inline__ pte_t pte_exprotect(pte_t pte)    { (pte).pte_low &= ~_PAGE_USER; return pte; }
  288. static __inline__ pte_t pte_mkclean(pte_t pte)    { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
  289. static __inline__ pte_t pte_mkold(pte_t pte)    { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
  290. static __inline__ pte_t pte_wrprotect(pte_t pte)    { (pte).pte_low &= ~_PAGE_RW; return pte; }
  291. static __inline__ pte_t pte_mkread(pte_t pte)    { (pte).pte_low |= _PAGE_USER; return pte; }
  292. static __inline__ pte_t pte_mkexec(pte_t pte)    { (pte).pte_low |= _PAGE_USER; return pte; }
  293. static __inline__ pte_t pte_mkdirty(pte_t pte)    { (pte).pte_low |= _PAGE_DIRTY; return pte; }
  294. static __inline__ pte_t pte_mkyoung(pte_t pte)    { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
  295. static __inline__ pte_t pte_mkwrite(pte_t pte)    { (pte).pte_low |= _PAGE_RW; return pte; }
  296.  
  297. static __inline__  int ptep_test_and_clear_dirty(pte_t *ptep)    { return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep); }
  298. static __inline__  int ptep_test_and_clear_young(pte_t *ptep)    { return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
  299. static __inline__ void ptep_set_wrprotect(pte_t *ptep)        { clear_bit(_PAGE_BIT_RW, ptep); }
  300. static __inline__ void ptep_mkdirty(pte_t *ptep)            { set_bit(_PAGE_BIT_DIRTY, ptep); }
  301.  
  302. /*
  303.  * Conversion functions: convert a page and protection to a page entry,
  304.  * and a page entry and page directory to the page they refer to.
  305.  */
  306.  
  307. #define mk_pte(page, pgprot)    __mk_pte((page) - mem_map, (pgprot))
  308.  
  309. /* This takes a physical page address that is used by the remapping functions */
  310. #define mk_pte_phys(physpage, pgprot)    __mk_pte((physpage) >> PAGE_SHIFT, pgprot)
  311.  
  312. static __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
  313. {
  314.     pte.pte_low &= _PAGE_CHG_MASK;
  315.     pte.pte_low |= pgprot_val(newprot);
  316.     return pte;
  317. }
  318.  
  319. #define page_pte(page) page_pte_prot(page, __pgprot(0))
  320.  
  321. #define pmd_page(pmd) \
  322. ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
  323.  
  324. /* to find an entry in a page-table-directory. */
  325. #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
  326.  
  327. #define __pgd_offset(address) pgd_index(address)
  328.  
  329. #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
  330.  
  331. /* to find an entry in a kernel page-table-directory */
  332. #define pgd_offset_k(address) pgd_offset(&init_mm, address)
  333.  
  334. #define __pmd_offset(address) \
  335.         (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
  336.  
  337. /* Find an entry in the third-level page table.. */
  338. #define __pte_offset(address) \
  339.         ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
  340. #define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \
  341.             __pte_offset(address))
  342.  
  343. /*
  344.  * The i386 doesn't have any external MMU info: the kernel page
  345.  * tables contain all the necessary information.
  346.  */
  347. #define update_mmu_cache(vma,address,pte) do { } while (0)
  348.  
  349. /* Encode and de-code a swap entry */
  350. #define SWP_TYPE(x)            (((x).val >> 1) & 0x3f)
  351. #define SWP_OFFSET(x)            ((x).val >> 8)
  352. #define SWP_ENTRY(type, offset)        ((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
  353. #define pte_to_swp_entry(pte)        ((swp_entry_t) { (pte).pte_low })
  354. #define swp_entry_to_pte(x)        ((pte_t) { (x).val })
  355.  
  356. #endif /* !__ASSEMBLY__ */
  357.  
  358. /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
  359. #define PageSkip(page)        (0)
  360. #define kern_addr_valid(addr)    (1)
  361.  
  362. #define io_remap_page_range remap_page_range
  363. #endif
  364.  
  365. #endif /* _I386_PGTABLE_H */
  366.