1#ifndef _X86_64_PGALLOC_H 2#define _X86_64_PGALLOC_H 3 4#include <asm/pda.h> 5#include <linux/threads.h> 6#include <linux/mm.h> 7 8#define pmd_populate_kernel(mm, pmd, pte) \ 9 set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))) 10#define pud_populate(mm, pud, pmd) \ 11 set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))) 12#define pgd_populate(mm, pgd, pud) \ 13 set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud))) 14 15static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte) 16{ 17 set_pmd(pmd, __pmd(_PAGE_TABLE | (page_to_pfn(pte) << PAGE_SHIFT))); 18} 19 20static inline void pmd_free(pmd_t *pmd) 21{ 22 BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); 23 free_page((unsigned long)pmd); 24} 25 26static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr) 27{ 28 return (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); 29} 30 31static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) 32{ 33 return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); 34} 35 36static inline void pud_free (pud_t *pud) 37{ 38 BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); 39 free_page((unsigned long)pud); 40} 41 42static inline void pgd_list_add(pgd_t *pgd) 43{ 44 struct page *page = virt_to_page(pgd); 45 46 spin_lock(&pgd_lock); 47 list_add(&page->lru, &pgd_list); 48 spin_unlock(&pgd_lock); 49} 50 51static inline void pgd_list_del(pgd_t *pgd) 52{ 53 struct page *page = virt_to_page(pgd); 54 55 spin_lock(&pgd_lock); 56 list_del(&page->lru); 57 spin_unlock(&pgd_lock); 58} 59 60static inline pgd_t *pgd_alloc(struct mm_struct *mm) 61{ 62 unsigned boundary; 63 pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); 64 if (!pgd) 65 return NULL; 66 pgd_list_add(pgd); 67 /* 68 * Copy kernel pointers in from init. 69 * Could keep a freelist or slab cache of those because the kernel 70 * part never changes. 71 */ 72 boundary = pgd_index(__PAGE_OFFSET); 73 memset(pgd, 0, boundary * sizeof(pgd_t)); 74 memcpy(pgd + boundary, 75 init_level4_pgt + boundary, 76 (PTRS_PER_PGD - boundary) * sizeof(pgd_t)); 77 return pgd; 78} 79 80static inline void pgd_free(pgd_t *pgd) 81{ 82 BUG_ON((unsigned long)pgd & (PAGE_SIZE-1)); 83 pgd_list_del(pgd); 84 free_page((unsigned long)pgd); 85} 86 87static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) 88{ 89 return (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); 90} 91 92static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) 93{ 94 void *p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); 95 if (!p) 96 return NULL; 97 return virt_to_page(p); 98} 99 100/* Should really implement gc for free page table pages. This could be 101 done with a reference count in struct page. */ 102 103static inline void pte_free_kernel(pte_t *pte) 104{ 105 BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); 106 free_page((unsigned long)pte); 107} 108 109static inline void pte_free(struct page *pte) 110{ 111 __free_page(pte); 112} 113 114#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) 115 116#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) 117#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) 118 119#endif /* _X86_64_PGALLOC_H */