Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

parisc: fix usage of 32bit PTE page table entries on 32bit kernels

This patch fixes a long outstanding bug on 32bit parisc linux kernels
which prevented us from using 32bit PTE table entries (instead of 64bit
entries of which 32bit were unused).

The problem was caused by this assembler statement in the L2_ptep
macro in arch/parisc/kernel/entry.S:447:
EXTR \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
which expanded to
extrw,u r8,9,11,r1
and which has undefined behavior since the length value (11) extends
beyond the leftmost bit (11-1 > 9).
Interestingly PA2.0 processors seem to don't care and just zero-extend
the value, while PA1.1 processors don't.

Fix this problem by detecting an address space overflow with ASM_BITS_PER_PGD
and adjusting it accordingly. To prevent such problems in the future,
some compile time sanity checks in arch/parisc/mm/init.c were added.

Since the page table now only consumes half of it's old size, we can
use the freed memory to harmonize 32- and 64bit kernels and let both
map 16MB for the initial page table.

Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Kyle McMartin <kyle@mcmartin.ca>

authored by

Helge Deller and committed by
Kyle McMartin
48d27cb2 15f7176e

+19 -16
+2 -11
arch/parisc/include/asm/page.h
··· 36 36 */ 37 37 #define STRICT_MM_TYPECHECKS 38 38 #ifdef STRICT_MM_TYPECHECKS 39 - typedef struct { unsigned long pte; 40 - #if !defined(CONFIG_64BIT) 41 - unsigned long future_flags; 42 - /* XXX: it's possible to remove future_flags and change BITS_PER_PTE_ENTRY 43 - to 2, but then strangely the identical 32bit kernel boots on a 44 - c3000(pa20), but not any longer on a 715(pa11). 45 - Still investigating... HelgeD. 46 - */ 47 - #endif 48 - } pte_t; /* either 32 or 64bit */ 39 + typedef struct { unsigned long pte; } pte_t; /* either 32 or 64bit */ 49 40 50 41 /* NOTE: even on 64 bits, these entries are __u32 because we allocate 51 42 * the pmd and pgd in ZONE_DMA (i.e. under 4GB) */ ··· 102 111 #define BITS_PER_PMD_ENTRY 2 103 112 #define BITS_PER_PGD_ENTRY 2 104 113 #else 105 - #define BITS_PER_PTE_ENTRY 3 114 + #define BITS_PER_PTE_ENTRY 2 106 115 #define BITS_PER_PMD_ENTRY 2 107 116 #define BITS_PER_PGD_ENTRY BITS_PER_PMD_ENTRY 108 117 #endif
+10 -5
arch/parisc/include/asm/pgtable.h
··· 50 50 printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e)) 51 51 52 52 /* This is the size of the initially mapped kernel memory */ 53 - #ifdef CONFIG_64BIT 54 53 #define KERNEL_INITIAL_ORDER 24 /* 0 to 1<<24 = 16MB */ 55 - #else 56 - #define KERNEL_INITIAL_ORDER 23 /* 0 to 1<<23 = 8MB */ 57 - #endif 58 54 #define KERNEL_INITIAL_SIZE (1 << KERNEL_INITIAL_ORDER) 59 55 60 56 #if defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB) ··· 87 91 88 92 /* Definitions for 1st level */ 89 93 #define PGDIR_SHIFT (PMD_SHIFT + BITS_PER_PMD) 94 + #if (PGDIR_SHIFT + PAGE_SHIFT + PGD_ORDER - BITS_PER_PGD_ENTRY) > BITS_PER_LONG 95 + #define BITS_PER_PGD (BITS_PER_LONG - PGDIR_SHIFT) 96 + #else 90 97 #define BITS_PER_PGD (PAGE_SHIFT + PGD_ORDER - BITS_PER_PGD_ENTRY) 98 + #endif 91 99 #define PGDIR_SIZE (1UL << PGDIR_SHIFT) 92 100 #define PGDIR_MASK (~(PGDIR_SIZE-1)) 93 101 #define PTRS_PER_PGD (1UL << BITS_PER_PGD) 94 102 #define USER_PTRS_PER_PGD PTRS_PER_PGD 95 103 104 + #ifdef CONFIG_64BIT 96 105 #define MAX_ADDRBITS (PGDIR_SHIFT + BITS_PER_PGD) 97 106 #define MAX_ADDRESS (1UL << MAX_ADDRBITS) 98 - 99 107 #define SPACEID_SHIFT (MAX_ADDRBITS - 32) 108 + #else 109 + #define MAX_ADDRBITS (BITS_PER_LONG) 110 + #define MAX_ADDRESS (1UL << MAX_ADDRBITS) 111 + #define SPACEID_SHIFT 0 112 + #endif 100 113 101 114 /* This calculates the number of initial pages we need for the initial 102 115 * page tables */
+7
arch/parisc/mm/init.c
··· 456 456 { 457 457 int codesize, reservedpages, datasize, initsize; 458 458 459 + /* Do sanity checks on page table constants */ 460 + BUILD_BUG_ON(PTE_ENTRY_SIZE != sizeof(pte_t)); 461 + BUILD_BUG_ON(PMD_ENTRY_SIZE != sizeof(pmd_t)); 462 + BUILD_BUG_ON(PGD_ENTRY_SIZE != sizeof(pgd_t)); 463 + BUILD_BUG_ON(PAGE_SHIFT + BITS_PER_PTE + BITS_PER_PMD + BITS_PER_PGD 464 + > BITS_PER_LONG); 465 + 459 466 high_memory = __va((max_pfn << PAGE_SHIFT)); 460 467 461 468 #ifndef CONFIG_DISCONTIGMEM