sh: Provide a sane valid_phys_addr_range() to prevent TLB reset with PMB.

With the PMB enabled, only P1SEG and up are covered by the PMB mappings,
meaning that situations where out-of-bounds physical addresses are read
from will lead to TLB reset after the PMB miss, allowing for use cases
like dd if=/dev/mem to reset the TLB.

Fix this up to make sure the reference is between __MEMORY_START (phys)
and __pa(high_memory). This is coherent across all variants of sh/sh64
with and without MMU, though the PMB bug itself is only applicable to
SH-4A parts.

Reported-by: Hideo Saito <saito@densan.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

+37 -2
+4
arch/sh/include/asm/io.h
··· 293 293 */ 294 294 #define xlate_dev_kmem_ptr(p) p 295 295 296 + #define ARCH_HAS_VALID_PHYS_ADDR_RANGE 297 + int valid_phys_addr_range(unsigned long addr, size_t size); 298 + int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); 299 + 296 300 #endif /* __KERNEL__ */ 297 301 298 302 #endif /* __ASM_SH_IO_H */
+1 -1
arch/sh/mm/Makefile_32
··· 2 2 # Makefile for the Linux SuperH-specific parts of the memory manager. 3 3 # 4 4 5 - obj-y := init.o extable_32.o consistent.o 5 + obj-y := init.o extable_32.o consistent.o mmap.o 6 6 7 7 ifndef CONFIG_CACHE_OFF 8 8 cache-$(CONFIG_CPU_SH2) := cache-sh2.o
+1 -1
arch/sh/mm/Makefile_64
··· 2 2 # Makefile for the Linux SuperH-specific parts of the memory manager. 3 3 # 4 4 5 - obj-y := init.o consistent.o 5 + obj-y := init.o consistent.o mmap.o 6 6 7 7 mmu-y := tlb-nommu.o pg-nommu.o extable_32.o 8 8 mmu-$(CONFIG_MMU) := fault_64.o ioremap_64.o tlbflush_64.o tlb-sh5.o \
+31
arch/sh/mm/mmap.c
··· 1 + /* 2 + * arch/sh/mm/mmap.c 3 + * 4 + * Copyright (C) 2008 Paul Mundt 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file "COPYING" in the main directory of this archive 8 + * for more details. 9 + */ 10 + #include <linux/io.h> 11 + #include <linux/mm.h> 12 + #include <asm/page.h> 13 + 14 + /* 15 + * You really shouldn't be using read() or write() on /dev/mem. This 16 + * might go away in the future. 17 + */ 18 + int valid_phys_addr_range(unsigned long addr, size_t count) 19 + { 20 + if (addr < (PAGE_OFFSET + (PFN_START << PAGE_SHIFT))) 21 + return 0; 22 + if (addr + count > __pa(high_memory)) 23 + return 0; 24 + 25 + return 1; 26 + } 27 + 28 + int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) 29 + { 30 + return 1; 31 + }