2009-03-11 01:53:29 +08:00
|
|
|
/* To be include by pgtable-hash64.h only */
|
2005-11-07 08:06:55 +08:00
|
|
|
|
|
|
|
/* Additional PTE bits (don't change without checking asm in hash_low.S) */
|
2008-07-28 11:28:03 +08:00
|
|
|
#define _PAGE_SPECIAL 0x00000400 /* software: special page */
|
2005-11-07 08:06:55 +08:00
|
|
|
#define _PAGE_HPTE_SUB 0x0ffff000 /* combo only: sub pages HPTE bits */
|
|
|
|
#define _PAGE_HPTE_SUB0 0x08000000 /* combo only: first sub page */
|
|
|
|
#define _PAGE_COMBO 0x10000000 /* this is a combo 4k page */
|
[POWERPC] Allow drivers to map individual 4k pages to userspace
Some drivers have resources that they want to be able to map into
userspace that are 4k in size. On a kernel configured with 64k pages
we currently end up mapping the 4k we want plus another 60k of
physical address space, which could contain anything. This can
introduce security problems, for example in the case of an infiniband
adaptor where the other 60k could contain registers that some other
program is using for its communications.
This patch adds a new function, remap_4k_pfn, which drivers can use to
map a single 4k page to userspace regardless of whether the kernel is
using a 4k or a 64k page size. Like remap_pfn_range, it would
typically be called in a driver's mmap function. It only maps a
single 4k page, which on a 64k page kernel appears replicated 16 times
throughout a 64k page. On a 4k page kernel it reduces to a call to
remap_pfn_range.
The way this works on a 64k kernel is that a new bit, _PAGE_4K_PFN,
gets set on the linux PTE. This alters the way that __hash_page_4K
computes the real address to put in the HPTE. The RPN field of the
linux PTE becomes the 4k RPN directly rather than being interpreted as
a 64k RPN. Since the RPN field is 32 bits, this means that physical
addresses being mapped with remap_4k_pfn have to be below 2^44,
i.e. 0x100000000000.
The patch also factors out the code in arch/powerpc/mm/hash_utils_64.c
that deals with demoting a process to use 4k pages into one function
that gets called in the various different places where we need to do
that. There were some discrepancies between exactly what was done in
the various places, such as a call to spu_flush_all_slbs in one case
but not in others.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-04-03 19:24:02 +08:00
|
|
|
#define _PAGE_4K_PFN 0x20000000 /* PFN is for a single 4k page */
|
2007-05-08 14:27:28 +08:00
|
|
|
|
2008-06-11 13:37:10 +08:00
|
|
|
/* For 64K page, we don't have a separate _PAGE_HASHPTE bit. Instead,
|
|
|
|
* we set that to be the whole sub-bits mask. The C code will only
|
|
|
|
* test this, so a multi-bit mask will work. For combo pages, this
|
|
|
|
* is equivalent as effectively, the old _PAGE_HASHPTE was an OR of
|
|
|
|
* all the sub bits. For real 64k pages, we now have the assembly set
|
|
|
|
* _PAGE_HPTE_SUB0 in addition to setting the HIDX bits which overlap
|
|
|
|
* that mask. This is fine as long as the HIDX bits are never set on
|
|
|
|
* a PTE that isn't hashed, which is the case today.
|
|
|
|
*
|
|
|
|
* A little nit is for the huge page C code, which does the hashing
|
|
|
|
* in C, we need to provide which bit to use.
|
|
|
|
*/
|
|
|
|
#define _PAGE_HASHPTE _PAGE_HPTE_SUB
|
|
|
|
|
2007-05-08 14:27:28 +08:00
|
|
|
/* Note the full page bits must be in the same location as for normal
|
|
|
|
* 4k pages as the same asssembly will be used to insert 64K pages
|
|
|
|
* wether the kernel has CONFIG_PPC_64K_PAGES or not
|
|
|
|
*/
|
2005-11-07 08:06:55 +08:00
|
|
|
#define _PAGE_F_SECOND 0x00008000 /* full page: hidx bits */
|
|
|
|
#define _PAGE_F_GIX 0x00007000 /* full page: hidx bits */
|
|
|
|
|
|
|
|
/* PTE flags to conserve for HPTE identification */
|
2008-06-11 13:37:10 +08:00
|
|
|
#define _PAGE_HPTEFLAGS (_PAGE_BUSY | _PAGE_HASHPTE | _PAGE_COMBO)
|
2005-11-07 08:06:55 +08:00
|
|
|
|
|
|
|
/* Shift to put page number into pte.
|
|
|
|
*
|
2007-08-03 12:08:24 +08:00
|
|
|
* That gives us a max RPN of 34 bits, which means a max of 50 bits
|
|
|
|
* of addressable physical space, or 46 bits for the special 4k PFNs.
|
2005-11-07 08:06:55 +08:00
|
|
|
*/
|
2007-08-03 12:08:24 +08:00
|
|
|
#define PTE_RPN_SHIFT (30)
|
2005-11-07 08:06:55 +08:00
|
|
|
|
2009-03-11 01:53:29 +08:00
|
|
|
#ifndef __ASSEMBLY__
|
2005-11-07 08:06:55 +08:00
|
|
|
|
2009-03-11 01:53:29 +08:00
|
|
|
/*
|
|
|
|
* With 64K pages on hash table, we have a special PTE format that
|
|
|
|
* uses a second "half" of the page table to encode sub-page information
|
|
|
|
* in order to deal with 64K made of 4K HW pages. Thus we override the
|
|
|
|
* generic accessors and iterators here
|
|
|
|
*/
|
2005-11-07 08:06:55 +08:00
|
|
|
#define __real_pte(e,p) ((real_pte_t) { \
|
|
|
|
(e), pte_val(*((p) + PTRS_PER_PTE)) })
|
|
|
|
#define __rpte_to_hidx(r,index) ((pte_val((r).pte) & _PAGE_COMBO) ? \
|
|
|
|
(((r).hidx >> ((index)<<2)) & 0xf) : ((pte_val((r).pte) >> 12) & 0xf))
|
|
|
|
#define __rpte_to_pte(r) ((r).pte)
|
|
|
|
#define __rpte_sub_valid(rpte, index) \
|
|
|
|
(pte_val(rpte.pte) & (_PAGE_HPTE_SUB0 >> (index)))
|
|
|
|
|
|
|
|
/* Trick: we set __end to va + 64k, which happens works for
|
|
|
|
* a 16M page as well as we want only one iteration
|
|
|
|
*/
|
|
|
|
#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
|
|
|
|
do { \
|
|
|
|
unsigned long __end = va + PAGE_SIZE; \
|
|
|
|
unsigned __split = (psize == MMU_PAGE_4K || \
|
|
|
|
psize == MMU_PAGE_64K_AP); \
|
|
|
|
shift = mmu_psize_defs[psize].shift; \
|
2008-07-24 12:27:55 +08:00
|
|
|
for (index = 0; va < __end; index++, va += (1L << shift)) { \
|
2005-11-07 08:06:55 +08:00
|
|
|
if (!__split || __rpte_sub_valid(rpte, index)) do { \
|
|
|
|
|
|
|
|
#define pte_iterate_hashed_end() } while(0); } } while(0)
|
|
|
|
|
2007-05-08 14:27:28 +08:00
|
|
|
#define pte_pagesize_index(mm, addr, pte) \
|
2006-06-15 08:45:18 +08:00
|
|
|
(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
|
2005-11-07 08:06:55 +08:00
|
|
|
|
[POWERPC] Allow drivers to map individual 4k pages to userspace
Some drivers have resources that they want to be able to map into
userspace that are 4k in size. On a kernel configured with 64k pages
we currently end up mapping the 4k we want plus another 60k of
physical address space, which could contain anything. This can
introduce security problems, for example in the case of an infiniband
adaptor where the other 60k could contain registers that some other
program is using for its communications.
This patch adds a new function, remap_4k_pfn, which drivers can use to
map a single 4k page to userspace regardless of whether the kernel is
using a 4k or a 64k page size. Like remap_pfn_range, it would
typically be called in a driver's mmap function. It only maps a
single 4k page, which on a 64k page kernel appears replicated 16 times
throughout a 64k page. On a 4k page kernel it reduces to a call to
remap_pfn_range.
The way this works on a 64k kernel is that a new bit, _PAGE_4K_PFN,
gets set on the linux PTE. This alters the way that __hash_page_4K
computes the real address to put in the HPTE. The RPN field of the
linux PTE becomes the 4k RPN directly rather than being interpreted as
a 64k RPN. Since the RPN field is 32 bits, this means that physical
addresses being mapped with remap_4k_pfn have to be below 2^44,
i.e. 0x100000000000.
The patch also factors out the code in arch/powerpc/mm/hash_utils_64.c
that deals with demoting a process to use 4k pages into one function
that gets called in the various different places where we need to do
that. There were some discrepancies between exactly what was done in
the various places, such as a call to spu_flush_all_slbs in one case
but not in others.
Signed-off-by: Paul Mackerras <paulus@samba.org>
2007-04-03 19:24:02 +08:00
|
|
|
#define remap_4k_pfn(vma, addr, pfn, prot) \
|
|
|
|
remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
|
|
|
|
__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
|
|
|
|
|
2009-03-11 01:53:29 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_PPC_SUBPAGE_PROT
|
|
|
|
/*
|
|
|
|
* For the sub-page protection option, we extend the PGD with one of
|
|
|
|
* these. Basically we have a 3-level tree, with the top level being
|
|
|
|
* the protptrs array. To optimize speed and memory consumption when
|
|
|
|
* only addresses < 4GB are being protected, pointers to the first
|
|
|
|
* four pages of sub-page protection words are stored in the low_prot
|
|
|
|
* array.
|
|
|
|
* Each page of sub-page protection words protects 1GB (4 bytes
|
|
|
|
* protects 64k). For the 3-level tree, each page of pointers then
|
|
|
|
* protects 8TB.
|
|
|
|
*/
|
|
|
|
struct subpage_prot_table {
|
|
|
|
unsigned long maxaddr; /* only addresses < this are protected */
|
|
|
|
unsigned int **protptrs[2];
|
|
|
|
unsigned int *low_prot[4];
|
|
|
|
};
|
|
|
|
|
|
|
|
#undef PGD_TABLE_SIZE
|
|
|
|
#define PGD_TABLE_SIZE ((sizeof(pgd_t) << PGD_INDEX_SIZE) + \
|
|
|
|
sizeof(struct subpage_prot_table))
|
|
|
|
|
|
|
|
#define SBP_L1_BITS (PAGE_SHIFT - 2)
|
|
|
|
#define SBP_L2_BITS (PAGE_SHIFT - 3)
|
|
|
|
#define SBP_L1_COUNT (1 << SBP_L1_BITS)
|
|
|
|
#define SBP_L2_COUNT (1 << SBP_L2_BITS)
|
|
|
|
#define SBP_L2_SHIFT (PAGE_SHIFT + SBP_L1_BITS)
|
|
|
|
#define SBP_L3_SHIFT (SBP_L2_SHIFT + SBP_L2_BITS)
|
|
|
|
|
|
|
|
extern void subpage_prot_free(pgd_t *pgd);
|
|
|
|
|
|
|
|
static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
|
|
|
|
{
|
|
|
|
return (struct subpage_prot_table *)(pgd + PTRS_PER_PGD);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_PPC_SUBPAGE_PROT */
|
|
|
|
#endif /* __ASSEMBLY__ */
|