From dfcc64497cbbf942cdd5af4b7eb17542b62aa759 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 30 Sep 2008 16:05:09 +0100 Subject: [ARM] 5271/1: get rid of pages_to_mb() There is no use of this in the whole tree. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/include/asm/pgtable.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 8e21ef15bd7..ec630109a8c 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -319,11 +319,6 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) #define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd))) -/* - * Permanent address of a page. We never have highmem, so this is trivial. - */ -#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT)) - /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. -- cgit v1.2.3-70-g09d2 From 9cff96e5bfc8e366166bfb07610604c7604ac48c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Sep 2008 18:53:37 +0100 Subject: [ARM] Re-jig Linux PTE bits to allow room for 4 memory type bits Signed-off-by: Russell King --- arch/arm/include/asm/pgtable.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 8e21ef15bd7..5c75e02b3c7 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -166,10 +166,10 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define L_PTE_YOUNG (1 << 1) #define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */ #define L_PTE_CACHEABLE (1 << 3) /* matches PTE */ -#define L_PTE_USER (1 << 4) -#define L_PTE_WRITE (1 << 5) -#define L_PTE_EXEC (1 << 6) -#define L_PTE_DIRTY (1 << 7) +#define L_PTE_DIRTY (1 << 6) +#define L_PTE_WRITE (1 << 7) +#define L_PTE_USER (1 << 8) +#define L_PTE_EXEC (1 << 9) #define L_PTE_SHARED (1 << 10) /* shared(v6), coherent(xsc3) */ #ifndef __ASSEMBLY__ -- cgit v1.2.3-70-g09d2 From bb30f36f9b71c31dc8fe3483bba4c9884fc86080 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Sep 2008 20:04:59 +0100 Subject: [ARM] Introduce new PTE memory type bits Provide L_PTE_MT_xxx definitions to describe the memory types that we use in Linux/ARM. These definitions are carefully picked such that: 1. their LSBs match what is required for pre-ARMv6 CPUs. 2. they all have a unique encoding, including after modification by build_mem_type_table() (the result being that some have more than one combination.) Signed-off-by: Russell King --- arch/arm/include/asm/pgtable.h | 33 ++++++++++++++++++---- arch/arm/mm/copypage-v4mc.c | 2 +- arch/arm/mm/copypage-xscale.c | 2 +- arch/arm/mm/fault-armv.c | 11 ++++---- arch/arm/mm/mmu.c | 62 ++++++++++++++++++++++-------------------- 5 files changed, 68 insertions(+), 42 deletions(-) (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 5c75e02b3c7..8df2e254a3e 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -164,14 +164,35 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define L_PTE_PRESENT (1 << 0) #define L_PTE_FILE (1 << 1) /* only when !PRESENT */ #define L_PTE_YOUNG (1 << 1) -#define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */ -#define L_PTE_CACHEABLE (1 << 3) /* matches PTE */ +#define L_PTE_BUFFERABLE (1 << 2) /* obsolete, matches PTE */ +#define L_PTE_CACHEABLE (1 << 3) /* obsolete, matches PTE */ #define L_PTE_DIRTY (1 << 6) #define L_PTE_WRITE (1 << 7) #define L_PTE_USER (1 << 8) #define L_PTE_EXEC (1 << 9) #define L_PTE_SHARED (1 << 10) /* shared(v6), coherent(xsc3) */ +/* + * These are the memory types, defined to be compatible with + * pre-ARMv6 CPUs cacheable and bufferable bits: XXCB + * (note: build_mem_type_table modifies these bits + * to work with our existing proc-*.S setup.) + */ +#define L_PTE_MT_UNCACHED (0x00 << 2) /* 0000 */ +#define L_PTE_MT_BUFFERABLE (0x01 << 2) /* 0001 */ +#define L_PTE_MT_WRITETHROUGH (0x02 << 2) /* 0010 */ +#define L_PTE_MT_WRITEBACK (0x03 << 2) /* 0011 */ +#define L_PTE_MT_MINICACHE (0x06 << 2) /* 0110 (sa1100, xscale) */ +#define L_PTE_MT_WRITEALLOC (0x07 << 2) /* 0111 */ +#define L_PTE_MT_DEV_SHARED (0x04 << 2) /* 0100 (pre-v6) */ +#define L_PTE_MT_DEV_SHARED2 (0x05 << 2) /* 0101 (v6) */ +#define L_PTE_MT_DEV_NONSHARED (0x0c << 2) /* 1100 */ +#define L_PTE_MT_DEV_IXP2000 (0x0d << 2) /* 1101 */ +#define L_PTE_MT_DEV_WC (0x09 << 2) /* 1001 (pre-v6, !xsc3) */ +#define L_PTE_MT_DEV_WC2 (0x08 << 2) /* 1000 (xsc3, v6) */ +#define L_PTE_MT_DEV_CACHED (0x0b << 2) /* 1011 */ +#define L_PTE_MT_MASK (0x0f << 2) + #ifndef __ASSEMBLY__ /* @@ -180,7 +201,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val); * as well as any architecture dependent bits like global/ASID and SMP * shared mapping bits. */ -#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_CACHEABLE | L_PTE_BUFFERABLE +#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG #define _L_PTE_READ L_PTE_USER | L_PTE_EXEC extern pgprot_t pgprot_user; @@ -286,8 +307,10 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; } /* * Mark the prot value as uncacheable and unbufferable. */ -#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE)) -#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE) +#define pgprot_noncached(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_UNCACHED) +#define pgprot_writecombine(prot) \ + __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_BUFFERABLE) #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_present(pmd) (pmd_val(pmd)) diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c index ded0e96d069..8d33e254934 100644 --- a/arch/arm/mm/copypage-v4mc.c +++ b/arch/arm/mm/copypage-v4mc.c @@ -28,7 +28,7 @@ * specific hacks for copying pages efficiently. */ #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ - L_PTE_CACHEABLE) + L_PTE_MT_MINICACHE) static DEFINE_SPINLOCK(minicache_lock); diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c index 2e455f82a4d..bad49331bbf 100644 --- a/arch/arm/mm/copypage-xscale.c +++ b/arch/arm/mm/copypage-xscale.c @@ -30,7 +30,7 @@ #define COPYPAGE_MINICACHE 0xffff8000 #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ - L_PTE_CACHEABLE) + L_PTE_MT_MINICACHE) static DEFINE_SPINLOCK(minicache_lock); diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index a8ec97b4752..6f92904a81e 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -21,7 +21,7 @@ #include #include -static unsigned long shared_pte_mask = L_PTE_CACHEABLE; +static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE; /* * We take the easy way out of this problem - we make the @@ -63,9 +63,10 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address) * If this page isn't present, or is already setup to * fault (ie, is old), we can safely ignore any issues. */ - if (ret && pte_val(entry) & shared_pte_mask) { + if (ret && (pte_val(entry) & L_PTE_MT_MASK) != shared_pte_mask) { flush_cache_page(vma, address, pte_pfn(entry)); - pte_val(entry) &= ~shared_pte_mask; + pte_val(entry) &= ~L_PTE_MT_MASK; + pte_val(entry) |= shared_pte_mask; set_pte_at(vma->vm_mm, address, pte, entry); flush_tlb_page(vma, address); } @@ -197,7 +198,7 @@ void __init check_writebuffer_bugs(void) unsigned long *p1, *p2; pgprot_t prot = __pgprot(L_PTE_PRESENT|L_PTE_YOUNG| L_PTE_DIRTY|L_PTE_WRITE| - L_PTE_BUFFERABLE); + L_PTE_MT_BUFFERABLE); p1 = vmap(&page, 1, VM_IOREMAP, prot); p2 = vmap(&page, 1, VM_IOREMAP, prot); @@ -218,7 +219,7 @@ void __init check_writebuffer_bugs(void) if (v) { printk("failed, %s\n", reason); - shared_pte_mask |= L_PTE_BUFFERABLE; + shared_pte_mask = L_PTE_MT_UNCACHED; } else { printk("ok\n"); } diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index a713e40e1f1..cfc0add4874 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -68,27 +68,27 @@ static struct cachepolicy cache_policies[] __initdata = { .policy = "uncached", .cr_mask = CR_W|CR_C, .pmd = PMD_SECT_UNCACHED, - .pte = 0, + .pte = L_PTE_MT_UNCACHED, }, { .policy = "buffered", .cr_mask = CR_C, .pmd = PMD_SECT_BUFFERED, - .pte = PTE_BUFFERABLE, + .pte = L_PTE_MT_BUFFERABLE, }, { .policy = "writethrough", .cr_mask = 0, .pmd = PMD_SECT_WT, - .pte = PTE_CACHEABLE, + .pte = L_PTE_MT_WRITETHROUGH, }, { .policy = "writeback", .cr_mask = 0, .pmd = PMD_SECT_WB, - .pte = PTE_BUFFERABLE|PTE_CACHEABLE, + .pte = L_PTE_MT_WRITEBACK, }, { .policy = "writealloc", .cr_mask = 0, .pmd = PMD_SECT_WBWA, - .pte = PTE_BUFFERABLE|PTE_CACHEABLE, + .pte = L_PTE_MT_WRITEALLOC, } }; @@ -186,35 +186,36 @@ void adjust_cr(unsigned long mask, unsigned long set) static struct mem_type mem_types[] = { [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */ - .prot_pte = PROT_PTE_DEVICE, + .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | + L_PTE_SHARED, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_UNCACHED, .domain = DOMAIN_IO, }, [MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */ - .prot_pte = PROT_PTE_DEVICE, + .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_NONSHARED, .prot_pte_ext = PTE_EXT_TEX(2), .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_TEX(2), .domain = DOMAIN_IO, }, [MT_DEVICE_CACHED] = { /* ioremap_cached */ - .prot_pte = PROT_PTE_DEVICE | L_PTE_CACHEABLE | L_PTE_BUFFERABLE, + .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB, .domain = DOMAIN_IO, }, [MT_DEVICE_IXP2000] = { /* IXP2400 requires XCB=101 for on-chip I/O */ - .prot_pte = PROT_PTE_DEVICE, + .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_IXP2000, .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE | PMD_SECT_TEX(1), .domain = DOMAIN_IO, }, [MT_DEVICE_WC] = { /* ioremap_wc */ - .prot_pte = PROT_PTE_DEVICE, + .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC, .prot_l1 = PMD_TYPE_TABLE, - .prot_sect = PROT_SECT_DEVICE, + .prot_sect = PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE, .domain = DOMAIN_IO, }, [MT_CACHECLEAN] = { @@ -259,7 +260,7 @@ static void __init build_mem_type_table(void) { struct cachepolicy *cp; unsigned int cr = get_cr(); - unsigned int user_pgprot, kern_pgprot; + unsigned int user_pgprot, kern_pgprot, vecs_pgprot; int cpu_arch = cpu_architecture(); int i; @@ -277,6 +278,9 @@ static void __init build_mem_type_table(void) cachepolicy = CPOLICY_WRITEBACK; ecc_mask = 0; } +#ifdef CONFIG_SMP + cachepolicy = CPOLICY_WRITEALLOC; +#endif /* * On non-Xscale3 ARMv5-and-older systems, use CB=01 @@ -286,10 +290,9 @@ static void __init build_mem_type_table(void) */ if (cpu_is_xsc3() || cpu_arch >= CPU_ARCH_ARMv6) { mem_types[MT_DEVICE_WC].prot_pte_ext |= PTE_EXT_TEX(1); + mem_types[MT_DEVICE_WC].prot_pte &= ~L_PTE_BUFFERABLE; mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_TEX(1); - } else { - mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_BUFFERABLE; - mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_BUFFERABLE; + mem_types[MT_DEVICE_WC].prot_sect &= ~PMD_SECT_BUFFERABLE; } /* @@ -312,7 +315,15 @@ static void __init build_mem_type_table(void) } cp = &cache_policies[cachepolicy]; - kern_pgprot = user_pgprot = cp->pte; + vecs_pgprot = kern_pgprot = user_pgprot = cp->pte; + +#ifndef CONFIG_SMP + /* + * Only use write-through for non-SMP systems + */ + if (cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH) + vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte; +#endif /* * Enable CPU-specific coherency if supported. @@ -349,30 +360,21 @@ static void __init build_mem_type_table(void) */ user_pgprot |= L_PTE_SHARED; kern_pgprot |= L_PTE_SHARED; + vecs_pgprot |= L_PTE_SHARED; mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; #endif } for (i = 0; i < 16; i++) { unsigned long v = pgprot_val(protection_map[i]); - v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot; - protection_map[i] = __pgprot(v); + protection_map[i] = __pgprot(v | user_pgprot); } - mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot; - mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot; + mem_types[MT_LOW_VECTORS].prot_pte |= vecs_pgprot; + mem_types[MT_HIGH_VECTORS].prot_pte |= vecs_pgprot; - if (cpu_arch >= CPU_ARCH_ARMv5) { -#ifndef CONFIG_SMP - /* - * Only use write-through for non-SMP systems - */ - mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE; - mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE; -#endif - } else { + if (cpu_arch < CPU_ARCH_ARMv5) mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1); - } pgprot_user = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot); pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | -- cgit v1.2.3-70-g09d2 From 9e8b5199a753a2583a8ef8360e6428304a242283 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Sep 2008 20:47:54 +0100 Subject: [ARM] Convert Xscale and Xscale3 to use new memory types Signed-off-by: Russell King --- arch/arm/include/asm/pgtable.h | 4 ++-- arch/arm/mm/proc-xsc3.S | 30 ++++++++++++++++++++---- arch/arm/mm/proc-xscale.S | 52 +++++++++++++++++++++++------------------- 3 files changed, 55 insertions(+), 31 deletions(-) (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 8df2e254a3e..8f039a08b00 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -188,8 +188,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define L_PTE_MT_DEV_SHARED2 (0x05 << 2) /* 0101 (v6) */ #define L_PTE_MT_DEV_NONSHARED (0x0c << 2) /* 1100 */ #define L_PTE_MT_DEV_IXP2000 (0x0d << 2) /* 1101 */ -#define L_PTE_MT_DEV_WC (0x09 << 2) /* 1001 (pre-v6, !xsc3) */ -#define L_PTE_MT_DEV_WC2 (0x08 << 2) /* 1000 (xsc3, v6) */ +#define L_PTE_MT_DEV_WC (0x09 << 2) /* 1001 (pre-v6) */ +#define L_PTE_MT_DEV_WC2 (0x08 << 2) /* 1000 (v6) */ #define L_PTE_MT_DEV_CACHED (0x0b << 2) /* 1011 */ #define L_PTE_MT_MASK (0x0f << 2) diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index ad1ce5a8922..96e47fc7fd6 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -347,16 +347,36 @@ ENTRY(cpu_xsc3_switch_mm) * Set a PTE and flush it out * */ + +cpu_xsc3_mt_table: + .long 0x00 @ L_PTE_MT_UNCACHED + .long PTE_BUFFERABLE @ L_PTE_MT_BUFFERABLE + .long PTE_EXT_TEX(5) | PTE_CACHEABLE @ L_PTE_MT_WRITETHROUGH + .long PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEBACK + .long 0x00 @ L_PTE_MT_DEV_SHARED + .long 0x00 @ L_PTE_MT_DEV_SHARED2 + .long 0x00 @ L_PTE_MT_MINICACHE (not present) + .long PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEALLOC (not present?) + .long PTE_EXT_TEX(1) @ L_PTE_MT_DEV_WC2 + .long PTE_EXT_TEX(1) @ L_PTE_MT_DEV_WC + .long 0x00 @ unused + .long PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED + .long 0x00 @ L_PTE_MT_DEV_NONSHARED + .long 0x00 @ L_PTE_MT_DEV_IXP2000 (not present) + .long 0x00 @ unused + .long 0x00 @ unused + .align 5 ENTRY(cpu_xsc3_set_pte_ext) xscale_set_pte_ext_prologue - @ If it's cacheable, it needs to be in L2 also. - tst r1, #L_PTE_CACHEABLE - orrne r2, r2, #PTE_EXT_TEX(0x5) - tst r1, #L_PTE_SHARED @ shared? - orrne r2, r2, #0x200 + and r1, r1, #L_PTE_MT_MASK + adr ip, cpu_xsc3_mt_table + ldr ip, [ip, r1] + orrne r2, r2, #PTE_EXT_COHERENT @ interlock: mask in coherent bit + bic r2, r2, #0x0c @ clear old C,B bits + orr r2, r2, ip xscale_set_pte_ext_epilogue mov pc, lr diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 8d7512f9cba..6fa525364bb 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -406,8 +406,6 @@ ENTRY(cpu_xscale_dcache_clean_area) /* =============================== PageTable ============================== */ -#define PTE_CACHE_WRITE_ALLOCATE 0 - /* * cpu_xscale_switch_mm(pgd) * @@ -431,34 +429,40 @@ ENTRY(cpu_xscale_switch_mm) * * Errata 40: must set memory to write-through for user read-only pages. */ +cpu_xscale_mt_table: + .long 0x00 @ L_PTE_MT_UNCACHED + .long PTE_BUFFERABLE @ L_PTE_MT_BUFFERABLE + .long PTE_CACHEABLE @ L_PTE_MT_WRITETHROUGH + .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEBACK + .long 0x00 @ L_PTE_MT_DEV_SHARED + .long 0x00 @ L_PTE_MT_DEV_SHARED2 + .long PTE_EXT_TEX(1) | PTE_CACHEABLE @ L_PTE_MT_MINICACHE + .long PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEALLOC + .long PTE_BUFFERABLE @ L_PTE_MT_DEV_WC2 + .long PTE_BUFFERABLE @ L_PTE_MT_DEV_WC + .long 0x00 @ unused + .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED + .long 0x00 @ L_PTE_MT_DEV_NONSHARED + .long PTE_EXT_TEX(1) | PTE_BUFFERABLE @ L_PTE_MT_DEV_IXP2000 + .long 0x00 @ unused + .long 0x00 @ unused + .align 5 ENTRY(cpu_xscale_set_pte_ext) xscale_set_pte_ext_prologue - @ - @ Handle the X bit. We want to set this bit for the minicache - @ (U = E = B = W = 0, C = 1) or when write allocate is enabled, - @ and we have a writeable, cacheable region. If we ignore the - @ U and E bits, we can allow user space to use the minicache as - @ well. - @ - @ X = (C & ~W & ~B) | (C & W & B & write_allocate) - @ - and ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE - teq ip, #L_PTE_CACHEABLE -#if PTE_CACHE_WRITE_ALLOCATE - teqne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE -#endif - orreq r2, r2, #PTE_EXT_TEX(1) @ - @ Erratum 40: The B bit must be cleared for a user read-only - @ cacheable page. - @ - @ B = B & ~(U & C & ~W) + @ Erratum 40: must set memory to write-through for user read-only pages @ - and ip, r1, #L_PTE_USER | L_PTE_WRITE | L_PTE_CACHEABLE - teq ip, #L_PTE_USER | L_PTE_CACHEABLE - biceq r2, r2, #PTE_BUFFERABLE + and ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_WRITE) & ~(4 << 2) + teq ip, #L_PTE_MT_WRITEBACK | L_PTE_USER + + moveq r1, #L_PTE_MT_WRITETHROUGH + and r1, r1, #L_PTE_MT_MASK + adr ip, cpu_xscale_mt_table + ldr ip, [ip, r1] + bic r2, r2, #0x0c + orr r2, r2, ip xscale_set_pte_ext_epilogue mov pc, lr -- cgit v1.2.3-70-g09d2 From 639b0ae7f5bcd645862a9c3ea2d4321475c71d7a Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Sep 2008 21:07:45 +0100 Subject: [ARM] Convert ARMv6 and ARMv7 to use new memory types Signed-off-by: Russell King --- arch/arm/include/asm/pgtable.h | 8 ++------ arch/arm/mm/mmu.c | 4 ---- arch/arm/mm/proc-macros.S | 30 ++++++++++++++++++++++++++++-- arch/arm/mm/proc-v6.S | 4 +++- arch/arm/mm/proc-v7.S | 4 +++- arch/arm/mm/proc-xsc3.S | 4 ++-- arch/arm/mm/proc-xscale.S | 4 ++-- 7 files changed, 40 insertions(+), 18 deletions(-) (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 8f039a08b00..dfeff814a94 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -175,8 +175,6 @@ extern void __pgd_error(const char *file, int line, unsigned long val); /* * These are the memory types, defined to be compatible with * pre-ARMv6 CPUs cacheable and bufferable bits: XXCB - * (note: build_mem_type_table modifies these bits - * to work with our existing proc-*.S setup.) */ #define L_PTE_MT_UNCACHED (0x00 << 2) /* 0000 */ #define L_PTE_MT_BUFFERABLE (0x01 << 2) /* 0001 */ @@ -184,12 +182,10 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define L_PTE_MT_WRITEBACK (0x03 << 2) /* 0011 */ #define L_PTE_MT_MINICACHE (0x06 << 2) /* 0110 (sa1100, xscale) */ #define L_PTE_MT_WRITEALLOC (0x07 << 2) /* 0111 */ -#define L_PTE_MT_DEV_SHARED (0x04 << 2) /* 0100 (pre-v6) */ -#define L_PTE_MT_DEV_SHARED2 (0x05 << 2) /* 0101 (v6) */ +#define L_PTE_MT_DEV_SHARED (0x04 << 2) /* 0100 */ #define L_PTE_MT_DEV_NONSHARED (0x0c << 2) /* 1100 */ #define L_PTE_MT_DEV_IXP2000 (0x0d << 2) /* 1101 */ -#define L_PTE_MT_DEV_WC (0x09 << 2) /* 1001 (pre-v6) */ -#define L_PTE_MT_DEV_WC2 (0x08 << 2) /* 1000 (v6) */ +#define L_PTE_MT_DEV_WC (0x09 << 2) /* 1001 */ #define L_PTE_MT_DEV_CACHED (0x0b << 2) /* 1011 */ #define L_PTE_MT_MASK (0x0f << 2) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index cfc0add4874..04602288da2 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -194,7 +194,6 @@ static struct mem_type mem_types[] = { }, [MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_NONSHARED, - .prot_pte_ext = PTE_EXT_TEX(2), .prot_l1 = PMD_TYPE_TABLE, .prot_sect = PROT_SECT_DEVICE | PMD_SECT_TEX(2), .domain = DOMAIN_IO, @@ -289,8 +288,6 @@ static void __init build_mem_type_table(void) * in xsc3 parlance, Uncached Normal in ARMv6 parlance). */ if (cpu_is_xsc3() || cpu_arch >= CPU_ARCH_ARMv6) { - mem_types[MT_DEVICE_WC].prot_pte_ext |= PTE_EXT_TEX(1); - mem_types[MT_DEVICE_WC].prot_pte &= ~L_PTE_BUFFERABLE; mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_TEX(1); mem_types[MT_DEVICE_WC].prot_sect &= ~PMD_SECT_BUFFERABLE; } @@ -351,7 +348,6 @@ static void __init build_mem_type_table(void) /* * Mark the device area as "shared device" */ - mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE; mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED; #ifdef CONFIG_SMP diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index d1be25313d7..64e59302085 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -104,14 +104,38 @@ * 11x0 0 1 0 r/w r/o * 1111 0 1 1 r/w r/w */ - .macro armv6_set_pte_ext + .macro armv6_mt_table pfx +\pfx\()_mt_table: + .long 0x00 @ L_PTE_MT_UNCACHED + .long PTE_EXT_TEX(1) @ L_PTE_MT_BUFFERABLE + .long PTE_CACHEABLE @ L_PTE_MT_WRITETHROUGH + .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEBACK + .long PTE_BUFFERABLE @ L_PTE_MT_DEV_SHARED + .long 0x00 @ unused + .long 0x00 @ L_PTE_MT_MINICACHE (not present) + .long PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEALLOC + .long 0x00 @ unused + .long PTE_EXT_TEX(1) @ L_PTE_MT_DEV_WC + .long 0x00 @ unused + .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED + .long PTE_EXT_TEX(2) @ L_PTE_MT_DEV_NONSHARED + .long 0x00 @ L_PTE_MT_DEV_IXP2000 + .long 0x00 @ unused + .long 0x00 @ unused + .endm + + .macro armv6_set_pte_ext pfx str r1, [r0], #-2048 @ linux version - bic r3, r1, #0x000003f0 + bic r3, r1, #0x000003fc bic r3, r3, #PTE_TYPE_MASK orr r3, r3, r2 orr r3, r3, #PTE_EXT_AP0 | 2 + adr ip, \pfx\()_mt_table + and r2, r1, #L_PTE_MT_MASK + ldr r2, [ip, r2] + tst r1, #L_PTE_WRITE tstne r1, #L_PTE_DIRTY orreq r3, r3, #PTE_EXT_APX @@ -124,6 +148,8 @@ tst r1, #L_PTE_EXEC orreq r3, r3, #PTE_EXT_XN + orr r3, r3, r2 + tst r1, #L_PTE_YOUNG tstne r1, #L_PTE_PRESENT moveq r3, #0 diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 70c62353402..ab457757e85 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -115,9 +115,11 @@ ENTRY(cpu_v6_switch_mm) * - pte - PTE value to store * - ext - value for extended PTE bits */ + armv6_mt_table cpu_v6 + ENTRY(cpu_v6_set_pte_ext) #ifdef CONFIG_MMU - armv6_set_pte_ext + armv6_set_pte_ext cpu_v6 #endif mov pc, lr diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 172e2eeb6dd..7c34c892b82 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -100,9 +100,11 @@ ENTRY(cpu_v7_switch_mm) * - pte - PTE value to store * - ext - value for extended PTE bits */ + armv6_mt_table cpu_v7 + ENTRY(cpu_v7_set_pte_ext) #ifdef CONFIG_MMU - armv6_set_pte_ext + armv6_set_pte_ext cpu_v7 #endif mov pc, lr diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 96e47fc7fd6..9c5318e476f 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -354,10 +354,10 @@ cpu_xsc3_mt_table: .long PTE_EXT_TEX(5) | PTE_CACHEABLE @ L_PTE_MT_WRITETHROUGH .long PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEBACK .long 0x00 @ L_PTE_MT_DEV_SHARED - .long 0x00 @ L_PTE_MT_DEV_SHARED2 + .long 0x00 @ unused .long 0x00 @ L_PTE_MT_MINICACHE (not present) .long PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEALLOC (not present?) - .long PTE_EXT_TEX(1) @ L_PTE_MT_DEV_WC2 + .long 0x00 @ unused .long PTE_EXT_TEX(1) @ L_PTE_MT_DEV_WC .long 0x00 @ unused .long PTE_EXT_TEX(5) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 6fa525364bb..1e0c3bb1905 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -435,10 +435,10 @@ cpu_xscale_mt_table: .long PTE_CACHEABLE @ L_PTE_MT_WRITETHROUGH .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEBACK .long 0x00 @ L_PTE_MT_DEV_SHARED - .long 0x00 @ L_PTE_MT_DEV_SHARED2 + .long 0x00 @ unused .long PTE_EXT_TEX(1) | PTE_CACHEABLE @ L_PTE_MT_MINICACHE .long PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_WRITEALLOC - .long PTE_BUFFERABLE @ L_PTE_MT_DEV_WC2 + .long 0x00 @ unused .long PTE_BUFFERABLE @ L_PTE_MT_DEV_WC .long 0x00 @ unused .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED -- cgit v1.2.3-70-g09d2 From db5b7169474882fabbd811a4cf5c1bae3157e677 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 7 Sep 2008 12:42:51 +0100 Subject: [ARM] Remove MT_DEVICE_IXP2000 and associated definitions As of the previous commit, MT_DEVICE_IXP2000 encodes to the same PTE bit encoding as MT_DEVICE, so it's now redundant. Convert MT_DEVICE_IXP2000 to use MT_DEVICE instead, and remove its aliases. Signed-off-by: Russell King --- arch/arm/include/asm/io.h | 5 ++--- arch/arm/include/asm/mach/map.h | 15 ++++++------- arch/arm/include/asm/pgtable.h | 1 - arch/arm/mach-ixp2000/core.c | 27 +++++++++-------------- arch/arm/mach-ixp2000/enp2611.c | 6 ++--- arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h | 8 +------ arch/arm/mm/mmu.c | 7 ------ arch/arm/mm/proc-macros.S | 2 +- arch/arm/mm/proc-xsc3.S | 2 +- arch/arm/mm/proc-xscale.S | 2 +- 10 files changed, 26 insertions(+), 49 deletions(-) (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 71934856fc2..a8094451be5 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -60,10 +60,9 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); #define MT_DEVICE 0 #define MT_DEVICE_NONSHARED 1 #define MT_DEVICE_CACHED 2 -#define MT_DEVICE_IXP2000 3 -#define MT_DEVICE_WC 4 +#define MT_DEVICE_WC 3 /* - * types 5 onwards can be found in asm/mach/map.h and are undefined + * types 4 onwards can be found in asm/mach/map.h and are undefined * for ioremap */ diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index 9eb936e49cc..72586cd4372 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -18,16 +18,15 @@ struct map_desc { unsigned int type; }; -/* types 0-4 are defined in asm/io.h */ -#define MT_CACHECLEAN 5 -#define MT_MINICLEAN 6 -#define MT_LOW_VECTORS 7 -#define MT_HIGH_VECTORS 8 -#define MT_MEMORY 9 -#define MT_ROM 10 +/* types 0-3 are defined in asm/io.h */ +#define MT_CACHECLEAN 4 +#define MT_MINICLEAN 5 +#define MT_LOW_VECTORS 6 +#define MT_HIGH_VECTORS 7 +#define MT_MEMORY 8 +#define MT_ROM 9 #define MT_NONSHARED_DEVICE MT_DEVICE_NONSHARED -#define MT_IXP2000_DEVICE MT_DEVICE_IXP2000 #ifdef CONFIG_MMU extern void iotable_init(struct map_desc *, int); diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index dfeff814a94..e5054b026c2 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -184,7 +184,6 @@ extern void __pgd_error(const char *file, int line, unsigned long val); #define L_PTE_MT_WRITEALLOC (0x07 << 2) /* 0111 */ #define L_PTE_MT_DEV_SHARED (0x04 << 2) /* 0100 */ #define L_PTE_MT_DEV_NONSHARED (0x0c << 2) /* 1100 */ -#define L_PTE_MT_DEV_IXP2000 (0x0d << 2) /* 1101 */ #define L_PTE_MT_DEV_WC (0x09 << 2) /* 1001 */ #define L_PTE_MT_DEV_CACHED (0x0b << 2) /* 1011 */ #define L_PTE_MT_MASK (0x0f << 2) diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index a6a4f93085f..628063ca31e 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -84,64 +84,57 @@ static struct map_desc ixp2000_io_desc[] __initdata = { .virtual = IXP2000_CAP_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE), .length = IXP2000_CAP_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_INTCTL_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE), .length = IXP2000_INTCTL_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_PCI_CREG_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE), .length = IXP2000_PCI_CREG_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_PCI_CSR_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE), .length = IXP2000_PCI_CSR_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_MSF_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE), .length = IXP2000_MSF_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_SCRATCH_RING_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE), .length = IXP2000_SCRATCH_RING_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_SRAM0_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE), .length = IXP2000_SRAM0_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_PCI_IO_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE), .length = IXP2000_PCI_IO_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_PCI_CFG0_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE), .length = IXP2000_PCI_CFG0_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = IXP2000_PCI_CFG1_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE), .length = IXP2000_PCI_CFG1_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, } }; void __init ixp2000_map_io(void) { - /* - * On IXP2400 CPUs we need to use MT_DEVICE_IXP2000 so that - * XCB=101 (to avoid triggering erratum #66), and given that - * this mode speeds up I/O accesses and we have write buffer - * flushes in the right places anyway, it doesn't hurt to use - * XCB=101 for all IXP2000s. - */ iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); /* Set slowport to 8-bit mode. */ diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index c62ed655c1a..8bb184dbc18 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c @@ -70,17 +70,17 @@ static struct map_desc enp2611_io_desc[] __initdata = { .virtual = ENP2611_CALEB_VIRT_BASE, .pfn = __phys_to_pfn(ENP2611_CALEB_PHYS_BASE), .length = ENP2611_CALEB_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = ENP2611_PM3386_0_VIRT_BASE, .pfn = __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE), .length = ENP2611_PM3386_0_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, }, { .virtual = ENP2611_PM3386_1_VIRT_BASE, .pfn = __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE), .length = ENP2611_PM3386_1_SIZE, - .type = MT_DEVICE_IXP2000, + .type = MT_DEVICE, } }; diff --git a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h b/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h index 19d80379a3e..822f63f2f4a 100644 --- a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h +++ b/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h @@ -41,13 +41,7 @@ * Most of the registers are clumped in 4K regions spread throughout * the 0xc0000000 -> 0xc0100000 address range, but we just map in * the whole range using a single 1 MB section instead of small - * 4K pages. This has two advantages for us: - * - * 1) We use only one TLB entry for large number of on-chip I/O devices. - * - * 2) We can easily set the Section attributes to XCB=101 on the IXP2400 - * as required per erratum #66. We accomplish this by using a - * new MT_IXP2000_DEVICE memory type with the bits set as required. + * 4K pages. * * CAP stands for CSR Access Proxy. * diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 685dc1bf008..06ad914928c 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -204,13 +204,6 @@ static struct mem_type mem_types[] = { .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB, .domain = DOMAIN_IO, }, - [MT_DEVICE_IXP2000] = { /* IXP2400 requires XCB=101 for on-chip I/O */ - .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_IXP2000, - .prot_l1 = PMD_TYPE_TABLE, - .prot_sect = PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE | - PMD_SECT_TEX(1), - .domain = DOMAIN_IO, - }, [MT_DEVICE_WC] = { /* ioremap_wc */ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC, .prot_l1 = PMD_TYPE_TABLE, diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 64e59302085..54b1f721dec 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -119,7 +119,7 @@ .long 0x00 @ unused .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED .long PTE_EXT_TEX(2) @ L_PTE_MT_DEV_NONSHARED - .long 0x00 @ L_PTE_MT_DEV_IXP2000 + .long 0x00 @ unused .long 0x00 @ unused .long 0x00 @ unused .endm diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index 22ecef533a8..ecdd944bc2b 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -360,7 +360,7 @@ cpu_xsc3_mt_table: .long 0x00 @ unused .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED .long PTE_EXT_TEX(2) @ L_PTE_MT_DEV_NONSHARED - .long 0x00 @ L_PTE_MT_DEV_IXP2000 (not present) + .long 0x00 @ unused .long 0x00 @ unused .long 0x00 @ unused diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 534b4be86ae..01adbd9462f 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -443,7 +443,7 @@ cpu_xscale_mt_table: .long 0x00 @ unused .long PTE_CACHEABLE | PTE_BUFFERABLE @ L_PTE_MT_DEV_CACHED .long 0x00 @ L_PTE_MT_DEV_NONSHARED - .long PTE_EXT_TEX(1) | PTE_BUFFERABLE @ L_PTE_MT_DEV_IXP2000 + .long 0x00 @ unused .long 0x00 @ unused .long 0x00 @ unused -- cgit v1.2.3-70-g09d2 From 8ec53663d2698076468b3e1edc4e1b418bd54de3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 7 Sep 2008 17:16:54 +0100 Subject: [ARM] Improve non-executable support Add support for detecting non-executable stack binaries, and adjust permissions to prevent execution from data and stack areas. Also, ensure that READ_IMPLIES_EXEC is enabled for older CPUs where that is true, and for any executable-stack binary. Signed-off-by: Russell King --- arch/arm/include/asm/elf.h | 68 ++++++++++++++++++------------------ arch/arm/include/asm/page.h | 5 +-- arch/arm/include/asm/pgtable.h | 47 ++++++++++++++----------- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/elf.c | 79 ++++++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/module.c | 2 +- 6 files changed, 145 insertions(+), 58 deletions(-) create mode 100644 arch/arm/kernel/elf.c (limited to 'arch/arm/include/asm/pgtable.h') diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 7ea302c14a5..5be016980c1 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -18,9 +18,32 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef struct user_fp elf_fpregset_t; #define EM_ARM 40 -#define EF_ARM_APCS26 0x08 -#define EF_ARM_SOFT_FLOAT 0x200 -#define EF_ARM_EABI_MASK 0xFF000000 + +#define EF_ARM_EABI_MASK 0xff000000 +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +#define EF_ARM_BE8 0x00800000 /* ABI 4,5 */ +#define EF_ARM_LE8 0x00400000 /* ABI 4,5 */ +#define EF_ARM_MAVERICK_FLOAT 0x00000800 /* ABI 0 */ +#define EF_ARM_VFP_FLOAT 0x00000400 /* ABI 0 */ +#define EF_ARM_SOFT_FLOAT 0x00000200 /* ABI 0 */ +#define EF_ARM_OLD_ABI 0x00000100 /* ABI 0 */ +#define EF_ARM_NEW_ABI 0x00000080 /* ABI 0 */ +#define EF_ARM_ALIGN8 0x00000040 /* ABI 0 */ +#define EF_ARM_PIC 0x00000020 /* ABI 0 */ +#define EF_ARM_MAPSYMSFIRST 0x00000010 /* ABI 2 */ +#define EF_ARM_APCS_FLOAT 0x00000010 /* ABI 0, floats in fp regs */ +#define EF_ARM_DYNSYMSUSESEGIDX 0x00000008 /* ABI 2 */ +#define EF_ARM_APCS_26 0x00000008 /* ABI 0 */ +#define EF_ARM_SYMSARESORTED 0x00000004 /* ABI 1,2 */ +#define EF_ARM_INTERWORK 0x00000004 /* ABI 0 */ +#define EF_ARM_HASENTRY 0x00000002 /* All */ +#define EF_ARM_RELEXEC 0x00000001 /* All */ #define R_ARM_NONE 0 #define R_ARM_PC24 1 @@ -57,23 +80,16 @@ typedef struct user_fp elf_fpregset_t; extern char elf_platform[]; -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ((x)->e_machine == EM_ARM && ELF_PROC_OK(x)) +struct elf32_hdr; /* - * 32-bit code is always OK. Some cpus can do 26-bit, some can't. + * This is used to ensure we don't load something for the wrong architecture. */ -#define ELF_PROC_OK(x) (ELF_THUMB_OK(x) && ELF_26BIT_OK(x)) - -#define ELF_THUMB_OK(x) \ - ((elf_hwcap & HWCAP_THUMB && ((x)->e_entry & 1) == 1) || \ - ((x)->e_entry & 3) == 0) +extern int elf_check_arch(const struct elf32_hdr *); +#define elf_check_arch elf_check_arch -#define ELF_26BIT_OK(x) \ - ((elf_hwcap & HWCAP_26BIT && (x)->e_flags & EF_ARM_APCS26) || \ - ((x)->e_flags & EF_ARM_APCS26) == 0) +extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int); +#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk) #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -90,23 +106,7 @@ extern char elf_platform[]; have no such handler. */ #define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 -/* - * Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0 - * and CP1, we only enable access to the iWMMXt coprocessor if the - * binary is EABI or softfloat (and thus, guaranteed not to use - * FPA instructions.) - */ -#define SET_PERSONALITY(ex, ibcs2) \ - do { \ - if ((ex).e_flags & EF_ARM_APCS26) { \ - set_personality(PER_LINUX); \ - } else { \ - set_personality(PER_LINUX_32BIT); \ - if (elf_hwcap & HWCAP_IWMMXT && (ex).e_flags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) \ - set_thread_flag(TIF_USING_IWMMXT); \ - else \ - clear_thread_flag(TIF_USING_IWMMXT); \ - } \ - } while (0) +extern void elf_set_personality(const struct elf32_hdr *); +#define SET_PERSONALITY(ex, ibcs2) elf_set_personality(&(ex)) #endif diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index cf2e2680daa..bed1c0a0036 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -184,8 +184,9 @@ typedef struct page *pgtable_t; #endif /* !__ASSEMBLY__ */ -#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS \ + (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) /* * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers. diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index e5054b026c2..b02be6c55ae 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -197,22 +197,29 @@ extern void __pgd_error(const char *file, int line, unsigned long val); * shared mapping bits. */ #define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG -#define _L_PTE_READ L_PTE_USER | L_PTE_EXEC extern pgprot_t pgprot_user; extern pgprot_t pgprot_kernel; -#define PAGE_NONE pgprot_user -#define PAGE_COPY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ) -#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \ - L_PTE_WRITE) -#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ) -#define PAGE_KERNEL pgprot_kernel - -#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT) -#define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ) -#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE) -#define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ) +#define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b)) + +#define PAGE_NONE pgprot_user +#define PAGE_SHARED _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE) +#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC) +#define PAGE_COPY _MOD_PROT(pgprot_user, L_PTE_USER) +#define PAGE_COPY_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC) +#define PAGE_READONLY _MOD_PROT(pgprot_user, L_PTE_USER) +#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_EXEC) +#define PAGE_KERNEL pgprot_kernel +#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_kernel, L_PTE_EXEC) + +#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT) +#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE) +#define __PAGE_SHARED_EXEC __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE | L_PTE_EXEC) +#define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | L_PTE_USER) +#define __PAGE_COPY_EXEC __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC) +#define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | L_PTE_USER) +#define __PAGE_READONLY_EXEC __pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_EXEC) #endif /* __ASSEMBLY__ */ @@ -228,19 +235,19 @@ extern pgprot_t pgprot_kernel; #define __P001 __PAGE_READONLY #define __P010 __PAGE_COPY #define __P011 __PAGE_COPY -#define __P100 __PAGE_READONLY -#define __P101 __PAGE_READONLY -#define __P110 __PAGE_COPY -#define __P111 __PAGE_COPY +#define __P100 __PAGE_READONLY_EXEC +#define __P101 __PAGE_READONLY_EXEC +#define __P110 __PAGE_COPY_EXEC +#define __P111 __PAGE_COPY_EXEC #define __S000 __PAGE_NONE #define __S001 __PAGE_READONLY #define __S010 __PAGE_SHARED #define __S011 __PAGE_SHARED -#define __S100 __PAGE_READONLY -#define __S101 __PAGE_READONLY -#define __S110 __PAGE_SHARED -#define __S111 __PAGE_SHARED +#define __S100 __PAGE_READONLY_EXEC +#define __S101 __PAGE_READONLY_EXEC +#define __S110 __PAGE_SHARED_EXEC +#define __S111 __PAGE_SHARED_EXEC #ifndef __ASSEMBLY__ /* diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 1d296fc8494..4305345987d 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -10,7 +10,7 @@ endif # Object file lists. -obj-y := compat.o entry-armv.o entry-common.o irq.o \ +obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \ process.o ptrace.o setup.o signal.o \ sys_arm.o stacktrace.o time.o traps.o diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c new file mode 100644 index 00000000000..513f332f040 --- /dev/null +++ b/arch/arm/kernel/elf.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +int elf_check_arch(const struct elf32_hdr *x) +{ + unsigned int eflags; + + /* Make sure it's an ARM executable */ + if (x->e_machine != EM_ARM) + return 0; + + /* Make sure the entry address is reasonable */ + if (x->e_entry & 1) { + if (!(elf_hwcap & HWCAP_THUMB)) + return 0; + } else if (x->e_entry & 3) + return 0; + + eflags = x->e_flags; + if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) { + /* APCS26 is only allowed if the CPU supports it */ + if ((eflags & EF_ARM_APCS_26) && !(elf_hwcap & HWCAP_26BIT)) + return 0; + + /* VFP requires the supporting code */ + if ((eflags & EF_ARM_VFP_FLOAT) && !(elf_hwcap & HWCAP_VFP)) + return 0; + } + return 1; +} +EXPORT_SYMBOL(elf_check_arch); + +void elf_set_personality(const struct elf32_hdr *x) +{ + unsigned int eflags = x->e_flags; + unsigned int personality = PER_LINUX_32BIT; + + /* + * APCS-26 is only valid for OABI executables + */ + if ((eflags & EF_ARM_EABI_MASK) == EF_ARM_EABI_UNKNOWN) { + if (eflags & EF_ARM_APCS_26) + personality = PER_LINUX; + } + + set_personality(personality); + + /* + * Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0 + * and CP1, we only enable access to the iWMMXt coprocessor if the + * binary is EABI or softfloat (and thus, guaranteed not to use + * FPA instructions.) + */ + if (elf_hwcap & HWCAP_IWMMXT && + eflags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) { + set_thread_flag(TIF_USING_IWMMXT); + } else { + clear_thread_flag(TIF_USING_IWMMXT); + } +} +EXPORT_SYMBOL(elf_set_personality); + +/* + * Set READ_IMPLIES_EXEC if: + * - the binary requires an executable stack + * - we're running on a CPU which doesn't support NX. + */ +int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack) +{ + if (executable_stack != EXSTACK_ENABLE_X) + return 1; + if (cpu_architecture() <= CPU_ARCH_ARMv6) + return 1; + return 0; +} +EXPORT_SYMBOL(arm_elf_read_implies_exec); diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index a68259a0ccc..9203ba7d58e 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -47,7 +47,7 @@ void *module_alloc(unsigned long size) if (!area) return NULL; - return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL); + return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); } #else /* CONFIG_MMU */ void *module_alloc(unsigned long size) -- cgit v1.2.3-70-g09d2