From 546db14ee74118296f425f3b91634fb767d67290 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 27 Jan 2000 01:05:20 +0000 Subject: Merge with Linux 2.3.23. The new bootmem stuff has broken various platforms. At this time I've only verified that IP22 support compiles and IP27 actually works. --- include/asm-i386/pgtable-3level.h | 131 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 include/asm-i386/pgtable-3level.h (limited to 'include/asm-i386/pgtable-3level.h') diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h new file mode 100644 index 000000000..99d718115 --- /dev/null +++ b/include/asm-i386/pgtable-3level.h @@ -0,0 +1,131 @@ +#ifndef _I386_PGTABLE_3LEVEL_H +#define _I386_PGTABLE_3LEVEL_H + +/* + * Intel Physical Address Extension (PAE) Mode - three-level page + * tables on PPro+ CPUs. + * + * Copyright (C) 1999 Ingo Molnar + */ + +/* + * PGDIR_SHIFT determines what a top-level page table entry can map + */ +#define PGDIR_SHIFT 30 +#define PTRS_PER_PGD 4 + +/* + * PMD_SHIFT determines the size of the area a middle-level + * page table can map + */ +#define PMD_SHIFT 21 +#define PTRS_PER_PMD 512 + +/* + * entries per page directory level + */ +#define PTRS_PER_PTE 512 + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e)) +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %016Lx.\n", __FILE__, __LINE__, pmd_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %016Lx.\n", __FILE__, __LINE__, pgd_val(e)) + +/* + * Subtle, in PAE mode we cannot have zeroes in the top level + * page directory, the CPU enforces this. + */ +#define pgd_none(x) (pgd_val(x) == 1ULL) +extern inline int pgd_bad(pgd_t pgd) { return 0; } +extern inline int pgd_present(pgd_t pgd) { return !pgd_none(pgd); } +/* + * Pentium-II errata A13: in PAE mode we explicitly have to flush + * the TLB via cr3 if the top-level pgd is changed... This was one tough + * thing to find out - guess i should first read all the documentation + * next time around ;) + */ +extern inline void __pgd_clear (pgd_t * pgd) +{ + pgd_val(*pgd) = 1; // no zero allowed! +} + +extern inline void pgd_clear (pgd_t * pgd) +{ + __pgd_clear(pgd); + __flush_tlb(); +} + +#define pgd_page(pgd) \ +((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) + +/* Find an entry in the second-level page table.. */ +#define pmd_offset(dir, address) ((pmd_t *) pgd_page(*(dir)) + \ + __pmd_offset(address)) + +extern __inline__ pmd_t *get_pmd_slow(void) +{ + pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL); + + if (ret) + memset(ret, 0, PAGE_SIZE); + return ret; +} + +extern __inline__ pmd_t *get_pmd_fast(void) +{ + unsigned long *ret; + + if ((ret = pmd_quicklist) != NULL) { + pmd_quicklist = (unsigned long *)(*ret); + ret[0] = 0; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pmd_slow(); + return (pmd_t *)ret; +} + +extern __inline__ void free_pmd_fast(pmd_t *pmd) +{ + *(unsigned long *)pmd = (unsigned long) pmd_quicklist; + pmd_quicklist = (unsigned long *) pmd; + pgtable_cache_size++; +} + +extern __inline__ void free_pmd_slow(pmd_t *pmd) +{ + free_page((unsigned long)pmd); +} + +extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) +{ + if (!pgd) + BUG(); + address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); + if (pgd_none(*pgd)) { + pmd_t *page = get_pmd_fast(); + + if (!page) + page = get_pmd_slow(); + if (page) { + if (pgd_none(*pgd)) { + pgd_val(*pgd) = 1 + __pa(page); + __flush_tlb(); + return page + address; + } else + free_pmd_fast(page); + } else + return NULL; + } + return (pmd_t *)pgd_page(*pgd) + address; +} + +/* + * Subtle. offset can overflow 32 bits and that's a feature - we can do + * up to 16 TB swap on PAE. (Not that anyone should need that much + * swapspace, but who knows?) + */ +#define SWP_ENTRY(type,offset) __pte((((type) << 1) | ((offset) << 8ULL))) + +#endif /* _I386_PGTABLE_3LEVEL_H */ -- cgit v1.2.3