Commit 21440cf0 authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: Preliminary support for SH-X2 MMU.



This adds some preliminary support for the SH-X2 MMU, used by
newer SH-4A parts (particularly SH7785).

This MMU implements a 'compat' mode with SH-X MMUs and an
'extended' mode for SH-X2 extended features. Extended features
include additional page sizes (8kB, 4MB, 64MB), as well as the
addition of page execute permissions.

The extended mode attributes are placed in a second data array,
which requires us to switch to 64-bit PTEs when in X2 mode.

With the addition of the exec perms, we also overhaul the mmap
prots somewhat, now that it's possible to handle them more
intelligently.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent b552c7e8
Loading
Loading
Loading
Loading
+47 −2
Original line number Diff line number Diff line
@@ -235,13 +235,22 @@ config MEMORY_SIZE

config 32BIT
	bool "Support 32-bit physical addressing through PMB"
	depends on CPU_SH4A && MMU
	depends on CPU_SH4A && MMU && (!X2TLB || BROKEN)
	default y
	help
	  If you say Y here, physical addressing will be extended to
	  32-bits through the SH-4A PMB. If this is not set, legacy
	  29-bit physical addressing will be used.

config X2TLB
	bool "Enable extended TLB mode"
	depends on CPU_SUBTYPE_SH7785 && MMU && EXPERIMENTAL
	help
	  Selecting this option will enable the extended mode of the SH-X2
	  TLB. For legacy SH-X behaviour and interoperability, say N. For
	  all of the fun new features and a willingless to submit bug reports,
	  say Y.

config VSYSCALL
	bool "Support vsyscall page"
	depends on MMU
@@ -255,17 +264,53 @@ config VSYSCALL
	  For systems with an MMU that can afford to give up a page,
	  (the default value) say Y.

choice
	prompt "Kernel page size"
	default PAGE_SIZE_4KB

config PAGE_SIZE_4KB
	bool "4kB"
	help
	  This is the default page size used by all SuperH CPUs.

config PAGE_SIZE_8KB
	bool "8kB"
	depends on EXPERIMENTAL && X2TLB
	help
	  This enables 8kB pages as supported by SH-X2 and later MMUs.

config PAGE_SIZE_64KB
	bool "64kB"
	depends on EXPERIMENTAL && CPU_SH4
	help
	  This enables support for 64kB pages, possible on all SH-4
	  CPUs and later. Highly experimental, not recommended.

endchoice

choice
	prompt "HugeTLB page size"
	depends on HUGETLB_PAGE && CPU_SH4 && MMU
	default HUGETLB_PAGE_SIZE_64K

config HUGETLB_PAGE_SIZE_64K
	bool "64K"
	bool "64kB"

config HUGETLB_PAGE_SIZE_256K
	bool "256kB"
	depends on X2TLB

config HUGETLB_PAGE_SIZE_1MB
	bool "1MB"

config HUGETLB_PAGE_SIZE_4MB
	bool "4MB"
	depends on X2TLB

config HUGETLB_PAGE_SIZE_64MB
	bool "64MB"
	depends on X2TLB

endchoice

source "mm/Kconfig"
+2 −2
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
	pud = pud_offset(pgd, addr);
	if (pud_none(*pud)) {
		pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
		set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
		set_pud(pud, __pud(__pa(pmd) | _PAGE_TABLE));
		if (pmd != pmd_offset(pud, 0)) {
			pud_ERROR(*pud);
			return;
@@ -103,7 +103,7 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
	pmd = pmd_offset(pud, addr);
	if (pmd_none(*pmd)) {
		pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
		set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
		set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE));
		if (pte != pte_offset_kernel(pmd, 0)) {
			pmd_ERROR(*pmd);
			return;
+1 −3
Original line number Diff line number Diff line
@@ -28,9 +28,7 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address,
{
	unsigned long end;
	unsigned long pfn;
	pgprot_t pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW |
				   _PAGE_DIRTY | _PAGE_ACCESSED |
				   _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | flags);
	pgprot_t pgprot = __pgprot(pgprot_val(PAGE_KERNEL_NOCACHE) | flags);

	address &= ~PMD_MASK;
	end = address + size;
+2 −10
Original line number Diff line number Diff line
@@ -37,10 +37,6 @@ void clear_user_page(void *to, unsigned long address, struct page *page)
	if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
		clear_page(to);
	else {
		pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
					   _PAGE_RW | _PAGE_CACHABLE |
					   _PAGE_DIRTY | _PAGE_ACCESSED |
					   _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
		unsigned long phys_addr = PHYSADDR(to);
		unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
		pgd_t *pgd = pgd_offset_k(p3_addr);
@@ -50,7 +46,7 @@ void clear_user_page(void *to, unsigned long address, struct page *page)
		pte_t entry;
		unsigned long flags;

		entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot);
		entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL);
		down(&p3map_sem[(address & CACHE_ALIAS)>>12]);
		set_pte(pte, entry);
		local_irq_save(flags);
@@ -77,10 +73,6 @@ void copy_user_page(void *to, void *from, unsigned long address,
	if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
		copy_page(to, from);
	else {
		pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
					   _PAGE_RW | _PAGE_CACHABLE |
					   _PAGE_DIRTY | _PAGE_ACCESSED |
					   _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
		unsigned long phys_addr = PHYSADDR(to);
		unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
		pgd_t *pgd = pgd_offset_k(p3_addr);
@@ -90,7 +82,7 @@ void copy_user_page(void *to, void *from, unsigned long address,
		pte_t entry;
		unsigned long flags;

		entry = pfn_pte(phys_addr >> PAGE_SHIFT, pgprot);
		entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL);
		down(&p3map_sem[(address & CACHE_ALIAS)>>12]);
		set_pte(pte, entry);
		local_irq_save(flags);
+1 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ typedef struct user_fpu_struct elf_fpregset_t;
#define ELF_ARCH	EM_SH

#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE	4096
#define ELF_EXEC_PAGESIZE	PAGE_SIZE

/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
   use of this is to invoke "./ld.so someprog" to test out a new version of
Loading